From 6a2a05b32ef9d8a86c052b9664ec579952fd7f60 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 21 Mar 2026 14:03:48 +0800 Subject: [PATCH] ✨ feat(mes): 添加生产批号字段及相关逻辑 --- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackRespVO.java | 3 +++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSaveReqVO.java | 3 +++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/MesProTaskController.java | 4 ++-- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/GanttDataRespVO.java | 2 +- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/feedback/MesProFeedbackDO.java | 6 ++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/task/MesProTaskMapper.java | 13 +++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderMapper.java | 9 +++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/packages/MesWmPackageLineMapper.java | 2 +- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productproduce/MesWmProductProduceLineMapper.java | 4 ++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java | 1 - yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java | 21 +++++++++++++++++---- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskService.java | 14 ++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java | 11 +++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderService.java | 9 +++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderServiceImpl.java | 9 +++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java | 3 ++- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemconsume/MesWmItemConsumeServiceImpl.java | 5 ++--- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineService.java | 8 ++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineServiceImpl.java | 5 +++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceService.java | 10 ++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImpl.java | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ 22 files changed, 313 insertions(+), 51 deletions(-) diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackRespVO.java index 3920840..b86dc24 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackRespVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackRespVO.java @@ -110,6 +110,9 @@ public class MesProFeedbackRespVO { @Schema(description = "过期日期") private LocalDateTime expireDate; + @Schema(description = "生产批号", example = "LOT20260321") + private String lotNumber; + @Schema(description = "排产数量", example = "5000.00") @ExcelProperty("排产数量") private BigDecimal scheduledQuantity; diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSaveReqVO.java index 20bf5e6..e4c8a15 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSaveReqVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/feedback/vo/MesProFeedbackSaveReqVO.java @@ -49,6 +49,9 @@ public class MesProFeedbackSaveReqVO { @Schema(description = "过期日期") private LocalDateTime expireDate; + @Schema(description = "生产批号", example = "LOT20260321") + private String lotNumber; + @Schema(description = "排产数量", example = "5000.00") private BigDecimal scheduledQuantity; diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/MesProTaskController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/MesProTaskController.java index d5b68c5..08ded4d 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/MesProTaskController.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/MesProTaskController.java @@ -134,7 +134,7 @@ public class MesProTaskController { } @GetMapping("/gantt-list") - @Operation(summary = "获得甘特图任务列表", description = "对齐 KTG:后端组装工单=project + 任务=task 列表") + @Operation(summary = "获得甘特图任务列表", description = "后端组装工单=project + 任务=task 列表") @PreAuthorize("@ss.hasPermission('mes:pro-task:query')") public CommonResult> listGanttTaskList(@Valid MesProWorkOrderPageReqVO reqVO) { // 1.1 查询匹配的工单(不分页) @@ -251,7 +251,7 @@ public class MesProTaskController { } /** - * 拼接甘特图显示文本,对齐 KTG 格式:"[产品名][数量][单位]" + * 拼接甘特图显示文本,格式:"[产品名][数量][单位]" */ private String buildGanttText(MesMdItemDO item, BigDecimal quantity, Map unitMap) { diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/GanttDataRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/GanttDataRespVO.java index ca911e1..173c91a 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/GanttDataRespVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/task/vo/GanttDataRespVO.java @@ -8,7 +8,7 @@ import java.math.BigDecimal; import java.time.LocalDateTime; /** - * 甘特图数据项 VO(对齐 KTG GanttData) + * 甘特图数据项 VO */ @Schema(description = "管理后台 - 甘特图数据项 Response VO") @Data diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/feedback/MesProFeedbackDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/feedback/MesProFeedbackDO.java index f56e012..840d2da 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/feedback/MesProFeedbackDO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/pro/feedback/MesProFeedbackDO.java @@ -97,6 +97,12 @@ public class MesProFeedbackDO extends BaseDO { */ private LocalDateTime expireDate; /** + * 生产批号 + * + * TODO @芋艿:预留字段,当前未启用 + */ + private String lotNumber; + /** * 排产数量 */ private BigDecimal scheduledQuantity; diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/task/MesProTaskMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/task/MesProTaskMapper.java index aa959a2..ade7495 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/task/MesProTaskMapper.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/task/MesProTaskMapper.java @@ -5,8 +5,10 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskPageReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; +import java.math.BigDecimal; import java.util.List; /** @@ -42,4 +44,15 @@ public interface MesProTaskMapper extends BaseMapperX { .orderByDesc(MesProTaskDO::getId)); } + default void updateProducedQuantity(Long id, + BigDecimal incrProducedQuantity, + BigDecimal incrQualifyQuantity, + BigDecimal incrUnqualifyQuantity) { + update(null, new LambdaUpdateWrapper() + .eq(MesProTaskDO::getId, id) + .setSql("produced_quantity = IFNULL(produced_quantity, 0) + " + incrProducedQuantity) + .setSql("qualify_quantity = IFNULL(qualify_quantity, 0) + " + incrQualifyQuantity) + .setSql("unqualify_quantity = IFNULL(unqualify_quantity, 0) + " + incrUnqualifyQuantity)); + } + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderMapper.java index 6097d81..e84c367 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderMapper.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/workorder/MesProWorkorderMapper.java @@ -5,8 +5,11 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderPageReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; +import java.math.BigDecimal; + /** * MES 生产工单 Mapper * @@ -32,4 +35,10 @@ public interface MesProWorkOrderMapper extends BaseMapperX { return selectOne(MesProWorkOrderDO::getCode, code); } + default void updateProducedQuantity(Long id, BigDecimal incrQuantityProduced) { + update(null, new LambdaUpdateWrapper() + .eq(MesProWorkOrderDO::getId, id) + .setSql("quantity_produced = IFNULL(quantity_produced, 0) + " + incrQuantityProduced)); + } + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/packages/MesWmPackageLineMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/packages/MesWmPackageLineMapper.java index 071ec18..4f4c593 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/packages/MesWmPackageLineMapper.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/packages/MesWmPackageLineMapper.java @@ -17,7 +17,7 @@ public interface MesWmPackageLineMapper extends BaseMapperX default PageResult selectPage(MesWmPackageLinePageReqVO reqVO) { // TODO @芋艿:需确认“父箱详情 -> 装箱清单”是否需要汇总当前箱及其所有子孙箱的明细; - // ktg-mes 当前通过 SQL + ancestors 实现聚合查询,这里现在仅按 packageId 精确查询。 + // TODO @芋艿:对齐,当前通过 SQL + ancestors 实现聚合查询,这里现在仅按 packageId 精确查询。 return selectPage(reqVO, new LambdaQueryWrapperX() .eqIfPresent(MesWmPackageLineDO::getPackageId, reqVO.getPackageId()) .orderByDesc(MesWmPackageLineDO::getId)); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productproduce/MesWmProductProduceLineMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productproduce/MesWmProductProduceLineMapper.java index f064427..2941f98 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productproduce/MesWmProductProduceLineMapper.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/productproduce/MesWmProductProduceLineMapper.java @@ -31,4 +31,8 @@ public interface MesWmProductProduceLineMapper extends BaseMapperX selectListByFeedbackId(Long feedbackId) { + return selectList(MesWmProductProduceLineDO::getFeedbackId, feedbackId); + } + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java index dd3b9d8..3032cb6 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java @@ -47,7 +47,6 @@ public interface DictTypeConstants { String MES_PRO_FEEDBACK_CHANNEL = "mes_pro_feedback_channel"; // MES 生产报工途径 String MES_WM_ARRIVAL_NOTICE_STATUS = "mes_wm_arrival_notice_status"; // MES 到货通知单状态 String MES_WM_ITEM_RECEIPT_STATUS = "mes_wm_item_receipt_status"; // MES 采购入库单状态 - String MES_WM_PRODUCT_PRODUCE_STATUS = "mes_product_produce_status"; // MES 生产入库单状态 String MES_WM_QUALITY_STATUS = "mes_wm_quality_status"; // MES 质量状态(待检/合格/不合格) String MES_WM_RETURN_ISSUE_STATUS = "mes_return_issue_status"; // MES 生产退料单状态 String MES_WM_RETURN_ISSUE_TYPE = "mes_return_issue_type"; // MES 生产退料类型 diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java index 89fe35d..0837837 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackService.java @@ -66,11 +66,24 @@ public interface MesProFeedbackService { void rejectFeedback(Long id); /** - * 审批报工(审批中 -> 已完成 或 待检验) + * 审批通过报工单,执行生产入库流程 * - * @param id 编号 - * @param userId 当前操作用户编号 - * @return true=已完成, false=待检验 + *

整体流程如下: + *

    + *
  1. 校验报工单状态和数量
  2. + *
  3. 生成物料消耗单,扣减线边库物料
  4. + *
  5. 根据工序配置(关键工序 & 是否需要检验)分情况处理: + *
      + *
    • 关键工序 + 需要检验:生成产出单(质量状态=待检验),报工单状态 → 待检验,等待质检完成回调
    • + *
    • 关键工序 + 无需检验:生成产出单(按合格/不合格拆行),执行产品入库,更新任务/工单已生产数量,报工单状态 → 已完成
    • + *
    • 非关键工序:不生成产出单,不更新任务/工单数量,报工单状态 → 已完成
    • + *
    + *
  6. + *
+ * + * @param id 报工单编号 + * @param userId 当前操作用户编号(审核人) + * @return true=已完成, false=待检验(需等质检回调) */ boolean approveFeedback(Long id, Long userId); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java index 8828e2b..a566be2 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java @@ -8,15 +8,20 @@ import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedba import cn.iocoder.yudao.module.mes.controller.admin.pro.feedback.vo.MesProFeedbackSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.itemconsume.MesWmItemConsumeDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceLineDO; import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper; import cn.iocoder.yudao.module.mes.enums.pro.MesProFeedbackStatusEnum; +import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum; import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService; import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProcessService; import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService; import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; import cn.iocoder.yudao.module.mes.service.wm.itemconsume.MesWmItemConsumeService; +import cn.iocoder.yudao.module.mes.service.wm.productproduce.MesWmProductProduceLineService; +import cn.iocoder.yudao.module.mes.service.wm.productproduce.MesWmProductProduceService; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -25,6 +30,7 @@ import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; import java.time.LocalDateTime; +import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @@ -44,19 +50,19 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService { @Resource private MesProWorkOrderService workOrderService; - @Resource private MesProRouteProcessService routeProcessService; - @Resource private MesMdWorkstationService workstationService; - @Resource @Lazy // 避免循环依赖 private MesProTaskService taskService; - @Resource private MesWmItemConsumeService itemConsumeService; + @Resource + private MesWmProductProduceService productProduceService; + @Resource + private MesWmProductProduceLineService produceLineService; @Override public Long createFeedback(MesProFeedbackSaveReqVO createReqVO) { @@ -143,39 +149,75 @@ public class MesProFeedbackServiceImpl implements MesProFeedbackService { throw exception(PRO_FEEDBACK_UNCHECK_QUANTITY_EXISTS, feedback.getUncheckQuantity()); } - // 2. 物料消耗:根据工序 BOM 生成消耗记录 + // 2. 物料消耗:根据工序 BOM 生成消耗记录并执行扣减 MesWmItemConsumeDO itemConsume = itemConsumeService.generateItemConsume(feedback); if (itemConsume != null) { itemConsumeService.finishItemConsume(itemConsume.getId()); } - // 3. 查询工序的 keyFlag + checkFlag + // 3. 查询工序的关键工序标识 + 检验标识 MesProRouteProcessDO routeProcess = routeProcessService.getRouteProcessByRouteIdAndProcessId( feedback.getRouteId(), feedback.getProcessId()); boolean keyFlag = routeProcess != null && Boolean.TRUE.equals(routeProcess.getKeyFlag()); boolean checkFlag = routeProcess != null && Boolean.TRUE.equals(routeProcess.getCheckFlag()); - // 4. 情况一:关键工序 + 需要检验 → 待检验状态(等质检完成后入库) - if (keyFlag && checkFlag) { - feedbackMapper.updateById(new MesProFeedbackDO().setId(id) - .setStatus(MesProFeedbackStatusEnum.UNCHECK.getStatus()) - .setApproveUserId(userId)); - // TODO @芋艿:WM 产品产出(WmProductProduceService)待补充 generateProductProduce(质量状态=待检验) - return false; - } - - // 4.1 情况二:关键工序 + 无需检验 → 直接完成 + // 4. 关键工序:生成产出单,并根据是否需要检验决定入库方式 if (keyFlag) { - // TODO @芋艿:WM 产品产出(WmProductProduceService)待补充 generateProductProduce + executeProductProduce - // TODO @芋艿:updateProTaskAndWorkorder 待补充级联更新任务/工单的已生产数量 + // 4.1 需要检验:生成产出单(质量状态=待检验),更新报工状态为待检验,等质检完成回调后再入库 + if (checkFlag) { + // TODO @AI(from codex):当前这里只生成待检产出并把报工置为待检验;后续还需要在 IPQC 完成时继续拆分产出行、完成产出入库、 + // 回写任务/工单进度,并把报工状态改为已完成。 + productProduceService.generateProductProduce(feedback, true); + feedbackMapper.updateById(new MesProFeedbackDO().setId(id) + .setStatus(MesProFeedbackStatusEnum.UNCHECK.getStatus())); + return false; + } + // 4.2 无需检验:生成产出单(按合格/不合格拆行),直接完成入库,并更新任务/工单的已生产数量 + MesWmProductProduceDO produce = productProduceService.generateProductProduce(feedback, false); + productProduceService.finishProductProduce(produce.getId()); + updateTaskAndWorkOrderByFeedback(feedback); } - // 4.2 更新状态为已完成 + 审核人 + + // 5. 非关键工序:不生成产出单,不更新任务/工单数量,直接完成 feedbackMapper.updateById(new MesProFeedbackDO().setId(id) .setStatus(MesProFeedbackStatusEnum.FINISHED.getStatus()) .setApproveUserId(userId)); return true; // 已完成 } + /** + * 根据当前报工单的最终结果,更新生产任务和生产工单的进度 + * + *
    + *
  • 使用报工数量(feedbackQuantity),累加任务和工单的已生产数量
  • + *
  • 使用产出单行按 qualityStatus 聚合的合格品/不合格品数量,累加任务的合格品/不合格品数量 + * (不直接用 feedback 上的数量,确保质检回调场景下数量来源正确)
  • + *
+ * + * @param feedback 报工单 + */ + private void updateTaskAndWorkOrderByFeedback(MesProFeedbackDO feedback) { + // 1. 查询该报工单关联的所有产出单行,按质量状态聚合数量 + BigDecimal qualifiedQty = BigDecimal.ZERO; + BigDecimal unqualifiedQty = BigDecimal.ZERO; + List lines = produceLineService.getProductProduceLineListByFeedbackId(feedback.getId()); + for (MesWmProductProduceLineDO line : lines) { + if (ObjUtil.equal(line.getQualityStatus(), MesWmQualityStatusEnum.FAIL.getStatus())) { + unqualifiedQty = unqualifiedQty.add(line.getQuantity()); + } + if (ObjUtil.equal(line.getQualityStatus(), MesWmQualityStatusEnum.PASS.getStatus())) { + qualifiedQty = qualifiedQty.add(line.getQuantity()); + } + } + + // 2. 更新任务的已生产/合格/不合格数量 + taskService.updateProducedQuantity(feedback.getTaskId(), + feedback.getFeedbackQuantity(), qualifiedQty, unqualifiedQty); + // 3. 更新工单的已生产数量 + workOrderService.updateProducedQuantity(feedback.getWorkOrderId(), + feedback.getFeedbackQuantity()); + } + // ==================== 校验方法 ==================== private MesProFeedbackDO validateFeedbackExists(Long id) { diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskService.java index adfdbfe..a65fa82 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskService.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.pro.task.vo.MesProTaskSaveRe import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO; import jakarta.validation.Valid; +import java.math.BigDecimal; import java.util.Collection; import java.util.List; import java.util.Map; @@ -121,4 +122,17 @@ public interface MesProTaskService { */ void cancelTaskByOrderId(Long workOrderId); + /** + * 累加任务的已生产、合格、不合格数量 + * + * @param id 任务编号 + * @param incrProducedQuantity 本次已生产数量增量(不良品也计入) + * @param incrQualifyQuantity 本次合格品数量增量 + * @param incrUnqualifyQuantity 本次不合格品数量增量 + */ + void updateProducedQuantity(Long id, + BigDecimal incrProducedQuantity, + BigDecimal incrQualifyQuantity, + BigDecimal incrUnqualifyQuantity); + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java index d4fe5bf..f232e24 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/task/MesProTaskServiceImpl.java @@ -196,4 +196,15 @@ public class MesProTaskServiceImpl implements MesProTaskService { } } + @Override + public void updateProducedQuantity(Long id, + BigDecimal incrProducedQuantity, + BigDecimal incrQualifyQuantity, + BigDecimal incrUnqualifyQuantity) { + // 校验任务存在 + validateTaskExists(id); + // 更新数量 + taskMapper.updateProducedQuantity(id, incrProducedQuantity, incrQualifyQuantity, incrUnqualifyQuantity); + } + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderService.java index 07494b8..9af01fd 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderService.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkO import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; import jakarta.validation.Valid; +import java.math.BigDecimal; import java.util.Collection; import java.util.List; import java.util.Map; @@ -119,4 +120,12 @@ public interface MesProWorkOrderService { */ List getWorkOrderSimpleList(); + /** + * 累加工单的已生产数量 + * + * @param id 工单编号 + * @param incrQuantityProduced 本次已生产数量增量 + */ + void updateProducedQuantity(Long id, BigDecimal incrQuantityProduced); + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderServiceImpl.java index 58b70ca..e5a15c9 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkorderServiceImpl.java @@ -20,6 +20,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.Collection; import java.util.Collections; @@ -233,4 +234,12 @@ public class MesProWorkOrderServiceImpl implements MesProWorkOrderService { return workOrderMapper.selectList(); } + @Override + public void updateProducedQuantity(Long id, BigDecimal incrQuantityProduced) { + // 校验工单存在 + validateWorkOrderExists(id); + // 更新数量 + workOrderMapper.updateProducedQuantity(id, incrQuantityProduced); + } + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java index 9b284df..9a799f0 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/ipqc/MesQcIpqcServiceImpl.java @@ -124,7 +124,8 @@ public class MesQcIpqcServiceImpl implements MesQcIpqcService { updateObj.setStatus(MesQcStatusEnum.FINISHED.getStatus()); ipqcMapper.updateById(updateObj); - // TODO @芋艿:IPQC 完成时的 PRO/WM 联动(报工反馈更新、产品产出单拆分),待 WM 模块迁移后对接 + // TODO @AI(from codex):如果检验来源是报工,需要对待检产出按检验结果拆分合格/不合格行、生成产出明细、完成产品产出入库、 + // 回写任务/工单数量,并将报工状态从待检验改为已完成。 } @Override diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemconsume/MesWmItemConsumeServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemconsume/MesWmItemConsumeServiceImpl.java index fcbad4d..b2d262b 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemconsume/MesWmItemConsumeServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemconsume/MesWmItemConsumeServiceImpl.java @@ -20,8 +20,6 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. /** * MES 物料消耗记录 Service 实现类 * - * 参考 KTG {@code WmItemConsumeServiceImpl#generateItemConsume} - * * @author 芋道源码 */ @Service @@ -60,12 +58,13 @@ public class MesWmItemConsumeServiceImpl implements MesWmItemConsumeService { .consumeId(consume.getId()).itemId(bom.getItemId()) .quantity(bom.getQuantity().multiply(feedback.getFeedbackQuantity())).build()); itemConsumeLineService.createItemConsumeLineBatch(lines); + // TODO @AI(from codex):对齐,这里还需要按线边库/FIFO 生成消耗明细,并在库存不足时回退为无批次消耗明细。 return consume; } @Override public void finishItemConsume(Long consumeId) { - // TODO @芋艿:待 MaterialStockService 补充 decreaseStock 后实现库存扣减 + // TODO @AI(from codex):对齐,这里还需要按消耗明细扣减线边库库存,不能只把消耗单状态改为已完成。 // List lines = itemConsumeLineService.getItemConsumeLineListByConsumeId(consumeId); // for (MesWmItemConsumeLineDO line : lines) { // materialStockService.decreaseStock(line.getItemId(), ..., line.getQuantity()); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineService.java index 9fa9620..3f78321 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineService.java @@ -74,4 +74,12 @@ public interface MesWmProductProduceLineService { */ MesWmProductProduceLineDO validateProductProduceLineExists(Long id); + /** + * 根据报工记录ID获取行列表 + * + * @param feedbackId 报工记录ID + * @return 行列表 + */ + List getProductProduceLineListByFeedbackId(Long feedbackId); + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineServiceImpl.java index 2cd63c7..ff115af 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceLineServiceImpl.java @@ -97,4 +97,9 @@ public class MesWmProductProduceLineServiceImpl implements MesWmProductProduceLi return line; } + @Override + public List getProductProduceLineListByFeedbackId(Long feedbackId) { + return produceLineMapper.selectListByFeedbackId(feedbackId); + } + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceService.java index 17513da..bca963f 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceService.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.mes.service.wm.productproduce; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.mes.controller.admin.wm.productproduce.vo.MesWmProductProducePageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.productproduce.vo.MesWmProductProduceSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceDO; import jakarta.validation.Valid; @@ -79,4 +80,13 @@ public interface MesWmProductProduceService { */ Boolean checkProductProduceQuantity(Long id); + /** + * 根据报工记录,自动生成产品产出单(头 + 行 + 明细) + * + * @param feedback 报工记录 + * @param checkFlag 是否需要检验(true=待检验,false=按合格/不合格拆分行) + * @return 生成的产品产出单 + */ + MesWmProductProduceDO generateProductProduce(MesProFeedbackDO feedback, boolean checkFlag); + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImpl.java index 142bc7c..3b96f29 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productproduce/MesWmProductProduceServiceImpl.java @@ -2,25 +2,36 @@ package cn.iocoder.yudao.module.mes.service.wm.productproduce; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.module.mes.controller.admin.wm.batch.vo.MesWmBatchGenerateReqVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.productproduce.vo.MesWmProductProducePageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.productproduce.vo.MesWmProductProduceSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceDetailDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceLineDO; +import cn.iocoder.yudao.module.mes.dal.mysql.wm.productproduce.MesWmProductProduceDetailMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.wm.productproduce.MesWmProductProduceLineMapper; import cn.iocoder.yudao.module.mes.dal.mysql.wm.productproduce.MesWmProductProduceMapper; import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductProduceStatusEnum; +import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum; import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkstationService; import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; +import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -34,7 +45,13 @@ import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; public class MesWmProductProduceServiceImpl implements MesWmProductProduceService { @Resource - private MesWmProductProduceMapper produceMapper; + private MesWmProductProduceMapper productProduceMapper; + // TODO @芋艿:需要优化,不要直接调用对方的 mapper + @Resource + private MesWmProductProduceLineMapper produceLineMapper; + // TODO @芋艿:需要优化,不要直接调用对方的 mapper + @Resource + private MesWmProductProduceDetailMapper produceDetailMapper; @Resource private MesWmProductProduceLineService produceLineService; @@ -44,6 +61,8 @@ public class MesWmProductProduceServiceImpl implements MesWmProductProduceServic private MesMdWorkstationService workstationService; @Resource private MesProWorkOrderService workOrderService; + @Resource + private MesWmBatchService batchService; @Override @Transactional(rollbackFor = Exception.class) @@ -59,7 +78,7 @@ public class MesWmProductProduceServiceImpl implements MesWmProductProduceServic // 2. 插入主表 MesWmProductProduceDO produce = BeanUtils.toBean(createReqVO, MesWmProductProduceDO.class); produce.setStatus(MesWmProductProduceStatusEnum.PREPARE.getStatus()); - produceMapper.insert(produce); + productProduceMapper.insert(produce); return produce.getId(); } @@ -78,7 +97,7 @@ public class MesWmProductProduceServiceImpl implements MesWmProductProduceServic // 2. 更新主表 MesWmProductProduceDO updateObj = BeanUtils.toBean(updateReqVO, MesWmProductProduceDO.class); - produceMapper.updateById(updateObj); + productProduceMapper.updateById(updateObj); } @Override @@ -92,32 +111,31 @@ public class MesWmProductProduceServiceImpl implements MesWmProductProduceServic // 2.2 级联删除行 produceLineService.deleteProductProduceLineByProduceId(id); // 2.3 删除主表 - produceMapper.deleteById(id); + productProduceMapper.deleteById(id); } @Override public MesWmProductProduceDO getProductProduce(Long id) { - return produceMapper.selectById(id); + return productProduceMapper.selectById(id); } @Override public PageResult getProductProducePage(MesWmProductProducePageReqVO pageReqVO) { - return produceMapper.selectPage(pageReqVO); + return productProduceMapper.selectPage(pageReqVO); } @Override @Transactional(rollbackFor = Exception.class) public void finishProductProduce(Long id) { - // 1. 校验存在 + 草稿状态 + // 1.1 校验存在 + 草稿状态 validateProductProduceExistsAndPrepare(id); - - // 2. 校验至少有一条行 + // 1.2 校验至少有一条行 List lines = produceLineService.getProductProduceLineListByProduceId(id); if (CollUtil.isEmpty(lines)) { throw exception(WM_PRODUCT_PRODUCE_NO_LINE); } - // 3. 校验每行明细数量之和等于行数量 + // 2. 校验每行明细数量之和等于行数量 for (MesWmProductProduceLineDO line : lines) { List details = produceDetailService.getProductProduceDetailListByLineId(line.getId()); BigDecimal totalDetailQty = CollectionUtils.getSumValue(details, @@ -127,17 +145,17 @@ public class MesWmProductProduceServiceImpl implements MesWmProductProduceServic } } - // TODO @芋艿:完成入库时更新库存(对齐 ktg-mes 的 storageCoreService.processProductProduce),待库存事务模块就绪后实现 + // TODO @AI(from codex):对齐,这里还需要按产出明细执行库存入账,而不是只校验明细并更新单据状态。 - // 4. 更新入库单状态 - produceMapper.updateById(new MesWmProductProduceDO() + // 3. 更新入库单状态 + productProduceMapper.updateById(new MesWmProductProduceDO() .setId(id).setStatus(MesWmProductProduceStatusEnum.FINISHED.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void cancelProductProduce(Long id) { - // 校验存在 + // 1. 校验存在 MesWmProductProduceDO produce = validateProductProduceExists(id); // 已完成和已取消不允许取消 if (ObjectUtils.equalsAny(produce.getStatus(), @@ -146,8 +164,8 @@ public class MesWmProductProduceServiceImpl implements MesWmProductProduceServic throw exception(WM_PRODUCT_PRODUCE_CANCEL_NOT_ALLOWED); } - // 取消 - produceMapper.updateById(new MesWmProductProduceDO() + // 2. 取消 + productProduceMapper.updateById(new MesWmProductProduceDO() .setId(id).setStatus(MesWmProductProduceStatusEnum.CANCELED.getStatus())); } @@ -166,8 +184,93 @@ public class MesWmProductProduceServiceImpl implements MesWmProductProduceServic } @Override + @Transactional(rollbackFor = Exception.class) + public MesWmProductProduceDO generateProductProduce(MesProFeedbackDO feedback, boolean checkFlag) { + // 0. 查询关联的工单(用于获取 clientId 等信息) + MesProWorkOrderDO workOrder = workOrderService.getWorkOrder(feedback.getWorkOrderId()); + + // 1. 创建产出单头 + MesWmProductProduceDO produce = MesWmProductProduceDO.builder() + .workOrderId(feedback.getWorkOrderId()).feedbackId(feedback.getId()).taskId(feedback.getTaskId()) + .workstationId(feedback.getWorkstationId()).processId(feedback.getProcessId()) + .produceDate(LocalDateTime.now()).status(MesWmProductProduceStatusEnum.PREPARE.getStatus()) + .build(); + productProduceMapper.insert(produce); + + // 2. 获取或生成批次 + MesWmBatchGenerateReqVO batchReqVO = new MesWmBatchGenerateReqVO() + .setItemId(feedback.getItemId()) + .setProduceDate(LocalDate.now().atStartOfDay()) // 截断到当天零点,确保同一天的报工生成相同批次号 + .setExpireDate(feedback.getExpireDate()) + .setWorkOrderId(feedback.getWorkOrderId()) + .setClientId(workOrder != null ? workOrder.getClientId() : null) + .setWorkstationId(feedback.getWorkstationId()) + .setLotNumber(feedback.getLotNumber()); + // TODO @AI(from codex):对齐 批次生成还需要带上工单来源单号(salesOrderCode / coCode 对应 orderSourceCode); + // 否则启用该维度的批次规则会生成错误批次或直接缺参失败。 + MesWmBatchDO batch = batchService.getOrGenerateBatchCode(batchReqVO); + Long batchId = batch != null ? batch.getId() : null; + String batchCode = batch != null ? batch.getCode() : null; + + // 3. 根据是否需要检验分支处理 + if (checkFlag) { + // 3.1 需要检验:创建一条行(质量状态=待检验),不生成明细 + MesWmProductProduceLineDO line = buildProduceLine(produce, feedback, batchId, batchCode, + feedback.getFeedbackQuantity(), MesWmQualityStatusEnum.PENDING.getStatus()); + produceLineMapper.insert(line); + // TODO @芋艿:先不生成明细行,等待检验完成时,再根据行的质量状态生成明细行 + } else { + // 3.2 无需检验:按合格品/不合格品各生成一行 + 明细 + BigDecimal qualifiedQty = ObjectUtil.defaultIfNull(feedback.getQualifiedQuantity(), BigDecimal.ZERO); + BigDecimal unqualifiedQty = ObjectUtil.defaultIfNull(feedback.getUnqualifiedQuantity(), BigDecimal.ZERO); + // 3.2.1 不合格品行 + 明细 + if (unqualifiedQty.compareTo(BigDecimal.ZERO) > 0) { + MesWmProductProduceLineDO unqualifiedLine = buildProduceLine(produce, feedback, batchId, batchCode, + unqualifiedQty, MesWmQualityStatusEnum.FAIL.getStatus()); + produceLineMapper.insert(unqualifiedLine); + MesWmProductProduceDetailDO unqualifiedDetail = buildProduceDetail(produce, feedback, batchId, batchCode, + unqualifiedLine.getId(), unqualifiedQty); + produceDetailMapper.insert(unqualifiedDetail); + } + // 3.2.2 合格品行 + 明细 + if (qualifiedQty.compareTo(BigDecimal.ZERO) > 0) { + MesWmProductProduceLineDO qualifiedLine = buildProduceLine(produce, feedback, batchId, batchCode, + qualifiedQty, MesWmQualityStatusEnum.PASS.getStatus()); + produceLineMapper.insert(qualifiedLine); + MesWmProductProduceDetailDO qualifiedDetail = buildProduceDetail(produce, feedback, batchId, batchCode, + qualifiedLine.getId(), qualifiedQty); + produceDetailMapper.insert(qualifiedDetail); + } + } + return produce; + } + + private MesWmProductProduceLineDO buildProduceLine(MesWmProductProduceDO produce, MesProFeedbackDO feedback, + Long batchId, String batchCode, + BigDecimal quantity, Integer qualityStatus) { + return MesWmProductProduceLineDO.builder() + .produceId(produce.getId()).feedbackId(feedback.getId()) + .itemId(feedback.getItemId()).quantity(quantity) + .batchId(batchId).batchCode(batchCode) + .expireDate(feedback.getExpireDate()).lotNumber(feedback.getLotNumber()) + .qualityStatus(qualityStatus) + .build(); + } + + private MesWmProductProduceDetailDO buildProduceDetail(MesWmProductProduceDO produce, MesProFeedbackDO feedback, + Long batchId, String batchCode, + Long lineId, BigDecimal quantity) { + return MesWmProductProduceDetailDO.builder() + .produceId(produce.getId()).lineId(lineId) + .itemId(feedback.getItemId()).quantity(quantity) + .batchId(batchId).batchCode(batchCode) + // TODO @AI(from codex):对齐 产出明细需要补齐虚拟仓/库区/库位(VIRTUAL_WH/VIRTUAL_WS/VIRTUAL_WA),否则后续库存入账定位不完整。 + .build(); + } + + @Override public MesWmProductProduceDO validateProductProduceExists(Long id) { - MesWmProductProduceDO produce = produceMapper.selectById(id); + MesWmProductProduceDO produce = productProduceMapper.selectById(id); if (produce == null) { throw exception(WM_PRODUCT_PRODUCE_NOT_EXISTS); } @@ -179,10 +282,11 @@ public class MesWmProductProduceServiceImpl implements MesWmProductProduceServic */ private MesWmProductProduceDO validateProductProduceExistsAndPrepare(Long id) { MesWmProductProduceDO produce = validateProductProduceExists(id); - if (ObjUtil.notEqual(MesWmProductProduceStatusEnum.PREPARE.getStatus(), produce.getStatus())) { + if (ObjUtil.notEqual(produce.getStatus(), MesWmProductProduceStatusEnum.PREPARE.getStatus())) { throw exception(WM_PRODUCT_PRODUCE_STATUS_INVALID); } return produce; } + } -- libgit2 0.21.4