.mcp.json
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,21 @@ { "mcpServers": { "mysql": { "type": "stdio", "command": "npx", "args": [ "@benborla29/mcp-server-mysql" ], "env": { "MYSQL_HOST": "127.0.0.1", "MYSQL_PORT": "3306", "MYSQL_USER": "root", "MYSQL_PASS": "123456", "MYSQL_DB": "product-inventory-management-new-pro", "ALLOW_INSERT_OPERATION": "false", "ALLOW_UPDATE_OPERATION": "false", "ALLOW_DELETE_OPERATION": "false" } } } } doc/20260826_Éú²ú¼Æ»®ÓëÏúÊÛ·¢»õÊýÁ¿¹æÔòǰ¶ËÁªµ÷Îĵµ.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,331 @@ # ç产计åä¸éå®åè´§æ°éè§åå端èè°ææ¡£ æ´æ°æ¶é´ï¼2026-08-26 ## 1. æ¬æ¬¡è°æ´æ¦è¿° ### 1.1 ç产计åä¸å ç产计åä¸åä¸åå以ä¸è§åéå¶ï¼ - ä¸åéå¶æ¬æ¬¡ä¸åæ°éä¸è½è¶ è¿éæ±æ°éå©ä½éã - å·²ä¸åæ°éè¾¾å°éæ±æ°éåï¼ä»å¯ä»¥ç»§ç»ä¸åã - `quantityIssued` å è®¸ç´¯è®¡è¶ è¿ `qtyRequired`ã ä»ç¶ä¿ç以䏿 ¡éªï¼ - è³å°éæ©ä¸ä¸ªç产计åã - `totalAssignedQuantity` å¿ é¡»å¤§äº 0ã - éæ©çç产计åå¿ é¡»åå¨ã - åå¹¶ä¸åçç产计åå¿ é¡»å±äºåä¸ä¸ªäº§ååå·ã ### 1.2 éå®åè´§ éå®åè´§ä¸åå以ä¸è§åéå¶ï¼ - ä¸ååéå®äº§å `quantity` éå¶ã - ä¸ååå·²åè´§æ°ééå¶ã - ä¸ååå¾ å®¡æ¹åè´§æ°ééå¶ã - éå®äº§åå·²æ¾ç¤ºâå·²åè´§âåï¼ä»å¯ä»¥ç»§ç»æäº¤åè´§ã éå®åè´§ä»ç¶å¿ 须满足åºåæ ¡éªï¼ ```text å¯ç¨åºå = åºåæ°é - å»ç»åºå - å¾ åºåºæ°é ``` åè´§æ°éè¶ è¿å¯ç¨åºåæ¶ï¼æ¥å£ä»ç¶è¿å失败ã ## 2. éç¨ååº æåååºç¤ºä¾ï¼ ```json { "code": 200, "msg": "æä½æå", "data": true } ``` 失败ååºç¤ºä¾ï¼ ```json { "code": 500, "msg": "ä¸å失败ï¼ä¸åæ°éå¿ é¡»å¤§äº0", "data": null } ``` ## 3. ç产计åä¸å ### 3.1 æ¥å£å°å ```text POST /productionPlan/combine ``` ### 3.2 请æ±ä½ ```json { "ids": [101, 102], "totalAssignedQuantity": 500, "planCompleteTime": "2026-08-30" } ``` åæ®µè¯´æï¼ | åæ®µ | ç±»å | å¿ å¡« | 说æ | | --- | --- | --- | --- | | `ids` | `number[]` | æ¯ | è¦ä¸åçç产计å ID éåï¼å»ºè®®å端å»é | | `totalAssignedQuantity` | `number` | æ¯ | æ¬æ¬¡æ»ç产æ°éï¼åªéå¤§äº 0ï¼ä¸åä¸éæ±å©ä½æ°éæ¯è¾ | | `planCompleteTime` | `string` | å¦ | 计åå®ææ¥æï¼æ ¼å¼ `yyyy-MM-dd` | ### 3.3 å端å¤çè¦æ± 1. ä¸åæ°éè¾å ¥æ¡åªæ ¡éªå¤§äº 0ï¼ä¸è¦å设置âå©ä½éæ±æ»éâä½ä¸ºæå¤§å¼ã 2. ç产计å `status=2` çè®°å½å è®¸åæ¬¡å¾éåä¸åã 3. ä¸è¦å 为 `quantityIssued >= qtyRequired` ç¦ç¨ä¸åæé®ã 4. ä¸åæååå·æ°ç产计åå表åç产订åå表ã 5. `quantityIssued` å¯è½å¤§äº `qtyRequired`ï¼å端ä¸è¦åè¶ éæªææå¼å¸¸æç¤ºã 6. ä»ç¶ç¦æ¢éæ©ä¸å产ååå·ç计åè¿è¡åå¹¶ä¸åï¼å端ä¼åæ¬¡æ ¡éªã ### 3.4 ç产计åç¶æ | ç¶æå¼ | å«ä¹ | | --- | --- | | `0` | æªä¸å | | `1` | é¨åä¸å | | `2` | å·²ä¸å | 注æï¼ç¶æ `2` ç°å¨åªè¡¨ç¤ºåéæ±æ°é已宿ï¼ä¸ä»£è¡¨è¯¥è®¡åä¸è½å次ä¸åãç¶æä¸º `2` ç计å忬¡ä¸ååï¼ç¶æä»å¯è½ä¿æ `2`ï¼åæ¶ `quantityIssued` ä¼ç»§ç»ç´¯è®¡ã ### 3.5 èè°åºæ¯ #### åºæ¯ä¸ï¼ä¸åæ°éè¶ è¿éæ±æ°é åè®¾ï¼ - éæ±æ°éï¼100 - å·²ä¸åæ°éï¼100 - æ¬æ¬¡ä¸åæ°éï¼20 请æ±ï¼ ```json { "ids": [101], "totalAssignedQuantity": 20 } ``` é¢æï¼ - è¯·æ±æåã - æ°å»ºçäº§è®¢åæ°é为 20ã - ç产计å `quantityIssued` æ´æ°ä¸º 120ã - ä¸è¿åâä¸è½å¤§äºè®¡åå©ä½éæ±æ»éâã #### åºæ¯äºï¼ä¸æ¬¡éæ©å¤ä¸ªååå·è®¡å ```json { "ids": [101, 102, 103], "totalAssignedQuantity": 500 } ``` 颿ç产订åçæ»æ°é为 500ï¼ä¸åæ ¹æ®å计åéæ±æ°éæªæã #### åºæ¯ä¸ï¼éæ©ä¸ååå·è®¡å 请æ±ä»ç¶å¤±è´¥ï¼æç¤ºæéç产计åç产ååå·ä¸ä¸è´ãè¯¥æ ¡éªæ²¡æåæ¶ã ## 4. éå®äº§åå表 éå®äº§åå表ä¸ç `noQuantity` ä¸å表示éå®è®¢åå©ä½å¯åæ°éã å端è¿åï¼ ```json { "quantity": 10, "shippedQuantity": 10, "pendingApprovalQuantity": 0, "noQuantity": null } ``` åæ®µè¯´æï¼ | åæ®µ | 说æ | | --- | --- | | `quantity` | éå®äº§ååå§æ°éï¼ä» ç¨äºéå®ä¸å¡å±ç¤ºï¼ä¸ä½ä¸ºåè´§æ°éä¸é | | `shippedQuantity` | å·²åè´§æ°éï¼ä» ç¨äºç»è®¡å±ç¤º | | `pendingApprovalQuantity` | å¾ å®¡æ ¸æå®¡æ ¸ä¸çåè´§æ°éï¼ä» ç¨äºç»è®¡å±ç¤º | | `noQuantity` | ä¸åæä¾éå®å©ä½å¯åæ°éï¼å¼ä¸º `null` | å端注æï¼ - ä¸è¦ä½¿ç¨ `noQuantity` ä½ä¸ºåè´§æ°éè¾å ¥æ¡ç `max`ã - ä¸è¦å 为 `noQuantity <= 0` ç¦ç¨åè´§æé®ã - ä¸è¦ç¨ `quantity - shippedQuantity - pendingApprovalQuantity` éæ°è®¡ç®åè´§ä¸éã - åè´§æ°éè¾å ¥æ¡çæå¤§å¼åºç±å®é åºåä¿¡æ¯æç¨æ·éæ©çåºåæ¹æ¬¡å³å®ã - `shippingStatus` ä»å¯ç¨äºå±ç¤ºï¼ä½ä¸è½ä½ä¸ºæ¯å¦å 许继ç»åè´§çç¡¬æ§æ¡ä»¶ã ## 5. æ°å¢éå®åè´§ ### 5.1 æ¥å£å°å ```text POST /shippingInfo/add ``` ### 5.2 请æ±ä½ç¤ºä¾ ```json { "salesLedgerId": 2001, "salesLedgerProductId": 3001, "type": "éå®åè´§", "batchNoDetailList": [ { "productModelId": 501, "batchNo": "BATCH-20260826-001", "quantity": 30 } ], "storageBlobDTOs": [] } ``` åæ®µè¯´æï¼ | åæ®µ | ç±»å | å¿ å¡« | 说æ | | --- | --- | --- | --- | | `salesLedgerId` | `number` | æä¸å¡ | éå®å°è´¦ ID | | `salesLedgerProductId` | `number` | å»ºè®®ä¼ å ¥ | éå®å°è´¦äº§å IDï¼ç¨äºå ³èéå®äº§ååéå¤æäº¤æ ¡éª | | `type` | `string` | å¦ | åè´§ç±»å | | `batchNoDetailList` | `array` | æ¯ | åè´§æ¹æ¬¡æç» | | `batchNoDetailList[].productModelId` | `number` | æ¯ | 产ååå· ID | | `batchNoDetailList[].batchNo` | `string` | æ¯ | åºåæ¹æ¬¡å· | | `batchNoDetailList[].quantity` | `number` | æ¯ | æ¬æ¹æ¬¡åè´§æ°é | | `storageBlobDTOs` | `array` | å¦ | éä»¶åè¡¨ï¼æ²¡æéä»¶æ¶ä¼ 空æ°ç» | ### 5.3 éè¦è§å 1. åè´§æ°éå¯ä»¥å¤§äºéå®äº§åå©ä½æ°éã 2. æ¯ä¸ªæ¹æ¬¡é½å¿ é¡»åå¨åºåè®°å½ã 3. æ¯ä¸ªæ¹æ¬¡çåè´§æ°éä¸è½è¶ è¿è¯¥æ¹æ¬¡å¯ç¨åºåã 4. å¯ç¨åºå伿£é¤å»ç»åºååå·²æå¾ åºåºæ°éã 5. åä¸éå®äº§åå·²æâå¾ å®¡æ ¸âæâå®¡æ ¸ä¸âåè´§è®°å½æ¶ï¼ä»ä¸å 许éå¤æäº¤ã 6. æ°å¢æååï¼åè´§åè¿å ¥å®¡æ¹æµç¨ï¼éå¸¸ç¶æä¸ºâå®¡æ ¸ä¸âã åºåä¸è¶³æ¶å¯è½è¿åï¼ ```text åºåè®°å½ä¸åå¨ ``` æï¼ ```text ç³è¯·æ°éè¶ è¿å¯ç¨åºåï¼å½åå¯ç¨åºå为ï¼xxx ``` ### 5.4 èè°åºæ¯ #### åºæ¯ä¸ï¼é宿°éå·²åå®ï¼ä½åºåå è¶³ åè®¾ï¼ - é宿°éï¼10 - å·²åè´§æ°éï¼10 - å½åæ¹æ¬¡å¯ç¨åºåï¼30 - æ¬æ¬¡åè´§æ°éï¼20 é¢æï¼ - `/shippingInfo/add` 请æ±å 许æäº¤ã - ä¸å 为é宿°éå·²ç¨å®è失败ã - åç»ä»æç §å®¡æ¹æµç¨å¤çã #### åºæ¯äºï¼é宿°éæªåå®ï¼ä½åºåä¸è¶³ åè®¾ï¼ - éå®å©ä½æ°éï¼100 - å½åæ¹æ¬¡å¯ç¨åºåï¼5 - æ¬æ¬¡åè´§æ°éï¼6 é¢æï¼ - 请æ±å¤±è´¥ã - è¿ååºåä¸è¶³ä¿¡æ¯ã - ä¸åºè®¤ä¸ºéå®å©ä½æ°éè¶³å¤å°±å 许åè´§ã #### åºæ¯ä¸ï¼å¤ä¸ªåºåæ¹æ¬¡ ```json { "salesLedgerProductId": 3001, "batchNoDetailList": [ { "productModelId": 501, "batchNo": "BATCH-A", "quantity": 10 }, { "productModelId": 501, "batchNo": "BATCH-B", "quantity": 15 } ] } ``` æ¯ä¸ªæ¹æ¬¡ç¬ç«æ ¡éªåºåï¼ä»»æä¸ä¸ªæ¹æ¬¡åºåä¸è¶³æ¶ï¼æ´æ¬¡è¯·æ±å¤±è´¥å¹¶åæ»ã ## 6. 审æ¹éè¿å确认åè´§ ### 6.1 æ¥å£å°å ```text POST /shippingInfo/deductStock ``` ### 6.2 请æ±ä½ç¤ºä¾ ```json { "id": 4001, "expressCompany": "顺丰", "expressNumber": "SF1234567890", "shippingCarNumber": "èA12345", "shippingDate": "2026-08-26" } ``` 说æï¼ - `id` 为åè´§å IDï¼å¿ å¡«ã - æ¥å£ä¼å次æåè´§æç»æ ¡éªåºåã - æåååè´§åç¶ææ´æ°ä¸ºâå·²åè´§âã - å½åæ¥å£ä¸ä¼æ ¹æ®éå®äº§ååå§æ°ééå¶åè´§ã - å·²ç»æ¯âå·²åè´§âç¶ææ¶ï¼ä¸ä¼é夿£ååºåã ## 7. å端èè°æ£æ¥æ¸ å - [ ] ç产计åä¸åæ°éè¾å ¥æ¡ä¸åç»å®éæ±å©ä½éæå¤§å¼ã - [ ] ç¶æä¸º `2` çç产计åä»å¯éæ©ä¸åã - [ ] ç产计åä¸åæååå 许 `quantityIssued > qtyRequired` å±ç¤ºã - [ ] éå®äº§åå表ä¸ä½¿ç¨ `noQuantity` éå¶åè´§æ°éã - [ ] `noQuantity=null` æ¶é¡µé¢ä¸æ¾ç¤ºä¸ºâä¸å¯åè´§âã - [ ] éå®äº§åç¶æâå·²åè´§âä¸åç´æ¥ç¦ç¨åè´§æä½ã - [ ] åè´§æ°éæ¹ç±åºåæ¹æ¬¡å¯ç¨éæ§å¶ã - [ ] åºåä¸è¶³æ¶æ£ç¡®å±ç¤ºå端é误信æ¯ã - [ ] åä¸éå®äº§åå¾ å®¡æ ¸/å®¡æ ¸ä¸éå¤æäº¤ä»æå端æç¤ºå¤çã - [ ] ç产计åãéå®åè´§æäº¤æååå·æ°åè¡¨æ°æ®ã sql/product-inventory-management-new-pro.sql
@@ -4895,6 +4895,7 @@ `company_phone` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'å ¬å¸çµè¯', `bank_account_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '弿·è¡', `bank_account_num` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'è´¦å·', `bank_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'é¶èè¡å·', `contact_user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'è系人', `contact_user_phone` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'èç³»çµè¯', `maintain_user_id` bigint NULL DEFAULT NULL COMMENT 'ç»´æ¤äººID', src/main/java/com/ruoyi/account/mapper/purchase/AccountPurchasePaymentMapper.java
@@ -26,4 +26,6 @@ IPage<AccountPurchasePaymentVo> listPageAccountPurchasePayment(Page page, @Param("req") AccountPurchasePaymentDto accountPurchasePaymentDto); List<IncomeExpenseAnalysisDto> selectPayment(@Param("startStr") String startStr, @Param("endStr") String endStr, @Param("dateFormat") String dateFormat); List<Long> selectStockInRecordIdsByPurchaseLedgerId(@Param("purchaseLedgerId") Long purchaseLedgerId); } src/main/java/com/ruoyi/account/mapper/sales/AccountSalesCollectionMapper.java
@@ -32,4 +32,6 @@ List<SalesOutboundVo> getOutboundBatchesByCustomer(@Param("customerId") Integer customerId); List<IncomeExpenseAnalysisDto> selectIncomeStats(@Param("startStr") String startStr, @Param("endStr") String endStr, @Param("dateFormat") String dateFormat); List<Long> selectStockOutRecordIdsBySalesLedgerId(@Param("salesLedgerId") Long salesLedgerId); } src/main/java/com/ruoyi/account/service/impl/purchase/AccountPurchasePaymentServiceImpl.java
@@ -1,10 +1,11 @@ package com.ruoyi.account.service.impl.purchase; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.github.xiaoymin.knife4j.core.util.CollectionUtils; import com.ruoyi.account.bean.dto.purchase.AccountPurchasePaymentDto; import com.ruoyi.account.bean.vo.purchase.AccountPurchasePaymentVo; import com.ruoyi.account.mapper.AccountStatementDetailsMapper; @@ -17,15 +18,20 @@ import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.purchase.dto.SavePaymentDto; import com.ruoyi.purchase.mapper.PurchaseLedgerMapper; import com.ruoyi.purchase.pojo.PurchaseLedger; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Random; import java.util.stream.Collectors; /** * <p> @@ -43,6 +49,7 @@ private final AccountPurchasePaymentMapper accountPurchasePaymentMapper; private final AccountStatementDetailsMapper accountStatementDetailsMapper; private final AccountPaymentApplicationMapper accountPaymentApplicationMapper; private final PurchaseLedgerMapper purchaseLedgerMapper; @Override public IPage<AccountPurchasePaymentVo> listPageAccountPurchasePayment(Page page, AccountPurchasePaymentDto accountPurchasePaymentDto) { @@ -84,6 +91,60 @@ return removeByIds(ids); } @Override @Transactional(rollbackFor = Exception.class) public boolean savePayment(SavePaymentDto dto) { if (dto.getPaymentDate() == null) { throw new ServiceException("è¯·éæ©ä»æ¬¾æ¥æ"); } if (dto.getPaymentAmount() == null || dto.getPaymentAmount().compareTo(BigDecimal.valueOf(0.01)) < 0) { throw new ServiceException("请è¾å ¥ä»æ¬¾éé¢"); } if (StringUtils.isEmpty(dto.getPurchaseContractNumber())) { throw new ServiceException("éè´ååå·ä¸è½ä¸ºç©º"); } if (dto.getSupplierId() == null) { throw new ServiceException("ä¾åºåä¸è½ä¸ºç©º"); } PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>() .eq(PurchaseLedger::getPurchaseContractNumber, dto.getPurchaseContractNumber())); if (purchaseLedger == null) { throw new ServiceException("éè´ååä¸åå¨"); } if (purchaseLedger.getSupplierId() == null || purchaseLedger.getSupplierId().longValue() != dto.getSupplierId().longValue()) { throw new ServiceException("ä¾åºåä¸ååä¸å¹é "); } List<Long> stockInRecordIds = accountPurchasePaymentMapper.selectStockInRecordIdsByPurchaseLedgerId(purchaseLedger.getId()); AccountPaymentApplication application = new AccountPaymentApplication(); application.setSupplierId(dto.getSupplierId().intValue()); application.setStockInRecordIds(stockInRecordIds.stream().map(String::valueOf).collect(Collectors.joining(","))); application.setInvoiceApplicationNo(genPaymentApplicationNo()); application.setPaymentMethod(dto.getPaymentMethod()); application.setPaymentContent(dto.getPurchaseContractNumber()); application.setApplyDate(dto.getPaymentDate()); application.setRemark(dto.getRemark()); application.setStatus(1); application.setPaymentAmount(dto.getPaymentAmount()); accountPaymentApplicationMapper.insert(application); AccountPurchasePayment payment = new AccountPurchasePayment(); payment.setAccountPaymentApplicationId(application.getId()); payment.setSupplierId(dto.getSupplierId().intValue()); payment.setPaymentDate(dto.getPaymentDate()); payment.setPaymentMethod(dto.getPaymentMethod()); payment.setPaymentAmount(dto.getPaymentAmount()); payment.setPaymentNumber(genAccountPurchasePaymentNo()); payment.setRemark(dto.getRemark()); return save(payment); } private String genPaymentApplicationNo() { return "FK" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10); } private String genAccountPurchasePaymentNo() { return "SK" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10); } src/main/java/com/ruoyi/account/service/impl/sales/AccountSalesCollectionServiceImpl.java
@@ -1,5 +1,6 @@ package com.ruoyi.account.service.impl.sales; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; @@ -16,13 +17,16 @@ import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.sales.dto.SaveReceiptPaymentDto; import com.ruoyi.sales.mapper.SalesLedgerMapper; import com.ruoyi.sales.pojo.SalesLedger; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.List; import java.util.Random; @@ -40,6 +44,7 @@ private final AccountSalesCollectionMapper accountSalesCollectionMapper; private final AccountStatementDetailsMapper accountStatementDetailsMapper; private final SalesLedgerMapper salesLedgerMapper; private static final DateTimeFormatter CODE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyMMddHHmmss"); @@ -90,6 +95,43 @@ return accountSalesCollectionMapper.getOutboundBatchesByCustomer(customerId); } @Override public boolean saveReceiptPayment(SaveReceiptPaymentDto dto) { if (dto.getPaymentDate() == null) { throw new ServiceException("è¯·éæ©åæ¬¾æ¥æ"); } if (dto.getPaymentAmount() == null || dto.getPaymentAmount().compareTo(BigDecimal.valueOf(0.01)) < 0) { throw new ServiceException("请è¾å ¥å款éé¢"); } if (StringUtils.isEmpty(dto.getSalesContractNo())) { throw new ServiceException("éå®ååå·ä¸è½ä¸ºç©º"); } if (dto.getCustomerId() == null) { throw new ServiceException("客æ·ä¸è½ä¸ºç©º"); } SalesLedger salesLedger = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>() .eq(SalesLedger::getSalesContractNo, dto.getSalesContractNo())); if (salesLedger == null) { throw new ServiceException("éå®ååä¸åå¨"); } if (salesLedger.getCustomerId() == null || salesLedger.getCustomerId().longValue() != dto.getCustomerId().longValue()) { throw new ServiceException("客æ·ä¸ååä¸å¹é "); } List<Long> stockOutRecordIds = accountSalesCollectionMapper.selectStockOutRecordIdsBySalesLedgerId(salesLedger.getId()); AccountSalesCollection collection = new AccountSalesCollection(); collection.setCustomerId(dto.getCustomerId().intValue()); collection.setStockOutRecordIds(stockOutRecordIds.stream().map(String::valueOf).collect(java.util.stream.Collectors.joining(","))); collection.setCollectionDate(dto.getPaymentDate()); collection.setCollectionAmount(dto.getPaymentAmount()); collection.setCollectionMethod(dto.getPaymentMethod()); collection.setCollectionNumber(genAccountSalesCollectionNo()); collection.setRemark(dto.getRemark()); return save(collection); } private String genAccountSalesCollectionNo() { return "SK" + LocalDateTime.now().format(CODE_TIME_FORMATTER) + new Random().nextInt(10); } src/main/java/com/ruoyi/account/service/purchase/AccountPurchasePaymentService.java
@@ -5,6 +5,7 @@ import com.ruoyi.account.bean.dto.purchase.AccountPurchasePaymentDto; import com.ruoyi.account.bean.vo.purchase.AccountPurchasePaymentVo; import com.ruoyi.account.pojo.purchase.AccountPurchasePayment; import com.ruoyi.purchase.dto.SavePaymentDto; import com.baomidou.mybatisplus.extension.service.IService; import jakarta.servlet.http.HttpServletResponse; @@ -27,4 +28,12 @@ void exportAccountPurchasePayment(HttpServletResponse response, AccountPurchasePaymentDto accountPurchasePaymentDto); boolean deleteAccountPurchasePayment(List<Long> ids); /** * éè´ç®¡ç--ä¾åºå徿¥ æ°å¢ä»æ¬¾ * * @param dto 仿¬¾è¯·æ±åæ° * @return æ¯å¦æå */ boolean savePayment(SavePaymentDto dto); } src/main/java/com/ruoyi/account/service/sales/AccountSalesCollectionService.java
@@ -6,6 +6,7 @@ import com.ruoyi.account.bean.vo.sales.AccountSalesCollectionVo; import com.ruoyi.account.bean.vo.sales.SalesOutboundVo; import com.ruoyi.account.pojo.sales.AccountSalesCollection; import com.ruoyi.sales.dto.SaveReceiptPaymentDto; import com.baomidou.mybatisplus.extension.service.IService; import jakarta.servlet.http.HttpServletResponse; @@ -30,4 +31,12 @@ boolean deleteAccountSalesCollection(List<Long> ids); List<SalesOutboundVo> getOutboundBatchesByCustomer(Integer customerId); /** * è¥é管ç--客æ·å¾æ¥ æ°å¢å款 * * @param dto 忬¾è¯·æ±åæ° * @return æ¯å¦æå */ boolean saveReceiptPayment(SaveReceiptPaymentDto dto); } src/main/java/com/ruoyi/basic/excel/SupplierManageExcelDto.java
@@ -30,6 +30,9 @@ @Excel(name = "è´¦å·") private String bankAccountNum; @Excel(name = "é¶èè¡å·") private String bankCode; @Excel(name = "è系人") private String contactUserName; src/main/java/com/ruoyi/basic/pojo/SupplierManage.java
@@ -40,6 +40,10 @@ @Excel(name = "è´¦å·") private String bankAccountNum; @Schema(description = "é¶èè¡å·") @Excel(name = "é¶èè¡å·") private String bankCode; @Schema(description = "è系人") @Excel(name = "è系人") private String contactUserName; src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -666,9 +666,6 @@ if (productModelIds.size() > 1) { throw new ServiceException("æéç产计åå¿ é¡»å±äºåä¸äº§åè§æ ¼"); } if (productionPlans.stream().anyMatch(item -> item.getStatus() != null && item.getStatus() == 2)) { throw new ServiceException("æéç产计åå·²ä¸å"); } ProductionPlan firstPlan = mainPlan; if (productionOrder.getProductModelId() == null) { productionOrder.setProductModelId(firstPlan.getProductModelId()); src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java
@@ -61,9 +61,8 @@ * åå¹¶ç产计åå¹¶ä¸åç产订åã * 约æï¼ * 1. ä» å 许åä¸äº§ååå·ç计ååå¹¶ï¼ * 2. å·²ä¸åæé¨åä¸åç计åä¸å è®¸åæ¬¡åå¹¶ï¼ * 3. ä¸åæ°éä¸è½å¤§äºæé计åå©ä½éæ±æ»éï¼ * 4. ä¸åæ¶ç»ä¸è°ç¨ ProductionOrderService.saveProductionOrderï¼ç¡®ä¿åç»å·¥èº/BOM/颿é»è¾ä¸è´ã * 2. ä¸åæ°éåªåè¾å ¥æ°éååºç¡æ°æ®æ ¡éªçº¦æï¼ * 3. ä¸åæ¶ç»ä¸è°ç¨ ProductionOrderService.saveProductionOrderï¼ç¡®ä¿åç»å·¥èº/BOM/颿é»è¾ä¸è´ã */ @Override @Transactional(rollbackFor = Exception.class) @@ -101,49 +100,18 @@ throw new BaseException("åå¹¶å¤±è´¥ï¼æéç产计åç产ååå·ä¸ä¸è´"); } // ä» âå·²ä¸åâ计åä¸å è®¸åæ¬¡åä¸åå¹¶ä¸åï¼ // âå¾ ä¸å/é¨åä¸åâå 许继ç»ä¸åå©ä½æ°éã boolean hasFullyIssuedPlan = planLists.stream() .anyMatch(item -> item.getStatus() != null && item.getStatus() == PLAN_STATUS_ISSUED); if (hasFullyIssuedPlan) { throw new BaseException("åå¹¶å¤±è´¥ï¼æéç产计ååå¨å·²ä¸åçæ°æ®"); } // è®¡ç®æ¬æ¬¡å¯ä¸åçå©ä½éæ±æ»é BigDecimal totalRequiredQuantity = planLists.stream() .map(this::resolveRemainingQuantity) .reduce(BigDecimal.ZERO, BigDecimal::add); if (totalRequiredQuantity.compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("ä¸åå¤±è´¥ï¼æéç产计åå©ä½éæ±æ»éå¿ é¡»å¤§äº0"); } // æ ¡éªä¸åæ°é BigDecimal assignedQuantity = productionPlanDto.getTotalAssignedQuantity(); if (assignedQuantity == null || assignedQuantity.compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("ä¸å失败ï¼ä¸åæ°éå¿ é¡»å¤§äº0"); } if (assignedQuantity.compareTo(totalRequiredQuantity) > 0) { throw new ServiceException("ä¸å失败ï¼ä¸åæ°éä¸è½å¤§äºè®¡åå©ä½éæ±æ»é"); } // æè®¡å顺åºåæä¸åæ°éï¼æ¶éå®é åä¸ä¸åç计å ID BigDecimal remainingForOrderBind = assignedQuantity; List<Long> issuedPlanIds = new ArrayList<>(); for (ProductionPlanDto plan : planLists) { BigDecimal remainingQuantity = resolveRemainingQuantity(plan); if (remainingForOrderBind.compareTo(BigDecimal.ZERO) <= 0 || remainingQuantity.compareTo(BigDecimal.ZERO) <= 0) { continue; } BigDecimal issueForThisPlan = remainingForOrderBind.min(remainingQuantity); remainingForOrderBind = remainingForOrderBind.subtract(issueForThisPlan); if (issueForThisPlan.compareTo(BigDecimal.ZERO) > 0) { issuedPlanIds.add(plan.getId()); } } if (issuedPlanIds.isEmpty()) { throw new ServiceException("ä¸åå¤±è´¥ï¼æ å¯ä¸åæ°é"); } // æ¬æ¬¡ä¸åæ°éä¸åæéæ±ééå¶ï¼ææéä¸è®¡åå ±åä½ä¸ºè®¢åæ¥æº List<Long> issuedPlanIds = planLists.stream() .map(ProductionPlanDto::getId) .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); // çæç产订å主åï¼å¹¶ç»å®æ¬æ¬¡ä¸åå ³èç计å ProductionOrder productionOrder = new ProductionOrder(); @@ -155,24 +123,18 @@ throw new ServiceException("ä¸å失败ï¼ç产订åä¿å失败"); } // å忝æ¡è®¡åç累计ä¸åéåç¶æ // å忝æ¡è®¡åç累计ä¸åéåç¶æï¼å 许累计ä¸åéè¶ è¿éæ±é BigDecimal remainingAssignedQuantity = assignedQuantity; List<ProductionPlan> updates = new ArrayList<>(); for (ProductionPlanDto plan : planLists) { BigDecimal requiredQuantity = Optional.ofNullable(plan.getQtyRequired()).orElse(BigDecimal.ZERO); if (requiredQuantity.compareTo(BigDecimal.ZERO) < 0) { requiredQuantity = BigDecimal.ZERO; } BigDecimal remainingQuantity = resolveRemainingQuantity(plan); BigDecimal historicalIssuedQuantity = requiredQuantity.subtract(remainingQuantity); BigDecimal issuedQuantity = BigDecimal.ZERO; if (remainingAssignedQuantity.compareTo(BigDecimal.ZERO) > 0 && remainingQuantity.compareTo(BigDecimal.ZERO) > 0) { issuedQuantity = remainingAssignedQuantity.min(remainingQuantity); remainingAssignedQuantity = remainingAssignedQuantity.subtract(issuedQuantity); } BigDecimal historicalIssuedQuantity = Optional.ofNullable(plan.getQuantityIssued()).orElse(BigDecimal.ZERO); BigDecimal issuedQuantity = remainingAssignedQuantity.min(assignedQuantity); remainingAssignedQuantity = remainingAssignedQuantity.subtract(issuedQuantity); BigDecimal totalIssuedQuantity = historicalIssuedQuantity.add(issuedQuantity); int planStatus = resolvePlanStatus(requiredQuantity, totalIssuedQuantity); int planStatus = plan.getStatus() != null && plan.getStatus() == PLAN_STATUS_ISSUED ? PLAN_STATUS_ISSUED : resolvePlanStatus(plan.getQtyRequired(), totalIssuedQuantity); ProductionPlan update = new ProductionPlan(); update.setId(plan.getId()); update.setStatus(planStatus); @@ -455,32 +417,6 @@ } } return sequence; } /** * 计ç®ç产计åçå©ä½æªä¸åæ°éï¼éæ±é - å·²ä¸åéï¼æå°ä¸º 0ï¼ã */ private BigDecimal resolveRemainingQuantity(ProductionPlan plan) { // 空对象æ 0 å¤ç if (plan == null) { return BigDecimal.ZERO; } // éæ±é为空æå°äºçäº 0ï¼è§ä¸ºæ å©ä½ BigDecimal requiredQuantity = Optional.ofNullable(plan.getQtyRequired()).orElse(BigDecimal.ZERO); if (requiredQuantity.compareTo(BigDecimal.ZERO) <= 0) { return BigDecimal.ZERO; } // å·²ä¸åé为空æå°äºçäº 0ï¼å©ä½å³éæ±é BigDecimal issuedQuantity = Optional.ofNullable(plan.getQuantityIssued()).orElse(BigDecimal.ZERO); if (issuedQuantity.compareTo(BigDecimal.ZERO) <= 0) { return requiredQuantity; } // å·²ä¸åé大äºçäºéæ±éï¼å©ä½å½é¶ if (issuedQuantity.compareTo(requiredQuantity) >= 0) { return BigDecimal.ZERO; } // æ£å¸¸åºæ¯è¿åå·®å¼ return requiredQuantity.subtract(issuedQuantity); } /** src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java
@@ -1,11 +1,13 @@ package com.ruoyi.purchase.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.account.service.purchase.AccountPurchasePaymentService; import com.ruoyi.basic.service.ISupplierService; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.framework.aspectj.lang.enums.BusinessType; import com.ruoyi.framework.web.domain.R; import com.ruoyi.purchase.dto.SavePaymentDto; import com.ruoyi.purchase.dto.VatDto; import com.ruoyi.purchase.service.PurchaseReportService; import com.ruoyi.purchase.vo.PurchaseReportVo; @@ -15,6 +17,7 @@ import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -28,6 +31,7 @@ private final ISupplierService supplierService; private final PurchaseReportService purchaseReportService; private final AccountPurchasePaymentService accountPurchasePaymentService; @GetMapping("/list") @@ -74,4 +78,11 @@ public R supplierTransactionsDetails(Page page, Long supplierId) { return R.ok(supplierService.supplierTransactionsDetails(page,supplierId)); } @PostMapping("/savePayment") @Log(title = "æ°å¢ä»æ¬¾", businessType = BusinessType.INSERT) @Operation(summary = "æ°å¢ä»æ¬¾") public R savePayment(@RequestBody SavePaymentDto dto) { return R.ok(accountPurchasePaymentService.savePayment(dto)); } } src/main/java/com/ruoyi/purchase/dto/SavePaymentDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,35 @@ package com.ruoyi.purchase.dto; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDate; /** * éè´ç®¡ç--ä¾åºå徿¥ æ°å¢ä»æ¬¾è¯·æ±åæ° */ @Data @Schema(name = "SavePaymentDto", description = "æ°å¢ä»æ¬¾è¯·æ±åæ°") public class SavePaymentDto { @Schema(description = "ä¾åºåID") private Long supplierId; @Schema(description = "éè´ååå·") private String purchaseContractNumber; @Schema(description = "仿¬¾æ¥æ") @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate paymentDate; @Schema(description = "仿¬¾éé¢") private BigDecimal paymentAmount; @Schema(description = "仿¬¾æ¹å¼") private String paymentMethod; @Schema(description = "夿³¨") private String remark; } src/main/java/com/ruoyi/sales/controller/MetricStatisticsController.java
@@ -1,18 +1,22 @@ package com.ruoyi.sales.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.account.service.sales.AccountSalesCollectionService; import com.ruoyi.basic.service.ICustomerService; import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.framework.aspectj.lang.enums.BusinessType; import com.ruoyi.framework.web.controller.BaseController; import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.framework.web.domain.R; import com.ruoyi.sales.dto.SaveReceiptPaymentDto; import com.ruoyi.sales.dto.StatisticsTableDto; import com.ruoyi.sales.service.impl.MetricStatisticsServiceImpl; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -28,6 +32,7 @@ private final MetricStatisticsServiceImpl metricStatisticsService; private final ICustomerService customerService; private final AccountSalesCollectionService accountSalesCollectionService; @Operation(summary = "头鍿»è®¡") @GetMapping("/total") @@ -55,4 +60,11 @@ return R.ok(customerService.customewTransactionsDetails(page,customerId)); } @PostMapping("/saveReceiptPayment") @Log(title = "æ°å¢å款", businessType = BusinessType.INSERT) @Operation(summary = "æ°å¢å款") public R saveReceiptPayment(@RequestBody SaveReceiptPaymentDto dto) { return R.ok(accountSalesCollectionService.saveReceiptPayment(dto)); } } src/main/java/com/ruoyi/sales/dto/SaveReceiptPaymentDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,35 @@ package com.ruoyi.sales.dto; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDate; /** * è¥é管ç--客æ·å¾æ¥ æ°å¢å款请æ±åæ° */ @Data @Schema(name = "SaveReceiptPaymentDto", description = "æ°å¢å款请æ±åæ°") public class SaveReceiptPaymentDto { @Schema(description = "客æ·ID") private Long customerId; @Schema(description = "éå®ååå·") private String salesContractNo; @Schema(description = "忬¾æ¥æ") @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate paymentDate; @Schema(description = "忬¾éé¢") private BigDecimal paymentAmount; @Schema(description = "忬¾æ¹å¼") private String paymentMethod; @Schema(description = "夿³¨") private String remark; } src/main/resources/application-dev.yml
@@ -74,7 +74,7 @@ druid: # ä¸»åºæ°æ®æº master: url: jdbc:mysql://localhost:3306/product-inventory-management-bdpro?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 url: jdbc:mysql://localhost:3306/product-inventory-management?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: 123456 # ä»åºæ°æ®æº src/main/resources/mapper/account/purchase/AccountPurchasePaymentMapper.xml
@@ -54,5 +54,13 @@ GROUP BY dateStr ORDER BY dateStr </select> <select id="selectStockInRecordIdsByPurchaseLedgerId" resultType="java.lang.Long"> SELECT sir.id FROM stock_in_record sir LEFT JOIN quality_inspect qi ON sir.record_type = 10 AND sir.record_id = qi.id WHERE sir.approval_status = 1 AND sir.record_type IN ('7','10') AND IF(sir.record_type = 7, sir.record_id, qi.purchase_ledger_id) = #{purchaseLedgerId} </select> </mapper> src/main/resources/mapper/account/sales/AccountSalesCollectionMapper.xml
@@ -112,5 +112,13 @@ GROUP BY dateStr ORDER BY dateStr </select> <select id="selectStockOutRecordIdsBySalesLedgerId" resultType="java.lang.Long"> SELECT sor.id FROM stock_out_record sor JOIN shipping_info s ON sor.record_id = s.id WHERE s.sales_ledger_id = #{salesLedgerId} AND sor.record_type = '13' AND sor.approval_status = 1 </select> </mapper> src/main/resources/mapper/basic/CustomerMapper.xml
@@ -177,14 +177,20 @@ left join ( select sl.id, sum(ascc.collection_amount) as receiptPaymentAmount from account_sales_collection ascc left join stock_out_record sor on FIND_IN_SET(sor.id, ascc.stock_out_record_ids) > 0 left join shipping_info s on sor.record_id = s.id LEFT JOIN sales_ledger sl ON s.sales_ledger_id = sl.id WHERE sor.record_type='13' and sor.approval_status=1 group by sl.id sum(t.collection_amount) as receiptPaymentAmount from ( select ascc.collection_amount, s.sales_ledger_id from account_sales_collection ascc left join stock_out_record sor on FIND_IN_SET(sor.id, ascc.stock_out_record_ids) > 0 left join shipping_info s on sor.record_id = s.id where sor.record_type='13' and sor.approval_status=1 group by ascc.id, s.sales_ledger_id ) t left join sales_ledger sl on t.sales_ledger_id = sl.id group by sl.id )T1 on T1.id = sl.id left join ( select sl.id, src/main/resources/mapper/basic/SupplierManageMapper.xml
@@ -13,6 +13,7 @@ T1.company_phone, T1.bank_account_name, T1.bank_account_num, T1.bank_code, T1.contact_user_name, T1.contact_user_phone, T1.maintain_user_id, @@ -47,6 +48,7 @@ T1.company_phone, T1.bank_account_name, T1.bank_account_num, T1.bank_code, T1.contact_user_name, T1.contact_user_phone, T1.maintain_user_id, @@ -106,17 +108,25 @@ left join ( select pl.id, sum(app.payment_amount) as paymentAmount from account_purchase_payment app left join account_payment_application apa on app.account_payment_application_id = apa.id left join stock_in_record sir on FIND_IN_SET(sir.id, apa.stock_in_record_ids) > 0 -- 10 ç±»åæå ³èè´¨æ£è¡¨ LEFT JOIN quality_inspect qi ON sir.record_type = 10 AND sir.record_id = qi.id -- å¨æå ³èéè´ï¼èªå¨éé 7 å 10ï¼ LEFT JOIN purchase_ledger pl ON pl.id = IF(sir.record_type = 7, sir.record_id, qi.purchase_ledger_id) WHERE sir.approval_status = 1 AND sir.record_type IN ('7','10') sum(t.payment_amount) as paymentAmount from ( select app.id, app.payment_amount, pl.id as purchase_ledger_id from account_purchase_payment app left join account_payment_application apa on app.account_payment_application_id = apa.id left join stock_in_record sir on FIND_IN_SET(sir.id, apa.stock_in_record_ids) > 0 -- 10 ç±»åæå ³èè´¨æ£è¡¨ LEFT JOIN quality_inspect qi ON sir.record_type = 10 AND sir.record_id = qi.id -- å¨æå ³èéè´ï¼èªå¨éé 7 å 10ï¼ LEFT JOIN purchase_ledger pl ON pl.id = IF(sir.record_type = 7, sir.record_id, qi.purchase_ledger_id) WHERE sir.approval_status = 1 AND sir.record_type IN ('7','10') group by app.id, pl.id ) t left join purchase_ledger pl on t.purchase_ledger_id = pl.id group by pl.id )T1 on T1.id = pl.id left join ( src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -33,7 +33,7 @@ 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) - IFNULL(t5.pending_approval_quantity, 0)) as no_quantity, NULL as no_quantity, IFNULL(t3.shipped_quantity, 0) as shipped_quantity, IFNULL(t6.return_quantity, 0) as return_quantity, IFNULL(t4.approved_stock_in_num, 0) as approved_stock_in_num,