docs/qc_bpm_migration_plan.md
@@ -13,11 +13,12 @@ - åæ£åæ ¼è¿å ¥é¨é¨å®¡æ¹ï¼åæ£ä¸åæ ¼å 夿£ï¼é¨é¨å®¡æ¹å®æåï¼ä¸¤æ¡çº¿æ±åå°å ¬å¸è´¨æ£å®¡æ¹ãéè´§å¤æ£ç»æè¿å ¥éå®é¨å®¡æ¹ã - BPM åè°ææµç¨å®ä¾ç¼å·å¹é è®°å½ï¼å®¡æ¹é©³å忏 ç对åºå®ä¾ç¼å·ï¼ä»¥ä¾¿éæ£åéæ°åèµ·ã - è´¨æ£è®°å½é¡µæä¾ BPM 详æ å ¥å£ï¼æµç¨å¯å¨å¤±è´¥æ¶å¯å¯¹è¯¥è®°å½éæ°åèµ·ã - ä¸ä»½ BPMN 模åæä»¶ä½äº `yudao-module-mes/src/main/resources/bpm/`ï¼åé人æä¸ºå½åæ°æ®åºé»è®¤ admin ç¨æ· ID 1ã - é¨é¨å®¡æ¹æå为å å·¥é¨ãéå®é¨ä¸¤ä¸ªç¬ç«æµç¨æ¨¡åï¼å 工鍿²¿ç¨ `mes_seed_quality_line_approve`ï¼éå®é¨æ°å¢ `mes_seed_quality_sales_line_approve`ï¼åèµ·å®¡æ¹æ¶æ `qcLine` éæ©å¯¹åºæµç¨å®ä¹ã - å份 BPMN 模åæä»¶ä½äº `yudao-module-mes/src/main/resources/bpm/`ï¼åé人æä¸ºå½åæ°æ®åºé»è®¤ admin ç¨æ· ID 1ã ## ä¸çº¿åç½®å·¥ä½ - å¨ BPM æµç¨æ¨¡å管çä¸å¯¼å ¥å¹¶åå¸ä¸ä»½ BPMN æä»¶ï¼æµç¨å®ä¹ key å¿ é¡»ä¸æä»¶ä¸ `process id` ä¸è´ãå¯ç¨ `scripts/deploy-seed-quality-bpm.ps1 -ApiBaseUrl <管çåå° API æ ¹å°å> -AccessToken <admin 令ç>` åå»ºææ´æ°å¹¶åå¸ãèæ¬æ¾å¼è®¾ç½® adminï¼ç¨æ· ID 1ï¼ä¸ºå®¡æ¹äººä¸ç¦ç¨èªå¨å®¡æ¹ï¼ç®æ ç¯å¢ä¸åºå 确认 admin ç ID 为 1ã - å¨ BPM æµç¨æ¨¡å管çä¸å¯¼å ¥å¹¶åå¸å份 BPMN æä»¶ï¼æµç¨å®ä¹ key å¿ é¡»ä¸æä»¶ä¸ `process id` ä¸è´ãå¯ç¨ `scripts/deploy-seed-quality-bpm.ps1 -ApiBaseUrl <管çåå° API æ ¹å°å> -AccessToken <admin 令ç>` åå»ºææ´æ°å¹¶åå¸ãèæ¬æ¾å¼è®¾ç½® adminï¼ç¨æ· ID 1ï¼ä¸ºå®¡æ¹äººä¸ç¦ç¨èªå¨å®¡æ¹ï¼ç®æ ç¯å¢ä¸åºå 确认 admin ç ID 为 1ã - æ§è¡ `sql/mysql/mes_seed_quality_dual_line_20261105.sql`ï¼ç¡®ä¿ `qc_line`ã`biz_type`ãæµç¨å®ä¾å段åå线å¯ä¸ç´¢å¼å·²å°±ç»ªã - å¤çæ§çå¨é人工审æ¹è®°å½åå·²ç»äº§çç BPM æµç¨å®ä¾ï¼é¿å æ°æ§ç¶ææ··ç¨ã - ä¸ä¸ª BPM æµç¨åå¸å¹¶å®æå¨éæ°æ®å¤çåï¼æ§è¡ `sql/mysql/mes_qc_approver_menu_retire_20261106.sql` éèæ§å®¡æ ¸äººé ç½®èåãåå²é ç½®æ°æ®ä¸å é¤ã docs/qc_seed_quality_dual_line_integration.md
@@ -11,7 +11,7 @@ 1. å å·¥é¨å¼éå®å ¥åºï¼è¢ç å ¥åºå坿«ç è´¨æ£ï¼æçç æ¯ 48 è¢æ 100 è¢çæï¼æ¹æ¬¡ç å¸¦åºæ´æ¹è¢æ°ã 2. **䏿¬¡ç§åè´¨æ£æäº¤å³åæ¶çæä¸¤æ¡è´¨æ£è®°å½**ï¼`qcLine=1`ï¼å å·¥é¨ï¼ä¸ `qcLine=2`ï¼éå®é¨ï¼ï¼ä¸¤æ¡è®°å½çææ ãç»è®ºå®å ¨ä¸è´ï¼åç»å¤æ£ã审æ¹åå«æè´¨æ£çº¿ç¬ç«è¿è¡ã 3. åæ£åæ ¼ç´æ¥è¿å ¥æ¬çº¿é¢å¯¼ BPM 审æ¹ï¼åæ£ä¸åæ ¼å 夿£ï¼åè¿å ¥æ¬çº¿é¢å¯¼å®¡æ¹ãé¨é¨å®¡æ¹é©³åå鿰忣ã 4. 两æ¡çº¿åå«ä½¿ç¨æµç¨å®ä¹ `mes_seed_quality_line_approve`ï¼businessKey 为 `è´¨æ£çº¿#çäº§æ¹æ¬¡å·`ï¼å®¡æ¹éè¿åè¿å ¥å ¬å¸è´¨æ£å¾ å®¡ç¶æã 4. 两æ¡çº¿ä½¿ç¨åèªçæµç¨å®ä¹ï¼å å·¥é¨ `mes_seed_quality_line_approve`ãéå®é¨ `mes_seed_quality_sales_line_approve`ï¼businessKey å为 `è´¨æ£çº¿#çäº§æ¹æ¬¡å·`ï¼å®¡æ¹éè¿åè¿å ¥å ¬å¸è´¨æ£å¾ å®¡ç¶æã 5. åä¸çäº§æ¹æ¬¡å ææè¢ç两æ¡çº¿é½å®æé¨é¨å®¡æ¹åï¼ç³»ç»èªå¨åèµ·**䏿¬¡**å ¬å¸è´¨æ£å®¡æ¹ï¼æµç¨å®ä¹ `mes_seed_quality_company_approve`ï¼businessKey 为**çäº§æ¹æ¬¡å·**ï¼ãå ¬å¸å®¡æ¹**ææ¹æ¬¡åèµ·ãæè¢è½åº**ï¼æ¯ä¸ªè¢ä¸¤æ¡çº¿é½ä¸ºåæ ¼ææ¾è¡å ¥åºï¼ä»»ä¸æ¡ä¸åæ ¼åè¯¥è¢æ¥åºï¼é©³ååæ´æ¹ä¸¤æ¡çº¿ä¸èµ·éåå¾ å¤æ£ã 6. æ¾è¡åäº§åæ£å¼å ¥åºï¼åç»åºç®¡æ«ç åºåºãéå®è½¬ç§»ç»éåãç»ç«¯åæ·æ«ç 溯æºã 7. ç»éåéè´§åæ¯ï¼éå®éè´§å确认ååèµ·éè´§è´¨æ£ â 夿£ â éå®é¨é¢å¯¼å®¡æ¹ï¼ä¸åæ ¼åéè´§åèªå¨åæ¶ãä¸äºéè´§å¹¶ä¿çæ£éªè®°å½ã @@ -99,10 +99,12 @@ | æµç¨å®ä¹ key | businessKey | æµç¨åé | |---|---|---| | `mes_seed_quality_line_approve` | `{qcLine}#{çäº§æ¹æ¬¡å·}` | `qcLine`ã`batchCode` | | `mes_seed_quality_sales_line_approve` | `{qcLine}#{çäº§æ¹æ¬¡å·}` | `qcLine`ã`batchCode` | | `mes_seed_quality_company_approve` | çäº§æ¹æ¬¡å· | `batchCode`ã`code`ï¼å ¼å®¹æ§æµç¨ï¼ã`passed` | | `mes_seed_return_approve` | éå®éè´§åç¼å· | `returnSalesId`ã`returnSalesCode`ã`code` | - æµç¨çå¬å¨å¨æµç¨ç»æï¼éè¿/驳åï¼æ¶ååè´¨æ£ç¶æï¼åæ¶ï¼CANCELï¼ä¸æ¹åä¸å¡ç¶æã - æµç¨çå¬å¨åæ¶çå¬å å·¥é¨ä¸éå®é¨ä¸¤ä¸ªæµç¨å®ä¹ï¼æµç¨ç»æï¼éè¿/驳åï¼æ¶ååè´¨æ£ç¶æï¼åæ¶ï¼CANCELï¼ä¸æ¹åä¸å¡ç¶æã - æµç¨è¯¦æ 页ï¼`views/mes/qc/seedQuality/process-detail.vue`ï¼å·²è¯å«æ°å¢ç `mes_seed_quality_sales_line_approve`ï¼å¹¶æè´¨æ£çº¿å±ç¤ºãå å·¥é¨å®¡æ¹ / éå®é¨å®¡æ¹ãæ é¢ã - è¥ BPM æµç¨å®ä¹æªé¨ç½²ï¼åèµ·æµç¨ä¼å¤±è´¥å¹¶è®°å½æ¥å¿ï¼ä¿®å¤é ç½®åå¯éè¿è´¨æ£è®°å½é¡µçâéæ°å起审æ¹âæ¢å¤ãæ°å线记å½ä¸è½ä½¿ç¨äººå·¥å®¡æ¹æ¥å£ã ## åæ®µå±ç¤ºè§å docs/wm_transaction_unit_measure_integration.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,62 @@ # åºåäºå¡æµæ°´è®¡éåä½ï¼è§æ ¼ï¼èè°æ¹æ¡ ## æ¶åé¡µé¢ - ä»å¨ç©æµ -> åºåäºå¡æµæ°´ - ä»å¨ç©æµ -> åºåç°æéï¼å段å½åä¿æä¸è´ï¼ ## ä¸å¡èæ¯ æéæ±ãåºåæµæ°´å¢å è§æ ¼å段ï¼åºåç°æéãåä½ãæ¹ä¸ºãè§æ ¼ãããè§æ ¼åå·ãæ¹ä¸ºãç±»å«ããï¼ - è§æ ¼åå±ç¤ºç©æç计éåä½åç§°ï¼å¦ `48åå `ã`100åå `ï¼ï¼æ°æ®æ¥æºä¸º MDM 计éåä½ã - ç±»å«åå±ç¤ºç©æçè§æ ¼åå·ï¼å¦ `大ç°ç¨ç§`ï¼ã ## API | æ¹æ³ | è·¯å¾ | 说æ | |------|------|------| | GET | /mes/wm/transaction/page | åºåäºå¡æµæ°´å页ï¼ååºæ°å¢åæ®µï¼ | **ååºå段æ°å¢ï¼** | åæ®µ | ç±»å | 说æ | |------|------|------| | unitMeasureName | String | 计éåä½åç§°ï¼æç©æ `unitMeasureId` å ³è MDM 计éåä½å¾å°ï¼æªç»´æ¤æ¶ä¸ºç©º | **ååºç¤ºä¾ï¼** ```json { "code": 0, "data": { "list": [ { "id": 1, "itemId": 1, "itemCode": "9335999888099723", "itemName": "塿²³4å·", "unitMeasureName": "48åå ", "specification": null, "itemTypeName": null, "quantity": 1.00 } ], "total": 1 } } ``` ## åæ®µå±ç¤ºè§å | åæ®µ | å±ç¤ºä½ç½® | åæ é¢ | 说æ | |------|----------|--------|------| | unitMeasureName | åºåäºå¡æµæ°´ãåºåç°æéãåºåéæ©å¼¹çª | è§æ ¼ | 计éåä½åç§° | | specification | åºåäºå¡æµæ°´ãåºåç°æéãåºåéæ©å¼¹çª | ç±»å« | ç©æè§æ ¼åå· | | itemTypeName | ä¸åå±ç¤º | - | æ¥å£ä»è¿åï¼å ¼å®¹æ§è°ç¨ | ## 注æäºé¡¹ - `unitMeasureName` ä¸ºç©ºè¡¨ç¤ºç©ææªç»´æ¤è®¡éåä½ï¼è¯·å å¨ MDM ç©ææ MES åç§ä¸ç»´æ¤ã - åºåç°æéæ¥å£ `/mes/wm/material-stock/page` 忬已è¿å `unitMeasureName`ï¼æ¬æ¬¡ä» è°æ´åç«¯åæ å°ï¼æ æ¥å£ååã - æ¬æ¬¡ä¸ºååå ¼å®¹çååºå段æ°å¢ï¼ä¸æ¶åæ°æ®åºç»æåæ´ã scripts/deploy-seed-quality-bpm.ps1
@@ -13,6 +13,7 @@ # 䏿å½åç»ä¸ä» BPMN æä»¶è¯»åï¼é¿å Windows PowerShell 5.1 æ ANSI è§£æèæ¬å¯¼è´ä¹±ç $models = @( 'mes_seed_quality_line_approve', 'mes_seed_quality_sales_line_approve', 'mes_seed_quality_company_approve', 'mes_seed_return_approve' ) yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/seedquality/MesQcSeedQualityController.java
@@ -86,7 +86,7 @@ @GetMapping("/resolve") @Operation(summary = "è§£æå¾ è´¨æ£è¢ç å确认该è¢è´¨æ£ç»æ") @PreAuthorize("@ss.hasAnyPermissions('mes:qc-seed-quality:submit', 'mes:qc-seed-quality:retest', 'mes:qc-seed-quality:process-approve', 'mes:qc-seed-quality:company-approve')") public CommonResult<java.util.Map<String, Object>> resolve(@RequestParam String code, @RequestParam(defaultValue = "BAG") String scanType, public CommonResult<java.util.Map<String, Object>> resolve(@RequestParam String code, @RequestParam(defaultValue = "AUTO") String scanType, @RequestParam(defaultValue = "1") Integer qcLine) { return success(service.resolveScan(code, scanType, qcLine)); } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/MesWmTransactionController.java
@@ -22,7 +22,9 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum; import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService; import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService; import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService; @@ -73,6 +75,7 @@ @Resource private MesWmProductSalesDetailMapper salesDetailMapper; @Resource private MesMdItemMapper mesMdItemMapper; @Resource private MesMdItemTypeService mesMdItemTypeService; @Resource private MesMdUnitMeasureService unitMeasureService; @GetMapping("/page") @Operation(summary = "è·ååºåäºå¡æµæ°´å页") @@ -100,6 +103,9 @@ mesItemTypeIds.remove(null); Map<Long, MesMdItemTypeDO> mesItemTypeMap = mesItemTypeIds.isEmpty() ? Map.of() : mesMdItemTypeService.getItemTypeMap(mesItemTypeIds); // å ³èæ¥è¯¢è®¡éåä½ï¼è§æ ¼åå±ç¤ºè®¡éåä½åç§° Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap( convertSet(itemMap.values(), MesMdmItemDO::getUnitMeasureId)); // å ³èæ¥è¯¢ä»åºä¿¡æ¯ Map<Long, MesWmWarehouseDO> warehouseMap = warehouseService.getWarehouseMap( convertSet(pageResult.getList(), MesWmTransactionDO::getWarehouseId)); @@ -152,6 +158,10 @@ // è§æ ¼ï¼åç§ç®¡çæªç»´æ¤æ¶ï¼åéå MES ç©æè§æ ¼åå· vo.setSpecification(StrUtil.blankToDefault(item.getSpecification(), mesItem != null ? mesItem.getSpecification() : null)); MesMdUnitMeasureDO unitMeasure = unitMeasureMap.get(item.getUnitMeasureId()); if (unitMeasure != null) { vo.setUnitMeasureName(unitMeasure.getName()); } // ç±»å«ï¼ä¼å åç§åç±»ï¼å ¶æ¬¡ MES ç©æåç±» MdmItemCategoryRespDTO category = itemCategoryMap.get(item.getCategoryId()); String itemTypeName = category != null ? category.getName() : null; yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transaction/vo/MesWmTransactionRespVO.java
@@ -45,6 +45,9 @@ @Schema(description = "è§æ ¼åå·", example = "10mm*100mm") private String specification; @Schema(description = "计éåä½åç§°", example = "48åå ") private String unitMeasureName; @Schema(description = "ç©æç±»å«åç§°", example = "äºéé ä»¶") private String itemTypeName; yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
@@ -12,9 +12,11 @@ import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualitySubmitReqVO; import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedReturnQualitySubmitReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO; import cn.iocoder.yudao.module.mes.framework.qrcode.MesTraceCodeUtils; import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.*; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesDO; @@ -78,8 +80,10 @@ private static final int QC_LINE_PROCESS = 1, QC_LINE_SALES = 2; /** ä¸å¡ç±»åï¼1 çäº§å ¥åºè´¨æ£ï¼2 ç»éåéè´§è´¨æ£ */ private static final int BIZ_TYPE_PRODUCTION = 1, BIZ_TYPE_RETURN = 2; /** æ¬çº¿é¢å¯¼å®¡æ¹æµç¨å®ä¹æ è¯ */ /** å å·¥é¨é¢å¯¼å®¡æ¹æµç¨å®ä¹æ è¯ */ private static final String LINE_PROCESS_KEY = "mes_seed_quality_line_approve"; /** éå®é¨é¢å¯¼å®¡æ¹æµç¨å®ä¹æ è¯ */ private static final String SALES_LINE_PROCESS_KEY = "mes_seed_quality_sales_line_approve"; /** å ¬å¸è´¨æ£å®¡æ¹æµç¨å®ä¹æ è¯ */ private static final String COMPANY_PROCESS_KEY = "mes_seed_quality_company_approve"; /** ç»éåéè´§è´¨æ£å®¡æ¹æµç¨å®ä¹æ è¯ */ @@ -194,7 +198,7 @@ @Override public Map<String, Object> resolveScan(String code) { MesProBagCodeDO bag = bagCodeMapper.selectByScanCode(code); MesProBagCodeDO bag = bagCodeMapper.selectByScanCode(MesTraceCodeUtils.extractCode(code)); if (bag == null) throw new IllegalArgumentException("æªè§£æå°ææè¢ç ï¼è¯·æ«æè¢ç "); Map<String, Object> result = new HashMap<>(); result.put("code", bag.getCode()); @@ -227,28 +231,66 @@ return result; } private record Scope(String code, String businessCode, String batchCode, boolean canceled, List<MesProBagCodeDO> bags) { } private record Scope(String type, String code, String businessCode, String batchCode, boolean canceled, List<MesProBagCodeDO> bags) { } /** æ«ç ç±»åï¼ç±ç å¼èªå¨è¯å«è¢ç / æçç / çäº§æ¹æ¬¡ç */ private static final String SCAN_TYPE_AUTO = "AUTO"; private Scope scope(String code, String type, boolean lock) { // æ ç¾äºç»´ç å 容å¯è½æ¯æ´æ®µè¿½æº¯é¾æ¥ï¼å æè§£ä¸ºçº¯ç å¼åå¹é code = MesTraceCodeUtils.extractCode(code); if (StrUtil.isBlank(type) || SCAN_TYPE_AUTO.equalsIgnoreCase(type)) { return autoScope(code, lock); } if ("BAG".equals(type)) { MesProBagCodeDO bag = bagCodeMapper.selectByScanCode(code); if (bag == null) throw invalidParamException("æªæ¾å°è¢ç ï¼è¯·æ ¸å¯¹æ«ç ç±»ååç å¼"); return new Scope(bag.getCode(), bag.getBusinessCode(), bag.getBatchCode(), Integer.valueOf(30).equals(bag.getStatus()), List.of(bag)); return bagScope(bag); } if ("PALLET".equals(type)) { var pallet = lock ? palletMapper.selectByScanCodeForUpdate(code) : palletMapper.selectByScanCode(code); if (pallet == null) throw invalidParamException("æªæ¾å°æçç ï¼è¯·æ ¸å¯¹æ«ç ç±»ååç å¼"); if (pallet.getBatchId() == null) throw invalidParamException("æçå°æªç»å®çäº§æ¹æ¬¡ï¼æ æ³è´¨æ£"); return new Scope(StrUtil.blankToDefault(pallet.getCode(), pallet.getTempCode()), pallet.getBusinessCode(), pallet.getBatchCode(), Integer.valueOf(20).equals(pallet.getStatus()), lock ? bagCodeMapper.selectListByPalletIdForUpdate(pallet.getId()) : bagCodeMapper.selectListByPalletId(pallet.getId())); return palletScope(pallet, lock); } if ("BATCH".equals(type)) { var batch = lock ? batchMapper.selectByScanCodeForUpdate(code) : batchMapper.selectByScanCode(code); if (batch == null) throw invalidParamException("æªæ¾å°çäº§æ¹æ¬¡ç ï¼è¯·æ ¸å¯¹æ«ç ç±»ååç å¼"); return new Scope(StrUtil.blankToDefault(batch.getCode(), batch.getTempCode()), batch.getBusinessCode(), batch.getCode(), Integer.valueOf(40).equals(batch.getStatus()), lock ? bagCodeMapper.selectListByBatchIdForUpdate(batch.getId()) : bagCodeMapper.selectListByBatchId(batch.getId())); return batchScope(batch, lock); } throw invalidParamException("䏿¯æçè´¨æ£æ«ç ç±»å"); } /** 䏿«ç ç»å®æçä¸è´ï¼æç å¼èªå¨è¯å«ç±»åï¼ä¾æ¬¡å°è¯è¢ç ãæçç ãçäº§æ¹æ¬¡ç */ private Scope autoScope(String code, boolean lock) { MesProBagCodeDO bag = bagCodeMapper.selectByScanCode(code); if (bag != null) { return bagScope(bag); } var pallet = lock ? palletMapper.selectByScanCodeForUpdate(code) : palletMapper.selectByScanCode(code); if (pallet != null) { return palletScope(pallet, lock); } var batch = lock ? batchMapper.selectByScanCodeForUpdate(code) : batchMapper.selectByScanCode(code); if (batch != null) { return batchScope(batch, lock); } throw invalidParamException("æªæ¾å°å¯¹åºçè¢ç ãæçç æçäº§æ¹æ¬¡ç ï¼è¯·æ ¸å¯¹ç å¼"); } private Scope bagScope(MesProBagCodeDO bag) { return new Scope("BAG", bag.getCode(), bag.getBusinessCode(), bag.getBatchCode(), Integer.valueOf(30).equals(bag.getStatus()), List.of(bag)); } private Scope palletScope(MesProPalletDO pallet, boolean lock) { if (pallet.getBatchId() == null) throw invalidParamException("æçå°æªç»å®çäº§æ¹æ¬¡ï¼æ æ³è´¨æ£"); return new Scope("PALLET", StrUtil.blankToDefault(pallet.getCode(), pallet.getTempCode()), pallet.getBusinessCode(), pallet.getBatchCode(), Integer.valueOf(20).equals(pallet.getStatus()), lock ? bagCodeMapper.selectListByPalletIdForUpdate(pallet.getId()) : bagCodeMapper.selectListByPalletId(pallet.getId())); } private Scope batchScope(MesProBatchDO batch, boolean lock) { return new Scope("BATCH", StrUtil.blankToDefault(batch.getCode(), batch.getTempCode()), batch.getBusinessCode(), batch.getCode(), Integer.valueOf(40).equals(batch.getStatus()), lock ? bagCodeMapper.selectListByBatchIdForUpdate(batch.getId()) : bagCodeMapper.selectListByBatchId(batch.getId())); } @Override @@ -266,7 +308,8 @@ .filter(q -> !isReturnQuality(q)) .map(MesQcSeedQualityDO::getCode).collect(java.util.stream.Collectors.toSet()); Map<String, Object> result = new HashMap<>(); result.put("scanType", scanType); result.put("code", scope.code()); result.put("businessCode", scope.businessCode()); // èªå¨è¯å«æ¶åä¼ å®é ç ç±»åï¼åç«¯æ®æ¤å±ç¤ºå¯¹è±¡ç±»åå¹¶ç¨äºæäº¤ result.put("scanType", scope.type()); result.put("code", scope.code()); result.put("businessCode", scope.businessCode()); result.put("batchCode", scope.batchCode()); result.put("canceled", scope.canceled()); result.put("totalCount", effective.size()); result.put("inbound", !effective.isEmpty() && effective.stream().allMatch(b -> b.getInboundEventId() != null)); @@ -278,7 +321,7 @@ result.put("itemCode", item == null ? null : item.getCode()); result.put("itemName", item == null ? null : item.getName()); result.put("indicators", toRangePayload(itemId)); if ("BAG".equals(scanType)) { if ("BAG".equals(scope.type())) { List<MesQcSeedQualityDO> qualities = qualityMapper.selectListByCode(scope.code()); MesQcSeedQualityDO quality = qualities.stream() .filter(q -> !isReturnQuality(q)).findFirst().orElse(null); @@ -1076,9 +1119,11 @@ Map<String, Object> variables = new HashMap<>(); variables.put("qcLine", qcLine); variables.put("batchCode", batchCode); String processDefinitionKey = Objects.equals(qcLine, QC_LINE_SALES) ? SALES_LINE_PROCESS_KEY : LINE_PROCESS_KEY; String processInstanceId = processInstanceApi.createProcessInstance(operatorId, new BpmProcessInstanceCreateReqDTO() .setProcessDefinitionKey(LINE_PROCESS_KEY) .setProcessDefinitionKey(processDefinitionKey) .setBusinessKey(qcLine + "#" + batchCode) .setVariables(variables)); for (MesQcSeedQualityDO quality : pending) { yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/listener/MesQcSeedLineStatusListener.java
@@ -1,35 +1,39 @@ package cn.iocoder.yudao.module.mes.service.qc.seedquality.listener; import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent; import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.mes.service.qc.seedquality.MesQcSeedQualityService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; import java.util.Set; /** * ç§åè´¨æ£æ¬çº¿é¢å¯¼å®¡æ¹ç¶æçå¬å¨ * ç§åè´¨æ£é¨é¨é¢å¯¼å®¡æ¹ç¶æçå¬å¨ * * <p>æµç¨å®ä¹ keyï¼mes_seed_quality_line_approveï¼businessKey æ ¼å¼ï¼{è´¨æ£çº¿}#{çäº§æ¹æ¬¡å·}ã * 审æ¹éè¿åæ¬çº¿è¿å ¥å¤æ£ï¼é©³ååæ¬çº¿éæ°åæ£ã * <p>å å·¥é¨ãéå®é¨å使ç¨ç¬ç«æµç¨å®ä¹ï¼businessKey æ ¼å¼ï¼{è´¨æ£çº¿}#{çäº§æ¹æ¬¡å·}ã * 审æ¹éè¿åæ¬çº¿è¿å ¥å ¬å¸è´¨æ£å¾ 审ï¼é©³ååæ¬çº¿éæ°åæ£ã */ @Component @Slf4j public class MesQcSeedLineStatusListener extends BpmProcessInstanceStatusEventListener { public class MesQcSeedLineStatusListener implements ApplicationListener<BpmProcessInstanceStatusEvent> { private static final String BPM_PROCESS_DEFINITION_KEY = "mes_seed_quality_line_approve"; /** å å·¥é¨é¢å¯¼å®¡æ¹æµç¨å®ä¹æ è¯ */ private static final String LINE_PROCESS_KEY = "mes_seed_quality_line_approve"; /** éå®é¨é¢å¯¼å®¡æ¹æµç¨å®ä¹æ è¯ */ private static final String SALES_LINE_PROCESS_KEY = "mes_seed_quality_sales_line_approve"; private static final Set<String> PROCESS_KEYS = Set.of(LINE_PROCESS_KEY, SALES_LINE_PROCESS_KEY); @Resource private MesQcSeedQualityService seedQualityService; @Override protected String getProcessDefinitionKey() { return BPM_PROCESS_DEFINITION_KEY; } @Override protected void onEvent(BpmProcessInstanceStatusEvent event) { public void onApplicationEvent(BpmProcessInstanceStatusEvent event) { if (!PROCESS_KEYS.contains(event.getProcessDefinitionKey())) { return; } if (!BpmProcessInstanceStatusEnum.isProcessEndStatus(event.getStatus()) || BpmProcessInstanceStatusEnum.CANCEL.getStatus().equals(event.getStatus())) { return; @@ -37,19 +41,19 @@ String businessKey = event.getBusinessKey(); int index = businessKey == null ? -1 : businessKey.indexOf('#'); if (index <= 0 || index == businessKey.length() - 1) { log.warn("[onEvent][æ¬çº¿å®¡æ¹ businessKey({}) æ ¼å¼æ æï¼åºä¸º è´¨æ£çº¿#æ¹æ¬¡å·]", businessKey); log.warn("[onApplicationEvent][é¨é¨å®¡æ¹ businessKey({}) æ ¼å¼æ æï¼åºä¸º è´¨æ£çº¿#æ¹æ¬¡å·]", businessKey); return; } Integer qcLine; try { qcLine = Integer.valueOf(businessKey.substring(0, index)); } catch (NumberFormatException ex) { log.warn("[onEvent][æ¬çº¿å®¡æ¹ businessKey({}) è´¨æ£çº¿æ æ]", businessKey); log.warn("[onApplicationEvent][é¨é¨å®¡æ¹ businessKey({}) è´¨æ£çº¿æ æ]", businessKey); return; } String batchCode = businessKey.substring(index + 1); boolean approved = BpmProcessInstanceStatusEnum.APPROVE.getStatus().equals(event.getStatus()); log.info("[onEvent][æ¬çº¿å®¡æ¹å®æï¼æ¹æ¬¡={} è´¨æ£çº¿={} ç»æ={}]", batchCode, qcLine, event.getStatus()); log.info("[onApplicationEvent][é¨é¨å®¡æ¹å®æï¼æ¹æ¬¡={} è´¨æ£çº¿={} ç»æ={}]", batchCode, qcLine, event.getStatus()); seedQualityService.handleLineProcessResult(event.getId(), qcLine, batchCode, approved, event.getReason()); } } yudao-module-mes/src/main/resources/bpm/mes_seed_quality_line_approve.bpmn20.xml
@@ -1,9 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" targetNamespace="http://www.flowable.org/processdef"> <process id="mes_seed_quality_line_approve" name="ç§åè´¨æ£é¨é¨å®¡æ¹" isExecutable="true"> <process id="mes_seed_quality_line_approve" name="ç§åè´¨æ£å å·¥é¨å®¡æ¹" isExecutable="true"> <startEvent id="start" /> <sequenceFlow id="start_to_review" sourceRef="start" targetRef="review" /> <userTask id="review" name="é¨é¨é¢å¯¼å®¡æ¹ï¼æç± admin å¤çï¼" flowable:candidateStrategy="30" flowable:candidateParam="1" /> <userTask id="review" name="å å·¥é¨é¢å¯¼å®¡æ¹ï¼æç± admin å¤çï¼" flowable:candidateStrategy="30" flowable:candidateParam="1" /> <sequenceFlow id="review_to_end" sourceRef="review" targetRef="end" /> <endEvent id="end" /> </process> yudao-module-mes/src/main/resources/bpm/mes_seed_quality_sales_line_approve.bpmn20.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,31 @@ <?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" targetNamespace="http://www.flowable.org/processdef"> <process id="mes_seed_quality_sales_line_approve" name="ç§åè´¨æ£éå®é¨å®¡æ¹" isExecutable="true"> <startEvent id="start" /> <sequenceFlow id="start_to_review" sourceRef="start" targetRef="review" /> <userTask id="review" name="éå®é¨é¢å¯¼å®¡æ¹ï¼æç± admin å¤çï¼" flowable:candidateStrategy="30" flowable:candidateParam="1" /> <sequenceFlow id="review_to_end" sourceRef="review" targetRef="end" /> <endEvent id="end" /> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_mes_seed_quality_sales_line_approve"> <bpmndi:BPMNPlane bpmnElement="mes_seed_quality_sales_line_approve" id="BPMNPlane_mes_seed_quality_sales_line_approve"> <bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start"> <omgdc:Bounds height="36.0" width="36.0" x="160.0" y="182.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="review" id="BPMNShape_review"> <omgdc:Bounds height="80.0" width="100.0" x="250.0" y="160.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end"> <omgdc:Bounds height="36.0" width="36.0" x="400.0" y="182.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNEdge bpmnElement="start_to_review" id="BPMNEdge_start_to_review"> <omgdi:waypoint x="196.0" y="200.0"></omgdi:waypoint> <omgdi:waypoint x="250.0" y="200.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="review_to_end" id="BPMNEdge_review_to_end"> <omgdi:waypoint x="350.0" y="200.0"></omgdi:waypoint> <omgdi:waypoint x="400.0" y="200.0"></omgdi:waypoint> </bpmndi:BPMNEdge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>