doc/20260526_product_borrow_tables.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,49 @@ -- 产åé¢ç¨è¡¨ CREATE TABLE IF NOT EXISTS `product_borrow` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主é®', `borrow_no` varchar(50) DEFAULT NULL COMMENT 'é¢ç¨åå·', `product_model_id` bigint NOT NULL COMMENT '产åè§æ ¼ID', `batch_no` varchar(100) DEFAULT NULL COMMENT 'æ¹å·', `borrow_quantity` decimal(18,4) NOT NULL COMMENT 'é¢ç¨æ°é', `returned_quantity` decimal(18,4) DEFAULT 0 COMMENT 'å·²å½è¿æ°é', `borrower_id` bigint DEFAULT NULL COMMENT 'é¢ç¨äººID', `borrower_name` varchar(100) DEFAULT NULL COMMENT 'é¢ç¨äººå§å', `borrow_time` datetime NOT NULL COMMENT 'é¢ç¨æ¶é´', `expected_return_time` datetime DEFAULT NULL COMMENT 'é¢è®¡å½è¿æ¶é´', `approval_status` tinyint DEFAULT 0 COMMENT '审æ¹ç¶æï¼0-å¾ å®¡æ¹ï¼1-å·²éè¿ï¼2-已驳åï¼', `status` tinyint DEFAULT 0 COMMENT 'å½è¿ç¶æï¼0-æªå½è¿ï¼1-é¨åå½è¿ï¼2-å·²å ¨é¨å½è¿ï¼', `remark` varchar(500) DEFAULT NULL COMMENT '夿³¨', `tenant_id` bigint DEFAULT NULL COMMENT 'ç§æ·ID', `dept_id` bigint DEFAULT NULL COMMENT 'é¨é¨ID', `create_user` int DEFAULT NULL COMMENT 'å建人', `create_time` datetime DEFAULT NULL COMMENT 'å建æ¶é´', `update_user` int DEFAULT NULL COMMENT 'æ´æ°äºº', `update_time` datetime DEFAULT NULL COMMENT 'æ´æ°æ¶é´', PRIMARY KEY (`id`), KEY `idx_borrow_no` (`borrow_no`), KEY `idx_product_model_id` (`product_model_id`), KEY `idx_borrower_id` (`borrower_id`), KEY `idx_approval_status` (`approval_status`), KEY `idx_status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='产åé¢ç¨è¡¨'; -- 产åå½è¿è®°å½è¡¨ CREATE TABLE IF NOT EXISTS `product_borrow_return` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主é®', `borrow_id` bigint NOT NULL COMMENT 'é¢ç¨è®°å½ID', `product_model_id` bigint NOT NULL COMMENT '产åè§æ ¼ID', `batch_no` varchar(100) DEFAULT NULL COMMENT 'æ¹å·', `return_quantity` decimal(18,4) NOT NULL COMMENT 'å½è¿æ°é', `returner_id` bigint DEFAULT NULL COMMENT 'å½è¿äººID', `returner_name` varchar(100) DEFAULT NULL COMMENT 'å½è¿äººå§å', `return_time` datetime NOT NULL COMMENT 'å½è¿æ¶é´', `remark` varchar(500) DEFAULT NULL COMMENT '夿³¨', `tenant_id` bigint DEFAULT NULL COMMENT 'ç§æ·ID', `dept_id` bigint DEFAULT NULL COMMENT 'é¨é¨ID', `create_user` int DEFAULT NULL COMMENT 'å建人', `create_time` datetime DEFAULT NULL COMMENT 'å建æ¶é´', PRIMARY KEY (`id`), KEY `idx_borrow_id` (`borrow_id`), KEY `idx_product_model_id` (`product_model_id`), KEY `idx_returner_id` (`returner_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='产åå½è¿è®°å½è¡¨'; doc/²úÆ·Ä£¿éÓë¿â´æÄ£¿é·ÖÎöÎĵµ.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,714 @@ # äº§åæ¨¡åä¸åºå模å详ç»åæææ¡£ ## ä¸ãäº§åæ¨¡å (Product Module) ### 1. æ¨¡åæ¦è¿° äº§åæ¨¡åè´è´£ç®¡ç产åçåºç¡ä¿¡æ¯ï¼éç¨æ å½¢ç»æç»ç»äº§ååç±»ï¼æ¯æäº§åè§æ ¼åå·ç管çã ### 2. æ ¸å¿å®ä½ #### 2.1 Product (产å) | åæ®µ | ç±»å | 说æ | |------|------|------| | id | Long | 主é®IDï¼èªå¢ | | parentId | Long | ç¶äº§åIDï¼æ¯ææ å½¢ç»æï¼ | | productName | String | 产ååç§° | | tenantId | Long | ç§æ·IDï¼èªå¨å¡«å ï¼ | | createUser | Integer | åå»ºç¨æ·ï¼èªå¨å¡«å ï¼ | | deptId | Long | é¨é¨IDï¼èªå¨å¡«å ï¼ | | deptIds | Long[] | é¨é¨IDæ°ç»ï¼éæ°æ®åºåæ®µï¼ | **æ°æ®è¡¨**: `product` #### 2.2 ProductModel (产åè§æ ¼åå·) | åæ®µ | ç±»å | 说æ | |------|------|------| | id | Long | 主é®IDï¼èªå¢ | | productId | Long | å ³è产åID | | model | String | è§æ ¼åå· | | productCode | String | 产åç¼ç | | unit | String | åä½ | | tenantId | Long | ç§æ·ID | | createUser | Integer | åå»ºç¨æ· | | deptId | Long | é¨é¨ID | | inboundNum | BigDecimal | å ¥åºæ°éï¼éæ°æ®åºåæ®µï¼ | | outboundNum | BigDecimal | åºåºæ°éï¼éæ°æ®åºåæ®µï¼ | | stockQuantity | BigDecimal | å©ä½åºåï¼éæ°æ®åºåæ®µï¼ | **æ°æ®è¡¨**: `product_model` ### 3. DTO æ°æ®ä¼ è¾å¯¹è±¡ #### 3.1 ProductDto ç»§æ¿èª `Product`ï¼æ©å±åæ®µï¼ - `productModelList`: List<ProductModel> - 产åè§æ ¼åå·å表 #### 3.2 ProductModelDto ç»§æ¿èª `ProductModel`ï¼æ©å±åæ®µï¼ - `productStructureList`: List<ProductStructureDto> - 产åç»æå表ï¼ç¨äºBOMï¼ #### 3.3 ProductTreeDto ç¨äºæ å½¢ç»æå±ç¤ºï¼ - `id`, `parentId`, `productName`, `label` - `children`: List<ProductTreeDto> - åèç¹å表 #### 3.4 ProductModelVo ç»§æ¿èª `ProductModel`ï¼æ©å±åæ®µï¼ - `batchNoList`: List<String> - æ¹å·å表 ### 4. Controller API æ¥å£ **ProductController** (`/basic/product`) | æ¹æ³ | HTTP | è·¯å¾ | 说æ | |------|------|------|------| | selectProductList | GET | /list | æ¥è¯¢äº§ååè¡¨ï¼æ å½¢ç»æï¼ | | selectModelList | GET | /modelList | æ ¹æ®äº§åIDæ¥è¯¢è§æ ¼åå·å表 | | addOrEditProduct | POST | /addOrEditProduct | æ°å¢/æ´æ°äº§å | | addOrEditProductModel | POST | /addOrEditProductModel | æ°å¢/æ´æ°äº§åè§æ ¼åå· | | remove | DELETE | /delProduct | å é¤äº§åï¼æ¹éï¼ | | delProductModel | DELETE | /delProductModel | å é¤äº§åè§æ ¼åå·ï¼æ¹éï¼ | | selectModelListPage | GET | /modelListPage | 产åè§æ ¼å页æ¥è¯¢ | | listPageProductModel | GET | /pageModel | å页æ¥è¯¢ææäº§ååå· | | importProductModel | POST | /import | å¯¼å ¥äº§åè§æ ¼åå· | | importProduct | GET | /export | ä¸è½½äº§åå¯¼å ¥æ¨¡æ¿ | ### 5. Service ä¸å¡é»è¾ #### 5.1 IProductService ```java // æ°å¢æç¼è¾äº§å int addOrEditProduct(ProductDto productDto) - éªè¯ç¶èç¹æ¯å¦åå¨ - éªè¯äº§ååç§°å¨åä¸ç¶èç¹ä¸å¯ä¸ - æ°å¢/æ´æ°äº§å // å é¤äº§åï¼æ¹éï¼ int delProductByIds(Long[] ids) - 级èå é¤å ³èç产åè§æ ¼åå· - å é¤äº§åæ¬èº« // æ¥è¯¢äº§ååè¡¨ï¼æ å½¢ï¼ List<ProductTreeDto> selectProductList(ProductDto productDto) - æ¥è¯¢æ ¹èç¹ï¼parentId为nullï¼ - éå½æå»ºåæ // å页æ¥è¯¢äº§ååå· IPage<ProductModelVo> listPageProductModel(Page<ProductModelVo> page, ProductModel productModel) ``` #### 5.2 IProductModelService ```java // æ°å¢æç¼è¾äº§åè§æ ¼åå· int addOrEditProductModel(ProductModelDto productModelDto) - éªè¯è§æ ¼åå·+产åç¼ç å¯ä¸æ§ - æ°å¢/æ´æ°è§æ ¼åå· // å é¤äº§åè§æ ¼åå· int delProductModel(Long[] ids) - æ£æ¥æ¯å¦åå¨éå®å°è´¦/éè´å°è´¦å ³è - æ£æ¥æ¯å¦åå¨BOMæ°æ®å ³è - æ§è¡å é¤ // æ¥è¯¢è§æ ¼åå·å表 List<ProductModel> selectModelList(ProductDto productDto) // å页æ¥è¯¢ IPage<ProductModel> modelListPage(Page page, ProductDto productDto) // å¯¼å ¥äº§åè§æ ¼åå· AjaxResult importProductModel(MultipartFile file, Integer productId) - éªè¯äº§åæ¯å¦åå¨ - éªè¯å¯¼å ¥æ°æ®ï¼äº§åç¼ç ãè§æ ¼åå·ãåä½å¿ å¡«ï¼ - å»éå¤çï¼è·³è¿å·²åå¨çåå·ï¼ - æ¹éä¿å ``` ### 6. ä¸å¡çº¦æ 1. **产åå é¤çº¦æ**: - åå¨éå®å°è´¦/éè´å°è´¦å ³èç产åä¸è½å é¤ 2. **产åè§æ ¼åå·å é¤çº¦æ**: - åå¨éå®å°è´¦/éè´å°è´¦å ³èä¸è½å é¤ - åå¨BOMæ°æ®å ³èä¸è½å é¤ 3. **å¯ä¸æ§çº¦æ**: - åä¸ç¶èç¹ä¸äº§ååç§°å¯ä¸ - è§æ ¼åå·+产åç¼ç ç»åå¯ä¸ ### 7. æ°æ®æµç¨å¾ ``` 产åç®¡çæµç¨ï¼ âââââââââââââââ âââââââââââââââ âââââââââââââââ â 产ååç±» âââââ>â 产å âââââ>â 产åè§æ ¼åå· â â (ç¶èç¹) â â (åèç¹) â â (å ·ä½åå·) â âââââââââââââââ âââââââââââââââ âââââââââââââââ â â¼ âââââââââââââââ â éå®å°è´¦ â â éè´å°è´¦ â â BOMæ°æ® â âââââââââââââââ ``` --- ## äºãåºå模å (Stock Module) ### 1. æ¨¡åæ¦è¿° åºå模å管ç产åçåºåä¿¡æ¯ï¼æ¯æå ¥åºãåºåºãåºåæ¥è¯¢ãå»ç»/è§£å»çåè½ï¼éç¨æ¹å·ç®¡çåºåã ### 2. æ ¸å¿å®ä½ #### 2.1 StockInventory (åºå表) | åæ®µ | ç±»å | 说æ | |------|------|------| | id | Long | 主é®ID | | productModelId | Long | 产åè§æ ¼IDï¼å¿ å¡«ï¼ | | batchNo | String | æ¹å· | | qualitity | BigDecimal | åºåæ°é | | lockedQuantity | BigDecimal | å»ç»/é宿°é | | warnNum | BigDecimal | é¢è¦æ°é | | version | Integer | çæ¬å· | | remark | String | 夿³¨ | | createTime | LocalDateTime | å建æ¶é´ | | updateTime | LocalDateTime | æ´æ°æ¶é´ | | createUser | Integer | åå»ºç¨æ· | | deptId | Long | é¨é¨ID | **æ°æ®è¡¨**: `stock_inventory` #### 2.2 StockInRecord (å ¥åºè®°å½) | åæ®µ | ç±»å | 说æ | |------|------|------| | id | Long | 主é®ID | | inboundBatches | String | å ¥åºæ¹æ¬¡ | | stockInNum | BigDecimal | å ¥åºæ°é | | batchNo | String | æ¹å· | | recordType | String | è®°å½ç±»åï¼æä¸¾ï¼ | | recordId | Long | å ³èè®°å½ID | | productModelId | Long | 产åè§æ ¼ID | | type | String | ç±»åï¼0åæ ¼/1ä¸åæ ¼ï¼ | | warnNum | BigDecimal | é¢è¦æ°é | | approvalStatus | Integer | 审æ¹ç¶æï¼0å¾ å®¡æ¹/1éè¿/2驳åï¼ | | remark | String | 夿³¨ | **æ°æ®è¡¨**: `stock_in_record` #### 2.3 StockOutRecord (åºåºè®°å½) | åæ®µ | ç±»å | 说æ | |------|------|------| | id | Long | 主é®ID | | outboundBatches | String | åºåºæ¹æ¬¡ | | stockOutNum | BigDecimal | åºåºæ°é | | batchNo | String | æ¹å· | | recordType | String | è®°å½ç±»åï¼æä¸¾ï¼ | | recordId | Long | å ³èè®°å½ID | | productModelId | Long | 产åè§æ ¼ID | | type | String | ç±»åï¼0åæ ¼/1ä¸åæ ¼ï¼ | | approvalStatus | Integer | 审æ¹ç¶æï¼0å¾ å®¡æ¹/1éè¿/2驳å/3éå®åºåºå¾ ç¡®è®¤ï¼ | | remark | String | 夿³¨ | **æ°æ®è¡¨**: `stock_out_record` ### 3. DTO æ°æ®ä¼ è¾å¯¹è±¡ #### 3.1 StockInventoryDto ç»§æ¿èª `StockInventory`ï¼æ©å±åæ®µï¼ | åæ®µ | ç±»å | 说æ | |------|------|------| | productName | String | 产ååç§° | | model | String | è§æ ¼åå· | | unit | String | åä½ | | recordType | String | å ¥åºç±»å | | recordId | Long | å ¥åºç±»å对åºID | | reportDate | LocalDate | æ¥è¡¨æ¥æ | | startMonth | endMonth | åºåææ¥æ¥è¯¢å段 | | totalStockIn | BigDecimal | æ»å ¥åºé | | totalStockOut | BigDecimal | æ»åºåºé | | currentStock | BigDecimal | å½ååºå | | stockType | String | åºåç±»åï¼qualified/unqualifiedï¼ | | qualifiedQuantity | BigDecimal | åæ ¼åºåæ°é | | unQualifiedQuantity | BigDecimal | ä¸åæ ¼åºåæ°é | | qualifiedLockedQuantity | BigDecimal | åæ ¼åºåå»ç»æ°é | | unQualifiedLockedQuantity | BigDecimal | ä¸åæ ¼åºåå»ç»æ°é | | qualifiedPendingOutQuantity | BigDecimal | åæ ¼åºåå¾ å®¡æ ¸åºåºæ°é | | productId | Long | 产åID | | topParentProductId | Long | é¡¶é¨ç¶äº§åID | ### 4. Controller API æ¥å£ **StockInventoryController** (`/stockInventory`) | æ¹æ³ | HTTP | è·¯å¾ | 说æ | |------|------|------|------| | pagestockInventory | GET | /pagestockInventory | å页æ¥è¯¢åºå | | pageListCombinedStockInventory | GET | /pageListCombinedStockInventory | å页æ¥è¯¢èååºåå表 | | getBatchNoQty | GET | /getBatchNoQty | æ¥è¯¢å¯¹åºæ¹å·åæ°é | | addstockInventory | POST | /addstockInventory | æ°å¢åºåï¼å ¥åºï¼ | | subtractStockInventory | POST | /subtractStockInventory | æ£ååºåï¼åºåºï¼ | | addStockInRecordOnly | POST | /addStockInRecordOnly | æ°å¢å ¥åºè®°å½ï¼ä¸è°æ´åºåï¼ | | addStockOutRecordOnly | POST | /addStockOutRecordOnly | æ°å¢åºåºè®°å½ï¼ä¸è°æ´åºåï¼ | | importStockInventory | POST | /importStockInventory | å¯¼å ¥åºå | | downloadStockInventory | POST | /downloadStockInventory | ä¸è½½åºåå¯¼å ¥æ¨¡æ¿ | | exportStockInventory | POST | /exportStockInventory | 导åºåºå | | stockInventoryPage | GET | /stockInventoryPage | åºåæ¥è¡¨æ¥è¯¢ | | stockInAndOutRecord | GET | /stockInAndOutRecord | ç»è®¡å ¥åºåºåºè®°å½ | | frozenStock | POST | /frozenStock | å»ç»åºå | | thawStock | POST | /thawStock | è§£å»åºå | | getByModelId | GET | /getByModelId | æ ¹æ®äº§åè§æ ¼IDè·åå ¥åºè®°å½ | **StockInRecordController** (`/stockInRecord`) | æ¹æ³ | HTTP | è·¯å¾ | 说æ | |------|------|------|------| | listPage | GET | /listPage | å ¥åºç®¡çå表 | | delete | DELETE | / | å é¤å ¥åºè®°å½ | | deletePending | DELETE | /pending | å é¤å¾ 审æ¹å ¥åºè®°å½ | | exportStockInRecord | POST | /exportStockInRecord | 导åºå ¥åºè®°å½ | | approve | POST | /approve | æ¹é审æ¹å ¥åºè®°å½ | | reAudit | POST | /reAudit | æ¹éåå®¡å ¥åºè®°å½ | **StockOutRecordController** (`/stockOutRecord`) | æ¹æ³ | HTTP | è·¯å¾ | 说æ | |------|------|------|------| | listPage | GET | /listPage | åºåºç®¡çå表 | | add | POST | / | æ°å¢åºåºè®°å½ | | update | PUT | /{id} | æ´æ°åºåºè®°å½ | | delete | DELETE | / | å é¤åºåºè®°å½ | | deletePending | DELETE | /pending | å é¤å¾ 审æ¹åºåºè®°å½ | | exportStockOutRecord | POST | /exportStockOutRecord | 导åºåºåºè®°å½ | | approve | POST | /approve | æ¹é审æ¹åºåºè®°å½ | ### 5. Service æ ¸å¿ä¸å¡é»è¾ #### 5.1 StockInventoryService ```java // å ¥åºæä½ï¼è®°å½+åºåè°æ´ï¼ Boolean addstockInventory(StockInventoryDto dto) 1. çææéªè¯æ¹å· 2. åå»ºå ¥åºè®°å½(StockInRecord) 3. æ£æ¥åºåæ¯å¦åå¨ - ä¸åå¨ï¼æ°å¢åºåè®°å½ - åå¨ï¼æ´æ°åºåæ°é // åºåºæä½ï¼è®°å½+åºåè°æ´ï¼ Boolean subtractStockInventory(StockInventoryDto dto) 1. æ¥è¯¢åºåè®°å½ 2. éªè¯åºåå è¶³ï¼æ£é¤å»ç»æ°éï¼ 3. å建åºåºè®°å½(StockOutRecord) 4. æ£ååºåæ°é // ä» åå»ºå ¥åºè®°å½ï¼ä¸è°æ´åºåï¼ Boolean addStockInRecordOnly(StockInventoryDto dto) - ç¨äºæå·¥å½å ¥å岿°æ® // ä» å建åºåºè®°å½ï¼ä¸è°æ´åºåï¼ Boolean addStockOutRecordOnly(StockInventoryDto dto) - éªè¯å¯ç¨åºåï¼åºå-å»ç»-å¾ å®¡æ ¸åºåºï¼ - å建åºåºè®°å½ // æ¹å·èªå¨çæè§å // æ ¼å¼: æ¥æ-产åç¼ç -åºå· // 示ä¾: 20260526-ABC001-001 String generateAutoBatchNo(Long productModelId) // å»ç»åºå Boolean frozenStock(StockInventoryDto dto) - éªè¯å»ç»æ°éä¸è¶ è¿åºåæ°é - ç´¯å å»ç»æ°é // è§£å»åºå Boolean thawStock(StockInventoryDto dto) - éªè¯è§£å»æ°éä¸è¶ è¿å»ç»æ°é - æ£åå»ç»æ°é ``` ### 6. æä¸¾ç±»å #### 6.1 å ¥åºè®°å½ç±»å (StockInQualifiedRecordTypeEnum) | 代ç | 说æ | |------|------| | CUSTOMIZATION_STOCK_IN | èªå®ä¹å ¥åºï¼æå·¥å ¥åºï¼ | #### 6.2 åºåºè®°å½ç±»å (StockOutQualifiedRecordTypeEnum) | 代ç | 说æ | |------|------| | CUSTOMIZATION_STOCK_OUT | èªå®ä¹åºåºï¼æå·¥åºåºï¼ | #### 6.3 审æ¹ç¶æ (ReviewStatusEnum) | å¼ | 说æ | |------|------| | 0 | å¾ å®¡æ¹ | | 1 | éè¿ | | 2 | 驳å | | 3 | éå®åºåºå¾ 确认 | ### 7. ä¸å¡æµç¨å¾ ``` å ¥åºæµç¨ï¼ ââââââââââââ ââââââââââââ ââââââââââââ â å ¥åºç³è¯· âââââ>â åå»ºå ¥åº âââââ>â æ´æ°åºå â â (æ¥æº) â â è®°å½ â â æ°é â ââââââââââââ ââââââââââââ ââââââââââââ â â¼ ââââââââââââ â çææ¹å· â â (èªå¨/æå·¥)â ââââââââââââ åºåºæµç¨ï¼ ââââââââââââ ââââââââââââ ââââââââââââ â åºåºç³è¯· âââââ>â éªè¯åºå âââââ>â å建åºåº â â â â æ¯å¦å è¶³ â â è®°å½ â ââââââââââââ ââââââââââââ ââââââââââââ â â¼ ââââââââââââ â æ£ååºå â â æ°é â ââââââââââââ åºåå»ç»/è§£å»ï¼ ââââââââââââ ââââââââââââ â å»ç»ç³è¯· âââââ>â ç´¯å å»ç» â â â â æ°é â ââââââââââââ ââââââââââââ ââââââââââââ ââââââââââââ â è§£å»ç³è¯· âââââ>â æ£åå»ç» â â â â æ°é â ââââââââââââ ââââââââââââ ``` ### 8. åºå计ç®å ¬å¼ ``` å¯ç¨åºå = åºåæ°é - å»ç»æ°é - å¾ å®¡æ ¸åºåºæ°é åºåºéªè¯æ¡ä»¶: ç³è¯·åºåºæ°é <= å¯ç¨åºå å»ç»éªè¯æ¡ä»¶: å»ç»æ°é <= åºåæ°é è§£å»éªè¯æ¡ä»¶: è§£å»æ°é <= å·²å»ç»æ°é ``` --- ## ä¸ã模åå ³èå ³ç³» ### 1. æ°æ®å ³è ``` Product (产å) â âââ productId ââ> ProductModel (产åè§æ ¼åå·) â â â âââ productModelId ââ> StockInventory (åæ ¼åºå) â â â âââ productModelId ââ> StockUninventory (ä¸åæ ¼åºå) â â â âââ productModelId ââ> StockInRecord (å ¥åºè®°å½) â â â âââ productModelId ââ> StockOutRecord (åºåºè®°å½) â âââ 被å 餿¶çº§èå é¤ ProductModel ``` ### 2. å é¤çº¦æ | 模å | å é¤åæ£æ¥ | |------|-----------| | Product | æ£æ¥éå®å°è´¦å ³è | | ProductModel | æ£æ¥éå®å°è´¦ãBOMæ°æ®å ³è | | StockInventory | ä¸å è®¸ç´æ¥å é¤ï¼ééè¿åºåºæ£å | ### 3. å ³é®ä¸å¡åºæ¯ #### 3.1 产åå ¥åºåºæ¯ 1. éè´å ¥åº â çæå ¥åºè®°å½ â å¢å åºå 2. çäº§å ¥åº â çæå ¥åºè®°å½ â å¢å åºå 3. æå·¥å ¥åº â èªå®ä¹å ¥åºç±»å #### 3.2 产ååºåºåºæ¯ 1. éå®åºåº â æ£æ¥åºå â å建åºåºè®°å½ â æ£ååºå 2. çäº§é¢æ â æ£æ¥åºå â å建åºåºè®°å½ â æ£ååºå 3. æå·¥åºåº â èªå®ä¹åºåºç±»å #### 3.3 åºåå»ç»åºæ¯ 1. 订åéå® â å»ç»åºå 2. è´¨éé®é¢ â å»ç»åºå 3. é®é¢è§£å³ â è§£å»åºå --- ## åãæä»¶ç»æ ### äº§åæ¨¡åæä»¶ ``` com.ruoyi.basic/ âââ controller/ â âââ ProductController.java âââ service/ â âââ IProductService.java â âââ IProductModelService.java â âââ impl/ â âââ ProductServiceImpl.java â âââ ProductModelServiceImpl.java âââ mapper/ â âââ ProductMapper.java â âââ ProductModelMapper.java âââ pojo/ â âââ Product.java â âââ ProductModel.java âââ dto/ â âââ ProductDto.java â âââ ProductModelDto.java â âââ ProductTreeDto.java âââ vo/ â âââ ProductModelVo.java âââ excel/ âââ (å¯¼å ¥å¯¼åºç¸å ³) ``` ### åºå模åæä»¶ ``` com.ruoyi.stock/ âââ controller/ â âââ StockInventoryController.java â âââ StockInRecordController.java â âââ StockOutRecordController.java â âââ StockUninventoryController.java âââ service/ â âââ StockInventoryService.java â âââ StockInRecordService.java â âââ StockOutRecordService.java â âââ impl/ â âââ StockInventoryServiceImpl.java â âââ StockInRecordServiceImpl.java â âââ StockOutRecordServiceImpl.java â âââ StockUninventoryServiceImpl.java âââ mapper/ â âââ StockInventoryMapper.java â âââ StockInRecordMapper.java â âââ StockOutRecordMapper.java âââ pojo/ â âââ StockInventory.java â âââ StockInRecord.java â âââ StockOutRecord.java âââ dto/ â âââ StockInventoryDto.java â âââ StockInRecordDto.java â âââ StockOutRecordDto.java âââ excel/ âââ StockInventoryExportData.java âââ StockInRecordExportData.java âââ StockOutRecordExportData.java ``` --- ## äºã注æäºé¡¹ 1. **äºå¡ç®¡ç**: å ¥åº/åºåºæä½ä½¿ç¨ `@Transactional(rollbackFor = Exception.class)` ä¿è¯æ°æ®ä¸è´æ§ 2. **æ¹å·ç®¡ç**: - èªå¨çææ ¼å¼: `YYYYMMDD-产åç¼ç -åºå·` - æ¯ææå·¥æå®æ¹å· - å䏿¹å·åä¸äº§åè§æ ¼åå¹¶åºå 3. **åºåå®å ¨**: - åºåºåæ£æ¥å¯ç¨åºå - å»ç»æ°éä¸å¯ç¨äºåºåº - å¾ å®¡æ ¸åºåºæ°éè®¡å ¥å¯ç¨åºåè®¡ç® 4. **å¤ç§æ·æ¯æ**: éè¿ `tenantId` åæ®µå®ç°æ°æ®é离 5. **é¨é¨é离**: éè¿ `deptId` åæ®µå®ç°é¨é¨æ°æ®é离 --- ## å ã产åé¢ç¨å½è¿æ¨¡å (Product Borrow Module) ### 1. æ¨¡åæ¦è¿° 产åé¢ç¨å½è¿æ¨¡å管ç产åçé¢ç¨åå½è¿æµç¨ï¼æ¯æå®¡æ¹æµç¨ååºåèå¨ã ### 2. æ ¸å¿å®ä½ #### 2.1 ProductBorrow (产åé¢ç¨è¡¨) | åæ®µ | ç±»å | 说æ | |------|------|------| | id | Long | 主é®ID | | borrowNo | String | é¢ç¨åå·ï¼èªå¨çæï¼ | | productModelId | Long | 产åè§æ ¼ID | | batchNo | String | æ¹å· | | borrowQuantity | BigDecimal | é¢ç¨æ°é | | returnedQuantity | BigDecimal | å·²å½è¿æ°é | | borrowerId | Long | é¢ç¨äººIDï¼ç³»ç»ç¨æ·ï¼ | | borrowerName | String | é¢ç¨äººå§å | | borrowTime | LocalDateTime | é¢ç¨æ¶é´ | | expectedReturnTime | LocalDateTime | é¢è®¡å½è¿æ¶é´ | | approvalStatus | Integer | 审æ¹ç¶æï¼0å¾ å®¡æ¹/1å·²éè¿/2已驳åï¼ | | status | Integer | å½è¿ç¶æï¼0æªå½è¿/1é¨åå½è¿/2å·²å ¨é¨å½è¿ï¼ | | remark | String | 夿³¨ | **æ°æ®è¡¨**: `product_borrow` #### 2.2 ProductBorrowReturn (产åå½è¿è®°å½è¡¨) | åæ®µ | ç±»å | 说æ | |------|------|------| | id | Long | 主é®ID | | borrowId | Long | é¢ç¨è®°å½ID | | productModelId | Long | 产åè§æ ¼ID | | batchNo | String | æ¹å· | | returnQuantity | BigDecimal | å½è¿æ°é | | returnerId | Long | å½è¿äººIDï¼ç³»ç»ç¨æ·ï¼ | | returnerName | String | å½è¿äººå§å | | returnTime | LocalDateTime | å½è¿æ¶é´ | | remark | String | 夿³¨ | **æ°æ®è¡¨**: `product_borrow_return` ### 3. Controller API æ¥å£ **ProductBorrowController** (`/productBorrow`) | æ¹æ³ | HTTP | è·¯å¾ | 说æ | |------|------|------|------| | listPage | GET | /listPage | å页æ¥è¯¢é¢ç¨è®°å½ | | getDetail | GET | /{id} | æ¥è¯¢é¢ç¨è®°å½è¯¦æ | | add | POST | / | æ°å¢é¢ç¨è®°å½ï¼å¾ 审æ¹ï¼ | | update | PUT | /{id} | ä¿®æ¹é¢ç¨è®°å½ | | delete | DELETE | / | å é¤é¢ç¨è®°å½ | | approve | POST | /approve | æ¹é审æ¹é¢ç¨è®°å½ | | reAudit | POST | /reAudit | æ¹éå审é¢ç¨è®°å½ | **ProductBorrowReturnController** (`/productBorrowReturn`) | æ¹æ³ | HTTP | è·¯å¾ | 说æ | |------|------|------|------| | listPage | GET | /listPage | å页æ¥è¯¢å½è¿è®°å½ | | listByBorrowId | GET | /listByBorrowId/{borrowId} | æ¥è¯¢æé¢ç¨è®°å½çå½è¿è®°å½ | | add | POST | / | æ°å¢å½è¿è®°å½ï¼ç´æ¥å¢å åºåï¼ | ### 4. ä¸å¡æµç¨ ``` é¢ç¨æµç¨ï¼ ââââââââââââ ââââââââââââ ââââââââââââ â æ°å¢é¢ç¨ âââââ>â å¾ å®¡æ¹ âââââ>â 审æ¹éè¿ â â è®°å½ â â ç¶æ â â â ââââââââââââ ââââââââââââ ââââââââââââ â â¼ ââââââââââââââââ â æ£ååºå â â (åºåºè®°å½) â ââââââââââââââââ å½è¿æµç¨ï¼ ââââââââââââ ââââââââââââ ââââââââââââ â éæ©é¢ç¨ âââââ>â å¡«åå½è¿ âââââ>â éªè¯å½è¿ â â è®°å½ â â ä¿¡æ¯ â â æ°é â ââââââââââââ ââââââââââââ ââââââââââââ â â â¼ â¼ ââââââââââââ ââââââââââââââââ â å¢å åºå â â æ´æ°é¢ç¨ç¶æ â â (å ¥åº) â ââââââââââââââââ ââââââââââââ ``` ### 5. ä¸å¡çº¦æ 1. **é¢ç¨çº¦æ**: - é¢ç¨äººä»ç³»ç»ç¨æ·è¡¨éæ© - æ°å¢é¢ç¨è®°å½ç¶æä¸º"å¾ å®¡æ¹" - åªæå¾ å®¡æ¹ç¶ææè½ä¿®æ¹/å é¤ 2. **审æ¹çº¦æ**: - åªæå¾ å®¡æ¹ç¶ææè½å®¡æ¹ - 审æ¹éè¿åèªå¨æ£ååºå - 审æ¹é©³å䏿£ååºå 3. **å½è¿çº¦æ**: - å½è¿æ°éä¸è½è¶ è¿å©ä½å¯å½è¿æ°é - é¢ç¨è®°å½å¿ 须审æ¹éè¿æè½å½è¿ - å½è¿ç´æ¥å¢å åºåï¼æ éå®¡æ¹ - å½è¿äººä»ç³»ç»ç¨æ·è¡¨éæ© ### 6. é¢ç¨åå·çæè§å ``` æ ¼å¼ï¼LY + å¹´ææ¥ + 4ä½åºå· 示ä¾ï¼LY202605260001 ``` ### 7. æä¸¾ç±»åæ©å± **å ¥åºç±»å** (StockInQualifiedRecordTypeEnum): - `PRODUCT_BORROW_RETURN("23", "产åå½è¿å ¥åº")` **åºåºç±»å** (StockOutQualifiedRecordTypeEnum): - `PRODUCT_BORROW("16", "产åé¢ç¨åºåº")` - `PRODUCT_RETURN("17", "产åå½è¿å ¥åº")` ### 8. æä»¶ç»æ ``` com.ruoyi.stock/ âââ controller/ â âââ ProductBorrowController.java â âââ ProductBorrowReturnController.java âââ service/ â âââ ProductBorrowService.java â âââ ProductBorrowReturnService.java â âââ impl/ â âââ ProductBorrowServiceImpl.java â âââ ProductBorrowReturnServiceImpl.java âââ mapper/ â âââ ProductBorrowMapper.java â âââ ProductBorrowReturnMapper.java âââ pojo/ â âââ ProductBorrow.java â âââ ProductBorrowReturn.java âââ dto/ âââ ProductBorrowDto.java âââ ProductBorrowReturnDto.java resources/mapper/stock/ âââ ProductBorrowMapper.xml âââ ProductBorrowReturnMapper.xml ``` ### 9. æ°æ®åºè¡¨ SQLèæ¬ä½ç½®: `doc/20260526_product_borrow_tables.sql` doc/²úÆ·ÁìÓù黹ģ¿é-ǰ¶Ë¶Ô½ÓÎĵµ.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,696 @@ # 产åé¢ç¨å½è¿æ¨¡å - åç«¯å¯¹æ¥ææ¡£ ## ä¸ãæ¨¡åæ¦è¿° 产åé¢ç¨å½è¿æ¨¡åç¨äºç®¡ç产åçé¢ç¨åå½è¿æµç¨ï¼ - **é¢ç¨**ï¼æ°å¢é¢ç¨æ¶èªå¨å®æåºåºæä½ï¼èªå¨å®¡æ¹éè¿ï¼åæ¶å®¡æ¹æµç¨ - **å½è¿**ï¼æ°å¢å½è¿æ¶èªå¨å®æå ¥åºæä½ï¼èªå¨å®¡æ¹éè¿ **注æ**ï¼æææ¥å£ç»ä¸ä½¿ç¨ POST æ¹å¼ --- ## äºãAPI æ¥å£è¯´æ ### 1. 产åé¢ç¨æ¥å£ #### 1.1 å页æ¥è¯¢é¢ç¨è®°å½ **请æ±** ``` POST /productBorrow/listPage Content-Type: application/json ``` **请æ±ä½** ```json { "current": 1, // å½å页ç ï¼é»è®¤1 "size": 10, // æ¯é¡µæ¡æ°ï¼é»è®¤10 "borrowNo": "LY202605260001", // éå¡«ï¼é¢ç¨åå·ï¼æ¨¡ç³æ¥è¯¢ "productModelId": 100, // éå¡«ï¼äº§åè§æ ¼ID "topParentProductId": 277, // éå¡«ï¼é¡¶é¨ç¶äº§åIDï¼äº§ååç±»IDï¼ï¼ç¨äºçé产ååç±»æ "model": "M6", // éå¡«ï¼è§æ ¼åå·ï¼æ¨¡ç³æ¥è¯¢ "borrowerId": 1, // éå¡«ï¼é¢ç¨äººID "borrowerName": "å¼ ä¸", // éå¡«ï¼é¢ç¨äººå§åï¼æ¨¡ç³æ¥è¯¢ "approvalStatus": 0, // éå¡«ï¼å®¡æ¹ç¶æï¼0å¾ å®¡æ¹/1å·²éè¿/2已驳å "status": 0 // éå¡«ï¼å½è¿ç¶æï¼0æªå½è¿/1é¨åå½è¿/2å·²å ¨é¨å½è¿ } ``` **ååºç¤ºä¾** ```json { "code": 200, "msg": "æä½æå", "data": { "records": [ { "id": 1, "borrowNo": "LY202605260001", "productModelId": 100, "batchNo": "20260526-ABC001-001", "borrowQuantity": 10.0000, "returnedQuantity": 5.0000, "borrowerId": 1, "borrowerName": "å¼ ä¸", "borrowTime": "2026-05-26 10:00:00", "expectedReturnTime": "2026-06-26 10:00:00", "approvalStatus": 1, "approvalStatusName": "å·²éè¿", "status": 1, "statusName": "é¨åå½è¿", "remark": "项ç®ä½¿ç¨", "productName": "èºä¸å", "model": "M6", "productCode": "LSD-M6", "unit": "æ", "remainingQuantity": 5.0000, "createTime": "2026-05-26 09:00:00" } ], "total": 100, "size": 10, "current": 1, "pages": 10 } } ``` #### 1.2 æ¥è¯¢é¢ç¨è®°å½è¯¦æ **请æ±** ``` POST /productBorrow/getDetail Content-Type: application/json ``` **请æ±ä½** ```json { "id": 1 // å¿ å¡«ï¼é¢ç¨è®°å½ID } ``` **ååºç¤ºä¾** ```json { "code": 200, "msg": "æä½æå", "data": { "id": 1, "borrowNo": "LY202605260001", "productModelId": 100, "batchNo": "20260526-ABC001-001", "borrowQuantity": 10.0000, "returnedQuantity": 5.0000, "remainingQuantity": 5.0000, "borrowerId": 1, "borrowerName": "å¼ ä¸", "borrowTime": "2026-05-26 10:00:00", "expectedReturnTime": "2026-06-26 10:00:00", "approvalStatus": 1, "approvalStatusName": "å·²éè¿", "status": 1, "statusName": "é¨åå½è¿", "remark": "项ç®ä½¿ç¨", "productName": "èºä¸å", "model": "M6", "productCode": "LSD-M6", "unit": "æ" } } ``` #### 1.3 æ°å¢é¢ç¨è®°å½ **请æ±** ``` POST /productBorrow/add Content-Type: application/json ``` **请æ±ä½** ```json { "productModelId": 100, // å¿ å¡«ï¼äº§åè§æ ¼ID "batchNo": "20260526-ABC001-001", // éå¡«ï¼æ¹å·ï¼ä¸å¡«å使ç¨é»è®¤æ¹å· "borrowQuantity": 10.0000, // å¿ å¡«ï¼é¢ç¨æ°é "borrowerId": 1, // å¿ å¡«ï¼é¢ç¨äººIDï¼ç³»ç»ç¨æ·IDï¼ "borrowerName": "å¼ ä¸", // å¿ å¡«ï¼é¢ç¨äººå§å "expectedReturnTime": "2026-06-26 10:00:00", // éå¡«ï¼é¢è®¡å½è¿æ¶é´ "remark": "项ç®ä½¿ç¨" // éå¡«ï¼å¤æ³¨ } ``` **ååºç¤ºä¾** ```json { "code": 200, "msg": "æä½æå" } ``` **èªå¨æ§è¡çæä½**ï¼ - èªå¨çæé¢ç¨åå·ï¼æ ¼å¼ï¼LY + å¹´ææ¥ + 4ä½åºå·ï¼ - èªå¨å建åºåºè®°å½ - èªå¨å®¡æ ¸éè¿ - èªå¨æ£ååºå - ç¶æç´æ¥è®¾ä¸º"å·²éè¿" #### 1.4 ä¿®æ¹é¢ç¨è®°å½ **请æ±** ``` POST /productBorrow/update Content-Type: application/json ``` **请æ±ä½** ```json { "id": 1, // å¿ å¡«ï¼é¢ç¨è®°å½ID "productModelId": 100, "batchNo": "20260526-ABC001-001", "borrowQuantity": 15.0000, "borrowerId": 1, "borrowerName": "å¼ ä¸", "expectedReturnTime": "2026-06-26 10:00:00", "remark": "项ç®ä½¿ç¨" } ``` **注æ**ï¼åªæå¾ 审æ¹ç¶æï¼approvalStatus=0ï¼çè®°å½æè½ä¿®æ¹ #### 1.5 å é¤é¢ç¨è®°å½ **请æ±** ``` POST /productBorrow/delete Content-Type: application/json ``` **请æ±ä½** ```json [1, 2, 3] // è¦å é¤çè®°å½IDæ°ç» ``` **注æ**ï¼åªæå¾ 审æ¹ç¶æçè®°å½æè½å é¤ #### 1.6 æ¹é审æ¹é¢ç¨è®°å½ **请æ±** ``` POST /productBorrow/approve Content-Type: application/json ``` **请æ±ä½** ```json { "ids": [1, 2, 3], // å¿ å¡«ï¼è¦å®¡æ¹çè®°å½IDæ°ç» "approvalStatusParam": 1 // å¿ å¡«ï¼å®¡æ¹ç¶æï¼1éè¿/2驳å } ``` **ååºç¤ºä¾** ```json { "code": 200, "msg": "æä½æå" } ``` --- ### 2. 产åå½è¿æ¥å£ #### 2.1 å页æ¥è¯¢å½è¿è®°å½ **请æ±** ``` POST /productBorrowReturn/listPage Content-Type: application/json ``` **请æ±ä½** ```json { "current": 1, // å½å页ç "size": 10, // æ¯é¡µæ¡æ° "borrowId": 1, // éå¡«ï¼é¢ç¨è®°å½ID "productModelId": 100, // éå¡«ï¼äº§åè§æ ¼ID "returnerId": 2, // éå¡«ï¼å½è¿äººID "returnerName": "æå" // éå¡«ï¼å½è¿äººå§å } ``` **ååºç¤ºä¾** ```json { "code": 200, "msg": "æä½æå", "data": { "records": [ { "id": 1, "borrowId": 1, "borrowNo": "LY202605260001", "productModelId": 100, "batchNo": "20260526-ABC001-001", "returnQuantity": 5.0000, "returnerId": 2, "returnerName": "æå", "returnTime": "2026-05-28 14:00:00", "remark": "项ç®ç»æå½è¿", "productName": "èºä¸å", "model": "M6", "productCode": "LSD-M6", "unit": "æ", "borrowQuantity": 10.0000, "borrowerName": "å¼ ä¸" } ], "total": 50, "size": 10, "current": 1, "pages": 5 } } ``` #### 2.2 æ¥è¯¢æä¸ªé¢ç¨è®°å½çå½è¿è®°å½ **请æ±** ``` POST /productBorrowReturn/listByBorrowId Content-Type: application/json ``` **请æ±ä½** ```json { "current": 1, // å½å页ç "size": 10, // æ¯é¡µæ¡æ° "borrowId": 1 // å¿ å¡«ï¼é¢ç¨è®°å½ID } ``` **ååºç¤ºä¾** ```json { "code": 200, "msg": "æä½æå", "data": { "records": [...], "total": 5, "size": 10, "current": 1, "pages": 1 } } ``` #### 2.3 æ°å¢å½è¿è®°å½ **请æ±** ``` POST /productBorrowReturn/add Content-Type: application/json ``` **请æ±ä½** ```json { "borrowId": 1, // å¿ å¡«ï¼é¢ç¨è®°å½ID "returnQuantity": 5.0000, // å¿ å¡«ï¼å½è¿æ°é "returnerId": 2, // å¿ å¡«ï¼å½è¿äººIDï¼ç³»ç»ç¨æ·IDï¼ "returnerName": "æå", // å¿ å¡«ï¼å½è¿äººå§å "remark": "项ç®ç»æå½è¿" // éå¡«ï¼å¤æ³¨ } ``` **ååºç¤ºä¾** ```json { "code": 200, "msg": "æä½æå" } ``` **èªå¨æ§è¡çæä½**ï¼ - èªå¨åå»ºå ¥åºè®°å½ - èªå¨å®¡æ ¸éè¿ - èªå¨å¢å åºå - èªå¨æ´æ°é¢ç¨è®°å½çå·²å½è¿æ°éåç¶æ **é误æ åµ**ï¼ ```json { "code": 500, "msg": "å½è¿æ°éä¸è½å¤§äºå©ä½å¯å½è¿æ°éï¼5.0000" } ``` --- ### 3. åºååé¢ç¨éæ¥è¯¢æ¥å£ #### 3.1 å页æ¥è¯¢äº§ååºååé¢ç¨é **æ¥å£è¯´æ**ï¼ - 以"产åè§æ ¼ + æ¹å·"ä¸ºä¸æ¡è®°å½ - æ¾ç¤ºæ¯ä¸ªæ¹å·çåºåæ°éå被é¢ç¨é - ç¨äºé¢ç¨æ¶éæ©äº§ååæ¹å·ï¼æ¥çå¯é¢ç¨æ°é **请æ±** ``` POST /stockInventory/pageStockAndBorrow Content-Type: application/json ``` **请æ±ä½** ```json { "current": 1, // å½å页ç "size": 10, // æ¯é¡µæ¡æ° "topParentProductId": 277, // å¿ å¡«ï¼é¡¶é¨ç¶äº§åIDï¼äº§ååç±»IDï¼ "productName": "èºä¸å", // éå¡«ï¼äº§ååç§°ï¼æ¨¡ç³æ¥è¯¢ "model": "M6", // éå¡«ï¼è§æ ¼åå·ï¼æ¨¡ç³æ¥è¯¢ "batchNo": "20260526" // éå¡«ï¼æ¹å·ï¼æ¨¡ç³æ¥è¯¢ } ``` **åæ°è¯´æ**ï¼ | åæ°å | ç±»å | å¿ å¡« | 说æ | |--------|------|------|------| | current | Integer | å¦ | å½å页ç ï¼é»è®¤1 | | size | Integer | å¦ | æ¯é¡µæ¡æ°ï¼é»è®¤10 | | topParentProductId | Long | æ¯ | é¡¶é¨ç¶äº§åIDï¼äº§ååç±»æ æ ¹èç¹IDï¼ï¼ç¨äºçé产ååç±» | | productName | String | å¦ | 产ååç§°ï¼æ¨¡ç³æ¥è¯¢ | | model | String | å¦ | è§æ ¼åå·ï¼æ¨¡ç³æ¥è¯¢ | | batchNo | String | å¦ | æ¹å·ï¼æ¨¡ç³æ¥è¯¢ | **ååºç¤ºä¾** ```json { "code": 200, "msg": "æä½æå", "data": { "records": [ { "productModelId": 100, "model": "M6", "productCode": "LSD-M6", "unit": "æ", "productName": "èºä¸å", "productId": 50, "batchNo": "20260526-ABC001-001", "qualitity": 100.0000, "lockedQuantity": 5.0000, "borrowedQuantity": 10.0000, "availableQuantity": 90.0000 }, { "productModelId": 100, "model": "M6", "productCode": "LSD-M6", "unit": "æ", "productName": "èºä¸å", "productId": 50, "batchNo": "20260527-ABC001-001", "qualitity": 50.0000, "lockedQuantity": 0, "borrowedQuantity": 0, "availableQuantity": 50.0000 } ], "total": 20, "size": 10, "current": 1, "pages": 2 } } ``` **ååºå段说æ**ï¼ | åæ®µå | ç±»å | 说æ | |--------|------|------| | productModelId | Long | 产åè§æ ¼IDï¼ç¨äºé¢ç¨æ¶ä¼ éï¼ | | model | String | è§æ ¼åå· | | productCode | String | 产åç¼ç | | unit | String | åä½ | | productName | String | 产ååç§° | | productId | Long | 产åID | | batchNo | String | æ¹å·ï¼ç¨äºé¢ç¨æ¶ä¼ éï¼å¯ä¸ºnullï¼ | | qualitity | BigDecimal | å½ååºåæ°é | | lockedQuantity | BigDecimal | å»ç»/é宿°é | | borrowedQuantity | BigDecimal | 被é¢ç¨ä¸æªå½è¿çæ°é | | availableQuantity | BigDecimal | å¯é¢ç¨æ°é = åºåæ°é - 被é¢ç¨æ°é | **计ç®å ¬å¼**ï¼ ``` å¯é¢ç¨æ°é(availableQuantity) = åºåæ°é(qualitity) - 被é¢ç¨é(borrowedQuantity) ``` **被é¢ç¨é计ç®é»è¾**ï¼ - åªç»è®¡å®¡æ¹éè¿çé¢ç¨è®°å½ï¼approval_status = 1ï¼ - åªç»è®¡æªå ¨é¨å½è¿çè®°å½ï¼status != 2ï¼ - 计ç®å ¬å¼ï¼é¢ç¨æ°é - å·²å½è¿æ°é - æäº§åè§æ ¼ID + æ¹å·åç»ç»è®¡ **使ç¨åºæ¯**ï¼ 1. **é¢ç¨éæ©äº§å**ï¼ - è°ç¨æ¤æ¥å£æ¥è¯¢åºå - ç¨æ·éæ©äº§ååæ¹å· - æ¾ç¤ºå¯é¢ç¨æ°éä¾åè - é¢ç¨æ¶ä¼ é `productModelId` å `batchNo` 2. **å端æ¾ç¤ºå»ºè®®**ï¼ - å表æ¾ç¤ºï¼äº§ååç§°ãè§æ ¼åå·ãæ¹å·ãåºåæ°éã被é¢ç¨éãå¯é¢ç¨é - å¯é¢ç¨æ°é为0æè´æ°çè®°å½å¯ä»¥æ 红æç¦ç¨éæ© - æ¯ææäº§ååç§°ãè§æ ¼åå·ãæ¹å·æç´¢ **å端页é¢ç¤ºä¾**ï¼ ``` ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â 产ååºååé¢ç¨éæ¥è¯¢ â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ⤠â 产ååç±»: [éæ©åç±» â¼] 产ååç§°: [____] è§æ ¼åå·: [____] [æ¥è¯¢] â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ⤠â â â ââââââââââ¬âââââââââ¬âââââââââââ¬âââââââââ¬âââââââââ¬âââââââââ¬âââââââââ â â â产ååç§°âè§æ ¼åå·â æ¹å· âåºåæ°éâ被é¢ç¨éâå¯é¢ç¨éâ æä½ â â â ââââââââââ¼âââââââââ¼âââââââââââ¼âââââââââ¼âââââââââ¼âââââââââ¼ââââââââ⤠â â âèºä¸å â M6 â20260526- â 100 â 10 â 90 â[é¢ç¨] â â â â â âABC001-001â â â â â â â ââââââââââ¼âââââââââ¼âââââââââââ¼âââââââââ¼âââââââââ¼âââââââââ¼ââââââââ⤠â â âèºä¸å â M6 â20260527- â 50 â 0 â 50 â[é¢ç¨] â â â â â âABC001-001â â â â â â â ââââââââââ¼âââââââââ¼âââââââââââ¼âââââââââ¼âââââââââ¼âââââââââ¼ââââââââ⤠â â âæ³æ â 10寸 â NULL â 30 â 5 â 25 â[é¢ç¨] â â â ââââââââââ´âââââââââ´âââââââââââ´âââââââââ´âââââââââ´âââââââââ´âââââââââ â â â ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ ``` --- ## ä¸ãæ¥å£æ±æ»è¡¨ ### 产åé¢ç¨æ¥å£ | æ¥å£åç§° | 请æ±è·¯å¾ | è¯·æ±æ¹å¼ | 说æ | |----------|----------|----------|------| | å页æ¥è¯¢ | /productBorrow/listPage | POST | æ¥è¯¢é¢ç¨è®°å½å表 | | æ¥è¯¢è¯¦æ | /productBorrow/getDetail | POST | æ ¹æ®IDæ¥è¯¢è¯¦æ | | æ°å¢é¢ç¨ | /productBorrow/add | POST | æ°å¢é¢ç¨ï¼èªå¨åºåºï¼ | | ä¿®æ¹é¢ç¨ | /productBorrow/update | POST | ä¿®æ¹é¢ç¨è®°å½ | | å é¤é¢ç¨ | /productBorrow/delete | POST | æ¹éå é¤é¢ç¨è®°å½ | | æ¹éå®¡æ¹ | /productBorrow/approve | POST | æ¹é审æ¹ï¼éè¿/驳åï¼ | ### 产åå½è¿æ¥å£ | æ¥å£åç§° | 请æ±è·¯å¾ | è¯·æ±æ¹å¼ | 说æ | |----------|----------|----------|------| | å页æ¥è¯¢ | /productBorrowReturn/listPage | POST | æ¥è¯¢å½è¿è®°å½å表 | | æé¢ç¨æ¥è¯¢ | /productBorrowReturn/listByBorrowId | POST | æ¥è¯¢æé¢ç¨çå½è¿è®°å½ | | æ°å¢å½è¿ | /productBorrowReturn/add | POST | æ°å¢å½è¿ï¼èªå¨å ¥åºï¼ | ### åºåæ¥è¯¢æ¥å£ | æ¥å£åç§° | 请æ±è·¯å¾ | è¯·æ±æ¹å¼ | 说æ | |----------|----------|----------|------| | åºååé¢ç¨é | /stockInventory/pageStockAndBorrow | POST | æ¥è¯¢åºåå被é¢ç¨é | --- ## åãç¶æè¯´æ ### 1. 审æ¹ç¶æ (approvalStatus) | å¼ | åç§° | 说æ | |----|------|------| | 0 | å¾ å®¡æ¹ | æ°å¢åçé»è®¤ç¶æï¼ä» æ¹é审æ¹åºæ¯ä½¿ç¨ï¼ | | 1 | å·²éè¿ | 审æ¹éè¿ï¼å·²æ£ååºåï¼å¯è¿è¡å½è¿æä½ | | 2 | 已驳å | å®¡æ¹æªéè¿ï¼ä¸æ£ååºå | **注æ**ï¼æ°å¢é¢ç¨æ¶ç´æ¥èªå¨å®¡æ¹éè¿ï¼ç¶æä¸º1 ### 2. å½è¿ç¶æ (status) | å¼ | åç§° | 说æ | |----|------|------| | 0 | æªå½è¿ | å°æªå½è¿ä»»ä½æ°é | | 1 | é¨åå½è¿ | å·²å½è¿é¨åæ°é | | 2 | å·²å ¨é¨å½è¿ | å·²å½è¿å ¨é¨æ°éï¼ä¸è½åå½è¿ | --- ## äºãä¸å¡æµç¨å¾ ``` âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â é¢ç¨æµç¨ï¼èªå¨åºåºï¼ â ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ⤠â â â ââââââââââââââ ââââââââââââââ ââââââââââââââ â â â æ°å¢é¢ç¨ ââââ>â èªå¨åºåº ââââ>â ç¶æè®¾ä¸º â â â â è®°å½ â â æ£ååºå â â å·²éè¿ â â â ââââââââââââââ ââââââââââââââ ââââââââââââââ â â â â â â¼ â â ââââââââââââââ â â â å建åºåº â â â â è®°å½ â â â ââââââââââââââ â â â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ â å½è¿æµç¨ï¼èªå¨å ¥åºï¼ â ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ⤠â â â ââââââââââââââ ââââââââââââââ ââââââââââââââ â â â éæ©é¢ç¨ ââââ>â å¡«åå½è¿ ââââ>â èªå¨å ¥åº â â â â è®°å½ â â ä¿¡æ¯ â â å¢å åºå â â â ââââââââââââââ ââââââââââââââ ââââââââââââââ â â â â â â¼ â â ââââââââââââââ â â â æ´æ°é¢ç¨ â â â â ç¶æ â â â ââââââââââââââ â â â âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ ``` --- ## å ãæ³¨æäºé¡¹ ### 1. æ°æ®æ ¡éª **åç«¯æ ¡éª**ï¼ - é¢ç¨æ°éå¿ é¡»å¤§äº0 - å½è¿æ°éä¸è½è¶ è¿å©ä½å¯å½è¿æ°é - é¢ç¨äººãå½è¿äººå¿ é¡»éæ©ç³»ç»ç¨æ· **åç«¯æ ¡éª**ï¼ - é¢ç¨æ¶æ£æ¥åºåæ¯å¦å è¶³ - å½è¿æ°éä¸è½è¶ è¿å©ä½æ°é - å·²å ¨é¨å½è¿çè®°å½ä¸è½åå½è¿ ### 2. ç¨æ·éæ© é¢ç¨äººåå½è¿äººéè¦ä»ç³»ç»ç¨æ·è¡¨éæ©ï¼è°ç¨ç³»ç»ç¨æ·æ¥å£ï¼ ``` POST /system/user/list ``` ### 3. 产åè§æ ¼éæ© éæ©äº§åè§æ ¼æ¶ï¼å¯ä»¥è°ç¨äº§åæ¥å£ï¼ ``` POST /basic/product/pageModel ``` ### 4. åºåèå¨ - **é¢ç¨**ï¼æ°å¢æ¶èªå¨åºåºï¼è°ç¨åºåæ£åæ¥å£ï¼ - **å½è¿**ï¼æ°å¢æ¶èªå¨å ¥åºï¼è°ç¨åºåå¢å æ¥å£ï¼ --- ## ä¸ãé误ç 说æ | éè¯¯ä¿¡æ¯ | åå | è§£å³æ¹æ¡ | |----------|------|----------| | é¢ç¨è®°å½ä¸åå¨ | IDæ æ | æ£æ¥è®°å½ID | | 产ååºåä¸åå¨ | åºå为空 | æ£æ¥åºåæ°æ® | | åºåä¸è¶³æ æ³åºåº | åºåä¸è¶³ | æ£æ¥åºåæ°é | | 该é¢ç¨è®°å½å·²å ¨é¨å½è¿ | å½è¿å®æ | æ é忬¡å½è¿ | | å½è¿æ°éä¸è½å¤§äºå©ä½å¯å½è¿æ°é | æ°éè¶ é | æ£æ¥å©ä½å¯å½è¿æ°é | --- ## å «ãæµè¯ç¨ä¾ ### 1. æ°å¢é¢ç¨ï¼èªå¨åºåºï¼ ```json POST /productBorrow/add { "productModelId": 1, "borrowQuantity": 10, "borrowerId": 1, "borrowerName": "管çå" } ``` ### 2. æ¥è¯¢åºååé¢ç¨é ```json POST /stockInventory/pageStockAndBorrow { "current": 1, "size": 10, "topParentProductId": 277 } ``` ### 3. å½è¿äº§åï¼èªå¨å ¥åºï¼ ```json POST /productBorrowReturn/add { "borrowId": 1, "returnQuantity": 5, "returnerId": 1, "returnerName": "管çå" } ``` ### 4. æ¥è¯¢é¢ç¨è¯¦æ ```json POST /productBorrow/getDetail { "id": 1 } ``` ### 5. æ¥è¯¢å½è¿è®°å½ ```json POST /productBorrowReturn/listByBorrowId { "borrowId": 1, "current": 1, "size": 10 } ``` src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java
@@ -89,9 +89,6 @@ @Override public int addOrEditProduct(ProductDto productDto) { if (ObjectUtils.isEmpty(productDto.getParentId())) { throw new IllegalArgumentException("è¯·éæ©ç¶èç¹"); } String productName = StringUtils.trim(productDto.getProductName()); if (StringUtils.isEmpty(productName)) { throw new IllegalArgumentException("产ååç§°ä¸è½ä¸ºç©º"); @@ -100,15 +97,17 @@ checkProductNameUnique(productDto.getParentId(), productName, productDto.getId()); if (productDto.getId() == null) { // æ°å¢äº§åé»è¾ // æ£æ¥ç¶èç¹æ¯å¦åå¨ï¼å¯éï¼æ ¹æ®ä¸å¡éæ±ï¼ Product parent = productMapper.selectById(productDto.getParentId()); if (parent == null) { throw new IllegalArgumentException("ç¶èç¹ä¸åå¨ï¼æ æ³æ·»å å产å"); // 妿æç¶èç¹ï¼æ£æ¥ç¶èç¹æ¯å¦åå¨ if (productDto.getParentId() != null) { Product parent = productMapper.selectById(productDto.getParentId()); if (parent == null) { throw new IllegalArgumentException("ç¶èç¹ä¸åå¨ï¼æ æ³æ·»å å产å"); } } return productMapper.insert(productDto); } else { // ç¼è¾äº§åé»è¾ // æ£æ¥äº§åæ¯å¦åå¨ï¼å¯éï¼æ ¹æ®ä¸å¡éæ±ï¼ // æ£æ¥äº§åæ¯å¦åå¨ Product existingProduct = productMapper.selectById(productDto.getId()); if (existingProduct == null) { throw new IllegalArgumentException("è¦ç¼è¾ç产åä¸åå¨"); @@ -119,10 +118,15 @@ private void checkProductNameUnique(Long parentId, String productName, Long currentId) { LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Product::getParentId, parentId) .eq(Product::getProductName, productName) .ne(currentId != null, Product::getId, currentId) .last("limit 1"); queryWrapper.eq(Product::getProductName, productName) .ne(currentId != null, Product::getId, currentId); // å¤ç parentId 为 null çæ åµ if (parentId == null) { queryWrapper.isNull(Product::getParentId); } else { queryWrapper.eq(Product::getParentId, parentId); } queryWrapper.last("limit 1"); Product duplicateProduct = productMapper.selectOne(queryWrapper); if (duplicateProduct != null) { throw new IllegalArgumentException("对åºç" + productName + "å·²ç»åå¨"); src/main/java/com/ruoyi/common/enums/StockInQualifiedRecordTypeEnum.java
@@ -19,7 +19,8 @@ RETURN_HE_IN("14", "éå®éè´§-åæ ¼å ¥åº"), RETURN_UNSTOCK_IN("15", "éå®éè´§-ä¸åæ ¼å ¥åº"), PICK_RETURN_IN("20", "颿éæ-åæ ¼å ¥åº"), FEED_RETURN_IN("22", "ç产éæ-åæ ¼å ¥åº"); FEED_RETURN_IN("22", "ç产éæ-åæ ¼å ¥åº"), PRODUCT_BORROW_RETURN("23", "产åå½è¿å ¥åº"); src/main/java/com/ruoyi/common/enums/StockOutQualifiedRecordTypeEnum.java
@@ -12,7 +12,9 @@ CUSTOMIZATION_UNSTOCK_OUT("10", "ä¸åæ ¼èªå®ä¹åºåº"), SALE_SHIP_STOCK_OUT("13", "éå®-åè´§åºåº"), PICK_STOCK_OUT("14", "çäº§é¢æåºåº"), FEED_STOCK_OUT("15", "ç产补æåºåº"); FEED_STOCK_OUT("15", "ç产补æåºåº"), PRODUCT_BORROW("16", "产åé¢ç¨åºåº"), PRODUCT_RETURN("17", "产åå½è¿å ¥åº"); private final String code; private final String value; src/main/java/com/ruoyi/stock/controller/ProductBorrowController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,96 @@ package com.ruoyi.stock.controller; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.framework.aspectj.lang.enums.BusinessType; import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.stock.dto.ProductBorrowDto; import com.ruoyi.stock.service.ProductBorrowService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import java.util.List; /** * 产åé¢ç¨ Controller * * @author ruoyi */ @Tag(name = "产åé¢ç¨") @RestController @RequestMapping("/productBorrow") @RequiredArgsConstructor public class ProductBorrowController { private final ProductBorrowService productBorrowService; @PostMapping("/listPage") @Log(title = "产åé¢ç¨-å表", businessType = BusinessType.OTHER) @Operation(summary = "å页æ¥è¯¢é¢ç¨è®°å½") public AjaxResult listPage(@RequestBody Page<ProductBorrowDto> page, @RequestBody ProductBorrowDto dto) { IPage<ProductBorrowDto> result = productBorrowService.listPage(page, dto); return AjaxResult.success(result); } @PostMapping("/getDetail") @Log(title = "产åé¢ç¨-详æ ", businessType = BusinessType.OTHER) @Operation(summary = "æ¥è¯¢é¢ç¨è®°å½è¯¦æ ") public AjaxResult getDetail(@RequestBody ProductBorrowDto dto) { ProductBorrowDto result = productBorrowService.getDetailById(dto.getId()); return AjaxResult.success(result); } @PostMapping("/add") @Log(title = "产åé¢ç¨-æ°å¢", businessType = BusinessType.INSERT) @Operation(summary = "æ°å¢é¢ç¨è®°å½") public AjaxResult add(@RequestBody ProductBorrowDto dto) { productBorrowService.add(dto); return AjaxResult.success(); } @PostMapping("/update") @Log(title = "产åé¢ç¨-ä¿®æ¹", businessType = BusinessType.UPDATE) @Operation(summary = "ä¿®æ¹é¢ç¨è®°å½") public AjaxResult update(@RequestBody ProductBorrowDto dto) { productBorrowService.update(dto); return AjaxResult.success(); } @PostMapping("/delete") @Log(title = "产åé¢ç¨-å é¤", businessType = BusinessType.DELETE) @Operation(summary = "å é¤é¢ç¨è®°å½") public AjaxResult delete(@RequestBody List<Long> ids) { if (CollectionUtils.isEmpty(ids)) { return AjaxResult.error("è¯·éæ©è³å°ä¸æ¡æ°æ®"); } productBorrowService.delete(ids); return AjaxResult.success(); } @PostMapping("/approve") @Log(title = "产åé¢ç¨-审æ¹", businessType = BusinessType.UPDATE) @Operation(summary = "æ¹é审æ¹é¢ç¨è®°å½") public AjaxResult approve(@RequestBody ProductBorrowDto dto) { if (CollectionUtils.isEmpty(dto.getIds())) { return AjaxResult.error("è¯·éæ©è³å°ä¸æ¡æ°æ®"); } productBorrowService.batchApprove(dto.getIds(), dto.getApprovalStatusParam()); return AjaxResult.success(); } @PostMapping("/reAudit") @Log(title = "产åé¢ç¨-å审", businessType = BusinessType.UPDATE) @Operation(summary = "æ¹éå审é¢ç¨è®°å½") public AjaxResult reAudit(@RequestBody ProductBorrowDto dto) { if (CollectionUtils.isEmpty(dto.getIds())) { return AjaxResult.error("è¯·éæ©è³å°ä¸æ¡æ°æ®"); } // å审ï¼å°å·²éè¿çè®°å½ç¶ææ¹åå¾ å®¡æ¹ï¼éè¦èèæ¯å¦å·²ç»å½è¿ // æ¤å¤æä¸å®ç°å审é»è¾ï¼å¦éè¦å¯ä»¥æ©å± return AjaxResult.error("å审åè½ææªå®ç°"); } } src/main/java/com/ruoyi/stock/controller/ProductBorrowReturnController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,51 @@ package com.ruoyi.stock.controller; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.framework.aspectj.lang.enums.BusinessType; import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.stock.dto.ProductBorrowReturnDto; import com.ruoyi.stock.service.ProductBorrowReturnService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; /** * 产åå½è¿ Controller * * @author ruoyi */ @Tag(name = "产åå½è¿") @RestController @RequestMapping("/productBorrowReturn") @RequiredArgsConstructor public class ProductBorrowReturnController { private final ProductBorrowReturnService productBorrowReturnService; @PostMapping("/listPage") @Log(title = "产åå½è¿-å表", businessType = BusinessType.OTHER) @Operation(summary = "å页æ¥è¯¢å½è¿è®°å½") public AjaxResult listPage(@RequestBody Page<ProductBorrowReturnDto> page, ProductBorrowReturnDto dto) { IPage<ProductBorrowReturnDto> result = productBorrowReturnService.listPage(page, dto); return AjaxResult.success(result); } @PostMapping("/listByBorrowId") @Log(title = "产åå½è¿-æ ¹æ®é¢ç¨IDæ¥è¯¢", businessType = BusinessType.OTHER) @Operation(summary = "æ¥è¯¢æä¸ªé¢ç¨è®°å½çå½è¿è®°å½") public AjaxResult listByBorrowId(@RequestBody Page<ProductBorrowReturnDto> page, @RequestBody ProductBorrowReturnDto dto) { IPage<ProductBorrowReturnDto> result = productBorrowReturnService.listByBorrowId(page, dto.getBorrowId()); return AjaxResult.success(result); } @PostMapping("/add") @Log(title = "产åå½è¿-æ°å¢", businessType = BusinessType.INSERT) @Operation(summary = "æ°å¢å½è¿è®°å½ï¼ç´æ¥å¢å åºåï¼æ é审æ¹ï¼") public AjaxResult add(@RequestBody ProductBorrowReturnDto dto) { productBorrowReturnService.add(dto); return AjaxResult.success(); } } src/main/java/com/ruoyi/stock/controller/StockInventoryController.java
@@ -147,4 +147,10 @@ public R getByModelId(Long productModelId) { return R.ok(stockInventoryService.getByModelId(productModelId)); } @PostMapping("/pageStockAndBorrow") @Operation(summary = "å页æ¥è¯¢äº§ååºååé¢ç¨é") public R pageStockAndBorrow(@RequestBody Page page, @RequestBody StockInventoryDto stockInventoryDto) { return R.ok(stockInventoryService.pageStockAndBorrow(page, stockInventoryDto)); } } src/main/java/com/ruoyi/stock/dto/ProductBorrowDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,49 @@ package com.ruoyi.stock.dto; import com.ruoyi.stock.pojo.ProductBorrow; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import java.util.List; /** * 产åé¢ç¨DTO * * @author ruoyi */ @EqualsAndHashCode(callSuper = true) @Data @Schema(description = "产åé¢ç¨DTO") public class ProductBorrowDto extends ProductBorrow { @Schema(description = "产ååç§°") private String productName; @Schema(description = "è§æ ¼åå·") private String model; @Schema(description = "产åç¼ç ") private String productCode; @Schema(description = "åä½") private String unit; @Schema(description = "å©ä½å¯å½è¿æ°é") private java.math.BigDecimal remainingQuantity; @Schema(description = "审æ¹ç¶æåç§°") private String approvalStatusName; @Schema(description = "å½è¿ç¶æåç§°") private String statusName; @Schema(description = "æ¹é审æ¹IDå表") private List<Long> ids; @Schema(description = "审æ¹ç¶æï¼ç¨äºå®¡æ¹æä½ï¼") private Integer approvalStatusParam; @Schema(description = "é¡¶é¨ç¶äº§åIDï¼äº§ååç±»IDï¼") private Long topParentProductId; } src/main/java/com/ruoyi/stock/dto/ProductBorrowReturnDto.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,38 @@ package com.ruoyi.stock.dto; import com.ruoyi.stock.pojo.ProductBorrowReturn; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; /** * 产åå½è¿DTO * * @author ruoyi */ @EqualsAndHashCode(callSuper = true) @Data @Schema(description = "产åå½è¿DTO") public class ProductBorrowReturnDto extends ProductBorrowReturn { @Schema(description = "é¢ç¨åå·") private String borrowNo; @Schema(description = "产ååç§°") private String productName; @Schema(description = "è§æ ¼åå·") private String model; @Schema(description = "产åç¼ç ") private String productCode; @Schema(description = "åä½") private String unit; @Schema(description = "é¢ç¨æ°é") private java.math.BigDecimal borrowQuantity; @Schema(description = "é¢ç¨äººå§å") private String borrowerName; } src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
@@ -80,4 +80,16 @@ @Schema(description = "产åid") private Long productId; @Schema(description = "被é¢ç¨æ°éï¼æªå½è¿ï¼") private BigDecimal borrowedQuantity; @Schema(description = "å¯é¢ç¨æ°éï¼åºå - 被é¢ç¨ï¼") private BigDecimal availableQuantity; @Schema(description = "产åç¼ç ") private String productCode; @Schema(description = "审æ¹ç¶æï¼ç¨äºå ¥åº/åºåºè®°å½ï¼") private Integer approvalStatus; } src/main/java/com/ruoyi/stock/mapper/ProductBorrowMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,28 @@ package com.ruoyi.stock.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.stock.dto.ProductBorrowDto; import com.ruoyi.stock.pojo.ProductBorrow; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * 产åé¢ç¨ Mapper æ¥å£ * * @author ruoyi */ @Mapper public interface ProductBorrowMapper extends BaseMapper<ProductBorrow> { /** * å页æ¥è¯¢é¢ç¨è®°å½ */ IPage<ProductBorrowDto> listPage(Page<ProductBorrowDto> page, @Param("ew") ProductBorrowDto dto); /** * æ ¹æ®IDæ¥è¯¢è¯¦æ */ ProductBorrowDto selectDetailById(@Param("id") Long id); } src/main/java/com/ruoyi/stock/mapper/ProductBorrowReturnMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,28 @@ package com.ruoyi.stock.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.stock.dto.ProductBorrowReturnDto; import com.ruoyi.stock.pojo.ProductBorrowReturn; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * 产åå½è¿è®°å½ Mapper æ¥å£ * * @author ruoyi */ @Mapper public interface ProductBorrowReturnMapper extends BaseMapper<ProductBorrowReturn> { /** * å页æ¥è¯¢å½è¿è®°å½ */ IPage<ProductBorrowReturnDto> listPage(Page<ProductBorrowReturnDto> page, @Param("ew") ProductBorrowReturnDto dto); /** * æ ¹æ®é¢ç¨IDæ¥è¯¢å½è¿è®°å½ */ IPage<ProductBorrowReturnDto> listByBorrowId(Page<ProductBorrowReturnDto> page, @Param("borrowId") Long borrowId); } src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java
@@ -58,4 +58,9 @@ List<StockInventory> getByModelId(@Param("productModelId") Long productModelId); IPage<StockInventoryDto> getBatchNoQty(Page page, @Param("ew") StockInventoryDto stockInventoryDto); /** * å页æ¥è¯¢äº§ååºååé¢ç¨é */ IPage<StockInventoryDto> pageStockAndBorrow(Page page, @Param("ew") StockInventoryDto stockInventoryDto); } src/main/java/com/ruoyi/stock/pojo/ProductBorrow.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,96 @@ package com.ruoyi.stock.pojo; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; /** * 产åé¢ç¨è¡¨ * * @author ruoyi */ @Data @TableName("product_borrow") @Schema(name = "ProductBorrow对象", description = "产åé¢ç¨è¡¨") public class ProductBorrow implements Serializable { private static final long serialVersionUID = 1L; @Schema(description = "主é®") @TableId(type = IdType.AUTO) private Long id; @Schema(description = "é¢ç¨åå·") private String borrowNo; @Schema(description = "产åè§æ ¼ID") private Long productModelId; @Schema(description = "æ¹å·") private String batchNo; @Schema(description = "é¢ç¨æ°é") private BigDecimal borrowQuantity; @Schema(description = "å·²å½è¿æ°é") private BigDecimal returnedQuantity; @Schema(description = "é¢ç¨äººID") private Long borrowerId; @Schema(description = "é¢ç¨äººå§å") private String borrowerName; @Schema(description = "é¢ç¨æ¶é´") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime borrowTime; @Schema(description = "é¢è®¡å½è¿æ¶é´") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime expectedReturnTime; @Schema(description = "审æ¹ç¶æï¼0-å¾ å®¡æ¹ï¼1-å·²éè¿ï¼2-已驳åï¼") private Integer approvalStatus; @Schema(description = "å½è¿ç¶æï¼0-æªå½è¿ï¼1-é¨åå½è¿ï¼2-å·²å ¨é¨å½è¿ï¼") private Integer status; @Schema(description = "夿³¨") private String remark; @Schema(description = "ç§æ·ID") @TableField(fill = FieldFill.INSERT) private Long tenantId; @Schema(description = "é¨é¨ID") @TableField(fill = FieldFill.INSERT) private Long deptId; @Schema(description = "å建人") @TableField(fill = FieldFill.INSERT) private Integer createUser; @Schema(description = "å建æ¶é´") @TableField(fill = FieldFill.INSERT) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; @Schema(description = "æ´æ°äºº") @TableField(fill = FieldFill.INSERT_UPDATE) private Integer updateUser; @Schema(description = "æ´æ°æ¶é´") @TableField(fill = FieldFill.INSERT_UPDATE) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime updateTime; } src/main/java/com/ruoyi/stock/pojo/ProductBorrowReturn.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,72 @@ package com.ruoyi.stock.pojo; import com.baomidou.mybatisplus.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; /** * 产åå½è¿è®°å½è¡¨ * * @author ruoyi */ @Data @TableName("product_borrow_return") @Schema(name = "ProductBorrowReturn对象", description = "产åå½è¿è®°å½è¡¨") public class ProductBorrowReturn implements Serializable { private static final long serialVersionUID = 1L; @Schema(description = "主é®") @TableId(type = IdType.AUTO) private Long id; @Schema(description = "é¢ç¨è®°å½ID") private Long borrowId; @Schema(description = "产åè§æ ¼ID") private Long productModelId; @Schema(description = "æ¹å·") private String batchNo; @Schema(description = "å½è¿æ°é") private BigDecimal returnQuantity; @Schema(description = "å½è¿äººID") private Long returnerId; @Schema(description = "å½è¿äººå§å") private String returnerName; @Schema(description = "å½è¿æ¶é´") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime returnTime; @Schema(description = "夿³¨") private String remark; @Schema(description = "ç§æ·ID") @TableField(fill = FieldFill.INSERT) private Long tenantId; @Schema(description = "é¨é¨ID") @TableField(fill = FieldFill.INSERT) private Long deptId; @Schema(description = "å建人") @TableField(fill = FieldFill.INSERT) private Integer createUser; @Schema(description = "å建æ¶é´") @TableField(fill = FieldFill.INSERT) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; } src/main/java/com/ruoyi/stock/service/ProductBorrowReturnService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,30 @@ package com.ruoyi.stock.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.stock.dto.ProductBorrowReturnDto; import com.ruoyi.stock.pojo.ProductBorrowReturn; /** * 产åå½è¿è®°å½ Service æ¥å£ * * @author ruoyi */ public interface ProductBorrowReturnService extends IService<ProductBorrowReturn> { /** * å页æ¥è¯¢å½è¿è®°å½ */ IPage<ProductBorrowReturnDto> listPage(Page<ProductBorrowReturnDto> page, ProductBorrowReturnDto dto); /** * æ°å¢å½è¿è®°å½ï¼ç´æ¥å¢å åºåï¼æ é审æ¹ï¼ */ Boolean add(ProductBorrowReturnDto dto); /** * æ¥è¯¢æä¸ªé¢ç¨è®°å½çå½è¿è®°å½ */ IPage<ProductBorrowReturnDto> listByBorrowId(Page<ProductBorrowReturnDto> page, Long borrowId); } src/main/java/com/ruoyi/stock/service/ProductBorrowService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,52 @@ package com.ruoyi.stock.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.stock.dto.ProductBorrowDto; import com.ruoyi.stock.pojo.ProductBorrow; import java.util.List; /** * 产åé¢ç¨ Service æ¥å£ * * @author ruoyi */ public interface ProductBorrowService extends IService<ProductBorrow> { /** * å页æ¥è¯¢é¢ç¨è®°å½ */ IPage<ProductBorrowDto> listPage(Page<ProductBorrowDto> page, ProductBorrowDto dto); /** * æ°å¢é¢ç¨è®°å½ï¼å¾ 审æ¹ï¼ */ Boolean add(ProductBorrowDto dto); /** * æ´æ°é¢ç¨è®°å½ */ Boolean update(ProductBorrowDto dto); /** * å é¤é¢ç¨è®°å½ï¼ä» å¾ å®¡æ¹ç¶æå¯å é¤ï¼ */ Boolean delete(List<Long> ids); /** * æ¹éå®¡æ¹ */ Boolean batchApprove(List<Long> ids, Integer approvalStatus); /** * 审æ¹éè¿åçåè°ï¼æ£ååºåï¼ */ void onApprovePass(ProductBorrow borrow); /** * æ ¹æ®IDæ¥è¯¢è¯¦æ */ ProductBorrowDto getDetailById(Long id); } src/main/java/com/ruoyi/stock/service/StockInventoryService.java
@@ -49,4 +49,9 @@ List<StockInventory> getByModelId(Long modelId); IPage<StockInventoryDto> getBatchNoQty(Page page, StockInventoryDto stockInventoryDto); /** * å页æ¥è¯¢äº§ååºååé¢ç¨é */ IPage<StockInventoryDto> pageStockAndBorrow(Page page, StockInventoryDto stockInventoryDto); } src/main/java/com/ruoyi/stock/service/impl/ProductBorrowReturnServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,109 @@ package com.ruoyi.stock.service.impl; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.stock.dto.ProductBorrowReturnDto; import com.ruoyi.stock.dto.StockInventoryDto; import com.ruoyi.stock.mapper.ProductBorrowReturnMapper; import com.ruoyi.stock.pojo.ProductBorrow; import com.ruoyi.stock.pojo.ProductBorrowReturn; import com.ruoyi.stock.service.ProductBorrowReturnService; import com.ruoyi.stock.service.ProductBorrowService; import com.ruoyi.stock.service.StockInventoryService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDateTime; /** * 产åå½è¿è®°å½ Service å®ç°ç±» * * @author ruoyi */ @Slf4j @Service @RequiredArgsConstructor public class ProductBorrowReturnServiceImpl extends ServiceImpl<ProductBorrowReturnMapper, ProductBorrowReturn> implements ProductBorrowReturnService { private final ProductBorrowReturnMapper productBorrowReturnMapper; private final ProductBorrowService productBorrowService; private final StockInventoryService stockInventoryService; @Override public IPage<ProductBorrowReturnDto> listPage(Page<ProductBorrowReturnDto> page, ProductBorrowReturnDto dto) { return productBorrowReturnMapper.listPage(page, dto); } @Override @Transactional(rollbackFor = Exception.class) public Boolean add(ProductBorrowReturnDto dto) { // 1. æ¥è¯¢é¢ç¨è®°å½ ProductBorrow borrow = productBorrowService.getById(dto.getBorrowId()); if (borrow == null) { throw new ServiceException("é¢ç¨è®°å½ä¸åå¨"); } // 2. æ£æ¥é¢ç¨è®°å½ç¶æï¼å·²éè¿çè®°å½æè½å½è¿ï¼ if (borrow.getApprovalStatus() != 1) { throw new ServiceException("é¢ç¨è®°å½æªå®æåºåºï¼æ æ³å½è¿"); } if (borrow.getStatus() == 2) { throw new ServiceException("该é¢ç¨è®°å½å·²å ¨é¨å½è¿"); } // 3. 计ç®å©ä½å¯å½è¿æ°é BigDecimal returnedQty = borrow.getReturnedQuantity() != null ? borrow.getReturnedQuantity() : BigDecimal.ZERO; BigDecimal remainingQty = borrow.getBorrowQuantity().subtract(returnedQty); // 4. éªè¯å½è¿æ°é if (dto.getReturnQuantity().compareTo(remainingQty) > 0) { throw new ServiceException("å½è¿æ°éä¸è½å¤§äºå©ä½å¯å½è¿æ°éï¼" + remainingQty); } // 5. è®¾ç½®å¿ è¦å段 dto.setProductModelId(borrow.getProductModelId()); dto.setBatchNo(borrow.getBatchNo()); dto.setReturnTime(LocalDateTime.now()); // 6. ä¿åå½è¿è®°å½ save(dto); // 7. æ´æ°é¢ç¨è®°å½çå·²å½è¿æ°éåç¶æ BigDecimal newReturnedQty = returnedQty.add(dto.getReturnQuantity()); borrow.setReturnedQuantity(newReturnedQty); // 夿æ¯å¦å ¨é¨å½è¿ if (newReturnedQty.compareTo(borrow.getBorrowQuantity()) >= 0) { borrow.setStatus(2); // å·²å ¨é¨å½è¿ } else if (newReturnedQty.compareTo(BigDecimal.ZERO) > 0) { borrow.setStatus(1); // é¨åå½è¿ } productBorrowService.updateById(borrow); // 8. å¢å åºåï¼å ¥åºï¼ï¼è®¾ç½®å®¡æ¹ç¶æä¸ºå·²éè¿ï¼èªå¨å®¡æ ¸ StockInventoryDto stockInDto = new StockInventoryDto(); stockInDto.setProductModelId(borrow.getProductModelId()); stockInDto.setBatchNo(borrow.getBatchNo()); stockInDto.setQualitity(dto.getReturnQuantity()); stockInDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.PRODUCT_BORROW_RETURN.getCode())); stockInDto.setRecordId(dto.getId()); stockInDto.setRemark("产åå½è¿å ¥åºï¼é¢ç¨åå·ï¼" + borrow.getBorrowNo()); // 设置审æ¹ç¶æä¸ºå·²éè¿ï¼èªå¨å®¡æ ¸ stockInDto.setApprovalStatus(1); stockInventoryService.addstockInventory(stockInDto); log.info("产åå½è¿æåï¼é¢ç¨åå·ï¼{}ï¼å½è¿æ°éï¼{}", borrow.getBorrowNo(), dto.getReturnQuantity()); return true; } @Override public IPage<ProductBorrowReturnDto> listByBorrowId(Page<ProductBorrowReturnDto> page, Long borrowId) { return productBorrowReturnMapper.listByBorrowId(page, borrowId); } } src/main/java/com/ruoyi/stock/service/impl/ProductBorrowServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,214 @@ package com.ruoyi.stock.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.stock.dto.ProductBorrowDto; import com.ruoyi.stock.dto.StockInventoryDto; import com.ruoyi.stock.mapper.ProductBorrowMapper; import com.ruoyi.stock.pojo.ProductBorrow; import com.ruoyi.stock.service.ProductBorrowService; import com.ruoyi.stock.service.StockInventoryService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; 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; /** * 产åé¢ç¨ Service å®ç°ç±» * * @author ruoyi */ @Slf4j @Service @RequiredArgsConstructor public class ProductBorrowServiceImpl extends ServiceImpl<ProductBorrowMapper, ProductBorrow> implements ProductBorrowService { private final ProductBorrowMapper productBorrowMapper; private final StockInventoryService stockInventoryService; @Override public IPage<ProductBorrowDto> listPage(Page<ProductBorrowDto> page, ProductBorrowDto dto) { IPage<ProductBorrowDto> result = productBorrowMapper.listPage(page, dto); // å¡«å ç¶æåç§° result.getRecords().forEach(this::fillStatusName); return result; } @Override @Transactional(rollbackFor = Exception.class) public Boolean add(ProductBorrowDto dto) { // çæé¢ç¨åå· String borrowNo = generateBorrowNo(); dto.setBorrowNo(borrowNo); // 设置åå§ç¶æ - ç´æ¥è®¾ä¸ºå·²éè¿ï¼åæ¶å®¡æ¹æµç¨ï¼ dto.setApprovalStatus(1); // å·²éè¿ dto.setStatus(0); // æªå½è¿ dto.setReturnedQuantity(BigDecimal.ZERO); dto.setBorrowTime(LocalDateTime.now()); // ä¿åé¢ç¨è®°å½ save(dto); // é¢ç¨æ¶ç´æ¥ååºåºæä½ï¼èªå¨å®¡æ ¸éè¿ doBorrowStockOut(dto); return true; } /** * æ§è¡é¢ç¨åºåºæä½ï¼èªå¨å®¡æ ¸éè¿ï¼ */ private void doBorrowStockOut(ProductBorrow borrow) { // æå»ºåºåæ£ååæ° StockInventoryDto stockInventoryDto = new StockInventoryDto(); stockInventoryDto.setProductModelId(borrow.getProductModelId()); stockInventoryDto.setBatchNo(borrow.getBatchNo()); stockInventoryDto.setQualitity(borrow.getBorrowQuantity()); stockInventoryDto.setRecordType(String.valueOf(StockOutQualifiedRecordTypeEnum.PRODUCT_BORROW.getCode())); stockInventoryDto.setRecordId(borrow.getId()); stockInventoryDto.setRemark("产åé¢ç¨åºåºï¼é¢ç¨åå·ï¼" + borrow.getBorrowNo()); // 设置审æ¹ç¶æä¸ºå·²éè¿ï¼èªå¨å®¡æ ¸ stockInventoryDto.setApprovalStatus(1); // è°ç¨åºåæå¡æ£ååºå stockInventoryService.subtractStockInventory(stockInventoryDto); log.info("产åé¢ç¨åºåºæåï¼é¢ç¨åå·ï¼{}ï¼æ°éï¼{}", borrow.getBorrowNo(), borrow.getBorrowQuantity()); } @Override @Transactional(rollbackFor = Exception.class) public Boolean update(ProductBorrowDto dto) { ProductBorrow existing = getById(dto.getId()); if (existing == null) { throw new ServiceException("é¢ç¨è®°å½ä¸åå¨"); } // åªææªéè¿å®¡æ¹ç¶ææè½ä¿®æ¹ï¼ä½ç°å¨é»è®¤å·²éè¿ï¼æä»¥ä¸å 许修æ¹ï¼ if (existing.getApprovalStatus() != 0) { throw new ServiceException("é¢ç¨è®°å½å·²å®æåºåºï¼ä¸è½ä¿®æ¹"); } return updateById(dto); } @Override @Transactional(rollbackFor = Exception.class) public Boolean delete(List<Long> ids) { for (Long id : ids) { ProductBorrow borrow = getById(id); if (borrow != null && borrow.getApprovalStatus() != 0) { throw new ServiceException("é¢ç¨è®°å½å·²å®æåºåºï¼ä¸è½å é¤"); } } return removeByIds(ids); } @Override @Transactional(rollbackFor = Exception.class) public Boolean batchApprove(List<Long> ids, Integer approvalStatus) { for (Long id : ids) { ProductBorrow borrow = getById(id); if (borrow == null) { throw new ServiceException("é¢ç¨è®°å½ä¸åå¨: " + id); } if (borrow.getApprovalStatus() != 0) { throw new ServiceException("åªæå¾ å®¡æ¹ç¶æçè®°å½æè½å®¡æ¹"); } borrow.setApprovalStatus(approvalStatus); updateById(borrow); // 审æ¹éè¿åæ£ååºå if (approvalStatus == 1) { onApprovePass(borrow); } } return true; } @Override @Transactional(rollbackFor = Exception.class) public void onApprovePass(ProductBorrow borrow) { // æå»ºåºåæ£ååæ°ï¼è®¾ç½®å®¡æ¹ç¶æä¸ºå·²éè¿ StockInventoryDto stockInventoryDto = new StockInventoryDto(); stockInventoryDto.setProductModelId(borrow.getProductModelId()); stockInventoryDto.setBatchNo(borrow.getBatchNo()); stockInventoryDto.setQualitity(borrow.getBorrowQuantity()); stockInventoryDto.setRecordType(String.valueOf(StockOutQualifiedRecordTypeEnum.PRODUCT_BORROW.getCode())); stockInventoryDto.setRecordId(borrow.getId()); stockInventoryDto.setRemark("产åé¢ç¨åºåºï¼é¢ç¨åå·ï¼" + borrow.getBorrowNo()); stockInventoryDto.setApprovalStatus(1); stockInventoryService.subtractStockInventory(stockInventoryDto); log.info("产åé¢ç¨å®¡æ¹éè¿ï¼æ£ååºåæåï¼é¢ç¨åå·ï¼{}ï¼æ°éï¼{}", borrow.getBorrowNo(), borrow.getBorrowQuantity()); } @Override public ProductBorrowDto getDetailById(Long id) { ProductBorrowDto dto = productBorrowMapper.selectDetailById(id); if (dto != null) { fillStatusName(dto); // 计ç®å©ä½å¯å½è¿æ°é if (dto.getBorrowQuantity() != null && dto.getReturnedQuantity() != null) { dto.setRemainingQuantity(dto.getBorrowQuantity().subtract(dto.getReturnedQuantity())); } } return dto; } /** * çæé¢ç¨åå· * æ ¼å¼ï¼LY + å¹´ææ¥ + 4ä½åºå· */ private String generateBorrowNo() { String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); LambdaQueryWrapper<ProductBorrow> wrapper = new LambdaQueryWrapper<>(); wrapper.likeRight(ProductBorrow::getBorrowNo, "LY" + dateStr) .orderByDesc(ProductBorrow::getBorrowNo) .last("LIMIT 1"); ProductBorrow lastBorrow = getOne(wrapper); int sequence = 1; if (lastBorrow != null && lastBorrow.getBorrowNo() != null) { String lastNo = lastBorrow.getBorrowNo(); if (lastNo.length() >= 14) { try { sequence = Integer.parseInt(lastNo.substring(10)) + 1; } catch (NumberFormatException ignored) { } } } return "LY" + dateStr + String.format("%04d", sequence); } /** * å¡«å ç¶æåç§° */ private void fillStatusName(ProductBorrowDto dto) { // 审æ¹ç¶æåç§° if (dto.getApprovalStatus() != null) { switch (dto.getApprovalStatus()) { case 0: dto.setApprovalStatusName("å¾ å®¡æ¹"); break; case 1: dto.setApprovalStatusName("å·²éè¿"); break; case 2: dto.setApprovalStatusName("已驳å"); break; } } // å½è¿ç¶æåç§° if (dto.getStatus() != null) { switch (dto.getStatus()) { case 0: dto.setStatusName("æªå½è¿"); break; case 1: dto.setStatusName("é¨åå½è¿"); break; case 2: dto.setStatusName("å·²å ¨é¨å½è¿"); break; } } } } src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
@@ -92,6 +92,11 @@ stockInRecordDto.setBatchNo(stockInventoryDto.getBatchNo()); stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); stockInRecordDto.setType("0"); stockInRecordDto.setRemark(stockInventoryDto.getRemark()); // 妿DTO䏿å®äºå®¡æ¹ç¶æï¼å使ç¨ï¼å¦åé»è®¤å¾ å®¡æ¹ if (stockInventoryDto.getApprovalStatus() != null) { stockInRecordDto.setApprovalStatus(stockInventoryDto.getApprovalStatus()); } stockInRecordService.add(stockInRecordDto); //åè¿è¡æ°å¢åºåæ°éåºå //å æ¥è¯¢åºå表ä¸çäº§åæ¯å¦åå¨ï¼ä¸å卿°å¢ï¼å卿´æ° @@ -132,6 +137,11 @@ stockOutRecordDto.setBatchNo(stockInventoryDto.getBatchNo()); stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); stockOutRecordDto.setType("0"); stockOutRecordDto.setRemark(stockInventoryDto.getRemark()); // 妿DTO䏿å®äºå®¡æ¹ç¶æï¼å使ç¨ï¼å¦åé»è®¤å¾ å®¡æ¹ if (stockInventoryDto.getApprovalStatus() != null) { stockOutRecordDto.setApprovalStatus(stockInventoryDto.getApprovalStatus()); } stockOutRecordService.add(stockOutRecordDto); @@ -440,4 +450,9 @@ public IPage<StockInventoryDto> getBatchNoQty(Page page, StockInventoryDto stockInventoryDto) { return stockInventoryMapper.getBatchNoQty(page, stockInventoryDto); } @Override public IPage<StockInventoryDto> pageStockAndBorrow(Page page, StockInventoryDto stockInventoryDto) { return stockInventoryMapper.pageStockAndBorrow(page, stockInventoryDto); } } src/main/resources/mapper/stock/ProductBorrowMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,95 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ruoyi.stock.mapper.ProductBorrowMapper"> <resultMap id="ProductBorrowDtoMap" type="com.ruoyi.stock.dto.ProductBorrowDto"> <id column="id" property="id"/> <result column="borrow_no" property="borrowNo"/> <result column="product_model_id" property="productModelId"/> <result column="batch_no" property="batchNo"/> <result column="borrow_quantity" property="borrowQuantity"/> <result column="returned_quantity" property="returnedQuantity"/> <result column="borrower_id" property="borrowerId"/> <result column="borrower_name" property="borrowerName"/> <result column="borrow_time" property="borrowTime"/> <result column="expected_return_time" property="expectedReturnTime"/> <result column="approval_status" property="approvalStatus"/> <result column="status" property="status"/> <result column="remark" property="remark"/> <result column="tenant_id" property="tenantId"/> <result column="dept_id" property="deptId"/> <result column="create_user" property="createUser"/> <result column="create_time" property="createTime"/> <result column="update_user" property="updateUser"/> <result column="update_time" property="updateTime"/> <result column="product_name" property="productName"/> <result column="model" property="model"/> <result column="product_code" property="productCode"/> <result column="unit" property="unit"/> </resultMap> <select id="listPage" resultMap="ProductBorrowDtoMap"> WITH RECURSIVE product_tree AS ( SELECT id FROM product WHERE id = #{ew.topParentProductId} UNION ALL SELECT p.id FROM product p INNER JOIN product_tree pt ON p.parent_id = pt.id ) SELECT pb.*, p.product_name, pm.model, pm.product_code, pm.unit FROM product_borrow pb LEFT JOIN product_model pm ON pb.product_model_id = pm.id LEFT JOIN product p ON pm.product_id = p.id <where> <if test="ew.borrowNo != null and ew.borrowNo != ''"> AND pb.borrow_no LIKE CONCAT('%', #{ew.borrowNo}, '%') </if> <if test="ew.productModelId != null"> AND pb.product_model_id = #{ew.productModelId} </if> <if test="ew.borrowerId != null"> AND pb.borrower_id = #{ew.borrowerId} </if> <if test="ew.borrowerName != null and ew.borrowerName != ''"> AND pb.borrower_name LIKE CONCAT('%', #{ew.borrowerName}, '%') </if> <if test="ew.approvalStatus != null"> AND pb.approval_status = #{ew.approvalStatus} </if> <if test="ew.status != null"> AND pb.status = #{ew.status} </if> <if test="ew.deptId != null"> AND pb.dept_id = #{ew.deptId} </if> <if test="ew.topParentProductId != null and ew.topParentProductId > 0"> AND p.id IN (SELECT id FROM product_tree) </if> <if test="ew.model != null and ew.model != ''"> AND pm.model LIKE CONCAT('%', #{ew.model}, '%') </if> </where> ORDER BY pb.create_time DESC </select> <select id="selectDetailById" resultMap="ProductBorrowDtoMap"> SELECT pb.*, p.product_name, pm.model, pm.product_code, pm.unit FROM product_borrow pb LEFT JOIN product_model pm ON pb.product_model_id = pm.id LEFT JOIN product p ON pm.product_id = p.id WHERE pb.id = #{id} </select> </mapper> src/main/resources/mapper/stock/ProductBorrowReturnMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,80 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ruoyi.stock.mapper.ProductBorrowReturnMapper"> <resultMap id="ProductBorrowReturnDtoMap" type="com.ruoyi.stock.dto.ProductBorrowReturnDto"> <id column="id" property="id"/> <result column="borrow_id" property="borrowId"/> <result column="product_model_id" property="productModelId"/> <result column="batch_no" property="batchNo"/> <result column="return_quantity" property="returnQuantity"/> <result column="returner_id" property="returnerId"/> <result column="returner_name" property="returnerName"/> <result column="return_time" property="returnTime"/> <result column="remark" property="remark"/> <result column="tenant_id" property="tenantId"/> <result column="dept_id" property="deptId"/> <result column="create_user" property="createUser"/> <result column="create_time" property="createTime"/> <result column="borrow_no" property="borrowNo"/> <result column="product_name" property="productName"/> <result column="model" property="model"/> <result column="product_code" property="productCode"/> <result column="unit" property="unit"/> <result column="borrow_quantity" property="borrowQuantity"/> <result column="borrower_name" property="borrowerName"/> </resultMap> <select id="listPage" resultMap="ProductBorrowReturnDtoMap"> SELECT pbr.*, pb.borrow_no, pb.borrow_quantity, pb.borrower_name, p.product_name, pm.model, pm.product_code, pm.unit FROM product_borrow_return pbr LEFT JOIN product_borrow pb ON pbr.borrow_id = pb.id LEFT JOIN product_model pm ON pbr.product_model_id = pm.id LEFT JOIN product p ON pm.product_id = p.id <where> <if test="ew.borrowId != null"> AND pbr.borrow_id = #{ew.borrowId} </if> <if test="ew.productModelId != null"> AND pbr.product_model_id = #{ew.productModelId} </if> <if test="ew.returnerId != null"> AND pbr.returner_id = #{ew.returnerId} </if> <if test="ew.returnerName != null and ew.returnerName != ''"> AND pbr.returner_name LIKE CONCAT('%', #{ew.returnerName}, '%') </if> <if test="ew.deptId != null"> AND pbr.dept_id = #{ew.deptId} </if> </where> ORDER BY pbr.create_time DESC </select> <select id="listByBorrowId" resultMap="ProductBorrowReturnDtoMap"> SELECT pbr.*, pb.borrow_no, pb.borrow_quantity, pb.borrower_name, p.product_name, pm.model, pm.product_code, pm.unit FROM product_borrow_return pbr LEFT JOIN product_borrow pb ON pbr.borrow_id = pb.id LEFT JOIN product_model pm ON pbr.product_model_id = pm.id LEFT JOIN product p ON pm.product_id = p.id WHERE pbr.borrow_id = #{borrowId} ORDER BY pbr.create_time DESC </select> </mapper> src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -671,4 +671,58 @@ batch_no </select> <!-- å页æ¥è¯¢äº§ååºååé¢ç¨éï¼ææ¹å·åºåï¼ --> <select id="pageStockAndBorrow" resultType="com.ruoyi.stock.dto.StockInventoryDto"> WITH RECURSIVE product_tree AS ( SELECT id FROM product WHERE id = #{ew.topParentProductId} UNION ALL SELECT p.id FROM product p INNER JOIN product_tree pt ON p.parent_id = pt.id ) SELECT pm.id as product_model_id, pm.model, pm.product_code, pm.unit, p.product_name, p.id as product_id, si.batch_no, IFNULL(si.qualitity, 0) as qualitity, IFNULL(si.locked_quantity, 0) as locked_quantity, IFNULL(borrowed.borrowed_quantity, 0) as borrowed_quantity, IFNULL(si.qualitity, 0) - IFNULL(borrowed.borrowed_quantity, 0) as available_quantity FROM product_model pm LEFT JOIN product p ON pm.product_id = p.id LEFT JOIN stock_inventory si ON pm.id = si.product_model_id LEFT JOIN ( SELECT product_model_id, batch_no, SUM(borrow_quantity - IFNULL(returned_quantity, 0)) as borrowed_quantity FROM product_borrow WHERE approval_status = 1 AND status != 2 GROUP BY product_model_id, batch_no ) borrowed ON pm.id = borrowed.product_model_id AND (si.batch_no = borrowed.batch_no OR (si.batch_no IS NULL AND borrowed.batch_no IS NULL)) <where> <if test="ew.topParentProductId != null and ew.topParentProductId > 0"> AND p.id IN (SELECT id FROM product_tree) </if> <if test="ew.productName != null and ew.productName != ''"> AND p.product_name LIKE CONCAT('%', #{ew.productName}, '%') </if> <if test="ew.model != null and ew.model != ''"> AND pm.model LIKE CONCAT('%', #{ew.model}, '%') </if> <if test="ew.batchNo != null and ew.batchNo != ''"> AND si.batch_no LIKE CONCAT('%', #{ew.batchNo}, '%') </if> </where> ORDER BY pm.id DESC, si.batch_no </select> </mapper>