Commit e838637fd3cfef50856e52e54b320db288592901
1 parent
c96487f5
feat(wms):增加 SKU、仓库、商户删除前的使用校验
Showing
36 changed files
with
736 additions
and
24 deletions
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/inventory/WmsInventoryDetailMapper.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.wms.dal.mysql.inventory; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.wms.dal.mysql.inventory; | ||
| 3 | import cn.hutool.core.util.StrUtil; | 3 | import cn.hutool.core.util.StrUtil; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | 5 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 6 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||
| 6 | import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; | 7 | import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; |
| 7 | import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.detail.WmsInventoryDetailPageReqVO; | 8 | import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.detail.WmsInventoryDetailPageReqVO; |
| 8 | import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDetailDO; | 9 | import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDetailDO; |
| @@ -15,6 +16,8 @@ import java.math.BigDecimal; | @@ -15,6 +16,8 @@ import java.math.BigDecimal; | ||
| 15 | import java.time.LocalDate; | 16 | import java.time.LocalDate; |
| 16 | import java.time.LocalDateTime; | 17 | import java.time.LocalDateTime; |
| 17 | import java.time.LocalTime; | 18 | import java.time.LocalTime; |
| 19 | +import java.util.Collection; | ||
| 20 | +import java.util.List; | ||
| 18 | 21 | ||
| 19 | /** | 22 | /** |
| 20 | * WMS 库存明细 Mapper | 23 | * WMS 库存明细 Mapper |
| @@ -73,4 +76,29 @@ public interface WmsInventoryDetailMapper extends BaseMapperX<WmsInventoryDetail | @@ -73,4 +76,29 @@ public interface WmsInventoryDetailMapper extends BaseMapperX<WmsInventoryDetail | ||
| 73 | throw new IllegalArgumentException("未知库存明细统计维度:" + type); | 76 | throw new IllegalArgumentException("未知库存明细统计维度:" + type); |
| 74 | } | 77 | } |
| 75 | 78 | ||
| 79 | + default WmsInventoryDetailDO selectByIdForUpdate(Long id) { | ||
| 80 | + return selectOneForUpdate(WmsInventoryDetailDO::getId, id); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + default List<WmsInventoryDetailDO> selectListByIdsForUpdate(Collection<Long> ids) { | ||
| 84 | + return selectList(new LambdaQueryWrapperX<WmsInventoryDetailDO>() | ||
| 85 | + .in(WmsInventoryDetailDO::getId, ids) | ||
| 86 | + .orderByAsc(WmsInventoryDetailDO::getId) | ||
| 87 | + .last("FOR UPDATE")); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + /** | ||
| 91 | + * 增量更新库存明细剩余数量 | ||
| 92 | + * | ||
| 93 | + * @param id 库存明细编号 | ||
| 94 | + * @param quantity 变更数量 | ||
| 95 | + * @return 更新行数 | ||
| 96 | + */ | ||
| 97 | + @SuppressWarnings("UnusedReturnValue") | ||
| 98 | + default int updateRemainQuantityIncr(Long id, BigDecimal quantity) { | ||
| 99 | + return update(null, new LambdaUpdateWrapper<WmsInventoryDetailDO>() | ||
| 100 | + .eq(WmsInventoryDetailDO::getId, id) | ||
| 101 | + .setSql("remain_quantity = remain_quantity + (" + quantity + ")")); | ||
| 102 | + } | ||
| 103 | + | ||
| 76 | } | 104 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/order/check/WmsCheckOrderDetailMapper.java
| @@ -31,4 +31,12 @@ public interface WmsCheckOrderDetailMapper extends BaseMapperX<WmsCheckOrderDeta | @@ -31,4 +31,12 @@ public interface WmsCheckOrderDetailMapper extends BaseMapperX<WmsCheckOrderDeta | ||
| 31 | delete(WmsCheckOrderDetailDO::getOrderId, orderId); | 31 | delete(WmsCheckOrderDetailDO::getOrderId, orderId); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | + default Long selectCountBySkuId(Long skuId) { | ||
| 35 | + return selectCount(WmsCheckOrderDetailDO::getSkuId, skuId); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + default Long selectCountByAreaId(Long areaId) { | ||
| 39 | + return selectCount(WmsCheckOrderDetailDO::getAreaId, areaId); | ||
| 40 | + } | ||
| 41 | + | ||
| 34 | } | 42 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/order/check/WmsCheckOrderMapper.java
| @@ -37,4 +37,12 @@ public interface WmsCheckOrderMapper extends BaseMapperX<WmsCheckOrderDO> { | @@ -37,4 +37,12 @@ public interface WmsCheckOrderMapper extends BaseMapperX<WmsCheckOrderDO> { | ||
| 37 | return selectOne(WmsCheckOrderDO::getNo, no); | 37 | return selectOne(WmsCheckOrderDO::getNo, no); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | + default Long selectCountByWarehouseId(Long warehouseId) { | ||
| 41 | + return selectCount(WmsCheckOrderDO::getWarehouseId, warehouseId); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + default Long selectCountByAreaId(Long areaId) { | ||
| 45 | + return selectCount(WmsCheckOrderDO::getAreaId, areaId); | ||
| 46 | + } | ||
| 47 | + | ||
| 40 | } | 48 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/order/movement/WmsMovementOrderDetailMapper.java
| @@ -31,4 +31,14 @@ public interface WmsMovementOrderDetailMapper extends BaseMapperX<WmsMovementOrd | @@ -31,4 +31,14 @@ public interface WmsMovementOrderDetailMapper extends BaseMapperX<WmsMovementOrd | ||
| 31 | delete(WmsMovementOrderDetailDO::getOrderId, orderId); | 31 | delete(WmsMovementOrderDetailDO::getOrderId, orderId); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | + default Long selectCountBySkuId(Long skuId) { | ||
| 35 | + return selectCount(WmsMovementOrderDetailDO::getSkuId, skuId); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + default Long selectCountByAreaId(Long areaId) { | ||
| 39 | + return selectCount(new LambdaQueryWrapperX<WmsMovementOrderDetailDO>() | ||
| 40 | + .and(query -> query.eq(WmsMovementOrderDetailDO::getSourceAreaId, areaId) | ||
| 41 | + .or().eq(WmsMovementOrderDetailDO::getTargetAreaId, areaId))); | ||
| 42 | + } | ||
| 43 | + | ||
| 34 | } | 44 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/order/movement/WmsMovementOrderMapper.java
| @@ -37,4 +37,16 @@ public interface WmsMovementOrderMapper extends BaseMapperX<WmsMovementOrderDO> | @@ -37,4 +37,16 @@ public interface WmsMovementOrderMapper extends BaseMapperX<WmsMovementOrderDO> | ||
| 37 | return selectOne(WmsMovementOrderDO::getNo, no); | 37 | return selectOne(WmsMovementOrderDO::getNo, no); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | + default Long selectCountByWarehouseId(Long warehouseId) { | ||
| 41 | + return selectCount(new LambdaQueryWrapperX<WmsMovementOrderDO>() | ||
| 42 | + .and(query -> query.eq(WmsMovementOrderDO::getSourceWarehouseId, warehouseId) | ||
| 43 | + .or().eq(WmsMovementOrderDO::getTargetWarehouseId, warehouseId))); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + default Long selectCountByAreaId(Long areaId) { | ||
| 47 | + return selectCount(new LambdaQueryWrapperX<WmsMovementOrderDO>() | ||
| 48 | + .and(query -> query.eq(WmsMovementOrderDO::getSourceAreaId, areaId) | ||
| 49 | + .or().eq(WmsMovementOrderDO::getTargetAreaId, areaId))); | ||
| 50 | + } | ||
| 51 | + | ||
| 40 | } | 52 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/order/receipt/WmsReceiptOrderDetailMapper.java
| @@ -31,4 +31,12 @@ public interface WmsReceiptOrderDetailMapper extends BaseMapperX<WmsReceiptOrder | @@ -31,4 +31,12 @@ public interface WmsReceiptOrderDetailMapper extends BaseMapperX<WmsReceiptOrder | ||
| 31 | delete(WmsReceiptOrderDetailDO::getOrderId, orderId); | 31 | delete(WmsReceiptOrderDetailDO::getOrderId, orderId); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | + default Long selectCountBySkuId(Long skuId) { | ||
| 35 | + return selectCount(WmsReceiptOrderDetailDO::getSkuId, skuId); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + default Long selectCountByAreaId(Long areaId) { | ||
| 39 | + return selectCount(WmsReceiptOrderDetailDO::getAreaId, areaId); | ||
| 40 | + } | ||
| 41 | + | ||
| 34 | } | 42 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/order/receipt/WmsReceiptOrderMapper.java
| @@ -39,4 +39,16 @@ public interface WmsReceiptOrderMapper extends BaseMapperX<WmsReceiptOrderDO> { | @@ -39,4 +39,16 @@ public interface WmsReceiptOrderMapper extends BaseMapperX<WmsReceiptOrderDO> { | ||
| 39 | return selectOne(WmsReceiptOrderDO::getNo, no); | 39 | return selectOne(WmsReceiptOrderDO::getNo, no); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | + default Long selectCountByMerchantId(Long merchantId) { | ||
| 43 | + return selectCount(WmsReceiptOrderDO::getMerchantId, merchantId); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + default Long selectCountByWarehouseId(Long warehouseId) { | ||
| 47 | + return selectCount(WmsReceiptOrderDO::getWarehouseId, warehouseId); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + default Long selectCountByAreaId(Long areaId) { | ||
| 51 | + return selectCount(WmsReceiptOrderDO::getAreaId, areaId); | ||
| 52 | + } | ||
| 53 | + | ||
| 42 | } | 54 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/order/shipment/WmsShipmentOrderDetailMapper.java
| @@ -31,4 +31,12 @@ public interface WmsShipmentOrderDetailMapper extends BaseMapperX<WmsShipmentOrd | @@ -31,4 +31,12 @@ public interface WmsShipmentOrderDetailMapper extends BaseMapperX<WmsShipmentOrd | ||
| 31 | delete(WmsShipmentOrderDetailDO::getOrderId, orderId); | 31 | delete(WmsShipmentOrderDetailDO::getOrderId, orderId); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | + default Long selectCountBySkuId(Long skuId) { | ||
| 35 | + return selectCount(WmsShipmentOrderDetailDO::getSkuId, skuId); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + default Long selectCountByAreaId(Long areaId) { | ||
| 39 | + return selectCount(WmsShipmentOrderDetailDO::getAreaId, areaId); | ||
| 40 | + } | ||
| 41 | + | ||
| 34 | } | 42 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/order/shipment/WmsShipmentOrderMapper.java
| @@ -39,4 +39,16 @@ public interface WmsShipmentOrderMapper extends BaseMapperX<WmsShipmentOrderDO> | @@ -39,4 +39,16 @@ public interface WmsShipmentOrderMapper extends BaseMapperX<WmsShipmentOrderDO> | ||
| 39 | return selectOne(WmsShipmentOrderDO::getNo, no); | 39 | return selectOne(WmsShipmentOrderDO::getNo, no); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | + default Long selectCountByMerchantId(Long merchantId) { | ||
| 43 | + return selectCount(WmsShipmentOrderDO::getMerchantId, merchantId); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + default Long selectCountByWarehouseId(Long warehouseId) { | ||
| 47 | + return selectCount(WmsShipmentOrderDO::getWarehouseId, warehouseId); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + default Long selectCountByAreaId(Long areaId) { | ||
| 51 | + return selectCount(WmsShipmentOrderDO::getAreaId, areaId); | ||
| 52 | + } | ||
| 53 | + | ||
| 42 | } | 54 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/DictTypeConstants.java
| @@ -12,7 +12,5 @@ public interface DictTypeConstants { | @@ -12,7 +12,5 @@ public interface DictTypeConstants { | ||
| 12 | String RECEIPT_ORDER_TYPE = "wms_receipt_order_type"; | 12 | String RECEIPT_ORDER_TYPE = "wms_receipt_order_type"; |
| 13 | String SHIPMENT_ORDER_TYPE = "wms_shipment_order_type"; | 13 | String SHIPMENT_ORDER_TYPE = "wms_shipment_order_type"; |
| 14 | String INVENTORY_HISTORY_TYPE = "wms_inventory_history_type"; | 14 | String INVENTORY_HISTORY_TYPE = "wms_inventory_history_type"; |
| 15 | - String MOVEMENT_STATUS = "wms_movement_status"; | ||
| 16 | - String CHECK_STATUS = "wms_check_status"; | ||
| 17 | 15 | ||
| 18 | } | 16 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java
| @@ -17,12 +17,14 @@ public interface ErrorCodeConstants { | @@ -17,12 +17,14 @@ public interface ErrorCodeConstants { | ||
| 17 | ErrorCode WAREHOUSE_NAME_DUPLICATE = new ErrorCode(1_060_100_001, "仓库名称重复"); | 17 | ErrorCode WAREHOUSE_NAME_DUPLICATE = new ErrorCode(1_060_100_001, "仓库名称重复"); |
| 18 | ErrorCode WAREHOUSE_CODE_DUPLICATE = new ErrorCode(1_060_100_002, "仓库编号重复"); | 18 | ErrorCode WAREHOUSE_CODE_DUPLICATE = new ErrorCode(1_060_100_002, "仓库编号重复"); |
| 19 | ErrorCode WAREHOUSE_HAS_AREA = new ErrorCode(1_060_100_003, "删除失败!请先删除该仓库下的库区!"); | 19 | ErrorCode WAREHOUSE_HAS_AREA = new ErrorCode(1_060_100_003, "删除失败!请先删除该仓库下的库区!"); |
| 20 | + ErrorCode WAREHOUSE_HAS_ORDER = new ErrorCode(1_060_100_004, "删除失败!仓库已被{}使用!"); | ||
| 20 | 21 | ||
| 21 | // ========== WMS 基础数据-库区 1-060-101-000 ========== | 22 | // ========== WMS 基础数据-库区 1-060-101-000 ========== |
| 22 | ErrorCode WAREHOUSE_AREA_NOT_EXISTS = new ErrorCode(1_060_101_000, "库区不存在"); | 23 | ErrorCode WAREHOUSE_AREA_NOT_EXISTS = new ErrorCode(1_060_101_000, "库区不存在"); |
| 23 | ErrorCode WAREHOUSE_AREA_NAME_DUPLICATE = new ErrorCode(1_060_101_001, "库区名称重复"); | 24 | ErrorCode WAREHOUSE_AREA_NAME_DUPLICATE = new ErrorCode(1_060_101_001, "库区名称重复"); |
| 24 | ErrorCode WAREHOUSE_AREA_CODE_DUPLICATE = new ErrorCode(1_060_101_002, "库区编号重复"); | 25 | ErrorCode WAREHOUSE_AREA_CODE_DUPLICATE = new ErrorCode(1_060_101_002, "库区编号重复"); |
| 25 | ErrorCode WAREHOUSE_AREA_NOT_MATCH_WAREHOUSE = new ErrorCode(1_060_101_003, "库区不属于仓库"); | 26 | ErrorCode WAREHOUSE_AREA_NOT_MATCH_WAREHOUSE = new ErrorCode(1_060_101_003, "库区不属于仓库"); |
| 27 | + ErrorCode WAREHOUSE_AREA_HAS_ORDER = new ErrorCode(1_060_101_004, "删除失败!库区已被{}使用!"); | ||
| 26 | 28 | ||
| 27 | // ========== WMS 基础数据-商品分类 1-060-102-000 ========== | 29 | // ========== WMS 基础数据-商品分类 1-060-102-000 ========== |
| 28 | ErrorCode ITEM_CATEGORY_NOT_EXISTS = new ErrorCode(1_060_102_000, "商品分类不存在"); | 30 | ErrorCode ITEM_CATEGORY_NOT_EXISTS = new ErrorCode(1_060_102_000, "商品分类不存在"); |
| @@ -44,11 +46,13 @@ public interface ErrorCodeConstants { | @@ -44,11 +46,13 @@ public interface ErrorCodeConstants { | ||
| 44 | ErrorCode ITEM_SKU_NAME_DUPLICATE = new ErrorCode(1_060_104_003, "商品规格名称【{}】重复"); | 46 | ErrorCode ITEM_SKU_NAME_DUPLICATE = new ErrorCode(1_060_104_003, "商品规格名称【{}】重复"); |
| 45 | ErrorCode ITEM_SKU_NOT_EXISTS = new ErrorCode(1_060_104_004, "商品规格不存在"); | 47 | ErrorCode ITEM_SKU_NOT_EXISTS = new ErrorCode(1_060_104_004, "商品规格不存在"); |
| 46 | ErrorCode ITEM_SKU_HAS_INVENTORY = new ErrorCode(1_060_104_005, "删除失败!商品规格【{}】已被库存业务使用!"); | 48 | ErrorCode ITEM_SKU_HAS_INVENTORY = new ErrorCode(1_060_104_005, "删除失败!商品规格【{}】已被库存业务使用!"); |
| 49 | + ErrorCode ITEM_SKU_HAS_ORDER = new ErrorCode(1_060_104_006, "删除失败!商品规格【{}】已被{}使用!"); | ||
| 47 | 50 | ||
| 48 | // ========== WMS 基础数据-往来企业 1-060-105-000 ========== | 51 | // ========== WMS 基础数据-往来企业 1-060-105-000 ========== |
| 49 | ErrorCode MERCHANT_NOT_EXISTS = new ErrorCode(1_060_105_000, "往来企业不存在"); | 52 | ErrorCode MERCHANT_NOT_EXISTS = new ErrorCode(1_060_105_000, "往来企业不存在"); |
| 50 | ErrorCode MERCHANT_NOT_SUPPLIER = new ErrorCode(1_060_105_001, "往来企业必须是供应商或客户/供应商类型"); | 53 | ErrorCode MERCHANT_NOT_SUPPLIER = new ErrorCode(1_060_105_001, "往来企业必须是供应商或客户/供应商类型"); |
| 51 | ErrorCode MERCHANT_NOT_CUSTOMER = new ErrorCode(1_060_105_002, "往来企业必须是客户或客户/供应商类型"); | 54 | ErrorCode MERCHANT_NOT_CUSTOMER = new ErrorCode(1_060_105_002, "往来企业必须是客户或客户/供应商类型"); |
| 55 | + ErrorCode MERCHANT_HAS_ORDER = new ErrorCode(1_060_105_003, "删除失败!往来企业已被{}使用!"); | ||
| 52 | 56 | ||
| 53 | // ========== WMS 入库单 1-060-200-000 ========== | 57 | // ========== WMS 入库单 1-060-200-000 ========== |
| 54 | ErrorCode RECEIPT_ORDER_NOT_EXISTS = new ErrorCode(1_060_200_000, "入库单不存在"); | 58 | ErrorCode RECEIPT_ORDER_NOT_EXISTS = new ErrorCode(1_060_200_000, "入库单不存在"); |
| @@ -68,6 +72,25 @@ public interface ErrorCodeConstants { | @@ -68,6 +72,25 @@ public interface ErrorCodeConstants { | ||
| 68 | ErrorCode SHIPMENT_ORDER_STATUS_NOT_DELETABLE = new ErrorCode(1_060_201_005, "出库单状态不是草稿或已作废,不能删除"); | 72 | ErrorCode SHIPMENT_ORDER_STATUS_NOT_DELETABLE = new ErrorCode(1_060_201_005, "出库单状态不是草稿或已作废,不能删除"); |
| 69 | ErrorCode SHIPMENT_ORDER_DETAIL_NOT_EXISTS = new ErrorCode(1_060_201_007, "出库单明细不存在"); | 73 | ErrorCode SHIPMENT_ORDER_DETAIL_NOT_EXISTS = new ErrorCode(1_060_201_007, "出库单明细不存在"); |
| 70 | 74 | ||
| 75 | + // ========== WMS 移库单 1-060-202-000 ========== | ||
| 76 | + ErrorCode MOVEMENT_ORDER_NOT_EXISTS = new ErrorCode(1_060_202_000, "移库单不存在"); | ||
| 77 | + ErrorCode MOVEMENT_ORDER_NO_DUPLICATE = new ErrorCode(1_060_202_001, "移库单号重复"); | ||
| 78 | + ErrorCode MOVEMENT_ORDER_STATUS_NOT_PREPARE = new ErrorCode(1_060_202_002, "移库单状态不是草稿,不能操作"); | ||
| 79 | + ErrorCode MOVEMENT_ORDER_DETAIL_REQUIRED = new ErrorCode(1_060_202_003, "移库单至少包含一条明细"); | ||
| 80 | + ErrorCode MOVEMENT_ORDER_AREA_REQUIRED = new ErrorCode(1_060_202_004, "库区模式下,移库单库区不能为空"); | ||
| 81 | + ErrorCode MOVEMENT_ORDER_STATUS_NOT_DELETABLE = new ErrorCode(1_060_202_005, "移库单状态不是草稿或已作废,不能删除"); | ||
| 82 | + ErrorCode MOVEMENT_ORDER_DETAIL_NOT_EXISTS = new ErrorCode(1_060_202_006, "移库单明细不存在"); | ||
| 83 | + ErrorCode MOVEMENT_ORDER_WAREHOUSE_AREA_SAME = new ErrorCode(1_060_202_007, "来源仓库库区和目标仓库库区不能相同"); | ||
| 84 | + | ||
| 85 | + // ========== WMS 盘库单 1-060-203-000 ========== | ||
| 86 | + ErrorCode CHECK_ORDER_NOT_EXISTS = new ErrorCode(1_060_203_000, "盘库单不存在"); | ||
| 87 | + ErrorCode CHECK_ORDER_NO_DUPLICATE = new ErrorCode(1_060_203_001, "盘库单号重复"); | ||
| 88 | + ErrorCode CHECK_ORDER_STATUS_NOT_PREPARE = new ErrorCode(1_060_203_002, "盘库单状态不是草稿,不能操作"); | ||
| 89 | + ErrorCode CHECK_ORDER_DETAIL_REQUIRED = new ErrorCode(1_060_203_003, "盘库单至少包含一条明细"); | ||
| 90 | + ErrorCode CHECK_ORDER_AREA_REQUIRED = new ErrorCode(1_060_203_004, "库区模式下,盘库单库区不能为空"); | ||
| 91 | + ErrorCode CHECK_ORDER_STATUS_NOT_DELETABLE = new ErrorCode(1_060_203_005, "盘库单状态不是草稿或已作废,不能删除"); | ||
| 92 | + ErrorCode CHECK_ORDER_DETAIL_NOT_EXISTS = new ErrorCode(1_060_203_006, "盘库单明细不存在"); | ||
| 93 | + | ||
| 71 | // ========== WMS 库存 1-060-300-000 ========== | 94 | // ========== WMS 库存 1-060-300-000 ========== |
| 72 | ErrorCode INVENTORY_QUANTITY_NOT_ENOUGH = new ErrorCode(1_060_300_000, "库存不足,当前库存:{},变更数量:{}"); | 95 | ErrorCode INVENTORY_QUANTITY_NOT_ENOUGH = new ErrorCode(1_060_300_000, "库存不足,当前库存:{},变更数量:{}"); |
| 73 | ErrorCode INVENTORY_DETAIL_NOT_EXISTS = new ErrorCode(1_060_300_001, "库存明细不存在"); | 96 | ErrorCode INVENTORY_DETAIL_NOT_EXISTS = new ErrorCode(1_060_300_001, "库存明细不存在"); |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsOrderTypeConstants.java
| @@ -12,6 +12,13 @@ public final class WmsOrderTypeConstants { | @@ -12,6 +12,13 @@ public final class WmsOrderTypeConstants { | ||
| 12 | 12 | ||
| 13 | private WmsOrderTypeConstants() {} | 13 | private WmsOrderTypeConstants() {} |
| 14 | 14 | ||
| 15 | + // ========== 单据名称 ========== | ||
| 16 | + | ||
| 17 | + public static final String ORDER_NAME_RECEIPT = "入库单"; | ||
| 18 | + public static final String ORDER_NAME_SHIPMENT = "出库单"; | ||
| 19 | + public static final String ORDER_NAME_MOVEMENT = "移库单"; | ||
| 20 | + public static final String ORDER_NAME_CHECK = "盘库单"; | ||
| 21 | + | ||
| 15 | // ========== 入库单类型 [100, 200) ========== | 22 | // ========== 入库单类型 [100, 200) ========== |
| 16 | 23 | ||
| 17 | public static final int RECEIPT_PRODUCTION = 100; // 生产入库:WmsReceiptOrderDO | 24 | public static final int RECEIPT_PRODUCTION = 100; // 生产入库:WmsReceiptOrderDO |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryDetailService.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.wms.service.inventory; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.wms.service.inventory; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.detail.WmsInventoryDetailPageReqVO; | 4 | import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.detail.WmsInventoryDetailPageReqVO; |
| 5 | import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDetailDO; | 5 | import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDetailDO; |
| 6 | +import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryChangeReqDTO; | ||
| 6 | 7 | ||
| 7 | import java.util.List; | 8 | import java.util.List; |
| 8 | 9 | ||
| @@ -28,4 +29,11 @@ public interface WmsInventoryDetailService { | @@ -28,4 +29,11 @@ public interface WmsInventoryDetailService { | ||
| 28 | */ | 29 | */ |
| 29 | void createInventoryDetailList(List<WmsInventoryDetailDO> list); | 30 | void createInventoryDetailList(List<WmsInventoryDetailDO> list); |
| 30 | 31 | ||
| 32 | + /** | ||
| 33 | + * 扣减库存明细剩余数量 | ||
| 34 | + * | ||
| 35 | + * @param items 库存变更明细列表 | ||
| 36 | + */ | ||
| 37 | + void decreaseInventoryDetailList(List<WmsInventoryChangeReqDTO.Item> items); | ||
| 38 | + | ||
| 31 | } | 39 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryDetailServiceImpl.java
| 1 | package cn.iocoder.yudao.module.wms.service.inventory; | 1 | package cn.iocoder.yudao.module.wms.service.inventory; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.util.ObjectUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.detail.WmsInventoryDetailPageReqVO; | 6 | import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.detail.WmsInventoryDetailPageReqVO; |
| 6 | import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDetailDO; | 7 | import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDetailDO; |
| 7 | import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryDetailMapper; | 8 | import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryDetailMapper; |
| 9 | +import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryChangeReqDTO; | ||
| 8 | import jakarta.annotation.Resource; | 10 | import jakarta.annotation.Resource; |
| 9 | import org.springframework.stereotype.Service; | 11 | import org.springframework.stereotype.Service; |
| 10 | import org.springframework.transaction.annotation.Transactional; | 12 | import org.springframework.transaction.annotation.Transactional; |
| 11 | import org.springframework.validation.annotation.Validated; | 13 | import org.springframework.validation.annotation.Validated; |
| 12 | 14 | ||
| 15 | +import java.math.BigDecimal; | ||
| 16 | +import java.util.Comparator; | ||
| 17 | +import java.util.LinkedHashMap; | ||
| 13 | import java.util.List; | 18 | import java.util.List; |
| 19 | +import java.util.Map; | ||
| 20 | + | ||
| 21 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 22 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | ||
| 23 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | ||
| 24 | +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.INVENTORY_DETAIL_NOT_EXISTS; | ||
| 25 | +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.INVENTORY_DETAIL_REMAIN_QUANTITY_NOT_ENOUGH; | ||
| 14 | 26 | ||
| 15 | /** | 27 | /** |
| 16 | * WMS 库存明细 Service 实现类 | 28 | * WMS 库存明细 Service 实现类 |
| @@ -38,4 +50,47 @@ public class WmsInventoryDetailServiceImpl implements WmsInventoryDetailService | @@ -38,4 +50,47 @@ public class WmsInventoryDetailServiceImpl implements WmsInventoryDetailService | ||
| 38 | inventoryDetailMapper.insertBatch(list); | 50 | inventoryDetailMapper.insertBatch(list); |
| 39 | } | 51 | } |
| 40 | 52 | ||
| 53 | + @Override | ||
| 54 | + @Transactional(rollbackFor = Exception.class) | ||
| 55 | + public void decreaseInventoryDetailList(List<WmsInventoryChangeReqDTO.Item> items) { | ||
| 56 | + if (CollUtil.isEmpty(items)) { | ||
| 57 | + return; | ||
| 58 | + } | ||
| 59 | + if (items.stream().anyMatch(item -> item.getInventoryDetailId() == null)) { | ||
| 60 | + throw exception(INVENTORY_DETAIL_NOT_EXISTS); | ||
| 61 | + } | ||
| 62 | + List<WmsInventoryChangeReqDTO.Item> sortedItems = items.stream() | ||
| 63 | + .sorted(Comparator.comparing(WmsInventoryChangeReqDTO.Item::getInventoryDetailId)) | ||
| 64 | + .toList(); | ||
| 65 | + | ||
| 66 | + // 1. 按库存明细编号固定顺序加锁,避免多明细并发扣减时交叉拿锁 | ||
| 67 | + Map<Long, WmsInventoryDetailDO> detailMap = convertMap(inventoryDetailMapper.selectListByIdsForUpdate( | ||
| 68 | + convertSet(sortedItems, WmsInventoryChangeReqDTO.Item::getInventoryDetailId)), | ||
| 69 | + WmsInventoryDetailDO::getId); | ||
| 70 | + | ||
| 71 | + // 2. 校验库存明细归属,并合并相同库存明细的扣减数量 | ||
| 72 | + Map<Long, BigDecimal> decreaseQuantityMap = new LinkedHashMap<>(); | ||
| 73 | + for (WmsInventoryChangeReqDTO.Item item : sortedItems) { | ||
| 74 | + WmsInventoryDetailDO detail = detailMap.get(item.getInventoryDetailId()); | ||
| 75 | + if (detail == null | ||
| 76 | + || ObjectUtil.notEqual(detail.getSkuId(), item.getSkuId()) | ||
| 77 | + || ObjectUtil.notEqual(detail.getWarehouseId(), item.getWarehouseId()) | ||
| 78 | + || ObjectUtil.notEqual(detail.getAreaId(), item.getAreaId())) { | ||
| 79 | + throw exception(INVENTORY_DETAIL_NOT_EXISTS); | ||
| 80 | + } | ||
| 81 | + decreaseQuantityMap.merge(detail.getId(), item.getQuantity().abs(), BigDecimal::add); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + // 3. 校验并扣减库存明细剩余数量 | ||
| 85 | + for (Map.Entry<Long, BigDecimal> entry : decreaseQuantityMap.entrySet()) { | ||
| 86 | + WmsInventoryDetailDO detail = detailMap.get(entry.getKey()); | ||
| 87 | + BigDecimal decreaseQuantity = entry.getValue(); | ||
| 88 | + if (detail.getRemainQuantity().compareTo(decreaseQuantity) < 0) { | ||
| 89 | + throw exception(INVENTORY_DETAIL_REMAIN_QUANTITY_NOT_ENOUGH, | ||
| 90 | + detail.getRemainQuantity(), decreaseQuantity); | ||
| 91 | + } | ||
| 92 | + inventoryDetailMapper.updateRemainQuantityIncr(detail.getId(), decreaseQuantity.negate()); | ||
| 93 | + } | ||
| 94 | + } | ||
| 95 | + | ||
| 41 | } | 96 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImpl.java
| @@ -19,7 +19,13 @@ import org.springframework.validation.annotation.Validated; | @@ -19,7 +19,13 @@ import org.springframework.validation.annotation.Validated; | ||
| 19 | 19 | ||
| 20 | import java.math.BigDecimal; | 20 | import java.math.BigDecimal; |
| 21 | import java.util.ArrayList; | 21 | import java.util.ArrayList; |
| 22 | +import java.util.Comparator; | ||
| 23 | +import java.util.IdentityHashMap; | ||
| 22 | import java.util.List; | 24 | import java.util.List; |
| 25 | +import java.util.Map; | ||
| 26 | + | ||
| 27 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 28 | +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*; | ||
| 23 | 29 | ||
| 24 | /** | 30 | /** |
| 25 | * WMS 库存 Service 实现类 | 31 | * WMS 库存 Service 实现类 |
| @@ -61,44 +67,72 @@ public class WmsInventoryServiceImpl implements WmsInventoryService { | @@ -61,44 +67,72 @@ public class WmsInventoryServiceImpl implements WmsInventoryService { | ||
| 61 | return; | 67 | return; |
| 62 | } | 68 | } |
| 63 | 69 | ||
| 64 | - // 1. 变更库存余额,并构建库存流水与批次库存明细 | 70 | + // 1. 按固定顺序变更库存余额,避免多 SKU/仓库并发操作时交叉拿锁 |
| 71 | + Map<WmsInventoryChangeReqDTO.Item, Tuple> resultMap = changeInventoryList(reqDTO.getItems()); | ||
| 72 | + | ||
| 73 | + // 2. 构建库存流水与批次库存明细 | ||
| 65 | boolean batchEnabled = wmsProperties.isBatchEnabled(); | 74 | boolean batchEnabled = wmsProperties.isBatchEnabled(); |
| 66 | List<WmsInventoryHistoryDO> histories = new ArrayList<>(reqDTO.getItems().size()); | 75 | List<WmsInventoryHistoryDO> histories = new ArrayList<>(reqDTO.getItems().size()); |
| 67 | List<WmsInventoryDetailDO> details = batchEnabled ? new ArrayList<>(reqDTO.getItems().size()) : List.of(); | 76 | List<WmsInventoryDetailDO> details = batchEnabled ? new ArrayList<>(reqDTO.getItems().size()) : List.of(); |
| 77 | + List<WmsInventoryChangeReqDTO.Item> decreaseItems = batchEnabled ? new ArrayList<>(reqDTO.getItems().size()) : List.of(); | ||
| 68 | for (WmsInventoryChangeReqDTO.Item item : reqDTO.getItems()) { | 78 | for (WmsInventoryChangeReqDTO.Item item : reqDTO.getItems()) { |
| 69 | - // 1.1 变更库存余额 | ||
| 70 | - Tuple result = changeInventory0(item); | ||
| 71 | - // 1.2 构建库存流水与批次库存明细 | ||
| 72 | - histories.add(buildInventoryHistory(reqDTO, item, result)); | 79 | + histories.add(buildInventoryHistory(reqDTO, item, resultMap.get(item))); |
| 73 | if (batchEnabled) { | 80 | if (batchEnabled) { |
| 74 | - details.add(buildInventoryDetail(reqDTO, item)); | 81 | + if (isIncrease(item)) { |
| 82 | + details.add(buildInventoryDetail(reqDTO, item)); | ||
| 83 | + } else { | ||
| 84 | + decreaseItems.add(item); | ||
| 85 | + } | ||
| 75 | } | 86 | } |
| 76 | } | 87 | } |
| 77 | 88 | ||
| 78 | - // 2.1 批量写入库存流水 | ||
| 79 | - inventoryHistoryService.createInventoryHistoryList(histories); | 89 | + // 3. 按固定顺序变更批次库存明细 |
| 80 | if (batchEnabled) { | 90 | if (batchEnabled) { |
| 81 | - // 2.2 批量写入批次库存明细 | 91 | + inventoryDetailService.decreaseInventoryDetailList(decreaseItems); |
| 82 | inventoryDetailService.createInventoryDetailList(details); | 92 | inventoryDetailService.createInventoryDetailList(details); |
| 83 | } | 93 | } |
| 94 | + | ||
| 95 | + // 4. 批量写入库存流水 | ||
| 96 | + inventoryHistoryService.createInventoryHistoryList(histories); | ||
| 84 | } | 97 | } |
| 85 | 98 | ||
| 86 | /** | 99 | /** |
| 87 | - * 变更库存余额 | 100 | + * 批量变更库存余额 |
| 88 | * | 101 | * |
| 89 | - * @param item 库存变更明细 | ||
| 90 | - * @return 变更前数量、变更后数量 | 102 | + * 按 SKU、仓库、库区固定顺序拿锁;相同库存余额只更新一次,避免同一批操作内反复更新。 |
| 103 | + * | ||
| 104 | + * @param items 库存变更明细列表 | ||
| 105 | + * @return 每条变更明细对应的变更前数量、变更后数量 | ||
| 91 | */ | 106 | */ |
| 92 | - private Tuple changeInventory0(WmsInventoryChangeReqDTO.Item item) { | ||
| 93 | - // 1. 获取或创建库存余额,使用 FOR UPDATE 锁定行 | ||
| 94 | - WmsInventoryDO inventory = getOrCreateInventory(item); | ||
| 95 | - // 2. 变更库存余额 | ||
| 96 | - BigDecimal beforeQuantity = inventory.getQuantity(); | ||
| 97 | - BigDecimal afterQuantity = beforeQuantity.add(item.getQuantity()); | ||
| 98 | - inventoryMapper.updateQuantity(inventory.getId(), item.getQuantity()); | ||
| 99 | - return new Tuple(beforeQuantity, afterQuantity); | ||
| 100 | - } | 107 | + private Map<WmsInventoryChangeReqDTO.Item, Tuple> changeInventoryList(List<WmsInventoryChangeReqDTO.Item> items) { |
| 108 | + List<WmsInventoryChangeReqDTO.Item> sortedItems = sortByInventoryKey(items); | ||
| 109 | + Map<WmsInventoryChangeReqDTO.Item, Tuple> resultMap = new IdentityHashMap<>(items.size()); | ||
| 110 | + for (int i = 0; i < sortedItems.size(); ) { | ||
| 111 | + WmsInventoryChangeReqDTO.Item firstItem = sortedItems.get(i); | ||
| 112 | + WmsInventoryDO inventory = getOrCreateInventory(firstItem); | ||
| 113 | + BigDecimal currentQuantity = inventory.getQuantity(); | ||
| 114 | + BigDecimal totalChangeQuantity = BigDecimal.ZERO; | ||
| 115 | + | ||
| 116 | + int j = i; | ||
| 117 | + while (j < sortedItems.size() && isSameInventoryKey(firstItem, sortedItems.get(j))) { | ||
| 118 | + WmsInventoryChangeReqDTO.Item item = sortedItems.get(j); | ||
| 119 | + BigDecimal beforeQuantity = currentQuantity; | ||
| 120 | + currentQuantity = currentQuantity.add(item.getQuantity()); | ||
| 121 | + if (currentQuantity.compareTo(BigDecimal.ZERO) < 0) { | ||
| 122 | + throw exception(INVENTORY_QUANTITY_NOT_ENOUGH, beforeQuantity, item.getQuantity()); | ||
| 123 | + } | ||
| 124 | + resultMap.put(item, new Tuple(beforeQuantity, currentQuantity)); | ||
| 125 | + totalChangeQuantity = totalChangeQuantity.add(item.getQuantity()); | ||
| 126 | + j++; | ||
| 127 | + } | ||
| 101 | 128 | ||
| 129 | + if (totalChangeQuantity.compareTo(BigDecimal.ZERO) != 0) { | ||
| 130 | + inventoryMapper.updateQuantity(inventory.getId(), totalChangeQuantity); | ||
| 131 | + } | ||
| 132 | + i = j; | ||
| 133 | + } | ||
| 134 | + return resultMap; | ||
| 135 | + } | ||
| 102 | 136 | ||
| 103 | private WmsInventoryDO getOrCreateInventory(WmsInventoryChangeReqDTO.Item item) { | 137 | private WmsInventoryDO getOrCreateInventory(WmsInventoryChangeReqDTO.Item item) { |
| 104 | // 1. 查询库存余额,使用 FOR UPDATE 锁定行 | 138 | // 1. 查询库存余额,使用 FOR UPDATE 锁定行 |
| @@ -147,4 +181,23 @@ public class WmsInventoryServiceImpl implements WmsInventoryService { | @@ -147,4 +181,23 @@ public class WmsInventoryServiceImpl implements WmsInventoryService { | ||
| 147 | .setOrderId(reqDTO.getOrderId()).setOrderNo(reqDTO.getOrderNo()).setOrderType(reqDTO.getOrderType()); | 181 | .setOrderId(reqDTO.getOrderId()).setOrderNo(reqDTO.getOrderNo()).setOrderType(reqDTO.getOrderType()); |
| 148 | } | 182 | } |
| 149 | 183 | ||
| 184 | + private boolean isIncrease(WmsInventoryChangeReqDTO.Item item) { | ||
| 185 | + return item.getQuantity().compareTo(BigDecimal.ZERO) > 0; | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + private static List<WmsInventoryChangeReqDTO.Item> sortByInventoryKey(List<WmsInventoryChangeReqDTO.Item> items) { | ||
| 189 | + return items.stream() | ||
| 190 | + .sorted(Comparator.comparing(WmsInventoryChangeReqDTO.Item::getSkuId) | ||
| 191 | + .thenComparing(WmsInventoryChangeReqDTO.Item::getWarehouseId) | ||
| 192 | + .thenComparing(WmsInventoryChangeReqDTO.Item::getAreaId)) | ||
| 193 | + .toList(); | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | + private static boolean isSameInventoryKey(WmsInventoryChangeReqDTO.Item item1, | ||
| 197 | + WmsInventoryChangeReqDTO.Item item2) { | ||
| 198 | + return item1.getSkuId().equals(item2.getSkuId()) | ||
| 199 | + && item1.getWarehouseId().equals(item2.getWarehouseId()) | ||
| 200 | + && item1.getAreaId().equals(item2.getAreaId()); | ||
| 201 | + } | ||
| 202 | + | ||
| 150 | } | 203 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuServiceImpl.java
| @@ -8,6 +8,10 @@ import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuSav | @@ -8,6 +8,10 @@ import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuSav | ||
| 8 | import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO; | 8 | import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO; |
| 9 | import cn.iocoder.yudao.module.wms.dal.mysql.md.item.WmsItemSkuMapper; | 9 | import cn.iocoder.yudao.module.wms.dal.mysql.md.item.WmsItemSkuMapper; |
| 10 | import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryService; | 10 | import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryService; |
| 11 | +import cn.iocoder.yudao.module.wms.service.order.check.WmsCheckOrderDetailService; | ||
| 12 | +import cn.iocoder.yudao.module.wms.service.order.movement.WmsMovementOrderDetailService; | ||
| 13 | +import cn.iocoder.yudao.module.wms.service.order.receipt.WmsReceiptOrderDetailService; | ||
| 14 | +import cn.iocoder.yudao.module.wms.service.order.shipment.WmsShipmentOrderDetailService; | ||
| 11 | import cn.iocoder.yudao.module.wms.util.WmsUtils; | 15 | import cn.iocoder.yudao.module.wms.util.WmsUtils; |
| 12 | import jakarta.annotation.Resource; | 16 | import jakarta.annotation.Resource; |
| 13 | import org.springframework.context.annotation.Lazy; | 17 | import org.springframework.context.annotation.Lazy; |
| @@ -23,6 +27,7 @@ import java.util.Set; | @@ -23,6 +27,7 @@ import java.util.Set; | ||
| 23 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 27 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 24 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | 28 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; |
| 25 | import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*; | 29 | import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*; |
| 30 | +import static cn.iocoder.yudao.module.wms.enums.order.WmsOrderTypeConstants.*; | ||
| 26 | 31 | ||
| 27 | /** | 32 | /** |
| 28 | * WMS 商品 SKU Service 实现类 | 33 | * WMS 商品 SKU Service 实现类 |
| @@ -38,6 +43,18 @@ public class WmsItemSkuServiceImpl implements WmsItemSkuService { | @@ -38,6 +43,18 @@ public class WmsItemSkuServiceImpl implements WmsItemSkuService { | ||
| 38 | @Resource | 43 | @Resource |
| 39 | @Lazy // 延迟加载,避免循环依赖 | 44 | @Lazy // 延迟加载,避免循环依赖 |
| 40 | private WmsInventoryService inventoryService; | 45 | private WmsInventoryService inventoryService; |
| 46 | + @Resource | ||
| 47 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 48 | + private WmsReceiptOrderDetailService receiptOrderDetailService; | ||
| 49 | + @Resource | ||
| 50 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 51 | + private WmsShipmentOrderDetailService shipmentOrderDetailService; | ||
| 52 | + @Resource | ||
| 53 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 54 | + private WmsMovementOrderDetailService movementOrderDetailService; | ||
| 55 | + @Resource | ||
| 56 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 57 | + private WmsCheckOrderDetailService checkOrderDetailService; | ||
| 41 | 58 | ||
| 42 | @Override | 59 | @Override |
| 43 | @Transactional(rollbackFor = Exception.class) | 60 | @Transactional(rollbackFor = Exception.class) |
| @@ -146,12 +163,28 @@ public class WmsItemSkuServiceImpl implements WmsItemSkuService { | @@ -146,12 +163,28 @@ public class WmsItemSkuServiceImpl implements WmsItemSkuService { | ||
| 146 | return; | 163 | return; |
| 147 | } | 164 | } |
| 148 | for (WmsItemSkuDO sku : skus) { | 165 | for (WmsItemSkuDO sku : skus) { |
| 166 | + validateItemSkuOrderUnused(sku); | ||
| 149 | if (inventoryService.getInventoryCountBySkuId(sku.getId()) > 0) { | 167 | if (inventoryService.getInventoryCountBySkuId(sku.getId()) > 0) { |
| 150 | throw exception(ITEM_SKU_HAS_INVENTORY, sku.getName()); | 168 | throw exception(ITEM_SKU_HAS_INVENTORY, sku.getName()); |
| 151 | } | 169 | } |
| 152 | } | 170 | } |
| 153 | } | 171 | } |
| 154 | 172 | ||
| 173 | + private void validateItemSkuOrderUnused(WmsItemSkuDO sku) { | ||
| 174 | + if (receiptOrderDetailService.getReceiptOrderDetailCountBySkuId(sku.getId()) > 0) { | ||
| 175 | + throw exception(ITEM_SKU_HAS_ORDER, sku.getName(), ORDER_NAME_RECEIPT); | ||
| 176 | + } | ||
| 177 | + if (shipmentOrderDetailService.getShipmentOrderDetailCountBySkuId(sku.getId()) > 0) { | ||
| 178 | + throw exception(ITEM_SKU_HAS_ORDER, sku.getName(), ORDER_NAME_SHIPMENT); | ||
| 179 | + } | ||
| 180 | + if (movementOrderDetailService.getMovementOrderDetailCountBySkuId(sku.getId()) > 0) { | ||
| 181 | + throw exception(ITEM_SKU_HAS_ORDER, sku.getName(), ORDER_NAME_MOVEMENT); | ||
| 182 | + } | ||
| 183 | + if (checkOrderDetailService.getCheckOrderDetailCountBySkuId(sku.getId()) > 0) { | ||
| 184 | + throw exception(ITEM_SKU_HAS_ORDER, sku.getName(), ORDER_NAME_CHECK); | ||
| 185 | + } | ||
| 186 | + } | ||
| 187 | + | ||
| 155 | /** | 188 | /** |
| 156 | * 填充空的条形码 | 189 | * 填充空的条形码 |
| 157 | * | 190 | * |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/merchant/WmsMerchantServiceImpl.java
| @@ -10,7 +10,10 @@ import cn.iocoder.yudao.module.wms.controller.admin.md.merchant.vo.WmsMerchantSa | @@ -10,7 +10,10 @@ import cn.iocoder.yudao.module.wms.controller.admin.md.merchant.vo.WmsMerchantSa | ||
| 10 | import cn.iocoder.yudao.module.wms.dal.dataobject.md.merchant.WmsMerchantDO; | 10 | import cn.iocoder.yudao.module.wms.dal.dataobject.md.merchant.WmsMerchantDO; |
| 11 | import cn.iocoder.yudao.module.wms.dal.mysql.md.merchant.WmsMerchantMapper; | 11 | import cn.iocoder.yudao.module.wms.dal.mysql.md.merchant.WmsMerchantMapper; |
| 12 | import cn.iocoder.yudao.module.wms.enums.md.WmsMerchantTypeEnum; | 12 | import cn.iocoder.yudao.module.wms.enums.md.WmsMerchantTypeEnum; |
| 13 | +import cn.iocoder.yudao.module.wms.service.order.receipt.WmsReceiptOrderService; | ||
| 14 | +import cn.iocoder.yudao.module.wms.service.order.shipment.WmsShipmentOrderService; | ||
| 13 | import jakarta.annotation.Resource; | 15 | import jakarta.annotation.Resource; |
| 16 | +import org.springframework.context.annotation.Lazy; | ||
| 14 | import org.springframework.stereotype.Service; | 17 | import org.springframework.stereotype.Service; |
| 15 | import org.springframework.validation.annotation.Validated; | 18 | import org.springframework.validation.annotation.Validated; |
| 16 | 19 | ||
| @@ -19,6 +22,7 @@ import java.util.List; | @@ -19,6 +22,7 @@ import java.util.List; | ||
| 19 | 22 | ||
| 20 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 23 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 21 | import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*; | 24 | import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*; |
| 25 | +import static cn.iocoder.yudao.module.wms.enums.order.WmsOrderTypeConstants.*; | ||
| 22 | 26 | ||
| 23 | /** | 27 | /** |
| 24 | * WMS 往来企业 Service 实现类 | 28 | * WMS 往来企业 Service 实现类 |
| @@ -31,6 +35,12 @@ public class WmsMerchantServiceImpl implements WmsMerchantService { | @@ -31,6 +35,12 @@ public class WmsMerchantServiceImpl implements WmsMerchantService { | ||
| 31 | 35 | ||
| 32 | @Resource | 36 | @Resource |
| 33 | private WmsMerchantMapper merchantMapper; | 37 | private WmsMerchantMapper merchantMapper; |
| 38 | + @Resource | ||
| 39 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 40 | + private WmsReceiptOrderService receiptOrderService; | ||
| 41 | + @Resource | ||
| 42 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 43 | + private WmsShipmentOrderService shipmentOrderService; | ||
| 34 | 44 | ||
| 35 | @Override | 45 | @Override |
| 36 | public Long createMerchant(WmsMerchantSaveReqVO createReqVO) { | 46 | public Long createMerchant(WmsMerchantSaveReqVO createReqVO) { |
| @@ -53,12 +63,22 @@ public class WmsMerchantServiceImpl implements WmsMerchantService { | @@ -53,12 +63,22 @@ public class WmsMerchantServiceImpl implements WmsMerchantService { | ||
| 53 | public void deleteMerchant(Long id) { | 63 | public void deleteMerchant(Long id) { |
| 54 | // 校验存在 | 64 | // 校验存在 |
| 55 | validateMerchantExists(id); | 65 | validateMerchantExists(id); |
| 56 | - // TODO 入库/出库单实现后,校验往来企业不存在业务关联后再删除 | 66 | + // 校验未被单据使用 |
| 67 | + validateMerchantUnused(id); | ||
| 57 | 68 | ||
| 58 | // 删除 | 69 | // 删除 |
| 59 | merchantMapper.deleteById(id); | 70 | merchantMapper.deleteById(id); |
| 60 | } | 71 | } |
| 61 | 72 | ||
| 73 | + private void validateMerchantUnused(Long id) { | ||
| 74 | + if (receiptOrderService.getReceiptOrderCountByMerchantId(id) > 0) { | ||
| 75 | + throw exception(MERCHANT_HAS_ORDER, ORDER_NAME_RECEIPT); | ||
| 76 | + } | ||
| 77 | + if (shipmentOrderService.getShipmentOrderCountByMerchantId(id) > 0) { | ||
| 78 | + throw exception(MERCHANT_HAS_ORDER, ORDER_NAME_SHIPMENT); | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | + | ||
| 62 | @Override | 82 | @Override |
| 63 | public WmsMerchantDO validateMerchantExists(Long id) { | 83 | public WmsMerchantDO validateMerchantExists(Long id) { |
| 64 | WmsMerchantDO merchant = merchantMapper.selectById(id); | 84 | WmsMerchantDO merchant = merchantMapper.selectById(id); |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/warehouse/WmsWarehouseAreaServiceImpl.java
| @@ -11,7 +11,16 @@ import cn.iocoder.yudao.module.wms.controller.admin.md.warehouse.vo.area.WmsWare | @@ -11,7 +11,16 @@ import cn.iocoder.yudao.module.wms.controller.admin.md.warehouse.vo.area.WmsWare | ||
| 11 | import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseAreaDO; | 11 | import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseAreaDO; |
| 12 | import cn.iocoder.yudao.module.wms.dal.mysql.md.warehouse.WmsWarehouseAreaMapper; | 12 | import cn.iocoder.yudao.module.wms.dal.mysql.md.warehouse.WmsWarehouseAreaMapper; |
| 13 | import cn.iocoder.yudao.module.wms.framework.config.WmsProperties; | 13 | import cn.iocoder.yudao.module.wms.framework.config.WmsProperties; |
| 14 | +import cn.iocoder.yudao.module.wms.service.order.check.WmsCheckOrderDetailService; | ||
| 15 | +import cn.iocoder.yudao.module.wms.service.order.check.WmsCheckOrderService; | ||
| 16 | +import cn.iocoder.yudao.module.wms.service.order.movement.WmsMovementOrderDetailService; | ||
| 17 | +import cn.iocoder.yudao.module.wms.service.order.movement.WmsMovementOrderService; | ||
| 18 | +import cn.iocoder.yudao.module.wms.service.order.receipt.WmsReceiptOrderDetailService; | ||
| 19 | +import cn.iocoder.yudao.module.wms.service.order.receipt.WmsReceiptOrderService; | ||
| 20 | +import cn.iocoder.yudao.module.wms.service.order.shipment.WmsShipmentOrderDetailService; | ||
| 21 | +import cn.iocoder.yudao.module.wms.service.order.shipment.WmsShipmentOrderService; | ||
| 14 | import jakarta.annotation.Resource; | 22 | import jakarta.annotation.Resource; |
| 23 | +import org.springframework.context.annotation.Lazy; | ||
| 15 | import org.springframework.stereotype.Service; | 24 | import org.springframework.stereotype.Service; |
| 16 | import org.springframework.validation.annotation.Validated; | 25 | import org.springframework.validation.annotation.Validated; |
| 17 | 26 | ||
| @@ -21,6 +30,7 @@ import java.util.List; | @@ -21,6 +30,7 @@ import java.util.List; | ||
| 21 | 30 | ||
| 22 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 31 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 23 | import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*; | 32 | import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*; |
| 33 | +import static cn.iocoder.yudao.module.wms.enums.order.WmsOrderTypeConstants.*; | ||
| 24 | 34 | ||
| 25 | /** | 35 | /** |
| 26 | * WMS 库区 Service 实现类 | 36 | * WMS 库区 Service 实现类 |
| @@ -37,6 +47,30 @@ public class WmsWarehouseAreaServiceImpl implements WmsWarehouseAreaService { | @@ -37,6 +47,30 @@ public class WmsWarehouseAreaServiceImpl implements WmsWarehouseAreaService { | ||
| 37 | private WmsWarehouseService warehouseService; | 47 | private WmsWarehouseService warehouseService; |
| 38 | @Resource | 48 | @Resource |
| 39 | private WmsProperties wmsProperties; | 49 | private WmsProperties wmsProperties; |
| 50 | + @Resource | ||
| 51 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 52 | + private WmsReceiptOrderService receiptOrderService; | ||
| 53 | + @Resource | ||
| 54 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 55 | + private WmsReceiptOrderDetailService receiptOrderDetailService; | ||
| 56 | + @Resource | ||
| 57 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 58 | + private WmsShipmentOrderService shipmentOrderService; | ||
| 59 | + @Resource | ||
| 60 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 61 | + private WmsShipmentOrderDetailService shipmentOrderDetailService; | ||
| 62 | + @Resource | ||
| 63 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 64 | + private WmsMovementOrderService movementOrderService; | ||
| 65 | + @Resource | ||
| 66 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 67 | + private WmsMovementOrderDetailService movementOrderDetailService; | ||
| 68 | + @Resource | ||
| 69 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 70 | + private WmsCheckOrderService checkOrderService; | ||
| 71 | + @Resource | ||
| 72 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 73 | + private WmsCheckOrderDetailService checkOrderDetailService; | ||
| 40 | 74 | ||
| 41 | @Override | 75 | @Override |
| 42 | public Long createWarehouseArea(WmsWarehouseAreaSaveReqVO createReqVO) { | 76 | public Long createWarehouseArea(WmsWarehouseAreaSaveReqVO createReqVO) { |
| @@ -98,11 +132,32 @@ public class WmsWarehouseAreaServiceImpl implements WmsWarehouseAreaService { | @@ -98,11 +132,32 @@ public class WmsWarehouseAreaServiceImpl implements WmsWarehouseAreaService { | ||
| 98 | validateAreaEnabled(); | 132 | validateAreaEnabled(); |
| 99 | // 校验存在 | 133 | // 校验存在 |
| 100 | validateWarehouseAreaExists(id); | 134 | validateWarehouseAreaExists(id); |
| 135 | + // 校验未被单据使用 | ||
| 136 | + validateWarehouseAreaUnused(id); | ||
| 101 | 137 | ||
| 102 | // 删除 | 138 | // 删除 |
| 103 | warehouseAreaMapper.deleteById(id); | 139 | warehouseAreaMapper.deleteById(id); |
| 104 | } | 140 | } |
| 105 | 141 | ||
| 142 | + private void validateWarehouseAreaUnused(Long id) { | ||
| 143 | + if (receiptOrderService.getReceiptOrderCountByAreaId(id) > 0 | ||
| 144 | + || receiptOrderDetailService.getReceiptOrderDetailCountByAreaId(id) > 0) { | ||
| 145 | + throw exception(WAREHOUSE_AREA_HAS_ORDER, ORDER_NAME_RECEIPT); | ||
| 146 | + } | ||
| 147 | + if (shipmentOrderService.getShipmentOrderCountByAreaId(id) > 0 | ||
| 148 | + || shipmentOrderDetailService.getShipmentOrderDetailCountByAreaId(id) > 0) { | ||
| 149 | + throw exception(WAREHOUSE_AREA_HAS_ORDER, ORDER_NAME_SHIPMENT); | ||
| 150 | + } | ||
| 151 | + if (movementOrderService.getMovementOrderCountByAreaId(id) > 0 | ||
| 152 | + || movementOrderDetailService.getMovementOrderDetailCountByAreaId(id) > 0) { | ||
| 153 | + throw exception(WAREHOUSE_AREA_HAS_ORDER, ORDER_NAME_MOVEMENT); | ||
| 154 | + } | ||
| 155 | + if (checkOrderService.getCheckOrderCountByAreaId(id) > 0 | ||
| 156 | + || checkOrderDetailService.getCheckOrderDetailCountByAreaId(id) > 0) { | ||
| 157 | + throw exception(WAREHOUSE_AREA_HAS_ORDER, ORDER_NAME_CHECK); | ||
| 158 | + } | ||
| 159 | + } | ||
| 160 | + | ||
| 106 | @Override | 161 | @Override |
| 107 | public WmsWarehouseAreaDO validateWarehouseAreaExists(Long id) { | 162 | public WmsWarehouseAreaDO validateWarehouseAreaExists(Long id) { |
| 108 | validateAreaEnabled(); | 163 | validateAreaEnabled(); |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/warehouse/WmsWarehouseServiceImpl.java
| @@ -11,7 +11,12 @@ import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO; | @@ -11,7 +11,12 @@ import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO; | ||
| 11 | import cn.iocoder.yudao.module.wms.dal.mysql.md.warehouse.WmsWarehouseAreaMapper; | 11 | import cn.iocoder.yudao.module.wms.dal.mysql.md.warehouse.WmsWarehouseAreaMapper; |
| 12 | import cn.iocoder.yudao.module.wms.dal.mysql.md.warehouse.WmsWarehouseMapper; | 12 | import cn.iocoder.yudao.module.wms.dal.mysql.md.warehouse.WmsWarehouseMapper; |
| 13 | import cn.iocoder.yudao.module.wms.framework.config.WmsProperties; | 13 | import cn.iocoder.yudao.module.wms.framework.config.WmsProperties; |
| 14 | +import cn.iocoder.yudao.module.wms.service.order.check.WmsCheckOrderService; | ||
| 15 | +import cn.iocoder.yudao.module.wms.service.order.movement.WmsMovementOrderService; | ||
| 16 | +import cn.iocoder.yudao.module.wms.service.order.receipt.WmsReceiptOrderService; | ||
| 17 | +import cn.iocoder.yudao.module.wms.service.order.shipment.WmsShipmentOrderService; | ||
| 14 | import jakarta.annotation.Resource; | 18 | import jakarta.annotation.Resource; |
| 19 | +import org.springframework.context.annotation.Lazy; | ||
| 15 | import org.springframework.stereotype.Service; | 20 | import org.springframework.stereotype.Service; |
| 16 | import org.springframework.validation.annotation.Validated; | 21 | import org.springframework.validation.annotation.Validated; |
| 17 | 22 | ||
| @@ -21,6 +26,7 @@ import java.util.List; | @@ -21,6 +26,7 @@ import java.util.List; | ||
| 21 | 26 | ||
| 22 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 27 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 23 | import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*; | 28 | import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*; |
| 29 | +import static cn.iocoder.yudao.module.wms.enums.order.WmsOrderTypeConstants.*; | ||
| 24 | 30 | ||
| 25 | /** | 31 | /** |
| 26 | * WMS 仓库 Service 实现类 | 32 | * WMS 仓库 Service 实现类 |
| @@ -37,6 +43,18 @@ public class WmsWarehouseServiceImpl implements WmsWarehouseService { | @@ -37,6 +43,18 @@ public class WmsWarehouseServiceImpl implements WmsWarehouseService { | ||
| 37 | private WmsWarehouseAreaMapper warehouseAreaMapper; | 43 | private WmsWarehouseAreaMapper warehouseAreaMapper; |
| 38 | @Resource | 44 | @Resource |
| 39 | private WmsProperties wmsProperties; | 45 | private WmsProperties wmsProperties; |
| 46 | + @Resource | ||
| 47 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 48 | + private WmsReceiptOrderService receiptOrderService; | ||
| 49 | + @Resource | ||
| 50 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 51 | + private WmsShipmentOrderService shipmentOrderService; | ||
| 52 | + @Resource | ||
| 53 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 54 | + private WmsMovementOrderService movementOrderService; | ||
| 55 | + @Resource | ||
| 56 | + @Lazy // 延迟加载,避免循环依赖 | ||
| 57 | + private WmsCheckOrderService checkOrderService; | ||
| 40 | 58 | ||
| 41 | @Override | 59 | @Override |
| 42 | public Long createWarehouse(WmsWarehouseSaveReqVO createReqVO) { | 60 | public Long createWarehouse(WmsWarehouseSaveReqVO createReqVO) { |
| @@ -93,6 +111,8 @@ public class WmsWarehouseServiceImpl implements WmsWarehouseService { | @@ -93,6 +111,8 @@ public class WmsWarehouseServiceImpl implements WmsWarehouseService { | ||
| 93 | public void deleteWarehouse(Long id) { | 111 | public void deleteWarehouse(Long id) { |
| 94 | // 校验存在 | 112 | // 校验存在 |
| 95 | validateWarehouseExists(id); | 113 | validateWarehouseExists(id); |
| 114 | + // 校验未被单据使用 | ||
| 115 | + validateWarehouseUnused(id); | ||
| 96 | // 库区模式下,存在库区时不允许删除仓库 | 116 | // 库区模式下,存在库区时不允许删除仓库 |
| 97 | if (wmsProperties.isAreaEnabled() && warehouseAreaMapper.selectCountByWarehouseId(id) > 0) { | 117 | if (wmsProperties.isAreaEnabled() && warehouseAreaMapper.selectCountByWarehouseId(id) > 0) { |
| 98 | throw exception(WAREHOUSE_HAS_AREA); | 118 | throw exception(WAREHOUSE_HAS_AREA); |
| @@ -102,6 +122,21 @@ public class WmsWarehouseServiceImpl implements WmsWarehouseService { | @@ -102,6 +122,21 @@ public class WmsWarehouseServiceImpl implements WmsWarehouseService { | ||
| 102 | warehouseMapper.deleteById(id); | 122 | warehouseMapper.deleteById(id); |
| 103 | } | 123 | } |
| 104 | 124 | ||
| 125 | + private void validateWarehouseUnused(Long id) { | ||
| 126 | + if (receiptOrderService.getReceiptOrderCountByWarehouseId(id) > 0) { | ||
| 127 | + throw exception(WAREHOUSE_HAS_ORDER, ORDER_NAME_RECEIPT); | ||
| 128 | + } | ||
| 129 | + if (shipmentOrderService.getShipmentOrderCountByWarehouseId(id) > 0) { | ||
| 130 | + throw exception(WAREHOUSE_HAS_ORDER, ORDER_NAME_SHIPMENT); | ||
| 131 | + } | ||
| 132 | + if (movementOrderService.getMovementOrderCountByWarehouseId(id) > 0) { | ||
| 133 | + throw exception(WAREHOUSE_HAS_ORDER, ORDER_NAME_MOVEMENT); | ||
| 134 | + } | ||
| 135 | + if (checkOrderService.getCheckOrderCountByWarehouseId(id) > 0) { | ||
| 136 | + throw exception(WAREHOUSE_HAS_ORDER, ORDER_NAME_CHECK); | ||
| 137 | + } | ||
| 138 | + } | ||
| 139 | + | ||
| 105 | @Override | 140 | @Override |
| 106 | public WmsWarehouseDO validateWarehouseExists(Long id) { | 141 | public WmsWarehouseDO validateWarehouseExists(Long id) { |
| 107 | WmsWarehouseDO warehouse = warehouseMapper.selectById(id); | 142 | WmsWarehouseDO warehouse = warehouseMapper.selectById(id); |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/check/WmsCheckOrderDetailService.java
| @@ -60,4 +60,20 @@ public interface WmsCheckOrderDetailService { | @@ -60,4 +60,20 @@ public interface WmsCheckOrderDetailService { | ||
| 60 | */ | 60 | */ |
| 61 | List<WmsCheckOrderDetailDO> validateCheckOrderDetailListExists(Long orderId); | 61 | List<WmsCheckOrderDetailDO> validateCheckOrderDetailListExists(Long orderId); |
| 62 | 62 | ||
| 63 | + /** | ||
| 64 | + * 获得指定 SKU 的盘库单明细数量 | ||
| 65 | + * | ||
| 66 | + * @param skuId SKU 编号 | ||
| 67 | + * @return 盘库单明细数量 | ||
| 68 | + */ | ||
| 69 | + long getCheckOrderDetailCountBySkuId(Long skuId); | ||
| 70 | + | ||
| 71 | + /** | ||
| 72 | + * 获得指定库区的盘库单明细数量 | ||
| 73 | + * | ||
| 74 | + * @param areaId 库区编号 | ||
| 75 | + * @return 盘库单明细数量 | ||
| 76 | + */ | ||
| 77 | + long getCheckOrderDetailCountByAreaId(Long areaId); | ||
| 78 | + | ||
| 63 | } | 79 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/check/WmsCheckOrderDetailServiceImpl.java
| @@ -111,6 +111,16 @@ public class WmsCheckOrderDetailServiceImpl implements WmsCheckOrderDetailServic | @@ -111,6 +111,16 @@ public class WmsCheckOrderDetailServiceImpl implements WmsCheckOrderDetailServic | ||
| 111 | return details; | 111 | return details; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | + @Override | ||
| 115 | + public long getCheckOrderDetailCountBySkuId(Long skuId) { | ||
| 116 | + return checkOrderDetailMapper.selectCountBySkuId(skuId); | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + @Override | ||
| 120 | + public long getCheckOrderDetailCountByAreaId(Long areaId) { | ||
| 121 | + return checkOrderDetailMapper.selectCountByAreaId(areaId); | ||
| 122 | + } | ||
| 123 | + | ||
| 114 | private List<WmsCheckOrderDetailDO> buildCheckOrderDetailList(WmsCheckOrderSaveReqVO reqVO) { | 124 | private List<WmsCheckOrderDetailDO> buildCheckOrderDetailList(WmsCheckOrderSaveReqVO reqVO) { |
| 115 | if (CollUtil.isEmpty(reqVO.getDetails())) { | 125 | if (CollUtil.isEmpty(reqVO.getDetails())) { |
| 116 | return ListUtil.of(); | 126 | return ListUtil.of(); |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/check/WmsCheckOrderService.java
| @@ -65,4 +65,20 @@ public interface WmsCheckOrderService { | @@ -65,4 +65,20 @@ public interface WmsCheckOrderService { | ||
| 65 | */ | 65 | */ |
| 66 | PageResult<WmsCheckOrderDO> getCheckOrderPage(WmsCheckOrderPageReqVO pageReqVO); | 66 | PageResult<WmsCheckOrderDO> getCheckOrderPage(WmsCheckOrderPageReqVO pageReqVO); |
| 67 | 67 | ||
| 68 | + /** | ||
| 69 | + * 获得指定仓库的盘库单数量 | ||
| 70 | + * | ||
| 71 | + * @param warehouseId 仓库编号 | ||
| 72 | + * @return 盘库单数量 | ||
| 73 | + */ | ||
| 74 | + long getCheckOrderCountByWarehouseId(Long warehouseId); | ||
| 75 | + | ||
| 76 | + /** | ||
| 77 | + * 获得指定库区的盘库单数量 | ||
| 78 | + * | ||
| 79 | + * @param areaId 库区编号 | ||
| 80 | + * @return 盘库单数量 | ||
| 81 | + */ | ||
| 82 | + long getCheckOrderCountByAreaId(Long areaId); | ||
| 83 | + | ||
| 68 | } | 84 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/check/WmsCheckOrderServiceImpl.java
| @@ -129,6 +129,16 @@ public class WmsCheckOrderServiceImpl implements WmsCheckOrderService { | @@ -129,6 +129,16 @@ public class WmsCheckOrderServiceImpl implements WmsCheckOrderService { | ||
| 129 | return checkOrderMapper.selectPage(pageReqVO); | 129 | return checkOrderMapper.selectPage(pageReqVO); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | + @Override | ||
| 133 | + public long getCheckOrderCountByWarehouseId(Long warehouseId) { | ||
| 134 | + return checkOrderMapper.selectCountByWarehouseId(warehouseId); | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + @Override | ||
| 138 | + public long getCheckOrderCountByAreaId(Long areaId) { | ||
| 139 | + return checkOrderMapper.selectCountByAreaId(areaId); | ||
| 140 | + } | ||
| 141 | + | ||
| 132 | private void validateCheckOrderSaveData(WmsCheckOrderSaveReqVO reqVO) { | 142 | private void validateCheckOrderSaveData(WmsCheckOrderSaveReqVO reqVO) { |
| 133 | // 校验盘库单号唯一 | 143 | // 校验盘库单号唯一 |
| 134 | validateCheckOrderNoUnique(reqVO.getId(), reqVO.getNo()); | 144 | validateCheckOrderNoUnique(reqVO.getId(), reqVO.getNo()); |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/movement/WmsMovementOrderDetailService.java
| @@ -60,4 +60,20 @@ public interface WmsMovementOrderDetailService { | @@ -60,4 +60,20 @@ public interface WmsMovementOrderDetailService { | ||
| 60 | */ | 60 | */ |
| 61 | List<WmsMovementOrderDetailDO> validateMovementOrderDetailListExists(Long orderId); | 61 | List<WmsMovementOrderDetailDO> validateMovementOrderDetailListExists(Long orderId); |
| 62 | 62 | ||
| 63 | + /** | ||
| 64 | + * 获得指定 SKU 的移库单明细数量 | ||
| 65 | + * | ||
| 66 | + * @param skuId SKU 编号 | ||
| 67 | + * @return 移库单明细数量 | ||
| 68 | + */ | ||
| 69 | + long getMovementOrderDetailCountBySkuId(Long skuId); | ||
| 70 | + | ||
| 71 | + /** | ||
| 72 | + * 获得指定库区的移库单明细数量 | ||
| 73 | + * | ||
| 74 | + * @param areaId 库区编号 | ||
| 75 | + * @return 移库单明细数量 | ||
| 76 | + */ | ||
| 77 | + long getMovementOrderDetailCountByAreaId(Long areaId); | ||
| 78 | + | ||
| 63 | } | 79 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/movement/WmsMovementOrderDetailServiceImpl.java
| @@ -112,6 +112,16 @@ public class WmsMovementOrderDetailServiceImpl implements WmsMovementOrderDetail | @@ -112,6 +112,16 @@ public class WmsMovementOrderDetailServiceImpl implements WmsMovementOrderDetail | ||
| 112 | return details; | 112 | return details; |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | + @Override | ||
| 116 | + public long getMovementOrderDetailCountBySkuId(Long skuId) { | ||
| 117 | + return movementOrderDetailMapper.selectCountBySkuId(skuId); | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + @Override | ||
| 121 | + public long getMovementOrderDetailCountByAreaId(Long areaId) { | ||
| 122 | + return movementOrderDetailMapper.selectCountByAreaId(areaId); | ||
| 123 | + } | ||
| 124 | + | ||
| 115 | private List<WmsMovementOrderDetailDO> buildMovementOrderDetailList(WmsMovementOrderSaveReqVO reqVO) { | 125 | private List<WmsMovementOrderDetailDO> buildMovementOrderDetailList(WmsMovementOrderSaveReqVO reqVO) { |
| 116 | if (CollUtil.isEmpty(reqVO.getDetails())) { | 126 | if (CollUtil.isEmpty(reqVO.getDetails())) { |
| 117 | return ListUtil.of(); | 127 | return ListUtil.of(); |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/movement/WmsMovementOrderService.java
| @@ -65,4 +65,20 @@ public interface WmsMovementOrderService { | @@ -65,4 +65,20 @@ public interface WmsMovementOrderService { | ||
| 65 | */ | 65 | */ |
| 66 | PageResult<WmsMovementOrderDO> getMovementOrderPage(WmsMovementOrderPageReqVO pageReqVO); | 66 | PageResult<WmsMovementOrderDO> getMovementOrderPage(WmsMovementOrderPageReqVO pageReqVO); |
| 67 | 67 | ||
| 68 | + /** | ||
| 69 | + * 获得指定仓库的移库单数量 | ||
| 70 | + * | ||
| 71 | + * @param warehouseId 仓库编号 | ||
| 72 | + * @return 移库单数量 | ||
| 73 | + */ | ||
| 74 | + long getMovementOrderCountByWarehouseId(Long warehouseId); | ||
| 75 | + | ||
| 76 | + /** | ||
| 77 | + * 获得指定库区的移库单数量 | ||
| 78 | + * | ||
| 79 | + * @param areaId 库区编号 | ||
| 80 | + * @return 移库单数量 | ||
| 81 | + */ | ||
| 82 | + long getMovementOrderCountByAreaId(Long areaId); | ||
| 83 | + | ||
| 68 | } | 84 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/movement/WmsMovementOrderServiceImpl.java
| @@ -128,6 +128,16 @@ public class WmsMovementOrderServiceImpl implements WmsMovementOrderService { | @@ -128,6 +128,16 @@ public class WmsMovementOrderServiceImpl implements WmsMovementOrderService { | ||
| 128 | return movementOrderMapper.selectPage(pageReqVO); | 128 | return movementOrderMapper.selectPage(pageReqVO); |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | + @Override | ||
| 132 | + public long getMovementOrderCountByWarehouseId(Long warehouseId) { | ||
| 133 | + return movementOrderMapper.selectCountByWarehouseId(warehouseId); | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + @Override | ||
| 137 | + public long getMovementOrderCountByAreaId(Long areaId) { | ||
| 138 | + return movementOrderMapper.selectCountByAreaId(areaId); | ||
| 139 | + } | ||
| 140 | + | ||
| 131 | private void validateMovementOrderSaveData(WmsMovementOrderSaveReqVO reqVO) { | 141 | private void validateMovementOrderSaveData(WmsMovementOrderSaveReqVO reqVO) { |
| 132 | // 校验移库单号唯一 | 142 | // 校验移库单号唯一 |
| 133 | validateMovementOrderNoUnique(reqVO.getId(), reqVO.getNo()); | 143 | validateMovementOrderNoUnique(reqVO.getId(), reqVO.getNo()); |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/receipt/WmsReceiptOrderDetailService.java
| @@ -60,4 +60,20 @@ public interface WmsReceiptOrderDetailService { | @@ -60,4 +60,20 @@ public interface WmsReceiptOrderDetailService { | ||
| 60 | */ | 60 | */ |
| 61 | List<WmsReceiptOrderDetailDO> validateReceiptOrderDetailListExists(Long orderId); | 61 | List<WmsReceiptOrderDetailDO> validateReceiptOrderDetailListExists(Long orderId); |
| 62 | 62 | ||
| 63 | + /** | ||
| 64 | + * 获得指定 SKU 的入库单明细数量 | ||
| 65 | + * | ||
| 66 | + * @param skuId SKU 编号 | ||
| 67 | + * @return 入库单明细数量 | ||
| 68 | + */ | ||
| 69 | + long getReceiptOrderDetailCountBySkuId(Long skuId); | ||
| 70 | + | ||
| 71 | + /** | ||
| 72 | + * 获得指定库区的入库单明细数量 | ||
| 73 | + * | ||
| 74 | + * @param areaId 库区编号 | ||
| 75 | + * @return 入库单明细数量 | ||
| 76 | + */ | ||
| 77 | + long getReceiptOrderDetailCountByAreaId(Long areaId); | ||
| 78 | + | ||
| 63 | } | 79 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/receipt/WmsReceiptOrderDetailServiceImpl.java
| @@ -111,6 +111,16 @@ public class WmsReceiptOrderDetailServiceImpl implements WmsReceiptOrderDetailSe | @@ -111,6 +111,16 @@ public class WmsReceiptOrderDetailServiceImpl implements WmsReceiptOrderDetailSe | ||
| 111 | return details; | 111 | return details; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | + @Override | ||
| 115 | + public long getReceiptOrderDetailCountBySkuId(Long skuId) { | ||
| 116 | + return receiptOrderDetailMapper.selectCountBySkuId(skuId); | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + @Override | ||
| 120 | + public long getReceiptOrderDetailCountByAreaId(Long areaId) { | ||
| 121 | + return receiptOrderDetailMapper.selectCountByAreaId(areaId); | ||
| 122 | + } | ||
| 123 | + | ||
| 114 | private List<WmsReceiptOrderDetailDO> buildReceiptOrderDetailList(WmsReceiptOrderSaveReqVO reqVO) { | 124 | private List<WmsReceiptOrderDetailDO> buildReceiptOrderDetailList(WmsReceiptOrderSaveReqVO reqVO) { |
| 115 | if (CollUtil.isEmpty(reqVO.getDetails())) { | 125 | if (CollUtil.isEmpty(reqVO.getDetails())) { |
| 116 | return ListUtil.of(); | 126 | return ListUtil.of(); |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/receipt/WmsReceiptOrderService.java
| @@ -65,4 +65,28 @@ public interface WmsReceiptOrderService { | @@ -65,4 +65,28 @@ public interface WmsReceiptOrderService { | ||
| 65 | */ | 65 | */ |
| 66 | PageResult<WmsReceiptOrderDO> getReceiptOrderPage(WmsReceiptOrderPageReqVO pageReqVO); | 66 | PageResult<WmsReceiptOrderDO> getReceiptOrderPage(WmsReceiptOrderPageReqVO pageReqVO); |
| 67 | 67 | ||
| 68 | + /** | ||
| 69 | + * 获得指定往来企业的入库单数量 | ||
| 70 | + * | ||
| 71 | + * @param merchantId 往来企业编号 | ||
| 72 | + * @return 入库单数量 | ||
| 73 | + */ | ||
| 74 | + long getReceiptOrderCountByMerchantId(Long merchantId); | ||
| 75 | + | ||
| 76 | + /** | ||
| 77 | + * 获得指定仓库的入库单数量 | ||
| 78 | + * | ||
| 79 | + * @param warehouseId 仓库编号 | ||
| 80 | + * @return 入库单数量 | ||
| 81 | + */ | ||
| 82 | + long getReceiptOrderCountByWarehouseId(Long warehouseId); | ||
| 83 | + | ||
| 84 | + /** | ||
| 85 | + * 获得指定库区的入库单数量 | ||
| 86 | + * | ||
| 87 | + * @param areaId 库区编号 | ||
| 88 | + * @return 入库单数量 | ||
| 89 | + */ | ||
| 90 | + long getReceiptOrderCountByAreaId(Long areaId); | ||
| 91 | + | ||
| 68 | } | 92 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/receipt/WmsReceiptOrderServiceImpl.java
| @@ -128,6 +128,21 @@ public class WmsReceiptOrderServiceImpl implements WmsReceiptOrderService { | @@ -128,6 +128,21 @@ public class WmsReceiptOrderServiceImpl implements WmsReceiptOrderService { | ||
| 128 | return receiptOrderMapper.selectPage(pageReqVO); | 128 | return receiptOrderMapper.selectPage(pageReqVO); |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | + @Override | ||
| 132 | + public long getReceiptOrderCountByMerchantId(Long merchantId) { | ||
| 133 | + return receiptOrderMapper.selectCountByMerchantId(merchantId); | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + @Override | ||
| 137 | + public long getReceiptOrderCountByWarehouseId(Long warehouseId) { | ||
| 138 | + return receiptOrderMapper.selectCountByWarehouseId(warehouseId); | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + @Override | ||
| 142 | + public long getReceiptOrderCountByAreaId(Long areaId) { | ||
| 143 | + return receiptOrderMapper.selectCountByAreaId(areaId); | ||
| 144 | + } | ||
| 145 | + | ||
| 131 | private void validateReceiptOrderSaveData(WmsReceiptOrderSaveReqVO reqVO) { | 146 | private void validateReceiptOrderSaveData(WmsReceiptOrderSaveReqVO reqVO) { |
| 132 | // 校验入库单号唯一 | 147 | // 校验入库单号唯一 |
| 133 | validateReceiptOrderNoUnique(reqVO.getId(), reqVO.getNo()); | 148 | validateReceiptOrderNoUnique(reqVO.getId(), reqVO.getNo()); |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/shipment/WmsShipmentOrderDetailService.java
| @@ -60,4 +60,20 @@ public interface WmsShipmentOrderDetailService { | @@ -60,4 +60,20 @@ public interface WmsShipmentOrderDetailService { | ||
| 60 | */ | 60 | */ |
| 61 | List<WmsShipmentOrderDetailDO> validateShipmentOrderDetailListExists(Long orderId); | 61 | List<WmsShipmentOrderDetailDO> validateShipmentOrderDetailListExists(Long orderId); |
| 62 | 62 | ||
| 63 | + /** | ||
| 64 | + * 获得指定 SKU 的出库单明细数量 | ||
| 65 | + * | ||
| 66 | + * @param skuId SKU 编号 | ||
| 67 | + * @return 出库单明细数量 | ||
| 68 | + */ | ||
| 69 | + long getShipmentOrderDetailCountBySkuId(Long skuId); | ||
| 70 | + | ||
| 71 | + /** | ||
| 72 | + * 获得指定库区的出库单明细数量 | ||
| 73 | + * | ||
| 74 | + * @param areaId 库区编号 | ||
| 75 | + * @return 出库单明细数量 | ||
| 76 | + */ | ||
| 77 | + long getShipmentOrderDetailCountByAreaId(Long areaId); | ||
| 78 | + | ||
| 63 | } | 79 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/shipment/WmsShipmentOrderDetailServiceImpl.java
| @@ -111,6 +111,16 @@ public class WmsShipmentOrderDetailServiceImpl implements WmsShipmentOrderDetail | @@ -111,6 +111,16 @@ public class WmsShipmentOrderDetailServiceImpl implements WmsShipmentOrderDetail | ||
| 111 | return details; | 111 | return details; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | + @Override | ||
| 115 | + public long getShipmentOrderDetailCountBySkuId(Long skuId) { | ||
| 116 | + return shipmentOrderDetailMapper.selectCountBySkuId(skuId); | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + @Override | ||
| 120 | + public long getShipmentOrderDetailCountByAreaId(Long areaId) { | ||
| 121 | + return shipmentOrderDetailMapper.selectCountByAreaId(areaId); | ||
| 122 | + } | ||
| 123 | + | ||
| 114 | private List<WmsShipmentOrderDetailDO> buildShipmentOrderDetailList(WmsShipmentOrderSaveReqVO reqVO) { | 124 | private List<WmsShipmentOrderDetailDO> buildShipmentOrderDetailList(WmsShipmentOrderSaveReqVO reqVO) { |
| 115 | if (CollUtil.isEmpty(reqVO.getDetails())) { | 125 | if (CollUtil.isEmpty(reqVO.getDetails())) { |
| 116 | return ListUtil.of(); | 126 | return ListUtil.of(); |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/shipment/WmsShipmentOrderService.java
| @@ -65,4 +65,28 @@ public interface WmsShipmentOrderService { | @@ -65,4 +65,28 @@ public interface WmsShipmentOrderService { | ||
| 65 | */ | 65 | */ |
| 66 | PageResult<WmsShipmentOrderDO> getShipmentOrderPage(WmsShipmentOrderPageReqVO pageReqVO); | 66 | PageResult<WmsShipmentOrderDO> getShipmentOrderPage(WmsShipmentOrderPageReqVO pageReqVO); |
| 67 | 67 | ||
| 68 | + /** | ||
| 69 | + * 获得指定往来企业的出库单数量 | ||
| 70 | + * | ||
| 71 | + * @param merchantId 往来企业编号 | ||
| 72 | + * @return 出库单数量 | ||
| 73 | + */ | ||
| 74 | + long getShipmentOrderCountByMerchantId(Long merchantId); | ||
| 75 | + | ||
| 76 | + /** | ||
| 77 | + * 获得指定仓库的出库单数量 | ||
| 78 | + * | ||
| 79 | + * @param warehouseId 仓库编号 | ||
| 80 | + * @return 出库单数量 | ||
| 81 | + */ | ||
| 82 | + long getShipmentOrderCountByWarehouseId(Long warehouseId); | ||
| 83 | + | ||
| 84 | + /** | ||
| 85 | + * 获得指定库区的出库单数量 | ||
| 86 | + * | ||
| 87 | + * @param areaId 库区编号 | ||
| 88 | + * @return 出库单数量 | ||
| 89 | + */ | ||
| 90 | + long getShipmentOrderCountByAreaId(Long areaId); | ||
| 91 | + | ||
| 68 | } | 92 | } |
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/order/shipment/WmsShipmentOrderServiceImpl.java
| @@ -129,6 +129,21 @@ public class WmsShipmentOrderServiceImpl implements WmsShipmentOrderService { | @@ -129,6 +129,21 @@ public class WmsShipmentOrderServiceImpl implements WmsShipmentOrderService { | ||
| 129 | return shipmentOrderMapper.selectPage(pageReqVO); | 129 | return shipmentOrderMapper.selectPage(pageReqVO); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | + @Override | ||
| 133 | + public long getShipmentOrderCountByMerchantId(Long merchantId) { | ||
| 134 | + return shipmentOrderMapper.selectCountByMerchantId(merchantId); | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + @Override | ||
| 138 | + public long getShipmentOrderCountByWarehouseId(Long warehouseId) { | ||
| 139 | + return shipmentOrderMapper.selectCountByWarehouseId(warehouseId); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + @Override | ||
| 143 | + public long getShipmentOrderCountByAreaId(Long areaId) { | ||
| 144 | + return shipmentOrderMapper.selectCountByAreaId(areaId); | ||
| 145 | + } | ||
| 146 | + | ||
| 132 | private void validateShipmentOrderSaveData(WmsShipmentOrderSaveReqVO reqVO) { | 147 | private void validateShipmentOrderSaveData(WmsShipmentOrderSaveReqVO reqVO) { |
| 133 | // 校验出库单号唯一 | 148 | // 校验出库单号唯一 |
| 134 | validateShipmentOrderNoUnique(reqVO.getId(), reqVO.getNo()); | 149 | validateShipmentOrderNoUnique(reqVO.getId(), reqVO.getNo()); |
yudao-module-wms/src/test/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImplTest.java
| @@ -3,9 +3,11 @@ package cn.iocoder.yudao.module.wms.service.inventory; | @@ -3,9 +3,11 @@ package cn.iocoder.yudao.module.wms.service.inventory; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | 4 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 5 | import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryPageReqVO; | 5 | import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryPageReqVO; |
| 6 | +import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDetailDO; | ||
| 6 | import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryHistoryDO; | 7 | import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryHistoryDO; |
| 7 | import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO; | 8 | import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO; |
| 8 | import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO; | 9 | import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO; |
| 10 | +import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryDetailMapper; | ||
| 9 | import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO; | 11 | import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO; |
| 10 | import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryHistoryMapper; | 12 | import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryHistoryMapper; |
| 11 | import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryMapper; | 13 | import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryMapper; |
| @@ -19,8 +21,12 @@ import org.junit.jupiter.api.Test; | @@ -19,8 +21,12 @@ import org.junit.jupiter.api.Test; | ||
| 19 | import org.springframework.context.annotation.Import; | 21 | import org.springframework.context.annotation.Import; |
| 20 | 22 | ||
| 21 | import java.math.BigDecimal; | 23 | import java.math.BigDecimal; |
| 24 | +import java.util.ArrayList; | ||
| 22 | import java.util.List; | 25 | import java.util.List; |
| 23 | 26 | ||
| 27 | +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; | ||
| 28 | +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.INVENTORY_DETAIL_REMAIN_QUANTITY_NOT_ENOUGH; | ||
| 29 | +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.INVENTORY_QUANTITY_NOT_ENOUGH; | ||
| 24 | import static org.junit.jupiter.api.Assertions.assertEquals; | 30 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| 25 | import static org.junit.jupiter.api.Assertions.assertNotNull; | 31 | import static org.junit.jupiter.api.Assertions.assertNotNull; |
| 26 | 32 | ||
| @@ -34,6 +40,8 @@ public class WmsInventoryServiceImplTest extends BaseDbUnitTest { | @@ -34,6 +40,8 @@ public class WmsInventoryServiceImplTest extends BaseDbUnitTest { | ||
| 34 | @Resource | 40 | @Resource |
| 35 | private WmsInventoryMapper inventoryMapper; | 41 | private WmsInventoryMapper inventoryMapper; |
| 36 | @Resource | 42 | @Resource |
| 43 | + private WmsInventoryDetailMapper inventoryDetailMapper; | ||
| 44 | + @Resource | ||
| 37 | private WmsInventoryHistoryMapper inventoryHistoryMapper; | 45 | private WmsInventoryHistoryMapper inventoryHistoryMapper; |
| 38 | @Resource | 46 | @Resource |
| 39 | private WmsItemMapper itemMapper; | 47 | private WmsItemMapper itemMapper; |
| @@ -97,6 +105,72 @@ public class WmsInventoryServiceImplTest extends BaseDbUnitTest { | @@ -97,6 +105,72 @@ public class WmsInventoryServiceImplTest extends BaseDbUnitTest { | ||
| 97 | } | 105 | } |
| 98 | 106 | ||
| 99 | @Test | 107 | @Test |
| 108 | + public void testChangeInventory_quantityNotEnough() { | ||
| 109 | + // mock 数据 | ||
| 110 | + wmsProperties.setBatchEnable(false); | ||
| 111 | + WmsItemDO item = createItem("ITEM-001", "红富士苹果"); | ||
| 112 | + WmsItemSkuDO sku = createSku(item.getId(), "SKU-001", "10kg 箱装"); | ||
| 113 | + inventoryMapper.insert(createInventory(sku.getId(), 100L, 1001L, "2.00")); | ||
| 114 | + WmsInventoryChangeReqDTO reqDTO = createChangeReq(sku.getId(), 100L, 1001L, "-3.00"); | ||
| 115 | + | ||
| 116 | + // 调用,并断言 | ||
| 117 | + assertServiceException(() -> inventoryService.changeInventory(reqDTO), INVENTORY_QUANTITY_NOT_ENOUGH, | ||
| 118 | + new BigDecimal("2.000000"), new BigDecimal("-3.00")); | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + @Test | ||
| 122 | + public void testChangeInventory_decreaseInventoryDetail() { | ||
| 123 | + // mock 数据 | ||
| 124 | + wmsProperties.setBatchEnable(true); | ||
| 125 | + WmsItemDO item = createItem("ITEM-001", "红富士苹果"); | ||
| 126 | + WmsItemSkuDO sku = createSku(item.getId(), "SKU-001", "10kg 箱装"); | ||
| 127 | + inventoryMapper.insert(createInventory(sku.getId(), 100L, 1001L, "10.00")); | ||
| 128 | + WmsInventoryDetailDO detail = createInventoryDetail(sku.getId(), 100L, 1001L, "5.00"); | ||
| 129 | + inventoryDetailMapper.insert(detail); | ||
| 130 | + WmsInventoryChangeReqDTO reqDTO = createChangeReq(sku.getId(), 100L, 1001L, "-3.00"); | ||
| 131 | + reqDTO.getItems().get(0).setInventoryDetailId(detail.getId()); | ||
| 132 | + | ||
| 133 | + // 调用 | ||
| 134 | + inventoryService.changeInventory(reqDTO); | ||
| 135 | + | ||
| 136 | + // 断言:库存余额 | ||
| 137 | + WmsInventoryDO inventory = inventoryMapper.selectBySkuIdAndWarehouseIdAndAreaId(sku.getId(), 100L, 1001L); | ||
| 138 | + assertEquals(0, new BigDecimal("7.00").compareTo(inventory.getQuantity())); | ||
| 139 | + // 断言:库存明细 | ||
| 140 | + WmsInventoryDetailDO dbDetail = inventoryDetailMapper.selectById(detail.getId()); | ||
| 141 | + assertEquals(0, new BigDecimal("2.00").compareTo(dbDetail.getRemainQuantity())); | ||
| 142 | + // 断言:库存流水 | ||
| 143 | + List<WmsInventoryHistoryDO> histories = inventoryHistoryMapper.selectList(); | ||
| 144 | + assertEquals(1, histories.size()); | ||
| 145 | + assertEquals(0, new BigDecimal("-3.00").compareTo(histories.get(0).getQuantity())); | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + @Test | ||
| 149 | + public void testChangeInventory_decreaseInventoryDetailRemainQuantityNotEnough() { | ||
| 150 | + // mock 数据 | ||
| 151 | + wmsProperties.setBatchEnable(true); | ||
| 152 | + WmsItemDO item = createItem("ITEM-001", "红富士苹果"); | ||
| 153 | + WmsItemSkuDO sku = createSku(item.getId(), "SKU-001", "10kg 箱装"); | ||
| 154 | + inventoryMapper.insert(createInventory(sku.getId(), 100L, 1001L, "10.00")); | ||
| 155 | + WmsInventoryDetailDO detail = createInventoryDetail(sku.getId(), 100L, 1001L, "5.00"); | ||
| 156 | + inventoryDetailMapper.insert(detail); | ||
| 157 | + WmsInventoryChangeReqDTO reqDTO = createChangeReq(sku.getId(), 100L, 1001L, "-3.00"); | ||
| 158 | + reqDTO.getItems().get(0).setInventoryDetailId(detail.getId()); | ||
| 159 | + List<WmsInventoryChangeReqDTO.Item> items = new ArrayList<>(reqDTO.getItems()); | ||
| 160 | + items.add(new WmsInventoryChangeReqDTO.Item() | ||
| 161 | + .setSkuId(sku.getId()) | ||
| 162 | + .setWarehouseId(100L) | ||
| 163 | + .setAreaId(1001L) | ||
| 164 | + .setInventoryDetailId(detail.getId()) | ||
| 165 | + .setQuantity(new BigDecimal("-3.00"))); | ||
| 166 | + reqDTO.setItems(items); | ||
| 167 | + | ||
| 168 | + // 调用,并断言:相同库存明细会合并后校验 | ||
| 169 | + assertServiceException(() -> inventoryService.changeInventory(reqDTO), | ||
| 170 | + INVENTORY_DETAIL_REMAIN_QUANTITY_NOT_ENOUGH, new BigDecimal("5.000000"), new BigDecimal("6.00")); | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + @Test | ||
| 100 | public void testGetInventoryPage_groupByWarehouse() { | 174 | public void testGetInventoryPage_groupByWarehouse() { |
| 101 | // mock 数据 | 175 | // mock 数据 |
| 102 | WmsItemDO item = createItem("ITEM-001", "红富士苹果"); | 176 | WmsItemDO item = createItem("ITEM-001", "红富士苹果"); |
| @@ -191,6 +265,17 @@ public class WmsInventoryServiceImplTest extends BaseDbUnitTest { | @@ -191,6 +265,17 @@ public class WmsInventoryServiceImplTest extends BaseDbUnitTest { | ||
| 191 | .build(); | 265 | .build(); |
| 192 | } | 266 | } |
| 193 | 267 | ||
| 268 | + private static WmsInventoryDetailDO createInventoryDetail(Long skuId, Long warehouseId, Long areaId, | ||
| 269 | + String remainQuantity) { | ||
| 270 | + return WmsInventoryDetailDO.builder() | ||
| 271 | + .skuId(skuId) | ||
| 272 | + .warehouseId(warehouseId) | ||
| 273 | + .areaId(areaId) | ||
| 274 | + .quantity(new BigDecimal(remainQuantity)) | ||
| 275 | + .remainQuantity(new BigDecimal(remainQuantity)) | ||
| 276 | + .build(); | ||
| 277 | + } | ||
| 278 | + | ||
| 194 | private static WmsInventoryChangeReqDTO createChangeReq(Long skuId, Long warehouseId, Long areaId, String quantity) { | 279 | private static WmsInventoryChangeReqDTO createChangeReq(Long skuId, Long warehouseId, Long areaId, String quantity) { |
| 195 | return new WmsInventoryChangeReqDTO() | 280 | return new WmsInventoryChangeReqDTO() |
| 196 | .setOrderId(1L) | 281 | .setOrderId(1L) |