Commit 2f4dfb69ee877e09ff6aff835624321f922fbf5c

Authored by YunaiV
1 parent b1e4a6df

✨ feat(transaction): 添加库存事务管理逻辑及相关 DTO

新增库存事务类型枚举及服务接口,支持创建和批量创建库存事务。更新库存数量时增加校验逻辑,确保库存充足。重构相关服务以支持新功能,提升库存管理的灵活性和准确性。
Showing 18 changed files with 444 additions and 92 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transaction/MesWmTransactionDO.java
@@ -40,16 +40,12 @@ public class MesWmTransactionDO extends BaseDO { @@ -40,16 +40,12 @@ public class MesWmTransactionDO extends BaseDO {
40 40
41 // ==================== 业务归属 ==================== 41 // ==================== 业务归属 ====================
42 42
43 - // codex reply:`transactionType` 收敛成 `type` 是对的,和项目里其他 DO 的命名保持一致。  
44 - // codex reply:不过这类改名要连同 `MesWmTransactionSaveReqVO`、Service 和查询条件一起同步,不然 DO 与上下游模型会割裂。  
45 /** 43 /**
46 * 事务类型 44 * 事务类型
47 * 45 *
48 * 枚举 {@link MesWmTransactionTypeEnum} 46 * 枚举 {@link MesWmTransactionTypeEnum}
49 */ 47 */
50 private Integer type; 48 private Integer type;
51 - // codex reply:`transactionQuantity` 收敛成 `quantity` 是对的;在事务流水这个上下文里,`transaction` 前缀没有额外信息。  
52 - // codex reply:`transactionFlag` 删除也合理,直接存带符号数量更符合当前写入逻辑,后续聚合查询也可以直接 `SUM(quantity)`。  
53 /** 49 /**
54 * 本次变动数量 50 * 本次变动数量
55 * 51 *
@@ -109,7 +105,6 @@ public class MesWmTransactionDO extends BaseDO { @@ -109,7 +105,6 @@ public class MesWmTransactionDO extends BaseDO {
109 * 关联 {@link MesWmBatchDO#getCode()} 105 * 关联 {@link MesWmBatchDO#getCode()}
110 */ 106 */
111 private String batchCode; 107 private String batchCode;
112 - // codex reply:`packageId` 当前删除是合理的。事务流水链路没有包装维度的输入输出,先不保留“预留字段”更干净。  
113 108
114 // ==================== 库存位置 ==================== 109 // ==================== 库存位置 ====================
115 110
@@ -134,8 +129,6 @@ public class MesWmTransactionDO extends BaseDO { @@ -134,8 +129,6 @@ public class MesWmTransactionDO extends BaseDO {
134 129
135 // ==================== 时间 ==================== 130 // ==================== 时间 ====================
136 131
137 - // codex reply:这里我不建议继续沿用 `erpTime` / `receiptTime` 这组命名;项目里的同类字段基本统一为 `receiptDate`,单独改成 `Time` 会破坏一致性。  
138 - // codex reply:如果这两个字段暂时没有业务赋值,建议宁可先删;若后续保留,ERP 侧更建议 `erpAccountDate`,收货侧保持 `receiptDate`。  
139 /** 132 /**
140 * 事务发生时间 133 * 事务发生时间
141 */ 134 */
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java
@@ -20,6 +20,10 @@ import java.util.List; @@ -20,6 +20,10 @@ import java.util.List;
20 @Mapper 20 @Mapper
21 public interface MesWmBatchMapper extends BaseMapperX<MesWmBatchDO> { 21 public interface MesWmBatchMapper extends BaseMapperX<MesWmBatchDO> {
22 22
  23 + default MesWmBatchDO selectByCode(String code) {
  24 + return selectOne(MesWmBatchDO:: getCode, code);
  25 + }
  26 +
23 default PageResult<MesWmBatchDO> selectPage(MesWmBatchPageReqVO reqVO) { 27 default PageResult<MesWmBatchDO> selectPage(MesWmBatchPageReqVO reqVO) {
24 return selectPage(reqVO, new LambdaQueryWrapperX<MesWmBatchDO>() 28 return selectPage(reqVO, new LambdaQueryWrapperX<MesWmBatchDO>()
25 .likeIfPresent(MesWmBatchDO::getCode, reqVO.getCode()) 29 .likeIfPresent(MesWmBatchDO::getCode, reqVO.getCode())
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java
@@ -51,15 +51,16 @@ public interface MesWmMaterialStockMapper extends BaseMapperX&lt;MesWmMaterialStock @@ -51,15 +51,16 @@ public interface MesWmMaterialStockMapper extends BaseMapperX&lt;MesWmMaterialStock
51 /** 51 /**
52 * 增量更新库存数量 52 * 增量更新库存数量
53 * 53 *
54 - * @param id 库存记录编号  
55 - * @param count 变动数量(正数=增加,负数=扣减)  
56 - * @return 影响行数(扣减时为 0 表示库存不足) 54 + * @param id 库存记录编号
  55 + * @param count 变动数量(正数=增加,负数=扣减)
  56 + * @param checkFlag 是否校验库存充足(为 true 时扣减不允许变为负数)
  57 + * @return 影响行数
57 */ 58 */
58 - default int updateQuantity(Long id, BigDecimal count) { 59 + default int updateQuantity(Long id, BigDecimal count, boolean checkFlag) {
59 LambdaUpdateWrapper<MesWmMaterialStockDO> updateWrapper = new LambdaUpdateWrapper<MesWmMaterialStockDO>() 60 LambdaUpdateWrapper<MesWmMaterialStockDO> updateWrapper = new LambdaUpdateWrapper<MesWmMaterialStockDO>()
60 .eq(MesWmMaterialStockDO::getId, id) 61 .eq(MesWmMaterialStockDO::getId, id)
61 .setSql("quantity = quantity + " + count); 62 .setSql("quantity = quantity + " + count);
62 - if (count.compareTo(BigDecimal.ZERO) < 0) { 63 + if (checkFlag && count.compareTo(BigDecimal.ZERO) < 0) {
63 updateWrapper.ge(MesWmMaterialStockDO::getQuantity, count.abs()); // CAS 防负库存 64 updateWrapper.ge(MesWmMaterialStockDO::getQuantity, count.abs()); // CAS 防负库存
64 } 65 }
65 return update(null, updateWrapper); 66 return update(null, updateWrapper);
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -355,7 +355,7 @@ public interface ErrorCodeConstants { @@ -355,7 +355,7 @@ public interface ErrorCodeConstants {
355 // ========== MES 仓库管理-库存(1-040-703-000) ========== 355 // ========== MES 仓库管理-库存(1-040-703-000) ==========
356 ErrorCode WM_MATERIAL_STOCK_NOT_EXISTS = new ErrorCode(1_040_703_000, "库存记录不存在"); 356 ErrorCode WM_MATERIAL_STOCK_NOT_EXISTS = new ErrorCode(1_040_703_000, "库存记录不存在");
357 ErrorCode WM_MATERIAL_STOCK_INSUFFICIENT = new ErrorCode(1_040_703_001, "库存数量不足"); 357 ErrorCode WM_MATERIAL_STOCK_INSUFFICIENT = new ErrorCode(1_040_703_001, "库存数量不足");
358 - ErrorCode WM_TRANSACTION_MATERIAL_STOCK_REQUIRED = new ErrorCode(1_040_703_002, "出库事务必须指定库存记录 ID"); 358 + ErrorCode WM_TRANSACTION_TYPE_NOT_EXISTS = new ErrorCode(1_040_703_002, "库存事务类型不存在");
359 359
360 // ========== MES 仓库管理-到货通知单(1-040-704-000) ========== 360 // ========== MES 仓库管理-到货通知单(1-040-704-000) ==========
361 ErrorCode WM_ARRIVAL_NOTICE_NOT_EXISTS = new ErrorCode(1_040_704_000, "到货通知单不存在"); 361 ErrorCode WM_ARRIVAL_NOTICE_NOT_EXISTS = new ErrorCode(1_040_704_000, "到货通知单不存在");
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java
@@ -29,6 +29,21 @@ public final class MesBizTypeConstants { @@ -29,6 +29,21 @@ public final class MesBizTypeConstants {
29 public static final int WM_PACKAGE = 105; // 装箱单:MesWmPackageDO 29 public static final int WM_PACKAGE = 105; // 装箱单:MesWmPackageDO
30 public static final int WM_STOCK = 106; // 库存:MesWmMaterialStockDO 30 public static final int WM_STOCK = 106; // 库存:MesWmMaterialStockDO
31 public static final int WM_BATCH = 107; // 批次:MesWmBatchDO 31 public static final int WM_BATCH = 107; // 批次:MesWmBatchDO
  32 + public static final int WM_TRANSACTION = 108; // 库存事务流水:MesWmTransactionDO
  33 + public static final int WM_ITEM_RECEIPT_IN = 110; // 采购入库:MesWmItemReceiptDO
  34 + public static final int WM_TRANSFER_OUT = 111; // 调拨出库:MesWmTransferDO
  35 + public static final int WM_TRANSFER_IN = 112; // 调拨入库:MesWmTransferDO
  36 + public static final int WM_MISC_ISSUE = 113; // 其他出库:MesWmMiscIssueDO
  37 + public static final int WM_MISC_RECPT = 114; // 其他入库:MesWmMiscReceiptDO
  38 + public static final int WM_ISSUE = 115; // 生产领料:MesWmProductionIssueDO
  39 + public static final int WM_RT_ISSUE = 116; // 生产退料:MesWmReturnIssueDO
  40 + public static final int WM_PRODUCT_RECPT = 117; // 生产入库:MesWmProductReceiptDO
  41 + public static final int WM_PRODUCT_SALES = 118; // 销售出库:MesWmProductSalesDO
  42 + public static final int WM_RT_SALES = 119; // 销售退货入库:MesWmReturnSalesDO
  43 + public static final int WM_OUTSOURCE_ISSUE = 120; // 外协发料:MesWmOutsourceIssueDO
  44 + public static final int WM_OUTSOURCE_RECPT = 121; // 外协入库:MesWmOutsourceReceiptDO
  45 + public static final int WM_ITEM_CONSUME = 122; // 生产消耗:MesWmItemConsumeDO
  46 + public static final int WM_PRODUCT_PRODUCE = 123; // 产品产出:MesWmProductProduceDO
32 47
33 // ========== CAL 排班模块 [200, 300) ========== 48 // ========== CAL 排班模块 [200, 300) ==========
34 49
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmTransactionTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.enums.wm;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.ObjUtil;
  5 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  6 +import lombok.AllArgsConstructor;
  7 +import lombok.Getter;
  8 +
  9 +import java.util.Arrays;
  10 +
  11 +/**
  12 + * MES 库存事务类型枚举
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Getter
  17 +@AllArgsConstructor
  18 +public enum MesWmTransactionTypeEnum implements ArrayValuable<Integer> {
  19 +
  20 + /**
  21 + * 入库
  22 + */
  23 + IN(1, "入库", true),
  24 + /**
  25 + * 出库
  26 + */
  27 + OUT(2, "出库", false),
  28 + /**
  29 + * 调拨移出
  30 + */
  31 + MOVE_OUT(3, "调拨移出", false),
  32 + /**
  33 + * 调拨移入
  34 + */
  35 + MOVE_IN(4, "调拨移入", true),
  36 + /**
  37 + * 盘盈
  38 + */
  39 + ADJUST_IN(5, "盘盈", true),
  40 + /**
  41 + * 盘亏
  42 + */
  43 + ADJUST_OUT(6, "盘亏", false);
  44 +
  45 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesWmTransactionTypeEnum::getType).toArray(Integer[]::new);
  46 +
  47 + /**
  48 + * 类型值
  49 + */
  50 + private final Integer type;
  51 + /**
  52 + * 类型名
  53 + */
  54 + private final String name;
  55 + /**
  56 + * 是否为入库方向
  57 + */
  58 + private final boolean inbound;
  59 +
  60 + public static MesWmTransactionTypeEnum valueOf(Integer type) {
  61 + return CollUtil.findOne(CollUtil.newArrayList(values()),
  62 + e -> ObjUtil.equal(e.getType(), type));
  63 + }
  64 +
  65 + @Override
  66 + public Integer[] array() {
  67 + return ARRAYS;
  68 + }
  69 +
  70 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchService.java
@@ -23,6 +23,22 @@ public interface MesWmBatchService { @@ -23,6 +23,22 @@ public interface MesWmBatchService {
23 PageResult<MesWmBatchDO> getBatchPage(MesWmBatchPageReqVO pageReqVO); 23 PageResult<MesWmBatchDO> getBatchPage(MesWmBatchPageReqVO pageReqVO);
24 24
25 /** 25 /**
  26 + * 获得批次
  27 + *
  28 + * @param id 批次编号
  29 + * @return 批次记录
  30 + */
  31 + MesWmBatchDO getBatch(Long id);
  32 +
  33 + /**
  34 + * 根据批次号获得批次
  35 + *
  36 + * @param code 批次号
  37 + * @return 批次记录
  38 + */
  39 + MesWmBatchDO getBatchByCode(String code);
  40 +
  41 + /**
26 * 获取或生成批次编码 42 * 获取或生成批次编码
27 * <p> 43 * <p>
28 * 根据物料批次配置,查询或生成批次记录 44 * 根据物料批次配置,查询或生成批次记录
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java
@@ -54,6 +54,16 @@ public class MesWmBatchServiceImpl implements MesWmBatchService { @@ -54,6 +54,16 @@ public class MesWmBatchServiceImpl implements MesWmBatchService {
54 } 54 }
55 55
56 @Override 56 @Override
  57 + public MesWmBatchDO getBatch(Long id) {
  58 + return batchMapper.selectById(id);
  59 + }
  60 +
  61 + @Override
  62 + public MesWmBatchDO getBatchByCode(String code) {
  63 + return batchMapper.selectByCode(code);
  64 + }
  65 +
  66 + @Override
57 @Transactional(rollbackFor = Exception.class) 67 @Transactional(rollbackFor = Exception.class)
58 public MesWmBatchDO getOrGenerateBatchCode(MesWmBatchGenerateReqVO reqVO) { 68 public MesWmBatchDO getOrGenerateBatchCode(MesWmBatchGenerateReqVO reqVO) {
59 // 1.1 查询物料信息,检查是否启用批次管理 69 // 1.1 查询物料信息,检查是否启用批次管理
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java
@@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterial @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterial
8 import jakarta.validation.Valid; 8 import jakarta.validation.Valid;
9 9
10 import java.math.BigDecimal; 10 import java.math.BigDecimal;
  11 +import java.time.LocalDateTime;
11 import java.util.Collection; 12 import java.util.Collection;
12 import java.util.List; 13 import java.util.List;
13 import java.util.Map; 14 import java.util.Map;
@@ -28,14 +29,6 @@ public interface MesWmMaterialStockService { @@ -28,14 +29,6 @@ public interface MesWmMaterialStockService {
28 MesWmMaterialStockDO getMaterialStock(Long id); 29 MesWmMaterialStockDO getMaterialStock(Long id);
29 30
30 /** 31 /**
31 - * 校验库存记录存在  
32 - *  
33 - * @param id 编号  
34 - * @return 库存记录  
35 - */  
36 - MesWmMaterialStockDO validateMaterialStockExists(Long id);  
37 -  
38 - /**  
39 * 获得库存台账分页 32 * 获得库存台账分页
40 * 33 *
41 * @param pageReqVO 分页参数 34 * @param pageReqVO 分页参数
@@ -95,31 +88,27 @@ public interface MesWmMaterialStockService { @@ -95,31 +88,27 @@ public interface MesWmMaterialStockService {
95 } 88 }
96 89
97 /** 90 /**
98 - * 增加库存  
99 - *  
100 - * 按 itemId + warehouseId + locationId + areaId + batchId 查找已有库存,  
101 - * 存在则增加 quantity;不存在则新建记录。 91 + * 获取或创建库存记录(按组合键唯一)
102 * 92 *
103 * @param itemId 物料编号 93 * @param itemId 物料编号
104 * @param warehouseId 仓库编号 94 * @param warehouseId 仓库编号
105 * @param locationId 库区编号 95 * @param locationId 库区编号
106 * @param areaId 库位编号 96 * @param areaId 库位编号
107 * @param batchId 批次编号 97 * @param batchId 批次编号
108 - * @param quantity 增加数量  
109 * @param vendorId 供应商编号 98 * @param vendorId 供应商编号
  99 + * @param receiptTime 入库时间(为空则默认当前时间)
  100 + * @return 库存记录编号
110 */ 101 */
111 - void increaseStock(Long itemId, Long warehouseId, Long locationId, Long areaId,  
112 - Long batchId, BigDecimal quantity, Long vendorId); 102 + Long getOrCreateMaterialStock(Long itemId, Long warehouseId, Long locationId, Long areaId,
  103 + Long batchId, Long vendorId, LocalDateTime receiptTime);
113 104
114 /** 105 /**
115 - * 扣减库存  
116 - *  
117 - * 根据库存记录 ID 直接扣减数量。 106 + * 更新库存数量
118 * 107 *
119 - * @param materialStockId 库存记录编号  
120 - * @param quantity 扣减数量(正数)  
121 - * @param storageCheckFlag 是否校验库存充足 108 + * @param materialStockId 库存记录编号
  109 + * @param quantity 变动数量(正数=增加,负数=扣减)
  110 + * @param checkFlag 是否校验库存充足(为 true 且扣减后为负则报错)
122 */ 111 */
123 - void decreaseStock(Long materialStockId, BigDecimal quantity, boolean storageCheckFlag); 112 + void updateMaterialStockQuantity(Long materialStockId, BigDecimal quantity, boolean checkFlag);
124 113
125 } 114 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java
@@ -46,7 +46,6 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService @@ -46,7 +46,6 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService
46 return materialStockMapper.selectById(id); 46 return materialStockMapper.selectById(id);
47 } 47 }
48 48
49 - @Override  
50 public MesWmMaterialStockDO validateMaterialStockExists(Long id) { 49 public MesWmMaterialStockDO validateMaterialStockExists(Long id) {
51 MesWmMaterialStockDO stock = materialStockMapper.selectById(id); 50 MesWmMaterialStockDO stock = materialStockMapper.selectById(id);
52 if (stock == null) { 51 if (stock == null) {
@@ -79,11 +78,10 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService @@ -79,11 +78,10 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService
79 public void updateMaterialStockFrozen(MesWmMaterialStockFreezeReqVO updateReqVO) { 78 public void updateMaterialStockFrozen(MesWmMaterialStockFreezeReqVO updateReqVO) {
80 // 校验存在 79 // 校验存在
81 validateMaterialStockExists(updateReqVO.getId()); 80 validateMaterialStockExists(updateReqVO.getId());
  81 +
82 // 更新冻结状态 82 // 更新冻结状态
83 - MesWmMaterialStockDO updateObj = new MesWmMaterialStockDO();  
84 - updateObj.setId(updateReqVO.getId());  
85 - updateObj.setFrozenFlag(updateReqVO.getFrozenFlag());  
86 - materialStockMapper.updateById(updateObj); 83 + materialStockMapper.updateById(new MesWmMaterialStockDO()
  84 + .setId(updateReqVO.getId()).setFrozenFlag(updateReqVO.getFrozenFlag()));
87 } 85 }
88 86
89 @Override 87 @Override
@@ -115,37 +113,34 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService @@ -115,37 +113,34 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService
115 } 113 }
116 114
117 @Override 115 @Override
118 - public void increaseStock(Long itemId, Long warehouseId, Long locationId, Long areaId,  
119 - Long batchId, BigDecimal quantity, Long vendorId) { 116 + public Long getOrCreateMaterialStock(Long itemId, Long warehouseId, Long locationId, Long areaId,
  117 + Long batchId, Long vendorId, LocalDateTime receiptTime) {
120 // 1. 查找已有库存记录 118 // 1. 查找已有库存记录
121 MesWmMaterialStockDO stock = materialStockMapper.selectByCompositeKey( 119 MesWmMaterialStockDO stock = materialStockMapper.selectByCompositeKey(
122 itemId, warehouseId, locationId, areaId, batchId); 120 itemId, warehouseId, locationId, areaId, batchId);
123 -  
124 - // 2a. 存在则增加数量  
125 if (stock != null) { 121 if (stock != null) {
126 - materialStockMapper.updateQuantity(stock.getId(), quantity);  
127 - return; 122 + return stock.getId();
128 } 123 }
129 124
130 - // 2b. 不存在则新建 125 + // 2. 不存在则新建
131 MesMdItemDO item = itemService.validateItemExists(itemId); 126 MesMdItemDO item = itemService.validateItemExists(itemId);
132 MesWmMaterialStockDO newStock = MesWmMaterialStockDO.builder() 127 MesWmMaterialStockDO newStock = MesWmMaterialStockDO.builder()
133 .itemId(itemId).itemTypeId(item.getItemTypeId()) 128 .itemId(itemId).itemTypeId(item.getItemTypeId())
134 .warehouseId(warehouseId).locationId(locationId).areaId(areaId) 129 .warehouseId(warehouseId).locationId(locationId).areaId(areaId)
135 - .batchId(batchId).vendorId(vendorId).quantity(quantity)  
136 - .receiptTime(LocalDateTime.now()).frozenFlag(false) 130 + .batchId(batchId).vendorId(vendorId)
  131 + .quantity(BigDecimal.ZERO) // 初始数量为 0,由 updateMaterialStockQuantity 更新
  132 + .receiptTime(receiptTime != null ? receiptTime : LocalDateTime.now())
  133 + .frozenFlag(false)
137 .build(); 134 .build();
138 materialStockMapper.insert(newStock); 135 materialStockMapper.insert(newStock);
  136 + return newStock.getId();
139 } 137 }
140 138
141 @Override 139 @Override
142 - public void decreaseStock(Long materialStockId, BigDecimal quantity, boolean storageCheckFlag) {  
143 - // 1. 校验库存记录存在  
144 - validateMaterialStockExists(materialStockId);  
145 -  
146 - // 2. 扣减库存(Mapper 层 CAS 防负库存)  
147 - int updatedRows = materialStockMapper.updateQuantity(materialStockId, quantity.negate());  
148 - if (storageCheckFlag && updatedRows == 0) { 140 + public void updateMaterialStockQuantity(Long materialStockId, BigDecimal quantity, boolean checkFlag) {
  141 + // 更新库存数量(Mapper 层 CAS 防负库存;checkFlag=false 时允许负数)
  142 + int updatedRows = materialStockMapper.updateQuantity(materialStockId, quantity, checkFlag);
  143 + if (updatedRows == 0) {
149 throw exception(WM_MATERIAL_STOCK_INSUFFICIENT); 144 throw exception(WM_MATERIAL_STOCK_INSUFFICIENT);
150 } 145 }
151 } 146 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscissue/MesWmMiscIssueServiceImpl.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.mes.service.wm.miscissue; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.mes.service.wm.miscissue;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.ObjUtil; 4 import cn.hutool.core.util.ObjUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
8 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; 7 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
9 import cn.iocoder.yudao.module.mes.controller.admin.wm.miscissue.vo.MesWmMiscIssuePageReqVO; 8 import cn.iocoder.yudao.module.mes.controller.admin.wm.miscissue.vo.MesWmMiscIssuePageReqVO;
@@ -12,17 +11,20 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.miscissue.MesWmMiscIssueDO; @@ -12,17 +11,20 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.miscissue.MesWmMiscIssueDO;
12 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.miscissue.MesWmMiscIssueLineDO; 11 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.miscissue.MesWmMiscIssueLineDO;
13 import cn.iocoder.yudao.module.mes.dal.mysql.wm.miscissue.MesWmMiscIssueMapper; 12 import cn.iocoder.yudao.module.mes.dal.mysql.wm.miscissue.MesWmMiscIssueMapper;
14 import cn.iocoder.yudao.module.mes.enums.wm.MesWmMiscIssueStatusEnum; 13 import cn.iocoder.yudao.module.mes.enums.wm.MesWmMiscIssueStatusEnum;
15 -import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; 14 +import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
  15 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
  16 +import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
  17 +import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
16 import jakarta.annotation.Resource; 18 import jakarta.annotation.Resource;
17 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
18 import org.springframework.stereotype.Service; 20 import org.springframework.stereotype.Service;
19 import org.springframework.transaction.annotation.Transactional; 21 import org.springframework.transaction.annotation.Transactional;
20 import org.springframework.validation.annotation.Validated; 22 import org.springframework.validation.annotation.Validated;
21 23
22 -import java.math.BigDecimal;  
23 import java.util.List; 24 import java.util.List;
24 25
25 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  27 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
26 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; 28 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
27 29
28 /** 30 /**
@@ -38,6 +40,8 @@ public class MesWmMiscIssueServiceImpl implements MesWmMiscIssueService { @@ -38,6 +40,8 @@ public class MesWmMiscIssueServiceImpl implements MesWmMiscIssueService {
38 40
39 @Resource 41 @Resource
40 private MesWmMiscIssueLineService miscIssueLineService; 42 private MesWmMiscIssueLineService miscIssueLineService;
  43 + @Resource
  44 + private MesWmTransactionService wmTransactionService;
41 45
42 @Override 46 @Override
43 public Long createMiscIssue(MesWmMiscIssueSaveReqVO createReqVO) { 47 public Long createMiscIssue(MesWmMiscIssueSaveReqVO createReqVO) {
@@ -110,21 +114,23 @@ public class MesWmMiscIssueServiceImpl implements MesWmMiscIssueService { @@ -110,21 +114,23 @@ public class MesWmMiscIssueServiceImpl implements MesWmMiscIssueService {
110 throw exception(WM_MISC_ISSUE_STATUS_INVALID); 114 throw exception(WM_MISC_ISSUE_STATUS_INVALID);
111 } 115 }
112 116
113 - // 遍历所有行,扣减库存  
114 - // TODO @AI:需要实现 materialStockService.decreaseStock 方法来扣减库存  
115 - List<MesWmMiscIssueLineDO> lines = miscIssueLineService.getMiscIssueLineListByIssueId(id);  
116 - for (MesWmMiscIssueLineDO line : lines) {  
117 - // materialStockService.decreaseStock(  
118 - // line.getItemId(), line.getWarehouseId(), line.getLocationId(), line.getAreaId(),  
119 - // line.getBatchId(), line.getQuantity());  
120 - log.warn("[finishMiscIssue][杂项出库单({}) 行({}) 需要扣减库存,但 decreaseStock 方法尚未实现]", id, line.getId());  
121 - } 117 + // 2. 遍历所有行,创建库存事务(扣减库存 + 记录流水)
  118 + createTransactionList(issue);
122 119
123 - // 更新出库单状态(待执行出库 → 已完成) 120 + // 3. 更新出库单状态(待执行出库 → 已完成)
124 miscIssueMapper.updateById(new MesWmMiscIssueDO() 121 miscIssueMapper.updateById(new MesWmMiscIssueDO()
125 .setId(id).setStatus(MesWmMiscIssueStatusEnum.FINISHED.getStatus())); 122 .setId(id).setStatus(MesWmMiscIssueStatusEnum.FINISHED.getStatus()));
126 } 123 }
127 124
  125 + private void createTransactionList(MesWmMiscIssueDO issue) {
  126 + List<MesWmMiscIssueLineDO> lines = miscIssueLineService.getMiscIssueLineListByIssueId(issue.getId());
  127 + wmTransactionService.createTransactionList(convertList(lines, line -> new MesWmTransactionSaveReqDTO()
  128 + .setType(MesWmTransactionTypeEnum.OUT.getType()).setItemId(line.getItemId())
  129 + .setQuantity(line.getQuantity().negate()) // 出库数量为负数
  130 + .setWarehouseId(line.getWarehouseId()).setLocationId(line.getLocationId()).setAreaId(line.getAreaId())
  131 + .setBizType(MesBizTypeConstants.WM_MISC_ISSUE).setBizId(issue.getId()).setBizCode(issue.getCode()).setBizLineId(line.getId())));
  132 + }
  133 +
128 @Override 134 @Override
129 @Transactional(rollbackFor = Exception.class) 135 @Transactional(rollbackFor = Exception.class)
130 public void cancelMiscIssue(Long id) { 136 public void cancelMiscIssue(Long id) {
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/miscreceipt/MesWmMiscReceiptServiceImpl.java
@@ -11,7 +11,10 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.miscreceipt.MesWmMiscReceip @@ -11,7 +11,10 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.miscreceipt.MesWmMiscReceip
11 import cn.iocoder.yudao.module.mes.dal.mysql.wm.miscreceipt.MesWmMiscReceiptLineMapper; 11 import cn.iocoder.yudao.module.mes.dal.mysql.wm.miscreceipt.MesWmMiscReceiptLineMapper;
12 import cn.iocoder.yudao.module.mes.dal.mysql.wm.miscreceipt.MesWmMiscReceiptMapper; 12 import cn.iocoder.yudao.module.mes.dal.mysql.wm.miscreceipt.MesWmMiscReceiptMapper;
13 import cn.iocoder.yudao.module.mes.enums.wm.MesWmMiscReceiptStatusEnum; 13 import cn.iocoder.yudao.module.mes.enums.wm.MesWmMiscReceiptStatusEnum;
14 -import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; 14 +import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
  15 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
  16 +import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
  17 +import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
15 import jakarta.annotation.Resource; 18 import jakarta.annotation.Resource;
16 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
17 import org.springframework.stereotype.Service; 20 import org.springframework.stereotype.Service;
@@ -21,6 +24,7 @@ import org.springframework.validation.annotation.Validated; @@ -21,6 +24,7 @@ import org.springframework.validation.annotation.Validated;
21 import java.util.List; 24 import java.util.List;
22 25
23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  27 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
24 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; 28 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
25 29
26 /** 30 /**
@@ -33,15 +37,13 @@ public class MesWmMiscReceiptServiceImpl implements MesWmMiscReceiptService { @@ -33,15 +37,13 @@ public class MesWmMiscReceiptServiceImpl implements MesWmMiscReceiptService {
33 37
34 @Resource 38 @Resource
35 private MesWmMiscReceiptMapper miscReceiptMapper; 39 private MesWmMiscReceiptMapper miscReceiptMapper;
36 -  
37 @Resource 40 @Resource
38 private MesWmMiscReceiptLineMapper miscReceiptLineMapper; 41 private MesWmMiscReceiptLineMapper miscReceiptLineMapper;
39 42
40 @Resource 43 @Resource
41 private MesWmMiscReceiptDetailService miscReceiptDetailService; 44 private MesWmMiscReceiptDetailService miscReceiptDetailService;
42 -  
43 @Resource 45 @Resource
44 - private MesWmMaterialStockService materialStockService; 46 + private MesWmTransactionService wmTransactionService;
45 47
46 @Override 48 @Override
47 public Long createMiscReceipt(MesWmMiscReceiptSaveReqVO createReqVO) { 49 public Long createMiscReceipt(MesWmMiscReceiptSaveReqVO createReqVO) {
@@ -116,27 +118,23 @@ public class MesWmMiscReceiptServiceImpl implements MesWmMiscReceiptService { @@ -116,27 +118,23 @@ public class MesWmMiscReceiptServiceImpl implements MesWmMiscReceiptService {
116 throw exception(WM_MISC_RECEIPT_STATUS_NOT_APPROVED); 118 throw exception(WM_MISC_RECEIPT_STATUS_NOT_APPROVED);
117 } 119 }
118 120
119 - // 遍历所有行,更新库存台账  
120 - List<MesWmMiscReceiptLineDO> lines = miscReceiptLineMapper.selectListByReceiptId(id);  
121 - for (MesWmMiscReceiptLineDO line : lines) {  
122 - materialStockService.increaseStock(  
123 - line.getItemId(),  
124 - line.getWarehouseId(),  
125 - line.getLocationId(),  
126 - line.getAreaId(),  
127 - null, // batchId 传 null(杂项入库使用 batchCode)  
128 - line.getQuantity(),  
129 - null, // vendorId 传 null(杂项入库无供应商)  
130 - line.getProductionDate(),  
131 - line.getExpireDate()  
132 - );  
133 - } 121 + // 2. 遍历所有行,创建库存事务(增加库存 + 记录流水)
  122 + createTransactionList(receipt);
134 123
135 - // 执行入库(已审批 → 已完成) 124 + // 3. 执行入库(已审批 → 已完成)
136 miscReceiptMapper.updateById(new MesWmMiscReceiptDO() 125 miscReceiptMapper.updateById(new MesWmMiscReceiptDO()
137 .setId(id).setStatus(MesWmMiscReceiptStatusEnum.FINISHED.getStatus())); 126 .setId(id).setStatus(MesWmMiscReceiptStatusEnum.FINISHED.getStatus()));
138 } 127 }
139 128
  129 + private void createTransactionList(MesWmMiscReceiptDO receipt) {
  130 + List<MesWmMiscReceiptLineDO> lines = miscReceiptLineMapper.selectListByReceiptId(receipt.getId());
  131 + wmTransactionService.createTransactionList(convertList(lines, line -> new MesWmTransactionSaveReqDTO()
  132 + .setType(MesWmTransactionTypeEnum.IN.getType()).setItemId(line.getItemId())
  133 + .setQuantity(line.getQuantity()) // 入库数量为正数
  134 + .setWarehouseId(line.getWarehouseId()).setLocationId(line.getLocationId()).setAreaId(line.getAreaId())
  135 + .setBizType(MesBizTypeConstants.WM_MISC_RECPT).setBizId(receipt.getId()).setBizCode(receipt.getCode()).setBizLineId(line.getId())));
  136 + }
  137 +
140 @Override 138 @Override
141 @Transactional(rollbackFor = Exception.class) 139 @Transactional(rollbackFor = Exception.class)
142 public void cancelMiscReceipt(Long id) { 140 public void cancelMiscReceipt(Long id) {
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/task/MesWmStockTakingTaskLineServiceImpl.java
@@ -69,7 +69,7 @@ public class MesWmStockTakingTaskLineServiceImpl implements MesWmStockTakingTask @@ -69,7 +69,7 @@ public class MesWmStockTakingTaskLineServiceImpl implements MesWmStockTakingTask
69 // 3. 批量生成明细行 69 // 3. 批量生成明细行
70 List<MesWmStockTakingTaskLineDO> lines = convertList(stocks, stock -> MesWmStockTakingTaskLineDO.builder() 70 List<MesWmStockTakingTaskLineDO> lines = convertList(stocks, stock -> MesWmStockTakingTaskLineDO.builder()
71 .taskId(task.getId()).materialStockId(stock.getId()).itemId(stock.getItemId()) 71 .taskId(task.getId()).materialStockId(stock.getId()).itemId(stock.getItemId())
72 - .batchId(stock.getBatchId()).quantity(stock.getQuantityOnhand()).takingQuantity(BigDecimal.ZERO) 72 + .batchId(stock.getBatchId()).quantity(stock.getQuantity()).takingQuantity(BigDecimal.ZERO)
73 .warehouseId(stock.getWarehouseId()).locationId(stock.getLocationId()).areaId(stock.getAreaId()) 73 .warehouseId(stock.getWarehouseId()).locationId(stock.getLocationId()).areaId(stock.getAreaId())
74 .status(MesWmStockTakingTaskLineStatusEnum.LOSS.getStatus()).build()); 74 .status(MesWmStockTakingTaskLineStatusEnum.LOSS.getStatus()).build());
75 stockTakingTaskLineMapper.insertBatch(lines); 75 stockTakingTaskLineMapper.insertBatch(lines);
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/task/MesWmStockTakingTaskServiceImpl.java
@@ -211,7 +211,7 @@ public class MesWmStockTakingTaskServiceImpl implements MesWmStockTakingTaskServ @@ -211,7 +211,7 @@ public class MesWmStockTakingTaskServiceImpl implements MesWmStockTakingTaskServ
211 private void updateMaterialStockFrozen(Long materialStockId, boolean frozen) { 211 private void updateMaterialStockFrozen(Long materialStockId, boolean frozen) {
212 MesWmMaterialStockFreezeReqVO reqVO = new MesWmMaterialStockFreezeReqVO(); 212 MesWmMaterialStockFreezeReqVO reqVO = new MesWmMaterialStockFreezeReqVO();
213 reqVO.setId(materialStockId); 213 reqVO.setId(materialStockId);
214 - reqVO.setFrozen(frozen); 214 + reqVO.setFrozenFlag(frozen);
215 materialStockService.updateMaterialStockFrozen(reqVO); 215 materialStockService.updateMaterialStockFrozen(reqVO);
216 } 216 }
217 217
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.transaction;
  2 +
  3 +import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
  4 +import jakarta.validation.Valid;
  5 +
  6 +import java.util.List;
  7 +
  8 +/**
  9 + * MES 库存事务流水 Service 接口
  10 + *
  11 + * 对齐 KTG WmTransactionServiceImpl.processTransaction 实现:
  12 + * 校验 → 库存台账更新 → 事务流水插入。
  13 + */
  14 +public interface MesWmTransactionService {
  15 +
  16 + /**
  17 + * 创建库存事务(含校验 + 库存更新 + 插入流水)
  18 + *
  19 + * @param reqDTO 事务数据
  20 + * @return 事务流水编号
  21 + */
  22 + Long createTransaction(@Valid MesWmTransactionSaveReqDTO reqDTO);
  23 +
  24 + /**
  25 + * 批量创建库存事务
  26 + *
  27 + * @param reqDTOs 事务数据列表
  28 + */
  29 + void createTransactionList(List<MesWmTransactionSaveReqDTO> reqDTOs);
  30 +
  31 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.transaction;
  2 +
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.util.ObjUtil;
  5 +import cn.hutool.core.util.StrUtil;
  6 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transaction.MesWmTransactionDO;
  8 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.transaction.MesWmTransactionMapper;
  9 +import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
  10 +import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
  11 +import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
  12 +import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
  13 +import jakarta.annotation.Resource;
  14 +import org.springframework.stereotype.Service;
  15 +import org.springframework.transaction.annotation.Transactional;
  16 +import org.springframework.validation.annotation.Validated;
  17 +
  18 +import java.math.BigDecimal;
  19 +import java.time.LocalDateTime;
  20 +import java.util.List;
  21 +
  22 +/**
  23 + * MES 库存事务流水 Service 实现类
  24 + */
  25 +@Service
  26 +@Validated
  27 +public class MesWmTransactionServiceImpl implements MesWmTransactionService {
  28 +
  29 + @Resource
  30 + private MesWmTransactionMapper transactionMapper;
  31 +
  32 + @Resource
  33 + private MesWmMaterialStockService materialStockService;
  34 + @Resource
  35 + private MesWmBatchService batchService;
  36 +
  37 + @Override
  38 + @Transactional(rollbackFor = Exception.class)
  39 + public Long createTransaction(MesWmTransactionSaveReqDTO reqDTO) {
  40 + // 1.1 校验事务类型
  41 + MesWmTransactionTypeEnum typeEnum = MesWmTransactionTypeEnum.valueOf(reqDTO.getType());
  42 + Assert.notNull(typeEnum, "事务类型({}) 不存在", reqDTO.getType());
  43 + // 1.2 校验 quantity 正负号与事务方向一致(入库必须正数,出库必须负数)
  44 + boolean inbound = typeEnum.isInbound();
  45 + if (inbound) {
  46 + Assert.isTrue(reqDTO.getQuantity().compareTo(BigDecimal.ZERO) > 0,
  47 + "入库事务数量必须为正数,实际值: {}", reqDTO.getQuantity());
  48 + } else {
  49 + Assert.isTrue(reqDTO.getQuantity().compareTo(BigDecimal.ZERO) < 0,
  50 + "出库事务数量必须为负数,实际值: {}", reqDTO.getQuantity());
  51 + }
  52 + // 1.3 batchId / batchCode 互补
  53 + completeBatchInfo(reqDTO);
  54 +
  55 + // 2.1 获取或创建库存记录
  56 + Long materialStockId = materialStockService.getOrCreateMaterialStock(
  57 + reqDTO.getItemId(), reqDTO.getWarehouseId(), reqDTO.getLocationId(), reqDTO.getAreaId(),
  58 + reqDTO.getBatchId(), reqDTO.getVendorId(), reqDTO.getReceiptTime());
  59 + // 2.2 更新库存数量
  60 + boolean checkFlag = ObjUtil.defaultIfNull(reqDTO.getCheckFlag(), true);
  61 + materialStockService.updateMaterialStockQuantity(materialStockId, reqDTO.getQuantity(), checkFlag);
  62 +
  63 + // 3. 插入事务流水
  64 + MesWmTransactionDO transaction = MesWmTransactionDO.builder()
  65 + .type(reqDTO.getType()).quantity(reqDTO.getQuantity()).transactionTime(LocalDateTime.now())
  66 + .itemId(reqDTO.getItemId()).batchId(reqDTO.getBatchId()).batchCode(reqDTO.getBatchCode())
  67 + .warehouseId(reqDTO.getWarehouseId()).locationId(reqDTO.getLocationId()).areaId(reqDTO.getAreaId())
  68 + .bizType(reqDTO.getBizType()).bizId(reqDTO.getBizId()).bizCode(reqDTO.getBizCode()).bizLineId(reqDTO.getBizLineId())
  69 + .materialStockId(materialStockId).relatedTransactionId(reqDTO.getRelatedTransactionId())
  70 + .build();
  71 + transactionMapper.insert(transaction);
  72 + return transaction.getId();
  73 + }
  74 +
  75 + @Override
  76 + @Transactional(rollbackFor = Exception.class)
  77 + public void createTransactionList(List<MesWmTransactionSaveReqDTO> reqDTOs) {
  78 + reqDTOs.forEach(this::createTransaction);
  79 + }
  80 +
  81 + /**
  82 + * batchId / batchCode 互补:有 batchId 无 batchCode 时,查出 batchCode;反之亦然。
  83 + *
  84 + * @param reqDTO 事务请求 DTO
  85 + */
  86 + private void completeBatchInfo(MesWmTransactionSaveReqDTO reqDTO) {
  87 + if (reqDTO.getBatchId() != null && StrUtil.isNotEmpty(reqDTO.getBatchCode())) {
  88 + return;
  89 + }
  90 + // 情况一:有 batchId,补 batchCode
  91 + if (reqDTO.getBatchId() != null) {
  92 + MesWmBatchDO batch = batchService.getBatch(reqDTO.getBatchId());
  93 + if (batch != null) {
  94 + reqDTO.setBatchCode(batch.getCode());
  95 + }
  96 + return;
  97 + }
  98 + // 情况二:有 batchCode,补 batchId
  99 + if (StrUtil.isNotEmpty(reqDTO.getBatchCode())) {
  100 + MesWmBatchDO batch = batchService.getBatchByCode(reqDTO.getBatchCode());
  101 + if (batch != null) {
  102 + reqDTO.setBatchId(batch.getId());
  103 + }
  104 + }
  105 + }
  106 +
  107 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/dto/MesWmTransactionSaveReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.transaction.dto;
  2 +
  3 +import jakarta.validation.constraints.NotNull;
  4 +import lombok.Data;
  5 +import lombok.experimental.Accessors;
  6 +
  7 +import java.math.BigDecimal;
  8 +import java.time.LocalDateTime;
  9 +
  10 +/**
  11 + * MES 库存事务 创建 Request DTO
  12 + */
  13 +@Data
  14 +@Accessors(chain = true)
  15 +public class MesWmTransactionSaveReqDTO {
  16 +
  17 + // ===== 事务核心 =====
  18 +
  19 + /**
  20 + * 事务类型
  21 + *
  22 + * 枚举 {@link cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum}
  23 + */
  24 + @NotNull(message = "事务类型不能为空")
  25 + private Integer type;
  26 +
  27 + // ===== 业务来源 =====
  28 +
  29 + /**
  30 + * 业务类型
  31 + *
  32 + * 对应 {@link cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants}
  33 + */
  34 + @NotNull(message = "业务类型不能为空")
  35 + private Integer bizType;
  36 + /**
  37 + * 业务主单 ID
  38 + */
  39 + @NotNull(message = "业务主单 ID 不能为空")
  40 + private Long bizId;
  41 + /**
  42 + * 业务单号
  43 + */
  44 + @NotNull(message = "业务单号不能为空")
  45 + private String bizCode;
  46 + /**
  47 + * 业务行 ID
  48 + */
  49 + @NotNull(message = "业务行 ID 不能为空")
  50 + private Long bizLineId;
  51 +
  52 + // ===== 物料维度 =====
  53 +
  54 + /**
  55 + * 物料 ID
  56 + */
  57 + @NotNull(message = "物料 ID 不能为空")
  58 + private Long itemId;
  59 + /**
  60 + * 变动数量(入库为正数,出库为负数)
  61 + */
  62 + @NotNull(message = "变动数量不能为空")
  63 + private BigDecimal quantity;
  64 + /**
  65 + * 批次 ID
  66 + */
  67 + private Long batchId;
  68 + /**
  69 + * 批次号
  70 + */
  71 + private String batchCode;
  72 +
  73 + // ===== 库存位置 =====
  74 +
  75 + /**
  76 + * 仓库 ID
  77 + */
  78 + @NotNull(message = "仓库 ID 不能为空")
  79 + private Long warehouseId;
  80 + /**
  81 + * 库区 ID
  82 + */
  83 + @NotNull(message = "库区 ID 不能为空")
  84 + private Long locationId;
  85 + /**
  86 + * 库位 ID
  87 + */
  88 + private Long areaId;
  89 +
  90 + // ===== 台账补充字段(入库时用于初始化 MesWmMaterialStockDO) =====
  91 +
  92 + /**
  93 + * 供应商 ID(采购入库场景)
  94 + */
  95 + private Long vendorId;
  96 + /**
  97 + * 入库时间(为空默认当前时间)
  98 + *
  99 + * 对应 KTG 的 recptDate
  100 + */
  101 + private LocalDateTime receiptTime;
  102 +
  103 + // ===== 关联 =====
  104 +
  105 + /**
  106 + * 关联事务 ID(成对事务中,入库事务关联出库事务)
  107 + */
  108 + private Long relatedTransactionId;
  109 +
  110 + // ===== 可选控制(非存储字段) =====
  111 +
  112 + /**
  113 + * 是否校验库存充足(默认 true;线边库消耗等场景设 false 允许负库存)
  114 + */
  115 + private Boolean checkFlag;
  116 +
  117 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferServiceImpl.java
@@ -274,7 +274,7 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @@ -274,7 +274,7 @@ public class MesWmTransferServiceImpl implements MesWmTransferService {
274 } 274 }
275 MesWmMaterialStockFreezeReqVO freezeReqVO = new MesWmMaterialStockFreezeReqVO(); 275 MesWmMaterialStockFreezeReqVO freezeReqVO = new MesWmMaterialStockFreezeReqVO();
276 freezeReqVO.setId(line.getMaterialStockId()); 276 freezeReqVO.setId(line.getMaterialStockId());
277 - freezeReqVO.setFrozen(frozen); 277 + freezeReqVO.setFrozenFlag(frozen);
278 materialStockService.updateMaterialStockFrozen(freezeReqVO); 278 materialStockService.updateMaterialStockFrozen(freezeReqVO);
279 } 279 }
280 } 280 }