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-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/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/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/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-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/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/materialstock/MesWmMaterialStockMapper.java
@@ -183,4 +183,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/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-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,7 +15,10 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import java.util.Collection; import java.util.Collections; import java.util.List; @Service @@ -79,6 +83,9 @@ @Override public List<SrmSupplierDO> getSupplierList(Collection<Long> ids) { if (CollUtil.isEmpty(ids)) { return Collections.emptyList(); } return supplierMapper.selectBatchIds(ids); }