doc/20260522_²ÆÎñÖúÊÖÌáÎÊÓÅ»¯Ç°¶Ë±ä¸üÎĵµ.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. è§£æ `options` åæ°å¹¶è½¬æ¢ä¸º ECharts `option` 忏²æå¾è¡¨ç»ä»¶ã 3. è§£æå¤±è´¥æ¶ä¸å±ç¤ºåå§é¿é¾æ¥ææ¬ï¼å±ç¤ºç»ä¸ç©ºææç¤ºã ## 5. èè°å彿¸ å 1. ç¹å»å¿«æ·æé® `çææ¬å¨ç»è¥å¨æ¥ï¼å©æ¶¦ä¸ç°éæµï¼` - æ ¡éªè¿å `type=financial_operation_report`ï¼å¹¶æ£å¸¸æ¸²ææè¦/建议/å¾è¡¨ã 2. ç¹å»å¿«æ·æé® `åææ¬æå©æ¶¦ä¸éåå ` - æ ¡éªè¿å `type=financial_order_profit_analysis`ï¼å¹¶å±ç¤ºäºæè®¢åä¸å®¢æ·å©æ¶¦æè¡ã 3. ç¹å»å¿«æ·æé® `è¿30天åªä¸ªå®¢æ·å©æ¶¦è´¡ç®æé«` - æ ¡éªè¿å `type=financial_order_profit_analysis`ï¼`summary.topCustomerByProfit` æå¼ã 4. æå·¥è¾å ¥ `åªä¸ªå®¢æ·æèµé±`ã`åªä¸ªå®¢æ·å©æ¶¦æé«` - æ ¡éªä»å½ä¸ `financial_order_profit_analysis`ï¼ä¸ååºç°åå§å¾è¡¨ Markdown 龿¥ç´åºã doc/20260522_²ÆÎñÉý¼¶AIÄ£¿éǰ¶Ë±ä¸üÁªµ÷Îĵµ.md
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,150 @@ # è´¢å¡æ¨¡åå级å AI 模ååç«¯åæ´èè°ææ¡£ï¼éè´/éå®/ç产/å¾ åï¼ æ´æ°æ¥æï¼2026-05-22 éç¨èå´ï¼`/sales-ai`ã`/purchase-ai`ã`/manufacturing-ai`ã`/xiaozhi`ï¼å®¡æ¹å¾ åï¼ ## 1. åæ´æ»è§ | 模å | 坹夿¥å£ | æ¯å¦éè¦å端æ¹é | ç»è®º | | --- | --- | --- | --- | | éå® AI | `POST /sales-ai/chat` | æ¯ | è´¢å¡å£å¾åæ¢å°æ°æ¶æ¬¾æ¨¡åï¼é¨å `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 | æ¶æ¬¾æ¥æï¼yyyy-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`ï¼éå®å°è´¦ï¼ åæ®µç»æä¸åï¼ä½éé¢å£å¾å·²åæ¢ï¼ - `receivedAmount` ç±æ°æ¶æ¬¾æ¨¡åæ±æ»å¾å°ï¼ - `pendingAmount = max(0, invoicedAmount - receivedAmount)`ï¼ - è¥æ¶æ¬¾è®°å½æªæ¾å¼å ³èå°è´¦ï¼åæå®¢æ·ç»´åº¦å åºå½éã å端æ¹é å»ºè®®ï¼ - 䏿¹å段åï¼ - éç¹åå½âå·²æ¶éé¢/å¾ åæ¬¾éé¢âæ¯å¦ä¸è´¢å¡å°è´¦ä¸è´ã ## 3. éè´ AI åæ´ï¼`/purchase-ai/chat`ï¼ ### 3.1 `type = purchase_stats`ï¼éè´ç»è®¡ï¼ 以ä¸å段已ä»å ä½å¼æ¹ä¸ºçå®ç»è®¡å¼ï¼ - `summary.paymentCount` - `summary.invoiceCount` - `summary.paymentAmount` - `summary.invoiceAmount` å票éé¢å£å¾ï¼ - ä¼å `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` éé¢å段å£å¾ï¼ - `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 è§£æã 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. å¾ åæé®ï¼âæ¥è¯¢æçå¾ å®¡æ¹å表â - æ ¡éªè¿åç»æä¸å级åä¸è´ï¼æ åæ®µç ´åï¼ã doc/20260522_Ê×Ò³²ÆÎñ½Ó¿ÚÉý¼¶Ç°¶Ë±ä¸üÎĵµ.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. è¿ååæ®µå£å¾åæ´ ### 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. åç«¯åæ®µæ å°æ éè°æ´ï¼å¯ç´æ¥æ²¿ç¨ç°æè§£æé»è¾ã 2. ç¾åæ¯å段ä»ä¸ºä¸å¸¦ `%` çå符串ï¼å端å¦éå±ç¤º `%` 请继ç»åç«¯æ¼æ¥ã 3. æ¬æ¬¡å端è¿åå¼ç±çå®è´¢å¡æ°æ®é©±å¨ï¼å»ºè®®éç¹åå½å¡çæ±æ»ä¸è¶å¿å¾çæ°å¼èå¨ã src/main/java/com/ruoyi/account/bean/dto/AccountDto.java
ÎļþÒÑɾ³ý src/main/java/com/ruoyi/account/bean/dto/AccountDto2.java
ÎļþÒÑɾ³ý src/main/java/com/ruoyi/account/bean/dto/AccountDto3.java
ÎļþÒÑɾ³ý src/main/java/com/ruoyi/account/bean/dto/AccountReportDto.java
ÎļþÃû´Ó src/main/java/com/ruoyi/account/bean/dto/ReportDateDto.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; } 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; } } 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)); } } 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); } 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); } 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; } } 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("æ¬å¹´", "") 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)) { 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; } 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); }); 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; } 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); // éè´å°è´¦ï¼type = 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; } 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); // 使ç¨ååºéåæå»ºæä½å表ï¼å ååç¶ï¼ç¡®ä¿å·¥èºè·¯çº¿é¡ºåºæ£ç¡®ï¼ // ä½¿ç¨æ·±åº¦ä½ä¸ºæåºä¾æ®çè¾ å©ç»æ 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() 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); 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; } 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); } 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()); } } 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") 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; } 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); } 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); } } 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; } 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)); } 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; /** 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); 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); } 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; } 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(); } } 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); } 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()); } // 妿æ¯ç产éæå ¥åºï¼æ¢å¤éææ°éï¼å ä¸ºé©³åæ¶å·²æ£åï¼ 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(); } } 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; } src/main/resources/financial-agent-prompt.txt
@@ -6,6 +6,6 @@ 2. å½ä¸ææ¬ã婿¶¦ãåºåèµéãç°éæµãé¢è¦ã驾驶è±ãæ¥æ¥å¨æ¥åºæ¯æ¶ï¼ä¼å è°ç¨å¯¹åºå·¥å ·ã 3. å·¥å ·è¿å JSON æ¶ï¼ç´æ¥è¾åºåå§ JSON å符串ï¼ä¸è¦é¢å¤å 裹 Markdownï¼ä¹ä¸è¦å¨åå追å è§£éææ¬ã 4. å½ç¨æ·é®é¢ç¼ºå°æ¶é´èå´æ¶ï¼é»è®¤ä½¿ç¨å·¥å ·å ç½®å£å¾ï¼å¦è¿30å¤©ãæ¬æãè¿90天ï¼ï¼å¹¶å¨åç»å¯æéç¨æ·è¡¥å èå´ã 5. ç¨æ·é®â为ä»ä¹å©æ¶¦ä¸éââåªä¸ªè®¢åäºæââåªä¸ªå®¢æ·æèµé±ââåªä¸ªè½¦é´/å·¥åºææ¬æé«âçé®é¢æ¶ï¼ä¼å åºäºè®¢å婿¶¦ä¸å·¥åºææ¬åæå·¥å ·ä½çã 5. ç¨æ·é®â为ä»ä¹å©æ¶¦ä¸éââåªä¸ªè®¢åäºæââåªä¸ªå®¢æ·æèµé±ââåªä¸ªå®¢æ·å©æ¶¦è´¡ç®æé«ââåªä¸ªè½¦é´/å·¥åºææ¬æé«âçé®é¢æ¶ï¼ä¼å åºäºè®¢å婿¶¦ä¸å·¥åºææ¬åæå·¥å ·ä½çã 6. åçå¿ é¡»ä½¿ç¨ä¸æï¼è¥æ°æ®ä¸è¶³ä»¥å¾åºç»è®ºï¼æç¡®æåºç¼ºå°åªäºå ³é®å段æç鿡件ã 7. ç¨æ·æå°âä»å¹´/æ¬æ/ä»å¤©/æè¿/䏿/å»å¹´âçç¸å¯¹æ¶é´æ¶ï¼å¿ é¡»ä¸¥æ ¼åºäºâå½åæ¥æâæ¢ç®ï¼ç¦æ¢èªè¡å设年份ã 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> 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> 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> 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 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> 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>