Commit 7d2bf8e36bc41427c5e0156a5cf684f72310b8e9
1 parent
ebad1419
feat(mes): IQC 与到货通知单集成重构
1. 新增 MesBizTypeConstants 集中管理业务类型常量 2. IQC sourceDocType 从 String 改 Integer,删除冗余 sourceDocCode 3. IQC checkQuantity/qualifiedQuantity/unqualifiedQuantity 从 Integer 改 BigDecimal 4. IQC 完成后回写逻辑提取为 writeBackSourceDoc(),按 sourceDocType 分发 5. IQC 完成回调从 arrivalNoticeLineService 上移至 arrivalNoticeService.approveArrivalNoticeWhenIqcComplete() 6. 到货通知单行 updateByIqcComplete() 简化为纯更新 + 校验存在 7. 到货通知单新增 approveArrivalNoticeWhenIqcComplete(),含状态校验 + 全行检验完成判断 8. 删除到货通知单 PUT /approve 控制器端点 9. 提取 initQualifiedQuantityIfNoIqc() 复用创建/更新逻辑
Showing
14 changed files
with
201 additions
and
72 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/MesQcIqcRespVO.java
| ... | ... | @@ -33,11 +33,8 @@ public class MesQcIqcRespVO { |
| 33 | 33 | @Schema(description = "来源单据 ID", example = "200") |
| 34 | 34 | private Long sourceDocId; |
| 35 | 35 | |
| 36 | - @Schema(description = "来源单据类型", example = "ARRIVAL") | |
| 37 | - private String sourceDocType; | |
| 38 | - | |
| 39 | - @Schema(description = "来源单据编号", example = "ARV20250101001") | |
| 40 | - private String sourceDocCode; | |
| 36 | + @Schema(description = "来源单据类型", example = "100") | |
| 37 | + private Integer sourceDocType; | |
| 41 | 38 | |
| 42 | 39 | @Schema(description = "来源单据行 ID", example = "300") |
| 43 | 40 | private Long sourceLineId; |
| ... | ... | @@ -87,15 +84,15 @@ public class MesQcIqcRespVO { |
| 87 | 84 | |
| 88 | 85 | @Schema(description = "本次检测数量", example = "10") |
| 89 | 86 | @ExcelProperty("检测数量") |
| 90 | - private Integer checkQuantity; | |
| 87 | + private BigDecimal checkQuantity; | |
| 91 | 88 | |
| 92 | 89 | @Schema(description = "合格品数量", example = "9") |
| 93 | 90 | @ExcelProperty("合格品数量") |
| 94 | - private Integer qualifiedQuantity; | |
| 91 | + private BigDecimal qualifiedQuantity; | |
| 95 | 92 | |
| 96 | 93 | @Schema(description = "不合格品数量", example = "1") |
| 97 | 94 | @ExcelProperty("不合格品数量") |
| 98 | - private Integer unqualifiedQuantity; | |
| 95 | + private BigDecimal unqualifiedQuantity; | |
| 99 | 96 | |
| 100 | 97 | // ========== 缺陷统计 ========== |
| 101 | 98 | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/MesQcIqcSaveReqVO.java
| ... | ... | @@ -32,11 +32,8 @@ public class MesQcIqcSaveReqVO { |
| 32 | 32 | @Schema(description = "来源单据 ID", example = "200") |
| 33 | 33 | private Long sourceDocId; |
| 34 | 34 | |
| 35 | - @Schema(description = "来源单据类型", example = "ARRIVAL") | |
| 36 | - private String sourceDocType; | |
| 37 | - | |
| 38 | - @Schema(description = "来源单据编号", example = "ARV20250101001") | |
| 39 | - private String sourceDocCode; | |
| 35 | + @Schema(description = "来源单据类型", example = "100") | |
| 36 | + private Integer sourceDocType; | |
| 40 | 37 | |
| 41 | 38 | @Schema(description = "来源单据行 ID", example = "300") |
| 42 | 39 | private Long sourceLineId; |
| ... | ... | @@ -69,13 +66,13 @@ public class MesQcIqcSaveReqVO { |
| 69 | 66 | private BigDecimal receivedQuantity; |
| 70 | 67 | |
| 71 | 68 | @Schema(description = "本次检测数量", example = "10") |
| 72 | - private Integer checkQuantity; | |
| 69 | + private BigDecimal checkQuantity; | |
| 73 | 70 | |
| 74 | 71 | @Schema(description = "合格品数量", example = "9") |
| 75 | - private Integer qualifiedQuantity; | |
| 72 | + private BigDecimal qualifiedQuantity; | |
| 76 | 73 | |
| 77 | 74 | @Schema(description = "不合格品数量", example = "1") |
| 78 | - private Integer unqualifiedQuantity; | |
| 75 | + private BigDecimal unqualifiedQuantity; | |
| 79 | 76 | |
| 80 | 77 | // ========== 检验 ========== |
| 81 | 78 | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/arrivalnotice/MesWmArrivalNoticeController.java
| ... | ... | @@ -112,15 +112,6 @@ public class MesWmArrivalNoticeController { |
| 112 | 112 | return success(true); |
| 113 | 113 | } |
| 114 | 114 | |
| 115 | - @PutMapping("/approve") | |
| 116 | - @Operation(summary = "审批到货通知单") | |
| 117 | - @Parameter(name = "id", description = "编号", required = true) | |
| 118 | - @PreAuthorize("@ss.hasPermission('mes:wm-arrival-notice:update')") | |
| 119 | - public CommonResult<Boolean> approveArrivalNotice(@RequestParam("id") Long id) { | |
| 120 | - arrivalNoticeService.approveArrivalNotice(id); | |
| 121 | - return success(true); | |
| 122 | - } | |
| 123 | - | |
| 124 | 115 | @GetMapping("/simple-list") |
| 125 | 116 | @Operation(summary = "获得到货通知单精简列表") |
| 126 | 117 | @Parameter(name = "status", description = "状态", example = "2") | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/lqc/MesQcIqcDO.java
| ... | ... | @@ -4,6 +4,9 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | 4 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| 5 | 5 | import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; |
| 6 | 6 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateDO; |
| 7 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalNoticeDO; | |
| 8 | +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalNoticeLineDO; | |
| 9 | +import cn.iocoder.yudao.module.mes.enums.qc.MesQcSourceDocTypeEnum; | |
| 7 | 10 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 8 | 11 | import com.baomidou.mybatisplus.annotation.TableId; |
| 9 | 12 | import com.baomidou.mybatisplus.annotation.TableName; |
| ... | ... | @@ -47,24 +50,26 @@ public class MesQcIqcDO extends BaseDO { |
| 47 | 50 | */ |
| 48 | 51 | private Long templateId; |
| 49 | 52 | |
| 50 | - // ========== 来源单据(TODO @芋艿:WM 模块迁移后接入) ========== | |
| 53 | + // ========== 来源单据 ========== | |
| 51 | 54 | |
| 52 | 55 | /** |
| 53 | - * 来源单据 ID | |
| 54 | - */ | |
| 55 | - private Long sourceDocId; | |
| 56 | - /** | |
| 57 | 56 | * 来源单据类型 |
| 58 | 57 | * |
| 59 | - * 字典 mes_qc_source_doc_type | |
| 58 | + * 枚举 {@link MesQcSourceDocTypeEnum} | |
| 60 | 59 | */ |
| 61 | - private String sourceDocType; | |
| 60 | + private Integer sourceDocType; | |
| 62 | 61 | /** |
| 63 | - * 来源单据编号 | |
| 62 | + * 来源单据 ID | |
| 63 | + * | |
| 64 | + * 关联:根据 {@link #sourceDocType} 不同: | |
| 65 | + * 1. {@link MesQcSourceDocTypeEnum#ARRIVAL_NOTICE} 时,关联 {@link MesWmArrivalNoticeDO#getId()} | |
| 64 | 66 | */ |
| 65 | - private String sourceDocCode; | |
| 67 | + private Long sourceDocId; | |
| 66 | 68 | /** |
| 67 | 69 | * 来源单据行 ID |
| 70 | + * | |
| 71 | + * 关联:根据 {@link #sourceDocType} 不同: | |
| 72 | + * 1. {@link MesQcSourceDocTypeEnum#ARRIVAL_NOTICE} 时,关联 {@link MesWmArrivalNoticeLineDO#getId()} | |
| 68 | 73 | */ |
| 69 | 74 | private Long sourceLineId; |
| 70 | 75 | |
| ... | ... | @@ -107,15 +112,15 @@ public class MesQcIqcDO extends BaseDO { |
| 107 | 112 | /** |
| 108 | 113 | * 本次检测数量 |
| 109 | 114 | */ |
| 110 | - private Integer checkQuantity; | |
| 115 | + private BigDecimal checkQuantity; | |
| 111 | 116 | /** |
| 112 | 117 | * 合格品数量 |
| 113 | 118 | */ |
| 114 | - private Integer qualifiedQuantity; | |
| 119 | + private BigDecimal qualifiedQuantity; | |
| 115 | 120 | /** |
| 116 | 121 | * 不合格品数量 |
| 117 | 122 | */ |
| 118 | - private Integer unqualifiedQuantity; | |
| 123 | + private BigDecimal unqualifiedQuantity; | |
| 119 | 124 | |
| 120 | 125 | // ========== 缺陷统计 ========== |
| 121 | 126 | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstock/MesWmMaterialStockDO.java
| ... | ... | @@ -36,8 +36,6 @@ public class MesWmMaterialStockDO extends BaseDO { |
| 36 | 36 | */ |
| 37 | 37 | @TableId |
| 38 | 38 | private Long id; |
| 39 | - // TODO DONE @AI:保留冗余字段。库存台账查询频繁,冗余存储可避免关联 item 表,提升查询性能 | |
| 40 | - // TODO @AI:还是不记录;因为它没有筛选的诉求;并且,它可以通过 itemId 间接获取;冗余存储反而增加了维护成本; | |
| 41 | 39 | /** |
| 42 | 40 | * 物料分类编号 |
| 43 | 41 | * |
| ... | ... | @@ -50,8 +48,6 @@ public class MesWmMaterialStockDO extends BaseDO { |
| 50 | 48 | * 关联 {@link MesMdItemDO#getId()} |
| 51 | 49 | */ |
| 52 | 50 | private Long itemId; |
| 53 | - // TODO DONE @AI:保留冗余字段。库存台账查询频繁,冗余存储可避免关联 item 表,提升查询性能 | |
| 54 | - // TODO @AI:还是不记录;因为它没有筛选的诉求;并且,它可以通过 itemId 间接获取;冗余存储反而增加了维护成本; | |
| 55 | 51 | /** |
| 56 | 52 | * 计量单位编号 |
| 57 | 53 | * |
| ... | ... | @@ -88,6 +84,7 @@ public class MesWmMaterialStockDO extends BaseDO { |
| 88 | 84 | * 关联 {@link MesMdVendorDO#getId()} |
| 89 | 85 | */ |
| 90 | 86 | private Long vendorId; |
| 87 | + // TODO @AI:这个字段,应该没有的。 | |
| 91 | 88 | /** |
| 92 | 89 | * 生产工单编号 |
| 93 | 90 | * | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/MesBizTypeConstants.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.enums; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * MES 业务类型常量 | |
| 5 | + * | |
| 6 | + * 集中管理业务类型枚举的编号,按业务域分段。 | |
| 7 | + * 各枚举类引用此处常量,避免硬编码数字。(也避免冲突!!!) | |
| 8 | + * | |
| 9 | + * @author 芋道源码 | |
| 10 | + */ | |
| 11 | +public final class MesBizTypeConstants { | |
| 12 | + | |
| 13 | + private MesBizTypeConstants() {} | |
| 14 | + | |
| 15 | + // ========== QC 质检模块 [1, 100) ========== | |
| 16 | + | |
| 17 | + public static final int QC_IQC = 1; // 来料检验:MesQcIqcDO | |
| 18 | + public static final int QC_IPQC = 2; // 过程检验:MesQcIpqcDO | |
| 19 | + public static final int QC_OQC = 3; // 出货检验:MesQcOqcDO | |
| 20 | + public static final int QC_RQC = 4; // 退货检验:MesQcRqcDO | |
| 21 | + | |
| 22 | + // ========== WM 仓库模块 [100, 200) ========== | |
| 23 | + | |
| 24 | + public static final int WM_ARRIVAL_NOTICE = 100; // 到货通知单:MesWmArrivalNoticeDO | |
| 25 | + // public static final int WM_OUTSOURCE_RECPT = 101; // TODO 外协入库单:未实现,占位 | |
| 26 | + | |
| 27 | + // ========== CAL 排班模块 [200, 300) ========== | |
| 28 | + | |
| 29 | + // TODO @芋艿【暂时忽略】:MesProWorkOrderTypeEnum | |
| 30 | + // TODO @芋艿【暂时忽略】:MesProWorkOrderSourceTypeEnum | |
| 31 | + | |
| 32 | + // ========== PRO 生产模块 [300, 400) ========== | |
| 33 | + | |
| 34 | + // ========== DV 设备模块 [400, 500) ========== | |
| 35 | + | |
| 36 | + // ========== TM 工装夹具模块 [500, 600) ========== | |
| 37 | + | |
| 38 | + // ========== MD 主数据模块 [600, 700) ========== | |
| 39 | + | |
| 40 | +} | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkorderSourceTypeEnum.java renamed to yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/pro/MesProWorkOrderSourceTypeEnum.java
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/MesQcSourceDocTypeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.mes.enums.qc; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.core.ArrayValuable; | |
| 4 | +import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; | |
| 5 | +import lombok.AllArgsConstructor; | |
| 6 | +import lombok.Getter; | |
| 7 | + | |
| 8 | +import java.util.Arrays; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * MES 质检来源单据类型枚举 | |
| 12 | + * | |
| 13 | + * @author 芋道源码 | |
| 14 | + */ | |
| 15 | +@Getter | |
| 16 | +@AllArgsConstructor | |
| 17 | +public enum MesQcSourceDocTypeEnum implements ArrayValuable<Integer> { | |
| 18 | + | |
| 19 | + ARRIVAL_NOTICE(MesBizTypeConstants.WM_ARRIVAL_NOTICE, "到货通知单"), | |
| 20 | + // OUTSOURCE_RECPT(MesBizTypeConstants.WM_OUTSOURCE_RECPT, "外协入库单"), // TODO 未实现,占位 | |
| 21 | + ; | |
| 22 | + | |
| 23 | + public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesQcSourceDocTypeEnum::getType).toArray(Integer[]::new); | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 类型值 | |
| 27 | + */ | |
| 28 | + private final Integer type; | |
| 29 | + /** | |
| 30 | + * 类型名 | |
| 31 | + */ | |
| 32 | + private final String name; | |
| 33 | + | |
| 34 | + @Override | |
| 35 | + public Integer[] array() { | |
| 36 | + return ARRAYS; | |
| 37 | + } | |
| 38 | + | |
| 39 | +} | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/qc/MesQcTypeEnum.java
| 1 | 1 | package cn.iocoder.yudao.module.mes.enums.qc; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.core.ArrayValuable; |
| 4 | +import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; | |
| 4 | 5 | import lombok.AllArgsConstructor; |
| 5 | 6 | import lombok.Getter; |
| 6 | 7 | |
| ... | ... | @@ -15,10 +16,10 @@ import java.util.Arrays; |
| 15 | 16 | @AllArgsConstructor |
| 16 | 17 | public enum MesQcTypeEnum implements ArrayValuable<Integer> { |
| 17 | 18 | |
| 18 | - IQC(1, "来料检验"), | |
| 19 | - IPQC(2, "过程检验"), | |
| 20 | - OQC(3, "出货检验"), | |
| 21 | - RQC(4, "退货检验"); | |
| 19 | + IQC(MesBizTypeConstants.QC_IQC, "来料检验"), | |
| 20 | + IPQC(MesBizTypeConstants.QC_IPQC, "过程检验"), | |
| 21 | + OQC(MesBizTypeConstants.QC_OQC, "出货检验"), | |
| 22 | + RQC(MesBizTypeConstants.QC_RQC, "退货检验"); | |
| 22 | 23 | |
| 23 | 24 | public static final Integer[] ARRAYS = Arrays.stream(values()).map(MesQcTypeEnum::getType).toArray(Integer[]::new); |
| 24 | 25 | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/lqc/MesQcIqcServiceImpl.java
| ... | ... | @@ -11,11 +11,13 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcDO; |
| 11 | 11 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateDO; |
| 12 | 12 | import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO; |
| 13 | 13 | import cn.iocoder.yudao.module.mes.dal.mysql.qc.lqc.MesQcIqcMapper; |
| 14 | +import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; | |
| 14 | 15 | import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum; |
| 15 | 16 | import cn.iocoder.yudao.module.mes.enums.qc.MesQcIqcStatusEnum; |
| 16 | 17 | import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum; |
| 17 | 18 | import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService; |
| 18 | 19 | import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateService; |
| 20 | +import cn.iocoder.yudao.module.mes.service.wm.arrivalnotice.MesWmArrivalNoticeService; | |
| 19 | 21 | import jakarta.annotation.Resource; |
| 20 | 22 | import org.springframework.stereotype.Service; |
| 21 | 23 | import org.springframework.transaction.annotation.Transactional; |
| ... | ... | @@ -48,6 +50,8 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { |
| 48 | 50 | private MesQcIqcLineService iqcLineService; |
| 49 | 51 | @Resource |
| 50 | 52 | private MesQcDefectRecordService defectRecordService; |
| 53 | + @Resource | |
| 54 | + private MesWmArrivalNoticeService arrivalNoticeService; | |
| 51 | 55 | |
| 52 | 56 | @Override |
| 53 | 57 | @Transactional(rollbackFor = Exception.class) |
| ... | ... | @@ -99,10 +103,10 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { |
| 99 | 103 | // 1.1 校验存在 + 草稿状态 |
| 100 | 104 | MesQcIqcDO iqc = validateIqcStatusPrepare(id); |
| 101 | 105 | // 1.2 校验合格品 + 不合格品 = 检测数量 |
| 102 | - if (iqc.getCheckQuantity() != null && iqc.getCheckQuantity() > 0) { | |
| 103 | - int total = (iqc.getQualifiedQuantity() != null ? iqc.getQualifiedQuantity() : 0) | |
| 104 | - + (iqc.getUnqualifiedQuantity() != null ? iqc.getUnqualifiedQuantity() : 0); | |
| 105 | - if (total != iqc.getCheckQuantity()) { | |
| 106 | + if (iqc.getCheckQuantity() != null && iqc.getCheckQuantity().compareTo(BigDecimal.ZERO) > 0) { | |
| 107 | + BigDecimal total = ObjUtil.defaultIfNull(iqc.getQualifiedQuantity(), BigDecimal.ZERO) | |
| 108 | + .add(ObjUtil.defaultIfNull(iqc.getUnqualifiedQuantity(), BigDecimal.ZERO)); | |
| 109 | + if (total.compareTo(iqc.getCheckQuantity()) != 0) { | |
| 106 | 110 | throw exception(QC_IQC_QUANTITY_MISMATCH); |
| 107 | 111 | } |
| 108 | 112 | } |
| ... | ... | @@ -112,7 +116,31 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { |
| 112 | 116 | .setId(id).setStatus(MesQcIqcStatusEnum.FINISHED.getType()); |
| 113 | 117 | iqcMapper.updateById(updateObj); |
| 114 | 118 | |
| 115 | - // TODO @芋艿:WM 模块迁移后,更新到货通知单行/外协入库单行的检验结果 | |
| 119 | + // 3. 回写来源单据 | |
| 120 | + writeBackSourceDoc(iqc); | |
| 121 | + } | |
| 122 | + | |
| 123 | + /** | |
| 124 | + * 回写来源单据(IQC 完成后) | |
| 125 | + * | |
| 126 | + * @param iqc 来料检验单 | |
| 127 | + */ | |
| 128 | + private void writeBackSourceDoc(MesQcIqcDO iqc) { | |
| 129 | + // 校验:sourceDocType 非空时,lineId 和 docId 必须非空,否则为脏数据 | |
| 130 | + if (iqc.getSourceDocType() == null) { | |
| 131 | + return; | |
| 132 | + } | |
| 133 | + if (iqc.getSourceLineId() == null || iqc.getSourceDocId() == null) { | |
| 134 | + throw new IllegalArgumentException( | |
| 135 | + "IQC 单[" + iqc.getId() + "] sourceDocType 非空但 sourceLineId 或 sourceDocId 为空"); | |
| 136 | + } | |
| 137 | + | |
| 138 | + // 根据不同的来源单据类型,回写不同的单据 | |
| 139 | + if (Objects.equals(iqc.getSourceDocType(), MesBizTypeConstants.WM_ARRIVAL_NOTICE)) { | |
| 140 | + arrivalNoticeService.approveArrivalNoticeWhenIqcComplete(iqc.getSourceDocId(), iqc.getSourceLineId(), | |
| 141 | + iqc.getId(), iqc.getQualifiedQuantity()); | |
| 142 | + } | |
| 143 | + // TODO 外协入库单:未实现,占位 | |
| 116 | 144 | } |
| 117 | 145 | |
| 118 | 146 | @Override |
| ... | ... | @@ -196,8 +224,8 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { |
| 196 | 224 | BigDecimal criticalRate = BigDecimal.ZERO; |
| 197 | 225 | BigDecimal majorRate = BigDecimal.ZERO; |
| 198 | 226 | BigDecimal minorRate = BigDecimal.ZERO; |
| 199 | - if (iqc.getCheckQuantity() != null && iqc.getCheckQuantity() > 0) { | |
| 200 | - BigDecimal checkQty = BigDecimal.valueOf(iqc.getCheckQuantity()); | |
| 227 | + if (iqc.getCheckQuantity() != null && iqc.getCheckQuantity().compareTo(BigDecimal.ZERO) > 0) { | |
| 228 | + BigDecimal checkQty = iqc.getCheckQuantity(); | |
| 201 | 229 | criticalRate = BigDecimal.valueOf(totalCritical).multiply(BigDecimal.valueOf(100)) |
| 202 | 230 | .divide(checkQty, 2, RoundingMode.HALF_UP); |
| 203 | 231 | majorRate = BigDecimal.valueOf(totalMajor).multiply(BigDecimal.valueOf(100)) | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeLineService.java
| ... | ... | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.arrivalnotice.vo.line.Mes |
| 6 | 6 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalNoticeLineDO; |
| 7 | 7 | import jakarta.validation.Valid; |
| 8 | 8 | |
| 9 | +import java.math.BigDecimal; | |
| 9 | 10 | import java.util.List; |
| 10 | 11 | |
| 11 | 12 | /** |
| ... | ... | @@ -66,4 +67,13 @@ public interface MesWmArrivalNoticeLineService { |
| 66 | 67 | */ |
| 67 | 68 | void deleteArrivalNoticeLineByNoticeId(Long noticeId); |
| 68 | 69 | |
| 70 | + /** | |
| 71 | + * IQC 检验完成后回写行数据 | |
| 72 | + * | |
| 73 | + * @param lineId 行编号 | |
| 74 | + * @param iqcId IQC 检验单编号 | |
| 75 | + * @param qualifiedQuantity 合格数量 | |
| 76 | + */ | |
| 77 | + void updateByIqcComplete(Long lineId, Long iqcId, BigDecimal qualifiedQuantity); | |
| 78 | + | |
| 69 | 79 | } | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeLineServiceImpl.java
| ... | ... | @@ -15,6 +15,7 @@ import org.springframework.context.annotation.Lazy; |
| 15 | 15 | import org.springframework.stereotype.Service; |
| 16 | 16 | import org.springframework.validation.annotation.Validated; |
| 17 | 17 | |
| 18 | +import java.math.BigDecimal; | |
| 18 | 19 | import java.util.List; |
| 19 | 20 | |
| 20 | 21 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| ... | ... | @@ -41,11 +42,7 @@ public class MesWmArrivalNoticeLineServiceImpl implements MesWmArrivalNoticeLine |
| 41 | 42 | |
| 42 | 43 | // 插入 |
| 43 | 44 | MesWmArrivalNoticeLineDO line = BeanUtils.toBean(createReqVO, MesWmArrivalNoticeLineDO.class); |
| 44 | - // 如果不需要检验,则合格品数量直接等于到货数量 | |
| 45 | - // TODO @AI:抽个通用方法,给 create 和 update 方法使用;然后最好注释下:“如果不需要 iqc 检验,则合格品数量直接 = 接收数量;否则,合格品数量就由对应的 iqc 检验单负责更新(对应方法)” | |
| 46 | - if (BooleanUtil.isFalse(line.getIqcCheckFlag())) { | |
| 47 | - line.setQualifiedQuantity(line.getArrivalQuantity()); | |
| 48 | - } | |
| 45 | + initQualifiedQuantityIfNoIqc(line); | |
| 49 | 46 | arrivalNoticeLineMapper.insert(line); |
| 50 | 47 | return line.getId(); |
| 51 | 48 | } |
| ... | ... | @@ -59,13 +56,21 @@ public class MesWmArrivalNoticeLineServiceImpl implements MesWmArrivalNoticeLine |
| 59 | 56 | |
| 60 | 57 | // 更新 |
| 61 | 58 | MesWmArrivalNoticeLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmArrivalNoticeLineDO.class); |
| 62 | - // 如果不需要检验,则合格品数量直接等于到货数量 | |
| 63 | - if (BooleanUtil.isFalse(updateObj.getIqcCheckFlag())) { | |
| 64 | - updateObj.setQualifiedQuantity(updateObj.getArrivalQuantity()); | |
| 65 | - } | |
| 59 | + initQualifiedQuantityIfNoIqc(updateObj); | |
| 66 | 60 | arrivalNoticeLineMapper.updateById(updateObj); |
| 67 | 61 | } |
| 68 | 62 | |
| 63 | + /** | |
| 64 | + * 初始化合格品数量: | |
| 65 | + * 1. 如果不需要 IQC 检验,则合格品数量直接 = 接收数量; | |
| 66 | + * 2. 否则,合格品数量由对应的 IQC 检验单负责更新(见 {@link #updateByIqcComplete}) | |
| 67 | + */ | |
| 68 | + private void initQualifiedQuantityIfNoIqc(MesWmArrivalNoticeLineDO line) { | |
| 69 | + if (BooleanUtil.isFalse(line.getIqcCheckFlag())) { | |
| 70 | + line.setQualifiedQuantity(line.getArrivalQuantity()); | |
| 71 | + } | |
| 72 | + } | |
| 73 | + | |
| 69 | 74 | @Override |
| 70 | 75 | public void deleteArrivalNoticeLine(Long id) { |
| 71 | 76 | // 校验存在 |
| ... | ... | @@ -94,6 +99,15 @@ public class MesWmArrivalNoticeLineServiceImpl implements MesWmArrivalNoticeLine |
| 94 | 99 | arrivalNoticeLineMapper.deleteByNoticeId(noticeId); |
| 95 | 100 | } |
| 96 | 101 | |
| 102 | + @Override | |
| 103 | + public void updateByIqcComplete(Long lineId, Long iqcId, BigDecimal qualifiedQuantity) { | |
| 104 | + // 校验行存在 | |
| 105 | + validateArrivalNoticeLineExists(lineId); | |
| 106 | + // 更新 | |
| 107 | + arrivalNoticeLineMapper.updateById(new MesWmArrivalNoticeLineDO() | |
| 108 | + .setId(lineId).setIqcId(iqcId).setQualifiedQuantity(qualifiedQuantity)); | |
| 109 | + } | |
| 110 | + | |
| 97 | 111 | private MesWmArrivalNoticeLineDO validateArrivalNoticeLineExists(Long id) { |
| 98 | 112 | MesWmArrivalNoticeLineDO line = arrivalNoticeLineMapper.selectById(id); |
| 99 | 113 | if (line == null) { | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeService.java
| ... | ... | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.arrivalnotice.vo.MesWmArr |
| 6 | 6 | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalNoticeDO; |
| 7 | 7 | import jakarta.validation.Valid; |
| 8 | 8 | |
| 9 | +import java.math.BigDecimal; | |
| 9 | 10 | import java.util.Collection; |
| 10 | 11 | import java.util.List; |
| 11 | 12 | import java.util.Map; |
| ... | ... | @@ -63,11 +64,14 @@ public interface MesWmArrivalNoticeService { |
| 63 | 64 | void submitArrivalNotice(Long id); |
| 64 | 65 | |
| 65 | 66 | /** |
| 66 | - * 审批到货通知单(待质检 → 待入库) | |
| 67 | + * IQC 检验完成后回写到货通知单(更新行 + 尝试推进主表状态) | |
| 67 | 68 | * |
| 68 | - * @param id 编号 | |
| 69 | + * @param id 到货通知单编号 | |
| 70 | + * @param lineId 到货通知单行编号 | |
| 71 | + * @param iqcId IQC 检验单编号 | |
| 72 | + * @param qualifiedQuantity 合格数量 | |
| 69 | 73 | */ |
| 70 | - void approveArrivalNotice(Long id); | |
| 74 | + void approveArrivalNoticeWhenIqcComplete(Long id, Long lineId, Long iqcId, BigDecimal qualifiedQuantity); | |
| 71 | 75 | |
| 72 | 76 | /** |
| 73 | 77 | * 完成到货通知单(待入库 → 已完成),内部调用 | ... | ... |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeServiceImpl.java
| ... | ... | @@ -12,10 +12,12 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalN |
| 12 | 12 | import cn.iocoder.yudao.module.mes.dal.mysql.wm.arrivalnotice.MesWmArrivalNoticeMapper; |
| 13 | 13 | import cn.iocoder.yudao.module.mes.enums.wm.MesWmArrivalNoticeStatusEnum; |
| 14 | 14 | import jakarta.annotation.Resource; |
| 15 | +import lombok.extern.slf4j.Slf4j; | |
| 15 | 16 | import org.springframework.stereotype.Service; |
| 16 | 17 | import org.springframework.transaction.annotation.Transactional; |
| 17 | 18 | import org.springframework.validation.annotation.Validated; |
| 18 | 19 | |
| 20 | +import java.math.BigDecimal; | |
| 19 | 21 | import java.util.Collection; |
| 20 | 22 | import java.util.Collections; |
| 21 | 23 | import java.util.List; |
| ... | ... | @@ -28,6 +30,7 @@ import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| 28 | 30 | */ |
| 29 | 31 | @Service |
| 30 | 32 | @Validated |
| 33 | +@Slf4j | |
| 31 | 34 | public class MesWmArrivalNoticeServiceImpl implements MesWmArrivalNoticeService { |
| 32 | 35 | |
| 33 | 36 | @Resource |
| ... | ... | @@ -107,25 +110,28 @@ public class MesWmArrivalNoticeServiceImpl implements MesWmArrivalNoticeService |
| 107 | 110 | } |
| 108 | 111 | } |
| 109 | 112 | |
| 110 | - // TODO DONE @AI:确认由 IQC 模块在检验完成后调用。前端审批按钮已移除,仅保留 Service 方法供内部调用 | |
| 111 | 113 | @Override |
| 112 | 114 | @Transactional(rollbackFor = Exception.class) |
| 113 | - public void approveArrivalNotice(Long id) { | |
| 114 | - // 1.1 校验存在 | |
| 115 | + public void approveArrivalNoticeWhenIqcComplete(Long id, Long lineId, Long iqcId, BigDecimal qualifiedQuantity) { | |
| 116 | + // 1.1 校验到货通知单存在 | |
| 115 | 117 | MesWmArrivalNoticeDO notice = validateArrivalNoticeExists(id); |
| 116 | - // 1.2 校验状态:只有待质检才允许审批 | |
| 118 | + // 1.2 校验状态为待质检 | |
| 117 | 119 | if (ObjUtil.notEqual(MesWmArrivalNoticeStatusEnum.PENDING_QC.getStatus(), notice.getStatus())) { |
| 118 | 120 | throw exception(WM_ARRIVAL_NOTICE_STATUS_NOT_PENDING_QC); |
| 119 | 121 | } |
| 120 | - // 1.3 校验所有 iqcCheckFlag=true 的行必须 iqcId 不为空 | |
| 122 | + | |
| 123 | + // 2. 更新到货通知单行:绑定 iqcId + 合格数量 | |
| 124 | + arrivalNoticeLineService.updateByIqcComplete(lineId, iqcId, qualifiedQuantity); | |
| 125 | + | |
| 126 | + // 3.1 判断是否所有需检行都已完成 | |
| 121 | 127 | List<MesWmArrivalNoticeLineDO> lines = arrivalNoticeLineService.getArrivalNoticeLineListByNoticeId(id); |
| 122 | 128 | boolean hasUnchecked = CollectionUtils.anyMatch(lines, |
| 123 | 129 | line -> Boolean.TRUE.equals(line.getIqcCheckFlag()) && line.getIqcId() == null); |
| 124 | 130 | if (hasUnchecked) { |
| 125 | - throw exception(WM_ARRIVAL_NOTICE_IQC_PENDING); | |
| 131 | + log.info("[updateWhenIqcComplete][到货通知单({}) 还有未完成检验的行,暂不更新状态]", id); | |
| 132 | + return; | |
| 126 | 133 | } |
| 127 | - | |
| 128 | - // 2. 审批通过 | |
| 134 | + // 3.2 所有行检验完成,更新主表状态 PENDING_QC → PENDING_RECEIPT | |
| 129 | 135 | arrivalNoticeMapper.updateById(new MesWmArrivalNoticeDO() |
| 130 | 136 | .setId(id).setStatus(MesWmArrivalNoticeStatusEnum.PENDING_RECEIPT.getStatus())); |
| 131 | 137 | } | ... | ... |