From 1fccd0a7eb0b06e757f677de6279edab0bc81236 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期五, 22 五月 2026 13:08:34 +0800
Subject: [PATCH] refactor(home): 重构首页财务统计功能实现

---
 src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java |  463 ++++++++++++++++++++++-----------------------------------
 1 files changed, 181 insertions(+), 282 deletions(-)

diff --git a/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java b/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
index 395a414..fac571b 100644
--- a/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
+++ b/src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -3,9 +3,12 @@
 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.ruoyi.account.mapper.AccountExpenseMapper;
-import com.ruoyi.account.mapper.AccountIncomeMapper;
-import com.ruoyi.account.pojo.AccountExpense;
+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.AccountStatement;
+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;
@@ -30,18 +33,14 @@
 import com.ruoyi.production.mapper.*;
 import com.ruoyi.project.system.domain.SysDept;
 import com.ruoyi.project.system.mapper.SysDeptMapper;
-import com.ruoyi.purchase.mapper.PaymentRegistrationMapper;
 import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
-import com.ruoyi.purchase.pojo.PaymentRegistration;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
 import com.ruoyi.quality.mapper.QualityInspectMapper;
 import com.ruoyi.quality.mapper.QualityUnqualifiedMapper;
 import com.ruoyi.quality.pojo.QualityInspect;
 import com.ruoyi.quality.pojo.QualityUnqualified;
-import com.ruoyi.sales.mapper.ReceiptPaymentMapper;
 import com.ruoyi.sales.mapper.SalesLedgerMapper;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
-import com.ruoyi.sales.pojo.ReceiptPayment;
 import com.ruoyi.sales.pojo.SalesLedger;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.staff.mapper.StaffOnJobMapper;
@@ -83,37 +82,37 @@
 
     private final ApproveProcessMapper approveProcessMapper;
 
-    private final ReceiptPaymentMapper receiptPaymentMapper;
-
-    private final PaymentRegistrationMapper paymentRegistrationMapper;
-
-    private  SysDeptMapper sysDeptMapper;
+    private final SysDeptMapper sysDeptMapper;
 
     private final NoticeMapper noticeMapper;
-    
+
     private final ProductionOrderMapper productionOrderMapper;
 
     private final ProductMapper productMapper;
-    
+
     private final StaffOnJobMapper staffOnJobMapper;
-    
+
     private final CustomerMapper customerMapper;
-    
+
     private final SupplierManageMapper supplierManageMapper;
-    
+
     private final HomeMapper homeMapper;
-    
+
     private final ProductionProductOutputMapper productionProductOutputMapper;
-    
+
     private final QualityInspectMapper qualityInspectMapper;
-    
+
     private final QualityUnqualifiedMapper qualityUnqualifiedMapper;
-    
+
     private final ProductionOperationTaskMapper productionOperationTaskMapper;
-    
-    private final AccountExpenseMapper accountExpenseMapper;
-    
-    private final AccountIncomeMapper accountIncomeMapper;
+
+    private final AccountPurchasePaymentMapper accountPurchasePaymentMapper;
+    private final AccountSalesCollectionMapper accountSalesCollectionMapper;
+    private final AccountStatementMapper accountStatementMapper;
+
+    private final ProductionAccountMapper productionAccountMapper;
+
+    private final ProductionProductInputMapper productionProductInputMapper;
 
     @Override
     public HomeBusinessDto business() {
@@ -137,12 +136,8 @@
                             salesLedgers.stream().map(SalesLedger::getId).collect(Collectors.toList()));
             List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper
                     .selectList(salesLedgerProductMapperLambdaQueryWrapper);
-            // 鏈紑绁ㄩ噾棰�
-            BigDecimal noInvoiceAmountTotal = salesLedgerProducts.stream().map(SalesLedgerProduct::getNoInvoiceAmount)
-                    .filter(Objects::nonNull)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
             homeBusinessDto.setMonthSaleMoney(contractAmount.setScale(2, RoundingMode.HALF_UP).toString());
