From 9944c43ec57c79d3eb72f09ac797e9d2b772dedd Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期五, 22 五月 2026 16:40:08 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_New_pro' into dev_鹤壁_强信宇_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/resources/mapper/sales/SalesLedgerMapper.xml | 16
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/ai/tools/PurchaseAgentTools.java | 4
src/main/java/com/ruoyi/purchase/service/PurchaseReportService.java | 14
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/resources/mapper/account/purchase/AccountPaymentApplicationMapper.xml | 2
src/main/java/com/ruoyi/stock/controller/StockInRecordController.java | 11
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/account/controller/AccountingController.java | 24
src/main/java/com/ruoyi/purchase/controller/AccountingReportController.java | 26
src/main/java/com/ruoyi/sales/mapper/SalesLedgerMapper.java | 4
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java | 52 +
src/main/resources/financial-agent-prompt.txt | 2
src/main/java/com/ruoyi/ai/tools/SalesAgentTools.java | 114 ---
src/main/java/com/ruoyi/ai/assistant/FinancialIntentExecutor.java | 22
doc/20260522_财务助手提问优化前端变更文档.md | 59 +
doc/20260522_首页财务接口升级前端变更文档.md | 120 +++
doc/20260522_财务升级AI模块前端变更联调文档.md | 150 ++++
src/main/java/com/ruoyi/purchase/dto/VatDto.java | 17
src/main/java/com/ruoyi/account/service/AccountingService.java | 19
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java | 2
src/main/java/com/ruoyi/account/bean/dto/AccountReportDto.java | 19
src/main/resources/mapper/stock/StockInventoryMapper.xml | 7
src/main/java/com/ruoyi/purchase/vo/PurchaseReportVo.java | 44 +
src/main/java/com/ruoyi/account/bean/vo/AccountReportVo.java | 66 ++
src/main/java/com/ruoyi/quality/pojo/QualityInspect.java | 5
src/main/resources/mapper/account/sales/AccountInvoiceApplicationMapper.xml | 2
src/main/resources/mapper/production/ProductionOperationTaskMapper.xml | 2
/dev/null | 39 -
src/main/java/com/ruoyi/device/service/impl/DeviceLedgerServiceImpl.java | 5
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/account/service/impl/AccountingServiceImpl.java | 189 ++++++
src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java | 16
42 files changed, 1,428 insertions(+), 421 deletions(-)
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 鏂囨湰灞曠ず锛堝 ``锛夈��
+- 蹇嵎鎻愰棶缂哄皯鏃堕棿鑼冨洿鍜屽垎鏋愮洰鏍囷紝缁撴灉绋冲畾鎬т笌鍙В閲婃�ц緝寮便��
+
+## 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_\350\264\242\345\212\241\345\215\207\347\272\247AI\346\250\241\345\235\227\345\211\215\347\253\257\345\217\230\346\233\264\350\201\224\350\260\203\346\226\207\346\241\243.md" "b/doc/20260522_\350\264\242\345\212\241\345\215\207\347\272\247AI\346\250\241\345\235\227\345\211\215\347\253\257\345\217\230\346\233\264\350\201\224\350\260\203\346\226\207\346\241\243.md"
new file mode 100644
index 0000000..e011374
--- /dev/null
+++ "b/doc/20260522_\350\264\242\345\212\241\345\215\207\347\272\247AI\346\250\241\345\235\227\345\211\215\347\253\257\345\217\230\346\233\264\350\201\224\350\260\203\346\226\207\346\241\243.md"
@@ -0,0 +1,150 @@
+# 璐㈠姟妯″潡鍗囩骇鍚� AI 妯″潡鍓嶇鍙樻洿鑱旇皟鏂囨。锛堥噰璐�/閿�鍞�/鐢熶骇/寰呭姙锛�
+
+鏇存柊鏃ユ湡锛�2026-05-22
+閫傜敤鑼冨洿锛歚/sales-ai`銆乣/purchase-ai`銆乣/manufacturing-ai`銆乣/xiaozhi`锛堝鎵瑰緟鍔烇級
+
+## 1. 鍙樻洿鎬昏
+
+| 妯″潡 | 瀵瑰鎺ュ彛 | 鏄惁闇�瑕佸墠绔敼閫� | 缁撹 |
+| --- | --- | --- | --- |
+| 閿�鍞� AI | `POST /sales-ai/chat` | 鏄� | 璐㈠姟鍙e緞鍒囨崲鍒版柊鏀舵妯″瀷锛岄儴鍒� `type` 鐨勫瓧娈佃涔夊彉鍖� |
+| 閲囪喘 AI | `POST /purchase-ai/chat` | 鏄� | 浠樻/鍙戠エ/寰呬粯娆捐绠楀垏鎹㈠埌鏂拌储鍔¢摼璺紝缁熻鍊间粠鍗犱綅鏀逛负鐪熷疄鍊� |
+| 鐢熶骇 AI | `POST /manufacturing-ai/chat` | 鍚� | 宸叉牳鏌ワ紝鏃犳棫璐㈠姟閫昏緫渚濊禆锛屾棤瀛楁鍙樻洿 |
+| 寰呭姙 AI | `POST /xiaozhi/chat` | 鍚� | 宸叉牳鏌ワ紝鏃犳棫璐㈠姟閫昏緫渚濊禆锛屾棤瀛楁鍙樻洿 |
+
+## 2. 閿�鍞� AI 鍙樻洿锛坄/sales-ai/chat`锛�
+
+### 2.1 `type = sales_return_list`锛堥攢鍞��娆�/鍥炴璁板綍锛�
+
+褰撳墠杩斿洖鏁版嵁鏉ユ簮缁熶竴涓烘柊璐㈠姟琛� `account_sales_collection`锛屼笉鍐嶈蛋鏃ф敹娆鹃��璐ч�昏緫銆�
+
+`data.items[]` 鍏抽敭瀛楁锛�
+
+| 瀛楁 | 绫诲瀷 | 璇存槑 |
+| --- | --- | --- |
+| id | number | 鏀舵璁板綍ID |
+| refundId | string | 鏄犲皠 `collectionNumber`锛屽墠绔彲缁х画浣滀负鈥滈��娆�/鍥炴鍗曞彿鈥濆睍绀� |
+| collectionNumber | string | 鏀舵鍗曞彿 |
+| paymentMethod | string | 鏀舵鏂瑰紡 |
+| actualAmount | number | 鏀舵閲戦锛堜笌 `collectionAmount` 鍚屽�硷級 |
+| collectionAmount | number | 鏀舵閲戦锛堟帹鑽愪富灞曠ず瀛楁锛� |
+| customerId | number | 瀹㈡埛ID |
+| remark | string | 澶囨敞 |
+| createTime | string | 鏀舵鏃ユ湡锛坹yyy-MM-dd锛� |
+
+`summary` 澧為噺鍏虫敞锛�
+- `returnAmount`锛氭椂闂磋寖鍥村唴閲戦姹囨�伙紙鎸� `collectionAmount` 缁熻锛�
+
+### 2.2 `type = sales_customer_interaction_list`锛堝鎴峰線鏉ワ級
+
+褰撳墠杩斿洖鍩轰簬鏂伴摼璺細
+`account_sales_collection.stock_out_record_ids -> stock_out_record(record_type=13) -> shipping_info -> sales_ledger`
+
+杩斿洖绾﹀畾锛�
+- 鏃犳暟鎹椂锛歚description = "no_customer_interactions"`
+- 鏈夋暟鎹椂锛歚description = "ok"`
+
+`summary` 鍏抽敭瀛楁锛�
+- `totalReceiptAmount`
+- `customerCount`
+
+`data.items[]` 鍏抽敭瀛楁锛�
+- `salesLedgerId`
+- `salesContractNo`
+- `customerName`
+- `projectName`
+- `receiptPaymentDate`
+- `receiptPaymentAmount`
+- `receiptPaymentType`
+- `collectionNumber`
+- `registrant`
+- `remark`
+
+### 2.3 `type = sales_ledger_list`锛堥攢鍞彴璐︼級
+
+瀛楁缁撴瀯涓嶅彉锛屼絾閲戦鍙e緞宸插垏鎹細
+- `receivedAmount` 鐢辨柊鏀舵妯″瀷姹囨�诲緱鍒帮紱
+- `pendingAmount = max(0, invoicedAmount - receivedAmount)`锛�
+- 鑻ユ敹娆捐褰曟湭鏄惧紡鍏宠仈鍙拌处锛屽垯鎸夊鎴风淮搴﹀厹搴曞綊闆嗐��
+
+鍓嶇鏀归�犲缓璁細
+- 涓嶆敼瀛楁鍚嶏紱
+- 閲嶇偣鍥炲綊鈥滃凡鏀堕噾棰�/寰呭洖娆鹃噾棰濃�濇槸鍚︿笌璐㈠姟鍙拌处涓�鑷淬��
+
+## 3. 閲囪喘 AI 鍙樻洿锛坄/purchase-ai/chat`锛�
+
+### 3.1 `type = purchase_stats`锛堥噰璐粺璁★級
+
+浠ヤ笅瀛楁宸蹭粠鍗犱綅鍊兼敼涓虹湡瀹炵粺璁″�硷細
+- `summary.paymentCount`
+- `summary.invoiceCount`
+- `summary.paymentAmount`
+- `summary.invoiceAmount`
+
+鍙戠エ閲戦鍙e緞锛�
+- 浼樺厛 `taxInclusivePrice`
+- 鑻ヤ负绌�/0锛屽垯浣跨敤 `taxExclusivelPrice + taxPrice`
+
+### 3.2 `type = purchase_pending_payment_list`锛堝緟浠樻閲囪喘鍗曪級
+
+鏍稿績璁$畻宸插垏鎹㈠埌鏂拌储鍔¢摼璺細
+
+`account_purchase_payment -> account_payment_application -> stock_in_record -> (purchase_ledger / quality_inspect) -> purchase_ledger_id`
+
+鏄犲皠瑙勫垯锛�
+1. `stock_in_record.record_type = 7`锛歚record_id` 鐩存帴瑙嗕负 `purchase_ledger_id`
+2. `stock_in_record.record_type = 10`锛氶�氳繃 `quality_inspect.id = record_id` 鍙� `quality_inspect.purchase_ledger_id`
+
+閲戦瀛楁鍙e緞锛�
+- `paidAmount`锛氭柊閾捐矾绱宸蹭粯娆鹃噾棰�
+- `pendingAmount = contractAmount - paidAmount`锛�<=0 鐨勮褰曚笉杩斿洖锛�
+
+`summary` 鍏抽敭瀛楁锛堝潎涓虹湡瀹炲�硷級锛�
+- `pendingOrderCount`
+- `totalContractAmount`
+- `totalPaidAmount`
+- `totalPendingAmount`
+
+### 3.3 鏁版嵁娓呮礂淇
+
+宸蹭慨澶� `record_type` 甯︾┖鏍煎鑷寸殑鏄犲皠涓㈠け闂锛堝悗绔粺涓� `trim()` 鍚庡啀鍒ゆ柇 `7/10`锛夈��
+
+## 4. 鐢熶骇 AI / 寰呭姙 AI 鏍告煡缁撹
+
+宸叉牳鏌ヤ互涓嬫ā鍧椾唬鐮侊紝鏈彂鐜版棫璐㈠姟閫昏緫鑰﹀悎鐐癸細
+- `ManufacturingAgentTools`锛堢敓浜э級
+- `ApproveTodoTools`锛堝緟鍔炲鎵癸級
+
+缁撹锛�
+- 瀵瑰 `type` 涓庡瓧娈电粨鏋勬棤鍙樻洿锛�
+- 鍓嶇鏃犻渶鍋氬吋瀹规敼閫狅紝浠呴渶鍋氫竴娆″洖褰掗獙璇併��
+
+## 5. 鍓嶇鑱旇皟瑕佺偣
+
+1. `/sales-ai/chat`銆乣/purchase-ai/chat` 缁х画鎸� SSE 鏂囨湰娴佹嫾鎺ュ悗鍋� JSON 瑙f瀽銆�
+2. 鎸� `type` 璺敱娓叉煋锛屼笉瑕佷粎渚濊禆 `description` 鏂囨銆�
+3. `sales_customer_interaction_list` 闇�鍏煎 `description` 鏋氫妇锛歚ok` / `no_customer_interactions`銆�
+4. `sales_return_list` 閲戦灞曠ず缁熶竴鐢� `collectionAmount`锛坄actualAmount` 淇濈暀鍏煎锛夈��
+5. `purchase_pending_payment_list` 鐨勬眹鎬诲崱鐗囪鐩存帴璇诲彇 `summary.totalPendingAmount` 绛夊瓧娈碉紝涓嶅啀鍓嶇浜屾浼扮畻銆�
+
+## 6. 鍥炲綊娓呭崟锛堝缓璁級
+
+### 閿�鍞�
+1. 鎻愰棶锛氣�滆繎30澶╁摢涓鍗曞洖娆炬渶灏戔��
+ - 鏍¢獙 `sales_ledger_list` 鐨� `receivedAmount/pendingAmount`銆�
+2. 鎻愰棶锛氣�滄煡璇㈡湰鏈堥攢鍞��娆锯��
+ - 鏍¢獙 `sales_return_list` 鐨� `collectionNumber/collectionAmount/returnAmount`銆�
+3. 鎻愰棶锛氣�滄煡璇㈡湰鏈堝鎴峰線鏉モ��
+ - 鏍¢獙 `sales_customer_interaction_list` 鐨� `totalReceiptAmount/customerCount`銆�
+
+### 閲囪喘
+1. 鎻愰棶锛氣�滅粺璁℃湰鏈堥噰璐暟鎹��
+ - 鏍¢獙 `purchase_stats` 鐨� `paymentCount/invoiceCount/paymentAmount/invoiceAmount` 闈炲浐瀹�0銆�
+2. 鎻愰棶锛氣�滃垪鍑哄緟浠樻閲囪喘鍗曗��
+ - 鏍¢獙 `purchase_pending_payment_list` 鐨� `paidAmount/pendingAmount` 涓庤储鍔″疄闄呬竴鑷淬��
+
+### 鐢熶骇/寰呭姙
+1. 鐢熶骇鎻愰棶锛氣�滄煡璇㈡湰鍛ㄨ澶囩淮淇褰曗��
+2. 寰呭姙鎻愰棶锛氣�滄煡璇㈡垜鐨勫緟瀹℃壒鍒楄〃鈥�
+ - 鏍¢獙杩斿洖缁撴瀯涓庡崌绾у墠涓�鑷达紙鏃犲瓧娈电牬鍧忥級銆�
+
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/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/ai/tools/PurchaseAgentTools.java b/src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java
index a294b68..bdd1f1f 100644
--- a/src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java
+++ b/src/main/java/com/ruoyi/ai/tools/PurchaseAgentTools.java
@@ -591,7 +591,7 @@
private Map<Long, Long> queryPurchaseLedgerIdByQualityInspectId(Collection<StockInRecord> stockInRecords) {
Set<Long> qualityInspectIds = stockInRecords.stream()
.filter(Objects::nonNull)
- .filter(item -> item.getRecordId() != null && "10".equals(safe(item.getRecordType())))
+ .filter(item -> item.getRecordId() != null && "10".equals(safe(item.getRecordType()).trim()))
.map(StockInRecord::getRecordId)
.collect(Collectors.toSet());
if (qualityInspectIds.isEmpty()) {
@@ -614,7 +614,7 @@
if (stockInRecord.getApprovalStatus() != null && stockInRecord.getApprovalStatus() != 1) {
continue;
}
- String recordType = safe(stockInRecord.getRecordType());
+ String recordType = safe(stockInRecord.getRecordType()).trim();
if ("7".equals(recordType)) {
result.add(stockInRecord.getRecordId());
} else if ("10".equals(recordType)) {
diff --git a/src/main/java/com/ruoyi/ai/tools/SalesAgentTools.java b/src/main/java/com/ruoyi/ai/tools/SalesAgentTools.java
index 8a63db7..0f7e586 100644
--- a/src/main/java/com/ruoyi/ai/tools/SalesAgentTools.java
+++ b/src/main/java/com/ruoyi/ai/tools/SalesAgentTools.java
@@ -121,60 +121,6 @@
@P(value = "杩斿洖鏉℃暟锛岄粯璁�10锛屾渶澶�30", required = false) Integer limit) {
LoginUser loginUser = currentLoginUser(memoryId);
DateRange range = resolveDateRange(startDate, endDate, null);
- /*
- List<AccountSalesCollection> collections = queryCollections(loginUser, range);
- if (collections.isEmpty()) {
- return jsonResponse(true, "sales_customer_interaction_list", "閺堫亝鐓$拠銏犲煂鐎广垺鍩涘鈧弶銉唶瑜�?, rangeSummary(range, 0, keyword), Map.of("items", List.of()), Map.of());
- }
-
- Map<Integer, Set<Long>> ledgerIdsByCollectionId = mapCollectionLedgerIds(loginUser, collections);
- Set<Long> ledgerIds = ledgerIdsByCollectionId.values().stream()
- .flatMap(Collection::stream)
- .collect(Collectors.toSet());
- Map<Long, SalesLedger> ledgerMap = defaultList(salesLedgerMapper.selectBatchIds(ledgerIds)).stream()
- .filter(ledger -> tenantMatched(ledger.getTenantId(), loginUser.getTenantId()))
- .collect(Collectors.toMap(SalesLedger::getId, item -> item, (a, b) -> a, LinkedHashMap::new));
-
- int finalLimit = normalizeLimit(limit);
- List<Map<String, Object>> items = new ArrayList<>();
- for (AccountSalesCollection collection : collections) {
- Set<Long> relatedLedgerIds = ledgerIdsByCollectionId.get(collection.getId());
- if (relatedLedgerIds == null || relatedLedgerIds.isEmpty()) {
- if (!matchInteractionKeyword(collection, null, keyword)) {
- continue;
- }
- items.add(toInteractionItem(collection, null));
- if (items.size() >= finalLimit) {
- break;
- }
- continue;
- }
- for (Long ledgerId : relatedLedgerIds) {
- SalesLedger ledger = ledgerMap.get(ledgerId);
- if (ledger == null || !matchInteractionKeyword(collection, ledger, keyword)) {
- continue;
- }
- items.add(toInteractionItem(collection, ledger));
- if (items.size() >= finalLimit) {
- break;
- }
- }
- if (items.size() >= finalLimit) {
- break;
- }
- }
-
- BigDecimal totalReceiptAmount = items.stream()
- .map(item -> asBigDecimal(item.get("receiptPaymentAmount")))
- .reduce(BigDecimal.ZERO, BigDecimal::add);
- Map<String, Object> summary = rangeSummary(range, items.size(), keyword);
- summary.put("totalReceiptAmount", totalReceiptAmount);
- summary.put("customerCount", items.stream()
- .map(item -> String.valueOf(item.get("customerName")))
- .filter(StringUtils::hasText)
- .distinct()
- .count());
- */
LambdaQueryWrapper<SalesQuotation> wrapper = new LambdaQueryWrapper<>();
applyTenantFilter(wrapper, loginUser.getTenantId(), SalesQuotation::getTenantId);
applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), SalesQuotation::getDeptId);
@@ -398,59 +344,7 @@
.filter(StringUtils::hasText)
.distinct()
.count());
- if (summary.size() >= 0) {
- return jsonResponse(true, "sales_customer_interaction_list", "ok", summary, Map.of("items", items), Map.of());
- }
-// LambdaQueryWrapper<ReceiptPayment> wrapper = new LambdaQueryWrapper<>();
-// applyTenantFilter(wrapper, loginUser.getTenantId(), ReceiptPayment::getTenantId);
-// applyDeptFilter(wrapper, loginUser.getCurrentDeptId(), ReceiptPayment::getDeptId);
-// wrapper.ge(ReceiptPayment::getReceiptPaymentDate, range.start())
-// .le(ReceiptPayment::getReceiptPaymentDate, range.end())
-// .orderByDesc(ReceiptPayment::getReceiptPaymentDate, ReceiptPayment::getId);
-// List<ReceiptPayment> payments = defaultList(receiptPaymentMapper.selectList(wrapper));
-// if (payments.isEmpty()) {
-// return jsonResponse(true, "sales_customer_interaction_list", "鏈煡璇㈠埌瀹㈡埛寰�鏉ヨ褰�", rangeSummary(range, 0, keyword), Map.of("items", List.of()), Map.of());
-// }
-//
-// List<Long> ledgerIds = payments.stream()
-// .map(ReceiptPayment::getSalesLedgerId)
-// .filter(Objects::nonNull)
-// .distinct()
-// .collect(Collectors.toList());
-// Map<Long, SalesLedger> ledgerMap = defaultList(salesLedgerMapper.selectBatchIds(ledgerIds)).stream()
-// .filter(ledger -> tenantMatched(ledger.getTenantId(), loginUser.getTenantId()))
-// .collect(Collectors.toMap(SalesLedger::getId, item -> item, (a, b) -> a, LinkedHashMap::new));
-//
-// List<ReceiptPayment> filtered = payments.stream()
-// .filter(item -> matchInteractionKeyword(item, ledgerMap.get(item.getSalesLedgerId()), keyword))
-// .limit(normalizeLimit(limit))
-// .collect(Collectors.toList());
-//
-// BigDecimal totalReceiptAmount = filtered.stream()
-// .map(ReceiptPayment::getReceiptPaymentAmount)
-// .filter(Objects::nonNull)
-// .reduce(BigDecimal.ZERO, BigDecimal::add);
-
-// List<Map<String, Object>> items = filtered.stream().map(item -> {
-// SalesLedger ledger = ledgerMap.get(item.getSalesLedgerId());
-// Map<String, Object> map = new LinkedHashMap<>();
-// map.put("id", item.getId());
-// map.put("salesLedgerId", item.getSalesLedgerId());
-// map.put("salesContractNo", ledger == null ? "" : safe(ledger.getSalesContractNo()));
-// map.put("customerName", ledger == null ? "" : safe(ledger.getCustomerName()));
-// map.put("projectName", ledger == null ? "" : safe(ledger.getProjectName()));
-// map.put("receiptPaymentDate", formatDate(item.getReceiptPaymentDate()));
-// map.put("receiptPaymentAmount", item.getReceiptPaymentAmount());
-// map.put("receiptPaymentType", safe(item.getReceiptPaymentType()));
-// map.put("registrant", safe(item.getRegistrant()));
-// return map;
-// }).collect(Collectors.toList());
-
-// Map<String, Object> summary = rangeSummary(range, items.size(), keyword);
-// summary.put("totalReceiptAmount", totalReceiptAmount);
-// summary.put("customerCount", items.stream().map(item -> String.valueOf(item.get("customerName"))).filter(StringUtils::hasText).distinct().count());
-// return jsonResponse(true, "sales_customer_interaction_list", "宸茶繑鍥炲鎴峰線鏉ユ槑缁�", summary, Map.of("items", items), Map.of());
- return jsonResponse(true, "sales_customer_interaction_list", "宸茶繑鍥炲鎴峰線鏉ユ槑缁�", null, Map.of("items", List.of()), Map.of());
+ return jsonResponse(true, "sales_customer_interaction_list", "ok", summary, Map.of("items", items), Map.of());
}
@Tool(name = "鏌ヨ鍙戣揣鍙拌处", value = "鎸夊叧閿瘝鍜屾椂闂磋寖鍥存煡璇㈠彂璐у彴璐�")
@@ -965,12 +859,6 @@
return Map.of();
}
Map<Long, BigDecimal> result = new HashMap<>();
-// for (InvoiceLedgerDto item : defaultList(invoiceLedgerMapper.invoicedTotal(ledgerIds))) {
-// if (item.getSalesLedgerId() == null) {
-// continue;
-// }
-// result.merge(item.getSalesLedgerId().longValue(), defaultDecimal(item.getInvoiceTotal()), BigDecimal::add);
-// }
return result;
}
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..4f6ebd6 100644
--- a/src/main/java/com/ruoyi/device/service/impl/DeviceLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/device/service/impl/DeviceLedgerServiceImpl.java
@@ -116,7 +116,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/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/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/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/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/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/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/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/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/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