docs/business_price_field_unification.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,72 @@ # åæº price åæ®µç»ä¸ä¸º businessPrice â å端èè°æ¹æ¡ ## é®é¢èæ¯ å端产åç¼è¾è¡¨ä½¿ç¨ `contractPrice` ä½ä¸ºä»·æ ¼å段åéç»å端ï¼ä½å端使ç¨çæ¯ `businessPrice`ï¼åæºä»·æ ¼ï¼ãä¸¤è æ¯åä¸ä¸ªæ¦å¿µï¼éè¦ç»ä¸ä¸º `businessPrice`ã ## æ¶åé¡µé¢ - åæºæ°å¢/ç¼è¾å¼¹çªï¼`src/views/crm/business/modules/form.vue`ï¼ - 产åç¼è¾è¡¨ç»ä»¶ï¼`src/views/crm/product/components/edit-table.vue`ï¼ - 产åç¼è¾è¡¨åå®ä¹ï¼`src/views/crm/product/components/data.ts`ï¼ ## API 说æ | æ¹æ³ | è·¯å¾ | 说æ | |------|------|------| | PUT | `/crm/business/update` | æ´æ°åæº | | POST | `/crm/business/create` | æ°å¢åæº | **请æ±ä½åæ®µåæ´ï¼`products[]` å ï¼ï¼** | åæ®µ | åæ´ | 说æ | |------|------|------| | `contractPrice` | â ç§»é¤ | æ¹ä¸º `businessPrice` | | `businessPrice` | â ç»ä¸ä½¿ç¨ | åæºä»·æ ¼ | | `totalProductPrice` | â å·²æ | äº§åæ»ä»·ï¼å端已æ°å¢æ¯æï¼ | | `totalPrice` | â å·²æ | åæºæ»ä»·ï¼æåï¼ï¼å端已æ°å¢æ¯æï¼ | ## å端修æ¹ç¹ ### 1. `edit-table.vue` â åæ®µå `contractPrice` â `businessPrice` æä»¶ï¼`src/views/crm/product/components/edit-table.vue` æ¶å 6 å¤ï¼ | è¡å· | ä¿®æ¹ | |------|------| | 55 | `row.contractPrice` â `row.businessPrice` | | 57 | `row.contractPrice` â `row.businessPrice` | | 63 | `row.contractPrice` â `row.businessPrice` | | 70 | `row.contractPrice` â `row.businessPrice` | | 132 | `contractPrice` â `businessPrice`ï¼template slot nameï¼ | | 134 | `row.contractPrice` â `row.businessPrice`ï¼v-modelï¼ | ### 2. `data.ts` â ç¼è¾è¡¨åå®ä¹ æä»¶ï¼`src/views/crm/product/components/data.ts` 第 91-95 è¡ï¼ç¼è¾è¡¨ï¼é business è§å¾ï¼çåå®ä¹ï¼ ``` field: 'contractPrice' â field: 'businessPrice' title: 'ååä»·ï¼å ï¼' â title: 'åæºä»·æ ¼ï¼å ï¼' slots: { default: 'contractPrice' } â slots: { default: 'businessPrice' } ``` ## ä¸å¡è§å说æ | åºæ¯ | è§å | |------|------| | æ´æ°åæºæ¶äº§å `businessPrice` 为 null | å端èªå¨ç¨æ§æ°æ®ç `businessPrice` mergeï¼æ éå端å¤çï¼ | | æ°å¢åæºæ¶ | `businessPrice` å¿ å¡«ï¼ä¸å¯ä¸º null | | 产å `totalPrice` | å端å¯ç´æ¥ä¼ 计ç®å¥½çå¼ï¼å端ä¼å 使ç¨ï¼æªä¼ æ¶åç«¯ç¨ `businessPrice * count` èªå¨è®¡ç® | | 头级 `totalProductPrice` / `totalPrice` | å端å¯ç´æ¥ä¼ ï¼å端ä¸åè¦ç | ## 注æäºé¡¹ - **䏿¶åçæä»¶**ï¼`contract`ã`statistics`ã`report`ã`saleTrace` ä¸ç `contractPrice` æ¯å ¶ä»ä¸å¡æ¦å¿µï¼ä¸ç¨æ¹ - 产å `id` åæ®µå端已æ°å¢æ¯æï¼æ´æ°æ¶ä¼ `id` å³å¯æ è¯å·²æäº§å - å端 `businessPrice` çåå§å弿¥èª `product.salesPrice`ï¼éä¸äº§åæ¶çé»è®¤ä»·ï¼ - æ´æ°æ¶åªéä¼ è¦ä¿®æ¹çåæ®µï¼æªä¼ åæ®µå端èªå¨ä»æ§æ°æ®ç»§æ¿ docs/work_order_material_requirement.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,257 @@ # å·¥åç©æéæ±å表ï¼å«åºåæ ¡éªï¼- å端èè°æ¹æ¡ ## æ¶åé¡µé¢ - å·¥å详æ 页 / å·¥åç©æéæ± Tab - å·¥åå表 â ç©æéæ±æ¥çï¼å¼¹çªæä¾§è¾¹æ ï¼ - **ERP éè´è®¢åæ°å¢é¡µé¢**ï¼åºåä¸è¶³æ¶è·³è½¬ï¼ ## ä¸å¡æµç¨ä¸æ°æ®å¸¦å ¥ 1. å·¥å详æ 页 â ç©æéæ± Tabï¼ä¼ å ¥å½åå·¥å `workOrderId` 2. æ¥å£æ ¹æ®å·¥åçæåä¸éå·¥åºææï¼æ²¿å·¥åºäº§åºé¾åå鿍ï¼å±å¼åºææåºå±åææçæ»éæ±æ°é 3. éæ±æ°é = æ¯å使åç¨é à 工åç产æ°é 4. èæ¥åºåè¿åå¯ç¨éåå è¶³æ è¯ï¼åç«¯æ®æ¤å±ç¤ºåºåç¶æ ## API | æ¹æ³ | è·¯å¾ | 说æ | |------|------|------| | GET | `/mes/pro/work-order-bom/item-list-by-work-order-id` | è·å¾å·¥åç©æéæ±å表ï¼å«åºåï¼ | **请æ±åæ°ï¼** | åæ° | ç±»å | å¿ å¡« | 说æ | |------|------|------|------| | workOrderId | Long | æ¯ | å·¥åç¼å· | **ååºå段ï¼** | åæ®µ | ç±»å | 说æ | |------|------|------| | itemId | Long | ç©æç¼å· | | itemCode | String | ç©æç¼ç | | itemName | String | ç©æåç§° | | itemSpecification | String | è§æ ¼åå· | | unitMeasureName | String | åä½åç§° | | quantity | BigDecimal | éæ±æ°éï¼å·¥åæ°é à BOM ç¨éï¼ | | stockQuantity | BigDecimal | å¯ç¨åºåï¼å¨åº - å»ç» - å ç¨ï¼ | | purchaseOrderQuantity | BigDecimal | å¨ééè´æ°ï¼æ¥æºä¸ºæ¬å·¥åçéè´è®¢åæªå ¥åºæ°éæ±æ»ï¼ | | stockSufficient | Boolean | åºåæ¯å¦å è¶³ï¼å¯ç¨åºå + å¨ééè´æ° >= éæ±æ°éï¼ï¼true=æ¯ false=å¦ | | itemOrProduct | String | ç©æ/äº§åæ è¯ | **ååºç¤ºä¾ï¼** ```json { "code": 0, "data": [ { "itemId": 41, "itemCode": "ITEM_20260716004", "itemName": "éæ", "itemSpecification": "Ï9.5mm", "unitMeasureName": "kg", "quantity": 600.00, "stockQuantity": 500.00, "purchaseOrderQuantity": 200.00, "stockSufficient": true, "itemOrProduct": "ITEM" }, { "itemId": 44, "itemCode": "ITEM_20260716008", "itemName": "ééé¢çº¿", "itemSpecification": "Ï1.6mm", "unitMeasureName": "kg", "quantity": 100.00, "stockQuantity": 50.00, "purchaseOrderQuantity": 0.00, "stockSufficient": false, "itemOrProduct": "ITEM" } ] } ``` ## åæ®µå±ç¤ºè§å | åæ®µ | å±ç¤ºä½ç½® | 说æ | |------|----------|------| | itemCode | å表å | ç©æç¼ç | | itemName | å表å | ç©æåç§° | | itemSpecification | å表å | è§æ ¼åå· | | unitMeasureName | å表å | åä½ | | quantity | å表å | éæ±æ°éï¼å³å¯¹é½ï¼åå使 ¼å¼ | | stockQuantity | å表å | å¯ç¨åºåï¼å³å¯¹é½ï¼åå使 ¼å¼ | | purchaseOrderQuantity | å表å | å¨ééè´æ°ï¼å³å¯¹é½ï¼åå使 ¼å¼ | | stockSufficient | å表å | åºåç¶æï¼è§ä¸æ¹ç¶æå±ç¤ºè§å | ### åºåç¶æå±ç¤ºè§å | stockSufficient | å±ç¤ºææ¬ | 建议é¢è² | 说æ | |-----------------|---------|---------|------| | true | å è¶³ | ç»¿è² | å¯ç¨åºå â¥ éæ±æ°é | | false | ä¸è¶³ | çº¢è² | å¯ç¨åºå < éæ±æ°é | ### æ°æ®å¸¦å ¥å ³ç³» | æ¥æº | å¸¦å ¥åæ®µ | 说æ | |------|----------|------| | å·¥å详æ | workOrderId | éè¿é¡µé¢è·¯ç±åæ°æè¡æ°æ®è·åï¼ä¼ ç»æ¥å£ | ## æ¥å£è°ç¨æ¶åº ``` å·¥å详æ 页å è½½ âââ GET /mes/pro/work-order/get?workOrderId=47 â è·åå·¥ååºæ¬ä¿¡æ¯ âââ GET /mes/pro/work-order-process/list-by-work-order-id?workOrderId=47 â è·åå·¥åºå表 âââ GET /mes/pro/work-order-bom/item-list-by-work-order-id?workOrderId=47 â è·åç©æéæ±ï¼å«åºåï¼ ``` æ éåç½®è°ç¨ï¼ä¼ å ¥ workOrderId å³å¯ç¬ç«è¯·æ±ã ## ä¸å¡è§å说æ | åºæ¯ | è§å | |------|------| | å·¥åæ å·¥åº | è¿å空å表 | | å·¥åæ BOM ææ | è¿å空å表 | | å·¥åäº§åæªå ³èå·¥èºè·¯çº¿ | è¿å空å表 | | ç©æéæ±è®¡ç® | 仿åä¸éå·¥åºï¼sort æå¤§ï¼çææåºåï¼æ²¿å·¥åºäº§åºé¾åå鿍å±å¼ | | æ°éè®¡ç® | æ¯å使åç¨é à 工åç产æ°éï¼quantityï¼ | | å¯ç¨åºåè®¡ç® | æ±æ»ææåºä½çï¼å¨åºæ°é - å»ç»æ°é - å ç¨æ°éï¼ï¼â¤0 çåºä½ä¸è®¡å ¥ | | å¨ééè´æ°è®¡ç® | æ¥è¯¢æ¥æºä¸ºæ¬å·¥åï¼sourceType=1, sourceId=å·¥åIDï¼çéè´è®¢åæç»ï¼æ±æ»ï¼è®¢è´æ°é - å·²å ¥åºæ°éï¼ | | å è¶³å¤æ | å¯ç¨åºå + å¨ééè´æ° >= éæ±æ°é | ## éè´ç³è¯·ï¼åºåä¸è¶³æ¶è·³è½¬ï¼ ### è§¦åæ¡ä»¶ åè¡¨ä¸ `stockSufficient = false` çè¡ï¼å¨æä½åå±ç¤ºã**ç³è¯·éè´**ãæé®ã ### è·³è½¬ç®æ ERP éè´è®¢åæ°å¢é¡µé¢ï¼`/erp/purchase-order/create`ï¼å端路ç±ï¼éæ¥å£è·¯å¾ï¼ ### æ°æ®å¸¦å ¥ ä»ç©æéæ±è¡ + å½åå·¥åæºå¸¦ä»¥ä¸æ°æ®è·³è½¬å°éè´è®¢åæ°å¢é¡µé¢ï¼ **工忥æºå段ï¼éè´è®¢åç¬æçè¿½æº¯åæ®µï¼ï¼** | æ¥æºå段 | ç®æ åæ®µ | ç±»å | 说æ | |----------|----------|------|------| | å·¥å `id` | `sourceId` | Long | æ¥æºåæ®ç¼å· | | å·¥å `code` | `sourceNo` | String | æ¥æºåå· | | â | `sourceType` | Integer | åºå®ä¼ `1`ï¼ç产工åï¼ | **产åè¡å段ï¼** | æ¥æºå段 | ç®æ åæ®µ | 说æ | |----------|----------|------| | `itemId` | `items[].productId` | 产åç¼å· | | `itemCode` | â | 产åç¼ç ï¼ä¾é¡µé¢æ¾ç¤º | | `itemName` | â | 产ååç§°ï¼ä¾é¡µé¢æ¾ç¤º | | `itemSpecification` | â | è§æ ¼åå·ï¼ä¾é¡µé¢æ¾ç¤º | | `quantity - stockQuantity` | `items[].count` | 建议éè´æ°éï¼ç¼ºå£ = éæ± - åºåï¼ | | `unitMeasureName` | â | åä½åç§°ï¼ä¾é¡µé¢æ¾ç¤º | ### 页é¢è·³è½¬æµç¨ ``` ç©æéæ±å表ï¼åºåä¸è¶³è¡ï¼ â ââ ç¹å»ãç³è¯·éè´ãæé® â ââ è·³è½¬å° ERP éè´è®¢åæ°å¢é¡µé¢ â æºå¸¦ï¼å·¥åæ¥æºä¿¡æ¯ï¼sourceIdãsourceNoãsourceType=1ï¼ â 产åè¡ä¿¡æ¯ï¼productIdãæ°éãç¼ç ãåç§°ãè§æ ¼ãåä½ï¼ â ââ éè´è®¢åæ°å¢é¡µé¢ ââ èªå¨é¢å¡«æ¥æºå段ï¼ä¸å¯ç¼è¾ï¼ ââ èªå¨é¢å¡«äº§åè¡ï¼productId + count + unitï¼ ââ ç¨æ·éæ©ä¾åºåï¼supplierIdï¼å¿ å¡«ï¼ ââ ç¨æ·è¡¥å åä»·ãç¨ççä¿¡æ¯ ââ æäº¤ POST /erp/purchase-order/create ``` ### 交äºè¯´æ | åºæ¯ | å¤çæ¹å¼ | |------|----------| | åä¸ªç©æä¸è¶³ | ç¹å»è¯¥è¡ãç³è¯·éè´ãâ 跳转éè´è®¢å页é¢ï¼é¢å¡« 1 è¡äº§å | | å¤ä¸ªç©æä¸è¶³ | å¯éè¡ç¹å»åå«ç³è¯·ï¼ææ¯æå¤éåæ¹é带å°åä¸ä¸ªéè´è®¢å | | å ¨é¨å è¶³ | ä¸å±ç¤ºãç³è¯·éè´ãæé® | | å¯ç¨åºå为 0 | `stockSufficient = false`ï¼åæ ·å±ç¤ºãç³è¯·éè´ãï¼ç¼ºå£ = å ¨é¨éæ±æ°é | ### éè´è®¢åå建 API | æ¹æ³ | è·¯å¾ | 说æ | |------|------|------| | POST | `/erp/purchase-order/create` | å建éè´è®¢å | **宿´è¯·æ±åæ°ï¼** | åæ° | ç±»å | å¿ å¡« | æ¥æº | |------|------|------|------| | `sourceType` | Integer | å¦ | åºå® `1`ï¼ç产工åï¼ï¼ç±é¡µé¢æºå¸¦ | | `sourceNo` | String | å¦ | å·¥åç¼ç `workOrder.code` | | `sourceId` | Long | å¦ | å·¥å ID `workOrder.id` | | `supplierId` | Long | æ¯ | ç¨æ·å¨éè´é¡µé¢éæ©ä¾åºå | | `orderTime` | LocalDateTime | æ¯ | é»è®¤å½å¤© | | `items[].productId` | Long | æ¯ | ç©æéæ±ç `itemId` | | `items[].productUnitId` | Long | æ¯ | ç©æå¯¹åºç计éåä½ ID | | `items[].count` | BigDecimal | æ¯ | ç¼ºå£æ°éï¼éæ± - åºåï¼ | | `items[].productPrice` | BigDecimal | å¦ | ç¨æ·æå·¥å¡«å | | `items[].taxPercent` | BigDecimal | å¦ | ç¨æ·æå·¥å¡«å | **请æ±ç¤ºä¾ï¼** ```json { "sourceType": 1, "sourceNo": "GD20260730001", "sourceId": 47, "supplierId": 10, "orderTime": "2026-07-30", "items": [ { "productId": 41, "productUnitId": 5, "count": 100.00, "productPrice": 12.50, "taxPercent": 13.00 } ] } ``` **ååºï¼** ```json { "code": 0, "data": { "id": 123, "no": "CGD20260730001", "sourceType": 1, "sourceNo": "GD20260730001", "sourceId": 47, "sourceTypeName": "ç产工å", "supplierId": 10, "items": [...] } } ``` ## 注æäºé¡¹ - `stockSufficient` 为 `false` æ¶ï¼å端åº**å·®å¼åå±ç¤º**ï¼å¦çº¢è²é«äº®ï¼ï¼å¹¶å¨æä½åæ¾ç¤ºãç³è¯·éè´ãæé® - å¯ç¨åºå为 0 æ¶ï¼`stockQuantity` è¿å `0`ï¼`stockSufficient` 为 `false` - æ¥å£è¿åçç©æå表å¯è½ä¸ºç©ºï¼å·¥åæ å·¥åº/æ BOM/æªå ³è路线ï¼ï¼å端éå¤çç©ºç¶ææç¤º - æ°éåæ®µä¸º `BigDecimal`ï¼å端å±ç¤ºæ¶æ³¨æå°æ°ä½å¤çï¼å»ºè®®ä¿ç 2 ä½å°æ° - 跳转éè´è®¢åæ¶ï¼`productUnitId` éè¦éè¿ç©æè¯¦æ æ¥å£è·åï¼å½åç©æéæ±å表æªè¿åæ¤å段ï¼ï¼æè éè´è®¢å页颿 ¹æ® `productId` èªè¡æ¥è¯¢é»è®¤åä½ - åä¸ä¸ªç©æå¯è½å¨å¤ä¸ªå·¥åä¸é½éè¦éè´ï¼éè´è®¢å页é¢åºæ¯æç¨æ·ä¿®æ¹æ°é - æ¥æºå段 `sourceType`ã`sourceNo`ã`sourceId` å¨éè´è®¢å页é¢å±ç¤ºä¸º**åªè¯»**ï¼ä¸å è®¸ç¨æ·ä¿®æ¹ - éè´è®¢å详æ /å表ä¸å¯éè¿ `sourceTypeName`ï¼å¦"ç产工å"ï¼å `sourceNo`ï¼å·¥åç¼ç ï¼è¿½æº¯å°æ¥æºå·¥å yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/databind/TimestampLocalDateTimeDeserializer.java
@@ -7,6 +7,7 @@ import tools.jackson.databind.ValueDeserializer; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; @@ -20,7 +21,8 @@ public static final TimestampLocalDateTimeDeserializer INSTANCE = new TimestampLocalDateTimeDeserializer(); private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); @Override public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws JacksonException { @@ -34,9 +36,13 @@ long millis = Long.parseLong(text); return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.systemDefault()); } catch (NumberFormatException e) { // 䏿¯çº¯æ°åï¼æé»è®¤æ¥ææ ¼å¼è§£æ // 䏿¯çº¯æ°åï¼ææ¥ææ ¼å¼è§£æ } return LocalDateTime.parse(text, DEFAULT_FORMATTER); // çº¯æ¥ææ ¼å¼ï¼å¦ "2026-07-29"ï¼ï¼è¡¥å ¨ä¸ºå½å¤© 00:00:00 if (text.length() == 10) { return LocalDate.parse(text, DATE_FORMATTER).atStartOfDay(); } return LocalDateTime.parse(text, DATE_TIME_FORMATTER); } } yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java
@@ -1,5 +1,6 @@ package cn.iocoder.yudao.framework.excel.core.util; import cn.idev.excel.ExcelWriter; import cn.idev.excel.FastExcelFactory; import cn.idev.excel.converters.longconverter.LongStringConverter; import cn.iocoder.yudao.framework.common.util.http.HttpUtils; @@ -33,12 +34,22 @@ public static <T> void write(HttpServletResponse response, String filename, String sheetName, Class<T> head, List<T> data) throws IOException { // è¾åº Excel FastExcelFactory.write(response.getOutputStream(), head) ExcelWriter excelWriter = FastExcelFactory.write(response.getOutputStream(), head) .autoCloseStream(false) // ä¸è¦èªå¨å ³éï¼äº¤ç» Servlet èªå·±å¤ç .registerWriteHandler(new ColumnWidthMatchStyleStrategy()) // åºäº column é¿åº¦ï¼èªå¨éé ãæå¤§ 255 宽度 .registerWriteHandler(new SelectSheetWriteHandler(head)) // åºäºåºå® sheet å®ç°ä¸ææ¡ .registerConverter(new LongStringConverter()) // é¿å Long ç±»å丢失精度 .sheet(sheetName).doWrite(data); .build(); try { excelWriter.write(data, FastExcelFactory.writerSheet(sheetName).build()); } finally { // finish() å° workbook åå ¥å° response è¾åºæµ excelWriter.finish(); // close() 触å dispose() æ¸ çä¸´æ¶æä»¶ï¼ // POI SXSSFWorkbook.dispose() å¯è½è¾åº WARN "Failed to dispose sheet"ï¼ // è¿æ¯ POI å·²ç¥é®é¢ï¼ä¸´æ¶æä»¶æ¸ çæ¶ BufferedWriter å·²å ³éï¼ï¼ä¸å½±å导åºç»æ excelWriter.close(); } // 设置 header å contentTypeãå卿åçåå æ¯ï¼é¿å æ¥éæ¶ï¼ååº contentType å·²ç»è¢«ä¿®æ¹äº response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename)); response.setContentType("application/vnd.ms-excel;charset=UTF-8"); yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java
@@ -58,6 +58,12 @@ @NotNull(message = "æ´åææ£ä¸è½ä¸ºç©º") private BigDecimal discountPercent; @Schema(description = "äº§åæ»ä»·", example = "12000.00") private BigDecimal totalProductPrice; @Schema(description = "åæºæ»ä»·ï¼æåï¼", example = "11280.00") private BigDecimal totalPrice; @Schema(description = "夿³¨", example = "é便") @DiffLogField(name = "夿³¨") private String remark; @@ -73,6 +79,9 @@ @NoArgsConstructor @AllArgsConstructor public static class BusinessProduct { @Schema(description = "产åå ³èç¼å·", example = "5") private Long id; @Schema(description = "MDM ç©æç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "20529") @NotNull(message = "ç©æç¼å·ä¸è½ä¸ºç©º") @@ -94,6 +103,9 @@ @NotNull(message = "æ°éä¸è½ä¸ºç©º") private BigDecimal count; @Schema(description = "æ»è®¡ä»·æ ¼ï¼businessPrice * countï¼", example = "12000.00") private BigDecimal totalPrice; } } yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
@@ -134,8 +134,9 @@ updateReqVO.setOwnerUserId(null).setStatusTypeId(null); // ä¸å è®¸æ´æ°çåæ®µ // 1.1 æ ¡éªåå¨ CrmBusinessDO oldBusiness = validateBusinessExists(updateReqVO.getId()); // 1.2 æ ¡éªäº§åé¡¹çæææ§ List<CrmBusinessProductDO> businessProducts = validateBusinessProducts(updateReqVO.getProducts()); // 1.2 æ ¡éªäº§åé¡¹çæææ§ï¼ä¼ å ¥æ§äº§åå表ç¨äºåå¹¶ null åæ®µï¼ List<CrmBusinessProductDO> oldProducts = businessProductMapper.selectListByBusinessId(updateReqVO.getId()); List<CrmBusinessProductDO> businessProducts = validateBusinessProducts(updateReqVO.getProducts(), oldProducts); // 1.3 æ ¡éªå ³èåæ®µ validateRelationDataExists(updateReqVO); @@ -147,7 +148,7 @@ updateBusinessProduct(updateObj.getId(), businessProducts); // 3. è®°å½æä½æ¥å¿ä¸ä¸æ updateReqVO.setOwnerUserId(oldBusiness.getOwnerUserId()); // é¿å æä½æ¥å¿åºç°âå é¤è´è´£äººâçæ åµ updateReqVO.setOwnerUserId(oldBusiness.getOwnerUserId()); // é¿å æä½æ¥å¿åºç°"å é¤è´è´£äºº"çæ åµ LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldBusiness, CrmBusinessSaveReqVO.class)); LogRecordContext.putVariable("businessName", oldBusiness.getName()); } @@ -216,6 +217,18 @@ } private List<CrmBusinessProductDO> validateBusinessProducts(List<CrmBusinessSaveReqVO.BusinessProduct> list) { return validateBusinessProducts(list, Collections.emptyList()); } /** * æ ¡éªäº§åé¡¹çæææ§ï¼æ´æ°åºæ¯åå¹¶æ§æ°æ®ï¼ * * @param list åç«¯ä¼ å ¥ç产åå表 * @param oldProducts å·²æäº§åå表ï¼ç¨äºåå¹¶ null åæ®µï¼ * @return å¤çåç产å DO å表 */ private List<CrmBusinessProductDO> validateBusinessProducts(List<CrmBusinessSaveReqVO.BusinessProduct> list, List<CrmBusinessProductDO> oldProducts) { // 1. æ ¡éªç©æåå¨ Set<Long> itemIds = convertSet(list, CrmBusinessSaveReqVO.BusinessProduct::getItemId); Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap(itemIds); @@ -224,15 +237,47 @@ throw exception(PRODUCT_NOT_EXISTS); } } // 2. 转å为 CrmBusinessProductDO å表 return convertList(list, o -> BeanUtils.toBean(o, CrmBusinessProductDO.class, item -> item.setTotalPrice(MoneyUtils.priceMultiply(item.getBusinessPrice(), item.getCount())))); // 2. æå»ºæ§äº§å Mapï¼æ id ç´¢å¼ï¼ Map<Long, CrmBusinessProductDO> oldProductMap = convertMap(oldProducts, CrmBusinessProductDO::getId); // 3. 转å为 CrmBusinessProductDO å表ï¼åå¹¶æ§æ°æ®ï¼ return convertList(list, o -> { CrmBusinessProductDO product = BeanUtils.toBean(o, CrmBusinessProductDO.class); // æ´æ°åºæ¯ï¼å¦æäº§åå·²æ id ä¸ææ§æ°æ®ï¼ååå¹¶ null åæ®µ if (o.getId() != null && oldProductMap.containsKey(o.getId())) { CrmBusinessProductDO old = oldProductMap.get(o.getId()); if (product.getBusinessPrice() == null) { product.setBusinessPrice(old.getBusinessPrice()); } if (product.getItemPrice() == null) { product.setItemPrice(old.getItemPrice()); } if (product.getCount() == null) { product.setCount(old.getCount()); } if (product.getItemUnitId() == null) { product.setItemUnitId(old.getItemUnitId()); } } // ä¼å 使ç¨åç«¯ä¼ å ¥ç totalPriceï¼å¦åéè¿ businessPrice * count è®¡ç® if (o.getTotalPrice() != null) { product.setTotalPrice(o.getTotalPrice()); } else { product.setTotalPrice(MoneyUtils.priceMultiply(product.getBusinessPrice(), product.getCount())); } return product; }); } private void calculateTotalPrice(CrmBusinessDO business, List<CrmBusinessProductDO> businessProducts) { business.setTotalProductPrice(getSumValue(businessProducts, CrmBusinessProductDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); BigDecimal discountPrice = MoneyUtils.priceMultiplyPercent(business.getTotalProductPrice(), business.getDiscountPercent()); business.setTotalPrice(business.getTotalProductPrice().subtract(discountPrice)); // totalProductPriceï¼ä¼å 使ç¨åç«¯ä¼ å ¥å¼ï¼å¦åä»äº§åæ±æ» if (business.getTotalProductPrice() == null) { business.setTotalProductPrice(getSumValue(businessProducts, CrmBusinessProductDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); } // totalPriceï¼ä¼å 使ç¨åç«¯ä¼ å ¥å¼ï¼å¦åæææ£è®¡ç® if (business.getTotalPrice() == null) { BigDecimal discountPrice = MoneyUtils.priceMultiplyPercent(business.getTotalProductPrice(), business.getDiscountPercent()); business.setTotalPrice(business.getTotalProductPrice().subtract(discountPrice)); } } @Override yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/api/purchase/ErpPurchaseOrderApi.java
@@ -84,4 +84,13 @@ */ CommonResult<Long> createPurchaseOrder(ErpPurchaseOrderCreateReqDTO createReqDTO); /** * ææ¥æºæ¥è¯¢éè´è®¢åæç»å表ï¼ç¨äºè¿½æº¯æ¥æºå·¥åçéè´æ åµï¼ * * @param sourceType æ¥æºç±»å * @param sourceId æ¥æºåæ®ç¼å· * @return éè´è®¢åæç»å表 */ CommonResult<List<ErpPurchaseOrderItemRespDTO>> getPurchaseOrderItemListBySource(Integer sourceType, Long sourceId); } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/api/purchase/ErpPurchaseOrderApiImpl.java
@@ -118,4 +118,20 @@ return success(purchaseOrderService.createPurchaseOrder(saveReqVO)); } @Override public CommonResult<List<ErpPurchaseOrderItemRespDTO>> getPurchaseOrderItemListBySource(Integer sourceType, Long sourceId) { if (sourceType == null || sourceId == null) { return success(Collections.emptyList()); } // 1. ææ¥æºæ¥è¯¢éè´è®¢å List<ErpPurchaseOrderDO> orders = purchaseOrderService.getPurchaseOrderListBySource(sourceType, sourceId); if (orders.isEmpty()) { return success(Collections.emptyList()); } // 2. æ¥è¯¢ææè®¢åçæç» List<Long> orderIds = orders.stream().map(ErpPurchaseOrderDO::getId).toList(); List<ErpPurchaseOrderItemDO> items = purchaseOrderItemMapper.selectListByOrderIds(orderIds); return success(BeanUtils.toBean(items, ErpPurchaseOrderItemRespDTO.class)); } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java
@@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderSaveReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO; import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO; import cn.iocoder.yudao.module.erp.enums.ErpPurchaseOrderSourceTypeEnum; import cn.iocoder.yudao.module.srm.api.supplier.SrmSupplierApi; import cn.iocoder.yudao.module.srm.api.supplier.dto.SrmSupplierRespDTO; import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseOrderService; @@ -128,7 +129,9 @@ item.setStockCount(BigDecimal.ZERO); MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem -> item.setProductName(mdmItem.getName()) .setProductBarCode(mdmItem.getBarCode())); })).setAttachmentList(storageAttachmentApi.listAttachments("erp_purchase_order", id)))); })).setAttachmentList(storageAttachmentApi.listAttachments("erp_purchase_order", id)) .setSourceTypeName(ErpPurchaseOrderSourceTypeEnum.WORK_ORDER.getType() .equals(purchaseOrder.getSourceType()) ? "ç产工å" : null))); } @GetMapping("/page") @@ -185,6 +188,8 @@ purchaseOrder.setProductNames(CollUtil.join(purchaseOrder.getItems(), "ï¼", ErpPurchaseOrderRespVO.Item::getProductName)); MapUtils.findAndThen(supplierMap, purchaseOrder.getSupplierId(), supplier -> purchaseOrder.setSupplierName(supplier.getName())); MapUtils.findAndThen(userMap, Long.parseLong(purchaseOrder.getCreator()), user -> purchaseOrder.setCreatorName(user.getNickname())); purchaseOrder.setSourceTypeName(ErpPurchaseOrderSourceTypeEnum.WORK_ORDER.getType() .equals(purchaseOrder.getSourceType()) ? "ç产工å" : null); }); } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderRespVO.java
@@ -64,6 +64,20 @@ @Schema(description = "å®ééé¢ï¼åä½ï¼å ", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") private BigDecimal depositPrice; @Schema(description = "æ¥æºç±»å", example = "1") @ExcelProperty("æ¥æºç±»å") private Integer sourceType; @Schema(description = "æ¥æºåå·", example = "GD20260730001") @ExcelProperty("æ¥æºåå·") private String sourceNo; @Schema(description = "æ¥æºåæ®ç¼å·", example = "48") private Long sourceId; @Schema(description = "æ¥æºç±»ååç§°", example = "ç产工å") private String sourceTypeName; @Schema(description = "夿³¨", example = "ä½ ç") @ExcelProperty("夿³¨") private String remark; yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderSaveReqVO.java
@@ -32,6 +32,15 @@ @Schema(description = "å®ééé¢ï¼åä½ï¼å ", example = "7127") private BigDecimal depositPrice; @Schema(description = "æ¥æºç±»å", example = "1") private Integer sourceType; @Schema(description = "æ¥æºåå·", example = "GD20260730001") private String sourceNo; @Schema(description = "æ¥æºåæ®ç¼å·", example = "48") private Long sourceId; @Schema(description = "夿³¨", example = "ä½ ç") private String remark; yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/request/ErpPurchaseRequestRespVO.java
@@ -1,5 +1,8 @@ package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.request; import cn.idev.excel.annotation.ExcelIgnore; import cn.idev.excel.annotation.ExcelIgnoreUnannotated; import cn.idev.excel.annotation.ExcelProperty; import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -11,75 +14,95 @@ @Schema(description = "管çåå° - ERP éè´ç³è¯· Response VO") @Data @ExcelIgnoreUnannotated public class ErpPurchaseRequestRespVO { @Schema(description = "ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @ExcelIgnore private Long id; @Schema(description = "éè´ç³è¯·åå·", requiredMode = Schema.RequiredMode.REQUIRED, example = "CGSQ001") @ExcelProperty("éè´ç³è¯·åå·") private String no; @Schema(description = "ç¶æ", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @ExcelProperty(value = "ç¶æ", converter = cn.iocoder.yudao.module.erp.convert.ErpPurchaseRequestStatusConvert.class) private Integer status; @Schema(description = "工使µç¼å·", example = "1043") private String processInstanceId; @Schema(description = "ç³è¯·äººç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @ExcelProperty("ç³è¯·äººç¼å·") private Long requestUserId; @Schema(description = "ç³è¯·äººå§å", example = "å¼ ä¸") @ExcelProperty("ç³è¯·äººå§å") private String requestUserName; @Schema(description = "ç³è¯·é¨é¨ç¼å·", example = "1") @ExcelProperty("ç³è¯·é¨é¨ç¼å·") private Long requestDeptId; @Schema(description = "ç³è¯·é¨é¨åç§°", example = "ç产é¨") @ExcelProperty("ç³è¯·é¨é¨åç§°") private String requestDeptName; @Schema(description = "ç³è¯·æ¶é´", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("ç³è¯·æ¶é´") private LocalDateTime requestTime; @Schema(description = "ç³è¯·çç±", example = "ç产éè¦") @ExcelProperty("ç³è¯·çç±") private String requestReason; @Schema(description = "ä¾åºåç¼å·", example = "1") @ExcelProperty("ä¾åºåç¼å·") private Long supplierId; @Schema(description = "ä¾åºååç§°", example = "ä¾åºåA") @ExcelProperty("ä¾åºååç§°") private String supplierName; @Schema(description = "å®ééé¢", example = "1000.00") @ExcelProperty("å®ééé¢") private BigDecimal depositPrice; @Schema(description = "å计æ°é", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("å计æ°é") private BigDecimal totalCount; @Schema(description = "åè®¡ä»·æ ¼", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("åè®¡ä»·æ ¼") private BigDecimal totalPrice; @Schema(description = "产ååç§°å表", example = "产åA,产åB") @ExcelProperty("产ååç§°å表") private String productNames; @Schema(description = "çæçéè´è®¢åç¼å·", example = "1") @ExcelIgnore private Long orderId; @Schema(description = "çæçéè´è®¢åå·", example = "CGDD001") @ExcelProperty("éè´è®¢åå·") private String orderNo; @Schema(description = "å ¥åºç¶æï¼0:æªå ¥åº 1:é¨åå ¥åº 2:å ¨é¨å ¥åºï¼", example = "0") @Schema(description = "å ¥åºç¶æ", example = "0") @ExcelProperty(value = "å ¥åºç¶æ", converter = cn.iocoder.yudao.module.erp.convert.ErpPurchaseOrderInStatusConvert.class) private Integer inStatus; @Schema(description = "夿³¨", example = "夿³¨") @ExcelProperty("夿³¨") private String remark; @Schema(description = "éä»¶å表") @ExcelIgnore private List<StorageBlobRespDTO> attachmentList; @Schema(description = "å建æ¶é´") @ExcelProperty("å建æ¶é´") private LocalDateTime createTime; @Schema(description = "ç³è¯·æç»å表") @ExcelIgnore private java.util.List<Item> items; @Schema(description = "ç³è¯·æç»é¡¹") yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/ErpSaleOrderController.java
@@ -10,6 +10,7 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.crm.api.customer.CrmCustomerApi; import cn.iocoder.yudao.module.crm.api.customer.dto.CrmCustomerRespDTO; import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderItemRespVO; import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderRespVO; import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order.ErpSaleOrderSaveReqVO; @@ -119,6 +120,20 @@ return success(true); } @GetMapping("/item/list-by-order-id") @Operation(summary = "æ¥è¯¢éå®è®¢åçç©ææç»å表ï¼ç¨äºåè´§éç¥åå建ï¼") @Parameter(name = "orderId", description = "éå®è®¢åç¼å·", required = true, example = "1") @PreAuthorize("@ss.hasPermission('erp:sale-order:query')") public CommonResult<List<ErpSaleOrderItemRespVO>> getSaleOrderItemListByOrderId(@RequestParam("orderId") Long orderId) { List<ErpSaleOrderItemDO> itemList = saleOrderService.getSaleOrderItemListByOrderId(orderId); Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap( convertSet(itemList, ErpSaleOrderItemDO::getProductId)); return success(BeanUtils.toBean(itemList, ErpSaleOrderItemRespVO.class, vo -> { MapUtils.findAndThen(itemMap, vo.getProductId(), item -> vo.setProductName(item.getName()).setProductBarCode(item.getBarCode())); })); } @GetMapping("/get") @Operation(summary = "è·å¾éå®è®¢å") @Parameter(name = "id", description = "ç¼å·", required = true, example = "1024") yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/sale/vo/order/ErpSaleOrderItemRespVO.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,48 @@ package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.order; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; /** * ERP éå®è®¢å项 Response VOï¼ä¾å端åè´§éç¥ååå»ºæ¶æ¥è¯¢è®¢åæç»ï¼ */ @Schema(description = "管çåå° - ERP éå®è®¢å项 Response VO") @Data public class ErpSaleOrderItemRespVO { @Schema(description = "ç¼å·ï¼éå®è®¢åè¡IDï¼", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Long id; @Schema(description = "éå®è®¢åç¼å·", example = "1") private Long orderId; @Schema(description = "ç©æç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Long productId; @Schema(description = "ç©æåç§°", example = "产åA") private String productName; @Schema(description = "ç©ææ¡ç ", example = "12345678") private String productBarCode; @Schema(description = "计éåä½ç¼å·", example = "1") private Long productUnitId; @Schema(description = "计éåä½åç§°", example = "个") private String productUnitName; @Schema(description = "产ååä»·", example = "100.00") private BigDecimal productPrice; @Schema(description = "æ°é", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") private BigDecimal count; @Schema(description = "æ»ä»·", example = "1000.00") private BigDecimal totalPrice; @Schema(description = "夿³¨", example = "夿³¨") private String remark; } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/convert/ErpPurchaseOrderInStatusConvert.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,48 @@ package cn.iocoder.yudao.module.erp.convert; import cn.idev.excel.converters.Converter; import cn.idev.excel.enums.CellDataTypeEnum; import cn.idev.excel.metadata.GlobalConfiguration; import cn.idev.excel.metadata.data.ReadCellData; import cn.idev.excel.metadata.data.WriteCellData; import cn.idev.excel.metadata.property.ExcelContentProperty; import cn.iocoder.yudao.module.erp.enums.ErpPurchaseOrderInStatusEnum; /** * ERP éè´å ¥åºç¶æ Excel 转æ¢å¨ * <p> * å° Integer å ¥åºç¶æç 转æ¢ä¸ºä¸æåç§° * * @author èéæºç */ public class ErpPurchaseOrderInStatusConvert implements Converter<Integer> { @Override public Class<?> supportJavaTypeKey() { return Integer.class; } @Override public CellDataTypeEnum supportExcelTypeKey() { return CellDataTypeEnum.STRING; } @Override public WriteCellData<?> convertToExcelData(Integer value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (value == null) { return new WriteCellData<>(""); } ErpPurchaseOrderInStatusEnum statusEnum = ErpPurchaseOrderInStatusEnum.fromStatus(value); return new WriteCellData<>(statusEnum != null ? statusEnum.getName() : String.valueOf(value)); } @Override public Integer convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { String label = cellData.getStringValue(); ErpPurchaseOrderInStatusEnum statusEnum = ErpPurchaseOrderInStatusEnum.fromName(label); return statusEnum != null ? statusEnum.getStatus() : null; } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/convert/ErpPurchaseRequestStatusConvert.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,48 @@ package cn.iocoder.yudao.module.erp.convert; import cn.idev.excel.converters.Converter; import cn.idev.excel.enums.CellDataTypeEnum; import cn.idev.excel.metadata.GlobalConfiguration; import cn.idev.excel.metadata.data.ReadCellData; import cn.idev.excel.metadata.data.WriteCellData; import cn.idev.excel.metadata.property.ExcelContentProperty; import cn.iocoder.yudao.module.erp.enums.ErpPurchaseRequestStatusEnum; /** * ERP éè´ç³è¯·ç¶æ Excel 转æ¢å¨ * <p> * å° Integer ç¶æç 转æ¢ä¸ºä¸æåç§°ï¼ç¨äº Excel å¯¼åº * * @author èéæºç */ public class ErpPurchaseRequestStatusConvert implements Converter<Integer> { @Override public Class<?> supportJavaTypeKey() { return Integer.class; } @Override public CellDataTypeEnum supportExcelTypeKey() { return CellDataTypeEnum.STRING; } @Override public WriteCellData<?> convertToExcelData(Integer value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { if (value == null) { return new WriteCellData<>(""); } ErpPurchaseRequestStatusEnum statusEnum = ErpPurchaseRequestStatusEnum.fromStatus(value); return new WriteCellData<>(statusEnum != null ? statusEnum.getName() : String.valueOf(value)); } @Override public Integer convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { String label = cellData.getStringValue(); ErpPurchaseRequestStatusEnum statusEnum = ErpPurchaseRequestStatusEnum.fromName(label); return statusEnum != null ? statusEnum.getStatus() : null; } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseOrderDO.java
@@ -92,6 +92,23 @@ private BigDecimal depositPrice; /** * æ¥æºç±»å * * æä¸¾ {@link cn.iocoder.yudao.module.erp.enums.ErpPurchaseOrderSourceTypeEnum} */ private Integer sourceType; /** * æ¥æºåå· */ private String sourceNo; /** * æ¥æºåæ®ç¼å· * * å ³èæ¥æºåæ®è¡¨çä¸»é® ID */ private Long sourceId; /** * 夿³¨ */ private String remark; yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseOrderMapper.java
@@ -81,4 +81,13 @@ .orderByDesc(ErpPurchaseOrderDO::getId)); } /** * ææ¥æºæ¥è¯¢éè´è®¢åï¼ç¨äºè¿½æº¯æ¥æºå·¥å对åºçéè´è®¢åï¼ */ default List<ErpPurchaseOrderDO> selectListBySource(Integer sourceType, Long sourceId) { return selectList(new LambdaQueryWrapperX<ErpPurchaseOrderDO>() .eq(ErpPurchaseOrderDO::getSourceType, sourceType) .eq(ErpPurchaseOrderDO::getSourceId, sourceId)); } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpPurchaseOrderInStatusEnum.java
@@ -30,4 +30,24 @@ return ARRAYS; } /** * æ ¹æ®ç¶æç è·åæä¸¾ */ public static ErpPurchaseOrderInStatusEnum fromStatus(Integer status) { return Arrays.stream(values()) .filter(e -> e.getStatus().equals(status)) .findFirst() .orElse(null); } /** * æ ¹æ®åç§°è·åæä¸¾ */ public static ErpPurchaseOrderInStatusEnum fromName(String name) { return Arrays.stream(values()) .filter(e -> e.getName().equals(name)) .findFirst() .orElse(null); } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpPurchaseOrderSourceTypeEnum.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,37 @@ package cn.iocoder.yudao.module.erp.enums; import cn.iocoder.yudao.framework.common.core.ArrayValuable; import lombok.Getter; import lombok.RequiredArgsConstructor; import java.util.Arrays; /** * ERP éè´è®¢åæ¥æºç±»åæä¸¾ * * @author èéæºç */ @RequiredArgsConstructor @Getter public enum ErpPurchaseOrderSourceTypeEnum implements ArrayValuable<Integer> { WORK_ORDER(1, "ç产工å"); public static final Integer[] ARRAYS = Arrays.stream(values()) .map(ErpPurchaseOrderSourceTypeEnum::getType).toArray(Integer[]::new); /** * ç±»åå¼ */ private final Integer type; /** * ç±»åå */ private final String name; @Override public Integer[] array() { return ARRAYS; } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpPurchaseRequestStatusEnum.java
@@ -35,4 +35,24 @@ return ARRAYS; } /** * æ ¹æ®ç¶æç è·åæä¸¾ */ public static ErpPurchaseRequestStatusEnum fromStatus(Integer status) { return Arrays.stream(values()) .filter(e -> e.getStatus().equals(status)) .findFirst() .orElse(null); } /** * æ ¹æ®åç§°è·åæä¸¾ */ public static ErpPurchaseRequestStatusEnum fromName(String name) { return Arrays.stream(values()) .filter(e -> e.getName().equals(name)) .findFirst() .orElse(null); } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderService.java
@@ -149,6 +149,15 @@ List<ErpPurchaseOrderDO> getPurchaseOrderList(List<Long> ids); /** * ææ¥æºæ¥è¯¢éè´è®¢åå表 * * @param sourceType æ¥æºç±»å * @param sourceId æ¥æºåæ®ç¼å· * @return éè´è®¢åå表 */ List<ErpPurchaseOrderDO> getPurchaseOrderListBySource(Integer sourceType, Long sourceId); /** * æ´æ°éè´è®¢åçå ¥åºç¶æ * * æ ¹æ®æç»å ¥åºæ°éèªå¨è®¡ç®è®¢åç¶æï¼ yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderServiceImpl.java
@@ -451,6 +451,14 @@ } @Override public List<ErpPurchaseOrderDO> getPurchaseOrderListBySource(Integer sourceType, Long sourceId) { if (sourceType == null || sourceId == null) { return Collections.emptyList(); } return purchaseOrderMapper.selectListBySource(sourceType, sourceId); } @Override public void updatePurchaseOrderInStatus(Long orderId) { // 1. è·åéè´è®¢å ErpPurchaseOrderDO order = validatePurchaseOrderExists(orderId); yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/employee/vo/HrmEmployeeSaveReqVO.java
@@ -94,14 +94,14 @@ @Schema(description = "æè²ç»åå表") @Valid private List<HrmEmployeeEducationSaveReqVO> educationList; private List<HrmEmployeeEducationSaveReqVO> educations; @Schema(description = "å·¥ä½ç»åå表") @Valid private List<HrmEmployeeWorkHistorySaveReqVO> workHistoryList; private List<HrmEmployeeWorkHistorySaveReqVO> workHistories; @Schema(description = "ç´§æ¥è系人å表") @Valid private List<HrmEmployeeEmergencyContactSaveReqVO> emergencyContactList; private List<HrmEmployeeEmergencyContactSaveReqVO> emergencyContacts; } yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/employee/HrmEmployeeEducationMapper.java
@@ -19,4 +19,8 @@ return selectList(HrmEmployeeEducationDO::getEmployeeId, employeeId); } default void deleteByEmployeeId(Long employeeId) { delete(HrmEmployeeEducationDO::getEmployeeId, employeeId); } } yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/employee/HrmEmployeeEmergencyContactMapper.java
@@ -21,4 +21,8 @@ .orderByAsc(HrmEmployeeEmergencyContactDO::getSort)); } default void deleteByEmployeeId(Long employeeId) { delete(HrmEmployeeEmergencyContactDO::getEmployeeId, employeeId); } } yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/mysql/employee/HrmEmployeeWorkHistoryMapper.java
@@ -19,4 +19,8 @@ return selectList(HrmEmployeeWorkHistoryDO::getEmployeeId, employeeId); } default void deleteByEmployeeId(Long employeeId) { delete(HrmEmployeeWorkHistoryDO::getEmployeeId, employeeId); } } yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/employee/HrmEmployeeServiceImpl.java
@@ -113,24 +113,24 @@ employeeMapper.insert(employee); Long employeeId = employee.getId(); // 7. åæ¥æ·»å æè²ç»å if (CollUtil.isNotEmpty(createReqVO.getEducationList())) { createReqVO.getEducationList().forEach(educationVO -> { if (CollUtil.isNotEmpty(createReqVO.getEducations())) { createReqVO.getEducations().forEach(educationVO -> { HrmEmployeeEducationDO education = BeanUtils.toBean(educationVO, HrmEmployeeEducationDO.class); education.setEmployeeId(employeeId); educationMapper.insert(education); }); } // 8. åæ¥æ·»å å·¥ä½ç»å if (CollUtil.isNotEmpty(createReqVO.getWorkHistoryList())) { createReqVO.getWorkHistoryList().forEach(workHistoryVO -> { if (CollUtil.isNotEmpty(createReqVO.getWorkHistories())) { createReqVO.getWorkHistories().forEach(workHistoryVO -> { HrmEmployeeWorkHistoryDO workHistory = BeanUtils.toBean(workHistoryVO, HrmEmployeeWorkHistoryDO.class); workHistory.setEmployeeId(employeeId); workHistoryMapper.insert(workHistory); }); } // 9. åæ¥æ·»å ç´§æ¥è系人 if (CollUtil.isNotEmpty(createReqVO.getEmergencyContactList())) { createReqVO.getEmergencyContactList().forEach(emergencyContactVO -> { if (CollUtil.isNotEmpty(createReqVO.getEmergencyContacts())) { createReqVO.getEmergencyContacts().forEach(emergencyContactVO -> { HrmEmployeeEmergencyContactDO emergencyContact = BeanUtils.toBean(emergencyContactVO, HrmEmployeeEmergencyContactDO.class); emergencyContact.setEmployeeId(employeeId); emergencyContactMapper.insert(emergencyContact); @@ -148,6 +148,7 @@ } @Override @Transactional(rollbackFor = Exception.class) public void updateEmployee(HrmEmployeeSaveReqVO updateReqVO) { // æ ¡éªåå¨ HrmEmployeeDO employee = validateEmployeeExists(updateReqVO.getId()); @@ -160,20 +161,69 @@ && employeeMapper.selectByPhone(updateReqVO.getPhone()) != null) { throw exception(EMPLOYEE_PHONE_EXISTS); } // æ´æ° // æ´æ°å工主表 HrmEmployeeDO updateObj = BeanUtils.toBean(updateReqVO, HrmEmployeeDO.class); // roleIds åå¨ä¸º JSON if (CollUtil.isNotEmpty(updateReqVO.getRoleIds())) { updateObj.setRoleIds(JSONUtil.toJsonStr(updateReqVO.getRoleIds())); } employeeMapper.updateById(updateObj); Long employeeId = updateReqVO.getId(); // 忥æè²ç»å syncEducationList(employeeId, updateReqVO.getEducations()); // 忥工ä½ç»å syncWorkHistoryList(employeeId, updateReqVO.getWorkHistories()); // åæ¥ç´§æ¥è系人 syncEmergencyContactList(employeeId, updateReqVO.getEmergencyContacts()); } private void syncEducationList(Long employeeId, List<HrmEmployeeEducationSaveReqVO> newList) { educationMapper.deleteByEmployeeId(employeeId); if (CollUtil.isNotEmpty(newList)) { newList.forEach(vo -> { HrmEmployeeEducationDO education = BeanUtils.toBean(vo, HrmEmployeeEducationDO.class); education.setId(null); education.setEmployeeId(employeeId); educationMapper.insert(education); }); } } private void syncWorkHistoryList(Long employeeId, List<HrmEmployeeWorkHistorySaveReqVO> newList) { workHistoryMapper.deleteByEmployeeId(employeeId); if (CollUtil.isNotEmpty(newList)) { newList.forEach(vo -> { HrmEmployeeWorkHistoryDO workHistory = BeanUtils.toBean(vo, HrmEmployeeWorkHistoryDO.class); workHistory.setId(null); workHistory.setEmployeeId(employeeId); workHistoryMapper.insert(workHistory); }); } } private void syncEmergencyContactList(Long employeeId, List<HrmEmployeeEmergencyContactSaveReqVO> newList) { emergencyContactMapper.deleteByEmployeeId(employeeId); if (CollUtil.isNotEmpty(newList)) { newList.forEach(vo -> { HrmEmployeeEmergencyContactDO emergencyContact = BeanUtils.toBean(vo, HrmEmployeeEmergencyContactDO.class); emergencyContact.setId(null); emergencyContact.setEmployeeId(employeeId); emergencyContactMapper.insert(emergencyContact); }); } } @Override @Transactional(rollbackFor = Exception.class) public void deleteEmployee(Long id) { // æ ¡éªåå¨ validateEmployeeExists(id); // å é¤ // 级èå é¤å表 educationMapper.deleteByEmployeeId(id); workHistoryMapper.deleteByEmployeeId(id); emergencyContactMapper.deleteByEmployeeId(id); // å é¤åå·¥ employeeMapper.deleteById(id); } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/plan/vo/MesCalPlanRespVO.java
@@ -52,6 +52,10 @@ @ExcelProperty("ç¶æ") private Integer status; @Schema(description = "æ¯å¦æé¤å¨æ«", example = "true") @ExcelProperty("æ¯å¦æé¤å¨æ«") private Boolean excludeWeekend; @Schema(description = "夿³¨") @ExcelProperty("夿³¨") private String remark; yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/cal/plan/vo/MesCalPlanSaveReqVO.java
@@ -47,7 +47,10 @@ @Schema(description = "ç¶æ", example = "0") private Integer status; @Schema(description = "æ¯å¦æé¤å¨æ«", example = "true") private Boolean excludeWeekend; @Schema(description = "夿³¨") private String remark; } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java
@@ -12,14 +12,24 @@ import cn.iocoder.yudao.module.mes.controller.admin.pro.workorder.vo.bom.MesProWorkOrderBomSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; 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.workorder.MesProWorkOrderBomDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderProcessDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper; import cn.iocoder.yudao.module.erp.api.purchase.ErpPurchaseOrderApi; import cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchaseOrderItemRespDTO; import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService; import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductBomService; import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProductBomService; import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProductService; import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderBomService; import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderProcessService; import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -31,6 +41,7 @@ import java.math.BigDecimal; import java.util.*; import java.util.Comparator; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; @@ -44,13 +55,23 @@ @Resource private MesProWorkOrderBomService workOrderBomService; @Resource private MesProWorkOrderService workOrderService; @Resource private MesProWorkOrderProcessService workOrderProcessService; @Resource private MesMdItemService itemService; @Resource private MesMdUnitMeasureService unitMeasureService; @Resource private MesMdItemTypeService itemTypeService; @Resource private MesMdProductBomService productBomService; private MesProRouteProductService routeProductService; @Resource private MesProRouteProductBomService routeProductBomService; @Resource private MesWmMaterialStockMapper materialStockMapper; @Resource private ErpPurchaseOrderApi purchaseOrderApi; @PostMapping("/create") @Operation(summary = "å建工å BOM") @@ -102,40 +123,67 @@ @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')") public CommonResult<List<MesProWorkOrderItemRespVO>> getWorkOrderBomItemListByWorkOrderId( @RequestParam("workOrderId") Long workOrderId) { // 1. è·åå·¥å BOM è¡ // 1. è·åå·¥å MesProWorkOrderDO workOrder = workOrderService.getWorkOrder(workOrderId); if (workOrder == null) { return success(Collections.emptyList()); } // 2. è·åå·¥åå·¥åºå表ï¼å«åå·¥åºçæææç»ä¸äº§åºåï¼ List<MesProWorkOrderProcessDO> processList = workOrderProcessService .getWorkOrderProcessListByWorkOrderId(workOrderId); if (CollUtil.isEmpty(processList)) { return success(Collections.emptyList()); } // 3. è·åå·¥å BOM è¡ï¼åå·¥åºçææè®°å½ï¼æ processId åç»ä½¿ç¨ï¼ List<MesProWorkOrderBomDO> bomList = workOrderBomService.getWorkOrderBomListByWorkOrderId(workOrderId); if (CollUtil.isEmpty(bomList)) { return success(Collections.emptyList()); } // 2. éå±å±å¼ï¼å¾å°å¶åç©æ itemId â quantity Map<Long, BigDecimal> leafItems = buildWorkOrderItems(bomList); // 4. éè¿äº§åID忥工èºè·¯çº¿ï¼å·¥å routeId å¯è½ä¸ºç©ºï¼ Long routeId = null; if (workOrder.getProductId() != null) { MesProRouteProductDO routeProduct = routeProductService.getRouteProductByItemId(workOrder.getProductId()); if (routeProduct != null) { routeId = routeProduct.getRouteId(); } } // 5. æå·¥åºäº§åºé¾éå±å±å¼ BOMï¼å¾å°å¶åç©æï¼æ¯å使åçç¨éï¼ Map<Long, BigDecimal> leafItems = buildWorkOrderItems(processList, bomList, routeId); if (CollUtil.isEmpty(leafItems)) { return success(Collections.emptyList()); } // 3. æ¼æ¥ VO åæ®µ Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(leafItems.keySet()); Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap( convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); Map<Long, MesMdItemTypeDO> itemTypeMap = itemTypeService.getItemTypeMap( convertSet(itemMap.values(), MesMdItemDO::getItemTypeId)); List<MesProWorkOrderItemRespVO> result = new ArrayList<>(leafItems.size()); // 6. ä¹ä»¥å·¥åç产æ°éï¼å¾å°æ»éæ± BigDecimal orderQty = workOrder.getQuantity() != null ? workOrder.getQuantity() : BigDecimal.ONE; Map<Long, BigDecimal> totalRequirements = new LinkedHashMap<>(); for (Map.Entry<Long, BigDecimal> entry : leafItems.entrySet()) { MesMdItemDO item = itemMap.get(entry.getKey()); if (item == null) { continue; } MesProWorkOrderItemRespVO vo = new MesProWorkOrderItemRespVO() .setItemId(item.getId()).setQuantity(entry.getValue()) .setItemCode(item.getCode()).setItemName(item.getName()).setItemSpecification(item.getSpecification()); MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(), unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); MapUtils.findAndThen(itemTypeMap, item.getItemTypeId(), itemType -> vo.setItemOrProduct(itemType.getItemOrProduct())); result.add(vo); totalRequirements.put(entry.getKey(), entry.getValue().multiply(orderQty)); } return success(result); // 7. æ¥è¯¢æ¥æºä¸ºæ¬å·¥åçéè´è®¢åæç»ï¼æäº§åæ±æ»å¨ééè´æ° // sourceType=1 è¡¨ç¤ºæ¥æºç±»å为"ç产工å" Map<Long, BigDecimal> purchaseOrderQtyMap = new HashMap<>(); List<ErpPurchaseOrderItemRespDTO> poItems = purchaseOrderApi .getPurchaseOrderItemListBySource(1, workOrderId) .getCheckedData(); if (CollUtil.isNotEmpty(poItems)) { for (ErpPurchaseOrderItemRespDTO poItem : poItems) { // å¨é = è®¢è´æ°é - å·²å ¥åºæ°é BigDecimal inCount = poItem.getInCount() != null ? poItem.getInCount() : BigDecimal.ZERO; BigDecimal inTransit = poItem.getCount().subtract(inCount); if (inTransit.compareTo(BigDecimal.ZERO) > 0) { purchaseOrderQtyMap.merge(poItem.getProductId(), inTransit, BigDecimal::add); } } } // 8. æ¥è¯¢åºåï¼æ¼æ¥ VO return success(buildItemRespVOList(totalRequirements, purchaseOrderQtyMap)); } // ==================== æ¼æ¥ VO ==================== @@ -164,47 +212,160 @@ }); } // ==================== ç©æéæ±éå±å±å¼ ==================== // ==================== ç©æéæ±å±å¼ï¼å·¥åºäº§åºé¾ + è·¯ç±äº§å BOMï¼ ==================== /** * éå± IN æ¥è¯¢å±å¼å·¥å BOM å°å¶åç©æï¼åå¹¶åç©æçéæ±æ°é * æå·¥åºäº§åºé¾éå±å±å¼ç©æéæ±ã * * @param bomList å·¥å BOM å表 * @return å¶åç©æ Mapï¼itemId â åå¹¶åçéæ±æ°é * <p><b>æ ¸å¿é»è¾ï¼</b></p> * <ol> * <li>æ¾åºå ³é®å·¥åºï¼keyFlag=trueï¼ï¼ä»¥å®çææä¸ºå±å¼èµ·ç¹</li> * <li>æå»ºäº§åºåâå·¥åºææçæ å°ï¼{@code outputItemId â per-unit bomItems}ï¼</li> * <li>éå±å±å¼ï¼è¥ç©ææ¯æå·¥åºç产åºå â ç¨è¯¥å·¥åºçææé æ¹æ¿ä»£ï¼ * å¦åæ¥è·¯ç±äº§å BOM â ç¨ BOM å项æ¿ä»£ï¼ * 两è 齿²¡æ â å¶åç©æï¼å¤è´ä»¶ï¼ï¼ç´¯å å°ç»æ</li> * </ol> * * <p>è¿æ ·é¿å äºæä¸é´å·¥åºçææç´æ¥çº³å ¥èµ·ç¹å¯¼è´çéå¤è®¡ç®é®é¢ã</p> * * @param processList å·¥åå·¥åºåè¡¨ï¼æ sort ååºï¼ * @param bomList å·¥å BOM è¡ï¼ææå·¥åºçæææç»ï¼ * @param routeId å·¥èºè·¯çº¿ç¼å·ï¼å¯ä¸º nullï¼null æ¶è·³è¿è·¯ç± BOM æ¥è¯¢ï¼ * @return å¶åç©æ Mapï¼itemId â éæ±æ°é */ private Map<Long, BigDecimal> buildWorkOrderItems(List<MesProWorkOrderBomDO> bomList) { // 1. åå§åï¼æ¶é第ä¸å±ç©æ ID åå¯¹åºæ°é Map<Long, BigDecimal> currentLayer = new LinkedHashMap<>(); for (MesProWorkOrderBomDO bom : bomList) { currentLayer.merge(bom.getItemId(), bom.getQuantity(), BigDecimal::add); private Map<Long, BigDecimal> buildWorkOrderItems(List<MesProWorkOrderProcessDO> processList, List<MesProWorkOrderBomDO> bomList, Long routeId) { // 1. æå»ºäº§åºå â å·¥åºææé æ¹ï¼per-unitï¼ // outputItemId â [{itemId, quantity}, ...] Map<Long, List<MesProWorkOrderBomDO>> processBomMap = new HashMap<>(); for (MesProWorkOrderProcessDO process : processList) { if (process.getOutputItemId() == null) { continue; } List<MesProWorkOrderBomDO> items = new ArrayList<>(); for (MesProWorkOrderBomDO bom : bomList) { if (bom.getProcessId().equals(process.getProcessId())) { items.add(bom); } } processBomMap.put(process.getOutputItemId(), items); } // 2. éå± IN æ¥è¯¢å±å¼ BOM // 2. åæåä¸éå·¥åºï¼sort æå¤§ï¼ä½ä¸ºå±å¼èµ·ç¹ï¼éå±åå鿍 MesProWorkOrderProcessDO lastProcess = processList.stream() .max(Comparator.comparing(MesProWorkOrderProcessDO::getSort)) .orElse(null); if (lastProcess == null) { return Collections.emptyMap(); } // 3. 以æåä¸éå·¥åºçææä¸ºèµ·ç¹ Map<Long, BigDecimal> currentLayer = new LinkedHashMap<>(); for (MesProWorkOrderBomDO bom : bomList) { if (bom.getProcessId().equals(lastProcess.getProcessId())) { currentLayer.merge(bom.getItemId(), bom.getQuantity(), BigDecimal::add); } } if (CollUtil.isEmpty(currentLayer)) { return Collections.emptyMap(); } // 4. éå±å±å¼ Map<Long, BigDecimal> leafItems = new LinkedHashMap<>(); for (int i = 0; i < Byte.MAX_VALUE && CollUtil.isNotEmpty(currentLayer); i++) { // 2.1 æ¹éæ¥è¯¢å½å屿æç©æçå BOM List<MesMdProductBomDO> subBomList = productBomService.getProductBomListByItemIds(currentLayer.keySet()); // 2.2 æ itemId åç» Map<Long, List<MesMdProductBomDO>> subBomMap = convertMultiMap(subBomList, MesMdProductBomDO::getItemId); // 2.3 åºåå¶åèç¹åéå¶åèç¹ Map<Long, BigDecimal> nextLayer = new LinkedHashMap<>(); // 4.1 æ¹éæ¥è¯¢è·¯ç±äº§å BOMï¼ç¨äºéå·¥åºäº§åºçç©æå±å¼ï¼ Map<Long, List<MesProRouteProductBomDO>> routeSubBomMap; if (routeId != null) { List<MesProRouteProductBomDO> routeSubBomList = routeProductBomService .getRouteProductBomListByProductIds(routeId, currentLayer.keySet()); routeSubBomMap = convertMultiMap(routeSubBomList, MesProRouteProductBomDO::getProductId); } else { routeSubBomMap = Collections.emptyMap(); } for (Map.Entry<Long, BigDecimal> entry : currentLayer.entrySet()) { Long itemId = entry.getKey(); BigDecimal quantity = entry.getValue(); List<MesMdProductBomDO> children = subBomMap.get(itemId); // æ åµä¸ï¼å¶åèç¹ï¼ç´¯å å°ç»æ if (CollUtil.isEmpty(children)) { leafItems.merge(itemId, quantity, BigDecimal::add); BigDecimal qty = entry.getValue(); // æ åµä¸ï¼ç©ææ¯æå·¥åºç产åºå â ç¨å·¥åºé æ¹æ¿ä»£ List<MesProWorkOrderBomDO> processBom = processBomMap.get(itemId); if (CollUtil.isNotEmpty(processBom)) { for (MesProWorkOrderBomDO child : processBom) { nextLayer.merge(child.getItemId(), qty.multiply(child.getQuantity()), BigDecimal::add); } continue; } // æ åµäºï¼éå¶åï¼åç©æè¿å ¥ä¸ä¸å± for (MesMdProductBomDO child : children) { nextLayer.merge(child.getBomItemId(), quantity.multiply(child.getQuantity()), BigDecimal::add); // æ åµäºï¼è·¯ç±äº§å BOM 䏿ä¸çº§ â å±å¼ List<MesProRouteProductBomDO> routeChildren = routeSubBomMap.get(itemId); if (CollUtil.isNotEmpty(routeChildren)) { for (MesProRouteProductBomDO child : routeChildren) { nextLayer.merge(child.getItemId(), qty.multiply(child.getQuantity()), BigDecimal::add); } continue; } // æ åµä¸ï¼å¶åç©æ leafItems.merge(itemId, qty, BigDecimal::add); } currentLayer = nextLayer; } return leafItems; } // ==================== æ¼æ¥ç©æéæ± VOï¼å«åºåæ ¡éªï¼ ==================== private List<MesProWorkOrderItemRespVO> buildItemRespVOList(Map<Long, BigDecimal> requirements, Map<Long, BigDecimal> purchaseOrderQtyMap) { // 1. æ¹éè·åç©æåºç¡ä¿¡æ¯ Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(requirements.keySet()); Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap( convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); Map<Long, MesMdItemTypeDO> itemTypeMap = itemTypeService.getItemTypeMap( convertSet(itemMap.values(), MesMdItemDO::getItemTypeId)); // 2. æ¹éæ¥è¯¢åºåï¼æ itemId æ±æ»å¯ç¨éï¼å¨åº - å»ç» - å ç¨ï¼ Map<Long, BigDecimal> stockMap = new HashMap<>(); List<MesWmMaterialStockDO> stockList = materialStockMapper.selectListByItemIds(requirements.keySet()); for (MesWmMaterialStockDO stock : stockList) { BigDecimal frozen = stock.getFrozenQuantity() != null ? stock.getFrozenQuantity() : BigDecimal.ZERO; BigDecimal reserved = stock.getReservedQuantity() != null ? stock.getReservedQuantity() : BigDecimal.ZERO; BigDecimal available = stock.getQuantity().subtract(frozen).subtract(reserved); if (available.compareTo(BigDecimal.ZERO) > 0) { stockMap.merge(stock.getItemId(), available, BigDecimal::add); } } // 3. æ¼æ¥ VO List<MesProWorkOrderItemRespVO> result = new ArrayList<>(requirements.size()); for (Map.Entry<Long, BigDecimal> entry : requirements.entrySet()) { MesMdItemDO item = itemMap.get(entry.getKey()); if (item == null) { continue; } BigDecimal requiredQty = entry.getValue(); BigDecimal stockQty = stockMap.getOrDefault(item.getId(), BigDecimal.ZERO); BigDecimal purchaseQty = purchaseOrderQtyMap.getOrDefault(item.getId(), BigDecimal.ZERO); // å è¶³å¤æ = å¯ç¨åºå + å¨ééè´æ° >= éæ±æ°é BigDecimal totalSupply = stockQty.add(purchaseQty); MesProWorkOrderItemRespVO vo = new MesProWorkOrderItemRespVO() .setItemId(item.getId()).setQuantity(requiredQty) .setItemCode(item.getCode()).setItemName(item.getName()).setItemSpecification(item.getSpecification()) .setStockQuantity(stockQty) .setPurchaseOrderQuantity(purchaseQty) .setStockSufficient(totalSupply.compareTo(requiredQty) >= 0); MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(), unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); MapUtils.findAndThen(itemTypeMap, item.getItemTypeId(), itemType -> vo.setItemOrProduct(itemType.getItemOrProduct())); result.add(vo); } return result; } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/vo/MesProWorkOrderItemRespVO.java
@@ -27,6 +27,15 @@ @Schema(description = "éæ±æ°é", example = "1000.00") private BigDecimal quantity; @Schema(description = "å¯ç¨åºå", example = "500.00") private BigDecimal stockQuantity; @Schema(description = "å¨ééè´æ°ï¼æ¥æºä¸ºæ¬å·¥åçéè´è®¢åæ°éæ±æ»ï¼", example = "200.00") private BigDecimal purchaseOrderQuantity; @Schema(description = "åºåæ¯å¦å è¶³ï¼å¯ç¨åºå + å¨ééè´æ° >= éæ±æ°éï¼", example = "true") private Boolean stockSufficient; @Schema(description = "ç©æ/äº§åæ è¯", example = "ITEM") private String itemOrProduct; yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/salesnotice/vo/line/MesWmSalesNoticeLineSaveReqVO.java
@@ -18,6 +18,9 @@ @NotNull(message = "åè´§éç¥åç¼å·ä¸è½ä¸ºç©º") private Long noticeId; @Schema(description = "éå®è®¢åæç»ID", example = "1") private Long saleOrderItemId; @Schema(description = "ç©æç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "ç©æç¼å·ä¸è½ä¸ºç©º") private Long itemId; yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/cal/plan/MesCalPlanDO.java
@@ -78,6 +78,14 @@ */ private Integer status; /** * æ¯å¦æé¤å¨æ« * * trueï¼å¨å æ¥ä¸çææçè®°å½ï¼é»è®¤ï¼ * falseï¼å¨å æ¥æ£å¸¸æçï¼å¦æ³¨å¡è½¦é´éè¦è¿ç»çäº§ï¼ */ private Boolean excludeWeekend; /** * 夿³¨ */ private String remark; yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/pro/route/MesProRouteProductBomMapper.java
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductBomDO; import org.apache.ibatis.annotations.Mapper; import java.util.Collection; import java.util.List; /** @@ -46,4 +47,10 @@ .eq(MesProRouteProductBomDO::getProductId, productId)); } default List<MesProRouteProductBomDO> selectListByProductIds(Long routeId, Collection<Long> productIds) { return selectList(new LambdaQueryWrapperX<MesProRouteProductBomDO>() .eq(MesProRouteProductBomDO::getRouteId, routeId) .in(MesProRouteProductBomDO::getProductId, productIds)); } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/batch/MesWmBatchMapper.java
@@ -72,12 +72,12 @@ .betweenIfPresent(MesWmBatchDO::getExpireDate, reqVO.getExpireDate()) .betweenIfPresent(MesWmBatchDO::getReceiptDate, reqVO.getReceiptDate()) .orderByDesc(MesWmBatchDO::getId); if (permittedClientIds != null) { if (CollUtil.isEmpty(permittedClientIds)) { return PageResult.empty(); } wrapper.in(MesWmBatchDO::getClientId, permittedClientIds); } // if (permittedClientIds != null) { // if (CollUtil.isEmpty(permittedClientIds)) { // return PageResult.empty(); // } // wrapper.in(MesWmBatchDO::getClientId, permittedClientIds); // } return selectPage(reqVO, wrapper); } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java
@@ -137,12 +137,13 @@ } else { wrapper.isNull(MesWmMaterialStockDO::getBatchId); } // vendorId=null æ¶ç²¾ç¡®å¹é is null // vendorId=null æ¶ä¸éå¶ï¼å¹é ä»»æä¾åºåçåºå // ï¼é¿å å ä¾åºå维度æåï¼OUT äºå¡æ¾ä¸å°çæ£æåºåçè®°å½èæ£éå° vendor_id IS NULL çè®°å½ï¼ if (vendorId != null) { wrapper.eq(MesWmMaterialStockDO::getVendorId, vendorId); } else { wrapper.isNull(MesWmMaterialStockDO::getVendorId); } // å¤è®°å½æ¶ä¼å ååºåéæå¤çï¼é¿å æ£å°é¶åºåæè´åºåçè®°å½ï¼ wrapper.last("ORDER BY quantity DESC LIMIT 1"); return selectOne(wrapper); } @@ -183,4 +184,16 @@ .orderByAsc(MesWmMaterialStockDO::getReceiptTime)); } /** * æç©æç¼å·æ¹éæ¥è¯¢åºåè®°å½ï¼ç¨äºç©æéæ±åºåæ ¡éªï¼ */ default List<MesWmMaterialStockDO> selectListByItemIds(Collection<Long> itemIds) { if (itemIds == null || itemIds.isEmpty()) { return java.util.Collections.emptyList(); } return selectList(new LambdaQueryWrapperX<MesWmMaterialStockDO>() .in(MesWmMaterialStockDO::getItemId, itemIds) .ne(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO)); } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/cal/team/MesCalTeamShiftServiceImpl.java
@@ -1,13 +1,16 @@ package cn.iocoder.yudao.module.mes.service.cal.team; import cn.iocoder.yudao.module.mes.controller.admin.cal.team.vo.shift.MesCalTeamShiftListReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.cal.holiday.MesCalHolidayDO; import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanDO; import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanShiftDO; import cn.iocoder.yudao.module.mes.dal.dataobject.cal.plan.MesCalPlanTeamDO; import cn.iocoder.yudao.module.mes.dal.dataobject.cal.team.MesCalTeamShiftDO; import cn.iocoder.yudao.module.mes.dal.mysql.cal.team.MesCalTeamShiftMapper; import cn.iocoder.yudao.module.mes.enums.cal.MesCalHolidayTypeEnum; import cn.iocoder.yudao.module.mes.enums.cal.MesCalShiftMethodEnum; import cn.iocoder.yudao.module.mes.enums.cal.MesCalShiftTypeEnum; import cn.iocoder.yudao.module.mes.service.cal.holiday.MesCalHolidayService; import cn.iocoder.yudao.module.mes.service.cal.plan.MesCalPlanService; import cn.iocoder.yudao.module.mes.service.cal.plan.MesCalPlanShiftService; import cn.iocoder.yudao.module.mes.service.cal.plan.MesCalPlanTeamService; @@ -18,11 +21,14 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.time.DayOfWeek; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.CAL_TEAM_SHIFT_GENERATE_SHIFT_NOT_ENOUGH; @@ -49,6 +55,9 @@ @Resource @Lazy private MesCalPlanTeamService planTeamService; @Resource @Lazy private MesCalHolidayService holidayService; @Transactional(rollbackFor = Exception.class) @Override @@ -69,23 +78,56 @@ throw exception(CAL_TEAM_SHIFT_GENERATE_SHIFT_NOT_ENOUGH); } // 2. è®¡ç®æ¥æè·¨åº¦ï¼éåæ¯å¤©çææçè®°å½ï¼æåç»ä¸åå ¥æ°æ®åº // 1.5 å è½½æ¥æåºé´å çåæ¥æ°æ®ï¼æå»º Map<æ¥æ, ç±»å> Map<LocalDate, Integer> holidayMap = holidayService.getHolidayList(plan.getStartDate(), plan.getEndDate()) .stream().collect(Collectors.toMap(h -> h.getDay().toLocalDate(), MesCalHolidayDO::getType)); // 2. è®¡ç®æ¥æè·¨åº¦ï¼é天夿工使¥ï¼çææçè®°å½ LocalDate startDate = plan.getStartDate().toLocalDate(); LocalDate endDate = plan.getEndDate().toLocalDate(); long days = ChronoUnit.DAYS.between(startDate, endDate) + 1; boolean excludeWeekend = plan.getExcludeWeekend() != null && plan.getExcludeWeekend(); List<MesCalTeamShiftDO> allRecords = new ArrayList<>(); int shiftIndex = 0; int workdayOffset = 0; // ä» å·¥ä½æ¥éå¢ï¼ç¨äºåçè½®æ¢è®¡æ° for (int i = 0; i < days; i++) { LocalDate currentDate = startDate.plusDays(i); // 2.1 è·³è¿é工使¥ if (!isWorkday(currentDate, holidayMap, excludeWeekend)) { continue; } LocalDateTime currentDay = currentDate.atStartOfDay(); // 2.2.1 æ ¹æ®åçæ¹å¼è®¡ç® shiftIndex shiftIndex = calculateShiftIndex(shiftIndex, i, currentDate, startDate, plan); // 2.2.1 æ ¹æ®åçæ¹å¼è®¡ç® shiftIndexï¼ä»¥å·¥ä½æ¥å移为åï¼ shiftIndex = calculateShiftIndex(shiftIndex, workdayOffset, currentDate, startDate, plan); // 2.2.2 æ ¹æ®è½®çæ¹å¼çææçè®°å½ï¼æ¶éå°å表 buildRecordsForDay(allRecords, planId, currentDay, shiftIndex, plan.getShiftType(), teams, shifts); workdayOffset++; } // 3. æ¹éæå ¥æçè®°å½ teamShiftMapper.insertBatch(allRecords); } /** * 夿æå®æ¥ææ¯å¦ä¸ºå·¥ä½æ¥ * * ä¼å 级ï¼holiday 表 > 卿«æé¤å¼å ³ > é»è®¤å·¥ä½æ¥ */ private boolean isWorkday(LocalDate date, Map<LocalDate, Integer> holidayMap, boolean excludeWeekend) { // 1. holiday 表ä¼å ï¼æ¾å¼æ è®°çæ¥æä»¥æ 记为å Integer holidayType = holidayMap.get(date); if (holidayType != null) { return MesCalHolidayTypeEnum.WORKDAY.getType().equals(holidayType); } // 2. è¥å¼å¯äºæé¤å¨æ«ï¼å¨å æ¥é»è®¤ä¸ºä¼æ¯æ¥ if (excludeWeekend) { DayOfWeek dow = date.getDayOfWeek(); if (dow == DayOfWeek.SATURDAY || dow == DayOfWeek.SUNDAY) { return false; } } // 3. é»è®¤å·¥ä½æ¥ return true; } /** @@ -96,6 +138,10 @@ if (dayOffset == 0) { return shiftIndex; // 第ä¸å¤©ä¸éå¢ } // åç½çä¸éè¦åçï¼shiftMethod 为 nullï¼ç´æ¥è¿å if (plan.getShiftMethod() == null) { return shiftIndex; } if (MesCalShiftMethodEnum.QUARTER.getMethod().equals(plan.getShiftMethod())) { // æå£åº¦è½®çï¼å°äºæ°å£åº¦ç第ä¸å¤© LocalDate quarterStart = LocalDateTimeUtils.getQuarterStart(currentDate); yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProductBomService.java
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductBomDO; import jakarta.validation.Valid; import java.util.Collection; import java.util.List; /** @@ -62,4 +63,13 @@ */ List<MesProRouteProductBomDO> getRouteProductBomListByRouteIdAndProductId(Long routeId, Long productId); /** * æå·¥èºè·¯çº¿åå¤ä¸ªäº§åæ¹éæ¥è¯¢ BOM å表 * * @param routeId å·¥èºè·¯çº¿ç¼å· * @param productIds 产åç©æç¼å·éå * @return BOM å表 */ List<MesProRouteProductBomDO> getRouteProductBomListByProductIds(Long routeId, Collection<Long> productIds); } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProductBomServiceImpl.java
@@ -13,6 +13,7 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.util.Collection; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -137,4 +138,12 @@ return routeProductBomMapper.selectListByRouteIdAndProductId(routeId, productId); } @Override public List<MesProRouteProductBomDO> getRouteProductBomListByProductIds(Long routeId, Collection<Long> productIds) { if (CollUtil.isEmpty(productIds)) { return java.util.Collections.emptyList(); } return routeProductBomMapper.selectListByProductIds(routeId, productIds); } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/batch/MesWmBatchServiceImpl.java
@@ -97,122 +97,107 @@ // 2. æ ¹æ®é ç½®æ ¡éªå¿ å¡«åæ°å¹¶æ¸ ç©ºä¸éè¦çåæ° MesWmBatchDO batch = MesWmBatchDO.builder().itemId(reqVO.getItemId()).build(); if (config != null) { // ========== å¿ å¡«æ ¡éªï¼flag=true è¡¨ç¤ºè¯¥åæ®µä¸ºå¿ å¡«ï¼ ========== // çäº§æ¥æ if (Boolean.TRUE.equals(config.getProduceDateFlag())) { if (ObjUtil.isNull(reqVO.getProduceDate())) { throw exception(WM_BATCH_PRODUCE_DATE_REQUIRED); } batch.setProduceDate(reqVO.getProduceDate()); if (Boolean.TRUE.equals(config.getProduceDateFlag()) && ObjUtil.isNull(reqVO.getProduceDate())) { throw exception(WM_BATCH_PRODUCE_DATE_REQUIRED); } // å ¥åºæ¥æ if (Boolean.TRUE.equals(config.getReceiptDateFlag())) { if (ObjUtil.isNull(reqVO.getReceiptDate())) { throw exception(WM_BATCH_RECEIPT_DATE_REQUIRED); } batch.setReceiptDate(reqVO.getReceiptDate()); if (Boolean.TRUE.equals(config.getReceiptDateFlag()) && ObjUtil.isNull(reqVO.getReceiptDate())) { throw exception(WM_BATCH_RECEIPT_DATE_REQUIRED); } // æææ if (Boolean.TRUE.equals(config.getExpireDateFlag())) { if (ObjUtil.isNull(reqVO.getExpireDate())) { throw exception(WM_BATCH_EXPIRE_DATE_REQUIRED); } batch.setExpireDate(reqVO.getExpireDate()); if (Boolean.TRUE.equals(config.getExpireDateFlag()) && ObjUtil.isNull(reqVO.getExpireDate())) { throw exception(WM_BATCH_EXPIRE_DATE_REQUIRED); } // ä¾åºå if (Boolean.TRUE.equals(config.getVendorFlag())) { if (ObjUtil.isNull(reqVO.getVendorId())) { throw exception(WM_BATCH_VENDOR_REQUIRED); } batch.setVendorId(reqVO.getVendorId()); if (Boolean.TRUE.equals(config.getVendorFlag()) && ObjUtil.isNull(reqVO.getVendorId())) { throw exception(WM_BATCH_VENDOR_REQUIRED); } // å®¢æ· if (Boolean.TRUE.equals(config.getClientFlag())) { if (ObjUtil.isNull(reqVO.getClientId())) { throw exception(WM_BATCH_CLIENT_REQUIRED); } batch.setClientId(reqVO.getClientId()); if (Boolean.TRUE.equals(config.getClientFlag()) && ObjUtil.isNull(reqVO.getClientId())) { throw exception(WM_BATCH_CLIENT_REQUIRED); } // éè´è®¢åç¼å· if (Boolean.TRUE.equals(config.getPurchaseOrderCodeFlag())) { if (ObjUtil.isNull(reqVO.getPurchaseOrderCode())) { throw exception(WM_BATCH_PURCHASE_ORDER_CODE_REQUIRED); } batch.setPurchaseOrderCode(reqVO.getPurchaseOrderCode()); if (Boolean.TRUE.equals(config.getPurchaseOrderCodeFlag()) && ObjUtil.isNull(reqVO.getPurchaseOrderCode())) { throw exception(WM_BATCH_PURCHASE_ORDER_CODE_REQUIRED); } // éå®è®¢åç¼å· if (Boolean.TRUE.equals(config.getSalesOrderCodeFlag())) { if (ObjUtil.isNull(reqVO.getSalesOrderCode())) { throw exception(WM_BATCH_CUSTOMER_ORDER_CODE_REQUIRED); } batch.setSalesOrderCode(reqVO.getSalesOrderCode()); if (Boolean.TRUE.equals(config.getSalesOrderCodeFlag()) && ObjUtil.isNull(reqVO.getSalesOrderCode())) { throw exception(WM_BATCH_CUSTOMER_ORDER_CODE_REQUIRED); } // ç产工å if (Boolean.TRUE.equals(config.getWorkOrderFlag())) { if (ObjUtil.isNull(reqVO.getWorkOrderId())) { throw exception(WM_BATCH_WORK_ORDER_REQUIRED); } batch.setWorkOrderId(reqVO.getWorkOrderId()); if (Boolean.TRUE.equals(config.getWorkOrderFlag()) && ObjUtil.isNull(reqVO.getWorkOrderId())) { throw exception(WM_BATCH_WORK_ORDER_REQUIRED); } // çäº§ä»»å¡ if (Boolean.TRUE.equals(config.getTaskFlag())) { if (ObjUtil.isNull(reqVO.getTaskId())) { throw exception(WM_BATCH_TASK_REQUIRED); } batch.setTaskId(reqVO.getTaskId()); if (Boolean.TRUE.equals(config.getTaskFlag()) && ObjUtil.isNull(reqVO.getTaskId())) { throw exception(WM_BATCH_TASK_REQUIRED); } // å·¥ä½ç« if (Boolean.TRUE.equals(config.getWorkstationFlag())) { if (ObjUtil.isNull(reqVO.getWorkstationId())) { throw exception(WM_BATCH_WORKSTATION_REQUIRED); } batch.setWorkstationId(reqVO.getWorkstationId()); if (Boolean.TRUE.equals(config.getWorkstationFlag()) && ObjUtil.isNull(reqVO.getWorkstationId())) { throw exception(WM_BATCH_WORKSTATION_REQUIRED); } // å·¥å · if (Boolean.TRUE.equals(config.getToolFlag())) { if (ObjUtil.isNull(reqVO.getToolId())) { throw exception(WM_BATCH_TOOL_REQUIRED); } batch.setToolId(reqVO.getToolId()); if (Boolean.TRUE.equals(config.getToolFlag()) && ObjUtil.isNull(reqVO.getToolId())) { throw exception(WM_BATCH_TOOL_REQUIRED); } // æ¨¡å · if (Boolean.TRUE.equals(config.getMoldFlag())) { if (ObjUtil.isNull(reqVO.getMoldId())) { throw exception(WM_BATCH_MOLD_REQUIRED); } batch.setMoldId(reqVO.getMoldId()); if (Boolean.TRUE.equals(config.getMoldFlag()) && ObjUtil.isNull(reqVO.getMoldId())) { throw exception(WM_BATCH_MOLD_REQUIRED); } // ç产æ¹å· if (Boolean.TRUE.equals(config.getLotNumberFlag())) { if (ObjUtil.isNull(reqVO.getLotNumber())) { throw exception(WM_BATCH_LOT_NUMBER_REQUIRED); } batch.setLotNumber(reqVO.getLotNumber()); if (Boolean.TRUE.equals(config.getLotNumberFlag()) && ObjUtil.isNull(reqVO.getLotNumber())) { throw exception(WM_BATCH_LOT_NUMBER_REQUIRED); } // è´¨éç¶æ if (Boolean.TRUE.equals(config.getQualityStatusFlag())) { if (ObjUtil.isNull(reqVO.getQualityStatus())) { throw exception(WM_BATCH_QUALITY_STATUS_REQUIRED); } batch.setQualityStatus(reqVO.getQualityStatus()); if (Boolean.TRUE.equals(config.getQualityStatusFlag()) && ObjUtil.isNull(reqVO.getQualityStatus())) { throw exception(WM_BATCH_QUALITY_STATUS_REQUIRED); } } // æ æ¹æ¬¡é ç½®æ¶ï¼ä½¿ç¨ä¼ å ¥çåæ°ï¼å®½æ¾æ¨¡å¼ï¼éç¨äºèªå®ä¹å ¥åºçåºæ¯ï¼ else { if (reqVO.getProduceDate() != null) { batch.setProduceDate(reqVO.getProduceDate()); } if (reqVO.getReceiptDate() != null) { batch.setReceiptDate(reqVO.getReceiptDate()); } if (reqVO.getExpireDate() != null) { batch.setExpireDate(reqVO.getExpireDate()); } if (reqVO.getVendorId() != null) { batch.setVendorId(reqVO.getVendorId()); } if (reqVO.getClientId() != null) { batch.setClientId(reqVO.getClientId()); } // ========== ä¿ååæ®µï¼æ è®ºææ é ç½®ï¼åªè¦è°ç¨æ¹ä¼ äºå°±ä¿åï¼ ========== if (reqVO.getProduceDate() != null) { batch.setProduceDate(reqVO.getProduceDate()); } if (reqVO.getReceiptDate() != null) { batch.setReceiptDate(reqVO.getReceiptDate()); } if (reqVO.getExpireDate() != null) { batch.setExpireDate(reqVO.getExpireDate()); } if (reqVO.getVendorId() != null) { batch.setVendorId(reqVO.getVendorId()); } if (reqVO.getClientId() != null) { batch.setClientId(reqVO.getClientId()); } if (reqVO.getPurchaseOrderCode() != null) { batch.setPurchaseOrderCode(reqVO.getPurchaseOrderCode()); } if (reqVO.getSalesOrderCode() != null) { batch.setSalesOrderCode(reqVO.getSalesOrderCode()); } if (reqVO.getWorkOrderId() != null) { batch.setWorkOrderId(reqVO.getWorkOrderId()); } if (reqVO.getTaskId() != null) { batch.setTaskId(reqVO.getTaskId()); } if (reqVO.getWorkstationId() != null) { batch.setWorkstationId(reqVO.getWorkstationId()); } if (reqVO.getToolId() != null) { batch.setToolId(reqVO.getToolId()); } if (reqVO.getMoldId() != null) { batch.setMoldId(reqVO.getMoldId()); } if (reqVO.getLotNumber() != null) { batch.setLotNumber(reqVO.getLotNumber()); } if (reqVO.getQualityStatus() != null) { batch.setQualityStatus(reqVO.getQualityStatus()); } // 3.1 æ åµä¸ï¼ä¼ å ¥äº batchCodeï¼æ¥è¯¢æ¯å¦åå¨è¯¥æ¹æ¬¡å· yudao-module-srm/src/main/java/cn/iocoder/yudao/module/srm/service/supplier/SrmSupplierServiceImpl.java
@@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.srm.service.supplier; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.srm.controller.admin.supplier.vo.SrmSupplierPageReqVO; @@ -14,6 +15,8 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.hutool.core.collection.CollUtil; import java.util.Collection; import java.util.Collections;