From f61043f70c126c4b464a4ebc7dd635fcf7b679df Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期五, 24 七月 2026 17:25:33 +0800
Subject: [PATCH] feat(erp): 为ERP模块添加附件功能支持
---
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 160 insertions(+), 1 deletions(-)
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java
index 34ca046..eff04b4 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java
@@ -12,11 +12,23 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.mps.MesProMpsMergeItemDO;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.mps.MesProMpsMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.mps.MesProMpsMergeItemMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.workorder.MesProWorkOrderMapper;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductBomDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
import cn.iocoder.yudao.module.mes.enums.pro.MesProMpsStatusEnum;
+import cn.iocoder.yudao.module.mes.enums.pro.MesProFeedbackStatusEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderSourceTypeEnum;
import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
+import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProductService;
+import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProcessService;
import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
+import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderProcessService;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.process.MesProWorkOrderProcessSaveReqVO;
import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@@ -27,9 +39,11 @@
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
@@ -61,6 +75,16 @@
private MesMdAutoCodeRecordService autoCodeRecordService;
@Resource
private CrmCustomerApi customerApi;
+ @Resource
+ private MesProFeedbackMapper feedbackMapper;
+ @Resource
+ private MesProWorkOrderMapper workOrderMapper;
+ @Resource
+ private MesProRouteProductService routeProductService;
+ @Resource
+ private MesProRouteProcessService routeProcessService;
+ @Resource
+ private MesProWorkOrderProcessService workOrderProcessService;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -331,6 +355,94 @@
mpsMapper.updateProducedQuantity(id, incrQuantity);
}
+ @Override
+ public Boolean checkSaleOrderProductionFinished(Long saleOrderId) {
+ if (saleOrderId == null) {
+ return false;
+ }
+ // 1. 鏌ヨ璇ラ攢鍞鍗曟墍鏈� MPS锛堥�氳繃 saleOrderId 鍏宠仈锛�
+ List<MesProMpsDO> mpsList = mpsMapper.selectList(
+ MesProMpsDO::getSaleOrderId, saleOrderId);
+ if (CollUtil.isEmpty(mpsList)) {
+ // 鏃� MPS 鍏宠仈锛岃涓哄畬鎴�
+ return true;
+ }
+ // 2. 妫�鏌ユ瘡涓� MPS 鏄惁瀹屾垚
+ for (MesProMpsDO mps : mpsList) {
+ if (!isMpsFinished(mps)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public MesProMpsDO getMpsByWorkOrderId(Long workOrderId) {
+ if (workOrderId == null) {
+ return null;
+ }
+ return mpsMapper.selectOne(MesProMpsDO::getWorkOrderId, workOrderId);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean checkAndFinishMps(Long mpsId) {
+ if (mpsId == null) {
+ log.warn("[checkAndFinishMps] mpsId is null");
+ return false;
+ }
+ MesProMpsDO mps = mpsMapper.selectById(mpsId);
+ if (mps == null) {
+ log.warn("[checkAndFinishMps] MPS not found, mpsId={}", mpsId);
+ return false;
+ }
+ // 宸插畬鎴愭垨宸插彇娑堬紝鐩存帴杩斿洖 true
+ if (MesProMpsStatusEnum.FINISHED.getStatus().equals(mps.getStatus())
+ || MesProMpsStatusEnum.CANCELED.getStatus().equals(mps.getStatus())) {
+ log.info("[checkAndFinishMps] MPS {} already finished or canceled, status={}", mpsId, mps.getStatus());
+ return true;
+ }
+ // 妫�鏌ユ槸鍚︽弧瓒冲畬鎴愭潯浠�
+ boolean finished = isMpsFinished(mps);
+ log.info("[checkAndFinishMps] MPS {} check result: {}, quantity={}, produced={}, workOrderId={}",
+ mpsId, finished, mps.getQuantity(), mps.getQuantityProduced(), mps.getWorkOrderId());
+ if (finished) {
+ // 鑷姩瀹屾垚 MPS
+ mpsMapper.updateById(new MesProMpsDO()
+ .setId(mpsId)
+ .setStatus(MesProMpsStatusEnum.FINISHED.getStatus())
+ .setFinishDate(LocalDateTime.now()));
+ log.info("[checkAndFinishMps] MPS {} auto finished", mpsId);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 鍒ゆ柇鍗曚釜 MPS 鏄惁瀹屾垚
+ */
+ private boolean isMpsFinished(MesProMpsDO mps) {
+ // 1. 宸茬敓浜ф暟閲� >= 璁″垝鏁伴噺
+ BigDecimal quantityProduced = ObjUtil.defaultIfNull(mps.getQuantityProduced(), BigDecimal.ZERO);
+ if (quantityProduced.compareTo(mps.getQuantity()) < 0) {
+ log.debug("[isMpsFinished] MPS {} quantity not enough: produced={}, required={}",
+ mps.getId(), quantityProduced, mps.getQuantity());
+ return false;
+ }
+ // 2. 妫�鏌ュ伐鍗曚笅鎵�鏈夋姤宸ユ槸鍚﹀畬鎴愶紙纭繚璐ㄦ瀹屾垚锛�
+ if (mps.getWorkOrderId() != null) {
+ Long unfinishedCount = feedbackMapper.selectCount(
+ new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<MesProFeedbackDO>()
+ .eq(MesProFeedbackDO::getWorkOrderId, mps.getWorkOrderId())
+ .ne(MesProFeedbackDO::getStatus, MesProFeedbackStatusEnum.FINISHED.getStatus()));
+ log.debug("[isMpsFinished] MPS {} unfinished feedback count: {}", mps.getId(), unfinishedCount);
+ if (unfinishedCount > 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
// ========== 绉佹湁鏂规硶 ==========
/**
@@ -398,6 +510,20 @@
* 鏍规嵁 MPS 鍒涘缓鐢熶骇宸ュ崟
*/
private Long createWorkOrderFromMps(MesProMpsDO mps, BigDecimal quantity) {
+ // 1. 鏍¢獙浜у搧鏄惁瀛樺湪宸ヨ壓璺嚎
+ MesProRouteProductDO routeProduct = routeProductService.getRouteProductByItemId(mps.getProductId());
+ if (routeProduct == null) {
+ throw exception(PRO_ROUTE_NOT_EXISTS);
+ }
+ Long routeId = routeProduct.getRouteId();
+
+ // 2. 鏍¢獙宸ヨ壓璺嚎鏄惁鏈夊伐搴�
+ List<MesProRouteProcessDO> routeProcesses = routeProcessService.getRouteProcessListByRouteId(routeId);
+ if (CollUtil.isEmpty(routeProcesses)) {
+ throw exception(PRO_ROUTE_ENABLE_NO_PROCESS);
+ }
+
+ // 3. 鍒涘缓鐢熶骇宸ュ崟
MesProWorkOrderSaveReqVO workOrderReq = new MesProWorkOrderSaveReqVO();
workOrderReq.setCode(generateWorkOrderCode());
workOrderReq.setName("鐢熶骇宸ュ崟-" + mps.getCode());
@@ -412,7 +538,40 @@
Long workOrderId = workOrderService.createWorkOrder(workOrderReq);
- // 宸ュ崟鐩存帴纭涓哄凡纭鐘舵�侊紙璺宠繃鑽夌锛�
+ // 4. 鏇存柊宸ュ崟宸ヨ壓璺嚎
+ workOrderMapper.updateById(new MesProWorkOrderDO().setId(workOrderId).setRouteId(routeId));
+
+ // 5. 淇濆瓨宸ュ崟宸ュ簭锛堜粠宸ヨ壓璺嚎宸ュ簭甯﹀叆锛屽惈鎶曟枡BOM锛�
+ Map<Long, List<MesProRouteProductBomDO>> bomMap = routeProcessService.getRouteProcessBomMapByProductId(mps.getProductId());
+ List<MesProWorkOrderProcessSaveReqVO> processList = new ArrayList<>();
+ for (MesProRouteProcessDO rp : routeProcesses) {
+ MesProWorkOrderProcessSaveReqVO process = new MesProWorkOrderProcessSaveReqVO();
+ process.setWorkOrderId(workOrderId);
+ process.setProcessId(rp.getProcessId());
+ process.setSort(rp.getSort());
+ process.setKeyFlag(rp.getKeyFlag());
+ process.setCheckFlag(rp.getCheckFlag());
+ process.setBackflushFlag(rp.getBackflushFlag());
+ process.setOutputItemId(rp.getOutputItemId());
+ process.setColorCode(rp.getColorCode());
+ // 甯﹀叆宸ュ簭鎶曟枡BOM
+ List<MesProRouteProductBomDO> routeBomItems = bomMap != null ? bomMap.get(rp.getProcessId()) : null;
+ if (CollUtil.isNotEmpty(routeBomItems)) {
+ List<MesProWorkOrderProcessSaveReqVO.BomItem> bomItems = new ArrayList<>();
+ for (MesProRouteProductBomDO bomDO : routeBomItems) {
+ MesProWorkOrderProcessSaveReqVO.BomItem bomItem = new MesProWorkOrderProcessSaveReqVO.BomItem();
+ bomItem.setItemId(bomDO.getItemId());
+ bomItem.setQuantity(bomDO.getQuantity());
+ bomItem.setRemark(bomDO.getRemark());
+ bomItems.add(bomItem);
+ }
+ process.setBomItems(bomItems);
+ }
+ processList.add(process);
+ }
+ workOrderProcessService.batchSaveWorkOrderProcess(processList);
+
+ // 6. 宸ュ崟鐩存帴纭涓哄凡纭鐘舵��
workOrderService.confirmWorkOrder(workOrderId);
return workOrderId;
--
Gitblit v1.9.3