doc/20260920_add_sales_ledger_to_stock_out_record.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,7 @@ -- åºåºè®°å½è¡¨æ°å¢ãç»å®çéå®å°è´¦ã -- æ§è¡åºï¼product-inventory-managementï¼åç§æ·åºåï¼ -- æ²¹ååºåºè¡¨åå ééå®å°è´¦ï¼å¸¦å ¥å¯¹åºäº§åä¸å®¢æ·ãåéæ°æ®ä¸º NULLï¼æªç»å®ï¼ï¼ -- ä¸ç»å°è´¦çåºå ¥åºè¡ä¸ºä¸æ¹å¨åå®å ¨ä¸è´ ALTER TABLE `stock_out_record` ADD COLUMN `sales_ledger_id` bigint NULL DEFAULT NULL COMMENT 'ç»å®çéå®å°è´¦idï¼ä¸ºç©ºè¡¨ç¤ºæªç»å®' AFTER `batch_no`, ADD INDEX `idx_stock_out_sales_ledger_id` (`sales_ledger_id`); doc/20260920_outsourcing_menu.sql
@@ -4,7 +4,7 @@ #说æï¼æ¾å¼æå® menu_idï¼å½ååº sys_menu æå¤§ id 为 2355ï¼ï¼å¯é夿§è¡ #å æ¸ çæ§æ°æ®ï¼ä¿è¯èæ¬å¯é夿§è¡ delete from sys_menu where menu_id between 2360 and 2380; delete from sys_menu where menu_id between 2360 and 2376; #1. ç®å½ï¼å§å¤ç®¡ç insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) doc/20260920_vehicle_menu.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,15 @@ #车è¾ä¿¡æ¯ èåèæ¬ #对åºéæ±ï¼éæ±æ¸ å第 7 æ¡ï¼è½¦è¾å¯ä¸æ è¯ + 车è¾ç®¡ç + åºåºæ®æ²¹ï¼ #å端页é¢è·¯å¾çº¦å®ï¼basicData/vehicle/index #sys_menu / sys_role_menu å±äºç§æ·å¿½ç¥è¡¨ï¼æ é tenant_id #说æï¼æ¾å¼æå® menu_idï¼2377ï¼ç´§æ¥å§å¤èå 2360-2376 ä¹åï¼ï¼å¯é夿§è¡ #注æï¼æ¬èæ¬ç delete åªé对 2377ï¼ä¸ä¼ç¢°å§å¤èåï¼å§å¤èæ¬ç delete èå´æ¯ 2360-2376ï¼ä¸¤è äºä¸å¹²æ° delete from sys_role_menu where menu_id = 2377; delete from sys_menu where menu_id = 2377; insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) values (2377, '车è¾ä¿¡æ¯', 2000, 4, 'vehicle', 'basicData/vehicle/index', 1, 0, 'C', '0', '0', '', '#', 'admin', sysdate(), '', null, '车è¾ä¿¡æ¯èå'); #ææç» ææ¯è´¨éï¼role_id=2ï¼ï¼ä¸å¼ååºä¿æä¸è´ insert into sys_role_menu (role_id, menu_id) values (2, 2377); doc/20260920_ÓÍÆ·³ö¿â°ó¶¨ÏúÊŲ̂ÕËǰ¶ËÁªµ÷Îĵµ.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,260 @@ # æ²¹ååºåºç»å®éå®å°è´¦ å端èè°ææ¡£ æ´æ°æ¶é´ï¼2026-09-20 éç¨çæ¬ï¼æ¬æ¬¡åç«¯åæ´å 对åºéæ±ï¼æ²¹ååºåºè¡¨åå¢å ãç»å®éå®å°è´¦ãââå ééå®å°è´¦ï¼å¸¦å ¥å¯¹åºäº§åä¸å®¢æ· DDL è§ `doc/20260920_add_sales_ledger_to_stock_out_record.sql`ï¼**éå å¨ç®æ åºæ§è¡**ã > ä¸ `doc/20260920_æ²¹ååºåºèå¨åè´§å°è´¦å端èè°ææ¡£.md` æ¯åä¸ååè½çåå两æï¼é£ä»½è®²ãåºåºæä¹è¿åè´§å°è´¦ãæä¹æ£åºåãï¼è¿ä»½è®²ãåºåºæä¹æå°éå®å°è´¦ä¸ããææ«çå·®å¼ç¹ä»¥æ¬æä¸ºåã --- ## 1. åæ´èå´ | å 容 | å½±åé¢ | | --- | --- | | `stock_out_record` æ°å¢ `sales_ledger_id` | åºåºè®°å½è¡¨ãåè´§å°è´¦ | | æ°å¢ãå¯ç»å®éå®å°è´¦ã䏿æ¥å£ | æ²¹ååºåºè¡¨å | | ç»å®åç±å端èªå¨å®åºåºç±»å«ãå填客æ·ï¼ä»£å¨è¿åå¡«æ²¹åº/å¨ç½ï¼ | æ²¹ååºåºè¡¨å | | åºåºè®°å½å表æ°å¢åºå `salesLedgerId` / `salesContractNo` | åºåºå°è´¦å表 | | åè´§å°è´¦ `oilOut` è¡çååå·ä¸åæä¸ºç©ºï¼ä¸æ¯ææååå·çé | åè´§å°è´¦ | --- ## 2. è¡¨ç»æåæ´ `stock_out_record` æ°å¢ä¸åï¼ | å | ç±»å | é»è®¤å¼ | 说æ | | --- | --- | --- | --- | | `sales_ledger_id` | `bigint NULL` | `NULL` | ç»å®çéå®å°è´¦idï¼ä¸ºç©ºè¡¨ç¤ºæªç»å® | > åéæ°æ®å ¨ä¸º `NULL`ï¼æªç»å®ï¼ï¼æä»¥**å级åè¡ä¸ºä¸æ¹å¨åä¸è´**ï¼å·²æçåºåºè®°å½ä¸è¿ä»»ä½å°è´¦ï¼ä¹ä¸å任使 ¡éªã --- ## 3. å端æµç¨ ``` ç»å®éå®å°è´¦ï¼ä¸æï¼å¯æç´¢ï¼ â ââ éãåæ²¹ãå°è´¦ âââ åºåºç±»å« = éå®ï¼å端强å¶ï¼å端ä¸ç¨ä¼ ï¼ â å®¢æ· â å°è´¦ â 产åè§æ ¼ â å¿ é¡»é该å°è´¦æç»éçè§æ ¼ï¼åç«¯æ ¡éªï¼ â åºåºæ¹æ¬¡ â å¿ å¡«ï¼æ²¿ç¨åæè§åï¼ â â 审æ¹éè¿æ¶æ£åºåãè¿åè´§å°è´¦ â ââ éã代å¨ãå°è´¦ âââ åºåºç±»å« = 代å¨ï¼å端强å¶ï¼å端ä¸ç¨ä¼ ï¼ å®¢æ· â å°è´¦ æ²¹åº / å¨ç½ â å°è´¦ï¼åç«¯å¸¦å ¥ï¼å端ä¸ç¨æéï¼ â 䏿 ¡éªäº§åãä¸éè¦æ¹æ¬¡ã䏿£åºåãä¸è¿åè´§å°è´¦ ``` éä¸å°è´¦åå端å两件äºï¼ 1. æè¿åè¡éç `customerId` / `customerName` å¡«è¿å®¢æ·æ§ä»¶ï¼**åªè¯»å±ç¤ºå³å¯**ï¼å端ä¹ä¼ä»¥å°è´¦ä¸ºåè¦çï¼ï¼ 2. æ `GET /sales/product/list?salesLedgerId=xx&type=1`ï¼æäº§åè§æ ¼ä¸æéå®ä¸ºè¯¥å°è´¦çæç»ã 代å¨å°è´¦æ²¡ææç»ï¼è¿ä¸æ¥å¯ä»¥è·³è¿ã --- ## 4. æ¥å£ ### 4.1 å¯ç»å®éå®å°è´¦ä¸æï¼**æ°å¢**ï¼ ``` GET /stockOutRecord/bindableSalesLedger ``` | åæ° | ç±»å | 说æ | | --- | --- | --- | | `salesContractNo` | String | éå®ååå·ï¼æ¨¡ç³å¹é | | `customerName` | String | 客æ·åç§°ï¼æ¨¡ç³å¹é | | `projectName` | String | 项ç®åç§°ï¼æ¨¡ç³å¹é | | å页忰 | - | **ä¸åºåºå°è´¦å表 `/stockOutRecord/listPage` ä¼ æ³å®å ¨ä¸è´**ï¼åä¸ä¸ª `Page` å½¢åï¼ï¼ç §æé£é¡µå³å¯ | è¿å `{code, msg, data}`ï¼å `data.records`ï¼ ```json { "code": 200, "msg": "æä½æå", "data": { "records": [ { "id": 88, "salesContractNo": "XS20260901-001", "projectName": "åéæé¡¹ç®", "entryDate": "2026-09-01", "salesman": "å¼ ä¸", "customerId": 12, "customerName": "åéææè¿è¾æéå ¬å¸", "ledgerType": "åæ²¹", "oilDepotId": null, "oilDepotName": null, "tankId": null, "tankNo": null, "contractAmount": 120000.00 } ], "total": 1, "size": 10, "current": 1 } } ``` **两ç¹å£å¾ï¼å端è¦ç¥é**ï¼ 1. **ä¸è¿æ»¤å°è´¦ç±»å**ï¼åæ²¹å代å¨é½ä¼ååºæ¥ï¼ç±ç¨æ·èªå·±éãå端å¯ä»¥ç¨ `ledgerType` å两段æ¾ç¤ºï¼æå 个çéï¼ï¼ä½ä¸è¦åè®¾åªæåæ²¹ã 2. **ä¸åæ°æ®æéè¿æ»¤**ï¼è¯¥æ¥å£æ¯**ä¸é¨**为åºåºè¡¨åå¼çï¼è·³è¿äº `create_user` / `dept_id` è¿æ»¤ ââ å¦åæ²¹åº/åè´§è§è²ä¼çä¸å°éå®å»ºçå°è´¦ï¼ä¸æç´æ¥æ¯ç©ºçãè¿æ¯å»æçï¼**ä¸è¦**æ®æ¤è®¤ä¸ºéå®å°è´¦é¡µçå¯è§èå´ä¹æ¾å¼äºï¼é£ä¸ªé¡µé¢ä»ææ°æ®æéè¿æ»¤ï¼ã ### 4.2 å°è´¦äº§åæç»ï¼**å¤ç¨ç°ææ¥å£ï¼æªæ¹å¨**ï¼ ``` GET /sales/product/list?salesLedgerId=88&type=1 ``` è¿å该å°è´¦ç产åè¡ï¼`productModelId`ã`specificationModel`ã`unit`ã`productCategory`ã`quantity` çï¼ã`type=1` æ¯éå®è¡ï¼**å¿ é¡»å¸¦ä¸**ï¼å¦å伿éè´è¡ä¹æåºæ¥ã ### 4.3 æ°å¢æ²¹ååºåºï¼**请æ±ä½æ°å¢ä¸ä¸ªå段**ï¼ ``` POST /stockInventory/addOilOutRecordOnly ``` 请æ±ä½å¨åæå段åºç¡ä¸**å¤ä¼ ä¸ä¸ª `salesLedgerId`**ï¼ ```json { "salesLedgerId": 88, "productModelId": 301, "batchNo": "20260917-CY001-001", "outTonnage": 9.00, "vehicleId": 5, "truckPlateNo": "èF12345", "outDate": "2026-09-20", "remark": "é¦è½¦" } ``` **ç»å®æ¶è¿ 4 ä¸ªåæ®µä¸ç¨ä¼ ï¼ä¼ äºä¹ä¼è¢«è¦çï¼**ï¼`outCategory`ã`customerId`ã`customerName`ï¼ä»£å¨å°è´¦è¿æ `oilDepotId` / `oilDepotName` / `tankId` / `tankNo`ï¼ã ä¸ä¼ `salesLedgerId` æ¶æ¥å£è¡ä¸º**䏿¹å¨åå®å ¨ä¸è´**ï¼èåç«¯ä¸æ¹ä¹è½è·ã --- ## 5. å端å½ä¸åè§å `salesLedgerId` 为空 â å ¨é¨è·³è¿ï¼ä¸æ ¡éªãä¸è¦çã `salesLedgerId` æå¼ â å æ¥å°è´¦ï¼åæå°è´¦ç**éå®ç±»å**åæµï¼ | å°è´¦ç±»å | åºåºç±»å« | å®¢æ· | 产å | æ²¹åº/å¨ç½ | | --- | --- | --- | --- | --- | | åæ²¹ï¼å«ç±»åä¸ºç©ºï¼ | å¼ºå¶ `éå®` | å°è´¦è¦ç | **å¿ é¡»**å±äºè¯¥å°è´¦æç»ï¼`type=1`ï¼ï¼å¦åæ¥é | ä¸å¨ï¼å端èªå·±é | | ä»£å¨ | å¼ºå¶ `代å¨` | å°è´¦è¦ç | **䏿 ¡éª**ï¼ä»£å¨å°è´¦æ²¡ææç»ï¼ | å°è´¦è¦ç | > åæ²¹å°è´¦çãç±»å为空ã乿忲¹å¤ç ââ åéå°è´¦å¯è½æ `ledgerType` 为空çï¼ä¸ååå½åæ²¹ï¼æ¥éææ¡ä¹è½æç¤ºåºæ¥ã ### 5.1 æ ¡éªéè¯¯ææ¡ | åºæ¯ | `msg` | | --- | --- | | `salesLedgerId` æ¥ä¸å°å°è´¦ | `æééå®å°è´¦ä¸åå¨,éå®å°è´¦id:88` | | ç»åæ²¹å°è´¦ä½æ²¡ä¼ `productModelId` | `ç»å®éå®å°è´¦æ¶å¿ é¡»éæ©äº§åè§æ ¼,éå®ååå·:XS20260901-001` | | ç»åæ²¹å°è´¦ä½äº§åä¸å¨è¯¥å°è´¦æç»é | `æé产åä¸å¨è¯¥éå®å°è´¦æç»ä¸,éå®ååå·:XS20260901-001` | | ç»äºåæ²¹å°è´¦ä½æ²¡éåºåºæ¹æ¬¡ | `éå®ç±»åºåºå¿ 须鿩åºåºæ¹æ¬¡`ï¼åææ ¡éªï¼ç»å®åä¼è§¦åï¼ | é误ååºå½¢æï¼ä¸å¡å¼å¸¸ç»ä¸èµ°å ¨å±å¤çå¨ï¼ï¼ ```json { "code": 500, "msg": "æé产åä¸å¨è¯¥éå®å°è´¦æç»ä¸,éå®ååå·:XS20260901-001" } ``` ### 5.2 ç¼è¾åºåºè®°å½ä¹è¦æ³¨æ `PUT /stockOutRecord/{id}` åæ ·ä¼è·ä¸é¢çå½ä¸åãä½è¯¥æ¥å£æ¯**æ´ä½è¦ç**è¯ä¹ï¼`BeanUtils.copyProperties`ï¼`null` ä¹ä¼çä¸å»ï¼ï¼ - **ç¼è¾å¿ é¡»åä¼ å®æ´å¯¹è±¡ï¼å å« `salesLedgerId`**ï¼ - è¥ç¼è¾æ¶ä¸ä¼ `salesLedgerId`ï¼**ç»å®ä¼è¢«æ¸ 空**ï¼`outCategory` / 客æ·åçï¼ãè¿æ¯è¯¥æ¥å£çæ¢æè¯ä¹ï¼ææå段é½ä¸æ ·ï¼ä¸æ¯æ¬æ¬¡å¼å ¥çã åªæ³æ¹æ°é/夿³¨çè¯ï¼å»ºè®®å端å å详æ åæ´ä½æäº¤ã --- ## 6. åºååå ### 6.1 åºåºå°è´¦å表 ââ `GET /stockOutRecord/listPage` `R.data.records` æ°å¢ä¸¤åï¼**åªå¤ä¸å°**ï¼ï¼ | åæ®µ | 说æ | | --- | --- | | `salesLedgerId` | ç»å®çéå®å°è´¦idï¼æªç»å®ä¸º `null` | | `salesContractNo` | éå®ååå·ï¼ç± `sales_ledger` å ³è带åºï¼ï¼æªç»å®ä¸º `null` | ### 6.2 åè´§å°è´¦ ââ `GET /shippingInfo/listPage` `source='oilOut'` çè¡ï¼éå®ç±»æ²¹ååºåºï¼**ä¸¤ä¸ªåæ®µç±ãæä¸ºç©ºãæ¹ä¸ºåç»å®å¼**ï¼ | åæ®µ | åå | | --- | --- | | `salesLedgerId` | åæä¸º `null` â å `stock_out_record.sales_ledger_id` | | `salesContractNo` | åæä¸º `null` â åç»å®å°è´¦çååå· | **çéè¡ä¸ºä¹è·çåäº**ï¼ | æ¥è¯¢åæ° | `shipping` è¡ | `oilOut` è¡ï¼æ¹å¨å â æ¹å¨åï¼ | | --- | --- | --- | | `salesContractNo` | æåè´§åå ³èçååå·å¹é | æä¸å¹é â **æç»å®å°è´¦çååå·å¹é **ï¼æªç»å®çè¡ä»ç¶ä¸ä¼è¢«çå° | | `expressNumber` | æå¿«éåå·å¹é | æä¸å¹é ï¼æ ååï¼æ²¹ååºåºæ²¡æå¿«éåï¼ | > 代å¨åºåº**ä¸è¿**åè´§å°è´¦ï¼`WHERE out_category='éå®'`ï¼ï¼æä»¥ä»£å¨ç»å®ä¸ä¼å¨è¿éåºç°ã --- ## 7. 注æäºé¡¹ **â ç»å®ä¸æ¯ãå ç¨ãï¼ä¸æ£æ¥å°è´¦ä½é** ç»å°è´¦åªæ¯æåºåºæå°å°è´¦ä¸ï¼**䏿 ¡éªè¯¥å°è´¦å·²åäºå¤å°ãè¿å©å¤å°**ãå°è´¦æ¯ä¸ªè§æ ¼çãå·²åè´§ / å¾ åè´§ãæ¯å¦ä¸å¥ç»è®¡ï¼`/sales/product/list` ç `shippedQuantity` / `noQuantity`ï¼ï¼æ¬æ¥å£ä¸åä¸ï¼ä¹ä¸ä¼ååãæ¯å¦è¶ é¢åè´§ï¼å端è¥è¦æ¦ï¼è¯·èªè¡æ¯å¯¹ã **â¡ ã代å¨ãåºåºå®å ¨ä¸æ£åºå** 代å¨åºåºçè¯ä¹æ¯å®¢æ·æèªå·±çæ²¹æèµ°ï¼ä¸æ¶åéå®ãæä»¥å³ä½¿åºåºç±»å«æ¯ä»£å¨ï¼å®¡æ¹éè¿ä¹ä¸æ£ `stock_inventory`ãå é¤ä¹ä¸å½è¿ï¼ä¸ã客åãä¸è´ãåªæ **éå®** ç±»ææ£åºåãç»ä¸ç»å°è´¦é½ä¸æ¹åè¿ä¸ç¹ã **⢠ä¸ä»£å¨å°è´¦æ²¡æäº§åæç»** 代å¨å°è´¦æ¯ãååå¨ä½ç½®ãï¼ä¸»è¡¨ä¸åªææ²¹åº + å¨ç½ + æå·¥å¡«çååéé¢ï¼`sales_ledger_product` éæ²¡æå®çè¡ãæä»¥ä»£å¨ç»å®**è·³è¿äº§åæ ¡éª**ï¼ä¹**ä¸è¦**æ¿ `/sales/product/list?salesLedgerId=xx&type=1` å»ç»å®å¡«äº§å䏿ï¼ä¼è¿å空ï¼ã **⣠ç»å®å°è´¦çäº§åæ ¡éªåªå¨æäº¤æ¶çæ** å端æäº§å䏿éå®ä¸ºå°è´¦æç»åªæ¯ä½éªä¼åï¼çæ£çæ¦æªå¨å端ãä½**代å¨è·³è¿äºè¿éæ ¡éª**ï¼å¦æä»£å¨å°è´¦è¢«è¯¯å½æåæ²¹å°è´¦ç¨ï¼æ¯å¦å°è´¦ç±»åæ¹äºï¼ï¼æäº¤æ¶æä¼æ¥ãæé产åä¸å¨è¯¥éå®å°è´¦æç»ä¸ãã **⤠åºåºè®°å½çå ¶å®å段没å** `outCategory` é¤äºè¢«ç»å®è¦çå¤ï¼å ¶ä½éå¼é»è¾ãæ¹æ¬¡å¿ å¡«ãæ£åºåæ¶æºãè¿åè´§å°è´¦çæ¡ä»¶é½æ²¿ç¨åå®ç°ï¼è§ `doc/20260920_æ²¹ååºåºèå¨åè´§å°è´¦å端èè°ææ¡£.md`ã --- ## 8. èè°èªæ¥æ¸ å - [ ] `/stockOutRecord/bindableSalesLedger` è½è¿åå°è´¦å表ï¼åæ²¹å代å¨é½å¨ - [ ] ç¨æ²¹åº/åè´§è§è²çè´¦å·ï¼ééå®ï¼ä¹è½çå°å°è´¦ï¼éªè¯æ°æ®æéç¡®å®è¢«è·³è¿ï¼ - [ ] æååå· / 客æ·å / 项ç®åæç´¢ï¼ç»ææ£ç¡® - [ ] éåæ²¹å°è´¦ â 客æ·èªå¨å¸¦å ¥ï¼äº§å䏿åªå©è¯¥å°è´¦æç»çè§æ ¼ - [ ] éåæ²¹å°è´¦ + å°è´¦å¤çè§æ ¼æäº¤ â æ¥ãæé产åä¸å¨è¯¥éå®å°è´¦æç»ä¸ã - [ ] éåæ²¹å°è´¦ + å°è´¦å è§æ ¼ + ç©ºæ¹æ¬¡æäº¤ â æ¥ãéå®ç±»åºåºå¿ 须鿩åºåºæ¹æ¬¡ã - [ ] éåæ²¹å°è´¦æäº¤æå â åºåºå°è´¦è¯¥è¡ `salesLedgerId` / `salesContractNo` æå¼ - [ ] 该è¡å®¡æ¹éè¿ â `stock_inventory` ææ¹æ¬¡æ£åï¼åè´§å°è´¦åºç°è¯¥è¡ä¸ `salesContractNo` æå¼ - [ ] é代å¨å°è´¦ â åºåºç±»å«èªå¨åã代å¨ãï¼æ²¹åº/å¨ç½èªå¨å¸¦å ¥ï¼äº§åä¸ç¨éä¹è½æäº¤ - [ ] 代å¨å°è´¦ç»å®æ¶ä¸ä¼ 产å â æäº¤æåï¼éªè¯è·³è¿äºäº§åæ ¡éªï¼ - [ ] 代å¨åºåºå®¡æ¹éè¿ â åºåä¸åï¼åè´§å°è´¦**ä¸åºç°**è¯¥è¡ - [ ] `salesLedgerId` ä¼ ä¸ä¸ªä¸åå¨ç id â æ¥ãæééå®å°è´¦ä¸åå¨ã - [ ] ä¸ä¼ `salesLedgerId` èµ°åæçéå®/代å¨/客ååºåº â è¡ä¸ºä¸æ¹å¨åä¸è´ï¼åå½ï¼ - [ ] åè´§å°è´¦æååå·çéï¼`oilOut` è¡éç»äºè¯¥ååçè½è¢«çå°ï¼æªç»å®çä¸åºç° - [ ] åè´§å°è´¦æå¿«éåå·çéï¼ä»ç¶ä¸è¿åä»»ä½ `oilOut` è¡ - [ ] ç¼è¾ä¸æ¡å·²ç»å®çåºåºè®°å½ï¼**åä¼ äº `salesLedgerId`** â ç»å®è¿å¨ - [ ] ç¼è¾æ¶ä¸åä¼ `salesLedgerId` â ç»å®è¢«æ¸ 空ï¼ç¡®è®¤è¿æ¯æ¥å£çæ´ä½è¦çè¯ä¹ï¼èé丢äºï¼ doc/20260920_ÓÍÆ·³ö¿âÁª¶¯·¢»ǫ̃ÕËǰ¶ËÁªµ÷Îĵµ.md
@@ -23,6 +23,8 @@ **æ¬æ¬¡æ²¡æä»»ä½ DDL**ï¼ç¨å°ç `stock_out_record.batch_no`ã`out_category`ã`tank_no`ã`truck_plate_no` çåé½å·²åå¨ã > **åç»è¿½å ï¼åä¸å¤©ï¼**ï¼ä¹åååäºãæ²¹ååºåºç»å®éå®å°è´¦ãï¼ç» `stock_out_record` è¡¥äº `sales_ledger_id` åï¼DDL è§ `doc/20260920_add_sales_ledger_to_stock_out_record.sql`ï¼ãä¸é¢ 2.2ã2.3 é `salesLedgerId` / `salesContractNo` çãæä¸ºç©ºããæä¸å¹é ãå·²é乿¹æåç»å®å¼ï¼ä»¥ **`doc/20260920_æ²¹ååºåºç»å®éå®å°è´¦å端èè°ææ¡£.md`** 为åã --- ## 2. åè´§å°è´¦å表å¥çº¦ï¼**å¿ ç `source`**ï¼ @@ -64,7 +66,8 @@ | `outBatchNo` | `batch_no`ï¼æ¹å·ï¼`source='shipping'` è¡æä¸º `null`ï¼ | | `batchNoList` | ç±æ¬è¡åæ®µæ¼æçåå ç´ æ°ç»ï¼ä¾è¯¦æ å¼¹æ¡ãæ¹å·ãæç»è¡¨ç¨ï¼ä» `oilOut` è¡ï¼ | | `outCategory` / `tankNo` / `oilProduct` / `oilDepotName` / `driverName` / `contactPerson` / `contactPhone` | åååºåºä¾§åï¼æ°å¢åºåï¼å¯ç¨ä½å±ç¤ºï¼ | | `salesContractNo` / `expressNumber` / `expressCompany` / `salesLedgerId` | **æä¸ºç©º**ï¼æ²¹ååºåºæ²¡æååå·/å¿«éåï¼ | | `salesLedgerId` / `salesContractNo` | ç»å®äºéå®å°è´¦æ¶æå¼ï¼æªç»å®ä¸º `null`ï¼è§ `doc/20260920_æ²¹ååºåºç»å®éå®å°è´¦å端èè°ææ¡£.md`ï¼ | | `expressNumber` / `expressCompany` | **æä¸ºç©º**ï¼æ²¹ååºåºæ²¡æå¿«éåï¼ | ### 2.2.1 æ¹å·æä¹æ¾ç¤ºï¼è¯¦æ å¼¹æ¡ï¼ @@ -97,8 +100,8 @@ | --- | --- | --- | | `shippingNo` | `shipping_info.shipping_no` | `stock_out_record.outbound_batches` | | `shippingCarNumber` | `shipping_info.shipping_car_number` | `stock_out_record.truck_plate_no` | | `salesContractNo` | `sales_ledger.sales_contract_no` | **æä¸å¹é **ï¼æååå·çéæ¶ä¸ä¼è¿åæ²¹åè¡ï¼è¿æ¯å»æçï¼ | | `expressNumber` | `shipping_info.express_number` | **æä¸å¹é ** | | `salesContractNo` | `shipping_info` â `sales_ledger` çååå· | æ**ç»å®ç**éå®å°è´¦ååå·å¹é ï¼æªç»å®çæ²¹åè¡ä¸ä¼è¢«çå° | | `expressNumber` | `shipping_info.express_number` | **æä¸å¹é **ï¼æ²¹ååºåºæ²¡æå¿«éåï¼ | --- @@ -150,7 +153,7 @@ - [ ] 该è¡ãåè´§ / å é¤ / éè´§ãæé®**ä¸åºç°**ï¼æç¹äºèµ°çæ¯åºåºå°è´¦ï¼ä¸æ¯ `shipping_info`ï¼ - [ ] å页 `total` ä¸å®é è¡æ°ä¸è´ï¼æ¬æ¬¡æ¹äº UNIONï¼éç¹åå½é¡¹ï¼ - [ ] æãåè´§åå·ãçéï¼`shipping` å `oilOut` 两类è¡é½è½è¢«çå° - [ ] æãéå®ååå·ãçéï¼åªå© `shipping` è¡ï¼æ²¹åè¡ä¸åºç° - [ ] æãéå®ååå·ãçéï¼ç»å®äºè¯¥ååçæ²¹åè¡ä¹è½è¢«çå°ï¼**æªç»å®**çæ²¹åè¡ä¸åºç° - [ ] æ²¹ååºåºè¡¨åï¼åºåºç±»å«=é宿¶ä¸å¡«æ¹æ¬¡ï¼æäº¤æ¥ãéå®ç±»åºåºå¿ 须鿩åºåºæ¹æ¬¡ã - [ ] æ²¹ååºåºè¡¨åï¼åºåºç±»å«=代å¨/客忶ä¸å¡«æ¹æ¬¡è½æ£å¸¸æäº¤ - [ ] æ°å»ºéå®ç±»åºåºï¼æ¹æ¬¡ `CG20260815005-187`ãæ°é 10ï¼â 审æ¹éè¿ â `stock_inventory.qualitity` ç± 1000 å 990 src/main/java/com/ruoyi/stock/controller/StockOutRecordController.java
@@ -5,6 +5,7 @@ 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.sales.dto.SalesLedgerDto; import com.ruoyi.stock.dto.StockOutRecordDto; import com.ruoyi.stock.service.StockOutRecordService; import io.swagger.v3.oas.annotations.tags.Tag; @@ -111,4 +112,10 @@ return AjaxResult.success(stockOutRecordService.updateResidualOil(id, stockOutRecordDto.getResidualOil())); } @GetMapping("/bindableSalesLedger") @Operation(summary = "æ²¹ååºåº-å¯ç»å®çéå®å°è´¦ä¸æ") public AjaxResult bindableSalesLedger(Page page, SalesLedgerDto salesLedgerDto) { return AjaxResult.success(stockOutRecordService.listBindableSalesLedger(page, salesLedgerDto)); } } src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java
@@ -33,6 +33,12 @@ private String createBy; /** * éå®ååå·ãç»å®äºéå®å°è´¦æ¶ç± sales_ledger å ³è带åºï¼ä¸æ¯ stock_out_record çå */ @Schema(description = "éå®ååå·ï¼ç»å®äºéå®å°è´¦æ¶æå¼ï¼") private String salesContractNo; @Schema(description = "é¡¶é¨ç¶äº§åid") private Long topParentProductId; src/main/java/com/ruoyi/stock/mapper/StockOutRecordMapper.java
@@ -6,6 +6,8 @@ import com.ruoyi.account.bean.dto.sales.SalesOutboundDto; import com.ruoyi.account.bean.vo.sales.SalesOutboundVo; import com.ruoyi.stock.dto.StockOutRecordDto; import com.ruoyi.sales.dto.SalesLedgerDto; import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.stock.execl.StockOutRecordExportData; import com.ruoyi.stock.pojo.StockOutRecord; import org.apache.ibatis.annotations.Mapper; @@ -38,4 +40,13 @@ */ List<StockOutRecord> selectByRecordIds(@Param("recordIds") List<Long> recordIds, @Param("recordType") String recordType); /** * æ²¹ååºåºå¯ç»å®çéå®å°è´¦ä¸æã * * <p>éå®å°è´¦æ¯è¢«åºåºåå¼ç¨çä¸»æ°æ®ï¼è {@code sales_ledger} ä¸å¨ {@code IgnoreTableConfig.IGNORE_TABLES} * ç½ååéï¼æ create_user/dept_id è¿æ»¤ä¼è®©æ²¹åº/åè´§è§è²éä¸å°éå®å»ºçå°è´¦ï¼æä»¥è¿éæ¾å¼è·³è¿æ°æ®æéã * åªè¯»æ¥è¯¢ï¼ä¸ä¸æ ledgerType è¿æ»¤ ââ 代å¨å°è´¦ä¹è¦è½ç»ï¼ç»äºèµ°ä»£å¨åºåºï¼</p> */ IPage<SalesLedger> bindableSalesLedgerPage(Page page, @Param("req") SalesLedgerDto salesLedgerDto); } src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java
@@ -38,6 +38,9 @@ @Schema(description = "æ¹å·") private String batchNo; @Schema(description = "ç»å®çéå®å°è´¦idï¼ä¸ºç©ºè¡¨ç¤ºæªç»å®") private Long salesLedgerId; @Schema(description = "å ¥åºæ°é") private BigDecimal stockOutNum; src/main/java/com/ruoyi/stock/service/StockOutRecordService.java
@@ -3,6 +3,8 @@ 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.sales.dto.SalesLedgerDto; import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.stock.dto.OilOutAvailableDto; import com.ruoyi.stock.dto.StockOutRecordDto; import com.ruoyi.stock.pojo.StockOutRecord; @@ -69,4 +71,10 @@ * @return å é¤çè®°å½æ° */ int releaseByRecordIds(List<Long> recordIds, String recordType); /** * æ²¹ååºåºå¯ç»å®çéå®å°è´¦ä¸æï¼æ¯ææååå·/客æ·å/项ç®å模ç³çéï¼ä¸å ledgerTypeï¼ä»£å¨å°è´¦ä¹è½ç»ï¼ã * ä¸åæ°æ®æé约æï¼çç±è§ {@code StockOutRecordMapper#bindableSalesLedgerPage} */ IPage<SalesLedger> listBindableSalesLedger(Page page, SalesLedgerDto salesLedgerDto); } src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java
@@ -23,6 +23,11 @@ import com.ruoyi.outsourcing.mapper.OutsourcingOrderProductMapper; import com.ruoyi.outsourcing.pojo.OutsourcingOrder; import com.ruoyi.outsourcing.pojo.OutsourcingOrderProduct; import com.ruoyi.sales.dto.SalesLedgerDto; import com.ruoyi.sales.mapper.SalesLedgerMapper; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.sales.pojo.SalesLedgerProduct; import java.time.LocalDateTime; import com.ruoyi.stock.dto.OilOutAvailableDto; @@ -64,6 +69,21 @@ */ private static final String OUT_CATEGORY_SALE = "éå®"; /** * åºåºç±»å«ï¼ä»£å¨ãå®¢æ·æèªå·±çæ²¹å¯å卿们çç½éï¼æèµ°åªæ¯è®°å½ä¸ç¬ï¼ä¸æ£åºåãä¸è¿åè´§å°è´¦ */ private static final String OUT_CATEGORY_DEPOSIT = "代å¨"; /** * éå®å°è´¦çéå®ç±»åï¼ä»£å¨ï¼ååå¨ä½ç½®ï¼ãè¿ç±»å°è´¦æ²¡æäº§åæç»ï¼åªææ²¹åº+å¨ç½ï¼è§ SalesLedger.ledgerType */ private static final String LEDGER_TYPE_DEPOSIT = "代å¨"; /** * éå®å°è´¦äº§åæç»çè¡ç±»åï¼éå®ãè§ sales_ledger_product.type */ private static final Integer LEDGER_PRODUCT_TYPE_SALE = 1; private final StockOutRecordMapper stockOutRecordMapper; private final IVehicleService vehicleService; private final StockInventoryMapper stockInventoryMapper; @@ -72,6 +92,8 @@ private final AccountInvoiceApplicationMapper accountInvoiceApplicationMapper; private final OutsourcingOrderProductMapper outsourcingOrderProductMapper; private final OutsourcingOrderMapper outsourcingOrderMapper; private final SalesLedgerMapper salesLedgerMapper; private final SalesLedgerProductMapper salesLedgerProductMapper; @Override public IPage<StockOutRecordDto> listPage(Page page, StockOutRecordDto stockOutRecordDto) { @@ -80,6 +102,7 @@ @Override public int add(StockOutRecordDto stockOutRecordDto) { resolveSalesLedgerBinding(stockOutRecordDto); if (OUT_CATEGORY_SALE.equals(stockOutRecordDto.getOutCategory())) { // éå®ç±»æ²¹ååºåºå®¡æ¹éè¿æ¶è¦ææ¹æ¬¡æ£ååºåï¼æ¹æ¬¡ä¸è½ä¸ºç©º if (StringUtils.isEmpty(stockOutRecordDto.getBatchNo())) { @@ -109,9 +132,53 @@ throw new BaseException("该åºåºè®°å½ä¸åå¨,æ æ³æ´æ°!!!"); } resolveSalesLedgerBinding(stockOutRecordDto); String[] ignoreProperties = {"id", "outbound_batches"};//æé¤id屿§ BeanUtils.copyProperties(stockOutRecordDto, stockOutRecord, ignoreProperties); return stockOutRecordMapper.updateById(stockOutRecord); } /** * ç»å®éå®å°è´¦ï¼å®¢æ·ä¸å¾ä»¥å°è´¦ä¸ºåè¦çï¼é¿å åºåºè®°å½ä¸å°è´¦ç客æ·å¯¹ä¸ä¸ï¼åºåºç±»å«æå°è´¦çéå®ç±»åèªå¨å®ï¼ * å å¾åºç°ãç»äºåæ²¹å°è´¦å´æä»£å¨ä¸æ£åºåãè¿ç±»çç¾æ°æ®ã * <ul> * <li>åæ²¹ï¼å« ledgerType 为空ï¼ï¼åºåºç±»å«ç½®ãéå®ãï¼å¹¶æ ¡éªæéè§æ ¼ç¡®å®å¨è¯¥å°è´¦çé宿ç»é</li> * <li>代å¨ï¼åºåºç±»å«ç½®ã代å¨ãï¼å¸¦å ¥å°è´¦çæ²¹åº/å¨ç½ï¼è·³è¿äº§åæ ¡éª ââ * 代å¨å°è´¦æ¬èº«å°±æ¯ååå¨ä½ç½®ï¼æ²¡æäº§åæç»</li> * </ul> * salesLedgerId ä¸ºç©ºæ¶æ´ä½è·³è¿ï¼ä¸ç»å°è´¦çåºåºè¡ä¸ºä¸æ¹å¨åå®å ¨ä¸è´ */ private void resolveSalesLedgerBinding(StockOutRecordDto stockOutRecordDto) { if (stockOutRecordDto.getSalesLedgerId() == null) { return; } SalesLedger salesLedger = salesLedgerMapper.selectById(stockOutRecordDto.getSalesLedgerId()); if (salesLedger == null) { throw new BaseException("æééå®å°è´¦ä¸åå¨,éå®å°è´¦id:" + stockOutRecordDto.getSalesLedgerId()); } stockOutRecordDto.setCustomerId(salesLedger.getCustomerId()); stockOutRecordDto.setCustomerName(salesLedger.getCustomerName()); if (LEDGER_TYPE_DEPOSIT.equals(salesLedger.getLedgerType())) { stockOutRecordDto.setOutCategory(OUT_CATEGORY_DEPOSIT); stockOutRecordDto.setOilDepotId(salesLedger.getOilDepotId()); stockOutRecordDto.setOilDepotName(salesLedger.getOilDepotName()); stockOutRecordDto.setTankId(salesLedger.getTankId()); stockOutRecordDto.setTankNo(salesLedger.getTankNo()); return; } stockOutRecordDto.setOutCategory(OUT_CATEGORY_SALE); if (stockOutRecordDto.getProductModelId() == null) { throw new BaseException("ç»å®éå®å°è´¦æ¶å¿ é¡»éæ©äº§åè§æ ¼,éå®ååå·:" + salesLedger.getSalesContractNo()); } boolean belongsToLedger = salesLedgerProductMapper.selectList( Wrappers.<SalesLedgerProduct>lambdaQuery() .eq(SalesLedgerProduct::getSalesLedgerId, stockOutRecordDto.getSalesLedgerId()) .eq(SalesLedgerProduct::getType, LEDGER_PRODUCT_TYPE_SALE)) .stream() .anyMatch(item -> stockOutRecordDto.getProductModelId().equals(item.getProductModelId())); if (!belongsToLedger) { throw new BaseException("æé产åä¸å¨è¯¥éå®å°è´¦æç»ä¸,éå®ååå·:" + salesLedger.getSalesContractNo()); } } @Override @@ -520,6 +587,15 @@ } @Override public IPage<SalesLedger> listBindableSalesLedger(Page page, SalesLedgerDto salesLedgerDto) { // 该æ¥è¯¢ç¨ /*data_scope*/ è·³è¿æ°æ®æéï¼è MP é»è®¤ä¼æ count è¯å¥ä¼åæãSELECT COUNT(*) FROM sales_ledger // WHERE ...ãï¼ä¼ååæ è®°ä¸¢å¤±ï¼count åèè¢«è¿½å æéæ¡ä»¶ï¼total 伿¯å®é è®°å½å°ãå ³æ count ä¼åå // count éåæãSELECT COUNT(*) FROM (åå¥) TOTALãï¼æ è®°åæ ·ä¿ç page.setOptimizeCountSql(false); return stockOutRecordMapper.bindableSalesLedgerPage(page, salesLedgerDto); } @Override @Transactional(rollbackFor = Exception.class) public int releaseByRecordIds(List<Long> recordIds, String recordType) { List<StockOutRecord> records = listByRecordIds(recordIds, recordType); src/main/resources/mapper/sales/ShippingInfoMapper.xml
@@ -66,7 +66,7 @@ UNION ALL SELECT o.id, NULL as sales_ledger_id, o.sales_ledger_id, o.out_date as shipping_date, o.truck_plate_no as shipping_car_number, NULL as express_number, @@ -79,7 +79,7 @@ o.create_user, o.update_user, NULL as tenant_id, NULL as sales_contract_no, sl2.sales_contract_no, pm2.model as specification_model, pm2.unit, p2.product_name, @@ -99,11 +99,13 @@ FROM stock_out_record o left join product_model pm2 on pm2.id = o.product_model_id left join product p2 on p2.id = pm2.product_id <!-- ç»å®äºéå®å°è´¦çæ²¹ååºåºå¸¦åºååå·ï¼æ²¡ç»çè¡è¯¥åä»ä¸ºç©º --> left join sales_ledger sl2 on sl2.id = o.sales_ledger_id WHERE o.out_category = 'éå®' AND o.approval_status = 1 <!-- æ²¹ååºåºæ²¡æååå·/å¿«éåï¼æè¿ä¸¤é¡¹çéæ¶ä¸åºè¿å任使²¹åè¡ --> <if test="req.salesContractNo != null and req.salesContractNo != ''"> AND 1=0 AND sl2.sales_contract_no LIKE CONCAT('%',#{req.salesContractNo},'%') </if> <!-- æ²¹ååºåºæ²¡æå¿«éåï¼æå¿«éåå·çéæ¶ä¸åºè¿å任使²¹åè¡ --> <if test="req.expressNumber != null and req.expressNumber != ''"> AND 1=0 </if> src/main/resources/mapper/stock/StockOutRecordMapper.xml
@@ -34,11 +34,14 @@ p.product_name as productName, pm.model, pm.unit, u.nick_name as createBy u.nick_name as createBy, sl.sales_contract_no as salesContractNo FROM stock_out_record as sor LEFT JOIN product_model as pm on sor.product_model_id = pm.id LEFT JOIN product as p on pm.product_id = p.id LEFT JOIN sys_user as u on sor.create_user = u.user_id <!-- ç»å®äºéå®å°è´¦çåºåºå¸¦åºååå·ï¼sales_ledger_id æ¬èº«å·²é sor.* è¿å --> LEFT JOIN sales_ledger as sl on sl.id = sor.sales_ledger_id <where> <if test="params.timeStr != null and params.timeStr != ''"> and sor.create_time like concat('%',#{params.timeStr},'%') @@ -76,6 +79,39 @@ </foreach> </select> <!-- æ²¹ååºåºå¯ç»å®çéå®å°è´¦ä¸æã sales_ledger ä¸å¨æ°æ®æéç½ååéï¼æ create_user/dept_id è¿æ»¤ä¼è®©æ²¹åº/åè´§è§è²éä¸å°éå®å»ºçå°è´¦ï¼ æä»¥å /*data_scope*/ è·³è¿æ°æ®æéï¼åªè¯»æ¥è¯¢ï¼ä¸æ ledger_type è¿æ»¤ï¼ä»£å¨å°è´¦ä¹è¦è½ç»ï¼ --> <select id="bindableSalesLedgerPage" resultType="com.ruoyi.sales.pojo.SalesLedger"> select /*data_scope*/ id, sales_contract_no, customer_contract_no, project_name, entry_date, salesman, customer_id, customer_name, ledger_type, oil_depot_id, oil_depot_name, tank_id, tank_no, approval_status, contract_amount from sales_ledger where 1=1 <if test="req.salesContractNo != null and req.salesContractNo != ''"> and sales_contract_no like concat('%',#{req.salesContractNo},'%') </if> <if test="req.customerName != null and req.customerName != ''"> and customer_name like concat('%',#{req.customerName},'%') </if> <if test="req.projectName != null and req.projectName != ''"> and project_name like concat('%',#{req.projectName},'%') </if> order by id desc </select> <select id="listStockOutRecordExportData" resultType="com.ruoyi.stock.execl.StockOutRecordExportData"> SELECT sor.*,