-            homeBusinessDto.setMonthSaleHaveMoney(noInvoiceAmountTotal.setScale(2, RoundingMode.HALF_UP).toString());
+            homeBusinessDto.setMonthSaleHaveMoney(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP).toString());
         }
         // 鍒涘缓LambdaQueryWrapper
         LambdaQueryWrapper<PurchaseLedger> queryWrapper = new LambdaQueryWrapper<>();
@@ -165,14 +160,8 @@
                     .filter(Objects::nonNull)
                     .reduce(BigDecimal.ZERO, BigDecimal::add);
 
-            //  寰呬粯娆炬�婚噾棰�
-            BigDecimal unReceiptPaymentAmount = salesLedgerProductsCopy.stream()
-                    .map(SalesLedgerProduct::getPendingTicketsTotal)
-                    .filter(Objects::nonNull)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-
             homeBusinessDto.setMonthPurchaseMoney(receiveAmount.setScale(2, RoundingMode.HALF_UP).toString());
-            homeBusinessDto.setMonthPurchaseHaveMoney(unReceiptPaymentAmount.setScale(2, RoundingMode.HALF_UP).toString());
+            homeBusinessDto.setMonthPurchaseHaveMoney(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP).toString());
         }
         // 缁熻搴撳瓨
         BigDecimal stockQuantityTotal = stockInventoryMapper.selectTotal();
@@ -410,76 +399,21 @@
      */
     @Override
     public StatisticsReceivablePayableDto statisticsReceivablePayable(Integer type) {
-        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;
-        }
-        // 搴旀敹
-        List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(new LambdaQueryWrapper<SalesLedger>()
-                // .ge(SalesLedger::getEntryDate, startDate)
-                // .lt(SalesLedger::getEntryDate, endDate)
-        );
-        // BigDecimal receivableMoney =
-        // salesLedgers.stream().map(SalesLedger::getContractAmount).reduce(BigDecimal.ZERO,
-        // BigDecimal::add);
-        BigDecimal receivableMoney = sumAmount(salesLedgers, SalesLedger::getContractAmount);
-        // 搴斾粯
-        List<PurchaseLedger> procurementRecords = purchaseLedgerMapper
-                .selectList(new LambdaQueryWrapper<PurchaseLedger>()
-                        // .ge(PurchaseLedger::getEntryDate, startDate)
-                        // .lt(PurchaseLedger::getEntryDate, endDate)
-                );
-        // BigDecimal payableMoney =
-        // procurementRecords.stream().map(PurchaseLedger::getContractAmount).reduce(BigDecimal.ZERO,
-        // BigDecimal::add);
-        BigDecimal payableMoney = sumAmount(procurementRecords, PurchaseLedger::getContractAmount);
-        // 棰勬敹
-        List<ReceiptPayment> receiptPayments = receiptPaymentMapper.selectList(new LambdaQueryWrapper<ReceiptPayment>()
-                // .ge(ReceiptPayment::getReceiptPaymentDate, startDate)
-                // .lt(ReceiptPayment::getReceiptPaymentDate, endDate)
-        );
-        // BigDecimal advanceMoney =
-        // receiptPayments.stream().map(ReceiptPayment::getReceiptPaymentAmount).reduce(BigDecimal.ZERO,
-        // BigDecimal::add);
-        BigDecimal advanceMoney = sumAmount(receiptPayments, ReceiptPayment::getReceiptPaymentAmount);
-        // 棰勪粯
-        List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper
-                .selectList(new LambdaQueryWrapper<PaymentRegistration>()
-                        // .ge(PaymentRegistration::getPaymentDate, startDate)
-                        // .lt(PaymentRegistration::getPaymentDate, endDate)
-                );
-        // BigDecimal prepayMoney =
-        // paymentRegistrations.stream().map(PaymentRegistration::getCurrentPaymentAmount).reduce(BigDecimal.ZERO,
-        // BigDecimal::add);
-        BigDecimal prepayMoney = sumAmount(paymentRegistrations, PaymentRegistration::getCurrentPaymentAmount);
-        StatisticsReceivablePayableDto statisticsReceivablePayableDto = new StatisticsReceivablePayableDto();
-        statisticsReceivablePayableDto.setPayableMoney(payableMoney.subtract(prepayMoney));
-        statisticsReceivablePayableDto.setReceivableMoney(receivableMoney.subtract(advanceMoney));
-        statisticsReceivablePayableDto.setAdvanceMoney(advanceMoney);
-        statisticsReceivablePayableDto.setPrepayMoney(prepayMoney);
+        BigDecimal receivableBase = sumSalesContractAmount(startDate, endDate);
+        BigDecimal payableBase = sumPurchaseContractAmount(startDate, endDate);
+        BigDecimal advanceMoney = sumCollectionAmount(startDate, endDate);
+        BigDecimal prepayMoney = sumPaymentAmount(startDate, endDate);
 
