From cbadfd8e691ab335965202a984db16e55ac8e42c Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期五, 30 十月 2026 17:51:06 +0800
Subject: [PATCH] 诚发五金:按技术方案重构业务功能并补齐库结构
---
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 153 insertions(+), 10 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 8ed8807..1326d89 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
@@ -5,9 +5,17 @@
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.erp.api.purchase.ErpPurchaseOrderApi;
+import cn.iocoder.yudao.module.erp.api.purchase.ErpPurchaseRequestApi;
+import cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchaseOrderItemRespDTO;
+import cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchaseRequestCreateReqDTO;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.mps.vo.MesProMpsAuditReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.mps.vo.MesProMpsPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.mps.vo.MesProMpsSaveReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderItemRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.MesProWorkOrderSaveReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.mps.MesProMpsDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.mps.MesProMpsMergeItemDO;
import cn.iocoder.yudao.module.mes.dal.mysql.pro.mps.MesProMpsMapper;
@@ -24,6 +32,7 @@
import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderSourceTypeEnum;
import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderStatusEnum;
import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
+import cn.iocoder.yudao.module.mes.service.pro.material.MesProMaterialRequirementService;
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;
@@ -46,6 +55,8 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -88,6 +99,12 @@
private MesProRouteProcessService routeProcessService;
@Resource
private MesProWorkOrderProcessService workOrderProcessService;
+ @Resource
+ private MesProMaterialRequirementService materialRequirementService;
+ @Resource
+ private ErpPurchaseOrderApi purchaseOrderApi;
+ @Resource
+ private ErpPurchaseRequestApi purchaseRequestApi;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -141,6 +158,13 @@
public Long createMps(MesProMpsSaveReqVO createReqVO) {
// 鏍¢獙浜у搧瀛樺湪
itemService.validateItemExists(createReqVO.getProductId());
+ // 璁¢噺鍗曚綅鏈~鍐欐椂锛岄粯璁ゅ彇浜у搧鍗曚綅
+ if (createReqVO.getUnitMeasureId() == null) {
+ MesMdItemDO product = itemService.getItem(createReqVO.getProductId());
+ if (product != null) {
+ createReqVO.setUnitMeasureId(product.getUnitMeasureId());
+ }
+ }
// 濡傛灉鏈~鍐欑紪鐮侊紝鑷姩鐢熸垚
if (StrUtil.isBlank(createReqVO.getCode())) {
@@ -164,22 +188,25 @@
@Override
@Transactional(rollbackFor = Exception.class)
public void updateMps(MesProMpsSaveReqVO updateReqVO) {
- // 鏍¢獙瀛樺湪 + 鑽夌鐘舵��
- validateMpsExistsAndDraft(updateReqVO.getId());
+ // 鏍¢獙瀛樺湪 + 鍙紪杈戠姸鎬侊紙鏈紑濮嬨�佸鏍镐腑锛�
+ MesProMpsDO mps = validateMpsExistsAndEditable(updateReqVO.getId());
// 鏍¢獙缂栫爜鍞竴
validateMpsCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
- // 鏇存柊
+ // 鏇存柊锛涘鏍镐腑鐨勮鍒掕淇敼鍚庨渶瑕侀噸鏂版彁浜ゅ鏍�
MesProMpsDO updateObj = BeanUtils.toBean(updateReqVO, MesProMpsDO.class);
+ if (MesProMpsStatusEnum.AUDITING.getStatus().equals(mps.getStatus())) {
+ updateObj.setStatus(MesProMpsStatusEnum.DRAFT.getStatus());
+ }
mpsMapper.updateById(updateObj);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteMps(Long id) {
- // 鏍¢獙瀛樺湪 + 鑽夌鐘舵��
- MesProMpsDO mps = validateMpsExistsAndDraft(id);
+ // 鏍¢獙瀛樺湪 + 鍙紪杈戠姸鎬侊紙鏈紑濮嬨�佸鏍镐腑锛�
+ MesProMpsDO mps = validateMpsExistsAndEditable(id);
// 鏍¢獙鏄惁宸插叧鑱斿伐鍗�
if (mps.getWorkOrderId() != null) {
@@ -192,9 +219,98 @@
@Override
@Transactional(rollbackFor = Exception.class)
+ public void submitMps(Long id) {
+ MesProMpsDO mps = validateMpsExists(id);
+ if (!MesProMpsStatusEnum.DRAFT.getStatus().equals(mps.getStatus())
+ && !MesProMpsStatusEnum.AUDITING.getStatus().equals(mps.getStatus())) {
+ throw exception(PRO_MPS_NOT_DRAFT);
+ }
+ mpsMapper.updateById(new MesProMpsDO()
+ .setId(id)
+ .setStatus(MesProMpsStatusEnum.AUDITING.getStatus()));
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void auditMps(MesProMpsAuditReqVO reqVO) {
+ MesProMpsDO mps = validateMpsExists(reqVO.getId());
+ if (!MesProMpsStatusEnum.AUDITING.getStatus().equals(mps.getStatus())) {
+ throw exception(PRO_MPS_NOT_AUDITING);
+ }
+ boolean approved = Boolean.TRUE.equals(reqVO.getApproved());
+ if (!approved && StrUtil.isBlank(reqVO.getAuditRemark())) {
+ throw exception(PRO_MPS_AUDIT_REMARK_REQUIRED);
+ }
+ mpsMapper.updateById(new MesProMpsDO()
+ .setId(reqVO.getId())
+ .setStatus(approved ? MesProMpsStatusEnum.APPROVED.getStatus()
+ : MesProMpsStatusEnum.DRAFT.getStatus())
+ .setAuditUserId(SecurityFrameworkUtils.getLoginUserId())
+ .setAuditTime(LocalDateTime.now())
+ .setAuditRemark(approved
+ ? StrUtil.blankToDefault(reqVO.getAuditRemark(), "瀹℃牳閫氳繃")
+ : reqVO.getAuditRemark()));
+ }
+
+ @Override
+ public List<MesProWorkOrderItemRespVO> getMpsItemList(Long id) {
+ MesProMpsDO mps = validateMpsExists(id);
+ // 鎸変骇鍝� BOM锛堜紭鍏堝伐鑹鸿矾绾� BOM锛夊睍寮�鍙跺瓙鐗╂枡锛屽苟鎸夎鍒掓暟閲忔姌绠楅渶姹傦紱
+ // 璁″垝灏氭湭鐢熸垚宸ュ崟锛屾棤鏉ユ簮涓烘湰璁″垝鐨勫湪閫旈噰璐紝鐩存帴鎸夊彲鐢ㄥ簱瀛樺垽鏂槸鍚﹀厖瓒�
+ return materialRequirementService.getItemListByProduct(mps.getProductId(), mps.getQuantity());
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Long generatePurchaseRequest(Long id) {
+ MesProMpsDO mps = validateMpsExists(id);
+ if (!MesProMpsStatusEnum.APPROVED.getStatus().equals(mps.getStatus())) {
+ throw exception(PRO_MPS_NOT_APPROVED);
+ }
+ // 1. 鍙缂哄彛鐗╂枡鐢熸垚閲囪喘鏄庣粏锛氱己鍙� = 闇�姹� - 鍙敤搴撳瓨 - 鍦ㄩ�旈噰璐�
+ List<ErpPurchaseRequestCreateReqDTO.Item> shortageItems = new ArrayList<>();
+ for (MesProWorkOrderItemRespVO item : getMpsItemList(id)) {
+ if (Boolean.TRUE.equals(item.getStockSufficient())) {
+ continue;
+ }
+ BigDecimal supply = nullToZero(item.getStockQuantity())
+ .add(nullToZero(item.getPurchaseOrderQuantity()));
+ BigDecimal shortage = nullToZero(item.getQuantity()).subtract(supply);
+ if (shortage.compareTo(BigDecimal.ZERO) <= 0) {
+ continue;
+ }
+ MesMdItemDO itemDO = itemService.getItem(item.getItemId());
+ if (itemDO == null) {
+ continue;
+ }
+ shortageItems.add(new ErpPurchaseRequestCreateReqDTO.Item()
+ .setProductId(item.getItemId())
+ .setProductUnitId(itemDO.getUnitMeasureId())
+ .setCount(shortage)
+ .setDemandTime(mps.getRequestDate() != null ? mps.getRequestDate().toLocalDate() : null)
+ .setRemark("鐢熶骇璁″垝 " + mps.getCode() + " 搴撳瓨缂哄彛 " + shortage.stripTrailingZeros().toPlainString()));
+ }
+ if (CollUtil.isEmpty(shortageItems)) {
+ throw exception(PRO_MPS_NO_MATERIAL_SHORTAGE);
+ }
+ // 2. 鐢熸垚閲囪喘鐢宠鍗曪紙鑽夌锛屾棤渚涘簲鍟嗭紝鍚庣画鐢遍噰璐汉鍛樿ˉ鍏呭苟鎸夋祦绋嬫彁浜わ級
+ ErpPurchaseRequestCreateReqDTO createReqDTO = new ErpPurchaseRequestCreateReqDTO()
+ .setRequestTime(LocalDateTime.now())
+ .setRequestReason("鐢熶骇璁″垝 " + mps.getCode() + " 杈呮枡閲囪喘")
+ .setRemark("鐢辩敓浜ц鍒掕嚜鍔ㄧ敓鎴愶紝鍏� " + shortageItems.size() + " 椤圭墿鏂欏簱瀛樹笉瓒�")
+ .setItems(shortageItems);
+ Long purchaseRequestId = purchaseRequestApi.createPurchaseRequest(createReqDTO).getCheckedData();
+ // 3. 鍥炲啓閲囪喘鐢宠鍗曠紪鍙凤紝渚夸簬浠庤鍒掕拷婧�
+ mpsMapper.updateById(new MesProMpsDO().setId(id).setPurchaseRequestId(purchaseRequestId));
+ log.info("[generatePurchaseRequest] 璁″垝({}) 鐢熸垚閲囪喘鐢宠鍗�({})锛屾槑缁� {} 椤�", mps.getCode(), purchaseRequestId, shortageItems.size());
+ return purchaseRequestId;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
public Long issueMps(Long id) {
- // 鏍¢獙瀛樺湪 + 鑽夌鐘舵��
- MesProMpsDO mps = validateMpsExistsAndDraft(id);
+ // 鏍¢獙瀛樺湪 + 宸插鏍哥姸鎬�
+ MesProMpsDO mps = validateMpsExistsAndApproved(id);
// 鍒涘缓鐢熶骇宸ュ崟
Long workOrderId = createWorkOrderFromMps(mps, mps.getQuantity());
@@ -223,11 +339,11 @@
throw exception(PRO_MPS_NOT_EXISTS);
}
- // 鏍¢獙锛氬繀椤绘槸鐩稿悓浜у搧銆佽崏绋跨姸鎬�
+ // 鏍¢獙锛氬繀椤绘槸鐩稿悓浜у搧銆佸凡瀹℃牳鐘舵��
Long productId = null;
for (MesProMpsDO mps : mpsList) {
- if (!MesProMpsStatusEnum.DRAFT.getStatus().equals(mps.getStatus())) {
- throw exception(PRO_MPS_NOT_DRAFT);
+ if (!MesProMpsStatusEnum.APPROVED.getStatus().equals(mps.getStatus())) {
+ throw exception(PRO_MPS_NOT_APPROVED);
}
if (productId == null) {
productId = mps.getProductId();
@@ -511,6 +627,33 @@
}
/**
+ * 鏍¢獙 MPS 瀛樺湪 + 宸插鏍哥姸鎬�
+ */
+ private MesProMpsDO validateMpsExistsAndApproved(Long id) {
+ MesProMpsDO mps = validateMpsExists(id);
+ if (!MesProMpsStatusEnum.APPROVED.getStatus().equals(mps.getStatus())) {
+ throw exception(PRO_MPS_NOT_APPROVED);
+ }
+ return mps;
+ }
+
+ /**
+ * 鏍¢獙 MPS 瀛樺湪 + 鍙紪杈戠姸鎬侊紙鏈紑濮嬨�佸鏍镐腑锛�
+ */
+ private MesProMpsDO validateMpsExistsAndEditable(Long id) {
+ MesProMpsDO mps = validateMpsExists(id);
+ if (!MesProMpsStatusEnum.DRAFT.getStatus().equals(mps.getStatus())
+ && !MesProMpsStatusEnum.AUDITING.getStatus().equals(mps.getStatus())) {
+ throw exception(PRO_MPS_NOT_DRAFT);
+ }
+ return mps;
+ }
+
+ private static BigDecimal nullToZero(BigDecimal value) {
+ return value != null ? value : BigDecimal.ZERO;
+ }
+
+ /**
* 鏍¢獙 MPS 缂栫爜鍞竴
*/
private void validateMpsCodeUnique(Long id, String code) {
--
Gitblit v1.9.3