docs/sale_order_production_status.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,118 @@ # éå®è®¢åçäº§ç¶æ - å端èè°æ¹æ¡ ## æ¶åé¡µé¢ - éå®è®¢åå表页 - éå®è®¢å详æ 页 ## ä¸å¡æµç¨ ``` éå®è®¢åå®¡æ ¸éè¿ â å建 MPS â ä¸å MPS çæç产工å â ç产æ¥å·¥ â è´¨æ£(å¦éè¦) â çäº§å®æ â æ´æ°éå®è®¢åçäº§ç¶æ ``` **çäº§å®æå¤ææ¡ä»¶**ï¼ 1. å·²ç产æ°é >= è®¡åæ°é 2. æææ¥å·¥åç¶æä¸º FINISHEDï¼ç¡®ä¿è´¨æ£å®æï¼ ## API ### éå®è®¢åæ¥è¯¢æ¥å£ï¼å·²æï¼ååºæ°å¢åæ®µï¼ | æ¹æ³ | è·¯å¾ | 说æ | |------|------|------| | GET | /erp/sale-order/page | éå®è®¢åå页æ¥è¯¢ | | GET | /erp/sale-order/get | éå®è®¢åè¯¦æ æ¥è¯¢ | **ååºå段æ°å¢ï¼** | åæ®µ | ç±»å | 说æ | |------|------|------| | productionStatus | Integer | çäº§ç¶æï¼0-æªå®æï¼1-已宿 | | productionFinishTime | DateTime | çäº§å®ææ¶é´ | **ååºç¤ºä¾ï¼** ```json { "code": 0, "data": { "id": 1024, "no": "XS20260718001", "status": 2, "customerId": 1001, "customerName": "æµè¯å®¢æ·", "productionStatus": 1, "productionFinishTime": "2026-07-18 16:30:00", "needProduction": 1, "canCreateSalesNotice": true, "items": [...] } } ``` ## åæ®µå±ç¤ºè§å ### å表页 | åæ®µ | å±ç¤ºä½ç½® | 说æ | |------|----------|------| | productionStatus | å表 | æ ç¾å½¢å¼ï¼0=æªå®æ(ç°è²)ï¼1=已宿(绿è²) | | productionFinishTime | å表ï¼å¯éï¼ | ä» å½ productionStatus=1 æ¶å±ç¤º | ### 详æ 页 | åæ®µ | å±ç¤ºä½ç½® | 说æ | |------|----------|------| | productionStatus | åºæ¬ä¿¡æ¯åºå | æ ç¾å½¢å¼å±ç¤º | | productionFinishTime | åºæ¬ä¿¡æ¯åºå | ä» å½ productionStatus=1 æ¶å±ç¤º | ## ä¸å¡è§å说æ | åºæ¯ | è§å | |------|------| | çäº§ç¶æåå§å¼ | éå®è®¢åå®¡æ ¸éè¿æ¶ï¼productionStatus é»è®¤ä¸º 0ï¼æªå®æï¼ | | çäº§ç¶ææ´æ°æ¶æº | 彿æå ³èçç产订å宿æ¶ï¼ç³»ç»èªå¨æ´æ°ä¸º 1ï¼å·²å®æï¼ | | çäº§å®æå¤æ | å·²ç产æ°é >= è®¡åæ°é ä¸ æææ¥å·¥å已宿ï¼å«è´¨æ£å®æï¼ | | åè´§éç¥åçæ | å½ productionStatus=1 æ¶ï¼canCreateSalesNotice 为 true | ## å±ç¤ºé»è¾è¯´æ | æ¡ä»¶ | å±ç¤ºå 容 | |------|----------| | needProduction !== 1ï¼æ éçäº§ï¼ | æ¾ç¤º"æ éç产"æ"-" | | productionStatus === 0 | æ¾ç¤ºç°è²æ ç¾"æªå®æ" | | productionStatus === 1 | æ¾ç¤ºç»¿è²æ ç¾"已宿"ï¼å¹¶å±ç¤ºå®ææ¶é´ | ## å顺åºå»ºè®® çäº§ç¶æå建议æ¾å¨"åºåºç¶æ"åä¹åã ## ç鿡件ï¼å¯éï¼ å¦éæçäº§ç¶æçéï¼å¯æ°å¢ä¸æçéï¼ - å ¨é¨ - æªå®æ - 已宿 注æï¼çéæ¶ä» æ¥è¯¢ `needProduction=1` ç订åã ## 注æäºé¡¹ 1. **ç¶æèå¨**ï¼`productionStatus` ä¸ `canCreateSalesNotice` å ³èï¼ç产æªå®ææ¶æ æ³çæåè´§éç¥å 2. **æ éç产ç订å**ï¼`needProduction !== 1` ç订åï¼`productionStatus` åæ®µä¸º nullï¼åç«¯åºæ¾ç¤º"æ éç产"æä¸æ¾ç¤º 3. **宿¶æ§**ï¼çäº§ç¶æç±å端èªå¨æ´æ°ï¼åç«¯å·æ°é¡µé¢å³å¯çå°ææ°ç¶æ ## 宿´æµç¨ç¤ºä¾ 1. ç¨æ·å建éå®è®¢åï¼æç»å¾é"éè¦ç产"ï¼ 2. éå®è®¢åå®¡æ ¸éè¿ â ç³»ç»èªå¨å建 MPS 3. MPS ä¸å â çæç产工å 4. ç产æ¥å·¥ â æ¥å·¥å®¡æ¹ - å ³é®å·¥åº+鿣éªï¼æ¥å·¥ç¶æâå¾ æ£éªâè´¨æ£å®æâ已宿 - å ¶ä»å·¥åºï¼æ¥å·¥å®¡æ¹åç´æ¥â已宿 5. æææ¥å·¥å®æ â ç³»ç»èªå¨æ´æ°éå®è®¢å productionStatus=1 6. ç¨æ·å·æ°éå®è®¢å页é¢ï¼çå°"çäº§å®æ"ç¶æ 7. ç¨æ·å¯çæåè´§éç¥å sql/mes_item_id_migration.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,303 @@ -- ============================================================ -- MES ç©æ ID è¿ç§»èæ¬ -- ç®çï¼å° mes_md_item.id æ´æ°ä¸ºä¸ mdm_item.id ä¸è´ -- æ§è¡å请å¤ä»½æ°æ®åºï¼ -- ============================================================ -- 1. åå»ºä¸´æ¶æ å°è¡¨ DROP TEMPORARY TABLE IF EXISTS tmp_item_id_mapping; CREATE TEMPORARY TABLE tmp_item_id_mapping ( old_id BIGINT NOT NULL, new_id BIGINT NOT NULL, code VARCHAR(64), PRIMARY KEY (old_id) ); -- 2. æå ¥éè¦è¿ç§»çç©ææ å°æ°æ® INSERT INTO tmp_item_id_mapping (old_id, new_id, code) SELECT id, mdm_item_id, code FROM mes_md_item WHERE mdm_item_id IS NOT NULL AND id != mdm_item_id; -- æ¥çéè¦è¿ç§»çæ°æ® SELECT * FROM tmp_item_id_mapping; -- 3. ç¦ç¨å¤é®æ£æ¥ï¼é¿å å¤é®çº¦æé»æ¢æ´æ°ï¼ SET FOREIGN_KEY_CHECKS = 0; -- 4. æ´æ°ææå¼ç¨ mes_md_item.id ç表 -- 注æï¼ä»¥ä¸è¯å¥ä¼æ´æ°ææ item_id åæ®µ -- 4.1 åºç¡æ°æ®è¡¨ UPDATE mes_md_item_batch_config t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_md_product_bom t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_md_product_sip t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_md_product_sop t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; -- 4.2 ç产ç¸å ³è¡¨ UPDATE mes_pro_card t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_pro_feedback t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_pro_route_product t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_pro_route_product_bom t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_pro_task t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_pro_task_issue t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_pro_work_order_bom t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; -- 4.3 è´¨éç¸å ³è¡¨ UPDATE mes_qc_indicator_result t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_qc_ipqc t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_qc_iqc t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_qc_oqc t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_qc_rqc t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_qc_template_item t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; -- 4.4 ä»åºç®¡ç表 - å ¥åº UPDATE mes_wm_arrival_notice_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_item_receipt_detail t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_item_receipt_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_misc_receipt_detail t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_misc_receipt_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_outsource_receipt_detail t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_outsource_receipt_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_product_receipt_detail t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_product_receipt_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; -- 4.5 ä»åºç®¡ç表 - åºåº UPDATE mes_wm_item_consume_detail t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_item_consume_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_misc_issue_detail t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_misc_issue_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_outsource_issue_detail t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_outsource_issue_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_product_issue_detail t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_product_issue_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_return_issue_detail t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_return_issue_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; -- 4.6 ä»åºç®¡ç表 - éå®/éè´§ UPDATE mes_wm_product_sales_detail t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_product_sales_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_return_sales_detail t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_return_sales_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_return_vendor_detail t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_return_vendor_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_sales_notice_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; -- 4.7 ä»åºç®¡ç表 - å ¶ä» UPDATE mes_wm_batch t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_material_stock t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_package_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_sn t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_stock_reserve t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_stock_taking_plan_param t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_stock_taking_task_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_stock_taking_task_result t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_transaction t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_transfer_detail t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_transfer_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; -- 4.8 ç产产åºè¡¨ UPDATE mes_wm_product_produce_detail t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; UPDATE mes_wm_product_produce_line t JOIN tmp_item_id_mapping m ON t.item_id = m.old_id SET t.item_id = m.new_id; -- 5. æ´æ°ä¸»è¡¨ mes_md_item ç id -- ç±äº id æ¯ä¸»é®ï¼éè¦å å 餿§è®°å½åæå ¥æ°è®°å½ -- å建临æ¶è¡¨ä¿å宿´æ°æ® DROP TEMPORARY TABLE IF EXISTS tmp_mes_md_item; CREATE TEMPORARY TABLE tmp_mes_md_item AS SELECT * FROM mes_md_item; -- å é¤éè¦è¿ç§»çè®°å½ DELETE FROM mes_md_item WHERE id IN (SELECT old_id FROM tmp_item_id_mapping); -- ä½¿ç¨æ° ID éæ°æå ¥ INSERT INTO mes_md_item ( id, mdm_item_id, code, name, specification, unit_measure_id, item_type_id, status, safe_stock_flag, min_stock, max_stock, high_value, batch_flag, remark, creator, create_time, updater, update_time, deleted ) SELECT m.new_id AS id, -- ä½¿ç¨ MDM ç©æ ID t.mdm_item_id, t.code, t.name, t.specification, t.unit_measure_id, t.item_type_id, t.status, t.safe_stock_flag, t.min_stock, t.max_stock, t.high_value, t.batch_flag, t.remark, t.creator, t.create_time, t.updater, t.update_time, t.deleted FROM tmp_mes_md_item t JOIN tmp_item_id_mapping m ON t.id = m.old_id; -- 6. éæ°å¯ç¨å¤é®æ£æ¥ SET FOREIGN_KEY_CHECKS = 1; -- 7. æ¸ ç临æ¶è¡¨ DROP TEMPORARY TABLE IF EXISTS tmp_item_id_mapping; DROP TEMPORARY TABLE IF EXISTS tmp_mes_md_item; -- 8. éªè¯è¿ç§»ç»æ SELECT id, mdm_item_id, code, name FROM mes_md_item WHERE mdm_item_id IS NOT NULL; -- æ£æ¥æ¯å¦è¿æ id != mdm_item_id çè®°å½ SELECT COUNT(*) AS need_migration_count FROM mes_md_item WHERE mdm_item_id IS NOT NULL AND id != mdm_item_id; yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderRespVO.java
@@ -115,6 +115,14 @@ @Schema(description = "æ¯å¦æéè¦ç产çæç»ï¼0=å¦ 1=æ¯ï¼", example = "1") private Integer needProduction; // ========== çäº§å ³è ========== @Schema(description = "çäº§ç¶æï¼0-æªå®æï¼1-已宿", example = "1") private Integer productionStatus; @Schema(description = "çäº§å®ææ¶é´") private LocalDateTime productionFinishTime; @Data public static class Item { yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/sale/ErpSaleOrderDO.java
@@ -128,4 +128,16 @@ */ private Integer outStatus; // ========== çäº§å ³è ========== /** * çäº§ç¶æï¼0-æªå®æï¼1-已宿 */ private Integer productionStatus; /** * çäº§å®ææ¶é´ */ private LocalDateTime productionFinishTime; } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/listener/ProductionFinishedListener.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,40 @@ package cn.iocoder.yudao.module.erp.service.sale.listener; import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderDO; import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOrderMapper; import cn.iocoder.yudao.module.mes.api.event.ProductionFinishedEvent; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; /** * çäº§å®æäºä»¶çå¬å¨ * * çå¬ MES 模ååå¸ç ProductionFinishedEventï¼æ´æ°éå®è®¢åççäº§ç¶æ * * @author èéæºç */ @Component @Slf4j public class ProductionFinishedListener { @Resource private ErpSaleOrderMapper saleOrderMapper; @EventListener @Async public void onProductionFinished(ProductionFinishedEvent event) { log.info("[onProductionFinished] æ¶å°çäº§å®æäºä»¶ï¼éå®è®¢åID: {}", event.getSaleOrderId()); // æ´æ°éå®è®¢åççäº§ç¶æ saleOrderMapper.updateById(new ErpSaleOrderDO() .setId(event.getSaleOrderId()) .setProductionStatus(1) .setProductionFinishTime(event.getFinishTime())); log.info("[onProductionFinished] éå®è®¢å {} çäº§ç¶æå·²æ´æ°ä¸ºå®æ", event.getSaleOrderId()); } } yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/event/ProductionFinishedEvent.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,31 @@ package cn.iocoder.yudao.module.mes.api.event; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.time.LocalDateTime; /** * çäº§å®æäºä»¶ * * å½éå®è®¢åå ³èçææç产订å宿æ¶å叿¤äºä»¶ * * @author èéæºç */ @Data @NoArgsConstructor @AllArgsConstructor public class ProductionFinishedEvent { /** * éå®è®¢åID */ private Long saleOrderId; /** * 宿æ¶é´ */ private LocalDateTime finishTime; } yudao-module-mes-api/src/main/java/cn/iocoder/yudao/module/mes/api/mps/MesProMpsApi.java
@@ -56,4 +56,24 @@ */ Boolean checkCanCreateSalesNotice(List<Long> saleOrderItemIds); /** * æ£æ¥éå®è®¢åçææ MPS æ¯å¦å·²å®æç产 * * 宿æ¡ä»¶ï¼ * 1. å·²ç产æ°é >= è®¡åæ°é * 2. æææ¥å·¥åç¶æä¸º FINISHEDï¼ç¡®ä¿è´¨æ£å®æï¼ * * @param saleOrderId éå®è®¢åID * @return true=å ¨é¨å®æï¼false=æªå ¨é¨å®æ */ Boolean checkSaleOrderProductionFinished(Long saleOrderId); /** * æ ¹æ®å·¥åIDè·å MPS * * @param workOrderId å·¥åID * @return MPS ä¿¡æ¯ */ MesProMpsRespDTO getMpsByWorkOrderId(Long workOrderId); } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/item/MesMdItemApiImpl.java
@@ -43,8 +43,12 @@ @Override public Long createItem(MesMdItemSyncReqDTO syncReqDTO) { log.info("[createItem] 忥å建 MES ç©æäº§åï¼code={}", syncReqDTO.getCode()); log.info("[createItem] 忥å建 MES ç©æäº§åï¼code={}, mdmItemId={}", syncReqDTO.getCode(), syncReqDTO.getMdmItemId()); MesMdItemSaveReqVO saveReqVO = buildSaveReqVO(syncReqDTO); // ä½¿ç¨ MDM ç©æ ID ä½ä¸º MES ç©æ ID if (syncReqDTO.getMdmItemId() != null) { saveReqVO.setId(syncReqDTO.getMdmItemId()); } Long itemId = itemService.createItem(saveReqVO); // åæ¥æ¹æ¬¡é ç½® // saveBatchConfig(itemId, syncReqDTO); @@ -53,10 +57,22 @@ @Override public void updateItem(MesMdItemSyncReqDTO syncReqDTO) { log.info("[updateItem] åæ¥æ´æ° MES ç©æäº§åï¼code={}", syncReqDTO.getCode()); log.info("[updateItem] åæ¥æ´æ° MES ç©æäº§åï¼code={}, mdmItemId={}", syncReqDTO.getCode(), syncReqDTO.getMdmItemId()); MesMdItemSaveReqVO saveReqVO = buildSaveReqVO(syncReqDTO); // æ code å¹é ï¼åå¨åæ´æ°ï¼ä¸åå¨åå建ï¼upsertï¼ MesMdItemDO existItem = itemService.getItemByCode(syncReqDTO.getCode()); // ä½¿ç¨ MDM ç©æ ID ä½ä¸º MES ç©æ ID if (syncReqDTO.getMdmItemId() != null) { saveReqVO.setId(syncReqDTO.getMdmItemId()); } // æ ID æ code å¹é ï¼åå¨åæ´æ°ï¼ä¸åå¨åå建ï¼upsertï¼ MesMdItemDO existItem = null; // ä¼å æ ID æ¥æ¾ if (syncReqDTO.getMdmItemId() != null) { existItem = itemService.getItem(syncReqDTO.getMdmItemId()); } // 妿æ ID æ¾ä¸å°ï¼åæ code æ¥æ¾ if (existItem == null) { existItem = itemService.getItemByCode(syncReqDTO.getCode()); } Long itemId; if (existItem == null) { itemId = itemService.createItem(saveReqVO); yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/api/mps/MesProMpsApiImpl.java
@@ -95,4 +95,15 @@ return true; } @Override public Boolean checkSaleOrderProductionFinished(Long saleOrderId) { return mpsService.checkSaleOrderProductionFinished(saleOrderId); } @Override public MesProMpsRespDTO getMpsByWorkOrderId(Long workOrderId) { MesProMpsDO mps = mpsService.getMpsByWorkOrderId(workOrderId); return BeanUtils.toBean(mps, MesProMpsRespDTO.class); } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdItemServiceImpl.java
@@ -77,6 +77,16 @@ // æ ¡éªæ°æ® validateItemSaveData(createReqVO); // 妿æå®äº IDï¼æ£æ¥è¯¥ ID æ¯å¦å·²åå¨ï¼ç¨äº MDM 忥æ¶ä¿æ ID ä¸è´ï¼ if (createReqVO.getId() != null) { MesMdItemDO existItem = itemMapper.selectById(createReqVO.getId()); if (existItem != null) { // ID å·²åå¨ï¼è½¬ä¸ºæ´æ° updateItem(createReqVO); return createReqVO.getId(); } } // æå ¥ MesMdItemDO item = BeanUtils.toBean(createReqVO, MesMdItemDO.class); item.setStatus(CommonStatusEnum.DISABLE.getStatus()); // é»è®¤ç¦ç¨ãä¿¡æ¯å®æåï¼åå¯ç¨ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
@@ -26,7 +26,11 @@ 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 cn.iocoder.yudao.module.mes.api.mps.MesProMpsApi; import cn.iocoder.yudao.module.mes.api.mps.dto.MesProMpsRespDTO; import cn.iocoder.yudao.module.mes.api.event.ProductionFinishedEvent; import jakarta.annotation.Resource; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -67,6 +71,10 @@ private MesWmProductProduceService productProduceService; @Resource private MesWmProductProduceLineService produceLineService; @Resource private MesProMpsApi mpsApi; @Resource private ApplicationEventPublisher eventPublisher; @Override public Long createFeedback(MesProFeedbackSaveReqVO createReqVO) { @@ -247,6 +255,25 @@ // 3. æ´æ°å·¥åçå·²ç产æ°é workOrderService.updateProducedQuantity(feedback.getWorkOrderId(), feedback.getFeedbackQuantity()); // 4. æ£æ¥å¹¶åå¸çäº§å®æäºä»¶ checkAndPublishProductionFinished(feedback.getWorkOrderId()); } /** * æ£æ¥å¹¶åå¸çäº§å®æäºä»¶ */ private void checkAndPublishProductionFinished(Long workOrderId) { // 1. è·åå·¥åå ³èç MPS MesProMpsRespDTO mps = mpsApi.getMpsByWorkOrderId(workOrderId); if (mps == null || mps.getSaleOrderId() == null) { return; // ééå®è®¢åæ¥æºçå·¥åï¼è·³è¿ } // 2. æ£æ¥éå®è®¢åææç产æ¯å¦å®æ if (mpsApi.checkSaleOrderProductionFinished(mps.getSaleOrderId())) { eventPublisher.publishEvent(new ProductionFinishedEvent(mps.getSaleOrderId(), java.time.LocalDateTime.now())); } } // ==================== æ ¡éªæ¹æ³ ==================== yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsService.java
@@ -145,4 +145,24 @@ */ void updateProducedQuantity(Long id, BigDecimal incrQuantity); /** * æ£æ¥éå®è®¢åçææ MPS æ¯å¦å·²å®æç产 * * 宿æ¡ä»¶ï¼ * 1. å·²ç产æ°é >= è®¡åæ°é * 2. æææ¥å·¥åç¶æä¸º FINISHEDï¼ç¡®ä¿è´¨æ£å®æï¼ * * @param saleOrderId éå®è®¢åID * @return true=å ¨é¨å®æï¼false=æªå ¨é¨å®æ */ Boolean checkSaleOrderProductionFinished(Long saleOrderId); /** * æ ¹æ®å·¥åIDè·å MPS * * @param workOrderId å·¥åID * @return MPS */ MesProMpsDO getMpsByWorkOrderId(Long workOrderId); } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/mps/MesProMpsServiceImpl.java
@@ -12,7 +12,10 @@ 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.dataobject.pro.feedback.MesProFeedbackDO; 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; @@ -61,6 +64,8 @@ private MesMdAutoCodeRecordService autoCodeRecordService; @Resource private CrmCustomerApi customerApi; @Resource private MesProFeedbackMapper feedbackMapper; @Override @Transactional(rollbackFor = Exception.class) @@ -331,6 +336,57 @@ 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); } /** * 夿å个 MPS æ¯å¦å®æ */ private boolean isMpsFinished(MesProMpsDO mps) { // 1. å·²ç产æ°é >= è®¡åæ°é BigDecimal quantityProduced = ObjUtil.defaultIfNull(mps.getQuantityProduced(), BigDecimal.ZERO); if (quantityProduced.compareTo(mps.getQuantity()) < 0) { 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())); if (unfinishedCount > 0) { return false; } } return true; } // ========== ç§ææ¹æ³ ========== /**