From 4635770544e2d57416ad88a8983ee293919f5fec Mon Sep 17 00:00:00 2001
From: liyong <18434998025@163.com>
Date: 星期一, 25 五月 2026 09:25:36 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_New_pro' into dev_New_pro

---
 src/main/java/com/ruoyi/account/mapper/AccountStatementMapper.java                     |    3 
 src/main/java/com/ruoyi/home/dto/StatisticsReceivablePayableDto.java                   |    4 
 src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java            |   24 
 src/main/resources/mapper/account/AccountStatementMapper.xml                           |   35 
 src/main/java/com/ruoyi/project/system/service/ISysUserService.java                    |    7 
 src/main/java/com/ruoyi/project/system/service/impl/SysUserServiceImpl.java            |    7 
 src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java           |   52 -
 src/main/java/com/ruoyi/purchase/service/PurchaseReportService.java                    |   14 
 src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml                            |  162 ++-
 src/main/java/com/ruoyi/stock/service/StockInRecordService.java                        |    2 
 src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java               |   88 +
 src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java                         |  431 +++++---
 src/main/java/com/ruoyi/device/controller/DeviceLedgerController.java                  |   29 
 src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java                |    5 
 src/main/resources/mapper/sales/SalesLedgerProductMapper.xml                           |   41 
 src/main/java/com/ruoyi/purchase/service/impl/PurchaseReportServiceImpl.java           |   32 
 src/main/java/com/ruoyi/project/system/controller/SysUserController.java               |    5 
 src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java                            |    4 
 doc/20260522_财务助手提问优化前端变更文档.md                                                         |   59 +
 src/main/java/com/ruoyi/account/service/AccountingService.java                         |   19 
 src/main/java/com/ruoyi/approve/bean/vo/ApproveGetAndUpdateVo.java                     |    9 
 doc/20260522_StockInRecord列表源单号前端联调文档.md                                               |   75 +
 src/main/java/com/ruoyi/account/bean/vo/AccountReportVo.java                           |   66 +
 src/main/resources/mapper/stock/StockInRecordMapper.xml                                |   87 +
 src/main/java/com/ruoyi/quality/pojo/QualityInspect.java                               |    5 
 src/main/resources/mapper/account/sales/AccountInvoiceApplicationMapper.xml            |    2 
 src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java               |  128 --
 src/main/resources/mapper/production/ProductionOperationTaskMapper.xml                 |    2 
 src/main/java/com/ruoyi/device/dto/DeviceLedgerDto.java                                |   17 
 src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java                |  189 +++
 src/main/java/com/ruoyi/approve/bean/vo/ApproveProcessVO.java                          |    9 
 doc/20260522_采购台账入库状态_销售产品入库审核状态前端联调文档.md                                              |  127 ++
 src/main/resources/mapper/sales/SalesLedgerMapper.xml                                  |   16 
 src/main/java/com/ruoyi/device/service/IDeviceLedgerService.java                       |    6 
 src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java                             |    4 
 src/main/resources/mapper/sales/SalesQuotationMapper.xml                               |    2 
 src/main/resources/mapper/account/purchase/AccountPaymentApplicationMapper.xml         |    2 
 src/main/java/com/ruoyi/stock/controller/StockInRecordController.java                  |   11 
 src/main/java/com/ruoyi/account/controller/AccountingController.java                   |   24 
 src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java            |   26 
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java                 |   52 
 src/main/resources/financial-agent-prompt.txt                                          |    2 
 src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java                   |   28 
 src/main/java/com/ruoyi/ai/assistant/FinancialIntentExecutor.java                      |   22 
 src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java            |  129 +-
 doc/20260522_首页财务接口升级前端变更文档.md                                                         |  120 ++
 src/main/java/com/ruoyi/approve/pojo/ApproveProcess.java                               |   10 
 src/main/java/com/ruoyi/purchase/dto/VatDto.java                                       |   17 
 src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java  |    2 
 src/main/java/com/ruoyi/account/bean/dto/AccountReportDto.java                         |   19 
 src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java                            |    2 
 src/main/resources/mapper/stock/StockInventoryMapper.xml                               |    7 
 doc/20260522_StockInRecord列表源单号前端联调文档_276补充.md                                         |   65 +
 src/main/java/com/ruoyi/purchase/vo/PurchaseReportVo.java                              |   44 
 src/main/resources/mapper/approve/ApproveProcessMapper.xml                             |    4 
 src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java                                |    3 
 src/main/resources/mapper/quality/QualityInspectMapper.xml                             |   43 
 /dev/null                                                                              |   39 
 src/main/java/com/ruoyi/device/service/impl/DeviceLedgerServiceImpl.java               |   55 +
 src/main/java/com/ruoyi/quality/controller/QualityInspectController.java               |    3 
 src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java |  156 +++
 src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java            |   16 
 doc/20260523_ 协同审批新增出差时间和结束时间.sql                                                      |    3 
 src/main/java/com/ruoyi/approve/service/impl/ApproveBusinessStatusService.java         |  175 +++
 64 files changed, 2,185 insertions(+), 661 deletions(-)

