docs/mock_data_check.md
@@ -14,11 +14,11 @@ | åæ° | ç±»å | å¿ å¡« | 说æ | |------|------|------|------| | modules | List\<String\> | æ¯ | è¦æ£æµç模åå表ï¼å¯éå¼ï¼salesï¼éå®ï¼ãpurchaseï¼éè´ï¼ãqualityï¼è´¨éï¼ | | modules | List\<String\> | æ¯ | è¦æ£æµç模åå表ï¼å¯éå¼ï¼salesï¼éå®ï¼ãpurchaseï¼éè´ï¼ãqualityï¼è´¨éï¼ãproductionï¼çäº§ï¼ | 请æ±ä½ç¤ºä¾ï¼ ```json { "modules": ["sales", "purchase", "quality"] } { "modules": ["sales", "purchase", "quality", "production"] } ``` **ååºï¼** @@ -68,6 +68,20 @@ | ä¾åºåæ°æ® | 1 | 缺å°ä¾åºåæ°æ®ï¼è¯·å å¨ãåºç¡æ°æ®-ä¾åºå管çã䏿·»å è³å°1æ¡ä¾åºå | | éè´å®¡æ¹æ¨¡æ¿ | 1 | 缺å°éè´å®¡æ¹æ¨¡æ¿ï¼è¯·å å¨ãç³»ç»ç®¡ç-å®¡æ¹æ¨¡æ¿ãä¸å建éè´å®¡æ¹æ¨¡æ¿ | ### ç产模å (production) | æ£æµé¡¹ | æä½æ°é | æªéè¿æç¤º | |--------|----------|------------| | äº§åæ°æ® | 1 | 缺å°äº§åæ°æ®ï¼è¯·å å¨ãåºç¡æ°æ®-产å管çã䏿·»å è³å°1æ¡äº§å | | 产åè§æ ¼ | 1 | 缺å°äº§åè§æ ¼ï¼è¯·å å¨ãåºç¡æ°æ®-产å管çãä¸ä¸ºäº§åæ·»å è§æ ¼åå· | | å·¥åº | 1 | 缺å°å·¥åºï¼è¯·å å¨ãå·¥èºè®¾è®¡-å·¥åºç®¡çãä¸åå»ºå·¥åº | | BOM | 1 | 缺å°BOMï¼è¯·å å¨ãå·¥èºè®¾è®¡-BOM管çãä¸å建BOM | | BOM产åç»æ | 1 | 缺å°BOM产åç»æï¼è¯·å å¨ãå·¥èºè®¾è®¡-BOM管çãä¸ä¸ºBOMæ·»å 产åç»æèç¹ | | å·¥èºè·¯çº¿ | 1 | 缺å°å·¥èºè·¯çº¿ï¼è¯·å å¨ãå·¥èºè®¾è®¡-å·¥èºè·¯çº¿ãä¸å建工èºè·¯çº¿ | | å·¥èºè·¯çº¿å·¥åº | 1 | 缺å°å·¥èºè·¯çº¿å·¥åºï¼è¯·å å¨ãå·¥èºè®¾è®¡-å·¥èºè·¯çº¿ãä¸ä¸ºå·¥èºè·¯çº¿æ·»å å·¥åº | | 产å-å·¥èºè·¯çº¿å ³è | â¥1 | é¨å产åè§æ ¼æªå ³èå·¥èºè·¯çº¿ï¼è¯·å å¨ãå·¥èºè®¾è®¡-å·¥èºè·¯çº¿ãä¸ä¸ºäº§åè§æ ¼å建工èºè·¯çº¿ | | å·¥èºè·¯çº¿-å·¥åºå ³è | â¥1 | é¨åå·¥èºè·¯çº¿æªæ·»å å·¥åºï¼è¯·å å¨ãå·¥èºè®¾è®¡-å·¥èºè·¯çº¿ãä¸ä¸ºå·¥èºè·¯çº¿æ·»å å·¥åº | | BOM-产åç»æå ³è | â¥1 | é¨åBOMæªæ·»å 产åç»æï¼è¯·å å¨ãå·¥èºè®¾è®¡-BOM管çãä¸ä¸ºBOMæ·»å 产åç»æèç¹ | ### è´¨éæ¨¡å (quality) | æ£æµé¡¹ | æä½æ°é | æªéè¿æç¤º | |--------|----------|------------| @@ -91,6 +105,7 @@ <el-checkbox label="sales">é宿¨¡å</el-checkbox> <el-checkbox label="purchase">éè´æ¨¡å</el-checkbox> <el-checkbox label="quality">è´¨éæ¨¡å</el-checkbox> <el-checkbox label="production">ç产模å</el-checkbox> </el-checkbox-group> <el-button type="primary" @click="handleCheck" :loading="checking"> å¼å§æ£æµ @@ -128,7 +143,7 @@ ```js data() { return { selectedModules: ['sales', 'purchase', 'quality'], selectedModules: ['sales', 'purchase', 'quality', 'production'], checking: false, checkResult: null, } @@ -165,3 +180,4 @@ - æ£æµä» ååªè¯»æ¥è¯¢ï¼ä¸åå ¥ä»»ä½æ°æ® - 模ååæ°ä¸ºç©ºæ°ç»æ¶è¿åç©ºæ£æµå表 - å»ºè®®å¨æ°æ®æ¨¡æå¼å§åå è°ç¨æ¤æ¥å£ç¡®è®¤åºç¡æ°æ®å°±ç»ª - ç产模åé¤äºæ£æµæ°æ®éï¼è¿ä¼æ£æµå ³èæ§ï¼äº§å-å·¥èºè·¯çº¿ãå·¥èºè·¯çº¿-å·¥åºãBOM-产åç»æï¼ï¼ç¡®ä¿å·¥èºè®¾è®¡æ°æ®å®æ´ src/main/java/com/ruoyi/account/bean/vo/sales/SalesOutboundVo.java
@@ -1,5 +1,6 @@ package com.ruoyi.account.bean.vo.sales; import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.framework.aspectj.lang.annotation.Excel; @@ -52,4 +53,8 @@ @Schema(description = "éå®è®¢åå·") @Excel(name = "éå®è®¢åå·") private String salesContractNo; @Schema(description = "å·²æ¶æ¬¾éé¢") @ExcelIgnore private BigDecimal amountReceived; } src/main/java/com/ruoyi/account/controller/sales/AccountInvoiceApplicationController.java
@@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.*; import java.util.Arrays; import java.util.List; /** * <p> @@ -41,6 +42,13 @@ return R.ok(listPage); } @GetMapping("/getAccountInvoiceApplicationList") @Log(title = "æ ¹æ®å®¢æ·idæ¥è¯¢å¼ç¥¨ç³è¯·å°è´¦", businessType = BusinessType.OTHER) @Operation(summary = "è´¢å¡ç®¡ç--å¼ç¥¨ç³è¯·å°è´¦") public R<List<AccountInvoiceApplicationVo>> getAccountInvoiceApplicationList(@RequestParam Integer customerId){ return R.ok(accountInvoiceApplicationService.getAccountInvoiceApplicationList(customerId)); } @GetMapping("/getOutboundBatchesByCustomer") @Log(title = "æ ¹æ®å®¢æ·æ¥è¯¢åºåºåå·(å¼ç¥¨ç³è¯·)", businessType = BusinessType.OTHER) @Operation(summary = "è´¢å¡ç®¡ç--æ ¹æ®å®¢æ·æ¥è¯¢åºåºåå·(å¼ç¥¨ç³è¯·)") src/main/java/com/ruoyi/account/mapper/sales/AccountInvoiceApplicationMapper.java
@@ -29,4 +29,6 @@ //å¤æè¯¥åºåºè®°å½æ¯å¦æå¼ç¥¨ç³è¯· boolean existsByStockOutRecordId(@Param("stockOutRecordIds") List<Long> stockOutRecordIds); List<AccountInvoiceApplicationVo> selectAccountInvoiceApplicationList(@Param("customerId") Integer customerId); } src/main/java/com/ruoyi/account/service/impl/sales/AccountInvoiceApplicationServiceImpl.java
@@ -91,6 +91,11 @@ return removeBatchByIds(ids); } @Override public List<AccountInvoiceApplicationVo> getAccountInvoiceApplicationList(Integer customerId) { return accountInvoiceApplicationMapper.selectAccountInvoiceApplicationList(customerId); } private String genInvoiceApplicationNo() { return "KP" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10); } src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesCollectionServiceImpl.java
@@ -53,15 +53,15 @@ if (StringUtils.isEmpty(accountSalesCollection.getCollectionNumber())) { accountSalesCollection.setCollectionNumber(genAccountSalesCollectionNo()); } String stockOutRecordIds = accountSalesCollection.getStockOutRecordIds(); if (stockOutRecordIds != null && !stockOutRecordIds.isEmpty()) { List<Long> ids = Arrays.stream(stockOutRecordIds.split(",")) .map(Long::valueOf) .toList(); if (accountSalesCollectionMapper.existsByStockOutRecordId(ids)){ throw new ServiceException("åå¨éå¤çåºåºå"); } } // String stockOutRecordIds = accountSalesCollection.getStockOutRecordIds(); // if (stockOutRecordIds != null && !stockOutRecordIds.isEmpty()) { // List<Long> ids = Arrays.stream(stockOutRecordIds.split(",")) // .map(Long::valueOf) // .toList(); // if (accountSalesCollectionMapper.existsByStockOutRecordId(ids)){ // throw new ServiceException("åå¨éå¤çåºåºå"); // } // } return save(accountSalesCollection); } src/main/java/com/ruoyi/account/service/sales/AccountInvoiceApplicationService.java
@@ -30,4 +30,6 @@ void exportAccountInvoiceApplication(HttpServletResponse response, AccountInvoiceApplicationDto accountInvoiceApplicationDto); boolean deleteAccountInvoiceApplication(List<Long> ids); List<AccountInvoiceApplicationVo> getAccountInvoiceApplicationList(Integer customerId); } src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
@@ -111,7 +111,6 @@ if (TypeEnums.PURCHASE_APPROVAL.getCode().equals(vo.getBusinessType())) { // éè´å®¡æ¹ - æ¥è¯¢éè´åå· PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(vo.getBusinessId()); System.out.println("ä¸å¡ç±»åï¼" + purchaseLedger.getPurchaseContractNumber()); if (purchaseLedger != null) { vo.setPurchaseContractNumber(purchaseLedger.getPurchaseContractNumber()); } src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java
@@ -13,6 +13,8 @@ import com.ruoyi.approve.bean.vo.ApprovalTemplateVo; import com.ruoyi.approve.mapper.ApprovalTemplateMapper; import com.ruoyi.approve.mapper.ApprovalTemplateNodeApproverMapper; import com.ruoyi.approve.mapper.ApprovalInstanceMapper; import com.ruoyi.approve.pojo.ApprovalInstance; import com.ruoyi.approve.pojo.ApprovalTemplate; import com.ruoyi.approve.pojo.ApprovalTemplateNode; import com.ruoyi.approve.pojo.ApprovalTemplateNodeApprover; @@ -48,6 +50,7 @@ private final ApprovalTemplateMapper approvalTemplateMapper; private final ApprovalTemplateNodeService approvalTemplateNodeService; private final ApprovalTemplateNodeApproverMapper approvalTemplateNodeApproverMapper; private final ApprovalInstanceMapper approvalInstanceMapper; private final FileUtil fileUtil; @Override @@ -82,6 +85,10 @@ @Override public Boolean updateApprovalTemplateDto(ApprovalTemplateDto approvalTemplateDto) { // æ£æ¥æ¨¡æ¿æ¯å¦è¢«å®¡æ¹å®ä¾å¼ç¨ if (isTemplateReferenced(approvalTemplateDto.getId())) { throw new RuntimeException("è¯¥å®¡æ¹æ¨¡æ¿å·²è¢«å®¡æ¹æµç¨å¼ç¨ï¼æ æ³ç¼è¾"); } approvalTemplateMapper.updateById(approvalTemplateDto); approvalTemplateNodeService.remove( new LambdaQueryWrapper<ApprovalTemplateNode>() @@ -111,6 +118,12 @@ public Boolean delete(List<Long> ids) { if (ids == null || ids.isEmpty()) { return false; } // æ£æ¥æ¨¡æ¿æ¯å¦è¢«å®¡æ¹å®ä¾å¼ç¨ for (Long id : ids) { if (isTemplateReferenced(id)) { throw new RuntimeException("å®¡æ¹æ¨¡æ¿ï¼ID: " + id + "ï¼å·²è¢«å®¡æ¹æµç¨å¼ç¨ï¼æ æ³å é¤"); } } ApprovalTemplate updateEntity = new ApprovalTemplate(); updateEntity.setDeleted(1); @@ -275,4 +288,21 @@ BeanUtils.copyProperties(approver, approverVo); return approverVo; } /** * æ£æ¥å®¡æ¹æ¨¡æ¿æ¯å¦è¢«å®¡æ¹å®ä¾å¼ç¨ * @param templateId 模æ¿ID * @return true 表示被å¼ç¨ï¼false 表示æªè¢«å¼ç¨ */ private boolean isTemplateReferenced(Long templateId) { if (templateId == null) { return false; } Long count = approvalInstanceMapper.selectCount( new LambdaQueryWrapper<ApprovalInstance>() .eq(ApprovalInstance::getTemplateId, templateId) .eq(ApprovalInstance::getDeleted, 0) ); return count != null && count > 0; } } src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
@@ -212,6 +212,7 @@ public int updateCustomer(Customer customer) { LoginUser loginUser = SecurityUtils.getLoginUser(); Long tenantId = loginUser.getTenantId(); validateCustomerEditPermission(customer.getId()); customer.setTenantId(tenantId); return customerMapper.updateById(customer); } @@ -341,6 +342,7 @@ public void recycleCustomer(CustomerDto customerDto) { Customer customer = customerMapper.selectById(customerDto.getId()); if (customer.getType() == 1 && customer.getIsAssigned() == 1) { // å ¬æµ·ä¸å·²åé validatePublicSeaRecyclePermission(customer.getId()); customer.setIsAssigned(0); customer.setUsageStatus(0L); customer.setUsageUser(0L); @@ -403,6 +405,44 @@ return this.updateById(customer); } private void validateCustomerEditPermission(Long customerId) { Customer customer = customerMapper.selectById(customerId); if (customer == null) { throw new RuntimeException("å®¢æ·æ¡£æ¡ä¸åå¨"); } if (!hasSalesModuleReference(customerId)) { return; } if (Objects.equals(customer.getType(), 0)) { throw new RuntimeException("已被é宿¨¡åå¼ç¨çç§æµ·å®¢æ·ä¸è½ç¼è¾"); } if (Objects.equals(customer.getType(), 1) && Objects.equals(customer.getIsAssigned(), 1)) { throw new RuntimeException("å·²é¢ç¨å¹¶ä¸è¢«é宿¨¡åå¼ç¨çå ¬æµ·å®¢æ·ä¸è½ç¼è¾"); } } private void validatePublicSeaRecyclePermission(Long customerId) { if (hasSalesModuleReference(customerId)) { throw new RuntimeException("å·²é¢ç¨å¹¶ä¸è¢«é宿¨¡åå¼ç¨çå ¬æµ·å®¢æ·ä¸è½åæ¶"); } } private boolean hasSalesModuleReference(Long customerId) { Long salesLedgerCount = salesLedgerMapper.selectCount(new QueryWrapper<SalesLedger>().lambda() .eq(SalesLedger::getCustomerId, customerId)); if (salesLedgerCount != null && salesLedgerCount > 0) { return true; } Long salesQuotationCount = salesQuotationMapper.selectCount(new QueryWrapper<SalesQuotation>().lambda() .eq(SalesQuotation::getCustomerId, customerId)); if (salesQuotationCount != null && salesQuotationCount > 0) { return true; } Long returnManagementCount = returnManagementMapper.selectCount(new QueryWrapper<ReturnManagement>().lambda() .eq(ReturnManagement::getCustomerId, customerId)); return returnManagementCount != null && returnManagementCount > 0; } @Override public IPage<CustomerTransactionsVo> customewTransactions(Page page, String customerName) { return customerMapper.customewTransactions(page, customerName); src/main/java/com/ruoyi/basic/vo/CustomerVo.java
@@ -25,4 +25,9 @@ * å ±äº«ç¨æ·IDå符串ï¼SQLæ¥è¯¢è¿åï¼ç¨äºè½¬æ¢ä¸ºListï¼ */ private String userIdsStr; /** * æ¯å¦è¢«é宿¨¡åå¼ç¨ï¼0-å¦ï¼1-æ¯ */ private Integer salesReferenceFlag; } src/main/java/com/ruoyi/common/enums/StockOutQualifiedRecordTypeEnum.java
@@ -7,7 +7,6 @@ public enum StockOutQualifiedRecordTypeEnum implements BaseEnum<String> { CUSTOMIZATION_STOCK_OUT("1", "åæ ¼èªå®ä¹åºåº"), PRODUCTION_REPORT_STOCK_OUT("3", "ç产æ¥å·¥-åºåº"), SALE_STOCK_OUT("8", "éå®-åºåº"), PURCHASE_RETURN_STOCK_OUT("9", "éè´éè´§"), CUSTOMIZATION_UNSTOCK_OUT("10", "ä¸åæ ¼èªå®ä¹åºåº"), SALE_SHIP_STOCK_OUT("13", "éå®-åè´§åºåº"), src/main/java/com/ruoyi/common/utils/DateUtils.java
@@ -3,11 +3,7 @@ import java.lang.management.ManagementFactory; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.*; import java.util.Date; import org.apache.commons.lang3.time.DateFormatUtils; @@ -45,10 +41,9 @@ public static LocalDate toLocalDate(Date date){ if(date == null) return LocalDate.now(); // 2. æå®åºå®æ¶åºè½¬æ¢ï¼å¦ä¸å «åºUTC+8ãUTCé¶æ¶åºï¼ return date.toInstant() .atZone(ZoneId.of("Asia/Shanghai")) // ä¸å «åºï¼å京/䏿µ·æ¶åºï¼ // .atZone(ZoneId.of("UTC")) // å¯éï¼UTCé¶æ¶åº // java.sql.Date.toInstant() 伿 UnsupportedOperationExceptionï¼éå 转为 java.util.Date Instant instant = new java.util.Date(date.getTime()).toInstant(); return instant.atZone(ZoneId.of("Asia/Shanghai")) .toLocalDate(); } src/main/java/com/ruoyi/home/controller/HomeController.java
@@ -61,7 +61,8 @@ private static final Integer ORDER_STATUS_WAIT = 1; private static final Integer ORDER_STATUS_RUNNING = 2; private static final Integer ORDER_STATUS_COMPLETED = 3; private static final Integer ORDER_STATUS_PAUSED = 4; //private static final Integer ORDER_STATUS_END = 4; // 已忶 private static final Integer ORDER_STATUS_END = 5; /********************************************************åºç¡ç±»*****************************************************/ @GetMapping("/todos") @@ -260,13 +261,14 @@ } Integer statusFromParam = parseOrderStatus(status); if (!isBlank(status) && statusFromParam == null && !"all".equalsIgnoreCase(status.trim())) { return R.fail("statusåæ°ä¸åæ³ï¼å¯éå¼ï¼all/waiting/inProgress/completed/paused æ 1/2/3/4"); return R.fail("statusåæ°ä¸åæ³ï¼å¯éå¼ï¼all/waiting/inProgress/completed/end æ 1/2/3/5"); } Integer queryStatus = resolveOrderStatus(status, tab); long safePageNum = pageNum == null || pageNum < 1 ? 1 : pageNum; long safePageSize = pageSize == null || pageSize < 1 ? 10 : Math.min(pageSize, 50); long offset = (safePageNum - 1) * safePageSize; boolean queryAll = pageSize != null && pageSize == -1; long safePageSize = queryAll ? -1 : (pageSize == null || pageSize < 1 ? 10 : Math.min(pageSize, 50)); long offset = queryAll ? 0 : (safePageNum - 1) * safePageSize; LocalDateTime startTime = queryDate == null ? null : queryDate.atStartOfDay(); LocalDateTime endTime = queryDate == null ? null : queryDate.plusDays(1).atStartOfDay(); @@ -281,7 +283,7 @@ long waitingCount = 0L; long inProgressCount = 0L; long completedCount = 0L; long pausedCount = 0L; long endCount = 0L; List<Map<String, Object>> statusCountRows = productionOrderMapper.countHomeOrderProgressByStatus(startTime, endTime); if (statusCountRows != null) { for (Map<String, Object> countRow : statusCountRows) { @@ -293,8 +295,8 @@ inProgressCount = cnt; } else if (Objects.equals(statusKey, ORDER_STATUS_COMPLETED)) { completedCount = cnt; } else if (Objects.equals(statusKey, ORDER_STATUS_PAUSED)) { pausedCount = cnt; } else if (Objects.equals(statusKey, ORDER_STATUS_END)) { endCount = cnt; } } } @@ -303,13 +305,13 @@ result.put("tab", mapOrderTab(queryStatus)); result.put("status", mapOrderStatus(queryStatus)); result.put("bizDate", queryDate == null ? null : queryDate.format(DATE_FORMATTER)); result.put("total", toLong(productionOrderMapper.countHomeOrderProgress(queryStatus, startTime, endTime))); result.put("total", toLong(productionOrderMapper.countHomeOrderProgress(null, startTime, endTime))); result.put("pageNum", safePageNum); result.put("pageSize", safePageSize); result.put("waitingCount", waitingCount); result.put("inProgressCount", inProgressCount); result.put("completedCount", completedCount); result.put("pausedCount", pausedCount); result.put("endCount", endCount); result.put("records", records); return R.ok(result); } @@ -529,8 +531,8 @@ if ("3".equals(normalized) || "completed".equals(normalized)) { return ORDER_STATUS_COMPLETED; } if ("4".equals(normalized) || "paused".equals(normalized)) { return ORDER_STATUS_PAUSED; if ("5".equals(normalized) || "end".equals(normalized)) { return ORDER_STATUS_END; } return null; } @@ -542,8 +544,8 @@ if (Objects.equals(status, ORDER_STATUS_COMPLETED)) { return "completed"; } if (Objects.equals(status, ORDER_STATUS_PAUSED)) { return "paused"; if (Objects.equals(status, ORDER_STATUS_END)) { return "end"; } if (Objects.equals(status, ORDER_STATUS_WAIT)) { return "waiting"; @@ -561,8 +563,8 @@ if (Objects.equals(status, ORDER_STATUS_COMPLETED)) { return "completed"; } if (Objects.equals(status, ORDER_STATUS_PAUSED)) { return "paused"; if (Objects.equals(status, ORDER_STATUS_END)) { return "end"; } return "all"; } @@ -577,8 +579,8 @@ if (Objects.equals(status, ORDER_STATUS_COMPLETED)) { return "已宿"; } if (Objects.equals(status, ORDER_STATUS_PAUSED)) { return "å·²æå"; if (Objects.equals(status, ORDER_STATUS_END)) { return "å·²ç»æ"; } return "æªç¥"; } @@ -635,7 +637,7 @@ .select(ProductionOrder::getQuantity, ProductionOrder::getCompleteQuantity) .ge(ProductionOrder::getCreateTime, day.atStartOfDay()) .lt(ProductionOrder::getCreateTime, day.plusDays(1).atStartOfDay()) .ne(ProductionOrder::getStatus, ORDER_STATUS_PAUSED)); .ne(ProductionOrder::getStatus, ORDER_STATUS_END)); BigDecimal totalQuantity = BigDecimal.ZERO; BigDecimal totalCompleteQuantity = BigDecimal.ZERO; src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -18,7 +18,11 @@ import com.ruoyi.account.pojo.purchase.AccountPurchasePayment; import com.ruoyi.account.pojo.sales.AccountSalesCollection; import com.ruoyi.approve.mapper.ApproveProcessMapper; import com.ruoyi.approve.mapper.ApprovalInstanceMapper; import com.ruoyi.approve.mapper.ApprovalTaskMapper; import com.ruoyi.approve.pojo.ApproveProcess; import com.ruoyi.approve.pojo.ApprovalInstance; import com.ruoyi.approve.pojo.ApprovalTask; import com.ruoyi.basic.mapper.CustomerMapper; import com.ruoyi.basic.mapper.ProductMapper; import com.ruoyi.basic.mapper.SupplierManageMapper; @@ -28,6 +32,7 @@ import com.ruoyi.collaborativeApproval.mapper.NoticeMapper; import com.ruoyi.collaborativeApproval.pojo.Notice; import com.ruoyi.common.enums.ApproveTypeEnum; import com.ruoyi.common.enums.TypeEnums; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.device.mapper.DeviceRepairMapper; @@ -97,6 +102,10 @@ private final QualityInspectMapper qualityStatisticsMapper; private final ApproveProcessMapper approveProcessMapper; private final ApprovalTaskMapper approvalTaskMapper; private final ApprovalInstanceMapper approvalInstanceMapper; private final SysDeptMapper sysDeptMapper; @@ -384,40 +393,58 @@ @Override public List<ApproveProcess> todos() throws ParseException { LoginUser loginUser = SecurityUtils.getLoginUser(); List<ApproveProcess> approveProcesses = new ArrayList<>(); // æ¥è¯¢æ§å®¡æ¹è¡¨ï¼approve_processï¼ LambdaQueryWrapper<ApproveProcess> approveProcessLambdaQueryWrapper = new LambdaQueryWrapper<>(); approveProcessLambdaQueryWrapper.eq(ApproveProcess::getApproveDelete, 0) .eq(ApproveProcess::getApproveUserCurrentId, loginUser.getUserId()) .ne(ApproveProcess::getApproveStatus, 2); // .eq(ApproveProcess::getTenantId, loginUser.getTenantId()); List<ApproveProcess> approveProcesses = approveProcessMapper.selectList(approveProcessLambdaQueryWrapper); if (CollectionUtils.isEmpty(approveProcesses)) { approveProcesses = new ArrayList<>(); } approveProcesses.forEach(a -> { List<ApproveProcess> oldList = approveProcessMapper.selectList(approveProcessLambdaQueryWrapper); if (!CollectionUtils.isEmpty(oldList)) { oldList.forEach(a -> { if (a.getApproveType() != null) { a.setApproveTypeName(ApproveTypeEnum.getNameByCode(a.getApproveType())); } }); // // æ¥è¯¢æªé¢ç¨å³ä¿è®°å½ // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // // LaborIssue laborIssue1 = new LaborIssue(); // laborIssue1.setAdoptedDate(new Date()); // laborIssue1.setIssueDate(sdf.parse(sdf.format(new Date()))); // List<LaborIssue> laborIssues = lavorIssueMapper.list(laborIssue1); // //staff_join_leave_record表被å é¤ // if(!CollectionUtils.isEmpty(laborIssues)){ // for (LaborIssue laborIssue : laborIssues) { // ApproveProcess approveProcess = new ApproveProcess(); // approveProcess.setApproveId(laborIssue.getOrderNo()); // approveProcess.setApproveDeptName(sysDeptMapper.selectDeptById(loginUser.getTenantId()).getDeptName()); // approveProcess.setApproveTime(laborIssue.getIssueDate()); // approveProcess.setApproveReason(laborIssue.getDictTypeName() + "-" + // laborIssue.getDictName() + "è¶ æ¶æªé¢å"); // approveProcesses.add(approveProcess); // } // } approveProcesses.addAll(oldList); } // æ¥è¯¢æ°å®¡æ¹è¡¨ï¼approval_task + approval_instanceï¼ List<ApprovalTask> pendingTasks = approvalTaskMapper.selectList(new LambdaQueryWrapper<ApprovalTask>() .eq(ApprovalTask::getApproverId, loginUser.getUserId()) .eq(ApprovalTask::getTaskStatus, "PENDING") .eq(ApprovalTask::getDeleted, 0)); if (!CollectionUtils.isEmpty(pendingTasks)) { List<Long> instanceIds = pendingTasks.stream() .map(ApprovalTask::getInstanceId) .distinct() .collect(Collectors.toList()); List<ApprovalInstance> instances = approvalInstanceMapper.selectList(new LambdaQueryWrapper<ApprovalInstance>() .in(ApprovalInstance::getId, instanceIds) .eq(ApprovalInstance::getDeleted, 0)); Map<Long, ApprovalInstance> instanceMap = instances.stream() .collect(Collectors.toMap(ApprovalInstance::getId, i -> i, (a, b) -> a)); for (ApprovalTask task : pendingTasks) { ApprovalInstance instance = instanceMap.get(task.getInstanceId()); if (instance == null) { continue; } ApproveProcess ap = new ApproveProcess(); ap.setId(instance.getId()); ap.setApproveId(instance.getInstanceNo()); ap.setApproveReason(instance.getTitle()); ap.setApproveTime(instance.getApplyTime() != null ? java.sql.Timestamp.valueOf(instance.getApplyTime()) : null); ap.setApproveUserName(instance.getApplicantName()); ap.setApproveDeptName(instance.getTemplateName()); if (instance.getBusinessType() != null) { ap.setApproveType(instance.getBusinessType().intValue()); ap.setApproveTypeName(TypeEnums.getLabelByValue(instance.getBusinessType())); } approveProcesses.add(ap); } } return approveProcesses; } @@ -470,18 +497,23 @@ @Override public Map<String, Object> approveAndDeviceTodos() { // 审æ¹ååå¾ å Long aLong = approveProcessMapper.selectCount(new LambdaQueryWrapper<ApproveProcess>() // æ§å®¡æ¹è¡¨å¾ å Long oldCount = approveProcessMapper.selectCount(new LambdaQueryWrapper<ApproveProcess>() .eq(ApproveProcess::getApproveUserCurrentId, SecurityUtils.getUserId()) .eq(ApproveProcess::getApproveDelete, 0) .in(ApproveProcess::getApproveStatus, 0, 1, 3)); // æ°å®¡æ¹è¡¨å¾ å Long newCount = approvalTaskMapper.selectCount(new LambdaQueryWrapper<ApprovalTask>() .eq(ApprovalTask::getApproverId, SecurityUtils.getUserId()) .eq(ApprovalTask::getTaskStatus, "PENDING") .eq(ApprovalTask::getDeleted, 0)); // è®¾å¤æ¥ä¿®å¾ å Long aLong1 = deviceRepairMapper.selectCount(new LambdaQueryWrapper<DeviceRepair>() .eq(DeviceRepair::getStatus, 0) .eq(DeviceRepair::getRepairName, SecurityUtils.getLoginUser().getNickName())); return new HashMap<String, Object>() { { put("approveTodo", aLong); put("approveTodo", oldCount + newCount); put("deviceRepairTodo", aLong1); } }; src/main/java/com/ruoyi/mock/prompt/MockDataPrompt.java
@@ -1,6 +1,9 @@ package com.ruoyi.mock.prompt; import com.ruoyi.project.system.domain.SysUser; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** @@ -12,17 +15,17 @@ public static String buildSystemPrompt() { return """ ä½ æ¯ä¸ä¸ªä¼ä¸ERPç³»ç»çæ°æ®æ¨¡æä¸å®¶ãä½ éè¦æ ¹æ®ç¨æ·æä¾çè¡ä¸ãæ°éãæ¶é´èå´çä¿¡æ¯ï¼ çæç¬¦åä¸å¡é»è¾çæ¨¡ææ°æ®ã ä½ æ¯ä¸ä¸ªä¼ä¸ERPç³»ç»çæ°æ®æ¨¡æä¸å®¶ã è¦æ±: æ ¸å¿è§åï¼å¿ é¡»ä¸¥æ ¼éµå®ï¼ï¼ 1. è¾åºå¿ é¡»æ¯çº¯JSONæ°ç»ï¼ä¸è¦ç¨markdown代ç åå 裹ï¼ä¸è¦æä»»ä½å ¶ä»æå 2. æ¯ä¸ªJSONå¯¹è±¡å¿ é¡»å å« "entity" åæ®µï¼å¼ä¸ºå®ä½ç±»åå 3. æ°æ®å 容è¦ç¬¦åæå®è¡ä¸çç¹å¾ï¼å ¬å¸åç§°ã产ååç§°ãè系人çè¦å该è¡ä¸çï¼ 4. æ¥æåæ®µå¨æå®çæ¶é´èå´å éæºåå¸ 5. éé¢ãæ°éçæ°å¼å段è¦åç 6. å䏿¨¡åå çå®ä½ä¹é´è¦æå¼ç¨å ³ç³»ï¼å¦éå®å°è´¦å¼ç¨å®¢æ·åç§°ï¼ 7. ææåç¬¦ä¸²åæ®µä¸è¦ä½¿ç¨emojiæç¹æ®unicodeå符 3. æ°æ®å 容è¦ç¬¦åæå®è¡ä¸çç¹å¾ 4. éé¢ãæ°éçæ°å¼å段è¦åç 5. å䏿¨¡åå çå®ä½ä¹é´è¦æå¼ç¨å ³ç³» 6. ä¸è¦ä½¿ç¨emojiæç¹æ®unicodeå符 7. æéè¦ï¼æ¥æåªä»"æå®æ¶é´èå´"ä¸åï¼ç»å¯¹ä¸è¦ç¨å ¶ä»å¹´ä»½ï¼ 8. 人ååæ®µï¼å¦entryPersonãsalesmançï¼å¿ é¡»ä»"ç³»ç»ç¨æ·å表"ä¸éåï¼æ ¹æ®è§è²åé¨é¨å¹é å¯¹åºæ¨¡åï¼ä¸è¦ç¼é 人åï¼ """; } @@ -30,196 +33,210 @@ int countMin, int countMax, String dateStart, String dateEnd, String additionalInfo, List<Long> productIds, List<Long> productModelIds) { Map<Long, String> productModelIdToCategory, List<SysUser> systemUsers, List<String> existingCustomerNames, List<String> existingSupplierNames) { StringBuilder sb = new StringBuilder(); sb.append("请为以ä¸è¡ä¸çææ¨¡æERPä¸å¡æ°æ®:\n"); sb.append("- è¡ä¸: ").append(String.join("ã", industries)).append("\n"); sb.append("- æ°æ®æ¡æ°: æ¯ç§å®ä½ ").append(countMin).append("-").append(countMax).append(" æ¡\n"); sb.append("- æ¶é´èå´: ").append(dateStart).append(" ~ ").append(dateEnd).append("\n"); sb.append("æå®è¡ä¸: ").append(String.join("ã", industries)).append("\n"); sb.append("æ¯ç§å®ä½çæ: ").append(countMin).append("-").append(countMax).append(" æ¡\n"); sb.append("æå®æ¶é´èå´: ").append(dateStart).append(" å° ").append(dateEnd); sb.append("ï¼æææ¥æåæ®µå¿ é¡»å¨è¿ä¸ªèå´å ï¼ç¦æ¢ä½¿ç¨2023ã2024ã2025çä»»ä½è¶ åºèå´ç年份ï¼ï¼\n"); if (additionalInfo != null && !additionalInfo.isBlank()) { sb.append("- è¡¥å ä¿¡æ¯: ").append(additionalInfo).append("\n"); sb.append("è¡¥å ä¿¡æ¯: ").append(additionalInfo).append("\n"); } sb.append("\n"); sb.append("å¯ç¨ç产åIDå表: ").append(productIds.stream().map(String::valueOf).collect(Collectors.joining(","))).append("\n"); sb.append("å¯ç¨ç产åè§æ ¼IDå表: ").append(productModelIds.stream().map(String::valueOf).collect(Collectors.joining(","))).append("\n"); sb.append("\n"); // æé¡¶çº§äº§ååç±»ï¼æå/åææ/åæåï¼åç»ååºäº§åè§æ ¼ Map<String, List<Map.Entry<Long, String>>> grouped = productModelIdToCategory.entrySet().stream() .collect(Collectors.groupingBy( e -> categorize(e.getValue()), java.util.LinkedHashMap::new, Collectors.toList())); sb.append("éè¦çæç模å: ").append(String.join("ã", modules)).append("\n\n"); sb.append("=== 产åè§æ ¼å表 ===\n"); for (Map.Entry<String, List<Map.Entry<Long, String>>> entry : grouped.entrySet()) { String label = entry.getKey(); List<Map.Entry<Long, String>> items = entry.getValue(); sb.append("ã").append(label).append("ã: "); sb.append(items.stream() .map(e -> e.getKey() + "(" + e.getValue() + ")") .collect(Collectors.joining(", "))).append("\n"); } sb.append("éå®å°è´¦çproductDataåªè½éãæåç±»ãè§æ ¼ï¼éè´å°è´¦åªè½éãåææç±»ãè§æ ¼ã\n\n"); // ç³»ç»ç¨æ·å表ï¼å«è§è²åé¨é¨ï¼ sb.append("=== ç³»ç»ç¨æ·å表ï¼äººååæ®µå¿ é¡»ä»ä¸éåï¼ä¸è¦ç¼é 人åï¼===\n"); for (SysUser u : systemUsers) { String roleNames = u.getRoleNames() != null && !u.getRoleNames().isBlank() ? u.getRoleNames() : "æ è§è²"; String deptNames = u.getDeptNames() != null && !u.getDeptNames().isBlank() ? u.getDeptNames() : "æ é¨é¨"; sb.append(u.getNickName()).append("ï¼è§è²: ").append(roleNames).append(", é¨é¨: ").append(deptNames).append("ï¼\n"); } sb.append("éæ©è§åï¼\n"); sb.append("- é宿¨¡åç人å(entryPersonãsalesman)éè§è²æé¨é¨å«\"éå®\"çç¨æ·\n"); sb.append("- éè´æ¨¡åç人åéè§è²æé¨é¨å«\"éè´\"çç¨æ·\n"); sb.append("- ç产模åç人åéè§è²æé¨é¨å«\"ç产\"çç¨æ·\n"); sb.append("- è´¨éæ¨¡åç人åéè§è²æé¨é¨å«\"è´¨é\"æ\"è´¨æ£\"çç¨æ·\n"); sb.append("- ä»åºæ¨¡åç人åéè§è²æé¨é¨å«\"ä»åº\"æ\"åºå\"çç¨æ·\n\n"); if (!existingCustomerNames.isEmpty()) { sb.append("=== å·²æå®¢æ·ï¼åªè½å¼ç¨ï¼ä¸è¦çææ°customerå®ä½ï¼===\n"); sb.append(String.join("ã", existingCustomerNames)).append("\n\n"); } if (!existingSupplierNames.isEmpty()) { sb.append("=== å·²æä¾åºåï¼åªè½å¼ç¨ï¼ä¸è¦çææ°supplierå®ä½ï¼===\n"); sb.append(String.join("ã", existingSupplierNames)).append("\n\n"); } sb.append("æ°æ®æ¨¡å: ").append(String.join("ã", modules)).append("\n\n"); if (modules.contains("sales")) { sb.append(buildSalesPrompt(countMin, countMax, dateStart, dateEnd)); sb.append(buildSalesPrompt(countMin, countMax, dateStart, dateEnd, existingCustomerNames)); } if (modules.contains("purchase")) { sb.append(buildPurchasePrompt(countMin, countMax, dateStart, dateEnd)); sb.append(buildPurchasePrompt(countMin, countMax, dateStart, dateEnd, existingSupplierNames)); } if (modules.contains("quality")) { sb.append(buildQualityPrompt(countMin, countMax)); sb.append(buildQualityPrompt(countMin, countMax, dateStart)); } if (modules.contains("production")) { sb.append(buildProductionPrompt(countMin, countMax, dateStart, dateEnd)); } if (modules.contains("stock")) { sb.append(buildStockPrompt(countMin, countMax)); sb.append(buildStockPrompt(countMin, countMax, dateStart)); } sb.append("\nè¯·ç´æ¥è¾åºJSONæ°ç»ï¼ä¸è¦æä»»ä½å ¶ä»å 容:"); sb.append("\nè¯·ç´æ¥è¾åºJSONæ°ç»:"); return sb.toString(); } private static String buildSalesPrompt(int min, int max, String dateStart, String dateEnd) { return """ é宿¨¡å - æä»¥ä¸æ ¼å¼çæ: { "entity": "customer", "customerName": "XXç§ææéå ¬å¸", "customerType": "ä¼ä¸å®¢æ·", "contactPerson": "å¼ ä¸", "contactPhone": "13800138000", "companyAddress": "XXçXXå¸XXåºXXè·¯XXå·", "companyPhone": "0513-XXXXXXXX", "taxpayerIdentificationNumber": "91110108XXXXXXXXXX", "maintainer": "æå", "maintenanceTime": "2026-06-01", "bankAccount": "622202XXXXXXXXXXXX", "basicBankAccount": "XXé¶è¡XXæ¯è¡", "bankCode": "308100XXXXXX" /** * å°é¡¶çº§äº§ååç§°æ å°ä¸ºåç±»æ ç¾ */ private static String categorize(String rootProductName) { if (rootProductName == null) return "å ¶ä»ç±»"; if (rootProductName.contains("æå") || rootProductName.contains("产æå")) return "æåç±»-éå®ä¼å éè¿äº"; if (rootProductName.contains("åæ") || rootProductName.contains("åææ") || rootProductName.contains("ææ")) return "åææç±»-éè´ä¼å éè¿äº"; if (rootProductName.contains("åæå")) return "åæåç±»"; return "å ¶ä»ç±»"; } private static String buildSalesPrompt(int min, int max, String dateStart, String dateEnd, List<String> existingCustomerNames) { String namesHint = existingCustomerNames.isEmpty() ? "" : "customerNameå¿ é¡»ä»ä»¥ä¸å·²æå®¢æ·ä¸éæ©: " + String.join("ã", existingCustomerNames) + "\n"; return """ é宿¨¡åæ ¼å¼ï¼æææ¥æå¿ é¡»å¨ %s ~ %s èå´å ï¼: %s注æï¼ä¸è¦çæcustomerå®ä½ï¼åªçæsalesLedgerï¼ productDataä¸çproductModelIdå¿ é¡»éãæåç±»ãè§æ ¼IDï¼ entryPersonåsalesmanå¿ é¡»ä»ç³»ç»ç¨æ·å表ä¸è§è²æé¨é¨å«"éå®"çç¨æ·ä¸éåï¼ { "entity": "salesLedger", "customerName": "å¼ç¨ä¸é¢çæç客æ·åç§°", "salesContractNo": "XS-20260601-001", "salesContractNo": "XS-YYYYMMDD-001", "projectName": "XX项ç®", "entryDate": "2026-06-01", "entryPerson": "å¼ ä¸", "salesman": "éå®åå§å", "entryDate": "%s", "entryPerson": "ä»ç¨æ·å表ä¸é", "salesman": "ä»ç¨æ·å表ä¸é", "contractAmount": 50000.00, "paymentMethod": "æç»30天", "executionDate": "2026-06-01", "deliveryDate": "2026-07-01", "executionDate": "%s", "deliveryDate": "%s", "type": 1, "productData": [ { "productId": 1, "productModelId": 1, "quantity": 100, "taxInclusiveUnitPrice": 500.00, "taxInclusiveTotalPrice": 50000.00, "taxExclusiveTotalPrice": 44247.79, "taxRate": 13.00, "unit": "ä»¶", "type": 1 "productData": [{ "productId": 1, "productModelId": 1, "quantity": 100, "taxInclusiveUnitPrice": 500.00, "taxInclusiveTotalPrice": 50000.00, "taxExclusiveTotalPrice": 44247.79, "taxRate": 13.00, "unit": "ä»¶", "type": 1 }] } ] } 客æ·åç§°è¦åæå®è¡ä¸çå ¬å¸ï¼ååç¼å·æ ¼å¼XS-å¹´ææ¥-åºå·ï¼éé¢åçã æ³¨æ taxExclusiveTotalPrice æ¯ä¸å«ç¨æ»ä»·ï¼éè¦æ ¹æ®å«ç¨æ»ä»·åç¨ç计ç®ï¼=å«ç¨æ»ä»·/(1+ç¨ç/100)ï¼ã æ¥æèå´: %s ~ %sï¼æ¯ç§å®ä½çæ%d-%dæ¡ã """.formatted(dateStart, dateEnd, min, max); salesContractNoä¸YYYYMMDDæ¿æ¢ä¸ºentryDateçæ¥æã%d-%dæ¡ã """.formatted(dateStart, dateEnd, namesHint, dateStart, dateStart, dateEnd, min, max); } private static String buildPurchasePrompt(int min, int max, String dateStart, String dateEnd) { private static String buildPurchasePrompt(int min, int max, String dateStart, String dateEnd, List<String> existingSupplierNames) { String namesHint = existingSupplierNames.isEmpty() ? "" : "supplierNameå¿ é¡»ä»ä»¥ä¸å·²æä¾åºåä¸éæ©: " + String.join("ã", existingSupplierNames) + "\n"; return """ éè´æ¨¡å - æä»¥ä¸æ ¼å¼çæ: { "entity": "supplier", "supplierName": "XXåæææéå ¬å¸", "supplierType": "åææä¾åºå", "contactUserName": "æå", "contactUserPhone": "13900139000", "companyAddress": "XXçXXå¸XXåºXXè·¯XXå·", "companyPhone": "0513-XXXXXXXX", "taxpayerIdentificationNum": "91110108XXXXXXXXXX", "bankAccountName": "XXé¶è¡XXæ¯è¡", "bankAccountNum": "622202XXXXXXXXXXXX", "isWhite": 0 } éè´æ¨¡åæ ¼å¼ï¼æææ¥æå¿ é¡»å¨ %s ~ %s èå´å ï¼: %s注æï¼ä¸è¦çæsupplierå®ä½ï¼åªçæpurchaseLedgerï¼ productDataä¸çproductModelIdå¿ é¡»éãåææç±»ãè§æ ¼IDï¼ äººååæ®µå¿ é¡»ä»ç³»ç»ç¨æ·å表ä¸è§è²æé¨é¨å«"éè´"çç¨æ·ä¸éåï¼ { "entity": "purchaseLedger", "supplierName": "å¼ç¨ä¸é¢çæçä¾åºååç§°", "purchaseContractNumber": "CG-20260601-001", "supplierName": "ä»å·²æä¾åºåä¸éæ©", "purchaseContractNumber": "CG-YYYYMMDD-001", "projectName": "XXéè´é¡¹ç®", "entryDate": "2026-06-01", "entryDate": "%s", "contractAmount": 30000.00, "paymentMethod": "è´§å°ä»æ¬¾", "executionDate": "2026-06-01", "productData": [ { "productId": 1, "productModelId": 1, "quantity": 50, "taxInclusiveUnitPrice": 600.00, "taxInclusiveTotalPrice": 30000.00, "taxExclusiveTotalPrice": 26548.67, "taxRate": 13.00, "unit": "ä»¶", "type": 2 "executionDate": "%s", "productData": [{ "productId": 1, "productModelId": 1, "quantity": 50, "taxInclusiveUnitPrice": 600.00, "taxInclusiveTotalPrice": 30000.00, "taxExclusiveTotalPrice": 26548.67, "taxRate": 13.00, "unit": "ä»¶", "type": 2 }] } ] } ä¾åºååç§°è¦åæå®è¡ä¸çä¾åºåï¼ååç¼å·æ ¼å¼CG-å¹´ææ¥-åºå·ã 注æ taxExclusiveTotalPrice æ¯ä¸å«ç¨æ»ä»·ï¼éè¦æ ¹æ®å«ç¨æ»ä»·åç¨ç计ç®ï¼=å«ç¨æ»ä»·/(1+ç¨ç/100)ï¼ã æ¥æèå´: %s ~ %sï¼æ¯ç§å®ä½çæ%d-%dæ¡ã """.formatted(dateStart, dateEnd, min, max); purchaseContractNumberä¸YYYYMMDDæ¿æ¢ä¸ºentryDateçæ¥æã%d-%dæ¡ã """.formatted(dateStart, dateEnd, namesHint, dateStart, dateStart, min, max); } private static String buildQualityPrompt(int min, int max) { private static String buildQualityPrompt(int min, int max, String dateStart) { return """ è´¨éæ¨¡å - æä»¥ä¸æ ¼å¼çæ: è´¨éæ¨¡åæ ¼å¼: { "entity": "qualityTestStandard", "standardNo": "QTS-20260601-001", "standardNo": "QTS-YYYYMMDD-001", "standardName": "XXäº§åæ£éªæ å", "inspectType": 0, "remark": "éç¨äºXXè¡ä¸çè´¨éæ£éªæ å" } inspectType: 0=åæææ£éª, 1=è¿ç¨æ£éª, 2=åºåæ£éªãä¸ç§ç±»åé½è¦è¦çã standardNoä¸YYYYMMDDæ¿æ¢ä¸º %sã%d-%dæ¡ã { "entity": "qualityTestStandardBinding", "productId": 1, "testStandardId": 1 } æ¯ç§å®ä½çæ%d-%dæ¡ã """.formatted(min, max); %d-%dæ¡ã """.formatted(dateStart.replace("-", ""), min, max, min, max); } private static String buildProductionPrompt(int min, int max, String dateStart, String dateEnd) { return """ ç产模å - æä»¥ä¸æ ¼å¼çæ: çäº§æ¨¡åæ ¼å¼ï¼æææ¥æå¿ é¡»å¨ %s ~ %s èå´å ï¼: { "entity": "productionPlan", "productModelId": 1, "qtyRequired": 200, "requiredDate": "2026-06-15", "requiredDate": "%s", "source": "éå®", "promisedDeliveryDate": "2026-07-01", "promisedDeliveryDate": "%s", "remark": "XX客æ·è®¢åéæ±" } { "entity": "productionOrder", "productModelId": 1, "quantity": 200, "planCompleteTime": "2026-06-30", "planCompleteTime": "%s", "remark": "æ ¹æ®ç产计åXXçæ" } productionPlançsourceå¯é"éå®"æ"å é¨"ã æ¥æèå´: %s ~ %sï¼æ¯ç§å®ä½çæ%d-%dæ¡ã """.formatted(dateStart, dateEnd, min, max); sourceå¯é"éå®"æ"å é¨"ã%d-%dæ¡ã """.formatted(dateStart, dateEnd, dateStart, dateEnd, dateEnd, min, max); } private static String buildStockPrompt(int min, int max) { private static String buildStockPrompt(int min, int max, String dateStart) { return """ åºå模å - æä»¥ä¸æ ¼å¼çæ: åºåæ¨¡åæ ¼å¼: { "entity": "stockInventory", "productModelId": 1, "qualitity": 500, "batchNo": "BATCH-20260601-001", "batchNo": "BATCH-YYYYMMDD-001", "warnNum": 50, "remark": "å®å ¨åºå" } æ¯ç§å®ä½çæ%d-%dæ¡ãbatchNoæ ¼å¼BATCH-å¹´ææ¥-åºå·ã """.formatted(min, max); batchNoä¸YYYYMMDDæ¿æ¢ä¸º %sã%d-%dæ¡ã """.formatted(dateStart.replace("-", ""), min, max); } } src/main/java/com/ruoyi/mock/service/impl/DataCheckServiceImpl.java
@@ -5,14 +5,26 @@ import com.ruoyi.approve.mapper.ApprovalTemplateMapper; import com.ruoyi.basic.mapper.CustomerMapper; import com.ruoyi.basic.mapper.ProductMapper; import com.ruoyi.basic.mapper.ProductModelMapper; import com.ruoyi.basic.mapper.SupplierManageMapper; import com.ruoyi.common.enums.TypeEnums; import com.ruoyi.mock.dto.DataCheckRequest; import com.ruoyi.mock.service.DataCheckService; import com.ruoyi.mock.vo.DataCheckResult; import com.ruoyi.mock.vo.DataCheckResult.CheckItem; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.quality.mapper.QualityTestStandardBindingMapper; import com.ruoyi.quality.mapper.QualityTestStandardMapper; import com.ruoyi.technology.mapper.TechnologyBomMapper; import com.ruoyi.technology.mapper.TechnologyBomStructureMapper; import com.ruoyi.technology.mapper.TechnologyOperationMapper; import com.ruoyi.technology.mapper.TechnologyRoutingMapper; import com.ruoyi.technology.mapper.TechnologyRoutingOperationMapper; import com.ruoyi.technology.pojo.TechnologyBom; import com.ruoyi.technology.pojo.TechnologyBomStructure; import com.ruoyi.technology.pojo.TechnologyRouting; import com.ruoyi.technology.pojo.TechnologyRoutingOperation; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -26,11 +38,18 @@ public class DataCheckServiceImpl implements DataCheckService { private final ProductMapper productMapper; private final ProductModelMapper productModelMapper; private final CustomerMapper customerMapper; private final SupplierManageMapper supplierManageMapper; private final ApprovalTemplateMapper approvalTemplateMapper; private final QualityTestStandardMapper qualityTestStandardMapper; private final QualityTestStandardBindingMapper qualityTestStandardBindingMapper; private final TechnologyRoutingMapper technologyRoutingMapper; private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper; private final TechnologyOperationMapper technologyOperationMapper; private final TechnologyBomMapper technologyBomMapper; private final TechnologyBomStructureMapper technologyBomStructureMapper; private final SysUserMapper sysUserMapper; @Override public DataCheckResult check(DataCheckRequest request) { @@ -43,6 +62,7 @@ if (!modules.isEmpty()) { addProductCheck(itemMap); addUserChecks(itemMap); } for (String module : modules) { @@ -50,6 +70,7 @@ case "sales" -> addSalesChecks(itemMap); case "purchase" -> addPurchaseChecks(itemMap); case "quality" -> addQualityChecks(itemMap); case "production" -> addProductionChecks(itemMap); } } @@ -70,6 +91,34 @@ long count = productMapper.selectCount(null); itemMap.put(key, buildItem("common", "äº§åæ°æ®", 1, (int) count, "缺å°äº§åæ°æ®ï¼è¯·å å¨ãåºç¡æ°æ®-产å管çã䏿·»å è³å°1æ¡äº§å")); } private void addUserChecks(Map<String, CheckItem> itemMap) { // 1. ç³»ç»ç¨æ· String userKey = "common:ç³»ç»ç¨æ·"; if (!itemMap.containsKey(userKey)) { List<SysUser> users = sysUserMapper.selectUserListWithDetail(); itemMap.put(userKey, buildItem("common", "ç³»ç»ç¨æ·", 1, (int) users.size(), "缺å°ç³»ç»ç¨æ·ï¼è¯·å å¨ãç³»ç»ç®¡ç-ç¨æ·ç®¡çã䏿·»å ç¨æ·")); } // 2. æè§è²çç¨æ· String userWithRoleKey = "common:ç¨æ·è§è²é ç½®"; if (!itemMap.containsKey(userWithRoleKey)) { List<SysUser> users = sysUserMapper.selectUserListWithDetail(); long withRole = users.stream().filter(u -> u.getRoleNames() != null && !u.getRoleNames().isBlank()).count(); itemMap.put(userWithRoleKey, buildItem("common", "ç¨æ·è§è²é ç½®", 1, (int) withRole, "没æç¨æ·åé è§è²ï¼è¯·å å¨ãç³»ç»ç®¡ç-ç¨æ·ç®¡çãä¸ä¸ºç¨æ·åé è§è²")); } // 3. æé¨é¨çç¨æ· String userWithDeptKey = "common:ç¨æ·é¨é¨é ç½®"; if (!itemMap.containsKey(userWithDeptKey)) { List<SysUser> users = sysUserMapper.selectUserListWithDetail(); long withDept = users.stream().filter(u -> u.getDeptNames() != null && !u.getDeptNames().isBlank()).count(); itemMap.put(userWithDeptKey, buildItem("common", "ç¨æ·é¨é¨é ç½®", 1, (int) withDept, "没æç¨æ·åé é¨é¨ï¼è¯·å å¨ãç³»ç»ç®¡ç-ç¨æ·ç®¡çãä¸ä¸ºç¨æ·åé é¨é¨")); } } private void addSalesChecks(Map<String, CheckItem> itemMap) { @@ -133,6 +182,93 @@ } } private void addProductionChecks(Map<String, CheckItem> itemMap) { // 1. 产åè§æ ¼ String modelKey = "production:产åè§æ ¼"; if (!itemMap.containsKey(modelKey)) { long count = productModelMapper.selectCount(null); itemMap.put(modelKey, buildItem("production", "产åè§æ ¼", 1, (int) count, "缺å°äº§åè§æ ¼ï¼è¯·å å¨ãåºç¡æ°æ®-产å管çãä¸ä¸ºäº§åæ·»å è§æ ¼åå·")); } // 2. å·¥åº String operationKey = "production:å·¥åº"; if (!itemMap.containsKey(operationKey)) { long count = technologyOperationMapper.selectCount(null); itemMap.put(operationKey, buildItem("production", "å·¥åº", 1, (int) count, "缺å°å·¥åºï¼è¯·å å¨ãå·¥èºè®¾è®¡-å·¥åºç®¡çãä¸å建工åº")); } // 3. BOM String bomKey = "production:BOM"; if (!itemMap.containsKey(bomKey)) { long count = technologyBomMapper.selectCount(null); itemMap.put(bomKey, buildItem("production", "BOM", 1, (int) count, "缺å°BOMï¼è¯·å å¨ãå·¥èºè®¾è®¡-BOM管çãä¸å建BOM")); } // 4. BOM产åç»æ String bomStructureKey = "production:BOM产åç»æ"; if (!itemMap.containsKey(bomStructureKey)) { long count = technologyBomStructureMapper.selectCount(null); itemMap.put(bomStructureKey, buildItem("production", "BOM产åç»æ", 1, (int) count, "缺å°BOM产åç»æï¼è¯·å å¨ãå·¥èºè®¾è®¡-BOM管çãä¸ä¸ºBOMæ·»å 产åç»æèç¹")); } // 5. å·¥èºè·¯çº¿ String routingKey = "production:å·¥èºè·¯çº¿"; if (!itemMap.containsKey(routingKey)) { long count = technologyRoutingMapper.selectCount(null); itemMap.put(routingKey, buildItem("production", "å·¥èºè·¯çº¿", 1, (int) count, "缺å°å·¥èºè·¯çº¿ï¼è¯·å å¨ãå·¥èºè®¾è®¡-å·¥èºè·¯çº¿ãä¸å建工èºè·¯çº¿")); } // 6. å·¥èºè·¯çº¿å·¥åº String routingOpKey = "production:å·¥èºè·¯çº¿å·¥åº"; if (!itemMap.containsKey(routingOpKey)) { long count = technologyRoutingOperationMapper.selectCount(null); itemMap.put(routingOpKey, buildItem("production", "å·¥èºè·¯çº¿å·¥åº", 1, (int) count, "缺å°å·¥èºè·¯çº¿å·¥åºï¼è¯·å å¨ãå·¥èºè®¾è®¡-å·¥èºè·¯çº¿ãä¸ä¸ºå·¥èºè·¯çº¿æ·»å å·¥åº")); } // 7. å ³èæ§æ£æµï¼æäº§åè§æ ¼ä½æ å·¥èºè·¯çº¿ç String linkageKey = "production:产å-å·¥èºè·¯çº¿å ³è"; if (!itemMap.containsKey(linkageKey)) { long modelCount = productModelMapper.selectCount(null); long routedCount = technologyRoutingMapper.selectCount( new LambdaQueryWrapper<TechnologyRouting>() .isNotNull(TechnologyRouting::getProductModelId) .gt(TechnologyRouting::getProductModelId, 0)); itemMap.put(linkageKey, buildItem("production", "产å-å·¥èºè·¯çº¿å ³è", (int) Math.min(modelCount, 1), (int) routedCount, "é¨å产åè§æ ¼æªå ³èå·¥èºè·¯çº¿ï¼è¯·å å¨ãå·¥èºè®¾è®¡-å·¥èºè·¯çº¿ãä¸ä¸ºäº§åè§æ ¼å建工èºè·¯çº¿")); } // 8. å ³èæ§æ£æµï¼æå·¥èºè·¯çº¿ä½æ å·¥åºç String routingOpLinkKey = "production:å·¥èºè·¯çº¿-å·¥åºå ³è"; if (!itemMap.containsKey(routingOpLinkKey)) { long routingCount = technologyRoutingMapper.selectCount(null); long routedOpCount = technologyRoutingOperationMapper.selectCount( new LambdaQueryWrapper<TechnologyRoutingOperation>() .gt(TechnologyRoutingOperation::getTechnologyRoutingId, 0)); itemMap.put(routingOpLinkKey, buildItem("production", "å·¥èºè·¯çº¿-å·¥åºå ³è", (int) Math.min(routingCount, 1), (int) routedOpCount, "é¨åå·¥èºè·¯çº¿æªæ·»å å·¥åºï¼è¯·å å¨ãå·¥èºè®¾è®¡-å·¥èºè·¯çº¿ãä¸ä¸ºå·¥èºè·¯çº¿æ·»å å·¥åº")); } // 9. å ³èæ§æ£æµï¼æBOM使 产åç»æç String bomStructureLinkKey = "production:BOM-产åç»æå ³è"; if (!itemMap.containsKey(bomStructureLinkKey)) { long bomCount = technologyBomMapper.selectCount(null); long structureCount = technologyBomStructureMapper.selectCount( new LambdaQueryWrapper<TechnologyBomStructure>() .gt(TechnologyBomStructure::getBomId, 0)); itemMap.put(bomStructureLinkKey, buildItem("production", "BOM-产åç»æå ³è", (int) Math.min(bomCount, 1), (int) structureCount, "é¨åBOMæªæ·»å 产åç»æï¼è¯·å å¨ãå·¥èºè®¾è®¡-BOM管çãä¸ä¸ºBOMæ·»å 产åç»æèç¹")); } } private CheckItem buildItem(String module, String itemName, int minRequired, int currentCount, String failMessage) { CheckItem item = new CheckItem(); item.setModule(module); src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java
@@ -4,32 +4,82 @@ import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.ruoyi.ai.assistant.Assistant; import com.ruoyi.approve.mapper.ApprovalInstanceMapper; import com.ruoyi.approve.mapper.ApprovalInstanceNodeMapper; import com.ruoyi.approve.mapper.ApprovalRecordMapper; import com.ruoyi.approve.mapper.ApprovalTaskMapper; import com.ruoyi.approve.pojo.ApprovalInstance; import com.ruoyi.approve.pojo.ApprovalInstanceNode; import com.ruoyi.approve.pojo.ApprovalRecord; import com.ruoyi.approve.pojo.ApprovalTask; import com.ruoyi.approve.service.ApprovalInstanceService; import com.ruoyi.basic.mapper.ProductMapper; import com.ruoyi.basic.mapper.ProductModelMapper; import com.ruoyi.basic.pojo.Customer; import com.ruoyi.basic.pojo.Product; import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.basic.pojo.SupplierManage; import com.ruoyi.basic.service.ICustomerService; import com.ruoyi.basic.service.ISupplierService; import com.ruoyi.common.enums.ReviewStatusEnum; import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.utils.OrderUtils; import com.ruoyi.mock.dto.DataGenerateRequest; import com.ruoyi.mock.prompt.MockDataPrompt; import com.ruoyi.mock.service.DataGenerateService; import com.ruoyi.mock.vo.DataGenerateResult; import com.ruoyi.mock.vo.DataGenerateResult.ModuleSummary; import com.ruoyi.production.pojo.ProductionOrder; import com.ruoyi.production.pojo.ProductionPlan; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.production.bean.dto.ProductionOrderPickDto; import com.ruoyi.production.bean.dto.ProductionPlanDto; import com.ruoyi.production.bean.dto.ProductionProductMainDto; import com.ruoyi.production.bean.vo.ProductionBomStructureVo; import com.ruoyi.production.mapper.*; import com.ruoyi.production.pojo.*; import com.ruoyi.production.service.ProductionOrderPickService; import com.ruoyi.production.service.ProductionOrderService; import com.ruoyi.production.service.ProductionPlanService; import com.ruoyi.production.service.ProductionProductMainService; import com.ruoyi.purchase.dto.PurchaseLedgerDto; import com.ruoyi.purchase.pojo.PurchaseLedger; import com.ruoyi.purchase.service.IPurchaseLedgerService; import com.ruoyi.project.system.domain.SysDept; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysDeptMapper; import com.ruoyi.project.system.mapper.SysUserDeptMapper; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.quality.mapper.QualityInspectMapper; import com.ruoyi.quality.pojo.QualityInspect; import com.ruoyi.quality.pojo.QualityTestStandard; import com.ruoyi.quality.pojo.QualityTestStandardBinding; import com.ruoyi.quality.service.IQualityInspectService; import com.ruoyi.quality.service.IQualityTestStandardService; import com.ruoyi.quality.service.QualityTestStandardBindingService; import com.ruoyi.sales.dto.SalesLedgerDto; import com.ruoyi.sales.dto.ShippingInfoDto; import com.ruoyi.sales.mapper.SalesLedgerMapper; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.mapper.ShippingInfoMapper; import com.ruoyi.sales.mapper.ShippingProductDetailMapper; import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.pojo.ShippingInfo; import com.ruoyi.sales.pojo.ShippingProductDetail; import com.ruoyi.sales.service.ISalesLedgerService; import com.ruoyi.sales.service.ShippingInfoService; import com.ruoyi.stock.mapper.StockInRecordMapper; import com.ruoyi.stock.mapper.StockInventoryMapper; import com.ruoyi.stock.mapper.StockOutRecordMapper; import com.ruoyi.stock.pojo.StockInventory; import com.ruoyi.stock.pojo.StockOutRecord; import com.ruoyi.stock.dto.StockInventoryDto; import com.ruoyi.stock.service.StockInRecordService; import com.ruoyi.stock.service.StockOutRecordService; import com.ruoyi.stock.service.StockInventoryService; import com.ruoyi.technology.mapper.TechnologyBomStructureMapper; import com.ruoyi.technology.mapper.TechnologyRoutingMapper; import com.ruoyi.technology.mapper.TechnologyRoutingOperationMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -37,10 +87,17 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; @Slf4j @@ -62,6 +119,47 @@ private final ProductionOrderService productionOrderService; private final StockInventoryService stockInventoryService; // éè´å®æ´æµç¨éè¦çservice private final ApprovalInstanceService approvalInstanceService; private final ApprovalInstanceMapper approvalInstanceMapper; private final ApprovalInstanceNodeMapper approvalInstanceNodeMapper; private final ApprovalTaskMapper approvalTaskMapper; private final ApprovalRecordMapper approvalRecordMapper; private final IQualityInspectService qualityInspectService; private final QualityInspectMapper qualityInspectMapper; private final StockInRecordService stockInRecordService; private final StockInRecordMapper stockInRecordMapper; // éå®å®æ´æµç¨éè¦çservice/mapper private final SalesLedgerMapper salesLedgerMapper; private final SalesLedgerProductMapper salesLedgerProductMapper; private final ProductionPlanMapper productionPlanMapper; private final ProductionOrderMapper productionOrderMapper; private final ProductionOperationTaskMapper productionOperationTaskMapper; private final ProductionProductMainService productionProductMainService; private final ShippingInfoService shippingInfoService; private final ShippingInfoMapper shippingInfoMapper; private final ShippingProductDetailMapper shippingProductDetailMapper; private final StockUtils stockUtils; private final StockOutRecordMapper stockOutRecordMapper; private final StockOutRecordService stockOutRecordService; private final StockInventoryMapper stockInventoryMapper; // å·¥èºæ°æ®æ£æµ private final TechnologyRoutingMapper technologyRoutingMapper; private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper; private final TechnologyBomStructureMapper technologyBomStructureMapper; // 颿 private final ProductionOrderPickService productionOrderPickService; private final ProductionOrderBomMapper productionOrderBomMapper; private final ProductionBomStructureMapper productionBomStructureMapper; // ç¨æ·/è§è²æ¥è¯¢ private final SysUserMapper sysUserMapper; private final SysDeptMapper sysDeptMapper; private final SysUserDeptMapper sysUserDeptMapper; @Override public DataGenerateResult generate(DataGenerateRequest request) { DataGenerateResult result = new DataGenerateResult(); @@ -70,10 +168,18 @@ int totalGenerated = 0; try { List<Long> productIds = productMapper.selectList(null).stream() .map(p -> p.getId()).collect(Collectors.toList()); List<Long> productModelIds = productModelMapper.selectList(null).stream() .map(m -> m.getId()).collect(Collectors.toList()); // æå»ºäº§åè§æ ¼åç±»ï¼éè¿Productæ æ ¹èç¹å¤ææå/åææ Map<Long, String> productModelIdToCategory = buildProductModelCategoryMap(); List<Long> productModelIds = new ArrayList<>(productModelIdToCategory.keySet()); // å 载已æå®¢æ·/ä¾åºåï¼ä¸æ°å¢ï¼ä½¿ç¨å·²ææ°æ®ï¼ Map<String, Long> customerNameToId = loadExistingCustomers(); Map<String, Long> supplierNameToId = loadExistingSuppliers(); List<String> existingCustomerNames = new ArrayList<>(customerNameToId.keySet()); List<String> existingSupplierNames = new ArrayList<>(supplierNameToId.keySet()); // å 载系ç»ç¨æ·ä¿¡æ¯ï¼æµç§°ãè§è²ãé¨é¨ï¼ List<SysUser> systemUsers = loadSystemUsersWithDetail(); String systemPrompt = MockDataPrompt.buildSystemPrompt(); String userMessage = MockDataPrompt.buildUserMessage( @@ -81,7 +187,9 @@ request.getCountMin(), request.getCountMax(), request.getDateStart(), request.getDateEnd(), request.getAdditionalInfo(), productIds, productModelIds); productModelIdToCategory, systemUsers, existingCustomerNames, existingSupplierNames); String fullPrompt = systemPrompt + "\n\n" + userMessage; log.info("è°ç¨AIçææ¨¡ææ°æ®, modules={}, industries={}", request.getModules(), request.getIndustries()); @@ -103,24 +211,17 @@ return result; } // ä¿®æ£AIçæçæ¥æå°æå®æ¶é´èå´å String dateStart = request.getDateStart(); String dateEnd = request.getDateEnd(); if (dateStart != null && dateEnd != null) { fixDatesInRange(entities, dateStart, dateEnd); } Map<String, List<JSONObject>> grouped = entities.stream() .collect(Collectors.groupingBy(e -> e.getString("entity"))); // åç§°âID æ å°è¡¨ï¼ç¨äºå建ä¸å¡åæ®æ¶åå¡«å¤é® Map<String, Long> customerNameToId = new HashMap<>(); Map<String, Long> supplierNameToId = new HashMap<>(); // Tier 0: åºç¡æ°æ® if (grouped.containsKey("customer")) { ModuleSummary s = createCustomers(grouped.get("customer"), customerNameToId); summaries.add(s); totalGenerated += s.getSuccessCount(); } if (grouped.containsKey("supplier")) { ModuleSummary s = createSuppliers(grouped.get("supplier"), supplierNameToId); summaries.add(s); totalGenerated += s.getSuccessCount(); } // Tier 0: åºç¡æ°æ®ï¼å®¢æ·åä¾åºåä¸èªå¨çæï¼ä½¿ç¨å·²ææ°æ®ï¼ if (grouped.containsKey("qualityTestStandard")) { ModuleSummary s = createQualityStandards(grouped.get("qualityTestStandard")); summaries.add(s); @@ -129,12 +230,13 @@ // Tier 1: ä¸å¡åæ® if (grouped.containsKey("salesLedger")) { ModuleSummary s = createSalesLedgers(grouped.get("salesLedger"), customerNameToId); ModuleSummary s = createSalesLedgers(grouped.get("salesLedger"), customerNameToId, request.getDateStart()); summaries.add(s); totalGenerated += s.getSuccessCount(); } if (grouped.containsKey("purchaseLedger")) { ModuleSummary s = createPurchaseLedgers(grouped.get("purchaseLedger"), supplierNameToId); ModuleSummary s = createPurchaseLedgers(grouped.get("purchaseLedger"), supplierNameToId, request.getAdditionalInfo(), request.getDateStart(), request.getDateEnd()); summaries.add(s); totalGenerated += s.getSuccessCount(); } @@ -198,7 +300,154 @@ } } /** * ä¿®æ£AIçæçæ¥æå°æå®æ¶é´èå´å ã * éåææå®ä½çææå段ï¼å¦æåç°æ¥æå符串ï¼yyyy-MM-ddæ ¼å¼ï¼è¶ åºèå´ï¼æ¿æ¢ä¸ºèå´å çéæºæ¥æã */ private void fixDatesInRange(List<JSONObject> entities, String dateStart, String dateEnd) { LocalDate start; LocalDate end; try { start = LocalDate.parse(dateStart); end = LocalDate.parse(dateEnd); } catch (Exception e) { log.warn("æ¥æèå´è§£æå¤±è´¥: {} ~ {}", dateStart, dateEnd); return; } long daysBetween = ChronoUnit.DAYS.between(start, end); if (daysBetween <= 0) { daysBetween = 1; } // ææå·²ç¥çæ¥æåæ®µå java.util.Set<String> dateFields = java.util.Set.of( "entryDate", "executionDate", "deliveryDate", "requiredDate", "promisedDeliveryDate", "planCompleteTime", "maintenanceTime", "checkTime", "registerDate" ); for (JSONObject entity : entities) { for (String key : dateFields) { String val = entity.getString(key); if (val != null && val.matches("\\d{4}-\\d{2}-\\d{2}")) { try { LocalDate d = LocalDate.parse(val); if (d.isBefore(start) || d.isAfter(end)) { LocalDate fixed = start.plusDays(ThreadLocalRandom.current().nextLong(daysBetween + 1)); entity.put(key, fixed.toString()); log.debug("ä¿®æ£æ¥æ {}: {} -> {}", key, val, fixed); } } catch (Exception ignored) { } } else if (val != null && !val.matches("\\d{4}-\\d{2}-\\d{2}")) { // AIè¿åäºæ ææ¥ææ ¼å¼ï¼ç´æ¥æ¿æ¢ä¸ºèå´å çéæºæ¥æ LocalDate fixed = start.plusDays(ThreadLocalRandom.current().nextLong(daysBetween + 1)); entity.put(key, fixed.toString()); log.debug("ä¿®æ£æ ææ¥æ {}: {} -> {}", key, val, fixed); } } // ä¿®æ£ååç¼å·ä¸çæ¥æ: CG-20230601-001 -> CG-YYYYMMDD-001 for (String key : java.util.Set.of("purchaseContractNumber", "salesContractNo", "standardNo", "batchNo")) { String val = entity.getString(key); if (val != null && val.matches(".*\\d{8}.*")) { String datePart = val.replaceAll(".*?(\\d{8}).*", "$1"); try { // éªè¯æåå°çæ¯æææ¥æ String dateStr = datePart.substring(0, 4) + "-" + datePart.substring(4, 6) + "-" + datePart.substring(6, 8); LocalDate d = LocalDate.parse(dateStr); if (d.isBefore(start) || d.isAfter(end)) { LocalDate fixed = start.plusDays(ThreadLocalRandom.current().nextLong(daysBetween + 1)); String newDatePart = fixed.format(java.time.format.DateTimeFormatter.BASIC_ISO_DATE); String newVal = val.replace(datePart, newDatePart); entity.put(key, newVal); log.debug("ä¿®æ£ç¼å· {}: {} -> {}", key, val, newVal); } } catch (Exception ignored) { } } } } } // ---- Tier 0: åºç¡æ°æ® ---- /** * 仿°æ®åºå 载已æå®¢æ·åç§°âIDæ å° */ private Map<String, Long> loadExistingCustomers() { Map<String, Long> map = new HashMap<>(); List<Customer> customers = customerService.list(); for (Customer c : customers) { if (c.getCustomerName() != null) { map.put(c.getCustomerName(), c.getId()); } } return map; } /** * 仿°æ®åºå 载已æä¾åºååç§°âIDæ å° */ private Map<String, Long> loadExistingSuppliers() { Map<String, Long> map = new HashMap<>(); List<SupplierManage> suppliers = supplierService.list(); for (SupplierManage s : suppliers) { if (s.getSupplierName() != null) { map.put(s.getSupplierName(), s.getId()); } } return map; } /** * å 载系ç»ç¨æ·ä¿¡æ¯ï¼å«è§è²åé¨é¨åç§°ï¼ */ private List<SysUser> loadSystemUsersWithDetail() { return sysUserMapper.selectUserListWithDetail(); } /** * æå»ºäº§åè§æ ¼IDâ顶级产ååç±»åç§°çæ å° * éè¿Productæ å䏿¾å°æ ¹èç¹ï¼å¤æ"æå"/"åææ"/"åæå" */ private Map<Long, String> buildProductModelCategoryMap() { // å è½½ææProductèç¹ List<Product> allProducts = productMapper.selectList(null); Map<Long, Product> productMap = allProducts.stream() .collect(Collectors.toMap(Product::getId, p -> p, (a, b) -> a)); // 对æ¯ä¸ªProductï¼æ²¿parentIdå䏿¾å°æ ¹èç¹åç§° Map<Long, String> productIdToRootName = new HashMap<>(); for (Product p : allProducts) { if (productIdToRootName.containsKey(p.getId())) continue; // åä¸éåæ¾æ ¹ List<Long> chain = new ArrayList<>(); Long currentId = p.getId(); while (currentId != null) { chain.add(currentId); Product current = productMap.get(currentId); if (current == null || current.getParentId() == null) break; currentId = current.getParentId(); } // æ ¹èç¹çproductNameå°±æ¯åç±»å Product root = productMap.get(chain.get(chain.size() - 1)); String rootName = root != null ? root.getProductName() : "å ¶ä»"; for (Long id : chain) { productIdToRootName.put(id, rootName); } } // 对æ¯ä¸ªProductModelï¼éè¿productIdæ¾å°å ¶æå±åç±» List<ProductModel> allModels = productModelMapper.selectList(null); Map<Long, String> result = new HashMap<>(); for (ProductModel m : allModels) { String category = m.getProductId() != null ? productIdToRootName.getOrDefault(m.getProductId(), "å ¶ä»") : "å ¶ä»"; result.put(m.getId(), category); } return result; } private ModuleSummary createCustomers(List<JSONObject> items, Map<String, Long> nameToId) { int success = 0, fail = 0; @@ -214,7 +463,10 @@ c.setTaxpayerIdentificationNumber(item.getString("taxpayerIdentificationNumber")); c.setMaintainer(item.getString("maintainer")); if (item.containsKey("maintenanceTime")) { c.setMaintenanceTime(java.sql.Date.valueOf(item.getString("maintenanceTime"))); String mtStr = item.getString("maintenanceTime"); if (mtStr != null && mtStr.matches("\\d{4}-\\d{2}-\\d{2}")) { c.setMaintenanceTime(java.sql.Date.valueOf(mtStr)); } } else { c.setMaintenanceTime(new java.sql.Date(System.currentTimeMillis())); } @@ -291,7 +543,7 @@ // ---- Tier 1: ä¸å¡åæ® ---- private ModuleSummary createSalesLedgers(List<JSONObject> items, Map<String, Long> customerNameToId) { private ModuleSummary createSalesLedgers(List<JSONObject> items, Map<String, Long> customerNameToId, String dateStart) { int success = 0, fail = 0; for (JSONObject item : items) { try { @@ -305,20 +557,56 @@ dto.setSalesman(item.getString("salesman")); dto.setPaymentMethod(item.getString("paymentMethod")); dto.setType(item.getInteger("type")); // å½å ¥äººï¼ä¼å 使ç¨AIæä¾çæ°æ®ï¼å¦åç¨å½åç»å½ç¨æ· if (item.containsKey("entryPerson")) { dto.setEntryPerson(item.getString("entryPerson")); // å½å ¥äººï¼ä¼å ç¨AIè¿åçï¼å¦åä»"éå®"è§è²/é¨é¨éæºé String entryPerson = item.getString("entryPerson"); if (entryPerson == null || entryPerson.isBlank()) { SysUser salesUser = randomUserByKeyword("éå®"); entryPerson = salesUser != null ? salesUser.getNickName() : "ç³»ç»"; } dto.setEntryPerson(entryPerson); // ä¸å¡åï¼ä¼å ç¨AIè¿åçï¼å¦åä»"éå®"è§è²/é¨é¨éæºé String salesman = dto.getSalesman(); if (salesman == null || salesman.isBlank()) { SysUser salesUser = randomUserByKeyword("éå®"); salesman = salesUser != null ? salesUser.getNickName() : "ç³»ç»"; dto.setSalesman(salesman); } // customerId为nullä¼å¯¼è´"客æ·ä¸åå¨"å¼å¸¸ï¼è·³è¿ if (customerId == null) { log.warn("è·³è¿éå®å°è´¦ï¼å®¢æ·[{}]ä¸åå¨", customerName); fail++; continue; } LocalDate entryDate = null; if (item.containsKey("entryDate")) { dto.setEntryDate(java.sql.Date.valueOf(item.getString("entryDate"))); String entryDateStr = item.getString("entryDate"); if (entryDateStr != null && entryDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) { entryDate = LocalDate.parse(entryDateStr); dto.setEntryDate(java.sql.Date.valueOf(entryDateStr)); } else { dto.setEntryDate(java.sql.Date.valueOf(dateStart)); } } if (item.containsKey("executionDate")) { dto.setExecutionDate(LocalDate.parse(item.getString("executionDate"))); String execDateStr = item.getString("executionDate"); if (execDateStr != null && execDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) { dto.setExecutionDate(LocalDate.parse(execDateStr)); } else { dto.setExecutionDate(LocalDate.parse(dateStart)); } } if (item.containsKey("deliveryDate")) { dto.setDeliveryDate(LocalDate.parse(item.getString("deliveryDate"))); String delDateStr = item.getString("deliveryDate"); if (delDateStr != null && delDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) { dto.setDeliveryDate(LocalDate.parse(delDateStr)); } else { dto.setDeliveryDate(LocalDate.parse(dateStart)); } } JSONArray productData = item.getJSONArray("productData"); boolean hasProduction = false; if (productData != null) { List<SalesLedgerProduct> products = new ArrayList<>(); for (int i = 0; i < productData.size(); i++) { @@ -335,7 +623,6 @@ if (pd.containsKey("taxExclusiveTotalPrice")) { slp.setTaxExclusiveTotalPrice(pd.getBigDecimal("taxExclusiveTotalPrice")); } else if (pd.getBigDecimal("taxInclusiveTotalPrice") != null && pd.getBigDecimal("taxRate") != null) { // ä¸å«ç¨æ»ä»· = å«ç¨æ»ä»· / (1 + ç¨ç/100) slp.setTaxExclusiveTotalPrice( pd.getBigDecimal("taxInclusiveTotalPrice").divide( BigDecimal.ONE.add(pd.getBigDecimal("taxRate").divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP)), @@ -343,21 +630,606 @@ } else { slp.setTaxExclusiveTotalPrice(BigDecimal.ZERO); } slp.setIsProduction(true); products.add(slp); hasProduction = true; } dto.setProductData(products); } salesLedgerService.addOrUpdateSalesLedger(dto); // addOrUpdateSalesLedgerå é¨ä¼èªå¨çæååå·å¹¶insertï¼ä½dto䏿²¡æåå // ç´æ¥ç¨dtoçentryDateåcustomerIdæ¥ææ°å建çè®°å½ SalesLedger savedLedger = salesLedgerMapper.selectOne( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SalesLedger>() .eq(SalesLedger::getCustomerId, dto.getCustomerId()) .orderByDesc(SalesLedger::getId) .last("limit 1")); if (savedLedger != null && hasProduction) { processSalesFullFlow(savedLedger, entryDate); } success++; } catch (Exception e) { log.warn("å建éå®å°è´¦å¤±è´¥: {}", e.getMessage()); log.warn("å建éå®å°è´¦å¤±è´¥: {}", e.getMessage(), e); fail++; } } return summary("sales", "éå®å°è´¦", items.size(), success, fail); } private ModuleSummary createPurchaseLedgers(List<JSONObject> items, Map<String, Long> supplierNameToId) { // ==================== éå®å®æ´æµç¨ ==================== /** * éå®å®æ´æµç¨: ç产计ååå¹¶ä¸å â 颿 â æ¥å·¥ â è´¨æ£(å¯é) â å ¥åº â åè´§ â åºåº * æ¶é´ä»¥éå®å½å ¥æ¥æä¸ºåºåï¼åç¯è鿍0-3天 */ private void processSalesFullFlow(SalesLedger salesLedger, LocalDate entryDate) { try { LocalDate baseDate = entryDate != null ? entryDate : LocalDate.now(); // 1. æ¥è¯¢éå®å°è´¦äº§åï¼å«ç产计åï¼ List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SalesLedgerProduct>() .eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId()) .eq(SalesLedgerProduct::getIsProduction, true)); if (products.isEmpty()) { log.info("éå®å°è´¦[{}]æ éç产ï¼è·³è¿ç产æµç¨", salesLedger.getSalesContractNo()); return; } // æ£æ¥äº§åæ¯å¦å ·å¤å®æ´çå·¥èºæ°æ®ï¼å·¥èºè·¯çº¿ãå·¥åºãBOMï¼ List<Long> missingTechProductIds = checkTechnologyDataReadiness(products); if (!missingTechProductIds.isEmpty()) { log.warn("éå®å°è´¦[{}]以ä¸äº§å缺å°å·¥èºæ°æ®ï¼å·¥èºè·¯çº¿/å·¥åº/BOMï¼ï¼è·³è¿ç产æµç¨: {}", salesLedger.getSalesContractNo(), missingTechProductIds); return; } // 2. ç产计ååå¹¶ä¸å â ç产订å LocalDate planDate = baseDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4)); processProductionCombine(salesLedger, planDate); // 3. 颿ï¼ç©æä¸è¶³èªå¨å ¥åºååé¢ï¼ LocalDate pickDate = planDate.plusDays(ThreadLocalRandom.current().nextInt(0, 3)); processMaterialPick(salesLedger, pickDate); // 4. ç产æ¥å·¥ LocalDate reportDate = pickDate.plusDays(ThreadLocalRandom.current().nextInt(1, 4)); processProductionReport(salesLedger, reportDate); // 5. è´¨æ£æäº¤ + å ¥åºå®¡æ¹ LocalDate qualityDate = reportDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4)); processSalesQualityAndStockIn(salesLedger, qualityDate); // 6. åè´§ + åè´§å®¡æ¹ + åºåºå®¡æ¹ LocalDate shipDate = qualityDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4)); processSalesShipping(salesLedger, shipDate); log.info("éå®å°è´¦[{}]宿´æµç¨å¤ç宿¯", salesLedger.getSalesContractNo()); } catch (Exception e) { log.warn("éå®å®æ´æµç¨å¤ç失败[{}]: {}", salesLedger.getSalesContractNo(), e.getMessage()); } } /** * æ¥è¯¢è§è²æé¨é¨å«æå®å ³é®åçç¨æ·ï¼éæºè¿åä¸ä¸ª */ private SysUser randomUserByKeyword(String keyword) { try { List<Long> userIds = new ArrayList<>(sysUserMapper.getUserByRole(keyword)); List<SysDept> depts = sysDeptMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SysDept>() .like(SysDept::getDeptName, keyword) .eq(SysDept::getDelFlag, "0") .eq(SysDept::getStatus, "0")); if (!depts.isEmpty()) { List<Long> deptIds = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList()); List<Long> deptUserIds = sysUserDeptMapper.selectDistinctUserIdsByDeptIds(deptIds); userIds.addAll(deptUserIds); } if (userIds.isEmpty()) { return null; } List<Long> distinctIds = userIds.stream().distinct().collect(Collectors.toList()); Long randomId = distinctIds.get(ThreadLocalRandom.current().nextInt(distinctIds.size())); return sysUserMapper.selectUserById(randomId); } catch (Exception e) { log.warn("æ¥è¯¢[{}]è§è²/é¨é¨ç¨æ·å¤±è´¥: {}", keyword, e.getMessage()); return null; } } /** * æ¥è¯¢è§è²æé¨é¨å«"ç产"çç¨æ·ï¼éæºè¿åä¸ä¸ª */ private SysUser randomProductionUser() { return randomUserByKeyword("ç产"); } /** * æ£æ¥äº§åæ¯å¦å ·å¤å®æ´çå·¥èºæ°æ®ï¼å·¥èºè·¯çº¿ãå·¥åºãBOMï¼ * @return 缺å°å·¥èºæ°æ®ç产åè§æ ¼IDå表ï¼ç©ºåè¡¨è¡¨ç¤ºå ¨é¨å°±ç»ªï¼ */ private List<Long> checkTechnologyDataReadiness(List<SalesLedgerProduct> products) { List<Long> missingIds = new ArrayList<>(); for (SalesLedgerProduct slp : products) { Long productModelId = slp.getProductModelId(); if (productModelId == null) continue; // 1. æ£æ¥å·¥èºè·¯çº¿ List<com.ruoyi.technology.pojo.TechnologyRouting> routings = technologyRoutingMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.technology.pojo.TechnologyRouting>() .eq(com.ruoyi.technology.pojo.TechnologyRouting::getProductModelId, productModelId)); if (routings.isEmpty()) { log.warn("产åè§æ ¼[{}]缺å°å·¥èºè·¯çº¿", productModelId); missingIds.add(productModelId); continue; } Long routingId = routings.get(0).getId(); // 2. æ£æ¥å·¥èºè·¯çº¿æ¯å¦æå ³èå·¥åº List<com.ruoyi.technology.pojo.TechnologyRoutingOperation> routingOps = technologyRoutingOperationMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.technology.pojo.TechnologyRoutingOperation>() .eq(com.ruoyi.technology.pojo.TechnologyRoutingOperation::getTechnologyRoutingId, routingId)); if (routingOps.isEmpty()) { log.warn("产åè§æ ¼[{}]å·¥èºè·¯çº¿[{}]缺å°å·¥åº", productModelId, routingId); missingIds.add(productModelId); continue; } // 3. æ£æ¥BOMï¼å¯é使æ´å¥½ï¼ com.ruoyi.technology.pojo.TechnologyRouting routing = routings.get(0); if (routing.getBomId() != null) { List<com.ruoyi.technology.pojo.TechnologyBomStructure> bomStructures = technologyBomStructureMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.technology.pojo.TechnologyBomStructure>() .eq(com.ruoyi.technology.pojo.TechnologyBomStructure::getBomId, routing.getBomId())); if (bomStructures.isEmpty()) { log.warn("产åè§æ ¼[{}]BOM[{}]缺å°äº§åç»æ", productModelId, routing.getBomId()); missingIds.add(productModelId); } } } return missingIds; } /** * ç产计ååå¹¶ä¸å â ç产订åï¼æproductModelIdåç»ï¼ååå·åå¹¶ä¸åï¼ */ private void processProductionCombine(SalesLedger salesLedger, LocalDate planDate) { try { List<ProductionPlan> plans = productionPlanMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionPlan>() .eq(ProductionPlan::getSalesLedgerId, salesLedger.getId()) .and(w -> w.eq(ProductionPlan::getStatus, 0).or().isNull(ProductionPlan::getStatus))); if (plans.isEmpty()) { log.info("éå®å°è´¦[{}]æ å¾ ä¸åç产计å", salesLedger.getSalesContractNo()); return; } // æproductModelIdåç»ï¼ååå·æè½åå¹¶ä¸åï¼productModelId为nullçåç¬é个ä¸å Map<Long, List<ProductionPlan>> grouped = plans.stream() .filter(p -> p.getProductModelId() != null) .collect(Collectors.groupingBy(ProductionPlan::getProductModelId)); for (Map.Entry<Long, List<ProductionPlan>> entry : grouped.entrySet()) { try { List<ProductionPlan> sameModelPlans = entry.getValue(); BigDecimal totalQty = sameModelPlans.stream() .map(p -> Optional.ofNullable(p.getQtyRequired()).orElse(BigDecimal.ZERO)) .reduce(BigDecimal.ZERO, BigDecimal::add); ProductionPlanDto combineDto = new ProductionPlanDto(); combineDto.setIds(sameModelPlans.stream().map(ProductionPlan::getId).collect(Collectors.toList())); combineDto.setTotalAssignedQuantity(totalQty); combineDto.setPlanCompleteTime(planDate.plusDays(ThreadLocalRandom.current().nextInt(3, 7))); productionPlanService.combine(combineDto); // ä¿®æ£ç产订åçplanCompleteTime List<ProductionOrder> orders = productionOrderMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionOrder>() .like(ProductionOrder::getProductionPlanIds, String.valueOf(sameModelPlans.get(0).getId()))); for (ProductionOrder order : orders) { order.setPlanCompleteTime(planDate.plusDays(ThreadLocalRandom.current().nextInt(3, 7))); order.setStartTime(planDate.atStartOfDay()); productionOrderMapper.updateById(order); } log.info("éå®å°è´¦[{}]ç产计åä¸åæå, productModelId={}, è®¡åæ°: {}", salesLedger.getSalesContractNo(), entry.getKey(), sameModelPlans.size()); } catch (Exception e) { log.warn("éå®å°è´¦[{}]ç产计åä¸å失败, productModelId={}: {}", salesLedger.getSalesContractNo(), entry.getKey(), e.getMessage()); } } } catch (Exception e) { log.warn("ç产计åä¸å失败[{}]: {}", salesLedger.getSalesContractNo(), e.getMessage()); } } /** * 颿: æ¥è¯¢ç产订åçBOMé¢ææ¸ åï¼æ£æ¥åºåï¼ä¸è¶³åå èªå¨å ¥åºå®¡æ¹åå颿 */ private void processMaterialPick(SalesLedger salesLedger, LocalDate pickDate) { try { List<ProductionOrder> orders = findOrdersForSalesLedger(salesLedger); if (orders.isEmpty()) { log.info("éå®å°è´¦[{}]æ ç产订åï¼è·³è¿é¢æ", salesLedger.getSalesContractNo()); return; } for (ProductionOrder order : orders) { try { // æ¥è¯¢è®¢åBOMé¢ææ¸ å List<com.ruoyi.production.bean.vo.ProductionOrderPickVo> pickList = productionOrderService.pick(order.getId()); if (pickList == null || pickList.isEmpty()) { log.info("ç产订å[{}]æ é¢ææ¸ å", order.getId()); continue; } // æ£æ¥åºåä¸è¶³çç©æï¼å èªå¨å ¥åº ensureMaterialStock(pickList, pickDate); // éæ°è·åé¢ææ¸ åï¼å ¥åºåæ¹å·ååºåéå·²æ´æ°ï¼ pickList = productionOrderService.pick(order.getId()); if (pickList == null || pickList.isEmpty()) { log.info("ç产订å[{}]éæ°è·åé¢ææ¸ å为空", order.getId()); continue; } // æ§è¡é¢æ List<ProductionOrderPickDto> pickDtoList = new ArrayList<>(); for (com.ruoyi.production.bean.vo.ProductionOrderPickVo pickVo : pickList) { ProductionOrderPickDto pickDto = new ProductionOrderPickDto(); pickDto.setProductionOrderId(order.getId()); pickDto.setProductModelId(pickVo.getProductModelId()); pickDto.setPickQuantity(pickVo.getDemandedQuantity()); pickDto.setPickType((byte) 1); pickDto.setOperationName(pickVo.getOperationName()); pickDto.setTechnologyOperationId(pickVo.getTechnologyOperationId()); pickDto.setDemandedQuantity(pickVo.getDemandedQuantity()); pickDto.setBom(pickVo.getBom()); // 设置æ¹å·ï¼ç¨æ´æ°åçæ¹å·åè¡¨ï¼ if (pickVo.getBatchNoList() != null && !pickVo.getBatchNoList().isEmpty()) { pickDto.setBatchNoList(pickVo.getBatchNoList()); pickDto.setBatchNo(pickVo.getBatchNoList().get(0)); } pickDtoList.add(pickDto); } if (!pickDtoList.isEmpty()) { ProductionOrderPickDto batchDto = new ProductionOrderPickDto(); batchDto.setPickList(pickDtoList); productionOrderPickService.savePick(batchDto); log.info("ç产订å[{}]颿æå, 颿项æ°: {}", order.getId(), pickDtoList.size()); } } catch (Exception e) { log.warn("ç产订å[{}]é¢æå¤±è´¥: {}", order.getId(), e.getMessage()); } } } catch (Exception e) { log.warn("颿æµç¨å¤±è´¥[{}]: {}", salesLedger.getSalesContractNo(), e.getMessage()); } } /** * ç¡®ä¿ç©æåºåå è¶³ï¼ä¸è¶³åå èªå¨å ¥åºå®¡æ¹ */ private void ensureMaterialStock(List<com.ruoyi.production.bean.vo.ProductionOrderPickVo> pickList, LocalDate pickDate) { LocalDateTime pickDateTime = pickDate.atTime(9, 0, 0).plusMinutes(ThreadLocalRandom.current().nextInt(0, 480)); String pickDateStr = pickDate.format(DateTimeFormatter.BASIC_ISO_DATE); for (com.ruoyi.production.bean.vo.ProductionOrderPickVo pickVo : pickList) { BigDecimal demanded = pickVo.getDemandedQuantity() != null ? pickVo.getDemandedQuantity() : BigDecimal.ZERO; BigDecimal stockQty = pickVo.getStockQuantity() != null ? pickVo.getStockQuantity() : BigDecimal.ZERO; BigDecimal shortage = demanded.subtract(stockQty); if (shortage.compareTo(BigDecimal.ZERO) <= 0) { continue; // åºåå è¶³ } // åºåä¸è¶³ï¼èªå¨å ¥åºè¡¥å try { StockInventoryDto dto = new StockInventoryDto(); dto.setProductModelId(pickVo.getProductModelId()); dto.setQualitity(shortage); dto.setRecordType(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_IN.getCode()); dto.setRecordId(0L); stockInventoryService.addStockInRecordOnly(dto); // æ¥æ¾åå建çå ¥åºè®°å½ List<com.ruoyi.stock.pojo.StockInRecord> records = stockInRecordService.list( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>() .eq(com.ruoyi.stock.pojo.StockInRecord::getProductModelId, pickVo.getProductModelId()) .eq(com.ruoyi.stock.pojo.StockInRecord::getApprovalStatus, 0) .orderByDesc(com.ruoyi.stock.pojo.StockInRecord::getId) .last("limit 1")); if (!records.isEmpty()) { com.ruoyi.stock.pojo.StockInRecord record = records.get(0); record.setCreateTime(pickDateTime); record.setBatchNo(fixBatchNoDate(record.getBatchNo(), pickDateStr)); record.setInboundBatches(fixBatchNoDate(record.getInboundBatches(), pickDateStr)); stockInRecordMapper.updateById(record); // 审æ¹éè¿ stockInRecordService.batchApprove(List.of(record.getId()), ReviewStatusEnum.APPROVED.getCode()); log.info("ç©æ[{}]èªå¨å ¥åºå®¡æ¹å®æ, å ¥åºæ°é: {}", pickVo.getProductModelId(), shortage); } } catch (Exception e) { log.warn("ç©æ[{}]èªå¨å ¥åºå¤±è´¥: {}", pickVo.getProductModelId(), e.getMessage()); } } } /** * ç产æ¥å·¥: éåå·¥åé个æ¥å·¥ï¼ä»ç产è§è²ç¨æ·ä¸éæºéåæ¥å·¥äºº */ private void processProductionReport(SalesLedger salesLedger, LocalDate reportDate) { try { List<ProductionOrder> orders = findOrdersForSalesLedger(salesLedger); if (orders.isEmpty()) { log.info("éå®å°è´¦[{}]æ ç产订å", salesLedger.getSalesContractNo()); return; } for (ProductionOrder order : orders) { List<ProductionOperationTask> tasks = productionOperationTaskMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionOperationTask>() .eq(ProductionOperationTask::getProductionOrderId, order.getId()) .orderByAsc(ProductionOperationTask::getId)); for (ProductionOperationTask task : tasks) { if (task.getStatus() != null && task.getStatus() >= 3) continue; // æ¯æ¬¡æ¥å·¥éæºéä¸ä¸ªçäº§ç¨æ· SysUser productionUser = randomProductionUser(); Long userId = productionUser != null ? productionUser.getUserId() : 1L; String userName = productionUser != null ? productionUser.getNickName() : "ç³»ç»"; // æ¥å·¥ ProductionProductMainDto reportDto = new ProductionProductMainDto(); reportDto.setProductionOperationTaskId(task.getId()); reportDto.setQuantity(task.getPlanQuantity()); reportDto.setScrapQty(BigDecimal.ZERO); reportDto.setUserId(userId); reportDto.setUserName(userName); productionProductMainService.addProductMain(reportDto); // ä¿®æ£æ¥å·¥æ¶é´ï¼éæ°ä»DB读åï¼é¿å è¦çaddProductMainæ´æ°çcompleteQuantityï¼ fixProductionReportTimes(task.getId(), reportDate); } // ä¿®æ£çäº§è®¢åæ¶é´ï¼éæ°ä»DB读åï¼é¿å è¦çaddProductMainæ´æ°çcompleteQuantityï¼ fixProductionOrderTimes(order.getId(), reportDate); } log.info("éå®å°è´¦[{}]ç产æ¥å·¥å®æ, è®¢åæ°: {}", salesLedger.getSalesContractNo(), orders.size()); } catch (Exception e) { log.warn("ç产æ¥å·¥å¤±è´¥[{}]: {}", salesLedger.getSalesContractNo(), e.getMessage()); } } /** * æ¥æ¾éå®å°è´¦å ³èçç产订å */ private List<ProductionOrder> findOrdersForSalesLedger(SalesLedger salesLedger) { List<ProductionOrder> orders = new ArrayList<>(); List<ProductionPlan> plans = productionPlanMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionPlan>() .eq(ProductionPlan::getSalesLedgerId, salesLedger.getId())); for (ProductionPlan plan : plans) { List<ProductionOrder> po = productionOrderMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionOrder>() .like(ProductionOrder::getProductionPlanIds, String.valueOf(plan.getId()))); orders.addAll(po); } // å»é return orders.stream() .collect(Collectors.toMap(ProductionOrder::getId, o -> o, (a, b) -> a)) .values().stream().collect(Collectors.toList()); } /** * ä¿®æ£ç产æ¥å·¥ç¸å ³æ¶é´ï¼éæ°ä»DB读åtaskï¼é¿å è¦çaddProductMainå·²æ´æ°çcompleteQuantityï¼ */ private void fixProductionReportTimes(Long taskId, LocalDate reportDate) { try { ProductionOperationTask freshTask = productionOperationTaskMapper.selectById(taskId); if (freshTask != null) { freshTask.setActualStartTime(reportDate); freshTask.setActualEndTime(reportDate); freshTask.setStatus(4); productionOperationTaskMapper.updateById(freshTask); } } catch (Exception e) { log.warn("ä¿®æ£ç产æ¥å·¥æ¶é´å¤±è´¥: {}", e.getMessage()); } } /** * ä¿®æ£çäº§è®¢åæ¶é´ï¼éæ°ä»DB读åorderï¼é¿å è¦çaddProductMainå·²æ´æ°çcompleteQuantityï¼ */ private void fixProductionOrderTimes(Long orderId, LocalDate reportDate) { try { ProductionOrder freshOrder = productionOrderMapper.selectById(orderId); if (freshOrder != null) { freshOrder.setStartTime(reportDate.minusDays(1).atStartOfDay()); freshOrder.setEndTime(reportDate.plusDays(1).atStartOfDay()); freshOrder.setStatus(3); productionOrderMapper.updateById(freshOrder); } } catch (Exception e) { log.warn("ä¿®æ£çäº§è®¢åæ¶é´å¤±è´¥: {}", e.getMessage()); } } /** * éå®è´¨æ£æäº¤ + å ¥åºå®¡æ¹ */ private void processSalesQualityAndStockIn(SalesLedger salesLedger, LocalDate qualityDate) { try { LocalDateTime qualityDateTime = qualityDate.atTime(9, 0, 0) .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480)); // æ¥æææªæäº¤çè´¨æ£åï¼inspectType=1è¿ç¨æ£éª, 2=åºåæ£éªï¼ç±ç产æ¥å·¥çæï¼ List<QualityInspect> allUnsubmitted = qualityInspectService.list( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<QualityInspect>() .eq(QualityInspect::getInspectState, 0) .in(QualityInspect::getInspectType, java.util.Arrays.asList(1, 2))); for (QualityInspect qi : allUnsubmitted) { qualityInspectService.autoSubmit(qi.getId()); qi.setCreateTime(qualityDateTime); qualityInspectMapper.updateById(qi); } log.info("éå®å°è´¦[{}]è´¨æ£æäº¤å®æ, è´¨æ£åæ°: {}", salesLedger.getSalesContractNo(), allUnsubmitted.size()); // å ¥åºå®¡æ¹ï¼å®¡æ¹ææå¾ 审æ¹çå ¥åºè®°å½ LocalDate stockDate = qualityDate.plusDays(ThreadLocalRandom.current().nextInt(0, 3)); LocalDateTime stockDateTime = stockDate.atTime(9, 0, 0) .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480)); String stockDateStr = stockDate.format(DateTimeFormatter.BASIC_ISO_DATE); List<com.ruoyi.stock.pojo.StockInRecord> stockRecords = stockInRecordService.list( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>() .eq(com.ruoyi.stock.pojo.StockInRecord::getApprovalStatus, 0)); List<Long> recordIds = stockRecords.stream() .map(com.ruoyi.stock.pojo.StockInRecord::getId) .collect(Collectors.toList()); if (!recordIds.isEmpty()) { for (com.ruoyi.stock.pojo.StockInRecord sr : stockRecords) { sr.setCreateTime(stockDateTime); sr.setBatchNo(fixBatchNoDate(sr.getBatchNo(), stockDateStr)); sr.setInboundBatches(fixBatchNoDate(sr.getInboundBatches(), stockDateStr)); stockInRecordMapper.updateById(sr); } stockInRecordService.batchApprove(recordIds, ReviewStatusEnum.APPROVED.getCode()); for (com.ruoyi.stock.pojo.StockInRecord sr : stockRecords) { StockInventory si = stockInventoryMapper.selectOne( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<StockInventory>() .eq(StockInventory::getProductModelId, sr.getProductModelId()) .eq(StockInventory::getBatchNo, sr.getBatchNo())); if (si != null) { si.setBatchNo(fixBatchNoDate(si.getBatchNo(), stockDateStr)); stockInventoryMapper.updateById(si); } } log.info("éå®å°è´¦[{}]å ¥åºå®¡æ¹å®æ, å ¥åºè®°å½æ°: {}", salesLedger.getSalesContractNo(), recordIds.size()); } } catch (Exception e) { log.warn("éå®è´¨æ£å ¥åºå¤±è´¥[{}]: {}", salesLedger.getSalesContractNo(), e.getMessage()); } } /** * åè´§ + å货审æ¹éè¿ + åºåºå®¡æ¹ */ private void processSalesShipping(SalesLedger salesLedger, LocalDate shipDate) { try { LocalDateTime shipDateTime = shipDate.atTime(9, 0, 0) .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480)); String shipDateStr = shipDate.format(DateTimeFormatter.BASIC_ISO_DATE); // æ¥æ¾æåºåç产åè§æ ¼ List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SalesLedgerProduct>() .eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId())); List<ShippingProductDetail> details = new ArrayList<>(); for (SalesLedgerProduct slp : products) { StockInventory si = stockInventoryMapper.selectOne( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<StockInventory>() .eq(StockInventory::getProductModelId, slp.getProductModelId()) .gt(StockInventory::getQualitity, BigDecimal.ZERO) .orderByDesc(StockInventory::getId) .last("limit 1")); if (si != null) { ShippingProductDetail detail = new ShippingProductDetail(); detail.setStockInventoryId(si.getId()); detail.setProductModelId(slp.getProductModelId()); detail.setBatchNo(si.getBatchNo()); detail.setQuantity(slp.getQuantity()); details.add(detail); } } if (details.isEmpty()) { log.info("éå®å°è´¦[{}]æ å¯ç¨åºåï¼è·³è¿åè´§", salesLedger.getSalesContractNo()); return; } // å建åè´§å ShippingInfoDto shipDto = new ShippingInfoDto(); shipDto.setSalesLedgerId(salesLedger.getId()); shipDto.setSalesLedgerProductId(products.get(0).getId()); shipDto.setCreateTime(shipDateTime); shipDto.setBatchNoDetailList(details); shippingInfoService.addReq(shipDto); // æ¾å°åè´§åå审æ¹å®ä¾ ShippingInfo shippingInfo = shippingInfoMapper.selectOne( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ShippingInfo>() .eq(ShippingInfo::getShippingNo, shipDto.getShippingNo()) .last("limit 1")); if (shippingInfo != null) { shippingInfo.setCreateTime(shipDateTime); shippingInfo.setShippingDate(java.sql.Date.valueOf(shipDate)); // æ ¹æ®å®¢æ·å°åçæå货车çå· shippingInfo.setShippingCarNumber(generateCarNumber(salesLedger.getCustomerName())); shippingInfoMapper.updateById(shippingInfo); // å货审æ¹èªå¨éè¿ ApprovalInstance shipApproval = approvalInstanceMapper.selectOne( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalInstance>() .eq(ApprovalInstance::getBusinessId, shippingInfo.getId()) .eq(ApprovalInstance::getBusinessType, 7L) .eq(ApprovalInstance::getDeleted, 0) .orderByDesc(ApprovalInstance::getId) .last("limit 1")); if (shipApproval != null) { LocalDate shipApproveDate = shipDate.plusDays(ThreadLocalRandom.current().nextInt(0, 3)); LocalDateTime shipApproveDateTime = shipApproveDate.atTime(9, 0, 0) .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480)); approvalInstanceService.autoApprove(shipApproval.getId()); fixApprovalTimes(shipApproval.getId(), shipApproveDateTime); shippingInfo.setStatus("å·²åè´§"); shippingInfo.setShippingDate(java.sql.Date.valueOf(shipApproveDate)); shippingInfoMapper.updateById(shippingInfo); } // åºåºå®¡æ¹ LocalDate outDate = shipDate.plusDays(ThreadLocalRandom.current().nextInt(0, 3)); LocalDateTime outDateTime = outDate.atTime(9, 0, 0) .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480)); String outDateStr = outDate.format(DateTimeFormatter.BASIC_ISO_DATE); List<StockOutRecord> outRecords = stockOutRecordMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<StockOutRecord>() .eq(StockOutRecord::getRecordId, shippingInfo.getId()) .eq(StockOutRecord::getRecordType, String.valueOf(StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode()))); List<Long> outIds = new ArrayList<>(); for (StockOutRecord sr : outRecords) { if (sr.getApprovalStatus() == null || sr.getApprovalStatus() == 0 || sr.getApprovalStatus() == 3) { sr.setCreateTime(outDateTime); sr.setOutboundBatches(fixBatchNoDate(sr.getOutboundBatches(), outDateStr)); sr.setBatchNo(fixBatchNoDate(sr.getBatchNo(), outDateStr)); stockOutRecordMapper.updateById(sr); outIds.add(sr.getId()); } } if (!outIds.isEmpty()) { // åºåºå®¡æ¹éè¿ï¼èµ°æ£å¼å®¡æ¹æµç¨ï¼å é¨ä¼æ£ååºåï¼ stockOutRecordService.batchApprove(outIds, ReviewStatusEnum.APPROVED.getCode()); log.info("éå®å°è´¦[{}]åºåºå®¡æ¹å®æ, åºåºè®°å½æ°: {}", salesLedger.getSalesContractNo(), outIds.size()); } } log.info("éå®å°è´¦[{}]åè´§æµç¨å®æ", salesLedger.getSalesContractNo()); } catch (Exception e) { log.warn("éå®åè´§æµç¨å¤±è´¥[{}]: {}", salesLedger.getSalesContractNo(), e.getMessage()); } } private ModuleSummary createPurchaseLedgers(List<JSONObject> items, Map<String, Long> supplierNameToId, String additionalInfo, String dateStart, String dateEnd) { // æ¯å¦éè¦è´¨æ£ï¼ä»è¡¥å ä¿¡æ¯å¤æï¼é»è®¤ä¸éè¦ boolean needQualityInspect = additionalInfo != null && (additionalInfo.contains("è´¨æ£") || additionalInfo.contains("éè¦æ£éª")); int success = 0, fail = 0; for (JSONObject item : items) { try { @@ -371,11 +1243,22 @@ dto.setProjectName(item.getString("projectName")); dto.setContractAmount(item.getBigDecimal("contractAmount")); dto.setPaymentMethod(item.getString("paymentMethod")); if (item.containsKey("entryDate")) { dto.setEntryDate(java.sql.Date.valueOf(item.getString("entryDate"))); String entryDateStr = item.getString("entryDate"); LocalDate entryDate = null; if (item.containsKey("entryDate") && entryDateStr != null && entryDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) { entryDate = LocalDate.parse(entryDateStr); dto.setEntryDate(java.sql.Date.valueOf(entryDateStr)); } else { dto.setEntryDate(java.sql.Date.valueOf(dateStart)); } if (item.containsKey("executionDate")) { dto.setExecutionDate(java.sql.Date.valueOf(item.getString("executionDate"))); String execDateStr = item.getString("executionDate"); if (execDateStr != null && execDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) { dto.setExecutionDate(java.sql.Date.valueOf(execDateStr)); } else { dto.setExecutionDate(java.sql.Date.valueOf(dateStart)); } } JSONArray productData = item.getJSONArray("productData"); if (productData != null) { @@ -391,6 +1274,8 @@ slp.setTaxRate(pd.getBigDecimal("taxRate")); slp.setUnit(pd.getString("unit")); slp.setType(2); // æ¯å¦è´¨æ£ï¼ä»è¡¥å ä¿¡æ¯å¤æï¼é»è®¤ä¸éè¦ slp.setIsChecked(needQualityInspect); if (pd.containsKey("taxExclusiveTotalPrice")) { slp.setTaxExclusiveTotalPrice(pd.getBigDecimal("taxExclusiveTotalPrice")); } else if (pd.getBigDecimal("taxInclusiveTotalPrice") != null && pd.getBigDecimal("taxRate") != null) { @@ -406,17 +1291,333 @@ dto.setProductData(products); } purchaseLedgerService.addOrEditPurchase(dto); // éè¿ååå·æ¾å°åå建çéè´å°è´¦ PurchaseLedger savedLedger = purchaseLedgerService.getOne( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<PurchaseLedger>() .eq(PurchaseLedger::getPurchaseContractNumber, dto.getPurchaseContractNumber()) .last("limit 1")); if (savedLedger != null) { // èµ°å®æ´æµç¨ï¼å®¡æ ¸éè¿ â è´¨æ£(å¯é) â å ¥åº + å ¥åºå®¡æ ¸éè¿ processPurchaseFullFlow(savedLedger, needQualityInspect, entryDate, dateEnd); } success++; } catch (Exception e) { log.warn("å建éè´å°è´¦å¤±è´¥: {}", e.getMessage()); log.warn("å建éè´å°è´¦å¤±è´¥: {}", e.getMessage(), e); fail++; } } return summary("purchase", "éè´å°è´¦", items.size(), success, fail); } /** * éè´å®æ´æµç¨: å®¡æ ¸éè¿ â è´¨æ£(å¯é) â å ¥åºå®¡æ ¸éè¿ * åç¯èæ¶é´ä»¥éè´å½å ¥æ¥æä¸ºåºåï¼å¶å°æ¨è¿1-3天 */ private void processPurchaseFullFlow(PurchaseLedger purchaseLedger, boolean needQualityInspect, LocalDate entryDate, String dateEnd) { try { // åºåæ¥æï¼éè´å½å ¥æ¥æï¼ä¸ºç©ºåç¨å½å¤© LocalDate baseDate = entryDate != null ? entryDate : LocalDate.now(); // å®¡æ¹æ¶é´ï¼åºäºå½å ¥æ¥æï¼éæºæ¨0-3天 LocalDate approveDate = baseDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4)); LocalDateTime approveDateTime = approveDate.atTime(9, 0, 0) .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480)); // 1. 审æ¹èªå¨éè¿ ApprovalInstance approvalInstance = approvalInstanceMapper.selectOne( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalInstance>() .eq(ApprovalInstance::getBusinessId, purchaseLedger.getId()) .eq(ApprovalInstance::getBusinessType, 5L) .eq(ApprovalInstance::getDeleted, 0) .orderByDesc(ApprovalInstance::getId) .last("limit 1")); if (approvalInstance != null) { approvalInstanceService.autoApprove(approvalInstance.getId()); // ä¿®æ£å®¡æ¹ç¸å ³æ¶é´ä¸ºéè´å½å ¥æ¥æèå´ fixApprovalTimes(approvalInstance.getId(), approveDateTime); log.info("éè´å°è´¦[{}]审æ¹éè¿, å®¡æ¹æ¥æ: {}", purchaseLedger.getPurchaseContractNumber(), approveDate); } // 2. è´¨æ£æµç¨ï¼å¦æéè¦è´¨æ£ï¼ if (needQualityInspect) { // è´¨æ£æ¶é´ï¼å®¡æ¹ä¹å忍0-3天 LocalDate inspectDate = approveDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4)); processQualityInspect(purchaseLedger, inspectDate); } // 3. å ¥åºå®¡æ¹éè¿ // å ¥åºæ¶é´ï¼è´¨æ£æ¶é´ï¼æè´¨æ£ï¼æå®¡æ¹æ¶é´ä¹å忍0-3天 LocalDate stockBaseDate = needQualityInspect ? approveDate.plusDays(ThreadLocalRandom.current().nextInt(1, 4)) : approveDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4)); processStockInApprove(purchaseLedger, stockBaseDate); } catch (Exception e) { log.warn("éè´å®æ´æµç¨å¤ç失败[{}]: {}", purchaseLedger.getPurchaseContractNumber(), e.getMessage()); } } /** * ä¿®æ£å®¡æ¹å®ä¾åå ³èèç¹ãä»»å¡ãè®°å½çæ¶é´ */ private void fixApprovalTimes(Long instanceId, LocalDateTime dateTime) { try { // æ´æ°å®¡æ¹å®ä¾çfinishTimeåcreateTime ApprovalInstance instance = approvalInstanceMapper.selectById(instanceId); if (instance != null) { instance.setFinishTime(dateTime); instance.setCreateTime(dateTime.minusHours(1)); approvalInstanceMapper.updateById(instance); } // æ´æ°å®¡æ¹å®ä¾èç¹çfinishTime List<ApprovalInstanceNode> nodes = approvalInstanceNodeMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalInstanceNode>() .eq(ApprovalInstanceNode::getInstanceId, instanceId)); for (ApprovalInstanceNode node : nodes) { node.setFinishTime(dateTime); node.setCreateTime(dateTime.minusHours(1)); approvalInstanceNodeMapper.updateById(node); } // æ´æ°å®¡æ¹ä»»å¡çcreateTime List<ApprovalTask> tasks = approvalTaskMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalTask>() .eq(ApprovalTask::getInstanceId, instanceId)); for (ApprovalTask task : tasks) { task.setCreateTime(dateTime.minusMinutes(30)); approvalTaskMapper.updateById(task); } // æ´æ°å®¡æ¹è®°å½çcreateTime List<ApprovalRecord> records = approvalRecordMapper.selectList( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalRecord>() .eq(ApprovalRecord::getInstanceId, instanceId)); for (ApprovalRecord record : records) { record.setCreateTime(dateTime.minusMinutes(10)); approvalRecordMapper.updateById(record); } } catch (Exception e) { log.warn("ä¿®æ£å®¡æ¹æ¶é´å¤±è´¥: {}", e.getMessage()); } } /** * è´¨æ£: æ¾å°éè´å ³èçè´¨æ£åï¼èªå¨æäº¤ä¸ºåæ ¼ */ private void processQualityInspect(PurchaseLedger purchaseLedger, LocalDate inspectDate) { try { LocalDateTime inspectDateTime = inspectDate.atTime(9, 0, 0) .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480)); List<QualityInspect> inspectList = qualityInspectService.list( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<QualityInspect>() .eq(QualityInspect::getPurchaseLedgerId, purchaseLedger.getId())); for (QualityInspect qi : inspectList) { if (qi.getInspectState() == null || qi.getInspectState() == 0) { qualityInspectService.autoSubmit(qi.getId()); // ä¿®æ£è´¨æ£æ¶é´ qi.setCreateTime(inspectDateTime); qualityInspectMapper.updateById(qi); log.info("éè´å°è´¦[{}]è´¨æ£å[{}]èªå¨æäº¤åæ ¼, è´¨æ£æ¥æ: {}", purchaseLedger.getPurchaseContractNumber(), qi.getId(), inspectDate); } } } catch (Exception e) { log.warn("è´¨æ£æµç¨å¤ç失败[{}]: {}", purchaseLedger.getPurchaseContractNumber(), e.getMessage()); } } /** * å ¥åºå®¡æ ¸: æ¾å°å ¥åºè®°å½å¹¶å®¡æ¹éè¿ï¼å¹¶ä¿®æ£æ¶é´ä¸æ¹å·æ¥æ */ private void processStockInApprove(PurchaseLedger purchaseLedger, LocalDate stockDate) { try { LocalDateTime stockDateTime = stockDate.atTime(9, 0, 0) .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480)); String stockDateStr = stockDate.format(java.time.format.DateTimeFormatter.BASIC_ISO_DATE); List<com.ruoyi.stock.pojo.StockInRecord> stockRecords = stockInRecordService.list( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>() .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordId, purchaseLedger.getId()) .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordType, String.valueOf(com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode()))); if (stockRecords.isEmpty()) { stockRecords = stockInRecordService.list( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>() .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordId, purchaseLedger.getId()) .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordType, String.valueOf(com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode()))); } for (QualityInspect qi : qualityInspectService.list( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<QualityInspect>() .eq(QualityInspect::getPurchaseLedgerId, purchaseLedger.getId()))) { List<com.ruoyi.stock.pojo.StockInRecord> qiRecords = stockInRecordService.list( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>() .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordId, qi.getId())); stockRecords.addAll(qiRecords); } stockRecords = stockRecords.stream() .collect(Collectors.toMap(com.ruoyi.stock.pojo.StockInRecord::getId, r -> r, (a, b) -> a)) .values().stream().collect(Collectors.toList()); if (!stockRecords.isEmpty()) { List<Long> recordIds = stockRecords.stream() .filter(r -> r.getApprovalStatus() == null || r.getApprovalStatus() == 0) .map(com.ruoyi.stock.pojo.StockInRecord::getId) .collect(Collectors.toList()); if (!recordIds.isEmpty()) { // å ä¿®æ£å ¥åºè®°å½çcreateTime忹巿¥æï¼batchApproveå é¨ä¼ç¨batchNoå建StockInventoryï¼ for (Long recordId : recordIds) { com.ruoyi.stock.pojo.StockInRecord sr = stockInRecordMapper.selectById(recordId); if (sr != null) { sr.setCreateTime(stockDateTime); sr.setBatchNo(fixBatchNoDate(sr.getBatchNo(), stockDateStr)); String s = OrderUtils.countTodayByCreateTime(stockInRecordMapper, "RK", "inbound_batches", stockDateTime); sr.setInboundBatches(s); stockInRecordMapper.updateById(sr); } } stockInRecordService.batchApprove(recordIds, ReviewStatusEnum.APPROVED.getCode()); log.info("éè´å°è´¦[{}]å ¥åºå®¡æ¹éè¿, å ¥åºæ¥æ: {}, å ¥åºè®°å½æ°: {}", purchaseLedger.getPurchaseContractNumber(), stockDate, recordIds.size()); } } } catch (Exception e) { log.warn("å ¥åºå®¡æ¹å¤±è´¥[{}]: {}", purchaseLedger.getPurchaseContractNumber(), e.getMessage()); } } /** * æ¿æ¢æ¹å·ä¸çæ¥æé¨åï¼yyyyMMdd â æå®æ¥æï¼ */ /** * æ ¹æ®å®¢æ·åç§°æ¥å°åï¼æ¨æç份ç®ç§°çæè½¦çå· * æ ¼å¼: ç份ç®ç§° + 忝 + 5ä½éæºæ°å忝, å¦ èA12345 */ private String generateCarNumber(String customerName) { // ç份ç®ç§°å°åå¸åæ¯çå¸¸è§æ å° Map<String, String[]> provinceCityMap = new HashMap<>(); provinceCityMap.put("京", new String[]{"A", "B", "C", "E", "F", "G"}); provinceCityMap.put("沪", new String[]{"A", "B", "D", "E", "F"}); provinceCityMap.put("粤", new String[]{"A", "B", "E", "F", "G", "H", "J", "K"}); provinceCityMap.put("è", new String[]{"A", "B", "E", "F", "G", "H", "J", "K", "L", "M"}); provinceCityMap.put("æµ", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L"}); provinceCityMap.put("é²", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "Y"}); provinceCityMap.put("豫", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "U"}); provinceCityMap.put("å·", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}); provinceCityMap.put("æ¸", new String[]{"A", "B", "C", "D"}); provinceCityMap.put("é", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S"}); provinceCityMap.put("æ¹", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "S"}); provinceCityMap.put("é½", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K"}); provinceCityMap.put("èµ£", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M"}); provinceCityMap.put("ç", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R", "S"}); provinceCityMap.put("å", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "R", "T"}); provinceCityMap.put("è¾½", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P"}); provinceCityMap.put("å", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K"}); provinceCityMap.put("é»", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R"}); provinceCityMap.put("æ", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M"}); provinceCityMap.put("é", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "V"}); provinceCityMap.put("æ¡", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R"}); provinceCityMap.put("äº", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S"}); provinceCityMap.put("è´µ", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J"}); provinceCityMap.put("ç", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P"}); provinceCityMap.put("ç¼", new String[]{"A", "B", "C", "D", "E", "F"}); provinceCityMap.put("å®", new String[]{"A", "B", "C", "D", "E"}); provinceCityMap.put("é", new String[]{"A", "B", "C", "D", "E", "F", "G", "H"}); provinceCityMap.put("è", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J"}); provinceCityMap.put("è", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M"}); provinceCityMap.put("æ°", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R"}); provinceCityMap.put("æ´¥", new String[]{"A", "B", "C", "E", "F", "G", "H", "J", "K", "L", "M", "N", "Q", "R"}); // å°åå ³é®è¯å°ç份ç®ç§°çæ å° Map<String, String> addressToProvince = new HashMap<>(); addressToProvince.put("å京", "京"); addressToProvince.put("䏿µ·", "沪"); addressToProvince.put("广å·", "粤"); addressToProvince.put("æ·±å³", "粤"); addressToProvince.put("ä¸è", "粤"); addressToProvince.put("ä½å±±", "粤"); addressToProvince.put("å京", "è"); addressToProvince.put("èå·", "è"); addressToProvince.put("æ é¡", "è"); addressToProvince.put("åé", "è"); addressToProvince.put("常å·", "è"); addressToProvince.put("å¾å·", "è"); addressToProvince.put("æå·", "æµ"); addressToProvince.put("宿³¢", "æµ"); addressToProvince.put("温å·", "æµ"); addressToProvince.put("åå ´", "æµ"); addressToProvince.put("æµå", "é²"); addressToProvince.put("éå²", "é²"); addressToProvince.put("éå·", "豫"); addressToProvince.put("æé½", "å·"); addressToProvince.put("éåº", "æ¸"); addressToProvince.put("æ¦æ±", "é"); addressToProvince.put("é¿æ²", "æ¹"); addressToProvince.put("ç¦å·", "é½"); addressToProvince.put("å¦é¨", "é½"); addressToProvince.put("åæ", "èµ£"); addressToProvince.put("åè¥", "ç"); addressToProvince.put("ç³å®¶åº", "å"); addressToProvince.put("æ²é³", "è¾½"); addressToProvince.put("大è¿", "è¾½"); addressToProvince.put("é¿æ¥", "å"); addressToProvince.put("åå°æ»¨", "é»"); addressToProvince.put("太å", "æ"); addressToProvince.put("西å®", "é"); addressToProvince.put("åå®", "æ¡"); addressToProvince.put("ææ", "äº"); addressToProvince.put("è´µé³", "è´µ"); addressToProvince.put("å °å·", "ç"); addressToProvince.put("æµ·å£", "ç¼"); addressToProvince.put("é¶å·", "å®"); addressToProvince.put("西å®", "é"); addressToProvince.put("æè¨", "è"); addressToProvince.put("å¼å浩ç¹", "è"); addressToProvince.put("ä¹é²æ¨é½", "æ°"); addressToProvince.put("天津", "æ´¥"); // çåæ å° addressToProvince.put("æ±è", "è"); addressToProvince.put("æµæ±", "æµ"); addressToProvince.put("å±±ä¸", "é²"); addressToProvince.put("æ²³å", "豫"); addressToProvince.put("åå·", "å·"); addressToProvince.put("æ¹å", "é"); addressToProvince.put("æ¹å", "æ¹"); addressToProvince.put("ç¦å»º", "é½"); addressToProvince.put("æ±è¥¿", "èµ£"); addressToProvince.put("å®å¾½", "ç"); addressToProvince.put("æ²³å", "å"); addressToProvince.put("è¾½å®", "è¾½"); addressToProvince.put("åæ", "å"); addressToProvince.put("é»é¾æ±", "é»"); addressToProvince.put("山西", "æ"); addressToProvince.put("é西", "é"); addressToProvince.put("广ä¸", "粤"); addressToProvince.put("广西", "æ¡"); addressToProvince.put("äºå", "äº"); addressToProvince.put("è´µå·", "è´µ"); addressToProvince.put("çè", "ç"); addressToProvince.put("æµ·å", "ç¼"); addressToProvince.put("å®å¤", "å®"); addressToProvince.put("éæµ·", "é"); addressToProvince.put("西è", "è"); addressToProvince.put("å èå¤", "è"); addressToProvince.put("æ°ç", "æ°"); String province = "è"; // é»è®¤æ±è // å°è¯ä»å®¢æ·å°åæ¨æç份 if (customerName != null) { try { Customer customer = customerService.getOne( new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Customer>() .eq(Customer::getCustomerName, customerName) .last("limit 1")); if (customer != null && customer.getCompanyAddress() != null) { String addr = customer.getCompanyAddress(); for (Map.Entry<String, String> e : addressToProvince.entrySet()) { if (addr.contains(e.getKey())) { province = e.getValue(); break; } } } } catch (Exception e) { log.debug("æ¥å®¢æ·å°å失败: {}", e.getMessage()); } } // çæè½¦çå·: ç份ç®ç§° + åå¸åæ¯ + 5ä½éæºå符(æ°å+大å忝) String[] cities = provinceCityMap.getOrDefault(province, new String[]{"A", "B", "C"}); String city = cities[ThreadLocalRandom.current().nextInt(cities.length)]; String chars = "ABCDEFGHJKLMNPQRSTUVWXYZ0123456789"; StringBuilder suffix = new StringBuilder(); for (int i = 0; i < 5; i++) { suffix.append(chars.charAt(ThreadLocalRandom.current().nextInt(chars.length()))); } return province + city + suffix; } private String fixBatchNoDate(String batchNo, String newDate) { if (batchNo == null || batchNo.length() < 8) { return batchNo; } // æ¹å·æ ¼å¼: yyyyMMdd-产åç¼ç -NNN String prefix = batchNo.substring(0, 8); if (prefix.matches("\\d{8}")) { return newDate + batchNo.substring(8); } return batchNo; } private ModuleSummary createProductionPlans(List<JSONObject> items) { int success = 0, fail = 0; List<ProductionPlan> createdPlans = new ArrayList<>(); for (JSONObject item : items) { try { ProductionPlan plan = new ProductionPlan(); @@ -425,18 +1626,48 @@ plan.setSource(item.getString("source")); plan.setRemark(item.getString("remark")); if (item.containsKey("requiredDate")) { plan.setRequiredDate(LocalDate.parse(item.getString("requiredDate"))); String dateStr = item.getString("requiredDate"); if (dateStr != null && dateStr.matches("\\d{4}-\\d{2}-\\d{2}")) { plan.setRequiredDate(LocalDate.parse(dateStr)); } } if (item.containsKey("promisedDeliveryDate")) { plan.setPromisedDeliveryDate(LocalDate.parse(item.getString("promisedDeliveryDate"))); String dateStr = item.getString("promisedDeliveryDate"); if (dateStr != null && dateStr.matches("\\d{4}-\\d{2}-\\d{2}")) { plan.setPromisedDeliveryDate(LocalDate.parse(dateStr)); } } productionPlanService.save(plan); createdPlans.add(plan); success++; } catch (Exception e) { log.warn("å建ç产计å失败: {}", e.getMessage()); fail++; } } // æproductModelIdåç»ï¼èªå¨åå¹¶ä¸å Map<Long, List<ProductionPlan>> grouped = createdPlans.stream() .filter(p -> p.getProductModelId() != null) .collect(Collectors.groupingBy(ProductionPlan::getProductModelId)); for (Map.Entry<Long, List<ProductionPlan>> entry : grouped.entrySet()) { try { List<Long> planIds = entry.getValue().stream().map(ProductionPlan::getId).collect(Collectors.toList()); BigDecimal totalQty = entry.getValue().stream() .map(ProductionPlan::getQtyRequired) .reduce(BigDecimal.ZERO, BigDecimal::add); ProductionPlanDto combineDto = new ProductionPlanDto(); combineDto.setIds(planIds); combineDto.setTotalAssignedQuantity(totalQty); combineDto.setPlanCompleteTime(LocalDate.now().plusDays(ThreadLocalRandom.current().nextInt(3, 10))); productionPlanService.combine(combineDto); log.info("ç产计åèªå¨ä¸åæå, productModelId={}, è®¡åæ°: {}, ä¸åæ°é: {}", entry.getKey(), planIds.size(), totalQty); } catch (Exception e) { log.warn("ç产计åèªå¨ä¸å失败, productModelId={}: {}", entry.getKey(), e.getMessage()); } } return summary("production", "ç产计å", items.size(), success, fail); } @@ -450,7 +1681,10 @@ order.setProductModelId(item.getLong("productModelId")); order.setQuantity(item.getBigDecimal("quantity")); if (item.containsKey("planCompleteTime")) { order.setPlanCompleteTime(LocalDate.parse(item.getString("planCompleteTime"))); String dateStr = item.getString("planCompleteTime"); if (dateStr != null && dateStr.matches("\\d{4}-\\d{2}-\\d{2}")) { order.setPlanCompleteTime(LocalDate.parse(dateStr)); } } productionOrderService.saveProductionOrder(order); success++; src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java
@@ -21,6 +21,7 @@ import com.ruoyi.procurementrecord.service.ReturnSaleProductService; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.sales.mapper.SalesLedgerMapper; import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.sales.pojo.ShippingInfo; import com.ruoyi.sales.service.ShippingInfoService; import lombok.RequiredArgsConstructor; @@ -100,31 +101,42 @@ public boolean handle(Long returnManagementId) { ReturnManagement byId = this.getById(returnManagementId); List<ReturnSaleProductDto> list = returnSaleProductService.listReturnSaleProduct(returnManagementId); byId.setStatus(1); byId.setSettler(SecurityUtils.getLoginUser().getNickName()); updateById(byId); SalesRefundAmountOrderDto salesRefundAmountOrder = new SalesRefundAmountOrderDto(); salesRefundAmountOrder.setReturnManagementId(returnManagementId); salesRefundAmountOrder.setStatus(0); salesRefundAmountOrder.setCreateTime(byId.getCreateTime()); salesRefundAmountOrder.setCreateUserId(SecurityUtils.getUserId()); BigDecimal bigDecimal = new BigDecimal(0); // 1. è®¡ç®æ£ç¡®ç鿬¾æ»é¢ï¼éé¢=åä»·Ãæ°éï¼ BigDecimal totalRefund = BigDecimal.ZERO; for (ReturnSaleProductDto returnSaleProduct : list) { bigDecimal = bigDecimal.add(returnSaleProduct.getPrice()); salesRefundAmountOrder.setRefundedAmount(new BigDecimal(0)); BigDecimal itemAmount = returnSaleProduct.getAmount() != null ? returnSaleProduct.getAmount() : BigDecimal.ZERO; totalRefund = totalRefund.add(itemAmount); // æ¯å¦æè´¨éé®é¢ if (returnSaleProduct.getIsQuality() == 1) { // æè´¨éé®é¢ï¼å ¥ä¸åæ ¼åº(å¸¦æ¹æ¬¡) stockUtils.addUnStockWithBatchNo(returnSaleProduct.getProductModelId(),returnSaleProduct.getNum(), StockInQualifiedRecordTypeEnum.RETURN_UNSTOCK_IN.getCode(),returnSaleProduct.getId(),returnSaleProduct.getBatchNo()); }else{ // æ è´¨éé®é¢ï¼å ¥åæ ¼åº(å¸¦æ¹æ¬¡) stockUtils.addStockWithBatchNo(returnSaleProduct.getProductModelId(),returnSaleProduct.getNum(), StockInQualifiedRecordTypeEnum.RETURN_HE_IN.getCode(),returnSaleProduct.getId(),returnSaleProduct.getBatchNo()); } } salesRefundAmountOrder.setRefundAmount(bigDecimal); salesRefundAmountOrder.setNotRefundedAmount(salesRefundAmountOrder.getRefundedAmount()); // 忹鿬¾ // salesRefundAmountOrderService.addSalesRefundAmountOrderDto(salesRefundAmountOrder); // 2. æ´æ°éè´§åç¶æå鿬¾æ»é¢ byId.setStatus(1); byId.setSettler(SecurityUtils.getLoginUser().getNickName()); byId.setRefundAmount(totalRefund); updateById(byId); // 3. æ´æ°éå®å°è´¦çå®é ååéé¢ if (byId.getShippingId() != null) { ShippingInfo shippingInfo = shippingInfoService.getById(byId.getShippingId()); if (shippingInfo != null && shippingInfo.getSalesLedgerId() != null) { SalesLedger salesLedger = salesLedgerMapper.selectById(shippingInfo.getSalesLedgerId()); if (salesLedger != null && salesLedger.getContractAmount() != null) { BigDecimal baseAmount = salesLedger.getNetContractAmount() != null ? salesLedger.getNetContractAmount() : salesLedger.getContractAmount(); salesLedger.setNetContractAmount(baseAmount.subtract(totalRefund)); salesLedgerMapper.updateById(salesLedger); } } } return true; } src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
@@ -20,6 +20,7 @@ import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.Collections; import java.util.List; @Component @RequiredArgsConstructor @@ -183,15 +184,25 @@ //å é¤åºåºè®°å½ public void deleteStockOutRecord(Long recordId, String recordType) { StockOutRecord one = stockOutRecordService.getOne(new QueryWrapper<StockOutRecord>() List<StockOutRecord> records = stockOutRecordService.list(new QueryWrapper<StockOutRecord>() .lambda().eq(StockOutRecord::getRecordId, recordId) .eq(StockOutRecord::getRecordType, recordType), false); if (ObjectUtils.isNotEmpty(one)) { if (ReviewStatusEnum.APPROVED.getCode().equals(one.getApprovalStatus())) { stockOutRecordService.batchDelete(Collections.singletonList(one.getId())); } else { stockOutRecordService.removeById(one.getId()); .eq(StockOutRecord::getRecordType, recordType)); if (ObjectUtils.isEmpty(records)) { return; } List<Long> approvedIds = records.stream() .filter(one -> ReviewStatusEnum.APPROVED.getCode().equals(one.getApprovalStatus())) .map(StockOutRecord::getId) .toList(); List<Long> pendingIds = records.stream() .filter(one -> !ReviewStatusEnum.APPROVED.getCode().equals(one.getApprovalStatus())) .map(StockOutRecord::getId) .toList(); if (!approvedIds.isEmpty()) { stockOutRecordService.batchDelete(approvedIds); } if (!pendingIds.isEmpty()) { stockOutRecordService.removeByIds(pendingIds); } } src/main/java/com/ruoyi/production/bean/dto/ProductionPlanImportDto.java
@@ -36,10 +36,6 @@ @Excel(name = "éæ±æ°é") private BigDecimal qtyRequired; @Schema(description = "æ¥æº éå®/å é¨") @Excel(name = "æ¥æº éå®/å é¨") private String source; @Schema(description = "æ¿è¯ºæ¥æ") @Excel(name = "æ¿è¯ºæ¥æ") private LocalDate promisedDeliveryDate; src/main/java/com/ruoyi/production/enums/ProductOrderStatusEnum.java
@@ -17,7 +17,8 @@ WAIT(1, "å¾ å¼å§"), RUNNING(2, "è¿è¡ä¸"), FINISHED(3, "已宿"), CANCEL(4, "已忶"); //CANCEL(4, "已忶"), END(5, "å·²ç»æ"); private final Integer code; private final String desc; @@ -43,10 +44,10 @@ } /** * 夿æ¯å¦å 许å é¤ï¼4ï¼ * 夿æ¯å¦å 许å é¤ï¼1ï¼ */ public static boolean canDelete(Integer code) { return WAIT.getCode().equals(code) || CANCEL.getCode().equals(code); return WAIT.getCode().equals(code); } /** @@ -57,9 +58,9 @@ } /** * 夿æ¯å¦å·²å¼å§ç产ï¼2ã3ï¼ * 夿æ¯å¦å·²å¼å§ç产ï¼2ã3ã5ï¼ */ public static boolean isStarted(Integer code) { return RUNNING.getCode().equals(code) || FINISHED.getCode().equals(code); return RUNNING.getCode().equals(code) || FINISHED.getCode().equals(code) || END.getCode().equals(code); } } src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationParamServiceImpl.java
@@ -161,11 +161,21 @@ // æ£æ¥æ°æ®æ¯å¦éå¤ï¼é¿å éå¤ä¿å boolean duplicate = productionOrderRoutingOperationParamMapper.selectCount( Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery() .eq(ProductionOrderRoutingOperationParam::getProductionOrderId, item.getProductionOrderId()) .isNull(ProductionOrderRoutingOperationParam::getProductionProductMainId) .eq(ProductionOrderRoutingOperationParam::getProductionOrderRoutingOperationId, item.getProductionOrderRoutingOperationId()) .eq(item.getTechnologyRoutingOperationParamId() != null, ProductionOrderRoutingOperationParam::getTechnologyRoutingOperationParamId, item.getTechnologyRoutingOperationParamId()) .eq(item.getTechnologyRoutingOperationParamId() == null && item.getParamCode() != null, .eq(item.getTechnologyRoutingOperationParamId() == null && item.getTechnologyOperationParamId() != null, ProductionOrderRoutingOperationParam::getTechnologyOperationParamId, item.getTechnologyOperationParamId()) .eq(item.getTechnologyRoutingOperationParamId() == null && item.getTechnologyOperationParamId() == null && item.getParamId() != null, ProductionOrderRoutingOperationParam::getParamId, item.getParamId()) .eq(item.getTechnologyRoutingOperationParamId() == null && item.getTechnologyOperationParamId() == null && item.getParamId() == null && item.getParamCode() != null, ProductionOrderRoutingOperationParam::getParamCode, item.getParamCode()) .ne(item.getId() != null, ProductionOrderRoutingOperationParam::getId, item.getId()) ) > 0; src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -1134,7 +1134,7 @@ @Override public int updateOrder(ProductionOrderDto productionOrderDto) { // æ´æ°ç产订åä¸»æ°æ® productionOrderDto.setStatus(5); productionOrderDto.setStatus(ProductOrderStatusEnum.END.getCode()); return baseMapper.updateById(productionOrderDto); } } src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java
@@ -311,7 +311,7 @@ BeanUtils.copyProperties(dto, entity); entity.setProductModelId(resolveProductModelId(dto, i + 2, allModels, productNameById)); entity.setStatus(PLAN_STATUS_WAIT); entity.setSource(StringUtils.isNotEmpty(dto.getSource()) ? StringUtils.trim(dto.getSource()) : "å é¨"); entity.setSource("å é¨"); entity.setQuantityIssued(BigDecimal.ZERO); entity.setCreateTime(now); entity.setUpdateTime(now); src/main/java/com/ruoyi/project/system/domain/SysUser.java
@@ -129,6 +129,12 @@ @TableField(exist = false) private String deptNames; /** * è§è²åç§° */ @TableField(exist = false) private String roleNames; public Long getCurrentDeptId() { return currentDeptId; } @@ -369,6 +375,14 @@ this.deptNames = deptNames; } public String getRoleNames() { return roleNames; } public void setRoleNames(String roleNames) { this.roleNames = roleNames; } public Long getDeptId() { return deptId; } src/main/java/com/ruoyi/project/system/mapper/SysUserMapper.java
@@ -155,5 +155,10 @@ List<Long> getUserByRole(@Param("role") String role); /** * æ¥è¯¢æææ´»è·ç¨æ·ï¼å«é¨é¨åç§°åè§è²åç§°ï¼ */ List<SysUser> selectUserListWithDetail(); List<Long> getUserByPerms(@Param("perms") List<String> perms); } src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
@@ -88,7 +88,7 @@ /** * å½å ¥æ¥æ */ @JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @Excel(name = "å½å ¥æ¥æ", width = 30, dateFormat = "yyyy-MM-dd") private Date entryDate; @@ -175,6 +175,12 @@ @Excel(name = "ååéé¢") private BigDecimal contractAmount = BigDecimal.ZERO; /** * å®é ååéé¢ï¼æ£åéè´§åï¼ */ @Schema(description = "å®é ååéé¢") private BigDecimal netContractAmount = BigDecimal.ZERO; @Schema(description = "æä»¶ç±»å å 4") @TableField(exist = false) src/main/java/com/ruoyi/purchase/pojo/PurchaseLedger.java
@@ -69,7 +69,7 @@ /** * å½å ¥æ¥æ */ @JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @Excel(name = "å½å ¥æ¥æ", width = 30, dateFormat = "yyyy-MM-dd") private Date entryDate; @@ -119,6 +119,12 @@ * ååéé¢ï¼äº§åå«ç¨æ»ä»·ï¼ */ private BigDecimal contractAmount; /** * å®é ååéé¢ï¼æ£åéè´§åï¼ */ @Schema(description = "å®é ååéé¢") private BigDecimal netContractAmount; // // /** // * ä¸å¡å src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -129,6 +129,9 @@ if (purchaseLedger.getApprovalStatus() != null) { queryWrapper.eq(PurchaseLedger::getApprovalStatus, purchaseLedger.getApprovalStatus()); } // åªæ¥è¯¢å ¥åºå·²å®¡æ¹éè¿çéè´å°è´¦ queryWrapper.inSql(PurchaseLedger::getId, "SELECT DISTINCT record_id FROM stock_in_record WHERE approval_status = 1"); return purchaseLedgerMapper.selectList(queryWrapper); } @@ -162,6 +165,8 @@ purchaseLedger.setRecorderId(purchaseLedgerDto.getRecorderId()); purchaseLedger.setApprovalStatus(1); // å®é ååéé¢å§ç»çäºååéé¢ purchaseLedger.setNetContractAmount(purchaseLedger.getContractAmount()); // 3. æ°å¢ææ´æ°ä¸»è¡¨ if (purchaseLedger.getId() == null) { if (!StringUtils.hasText(purchaseLedger.getPurchaseContractNumber())) { @@ -754,13 +759,30 @@ for (Long id : ids) { PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(id); if(purchaseLedger != null){ ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>() List<ApprovalInstance> approvalInstances = approvalInstanceService.list(new LambdaQueryWrapper<ApprovalInstance>() .eq(ApprovalInstance::getBusinessId, purchaseLedger.getId()) .eq(ApprovalInstance::getBusinessType, 5L) .eq(ApprovalInstance::getDeleted, 0)); if (CollectionUtils.isNotEmpty(approvalInstances)) { approvalInstanceService.delete( approvalInstances.stream() .map(ApprovalInstance::getId) .filter(Objects::nonNull) .collect(Collectors.toList()) ); } List<ApproveProcess> approveProcesses = approveProcessService.list(new LambdaQueryWrapper<ApproveProcess>() .eq(ApproveProcess::getApproveType, 5) .eq(ApproveProcess::getApproveDelete, 0) .eq(ApproveProcess::getApproveReason, purchaseLedger.getPurchaseContractNumber()) .last("limit 1")); if (one != null) { approveProcessService.delByIds(Collections.singletonList(one.getId())); .eq(ApproveProcess::getApproveReason, purchaseLedger.getPurchaseContractNumber())); if (CollectionUtils.isNotEmpty(approveProcesses)) { approveProcessService.delByIds( approveProcesses.stream() .map(ApproveProcess::getId) .filter(Objects::nonNull) .collect(Collectors.toList()) ); } } } @@ -941,6 +963,7 @@ salesLedger.setContractAmount(salesLedgerProductImportDtos.stream() .map(PurchaseLedgerProductImportDto::getTaxInclusiveTotalPrice) .reduce(BigDecimal.ZERO,BigDecimal::add)); salesLedger.setNetContractAmount(salesLedger.getContractAmount()); // éè¿éå®åå·ç»å®éå® SalesLedger salesLedger1 = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>() .eq(SalesLedger::getSalesContractNo, salesLedger.getSalesContractNo()) src/main/java/com/ruoyi/purchase/service/impl/PurchaseReturnOrdersServiceImpl.java
@@ -14,6 +14,7 @@ import com.ruoyi.purchase.mapper.PurchaseLedgerMapper; import com.ruoyi.purchase.mapper.PurchaseReturnOrderProductsMapper; import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper; import com.ruoyi.purchase.pojo.PurchaseLedger; import com.ruoyi.purchase.pojo.PurchaseReturnOrderProducts; import com.ruoyi.purchase.pojo.PurchaseReturnOrders; import com.ruoyi.purchase.service.PurchaseReturnOrdersService; @@ -28,6 +29,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.List; /** @@ -76,6 +78,18 @@ }else { throw new RuntimeException("è¯·éæ©éè´§åå"); } // æ´æ°éè´å°è´¦çå®é ååéé¢ if (purchaseReturnOrderDto.getPurchaseLedgerId() != null && purchaseReturnOrderDto.getTotalAmount() != null) { PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(purchaseReturnOrderDto.getPurchaseLedgerId()); if (purchaseLedger != null) { BigDecimal baseAmount = purchaseLedger.getNetContractAmount() != null ? purchaseLedger.getNetContractAmount() : purchaseLedger.getContractAmount(); purchaseLedger.setNetContractAmount(baseAmount.subtract(purchaseReturnOrderDto.getTotalAmount())); purchaseLedgerMapper.updateById(purchaseLedger); } } return true; } src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
@@ -38,7 +38,7 @@ /** * æ£æµæ¥æ */ @JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @Excel(name = "æ£æµæ¥æ", width = 30, dateFormat = "yyyy-MM-dd") private Date checkTime; src/main/java/com/ruoyi/quality/pojo/QualityUnqualified.java
@@ -47,7 +47,7 @@ /** * æ£æµæ¥æ */ @JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @Excel(name = "æ£æµæ¥æ", width = 30, dateFormat = "yyyy-MM-dd") private Date checkTime; @@ -107,7 +107,7 @@ /** * å¤çæ¥æ */ @JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @Excel(name = "å¤çæ¥æ", width = 30, dateFormat = "yyyy-MM-dd") private Date dealTime; src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java
@@ -7,20 +7,13 @@ import com.ruoyi.framework.web.controller.BaseController; import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.framework.web.domain.R; import com.ruoyi.procurementrecord.service.ProcurementRecordService; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.purchase.dto.SimpleReturnOrderGroupDto; import com.ruoyi.purchase.mapper.PurchaseReturnOrderProductsMapper; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.service.ISalesLedgerProductService; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; import java.math.BigDecimal; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * 产åä¿¡æ¯Controller @@ -34,9 +27,6 @@ public class SalesLedgerProductController extends BaseController { private final ISalesLedgerProductService salesLedgerProductService; private final ProcurementRecordService procurementRecordService; private final StockUtils stockUtils; private final PurchaseReturnOrderProductsMapper purchaseReturnOrderProductsMapper; /** @@ -45,13 +35,7 @@ @GetMapping("/list") public AjaxResult list(SalesLedgerProduct salesLedgerProduct) { List<SalesLedgerProduct> list = salesLedgerProductService.selectSalesLedgerProductList(salesLedgerProduct); if (CollUtil.isEmpty(list)) { return AjaxResult.success(list); } List<Long> productIds = list.stream().map(SalesLedgerProduct::getProductModelId).collect(Collectors.toList()); List<SimpleReturnOrderGroupDto> groupListByProductIds = purchaseReturnOrderProductsMapper.getReturnOrderGroupListByProductIds(productIds); Map<Long, BigDecimal> returnOrderGroupDtoMap = groupListByProductIds.stream().collect(Collectors.toMap(SimpleReturnOrderGroupDto::getProductModelId, item -> item.getSumReturnQuantity())); if (CollUtil.isNotEmpty(list)) { list.forEach(item -> { if (item.getApproveStatus() != 2) { if (item.getHasSufficientStock() == 0) { @@ -60,11 +44,16 @@ item.setApproveStatus(1); } } // ç»è®¡éè´§æ°é BigDecimal returnQuality = returnOrderGroupDtoMap.getOrDefault(item.getProductModelId(), BigDecimal.ZERO); item.setReturnQuality(returnQuality); item.setAvailableQuality(item.getQuantity().subtract(returnQuality)); java.math.BigDecimal returnQuantity = item.getReturnQuantity() == null ? java.math.BigDecimal.ZERO : item.getReturnQuantity(); java.math.BigDecimal quantity = item.getQuantity() == null ? java.math.BigDecimal.ZERO : item.getQuantity(); item.setReturnQuantity(returnQuantity); item.setAvailableQuality(quantity.subtract(returnQuantity)); }); } return AjaxResult.success(list); } src/main/java/com/ruoyi/sales/dto/SalesLedgerDto.java
@@ -19,7 +19,7 @@ private String salesContractNo; private String customerContractNo; private String projectName; @JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") private Date entryDate; private String entryDateStart; src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
@@ -50,7 +50,7 @@ /** * å½å ¥æ¥æ */ @JsonFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") @Excel(name = "å½å ¥æ¥æ", width = 30, dateFormat = "yyyy-MM-dd") @DateTimeFormat(pattern = "yyyy-MM-dd") private Date entryDate; @@ -109,6 +109,9 @@ @Schema(description = "仿¬¾æ¹å¼") private String paymentMethod; @Schema(description = "å®é ååéé¢") private BigDecimal netContractAmount; @TableField(exist = false) @Schema(description = "çäº§ç¶æ") private String productionStatus = "æªå¼å§"; src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -164,11 +164,7 @@ @TableField(exist = false) private Integer hasSufficientStock; // éè´§æ°é @TableField(exist = false) private BigDecimal returnQuality; // å¯ç¨æ°é quantity - returnQuality // å¯ç¨æ°é quantity - returnQuantity @TableField(exist = false) private BigDecimal availableQuality; @Schema(description = "åå»ºç¨æ·") @@ -187,6 +183,10 @@ private BigDecimal noQuantity; @TableField(exist = false) @Schema(description = "éè´§æ°é") private BigDecimal returnQuantity; @TableField(exist = false) @Schema(description = "审æ¹ä¸æ°é") private BigDecimal pendingApprovalQuantity; } src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -98,16 +98,29 @@ List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectSalesLedgerProductList(salesLedgerProduct); if(!CollectionUtils.isEmpty(salesLedgerProducts)){ salesLedgerProducts.forEach(item -> { // åè´§ä¿¡æ¯ ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>() // åè´§ä¿¡æ¯ï¼åææ°ä¸æ¡ï¼åªæ¥è¯¢å®¡æ ¸éè¿æå·²åè´§çè®°å½ï¼ ShippingInfo latestShippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>() .eq(ShippingInfo::getSalesLedgerProductId, item.getId()) .in(ShippingInfo::getStatus, "å®¡æ ¸éè¿", "å·²åè´§") .orderByDesc(ShippingInfo::getCreateTime) .last("limit 1")); if(shippingInfo != null){ item.setShippingDate(shippingInfo.getShippingDate()); item.setShippingCarNumber(shippingInfo.getShippingCarNumber()); item.setExpressCompany(shippingInfo.getExpressCompany()); item.setExpressNumber(shippingInfo.getExpressNumber()); if(latestShippingInfo != null){ item.setShippingDate(latestShippingInfo.getShippingDate()); item.setExpressCompany(latestShippingInfo.getExpressCompany()); item.setExpressNumber(latestShippingInfo.getExpressNumber()); } // 车çå·ï¼åææå®¡æ ¸éè¿æå·²åè´§è®°å½ç车çå·ï¼éå·æ¼æ¥ List<ShippingInfo> allShippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>() .eq(ShippingInfo::getSalesLedgerProductId, item.getId()) .in(ShippingInfo::getStatus, "å®¡æ ¸éè¿", "å·²åè´§") .orderByAsc(ShippingInfo::getCreateTime)); if(!CollectionUtils.isEmpty(allShippingInfos)){ String carNumbers = allShippingInfos.stream() .map(ShippingInfo::getShippingCarNumber) .filter(carNo -> carNo != null && !carNo.trim().isEmpty()) .distinct() .collect(Collectors.joining(",")); item.setShippingCarNumber(carNumbers); } }); } @@ -223,9 +236,8 @@ ProductionPlan productionPlan = new ProductionPlan(); productionPlan.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId()); productionPlan.setSalesLedgerProductId(salesLedgerProduct.getId()); productionPlan.setMpsNo(generateNextPlanNo(salesLedger.getEntryDate().toInstant() .atZone(ZoneId.systemDefault()) .toLocalDate().format(DateTimeFormatter.ofPattern("yyyyMMdd")))); productionPlan.setMpsNo(generateNextPlanNo(com.ruoyi.common.utils.DateUtils.toLocalDate(salesLedger.getEntryDate()) .format(DateTimeFormatter.ofPattern("yyyyMMdd")))); productionPlan.setProductModelId(salesLedgerProduct.getProductModelId()); productionPlan.setQtyRequired(salesLedgerProduct.getQuantity()); productionPlan.setSource("éå®"); src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -38,8 +38,6 @@ import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysDeptMapper; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.purchase.dto.SimpleReturnOrderGroupDto; import com.ruoyi.purchase.mapper.PurchaseReturnOrderProductsMapper; import com.ruoyi.quality.mapper.QualityInspectMapper; import com.ruoyi.sales.dto.*; import com.ruoyi.sales.mapper.CommonFileMapper; @@ -121,9 +119,6 @@ @Autowired private ProductionProductMainService productionProductMainService; @Autowired private PurchaseReturnOrderProductsMapper purchaseReturnOrderProductsMapper; ; @Autowired private SysUserMapper sysUserMapper; @Override @@ -148,17 +143,11 @@ productWrapper.eq(SalesLedgerProduct::getType, type.getCode()); List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(productWrapper); if (type.equals(SaleEnum.PURCHASE)) { // æ¥è¯¢éè´§ä¿¡æ¯ List<Long> productIds = salesLedgerProducts.stream().map(SalesLedgerProduct::getProductModelId).collect(Collectors.toList()); List<SimpleReturnOrderGroupDto> groupListByProductIds = new ArrayList<>(); if(CollectionUtils.isNotEmpty(productIds)){ groupListByProductIds = purchaseReturnOrderProductsMapper.getReturnOrderGroupListByProductIds(productIds); } Map<Long, BigDecimal> returnOrderGroupDtoMap = groupListByProductIds.stream().collect(Collectors.toMap(SimpleReturnOrderGroupDto::getProductModelId, SimpleReturnOrderGroupDto::getSumReturnQuantity)); salesLedgerProducts.forEach(item -> { BigDecimal returnQuality = returnOrderGroupDtoMap.getOrDefault(item.getProductModelId(), BigDecimal.ZERO); item.setReturnQuality(returnQuality); item.setAvailableQuality(item.getQuantity().subtract(returnQuality)); BigDecimal returnQuantity = item.getReturnQuantity() == null ? BigDecimal.ZERO : item.getReturnQuantity(); item.setReturnQuantity(returnQuantity); BigDecimal quantity = item.getQuantity() == null ? BigDecimal.ZERO : item.getQuantity(); item.setAvailableQuality(quantity.subtract(returnQuantity)); }); } return salesLedgerProducts; @@ -396,6 +385,7 @@ salesLedger.setContractAmount(salesLedgerProductImportDtos.stream() .map(SalesLedgerProductImportDto::getTaxInclusiveTotalPrice) .reduce(BigDecimal.ZERO, BigDecimal::add)); salesLedger.setNetContractAmount(salesLedger.getContractAmount()); salesLedgerMapper.insert(salesLedger); @@ -601,7 +591,18 @@ ); } // 5. ä¿åéå®å°è´¦éä»¶ // 5. å åºï¼ç¡®ä¿å®é ååé颿åå§å¼çäºååéé¢ if (salesLedger.getNetContractAmount() == null) { SalesLedger dbLedger = salesLedgerMapper.selectById(salesLedger.getId()); if (dbLedger != null && dbLedger.getNetContractAmount() == null && dbLedger.getContractAmount() != null) { SalesLedger updateEntity = new SalesLedger(); updateEntity.setId(salesLedger.getId()); updateEntity.setNetContractAmount(dbLedger.getContractAmount()); salesLedgerMapper.updateById(updateEntity); } } // 6. ä¿åéå®å°è´¦éä»¶ fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.SALES_LEDGER, salesLedger.getId(), salesLedgerDto.getStorageBlobDTOs()); return 1; @@ -739,6 +740,15 @@ amountField.setAccessible(true); amountField.set(entity, totalAmount); // å®é ååéé¢åå§å¼çäºååéé¢ try { Field netAmountField = mainEntityClass.getDeclaredField("netContractAmount"); netAmountField.setAccessible(true); netAmountField.set(entity, totalAmount); } catch (NoSuchFieldException ignored) { // åç±»å¯è½æ²¡æè¯¥å段ï¼å¿½ç¥ } mainMapper.updateById(entity); } catch (Exception e) { throw new RuntimeException("å¨ææ´æ°ä¸»è¡¨éé¢å¤±è´¥", e); src/main/java/com/ruoyi/sales/service/impl/SalesQuotationServiceImpl.java
@@ -194,13 +194,31 @@ if(salesQuotation==null) return false; salesQuotationMapper.deleteById(id); salesQuotationProductMapper.delete(new LambdaQueryWrapper<SalesQuotationProduct>().eq(SalesQuotationProduct::getSalesQuotationId, id)); // å 餿¥ä»·å®¡æ¹ ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>() // å é¤è¯¥æ¥ä»·å¯¹åºçå ¨é¨å®¡æ¹å®ä¾ï¼å¯è½åå¨å¤æ¬¡æäº¤/éå®¡ï¼ List<ApprovalInstance> approvalInstances = approvalInstanceService.list(new LambdaQueryWrapper<ApprovalInstance>() .eq(ApprovalInstance::getBusinessId, id) .eq(ApprovalInstance::getBusinessType, 6L) .eq(ApprovalInstance::getDeleted, 0)); if(!approvalInstances.isEmpty()){ approvalInstanceService.delete( approvalInstances.stream() .map(ApprovalInstance::getId) .filter(Objects::nonNull) .collect(Collectors.toList()) ); } // å é¤è¯¥æ¥ä»·å¯¹åºçå ¨é¨å®¡æ¹æµç¨ï¼å䏿¥ä»·å¯è½åå¤åèµ·ï¼ List<ApproveProcess> approveProcesses = approveProcessService.list(new LambdaQueryWrapper<ApproveProcess>() .eq(ApproveProcess::getApproveType, 6) .eq(ApproveProcess::getApproveDelete, IsDeleteEnum.NOT_DELETED) .eq(ApproveProcess::getApproveReason, salesQuotation.getQuotationNo())); if(one != null){ approveProcessService.delByIds(Collections.singletonList(one.getId())); if(!approveProcesses.isEmpty()){ approveProcessService.delByIds( approveProcesses.stream() .map(ApproveProcess::getId) .filter(Objects::nonNull) .collect(Collectors.toList()) ); } return true; } src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
@@ -172,6 +172,17 @@ @Override public boolean addReq(ShippingInfoDto req) { // æ ¡éªè¯¥äº§åæ¯å¦å·²æå¾ å®¡æ ¸/å®¡æ ¸ä¸çåè´§è®°å½ï¼é²æ¢éå¤æäº¤ Long salesLedgerProductId = req.getSalesLedgerProductId(); if (salesLedgerProductId != null) { long pendingCount = this.count(new LambdaQueryWrapper<ShippingInfo>() .eq(ShippingInfo::getSalesLedgerProductId, salesLedgerProductId) .in(ShippingInfo::getStatus, "å¾ å®¡æ ¸", "å®¡æ ¸ä¸")); if (pendingCount > 0) { throw new RuntimeException("该产åå·²æå¾ å®¡æ ¸çåè´§è®°å½ï¼è¯·å¿éå¤æäº¤"); } } LoginUser loginUser = SecurityUtils.getLoginUser(); String sh = OrderUtils.countTodayByCreateTime(shippingInfoMapper, "SH","shipping_no",req.getCreateTime()); // å ä¿ååè´§åï¼åå起审æ¹ï¼æ å®¡æ ¸äººèªå¨éè¿æ¶éè¦æåè´§ç¼å·åååè´§ç¶æã @@ -200,6 +211,9 @@ approvalInstance.setApplicantName(loginUser.getNickName()); approvalInstance.setApplyTime(LocalDateTime.now()); approvalInstanceService.add(approvalInstance); // å建审æ¹å®ä¾åï¼æ´æ°åè´§ç¶æä¸º"å®¡æ ¸ä¸"ï¼ä½¿å端æ£ç¡®æ¾ç¤ºå®¡æ¹ç¶æ req.setStatus("å®¡æ ¸ä¸"); this.updateById(req); return true; } } src/main/java/com/ruoyi/staff/service/impl/SchemeApplicableStaffServiceImpl.java
@@ -172,8 +172,8 @@ : calculateLatestDeptSocialSupplementAmount(staffOnJobDto); BigDecimal pieceSalary = normalizeMoney(getBigDecimal(map, "pieceSalary")); BigDecimal hourlySalary = normalizeMoney(getBigDecimal(map, "hourlySalary")); BigDecimal socialPersonal = normalizeMoney(getBigDecimal(map, "socialPersonal")); BigDecimal fundPersonal = normalizeMoney(getBigDecimal(map, "fundPersonal")); BigDecimal socialPersonal = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); BigDecimal fundPersonal = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); UserProductionAccountingDto userProductionAccountingDto = new UserProductionAccountingDto(); userProductionAccountingDto.setUserId(getUidByStaffId(staffId)); @@ -194,9 +194,9 @@ } for (SchemeInsuranceDetail detail : detailList) { if("å ¬ç§¯é".equals(detail.getInsuranceType())){ fundPersonal = fundPersonal.add(calculateByEmployeeIdType(detail.getInsuranceType(), fundPersonal, staffOnJobDto, detail)); fundPersonal = calculateByEmployeeIdType(detail.getInsuranceType(), fundPersonal, basicSalary, staffOnJobDto, detail); }else{ socialPersonal = socialPersonal.add(calculateByEmployeeIdType(detail.getInsuranceType(), socialPersonal, staffOnJobDto, detail)); socialPersonal = calculateByEmployeeIdType(detail.getInsuranceType(), socialPersonal, basicSalary, staffOnJobDto, detail); } } } @@ -263,14 +263,14 @@ * @param detail * @return */ public BigDecimal calculateByEmployeeIdType(String type,BigDecimal bigDecimal, StaffOnJob staffOnJobDto,SchemeInsuranceDetail detail) { public BigDecimal calculateByEmployeeIdType(String type,BigDecimal bigDecimal, BigDecimal basicSalary, StaffOnJob staffOnJobDto,SchemeInsuranceDetail detail) { // 夿æ¯å¦è°ç¨åºæ¬å·¥èµ if (detail.getUseBasicSalary() == 1) { BigDecimal divide = detail.getPaymentBase().multiply(detail.getPersonalRatio()).divide(new BigDecimal("100"), 2); bigDecimal = bigDecimal.add(divide); }else{ // è°ç¨åºæ¬å·¥èµ BigDecimal multiply = staffOnJobDto.getBasicSalary().multiply(detail.getPersonalRatio().divide(new BigDecimal("100"), 2)); // è°ç¨å½åå·¥èµè¡¨ä¸çåºæ¬å·¥èµ BigDecimal multiply = basicSalary.multiply(detail.getPersonalRatio().divide(new BigDecimal("100"), 2)); bigDecimal = bigDecimal.add(multiply); } bigDecimal = bigDecimal.add(detail.getPersonalFixed()); @@ -292,8 +292,12 @@ BigDecimal socialSupplementAmount = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); for (SchemeInsuranceDetail detail : detailList) { if (!"å ¬ç§¯é".equals(detail.getInsuranceType())) { socialSupplementAmount = socialSupplementAmount.add( calculateByEmployeeIdType(detail.getInsuranceType(), socialSupplementAmount, staffOnJobDto, detail) socialSupplementAmount = calculateByEmployeeIdType( detail.getInsuranceType(), socialSupplementAmount, normalizeMoney(staffOnJobDto.getBasicSalary()), staffOnJobDto, detail ); } } src/main/java/com/ruoyi/stock/controller/StockOutRecordController.java
@@ -87,4 +87,15 @@ return AjaxResult.success(); } @PostMapping("/reAudit") @Log(title = "åºåºç®¡ç-å审åºåº", businessType = BusinessType.UPDATE) @Operation(summary = "æ¹éå审åºåºè®°å½") public AjaxResult reAudit(@RequestBody StockOutRecordDto approveDto) { if(CollectionUtils.isEmpty(approveDto.getIds())){ return AjaxResult.error("è¯·éæ©è³å°ä¸æ¡æ°æ®"); } stockOutRecordService.batchReAudit(approveDto.getIds()); return AjaxResult.success(); } } src/main/java/com/ruoyi/stock/service/StockOutRecordService.java
@@ -31,4 +31,6 @@ void exportStockOutRecord(HttpServletResponse response, StockOutRecordDto stockOutRecordDto); int batchApprove(List<Long> ids, Integer approvalStatus); int batchReAudit(List<Long> ids); } src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java
@@ -246,6 +246,7 @@ stockInventoryDto.setQualitity(stockInRecord.getStockInNum()); stockInventoryDto.setRemark(stockInRecord.getRemark()); if (stockInventory == null) { try { stockInventoryMapper.insert(new StockInventory() {{ setProductModelId(stockInRecord.getProductModelId()); setQualitity(stockInRecord.getStockInNum()); @@ -254,6 +255,9 @@ setWarnNum(stockInRecord.getWarnNum()); setVersion(1); }}); } catch (org.springframework.dao.DuplicateKeyException e) { stockInventoryMapper.updateAddStockInventory(stockInventoryDto); } } else { stockInventoryMapper.updateAddStockInventory(stockInventoryDto); } @@ -266,6 +270,7 @@ stockUninventoryDto.setQualitity(stockInRecord.getStockInNum()); stockUninventoryDto.setRemark(stockInRecord.getRemark()); if (stockUninventory == null) { try { stockUninventoryMapper.insert(new StockUninventory() {{ setProductModelId(stockInRecord.getProductModelId()); setQualitity(stockInRecord.getStockInNum()); @@ -273,6 +278,9 @@ setRemark(stockInRecord.getRemark()); setVersion(1); }}); } catch (org.springframework.dao.DuplicateKeyException e) { stockUninventoryMapper.updateAddStockUnInventory(stockUninventoryDto); } } else { stockUninventoryMapper.updateAddStockUnInventory(stockUninventoryDto); } src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
@@ -105,7 +105,11 @@ newStockInventory.setBatchNo(stockInventoryDto.getBatchNo()); newStockInventory.setLockedQuantity(stockInventoryDto.getLockedQuantity()); newStockInventory.setWarnNum(stockInventoryDto.getWarnNum()); try { stockInventoryMapper.insert(newStockInventory); } catch (org.springframework.dao.DuplicateKeyException e) { stockInventoryMapper.updateAddStockInventory(stockInventoryDto); } } else { stockInventoryMapper.updateAddStockInventory(stockInventoryDto); } src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java
@@ -215,6 +215,26 @@ return ids.size(); } @Override @Transactional(rollbackFor = Exception.class) public int batchReAudit(List<Long> ids) { if (CollectionUtils.isEmpty(ids)) { throw new BaseException("è¯·éæ©è³å°ä¸æ¡æ°æ®"); } for (Long id : ids) { StockOutRecord stockOutRecord = stockOutRecordMapper.selectById(id); if (stockOutRecord == null) { throw new BaseException("åºåºè®°å½ä¸åå¨,æ æ³éæ°å®¡æ ¸!!!"); } if (!ReviewStatusEnum.REJECTED.getCode().equals(stockOutRecord.getApprovalStatus())) { throw new BaseException("åªæé©³åç¶æçè®°å½æè½éæ°å®¡æ ¸,åºåºæ¹æ¬¡:" + stockOutRecord.getOutboundBatches()); } stockOutRecord.setApprovalStatus(ReviewStatusEnum.PENDING_REVIEW.getCode()); stockOutRecordMapper.updateById(stockOutRecord); } return ids.size(); } private StockInventory getStockInventory(Long productModelId, String batchNo) { LambdaQueryWrapper<StockInventory> eq = new LambdaQueryWrapper<>(); eq.eq(StockInventory::getProductModelId, productModelId); src/main/java/com/ruoyi/technology/controller/TechnologyOperationController.java
@@ -41,7 +41,7 @@ @Log(title = "å·¥åºæ´æ°", businessType = BusinessType.UPDATE) @Operation(summary = "ä¿®æ¹å·¥åº") public R update(@RequestBody com.ruoyi.technology.pojo.TechnologyOperation technologyOperation) { return R.ok(technologyOperationService.updateById(technologyOperation)); return technologyOperationService.update(technologyOperation); } @DeleteMapping("/batchDelete") src/main/java/com/ruoyi/technology/service/TechnologyOperationService.java
@@ -16,6 +16,8 @@ R add(TechnologyOperationDto technologyOperationDto); R update(TechnologyOperation technologyOperation); String batchDelete(List<Long> ids); List<TechnologyOperationVo> listVo(); src/main/java/com/ruoyi/technology/service/impl/TechnologyOperationServiceImpl.java
@@ -57,6 +57,27 @@ return R.ok(); } @Override public R update(TechnologyOperation technologyOperation) { if (technologyOperation.getId() == null) { return R.fail("å·¥åºIDä¸è½ä¸ºç©º"); } boolean updated = technologyOperationMapper.update( null, Wrappers.<TechnologyOperation>lambdaUpdate() .eq(TechnologyOperation::getId, technologyOperation.getId()) .set(TechnologyOperation::getName, technologyOperation.getName()) .set(TechnologyOperation::getNo, technologyOperation.getNo()) .set(TechnologyOperation::getRemark, technologyOperation.getRemark()) .set(TechnologyOperation::getSalaryQuota, technologyOperation.getSalaryQuota()) .set(TechnologyOperation::getIsQuality, technologyOperation.getIsQuality()) .set(TechnologyOperation::getIsProduction, technologyOperation.getIsProduction()) .set(TechnologyOperation::getType, technologyOperation.getType()) .set(TechnologyOperation::getDeviceLedgerId, technologyOperation.getDeviceLedgerId()) ) > 0; return updated ? R.ok() : R.fail("ä¿®æ¹å¤±è´¥"); } /** * å é¤å·¥åºåæ ¡éªæ¯å¦å·²è¢«BOMç»ææå·¥èºè·¯çº¿å¼ç¨ã */ src/main/resources/application-dev.yml
@@ -74,7 +74,7 @@ druid: # ä¸»åºæ°æ®æº master: url: jdbc:mysql://localhost:3306/product-inventory-management-new-pro?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 url: jdbc:mysql://localhost:3306/product-inventory-management-bdpro?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: 123456 # ä»åºæ°æ®æº src/main/resources/application-myhb-pro.yml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,268 @@ # 项ç®ç¸å ³é ç½® ruoyi: # åç§° name: RuoYi # çæ¬ version: 3.8.9 # çæå¹´ä»½ copyrightYear: 2025 # æä»¶è·¯å¾ 示ä¾ï¼ Windowsé ç½®D:/ruoyi/uploadPathï¼Linuxé ç½® /home/ruoyi/uploadPathï¼ profile: /javaWork/product-inventory-management/file # è·åipå°åå¼å ³ addressEnabled: false # éªè¯ç ç±»å math æ°åè®¡ç® char å符éªè¯ captchaType: math # åå审æ¹ç¼å·åç¼(é ç½®æä»¶åç¼å½å) approvalNumberPrefix: NEW # ä¸ªæ¨ Unipush é ç½® getui: appId: PfjyAAE0FK64FaO1w2CMb1 appKey: zTMb831OEL6J4GK1uE3Ob4 masterSecret: K1GFtsv42v61tXGnF7SGE5 domain: https://restapi.getui.cn/v2/ # 离线æ¨é使ç¨çå å/ç»ä»¶å intentComponent: uni.app.UNI099A590/io.dcloud.PandoraEntry # å¼åç¯å¢é ç½® server: # æå¡å¨çHTTP端å£ï¼é»è®¤ä¸º8080 port: 9110 servlet: # åºç¨ç访é®è·¯å¾ context-path: / tomcat: # tomcatçURIç¼ç uri-encoding: UTF-8 # è¿æ¥æ°æ»¡åçæéæ°ï¼é»è®¤ä¸º100 accept-count: 1000 threads: # tomcatæå¤§çº¿ç¨æ°ï¼é»è®¤ä¸º200 max: 800 # Tomcatå¯å¨åå§åççº¿ç¨æ°ï¼é»è®¤å¼10 min-spare: 100 # æ¥å¿é ç½® logging: level: com.ruoyi: warn org.springframework: warn minio: endpoint: http://114.132.189.42/ port: 7019 secure: false accessKey: admin secretKey: 12345678 preview-expiry: 24 # é¢è§å°åé»è®¤24å°æ¶ default-bucket: jxc # ç¨æ·é ç½® user: password: # å¯ç æå¤§éè¯¯æ¬¡æ° maxRetryCount: 5 # å¯ç é宿¶é´ï¼é»è®¤10åéï¼ lockTime: 10 # Springé ç½® spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver druid: # ä¸»åºæ°æ®æº master: url: jdbc:mysql://172.17.0.1:3306/product-inventory-management-myhb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: xd@123456.. # ä»åºæ°æ®æº slave: # 仿°æ®æºå¼å ³/é»è®¤å ³é enabled: false url: username: password: # åå§è¿æ¥æ° initialSize: 5 # æå°è¿æ¥æ± æ°é minIdle: 10 # æå¤§è¿æ¥æ± æ°é maxActive: 20 # é ç½®è·åè¿æ¥çå¾ è¶ æ¶çæ¶é´ maxWait: 60000 # é ç½®è¿æ¥è¶ æ¶æ¶é´ connectTimeout: 30000 # é ç½®ç½ç»è¶ æ¶æ¶é´ socketTimeout: 60000 # é ç½®é´éå¤ä¹ æè¿è¡ä¸æ¬¡æ£æµï¼æ£æµéè¦å ³éç空é²è¿æ¥ï¼å使¯æ¯«ç§ timeBetweenEvictionRunsMillis: 60000 # é ç½®ä¸ä¸ªè¿æ¥å¨æ± 䏿å°çåçæ¶é´ï¼å使¯æ¯«ç§ minEvictableIdleTimeMillis: 300000 # é ç½®ä¸ä¸ªè¿æ¥å¨æ± 䏿大çåçæ¶é´ï¼å使¯æ¯«ç§ maxEvictableIdleTimeMillis: 900000 # é ç½®æ£æµè¿æ¥æ¯å¦ææ validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false webStatFilter: enabled: true statViewServlet: enabled: true # 设置ç½ååï¼ä¸å¡«åå 许ææè®¿é® allow: url-pattern: /druid/* # æ§å¶å°ç®¡çç¨æ·ååå¯ç login-username: ruoyi login-password: 123456 filter: stat: enabled: true # æ ¢SQLè®°å½ log-slow-sql: true slow-sql-millis: 1000 merge-sql: true wall: config: multi-statement-allow: true # èµæºä¿¡æ¯ messages: # å½é åèµæºæä»¶è·¯å¾ basename: i18n/messages # æä»¶ä¸ä¼ servlet: multipart: # å个æä»¶å¤§å° max-file-size: 1GB # 设置æ»ä¸ä¼ çæä»¶å¤§å° max-request-size: 2GB # æå¡æ¨¡å devtools: restart: # çé¨ç½²å¼å ³ enabled: false # redis é ç½® data: mongodb: uri: mongodb://114.132.189.42:9028/chat_memory_db_qlmc # redis é ç½® redis: # å°å # host: 127.0.0.1 host: 172.17.0.1 # 端å£ï¼é»è®¤ä¸º6379 port: 6379 # æ°æ®åºç´¢å¼ database: 0 # å¯ç # password: root2022! password: # è¿æ¥è¶ æ¶æ¶é´ timeout: 10s lettuce: pool: # è¿æ¥æ± ä¸çæå°ç©ºé²è¿æ¥ min-idle: 0 # è¿æ¥æ± ä¸çæå¤§ç©ºé²è¿æ¥ max-idle: 8 # è¿æ¥æ± çæå¤§æ°æ®åºè¿æ¥æ° max-active: 8 # #è¿æ¥æ± æå¤§é»å¡çå¾ æ¶é´ï¼ä½¿ç¨è´å¼è¡¨ç¤ºæ²¡æéå¶ï¼ max-wait: -1ms # Quartz宿¶ä»»å¡é ç½®ï¼æ°å¢é¨åï¼ quartz: job-store-type: jdbc # ä½¿ç¨æ°æ®åºåå¨ jdbc: initialize-schema: never # 馿¬¡è¿è¡æ¶èªå¨åå»ºè¡¨ç»æï¼æååæ¹ä¸ºnever schema: classpath:org/quartz/impl/jdbcjobstore/tables_mysql_innodb.sql # MySQLè¡¨ç»æèæ¬ properties: org: quartz: scheduler: instanceName: RuoYiScheduler instanceId: AUTO jobStore: class: org.quartz.impl.jdbcjobstore.JobStoreTX driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate # MySQLéé tablePrefix: qrtz_ # 表ååç¼ï¼ä¸èæ¬ä¸è´ isClustered: false # åèç¹æ¨¡å¼ï¼éç¾¤éæ¹ä¸ºtrueï¼ clusterCheckinInterval: 10000 txIsolationLevelSerializable: true threadPool: class: org.quartz.simpl.SimpleThreadPool threadCount: 10 # çº¿ç¨æ± å¤§å° threadPriority: 5 makeThreadsDaemons: true updateCheck: false # å ³éçæ¬æ£æ¥ # tokené ç½® token: # 令çèªå®ä¹æ è¯ header: Authorization # 令çå¯é¥ secret: xpAVjhCjQDaDB7mjPAzMDSbQWXNu2zYkTdDNUsPMS5Xx8QMmQVYN7n74eZrYJxDJ # ä»¤çæææï¼é»è®¤30åéï¼ expireTime: 450 # MyBatis Plusé ç½® mybatis-plus: # æç´¢æå®å å«å æ ¹æ®èªå·±çé¡¹ç®æ¥ typeAliasesPackage: com.ruoyi.**.pojo # é ç½®mapperçæ«æï¼æ¾å°ææçmapper.xmlæ å°æä»¶ mapperLocations: classpath*:mapper/**/*Mapper.xml # å è½½å ¨å±çé ç½®æä»¶ configLocation: classpath:mybatis/mybatis-config.xml global-config: enable-sql-runner: true db-config: id-type: auto # PageHelperå页æä»¶ pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql # Swaggeré ç½® swagger: # æ¯å¦å¼å¯swagger enabled: true # 请æ±åç¼ pathMapping: /dev-api # 鲿¢XSSæ»å» xss: # è¿æ»¤å¼å ³ enabled: true # æé¤é¾æ¥ï¼å¤ä¸ªç¨éå·åéï¼ excludes: /system/notice # å¹é 龿¥ urlPatterns: /system/*,/monitor/*,/tool/* # 代ç çæ gen: # ä½è author: ruoyi # é»è®¤çæå è·¯å¾ system éæ¹æèªå·±ç模ååç§° å¦ system monitor tool packageName: com.ruoyi.project.system # èªå¨å»é¤è¡¨åç¼ï¼é»è®¤æ¯true autoRemovePre: false # 表åç¼ï¼çæç±»åä¸ä¼å å«è¡¨åç¼ï¼å¤ä¸ªç¨éå·åéï¼ tablePrefix: sys_ # æ¯å¦å è®¸çææä»¶è¦çå°æ¬å°ï¼èªå®ä¹è·¯å¾ï¼ï¼é»è®¤ä¸å 许 allowOverwrite: false # æä»¶ä¸ä¼ é ç½® file: temp-dir: /javaWork/product-inventory-management/file/temp/uploads # 临æ¶ç®å½ upload-dir: /javaWork/product-inventory-management/file/prod/uploads # æ£å¼ç®å½ path: /javaWork/product-inventory-management/file # ä¸ä¼ ç®å½ urlPrefix: /prod-api/common # 龿¥åç¼ domain: http://1.15.17.182:9095 # åååç¼ expired: 120 # è¿ææ¶é´(åä½:åé) useLimit: 10 # ä½¿ç¨æ¬¡æ° compress: true # æ¯å¦å缩 needCompressSize: 10MB # å缩éå¼ compressQuality: 0.5 # å缩质é(0.0-1.0) src/main/resources/mapper/account/sales/AccountInvoiceApplicationMapper.xml
@@ -72,5 +72,26 @@ </foreach> ) </select> <select id="selectAccountInvoiceApplicationList" resultType="com.ruoyi.account.bean.vo.sales.AccountInvoiceApplicationVo"> select * from ( select aia.*, asi.id AS sales_invoice_id, asi.status AS sales_invoice_status, c.customer_name, GROUP_CONCAT(sour.outbound_batches SEPARATOR ',') AS outboundBatches from account_invoice_application aia left join customer c on aia.customer_id = c.id left join stock_out_record sour on FIND_IN_SET(sour.id, aia.stock_out_record_ids) > 0 left join account_sales_invoice asi on aia.id = asi.account_invoice_application_id GROUP BY aia.id )A WHERE A.customer_id = #{customerId} AND (COALESCE(A.sales_invoice_id,'') = '' OR A.sales_invoice_status = 1) AND A.status = 1 order by A.id desc </select> </mapper> src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml
@@ -58,36 +58,51 @@ <select id="getOutboundBatchesByCustomer" resultType="com.ruoyi.account.bean.vo.sales.SalesOutboundVo"> SELECT id, outbound_batches, customer_name, shipping_date, product_name, specification_model, tax_rate, outbound_amount, shipping_no, sales_contract_no, amount_received FROM ( SELECT sor.id, sor.outbound_batches, sl.customer_name, sor.create_time as shippingDate, sor.create_time AS shipping_date, p.product_name, pm.model as specification_model, pm.model AS specification_model, slp.tax_rate, sor.stock_out_num * slp.tax_inclusive_unit_price as outboundAmount, sor.stock_out_num * slp.tax_inclusive_unit_price AS outbound_amount, s.shipping_no, sl.sales_contract_no FROM stock_out_record sor left join shipping_info s on sor.record_id = s.id sl.sales_contract_no, COALESCE ( SUM( acsc.collection_amount ), 0 ) AS amount_received FROM stock_out_record sor LEFT JOIN shipping_info s ON sor.record_id = s.id LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id LEFT JOIN sales_ledger_product slp ON s.sales_ledger_product_id = slp.id and slp.type = 1 left join product_model pm on slp.product_model_id = pm.id left join product p on pm.product_id = p.id WHERE sor.record_type='13' and sor.approval_status=1 and sl.customer_id=#{customerId} and sor.id NOT IN ( SELECT DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(a.stock_out_record_ids, ',', n.n), ',', -1) FROM account_sales_collection a CROSS JOIN ( SELECT 1 n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 ) n WHERE n.n <= CHAR_LENGTH(a.stock_out_record_ids) - CHAR_LENGTH(REPLACE(a.stock_out_record_ids, ',', '')) + 1 ) order by sor.id DESC LEFT JOIN sales_ledger_product slp ON s.sales_ledger_product_id = slp.id AND slp.type = 1 LEFT JOIN product_model pm ON slp.product_model_id = pm.id LEFT JOIN product p ON pm.product_id = p.id LEFT JOIN account_sales_collection acsc ON acsc.stock_out_record_ids = sor.id WHERE sor.record_type = '13' AND sor.approval_status = 1 AND sl.customer_id = #{customerId} GROUP BY sor.outbound_batches ORDER BY sor.id ) tempA WHERE amount_received < outbound_amount </select> <select id="selectIncomeStats" resultType="com.ruoyi.home.dto.IncomeExpenseAnalysisDto"> SELECT DATE_FORMAT(collection_date, #{dateFormat}) AS dateStr, src/main/resources/mapper/basic/CustomerMapper.xml
@@ -22,7 +22,14 @@ from customer_user cu where cu.customer_id = c.id and cu.user_id != c.usage_user ) as user_ids_str ) as user_ids_str, CASE WHEN EXISTS (SELECT 1 FROM sales_ledger sl WHERE sl.customer_id = c.id) OR EXISTS (SELECT 1 FROM sales_quotation sq WHERE sq.customer_id = c.id) OR EXISTS (SELECT 1 FROM return_management rm WHERE rm.customer_id = c.id) THEN 1 ELSE 0 END AS sales_reference_flag from customer c left join sys_user u on c.usage_user = u.user_id <where> @@ -71,7 +78,14 @@ from customer_user cu where cu.customer_id = c.id and cu.user_id != c.usage_user ) as user_ids_str ) as user_ids_str, CASE WHEN EXISTS (SELECT 1 FROM sales_ledger sl WHERE sl.customer_id = c.id) OR EXISTS (SELECT 1 FROM sales_quotation sq WHERE sq.customer_id = c.id) OR EXISTS (SELECT 1 FROM return_management rm WHERE rm.customer_id = c.id) THEN 1 ELSE 0 END AS sales_reference_flag from customer c left join sys_user u on c.usage_user = u.user_id <where> @@ -112,7 +126,7 @@ <select id="customewTransactions" resultType="com.ruoyi.sales.vo.CustomerTransactionsVo"> select T1.customer_id, c.customer_name, T1.contractAmounts, T1.contractAmounts - IFNULL(T4.returnAmount, 0) AS contractAmounts, IFNULL(T2.receiptPaymentAmount, 0) AS receiptPaymentAmount, IFNULL(T3.outboundAmount, 0) - IFNULL(T4.returnAmount, 0) AS receiptableAmount from (select customer_id, sum(contract_amount) as contractAmounts from sales_ledger group by customer_id) T1 @@ -153,7 +167,7 @@ select sl.id salesLedgerId, sl.sales_contract_no, sl.execution_date, sl.contract_amount, sl.contract_amount - IFNULL(T3.returnAmount, 0) AS contract_amount, IFNULL(T1.receiptPaymentAmount, 0) AS receiptPaymentAmount, IFNULL(T2.outboundAmount, 0) - IFNULL(T3.returnAmount, 0) AS receiptableAmount from sales_ledger sl src/main/resources/mapper/basic/SupplierManageMapper.xml
@@ -75,7 +75,7 @@ T1.contractAmounts, IFNULL(T2.paymentAmount, 0) AS paymentAmount, IFNULL(T3.InboundAmount, 0) - IFNULL(T4.returnAmount, 0) AS payableAmount from (select supplier_id, sum(contract_amount) as contractAmounts from purchase_ledger group by supplier_id) T1 from (select supplier_id, sum(COALESCE(net_contract_amount, contract_amount)) as contractAmounts from purchase_ledger group by supplier_id) T1 left join (select supplier_id, sum(payment_amount) as paymentAmount from account_purchase_payment group by supplier_id) T2 on T1.supplier_id = T2.supplier_id left join ( SELECT @@ -114,7 +114,7 @@ select pl.id purchaseLedgerId, pl.purchase_contract_number, pl.execution_date, pl.contract_amount, COALESCE(pl.net_contract_amount, pl.contract_amount) AS contract_amount, IFNULL(T1.paymentAmount, 0) AS paymentAmount, IFNULL(T2.InboundAmount, 0) - IFNULL(T3.returnAmount, 0) AS payableAmount from purchase_ledger pl src/main/resources/mapper/production/ProductionOrderMapper.xml
@@ -233,7 +233,9 @@ </if> </where> order by po.id desc <if test="size != null and size >= 0"> limit #{offset}, #{size} </if> </select> <select id="countHomeOrderProgress" resultType="java.lang.Long"> src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
@@ -6,7 +6,8 @@ <update id="updateContractAmountById"> UPDATE purchase_ledger SET contract_amount = #{totalTaxInclusiveAmount} SET contract_amount = #{totalTaxInclusiveAmount}, net_contract_amount = #{totalTaxInclusiveAmount} WHERE id = #{id} </update> <select id="selectPurchaseStats" resultType="com.ruoyi.home.dto.IncomeExpenseAnalysisDto"> @@ -27,6 +28,7 @@ pl.supplier_name, pl.project_name, pl.contract_amount, pl.net_contract_amount, pl.entry_date, pl.execution_date, pl.recorder_id, src/main/resources/mapper/sales/SalesLedgerMapper.xml
@@ -56,6 +56,7 @@ T1.attachment_materials, T1.tenant_id, T1.contract_amount, T1.net_contract_amount, T1.contract_amount AS noInvoiceAmountTotal, T1.execution_date, T2.nick_name AS entry_person_name, src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -33,7 +33,8 @@ WHEN (IFNULL(t2.qualitity, 0) - IFNULL(t2.locked_quantity, 0)) >0 THEN 1 ELSE 0 END as has_sufficient_stock, (IFNULL(T1.quantity, 0) - IFNULL(t3.shipped_quantity, 0)) as no_quantity, (IFNULL(T1.quantity, 0) - IFNULL(t3.shipped_quantity, 0) - IFNULL(t5.pending_approval_quantity, 0)) as no_quantity, IFNULL(t6.return_quantity, 0) as return_quantity, IFNULL(t5.pending_approval_quantity, 0) as pending_approval_quantity, CASE WHEN IFNULL(t3.shipped_quantity, 0) = 0 AND IFNULL(t5.pending_approval_quantity, 0) = 0 THEN 'å¾ åè´§' @@ -55,11 +56,17 @@ GROUP BY product_model_id ) t2 ON T1.product_model_id = t2.product_model_id LEFT JOIN ( SELECT sales_ledger_product_id, IFNULL(SUM(spd.quantity), 0) as shipped_quantity SELECT si.sales_ledger_product_id, IFNULL(SUM(spd.quantity), 0) as shipped_quantity FROM shipping_info si LEFT JOIN shipping_product_detail spd ON si.id = spd.shipping_info_id where si.status = 'å®¡æ ¸éè¿' OR si.status = 'å·²åè´§' GROUP BY sales_ledger_product_id INNER JOIN shipping_product_detail spd ON si.id = spd.shipping_info_id WHERE si.status IN ('å®¡æ ¸éè¿', 'å·²åè´§') AND EXISTS ( SELECT 1 FROM stock_out_record sor WHERE sor.record_id = si.id AND TRIM(sor.record_type) = '13' AND sor.approval_status = 1 ) GROUP BY si.sales_ledger_product_id ) t3 ON t3.sales_ledger_product_id = T1.id LEFT JOIN ( SELECT rel.sales_ledger_product_id, @@ -95,12 +102,24 @@ GROUP BY rel.sales_ledger_product_id ) t4 ON t4.sales_ledger_product_id = T1.id LEFT JOIN ( SELECT sales_ledger_product_id, IFNULL(SUM(spd.quantity), 0) as pending_approval_quantity SELECT si.sales_ledger_product_id, IFNULL(SUM(spd.quantity), 0) as pending_approval_quantity FROM shipping_info si LEFT JOIN shipping_product_detail spd ON si.id = spd.shipping_info_id WHERE si.status IN ('å¾ å®¡æ ¸', 'å®¡æ ¸ä¸') GROUP BY sales_ledger_product_id OR (si.status = 'å®¡æ ¸éè¿' AND NOT EXISTS ( SELECT 1 FROM stock_out_record sor WHERE sor.record_id = si.id AND TRIM(sor.record_type) = '13' AND sor.approval_status = 1 )) GROUP BY si.sales_ledger_product_id ) t5 ON t5.sales_ledger_product_id = T1.id LEFT JOIN ( SELECT prop.sales_ledger_product_id, IFNULL(SUM(prop.return_quantity), 0) AS return_quantity FROM purchase_return_order_products prop INNER JOIN purchase_return_orders pro ON prop.purchase_return_order_id = pro.id GROUP BY prop.sales_ledger_product_id ) t6 ON t6.sales_ledger_product_id = T1.id left join product_model pm ON T1.product_model_id = pm.id left join product p ON pm.product_id = p.id <where> src/main/resources/mapper/sales/ShippingInfoMapper.xml
@@ -101,8 +101,9 @@ order by sor.id </select> <select id="getShippingInfoByCustomerName" resultType="com.ruoyi.sales.pojo.ShippingInfo"> select * from shipping_info si select distinct si.* from shipping_info si left join sales_ledger sl on si.sales_ledger_id = sl.id where sl.customer_name = #{customerName} inner join stock_out_record sor on sor.record_id = si.id and sor.record_type = '13' and sor.approval_status = 1 where sl.customer_name = #{customerName} and si.status = 'å®¡æ ¸éè¿' </select> </mapper> src/main/resources/mapper/staff/PersonalShiftMapper.xml
@@ -20,6 +20,7 @@ LEFT JOIN staff_on_job u ON u.id = s.staff_on_job_id LEFT JOIN personal_attendance_location_config palc ON palc.id = s.personal_attendance_location_config_id <where> u.id IS NOT NULL <if test="sysDeptId != null and sysDeptId != ''"> and u.sys_dept_id = #{sysDeptId} </if> src/main/resources/mapper/stock/StockInRecordMapper.xml
@@ -21,9 +21,9 @@ pm.unit, u.nick_name as createBy, CASE WHEN #{params.topParentProductId} = 278 AND TRIM(sir.record_type) = '7' THEN WHEN TRIM(sir.record_type) = '7' THEN COALESCE(pl_by_product.purchase_contract_number, pl_direct.purchase_contract_number) WHEN #{params.topParentProductId} = 278 AND TRIM(sir.record_type) = '10' THEN WHEN TRIM(sir.record_type) = '10' THEN pl_by_quality.purchase_contract_number WHEN #{params.topParentProductId} = 276 THEN CASE src/main/resources/mapper/system/SysDeptMapper.xml
@@ -26,7 +26,6 @@ <sql id="selectDeptVo"> select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time from sys_dept d order by d.create_time desc </sql> <select id="selectDeptList" parameterType="com.ruoyi.project.system.domain.SysDept" resultMap="SysDeptResult"> @@ -92,7 +91,7 @@ <select id="checkDeptNameUnique" resultMap="SysDeptResult"> <include refid="selectDeptVo"/> where dept_name=#{deptName} and parent_id = #{parentId} and del_flag = '0' limit 1 where dept_name=#{deptName} and parent_id = #{parentId} and del_flag = '0' order by d.create_time desc limit 1 </select> <insert id="insertDept" parameterType="com.ruoyi.project.system.domain.SysDept"> src/main/resources/mapper/system/SysUserMapper.xml
@@ -25,6 +25,7 @@ <result property="remark" column="remark" /> <result property="deptNames" column="dept_names" /> <result property="tenantId" column="tenant_id" /> <result property="roleNames" column="role_names" /> <association property="dept" javaType="com.ruoyi.project.system.domain.SysDept" resultMap="deptResult" /> <collection property="roles" javaType="java.util.List" resultMap="RoleResult" /> </resultMap> @@ -290,6 +291,29 @@ and su.del_flag = '0' ORDER BY su.create_time DESC </select> <select id="selectUserListWithDetail" resultMap="SysUserResult"> select u.user_id, u.nick_name, u.user_name, u.status, u.del_flag, dept_agg.dept_names, role_agg.role_names from sys_user u left join ( SELECT ud.user_id, GROUP_CONCAT(d.dept_name SEPARATOR ', ') AS dept_names FROM sys_user_dept ud LEFT JOIN sys_dept d ON ud.dept_id = d.dept_id WHERE d.del_flag = '0' AND d.status = '0' GROUP BY ud.user_id ) dept_agg on dept_agg.user_id = u.user_id left join ( SELECT ur.user_id, GROUP_CONCAT(r.role_name SEPARATOR ', ') AS role_names FROM sys_user_role ur LEFT JOIN sys_role r ON ur.role_id = r.role_id WHERE r.del_flag = '0' AND r.status = '0' GROUP BY ur.user_id ) role_agg on role_agg.user_id = u.user_id where u.del_flag = '0' AND u.status = '0' </select> <select id="getUserByPerms" resultType="java.lang.Long"> select distinct t5.user_id from sys_role_menu t1