-        return statisticsReceivablePayableDto;
+        dto.setReceivableMoney(scaleMoney(maxZero(receivableBase.subtract(advanceMoney))));
+        dto.setPayableMoney(scaleMoney(maxZero(payableBase.subtract(prepayMoney))));
+        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) {
@@ -490,7 +424,7 @@
                 .reduce(BigDecimal.ZERO, BigDecimal::add);
     }
 
-    
+
     private DeviceRepairMapper deviceRepairMapper;
 
     @Override
@@ -1160,13 +1094,9 @@
         String endStr = endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
 
         // 2. 鏌ヨ鏁版嵁
-        List<IncomeExpenseAnalysisDto> incomeList = accountIncomeMapper.selectIncomeStats(startStr, endStr, dateFormat);
+        List<IncomeExpenseAnalysisDto> incomeList = accountSalesCollectionMapper.selectIncomeStats(startStr, endStr, dateFormat);
+        List<IncomeExpenseAnalysisDto> expenseList = accountPurchasePaymentMapper.selectPayment(startStr, endStr, dateFormat);
 
-        // List<IncomeExpenseAnalysisDto> purchaseList =
-        // purchaseLedgerMapper.selectPurchaseStats(startStr, endStr, dateFormat);
-
-        List<IncomeExpenseAnalysisDto> expenseList = accountExpenseMapper.selectAccountExpenseStats(startStr, endStr,
-                dateFormat);
 
         // 3. 杞� Map锛堣嚜鍔ㄥ悎骞讹級
         Map<String, BigDecimal> incomeMap = incomeList.stream()
@@ -1175,11 +1105,7 @@
                         IncomeExpenseAnalysisDto::getAmount,
                         BigDecimal::add));
 
