docs/erp_purchase_qc_check_flag.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,103 @@ # ERP éè´è®¢åè´¨æ£åæ®µä¸ MES æ¥ææ£éªèªå¨å建 - å端èè°æ¹æ¡ ## æ¶åé¡µé¢ - ERP éè´è®¢åå表页 - ERP éè´è®¢åæ°å¢/ç¼è¾é¡µ - ERP éè´è®¢å详æ 页 - MES å°è´§éç¥åå表页 - MES å°è´§éç¥å详æ 页 - MES æ¥ææ£éªï¼IQCï¼å表页 ## ä¸å¡æµç¨ ### 1. éè´è®¢åæ°å¢è´¨æ£æ è¯ 1. ç¨æ·å¨ ERP éè´è®¢åæ°å¢/ç¼è¾é¡µé¢ï¼å¯ä»¥ä¸ºæ¯ä¸ªäº§åæç»å¾é"æ¯å¦éè¦æ¥ææ£éª" 2. ä¿åæ¶ï¼`qcCheckFlag` åæ®µé订åæç»ä¸èµ·ä¿å ### 2. ä»éè´è®¢åçæå°è´§éç¥å 1. ç¨æ·ç¹å»"çæå°è´§éç¥å"æé® 2. ç³»ç»èªå¨å°éè´è®¢åæç»ç `qcCheckFlag` å¸¦å ¥å°è´§éç¥åè¡ç `iqcCheckFlag` 3. ç¨æ·å¯å¨å°è´§éç¥å详æ é¡µä¿®æ¹æ¯è¡çè´¨æ£æ è¯ ### 3. å°è´§éç¥åæäº¤èªå¨å建 IQC 1. ç¨æ·æäº¤å°è´§éç¥å 2. 妿æè¡æ 记为éè¦è´¨æ£ï¼`iqcCheckFlag = true`ï¼ï¼ - å°è´§éç¥åç¶æå为"å¾ è´¨æ£" - ç³»ç»èªå¨ä¸ºæ¯ä¸ªéè¦è´¨æ£çè¡åå»ºä¸æ¡ IQC æ¥ææ£éªå - è¡ä¸ç `iqcId` å ³èå°åå»ºçæ£éªå 3. å¦ææ²¡æéè¦è´¨æ£çè¡ï¼ç¶æç´æ¥å为"å¾ å ¥åº" ## API åæ´ ### ERP éè´è®¢å #### 请æ±åæ°åæ´ **ErpPurchaseOrderSaveReqVO.Item æ°å¢å段ï¼** | åæ®µ | ç±»å | å¿ å¡« | 说æ | |------|------|------|------| | qcCheckFlag | Boolean | å¦ | æ¯å¦éè¦æ¥ææ£éª | #### ååºåæ°åæ´ **ErpPurchaseOrderRespVO.Item æ°å¢å段ï¼** | åæ®µ | ç±»å | 说æ | |------|------|------| | qcCheckFlag | Boolean | æ¯å¦éè¦æ¥ææ£éª | ### MES å°è´§éç¥å #### ååºåæ°åæ´ **å°è´§éç¥åè¡æ°å¢å段ï¼å·²åå¨ï¼å¼ºè°å¸¦å ¥é»è¾ï¼ï¼** | åæ®µ | ç±»å | 说æ | |------|------|------| | iqcCheckFlag | Boolean | æ¯å¦éè¦æ¥ææ£éªï¼ä»éè´è®¢åå¸¦å ¥ï¼ | | iqcId | Long | å ³èç IQC æ£éªå IDï¼æäº¤åèªå¨åå»ºï¼ | ## åæ®µå±ç¤ºè§å ### ERP éè´è®¢å | åæ®µ | å±ç¤ºä½ç½® | 说æ | |------|----------|------| | æ¯å¦è´¨æ£ | 订åæç»è¡¨æ ¼ | ä½¿ç¨ Checkbox æ Switch å±ç¤ºï¼å¯ç¼è¾ | ### MES å°è´§éç¥å | åæ®µ | å±ç¤ºä½ç½® | 说æ | |------|----------|------| | æ¯å¦è´¨æ£ | è¡æç»è¡¨æ ¼ | ä½¿ç¨ Tag æ Checkbox å±ç¤ºï¼æäº¤åä¸å¯ä¿®æ¹ | | IQC æ£éªå | è¡æç»è¡¨æ ¼ | å ³èçæ£éªåç¼å·ï¼ç¹å»å¯è·³è½¬ï¼æäº¤åèªå¨å ³èï¼ | ### MES æ¥ææ£éª | åæ®µ | å±ç¤ºä½ç½® | 说æ | |------|----------|------| | æ¥æºåæ® | 详æ 页 | æ¾ç¤ºå°è´§éç¥åç¼å·ï¼ç¹å»å¯è·³è½¬ | | æ¥æºåæ®è¡ | 详æ 页 | æ¾ç¤ºå°è´§éç¥åè¡ç¼å· | ## ä¸å¡è§å说æ | åºæ¯ | è§å | |------|------| | éè´è®¢åä¿å | `qcCheckFlag` é»è®¤ä¸º falseï¼ä¸è´¨æ£ï¼ | | çæå°è´§éç¥å | ä»éè´è®¢åæç»å¸¦å ¥ `qcCheckFlag` å° `iqcCheckFlag` | | å°è´§éç¥åæäº¤ | 妿éè¦è´¨æ£çè¡ï¼èªå¨å建 IQC æ£éªåå¹¶å ³è | | IQC å建æ¡ä»¶ | ç©æå¿ é¡»é ç½®äº IQC æ£éªæ¨¡æ¿ï¼å¦åè·³è¿å¹¶è®°å½æ¥å¿ | | IQC åæ®ç¶æ | èªå¨å建ç IQC 为èç¨¿ç¶æï¼éè¦æ£éªå填忣éªç»æ | ## 注æäºé¡¹ 1. **æ£éªæ¨¡æ¿é ç½®**ï¼ç©æå¿ é¡»å å¨ MES è´¨éæ¨¡åé ç½® IQC æ£éªæ¨¡æ¿ï¼å¦åèªå¨å建 IQC ä¼å¤±è´¥ 2. **æ°æ®å¸¦å ¥**ï¼ä»éè´è®¢åçæå°è´§éç¥åæ¶ï¼è´¨æ£æ è¯ä¼èªå¨å¸¦å ¥ï¼ä½ç¨æ·å¯å¨å°è´§éç¥åä¸ä¿®æ¹ 3. **ç¶ææµè½¬**ï¼å°è´§éç¥åæäº¤åï¼éè¦è´¨æ£çè¡ä¼è¿å ¥"å¾ è´¨æ£"ç¶æï¼æææ£éªå®æåæå¯å ¥åº 4. **æ£éªåå ³è**ï¼æäº¤åè¡ä¸ä¼å ³è IQC æ£éªå IDï¼ç¹å»å¯è·³è½¬æ¥çæ£éªè¯¦æ 5. **å¼å¸¸å¤ç**ï¼å¦ææè¡å建 IQC 失败ï¼å¦ç¼ºå°æ¨¡æ¿ï¼ï¼ä¸ä¼ä¸ææ´ä¸ªæäº¤æµç¨ï¼ä¼è®°å½æ¥å¿ç»§ç»å¤çå ¶ä»è¡ yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java
@@ -62,6 +62,9 @@ @Override public List<ProcessDefinition> getProcessDefinitionList(Set<String> ids) { if (CollUtil.isEmpty(ids)) { return emptyList(); } return repositoryService.createProcessDefinitionQuery().processDefinitionIds(ids).list(); } yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/api/purchase/dto/ErpPurchaseOrderItemRespDTO.java
@@ -36,4 +36,7 @@ @Schema(description = "夿³¨", example = "夿³¨ä¿¡æ¯") private String remark; @Schema(description = "æ¯å¦éè¦æ¥ææ£éª", example = "true") private Boolean qcCheckFlag; } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseOrderController.java
@@ -39,6 +39,7 @@ 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; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @Tag(name = "管çåå° - ERP éè´è®¢å") @RestController @@ -80,6 +81,23 @@ return success(true); } @PostMapping("/submit") @Operation(summary = "æäº¤éè´è®¢å审æ¹") @PreAuthorize("@ss.hasPermission('erp:purchase-order:update-status')") public CommonResult<Boolean> submitPurchaseOrder(@RequestParam("id") Long id, @RequestParam("processDefinitionKey") String processDefinitionKey) { Long userId = getLoginUserId(); purchaseOrderService.submitPurchaseOrder(id, processDefinitionKey, userId); return success(true); } @GetMapping("/approve-process-list") @Operation(summary = "è·åéè´è®¢åå®¡æ¹æµç¨å表") @PreAuthorize("@ss.hasPermission('erp:purchase-order:query')") public CommonResult<List<Map<String, Object>>> getApproveProcessList() { return success(purchaseOrderService.getPurchaseOrderApproveProcessDefinitionList()); } @DeleteMapping("/delete") @Operation(summary = "å é¤éè´è®¢å") @Parameter(name = "ids", description = "ç¼å·æ°ç»", required = true) yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/ErpPurchaseRequestController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,182 @@ package cn.iocoder.yudao.module.erp.controller.admin.purchase; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.request.ErpPurchaseRequestPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.request.ErpPurchaseRequestRespVO; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.request.ErpPurchaseRequestSaveReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseRequestDO; import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseRequestItemDO; import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO; import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseRequestService; import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi; import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.io.IOException; import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; 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; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @Tag(name = "管çåå° - ERP éè´ç³è¯·") @RestController @RequestMapping("/erp/purchase-request") @Validated public class ErpPurchaseRequestController { @Resource private ErpPurchaseRequestService purchaseRequestService; @Resource private ErpSupplierService supplierService; @Resource private MdmItemApi mdmItemApi; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @PostMapping("/create") @Operation(summary = "å建éè´ç³è¯·") @PreAuthorize("@ss.hasPermission('erp:purchase-request:create')") public CommonResult<Long> createPurchaseRequest(@Valid @RequestBody ErpPurchaseRequestSaveReqVO createReqVO) { return success(purchaseRequestService.createPurchaseRequest(createReqVO)); } @PutMapping("/update") @Operation(summary = "æ´æ°éè´ç³è¯·") @PreAuthorize("@ss.hasPermission('erp:purchase-request:update')") public CommonResult<Boolean> updatePurchaseRequest(@Valid @RequestBody ErpPurchaseRequestSaveReqVO updateReqVO) { purchaseRequestService.updatePurchaseRequest(updateReqVO); return success(true); } @DeleteMapping("/delete") @Operation(summary = "å é¤éè´ç³è¯·") @Parameter(name = "ids", description = "ç¼å·æ°ç»", required = true) @PreAuthorize("@ss.hasPermission('erp:purchase-request:delete')") public CommonResult<Boolean> deletePurchaseRequest(@RequestParam("ids") List<Long> ids) { purchaseRequestService.deletePurchaseRequest(ids); return success(true); } @GetMapping("/get") @Operation(summary = "è·å¾éè´ç³è¯·") @Parameter(name = "id", description = "ç¼å·", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('erp:purchase-request:query')") public CommonResult<ErpPurchaseRequestRespVO> getPurchaseRequest(@RequestParam("id") Long id) { ErpPurchaseRequestDO purchaseRequest = purchaseRequestService.getPurchaseRequest(id); if (purchaseRequest == null) { return success(null); } List<ErpPurchaseRequestItemDO> purchaseRequestItemList = purchaseRequestService.getPurchaseRequestItemListByRequestId(id); Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap( convertSet(purchaseRequestItemList, ErpPurchaseRequestItemDO::getProductId)); return success(BeanUtils.toBean(purchaseRequest, ErpPurchaseRequestRespVO.class, purchaseRequestVO -> purchaseRequestVO.setItems(BeanUtils.toBean(purchaseRequestItemList, ErpPurchaseRequestRespVO.Item.class, item -> { MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem -> item.setProductName(mdmItem.getName()) .setProductBarCode(mdmItem.getBarCode())); })))); } @GetMapping("/page") @Operation(summary = "è·å¾éè´ç³è¯·å页") @PreAuthorize("@ss.hasPermission('erp:purchase-request:query')") public CommonResult<PageResult<ErpPurchaseRequestRespVO>> getPurchaseRequestPage(@Valid ErpPurchaseRequestPageReqVO pageReqVO) { PageResult<ErpPurchaseRequestDO> pageResult = purchaseRequestService.getPurchaseRequestPage(pageReqVO); return success(buildPurchaseRequestVOPageResult(pageResult)); } @GetMapping("/export-excel") @Operation(summary = "导åºéè´ç³è¯· Excel") @PreAuthorize("@ss.hasPermission('erp:purchase-request:export')") @ApiAccessLog(operateType = EXPORT) public void exportPurchaseRequestExcel(@Valid ErpPurchaseRequestPageReqVO pageReqVO, HttpServletResponse response) throws IOException { pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); List<ErpPurchaseRequestRespVO> list = buildPurchaseRequestVOPageResult(purchaseRequestService.getPurchaseRequestPage(pageReqVO)).getList(); ExcelUtils.write(response, "éè´ç³è¯·.xls", "æ°æ®", ErpPurchaseRequestRespVO.class, list); } @PutMapping("/submit") @Operation(summary = "æäº¤éè´ç³è¯·å®¡æ¹") @PreAuthorize("@ss.hasPermission('erp:purchase-request:submit')") public CommonResult<Boolean> submitPurchaseRequest(@RequestParam("id") Long id, @RequestParam("processDefinitionKey") String processDefinitionKey) { Long userId = getLoginUserId(); purchaseRequestService.submitPurchaseRequest(id, processDefinitionKey, userId); return success(true); } @GetMapping("/approve-process-list") @Operation(summary = "è·åéè´ç³è¯·å®¡æ¹æµç¨å表") @PreAuthorize("@ss.hasPermission('erp:purchase-request:query')") public CommonResult<List<Map<String, Object>>> getApproveProcessList() { return success(purchaseRequestService.getPurchaseRequestApproveProcessDefinitionList()); } @PostMapping("/generate-order") @Operation(summary = "çæéè´è®¢å") @PreAuthorize("@ss.hasPermission('erp:purchase-request:generate-order')") public CommonResult<Long> generatePurchaseOrder(@RequestParam("id") Long id, @RequestParam("supplierId") Long supplierId) { return success(purchaseRequestService.generatePurchaseOrder(id, supplierId)); } private PageResult<ErpPurchaseRequestRespVO> buildPurchaseRequestVOPageResult(PageResult<ErpPurchaseRequestDO> pageResult) { if (CollUtil.isEmpty(pageResult.getList())) { return PageResult.empty(pageResult.getTotal()); } // 1.1 ç³è¯·æç» List<ErpPurchaseRequestItemDO> purchaseRequestItemList = purchaseRequestService.getPurchaseRequestItemListByRequestIds( convertSet(pageResult.getList(), ErpPurchaseRequestDO::getId)); Map<Long, List<ErpPurchaseRequestItemDO>> purchaseRequestItemMap = convertMultiMap(purchaseRequestItemList, ErpPurchaseRequestItemDO::getRequestId); // 1.2 ç©æä¿¡æ¯ Map<Long, MdmItemRespDTO> itemMap = mdmItemApi.getItemMap( convertSet(purchaseRequestItemList, ErpPurchaseRequestItemDO::getProductId)); // 1.3 ä¾åºåä¿¡æ¯ Map<Long, ErpSupplierDO> supplierMap = supplierService.getSupplierMap( convertSet(pageResult.getList(), ErpPurchaseRequestDO::getSupplierId)); // 1.4 ç¨æ·ä¿¡æ¯ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( convertSet(pageResult.getList(), ErpPurchaseRequestDO::getRequestUserId)); // 1.5 é¨é¨ä¿¡æ¯ Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap( convertSet(pageResult.getList(), ErpPurchaseRequestDO::getRequestDeptId)); // 2. å¼å§æ¼æ¥ return BeanUtils.toBean(pageResult, ErpPurchaseRequestRespVO.class, purchaseRequest -> { purchaseRequest.setItems(BeanUtils.toBean(purchaseRequestItemMap.get(purchaseRequest.getId()), ErpPurchaseRequestRespVO.Item.class, item -> MapUtils.findAndThen(itemMap, item.getProductId(), mdmItem -> item.setProductName(mdmItem.getName()) .setProductBarCode(mdmItem.getBarCode())))); purchaseRequest.setProductNames(CollUtil.join(purchaseRequest.getItems(), "ï¼", ErpPurchaseRequestRespVO.Item::getProductName)); MapUtils.findAndThen(supplierMap, purchaseRequest.getSupplierId(), supplier -> purchaseRequest.setSupplierName(supplier.getName())); MapUtils.findAndThen(userMap, purchaseRequest.getRequestUserId(), user -> purchaseRequest.setRequestUserName(user.getNickname())); MapUtils.findAndThen(deptMap, purchaseRequest.getRequestDeptId(), dept -> purchaseRequest.setRequestDeptName(dept.getName())); }); } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderRespVO.java
@@ -145,8 +145,13 @@ private String productUnitName; @Schema(description = "åºåæ°é", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") private BigDecimal stockCount; // è¯¥åæ®µä» ä» å¨â详æ âåâç¼è¾âæ¶ä½¿ç¨ private BigDecimal stockCount; // è¯¥åæ®µä» ä» å¨è¯¦æ åç¼è¾æ¶ä½¿ç¨ // ========== è´¨æ£ ========== @Schema(description = "æ¯å¦éè¦æ¥ææ£éª", example = "true") private Boolean qcCheckFlag; } } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/order/ErpPurchaseOrderSaveReqVO.java
@@ -68,6 +68,9 @@ @Schema(description = "夿³¨", example = "é便") private String remark; @Schema(description = "æ¯å¦éè¦æ¥ææ£éª", example = "true") private Boolean qcCheckFlag; } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/request/ErpPurchaseRequestPageReqVO.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,42 @@ package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.request; import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; @Schema(description = "管çåå° - ERP éè´ç³è¯·å页 Request VO") @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) public class ErpPurchaseRequestPageReqVO extends PageParam { @Schema(description = "éè´ç³è¯·åå·", example = "CGSQ001") private String no; @Schema(description = "ç³è¯·äººç¼å·", example = "1") private Long requestUserId; @Schema(description = "ç³è¯·é¨é¨ç¼å·", example = "1") private Long requestDeptId; @Schema(description = "ä¾åºåç¼å·", example = "1") private Long supplierId; @Schema(description = "ç¶æ", example = "0") private Integer status; @Schema(description = "ç³è¯·æ¶é´") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) private LocalDateTime[] requestTime; @Schema(description = "产åç¼å·", example = "1") private Long productId; } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/request/ErpPurchaseRequestRespVO.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,118 @@ package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.request; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; @Schema(description = "管çåå° - ERP éè´ç³è¯· Response VO") @Data public class ErpPurchaseRequestRespVO { @Schema(description = "ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Long id; @Schema(description = "éè´ç³è¯·åå·", requiredMode = Schema.RequiredMode.REQUIRED, example = "CGSQ001") private String no; @Schema(description = "ç¶æ", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") private Integer status; @Schema(description = "ç³è¯·äººç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Long requestUserId; @Schema(description = "ç³è¯·äººå§å", example = "å¼ ä¸") private String requestUserName; @Schema(description = "ç³è¯·é¨é¨ç¼å·", example = "1") private Long requestDeptId; @Schema(description = "ç³è¯·é¨é¨åç§°", example = "ç产é¨") private String requestDeptName; @Schema(description = "ç³è¯·æ¶é´", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime requestTime; @Schema(description = "ç³è¯·çç±", example = "ç产éè¦") private String requestReason; @Schema(description = "ä¾åºåç¼å·", example = "1") private Long supplierId; @Schema(description = "ä¾åºååç§°", example = "ä¾åºåA") private String supplierName; @Schema(description = "å计æ°é", requiredMode = Schema.RequiredMode.REQUIRED) private BigDecimal totalCount; @Schema(description = "åè®¡ä»·æ ¼", requiredMode = Schema.RequiredMode.REQUIRED) private BigDecimal totalPrice; @Schema(description = "产ååç§°å表", example = "产åA,产åB") private String productNames; @Schema(description = "çæçéè´è®¢åç¼å·", example = "1") private Long orderId; @Schema(description = "çæçéè´è®¢åå·", example = "CGDD001") private String orderNo; @Schema(description = "éä»¶å°å", example = "https://xxx.com/xxx.pdf") private String fileUrl; @Schema(description = "夿³¨", example = "夿³¨") private String remark; @Schema(description = "å建æ¶é´") private LocalDateTime createTime; @Schema(description = "ç³è¯·æç»å表") private java.util.List<Item> items; @Schema(description = "ç³è¯·æç»é¡¹") @Data public static class Item { @Schema(description = "ç¼å·", example = "1") private Long id; @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 = "13") private BigDecimal taxPercent; @Schema(description = "ç¨é¢", example = "130.00") private BigDecimal taxPrice; @Schema(description = "éæ±æ¥æ") private LocalDateTime demandTime; @Schema(description = "夿³¨", example = "夿³¨") private String remark; } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/purchase/vo/request/ErpPurchaseRequestSaveReqVO.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,86 @@ package cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.request; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.List; @Schema(description = "管çåå° - ERP éè´ç³è¯·æ°å¢/ä¿®æ¹ Request VO") @Data public class ErpPurchaseRequestSaveReqVO { @Schema(description = "ç¼å·ï¼ä¿®æ¹æ¶å¿ å¡«ï¼", example = "1") private Long id; @Schema(description = "ç³è¯·æ¶é´", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "ç³è¯·æ¶é´ä¸è½ä¸ºç©º") private LocalDateTime requestTime; @Schema(description = "ç³è¯·çç±", example = "ç产éè¦") private String requestReason; @Schema(description = "ä¾åºåç¼å·", example = "1") private Long supplierId; @Schema(description = "伿 çï¼ç¾åæ¯", example = "10") private BigDecimal discountPercent; @Schema(description = "éä»¶å°å", example = "https://xxx.com/xxx.pdf") private String fileUrl; @Schema(description = "夿³¨", example = "夿³¨") private String remark; @Schema(description = "ç³è¯·æç»å表", requiredMode = Schema.RequiredMode.REQUIRED) @NotEmpty(message = "ç³è¯·æç»ä¸è½ä¸ºç©º") @Valid private List<Item> items; @Schema(description = "ç³è¯·æç»é¡¹") @Data public static class Item { @Schema(description = "ç¼å·ï¼ä¿®æ¹æ¶å¿ å¡«ï¼", example = "1") private Long id; @Schema(description = "产åç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "产åç¼å·ä¸è½ä¸ºç©º") private Long productId; @Schema(description = "产ååä½ç¼å·", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "产ååä½ä¸è½ä¸ºç©º") private Long productUnitId; @Schema(description = "产ååèåä»·", example = "100.00") private BigDecimal productPrice; @Schema(description = "æ°é", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") @NotNull(message = "æ°éä¸è½ä¸ºç©º") private BigDecimal count; @Schema(description = "ç¨çï¼ç¾åæ¯", example = "13") private BigDecimal taxPercent; @Schema(description = "éæ±æ¥æ") private LocalDateTime demandTime; @Schema(description = "夿³¨", example = "夿³¨") private String remark; @Schema(description = "产ååç§°ï¼å端å±ç¤ºç¨ï¼å端忽ç¥ï¼", example = "产åA") private String productName; @Schema(description = "äº§åæ¡ç ï¼å端å±ç¤ºç¨ï¼å端忽ç¥ï¼", example = "12345678") private String productBarCode; @Schema(description = "产ååä½åç§°ï¼å端å±ç¤ºç¨ï¼å端忽ç¥ï¼", example = "个") private String productUnitName; } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseOrderDO.java
@@ -119,4 +119,9 @@ */ private Integer inStatus; /** * BPM æµç¨å®ä¾ç¼å· */ private String processInstanceId; } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseOrderItemDO.java
@@ -89,4 +89,10 @@ */ private BigDecimal returnCount; // ========== è´¨æ£ ========== /** * æ¯å¦éè¦æ¥ææ£éª */ private Boolean qcCheckFlag; } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseRequestDO.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,127 @@ package cn.iocoder.yudao.module.erp.dal.dataobject.purchase; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; import java.math.BigDecimal; import java.time.LocalDateTime; /** * ERP éè´ç³è¯· DO */ @TableName("erp_purchase_request") @KeySequence("erp_purchase_request_seq") @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor public class ErpPurchaseRequestDO extends BaseDO { /** * ç¼å· */ @TableId private Long id; /** * éè´ç³è¯·åå· */ private String no; /** * ç¶æ * * 0: æªæäº¤ * 10: 审æ¹ä¸ * 20: å®¡æ ¸éè¿ * 30: å®¡æ ¸ä¸éè¿ * 40: 已忶 */ private Integer status; /** * ç³è¯·äººç¼å· */ private Long requestUserId; /** * ç³è¯·é¨é¨ç¼å· */ private Long requestDeptId; /** * ç³è¯·æ¶é´ */ private LocalDateTime requestTime; /** * ç³è¯·çç± */ private String requestReason; /** * ä¾åºåç¼å·ï¼å¯éï¼ */ private Long supplierId; /** * å计æ°é */ private BigDecimal totalCount; /** * åè®¡ä»·æ ¼ */ private BigDecimal totalPrice; /** * å计产åä»·æ ¼ */ private BigDecimal totalProductPrice; /** * å计ç¨é¢ */ private BigDecimal totalTaxPrice; /** * 伿 çï¼ç¾åæ¯ */ private BigDecimal discountPercent; /** * 伿 éé¢ */ private BigDecimal discountPrice; /** * éä»¶å°å */ private String fileUrl; /** * 夿³¨ */ private String remark; /** * BPM æµç¨å®ä¾ç¼å· */ private String processInstanceId; /** * çæçéè´è®¢åç¼å· */ private Long orderId; /** * çæçéè´è®¢åå· */ private String orderNo; } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/purchase/ErpPurchaseRequestItemDO.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,81 @@ package cn.iocoder.yudao.module.erp.dal.dataobject.purchase; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; import java.math.BigDecimal; import java.time.LocalDateTime; /** * ERP éè´ç³è¯·æç» DO */ @TableName("erp_purchase_request_items") @KeySequence("erp_purchase_request_items_seq") @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor public class ErpPurchaseRequestItemDO extends BaseDO { /** * ç¼å· */ @TableId private Long id; /** * éè´ç³è¯·ç¼å· */ private Long requestId; /** * 产åç¼å· */ private Long productId; /** * 产ååä½ç¼å· */ private Long productUnitId; /** * 产ååèåä»· */ private BigDecimal productPrice; /** * æ°é */ private BigDecimal count; /** * æ»ä»· */ private BigDecimal totalPrice; /** * ç¨çï¼ç¾åæ¯ */ private BigDecimal taxPercent; /** * ç¨é¢ */ private BigDecimal taxPrice; /** * éæ±æ¥æ */ private LocalDateTime demandTime; /** * 夿³¨ */ private String remark; } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseRequestItemMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,29 @@ package cn.iocoder.yudao.module.erp.dal.mysql.purchase; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseRequestItemDO; import org.apache.ibatis.annotations.Mapper; import java.util.Collection; import java.util.List; /** * ERP éè´ç³è¯·æç» Mapper */ @Mapper public interface ErpPurchaseRequestItemMapper extends BaseMapperX<ErpPurchaseRequestItemDO> { default List<ErpPurchaseRequestItemDO> selectListByRequestId(Long requestId) { return selectList(ErpPurchaseRequestItemDO::getRequestId, requestId); } default List<ErpPurchaseRequestItemDO> selectListByRequestIds(Collection<Long> requestIds) { return selectList(ErpPurchaseRequestItemDO::getRequestId, requestIds); } default void deleteByRequestId(Long requestId) { delete(new LambdaQueryWrapperX<ErpPurchaseRequestItemDO>().eq(ErpPurchaseRequestItemDO::getRequestId, requestId)); } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/purchase/ErpPurchaseRequestMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,44 @@ package cn.iocoder.yudao.module.erp.dal.mysql.purchase; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.request.ErpPurchaseRequestPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseRequestDO; import org.apache.ibatis.annotations.Mapper; import java.util.Collection; import java.util.List; /** * ERP éè´ç³è¯· Mapper */ @Mapper public interface ErpPurchaseRequestMapper extends BaseMapperX<ErpPurchaseRequestDO> { default ErpPurchaseRequestDO selectByNo(String no) { return selectOne(ErpPurchaseRequestDO::getNo, no); } default List<ErpPurchaseRequestDO> selectRequestListByIds(Collection<Long> ids) { return selectList(ErpPurchaseRequestDO::getId, ids); } default List<ErpPurchaseRequestDO> selectList(Long supplierId, Integer status) { return selectList(new LambdaQueryWrapperX<ErpPurchaseRequestDO>() .eqIfPresent(ErpPurchaseRequestDO::getSupplierId, supplierId) .eqIfPresent(ErpPurchaseRequestDO::getStatus, status)); } default PageResult<ErpPurchaseRequestDO> selectPage(ErpPurchaseRequestPageReqVO pageReqVO) { return selectPage(pageReqVO, new LambdaQueryWrapperX<ErpPurchaseRequestDO>() .likeIfPresent(ErpPurchaseRequestDO::getNo, pageReqVO.getNo()) .eqIfPresent(ErpPurchaseRequestDO::getRequestUserId, pageReqVO.getRequestUserId()) .eqIfPresent(ErpPurchaseRequestDO::getRequestDeptId, pageReqVO.getRequestDeptId()) .eqIfPresent(ErpPurchaseRequestDO::getSupplierId, pageReqVO.getSupplierId()) .eqIfPresent(ErpPurchaseRequestDO::getStatus, pageReqVO.getStatus()) .betweenIfPresent(ErpPurchaseRequestDO::getRequestTime, pageReqVO.getRequestTime()) .orderByDesc(ErpPurchaseRequestDO::getId)); } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java
@@ -30,6 +30,11 @@ public static final String PURCHASE_ORDER_NO_PREFIX = "CGDD"; /** * éè´ç³è¯· {@link cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseRequestDO} */ public static final String PURCHASE_REQUEST_NO_PREFIX = "CGSQ"; /** * 仿¬¾å {@link cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpFinancePaymentDO} */ public static final String FINANCE_PAYMENT_NO_PREFIX = "FKD"; yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpAuditStatus.java
@@ -17,7 +17,8 @@ @Getter public enum ErpAuditStatus implements ArrayValuable<Integer> { PROCESS(10, "æªå®¡æ ¸"), // å®¡æ ¸ä¸ PROCESS(10, "æªå®¡æ ¸"), // æªå®¡æ ¸/è稿 APPROVING(15, "审æ¹ä¸"), // 审æ¹ä¸ APPROVE(20, "å·²å®¡æ ¸"), // å®¡æ ¸éè¿ CANCEL(30, "å·²ä½åº"); // å·²ä½åº/å·²æ¤é yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErpPurchaseRequestStatusEnum.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,38 @@ 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 éè´ç³è¯·ç¶ææä¸¾ */ @RequiredArgsConstructor @Getter public enum ErpPurchaseRequestStatusEnum implements ArrayValuable<Integer> { DRAFT(0, "æªæäº¤"), PROCESS(10, "审æ¹ä¸"), APPROVE(20, "å®¡æ ¸éè¿"), REJECT(30, "å®¡æ ¸ä¸éè¿"), CANCEL(40, "已忶"); public static final Integer[] ARRAYS = Arrays.stream(values()).map(ErpPurchaseRequestStatusEnum::getStatus).toArray(Integer[]::new); /** * ç¶æ */ private final Integer status; /** * ç¶æå */ private final String name; @Override public Integer[] array() { return ARRAYS; } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java
@@ -27,6 +27,7 @@ ErrorCode PURCHASE_ORDER_PROCESS_FAIL_EXISTS_RETURN = new ErrorCode(1_030_101_010, "åå®¡æ ¸å¤±è´¥ï¼å·²åå¨å¯¹åºçéè´éè´§å"); ErrorCode PURCHASE_ORDER_BPM_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_101_011, "éè´å®¡æ ¸åç±»ä¸åå¨ï¼è¯·å å¨BPM模åå建éè´å®¡æ ¸æµç¨åç±»"); ErrorCode PURCHASE_ORDER_BPM_PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1_030_101_012, "éè´å®¡æ ¸åç±»ä¸æ²¡æå¯ç¨çæµç¨æ¨¡åï¼è¯·å å建并å叿µç¨"); ErrorCode PURCHASE_ORDER_SUBMIT_FAIL_STATUS = new ErrorCode(1_030_101_013, "æäº¤å®¡æ¹å¤±è´¥ï¼åªææªå®¡æ ¸ç¶æçéè´è®¢åæè½æäº¤"); // ========== ERP éè´å ¥åºï¼1-030-102-000ï¼ ========== ErrorCode PURCHASE_IN_NOT_EXISTS = new ErrorCode(1_030_102_000, "éè´å ¥åºåä¸åå¨"); yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderService.java
@@ -43,6 +43,30 @@ void updatePurchaseOrderStatus(Long id, Integer status); /** * æäº¤éè´è®¢åå®¡æ¹ * * @param id ç¼å· * @param processDefinitionKey æµç¨å®ä¹ Key * @param userId ç¨æ·ç¼å· */ void submitPurchaseOrder(Long id, String processDefinitionKey, Long userId); /** * è·åéè´è®¢åå®¡æ¹æµç¨å表 * * @return æµç¨å®ä¹å表 */ List<Map<String, Object>> getPurchaseOrderApproveProcessDefinitionList(); /** * æ´æ°éè´è®¢å审æ¹ç»æï¼BPM åè°ï¼ * * @param id ç¼å· * @param bpmResult BPM 审æ¹ç»æ */ void updatePurchaseOrderAuditStatus(Long id, Integer bpmResult); /** * æ´æ°éè´è®¢åçå ¥åºæ°é * * @param id ç¼å· yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderServiceImpl.java
@@ -5,6 +5,13 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderSaveReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO; @@ -16,6 +23,8 @@ import cn.iocoder.yudao.module.erp.enums.ErpPurchaseOrderInStatusEnum; import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.repository.ProcessDefinition; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -34,7 +43,13 @@ */ @Service @Validated @Slf4j public class ErpPurchaseOrderServiceImpl implements ErpPurchaseOrderService { /** * BPM éè´è®¢å审æ¹åç±»ç¼ç */ private static final String PURCHASE_ORDER_APPROVE_CATEGORY_CODE = "purchase_request_approve"; @Resource private ErpPurchaseOrderMapper purchaseOrderMapper; @@ -48,6 +63,13 @@ private ErpSupplierService supplierService; @Resource private ErpAccountService accountService; @Resource private BpmProcessInstanceApi processInstanceApi; @Resource private BpmCategoryService bpmCategoryService; @Resource private BpmProcessDefinitionService bpmProcessDefinitionService; @Override @Transactional(rollbackFor = Exception.class) @@ -66,9 +88,10 @@ throw exception(PURCHASE_ORDER_NO_EXISTS); } // 2.1 æå ¥è®¢åï¼éè´è®¢åä¸éè¦å®¡æ¹ï¼ç´æ¥ä¸ºå·²å®¡æ ¸ç¶æï¼ // 2.1 æå ¥è®¢åï¼éè´è®¢åå建å为æªå®¡æ ¸ç¶æï¼éè¦æäº¤å®¡æ¹ï¼ ErpPurchaseOrderDO purchaseOrder = BeanUtils.toBean(createReqVO, ErpPurchaseOrderDO.class, in -> in .setNo(no).setStatus(ErpAuditStatus.APPROVE.getStatus())); .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()) .setInCount(BigDecimal.ZERO).setInStatus(ErpPurchaseOrderInStatusEnum.NOT_IN.getStatus())); calculateTotalPrice(purchaseOrder, purchaseOrderItems); purchaseOrderMapper.insert(purchaseOrder); // 2.2 æå ¥è®¢å项 @@ -119,8 +142,6 @@ @Override @Transactional(rollbackFor = Exception.class) public void updatePurchaseOrderStatus(Long id, Integer status) { // éè´è®¢åä¸åæ¯æç¶ææµè½¬ï¼ä¸éè¦å®¡æ¹ï¼ // æ¤æ¹æ³ä¿çç¨äºç¹æ®æ åµï¼å¦åå®¡æ ¸åéæ°å®¡æ ¸ï¼ boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); // 1.1 æ ¡éªåå¨ ErpPurchaseOrderDO purchaseOrder = validatePurchaseOrderExists(id); @@ -147,6 +168,109 @@ } } @Override @Transactional(rollbackFor = Exception.class) public void submitPurchaseOrder(Long id, String processDefinitionKey, Long userId) { // 1. æ ¡éªåå¨ + æªå®¡æ ¸ç¶æ ErpPurchaseOrderDO purchaseOrder = validatePurchaseOrderExists(id); if (!ErpAuditStatus.PROCESS.getStatus().equals(purchaseOrder.getStatus())) { throw exception(PURCHASE_ORDER_SUBMIT_FAIL_STATUS); } // 2. å建 BPM æµç¨å®ä¾ String processInstanceId = processInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO() .setProcessDefinitionKey(processDefinitionKey) .setBusinessKey(String.valueOf(id))); // 3. æ´æ°éè´è®¢åç¶æä¸ºå®¡æ¹ä¸ purchaseOrderMapper.updateById(new ErpPurchaseOrderDO() .setId(id) .setStatus(ErpAuditStatus.APPROVING.getStatus()) .setProcessInstanceId(processInstanceId)); } @Override public List<Map<String, Object>> getPurchaseOrderApproveProcessDefinitionList() { // 1. æ ¡éªåç±»åæµç¨å®ä¹æ¯å¦åå¨ validatePurchaseOrderApproveCategoryAndProcessDefinition(); // 2. è·ååç±»ä¸çæµç¨å®ä¹ä¿¡æ¯ List<BpmProcessDefinitionInfoDO> definitionInfoList = bpmProcessDefinitionService .getProcessDefinitionInfoListByCategory(PURCHASE_ORDER_APPROVE_CATEGORY_CODE); if (CollUtil.isEmpty(definitionInfoList)) { return Collections.emptyList(); } // 3. éåè·åæµç¨å®ä¹è¯¦æ ï¼è¿æ»¤æ¿æ´»ç¶æï¼ä¿çææ°çæ¬ Map<String, ProcessDefinition> latestVersionMap = new HashMap<>(); for (BpmProcessDefinitionInfoDO info : definitionInfoList) { ProcessDefinition pd = bpmProcessDefinitionService.getProcessDefinition(info.getProcessDefinitionId()); if (pd == null || pd.isSuspended()) { continue; } ProcessDefinition existing = latestVersionMap.get(pd.getKey()); if (existing == null || pd.getVersion() > existing.getVersion()) { latestVersionMap.put(pd.getKey(), pd); } } // 4. è¿åæµç¨å®ä¹å表 List<Map<String, Object>> result = new ArrayList<>(); for (ProcessDefinition pd : latestVersionMap.values()) { Map<String, Object> item = new HashMap<>(); item.put("id", pd.getId()); item.put("key", pd.getKey()); item.put("name", pd.getName()); result.add(item); } return result; } @Override @Transactional(rollbackFor = Exception.class) public void updatePurchaseOrderAuditStatus(Long id, Integer bpmResult) { // 1. æ ¡éªåå¨ ErpPurchaseOrderDO purchaseOrder = validatePurchaseOrderExists(id); if (!ErpAuditStatus.APPROVING.getStatus().equals(purchaseOrder.getStatus())) { log.warn("[updatePurchaseOrderAuditStatus] éè´è®¢å({}) ä¸å¤äºå®¡æ¹ä¸ç¶æ", id); return; } // 2. æ ¹æ®å®¡æ¹ç»ææ´æ°ç¶æ Integer newStatus = convertBpmResultToAuditStatus(bpmResult); if (newStatus != null) { purchaseOrderMapper.updateById(new ErpPurchaseOrderDO() .setId(id).setStatus(newStatus)); } } /** * æ ¡éªéè´è®¢å审æ¹åç±»åæµç¨å®ä¹æ¯å¦åå¨ */ private void validatePurchaseOrderApproveCategoryAndProcessDefinition() { // 1. æ ¡éªåç±»æ¯å¦åå¨ List<BpmCategoryDO> categories = bpmCategoryService.getCategoryListByCode( Collections.singletonList(PURCHASE_ORDER_APPROVE_CATEGORY_CODE)); if (CollUtil.isEmpty(categories)) { throw exception(PURCHASE_ORDER_BPM_CATEGORY_NOT_EXISTS); } } /** * è½¬æ¢ BPM 审æ¹ç»æä¸ºå®¡æ ¸ç¶æ */ private Integer convertBpmResultToAuditStatus(Integer bpmResult) { if (BpmTaskStatusEnum.APPROVE.getStatus().equals(bpmResult)) { return ErpAuditStatus.APPROVE.getStatus(); } else if (BpmTaskStatusEnum.REJECT.getStatus().equals(bpmResult)) { return ErpAuditStatus.PROCESS.getStatus(); } else if (BpmTaskStatusEnum.CANCEL.getStatus().equals(bpmResult)) { return ErpAuditStatus.CANCEL.getStatus(); } return null; } private List<ErpPurchaseOrderItemDO> validatePurchaseOrderItems(List<ErpPurchaseOrderSaveReqVO.Item> list) { // 转å为 ErpPurchaseOrderItemDO å表ï¼äº§åéªè¯å·²ç§»é¤ï¼ return convertList(list, o -> BeanUtils.toBean(o, ErpPurchaseOrderItemDO.class, item -> { yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseRequestService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,114 @@ package cn.iocoder.yudao.module.erp.service.purchase; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.request.ErpPurchaseRequestPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.request.ErpPurchaseRequestSaveReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseRequestDO; import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseRequestItemDO; import jakarta.validation.Valid; import java.util.Collection; import java.util.List; import java.util.Map; /** * ERP éè´ç³è¯· Service æ¥å£ */ public interface ErpPurchaseRequestService { /** * å建éè´ç³è¯· * * @param createReqVO åå»ºä¿¡æ¯ * @return ç¼å· */ Long createPurchaseRequest(@Valid ErpPurchaseRequestSaveReqVO createReqVO); /** * æ´æ°éè´ç³è¯· * * @param updateReqVO æ´æ°ä¿¡æ¯ */ void updatePurchaseRequest(@Valid ErpPurchaseRequestSaveReqVO updateReqVO); /** * å é¤éè´ç³è¯· * * @param ids ç¼å·æ°ç» */ void deletePurchaseRequest(List<Long> ids); /** * è·å¾éè´ç³è¯· * * @param id ç¼å· * @return éè´ç³è¯· */ ErpPurchaseRequestDO getPurchaseRequest(Long id); /** * è·å¾éè´ç³è¯·å页 * * @param pageReqVO å页æ¥è¯¢ * @return éè´ç³è¯·å页 */ PageResult<ErpPurchaseRequestDO> getPurchaseRequestPage(ErpPurchaseRequestPageReqVO pageReqVO); /** * è·å¾éè´ç³è¯·é¡¹å表 * * @param requestId éè´ç³è¯·ç¼å· * @return éè´ç³è¯·é¡¹å表 */ List<ErpPurchaseRequestItemDO> getPurchaseRequestItemListByRequestId(Long requestId); /** * è·å¾éè´ç³è¯·é¡¹ List * * @param requestIds éè´ç³è¯·ç¼å·æ°ç» * @return éè´ç³è¯·é¡¹ List */ List<ErpPurchaseRequestItemDO> getPurchaseRequestItemListByRequestIds(Collection<Long> requestIds); /** * æäº¤éè´ç³è¯·å®¡æ¹ * * @param id ç¼å· * @param processDefinitionKey æµç¨å®ä¹ Key * @param userId ç¨æ·ç¼å· */ void submitPurchaseRequest(Long id, String processDefinitionKey, Long userId); /** * è·åéè´ç³è¯·å®¡æ¹æµç¨å表 * * @return æµç¨å®ä¹å表 */ List<Map<String, Object>> getPurchaseRequestApproveProcessDefinitionList(); /** * æ´æ°éè´ç³è¯·å®¡æ¹ç»æï¼BPM åè°ï¼ * * @param id ç¼å· * @param bpmResult BPM 审æ¹ç»æ */ void updatePurchaseRequestAuditStatus(Long id, Integer bpmResult); /** * çæéè´è®¢å * * @param id éè´ç³è¯·ç¼å· * @param supplierId ä¾åºåç¼å· * @return éè´è®¢åç¼å· */ Long generatePurchaseOrder(Long id, Long supplierId); /** * æ ¹æ®ç¼å·å表è·åéè´ç³è¯·å表 * * @param ids ç¼å·å表 * @return éè´ç³è¯·å表 */ List<ErpPurchaseRequestDO> getPurchaseRequestList(List<Long> ids); } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseRequestServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,430 @@ package cn.iocoder.yudao.module.erp.service.purchase; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.request.ErpPurchaseRequestPageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.request.ErpPurchaseRequestSaveReqVO; 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.dal.dataobject.purchase.ErpPurchaseRequestDO; import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseRequestItemDO; import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseOrderItemMapper; import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseOrderMapper; import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseRequestItemMapper; import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseRequestMapper; import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; import cn.iocoder.yudao.module.erp.enums.ErpPurchaseRequestStatusEnum; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.repository.ProcessDefinition; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; /** * ERP éè´ç³è¯· Service å®ç°ç±» */ @Service @Validated @Slf4j public class ErpPurchaseRequestServiceImpl implements ErpPurchaseRequestService { /** * BPM éè´ç³è¯·å®¡æ¹åç±»ç¼ç */ private static final String PURCHASE_REQUEST_APPROVE_CATEGORY_CODE = "purchase_request_approve"; @Resource private ErpPurchaseRequestMapper purchaseRequestMapper; @Resource private ErpPurchaseRequestItemMapper purchaseRequestItemMapper; @Resource private ErpPurchaseOrderMapper purchaseOrderMapper; @Resource private ErpPurchaseOrderItemMapper purchaseOrderItemMapper; @Resource private ErpNoRedisDAO noRedisDAO; @Resource private ErpSupplierService supplierService; @Resource private BpmProcessInstanceApi processInstanceApi; @Resource private BpmCategoryService bpmCategoryService; @Resource private BpmProcessDefinitionService bpmProcessDefinitionService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Override @Transactional(rollbackFor = Exception.class) public Long createPurchaseRequest(ErpPurchaseRequestSaveReqVO createReqVO) { // 1. æ ¡éªè®¢åé¡¹çæææ§ List<ErpPurchaseRequestItemDO> requestItems = validatePurchaseRequestItems(createReqVO.getItems()); // 2. æ ¡éªä¾åºåï¼å¦ææå®ï¼ if (createReqVO.getSupplierId() != null) { supplierService.validateSupplier(createReqVO.getSupplierId()); } // 3. çæç³è¯·åå· String no = noRedisDAO.generate(ErpNoRedisDAO.PURCHASE_REQUEST_NO_PREFIX); if (purchaseRequestMapper.selectByNo(no) != null) { throw exception(PURCHASE_REQUEST_NO_EXISTS); } // 4. è·åå½åç¨æ·ä¿¡æ¯ Long userId = Long.parseLong(getCurrentUserId()); AdminUserRespDTO user = adminUserApi.getUser(userId); Long deptId = user != null ? user.getDeptId() : null; // 5. æå ¥ç³è¯·å ErpPurchaseRequestDO purchaseRequest = BeanUtils.toBean(createReqVO, ErpPurchaseRequestDO.class, req -> req .setNo(no) .setStatus(ErpPurchaseRequestStatusEnum.DRAFT.getStatus()) .setRequestUserId(userId) .setRequestDeptId(deptId)); calculateTotalPrice(purchaseRequest, requestItems); purchaseRequestMapper.insert(purchaseRequest); // 6. æå ¥ç³è¯·æç» requestItems.forEach(o -> o.setRequestId(purchaseRequest.getId())); purchaseRequestItemMapper.insertBatch(requestItems); return purchaseRequest.getId(); } @Override @Transactional(rollbackFor = Exception.class) public void updatePurchaseRequest(ErpPurchaseRequestSaveReqVO updateReqVO) { // 1. æ ¡éªåå¨ + èç¨¿ç¶æ ErpPurchaseRequestDO purchaseRequest = validatePurchaseRequestExistsAndDraft(updateReqVO.getId()); // 2. æ ¡éªä¾åºåï¼å¦ææå®ï¼ if (updateReqVO.getSupplierId() != null) { supplierService.validateSupplier(updateReqVO.getSupplierId()); } // 3. æ ¡éªè®¢åé¡¹çæææ§ List<ErpPurchaseRequestItemDO> requestItems = validatePurchaseRequestItems(updateReqVO.getItems()); // 4. æ´æ°ç³è¯·å ErpPurchaseRequestDO updateObj = BeanUtils.toBean(updateReqVO, ErpPurchaseRequestDO.class); calculateTotalPrice(updateObj, requestItems); purchaseRequestMapper.updateById(updateObj); // 5. æ´æ°ç³è¯·æç» updatePurchaseRequestItemList(updateReqVO.getId(), requestItems); } private void calculateTotalPrice(ErpPurchaseRequestDO purchaseRequest, List<ErpPurchaseRequestItemDO> requestItems) { purchaseRequest.setTotalCount(getSumValue(requestItems, ErpPurchaseRequestItemDO::getCount, BigDecimal::add)); purchaseRequest.setTotalProductPrice(getSumValue(requestItems, ErpPurchaseRequestItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO)); purchaseRequest.setTotalTaxPrice(getSumValue(requestItems, ErpPurchaseRequestItemDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO)); purchaseRequest.setTotalPrice(purchaseRequest.getTotalProductPrice().add(purchaseRequest.getTotalTaxPrice())); // 计ç®ä¼æ ä»·æ ¼ if (purchaseRequest.getDiscountPercent() == null) { purchaseRequest.setDiscountPercent(BigDecimal.ZERO); } purchaseRequest.setDiscountPrice(MoneyUtils.priceMultiplyPercent(purchaseRequest.getTotalPrice(), purchaseRequest.getDiscountPercent())); purchaseRequest.setTotalPrice(purchaseRequest.getTotalPrice().subtract(purchaseRequest.getDiscountPrice())); } private List<ErpPurchaseRequestItemDO> validatePurchaseRequestItems(List<ErpPurchaseRequestSaveReqVO.Item> list) { return convertList(list, o -> BeanUtils.toBean(o, ErpPurchaseRequestItemDO.class, item -> { if (item.getProductPrice() != null && item.getCount() != null) { item.setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())); if (item.getTaxPercent() != null) { item.setTaxPrice(MoneyUtils.priceMultiplyPercent(item.getTotalPrice(), item.getTaxPercent())); } } })); } private void updatePurchaseRequestItemList(Long id, List<ErpPurchaseRequestItemDO> newList) { List<ErpPurchaseRequestItemDO> oldList = purchaseRequestItemMapper.selectListByRequestId(id); List<List<ErpPurchaseRequestItemDO>> diffList = diffList(oldList, newList, (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); if (CollUtil.isNotEmpty(diffList.get(0))) { diffList.get(0).forEach(o -> o.setRequestId(id)); purchaseRequestItemMapper.insertBatch(diffList.get(0)); } if (CollUtil.isNotEmpty(diffList.get(1))) { purchaseRequestItemMapper.updateBatch(diffList.get(1)); } if (CollUtil.isNotEmpty(diffList.get(2))) { purchaseRequestItemMapper.deleteByIds(convertList(diffList.get(2), ErpPurchaseRequestItemDO::getId)); } } @Override @Transactional(rollbackFor = Exception.class) public void deletePurchaseRequest(List<Long> ids) { List<ErpPurchaseRequestDO> purchaseRequests = purchaseRequestMapper.selectRequestListByIds(ids); if (CollUtil.isEmpty(purchaseRequests)) { return; } purchaseRequests.forEach(purchaseRequest -> { // åªæèç¨¿ç¶ææè½å é¤ if (!ErpPurchaseRequestStatusEnum.DRAFT.getStatus().equals(purchaseRequest.getStatus())) { throw exception(PURCHASE_REQUEST_DELETE_FAIL_NOT_DRAFT, purchaseRequest.getNo()); } }); purchaseRequests.forEach(purchaseRequest -> { purchaseRequestMapper.deleteById(purchaseRequest.getId()); purchaseRequestItemMapper.deleteByRequestId(purchaseRequest.getId()); }); } @Override public ErpPurchaseRequestDO getPurchaseRequest(Long id) { return purchaseRequestMapper.selectById(id); } @Override public PageResult<ErpPurchaseRequestDO> getPurchaseRequestPage(ErpPurchaseRequestPageReqVO pageReqVO) { return purchaseRequestMapper.selectPage(pageReqVO); } @Override public List<ErpPurchaseRequestItemDO> getPurchaseRequestItemListByRequestId(Long requestId) { return purchaseRequestItemMapper.selectListByRequestId(requestId); } @Override public List<ErpPurchaseRequestItemDO> getPurchaseRequestItemListByRequestIds(Collection<Long> requestIds) { if (CollUtil.isEmpty(requestIds)) { return Collections.emptyList(); } return purchaseRequestItemMapper.selectListByRequestIds(requestIds); } @Override public List<ErpPurchaseRequestDO> getPurchaseRequestList(List<Long> ids) { if (CollUtil.isEmpty(ids)) { return Collections.emptyList(); } return purchaseRequestMapper.selectRequestListByIds(ids); } @Override @Transactional(rollbackFor = Exception.class) public void submitPurchaseRequest(Long id, String processDefinitionKey, Long userId) { // 1. æ ¡éªåå¨ + èç¨¿ç¶æ ErpPurchaseRequestDO purchaseRequest = validatePurchaseRequestExistsAndDraft(id); // 2. æ ¡éªæ¯å¦ææç» List<ErpPurchaseRequestItemDO> items = purchaseRequestItemMapper.selectListByRequestId(id); if (CollUtil.isEmpty(items)) { throw exception(PURCHASE_REQUEST_NOT_EXISTS); // TODO: æ·»å æç»ä¸ºç©ºçé误ç } // 3. å建 BPM æµç¨å®ä¾ String processInstanceId = processInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO() .setProcessDefinitionKey(processDefinitionKey) .setBusinessKey(String.valueOf(id))); // 4. æ´æ°éè´ç³è¯·ç¶æä¸ºå®¡æ¹ä¸ purchaseRequestMapper.updateById(new ErpPurchaseRequestDO() .setId(id) .setStatus(ErpPurchaseRequestStatusEnum.PROCESS.getStatus()) .setProcessInstanceId(processInstanceId)); } @Override public List<Map<String, Object>> getPurchaseRequestApproveProcessDefinitionList() { // 1. æ ¡éªåç±»åæµç¨å®ä¹æ¯å¦åå¨ validatePurchaseRequestApproveCategoryAndProcessDefinition(); // 2. è·ååç±»ä¸çæµç¨å®ä¹ä¿¡æ¯ List<BpmProcessDefinitionInfoDO> definitionInfoList = bpmProcessDefinitionService .getProcessDefinitionInfoListByCategory(PURCHASE_REQUEST_APPROVE_CATEGORY_CODE); if (CollUtil.isEmpty(definitionInfoList)) { return Collections.emptyList(); } // 3. éåè·åæµç¨å®ä¹è¯¦æ ï¼è¿æ»¤æ¿æ´»ç¶æï¼ä¿çææ°çæ¬ Map<String, ProcessDefinition> latestVersionMap = new HashMap<>(); for (BpmProcessDefinitionInfoDO info : definitionInfoList) { ProcessDefinition pd = bpmProcessDefinitionService.getProcessDefinition(info.getProcessDefinitionId()); if (pd == null || pd.isSuspended()) { continue; } ProcessDefinition existing = latestVersionMap.get(pd.getKey()); if (existing == null || pd.getVersion() > existing.getVersion()) { latestVersionMap.put(pd.getKey(), pd); } } // 4. è¿åæµç¨å®ä¹å表 List<Map<String, Object>> result = new ArrayList<>(); for (ProcessDefinition pd : latestVersionMap.values()) { Map<String, Object> item = new HashMap<>(); item.put("id", pd.getId()); item.put("key", pd.getKey()); item.put("name", pd.getName()); result.add(item); } return result; } @Override @Transactional(rollbackFor = Exception.class) public void updatePurchaseRequestAuditStatus(Long id, Integer bpmResult) { // 1. æ ¡éªåå¨ ErpPurchaseRequestDO purchaseRequest = validatePurchaseRequestExists(id); if (!ErpPurchaseRequestStatusEnum.PROCESS.getStatus().equals(purchaseRequest.getStatus())) { log.warn("[updatePurchaseRequestAuditStatus] éè´ç³è¯·({}) ä¸å¤äºå®¡æ¹ä¸ç¶æ", id); return; } // 2. æ ¹æ®å®¡æ¹ç»ææ´æ°ç¶æ Integer newStatus = convertBpmResultToStatus(bpmResult); if (newStatus != null) { purchaseRequestMapper.updateById(new ErpPurchaseRequestDO() .setId(id).setStatus(newStatus)); } } @Override @Transactional(rollbackFor = Exception.class) public Long generatePurchaseOrder(Long id, Long supplierId) { // 1. æ ¡éªåå¨ + å®¡æ ¸éè¿ç¶æ ErpPurchaseRequestDO purchaseRequest = validatePurchaseRequestExists(id); if (!ErpPurchaseRequestStatusEnum.APPROVE.getStatus().equals(purchaseRequest.getStatus())) { throw exception(PURCHASE_REQUEST_NOT_APPROVE); } // 2. æ ¡éªæ¯å¦å·²çæè®¢å if (purchaseRequest.getOrderId() != null) { throw exception(PURCHASE_REQUEST_ORDER_EXISTS); } // 3. æ ¡éªä¾åºå supplierService.validateSupplier(supplierId); // 4. è·åç³è¯·æç» List<ErpPurchaseRequestItemDO> requestItems = purchaseRequestItemMapper.selectListByRequestId(id); if (CollUtil.isEmpty(requestItems)) { throw exception(PURCHASE_REQUEST_NOT_EXISTS); } // 5. çæéè´è®¢åå· String orderNo = noRedisDAO.generate(ErpNoRedisDAO.PURCHASE_ORDER_NO_PREFIX); if (purchaseOrderMapper.selectByNo(orderNo) != null) { throw exception(PURCHASE_ORDER_NO_EXISTS); } // 6. å建éè´è®¢å ErpPurchaseOrderDO purchaseOrder = new ErpPurchaseOrderDO(); purchaseOrder.setNo(orderNo); purchaseOrder.setStatus(ErpAuditStatus.APPROVE.getStatus()); // éè´è®¢åç´æ¥ä¸ºå·²å®¡æ ¸ç¶æ purchaseOrder.setSupplierId(supplierId); purchaseOrder.setOrderTime(purchaseRequest.getRequestTime()); purchaseOrder.setTotalCount(purchaseRequest.getTotalCount()); purchaseOrder.setTotalPrice(purchaseRequest.getTotalPrice()); purchaseOrder.setTotalProductPrice(purchaseRequest.getTotalProductPrice()); purchaseOrder.setTotalTaxPrice(purchaseRequest.getTotalTaxPrice()); purchaseOrder.setDiscountPercent(purchaseRequest.getDiscountPercent()); purchaseOrder.setDiscountPrice(purchaseRequest.getDiscountPrice()); purchaseOrder.setRemark(purchaseRequest.getRemark()); purchaseOrder.setInCount(BigDecimal.ZERO); purchaseOrder.setInStatus(0); purchaseOrderMapper.insert(purchaseOrder); // 7. å建éè´è®¢åæç» List<ErpPurchaseOrderItemDO> orderItems = convertList(requestItems, item -> { ErpPurchaseOrderItemDO orderItem = new ErpPurchaseOrderItemDO(); orderItem.setOrderId(purchaseOrder.getId()); orderItem.setProductId(item.getProductId()); orderItem.setProductUnitId(item.getProductUnitId()); orderItem.setProductPrice(item.getProductPrice()); orderItem.setCount(item.getCount()); orderItem.setTotalPrice(item.getTotalPrice()); orderItem.setTaxPercent(item.getTaxPercent()); orderItem.setTaxPrice(item.getTaxPrice()); orderItem.setRemark(item.getRemark()); orderItem.setInCount(BigDecimal.ZERO); orderItem.setQcCheckFlag(false); // é»è®¤ä¸éè¦è´¨æ£ return orderItem; }); purchaseOrderItemMapper.insertBatch(orderItems); // 8. æ´æ°éè´ç³è¯·ç订åä¿¡æ¯ purchaseRequestMapper.updateById(new ErpPurchaseRequestDO() .setId(id) .setOrderId(purchaseOrder.getId()) .setOrderNo(orderNo)); return purchaseOrder.getId(); } /** * æ ¡éªéè´ç³è¯·å®¡æ¹åç±»åæµç¨å®ä¹æ¯å¦åå¨ */ private void validatePurchaseRequestApproveCategoryAndProcessDefinition() { List<BpmCategoryDO> categories = bpmCategoryService.getCategoryListByCode( Collections.singletonList(PURCHASE_REQUEST_APPROVE_CATEGORY_CODE)); if (CollUtil.isEmpty(categories)) { throw exception(PURCHASE_REQUEST_BPM_CATEGORY_NOT_EXISTS); } } /** * è½¬æ¢ BPM 审æ¹ç»æä¸ºç¶æ */ private Integer convertBpmResultToStatus(Integer bpmResult) { if (BpmTaskStatusEnum.APPROVE.getStatus().equals(bpmResult)) { return ErpPurchaseRequestStatusEnum.APPROVE.getStatus(); } else if (BpmTaskStatusEnum.REJECT.getStatus().equals(bpmResult)) { return ErpPurchaseRequestStatusEnum.REJECT.getStatus(); } else if (BpmTaskStatusEnum.CANCEL.getStatus().equals(bpmResult)) { return ErpPurchaseRequestStatusEnum.CANCEL.getStatus(); } return null; } private ErpPurchaseRequestDO validatePurchaseRequestExists(Long id) { ErpPurchaseRequestDO purchaseRequest = purchaseRequestMapper.selectById(id); if (purchaseRequest == null) { throw exception(PURCHASE_REQUEST_NOT_EXISTS); } return purchaseRequest; } private ErpPurchaseRequestDO validatePurchaseRequestExistsAndDraft(Long id) { ErpPurchaseRequestDO purchaseRequest = validatePurchaseRequestExists(id); if (!ErpPurchaseRequestStatusEnum.DRAFT.getStatus().equals(purchaseRequest.getStatus())) { throw exception(PURCHASE_REQUEST_UPDATE_FAIL_NOT_DRAFT, purchaseRequest.getNo()); } return purchaseRequest; } private String getCurrentUserId() { return cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId().toString(); } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/iqc/MesQcIqcService.java
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalNoticeLineDO; import jakarta.validation.Valid; import java.util.Collection; @@ -95,4 +96,15 @@ */ Long getIqcCountByVendorId(Long vendorId); /** * æ ¹æ®å°è´§éç¥åè¡èªå¨åå»ºæ¥ææ£éªå * * @param noticeId å°è´§éç¥å ID * @param line å°è´§éç¥åè¡ * @param noticeCode å°è´§éç¥åç¼å· * @param vendorId ä¾åºå ID * @return IQC æ£éªå ID */ Long createIqcFromArrivalNotice(Long noticeId, MesWmArrivalNoticeLineDO line, String noticeCode, Long vendorId); } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/iqc/MesQcIqcServiceImpl.java
@@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.iqc.MesQcIqcDO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalNoticeLineDO; import cn.iocoder.yudao.module.mes.dal.mysql.qc.iqc.MesQcIqcMapper; import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum; @@ -308,4 +309,40 @@ return iqcMapper.selectCountByVendorId(vendorId); } @Override @Transactional(rollbackFor = Exception.class) public Long createIqcFromArrivalNotice(Long noticeId, MesWmArrivalNoticeLineDO line, String noticeCode, Long vendorId) { // 1. æ ¡éªç©ææ¯å¦é ç½®äº IQC æ£éªæ¨¡æ¿ MesQcTemplateItemDO templateItem = templateItemService.getRequiredTemplateByItemIdAndType( line.getItemId(), MesQcTypeEnum.IQC.getType()); Long templateId = templateItem.getTemplateId(); // 2. çææ£éªåç¼ç String code = "IQC" + System.currentTimeMillis(); // 3. å建 IQC 主表ï¼å¾ æ£éªç¶æï¼åå§åæ ¼æ°é为 0ï¼ MesQcIqcDO iqc = new MesQcIqcDO(); iqc.setCode(code); iqc.setName(noticeCode + "-ç©ææ£éª"); iqc.setTemplateId(templateId); iqc.setSourceDocType(MesBizTypeConstants.WM_ARRIVAL_NOTICE); iqc.setSourceDocId(noticeId); iqc.setSourceLineId(line.getId()); iqc.setSourceDocCode(noticeCode); iqc.setVendorId(vendorId); iqc.setItemId(line.getItemId()); iqc.setReceivedQuantity(line.getArrivalQuantity()); iqc.setCheckQuantity(BigDecimal.ZERO); // å¾ å¡«å iqc.setQualifiedQuantity(BigDecimal.ZERO); // å¾ å¡«å iqc.setUnqualifiedQuantity(BigDecimal.ZERO); // å¾ å¡«å iqc.setReceiveDate(java.time.LocalDateTime.now()); iqc.setStatus(MesQcStatusEnum.DRAFT.getStatus()); iqcMapper.insert(iqc); // 4. 仿¨¡æ¿ææ èªå¨çææ£éªè¡ iqcLineService.createLinesFromTemplate(iqc.getId(), templateId); return iqc.getId(); } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeLineService.java
@@ -100,4 +100,12 @@ */ void createArrivalNoticeLineFromPurchaseOrderItem(MesWmArrivalNoticeLineDO line); /** * æ´æ°å°è´§éç¥åè¡ç IQC æ£éªå ID * * @param lineId è¡ç¼å· * @param iqcId IQC æ£éªåç¼å· */ void updateArrivalNoticeLineIqcId(Long lineId, Long iqcId); } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeLineServiceImpl.java
@@ -146,4 +146,10 @@ arrivalNoticeLineMapper.insert(line); } @Override public void updateArrivalNoticeLineIqcId(Long lineId, Long iqcId) { arrivalNoticeLineMapper.updateById(new MesWmArrivalNoticeLineDO() .setId(lineId).setIqcId(iqcId)); } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/arrivalnotice/MesWmArrivalNoticeServiceImpl.java
@@ -15,8 +15,10 @@ import cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchaseOrderRespDTO; import cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchaseOrderItemRespDTO; import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; import cn.iocoder.yudao.module.mes.service.qc.iqc.MesQcIqcService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -50,6 +52,10 @@ @Resource private MesMdmItemService mdmItemService; @Resource @Lazy private MesQcIqcService iqcService; @Override public Long createArrivalNotice(MesWmArrivalNoticeSaveReqVO createReqVO) { @@ -115,7 +121,7 @@ @Transactional(rollbackFor = Exception.class) public void submitArrivalNotice(Long id) { // 1.1 æ ¡éªåå¨ + èç¨¿ç¶æ validateArrivalNoticeExistsAndDraft(id); MesWmArrivalNoticeDO notice = validateArrivalNoticeExistsAndDraft(id); // 1.2 æ£æ¥æ¯å¦æè¡é¡¹ç® List<MesWmArrivalNoticeLineDO> lines = arrivalNoticeLineService.getArrivalNoticeLineListByNoticeId(id); if (CollUtil.isEmpty(lines)) { @@ -126,9 +132,26 @@ boolean needCheck = CollectionUtils.anyMatch(lines, line -> Boolean.TRUE.equals(line.getIqcCheckFlag())); if (needCheck) { // éè¦æ£éªï¼è¿å ¥å¾ è´¨æ£ // 2.1 éè¦æ£éªï¼è¿å ¥å¾ è´¨æ£ arrivalNoticeMapper.updateById(new MesWmArrivalNoticeDO() .setId(id).setStatus(MesWmArrivalNoticeStatusEnum.PENDING_QC.getStatus())); // 2.2 为éè¦è´¨æ£çè¡èªå¨å建 IQC æ£éªå for (MesWmArrivalNoticeLineDO line : lines) { if (Boolean.TRUE.equals(line.getIqcCheckFlag()) && line.getIqcId() == null) { try { Long iqcId = iqcService.createIqcFromArrivalNotice( id, line, notice.getCode(), notice.getVendorId()); // æ´æ°è¡ä¸ç iqcId arrivalNoticeLineService.updateArrivalNoticeLineIqcId(line.getId(), iqcId); log.info("[submitArrivalNotice][å°è´§éç¥å({}) è¡({}) èªå¨å建 IQC æ£éªå({})]", id, line.getId(), iqcId); } catch (Exception e) { log.warn("[submitArrivalNotice][å°è´§éç¥å({}) è¡({}) å建 IQC 失败: {}]", id, line.getId(), e.getMessage()); // ç»§ç»å¤çå ¶ä»è¡ï¼ä¸ä¸ææµç¨ } } } return; } // ä¸éè¦æ£éªï¼ç´æ¥è¿å ¥å¾ å ¥åº @@ -295,7 +318,8 @@ // 注æï¼è¿ééè¦æ ¹æ® ERP 产å ID æ å°å° MES ç©æ ID // å®é 项ç®ä¸éè¦éè¿æ å°æå¡å¤çï¼è¿éææ¶çç©ºè®©ç¨æ·æå¨éæ© line.setArrivalQuantity(item.getCount() != null ? item.getCount().subtract(item.getInCount() != null ? item.getInCount() : BigDecimal.ZERO) : BigDecimal.ZERO); line.setIqcCheckFlag(false); // é»è®¤ä¸éè¦æ£éªï¼ç¨æ·å¯ä¿®æ¹ // ä»éè´è®¢åæç»å¸¦å ¥è´¨æ£æ è¯ line.setIqcCheckFlag(Boolean.TRUE.equals(item.getQcCheckFlag())); arrivalNoticeLineService.createArrivalNoticeLineFromPurchaseOrderItem(line); }