diff --git "a/doc/20260522_StockInRecord\345\210\227\350\241\250\346\272\220\345\215\225\345\217\267\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md" "b/doc/20260522_StockInRecord\345\210\227\350\241\250\346\272\220\345\215\225\345\217\267\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..56d1570
--- /dev/null
+++ "b/doc/20260522_StockInRecord\345\210\227\350\241\250\346\272\220\345\215\225\345\217\267\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
@@ -0,0 +1,75 @@
+# StockInRecord 鍒楄〃婧愬崟鍙峰墠绔仈璋冩枃妗�
+
+鏇存柊鏃堕棿锛�2026-05-22  
+閫傜敤鎺ュ彛锛歚GET /stockInRecord/listPage`
+
+## 1. 鍙樻洿璇存槑
+
+鏈瀵瑰叆搴撶鐞嗗垪琛ㄦ帴鍙e鍔犺繑鍥炲瓧娈� `sourceOrderNo`锛堟簮鍗曞彿锛夛紝鐢ㄤ簬鍘熸潗鏂欏満鏅睍绀洪噰璐潵婧愬崟鍙枫��
+
+鐢熸晥鏉′欢锛�
+
+- 褰撹姹傚弬鏁� `topParentProductId = 278` 鏃讹紝鍚庣杩斿洖 `sourceOrderNo`銆�
+- 鍏朵粬 `topParentProductId` 鍦烘櫙涓嬶紝璇ュ瓧娈佃繑鍥� `null`锛堟垨涓嶅睍绀猴級銆�
+
+## 2. 瀛楁瀹氫箟
+
+鏂板瀛楁锛�
+
+- `sourceOrderNo`锛歚string`锛屾簮鍗曞彿锛堥噰璐悎鍚屽彿锛夈��
+
+## 3. 鍙栧�艰鍒�
+
+浠呭湪 `topParentProductId = 278` 鏃舵寜鈥滄潵婧愨�濊绠楋細
+
+1. 鏉ユ簮 = `閲囪喘-鍏ュ簱`锛坄recordType = 7`锛�  
+   - 鍏堟寜 `recordId` 鏌ラ噰璐骇鍝佽〃 `sales_ledger_product`锛坄type=2`锛夛紱
+   - 鍐嶉�氳繃 `sales_ledger_product.sales_ledger_id` 鏌ラ噰璐彴璐﹁〃 `purchase_ledger`锛�
+   - 杩斿洖 `purchase_ledger.purchase_contract_number` 浣滀负 `sourceOrderNo`銆�
+   - 鍏煎鍏滃簳锛氳嫢鏈懡涓噰璐骇鍝侀摼璺紝鍒欐寜 `recordId` 鐩存帴鏌� `purchase_ledger.id` 鍙栧崟鍙枫��
+
+2. 鏉ユ簮 = `閲囪喘-璐ㄦ-鍚堟牸鍏ュ簱`锛坄recordType = 10`锛�  
+   - 鍏堟寜 `recordId` 鏌ヨ川妫�琛� `quality_inspect`锛�
+   - 鍐嶉�氳繃 `quality_inspect.purchase_ledger_id` 鏌ラ噰璐彴璐﹁〃 `purchase_ledger`锛�
+   - 杩斿洖 `purchase_ledger.purchase_contract_number` 浣滀负 `sourceOrderNo`銆�
+
+## 4. 杩斿洖绀轰緥
+
+```json
+{
+  "code": 200,
+  "msg": "鎿嶄綔鎴愬姛",
+  "data": {
+    "records": [
+      {
+        "id": 1024,
+        "recordType": "7",
+        "productName": "閾滄帓",
+        "model": "T2-30x3",
+        "sourceOrderNo": "CG-2026-00128"
+      },
+      {
+        "id": 1025,
+        "recordType": "10",
+        "productName": "閾滄帓",
+        "model": "T2-30x3",
+        "sourceOrderNo": "CG-2026-00131"
+      }
+    ],
+    "total": 2
+  }
+}
+```
+
+## 5. 鍓嶇鑱旇皟寤鸿
+
+1. 鍒楄〃鍒楁柊澧炩�滄簮鍗曞彿鈥濓紝璇诲彇瀛楁 `sourceOrderNo`銆�
+2. 寤鸿浠呭湪 `topParentProductId = 278` 鐨勯〉闈�/绛涢�夋潯浠朵笅灞曠ず璇ュ垪銆�
+3. 褰� `sourceOrderNo` 涓虹┖鏃跺睍绀� `--`锛岄伩鍏嶇┖鐧姐��
+
+## 6. 鍥炲綊娓呭崟
+
+1. `topParentProductId=278` + `recordType=7`锛氬簲杩斿洖閲囪喘鍚堝悓鍙枫��
+2. `topParentProductId=278` + `recordType=10`锛氬簲杩斿洖閲囪喘鍚堝悓鍙凤紙缁忚川妫�閾捐矾锛夈��
+3. `topParentProductId!=278`锛歚sourceOrderNo` 搴斾负 `null` 鎴栧墠绔笉灞曠ず銆�
+4. 鍘熸湁瀛楁锛坄productName/model/unit/createBy` 绛夛級涓嶅彈褰卞搷銆�
diff --git "a/doc/20260522_StockInRecord\345\210\227\350\241\250\346\272\220\345\215\225\345\217\267\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243_276\350\241\245\345\205\205.md" "b/doc/20260522_StockInRecord\345\210\227\350\241\250\346\272\220\345\215\225\345\217\267\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243_276\350\241\245\345\205\205.md"
new file mode 100644
index 0000000..93d9b25
--- /dev/null
+++ "b/doc/20260522_StockInRecord\345\210\227\350\241\250\346\272\220\345\215\225\345\217\267\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243_276\350\241\245\345\205\205.md"
@@ -0,0 +1,65 @@
+# StockInRecord 鍒楄〃婧愬崟鍙峰墠绔仈璋冩枃妗o紙`topParentProductId=276`琛ュ厖锛�
+
+鏇存柊鏃堕棿锛�2026-05-22  
+閫傜敤鎺ュ彛锛歚GET /stockInRecord/listPage`
+
+## 1. 鍙樻洿璇存槑
+
+鍦ㄥ凡鏈� `sourceOrderNo` 鍩虹涓婏紝鏂板 `topParentProductId = 276` 鐨勬簮鍗曞彿婧簮閫昏緫锛�
+
+- 鏍规嵁鈥滄潵婧愶紙recordType锛�+ recordId鈥濇函婧愶紱
+- 浼樺厛杩斿洖閿�鍞崟鍙凤紙閿�鍞悎鍚屽彿锛夛紱
+- 鑻ラ攢鍞崟鍙蜂负绌猴紝鍒欏洖閫�杩斿洖鐢熶骇璁㈠崟鍙凤紱
+- 涓嶈�冭檻鑷畾涔夊叆搴擄紙`recordType=0/9`锛夈��
+
+## 2. 杩斿洖瀛楁
+
+瀛楁鏃犳柊澧烇紝缁х画浣跨敤锛�
+
+- `sourceOrderNo`锛歚string`锛屾簮鍗曞彿銆�
+
+## 3. 276 鍦烘櫙鍙栧�艰鍒�
+
+璇锋眰鍙傛暟婊¤冻 `topParentProductId = 276` 鏃讹細
+
+1. `recordType = 14/15`锛堥攢鍞��璐�-鍚堟牸/涓嶅悎鏍煎叆搴擄級  
+   - `stock_in_record.record_id -> return_sale_product.id -> return_management.shipping_id -> shipping_info.sales_ledger_id -> sales_ledger.sales_contract_no`
+   - 杩斿洖閿�鍞悎鍚屽彿銆�
+
+2. `recordType = 2/5`锛堢敓浜ф姤宸�-鍏ュ簱/鎶ュ簾锛�  
+   - `stock_in_record.record_id -> production_product_main.id -> production_operation_task.production_order_id -> production_order`
+   - 鍏堝彇璇ョ敓浜ц鍗曞叧鑱旈攢鍞悎鍚屽彿锛堢敱鐢熶骇璁″垝鍏宠仈閿�鍞彴璐﹁仛鍚堬級锛�
+   - 閿�鍞悎鍚屽彿涓虹┖鏃讹紝杩斿洖 `production_order.nps_no`銆�
+
+3. `recordType = 6`锛堣川妫�-鍚堟牸鍏ュ簱锛�  
+   - `stock_in_record.record_id -> quality_inspect.id -> quality_inspect.product_main_id -> production_product_main -> production_operation_task -> production_order`
+   - 鍏堝彇閿�鍞悎鍚屽彿锛岀┖鍒欏洖閫� `production_order.nps_no`銆�
+
+4. `recordType = 4/11`锛堜笉鍚堟牸澶勭悊-鎶ュ簾/璁╂鏀捐锛�  
+   - `stock_in_record.record_id -> quality_unqualified.id -> quality_unqualified.inspect_id -> quality_inspect -> production_product_main -> production_operation_task -> production_order`
+   - 鍏堝彇閿�鍞悎鍚屽彿锛岀┖鍒欏洖閫� `production_order.nps_no`銆�
+
+5. `recordType = 20/22`锛堥鏂欓��鏂�/鐢熶骇閫�鏂�-鍚堟牸鍏ュ簱锛�  
+   - `stock_in_record.record_id -> production_order_pick.id -> production_order`
+   - 鍏堝彇閿�鍞悎鍚屽彿锛岀┖鍒欏洖閫� `production_order.nps_no`銆�
+
+6. `recordType = 0/9`锛堣嚜瀹氫箟鍏ュ簱锛�  
+   - 涓嶅弬涓庢函婧愶紝`sourceOrderNo = null`銆�
+
+## 4. 鍏朵粬鍦烘櫙璇存槑
+
+- `topParentProductId = 278` 鐨勯噰璐摼璺簮鍗曞彿閫昏緫淇濇寔涓嶅彉銆�
+- 鍏朵粬 `topParentProductId` 涓嶈Е鍙戞湰娆� 276 瑙勫垯锛宍sourceOrderNo` 涓虹┖銆�
+
+## 5. 鍓嶇鑱旇皟寤鸿
+
+1. 鍦� `topParentProductId=276` 鐨勫垪琛ㄥ満鏅睍绀衡�滄簮鍗曞彿鈥濆垪锛岃鍙� `sourceOrderNo`銆�
+2. 寤鸿绌哄�肩粺涓�灞曠ず `--`銆�
+3. 涓嶉渶瑕佹柊澧炶姹傚弬鏁帮紝娌跨敤鐜版湁 `/stockInRecord/listPage`銆�
+
+## 6. 鍥炲綊娓呭崟
+
+1. `topParentProductId=276` + `recordType=14/15`锛氬簲杩斿洖閿�鍞悎鍚屽彿銆�  
+2. `topParentProductId=276` + `recordType=2/5/6/4/11/20/22`锛氫紭鍏堥攢鍞悎鍚屽彿锛岀己澶辨椂杩斿洖鐢熶骇璁㈠崟鍙枫��  
+3. `topParentProductId=276` + `recordType=0/9`锛歚sourceOrderNo` 涓虹┖銆�  
+4. `topParentProductId=278`锛氫粛鎸夐噰璐摼璺繑鍥為噰璐悎鍚屽彿銆�  
diff --git "a/doc/20260522_\350\264\242\345\212\241\345\212\251\346\211\213\346\217\220\351\227\256\344\274\230\345\214\226\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md" "b/doc/20260522_\350\264\242\345\212\241\345\212\251\346\211\213\346\217\220\351\227\256\344\274\230\345\214\226\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..ad4656e
--- /dev/null
+++ "b/doc/20260522_\350\264\242\345\212\241\345\212\251\346\211\213\346\217\220\351\227\256\344\274\230\345\214\226\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md"
@@ -0,0 +1,59 @@
+# 璐㈠姟鍔╂墜鎻愰棶浼樺寲鍓嶇鍙樻洿鏂囨。
+
+鏇存柊鏃堕棿锛�2026-05-22  
+閫傜敤妯″潡锛氳储鍔℃櫤鑳藉姪鎵嬶紙`/financial-ai`锛�
+
+## 1. 鑳屾櫙
+
+褰撳墠棣栭〉璐㈠姟鍔╂墜蹇嵎鎻愰棶涓猴細
+
+1. `鐢熸垚鏈懆缁忚惀鍛ㄦ姤`
+2. `涓轰粈涔堝埄娑︿笅闄峘
+3. `鍝釜瀹㈡埛鏈�璧氶挶`
+
+闂鐐癸細
+
+- 绗� 3 鏉¢棶娉曞湪閮ㄥ垎鍦烘櫙涓嬫剰鍥惧懡涓笉绋冲畾锛屽鏄撹蛋鏅�氭枃鏈洖绛旓紝瀵艰嚧鍥捐〃閾炬帴浠ュ師濮� Markdown 鏂囨湰灞曠ず锛堝 `![...](https://local/generate_chart?options=...)`锛夈��
+- 蹇嵎鎻愰棶缂哄皯鏃堕棿鑼冨洿鍜屽垎鏋愮洰鏍囷紝缁撴灉绋冲畾鎬т笌鍙В閲婃�ц緝寮便��
+
+## 2. 鍓嶇蹇嵎鎻愰棶鏂囨浼樺寲锛堝繀鏀癸級
+
+寤鸿灏嗛粯璁や笁鏉″揩鎹锋彁闂皟鏁翠负锛�
+
+1. `鐢熸垚鏈懆缁忚惀鍛ㄦ姤锛堝埄娑︿笌鐜伴噾娴侊級`
+2. `鍒嗘瀽鏈湀鍒╂鼎涓嬮檷鍘熷洜`
+3. `杩�30澶╁摢涓鎴峰埄娑﹁础鐚渶楂榒
+
+璇存槑锛�
+
+- 涓夋潯闂硶鍧囧甫鏃堕棿鑼冨洿鎴栧垎鏋愮洰鏍囷紝鍚庣鍛戒腑鏇寸ǔ瀹氥��
+- 绗� 3 鏉′笌鈥滄渶璧氶挶瀹㈡埛鈥濊涔変竴鑷达紝浣嗏�滃埄娑﹁础鐚渶楂樷�濇洿鏄庣‘锛岄�傚悎鐩存帴椹卞姩鍒╂鼎鍒嗘瀽缁撴灉椤点��
+
+## 3. 涓庡悗绔兘鍔涙槧灏�
+
+| 蹇嵎鎻愰棶 | 棰勬湡鍛戒腑鑳藉姏 | 棰勬湡 `type` |
+| --- | --- | --- |
+| 鐢熸垚鏈懆缁忚惀鍛ㄦ姤锛堝埄娑︿笌鐜伴噾娴侊級 | 缁忚惀鎶ュ憡鐢熸垚 | `financial_operation_report` |
+| 鍒嗘瀽鏈湀鍒╂鼎涓嬮檷鍘熷洜 | 璁㈠崟鍒╂鼎鍒嗘瀽 | `financial_order_profit_analysis` |
+| 杩�30澶╁摢涓鎴峰埄娑﹁础鐚渶楂� | 璁㈠崟鍒╂鼎鍒嗘瀽 | `financial_order_profit_analysis` |
+
+鍚庣宸插悓姝ュ寮衡�滄渶璧氶挶瀹㈡埛/瀹㈡埛鍒╂鼎鏈�楂�/鍒╂鼎璐$尞鏈�楂樷�濈瓑鍚屼箟闂硶璇嗗埆锛屽墠绔寜浠ヤ笂鏂囨鏀归�犲悗鍙洿鎺ヨ仈璋冦��
+
+## 4. 鑱婂ぉ鍐呭娓叉煋鍏滃簳锛堝缓璁敼锛�
+
+閽堝鑱婂ぉ杩斿洖鏂囨湰涓嚭鐜扮殑鍥捐〃 Markdown 閾炬帴锛坄https://local/generate_chart?options=...`锛夛紝寤鸿鍓嶇澧炲姞鍏滃簳澶勭悊锛�
+
+1. 璇嗗埆 Markdown 鍥剧墖璇硶涓殑 `local/generate_chart` 閾炬帴銆�
+2. 瑙f瀽 `options` 鍙傛暟骞惰浆鎹负 ECharts `option` 鍚庢覆鏌撳浘琛ㄧ粍浠躲��
+3. 瑙f瀽澶辫触鏃朵笉灞曠ず鍘熷闀块摼鎺ユ枃鏈紝灞曠ず缁熶竴绌烘�佹彁绀恒��
+
+## 5. 鑱旇皟鍥炲綊娓呭崟
+
+1. 鐐瑰嚮蹇嵎鎻愰棶 `鐢熸垚鏈懆缁忚惀鍛ㄦ姤锛堝埄娑︿笌鐜伴噾娴侊級`  
+   - 鏍¢獙杩斿洖 `type=financial_operation_report`锛屽苟姝e父娓叉煋鎽樿/寤鸿/鍥捐〃銆�
+2. 鐐瑰嚮蹇嵎鎻愰棶 `鍒嗘瀽鏈湀鍒╂鼎涓嬮檷鍘熷洜`  
+   - 鏍¢獙杩斿洖 `type=financial_order_profit_analysis`锛屽苟灞曠ず浜忔崯璁㈠崟涓庡鎴峰埄娑︽帓琛屻��
+3. 鐐瑰嚮蹇嵎鎻愰棶 `杩�30澶╁摢涓鎴峰埄娑﹁础鐚渶楂榒  
+   - 鏍¢獙杩斿洖 `type=financial_order_profit_analysis`锛宍summary.topCustomerByProfit` 鏈夊�笺��
+4. 鎵嬪伐杈撳叆 `鍝釜瀹㈡埛鏈�璧氶挶`銆乣鍝釜瀹㈡埛鍒╂鼎鏈�楂榒  
+   - 鏍¢獙浠嶅懡涓� `financial_order_profit_analysis`锛屼笉鍐嶅嚭鐜板師濮嬪浘琛� Markdown 閾炬帴鐩村嚭銆�
diff --git "a/doc/20260522_\351\207\207\350\264\255\345\217\260\350\264\246\345\205\245\345\272\223\347\212\266\346\200\201_\351\224\200\345\224\256\344\272\247\345\223\201\345\205\245\345\272\223\345\256\241\346\240\270\347\212\266\346\200\201\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md" "b/doc/20260522_\351\207\207\350\264\255\345\217\260\350\264\246\345\205\245\345\272\223\347\212\266\346\200\201_\351\224\200\345\224\256\344\272\247\345\223\201\345\205\245\345\272\223\345\256\241\346\240\270\347\212\266\346\200\201\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..ae212fc
--- /dev/null
+++ "b/doc/20260522_\351\207\207\350\264\255\345\217\260\350\264\246\345\205\245\345\272\223\347\212\266\346\200\201_\351\224\200\345\224\256\344\272\247\345\223\201\345\205\245\345\272\223\345\256\241\346\240\270\347\212\266\346\200\201\345\211\215\347\253\257\350\201\224\350\260\203\346\226\207\346\241\243.md"
@@ -0,0 +1,127 @@
+# 閲囪喘鍏ュ簱鐘舵�佸墠绔仈璋冩枃妗�
+鏇存柊鏃堕棿锛�2026-05-22  
+閫傜敤鐗堟湰锛氭湰娆″悗绔彉鏇村悗
+
+## 1. 鍙樻洿鑼冨洿
+
+1. `GET /purchaseLedger/listPage`  
+   - 鏂板鏌ヨ鏉′欢锛歚stockInStatus`锛堝叆搴撶姸鎬侊級
+   - 鏂板杩斿洖瀛楁锛歚stockInStatus`锛堝叆搴撶姸鎬侊級
+2. `GET /salesLedgerProduct/list`  
+   - 鏂板杩斿洖瀛楁锛歚stockInApprovalStatus`锛堟瘡涓骇鍝佺殑鍏ュ簱瀹℃牳鐘舵�侊級
+
+---
+
+## 2. 鍏ュ簱鐘舵�佹灇涓撅紙涓ゆ帴鍙d竴鑷达級
+
+- `寰呭叆搴揱
+- `鍏ュ簱涓璥
+- `瀹屽叏鍏ュ簱`
+
+璇存槑锛氬墠绔瓫閫夊�艰鐩存帴浣跨敤浠ヤ笂涓枃鏋氫妇鍊笺��
+
+---
+
+## 3. 鎺ュ彛涓�锛歚GET /purchaseLedger/listPage`
+
+### 3.1 鏂板璇锋眰鍙傛暟
+
+- `stockInStatus`锛歚string`锛屽彲閫�  
+  鍙紶鍊硷細`寰呭叆搴揱 / `鍏ュ簱涓璥 / `瀹屽叏鍏ュ簱`
+
+### 3.2 鏂板杩斿洖瀛楁
+
+- `stockInStatus`锛歚string`锛岄噰璐彴璐︾淮搴﹀叆搴撶姸鎬�
+
+### 3.3 鐘舵�佽绠楄鍒欙紙閲囪喘鍙拌处缁村害锛�
+
+浠ヨ閲囪喘鍙拌处涓� `sales_ledger_product.type = 2` 鐨勯噰璐骇鍝佷负璁$畻鑼冨洿锛�
+
+1. 鍏ㄩ儴浜у搧閮借揪鍒扳�滃畬鍏ㄥ叆搴撯�� => 鍙拌处鐘舵�� `瀹屽叏鍏ュ簱`
+2. 鑷冲皯鏈変竴涓骇鍝佸瓨鍦ㄢ�滃鏍搁�氳繃鍏ュ簱鈥濓紝浣嗘湭鍏ㄩ儴瀹屽叏鍏ュ簱 => 鍙拌处鐘舵�� `鍏ュ簱涓璥
+3. 娌℃湁浠讳綍浜у搧瀛樺湪鈥滃鏍搁�氳繃鍏ュ簱鈥� => 鍙拌处鐘舵�� `寰呭叆搴揱
+
+鈥滃鏍搁�氳繃鍏ュ簱鈥濈粺璁″彛寰勶細`stock_in_record.approval_status = 1`锛屽苟鎸変互涓嬫潵婧愭函婧愶細
+- `record_type = 7`锛堥噰璐�-鍏ュ簱锛夛細鎸夐噰璐彴璐�+浜у搧鍏宠仈缁熻
+- `record_type = 10`锛堥噰璐�-璐ㄦ-鍚堟牸鍏ュ簱锛夛細閫氳繃 `quality_inspect` 鍥炴函鍒伴噰璐彴璐�+浜у搧缁熻
+
+### 3.4 杩斿洖绀轰緥锛堣妭閫夛級
+
+```json
+{
+  "code": 200,
+  "msg": "鎿嶄綔鎴愬姛",
+  "data": {
+    "records": [
+      {
+        "id": 1201,
+        "purchaseContractNumber": "CG20260522001",
+        "supplierName": "XX渚涘簲鍟�",
+        "stockInStatus": "鍏ュ簱涓�"
+      }
+    ],
+    "total": 1
+  }
+}
+```
+
+---
+
+## 4. 鎺ュ彛浜岋細`GET /salesLedgerProduct/list`
+
+### 4.1 鏂板杩斿洖瀛楁
+
+- `stockInApprovalStatus`锛歚string`锛屽綋鍓嶄骇鍝佽鐨勫叆搴撳鏍哥姸鎬�
+
+### 4.2 鐘舵�佽绠楄鍒欙紙浜у搧缁村害锛�
+
+浠呭綋浜у搧 `type = 2`锛堥噰璐骇鍝侊級鏃惰绠楀苟杩斿洖锛�
+
+1. 瀹℃牳閫氳繃鍏ュ簱鏁伴噺 `<= 0` => `寰呭叆搴揱
+2. 瀹℃牳閫氳繃鍏ュ簱鏁伴噺 `>= 浜у搧閲囪喘鏁伴噺` => `瀹屽叏鍏ュ簱`
+3. 鍏朵粬鎯呭喌 => `鍏ュ簱涓璥
+
+鍏朵腑鈥滃鏍搁�氳繃鍏ュ簱鏁伴噺鈥濈粺璁″悓鏍峰熀浜庯細
+- `stock_in_record.approval_status = 1`
+- 鏉ユ簮 `record_type = 7 / 10` 鐨勬函婧愬叧鑱旈�昏緫
+
+`type != 2` 鐨勪骇鍝侊紝璇ュ瓧娈佃繑鍥� `null`銆�
+
+### 4.3 杩斿洖绀轰緥锛堣妭閫夛級
+
+```json
+{
+  "code": 200,
+  "msg": "鎿嶄綔鎴愬姛",
+  "data": [
+    {
+      "id": 5566,
+      "type": 2,
+      "productCategory": "閾滄潗",
+      "specificationModel": "T2-30x3",
+      "quantity": 100,
+      "stockInApprovalStatus": "寰呭叆搴�"
+    }
+  ]
+}
+```
+
+---
+
+## 5. 鍓嶇鏀归�犲缓璁�
+
+1. 閲囪喘鍙拌处鍒楄〃鏂板鈥滃叆搴撶姸鎬佲�濈瓫閫夐」锛屽�煎浐瀹氾細`寰呭叆搴�/鍏ュ簱涓�/瀹屽叏鍏ュ簱`銆�
+2. 閲囪喘鍙拌处鍒楄〃鏂板鈥滃叆搴撶姸鎬佲�濆垪锛屽睍绀� `stockInStatus`銆�
+3. 閲囪喘浜у搧鍒楄〃鏂板鈥滃叆搴撳鏍哥姸鎬佲�濆垪锛屽睍绀� `stockInApprovalStatus`銆�
+4. 绌哄�硷紙濡� `type != 2`锛夊缓璁睍绀轰负 `--`銆�
+
+---
+
+## 6. 鑱旇皟妫�鏌ユ竻鍗�
+
+1. `/purchaseLedger/listPage` 涓嶄紶 `stockInStatus`锛氬簲姝e父杩斿洖鍏ㄩ儴鏁版嵁锛屽苟甯� `stockInStatus`銆�
+2. `/purchaseLedger/listPage?stockInStatus=寰呭叆搴揱锛氫粎杩斿洖寰呭叆搴撳彴璐︺��
+3. `/purchaseLedger/listPage?stockInStatus=鍏ュ簱涓璥锛氫粎杩斿洖鍏ュ簱涓彴璐︺��
+4. `/purchaseLedger/listPage?stockInStatus=瀹屽叏鍏ュ簱`锛氫粎杩斿洖瀹屽叏鍏ュ簱鍙拌处銆�
+5. `/salesLedgerProduct/list` 鍦ㄩ噰璐骇鍝侊紙`type=2`锛変笅杩斿洖 `stockInApprovalStatus`銆�
+6. `/salesLedgerProduct/list` 鍦ㄩ潪閲囪喘浜у搧锛坄type!=2`锛変笅 `stockInApprovalStatus` 涓� `null`銆�
diff --git "a/doc/20260522_\351\246\226\351\241\265\350\264\242\345\212\241\346\216\245\345\217\243\345\215\207\347\272\247\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md" "b/doc/20260522_\351\246\226\351\241\265\350\264\242\345\212\241\346\216\245\345\217\243\345\215\207\347\272\247\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..532eba7
--- /dev/null
+++ "b/doc/20260522_\351\246\226\351\241\265\350\264\242\345\212\241\346\216\245\345\217\243\345\215\207\347\272\247\345\211\215\347\253\257\345\217\230\346\233\264\346\226\207\346\241\243.md"
@@ -0,0 +1,120 @@
+# 棣栭〉璐㈠姟鎺ュ彛鍗囩骇鍓嶇鍙樻洿鏂囨。
+
+鏇存柊鏃堕棿锛�2026-05-22  
+閫傜敤妯″潡锛氶椤碉紙`/home`锛�
+
+## 1. 鍙樻洿姒傝
+
+鏈涓� **鍏煎寮忓崌绾�**锛屾帴鍙� URL銆佽姹傚弬鏁般�佽繑鍥炲瓧娈典繚鎸佷笉鍙樸��  
+涓昏鍙樻洿鏄椤佃储鍔℃暟鎹粠鍗犱綅/鍗婃垚鍝侀�昏緫锛屽垏鎹负鎸夎储鍔$湡瀹炴暟鎹彛寰勮绠椼��
+
+娑夊強鎺ュ彛锛�
+
+1. `GET /home/statisticsReceivablePayable`
+2. `GET /home/monthlyIncome`
+3. `GET /home/monthlyExpenditure`
+
+## 2. 鍙傛暟璇存槑锛堟棤鏂板锛�
+
+### 2.1 `GET /home/statisticsReceivablePayable`
+
+- `type`锛歚1` 鏈懆锛宍2` 鏈湀锛宍3` 鏈搴︼紙榛樿 `1`锛�
+
+### 2.2 `GET /home/monthlyIncome`
+
+- 鏃犲弬鏁�
+
+### 2.3 `GET /home/monthlyExpenditure`
+
+- 鏃犲弬鏁�
+
+## 3. 杩斿洖瀛楁鍙e緞鍙樻洿
+
+### 3.1 搴旀敹搴斾粯缁熻 `statisticsReceivablePayable`
+
+杩斿洖瀛楁涓嶅彉锛�
+
+- `receivableMoney`
+- `payableMoney`
+- `advanceMoney`
+- `prepayMoney`
+
+鏂板彛寰勶細
+
+- `receivableMoney = max(閿�鍞悎鍚岄噾棰濆悎璁� - 鏀舵閲戦鍚堣, 0)`
+- `payableMoney = max(閲囪喘鍚堝悓閲戦鍚堣 - 浠樻閲戦鍚堣, 0)`
+- `advanceMoney = 鏀舵閲戦鍚堣`
+- `prepayMoney = 浠樻閲戦鍚堣`
+
+浠ヤ笂閲戦鍧囨寜 `type` 瀵瑰簲鏃堕棿鑼冨洿缁熻锛屼繚鐣欎袱浣嶅皬鏁般��
+
+杩斿洖绀轰緥锛�
+
+```json
+{
+  "receivableMoney": 128000.00,
+  "payableMoney": 76000.00,
+  "advanceMoney": 42000.00,
+  "prepayMoney": 31000.00
+}
+```
+
+### 3.2 鏈堝害鏀跺叆 `monthlyIncome`
+
+杩斿洖瀛楁涓嶅彉锛�
+
+- `monthlyIncome`
+- `collectionRate`
+- `overdueNum`
+- `overdueRate`
+
+鏂板彛寰勶細
+
+- `monthlyIncome`锛氬綋鏈堟敹娆惧悎璁�
+- `collectionRate`锛歚褰撴湀鏀舵鍚堣 / 褰撴湀閿�鍞悎鍚岄噾棰濆悎璁� * 100`
+- `overdueNum`锛氬巻鍙插簲鏀跺璐﹀崟锛坄account_statement.account_type=1`锛変腑锛屾棭浜庡綋鏈堜笖 `closing_balance > 0` 鐨勬暟閲�
+- `overdueRate`锛歚overdueNum / 鍘嗗彶搴旀敹瀵硅处鍗曟�绘暟 * 100`
+
+杩斿洖绀轰緥锛�
+
+```json
+{
+  "monthlyIncome": 89500.00,
+  "collectionRate": "62.80",
+  "overdueNum": 4,
+  "overdueRate": "18.18"
+}
+```
+
+### 3.3 鏈堝害鏀嚭 `monthlyExpenditure`
+
+杩斿洖瀛楁涓嶅彉锛�
+
+- `monthlyExpenditure`
+- `paymentRate`
+- `grossProfit`
+- `profitMarginRate`
+
+鏂板彛寰勶細
+
+- `monthlyExpenditure`锛氬綋鏈堜粯娆惧悎璁�
+- `paymentRate`锛歚褰撴湀浠樻鍚堣 / 褰撴湀閲囪喘鍚堝悓閲戦鍚堣 * 100`
+- `grossProfit`锛歚褰撴湀鏀舵鍚堣 - 褰撴湀浠樻鍚堣`
+- `profitMarginRate`锛歚grossProfit / 褰撴湀鏀舵鍚堣 * 100`
+
+杩斿洖绀轰緥锛�
+
+```json
+{
+  "monthlyExpenditure": 73400.00,
+  "paymentRate": "57.34",
+  "grossProfit": 16100.00,
+  "profitMarginRate": "17.99"
+}
+```
+
+## 4. 鍓嶇鑱旇皟璇存槑
+
+1. 鍓嶇瀛楁鏄犲皠鏃犻渶璋冩暣锛屽彲鐩存帴娌跨敤鐜版湁瑙f瀽閫昏緫銆�  
+2. 鐧惧垎姣斿瓧娈典粛涓轰笉甯� `%` 鐨勫瓧绗︿覆锛屽墠绔闇�灞曠ず `%` 璇风户缁墠绔嫾鎺ャ��  
+3. 鏈鍚庣杩斿洖鍊肩敱鐪熷疄璐㈠姟鏁版嵁椹卞姩锛屽缓璁噸鐐瑰洖褰掑崱鐗囨眹鎬讳笌瓒嬪娍鍥剧殑鏁板�艰仈鍔ㄣ��  
diff --git "a/doc/20260523_ \345\215\217\345\220\214\345\256\241\346\211\271\346\226\260\345\242\236\345\207\272\345\267\256\346\227\266\351\227\264\345\222\214\347\273\223\346\235\237\346\227\266\351\227\264.sql" "b/doc/20260523_ \345\215\217\345\220\214\345\256\241\346\211\271\346\226\260\345\242\236\345\207\272\345\267\256\346\227\266\351\227\264\345\222\214\347\273\223\346\235\237\346\227\266\351\227\264.sql"
new file mode 100644
index 0000000..0e0c5ce
--- /dev/null
+++ "b/doc/20260523_ \345\215\217\345\220\214\345\256\241\346\211\271\346\226\260\345\242\236\345\207\272\345\267\256\346\227\266\351\227\264\345\222\214\347\273\223\346\235\237\346\227\266\351\227\264.sql"
@@ -0,0 +1,3 @@
+ALTER TABLE approve_process
+    ADD COLUMN start_date_time datetime DEFAULT NULL COMMENT '鍑哄樊寮�濮嬫椂闂�',
+    ADD COLUMN end_date_time   datetime DEFAULT NULL COMMENT '鍑哄樊缁撴潫鏃堕棿';
diff --git a/src/main/java/com/ruoyi/account/bean/dto/AccountDto.java b/src/main/java/com/ruoyi/account/bean/dto/AccountDto.java
deleted file mode 100644
index 5af0ca6..0000000
--- a/src/main/java/com/ruoyi/account/bean/dto/AccountDto.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.ruoyi.account.bean.dto;
-
-import lombok.Data;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.util.List;
-
-/**
- * 璐㈠姟绠$悊--璐㈠姟鎶ヨ〃
- */
-
-@Data
-public class AccountDto implements Serializable {
-
-
-    /**
-     * 鎬绘敹鍏�
-     */
-    private BigDecimal totalIncome;
-
-    /**
-     * 鍚勭被鍨嬫敹鍏ラ噾棰�(閿�鍞敹鍏ワ紝鏈嶅姟鏀跺叆锛屽叾浠栨敹鍏�)
-     */
-    private List<AccountDto2> incomeType;
-
-
-    /**
-     * 鏀跺叆绗旀暟
-     */
-    private Long incomeNumber;
-
-    /**
-     * 鎬绘敮鍑�
-     */
-    private BigDecimal totalExpense;
-
-
-    /**
-     * 鍚勭被鍨嬫敮鍑洪噾棰�(鍔炲叕鐢ㄥ搧锛屽憳宸ュ伐璧勶紝宸梾璐癸紝璁惧璐圭敤锛屽叾浠�)
-     */
-    private List<AccountDto2> expenseType;
-
-    /**
-     * 鏀嚭绗旀暟
-     */
-    private Long expenseNumber;
-
-    /**
-     * 鍑�鏀跺叆
-     */
-    private BigDecimal netRevenue;
-
-
-
-
-}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/AccountDto2.java b/src/main/java/com/ruoyi/account/bean/dto/AccountDto2.java
deleted file mode 100644
index 7c4e9e5..0000000
--- a/src/main/java/com/ruoyi/account/bean/dto/AccountDto2.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.ruoyi.account.bean.dto;
-
-import lombok.Data;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-
-/**
- * 璐㈠姟绠$悊--璐㈠姟鎶ヨ〃(绫诲瀷)
- */
-
-@Data
-public class AccountDto2 implements Serializable {
-
-
-    /**
-     * 绫诲瀷
-     */
-    private String typeName;
-
-
-    /**
-     * 鐧惧垎鍗犳瘮
-     */
-    private BigDecimal proportion;
-
-
-
-    /**
-     * 閲戦
-     */
-    private BigDecimal account;
-
-
-
-
-
-}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/AccountDto3.java b/src/main/java/com/ruoyi/account/bean/dto/AccountDto3.java
deleted file mode 100644
index 117fa77..0000000
--- a/src/main/java/com/ruoyi/account/bean/dto/AccountDto3.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.ruoyi.account.bean.dto;
-
-import lombok.Data;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-import java.util.List;
-
-/**
- * 璐㈠姟绠$悊--璐㈠姟鎶ヨ〃(绫诲瀷)
- */
-
-@Data
-public class AccountDto3 implements Serializable {
-
-
-    /**
-     * 绫诲瀷
-     */
-    private String typeName;
-
-
-    /**
-     * 鐧惧垎鍗犳瘮
-     */
-    private BigDecimal proportion;
-
-
-
-    /**
-     * 閲戦
-     */
-    private List<BigDecimal> account;
-
-
-
-
-
-}
diff --git a/src/main/java/com/ruoyi/account/bean/dto/ReportDateDto.java b/src/main/java/com/ruoyi/account/bean/dto/AccountReportDto.java
similarity index 70%
rename from src/main/java/com/ruoyi/account/bean/dto/ReportDateDto.java
rename to src/main/java/com/ruoyi/account/bean/dto/AccountReportDto.java
index 5e89162..8d4bf31 100644
--- a/src/main/java/com/ruoyi/account/bean/dto/ReportDateDto.java
+++ b/src/main/java/com/ruoyi/account/bean/dto/AccountReportDto.java
@@ -1,17 +1,16 @@
 package com.ruoyi.account.bean.dto;
 
 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.time.LocalDate;
 
-/**
- * @author :yys
- * @date : 2026/1/16 16:57
- */
+
 @Data
-public class ReportDateDto {
+@Schema(name = "AccountReportDto", description = "璐㈠姟鎶ヨ〃--鏃ユ湡鍙傛暟")
+public class AccountReportDto {
 
     /**
      * 寮�濮嬫椂闂�
@@ -26,15 +25,5 @@
     @JsonFormat(pattern = "yyyy-MM-dd")
     @DateTimeFormat(pattern = "yyyy-MM-dd")
     private LocalDate entryDateEnd;
-
-    /**
-     * 寮�濮嬫湀浠�
-     */
-    private Integer startMonth;
-
-    /**
-     * 缁撴潫鏈堜唤
-     */
-    private Integer endMonth;
 
 }
diff --git a/src/main/java/com/ruoyi/account/bean/vo/AccountReportVo.java b/src/main/java/com/ruoyi/account/bean/vo/AccountReportVo.java
new file mode 100644
index 0000000..f7b39d8
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/bean/vo/AccountReportVo.java
@@ -0,0 +1,66 @@
+package com.ruoyi.account.bean.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+
+@Data
+@Schema(name = "AccountReportVo", description = "璐㈠姟鎶ヨ〃--杩斿洖鍙傛暟")
+public class AccountReportVo {
+
+    @Schema(description = "鎬昏惀鏀�")
+    private BigDecimal totalIncome;
+
+    @Schema(description = "鎬绘敮鍑�")
+    private BigDecimal totalExpense;
+
+    @Schema(description = "搴旀敹璐︽")
+    private BigDecimal accountsReceivable;
+
+    @Schema(description = "搴斾粯璐︽")
+    private BigDecimal accountsPayable;
+
+    @Schema(description = "鍑�鏀跺叆")
+    private BigDecimal netRevenue;
+
+    // --- 鎶樼嚎鍥撅細鏈堝害瓒嬪娍鏁版嵁 ---
+    @Schema(description = "鏈堝害瓒嬪娍鏁版嵁鍒楄〃")
+    private List<MonthlyTrendVO> monthlyTrendList;
+
+    // --- 鏌辩姸鍥撅細搴旀敹搴斾粯鏈堝害鏁版嵁 ---
+    @Schema(description = "搴旀敹搴斾粯鏈堝害鏁版嵁鍒楄〃")
+    private List<ReceivablePayableVO> receivablePayableList;
+
+    @Data
+    @Schema(description = "鏈堝害瓒嬪娍VO锛堟姌绾垮浘鐢級")
+    public static class MonthlyTrendVO {
+        @Schema(description = "鏈堜唤锛屾牸寮忥細yyyy-MM")
+        private String month;
+
+        @Schema(description = "褰撴湀钀ユ敹")
+        private BigDecimal income;
+
+        @Schema(description = "褰撴湀鏀嚭")
+        private BigDecimal expense;
+
+        @Schema(description = "褰撴湀鍑�鍒╂鼎")
+        private BigDecimal profit;
+    }
+
+    @Data
+    @Schema(description = "搴旀敹搴斾粯鏈堝害VO锛堟煴鐘跺浘鐢級")
+    public static class ReceivablePayableVO {
+        @Schema(description = "鏈堜唤锛屾牸寮忥細yyyy-MM")
+        private String month;
+
+        @Schema(description = "搴旀敹璐︽閲戦")
+        private BigDecimal receivable;
+
+        @Schema(description = "搴斾粯璐︽閲戦")
+        private BigDecimal payable;
+    }
+
+}
diff --git a/src/main/java/com/ruoyi/account/controller/AccountingController.java b/src/main/java/com/ruoyi/account/controller/AccountingController.java
index 4688942..9eeb208 100644
--- a/src/main/java/com/ruoyi/account/controller/AccountingController.java
+++ b/src/main/java/com/ruoyi/account/controller/AccountingController.java
@@ -1,12 +1,16 @@
 package com.ruoyi.account.controller;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.account.service.impl.AccountingServiceImpl;
+import com.ruoyi.account.bean.dto.AccountReportDto;
+import com.ruoyi.account.service.AccountingService;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
 import com.ruoyi.framework.web.controller.BaseController;
 import com.ruoyi.framework.web.domain.AjaxResult;
-import io.swagger.v3.oas.annotations.tags.Tag;
+import com.ruoyi.framework.web.domain.R;
 import io.swagger.v3.oas.annotations.Operation;
-import lombok.AllArgsConstructor;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -19,11 +23,11 @@
 @Tag(name = "浼氳鏍哥畻")
 @RestController
 @RequestMapping("/accounting")
-@AllArgsConstructor
+@RequiredArgsConstructor
 public class AccountingController extends BaseController {
 
 
-    private AccountingServiceImpl accountingService;
+    private final AccountingService accountingService;
 
     @Operation(summary = "鎬昏")
     @GetMapping("/total")
@@ -43,4 +47,14 @@
         return accountingService.calculateDepreciation(page,year);
     }
 
+    /*****************************************璐㈠姟鎶ヨ〃******************************************************************************/
+
+    @GetMapping("/accountStatementDetailsByMonth")
+    @Log(title = "璐㈠姟鎶ヨ〃", businessType = BusinessType.OTHER)
+    @Operation(summary = "璐㈠姟鎶ヨ〃")
+    public R getAccountStatementDetailsByMonth(AccountReportDto accountReportDto) {
+        return R.ok(accountingService.getAccountStatementDetailsByMonth(accountReportDto));
+    }
+
+
 }
diff --git a/src/main/java/com/ruoyi/account/mapper/AccountStatementMapper.java b/src/main/java/com/ruoyi/account/mapper/AccountStatementMapper.java
index 307cf1a..89730cb 100644
--- a/src/main/java/com/ruoyi/account/mapper/AccountStatementMapper.java
+++ b/src/main/java/com/ruoyi/account/mapper/AccountStatementMapper.java
@@ -6,6 +6,7 @@
 import com.ruoyi.account.bean.dto.StatementAccountDto;
 import com.ruoyi.account.bean.vo.StatementAccountVo;
 import com.ruoyi.account.pojo.AccountStatement;
+import com.ruoyi.purchase.dto.VatDto;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -22,4 +23,6 @@
 
 
     IPage<StatementAccountVo> listPageAccountStatement(Page page, @Param("req") StatementAccountDto statementAccountDto);
+
+    IPage<VatDto> selectVatDtoPage(Page page, @Param("month") String month);
 }
diff --git a/src/main/java/com/ruoyi/account/service/AccountingService.java b/src/main/java/com/ruoyi/account/service/AccountingService.java
new file mode 100644
index 0000000..6190dc8
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/AccountingService.java
@@ -0,0 +1,19 @@
+package com.ruoyi.account.service;
+
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.AccountReportDto;
+import com.ruoyi.account.bean.vo.AccountReportVo;
+import com.ruoyi.framework.web.domain.AjaxResult;
+
+public interface AccountingService {
+
+    AjaxResult total(Integer year);
+
+    AjaxResult deviceTypeDistribution(Integer year);
+
+    AjaxResult calculateDepreciation(Page page, Integer year);
+
+    AccountReportVo getAccountStatementDetailsByMonth(AccountReportDto accountReportDto);
+
+}
diff --git a/src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java
index 01f5687..f42599a 100644
--- a/src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java
+++ b/src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java
@@ -3,25 +3,47 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.AccountReportDto;
 import com.ruoyi.account.bean.dto.DeviceTypeDetail;
 import com.ruoyi.account.bean.dto.DeviceTypeDistributionVO;
+import com.ruoyi.account.bean.dto.purchase.PurchaseInboundDto;
+import com.ruoyi.account.bean.dto.purchase.PurchaseReturnDto;
+import com.ruoyi.account.bean.dto.sales.SalesOutboundDto;
+import com.ruoyi.account.bean.dto.sales.SalesReturnDto;
+import com.ruoyi.account.bean.vo.AccountReportVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseReturnVo;
+import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
+import com.ruoyi.account.bean.vo.sales.SalesReturnVo;
+import com.ruoyi.account.mapper.purchase.AccountPurchasePaymentMapper;
+import com.ruoyi.account.mapper.sales.AccountSalesCollectionMapper;
+import com.ruoyi.account.pojo.purchase.AccountPurchasePayment;
+import com.ruoyi.account.pojo.sales.AccountSalesCollection;
+import com.ruoyi.account.service.AccountingService;
 import com.ruoyi.device.mapper.DeviceLedgerMapper;
 import com.ruoyi.device.pojo.DeviceLedger;
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.procurementrecord.mapper.CustomStorageMapper;
 import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper;
 import com.ruoyi.procurementrecord.mapper.ProcurementRecordOutMapper;
+import com.ruoyi.procurementrecord.mapper.ReturnManagementMapper;
 import com.ruoyi.procurementrecord.pojo.CustomStorage;
 import com.ruoyi.procurementrecord.pojo.ProcurementRecordOut;
 import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
+import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper;
+import com.ruoyi.stock.mapper.StockInRecordMapper;
+import com.ruoyi.stock.mapper.StockOutRecordMapper;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.Year;
+import java.time.format.DateTimeFormatter;
 import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -33,13 +55,21 @@
 @Service
 @Slf4j
 @RequiredArgsConstructor
-public class AccountingServiceImpl {
+public class AccountingServiceImpl implements AccountingService {
 
     private final DeviceLedgerMapper deviceLedgerMapper;
     private final CustomStorageMapper customStorageMapper;
     private final ProcurementRecordMapper procurementRecordMapper;
     private final ProcurementRecordOutMapper procurementRecordOutMapper;
+    private final AccountSalesCollectionMapper accountSalesCollectionMapper;
+    private final AccountPurchasePaymentMapper accountPurchasePaymentMapper;
+    private final StockOutRecordMapper stockOutRecordMapper;
+    private final ReturnManagementMapper returnManagementMapper;
+    private final StockInRecordMapper stockInRecordMapper;
+    private final PurchaseReturnOrdersMapper purchaseReturnOrdersMapper;
 
+
+    @Override
     public AjaxResult total(Integer year) {
         Map<String,Object> map = new HashMap<>();
         map.put("deprAmount",0); // 鎶樻棫閲戦
@@ -233,6 +263,7 @@
         return totalDepreciation.setScale(2, BigDecimal.ROUND_HALF_UP);
     }
 
+    @Override
     public AjaxResult deviceTypeDistribution(Integer year) {
         // 2. 缁勮杩斿洖VO
        DeviceTypeDistributionVO vo = new DeviceTypeDistributionVO();
@@ -256,6 +287,7 @@
         return AjaxResult.success(vo);
     }
 
+    @Override
     public AjaxResult calculateDepreciation(Page page, Integer year) {
         LambdaQueryWrapper<DeviceLedger> deviceLedgerLambdaQueryWrapper = new LambdaQueryWrapper<>();
         deviceLedgerLambdaQueryWrapper.like(DeviceLedger::getCreateTime,year)
@@ -267,4 +299,159 @@
         }
         return AjaxResult.success(deviceLedgerIPage);
     }
+
+    @Override
+    public AccountReportVo getAccountStatementDetailsByMonth(AccountReportDto accountReportDto) {
+        AccountReportVo accountReportVo = new AccountReportVo();
+        LocalDate start = accountReportDto.getEntryDateStart();
+        LocalDate end = accountReportDto.getEntryDateEnd();
+        DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM");
+
+        // ========== 1. 椤堕儴鍗$墖鏁版嵁 ==========
+        // 1.1 鎬昏惀鏀� = 鏀舵鍗曟�婚噾棰�
+        List<AccountSalesCollection> accountSalesCollections = accountSalesCollectionMapper.selectList(
+                Wrappers.<AccountSalesCollection>lambdaQuery()
+                        .between(AccountSalesCollection::getCollectionDate, start, end)
+        );
+        BigDecimal totalIncome = Optional.of(
+                accountSalesCollections.stream()
+                        .map(AccountSalesCollection::getCollectionAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add)
+        ).orElse(BigDecimal.ZERO);
+        accountReportVo.setTotalIncome(totalIncome);
+        // 1.2 鎬绘敮鍑� = 浠樻鍗曟�婚噾棰�
+        List<AccountPurchasePayment> accountPurchasePayments = accountPurchasePaymentMapper.selectList(
+                Wrappers.<AccountPurchasePayment>lambdaQuery()
+                        .between(AccountPurchasePayment::getPaymentDate, start, end)
+        );
+        BigDecimal totalExpense = Optional.of(
+                accountPurchasePayments.stream()
+                        .map(AccountPurchasePayment::getPaymentAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add)
+        ).orElse(BigDecimal.ZERO);
+        accountReportVo.setTotalExpense(totalExpense);
+        // 1.3 搴旀敹璐︽ = 閿�鍞嚭搴撻噾棰濆悎璁� - 閿�鍞��璐ч噾棰濆悎璁�
+        SalesOutboundDto salesOutboundDto = new SalesOutboundDto();
+        salesOutboundDto.setStartDate(accountReportDto.getEntryDateStart());
+        salesOutboundDto.setEndDate(accountReportDto.getEntryDateEnd());
+        List<SalesOutboundVo> salesOutboundVos = stockOutRecordMapper.listPageAccountSales(new Page(1, -1), salesOutboundDto).getRecords();
+        BigDecimal salesOutAmount = Optional.of(
+                salesOutboundVos.stream()
+                        .map(SalesOutboundVo::getOutboundAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add)
+        ).orElse(BigDecimal.ZERO);
+        SalesReturnDto salesReturnDto = new SalesReturnDto();
+        salesReturnDto.setStartDate(accountReportDto.getEntryDateStart());
+        salesReturnDto.setEndDate(accountReportDto.getEntryDateEnd());
+        List<SalesReturnVo> salesReturnVos = returnManagementMapper.listPageAccountSalesReturn(new Page(1, -1), salesReturnDto).getRecords();
+        BigDecimal salesReturnAmount = Optional.of(
+                salesReturnVos.stream()
+                        .map(SalesReturnVo::getRefundAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add)
+        ).orElse(BigDecimal.ZERO);
+        accountReportVo.setAccountsReceivable(salesOutAmount.subtract(salesReturnAmount));
+        // 1.4 搴斾粯璐︽ = 閲囪喘鍏ュ簱閲戦鍚堣 - 閲囪喘閫�璐ч噾棰濆悎璁�
+        PurchaseInboundDto purchaseInboundDto = new PurchaseInboundDto();
+        purchaseInboundDto.setStartDate(accountReportDto.getEntryDateStart());
+        purchaseInboundDto.setEndDate(accountReportDto.getEntryDateEnd());
+        List<PurchaseInboundVo> purchaseInboundVos = stockInRecordMapper.listPageAccountPurchase(new Page(1, -1), purchaseInboundDto).getRecords();
+        BigDecimal purchaseInAmount = Optional.of(
+                purchaseInboundVos.stream()
+                        .map(PurchaseInboundVo::getInboundAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add)
+        ).orElse(BigDecimal.ZERO);
+        PurchaseReturnDto purchaseReturnDto = new PurchaseReturnDto();
+        purchaseReturnDto.setStartDate(accountReportDto.getEntryDateStart());
+        purchaseReturnDto.setEndDate(accountReportDto.getEntryDateEnd());
+        List<PurchaseReturnVo> purchaseReturnVos = purchaseReturnOrdersMapper.listPageAccountPurchaseReturn(new Page(1, -1), purchaseReturnDto).getRecords();
+        BigDecimal purchaseReturnAmount = Optional.of(
+                purchaseReturnVos.stream()
+                        .map(PurchaseReturnVo::getTotalAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add)
+        ).orElse(BigDecimal.ZERO);
+        accountReportVo.setAccountsPayable(purchaseInAmount.subtract(purchaseReturnAmount));
+        // 1.5 鍑�鍒╂鼎 = 鎬昏惀鏀� - 鎬绘敮鍑�
+        BigDecimal netProfit = totalIncome.subtract(totalExpense);
+        accountReportVo.setNetRevenue(netProfit);
+
+        // ========== 2. 鎶樼嚎鍥撅細鏈堝害钀ユ敹/鏀嚭/鍑�鍒╂鼎瓒嬪娍 ==========
+        Map<String, BigDecimal> monthIncomeMap = new HashMap<>();
+        Map<String, BigDecimal> monthExpenseMap = new HashMap<>();
+        // 鏈堝害钀ユ敹
+        accountSalesCollections.forEach(item -> {
+            String month = item.getCollectionDate().format(monthFormatter);
+            monthIncomeMap.put(month, monthIncomeMap.getOrDefault(month, BigDecimal.ZERO)
+                    .add(Optional.ofNullable(item.getCollectionAmount()).orElse(BigDecimal.ZERO)));
+        });
+        // 鏈堝害鏀嚭
+        accountPurchasePayments.forEach(item -> {
+            String month = item.getPaymentDate().format(monthFormatter);
+            monthExpenseMap.put(month, monthExpenseMap.getOrDefault(month, BigDecimal.ZERO)
+                    .add(Optional.ofNullable(item.getPaymentAmount()).orElse(BigDecimal.ZERO)));
+        });
+        // 鐢熸垚杩炵画鏈堜唤鍒楄〃
+        List<String> monthList = new ArrayList<>();
+        LocalDate current = start.withDayOfMonth(1);
+        while (!current.isAfter(end.withDayOfMonth(1))) {
+            monthList.add(current.format(monthFormatter));
+            current = current.plusMonths(1);
+        }
+        // 缁勮瓒嬪娍鏁版嵁
+        List<AccountReportVo.MonthlyTrendVO> trendList = new ArrayList<>();
+        for (String month : monthList) {
+            BigDecimal income = monthIncomeMap.getOrDefault(month, BigDecimal.ZERO);
+            BigDecimal expense = monthExpenseMap.getOrDefault(month, BigDecimal.ZERO);
+            AccountReportVo.MonthlyTrendVO trend = new AccountReportVo.MonthlyTrendVO();
+            trend.setMonth(month);
+            trend.setIncome(income);
+            trend.setExpense(expense);
+            trend.setProfit(income.subtract(expense));
+            trendList.add(trend);
+        }
+        accountReportVo.setMonthlyTrendList(trendList);
+
+        // ========== 3. 鏌辩姸鍥撅細鏈堝害搴旀敹/搴斾粯鏁版嵁 ==========
+        Map<String, BigDecimal> monthReceivableMap = new HashMap<>();
+        Map<String, BigDecimal> monthPayableMap = new HashMap<>();
+        // 鏈堝害搴旀敹锛堥攢鍞嚭搴�-閫�璐э級
+        salesOutboundVos.forEach(item -> {
+            String month = item.getShippingDate().format(monthFormatter);
+            monthReceivableMap.put(month, monthReceivableMap.getOrDefault(month, BigDecimal.ZERO)
+                    .add(Optional.ofNullable(item.getOutboundAmount()).orElse(BigDecimal.ZERO)));
+        });
+        salesReturnVos.forEach(item -> {
+            String month = item.getMakeTime().format(monthFormatter);
+            monthReceivableMap.put(month, monthReceivableMap.getOrDefault(month, BigDecimal.ZERO)
+                    .subtract(Optional.ofNullable(item.getRefundAmount()).orElse(BigDecimal.ZERO)));
+        });
+
+        // 鏈堝害搴斾粯锛堥噰璐叆搴�-閫�璐э級
+        purchaseInboundVos.forEach(item -> {
+            String month = item.getInboundDate().format(monthFormatter);
+            monthPayableMap.put(month, monthPayableMap.getOrDefault(month, BigDecimal.ZERO)
+                    .add(Optional.ofNullable(item.getInboundAmount()).orElse(BigDecimal.ZERO)));
+        });
+        purchaseReturnVos.forEach(item -> {
+            String month = item.getPreparedAt().format(monthFormatter);
+            monthPayableMap.put(month, monthPayableMap.getOrDefault(month, BigDecimal.ZERO)
+                    .subtract(Optional.ofNullable(item.getTotalAmount()).orElse(BigDecimal.ZERO)));
+        });
+        // 缁勮搴旀敹搴斾粯鏁版嵁
+        List<AccountReportVo.ReceivablePayableVO> rpList = new ArrayList<>();
+        for (String month : monthList) {
+            AccountReportVo.ReceivablePayableVO rp = new AccountReportVo.ReceivablePayableVO();
+            rp.setMonth(month);
+            rp.setReceivable(monthReceivableMap.getOrDefault(month, BigDecimal.ZERO));
+            rp.setPayable(monthPayableMap.getOrDefault(month, BigDecimal.ZERO));
+            rpList.add(rp);
+        }
+        accountReportVo.setReceivablePayableList(rpList);
+        return accountReportVo;
+    }
 }
diff --git a/src/main/java/com/ruoyi/ai/assistant/FinancialIntentExecutor.java b/src/main/java/com/ruoyi/ai/assistant/FinancialIntentExecutor.java
index c1f349c..9afadff 100644
--- a/src/main/java/com/ruoyi/ai/assistant/FinancialIntentExecutor.java
+++ b/src/main/java/com/ruoyi/ai/assistant/FinancialIntentExecutor.java
@@ -45,7 +45,8 @@
         if (containsAny(text, "鎴愭湰鏍哥畻", "浜у搧鎴愭湰", "宸ュ簭鎴愭湰", "浜哄伐鎴愭湰", "鎶樻棫", "鏉愭枡鎹熻��")) {
             return financialAgentTools.calculateIntelligentCost(memoryId, startDate, endDate, timeRange, keyword, limit);
         }
-        if (containsAny(text, "鍒╂鼎鍒嗘瀽", "璁㈠崟鍒╂鼎", "浜忔崯璁㈠崟", "浣庡埄娑�", "鏈�璧氶挶瀹㈡埛", "鍒╂鼎涓嬮檷")) {
+        if (containsAny(text, "鍒╂鼎鍒嗘瀽", "璁㈠崟鍒╂鼎", "浜忔崯璁㈠崟", "浣庡埄娑�",
+                "鏈�璧氶挶瀹㈡埛", "鍝釜瀹㈡埛鏈�璧氶挶", "瀹㈡埛鏈�璧氶挶", "鍒╂鼎鏈�楂樺鎴�", "鍒╂鼎璐$尞鏈�楂樺鎴�", "鍒╂鼎涓嬮檷")) {
             return financialAgentTools.analyzeOrderProfit(memoryId, startDate, endDate, timeRange, keyword, limit);
         }
         if (containsAny(text, "搴撳瓨璧勯噾", "搴撳瓨绉帇", "鍛嗘粸搴撳瓨", "璧勯噾鍗犵敤", "鍛ㄨ浆鐜�", "搴撳瓨鍛ㄨ浆")) {
@@ -86,6 +87,15 @@
         }
         if ("涓轰粈涔堝埄娑︿笅闄�".equals(normalized)) {
             DateRange range = monthRange();
+            return financialAgentTools.analyzeOrderProfit(memoryId, range.startDate(), range.endDate(), range.label(), null, 20);
+        }
+        if ("鍝釜瀹㈡埛鏈�璧氶挶".equals(normalized)
+                || "鏈�杩戝摢涓鎴锋渶璧氶挶".equals(normalized)
+                || "鏈湀鍝釜瀹㈡埛鏈�璧氶挶".equals(normalized)
+                || "杩�30澶╁摢涓鎴锋渶璧氶挶".equals(normalized)
+                || "鍝釜瀹㈡埛鍒╂鼎鏈�楂�".equals(normalized)
+                || "鍝釜瀹㈡埛鍒╂鼎璐$尞鏈�楂�".equals(normalized)) {
+            DateRange range = extractDateRange(text);
             return financialAgentTools.analyzeOrderProfit(memoryId, range.startDate(), range.endDate(), range.label(), null, 20);
         }
         return null;
@@ -216,6 +226,16 @@
                 .replace("璇�", "")
                 .replace("涓�涓�", "")
                 .replace("涓轰粈涔�", "")
+                .replace("鍝釜瀹㈡埛鏈�璧氶挶", "")
+                .replace("鏈�杩戝摢涓鎴锋渶璧氶挶", "")
+                .replace("鏈湀鍝釜瀹㈡埛鏈�璧氶挶", "")
+                .replace("杩�30澶╁摢涓鎴锋渶璧氶挶", "")
+                .replace("鏈�璧氶挶瀹㈡埛", "")
+                .replace("瀹㈡埛鏈�璧氶挶", "")
+                .replace("鍝釜瀹㈡埛鍒╂鼎鏈�楂�", "")
+                .replace("鍒╂鼎鏈�楂樺鎴�", "")
+                .replace("鍝釜瀹㈡埛鍒╂鼎璐$尞鏈�楂�", "")
+                .replace("鍒╂鼎璐$尞鏈�楂樺鎴�", "")
                 .replace("鏈湀", "")
                 .replace("鏈懆", "")
                 .replace("鏈勾", "")
diff --git a/src/main/java/com/ruoyi/approve/bean/vo/ApproveGetAndUpdateVo.java b/src/main/java/com/ruoyi/approve/bean/vo/ApproveGetAndUpdateVo.java
index f43ecac..4bf8d2f 100644
--- a/src/main/java/com/ruoyi/approve/bean/vo/ApproveGetAndUpdateVo.java
+++ b/src/main/java/com/ruoyi/approve/bean/vo/ApproveGetAndUpdateVo.java
@@ -9,6 +9,7 @@
 import org.springframework.format.annotation.DateTimeFormat;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.Date;
 import java.util.List;
 
@@ -45,6 +46,14 @@
     @DateTimeFormat(pattern = "yyyy-MM-dd")
     private Date endDate;
 
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
+    @Schema(description = "鍑哄樊寮�濮嬫椂闂�")
+    private LocalDateTime startDateTime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
+    @Schema(description = "鍑哄樊缁撴潫鏃堕棿")
+    private LocalDateTime endDateTime;
+
     private BigDecimal price;
 
     private String location;
diff --git a/src/main/java/com/ruoyi/approve/bean/vo/ApproveProcessVO.java b/src/main/java/com/ruoyi/approve/bean/vo/ApproveProcessVO.java
index 8c5db04..8e730ff 100644
--- a/src/main/java/com/ruoyi/approve/bean/vo/ApproveProcessVO.java
+++ b/src/main/java/com/ruoyi/approve/bean/vo/ApproveProcessVO.java
@@ -8,6 +8,7 @@
 import org.springframework.format.annotation.DateTimeFormat;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.Date;
 import java.util.List;
 
@@ -58,6 +59,14 @@
     @DateTimeFormat(pattern = "yyyy-MM-dd")
     private Date endDate;
 
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
+    @Schema(description = "鍑哄樊寮�濮嬫椂闂�")
+    private LocalDateTime startDateTime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
+    @Schema(description = "鍑哄樊缁撴潫鏃堕棿")
+    private LocalDateTime endDateTime;
+
     private BigDecimal price;
 
     private String location;
diff --git a/src/main/java/com/ruoyi/approve/pojo/ApproveProcess.java b/src/main/java/com/ruoyi/approve/pojo/ApproveProcess.java
index bd56b0f..728878b 100644
--- a/src/main/java/com/ruoyi/approve/pojo/ApproveProcess.java
+++ b/src/main/java/com/ruoyi/approve/pojo/ApproveProcess.java
@@ -151,6 +151,16 @@
     @DateTimeFormat(pattern = "yyyy-MM-dd")
     private Date endDate;
 
+    @Excel(name = "鍑哄樊寮�濮嬫椂闂�", dateFormat = "yyyy-MM-dd HH:mm", width = 30)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
+    @Schema(description = "鍑哄樊寮�濮嬫椂闂�")
+    private LocalDateTime startDateTime;
+
+    @Excel(name = "鍑哄樊缁撴潫鏃堕棿", dateFormat = "yyyy-MM-dd HH:mm", width = 30)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
+    @Schema(description = "鍑哄樊缁撴潫鏃堕棿")
+    private LocalDateTime endDateTime;
+
     private BigDecimal price;
 
     private String location;
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApproveBusinessStatusService.java b/src/main/java/com/ruoyi/approve/service/impl/ApproveBusinessStatusService.java
new file mode 100644
index 0000000..8135c3a
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApproveBusinessStatusService.java
@@ -0,0 +1,175 @@
+package com.ruoyi.approve.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
+import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
+import com.ruoyi.procurementrecord.utils.StockUtils;
+import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
+import com.ruoyi.purchase.pojo.PurchaseLedger;
+import com.ruoyi.quality.mapper.QualityInspectMapper;
+import com.ruoyi.quality.mapper.QualityInspectParamMapper;
+import com.ruoyi.quality.mapper.QualityTestStandardMapper;
+import com.ruoyi.quality.mapper.QualityTestStandardParamMapper;
+import com.ruoyi.quality.pojo.QualityInspect;
+import com.ruoyi.quality.pojo.QualityInspectParam;
+import com.ruoyi.quality.pojo.QualityTestStandard;
+import com.ruoyi.quality.pojo.QualityTestStandardParam;
+import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
+import com.ruoyi.sales.mapper.SalesQuotationMapper;
+import com.ruoyi.sales.mapper.ShippingInfoMapper;
+import com.ruoyi.sales.pojo.SalesLedgerProduct;
+import com.ruoyi.sales.pojo.SalesQuotation;
+import com.ruoyi.sales.pojo.ShippingInfo;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.util.Date;
+import java.util.List;
+
+@Service
+@RequiredArgsConstructor
+public class ApproveBusinessStatusService {
+
+    private final PurchaseLedgerMapper purchaseLedgerMapper;
+    private final SalesQuotationMapper salesQuotationMapper;
+    private final ShippingInfoMapper shippingInfoMapper;
+    private final SalesLedgerProductMapper salesLedgerProductMapper;
+    private final StockUtils stockUtils;
+    private final QualityInspectMapper qualityInspectMapper;
+    private final QualityTestStandardMapper qualityTestStandardMapper;
+    private final QualityTestStandardParamMapper qualityTestStandardParamMapper;
+    private final QualityInspectParamMapper qualityInspectParamMapper;
+
+    /**
+     * 缁熶竴鍚屾瀹℃壒缁撴灉瀵瑰簲鐨勪笟鍔″崟鎹姸鎬併��
+     * status锛�1-瀹℃牳涓紝2-瀹℃牳瀹屾垚锛�3-瀹℃牳鏈�氳繃銆�
+     */
+    public void syncBusinessStatus(Integer approveType, String approveReason, Integer status) {
+        if (approveType == null || status == null || !StringUtils.hasText(approveReason)) {
+            return;
+        }
+        switch (approveType) {
+            case 5:
+                syncPurchaseStatus(approveReason, status);
+                break;
+            case 6:
+                syncSalesQuotationStatus(approveReason, status);
+                break;
+            case 7:
+                syncShippingStatus(approveReason, status);
+                break;
+            default:
+                break;
+        }
+    }
+
+    // 閲囪喘瀹℃壒閫氳繃鏃讹紝鎸変骇鍝佽川妫�閰嶇疆鍐冲畾鐢熸垚璐ㄦ鍗曟垨鐩存帴鍏ュ簱銆�
+    private void syncPurchaseStatus(String approveReason, Integer status) {
+        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
+                .eq(PurchaseLedger::getPurchaseContractNumber, approveReason)
+                .last("limit 1"));
+        if (purchaseLedger == null) {
+            return;
+        }
+        if (status.equals(2)) {
+            purchaseLedger.setApprovalStatus(3);
+            List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(new QueryWrapper<SalesLedgerProduct>()
+                    .lambda().eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId()).eq(SalesLedgerProduct::getType, 2));
+            for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) {
+                if (Boolean.TRUE.equals(salesLedgerProduct.getIsChecked())) {
+                    addQualityInspect(purchaseLedger, salesLedgerProduct);
+                } else {
+                    stockUtils.addStockWithBatchNo(
+                            salesLedgerProduct.getProductModelId(),
+                            salesLedgerProduct.getQuantity(),
+                            StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(),
+                            purchaseLedger.getId(),
+                            purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId());
+                }
+            }
+        } else if (status.equals(3)) {
+            purchaseLedger.setApprovalStatus(4);
+        } else if (status.equals(1)) {
+            purchaseLedger.setApprovalStatus(2);
+        } else {
+            return;
+        }
+        purchaseLedgerMapper.updateById(purchaseLedger);
+    }
+
+    // 鎶ヤ环瀹℃壒鐘舵�佸洖鍐欏埌閿�鍞姤浠峰崟鐘舵�併��
+    private void syncSalesQuotationStatus(String approveReason, Integer status) {
+        SalesQuotation salesQuote = salesQuotationMapper.selectOne(new LambdaQueryWrapper<SalesQuotation>()
+                .eq(SalesQuotation::getQuotationNo, approveReason)
+                .last("limit 1"));
+        if (salesQuote == null) {
+            return;
+        }
+        if (status.equals(2)) {
+            salesQuote.setStatus("閫氳繃");
+        } else if (status.equals(3)) {
+            salesQuote.setStatus("鎷掔粷");
+        } else if (status.equals(1)) {
+            salesQuote.setStatus("瀹℃牳涓�");
+        } else {
+            return;
+        }
+        salesQuotationMapper.updateById(salesQuote);
+    }
+
+    // 鍙戣揣瀹℃壒閫氳繃鏃跺悓姝ュ彂璐х姸鎬佸拰鍑哄簱瀹℃壒鐘舵�侊紱鎷掔粷鏃跺垹闄ゅ緟纭鍑哄簱璁板綍銆�
+    private void syncShippingStatus(String approveReason, Integer status) {
+        ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>()
+                .eq(ShippingInfo::getShippingNo, approveReason)
+                .orderByDesc(ShippingInfo::getCreateTime)
+                .last("limit 1"));
+        if (shippingInfo == null) {
+            return;
+        }
+        if (status.equals(2)) {
+            shippingInfo.setStatus("瀹℃牳閫氳繃");
+            shippingInfo.setShippingDate(new Date());
+            stockUtils.shipmentStatus(StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), shippingInfo.getId());
+        } else if (status.equals(3)) {
+            stockUtils.deleteStockOutRecord(shippingInfo.getId(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode());
+            shippingInfo.setStatus("瀹℃牳鎷掔粷");
+        } else if (status.equals(1)) {
+            shippingInfo.setStatus("瀹℃牳涓�");
+        } else {
+            return;
+        }
+        shippingInfoMapper.updateById(shippingInfo);
+    }
+
+    // 鐢熸垚閲囪喘璐ㄦ鍗曪紝骞舵寜浜у搧璐ㄦ鏍囧噯鍒濆鍖栬川妫�鍙傛暟銆�
+    private void addQualityInspect(PurchaseLedger purchaseLedger, SalesLedgerProduct saleProduct) {
+        QualityInspect qualityInspect = new QualityInspect();
+        qualityInspect.setInspectType(0);
+        qualityInspect.setSupplier(purchaseLedger.getSupplierName());
+        qualityInspect.setPurchaseLedgerId(purchaseLedger.getId());
+        qualityInspect.setProductId(saleProduct.getProductId());
+        qualityInspect.setProductName(saleProduct.getProductCategory());
+        qualityInspect.setModel(saleProduct.getSpecificationModel());
+        qualityInspect.setProductModelId(saleProduct.getProductModelId());
+        qualityInspect.setUnit(saleProduct.getUnit());
+        qualityInspect.setQuantity(saleProduct.getQuantity());
+        qualityInspectMapper.insert(qualityInspect);
+        List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(saleProduct.getProductId(), 0, null);
+        if (qualityTestStandard.size() > 0) {
+            qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId());
+            qualityInspectMapper.updateById(qualityInspect);
+            qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery()
+                            .eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId()))
+                    .forEach(qualityTestStandardParam -> {
+                        QualityInspectParam param = new QualityInspectParam();
+                        com.ruoyi.common.utils.bean.BeanUtils.copyProperties(qualityTestStandardParam, param);
+                        param.setId(null);
+                        param.setInspectId(qualityInspect.getId());
+                        qualityInspectParamMapper.insert(param);
+                    });
+        }
+    }
+}
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
index 0b1a854..964be23 100644
--- a/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
@@ -1,7 +1,6 @@
 package com.ruoyi.approve.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -14,26 +13,12 @@
 import com.ruoyi.basic.enums.RecordTypeEnum;
 import com.ruoyi.basic.utils.FileUtil;
 import com.ruoyi.common.enums.FileNameType;
-import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
-import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
 import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.device.mapper.DeviceRepairMapper;
-import com.ruoyi.procurementrecord.utils.StockUtils;
 import com.ruoyi.project.system.domain.SysUser;
 import com.ruoyi.project.system.mapper.SysUserMapper;
 import com.ruoyi.project.system.service.ISysNoticeService;
-import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
-import com.ruoyi.purchase.pojo.PurchaseLedger;
-import com.ruoyi.quality.mapper.QualityInspectMapper;
-import com.ruoyi.quality.mapper.QualityInspectParamMapper;
-import com.ruoyi.quality.mapper.QualityTestStandardMapper;
-import com.ruoyi.quality.mapper.QualityTestStandardParamMapper;
-import com.ruoyi.quality.pojo.QualityInspect;
-import com.ruoyi.quality.pojo.QualityInspectParam;
-import com.ruoyi.quality.pojo.QualityTestStandard;
-import com.ruoyi.quality.pojo.QualityTestStandardParam;
-import com.ruoyi.sales.mapper.*;
-import com.ruoyi.sales.pojo.*;
+import com.ruoyi.sales.mapper.CommonFileMapper;
+import com.ruoyi.sales.pojo.CommonFile;
 import com.ruoyi.sales.service.impl.CommonFileServiceImpl;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
@@ -55,18 +40,8 @@
     private final SysUserMapper sysUserMapper;
     private final ISysNoticeService sysNoticeService;
     private final CommonFileMapper fileMapper;
-    private final DeviceRepairMapper deviceRepairMapper;
-    private final PurchaseLedgerMapper purchaseLedgerMapper;
-    private final SalesQuotationMapper salesQuotationMapper;
-    private final ShippingInfoMapper shippingInfoMapper;
-    private final ShippingProductDetailMapper shippingProductDetailMapper;
     private final CommonFileServiceImpl commonFileService;
-    private final StockUtils stockUtils;
-    private final SalesLedgerProductMapper salesLedgerProductMapper;
-    private final QualityInspectMapper qualityInspectMapper;
-    private final QualityTestStandardMapper qualityTestStandardMapper;
-    private final QualityTestStandardParamMapper qualityTestStandardParamMapper;
-    private final QualityInspectParamMapper qualityInspectParamMapper;
+    private final ApproveBusinessStatusService approveBusinessStatusService;
     private final FileUtil fileUtil;
 
 
@@ -162,74 +137,7 @@
         }
         approveProcessMapper.updateById(approveProcess);
 
-        //閲囪喘瀹℃牳
-        if (approveProcess.getApproveType().equals(5)) {
-            PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
-                    .eq(PurchaseLedger::getPurchaseContractNumber, approveProcess.getApproveReason())
-                    .last("limit 1"));
-            if (purchaseLedger != null) {
-                if (status.equals(2)) {
-                    // 鍚屾剰
-                    purchaseLedger.setApprovalStatus(3);
-                    List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(new QueryWrapper<SalesLedgerProduct>()
-                            .lambda().eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId()).eq(SalesLedgerProduct::getType, 2));
-                    for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) {
-                        // 璐ㄦ
-                        if (salesLedgerProduct.getIsChecked()) {
-                            addQualityInspect(purchaseLedger, salesLedgerProduct);
-                        } else {
-                            //鐩存帴鍏ュ簱
-                            stockUtils.addStockWithBatchNo(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(), purchaseLedger.getId(), purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId());
-                        }
-                    }
-                } else if (status.equals(3)) {
-                    // 鎷掔粷
-                    purchaseLedger.setApprovalStatus(4);
-                } else if (status.equals(1)) {
-                    // 瀹℃牳涓�
-                    purchaseLedger.setApprovalStatus(2);
-                }
-                purchaseLedgerMapper.updateById(purchaseLedger);
-            }
-        }
-        // 閿�鍞姤浠风姸鎬佷慨鏀�
-        if (approveProcess.getApproveType().equals(6)) {
-            SalesQuotation salesQuote = salesQuotationMapper.selectOne(new LambdaQueryWrapper<SalesQuotation>()
-                    .eq(SalesQuotation::getQuotationNo, approveProcess.getApproveReason())
-                    .last("limit 1"));
-            // 鍚屾剰
-            if (status.equals(2) && salesQuote != null) {
-                salesQuote.setStatus("閫氳繃");
-            } else if (status.equals(3) && salesQuote != null) {
-                salesQuote.setStatus("鎷掔粷");
-            } else if (status.equals(1) && salesQuote != null) {
-                salesQuote.setStatus("瀹℃牳涓�");
-            }
-            salesQuotationMapper.updateById(salesQuote);
-        }
-        // 鍑哄簱瀹℃壒淇敼=鍙戣揣瀹℃壒
-        if (approveProcess.getApproveType().equals(7)) {
-            ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>()
-                    .eq(ShippingInfo::getShippingNo, approveProcess.getApproveReason())
-                    .orderByDesc(ShippingInfo::getCreateTime)
-                    .last("limit 1"));
-            if (shippingInfo != null) {
-                if (status.equals(2)) {
-                    shippingInfo.setStatus("瀹℃牳閫氳繃");
-                    shippingInfo.setShippingDate(new Date());
-                    //鏇存敼鍑哄簱瀹℃牳鐘舵�侊紙寰呯‘璁ゆ敼鎴愬緟瀹℃牳锛�
-                    stockUtils.shipmentStatus(StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), shippingInfo.getId());
-                } else if (status.equals(3)) {
-                    //鍒犻櫎鍘熸湰锛堝緟纭锛夌殑鍑哄簱瀹℃牳鐘舵��
-                    stockUtils.deleteStockOutRecord(shippingInfo.getId(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode());
-                    shippingInfo.setStatus("瀹℃牳鎷掔粷");
-                } else if (status.equals(1)) {
-                    shippingInfo.setStatus("瀹℃牳涓�");
-                }
-                shippingInfoMapper.updateById(shippingInfo);
-            }
-
-        }
+        approveBusinessStatusService.syncBusinessStatus(approveProcess.getApproveType(), approveProcess.getApproveReason(), status);
         fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVE_NODE, approveNode.getId(), approveNode.getStorageBlobDTOS());
     }
 
@@ -305,34 +213,6 @@
                 return "鍔炲叕鐢ㄥ搧瀹℃壒";
         }
         return null;
-    }
-
-    private void addQualityInspect(PurchaseLedger purchaseLedger, SalesLedgerProduct saleProduct) {
-        QualityInspect qualityInspect = new QualityInspect();
-        qualityInspect.setInspectType(0);
-        qualityInspect.setSupplier(purchaseLedger.getSupplierName());
-        qualityInspect.setPurchaseLedgerId(purchaseLedger.getId());
-        qualityInspect.setProductId(saleProduct.getProductId());
-        qualityInspect.setProductName(saleProduct.getProductCategory());
-        qualityInspect.setModel(saleProduct.getSpecificationModel());
-        qualityInspect.setProductModelId(saleProduct.getProductModelId());
-        qualityInspect.setUnit(saleProduct.getUnit());
-        qualityInspect.setQuantity(saleProduct.getQuantity());
-        qualityInspectMapper.insert(qualityInspect);
-        List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(saleProduct.getProductId(), 0, null);
-        if (qualityTestStandard.size() > 0) {
-            qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId());
-            qualityInspectMapper.updateById(qualityInspect);
-            qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery()
-                            .eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId()))
-                    .forEach(qualityTestStandardParam -> {
-                        QualityInspectParam param = new QualityInspectParam();
-                        com.ruoyi.common.utils.bean.BeanUtils.copyProperties(qualityTestStandardParam, param);
-                        param.setId(null);
-                        param.setInspectId(qualityInspect.getId());
-                        qualityInspectParamMapper.insert(param);
-                    });
-        }
     }
 
 }
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
index c9d7aae..c356708 100644
--- a/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
@@ -1,8 +1,6 @@
 package com.ruoyi.approve.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -25,10 +23,8 @@
 import com.ruoyi.basic.enums.RecordTypeEnum;
 import com.ruoyi.basic.utils.FileUtil;
 import com.ruoyi.common.enums.FileNameType;
-import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
 import com.ruoyi.common.utils.OrderUtils;
 import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.procurementrecord.utils.StockUtils;
 import com.ruoyi.project.system.domain.SysDept;
 import com.ruoyi.project.system.domain.SysNotice;
 import com.ruoyi.project.system.domain.SysUser;
@@ -38,10 +34,8 @@
 import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
 import com.ruoyi.sales.mapper.CommonFileMapper;
-import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
 import com.ruoyi.sales.mapper.ShippingInfoMapper;
 import com.ruoyi.sales.pojo.CommonFile;
-import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.sales.pojo.ShippingInfo;
 import com.ruoyi.sales.service.impl.CommonFileServiceImpl;
 import lombok.RequiredArgsConstructor;
@@ -53,15 +47,12 @@
 import java.io.IOException;
 import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.stream.Collectors;
 
 @Service
 @RequiredArgsConstructor
 public class ApproveProcessServiceImpl extends ServiceImpl<ApproveProcessMapper, ApproveProcess> implements IApproveProcessService {
-    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd");
-
     private final SysDeptMapper sysDeptMapper;
     private final IApproveNodeService approveNodeService;
     private final SysUserMapper sysUserMapper;
@@ -70,11 +61,10 @@
     private final CommonFileServiceImpl commonFileService;
     private final ISysNoticeService sysNoticeService;
     private final PurchaseLedgerMapper purchaseLedgerMapper;
-    private final SalesLedgerProductMapper salesLedgerProductMapper;
-    private final StockUtils stockUtils;
     private final ShippingInfoMapper shippingInfoMapper;
     private final ApproveNodeMapper approveNodeMapper;
     private final ApproveProcessConfigNodeService approveProcessConfigNodeService;
+    private final ApproveBusinessStatusService approveBusinessStatusService;
     private final FileUtil fileUtil;
     private final ApproveProcessConfigNodeMapper approveProcessConfigNodeMapper;
 
@@ -82,61 +72,34 @@
     public void addApprove(ApproveProcessVO approveProcessVO) throws Exception {
         SysUser sysUser = SecurityUtils.getLoginUser().getUser();
         SysDept sysDept = sysDeptMapper.selectDeptById(SecurityUtils.getLoginUser().getCurrentDeptId());
-        List<ApproveProcessConfigNodeVo> list = approveProcessConfigNodeService.listNode(approveProcessVO.getApproveType());
+        if (sysDept == null) throw new RuntimeException("閮ㄩ棬涓嶅瓨鍦�");
+        if (sysUser == null) throw new RuntimeException("鐢宠浜轰笉瀛樺湪");
+
+        List<ApproveProcessConfigNodeVo> list = Optional.ofNullable(approveProcessConfigNodeService.listNode(approveProcessVO.getApproveType()))
+                .orElse(Collections.emptyList());
         List<Long> nodeIds = list.stream()
                 .map(ApproveProcessConfigNodeVo::getApproverId)
                 .filter(Objects::nonNull)
                 .collect(Collectors.toList());
-        // 鏃犲鏍镐汉閫昏緫娣诲姞
+
+        // 瀹℃壒閰嶇疆娌℃湁鏈夋晥瀹℃牳浜烘椂锛屼笉鏂板鍗忓悓瀹℃壒娴佺▼锛岀洿鎺ユ墽琛屼笟鍔″鏍搁�氳繃閫昏緫銆�
         if (CollectionUtils.isEmpty(nodeIds)) {
-            autoPassPurchaseApproveIfNoApprover(approveProcessVO); // 閲囪喘鍗曟棤瀹℃牳浜洪�昏緫
+            approveBusinessStatusService.syncBusinessStatus(approveProcessVO.getApproveType(), approveProcessVO.getApproveReason(), 2);
             return;
         }
+
         List<SysUser> sysUsers = sysUserMapper.selectUserByIds(nodeIds);
         if (CollectionUtils.isEmpty(sysUsers)) throw new RuntimeException("瀹℃牳鐢ㄦ埛涓嶅瓨鍦�");
-        if (sysDept == null) throw new RuntimeException("閮ㄩ棬涓嶅瓨鍦�");
-        if (sysUser == null) throw new RuntimeException("鐢宠浜轰笉瀛樺湪");
-        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
-        ApproveProcess approveProcess = new ApproveProcess();
-        String no = OrderUtils.countTodayByCreateTime(approveProcessMapper, "", "approve_id");
-        approveProcess.setApproveId(no);
-        approveProcess.setApproveUser(sysUser.getUserId());
-        approveProcess.setApproveUserName(sysUser.getNickName());
-        approveProcess.setApproveDeptId(sysDept.getDeptId());
-        approveProcess.setApproveUserIds(nodeIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
-        approveProcess.setApproveDeptName(sysDept.getDeptName());
-        approveProcess.setApproveUserNames(sysUsers.stream().map(SysUser::getNickName).collect(Collectors.joining(",")));
-        approveProcess.setApproveTime(StringUtils.isEmpty(approveProcessVO.getApproveTime()) ? new Date() : dateFormat.parse(approveProcessVO.getApproveTime()));
-        approveProcess.setApproveReason(approveProcessVO.getApproveReason());
-        approveProcess.setDeviceRepairId(approveProcessVO.getDeviceRepairId());
-        approveProcess.setMaintenancePrice(approveProcessVO.getMaintenancePrice());
-        approveProcess.setPrice(approveProcessVO.getPrice());
-        approveProcess.setStartDate(approveProcessVO.getStartDate());
-        approveProcess.setEndDate(approveProcessVO.getEndDate());
-        approveProcess.setApproveStatus(0);
-        approveProcess.setApproveDelete(0);
-        approveProcess.setApproveType(approveProcessVO.getApproveType());
-        approveProcess.setCreateTime(LocalDateTime.now());
-        approveProcess.setTenantId(approveProcessVO.getApproveDeptId());
-        approveProcess.setApproveUserCurrentId(nodeIds.get(0));
-        approveProcess.setApproveUserCurrentName(sysUsers
-                .stream()
-                .filter(SysUser -> SysUser.getUserId().equals(nodeIds.get(0)))
-                .collect(Collectors.toList())
-                .get(0)
-                .getNickName());
-        // 璁剧疆鐘舵�佷负閲嶆柊鎻愪氦
-        if (approveProcessVO.getId() != null) {
-            ApproveProcess approveProcess1 = approveProcessMapper.selectById(approveProcessVO.getId());
-            approveProcess1.setApproveStatus(4);
-            approveProcessMapper.updateById(approveProcess1);
-        }
+
+        // 鏈夊鏍镐汉鏃讹紝鎸夋甯稿崗鍚屽鎵规祦绋嬪垱寤哄鎵逛富琛ㄣ�佸鎵硅妭鐐瑰苟閫氱煡棣栦釜瀹℃牳浜恒��
+        ApproveProcess approveProcess = buildApproveProcess(approveProcessVO, sysUser, sysDept, nodeIds, sysUsers, 0);
+        markResubmitted(approveProcessVO);
         save(approveProcess);
         //鍒濆鍖栧鎵硅妭鐐�
         String nodeIdStr = nodeIds.stream()
                 .map(String::valueOf)
                 .collect(Collectors.joining(","));
-        approveNodeService.initApproveNodes(nodeIdStr, no, approveProcessVO.getApproveDeptId());
+        approveNodeService.initApproveNodes(nodeIdStr, approveProcess.getApproveId(), approveProcessVO.getApproveDeptId());
         // 闄勪欢缁戝畾
         fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVE_PROCESS, approveProcess.getId(), approveProcessVO.getStorageBlobDTOS());
         /*娑堟伅閫氱煡*/
@@ -154,24 +117,56 @@
         }
     }
 
-    private void autoPassPurchaseApproveIfNoApprover(ApproveProcessVO approveProcessVO) {
-        if (!Objects.equals(approveProcessVO.getApproveType(), 5)
-                || !StringUtils.hasText(approveProcessVO.getApproveReason())) {
-            throw new RuntimeException("瀹℃牳鐢ㄦ埛涓嶅瓨鍦�");
+    private ApproveProcess buildApproveProcess(ApproveProcessVO approveProcessVO, SysUser sysUser, SysDept sysDept,
+                                               List<Long> nodeIds, List<SysUser> sysUsers, Integer approveStatus) throws Exception {
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        ApproveProcess approveProcess = new ApproveProcess();
+        String no = OrderUtils.countTodayByCreateTime(approveProcessMapper, "", "approve_id");
+        approveProcess.setApproveId(no);
+        approveProcess.setApproveUser(sysUser.getUserId());
+        approveProcess.setApproveUserName(sysUser.getNickName());
+        approveProcess.setApproveDeptId(sysDept.getDeptId());
+        approveProcess.setApproveDeptName(sysDept.getDeptName());
+        approveProcess.setApproveUserIds(nodeIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
+        approveProcess.setApproveUserNames(sysUsers.stream().map(SysUser::getNickName).collect(Collectors.joining(",")));
+        approveProcess.setApproveTime(StringUtils.isEmpty(approveProcessVO.getApproveTime()) ? new Date() : dateFormat.parse(approveProcessVO.getApproveTime()));
+        approveProcess.setApproveReason(approveProcessVO.getApproveReason());
+        approveProcess.setDeviceRepairId(approveProcessVO.getDeviceRepairId());
+        approveProcess.setMaintenancePrice(approveProcessVO.getMaintenancePrice());
+        approveProcess.setPrice(approveProcessVO.getPrice());
+        approveProcess.setStartDate(approveProcessVO.getStartDate());
+        approveProcess.setEndDate(approveProcessVO.getEndDate());
+        approveProcess.setStartDateTime(approveProcessVO.getStartDateTime());
+        approveProcess.setEndDateTime(approveProcessVO.getEndDateTime());
+        approveProcess.setApproveStatus(approveStatus);
+        approveProcess.setApproveDelete(0);
+        approveProcess.setApproveType(approveProcessVO.getApproveType());
+        approveProcess.setCreateTime(LocalDateTime.now());
+        approveProcess.setTenantId(approveProcessVO.getApproveDeptId());
+        if (!CollectionUtils.isEmpty(nodeIds)) {
+            SysUser currentUser = sysUsers.stream()
+                    .filter(user -> user.getUserId().equals(nodeIds.get(0)))
+                    .findFirst()
+                    .orElseThrow(() -> new RuntimeException("瀹℃牳鐢ㄦ埛涓嶅瓨鍦�"));
+            approveProcess.setApproveUserCurrentId(currentUser.getUserId());
+            approveProcess.setApproveUserCurrentName(currentUser.getNickName());
         }
+        if (approveStatus.equals(2) || approveStatus.equals(3) || approveStatus.equals(4)) {
+            approveProcess.setApproveOverTime(new Date());
+        }
+        return approveProcess;
+    }
 
-        purchaseLedgerMapper.update(null, new LambdaUpdateWrapper<PurchaseLedger>()
-                .eq(PurchaseLedger::getPurchaseContractNumber, approveProcessVO.getApproveReason())
-                .set(PurchaseLedger::getApprovalStatus, 3));
-        //閲囪喘鍏ュ簱
-        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
-                .eq(PurchaseLedger::getPurchaseContractNumber, approveProcessVO.getApproveReason())
-                .last("limit 1"));
-        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(new QueryWrapper<SalesLedgerProduct>()
-                .lambda().eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId()).eq(SalesLedgerProduct::getType, 2));
-        for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) {
-            stockUtils.addStockWithBatchNo(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(), purchaseLedger.getId(),purchaseLedger.getPurchaseContractNumber()+"-"+salesLedgerProduct.getId());
+    private void markResubmitted(ApproveProcessVO approveProcessVO) {
+        if (approveProcessVO.getId() == null) {
+            return;
         }
+        ApproveProcess approveProcess = approveProcessMapper.selectById(approveProcessVO.getId());
+        if (approveProcess == null) {
+            return;
+        }
+        approveProcess.setApproveStatus(4);
+        approveProcessMapper.updateById(approveProcess);
     }
 
     @Override
diff --git a/src/main/java/com/ruoyi/device/controller/DeviceLedgerController.java b/src/main/java/com/ruoyi/device/controller/DeviceLedgerController.java
index f4b807d..298980e 100644
--- a/src/main/java/com/ruoyi/device/controller/DeviceLedgerController.java
+++ b/src/main/java/com/ruoyi/device/controller/DeviceLedgerController.java
@@ -35,30 +35,29 @@
     private DeviceMaintenanceMapper deviceMaintenanceMapper;
 
 
-
     @Operation(summary = "璁惧鍙拌处鍒楄〃")
     @GetMapping("/page")
-    public AjaxResult page(Page page , DeviceLedgerDto deviceLedger) {
-        return AjaxResult.success(deviceLedgerService.queryPage(page,deviceLedger));
+    public AjaxResult page(Page page, DeviceLedgerDto deviceLedger) {
+        return AjaxResult.success(deviceLedgerService.queryPage(page, deviceLedger));
     }
 
     @PostMapping()
     @Operation(summary = "娣诲姞璁惧鍙拌处")
-    public AjaxResult add(@RequestBody DeviceLedger deviceLedger) {
-
-        return deviceLedgerService.saveDeviceLedger(deviceLedger);
+    public AjaxResult add(@RequestBody DeviceLedgerDto deviceLedgerDto) {
+        return deviceLedgerService.saveDeviceLedger(deviceLedgerDto);
     }
 
     @Operation(summary = "鏍规嵁id鏌ヨ璁惧鍙拌处")
     @GetMapping("/{id}")
     public AjaxResult detail(@PathVariable Long id) {
-        return AjaxResult.success(deviceLedgerService.getById(id));
+        DeviceLedgerDto deviceLedgerDto = deviceLedgerService.getDeviceLedgerDetail(id);
+        return AjaxResult.success(deviceLedgerDto);
     }
 
-    @PutMapping ()
+    @PutMapping()
     @Operation(summary = "淇敼璁惧鍙拌处")
-    public AjaxResult update(@RequestBody DeviceLedger deviceLedger) {
-        return deviceLedgerService.updateDeviceLedger(deviceLedger);
+    public AjaxResult update(@RequestBody DeviceLedgerDto deviceLedgerDto) {
+        return deviceLedgerService.updateDeviceLedger(deviceLedgerDto);
     }
 
     @DeleteMapping("/{ids}")
@@ -74,7 +73,7 @@
     @PostMapping("export")
     @Operation(summary = "瀵煎嚭璁惧鍙拌处")
     public void export(HttpServletResponse response, Long[] ids) {
-         deviceLedgerService.export(response, ids);
+        deviceLedgerService.export(response, ids);
     }
 
     @Operation(summary = "涓嬭浇妯℃澘")
@@ -97,9 +96,9 @@
 
     @GetMapping("getDeviceLedger")
     @Operation(summary = "鑾峰彇璁惧鍙拌处")
-    public AjaxResult getDeviceLedger( ) {
+    public AjaxResult getDeviceLedger() {
         return AjaxResult.success(deviceLedgerService.list(new QueryWrapper<DeviceLedger>().lambda()
-                .select(DeviceLedger::getId, DeviceLedger::getDeviceName,DeviceLedger::getDeviceModel)));
+                .select(DeviceLedger::getId, DeviceLedger::getDeviceName, DeviceLedger::getDeviceModel)));
     }
 
     @GetMapping("scanDevice")
@@ -108,8 +107,8 @@
     public AjaxResult scanDevice(Long id) {
         List<DeviceMaintenance> list = deviceMaintenanceMapper.list1(id);
         DeviceLedger deviceLedger = deviceLedgerMapper.selectById1(id);
-        if (list.size()>0){
-            deviceLedger.setUpdateTime(list.get(0).getMaintenanceActuallyTime());//鏈�鍚庣淮鎶ゆ椂闂�
+        if (!list.isEmpty()) {
+            deviceLedger.setUpdateTime(list.getFirst().getMaintenanceActuallyTime());//鏈�鍚庣淮鎶ゆ椂闂�
         }
         deviceLedger.setCreateTime(deviceLedger.getUpdateTime().plusMonths(1));//涓嬫缁存姢鏃堕棿
         return AjaxResult.success(deviceLedger);
diff --git a/src/main/java/com/ruoyi/device/dto/DeviceLedgerDto.java b/src/main/java/com/ruoyi/device/dto/DeviceLedgerDto.java
index 79e0aff..8ceb915 100644
--- a/src/main/java/com/ruoyi/device/dto/DeviceLedgerDto.java
+++ b/src/main/java/com/ruoyi/device/dto/DeviceLedgerDto.java
@@ -12,6 +12,9 @@
 import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.util.List;
+import com.ruoyi.basic.dto.StorageBlobDTO;
+import com.ruoyi.basic.dto.StorageBlobVO;
 
 /**
  * 璁惧鍙拌处瀹炰綋绫�
@@ -55,6 +58,20 @@
     private String supplierName;
 
     /**
+     * 璁惧闄勪欢(鐢ㄤ簬鎺ユ敹)
+     */
+    @TableField(exist = false)
+    @Schema(description = "璁惧闄勪欢鎺ユ敹鍒楄〃")
+    private List<StorageBlobDTO> storageBlobDTOs;
+
+    /**
+     * 璁惧闄勪欢(鐢ㄤ簬杩斿洖)
+     */
+    @TableField(exist = false)
+    @Schema(description = "璁惧闄勪欢灞曠ず鍒楄〃")
+    private List<StorageBlobVO> storageBlobVOs;
+
+    /**
      * 鍗曚綅
      */
     private String unit;
diff --git a/src/main/java/com/ruoyi/device/service/IDeviceLedgerService.java b/src/main/java/com/ruoyi/device/service/IDeviceLedgerService.java
index d34ea65..78dfcac 100644
--- a/src/main/java/com/ruoyi/device/service/IDeviceLedgerService.java
+++ b/src/main/java/com/ruoyi/device/service/IDeviceLedgerService.java
@@ -14,9 +14,11 @@
 public interface IDeviceLedgerService  extends IService<DeviceLedger> {
     IPage<DeviceLedgerDto> queryPage(Page page, DeviceLedgerDto deviceLedger);
 
-    AjaxResult saveDeviceLedger(DeviceLedger deviceLedger);
+    AjaxResult saveDeviceLedger(DeviceLedgerDto deviceLedgerDto);
 
-    AjaxResult updateDeviceLedger(DeviceLedger deviceLedger);
+    AjaxResult updateDeviceLedger(DeviceLedgerDto deviceLedgerDto);
+
+    DeviceLedgerDto getDeviceLedgerDetail(Long id);
 
     void export(HttpServletResponse response, Long[] ids);
 
diff --git a/src/main/java/com/ruoyi/device/service/impl/DeviceLedgerServiceImpl.java b/src/main/java/com/ruoyi/device/service/impl/DeviceLedgerServiceImpl.java
index b4c5d65..154923d 100644
--- a/src/main/java/com/ruoyi/device/service/impl/DeviceLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/device/service/impl/DeviceLedgerServiceImpl.java
@@ -12,6 +12,9 @@
 import com.ruoyi.device.execl.DeviceLedgerExeclDto;
 import com.ruoyi.device.mapper.DeviceLedgerMapper;
 import com.ruoyi.device.pojo.DeviceLedger;
+import com.ruoyi.basic.dto.StorageAttachmentDTO;
+import com.ruoyi.basic.enums.RecordTypeEnum;
+import com.ruoyi.basic.service.StorageAttachmentService;
 import com.ruoyi.device.service.IDeviceLedgerService;
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.project.system.domain.SysUser;
@@ -36,6 +39,7 @@
 
     private final DeviceLedgerMapper deviceLedgerMapper;
     private final SysUserMapper sysUserMapper;
+    private final StorageAttachmentService storageAttachmentService;
 
     @Override
     public IPage<DeviceLedgerDto> queryPage(Page page, DeviceLedgerDto deviceLedger) {
@@ -44,25 +48,61 @@
     }
 
     @Override
-    public AjaxResult saveDeviceLedger(DeviceLedger deviceLedger) {
+    public AjaxResult saveDeviceLedger(DeviceLedgerDto deviceLedgerDto) {
         LambdaQueryWrapper<DeviceLedger> deviceLedgerLambdaQueryWrapper = new LambdaQueryWrapper<>();
-        deviceLedgerLambdaQueryWrapper.eq(DeviceLedger::getDeviceName,deviceLedger.getDeviceName());
+        deviceLedgerLambdaQueryWrapper.eq(DeviceLedger::getDeviceName,deviceLedgerDto.getDeviceName());
         if (this.count(deviceLedgerLambdaQueryWrapper) > 0) {
             return AjaxResult.error("璁惧鍚嶇О宸插瓨鍦�");
         }
+        DeviceLedger deviceLedger = new DeviceLedger();
+        BeanUtils.copyProperties(deviceLedgerDto, deviceLedger);
         boolean save = this.save(deviceLedger);
         if (save){
+            if (deviceLedgerDto.getStorageBlobDTOs() != null) {
+                StorageAttachmentDTO attachmentDTO = new StorageAttachmentDTO();
+                attachmentDTO.setApplication("image");
+                attachmentDTO.setRecordType(RecordTypeEnum.DEVICE_LEDGER.getType());
+                attachmentDTO.setRecordId(deviceLedger.getId());
+                attachmentDTO.setStorageBlobDTOs(deviceLedgerDto.getStorageBlobDTOs());
+                storageAttachmentService.saveStorageAttachment(attachmentDTO);
+            }
             return AjaxResult.success();
         }
         return AjaxResult.error();
     }
 
     @Override
-    public AjaxResult updateDeviceLedger(DeviceLedger deviceLedger) {
+    public AjaxResult updateDeviceLedger(DeviceLedgerDto deviceLedgerDto) {
+        DeviceLedger deviceLedger = new DeviceLedger();
+        BeanUtils.copyProperties(deviceLedgerDto, deviceLedger);
         if (this.updateById(deviceLedger)) {
+            if (deviceLedgerDto.getStorageBlobDTOs() != null) {
+                StorageAttachmentDTO attachmentDTO = new StorageAttachmentDTO();
+                attachmentDTO.setApplication("image");
+                attachmentDTO.setRecordType(RecordTypeEnum.DEVICE_LEDGER.getType());
+                attachmentDTO.setRecordId(deviceLedger.getId());
+                attachmentDTO.setStorageBlobDTOs(deviceLedgerDto.getStorageBlobDTOs());
+                storageAttachmentService.saveStorageAttachment(attachmentDTO);
+            }
             return AjaxResult.success();
         }
         return AjaxResult.error();
+    }
+
+    @Override
+    public DeviceLedgerDto getDeviceLedgerDetail(Long id) {
+        DeviceLedger deviceLedger = this.getById(id);
+        if (deviceLedger != null) {
+            DeviceLedgerDto deviceLedgerDto = new DeviceLedgerDto();
+            BeanUtils.copyProperties(deviceLedger, deviceLedgerDto);
+            StorageAttachmentDTO dto = new StorageAttachmentDTO();
+            dto.setRecordType(RecordTypeEnum.DEVICE_LEDGER.getType());
+            dto.setRecordId(id);
+            dto.setApplication("image");
+            deviceLedgerDto.setStorageBlobVOs(storageAttachmentService.list(dto));
+            return deviceLedgerDto;
+        }
+        return null;
     }
 
     @Override
@@ -82,9 +122,7 @@
             util.exportExcel(response, deviceLedgerExeclDtos, "璁惧鍙拌处瀵煎嚭");
         }else  {
             ArrayList<Long> arrayList = new ArrayList<>();
-            Arrays.stream(ids).map(id -> {
-                return arrayList.add( id);
-            });
+            Arrays.stream(ids).map(arrayList::add);
             List<DeviceLedger> supplierManageList = deviceLedgerMapper.selectBatchIds(arrayList);
             ArrayList<DeviceLedgerExeclDto> deviceLedgerExeclDtos = new ArrayList<>();
             supplierManageList.stream().forEach(deviceLedger -> {
@@ -116,7 +154,10 @@
             deviceLedger.setTaxIncludingPriceTotal(c.getTaxIncludingPriceUnit());
             deviceLedger.setNumber(BigDecimal.ONE);
             deviceLedger.setPlanRuntimeTime(DateUtils.toLocalDate(c.getPlanRuntimeTime()));
-            deviceLedger.setUnTaxIncludingPriceTotal(deviceLedger.getTaxIncludingPriceTotal().divide(BigDecimal.ONE.add(c.getTaxRate()),2, RoundingMode.HALF_UP));
+            // 璁$畻涓嶅惈绋庢�讳环锛屽鐞嗙┖鍊兼儏鍐�
+            if (deviceLedger.getTaxIncludingPriceTotal() != null && c.getTaxRate() != null) {
+                deviceLedger.setUnTaxIncludingPriceTotal(deviceLedger.getTaxIncludingPriceTotal().divide(BigDecimal.ONE.add(c.getTaxRate()), 2, RoundingMode.HALF_UP));
+            }
             deviceLedgerMapper.insert(deviceLedger);
         });
 
diff --git a/src/main/java/com/ruoyi/home/dto/StatisticsReceivablePayableDto.java b/src/main/java/com/ruoyi/home/dto/StatisticsReceivablePayableDto.java
index a16390c..4f1509b 100644
--- a/src/main/java/com/ruoyi/home/dto/StatisticsReceivablePayableDto.java
+++ b/src/main/java/com/ruoyi/home/dto/StatisticsReceivablePayableDto.java
@@ -19,10 +19,10 @@
     @Schema(description = "搴斾粯閲戦")
     private BigDecimal payableMoney;
 
-    @Schema(description = "棰勬敹閲戦")
+    @Schema(description = "鏀舵閲戦")
     private BigDecimal advanceMoney;
 
-    @Schema(description = "棰勪粯閲戦")
+    @Schema(description = "浠樻閲戦")
     private BigDecimal prepayMoney;
 
 }
diff --git a/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java b/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
index a17c012..d3c21a2 100644
--- a/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
+++ b/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -3,8 +3,20 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.purchase.PurchaseInboundDto;
+import com.ruoyi.account.bean.dto.purchase.PurchaseReturnDto;
+import com.ruoyi.account.bean.dto.sales.SalesOutboundDto;
+import com.ruoyi.account.bean.dto.sales.SalesReturnDto;
+import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseReturnVo;
+import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
+import com.ruoyi.account.bean.vo.sales.SalesReturnVo;
+import com.ruoyi.account.mapper.AccountStatementMapper;
 import com.ruoyi.account.mapper.purchase.AccountPurchasePaymentMapper;
 import com.ruoyi.account.mapper.sales.AccountSalesCollectionMapper;
+import com.ruoyi.account.pojo.purchase.AccountPurchasePayment;
+import com.ruoyi.account.pojo.sales.AccountSalesCollection;
 import com.ruoyi.approve.mapper.ApproveProcessMapper;
 import com.ruoyi.approve.pojo.ApproveProcess;
 import com.ruoyi.basic.mapper.CustomerMapper;
@@ -25,11 +37,13 @@
 import com.ruoyi.home.dto.*;
 import com.ruoyi.home.mapper.HomeMapper;
 import com.ruoyi.home.service.HomeService;
+import com.ruoyi.procurementrecord.mapper.ReturnManagementMapper;
 import com.ruoyi.production.bean.dto.ProductionProductOutputDto;
 import com.ruoyi.production.mapper.*;
 import com.ruoyi.project.system.domain.SysDept;
 import com.ruoyi.project.system.mapper.SysDeptMapper;
 import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
+import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
 import com.ruoyi.quality.mapper.QualityInspectMapper;
 import com.ruoyi.quality.mapper.QualityUnqualifiedMapper;
@@ -41,7 +55,9 @@
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.staff.mapper.StaffOnJobMapper;
 import com.ruoyi.staff.pojo.StaffOnJob;
+import com.ruoyi.stock.mapper.StockInRecordMapper;
 import com.ruoyi.stock.mapper.StockInventoryMapper;
+import com.ruoyi.stock.mapper.StockOutRecordMapper;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -67,6 +83,10 @@
 public class HomeServiceImpl implements HomeService {
 
     private final SalesLedgerMapper salesLedgerMapper;
+    private final StockOutRecordMapper stockOutRecordMapper;
+    private final ReturnManagementMapper returnManagementMapper;
+    private final StockInRecordMapper stockInRecordMapper;
+    private final PurchaseReturnOrdersMapper purchaseReturnOrdersMapper;
 
     private final PurchaseLedgerMapper purchaseLedgerMapper;
 
@@ -104,6 +124,7 @@
 
     private final AccountPurchasePaymentMapper accountPurchasePaymentMapper;
     private final AccountSalesCollectionMapper accountSalesCollectionMapper;
+    private final AccountStatementMapper accountStatementMapper;
 
     private final ProductionAccountMapper productionAccountMapper;
 
@@ -292,19 +313,35 @@
             queryWrapper.ge(QualityInspect::getCheckTime, monthStart.toString())
                     .le(QualityInspect::getCheckTime, monthEnd.toString());
             List<QualityInspect> monthInspects = qualityStatisticsMapper.selectList(queryWrapper);
+
+            // 缁熻鎬绘暟閲忥紙鍚堟牸鏁伴噺 + 涓嶅悎鏍兼暟閲忥級
             BigDecimal reduce = monthInspects.stream()
                     .filter(inspect -> inspect.getInspectType().equals(0))
-                    .map(QualityInspect::getQuantity)
+                    .map(inspect -> {
+                        BigDecimal qualified = inspect.getQualifiedQuantity() != null ? inspect.getQualifiedQuantity() : BigDecimal.ZERO;
+                        BigDecimal unqualified = inspect.getUnqualifiedQuantity() != null ? inspect.getUnqualifiedQuantity() : BigDecimal.ZERO;
+                        return qualified.add(unqualified);
+                    })
                     .reduce(BigDecimal.ZERO, BigDecimal::add);
             supplierNum = supplierNum.add(reduce);
+
             BigDecimal reduce1 = monthInspects.stream()
                     .filter(inspect -> inspect.getInspectType().equals(1))
-                    .map(QualityInspect::getQuantity)
+                    .map(inspect -> {
+                        BigDecimal qualified = inspect.getQualifiedQuantity() != null ? inspect.getQualifiedQuantity() : BigDecimal.ZERO;
+                        BigDecimal unqualified = inspect.getUnqualifiedQuantity() != null ? inspect.getUnqualifiedQuantity() : BigDecimal.ZERO;
+                        return qualified.add(unqualified);
+                    })
                     .reduce(BigDecimal.ZERO, BigDecimal::add);
             processNum = processNum.add(reduce1);
+
             BigDecimal reduce2 = monthInspects.stream()
                     .filter(inspect -> inspect.getInspectType().equals(2))
-                    .map(QualityInspect::getQuantity)
+                    .map(inspect -> {
+                        BigDecimal qualified = inspect.getQualifiedQuantity() != null ? inspect.getQualifiedQuantity() : BigDecimal.ZERO;
+                        BigDecimal unqualified = inspect.getUnqualifiedQuantity() != null ? inspect.getUnqualifiedQuantity() : BigDecimal.ZERO;
+                        return qualified.add(unqualified);
+                    })
                     .reduce(BigDecimal.ZERO, BigDecimal::add);
             factoryNum = factoryNum.add(reduce2);
 
@@ -314,25 +351,22 @@
 
             // 1. 渚涘簲鍟嗘楠岋紙绫诲瀷0锛�- 鍚堟牸鏁伴噺
             BigDecimal supplierQualified = monthInspects.stream()
-                    .filter(inspect -> inspect.getInspectType().equals(0)
-                            && "鍚堟牸".equals(inspect.getCheckResult()))
-                    .map(QualityInspect::getQuantity)
+                    .filter(inspect -> inspect.getInspectType().equals(0))
+                    .map(inspect -> inspect.getQualifiedQuantity() != null ? inspect.getQualifiedQuantity() : BigDecimal.ZERO)
                     .reduce(BigDecimal.ZERO, BigDecimal::add);
             item.setSupplierNum(supplierQualified);
 
             // 2. 宸ュ簭妫�楠岋紙绫诲瀷1锛�- 鍚堟牸鏁伴噺
             BigDecimal processQualified = monthInspects.stream()
-                    .filter(inspect -> inspect.getInspectType().equals(1)
-                            && "鍚堟牸".equals(inspect.getCheckResult()))
-                    .map(QualityInspect::getQuantity)
+                    .filter(inspect -> inspect.getInspectType().equals(1))
+                    .map(inspect -> inspect.getQualifiedQuantity() != null ? inspect.getQualifiedQuantity() : BigDecimal.ZERO)
                     .reduce(BigDecimal.ZERO, BigDecimal::add);
             item.setProcessNum(processQualified);
 
             // 3. 宸ュ巶妫�楠岋紙绫诲瀷2锛�- 鍚堟牸鏁伴噺
             BigDecimal factoryQualified = monthInspects.stream()
-                    .filter(inspect -> inspect.getInspectType().equals(2)
-                            && "鍚堟牸".equals(inspect.getCheckResult()))
-                    .map(QualityInspect::getQuantity)
+                    .filter(inspect -> inspect.getInspectType().equals(2))
+                    .map(inspect -> inspect.getQualifiedQuantity() != null ? inspect.getQualifiedQuantity() : BigDecimal.ZERO)
                     .reduce(BigDecimal.ZERO, BigDecimal::add);
             item.setFactoryNum(factoryQualified);
 
@@ -394,43 +428,33 @@
      */
     @Override
     public StatisticsReceivablePayableDto statisticsReceivablePayable(Integer type) {
-        StatisticsReceivablePayableDto statisticsReceivablePayableDto = new StatisticsReceivablePayableDto();
-        LocalDate today = LocalDate.now();
-        LocalDate startDate = null;
-        LocalDate endDate = null;
-        switch (type) {
-            case 1:
-                // 鑾峰彇鏈懆鍛ㄤ竴
-                startDate = today.with(DayOfWeek.MONDAY);
-                // 鑾峰彇鏈懆鍛ㄦ棩
-                endDate = today.with(DayOfWeek.SUNDAY);
-                break;
-            case 2:
-                startDate = today.with(TemporalAdjusters.firstDayOfMonth());
-                endDate = today.with(TemporalAdjusters.lastDayOfMonth());
-                break;
-            case 3:
-                Month currentMonth = today.getMonth();
-                Month firstMonthOfQuarter = currentMonth.firstMonthOfQuarter();
-                Month lastMonthOfQuarter = Month.of(firstMonthOfQuarter.getValue() + 2);
+        StatisticsReceivablePayableDto dto = new StatisticsReceivablePayableDto();
+        LocalDate[] range = resolveFinanceRange(type);
+        LocalDate startDate = range[0];
+        LocalDate endDate = range[1];
 
-                startDate = today.withMonth(firstMonthOfQuarter.getValue())
-                        .with(TemporalAdjusters.firstDayOfMonth());
-                endDate = today.withMonth(lastMonthOfQuarter.getValue())
-                        .with(TemporalAdjusters.lastDayOfMonth());
-                break;
-        }
-        // 搴旀敹
+        //閿�鍞嚭搴�
+        BigDecimal receivableBase = sumSalesContractAmount(startDate, endDate);
+        //閿�鍞��璐�
+        BigDecimal salesReturnAmount = sumSalesReturnAmount(startDate, endDate);
+        //閲囪喘鍏ュ簱
+        BigDecimal payableBase = sumPurchaseContractAmount(startDate, endDate);
+        //閲囪喘閫�璐�
+        BigDecimal purchaseReturnAmount = sumPurchaseReturnAmount(startDate, endDate);
+        //鏀舵
+        BigDecimal advanceMoney = sumCollectionAmount(startDate, endDate);
+        //浠樻
+        BigDecimal prepayMoney = sumPaymentAmount(startDate, endDate);
 
-        // 搴斾粯
-
-        // 棰勬敹
-
-        // 棰勪粯
-
-
-
-        return statisticsReceivablePayableDto;
+        //搴旀敹閲戦=閿�鍞嚭搴�-閿�鍞��璐�
+        dto.setReceivableMoney(scaleMoney(maxZero(receivableBase.subtract(salesReturnAmount))));
+        //搴斾粯閲戦=閲囪喘鍏ュ簱-閲囪喘閫�璐�
+        dto.setPayableMoney(scaleMoney(maxZero(payableBase.subtract(purchaseReturnAmount))));
+        //鏀舵閲戦=鏀舵鍗�
+        dto.setAdvanceMoney(scaleMoney(advanceMoney));
+        //浠樻閲戦=浠樻鍗�
+        dto.setPrepayMoney(scaleMoney(prepayMoney));
+        return dto;
     }
 
     public static <T> BigDecimal sumAmount(List<T> list, java.util.function.Function<T, BigDecimal> amountExtractor) {
@@ -1239,102 +1263,55 @@
     @Override
     public MonthlyIncomeDto monthlyIncome() {
         MonthlyIncomeDto dto = new MonthlyIncomeDto();
-        LocalDate now = LocalDate.now();
-        YearMonth currentMonth = YearMonth.from(now);
-        LocalDateTime startOfMonth = currentMonth.atDay(1).atStartOfDay();
-        LocalDateTime endOfMonth = currentMonth.atEndOfMonth().atTime(23, 59, 59);
-
-        LambdaQueryWrapper<SalesLedgerProduct> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(SalesLedgerProduct::getType, 1);
-        wrapper.ge(SalesLedgerProduct::getRegisterDate, startOfMonth);
-        wrapper.le(SalesLedgerProduct::getRegisterDate, endOfMonth);
-
-        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(wrapper);
-
-        if (CollectionUtils.isEmpty(products)) {
-            return dto;
-        }
-
+        LocalDate today = LocalDate.now();
+        YearMonth currentMonth = YearMonth.from(today);
+        LocalDate startDate = currentMonth.atDay(1);
+        LocalDate endDate = currentMonth.atEndOfMonth();
+        //鏀舵
+        BigDecimal monthlyIncome = sumCollectionAmount(startDate, endDate);
+        //閿�鍞嚭搴�
+        BigDecimal receivableBase = sumSalesContractAmount(startDate, endDate);
+        //閿�鍞��璐�
+        BigDecimal salesReturnAmount = sumSalesReturnAmount(startDate, endDate);
+        //鍥炴鐜�=鏀舵/(閿�鍞嚭搴�-閿�鍞��璐�)搴旀敹
+        String collectionRate = toRateString(monthlyIncome, receivableBase.subtract(salesReturnAmount));
+        //閫炬湡鏁�=(閿�鍞嚭搴撻噾棰�-閿�鍞��璐ч噾棰�)搴旀敹閲戦-鏀舵閲戦
+        BigDecimal overdueAmount = receivableBase.subtract(salesReturnAmount).subtract(monthlyIncome);
+        //閫炬湡鐜�=閫炬湡鏁�/搴旀敹閲戦
+        String overdueRate = toRateString(overdueAmount, receivableBase);
+        dto.setMonthlyIncome(scaleMoney(monthlyIncome));
+        dto.setCollectionRate(collectionRate);
+        dto.setOverdueNum(overdueAmount);
+        dto.setOverdueRate(overdueRate);
         return dto;
     }
 
+    @Override
     public MonthlyExpenditureDto monthlyExpenditure() {
-
         MonthlyExpenditureDto dto = new MonthlyExpenditureDto();
+        LocalDate today = LocalDate.now();
+        YearMonth currentMonth = YearMonth.from(today);
+        LocalDate startDate = currentMonth.atDay(1);
+        LocalDate endDate = currentMonth.atEndOfMonth();
+        //鏀嚭
+        BigDecimal monthlyExpenditure = sumPaymentAmount(startDate, endDate);
+        //閲囪喘鍏ュ簱
+        BigDecimal payableBase = sumPurchaseContractAmount(startDate, endDate);
+        //閲囪喘閫�璐�
+        BigDecimal purchaseReturnAmount = sumPurchaseReturnAmount(startDate, endDate);
+        //浠樻鐜�=浠樻/(閲囪喘鍏ュ簱-閲囪喘閫�璐�)搴斾粯
+        String paymentRate = toRateString(monthlyExpenditure, payableBase.subtract(purchaseReturnAmount));
+        //鏀舵
+        BigDecimal monthlyIncome = sumCollectionAmount(startDate, endDate);
+        //姣涘埄娑�= 鏀舵-鏀嚭
+        BigDecimal grossProfit = monthlyIncome.subtract(monthlyExpenditure);
+        //鍒╂鼎鐜�=姣涘埄娑�/鏀舵
+        String profitMarginRate = toRateString(grossProfit, monthlyIncome);
 
-        // 褰撴湀鏃堕棿鑼冨洿
-        LocalDate now = LocalDate.now();
-        YearMonth currentMonth = YearMonth.from(now);
-        LocalDateTime startOfMonth = currentMonth.atDay(1).atStartOfDay();
-        LocalDateTime endOfMonth = currentMonth.atEndOfMonth().atTime(23, 59, 59);
-
-        // 閲囪喘鍙拌处锛坱ype = 2锛�
-        LambdaQueryWrapper<SalesLedgerProduct> purchaseWrapper = new LambdaQueryWrapper<>();
-        purchaseWrapper.eq(SalesLedgerProduct::getType, 2);
-        purchaseWrapper.ge(SalesLedgerProduct::getRegisterDate, startOfMonth);
-        purchaseWrapper.le(SalesLedgerProduct::getRegisterDate, endOfMonth);
-
-        List<SalesLedgerProduct> purchaseProducts = salesLedgerProductMapper.selectList(purchaseWrapper);
-
-        BigDecimal rawMaterialCost = BigDecimal.ZERO; // 鍘熸潗鏂欐垚鏈�
-        BigDecimal paidAmount = BigDecimal.ZERO; // 宸蹭粯娆鹃噾棰�
-        BigDecimal pendingAmount = BigDecimal.ZERO; // 寰呬粯娆鹃噾棰�
-
-        if (!CollectionUtils.isEmpty(purchaseProducts)) {
-            for (SalesLedgerProduct p : purchaseProducts) {
-
-                if (p.getTaxInclusiveTotalPrice() != null) {
-                    rawMaterialCost = rawMaterialCost.add(p.getTaxInclusiveTotalPrice());
-                }
-            }
-        }
-
-        // 鍏朵粬璐圭敤
-
-
-        // 鏈堝害鎬绘敮鍑�
-        BigDecimal monthlyExpenditure = BigDecimal.ZERO;
-        dto.setMonthlyExpenditure(monthlyExpenditure);
-
-        // 宸蹭粯娆� 梅锛堝凡浠樻 + 寰呬粯娆撅級
-        BigDecimal totalPayable = paidAmount.add(pendingAmount);
-        if (totalPayable.compareTo(BigDecimal.ZERO) > 0) {
-            String paymentRate = paidAmount
-                    .divide(totalPayable, 4, RoundingMode.HALF_UP)
-                    .multiply(BigDecimal.valueOf(100))
-                    .setScale(2, RoundingMode.HALF_UP)
-                    .toString();
-            dto.setPaymentRate(paymentRate);
-        }
-
-        // 鍞彴璐︼紙type = 1锛�
-        LambdaQueryWrapper<SalesLedgerProduct> salesWrapper = new LambdaQueryWrapper<>();
-        salesWrapper.eq(SalesLedgerProduct::getType, 1);
-        salesWrapper.ge(SalesLedgerProduct::getRegisterDate, startOfMonth);
-        salesWrapper.le(SalesLedgerProduct::getRegisterDate, endOfMonth);
-
-        List<SalesLedgerProduct> salesProducts = salesLedgerProductMapper.selectList(salesWrapper);
-
-        BigDecimal revenue = BigDecimal.ZERO;
-
-        // 姣涘埄娑� & 鍒╂鼎鐜�
-        if (revenue.compareTo(BigDecimal.ZERO) > 0) {
-
-            // 姣涘埄娑� = 閿�鍞敹鍏� - 鍘熸潗鏂欐垚鏈�
-            BigDecimal grossProfit = revenue.subtract(rawMaterialCost);
-            dto.setGrossProfit(grossProfit);
-
-            // 鍒╂鼎鐜� = (閿�鍞敹鍏� - 鏈堝害鎬绘敮鍑�) / 閿�鍞敹鍏�
-            BigDecimal profit = revenue.subtract(monthlyExpenditure);
-            String profitMarginRate = profit
-                    .divide(revenue, 4, RoundingMode.HALF_UP)
-                    .multiply(BigDecimal.valueOf(100))
-                    .setScale(2, RoundingMode.HALF_UP)
-                    .toString();
-
-            dto.setProfitMarginRate(profitMarginRate);
-        }
-
+        dto.setMonthlyExpenditure(scaleMoney(monthlyExpenditure));
+        dto.setPaymentRate(paymentRate);
+        dto.setGrossProfit(scaleMoney(grossProfit));
+        dto.setProfitMarginRate(profitMarginRate);
         return dto;
     }
 
@@ -1773,11 +1750,8 @@
         BigDecimal unqualifiedCount = BigDecimal.ZERO;
 
         for (QualityInspect item : list) {
-            if ("鍚堟牸".equals(item.getCheckResult())) {
-                qualifiedCount = qualifiedCount.add(item.getQuantity());
-            } else {
-                unqualifiedCount = unqualifiedCount.add(item.getQuantity());
-            }
+            qualifiedCount = qualifiedCount.add(item.getQualifiedQuantity() != null ? item.getQualifiedQuantity() : BigDecimal.ZERO);
+            unqualifiedCount = unqualifiedCount.add(item.getUnqualifiedQuantity() != null ? item.getUnqualifiedQuantity() : BigDecimal.ZERO);
         }
 
         BigDecimal totalCount = qualifiedCount.add(unqualifiedCount);
@@ -2046,13 +2020,11 @@
                 continue;
             }
 
-            BigDecimal quantity = item.getQuantity();
+            BigDecimal qualifiedQty = item.getQualifiedQuantity() != null ? item.getQualifiedQuantity() : BigDecimal.ZERO;
+            BigDecimal unqualifiedQty = item.getUnqualifiedQuantity() != null ? item.getUnqualifiedQuantity() : BigDecimal.ZERO;
 
-            if ("鍚堟牸".equals(item.getCheckResult())) {
-                dto.setQualifiedCount(dto.getQualifiedCount().add(quantity));
-            } else {
-                dto.setUnqualifiedCount(dto.getUnqualifiedCount().add(quantity));
-            }
+            dto.setQualifiedCount(dto.getQualifiedCount().add(qualifiedQty));
+            dto.setUnqualifiedCount(dto.getUnqualifiedCount().add(unqualifiedQty));
         }
 
         // 璁$畻鍚堟牸鐜�
@@ -2093,14 +2065,12 @@
             BigDecimal unqualifiedCount = BigDecimal.ZERO;
 
             for (QualityInspect item : items) {
-                BigDecimal qty = item.getQuantity();
-                totalCount = totalCount.add(qty);
+                BigDecimal qualifiedQty = item.getQualifiedQuantity() != null ? item.getQualifiedQuantity() : BigDecimal.ZERO;
+                BigDecimal unqualifiedQty = item.getUnqualifiedQuantity() != null ? item.getUnqualifiedQuantity() : BigDecimal.ZERO;
 
-                if ("鍚堟牸".equals(item.getCheckResult())) {
-                    qualifiedCount = qualifiedCount.add(qty);
-                } else {
-                    unqualifiedCount = unqualifiedCount.add(qty);
-                }
+                totalCount = totalCount.add(qualifiedQty.add(unqualifiedQty));
+                qualifiedCount = qualifiedCount.add(qualifiedQty);
+                unqualifiedCount = unqualifiedCount.add(unqualifiedQty);
             }
 
             if (totalCount.compareTo(BigDecimal.ZERO) == 0) {
@@ -2229,13 +2199,17 @@
         dto.setProcessNum(sumQuantity(qualityInspectList, 1)); // 杩囩▼
         dto.setFactoryNum(sumQuantity(qualityInspectList, 2)); // 鍑哄巶
 
-        // 鍋囪 qualityInspectList 鏄竴涓� List<QualityInspect> 绫诲瀷鐨勯泦鍚�
-        Map<String, List<QualityInspect>> groupedByCheckResult = qualityInspectList.stream()
-                .collect(Collectors.groupingBy(QualityInspect::getCheckResult));
-        List<QualityInspect> qualityInspects = groupedByCheckResult.get("涓嶅悎鏍�");
-        if (ObjectUtils.isNull(qualityInspects) || qualityInspects.size() == 0) {
-            return null;
+        // 鏍规嵁 unqualifiedQuantity > 0 绛涢�変笉鍚堟牸璁板綍
+        List<QualityInspect> qualityInspects = qualityInspectList.stream()
+                .filter(i -> i.getUnqualifiedQuantity() != null && i.getUnqualifiedQuantity().compareTo(BigDecimal.ZERO) > 0)
+                .collect(Collectors.toList());
+
+        if (ObjectUtils.isEmpty(qualityInspects)) {
+            // 鍗充娇娌℃湁涓嶅悎鏍艰褰曪紝涔熷簲璇ヨ繑鍥炵粺璁℃暟鎹紝鍙槸鍥捐〃椤逛负绌�
+            dto.setItem(new ArrayList<>());
+            return dto;
         }
+
         // 4. 澶勭悊鍥捐〃椤� (Item)
         List<QualityStatisticsItem> itemList = new ArrayList<>();
 
@@ -2278,8 +2252,11 @@
     private BigDecimal sumQuantity(List<QualityInspect> list, Integer type) {
         return list.stream()
                 .filter(i -> i.getInspectType().equals(type))
-                .map(QualityInspect::getQuantity)
-                .filter(Objects::nonNull)
+                .map(i -> {
+                    BigDecimal qualified = i.getQualifiedQuantity() != null ? i.getQualifiedQuantity() : BigDecimal.ZERO;
+                    BigDecimal unqualified = i.getUnqualifiedQuantity() != null ? i.getUnqualifiedQuantity() : BigDecimal.ZERO;
+                    return qualified.add(unqualified);
+                })
                 .reduce(BigDecimal.ZERO, BigDecimal::add);
     }
 
@@ -2287,11 +2264,18 @@
         QualityStatisticsItem item = new QualityStatisticsItem();
         item.setDate(dateLabel);
 
-        item.setSupplierNum(list.stream().filter(i -> i.getInspectType() == 0).map(QualityInspect::getQuantity)
+        // 缁熻姣忕妫�楠岀被鍨嬬殑涓嶅悎鏍兼暟閲�
+        item.setSupplierNum(list.stream()
+                .filter(i -> i.getInspectType() == 0)
+                .map(i -> i.getUnqualifiedQuantity() != null ? i.getUnqualifiedQuantity() : BigDecimal.ZERO)
                 .reduce(BigDecimal.ZERO, BigDecimal::add));
-        item.setProcessNum(list.stream().filter(i -> i.getInspectType() == 1).map(QualityInspect::getQuantity)
+        item.setProcessNum(list.stream()
+                .filter(i -> i.getInspectType() == 1)
+                .map(i -> i.getUnqualifiedQuantity() != null ? i.getUnqualifiedQuantity() : BigDecimal.ZERO)
                 .reduce(BigDecimal.ZERO, BigDecimal::add));
-        item.setFactoryNum(list.stream().filter(i -> i.getInspectType() == 2).map(QualityInspect::getQuantity)
+        item.setFactoryNum(list.stream()
+                .filter(i -> i.getInspectType() == 2)
+                .map(i -> i.getUnqualifiedQuantity() != null ? i.getUnqualifiedQuantity() : BigDecimal.ZERO)
                 .reduce(BigDecimal.ZERO, BigDecimal::add));
 
         return item;
@@ -2331,6 +2315,121 @@
         return productionOperationTaskMapper.calculateProductionStatistics(startDateTime, endDateTime, userId, processIds);
     }
 
+    private LocalDate[] resolveFinanceRange(Integer type) {
+        LocalDate today = LocalDate.now();
+        int safeType = type == null ? 1 : type;
+        LocalDate startDate;
+        LocalDate endDate;
+        switch (safeType) {
+            case 1:
+                startDate = today.with(DayOfWeek.MONDAY);
+                endDate = today.with(DayOfWeek.SUNDAY);
+                break;
+            case 2:
+                startDate = today.with(TemporalAdjusters.firstDayOfMonth());
+                endDate = today.with(TemporalAdjusters.lastDayOfMonth());
+                break;
+            case 3:
+                Month firstMonthOfQuarter = today.getMonth().firstMonthOfQuarter();
+                startDate = LocalDate.of(today.getYear(), firstMonthOfQuarter, 1);
+                endDate = startDate.plusMonths(2).with(TemporalAdjusters.lastDayOfMonth());
+                break;
+            default:
+                startDate = today.with(DayOfWeek.MONDAY);
+                endDate = today.with(DayOfWeek.SUNDAY);
+                break;
+        }
+        return new LocalDate[]{startDate, endDate};
+    }
+
+    //璁$畻鏃ユ湡鍐呯殑閿�鍞嚭搴撻噾棰�
+    private BigDecimal sumSalesContractAmount(LocalDate startDate, LocalDate endDate) {
+        SalesOutboundDto salesOutboundDto = new SalesOutboundDto();
+        salesOutboundDto.setStartDate(startDate);
+        salesOutboundDto.setEndDate(endDate);
+        List<SalesOutboundVo> salesOutboundVos = stockOutRecordMapper.listPageAccountSales(new Page(1, -1), salesOutboundDto).getRecords();
+        return sumAmount(salesOutboundVos, SalesOutboundVo::getOutboundAmount);
+    }
+
+    //璁$畻鏃ユ湡鍐呯殑閿�鍞��璐ч噾棰�
+    private BigDecimal sumSalesReturnAmount(LocalDate startDate, LocalDate endDate) {
+        SalesReturnDto salesReturnDto = new SalesReturnDto();
+        salesReturnDto.setStartDate(startDate);
+        salesReturnDto.setEndDate(endDate);
+        List<SalesReturnVo> salesReturnVos = returnManagementMapper.listPageAccountSalesReturn(new Page(1, -1), salesReturnDto).getRecords();
+        return sumAmount(salesReturnVos, SalesReturnVo::getRefundAmount);
+    }
+
+    //璁$畻鏃ユ湡鍐呯殑閲囪喘鍏ュ簱閲戦
+    private BigDecimal sumPurchaseContractAmount(LocalDate startDate, LocalDate endDate) {
+        PurchaseInboundDto purchaseInboundDto = new PurchaseInboundDto();
+        purchaseInboundDto.setStartDate(startDate);
+        purchaseInboundDto.setEndDate(endDate);
+        List<PurchaseInboundVo> purchaseInboundVos = stockInRecordMapper.listPageAccountPurchase(new Page(1, -1), purchaseInboundDto).getRecords();
+        return sumAmount(purchaseInboundVos, PurchaseInboundVo::getInboundAmount);
+    }
+
+    //璁$畻鏃ユ湡鍐呯殑閲囪喘閫�璐ч噾棰�
+    private BigDecimal sumPurchaseReturnAmount(LocalDate startDate, LocalDate endDate) {
+        PurchaseReturnDto purchaseReturnDto = new PurchaseReturnDto();
+        purchaseReturnDto.setStartDate(startDate);
+        purchaseReturnDto.setEndDate(endDate);
+        List<PurchaseReturnVo> purchaseReturnVos = purchaseReturnOrdersMapper.listPageAccountPurchaseReturn(new Page(1, -1), purchaseReturnDto).getRecords();
+        return sumAmount(purchaseReturnVos, PurchaseReturnVo::getTotalAmount);
+    }
+
+    //璁$畻鏃ユ湡鍐呯殑鎬绘敹娆鹃噾棰�
+    private BigDecimal sumCollectionAmount(LocalDate startDate, LocalDate endDate) {
+        List<AccountSalesCollection> collections = defaultList(accountSalesCollectionMapper.selectList(
+                new LambdaQueryWrapper<AccountSalesCollection>()
+                        .ge(AccountSalesCollection::getCollectionDate, startDate)
+                        .le(AccountSalesCollection::getCollectionDate, endDate)));
+        return sumAmount(collections, AccountSalesCollection::getCollectionAmount);
+    }
+
+    //璁$畻鏃ユ湡鍐呯殑鎬讳粯娆鹃噾棰�
+    private BigDecimal sumPaymentAmount(LocalDate startDate, LocalDate endDate) {
+        List<AccountPurchasePayment> payments = defaultList(accountPurchasePaymentMapper.selectList(
+                new LambdaQueryWrapper<AccountPurchasePayment>()
+                        .ge(AccountPurchasePayment::getPaymentDate, startDate)
+                        .le(AccountPurchasePayment::getPaymentDate, endDate)));
+        return sumAmount(payments, AccountPurchasePayment::getPaymentAmount);
+    }
+
+    private Date toDate(LocalDate localDate) {
+        return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
+    }
+
+    private Date toExclusiveEndDate(LocalDate localDate) {
+        return Date.from(localDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
+    }
+
+    private String toRateString(BigDecimal numerator, BigDecimal denominator) {
+        if (denominator == null || denominator.compareTo(BigDecimal.ZERO) <= 0) {
+            return "0.00";
+        }
+        return defaultDecimal(numerator)
+                .divide(denominator, 4, RoundingMode.HALF_UP)
+                .multiply(BigDecimal.valueOf(100))
+                .setScale(2, RoundingMode.HALF_UP)
+                .toString();
+    }
+
+    private BigDecimal maxZero(BigDecimal value) {
+        if (value == null) {
+            return BigDecimal.ZERO;
+        }
+        return value.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : value;
+    }
+
+    private BigDecimal scaleMoney(BigDecimal value) {
+        return defaultDecimal(value).setScale(2, RoundingMode.HALF_UP);
+    }
+
+    private <T> List<T> defaultList(List<T> list) {
+        return list == null ? List.of() : list;
+    }
+
     private BigDecimal defaultDecimal(BigDecimal value) {
         return value == null ? BigDecimal.ZERO : value;
     }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
index c6256a8..0513bdc 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
@@ -311,7 +311,7 @@
             if (matchedOperation == null) {
                 matchedOperation = insertRoutingOperationSnapshot(orderRouting.getId(), productionOrderId, desiredOperation);
             } else {
-                updateRoutingOperationSnapshotIfNecessary(desiredOperation, orderRouting.getId(), productionOrderId, matchedOperation);
+                updateRoutingOperationSnapshotIfNecessary(matchedOperation, orderRouting.getId(), productionOrderId, desiredOperation);
             }
             finalOperationList.add(matchedOperation);
         }
@@ -382,17 +382,32 @@
         Map<Long, ProductionBomStructure> structureById = structureList.stream()
                 .filter(item -> item != null && item.getId() != null)
                 .collect(Collectors.toMap(ProductionBomStructure::getId, item -> item, (left, right) -> left));
-        Map<String, ProductionBomStructure> uniqueOperationMap = new LinkedHashMap<>();
-        for (ProductionBomStructure bomStructure : structureList) {
-            if (bomStructure == null || bomStructure.getTechnologyOperationId() == null) {
-                continue;
+
+        // 鏋勫缓鐖�-瀛愭槧灏勫叧绯�
+        Map<Long, List<ProductionBomStructure>> treeMap = buildParentChildMap(structureList);
+
+        // 浣跨敤鍚庡簭閬嶅巻鏋勫缓鎿嶄綔鍒楄〃锛堝厛瀛愬悗鐖讹紝纭繚宸ヨ壓璺嚎椤哄簭姝g‘锛�
+        // 浣跨敤娣卞害浣滀负鎺掑簭渚濇嵁鐨勮緟鍔╃粨鏋�
+        Map<String, ProductionBomStructure> operationMap = new LinkedHashMap<>();
+        Map<String, Integer> depthMap = new HashMap<>();
+        buildOperationListPostOrderWithDepth(null, treeMap, operationMap, depthMap, structureById, rootProductModelId, 1);
+
+        // 鎸夋繁搴︽帓搴忥紝娣卞害澶х殑鎺掑墠闈�
+        List<Map.Entry<String, ProductionBomStructure>> sortedEntries = new ArrayList<>(operationMap.entrySet());
+        sortedEntries.sort((a, b) -> {
+            int depthCompare = Integer.compare(
+                    depthMap.getOrDefault(b.getKey(), 0),
+                    depthMap.getOrDefault(a.getKey(), 0));
+            if (depthCompare != 0) {
+                return depthCompare;
             }
-            Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(bomStructure, structureById), rootProductModelId);
-            uniqueOperationMap.putIfAbsent(buildBomOperationDedupKey(bomStructure, outputProductModelId), bomStructure);
-        }
+            return 0;
+        });
+
         List<ProductionOrderRoutingOperation> desiredOperationList = new ArrayList<>();
         int dragSort = 1;
-        for (ProductionBomStructure bomStructure : uniqueOperationMap.values()) {
+        for (Map.Entry<String, ProductionBomStructure> entry : sortedEntries) {
+            ProductionBomStructure bomStructure = entry.getValue();
             Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(bomStructure, structureById), rootProductModelId);
             TechnologyOperation technologyOperation = getTechnologyOperation(bomStructure.getTechnologyOperationId());
             ProductionOrderRoutingOperation routingOperation = new ProductionOrderRoutingOperation();
@@ -406,6 +421,127 @@
             desiredOperationList.add(routingOperation);
         }
         return desiredOperationList;
+    }
+
+    private void buildOperationListPostOrderWithDepth(Long parentId,
+                                                      Map<Long, List<ProductionBomStructure>> treeMap,
+                                                      Map<String, ProductionBomStructure> operationMap,
+                                                      Map<String, Integer> depthMap,
+                                                      Map<Long, ProductionBomStructure> structureById,
+                                                      Long rootProductModelId,
+                                                      int currentDepth) {
+        List<ProductionBomStructure> children = treeMap.get(parentId);
+        if (children == null || children.isEmpty()) {
+            return;
+        }
+        for (ProductionBomStructure child : children) {
+            // 鍏堥�掑綊澶勭悊瀛愯妭鐐�
+            buildOperationListPostOrderWithDepth(child.getId(), treeMap, operationMap, depthMap, structureById, rootProductModelId, currentDepth + 1);
+
+            // 鍐嶅鐞嗗綋鍓嶈妭鐐�
+            if (child.getTechnologyOperationId() != null) {
+                Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(child, structureById), rootProductModelId);
+                String key = buildBomOperationDedupKey(child, outputProductModelId);
+                // 淇濈暀娣卞害鏈�澶х殑鎿嶄綔
+                Integer existingDepth = depthMap.get(key);
+                if (existingDepth == null || currentDepth > existingDepth) {
+                    operationMap.put(key, child);
+                    depthMap.put(key, currentDepth);
+                }
+            }
+        }
+    }
+
+    private Map<Long, List<ProductionBomStructure>> buildParentChildMap(List<ProductionBomStructure> structureList) {
+        Map<Long, List<ProductionBomStructure>> treeMap = new LinkedHashMap<>();
+        Map<Long, ProductionBomStructure> structureById = new HashMap<>();
+
+        // 鏋勫缓鐖�-瀛愭槧灏勫拰ID鏄犲皠
+        for (ProductionBomStructure structure : structureList) {
+            if (structure == null) continue;
+            Long parentId = structure.getParentId();
+            treeMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(structure);
+            if (structure.getId() != null) {
+                structureById.put(structure.getId(), structure);
+            }
+        }
+
+        // 璁$畻姣忎釜鑺傜偣鐨勬繁搴︼紙浠庢牴鑺傜偣鍒板綋鍓嶈妭鐐圭殑璺濈锛屾牴鑺傜偣娣卞害涓�1锛�
+        Map<Long, Integer> depthMap = new HashMap<>();
+        for (ProductionBomStructure structure : structureList) {
+            if (structure == null || structure.getId() == null) continue;
+            computeDepthFromRoot(structure.getId(), structureById, depthMap);
+        }
+
+        // 瀵规瘡涓埗鑺傜偣涓嬬殑瀛愯妭鐐规寜娣卞害鍊掑簭鎺掑簭锛堟渶娣卞眰鐨勪紭鍏堬級
+        for (Map.Entry<Long, List<ProductionBomStructure>> entry : treeMap.entrySet()) {
+            List<ProductionBomStructure> children = entry.getValue();
+            children.sort((a, b) -> {
+                // 浼樺厛鎸夋繁搴︽帓搴忥紝娣卞害澶х殑鎺掑墠闈紙鏈�娣卞眰浼樺厛锛�
+                int depthCompare = Integer.compare(
+                        depthMap.getOrDefault(b.getId(), 0),
+                        depthMap.getOrDefault(a.getId(), 0));
+                if (depthCompare != 0) {
+                    return depthCompare;
+                }
+                // 娣卞害鐩稿悓鏃舵寜ID鎺掑簭淇濊瘉绋冲畾鎬�
+                return Long.compare(a.getId(), b.getId());
+            });
+        }
+
+        return treeMap;
+    }
+
+    /**
+     * 璁$畻鑺傜偣娣卞害锛堜粠鏍硅妭鐐瑰埌褰撳墠鑺傜偣鐨勮窛绂伙級
+     * 鏍硅妭鐐规繁搴︿负1锛屾瘡鍚戜笅涓�灞傛繁搴﹀姞1
+     */
+    private int computeDepthFromRoot(Long nodeId, Map<Long, ProductionBomStructure> structureById, Map<Long, Integer> depthMap) {
+        if (depthMap.containsKey(nodeId)) {
+            return depthMap.get(nodeId);
+        }
+
+        ProductionBomStructure structure = structureById.get(nodeId);
+        if (structure == null) {
+            depthMap.put(nodeId, 1);
+            return 1;
+        }
+
+        Long parentId = structure.getParentId();
+        if (parentId == null || parentId == 0L) {
+            // 鏍硅妭鐐规繁搴︿负1
+            depthMap.put(nodeId, 1);
+            return 1;
+        }
+
+        // 瀛愯妭鐐规繁搴� = 鐖惰妭鐐规繁搴� + 1
+        int parentDepth = computeDepthFromRoot(parentId, structureById, depthMap);
+        int depth = parentDepth + 1;
+        depthMap.put(nodeId, depth);
+        return depth;
+    }
+
+    private void buildOperationListPostOrder(Long parentId,
+                                             Map<Long, List<ProductionBomStructure>> treeMap,
+                                             Map<String, ProductionBomStructure> uniqueOperationMap,
+                                             Map<Long, ProductionBomStructure> structureById,
+                                             Long rootProductModelId) {
+        List<ProductionBomStructure> children = treeMap.get(parentId);
+        if (children == null || children.isEmpty()) {
+            return;
+        }
+        for (ProductionBomStructure child : children) {
+            // 鍏堥�掑綊澶勭悊瀛愯妭鐐�
+            buildOperationListPostOrder(child.getId(), treeMap, uniqueOperationMap, structureById, rootProductModelId);
+
+            // 鍐嶅鐞嗗綋鍓嶈妭鐐�
+            if (child.getTechnologyOperationId() != null) {
+                Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(child, structureById), rootProductModelId);
+                String key = buildBomOperationDedupKey(child, outputProductModelId);
+                // 鍘婚噸鏃朵繚鐣欐繁搴︽渶澶х殑鎿嶄綔锛堝悗搴忛亶鍘嗗厛閬囧埌娣卞眰鑺傜偣锛屾墍浠ョ洿鎺ヨ鐩栧嵆鍙級
+                uniqueOperationMap.put(key, child);
+            }
+        }
     }
 
     private Map<String, Deque<ProductionOrderRoutingOperation>> buildExistingRoutingOperationBucketMap(List<ProductionOrderRoutingOperation> existingOperationList) {
@@ -572,7 +708,7 @@
             return;
         }
         if (defaultDecimal(task.getCompleteQuantity()).compareTo(BigDecimal.ZERO) > 0) {
-            throw new ServiceException("宸ュ簭宸蹭骇鐢熸姤宸ヨ褰曪紝鏃犳硶鏍规嵁 BOM 鍙樻洿鍒犻櫎瀵瑰簲宸ュ簭蹇収");
+            throw new ServiceException("宸ュ簭宸蹭骇鐢熸姤宸ヨ褰曪紝鏃犳硶鏍规嵁 BOM 鍙樻洿鍒犻櫎瀵瑰簲宸ュ簭蹇収" + task.getWorkOrderNo());
         }
         long reportCount = productionProductMainMapper.selectCount(
                 Wrappers.<ProductionProductMain>lambdaQuery()
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
index 2e1e578..c52892a 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -401,7 +401,7 @@
             productionAccount.setSchedulingUserId(user == null ? null : user.getUserId());
             productionAccount.setSchedulingUserName(user == null ? dto.getUserName() : user.getNickName());
             productionAccount.setFinishedNum(productQty);
-            productionAccount.setWorkHours(workHours);
+            productionAccount.setWorkHours(technologyOperation != null ? technologyOperation.getSalaryQuota() : null);
             productionAccount.setTechnologyOperationName(technologyOperation == null ? null : technologyOperation.getName());
             productionAccount.setSchedulingDate(LocalDateTime.now());
             productionAccountMapper.insert(productionAccount);
diff --git a/src/main/java/com/ruoyi/project/system/controller/SysUserController.java b/src/main/java/com/ruoyi/project/system/controller/SysUserController.java
index 08be9f2..9e15e50 100644
--- a/src/main/java/com/ruoyi/project/system/controller/SysUserController.java
+++ b/src/main/java/com/ruoyi/project/system/controller/SysUserController.java
@@ -120,10 +120,7 @@
         List<SysRole> roles = roleService.selectRoleAll();
         ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
         ajax.put("posts", postService.selectPostAll());
-        SysUserDeptVo sysUserDeptVo = new SysUserDeptVo();
-        sysUserDeptVo.setUserId(userId);
-        List<SysUserDeptVo> sysUserDeptVos = userDeptService.userLoginFacotryList(sysUserDeptVo);
-        ajax.put("deptIds",sysUserDeptVos.stream().map(SysUserDeptVo::getDeptId).collect(Collectors.toList()));
+        ajax.put("deptIds", userService.selectDeptIdsByUserId(userId));
         return ajax;
     }
 
diff --git a/src/main/java/com/ruoyi/project/system/service/ISysUserService.java b/src/main/java/com/ruoyi/project/system/service/ISysUserService.java
index 7d5ba4a..e3be5f4 100644
--- a/src/main/java/com/ruoyi/project/system/service/ISysUserService.java
+++ b/src/main/java/com/ruoyi/project/system/service/ISysUserService.java
@@ -217,4 +217,11 @@
      * @return
      */
     int bindUserDept(SysUser user);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鎵�鏈夊叧鑱旂殑閮ㄩ棬ID
+     * @param userId
+     * @return
+     */
+    List<Long> selectDeptIdsByUserId(Long userId);
 }
diff --git a/src/main/java/com/ruoyi/project/system/service/impl/SysUserServiceImpl.java b/src/main/java/com/ruoyi/project/system/service/impl/SysUserServiceImpl.java
index 39f7234..01addd4 100644
--- a/src/main/java/com/ruoyi/project/system/service/impl/SysUserServiceImpl.java
+++ b/src/main/java/com/ruoyi/project/system/service/impl/SysUserServiceImpl.java
@@ -560,4 +560,11 @@
         }
         return user.getDeptIds().length;
     }
+
+    @Override
+    public List<Long> selectDeptIdsByUserId(Long userId) {
+        LambdaQueryWrapper<SysUserDept> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(SysUserDept::getUserId, userId);
+        return sysUserDeptMapper.selectList(queryWrapper).stream().map(SysUserDept::getDeptId).collect(Collectors.toList());
+    }
 }
diff --git a/src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java b/src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java
index f265ab0..798112b 100644
--- a/src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java
+++ b/src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java
@@ -2,10 +2,13 @@
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.basic.service.ISupplierService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.aspectj.lang.annotation.Log;
 import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
-import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.framework.web.domain.R;
+import com.ruoyi.purchase.dto.VatDto;
+import com.ruoyi.purchase.service.PurchaseReportService;
+import com.ruoyi.purchase.vo.PurchaseReportVo;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import jakarta.servlet.http.HttpServletResponse;
@@ -15,6 +18,8 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
+
 @RestController
 @Tag(name = "閲囪喘鎶ヨ〃")
 @RequestMapping("/purchase/report")
@@ -22,31 +27,38 @@
 public class AccountingReportController {
 
     private final ISupplierService supplierService;
+    private final PurchaseReportService purchaseReportService;
 
 
     @GetMapping("/list")
     @Log(title = "閲囪喘鎶ヨ〃-椤圭洰鍒╂鼎", businessType = BusinessType.OTHER)
-    public AjaxResult list(Page page) {
-        return AjaxResult.success();
+    public R list(Page page, String customerName) {
+        return R.ok(purchaseReportService.list(page,customerName));
     }
 
     @Log(title = "閲囪喘鎶ヨ〃-椤圭洰鍒╂鼎瀵煎嚭", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
     @Operation(summary = "閲囪喘鎶ヨ〃-椤圭洰鍒╂鼎瀵煎嚭")
-    public void export(HttpServletResponse response) {
+    public void export(HttpServletResponse response, String customerName) {
+        List<PurchaseReportVo> list = purchaseReportService.list(new Page(1,-1),customerName).getRecords();
+        ExcelUtil<PurchaseReportVo> util = new ExcelUtil<>(PurchaseReportVo.class);
+        util.exportExcel(response, list , "椤圭洰鍒╂鼎");
 
     }
 
     @Log(title = "閲囪喘鎶ヨ〃-澧炲�肩◣姣斿", businessType = BusinessType.OTHER)
     @GetMapping("/listVat")
-    public AjaxResult listVat(Page page,String month) {
-        return AjaxResult.success();
+    public R listVat(Page page,String month) {
+        return R.ok(purchaseReportService.listVat(page,month));
     }
 
     @Log(title = "閲囪喘鎶ヨ〃-澧炲�肩◣姣斿", businessType = BusinessType.EXPORT)
     @PostMapping("/exportTwo")
     @Operation(summary = "閲囪喘鎶ヨ〃-澧炲�肩◣姣斿")
-    public void exportTwo(HttpServletResponse response) {
+    public void exportTwo(HttpServletResponse response,String month) {
+        List<VatDto> list = purchaseReportService.listVat(new Page(1,-1),month).getRecords();
+        ExcelUtil<VatDto> util = new ExcelUtil<>(VatDto.class);
+        util.exportExcel(response, list , "澧炲�肩◣姣斿");
     }
 
     @GetMapping("/supplierTransactions")
diff --git a/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java b/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
index cd3b9fd..22faea3 100644
--- a/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
+++ b/src/main/java/com/ruoyi/purchase/dto/PurchaseLedgerDto.java
@@ -27,6 +27,8 @@
 
     private String entryDateStart;
     private String entryDateEnd;
+    @Schema(description = "鍏ュ簱鐘舵��")
+    private String stockInStatus;
 
     private Long id;
 
diff --git a/src/main/java/com/ruoyi/purchase/dto/VatDto.java b/src/main/java/com/ruoyi/purchase/dto/VatDto.java
index c70ebeb..3564183 100644
--- a/src/main/java/com/ruoyi/purchase/dto/VatDto.java
+++ b/src/main/java/com/ruoyi/purchase/dto/VatDto.java
@@ -1,27 +1,30 @@
 package com.ruoyi.purchase.dto;
 
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
 import java.math.BigDecimal;
-import java.time.LocalDate;
-
 @Data
+@Schema(name = "VatDto", description = "绠$悊椹鹃┒鑸�--澧炲�肩◣姣斿鍙傛暟")
+@ExcelIgnoreUnannotated
 public class VatDto {
 
-    //鏈堜唤
     @Excel(name = "鏈堜唤")
+    @Schema(description = "鏈堜唤")
     private String month ;
 
-    //杩涢」绋�
-    @Excel(name = "杩涢」绋庨")
+    @Excel(name = "閿�椤圭◣棰�")
+    @Schema(description = "閿�椤圭◣棰�")
     private BigDecimal jTaxAmount;
 
-    //閿�椤圭◣
-    @Excel(name = "閿�椤圭◣棰�")
+    @Excel(name = "杩涢」绋庨")
+    @Schema(description = "杩涢」绋庨")
     private BigDecimal xTaxAmount;
 
     @Excel(name = "閿�-杩�")
+    @Schema(description = "閿�-杩�")
     private BigDecimal taxAmount;
 
 }
diff --git a/src/main/java/com/ruoyi/purchase/service/PurchaseReportService.java b/src/main/java/com/ruoyi/purchase/service/PurchaseReportService.java
new file mode 100644
index 0000000..4ec6522
--- /dev/null
+++ b/src/main/java/com/ruoyi/purchase/service/PurchaseReportService.java
@@ -0,0 +1,14 @@
+package com.ruoyi.purchase.service;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.purchase.dto.VatDto;
+import com.ruoyi.purchase.vo.PurchaseReportVo;
+
+public interface PurchaseReportService {
+
+    IPage<PurchaseReportVo> list(Page page, String customerName);
+
+    IPage<VatDto> listVat(Page page, String month);
+}
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
index c8b53b6..09d5d20 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -6,12 +6,8 @@
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
 import com.ruoyi.approve.bean.vo.ApproveProcessVO;
-import com.ruoyi.approve.mapper.ApprovalTemplateMapper;
-import com.ruoyi.approve.pojo.ApprovalInstance;
 import com.ruoyi.approve.pojo.ApproveProcess;
-import com.ruoyi.approve.service.ApprovalInstanceService;
 import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl;
 import com.ruoyi.basic.enums.ApplicationTypeEnum;
 import com.ruoyi.basic.enums.RecordTypeEnum;
@@ -104,8 +100,6 @@
     private final ApproveProcessServiceImpl approveProcessService;
     private final ProcurementRecordMapper procurementRecordStorageMapper;
     private final FileUtil fileUtil;
-    private final ApprovalInstanceService approvalInstanceService;
-    private final ApprovalTemplateMapper approvalTemplateMapper;
 
     @Override
     public List<PurchaseLedger> selectPurchaseLedgerList(PurchaseLedger purchaseLedger) {
@@ -156,7 +150,7 @@
         if (purchaseLedger.getId() == null) {
             purchaseLedgerMapper.insert(purchaseLedger);
         } else {
-//            // 鍒犻櫎閲囪喘瀹℃牳锛岄噸鏂版彁浜�
+            // 鍒犻櫎閲囪喘瀹℃牳锛岄噸鏂版彁浜�
             ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
                     .eq(ApproveProcess::getApproveType, 5)
                     .eq(ApproveProcess::getApproveReason, purchaseLedger.getPurchaseContractNumber())
@@ -166,22 +160,8 @@
                 approveProcessService.delByIds(Collections.singletonList(one.getId()));
             }
             purchaseLedgerMapper.updateById(purchaseLedger);
-            //鍒犻櫎鏂伴噰璐鎵�
-            approvalInstanceService.remove(new LambdaQueryWrapper<ApprovalInstance>().eq(ApprovalInstance::getBusinessId, purchaseLedger.getId()).eq(ApprovalInstance::getBusinessType, 5));
         }
 
-        //鏂伴噰璐鎵�
-        ApprovalInstanceDto approvalInstanceDto = new ApprovalInstanceDto();
-        approvalInstanceDto.setTemplateId(purchaseLedger.getTemplateId());
-        approvalInstanceDto.setBusinessId(purchaseLedger.getId());
-        approvalInstanceDto.setBusinessType(5L);
-        approvalInstanceDto.setTitle("閲囪喘鍚堝悓鍙凤細" + purchaseLedger.getPurchaseContractNumber());
-        approvalInstanceDto.setApplicantId(SecurityUtils.getUserId());
-        approvalInstanceDto.setTemplateId(purchaseLedger.getTemplateId());
-        approvalInstanceDto.setTemplateName(approvalTemplateMapper.selectById(purchaseLedger.getTemplateId()).getTemplateName());
-        approvalInstanceDto.setApplicantName(SecurityUtils.getLoginUser().getNickName());
-        approvalInstanceDto.setApplyTime(LocalDateTime.now());
-        approvalInstanceService.add(approvalInstanceDto);
         // 4. 澶勭悊瀛愯〃鏁版嵁
         List<SalesLedgerProduct> productList = purchaseLedgerDto.getProductData();
         if (productList != null && !productList.isEmpty()) {
@@ -471,31 +451,7 @@
 
     @Override
     public IPage<PurchaseLedgerDto> selectPurchaseLedgerListPage(IPage ipage, PurchaseLedgerDto purchaseLedger) {
-        IPage<PurchaseLedgerDto> purchaseLedgerDtoIPage = purchaseLedgerMapper.selectPurchaseLedgerListPage(ipage, purchaseLedger);
-        List<PurchaseLedgerDto> records = purchaseLedgerDtoIPage.getRecords();
-        if (records == null || records.isEmpty()) {
-            return purchaseLedgerDtoIPage;
-        }
-
-        // 鎵归噺鏌ヨ鏂囦欢锛岄伩鍏� N+1 闂
-        List<Long> ledgerIds = records.stream()
-                .map(PurchaseLedgerDto::getId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toList());
-
-        if (!ledgerIds.isEmpty()) {
-            List<CommonFile> allFiles = commonFileMapper.selectList(
-                    new LambdaQueryWrapper<CommonFile>()
-                            .in(CommonFile::getCommonId, ledgerIds)
-                            .eq(CommonFile::getType, FileNameType.PURCHASE.getValue())
-            );
-
-            Map<Long, List<CommonFile>> fileMap = allFiles.stream()
-                    .collect(Collectors.groupingBy(CommonFile::getCommonId));
-
-            records.forEach(dto -> dto.setSalesLedgerFiles(fileMap.getOrDefault(dto.getId(), new ArrayList<>())));
-        }
-        return purchaseLedgerDtoIPage;
+        return purchaseLedgerMapper.selectPurchaseLedgerListPage(ipage, purchaseLedger);
     }
 
     @Override
@@ -625,9 +581,9 @@
 
             return AjaxResult.success("瀵煎叆鎴愬姛");
         } catch (Exception e) {
-            log.error("PurchaseLedgerServiceImpl importData error", e);
-            return AjaxResult.error("瀵煎叆澶辫触: " + e.getMessage());
+            e.printStackTrace();
         }
+        return AjaxResult.success("瀵煎叆澶辫触");
     }
 
     @Override
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseReportServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseReportServiceImpl.java
new file mode 100644
index 0000000..676cf46
--- /dev/null
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseReportServiceImpl.java
@@ -0,0 +1,32 @@
+package com.ruoyi.purchase.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.mapper.AccountStatementMapper;
+import com.ruoyi.purchase.dto.VatDto;
+import com.ruoyi.purchase.service.PurchaseReportService;
+import com.ruoyi.purchase.vo.PurchaseReportVo;
+import com.ruoyi.sales.mapper.SalesLedgerMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class PurchaseReportServiceImpl implements PurchaseReportService {
+
+    private final SalesLedgerMapper salesLedgerMapper;
+    private final AccountStatementMapper accountStatementMapper;
+
+    @Override
+    public IPage<PurchaseReportVo> list(Page page, String customerName) {
+        return salesLedgerMapper.selectPurchaseReportVoPage(page, customerName);
+    }
+
+    @Override
+    public IPage<VatDto> listVat(Page page, String month) {
+        return accountStatementMapper.selectVatDtoPage(page, month);
+    }
+}
diff --git a/src/main/java/com/ruoyi/purchase/vo/PurchaseReportVo.java b/src/main/java/com/ruoyi/purchase/vo/PurchaseReportVo.java
new file mode 100644
index 0000000..afe7f98
--- /dev/null
+++ b/src/main/java/com/ruoyi/purchase/vo/PurchaseReportVo.java
@@ -0,0 +1,44 @@
+package com.ruoyi.purchase.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.ruoyi.framework.aspectj.lang.annotation.Excel;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+@Schema(name = "PurchaseReportVo", description = "绠$悊椹鹃┒鑸�--椤圭洰鍒╂鼎鍙傛暟")
+@ExcelIgnoreUnannotated
+public class PurchaseReportVo {
+
+    @Schema(description = "閿�鍞悎鍚屽彿")
+    @Excel(name = "閿�鍞悎鍚屽彿")
+    private String customerContractNo;
+
+    @Schema(description = "瀹㈡埛鍚嶇О")
+    @Excel(name = "瀹㈡埛鍚嶇О")
+    private String customerName;
+
+    @Schema(description = "椤圭洰鍚嶇О")
+    @Excel(name = "椤圭洰鍚嶇О")
+    private String projectName;
+
+    @Excel(name = "鍚堝悓閲戦")
+    @Schema(description = "鍚堝悓閲戦")
+    private BigDecimal contractAmount;
+
+    @Excel(name = "閲囪喘閲戦")
+    @Schema(description = "閲囪喘閲戦")
+    private BigDecimal purchaseAmount;
+
+    @Schema(description = "鍒╂鼎")
+    @Excel(name = "鍒╂鼎")
+    private BigDecimal balance;
+
+    @Schema(description = "鍒╂鼎鐜�")
+    @Excel(name = "鍒╂鼎鐜�")
+    private BigDecimal balanceRatio;
+
+
+}
diff --git a/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java b/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
index dc05d88..cc295d5 100644
--- a/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
+++ b/src/main/java/com/ruoyi/quality/controller/QualityInspectController.java
@@ -14,7 +14,6 @@
 import com.ruoyi.quality.service.IQualityInspectService;
 import io.swagger.v3.oas.annotations.Operation;
 import jakarta.servlet.http.HttpServletResponse;
-import jakarta.validation.Valid;
 import lombok.AllArgsConstructor;
 import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.*;
@@ -139,7 +138,7 @@
     @PostMapping("/submit")
     @Operation(summary = "鎻愪氦妫�楠�")
     @Log(title = "鎻愪氦妫�楠�", businessType = BusinessType.OTHER)
-    public R<?> submit(@Valid @RequestBody QualityInspect qualityInspect) {
+    public R<?> submit(@RequestBody QualityInspect qualityInspect) {
         return R.ok(qualityInspectService.submit(qualityInspect));
     }
 
diff --git a/src/main/java/com/ruoyi/quality/pojo/QualityInspect.java b/src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
index 73179fa..bc3f60a 100644
--- a/src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
+++ b/src/main/java/com/ruoyi/quality/pojo/QualityInspect.java
@@ -5,7 +5,6 @@
 import com.ruoyi.dto.DateQueryDto;
 import com.ruoyi.framework.aspectj.lang.annotation.Excel;
 import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 
 import java.io.Serial;
@@ -34,7 +33,6 @@
      * 绫诲埆(0:鍘熸潗鏂欐楠�;1:杩囩▼妫�楠�;2:鍑哄巶妫�楠�)
      */
     @Excel(name = "绫诲埆",readConverterExp = "0=鍘熸潗鏂欐楠�,1=杩囩▼妫�楠�,2=鍑哄巶妫�楠�")
-    @NotNull(message = "绫诲埆涓嶈兘涓虹┖")
     private Integer inspectType;
 
     /**
@@ -74,7 +72,6 @@
     /**
      * 鍏宠仈浜у搧id
      */
-    @NotNull(message = "浜у搧id涓嶈兘涓虹┖")
     private Long productId;
 
     /**
@@ -103,12 +100,10 @@
 
     @Excel(name = "鍚堟牸鏁伴噺")
     @TableField("qualified_quantity")
-    @NotNull(message = "鍚堟牸鏁伴噺涓嶈兘涓虹┖")
     private BigDecimal qualifiedQuantity;
 
     @Excel(name = "涓嶅悎鏍兼暟閲�")
     @TableField("unqualified_quantity")
-    @NotNull(message = "涓嶅悎鏍兼暟閲忎笉鑳戒负绌�")
     private BigDecimal unqualifiedQuantity;
 
     /**
diff --git a/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java b/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
index 7be310d..0707375 100644
--- a/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
+++ b/src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -10,6 +10,7 @@
 import com.deepoove.poi.XWPFTemplate;
 import com.deepoove.poi.config.Configure;
 import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.HackLoopTableRenderPolicy;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.procurementrecord.service.ProcurementRecordService;
@@ -90,24 +91,32 @@
     @Override
     public int submit(QualityInspect inspect) {
         QualityInspect qualityInspect = qualityInspectMapper.selectById(inspect.getId());
+
         //鎻愪氦鍓嶅繀椤诲垽鏂槸鍚﹀悎鏍�
         if (ObjectUtils.isNull(qualityInspect.getCheckResult())) {
-            throw new RuntimeException("璇峰厛鍒ゆ柇鏄惁鍚堟牸");
+            throw new ServiceException("璇峰厛鍒ゆ柇鏄惁鍚堟牸");
         }
 
         if (ObjectUtils.isNull(qualityInspect.getQualifiedQuantity())) {
-            throw new RuntimeException("鍚堟牸鏁伴噺涓嶈兘涓虹┖");
+            throw new ServiceException("鍚堟牸鏁伴噺涓嶈兘涓虹┖");
         }
 
         if (ObjectUtils.isNull(qualityInspect.getUnqualifiedQuantity())) {
-            throw new RuntimeException("涓嶅悎鏍兼暟閲忎笉鑳戒负绌�");
+            throw new ServiceException("涓嶅悎鏍兼暟閲忎笉鑳戒负绌�");
         }
 
-        // 鍖哄垎鍚堟牸鏁伴噺浠ュ強涓嶅悎鏍煎鐞嗚繘琛屽搴旂殑澶勭悊
-        Assert.isTrue(qualityInspect.getQuantity().compareTo(qualityInspect.getQualifiedQuantity().add(qualityInspect.getUnqualifiedQuantity())) == 0,"璇锋鏌ュ悎鏍兼暟閲忓拰涓嶅悎鏍兼暟閲忥紝闇�瑕佸悎鏍兼暟閲�+涓嶅悎鏍兼暟閲忎笌鎬绘暟淇濇寔涓�鑷�");
+        // 濡傛灉鍚堟牸鏁伴噺涓虹┖锛岃涓�0
+        if (qualityInspect.getQualifiedQuantity() == null) {
+            qualityInspect.setQualifiedQuantity(BigDecimal.ZERO);
+        }
+
+        // 濡傛灉涓嶅悎鏍兼暟閲忎负绌猴紝璁句负0
+        if (qualityInspect.getUnqualifiedQuantity() == null) {
+            qualityInspect.setUnqualifiedQuantity(BigDecimal.ZERO);
+        }
+
+        // 鍚堟牸鐩存帴鍏ュ簱
         if(qualityInspect.getQualifiedQuantity().compareTo(BigDecimal.ZERO) > 0){
-            //鍚堟牸鐩存帴鍏ュ簱
-            // stockUtils.addStock(qualityInspect.getProductModelId(), qualityInspect.getQuantity(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode(), qualityInspect.getId());
             //浠呮坊鍔犲叆搴撹褰�
             StockInventoryDto stockInventoryDto = new StockInventoryDto();
             //濡傛灉鏄噰璐川妫�鍚堟牸鍏ュ簱閫夌敤CUSTOMIZATION_UNSTOCK_OUT,鍏朵綑鍚堟牸鍏ュ簱閫夌敤QUALITYINSPECT_STOCK_IN
@@ -124,6 +133,7 @@
                     qualityInspect.getProductModelId()));
             stockInventoryService.addStockInRecordOnly(stockInventoryDto);
         }
+        // 涓嶅悎鏍煎鐞�
         if(qualityInspect.getUnqualifiedQuantity().compareTo(BigDecimal.ZERO) > 0){
             QualityUnqualified qualityUnqualified = new QualityUnqualified();
             BeanUtils.copyProperties(qualityInspect, qualityUnqualified);
diff --git a/src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java b/src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java
index 95ab518..1dbfb65 100644
--- a/src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java
+++ b/src/main/java/com/ruoyi/sales/controller/ShippingInfoController.java
@@ -2,10 +2,7 @@
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
 import com.ruoyi.approve.bean.vo.ApproveProcessVO;
-import com.ruoyi.approve.mapper.ApprovalTemplateMapper;
-import com.ruoyi.approve.service.ApprovalInstanceService;
 import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl;
 import com.ruoyi.common.utils.OrderUtils;
 import com.ruoyi.common.utils.SecurityUtils;
@@ -29,7 +26,6 @@
 
 import java.io.IOException;
 import java.time.LocalDate;
-import java.time.LocalDateTime;
 import java.util.List;
 
 /**
@@ -42,8 +38,6 @@
 @AllArgsConstructor
 public class ShippingInfoController extends BaseController {
 
-    private final ApprovalTemplateMapper approvalTemplateMapper;
-    private final ApprovalInstanceService approvalInstanceService;
     private ShippingInfoService shippingInfoService;
     private ApproveProcessServiceImpl approveProcessService;
     private ShippingInfoMapper shippingInfoMapper;
@@ -71,25 +65,15 @@
         approveProcessVO.setApproveUserIds(req.getApproveUserIds());
         approveProcessVO.setApproveUser(loginUser.getUserId());
         approveProcessVO.setApproveTime(LocalDate.now().toString());
-        approveProcessService.addApprove(approveProcessVO);
-
-        ApprovalInstanceDto approvalInstanceDto = new ApprovalInstanceDto();
-        approvalInstanceDto.setTemplateId(req.getTemplateId());
-        approvalInstanceDto.setBusinessId(req.getId());
-        approvalInstanceDto.setBusinessType(7L);
-        approvalInstanceDto.setTitle("鍙戣揣缂栧彿锛�" + sh);
-        approvalInstanceDto.setApplicantId(SecurityUtils.getUserId());
-        approvalInstanceDto.setTemplateId(req.getTemplateId());
-        approvalInstanceDto.setTemplateName(approvalTemplateMapper.selectById(req.getTemplateId()).getTemplateName());
-        approvalInstanceDto.setApplicantName(SecurityUtils.getLoginUser().getNickName());
-        approvalInstanceDto.setApplyTime(LocalDateTime.now());
-        approvalInstanceService.add(approvalInstanceDto);
-
-        // 娣诲姞鍙戣揣娑堟伅
+        // 鍏堜繚瀛樺彂璐у崟锛屽啀鍙戣捣瀹℃壒锛涙棤瀹℃牳浜鸿嚜鍔ㄩ�氳繃鏃堕渶瑕佹寜鍙戣揣缂栧彿鍥炲啓鍙戣揣鐘舵�併��
         req.setShippingNo(sh);
         req.setStatus("寰呭鏍�");
         boolean save = shippingInfoService.add(req);
-        return save ? AjaxResult.success() : AjaxResult.error();
+        if (!save) {
+            return AjaxResult.error();
+        }
+        approveProcessService.addApprove(approveProcessVO);
+        return AjaxResult.success();
     }
 
     @Operation(summary = "鍙戣揣鎵e簱瀛�")
diff --git a/src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java b/src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java
index 9f49265..5518290 100644
--- a/src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java
+++ b/src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java
@@ -6,6 +6,7 @@
 import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.home.dto.IncomeExpenseAnalysisDto;
+import com.ruoyi.purchase.vo.PurchaseReportVo;
 import com.ruoyi.sales.dto.SalesLedgerDto;
 import com.ruoyi.sales.dto.SalesTrendDto;
 import com.ruoyi.sales.dto.StatisticsTableDto;
@@ -86,4 +87,7 @@
     List<SalesTrendDto> statisticsTable(@Param("statisticsTableDto")StatisticsTableDto statisticsTableDto);
 
     IPage<SalesLedgerDto> listSalesLedgerAndShipped(Page page, @Param("ew") SalesLedgerDto salesLedgerDto);
+
+    IPage<PurchaseReportVo> selectPurchaseReportVoPage(Page page, @Param("customerName") String customerName);
+
 }
diff --git a/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java b/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
index 08bb128..f4a42d6 100644
--- a/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
+++ b/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -149,6 +149,10 @@
     /**
      * 浜у搧鐘舵��
      */
+    @TableField(exist = false)
+    @Schema(description = "鍏ュ簱瀹℃牳鐘舵��")
+    private String stockInApprovalStatus;
+
 //    @TableField(exist = false)
     @Schema(description = "浜у搧鐘舵�侊細1-鍏呰冻")
     private Integer approveStatus;
diff --git a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
index a76b149..fe385f1 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -8,6 +8,10 @@
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.account.mapper.sales.AccountInvoiceApplicationMapper;
+import com.ruoyi.account.mapper.sales.AccountSalesCollectionMapper;
+import com.ruoyi.account.pojo.sales.AccountInvoiceApplication;
+import com.ruoyi.account.pojo.sales.AccountSalesCollection;
 import com.ruoyi.basic.enums.ApplicationTypeEnum;
 import com.ruoyi.basic.enums.RecordTypeEnum;
 import com.ruoyi.basic.mapper.CustomerMapper;
@@ -26,7 +30,9 @@
 import com.ruoyi.framework.security.LoginUser;
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.other.mapper.TempFileMapper;
-import com.ruoyi.production.mapper.*;
+import com.ruoyi.production.mapper.ProductionProductInputMapper;
+import com.ruoyi.production.mapper.ProductionProductMainMapper;
+import com.ruoyi.production.mapper.ProductionProductOutputMapper;
 import com.ruoyi.production.service.ProductionProductMainService;
 import com.ruoyi.project.system.domain.SysDept;
 import com.ruoyi.project.system.domain.SysUser;
@@ -36,8 +42,14 @@
 import com.ruoyi.purchase.mapper.PurchaseReturnOrderProductsMapper;
 import com.ruoyi.quality.mapper.QualityInspectMapper;
 import com.ruoyi.sales.dto.*;
-import com.ruoyi.sales.mapper.*;
-import com.ruoyi.sales.pojo.*;
+import com.ruoyi.sales.mapper.CommonFileMapper;
+import com.ruoyi.sales.mapper.SalesLedgerMapper;
+import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
+import com.ruoyi.sales.mapper.ShippingInfoMapper;
+import com.ruoyi.sales.pojo.CommonFile;
+import com.ruoyi.sales.pojo.SalesLedger;
+import com.ruoyi.sales.pojo.SalesLedgerProduct;
+import com.ruoyi.sales.pojo.ShippingInfo;
 import com.ruoyi.sales.service.ISalesLedgerService;
 import com.ruoyi.sales.vo.SalesLedgerVo;
 import lombok.RequiredArgsConstructor;
@@ -93,6 +105,8 @@
     private final QualityInspectMapper qualityInspectMapper;
     private final RedisTemplate<String, String> redisTemplate;
     private final FileUtil fileUtil;
+    private final AccountInvoiceApplicationMapper accountInvoiceApplicationMapper;
+    private final AccountSalesCollectionMapper accountSalesCollectionMapper;
 
     @Autowired
     private SysDeptMapper sysDeptMapper;
@@ -263,23 +277,37 @@
 
     @Override
     public List<MonthlyAmountDto> getAmountHalfYear(Integer type) {
-
         LocalDate now = LocalDate.now();
         List<MonthlyAmountDto> result = new ArrayList<>();
-
         for (int i = 5; i >= 0; i--) {
             YearMonth yearMonth = YearMonth.from(now.minusMonths(i));
-            LocalDateTime startTime = yearMonth.atDay(1).atStartOfDay();
-            LocalDateTime endTime = yearMonth.atEndOfMonth().atTime(23, 59, 59);
-
+            LocalDate startTime = yearMonth.atDay(1);
+            LocalDate endTime = yearMonth.atEndOfMonth();
             MonthlyAmountDto dto = new MonthlyAmountDto();
             dto.setMonth(yearMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")));
-            dto.setReceiptAmount(BigDecimal.ZERO);
-            dto.setInvoiceAmount(BigDecimal.ZERO);
-
+            //鍥炴閲戦
+            List<AccountSalesCollection> accountSalesCollections = accountSalesCollectionMapper.selectList(new LambdaQueryWrapper<AccountSalesCollection>()
+                    .between(AccountSalesCollection::getCollectionDate, startTime, endTime));
+            BigDecimal totalIncome = Optional.of(
+                    accountSalesCollections.stream()
+                            .map(AccountSalesCollection::getCollectionAmount)
+                            .filter(Objects::nonNull)
+                            .reduce(BigDecimal.ZERO, BigDecimal::add)
+            ).orElse(BigDecimal.ZERO);
+            dto.setReceiptAmount(totalIncome);
+            //寮�绁ㄩ噾棰�
+            List<AccountInvoiceApplication> accountInvoiceApplications = accountInvoiceApplicationMapper.selectList(new LambdaQueryWrapper<AccountInvoiceApplication>()
+                            .eq(AccountInvoiceApplication::getStatus,1)
+                    .between(AccountInvoiceApplication::getApplyDate, startTime, endTime));
+            BigDecimal totalInvoiceAmount = Optional.of(
+                    accountInvoiceApplications.stream()
+                            .map(AccountInvoiceApplication::getInvoiceAmount)
+                            .filter(Objects::nonNull)
+                            .reduce(BigDecimal.ZERO, BigDecimal::add)
+            ).orElse(BigDecimal.ZERO);
+            dto.setInvoiceAmount(totalInvoiceAmount);
             result.add(dto);
         }
-
         return result;
     }
 
diff --git a/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
index 8d16029..0a84bf9 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
@@ -26,6 +26,7 @@
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
 
@@ -89,10 +90,14 @@
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public boolean delete(List<Long> ids) {
         List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>()
                 .in(ShippingInfo::getId, ids));
         if (CollectionUtils.isEmpty(shippingInfos)) return false;
+        // 鍙湁寰呭鏍哥姸鎬佹墠鑳藉垹闄�
+        boolean allPending = shippingInfos.stream().allMatch(s -> "寰呭鏍�".equals(s.getStatus()));
+        if (!allPending) throw new RuntimeException("鍙湁寰呭鏍哥姸鎬佹墠鑳藉垹闄�");
         // 鍒犻櫎闄勪欢
         commonFileService.deleteByBusinessIds(ids, FileNameType.SHIP.getValue());
         // 鍒犻櫎鍙戣揣瀹℃壒
diff --git a/src/main/java/com/ruoyi/stock/controller/StockInRecordController.java b/src/main/java/com/ruoyi/stock/controller/StockInRecordController.java
index 1887b27..f4ca0cc 100644
--- a/src/main/java/com/ruoyi/stock/controller/StockInRecordController.java
+++ b/src/main/java/com/ruoyi/stock/controller/StockInRecordController.java
@@ -70,4 +70,15 @@
         return AjaxResult.success();
     }
 
+    @PostMapping("/reAudit")
+    @Log(title = "鍏ュ簱绠$悊-鍙嶅鍏ュ簱", businessType = BusinessType.UPDATE)
+    @Operation(summary = "鎵归噺鍙嶅鍏ュ簱璁板綍")
+    public AjaxResult reAudit(@RequestBody StockInRecordDto approveDto) {
+        if(CollectionUtils.isEmpty(approveDto.getIds())){
+            return AjaxResult.error("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
+        }
+        stockInRecordService.batchReAudit(approveDto.getIds());
+        return AjaxResult.success();
+    }
+
 }
diff --git a/src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java b/src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java
index 17d7e77..f4f03ba 100644
--- a/src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java
+++ b/src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java
@@ -40,4 +40,7 @@
     @Schema(description = "璁板綍ID鍒楄〃")
     private List<Long> ids;
 
+    @Schema(description = "婧愬崟鍙�")
+    private String sourceOrderNo;
+
 }
diff --git a/src/main/java/com/ruoyi/stock/service/StockInRecordService.java b/src/main/java/com/ruoyi/stock/service/StockInRecordService.java
index 249f261..117b70f 100644
--- a/src/main/java/com/ruoyi/stock/service/StockInRecordService.java
+++ b/src/main/java/com/ruoyi/stock/service/StockInRecordService.java
@@ -23,4 +23,6 @@
     void exportStockInRecord(HttpServletResponse response, StockInRecordDto stockInRecordDto);
 
     int batchApprove(List<Long> ids, Integer approvalStatus);
+
+    int batchReAudit(List<Long> ids);
 }
diff --git a/src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java b/src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java
index 7051075..e718611 100644
--- a/src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java
+++ b/src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java
@@ -17,6 +17,8 @@
 import com.ruoyi.stock.dto.StockInventoryDto;
 import com.ruoyi.stock.dto.StockUninventoryDto;
 import com.ruoyi.stock.execl.StockInRecordExportData;
+import com.ruoyi.production.mapper.ProductionOrderPickMapper;
+import com.ruoyi.production.pojo.ProductionOrderPick;
 import com.ruoyi.stock.mapper.StockInRecordMapper;
 import com.ruoyi.stock.mapper.StockInventoryMapper;
 import com.ruoyi.stock.mapper.StockUninventoryMapper;
@@ -30,6 +32,7 @@
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 @Service
@@ -39,6 +42,7 @@
     private StockInRecordMapper stockInRecordMapper;
     private StockInventoryMapper stockInventoryMapper;
     private StockUninventoryMapper stockUninventoryMapper;
+    private ProductionOrderPickMapper productionOrderPickMapper;
 
     @Override
     public IPage<StockInRecordDto> listPage(Page page, StockInRecordDto stockInRecordDto) {
@@ -152,6 +156,32 @@
         return stockUninventoryMapper.selectOne(eq);
     }
 
+    /**
+     * 鍥炴粴鐢熶骇閫�鏂欏叆搴撶殑棰嗘枡璁板綍閫�鏂欐暟閲�
+     * @param stockInRecord 鍏ュ簱璁板綍
+     */
+    private void rollbackFeedReturnQty(StockInRecord stockInRecord) {
+        ProductionOrderPick productionOrderPick = productionOrderPickMapper.selectById(stockInRecord.getRecordId());
+        if (productionOrderPick != null) {
+            BigDecimal returnQty = productionOrderPick.getReturnQty();
+            if (returnQty == null) {
+                returnQty = BigDecimal.ZERO;
+            }
+            BigDecimal newReturnQty = returnQty.subtract(stockInRecord.getStockInNum());
+            if (newReturnQty.compareTo(BigDecimal.ZERO) < 0) {
+                newReturnQty = BigDecimal.ZERO;
+            }
+            productionOrderPick.setReturnQty(newReturnQty);
+            // 閲嶆柊璁$畻瀹為檯鐢ㄩ噺
+            BigDecimal actualQty = productionOrderPick.getQuantity().add(
+                productionOrderPick.getFeedingQty() != null ? productionOrderPick.getFeedingQty() : BigDecimal.ZERO)
+                .subtract(newReturnQty);
+            productionOrderPick.setActualQty(actualQty);
+            productionOrderPick.setReturned(newReturnQty.compareTo(BigDecimal.ZERO) > 0);
+            productionOrderPickMapper.updateById(productionOrderPick);
+        }
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int batchDeletePending(List<Long> ids) {
@@ -162,6 +192,11 @@
             }
             if (stockInRecord.getApprovalStatus() != null && !ReviewStatusEnum.PENDING_REVIEW.getCode().equals(stockInRecord.getApprovalStatus())) {
                 throw new BaseException("鍙湁寰呭鎵圭姸鎬佺殑璁板綍鎵嶈兘鍒犻櫎,鍏ュ簱鎵规:" + stockInRecord.getInboundBatches());
+            }
+
+            // 濡傛灉鏄敓浜ч��鏂欏叆搴擄紝鍒犻櫎鏃堕渶瑕佸洖婊氶鏂欒褰曠殑閫�鏂欐暟閲�
+            if (StockInQualifiedRecordTypeEnum.FEED_RETURN_IN.getCode().equals(stockInRecord.getRecordType())) {
+                rollbackFeedReturnQty(stockInRecord);
             }
         }
         return stockInRecordMapper.deleteBatchIds(ids);
@@ -186,6 +221,13 @@
             }
             stockInRecord.setApprovalStatus(approvalStatus);
             stockInRecordMapper.updateById(stockInRecord);
+
+            // 瀹℃壒椹冲洖鏃讹紝濡傛灉鏄敓浜ч��鏂欏叆搴擄紝闇�瑕佸洖婊氶鏂欒褰曠殑閫�鏂欐暟閲�
+            if (ReviewStatusEnum.REJECTED.getCode().equals(approvalStatus) &&
+                StockInQualifiedRecordTypeEnum.FEED_RETURN_IN.getCode().equals(stockInRecord.getRecordType())) {
+                rollbackFeedReturnQty(stockInRecord);
+            }
+
             // 瀹℃壒閫氳繃鏃讹紝搴撳瓨澧炲姞
             if (ReviewStatusEnum.APPROVED.getCode().equals(approvalStatus)) {
                 if ("0".equals(stockInRecord.getType())) {
@@ -231,4 +273,50 @@
         }
         return ids.size();
     }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int batchReAudit(List<Long> ids) {
+        if (CollectionUtils.isEmpty(ids)) {
+            throw new BaseException("璇烽�夋嫨鑷冲皯涓�鏉℃暟鎹�");
+        }
+
+        for (Long id : ids) {
+            StockInRecord stockInRecord = stockInRecordMapper.selectById(id);
+            if (stockInRecord == null) {
+                throw new BaseException("鍏ュ簱璁板綍涓嶅瓨鍦�,鏃犳硶閲嶆柊瀹℃牳!!!");
+            }
+            // 鍙湁椹冲洖鐘舵�佹墠鑳介噸鏂板鏍�
+            if (!ReviewStatusEnum.REJECTED.getCode().equals(stockInRecord.getApprovalStatus())) {
+                throw new BaseException("鍙湁椹冲洖鐘舵�佺殑璁板綍鎵嶈兘閲嶆柊瀹℃牳,鍏ュ簱鎵规:" + stockInRecord.getInboundBatches());
+            }
+
+            // 濡傛灉鏄敓浜ч��鏂欏叆搴擄紝鎭㈠閫�鏂欐暟閲忥紙鍥犱负椹冲洖鏃跺凡鎵e噺锛�
+            if (StockInQualifiedRecordTypeEnum.FEED_RETURN_IN.getCode().equals(stockInRecord.getRecordType())) {
+                ProductionOrderPick productionOrderPick = productionOrderPickMapper.selectById(stockInRecord.getRecordId());
+                if (productionOrderPick != null) {
+                    BigDecimal returnQty = productionOrderPick.getReturnQty();
+                    if (returnQty == null) {
+                        returnQty = BigDecimal.ZERO;
+                    }
+                    // 閲嶆柊瀹℃牳鏃舵仮澶嶉��鏂欐暟閲�
+                    BigDecimal newReturnQty = returnQty.add(stockInRecord.getStockInNum());
+                    productionOrderPick.setReturnQty(newReturnQty);
+                    // 閲嶆柊璁$畻瀹為檯鐢ㄩ噺
+                    BigDecimal actualQty = productionOrderPick.getQuantity().add(
+                        productionOrderPick.getFeedingQty() != null ? productionOrderPick.getFeedingQty() : BigDecimal.ZERO)
+                        .subtract(newReturnQty);
+                    productionOrderPick.setActualQty(actualQty);
+                    productionOrderPick.setReturned(newReturnQty.compareTo(BigDecimal.ZERO) > 0);
+                    productionOrderPickMapper.updateById(productionOrderPick);
+                }
+            }
+
+            // 灏嗙姸鎬佹敼涓哄緟瀹℃牳
+            stockInRecord.setApprovalStatus(ReviewStatusEnum.PENDING_REVIEW.getCode());
+            stockInRecordMapper.updateById(stockInRecord);
+        }
+
+        return ids.size();
+    }
 }
diff --git a/src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java b/src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java
index 4c7d157..47f7d34 100644
--- a/src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java
+++ b/src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java
@@ -80,21 +80,7 @@
         stockInRecordDto.setProductModelId(stockUninventoryDto.getProductModelId());
         stockInRecordDto.setType("1");
         stockInRecordService.add(stockInRecordDto);
-        //鍐嶈繘琛屾柊澧炲簱瀛樻暟閲忓簱瀛�
-        //鍏堟煡璇㈠簱瀛樿〃涓殑浜у搧鏄惁瀛樺湪锛屼笉瀛樺湪鏂板锛屽瓨鍦ㄦ洿鏂�
-        StockUninventory oldStockUnInventory = stockUninventoryMapper.selectOne(wrapper);
-        if (ObjectUtils.isEmpty(oldStockUnInventory)) {
-            StockUninventory newStockUnInventory = new StockUninventory();
-            newStockUnInventory.setProductModelId(stockUninventoryDto.getProductModelId());
-            newStockUnInventory.setQualitity(stockUninventoryDto.getQualitity());
-            newStockUnInventory.setLockedQuantity(stockUninventoryDto.getLockedQuantity());
-            newStockUnInventory.setBatchNo(stockUninventoryDto.getBatchNo());
-            newStockUnInventory.setVersion(1);
-            newStockUnInventory.setRemark(stockUninventoryDto.getRemark());
-            stockUninventoryMapper.insert(newStockUnInventory);
-        }else {
-            stockUninventoryMapper.updateAddStockUnInventory(stockUninventoryDto);
-        }
+        //瀹℃壒鍐嶆坊鍔�
         return 1;
     }
 
diff --git a/src/main/resources/financial-agent-prompt.txt b/src/main/resources/financial-agent-prompt.txt
index 2627da3..c7a4a3f 100644
--- a/src/main/resources/financial-agent-prompt.txt
+++ b/src/main/resources/financial-agent-prompt.txt
@@ -6,6 +6,6 @@
 2. 鍛戒腑鎴愭湰銆佸埄娑︺�佸簱瀛樿祫閲戙�佺幇閲戞祦銆侀璀︺�侀┚椹惰埍銆佹棩鎶ュ懆鎶ュ満鏅椂锛屼紭鍏堣皟鐢ㄥ搴斿伐鍏枫��
 3. 宸ュ叿杩斿洖 JSON 鏃讹紝鐩存帴杈撳嚭鍘熷 JSON 瀛楃涓诧紝涓嶈棰濆鍖呰9 Markdown锛屼篃涓嶈鍦ㄥ墠鍚庤拷鍔犺В閲婃枃鏈��
 4. 褰撶敤鎴烽棶棰樼己灏戞椂闂磋寖鍥存椂锛岄粯璁や娇鐢ㄥ伐鍏峰唴缃彛寰勶紙濡傝繎30澶┿�佹湰鏈堛�佽繎90澶╋級锛屽苟鍦ㄥ悗缁彲鎻愰啋鐢ㄦ埛琛ュ厖鑼冨洿銆�
-5. 鐢ㄦ埛闂�滀负浠�涔堝埄娑︿笅闄嶁�濃�滃摢涓鍗曚簭鎹熲�濃�滃摢涓鎴锋渶璧氶挶鈥濃�滃摢涓溅闂�/宸ュ簭鎴愭湰鏈�楂樷�濈瓑闂鏃讹紝浼樺厛鍩轰簬璁㈠崟鍒╂鼎涓庡伐搴忔垚鏈垎鏋愬伐鍏蜂綔绛斻��
+5. 鐢ㄦ埛闂�滀负浠�涔堝埄娑︿笅闄嶁�濃�滃摢涓鍗曚簭鎹熲�濃�滃摢涓鎴锋渶璧氶挶鈥濃�滃摢涓鎴峰埄娑﹁础鐚渶楂樷�濃�滃摢涓溅闂�/宸ュ簭鎴愭湰鏈�楂樷�濈瓑闂鏃讹紝浼樺厛鍩轰簬璁㈠崟鍒╂鼎涓庡伐搴忔垚鏈垎鏋愬伐鍏蜂綔绛斻��
 6. 鍥炵瓟蹇呴』浣跨敤涓枃锛涜嫢鏁版嵁涓嶈冻浠ュ緱鍑虹粨璁猴紝鏄庣‘鎸囧嚭缂哄皯鍝簺鍏抽敭瀛楁鎴栫瓫閫夋潯浠躲��
 7. 鐢ㄦ埛鎻愬埌鈥滀粖骞�/鏈湀/浠婂ぉ/鏈�杩�/涓婃湀/鍘诲勾鈥濈瓑鐩稿鏃堕棿鏃讹紝蹇呴』涓ユ牸鍩轰簬鈥滃綋鍓嶆棩鏈熲�濇崲绠楋紝绂佹鑷鍋囪骞翠唤銆�
diff --git a/src/main/resources/mapper/account/AccountStatementMapper.xml b/src/main/resources/mapper/account/AccountStatementMapper.xml
index 331c61b..32b1621 100644
--- a/src/main/resources/mapper/account/AccountStatementMapper.xml
+++ b/src/main/resources/mapper/account/AccountStatementMapper.xml
@@ -40,4 +40,39 @@
             </if>
     ORDER BY lj.statement_month DESC
     </select>
+    <select id="selectVatDtoPage" resultType="com.ruoyi.purchase.dto.VatDto">
+    SELECT
+        month,
+        jTaxAmount,
+        xTaxAmount,
+        (jTaxAmount - xTaxAmount) AS taxAmount
+    FROM (
+        SELECT
+            month,
+            SUM(IF(type = 'purchase', tax_price, 0)) AS xTaxAmount,
+            SUM(IF(type = 'sales', tax_price, 0)) AS jTaxAmount
+        FROM (
+            SELECT
+                DATE_FORMAT(issue_date, '%Y-%m') AS month,
+                tax_price,
+                'sales' AS type
+            FROM account_sales_invoice
+            WHERE status != 1
+            UNION ALL
+            SELECT
+                DATE_FORMAT(issue_date, '%Y-%m') AS month,
+                tax_price,
+                'purchase' AS type
+            FROM account_purchase_invoice
+            WHERE status != 1
+        ) AS all_data
+    GROUP BY month
+    ) AS TT
+     <where>
+            <if test="month != null">
+                and TT.month = #{month}
+            </if>
+     </where>
+    ORDER BY TT.month
+    </select>
 </mapper>
diff --git a/src/main/resources/mapper/account/purchase/AccountPaymentApplicationMapper.xml b/src/main/resources/mapper/account/purchase/AccountPaymentApplicationMapper.xml
index f1f5c5b..8b23627 100644
--- a/src/main/resources/mapper/account/purchase/AccountPaymentApplicationMapper.xml
+++ b/src/main/resources/mapper/account/purchase/AccountPaymentApplicationMapper.xml
@@ -89,7 +89,7 @@
     <select id="existsByStockInRecordId" resultType="java.lang.Boolean">
          SELECT COUNT(*) > 0
         FROM account_payment_application
-        WHERE
+        WHERE  status != 2
         <foreach collection="stockInRecordIds" item="id" open="(" separator=" OR " close=")">
             FIND_IN_SET(#{id}, stock_in_record_ids)
         </foreach>
diff --git a/src/main/resources/mapper/account/sales/AccountInvoiceApplicationMapper.xml b/src/main/resources/mapper/account/sales/AccountInvoiceApplicationMapper.xml
index 99b16d2..842e94c 100644
--- a/src/main/resources/mapper/account/sales/AccountInvoiceApplicationMapper.xml
+++ b/src/main/resources/mapper/account/sales/AccountInvoiceApplicationMapper.xml
@@ -64,7 +64,7 @@
     <select id="existsByStockOutRecordId" resultType="java.lang.Boolean">
         SELECT COUNT(*) > 0
         FROM account_invoice_application
-        WHERE
+        WHERE status!=2
         <foreach collection="stockOutRecordIds" item="id" open="(" separator=" OR " close=")">
             FIND_IN_SET(#{id}, stock_out_record_ids)
         </foreach>
diff --git a/src/main/resources/mapper/approve/ApproveProcessMapper.xml b/src/main/resources/mapper/approve/ApproveProcessMapper.xml
index fef06f7..dd651c0 100644
--- a/src/main/resources/mapper/approve/ApproveProcessMapper.xml
+++ b/src/main/resources/mapper/approve/ApproveProcessMapper.xml
@@ -20,12 +20,14 @@
             <result property="tenantId" column="tenant_id" />
             <result property="approveType" column="approve_type" />
             <result property="approveRemark" column="approve_remark" />
+            <result property="startDateTime" column="start_date_time" />
+            <result property="endDateTime" column="end_date_time" />
     </resultMap>
 
     <sql id="Base_Column_List">
         id,approve_id,approve_user,approve_dept_id,approve_dept_name,approve_user_ids,
         approve_user_names,approve_reason,approve_time,approve_over_time,approve_status,
-        approve_delete,tenant_id,approve_type,approve_remark
+        approve_delete,tenant_id,approve_type,approve_remark,start_date_time,end_date_time
     </sql>
     <select id="listPage" resultType="com.ruoyi.approve.vo.ApproveProcessVo">
         select * from approve_process where approve_delete = 0
diff --git a/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml b/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml
index 199eb21..5ecf0e9 100644
--- a/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml
+++ b/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml
@@ -110,7 +110,7 @@
         select poro.operation_name as processName,
                sum(ifnull(ppi.input_quantity, 0)) as totalInput,
                sum(ifnull(ppo.scrap_qty, 0)) as totalScrap,
-               sum(ifnull(ppo.quantity, 0) - ifnull(ppo.scrap_qty, 0)) as totalOutput
+               sum(greatest(ifnull(ppo.quantity, 0) - ifnull(ppo.scrap_qty, 0), 0)) as totalOutput
         from production_product_output ppo
                  inner join production_product_main ppm on ppo.production_product_main_id = ppm.id
                  inner join production_operation_task pot on ppm.production_operation_task_id = pot.id
diff --git a/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml b/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
index ecdd1f3..a818160 100644
--- a/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
+++ b/src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
@@ -17,56 +17,118 @@
     </select>
 
     <select id="selectPurchaseLedgerListPage" resultType="com.ruoyi.purchase.dto.PurchaseLedgerDto">
-        SELECT
-        pl.id,
-        pl.purchase_contract_number,
-        pl.sales_contract_no,
-        pl.supplier_id,
-        pl.supplier_name,
-        pl.project_name,
-        pl.contract_amount,
-        pl.entry_date,
-        pl.execution_date,
-        pl.recorder_id,
-        pl.recorder_name,
-        pl.template_name,
-        pl.approve_user_ids,
-        sm.is_white,
-        pl.approval_status,
-        pl.payment_method,
-        pl.remarks
-        FROM purchase_ledger pl
-        LEFT JOIN supplier_manage sm ON pl.supplier_id = sm.id
-        <where>
-            <if test="c.purchaseContractNumber != null and c.purchaseContractNumber != ''">
-                AND pl.purchase_contract_number LIKE CONCAT('%', #{c.purchaseContractNumber}, '%')
-            </if>
-            <if test="c.approvalStatus != null and c.approvalStatus != ''">
-                AND pl.approval_status = #{c.approvalStatus}
-            </if>
-            <if test="c.supplierName != null and c.supplierName != ''">
-                AND pl.supplier_name LIKE CONCAT('%', #{c.supplierName}, '%')
-            </if>
-            <if test="c.salesContractNo != null and c.salesContractNo != ''">
-                AND pl.sales_contract_no LIKE CONCAT('%', #{c.salesContractNo}, '%')
-            </if>
-            <if test="c.projectName != null and c.projectName != ''">
-                AND pl.project_name LIKE CONCAT('%', #{c.projectName}, '%')
-            </if>
-            <if test="c.entryDateStart != null and c.entryDateStart != ''">
-                AND pl.entry_date &gt;= #{c.entryDateStart}
-            </if>
-            <if test="c.entryDateEnd != null and c.entryDateEnd != ''">
-                AND pl.entry_date &lt;= #{c.entryDateEnd}
-            </if>
-            <if test="c.supplierId != null">
-                AND pl.supplier_id = #{c.supplierId}
-            </if>
-            <if test="c.approvalStatus != null">
-                AND pl.approval_status = #{c.approvalStatus}
-            </if>
-        </where>
-        ORDER BY pl.entry_date DESC
+        SELECT result.*
+        FROM (
+            SELECT
+                pl.id,
+                pl.purchase_contract_number,
+                pl.sales_contract_no,
+                pl.supplier_id,
+                pl.supplier_name,
+                pl.project_name,
+                pl.contract_amount,
+                pl.entry_date,
+                pl.execution_date,
+                pl.recorder_id,
+                pl.recorder_name,
+                pl.template_name,
+                pl.approve_user_ids,
+                sm.is_white,
+                pl.approval_status,
+                pl.payment_method,
+                pl.remarks,
+                CASE
+                    WHEN IFNULL(ls.total_product_count, 0) = 0 THEN '寰呭叆搴�'
+                    WHEN IFNULL(ls.full_product_count, 0) &gt;= IFNULL(ls.total_product_count, 0) THEN '瀹屽叏鍏ュ簱'
+                    WHEN IFNULL(ls.approved_product_count, 0) &gt; 0 THEN '鍏ュ簱涓�'
+                    ELSE '寰呭叆搴�'
+                END AS stock_in_status
+            FROM purchase_ledger pl
+            LEFT JOIN supplier_manage sm ON pl.supplier_id = sm.id
+            LEFT JOIN (
+                SELECT
+                    product_status.sales_ledger_id,
+                    COUNT(1) AS total_product_count,
+                    SUM(CASE WHEN product_status.approved_stock_in_num &gt; 0 THEN 1 ELSE 0 END) AS approved_product_count,
+                    SUM(CASE WHEN product_status.approved_stock_in_num &gt;= product_status.product_quantity THEN 1 ELSE 0 END) AS full_product_count
+                FROM (
+                    SELECT
+                        slp.id AS sales_ledger_product_id,
+                        slp.sales_ledger_id,
+                        IFNULL(slp.quantity, 0) AS product_quantity,
+                        IFNULL(approved_qty.approved_stock_in_num, 0) AS approved_stock_in_num
+                    FROM sales_ledger_product slp
+                    LEFT JOIN (
+                        SELECT rel.sales_ledger_product_id,
+                               IFNULL(SUM(rel.stock_in_num), 0) AS approved_stock_in_num
+                        FROM (
+                            SELECT slp.id AS sales_ledger_product_id,
+                                   sir.stock_in_num
+                            FROM stock_in_record sir
+                            INNER JOIN sales_ledger_product slp
+                                ON slp.type = 2
+                                AND TRIM(sir.record_type) = '7'
+                                AND sir.record_id = slp.sales_ledger_id
+                                AND (
+                                    (sir.batch_no IS NOT NULL AND sir.batch_no LIKE CONCAT('%-', slp.id))
+                                    OR (sir.batch_no IS NULL AND sir.product_model_id = slp.product_model_id)
+                                )
+                            WHERE sir.approval_status = 1
+
+                            UNION ALL
+
+                            SELECT slp.id AS sales_ledger_product_id,
+                                   sir.stock_in_num
+                            FROM stock_in_record sir
+                            INNER JOIN quality_inspect qi
+                                ON TRIM(sir.record_type) = '10'
+                                AND sir.record_id = qi.id
+                            INNER JOIN sales_ledger_product slp
+                                ON slp.type = 2
+                                AND slp.sales_ledger_id = qi.purchase_ledger_id
+                                AND slp.product_model_id = qi.product_model_id
+                            WHERE sir.approval_status = 1
+                        ) rel
+                        GROUP BY rel.sales_ledger_product_id
+                    ) approved_qty ON approved_qty.sales_ledger_product_id = slp.id
+                    WHERE slp.type = 2
+                ) product_status
+                GROUP BY product_status.sales_ledger_id
+            ) ls ON ls.sales_ledger_id = pl.id
+            <where>
+                <if test="c.purchaseContractNumber != null and c.purchaseContractNumber != ''">
+                    AND pl.purchase_contract_number LIKE CONCAT('%', #{c.purchaseContractNumber}, '%')
+                </if>
+                <if test="c.approvalStatus != null and c.approvalStatus != ''">
+                    AND pl.approval_status = #{c.approvalStatus}
+                </if>
+                <if test="c.supplierName != null and c.supplierName != ''">
+                    AND pl.supplier_name LIKE CONCAT('%', #{c.supplierName}, '%')
+                </if>
+                <if test="c.salesContractNo != null and c.salesContractNo != ''">
+                    AND pl.sales_contract_no LIKE CONCAT('%', #{c.salesContractNo}, '%')
+                </if>
+                <if test="c.projectName != null and c.projectName != ''">
+                    AND pl.project_name LIKE CONCAT('%', #{c.projectName}, '%')
+                </if>
+                <if test="c.entryDateStart != null and c.entryDateStart != ''">
+                    AND pl.entry_date &gt;= #{c.entryDateStart}
+                </if>
+                <if test="c.entryDateEnd != null and c.entryDateEnd != ''">
+                    AND pl.entry_date &lt;= #{c.entryDateEnd}
+                </if>
+                <if test="c.supplierId != null">
+                    AND pl.supplier_id = #{c.supplierId}
+                </if>
+                <if test="c.approvalStatus != null">
+                    AND pl.approval_status = #{c.approvalStatus}
+                </if>
+            </where>
+        ) result
+        <if test="c.stockInStatus != null and c.stockInStatus != ''">
+            WHERE result.stock_in_status = #{c.stockInStatus}
+        </if>
+        ORDER BY result.entry_date DESC
     </select>
 
     <select id="selectTotalPurchaseAmount" resultType="java.math.BigDecimal">
diff --git a/src/main/resources/mapper/quality/QualityInspectMapper.xml b/src/main/resources/mapper/quality/QualityInspectMapper.xml
index f252881..0ac0254 100644
--- a/src/main/resources/mapper/quality/QualityInspectMapper.xml
+++ b/src/main/resources/mapper/quality/QualityInspectMapper.xml
@@ -128,8 +128,7 @@
                COALESCE(SUM(
                                 CASE
                                     WHEN qi.inspect_state = 1
-                                        AND qi.check_result = '鍚堟牸'
-                                        THEN qi.quantity
+                                        THEN qi.qualified_quantity
                                     ELSE 0
                                     END
                         ), 0)                AS qualifiedCount,
@@ -137,8 +136,7 @@
                COALESCE(SUM(
                                 CASE
                                     WHEN qi.inspect_state = 1
-                                        AND qi.check_result = '涓嶅悎鏍�'
-                                        THEN qi.quantity
+                                        THEN qi.unqualified_quantity
                                     ELSE 0
                                     END
                         ), 0)                AS unqualifiedCount,
@@ -166,8 +164,7 @@
                           COALESCE(SUM(
                                            CASE
                                                WHEN qi.inspect_state = 1
-                                                   AND qi.check_result = '鍚堟牸'
-                                                   THEN qi.quantity
+                                                   THEN qi.qualified_quantity
                                                ELSE 0
                                                END
                                    ), 0)
@@ -248,8 +245,8 @@
             /* 鍚堟牸 */
                COALESCE(SUM(
                                 CASE
-                                    WHEN qi.inspect_state = 1 AND qi.check_result = '鍚堟牸'
-                                        THEN qi.quantity
+                                    WHEN qi.inspect_state = 1
+                                        THEN qi.qualified_quantity
                                     ELSE 0
                                     END
                         ), 0)                AS qualifiedCount,
@@ -257,8 +254,8 @@
             /* 涓嶅悎鏍� */
                COALESCE(SUM(
                                 CASE
-                                    WHEN qi.inspect_state = 1 AND qi.check_result = '涓嶅悎鏍�'
-                                        THEN qi.quantity
+                                    WHEN qi.inspect_state = 1
+                                        THEN qi.unqualified_quantity
                                     ELSE 0
                                     END
                         ), 0)                AS unqualifiedCount,
@@ -279,8 +276,8 @@
                   ROUND(
                           COALESCE(SUM(
                                            CASE
-                                               WHEN qi.inspect_state = 1 AND qi.check_result = '鍚堟牸'
-                                                   THEN qi.quantity
+                                               WHEN qi.inspect_state = 1
+                                                   THEN qi.qualified_quantity
                                                ELSE 0
                                                END
                                    ), 0)
@@ -312,7 +309,6 @@
 
     <select id="getYearlyPassRateStatistics" resultType="com.ruoyi.quality.dto.QualityPassRateDto">
         SELECT t.modelType,
-
                COALESCE(SUM(
                                 CASE
                                     WHEN pp.product_name = '鍘熸潗鏂�' AND t.modelType = 0 THEN qi.quantity
@@ -320,8 +316,23 @@
                                     WHEN pp.product_name = '鎴愬搧' AND t.modelType = 2 THEN qi.quantity
                                     ELSE 0
                                     END
-                        ), 0) AS totalCount
-
+                        ), 0) AS totalCount,
+               COALESCE(SUM(
+                                CASE
+                                    WHEN pp.product_name = '鍘熸潗鏂�' AND t.modelType = 0 THEN qi.qualified_quantity
+                                    WHEN pp.product_name = '鍗婃垚鍝�' AND t.modelType = 1 THEN qi.qualified_quantity
+                                    WHEN pp.product_name = '鎴愬搧' AND t.modelType = 2 THEN qi.qualified_quantity
+                                    ELSE 0
+                                    END
+                        ), 0) AS qualifiedCount,
+               COALESCE(SUM(
+                                CASE
+                                    WHEN pp.product_name = '鍘熸潗鏂�' AND t.modelType = 0 THEN qi.unqualified_quantity
+                                    WHEN pp.product_name = '鍗婃垚鍝�' AND t.modelType = 1 THEN qi.unqualified_quantity
+                                    WHEN pp.product_name = '鎴愬搧' AND t.modelType = 2 THEN qi.unqualified_quantity
+                                    ELSE 0
+                                    END
+                        ), 0) AS unqualifiedCount
         FROM (SELECT 0 AS modelType
               UNION ALL
               SELECT 1
@@ -334,8 +345,6 @@
                            ON qi.product_model_id = pm.id
                                AND YEAR(qi.check_time) = #{year}
                                AND qi.inspect_state = 1
-                               AND qi.check_result = '鍚堟牸'
-
         GROUP BY t.modelType
         ORDER BY t.modelType;
     </select>
diff --git a/src/main/resources/mapper/sales/SalesLedgerMapper.xml b/src/main/resources/mapper/sales/SalesLedgerMapper.xml
index e08632a..c145e0a 100644
--- a/src/main/resources/mapper/sales/SalesLedgerMapper.xml
+++ b/src/main/resources/mapper/sales/SalesLedgerMapper.xml
@@ -121,5 +121,21 @@
         </if>
         order by sl.execution_date desc
     </select>
+    <select id="selectPurchaseReportVoPage" resultType="com.ruoyi.purchase.vo.PurchaseReportVo">
+        select sl.sales_contract_no customerContractNo,
+               c.customer_name,
+               sl.project_name,
+               sl.contract_amount contractAmount,
+               pl.contract_amount purchaseAmount,
+               sl.contract_amount-pl.contract_amount balance,
+               (sl.contract_amount-pl.contract_amount)/sl.contract_amount balanceRatio
+        from sales_ledger sl
+        left join purchase_ledger pl on sl.id = pl.sales_ledger_id
+        left join customer c on sl.customer_id = c.id
+        where 1=1
+        <if test="customerName != null and customerName != '' ">
+            and c.customer_name like concat('%',#{customerName},'%')
+        </if>
+    </select>
 
 </mapper>
diff --git a/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml b/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
index 7eb7b79..49569de 100644
--- a/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
+++ b/src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -38,7 +38,13 @@
          WHEN IFNULL(t3.shipped_quantity, 0) = 0 THEN '寰呭彂璐�'
          WHEN (IFNULL(T1.quantity, 0) - IFNULL(t3.shipped_quantity, 0)) > 0 THEN '閮ㄥ垎鍙戣揣'
         ELSE '宸插彂璐�'
-        END as shippingStatus
+        END as shippingStatus,
+        CASE
+         WHEN T1.type != 2 THEN NULL
+         WHEN IFNULL(t4.approved_stock_in_num, 0) &lt;= 0 THEN '寰呭叆搴�'
+         WHEN IFNULL(t4.approved_stock_in_num, 0) &gt;= IFNULL(T1.quantity, 0) THEN '瀹屽叏鍏ュ簱'
+        ELSE '鍏ュ簱涓�'
+        END AS stock_in_approval_status
         FROM
         sales_ledger_product T1
         LEFT JOIN (
@@ -53,6 +59,39 @@
         where si.status != '瀹℃牳鎷掔粷'
         GROUP BY sales_ledger_product_id
         ) t3 ON t3.sales_ledger_product_id = T1.id
+        LEFT JOIN (
+        SELECT rel.sales_ledger_product_id,
+               IFNULL(SUM(rel.stock_in_num), 0) AS approved_stock_in_num
+        FROM (
+            SELECT slp.id AS sales_ledger_product_id,
+                   sir.stock_in_num
+            FROM stock_in_record sir
+            INNER JOIN sales_ledger_product slp
+                ON slp.type = 2
+                AND TRIM(sir.record_type) = '7'
+                AND sir.record_id = slp.sales_ledger_id
+                AND (
+                    (sir.batch_no IS NOT NULL AND sir.batch_no LIKE CONCAT('%-', slp.id))
+                    OR (sir.batch_no IS NULL AND sir.product_model_id = slp.product_model_id)
+                )
+            WHERE sir.approval_status = 1
+
+            UNION ALL
+
+            SELECT slp.id AS sales_ledger_product_id,
+                   sir.stock_in_num
+            FROM stock_in_record sir
+            INNER JOIN quality_inspect qi
+                ON TRIM(sir.record_type) = '10'
+                AND sir.record_id = qi.id
+            INNER JOIN sales_ledger_product slp
+                ON slp.type = 2
+                AND slp.sales_ledger_id = qi.purchase_ledger_id
+                AND slp.product_model_id = qi.product_model_id
+            WHERE sir.approval_status = 1
+        ) rel
+        GROUP BY rel.sales_ledger_product_id
+        ) t4 ON t4.sales_ledger_product_id = T1.id
         left join product_model pm ON T1.product_model_id = pm.id
         left join product p ON pm.product_id = p.id
         <where>
diff --git a/src/main/resources/mapper/sales/SalesQuotationMapper.xml b/src/main/resources/mapper/sales/SalesQuotationMapper.xml
index 3c93850..5448933 100644
--- a/src/main/resources/mapper/sales/SalesQuotationMapper.xml
+++ b/src/main/resources/mapper/sales/SalesQuotationMapper.xml
@@ -9,7 +9,7 @@
         FROM sales_quotation t1
         LEFT JOIN approve_process t2 ON t1.quotation_no = t2.approve_reason and t2.approve_type = 6
         WHERE 1=1
-          and t2.approve_deleted = 0
+          and t2.approve_delete = 0
         <if test="salesQuotationDto.quotationNo != null and salesQuotationDto.quotationNo != '' ">
             AND t1.quotation_no LIKE CONCAT('%',#{salesQuotationDto.quotationNo},'%')
         </if>
diff --git a/src/main/resources/mapper/stock/StockInRecordMapper.xml b/src/main/resources/mapper/stock/StockInRecordMapper.xml
index 5545c1e..a3bf3f9 100644
--- a/src/main/resources/mapper/stock/StockInRecordMapper.xml
+++ b/src/main/resources/mapper/stock/StockInRecordMapper.xml
@@ -19,11 +19,96 @@
         p.product_name as product_name,
         pm.model,
         pm.unit,
-        u.nick_name as createBy
+        u.nick_name as createBy,
+        CASE
+            WHEN #{params.topParentProductId} = 278 AND TRIM(sir.record_type) = '7' THEN
+                COALESCE(pl_by_product.purchase_contract_number, pl_direct.purchase_contract_number)
+            WHEN #{params.topParentProductId} = 278 AND TRIM(sir.record_type) = '10' THEN
+                pl_by_quality.purchase_contract_number
+            WHEN #{params.topParentProductId} = 276 THEN
+                CASE
+                    WHEN TRIM(sir.record_type) IN ('14', '15') THEN
+                        sl_return.sales_contract_no
+                    WHEN TRIM(sir.record_type) IN ('2', '5') THEN
+                        COALESCE(po_sales_main.sales_contract_no, po_main.nps_no)
+                    WHEN TRIM(sir.record_type) = '6' THEN
+                        COALESCE(po_sales_qi.sales_contract_no, po_qi.nps_no)
+                    WHEN TRIM(sir.record_type) IN ('4', '11') THEN
+                        COALESCE(po_sales_uq.sales_contract_no, po_uq.nps_no)
+                    WHEN TRIM(sir.record_type) IN ('20', '22') THEN
+                        COALESCE(po_sales_pick.sales_contract_no, po_pick.nps_no)
+                    ELSE NULL
+                END
+            ELSE NULL
+        END AS sourceOrderNo
         FROM stock_in_record as sir
         LEFT JOIN product_model as pm on sir.product_model_id = pm.id
         LEFT JOIN product as p on pm.product_id = p.id
         LEFT JOIN sys_user as u on sir.create_user = u.user_id
+        LEFT JOIN quality_inspect as qi_purchase on TRIM(sir.record_type) = '10' and sir.record_id = qi_purchase.id
+        LEFT JOIN sales_ledger_product as slp on TRIM(sir.record_type) = '7' and slp.id = sir.record_id and slp.type = 2
+        LEFT JOIN purchase_ledger as pl_by_product on TRIM(sir.record_type) = '7' and pl_by_product.id = slp.sales_ledger_id
+        LEFT JOIN purchase_ledger as pl_direct on TRIM(sir.record_type) = '7' and pl_direct.id = sir.record_id
+        LEFT JOIN purchase_ledger as pl_by_quality on TRIM(sir.record_type) = '10' and pl_by_quality.id = qi_purchase.purchase_ledger_id
+
+        LEFT JOIN production_product_main as ppm_main on TRIM(sir.record_type) IN ('2', '5') and sir.record_id = ppm_main.id
+        LEFT JOIN production_operation_task as pot_main on ppm_main.production_operation_task_id = pot_main.id
+        LEFT JOIN production_order as po_main on pot_main.production_order_id = po_main.id
+        LEFT JOIN (
+            select po2.id as production_order_id,
+                   group_concat(distinct sl2.sales_contract_no order by sl2.sales_contract_no separator ',') as sales_contract_no
+            from production_order po2
+                     left join production_plan pp2
+                               on find_in_set(pp2.id, replace(replace(replace(po2.production_plan_ids, '[', ''), ']', ''), ' ', '')) > 0
+                     left join sales_ledger sl2 on sl2.id = pp2.sales_ledger_id
+            group by po2.id
+        ) as po_sales_main on po_sales_main.production_order_id = po_main.id
+
+        LEFT JOIN quality_inspect as qi_prod on TRIM(sir.record_type) = '6' and sir.record_id = qi_prod.id
+        LEFT JOIN production_product_main as ppm_qi on qi_prod.product_main_id = ppm_qi.id
+        LEFT JOIN production_operation_task as pot_qi on ppm_qi.production_operation_task_id = pot_qi.id
+        LEFT JOIN production_order as po_qi on pot_qi.production_order_id = po_qi.id
+        LEFT JOIN (
+            select po2.id as production_order_id,
+                   group_concat(distinct sl2.sales_contract_no order by sl2.sales_contract_no separator ',') as sales_contract_no
+            from production_order po2
+                     left join production_plan pp2
+                               on find_in_set(pp2.id, replace(replace(replace(po2.production_plan_ids, '[', ''), ']', ''), ' ', '')) > 0
+                     left join sales_ledger sl2 on sl2.id = pp2.sales_ledger_id
+            group by po2.id
+        ) as po_sales_qi on po_sales_qi.production_order_id = po_qi.id
+
+        LEFT JOIN quality_unqualified as qu on TRIM(sir.record_type) IN ('4', '11') and sir.record_id = qu.id
+        LEFT JOIN quality_inspect as qi_uq on qu.inspect_id = qi_uq.id
+        LEFT JOIN production_product_main as ppm_uq on qi_uq.product_main_id = ppm_uq.id
+        LEFT JOIN production_operation_task as pot_uq on ppm_uq.production_operation_task_id = pot_uq.id
+        LEFT JOIN production_order as po_uq on pot_uq.production_order_id = po_uq.id
+        LEFT JOIN (
+            select po2.id as production_order_id,
+                   group_concat(distinct sl2.sales_contract_no order by sl2.sales_contract_no separator ',') as sales_contract_no
+            from production_order po2
+                     left join production_plan pp2
+                               on find_in_set(pp2.id, replace(replace(replace(po2.production_plan_ids, '[', ''), ']', ''), ' ', '')) > 0
+                     left join sales_ledger sl2 on sl2.id = pp2.sales_ledger_id
+            group by po2.id
+        ) as po_sales_uq on po_sales_uq.production_order_id = po_uq.id
+
+        LEFT JOIN production_order_pick as pop on TRIM(sir.record_type) IN ('20', '22') and sir.record_id = pop.id
+        LEFT JOIN production_order as po_pick on pop.production_order_id = po_pick.id
+        LEFT JOIN (
+            select po2.id as production_order_id,
+                   group_concat(distinct sl2.sales_contract_no order by sl2.sales_contract_no separator ',') as sales_contract_no
+            from production_order po2
+                     left join production_plan pp2
+                               on find_in_set(pp2.id, replace(replace(replace(po2.production_plan_ids, '[', ''), ']', ''), ' ', '')) > 0
+                     left join sales_ledger sl2 on sl2.id = pp2.sales_ledger_id
+            group by po2.id
+        ) as po_sales_pick on po_sales_pick.production_order_id = po_pick.id
+
+        LEFT JOIN return_sale_product as rsp on TRIM(sir.record_type) IN ('14', '15') and sir.record_id = rsp.id
+        LEFT JOIN return_management as rm on rsp.return_management_id = rm.id
+        LEFT JOIN shipping_info as si_return on rm.shipping_id = si_return.id
+        LEFT JOIN sales_ledger as sl_return on si_return.sales_ledger_id = sl_return.id
         <where>
             <if test="params.timeStr != null and params.timeStr != ''">
                 and sir.create_time like concat('%',#{params.timeStr},'%')
diff --git a/src/main/resources/mapper/stock/StockInventoryMapper.xml b/src/main/resources/mapper/stock/StockInventoryMapper.xml
index 428e8da..6ca5bf7 100644
--- a/src/main/resources/mapper/stock/StockInventoryMapper.xml
+++ b/src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -512,8 +512,9 @@
           and (si.qualitity - ifnull(si.locked_quantity, 0)) > 0
         order by si.product_model_id, si.batch_no
     </select>
-    <select id="getByModelId" resultType="com.ruoyi.stock.pojo.StockInventory">
-        select si.id, si.batch_no, si.locked_quantity, (si.qualitity - IFNULL(sd.qualitity, 0)) as qualitity
+    <select id="getByModelId" resultType="com.ruoyi.stock.dto.StockInventoryDto">
+        select si.id, si.batch_no, si.locked_quantity, (si.qualitity - IFNULL(sd.qualitity, 0)) as qualitity,
+               p.product_name, pm.model, pm.unit
         from stock_inventory si
                  left join (
                     select spd.stock_inventory_id, sum(spd.quantity) as qualitity
@@ -530,6 +531,8 @@
                     )
                     group by spd.stock_inventory_id
                  ) as sd on sd.stock_inventory_id = si.id
+                 left join product_model pm on si.product_model_id = pm.id
+                 left join product p on pm.product_id = p.id
         where si.product_model_id = #{productModelId}
         and si.qualitity > IFNULL(sd.qualitity, 0)
     </select>

--
Gitblit v1.9.3