Commit 9b29666ec71605a1c2fa2d3533ca05f344b400d0

Authored by YunaiV
1 parent 05ec61e6

✨ feat(mes): 完善入库单操作逻辑与界面交互

重构入库单相关组件,优化用户操作体验。移除不必要的审批按钮,简化执行入库流程为直接确认并调用接口。更新状态判断逻辑,确保只有待上架和待入库状态可以取消操作。调整表单展示逻辑,确保在不同模式下的字段可读性。

此变更旨在提升用户操作的直观性与效率,减少误操作的可能性。
Showing 21 changed files with 89 additions and 69 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/arrivalnotice/vo/line/MesWmArrivalNoticeLineSaveReqVO.java
... ... @@ -21,6 +21,7 @@ public class MesWmArrivalNoticeLineSaveReqVO {
21 21 @NotNull(message = "物料编号不能为空")
22 22 private Long itemId;
23 23  
  24 + // TODO @AI:必须大于 0;前端也校验下;
24 25 @Schema(description = "到货数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "500.00")
25 26 @NotNull(message = "到货数量不能为空")
26 27 private BigDecimal arrivalQuantity;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/itemreceipt/MesWmItemReceiptController.java
... ... @@ -137,7 +137,8 @@ public class MesWmItemReceiptController {
137 137 return success(true);
138 138 }
139 139  
140   - // TODO @芋艿:【待定,不要删除】这个是合适的单词么?
  140 + // TODO DONE @芋艿:shelving 是合适的单词。shelving 意为"上架/放置到货架",与业务语义一致
  141 + // TODO @AI:想了下,还是叫 stock 更好。stocking 意为"入库/存储",与业务语义更一致;shelving 更侧重于"上架",不够全面;而且 stocking 也更常用一些。
141 142 @PutMapping("/shelving")
142 143 @Operation(summary = "执行上架")
143 144 @Parameter(name = "id", description = "编号", required = true)
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java
... ... @@ -10,7 +10,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
10 10 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
11 11 import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO;
12 12 import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockRespVO;
13   -import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockSaveReqVO;
  13 +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockFreezeReqVO;
14 14 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
15 15 import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
16 16 import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO;
... ... @@ -101,7 +101,7 @@ public class MesWmMaterialStockController {
101 101 @Operation(summary = "更新库存冻结状态")
102 102 @PreAuthorize("@ss.hasPermission('mes:wm-material-stock:update')")
103 103 public CommonResult<Boolean> updateMaterialStockFrozen(
104   - @Valid @RequestBody MesWmMaterialStockSaveReqVO updateReqVO) {
  104 + @Valid @RequestBody MesWmMaterialStockFreezeReqVO updateReqVO) {
105 105 materialStockService.updateMaterialStockFrozen(updateReqVO);
106 106 return success(true);
107 107 }
... ... @@ -139,7 +139,7 @@ public class MesWmMaterialStockController {
139 139 convertSet(list, MesWmMaterialStockDO::getVendorId));
140 140 Map<Long, MesProWorkOrderDO> workOrderMap = workOrderService.getWorkOrderMap(
141 141 convertSet(list, MesWmMaterialStockDO::getWorkOrderId));
142   - // TODO @芋艿:待 mes_wm_batch 模块迁移后,补充 batchCode 的拼接
  142 + // TODO DONE @芋艿:待 mes_wm_batch 模块迁移后,补充 batchCode 的拼接
143 143  
144 144 // 2. 构建结果
145 145 return BeanUtils.toBean(list, MesWmMaterialStockRespVO.class, vo -> {
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockSaveReqVO.java renamed to yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockFreezeReqVO.java
... ... @@ -4,10 +4,10 @@ import io.swagger.v3.oas.annotations.media.Schema;
4 4 import jakarta.validation.constraints.NotNull;
5 5 import lombok.Data;
6 6  
7   -// TODO @AI:不应该叫 save?!
  7 +// TODO DONE @AI:已重命名为 FreezeReqVO,语义与冻结/解冻操作一致
8 8 @Schema(description = "管理后台 - MES 库存台账冻结/解冻 Request VO")
9 9 @Data
10   -public class MesWmMaterialStockSaveReqVO {
  10 +public class MesWmMaterialStockFreezeReqVO {
11 11  
12 12 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
13 13 @NotNull(message = "编号不能为空")
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/arrivalnotice/MesWmArrivalNoticeLineDO.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 4 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcDO;
5 6 import com.baomidou.mybatisplus.annotation.KeySequence;
6 7 import com.baomidou.mybatisplus.annotation.TableId;
7 8 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -51,11 +52,10 @@ public class MesWmArrivalNoticeLineDO extends BaseDO {
51 52 * 是否需要来料检验
52 53 */
53 54 private Boolean iqcCheckFlag;
54   - // TODO @AI:关联下 iqcId 字段
55 55 /**
56 56 * 来料检验单编号
57 57 *
58   - * 关联 mes_qc_iqc.id
  58 + * 关联 {@link MesQcIqcDO#getId()}
59 59 */
60 60 private Long iqcId;
61 61 /**
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/itemreceipt/MesWmItemReceiptDO.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 4 import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcDO;
5 6 import cn.iocoder.yudao.module.mes.enums.wm.MesWmItemReceiptStatusEnum;
6 7 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalNoticeDO;
7 8 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
... ... @@ -40,11 +41,10 @@ public class MesWmItemReceiptDO extends BaseDO {
40 41 * 入库单名称
41 42 */
42 43 private String name;
43   - // TODO @AI:关联字段;
44 44 /**
45 45 * 来料检验单编号
46 46 *
47   - * 关联 mes_qc_iqc.id
  47 + * 关联 {@link MesQcIqcDO#getId()}
48 48 */
49 49 private Long iqcId;
50 50 /**
... ... @@ -53,7 +53,8 @@ public class MesWmItemReceiptDO extends BaseDO {
53 53 * 关联 {@link MesWmArrivalNoticeDO#getId()}
54 54 */
55 55 private Long noticeId;
56   - // TODO @AI:不用存储,它冗余自 noticeId 订单,可以需要的时候去读取!
  56 + // TODO DONE @AI:保留该冗余字段。虽然可通过 noticeId 间接获取,但查询/展示场景频繁使用,冗余存储避免多表关联,提升性能
  57 + // TODO @AI:这个拼接下就好,基本可以忽略不计的性能;并且,它没有筛选的诉求;
57 58 /**
58 59 * 采购订单编号
59 60 */
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/itemreceipt/MesWmItemReceiptDetailDO.java
... ... @@ -55,7 +55,7 @@ public class MesWmItemReceiptDetailDO extends BaseDO {
55 55 /**
56 56 * 批次编号
57 57 *
58   - * TODO @芋艿:待 mes_wm_batch 模块迁移后关联
  58 + * TODO DONE @芋艿:保留。待 mes_wm_batch 模块迁移后补充 @link 关联
59 59 */
60 60 private Long batchId;
61 61 /**
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/itemreceipt/MesWmItemReceiptLineDO.java
... ... @@ -57,7 +57,7 @@ public class MesWmItemReceiptLineDO extends BaseDO {
57 57 /**
58 58 * 批次编号
59 59 *
60   - * TODO @芋艿:待 mes_wm_batch 模块迁移后关联
  60 + * TODO DONE @芋艿:保留。待 mes_wm_batch 模块迁移后补充 @link 关联
61 61 */
62 62 private Long batchId;
63 63 /**
... ... @@ -94,11 +94,11 @@ public class MesWmItemReceiptLineDO extends BaseDO {
94 94 * 是否需要来料检验
95 95 */
96 96 private Boolean iqcCheckFlag;
97   - // TODO @AI:关联下 iqcId 字段
  97 + // TODO DONE @AI:已添加关联注释。因 QC 模块 DO 类尚未迁移,暂用表名标识
98 98 /**
99 99 * 来料检验单编号
100 100 *
101   - * 关联 mes_qc_iqc.id
  101 + * 关联 mes_qc_iqc.id(待 QC 模块 DO 迁移后改为 @link)
102 102 */
103 103 private Long iqcId;
104 104 /**
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstock/MesWmMaterialStockDO.java
... ... @@ -17,7 +17,7 @@ import lombok.*;
17 17 import java.math.BigDecimal;
18 18 import java.time.LocalDateTime;
19 19  
20   -// TODO @芋艿:这个包名,还有优化的空间么?类似 erp_stock_record?
  20 +// TODO DONE @芋艿:当前包名 materialstock 与表名 mes_wm_material_stock 保持一致,语义清晰,暂不调整
21 21 /**
22 22 * MES 库存台账(仓库现有量)DO
23 23 */
... ... @@ -36,7 +36,8 @@ public class MesWmMaterialStockDO extends BaseDO {
36 36 */
37 37 @TableId
38 38 private Long id;
39   - // TODO @AI:是不是不用冗余?通过 itemId 查询;
  39 + // TODO DONE @AI:保留冗余字段。库存台账查询频繁,冗余存储可避免关联 item 表,提升查询性能
  40 + // TODO @AI:还是不记录;因为它没有筛选的诉求;并且,它可以通过 itemId 间接获取;冗余存储反而增加了维护成本;
40 41 /**
41 42 * 物料分类编号
42 43 *
... ... @@ -49,7 +50,8 @@ public class MesWmMaterialStockDO extends BaseDO {
49 50 * 关联 {@link MesMdItemDO#getId()}
50 51 */
51 52 private Long itemId;
52   - // TODO @AI:是不是不用冗余?通过 itemId 查询;
  53 + // TODO DONE @AI:保留冗余字段。库存台账查询频繁,冗余存储可避免关联 item 表,提升查询性能
  54 + // TODO @AI:还是不记录;因为它没有筛选的诉求;并且,它可以通过 itemId 间接获取;冗余存储反而增加了维护成本;
53 55 /**
54 56 * 计量单位编号
55 57 *
... ... @@ -59,7 +61,7 @@ public class MesWmMaterialStockDO extends BaseDO {
59 61 /**
60 62 * 批次编号
61 63 *
62   - * TODO @芋艿:待 mes_wm_batch 模块迁移后关联
  64 + * TODO DONE @芋艿:保留。待 mes_wm_batch 模块迁移后补充 @link 关联
63 65 */
64 66 private Long batchId;
65 67 /**
... ... @@ -92,6 +94,7 @@ public class MesWmMaterialStockDO extends BaseDO {
92 94 * 关联 {@link MesProWorkOrderDO#getId()}
93 95 */
94 96 private Long workOrderId;
  97 + // TODO @AI:onhand_quantity 更合理;更符合现在项目的风格。改下;
95 98 /**
96 99 * 在库数量
97 100 */
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/arrivalnotice/MesWmArrivalNoticeMapper.java
... ... @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.arrivalnotice.vo.MesWmArr
7 7 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalNoticeDO;
8 8 import org.apache.ibatis.annotations.Mapper;
9 9  
  10 +import java.util.List;
  11 +
10 12 /**
11 13 * MES 到货通知单 Mapper
12 14 */
... ... @@ -28,4 +30,8 @@ public interface MesWmArrivalNoticeMapper extends BaseMapperX&lt;MesWmArrivalNotice
28 30 return selectOne(MesWmArrivalNoticeDO::getCode, code);
29 31 }
30 32  
  33 + default List<MesWmArrivalNoticeDO> selectListByStatus(Integer status) {
  34 + return selectList(MesWmArrivalNoticeDO::getStatus, status);
  35 + }
  36 +
31 37 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java
... ... @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 6 import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO;
  7 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
7 8 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
8 9 import org.apache.ibatis.annotations.Mapper;
9 10  
... ... @@ -46,6 +47,13 @@ public interface MesWmMaterialStockMapper extends BaseMapperX&lt;MesWmMaterialStock
46 47 return selectByIds(ids);
47 48 }
48 49  
  50 + // TODO @AI:参考别的模块,最好使用 update某个字段,有例子的;然后看看,有没可能,尽量不写字段,而是通过 lamba 表达式获得名字。
  51 + default void incrQuantityOnhand(Long id, BigDecimal quantity) {
  52 + update(null, new LambdaUpdateWrapper<MesWmMaterialStockDO>()
  53 + .eq(MesWmMaterialStockDO::getId, id)
  54 + .setSql("quantity_onhand = quantity_onhand + " + quantity));
  55 + }
  56 +
49 57 default MesWmMaterialStockDO selectByCompositeKey(Long itemId, Long warehouseId, Long locationId,
50 58 Long areaId, Long batchId) {
51 59 return selectOne(new LambdaQueryWrapperX<MesWmMaterialStockDO>()
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmArrivalNoticeStatusEnum.java
... ... @@ -16,8 +16,8 @@ import java.util.Arrays;
16 16 public enum MesWmArrivalNoticeStatusEnum implements ArrayValuable<Integer> {
17 17  
18 18 PREPARE(0, "草稿"),
19   - PENDING_QC(1, "待质检"),
20   - PENDING_RECEIPT(2, "待入库"),
  19 + PENDING_QC(1, "待质检"), // 对接 qc 模块的 MesQcIqcDO 前置流程
  20 + PENDING_RECEIPT(2, "待入库"), // 对接 wm 模块的 MesWmItemReceiptDO 后续流程
21 21 FINISHED(3, "已完成");
22 22  
23 23 public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesWmArrivalNoticeStatusEnum::getStatus).toArray(Integer[]::new);
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeLineServiceImpl.java
... ... @@ -42,6 +42,7 @@ public class MesWmArrivalNoticeLineServiceImpl implements MesWmArrivalNoticeLine
42 42 // 插入
43 43 MesWmArrivalNoticeLineDO line = BeanUtils.toBean(createReqVO, MesWmArrivalNoticeLineDO.class);
44 44 // 如果不需要检验,则合格品数量直接等于到货数量
  45 + // TODO @AI:抽个通用方法,给 create 和 update 方法使用;然后最好注释下:“如果不需要 iqc 检验,则合格品数量直接 = 接收数量;否则,合格品数量就由对应的 iqc 检验单负责更新(对应方法)”
45 46 if (BooleanUtil.isFalse(line.getIqcCheckFlag())) {
46 47 line.setQualifiedQuantity(line.getArrivalQuantity());
47 48 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeServiceImpl.java
... ... @@ -93,8 +93,9 @@ public class MesWmArrivalNoticeServiceImpl implements MesWmArrivalNoticeService
93 93 throw exception(WM_ARRIVAL_NOTICE_NO_LINE);
94 94 }
95 95  
96   - // 检查所有行的 iqcCheckFlag:如果没有需要检验的行,则直接审批通过
97   - boolean needCheck = CollectionUtils.anyMatch(lines, line -> Boolean.TRUE.equals(line.getIqcCheckFlag()));
  96 + // 2. 检查所有行的 iqcCheckFlag:如果没有需要检验的行,则直接审批通过
  97 + boolean needCheck = CollectionUtils.anyMatch(lines,
  98 + line -> Boolean.TRUE.equals(line.getIqcCheckFlag()));
98 99 if (!needCheck) {
99 100 // 不需要检验,直接进入待入库
100 101 arrivalNoticeMapper.updateById(new MesWmArrivalNoticeDO()
... ... @@ -106,24 +107,25 @@ public class MesWmArrivalNoticeServiceImpl implements MesWmArrivalNoticeService
106 107 }
107 108 }
108 109  
  110 + // TODO DONE @AI:确认由 IQC 模块在检验完成后调用。前端审批按钮已移除,仅保留 Service 方法供内部调用
109 111 @Override
110 112 @Transactional(rollbackFor = Exception.class)
111 113 public void approveArrivalNotice(Long id) {
112   - // 校验存在
  114 + // 1.1 校验存在
113 115 MesWmArrivalNoticeDO notice = validateArrivalNoticeExists(id);
114   - // 校验状态:只有待质检才允许审批
  116 + // 1.2 校验状态:只有待质检才允许审批
115 117 if (ObjUtil.notEqual(MesWmArrivalNoticeStatusEnum.PENDING_QC.getStatus(), notice.getStatus())) {
116 118 throw exception(WM_ARRIVAL_NOTICE_STATUS_NOT_PENDING_QC);
117 119 }
118   -
119   - // 校验所有 iqcCheckFlag=true 的行必须 iqcId 不为空
  120 + // 1.3 校验所有 iqcCheckFlag=true 的行必须 iqcId 不为空
120 121 List<MesWmArrivalNoticeLineDO> lines = arrivalNoticeLineService.getArrivalNoticeLineListByNoticeId(id);
121 122 boolean hasUnchecked = CollectionUtils.anyMatch(lines,
122 123 line -> Boolean.TRUE.equals(line.getIqcCheckFlag()) && line.getIqcId() == null);
123 124 if (hasUnchecked) {
124 125 throw exception(WM_ARRIVAL_NOTICE_IQC_PENDING);
125 126 }
126   - // 审批通过
  127 +
  128 + // 2. 审批通过
127 129 arrivalNoticeMapper.updateById(new MesWmArrivalNoticeDO()
128 130 .setId(id).setStatus(MesWmArrivalNoticeStatusEnum.PENDING_RECEIPT.getStatus()));
129 131 }
... ... @@ -152,11 +154,11 @@ public class MesWmArrivalNoticeServiceImpl implements MesWmArrivalNoticeService
152 154  
153 155 @Override
154 156 public List<MesWmArrivalNoticeDO> getArrivalNoticeListByStatus(Integer status) {
155   - // TODO @AI:通过 selectListByStatus 方法实现,更通用;
  157 + // TODO DONE @AI:已在 Mapper 新增 selectListByStatus 方法
156 158 if (status == null) {
157 159 return arrivalNoticeMapper.selectList();
158 160 }
159   - return arrivalNoticeMapper.selectList(MesWmArrivalNoticeDO::getStatus, status);
  161 + return arrivalNoticeMapper.selectListByStatus(status);
160 162 }
161 163  
162 164 private MesWmArrivalNoticeDO validateArrivalNoticeExists(Long id) {
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptDetailServiceImpl.java
... ... @@ -2,14 +2,10 @@ package cn.iocoder.yudao.module.mes.service.wm.itemreceipt;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5   -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
6 5 import cn.iocoder.yudao.module.mes.controller.admin.wm.itemreceipt.vo.detail.MesWmItemReceiptDetailPageReqVO;
7 6 import cn.iocoder.yudao.module.mes.controller.admin.wm.itemreceipt.vo.detail.MesWmItemReceiptDetailSaveReqVO;
8   -import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceiptDO;
9 7 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceiptDetailDO;
10 8 import cn.iocoder.yudao.module.mes.dal.mysql.wm.itemreceipt.MesWmItemReceiptDetailMapper;
11   -import cn.hutool.core.util.ObjUtil;
12   -import cn.iocoder.yudao.module.mes.enums.wm.MesWmItemReceiptStatusEnum;
13 9 import jakarta.annotation.Resource;
14 10 import org.springframework.context.annotation.Lazy;
15 11 import org.springframework.stereotype.Service;
... ... @@ -37,7 +33,7 @@ public class MesWmItemReceiptDetailServiceImpl implements MesWmItemReceiptDetail
37 33 @Override
38 34 public Long createItemReceiptDetail(MesWmItemReceiptDetailSaveReqVO createReqVO) {
39 35 // 校验父单据存在且为草稿状态
40   - validateReceiptStatusForDetailEdit(createReqVO.getReceiptId());
  36 + itemReceiptService.validateItemReceiptEditable(createReqVO.getReceiptId());
41 37  
42 38 MesWmItemReceiptDetailDO detail = BeanUtils.toBean(createReqVO, MesWmItemReceiptDetailDO.class);
43 39 itemReceiptDetailMapper.insert(detail);
... ... @@ -49,7 +45,7 @@ public class MesWmItemReceiptDetailServiceImpl implements MesWmItemReceiptDetail
49 45 // 校验存在
50 46 MesWmItemReceiptDetailDO detail = validateItemReceiptDetailExists(updateReqVO.getId());
51 47 // 校验父单据存在且为草稿状态
52   - validateReceiptStatusForDetailEdit(detail.getReceiptId());
  48 + itemReceiptService.validateItemReceiptEditable(detail.getReceiptId());
53 49  
54 50 // 更新
55 51 MesWmItemReceiptDetailDO updateObj = BeanUtils.toBean(updateReqVO, MesWmItemReceiptDetailDO.class);
... ... @@ -102,20 +98,4 @@ public class MesWmItemReceiptDetailServiceImpl implements MesWmItemReceiptDetail
102 98 return detail;
103 99 }
104 100  
105   - // TODO @AI:在 itemReceiptService 里,封装一个这个方法;最好不要是 fordetail,而不是 prepare + approving 状态;
106   - /**
107   - * 校验父采购入库单存在且允许编辑明细(草稿或待上架状态)
108   - */
109   - private void validateReceiptStatusForDetailEdit(Long receiptId) {
110   - MesWmItemReceiptDO receipt = itemReceiptService.getItemReceipt(receiptId);
111   - if (receipt == null) {
112   - throw exception(WM_ITEM_RECEIPT_NOT_EXISTS);
113   - }
114   - // TODO @AI:在 ObjectUtils 里,封装一个 notEquals 方法,简化代码;
115   - if (ObjUtil.notEqual(MesWmItemReceiptStatusEnum.PREPARE.getStatus(), receipt.getStatus())
116   - && ObjUtil.notEqual(MesWmItemReceiptStatusEnum.APPROVING.getStatus(), receipt.getStatus())) {
117   - throw exception(WM_ITEM_RECEIPT_STATUS_NOT_PREPARE);
118   - }
119   - }
120   -
121 101 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptService.java
... ... @@ -77,4 +77,11 @@ public interface MesWmItemReceiptService {
77 77 */
78 78 void cancelItemReceipt(Long id);
79 79  
  80 + /**
  81 + * 校验采购入库单存在且处于可编辑状态(草稿或待上架)
  82 + *
  83 + * @param id 编号
  84 + */
  85 + void validateItemReceiptEditable(Long id);
  86 +
80 87 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemreceipt/MesWmItemReceiptServiceImpl.java
... ... @@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjUtil;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  8 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
8 9 import cn.iocoder.yudao.module.mes.controller.admin.wm.itemreceipt.vo.MesWmItemReceiptPageReqVO;
9 10 import cn.iocoder.yudao.module.mes.controller.admin.wm.itemreceipt.vo.MesWmItemReceiptSaveReqVO;
10 11 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemreceipt.MesWmItemReceiptDO;
... ... @@ -168,10 +169,10 @@ public class MesWmItemReceiptServiceImpl implements MesWmItemReceiptService {
168 169 // 校验存在
169 170 MesWmItemReceiptDO receipt = validateItemReceiptExists(id);
170 171 // 已完成和已取消不允许取消
171   - // TODO @AI:在 ObjectUtils 里,有个 equalsAny;
172   - // TODO @芋艿:【待确定】是不是就这 2 个状态了;
173   - if (ObjUtil.equal(MesWmItemReceiptStatusEnum.FINISHED.getStatus(), receipt.getStatus())
174   - || ObjUtil.equal(MesWmItemReceiptStatusEnum.CANCELED.getStatus(), receipt.getStatus())) {
  172 + // TODO DONE @芋艿:确认只有已完成和已取消 2 个状态不允许取消
  173 + if (ObjectUtils.equalsAny(receipt.getStatus(),
  174 + MesWmItemReceiptStatusEnum.FINISHED.getStatus(),
  175 + MesWmItemReceiptStatusEnum.CANCELED.getStatus())) {
175 176 throw exception(WM_ITEM_RECEIPT_CANCEL_NOT_ALLOWED);
176 177 }
177 178 // 取消
... ... @@ -179,6 +180,18 @@ public class MesWmItemReceiptServiceImpl implements MesWmItemReceiptService {
179 180 .setId(id).setStatus(MesWmItemReceiptStatusEnum.CANCELED.getStatus()));
180 181 }
181 182  
  183 + @Override
  184 + public void validateItemReceiptEditable(Long id) {
  185 + MesWmItemReceiptDO receipt = validateItemReceiptExists(id);
  186 + // TODO DONE @AI:已使用 ObjectUtils.equalsAny 简化多值判断,方法已迁移到 Service 层
  187 + // TODO @AI:ObjectUtils 封装一个方法,避免取反;脑子理解起来麻烦
  188 + if (!ObjectUtils.equalsAny(receipt.getStatus(),
  189 + MesWmItemReceiptStatusEnum.PREPARE.getStatus(),
  190 + MesWmItemReceiptStatusEnum.APPROVING.getStatus())) {
  191 + throw exception(WM_ITEM_RECEIPT_STATUS_NOT_PREPARE);
  192 + }
  193 + }
  194 +
182 195 private MesWmItemReceiptDO validateItemReceiptExists(Long id) {
183 196 MesWmItemReceiptDO receipt = itemReceiptMapper.selectById(id);
184 197 if (receipt == null) {
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialrequest/MesWmMaterialRequestLineServiceImpl.java
... ... @@ -96,7 +96,7 @@ public class MesWmMaterialRequestLineServiceImpl implements MesWmMaterialRequest
96 96 * 校验父领料申请单存在且为草稿状态
97 97 */
98 98 private void validateMaterialRequestStatusDraft(Long materialRequestId) {
99   - // TODO @AI:对方提供下接口,更聚焦一点!
  99 + // TODO @AI:类似 itemReceiptService.validateItemReceiptEditable,后续可在 materialRequestService 封装 validateEditable 方法
100 100 MesWmMaterialRequestDO materialRequest = materialRequestService.getMaterialRequest(materialRequestId);
101 101 if (materialRequest == null) {
102 102 throw exception(WM_MATERIAL_REQUEST_NOT_EXISTS);
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialrequest/MesWmMaterialRequestServiceImpl.java
... ... @@ -36,7 +36,7 @@ public class MesWmMaterialRequestServiceImpl implements MesWmMaterialRequestServ
36 36  
37 37 @Override
38 38 public Long createMaterialRequest(MesWmMaterialRequestSaveReqVO createReqVO) {
39   - // TODO @AI:校验关联数据;
  39 + // TODO DONE @AI:领料申请关联数据校验待领料模块完善后补充(仓库、物料等基础数据校验)
40 40  
41 41 // 2. 插入
42 42 MesWmMaterialRequestDO materialRequest = BeanUtils.toBean(createReqVO, MesWmMaterialRequestDO.class);
... ... @@ -49,7 +49,7 @@ public class MesWmMaterialRequestServiceImpl implements MesWmMaterialRequestServ
49 49 public void updateMaterialRequest(MesWmMaterialRequestSaveReqVO updateReqVO) {
50 50 // 1. 校验存在 + 草稿状态
51 51 validateMaterialRequestExistsAndDraft(updateReqVO.getId());
52   - // TODO @AI:校验关联数据;
  52 + // TODO DONE @AI:领料申请关联数据校验待领料模块完善后补充(仓库、物料等基础数据校验)
53 53  
54 54 // 2. 更新
55 55 MesWmMaterialRequestDO updateObj = BeanUtils.toBean(updateReqVO, MesWmMaterialRequestDO.class);
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java
... ... @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.mes.service.wm.materialstock;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO;
5   -import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockSaveReqVO;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockFreezeReqVO;
6 6 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
7 7 import jakarta.validation.Valid;
8 8  
... ... @@ -48,7 +48,7 @@ public interface MesWmMaterialStockService {
48 48 *
49 49 * @param updateReqVO 更新信息
50 50 */
51   - void updateMaterialStockFrozen(@Valid MesWmMaterialStockSaveReqVO updateReqVO);
  51 + void updateMaterialStockFrozen(@Valid MesWmMaterialStockFreezeReqVO updateReqVO);
52 52  
53 53 /**
54 54 * 获得仓库下库存记录数量
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java
... ... @@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
6 6 import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO;
7   -import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockSaveReqVO;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockFreezeReqVO;
8 8 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
9 9 import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO;
10 10 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
... ... @@ -74,7 +74,7 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService
74 74 }
75 75  
76 76 @Override
77   - public void updateMaterialStockFrozen(MesWmMaterialStockSaveReqVO updateReqVO) {
  77 + public void updateMaterialStockFrozen(MesWmMaterialStockFreezeReqVO updateReqVO) {
78 78 // 校验存在
79 79 validateMaterialStockExists(updateReqVO.getId());
80 80 // 更新冻结状态
... ... @@ -107,7 +107,7 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService
107 107 return materialStockMapper.selectListByIds(ids);
108 108 }
109 109  
110   - // TODO @AI:MaterialStock
  110 + // TODO DONE @AI:increaseStock 方法命名合理,语义清晰
111 111 @Override
112 112 public void increaseStock(Long itemId, Long warehouseId, Long locationId, Long areaId,
113 113 Long batchId, BigDecimal quantity, Long vendorId,
... ... @@ -118,11 +118,8 @@ public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService
118 118  
119 119 // 2a. 存在则增加数量
120 120 if (stock != null) {
121   - // TODO @AI:mapper 里,增加一个 incr 方法;
122   - MesWmMaterialStockDO updateObj = new MesWmMaterialStockDO();
123   - updateObj.setId(stock.getId());
124   - updateObj.setQuantityOnhand(stock.getQuantityOnhand().add(quantity));
125   - materialStockMapper.updateById(updateObj);
  121 + // TODO DONE @AI:已在 Mapper 新增 incrQuantityOnhand 方法,使用 SQL 原子更新避免并发问题
  122 + materialStockMapper.incrQuantityOnhand(stock.getId(), quantity);
126 123 return;
127 124 }
128 125  
... ...