yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
@@ -18,6 +18,7 @@ import cn.iocoder.yudao.module.erp.service.sale.ErpSaleOrderService; import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi; import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; import cn.iocoder.yudao.module.mes.api.mps.MesProMpsApi; import cn.iocoder.yudao.module.mes.api.salesnotice.MesWmSalesNoticeApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; @@ -58,6 +59,8 @@ private AdminUserApi adminUserApi; @Resource private MesWmSalesNoticeApi salesNoticeApi; @Resource private MesProMpsApi mpsApi; @PostMapping("/create") @Operation(summary = "å建éå®è®¢å") @@ -171,6 +174,40 @@ // 1.5 åè´§éç¥åä¿¡æ¯ Map<Long, Boolean> salesNoticeMap = salesNoticeApi.checkSalesNoticeBySaleOrderIds( convertSet(pageResult.getList(), ErpSaleOrderDO::getId)); // 1.6 æ£æ¥æ¯å¦å¯ä»¥çæåè´§éç¥åï¼éè¦ç产çæç»å¯¹åºç MPS æ¯å¦å·²å®æï¼ // çéåºéè¦ç产çæç»ID List<Long> needProductionItemIds = saleOrderItemList.stream() .filter(item -> item.getNeedProduction() != null && item.getNeedProduction() == 1) .map(ErpSaleOrderItemDO::getId) .toList(); Map<Long, Boolean> canCreateSalesNoticeMap = new java.util.HashMap<>(); if (!needProductionItemIds.isEmpty()) { // æè®¢ååç»æç»ID Map<Long, List<Long>> orderItemIdsMap = new java.util.HashMap<>(); for (ErpSaleOrderItemDO item : saleOrderItemList) { orderItemIdsMap.computeIfAbsent(item.getOrderId(), k -> new java.util.ArrayList<>()) .add(item.getId()); } // æ£æ¥æ¯ä¸ªè®¢å for (Map.Entry<Long, List<Long>> entry : orderItemIdsMap.entrySet()) { List<Long> itemIds = entry.getValue().stream() .filter(id -> { ErpSaleOrderItemDO item = saleOrderItemList.stream() .filter(i -> i.getId().equals(id)) .findFirst().orElse(null); return item != null && item.getNeedProduction() != null && item.getNeedProduction() == 1; } ).toList(); if (itemIds.isEmpty()) { canCreateSalesNoticeMap.put(entry.getKey(), true); } else { canCreateSalesNoticeMap.put(entry.getKey(), mpsApi.checkCanCreateSalesNotice(itemIds)); } } } else { // 没æéè¦ç产çæç»ï¼é½å¯ä»¥çæåè´§éç¥å pageResult.getList().forEach(order -> canCreateSalesNoticeMap.put(order.getId(), true)); } // 2. å¼å§æ¼æ¥ return BeanUtils.toBean(pageResult, ErpSaleOrderRespVO.class, saleOrder -> { saleOrder.setItems(BeanUtils.toBean(saleOrderItemMap.get(saleOrder.getId()), ErpSaleOrderRespVO.Item.class, @@ -181,6 +218,12 @@ MapUtils.findAndThen(userMap, Long.parseLong(saleOrder.getCreator()), user -> saleOrder.setCreatorName(user.getNickname())); // 设置æ¯å¦å·²çæåè´§éç¥å saleOrder.setHasSalesNotice(salesNoticeMap.getOrDefault(saleOrder.getId(), false)); // 设置æ¯å¦å¯ä»¥çæåè´§éç¥å saleOrder.setCanCreateSalesNotice(canCreateSalesNoticeMap.getOrDefault(saleOrder.getId(), true)); // 设置æ¯å¦æéè¦ç产çæç» boolean hasNeedProduction = saleOrder.getItems().stream() .anyMatch(item -> item.getNeedProduction() != null && item.getNeedProduction() == 1); saleOrder.setNeedProduction(hasNeedProduction ? 1 : 0); }); } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java
@@ -109,6 +109,12 @@ @Schema(description = "æ¯å¦å·²çæåè´§éç¥å", example = "false") private Boolean hasSalesNotice; @Schema(description = "æ¯å¦å¯ä»¥çæåè´§éç¥åï¼æéè¦çäº§ä¸æªå®æçæç»æ¶ä¸º falseï¼", example = "true") private Boolean canCreateSalesNotice; @Schema(description = "æ¯å¦æéè¦ç产çæç»ï¼0=å¦ 1=æ¯ï¼", example = "1") private Integer needProduction; @Data public static class Item { yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpSupplierServiceImpl.java
@@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.erp.service.purchase; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -78,6 +79,9 @@ @Override public List<ErpSupplierDO> getSupplierList(Collection<Long> ids) { if (CollUtil.isEmpty(ids)) { return CollUtil.newArrayList(); } return supplierMapper.selectByIds(ids); } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java
@@ -17,13 +17,20 @@ import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; import cn.iocoder.yudao.module.erp.api.sale.enums.ErpSaleOrderOutStatusEnum; import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi; import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; import cn.iocoder.yudao.module.mes.api.mps.MesProMpsApi; import cn.iocoder.yudao.module.mes.api.mps.dto.MesProMpsCreateReqDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; 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.time.format.DateTimeFormatter; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -40,6 +47,7 @@ */ @Service @Validated @Slf4j public class ErpSaleOrderServiceImpl implements ErpSaleOrderService { @Resource @@ -59,6 +67,11 @@ @Resource private AdminUserApi adminUserApi; @Resource private MdmItemApi mdmItemApi; @Resource private MesProMpsApi mpsApi; @Override @Transactional(rollbackFor = Exception.class) @@ -157,6 +170,85 @@ if (updateCount == 0) { throw exception(approve ? SALE_ORDER_APPROVE_FAIL : SALE_ORDER_PROCESS_FAIL); } // 3. å®¡æ ¸éè¿æ¶ï¼ä¸ºéè¦ç产çæç»å建 MPS if (approve) { createMpsForSaleOrder(id, saleOrder); } } /** * 为éå®è®¢åä¸éè¦ç产çæç»å建 MPS * * @param orderId éå®è®¢åç¼å· * @param saleOrder éå®è®¢å */ private void createMpsForSaleOrder(Long orderId, ErpSaleOrderDO saleOrder) { List<ErpSaleOrderItemDO> items = saleOrderItemMapper.selectListByOrderId(orderId); if (CollUtil.isEmpty(items)) { return; } int mpsCount = 0; for (ErpSaleOrderItemDO item : items) { if (item.getNeedProduction() == null || item.getNeedProduction() != 1) { continue; } try { Long mpsId = createMpsForSaleOrderItem(saleOrder, item); if (mpsId != null) { mpsCount++; // æ´æ°éå®è®¢åæç»ç MPS å ³è saleOrderItemMapper.updateById(new ErpSaleOrderItemDO() .setId(item.getId()) .setMpsId(mpsId)); } } catch (Exception e) { log.error("[createMpsForSaleOrder] å建 MPS 失败ï¼saleOrderItemId={}", item.getId(), e); } } log.info("[createMpsForSaleOrder] éå®è®¢å({}) å®¡æ ¸å®æï¼å建 MPS {} æ¡", orderId, mpsCount); } /** * 为éå®è®¢åæç»å建 MPS */ private Long createMpsForSaleOrderItem(ErpSaleOrderDO saleOrder, ErpSaleOrderItemDO item) { // è·å MDM ç©æä¿¡æ¯ï¼ç¨äºè·å产ååç§°ï¼ String productName = null; try { MdmItemRespDTO mdmItem = mdmItemApi.getItem(item.getProductId()).getCheckedData(); if (mdmItem != null) { productName = mdmItem.getName(); } } catch (Exception e) { log.warn("[createMpsForSaleOrderItem] è·å MDM ç©æä¿¡æ¯å¤±è´¥ï¼productId={}", item.getProductId(), e); } MesProMpsCreateReqDTO createReqDTO = new MesProMpsCreateReqDTO(); createReqDTO.setSaleOrderId(saleOrder.getId()); createReqDTO.setSaleOrderNo(saleOrder.getNo()); createReqDTO.setSaleOrderItemId(item.getId()); createReqDTO.setMdmItemId(item.getProductId()); createReqDTO.setProductName(productName); createReqDTO.setQuantity(item.getCount()); createReqDTO.setClientId(saleOrder.getCustomerId()); createReqDTO.setRequestDate(formatRequestDate(saleOrder.getOrderTime())); createReqDTO.setRemark("èªå¨çæï¼æ¥èªéå®è®¢åï¼" + saleOrder.getNo()); Long mpsId = mpsApi.createMps(createReqDTO); log.info("[createMpsForSaleOrderItem] MPS å建æåï¼mpsId={}, saleOrderItemId={}", mpsId, item.getId()); return mpsId; } /** * æ ¼å¼åéæ±æ¥æ */ private String formatRequestDate(LocalDateTime dateTime) { if (dateTime == null) { return null; } return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); } @Override yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/listener/ErpSaleOrderStatusListener.java
ÎļþÒÑɾ³ý yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/mps/MesProMpsApi.java
@@ -46,4 +46,14 @@ */ List<MesProMpsRespDTO> getMpsListBySaleOrderItemIds(List<Long> saleOrderItemIds); /** * æ£æ¥éå®è®¢åæ¯å¦å¯ä»¥çæåè´§éç¥å * * è§åï¼å¦ææéè¦ç产çæç»ï¼å¯¹åºç MPS å¿ é¡»å·²å®æï¼status=2ï¼æå·²åæ¶ï¼status=3ï¼ * * @param saleOrderItemIds éå®è®¢åæç»IDå表 * @return true=å¯ä»¥çæåè´§éç¥åï¼false=ä¸å¯ä»¥ */ Boolean checkCanCreateSalesNotice(List<Long> saleOrderItemIds); } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/mps/MesProMpsApiImpl.java
@@ -1,9 +1,11 @@ package cn.iocoder.yudao.module.mes.api.mps; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.mes.api.mps.dto.MesProMpsCreateReqDTO; import cn.iocoder.yudao.module.mes.api.mps.dto.MesProMpsRespDTO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.mps.MesProMpsDO; import cn.iocoder.yudao.module.mes.enums.pro.MesProMpsStatusEnum; import cn.iocoder.yudao.module.mes.service.pro.mps.MesProMpsService; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; @@ -11,6 +13,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; /** * MPS API å®ç°ç±» @@ -60,4 +63,36 @@ return BeanUtils.toBean(mpsList, MesProMpsRespDTO.class); } @Override public Boolean checkCanCreateSalesNotice(List<Long> saleOrderItemIds) { if (CollUtil.isEmpty(saleOrderItemIds)) { return true; } List<MesProMpsDO> mpsList = mpsService.getMpsListBySaleOrderItemIds(saleOrderItemIds); // æå»º saleOrderItemId -> MPS çæ å° Map<Long, MesProMpsDO> mpsMap = new java.util.HashMap<>(); for (MesProMpsDO mps : mpsList) { if (mps.getSaleOrderItemId() != null) { mpsMap.put(mps.getSaleOrderItemId(), mps); } } // æ£æ¥æ¯ä¸ªéå®è®¢åæç»ï¼ // - 妿 MPS ä¸åå¨ï¼ä¸è½çæåè´§éç¥å // - 妿 MPS åå¨ä¸ç¶æä¸ºè稿/å·²ä¸åï¼ä¸è½çæåè´§éç¥å // - 妿 MPS åå¨ä¸ç¶æä¸ºå·²å®æ/已忶ï¼å¯ä»¥çæåè´§éç¥å for (Long itemId : saleOrderItemIds) { MesProMpsDO mps = mpsMap.get(itemId); if (mps == null) { // MPS ä¸åå¨ï¼ä¸è½çæåè´§éç¥å return false; } if (mps.getStatus().equals(MesProMpsStatusEnum.DRAFT.getStatus()) || mps.getStatus().equals(MesProMpsStatusEnum.ISSUED.getStatus())) { // MPS æªå®æï¼ä¸è½çæåè´§éç¥å return false; } } return true; } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/oqc/MesQcOqcServiceImpl.java
@@ -13,7 +13,6 @@ import cn.iocoder.yudao.module.mes.enums.qc.MesQcStatusEnum; import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum; import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService; import cn.iocoder.yudao.module.mes.service.qc.indicatorresult.MesQcIndicatorResultService; import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateItemService; @@ -57,9 +56,6 @@ @Resource @Lazy private MesQcDefectRecordService defectRecordService; @Resource @Lazy private MesMdItemService itemService; @Resource @Lazy private MesWmProductSalesLineService productSalesLineService; @@ -121,8 +117,8 @@ // æ ¡éªç¼å·å¯ä¸ validateOqcCodeUnique(reqVO.getId(), reqVO.getCode()); // æ ¡éªç©æãæ£æµäººååå¨ // 注ï¼å®¢æ· ID æ¥èª CRMï¼ä¸éè¦å¨ MES 䏿 ¡éª itemService.validateItemExists(reqVO.getItemId()); // 注ï¼ç©æ ID æ¥èª MDMï¼å®¢æ· ID æ¥èª CRM mdmItemApi.validateItemExists(reqVO.getItemId()); adminUserApi.validateUser(reqVO.getInspectorUserId()); } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transaction/MesWmTransactionServiceImpl.java
@@ -100,12 +100,20 @@ reqDTO.getItemId(), reqDTO.getWarehouseId(), reqDTO.getLocationId(), reqDTO.getAreaId(), reqDTO.getBatchId(), reqDTO.getBatchCode(), reqDTO.getVendorId(), reqDTO.getReceiptTime()); } else { // åºåºäºå¡ï¼åºåè®°å½å¿ 须已åå¨ï¼ä¸å 许èªå¨å建 // åºåºäºå¡ï¼åºåè®°å½å¿ 须已åå¨ï¼ä¸å 许èªå¨å建ï¼é¤é checkFlag=false å 许è´åºåï¼ materialStock = materialStockService.getMaterialStockByCompositeKey( reqDTO.getItemId(), reqDTO.getWarehouseId(), reqDTO.getLocationId(), reqDTO.getAreaId(), reqDTO.getBatchId(), reqDTO.getVendorId()); if (materialStock == null) { throw exception(WM_MATERIAL_STOCK_NOT_EXISTS); // checkFlag=false æ¶å 许è´åºåï¼èªå¨å建åºåè®°å½ï¼æ°éå°ä» 0 æ£åä¸ºè´æ°ï¼ boolean allowNegative = !ObjUtil.defaultIfNull(reqDTO.getCheckFlag(), true); if (allowNegative) { materialStock = materialStockService.getOrCreateMaterialStock( reqDTO.getItemId(), reqDTO.getWarehouseId(), reqDTO.getLocationId(), reqDTO.getAreaId(), reqDTO.getBatchId(), reqDTO.getBatchCode(), reqDTO.getVendorId(), reqDTO.getReceiptTime()); } else { throw exception(WM_MATERIAL_STOCK_NOT_EXISTS); } } } if (materialStock == null || materialStock.getId() == null) {