-        // Map<String, BigDecimal> purchaseMap = purchaseList.stream()
-        // .collect(Collectors.toMap(
-        // IncomeExpenseAnalysisDto::getDateStr,
-        // IncomeExpenseAnalysisDto::getAmount,
-        // BigDecimal::add));
+
 
         Map<String, BigDecimal> expenseMap = expenseList.stream()
                 .collect(Collectors.toMap(
@@ -1193,18 +1119,12 @@
         for (String dateStr : xAxis) {
             Map<String, Object> item = new HashMap<>();
             item.put("date", dateStr);
-
             // 鏀跺叆
             BigDecimal income = incomeMap.getOrDefault(dateStr, BigDecimal.ZERO);
             item.put("income", income.setScale(2, RoundingMode.HALF_UP));
-
-            // 鏀嚭 = 閲囪喘 + 璐㈠姟鏀嚭
-            // BigDecimal purchase = purchaseMap.getOrDefault(dateStr, BigDecimal.ZERO);
+            // 鏀嚭
             BigDecimal expense = expenseMap.getOrDefault(dateStr, BigDecimal.ZERO);
-            // BigDecimal totalExpense = purchase.add(expense);
-            BigDecimal totalExpense = expense;
-
-            item.put("expense", totalExpense.setScale(2, RoundingMode.HALF_UP));
+            item.put("expense", expense.setScale(2, RoundingMode.HALF_UP));
 
             result.add(item);
         }
@@ -1231,8 +1151,8 @@
         String startStr = startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
         String endStr = endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
 
-        List<IncomeExpenseAnalysisDto> incomeList = accountIncomeMapper.selectIncomeStats(startStr, endStr, dateFormat);
-        List<IncomeExpenseAnalysisDto> expenseList = accountExpenseMapper.selectAccountExpenseStats(startStr, endStr, dateFormat);
+        List<IncomeExpenseAnalysisDto> incomeList = accountSalesCollectionMapper.selectIncomeStats(startStr, endStr, dateFormat);
+        List<IncomeExpenseAnalysisDto> expenseList = accountPurchasePaymentMapper.selectPayment(startStr, endStr, dateFormat);
 
         Map<String, BigDecimal> incomeMap = incomeList.stream().collect(Collectors
                 .toMap(IncomeExpenseAnalysisDto::getDateStr, IncomeExpenseAnalysisDto::getAmount, BigDecimal::add));
@@ -1268,11 +1188,6 @@
             rawMaterialDto.setName("鍘熸潗鏂�");
             rawMaterialDto.setValue(rawMaterialAmount != null ? rawMaterialAmount.toString() : "0");
             result.add(rawMaterialDto);
-
-            List<MapDto> expenseList = accountExpenseMapper.selectExpenseComposition(null, null);
-            if (expenseList != null) {
-                result.addAll(expenseList);
-            }
         }
 
         BigDecimal total = BigDecimal.ZERO;
@@ -1307,166 +1222,60 @@
     @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);
+        LocalDate today = LocalDate.now();
+        YearMonth currentMonth = YearMonth.from(today);
+        LocalDate startDate = currentMonth.atDay(1);
+        LocalDate endDate = currentMonth.atEndOfMonth();
 
-        LambdaQueryWrapper<SalesLedgerProduct> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(SalesLedgerProduct::getType, 1);
-        wrapper.ge(SalesLedgerProduct::getRegisterDate, startOfMonth);
-        wrapper.le(SalesLedgerProduct::getRegisterDate, endOfMonth);
+        BigDecimal monthlyIncome = sumCollectionAmount(startDate, endDate);
+        BigDecimal receivableBase = sumSalesContractAmount(startDate, endDate);
+        String collectionRate = toRateString(monthlyIncome, receivableBase);
 
-        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(wrapper);
+        String currentMonthText = currentMonth.toString();
+        List<AccountStatement> receivableStatements = defaultList(accountStatementMapper.selectList(
+                new LambdaQueryWrapper<AccountStatement>()
+                        .eq(AccountStatement::getAccountType, 1)
+                        .le(AccountStatement::getStatementMonth, currentMonthText)));
 
-        if (CollectionUtils.isEmpty(products)) {
-            return dto;
-        }
+        long overdueNum = receivableStatements.stream()
+                .filter(item -> item.getStatementMonth() != null && item.getStatementMonth().compareTo(currentMonthText) < 0)
+                .filter(item -> defaultDecimal(item.getClosingBalance()).compareTo(BigDecimal.ZERO) > 0)
+                .count();
 
-        BigDecimal collected = products.stream()
-                .map(SalesLedgerProduct::getInvoiceTotal)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        dto.setMonthlyIncome(collected);
+        long totalReceivableCount = receivableStatements.size();
+        String overdueRate = totalReceivableCount == 0
+                ? "0.00"
+                : BigDecimal.valueOf(overdueNum)
+                .multiply(BigDecimal.valueOf(100))
+                .divide(BigDecimal.valueOf(totalReceivableCount), 2, RoundingMode.HALF_UP)
+                .toString();
 
-        BigDecimal overdue = products.stream()
-                .map(SalesLedgerProduct::getPendingInvoiceTotal)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        dto.setOverdueNum(overdue);
-
-        BigDecimal total = collected.add(overdue);
-
-        if (total.compareTo(BigDecimal.ZERO) > 0) {
-            String collectionRate = collected.divide(total, 4, RoundingMode.HALF_UP)
-                    .multiply(new BigDecimal("100"))
-                    .setScale(2, RoundingMode.HALF_UP)
-                    .toString();
-            dto.setCollectionRate(collectionRate);
-
-            String overdueRate = overdue.divide(total, 4, RoundingMode.HALF_UP)
-                    .multiply(new BigDecimal("100"))
-                    .setScale(2, RoundingMode.HALF_UP)
-                    .toString();
-            dto.setOverdueRate(overdueRate);
-        }
-
+        dto.setMonthlyIncome(scaleMoney(monthlyIncome));
+        dto.setCollectionRate(collectionRate);
+        dto.setOverdueNum(BigDecimal.valueOf(overdueNum));
+        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();
 
-        // 褰撴湀鏃堕棿鑼冨洿
-        LocalDate now = LocalDate.now();
-        YearMonth currentMonth = YearMonth.from(now);
-        LocalDateTime startOfMonth = currentMonth.atDay(1).atStartOfDay();
-        LocalDateTime endOfMonth = currentMonth.atEndOfMonth().atTime(23, 59, 59);
+        BigDecimal monthlyExpenditure = sumPaymentAmount(startDate, endDate);
+        BigDecimal payableBase = sumPurchaseContractAmount(startDate, endDate);
+        BigDecimal monthlyIncome = sumCollectionAmount(startDate, endDate);
+        BigDecimal grossProfit = monthlyIncome.subtract(monthlyExpenditure);
 
-        // 閲囪喘鍙拌处锛坱ype = 2锛�
-        LambdaQueryWrapper<SalesLedgerProduct> purchaseWrapper = new LambdaQueryWrapper<>();
-        purchaseWrapper.eq(SalesLedgerProduct::getType, 2);
-        purchaseWrapper.ge(SalesLedgerProduct::getRegisterDate, startOfMonth);
-        purchaseWrapper.le(SalesLedgerProduct::getRegisterDate, endOfMonth);
-
-        List<SalesLedgerProduct> purchaseProducts = salesLedgerProductMapper.selectList(purchaseWrapper);
-
-        BigDecimal rawMaterialCost = BigDecimal.ZERO; // 鍘熸潗鏂欐垚鏈�
-        BigDecimal paidAmount = BigDecimal.ZERO; // 宸蹭粯娆鹃噾棰�
-        BigDecimal pendingAmount = BigDecimal.ZERO; // 寰呬粯娆鹃噾棰�
-
-        if (!CollectionUtils.isEmpty(purchaseProducts)) {
-            for (SalesLedgerProduct p : purchaseProducts) {
-
-                if (p.getTaxInclusiveTotalPrice() != null) {
-                    rawMaterialCost = rawMaterialCost.add(p.getTaxInclusiveTotalPrice());
-                }
-
-                if (p.getTicketsTotal() != null) {
-                    paidAmount = paidAmount.add(p.getTicketsTotal());
-                }
-
-                if (p.getPendingTicketsTotal() != null) {
-                    pendingAmount = pendingAmount.add(p.getPendingTicketsTotal());
-                }
-            }
-        }
-
-        // 鍏朵粬璐圭敤
-        LambdaQueryWrapper<AccountExpense> expenseWrapper = new LambdaQueryWrapper<>();
-        expenseWrapper.ge(AccountExpense::getExpenseDate,
-                java.sql.Date.valueOf(currentMonth.atDay(1)));
-        expenseWrapper.le(AccountExpense::getExpenseDate,
-                java.sql.Date.valueOf(currentMonth.atEndOfMonth()));
-
-        List<AccountExpense> expenses = accountExpenseMapper.selectList(expenseWrapper);
-
-        BigDecimal otherExpense = BigDecimal.ZERO;
-        if (!CollectionUtils.isEmpty(expenses)) {
-            for (AccountExpense e : expenses) {
-                if (e.getExpenseMoney() != null) {
-                    otherExpense = otherExpense.add(e.getExpenseMoney());
-                }
-            }
-        }
-
-        // 鏈堝害鎬绘敮鍑�
-        // BigDecimal monthlyExpenditure = rawMaterialCost.add(otherExpense);
-        BigDecimal monthlyExpenditure = otherExpense;
-        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 (!CollectionUtils.isEmpty(salesProducts)) {
-            for (SalesLedgerProduct s : salesProducts) {
-                if (s.getInvoiceAmount() != null) {
-                    revenue = revenue.add(s.getInvoiceAmount());
-                }
-            }
-        }
-
-        // 姣涘埄娑� & 鍒╂鼎鐜�
-        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(toRateString(monthlyExpenditure, payableBase));
+        dto.setGrossProfit(scaleMoney(grossProfit));
+        dto.setProfitMarginRate(toRateString(grossProfit, monthlyIncome));
         return dto;
     }
-
-    
-    private ProductionProductInputMapper productionProductInputMapper;
 
     @Override
     public List<InputOutputAnalysisDto> inputOutputAnalysis(Integer type) {
@@ -1498,7 +1307,8 @@
         String endStr = endDate.atStartOfDay()
                 .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
 
-        List<Map<String, Object>> inputList = productionProductInputMapper.selectInputStats(startStr, endStr);
+//        List<Map<String, Object>> inputList = productionProductInputMapper.selectInputStats(startStr, endStr);
+        List<Map<String, Object>> inputList = null;
         List<Map<String, Object>> outputList = productionProductOutputMapper.selectDailyOutputStats(startStr, endStr);
 
         Map<String, InputOutputAnalysisDto> dateMap = new HashMap<>();
@@ -1724,8 +1534,6 @@
                 .collect(Collectors.toList());
     }
 
-    
-    private ProductionAccountMapper salesLedgerProductionAccountingMapper;
 
     @Override
     public List<ProductionAccountingDto> productionAccountingAnalysis(Integer type) {
@@ -1754,7 +1562,7 @@
 
         String endStr = endDate.plusDays(1).atStartOfDay().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
 
-        List<Map<String, Object>> wagesList = salesLedgerProductionAccountingMapper.selectDailyWagesStats(startStr,
+        List<Map<String, Object>> wagesList = productionAccountMapper.selectDailyWagesStats(startStr,
                 endStr);
 
         if (CollectionUtils.isEmpty(wagesList)) {
@@ -2462,6 +2270,97 @@
         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) {
+        List<SalesLedger> salesLedgers = defaultList(salesLedgerMapper.selectList(new LambdaQueryWrapper<SalesLedger>()
+                .ge(SalesLedger::getEntryDate, toDate(startDate))
+                .lt(SalesLedger::getEntryDate, toExclusiveEndDate(endDate))));
+        return sumAmount(salesLedgers, SalesLedger::getContractAmount);
+    }
+
+    private BigDecimal sumPurchaseContractAmount(LocalDate startDate, LocalDate endDate) {
+        List<PurchaseLedger> purchaseLedgers = defaultList(purchaseLedgerMapper.selectList(new LambdaQueryWrapper<PurchaseLedger>()
+                .ge(PurchaseLedger::getEntryDate, toDate(startDate))
+                .lt(PurchaseLedger::getEntryDate, toExclusiveEndDate(endDate))));
+        return sumAmount(purchaseLedgers, PurchaseLedger::getContractAmount);
+    }
+
+    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;
     }

--
Gitblit v1.9.3