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

---
 src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java |  189 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 188 insertions(+), 1 deletions(-)

diff --git a/src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java b/src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java
index 01f5687..f42599a 100644
--- a/src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java
+++ b/src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java
@@ -3,25 +3,47 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.account.bean.dto.AccountReportDto;
 import com.ruoyi.account.bean.dto.DeviceTypeDetail;
 import com.ruoyi.account.bean.dto.DeviceTypeDistributionVO;
+import com.ruoyi.account.bean.dto.purchase.PurchaseInboundDto;
+import com.ruoyi.account.bean.dto.purchase.PurchaseReturnDto;
+import com.ruoyi.account.bean.dto.sales.SalesOutboundDto;
+import com.ruoyi.account.bean.dto.sales.SalesReturnDto;
+import com.ruoyi.account.bean.vo.AccountReportVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseInboundVo;
+import com.ruoyi.account.bean.vo.purchase.PurchaseReturnVo;
+import com.ruoyi.account.bean.vo.sales.SalesOutboundVo;
+import com.ruoyi.account.bean.vo.sales.SalesReturnVo;
+import com.ruoyi.account.mapper.purchase.AccountPurchasePaymentMapper;
+import com.ruoyi.account.mapper.sales.AccountSalesCollectionMapper;
+import com.ruoyi.account.pojo.purchase.AccountPurchasePayment;
+import com.ruoyi.account.pojo.sales.AccountSalesCollection;
+import com.ruoyi.account.service.AccountingService;
 import com.ruoyi.device.mapper.DeviceLedgerMapper;
 import com.ruoyi.device.pojo.DeviceLedger;
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.procurementrecord.mapper.CustomStorageMapper;
 import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper;
 import com.ruoyi.procurementrecord.mapper.ProcurementRecordOutMapper;
+import com.ruoyi.procurementrecord.mapper.ReturnManagementMapper;
 import com.ruoyi.procurementrecord.pojo.CustomStorage;
 import com.ruoyi.procurementrecord.pojo.ProcurementRecordOut;
 import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
+import com.ruoyi.purchase.mapper.PurchaseReturnOrdersMapper;
+import com.ruoyi.stock.mapper.StockInRecordMapper;
+import com.ruoyi.stock.mapper.StockOutRecordMapper;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.Year;
+import java.time.format.DateTimeFormatter;
 import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -33,13 +55,21 @@
 @Service
 @Slf4j
 @RequiredArgsConstructor
-public class AccountingServiceImpl {
+public class AccountingServiceImpl implements AccountingService {
 
     private final DeviceLedgerMapper deviceLedgerMapper;
     private final CustomStorageMapper customStorageMapper;
     private final ProcurementRecordMapper procurementRecordMapper;
     private final ProcurementRecordOutMapper procurementRecordOutMapper;
+    private final AccountSalesCollectionMapper accountSalesCollectionMapper;
+    private final AccountPurchasePaymentMapper accountPurchasePaymentMapper;
+    private final StockOutRecordMapper stockOutRecordMapper;
+    private final ReturnManagementMapper returnManagementMapper;
+    private final StockInRecordMapper stockInRecordMapper;
+    private final PurchaseReturnOrdersMapper purchaseReturnOrdersMapper;
 
+
+    @Override
     public AjaxResult total(Integer year) {
         Map<String,Object> map = new HashMap<>();
         map.put("deprAmount",0); // 鎶樻棫閲戦
@@ -233,6 +263,7 @@
         return totalDepreciation.setScale(2, BigDecimal.ROUND_HALF_UP);
     }
 
+    @Override
     public AjaxResult deviceTypeDistribution(Integer year) {
         // 2. 缁勮杩斿洖VO
        DeviceTypeDistributionVO vo = new DeviceTypeDistributionVO();
@@ -256,6 +287,7 @@
         return AjaxResult.success(vo);
     }
 
+    @Override
     public AjaxResult calculateDepreciation(Page page, Integer year) {
         LambdaQueryWrapper<DeviceLedger> deviceLedgerLambdaQueryWrapper = new LambdaQueryWrapper<>();
         deviceLedgerLambdaQueryWrapper.like(DeviceLedger::getCreateTime,year)
@@ -267,4 +299,159 @@
         }
         return AjaxResult.success(deviceLedgerIPage);
     }
+
+    @Override
+    public AccountReportVo getAccountStatementDetailsByMonth(AccountReportDto accountReportDto) {
+        AccountReportVo accountReportVo = new AccountReportVo();
+        LocalDate start = accountReportDto.getEntryDateStart();
+        LocalDate end = accountReportDto.getEntryDateEnd();
+        DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM");
+
+        // ========== 1. 椤堕儴鍗$墖鏁版嵁 ==========
+        // 1.1 鎬昏惀鏀� = 鏀舵鍗曟�婚噾棰�
+        List<AccountSalesCollection> accountSalesCollections = accountSalesCollectionMapper.selectList(
+                Wrappers.<AccountSalesCollection>lambdaQuery()
+                        .between(AccountSalesCollection::getCollectionDate, start, end)
+        );
+        BigDecimal totalIncome = Optional.of(
+                accountSalesCollections.stream()
+                        .map(AccountSalesCollection::getCollectionAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add)
+        ).orElse(BigDecimal.ZERO);
+        accountReportVo.setTotalIncome(totalIncome);
+        // 1.2 鎬绘敮鍑� = 浠樻鍗曟�婚噾棰�
+        List<AccountPurchasePayment> accountPurchasePayments = accountPurchasePaymentMapper.selectList(
+                Wrappers.<AccountPurchasePayment>lambdaQuery()
+                        .between(AccountPurchasePayment::getPaymentDate, start, end)
+        );
+        BigDecimal totalExpense = Optional.of(
+                accountPurchasePayments.stream()
+                        .map(AccountPurchasePayment::getPaymentAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add)
+        ).orElse(BigDecimal.ZERO);
+        accountReportVo.setTotalExpense(totalExpense);
+        // 1.3 搴旀敹璐︽ = 閿�鍞嚭搴撻噾棰濆悎璁� - 閿�鍞��璐ч噾棰濆悎璁�
+        SalesOutboundDto salesOutboundDto = new SalesOutboundDto();
+        salesOutboundDto.setStartDate(accountReportDto.getEntryDateStart());
+        salesOutboundDto.setEndDate(accountReportDto.getEntryDateEnd());
+        List<SalesOutboundVo> salesOutboundVos = stockOutRecordMapper.listPageAccountSales(new Page(1, -1), salesOutboundDto).getRecords();
+        BigDecimal salesOutAmount = Optional.of(
+                salesOutboundVos.stream()
+                        .map(SalesOutboundVo::getOutboundAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add)
+        ).orElse(BigDecimal.ZERO);
+        SalesReturnDto salesReturnDto = new SalesReturnDto();
+        salesReturnDto.setStartDate(accountReportDto.getEntryDateStart());
+        salesReturnDto.setEndDate(accountReportDto.getEntryDateEnd());
+        List<SalesReturnVo> salesReturnVos = returnManagementMapper.listPageAccountSalesReturn(new Page(1, -1), salesReturnDto).getRecords();
+        BigDecimal salesReturnAmount = Optional.of(
+                salesReturnVos.stream()
+                        .map(SalesReturnVo::getRefundAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add)
+        ).orElse(BigDecimal.ZERO);
+        accountReportVo.setAccountsReceivable(salesOutAmount.subtract(salesReturnAmount));
+        // 1.4 搴斾粯璐︽ = 閲囪喘鍏ュ簱閲戦鍚堣 - 閲囪喘閫�璐ч噾棰濆悎璁�
+        PurchaseInboundDto purchaseInboundDto = new PurchaseInboundDto();
+        purchaseInboundDto.setStartDate(accountReportDto.getEntryDateStart());
+        purchaseInboundDto.setEndDate(accountReportDto.getEntryDateEnd());
+        List<PurchaseInboundVo> purchaseInboundVos = stockInRecordMapper.listPageAccountPurchase(new Page(1, -1), purchaseInboundDto).getRecords();
+        BigDecimal purchaseInAmount = Optional.of(
+                purchaseInboundVos.stream()
+                        .map(PurchaseInboundVo::getInboundAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add)
+        ).orElse(BigDecimal.ZERO);
+        PurchaseReturnDto purchaseReturnDto = new PurchaseReturnDto();
+        purchaseReturnDto.setStartDate(accountReportDto.getEntryDateStart());
+        purchaseReturnDto.setEndDate(accountReportDto.getEntryDateEnd());
+        List<PurchaseReturnVo> purchaseReturnVos = purchaseReturnOrdersMapper.listPageAccountPurchaseReturn(new Page(1, -1), purchaseReturnDto).getRecords();
+        BigDecimal purchaseReturnAmount = Optional.of(
+                purchaseReturnVos.stream()
+                        .map(PurchaseReturnVo::getTotalAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add)
+        ).orElse(BigDecimal.ZERO);
+        accountReportVo.setAccountsPayable(purchaseInAmount.subtract(purchaseReturnAmount));
+        // 1.5 鍑�鍒╂鼎 = 鎬昏惀鏀� - 鎬绘敮鍑�
+        BigDecimal netProfit = totalIncome.subtract(totalExpense);
+        accountReportVo.setNetRevenue(netProfit);
+
+        // ========== 2. 鎶樼嚎鍥撅細鏈堝害钀ユ敹/鏀嚭/鍑�鍒╂鼎瓒嬪娍 ==========
+        Map<String, BigDecimal> monthIncomeMap = new HashMap<>();
+        Map<String, BigDecimal> monthExpenseMap = new HashMap<>();
+        // 鏈堝害钀ユ敹
+        accountSalesCollections.forEach(item -> {
+            String month = item.getCollectionDate().format(monthFormatter);
+            monthIncomeMap.put(month, monthIncomeMap.getOrDefault(month, BigDecimal.ZERO)
+                    .add(Optional.ofNullable(item.getCollectionAmount()).orElse(BigDecimal.ZERO)));
+        });
+        // 鏈堝害鏀嚭
+        accountPurchasePayments.forEach(item -> {
+            String month = item.getPaymentDate().format(monthFormatter);
+            monthExpenseMap.put(month, monthExpenseMap.getOrDefault(month, BigDecimal.ZERO)
+                    .add(Optional.ofNullable(item.getPaymentAmount()).orElse(BigDecimal.ZERO)));
+        });
+        // 鐢熸垚杩炵画鏈堜唤鍒楄〃
+        List<String> monthList = new ArrayList<>();
+        LocalDate current = start.withDayOfMonth(1);
+        while (!current.isAfter(end.withDayOfMonth(1))) {
+            monthList.add(current.format(monthFormatter));
+            current = current.plusMonths(1);
+        }
+        // 缁勮瓒嬪娍鏁版嵁
+        List<AccountReportVo.MonthlyTrendVO> trendList = new ArrayList<>();
+        for (String month : monthList) {
+            BigDecimal income = monthIncomeMap.getOrDefault(month, BigDecimal.ZERO);
+            BigDecimal expense = monthExpenseMap.getOrDefault(month, BigDecimal.ZERO);
+            AccountReportVo.MonthlyTrendVO trend = new AccountReportVo.MonthlyTrendVO();
+            trend.setMonth(month);
+            trend.setIncome(income);
+            trend.setExpense(expense);
+            trend.setProfit(income.subtract(expense));
+            trendList.add(trend);
+        }
+        accountReportVo.setMonthlyTrendList(trendList);
+
+        // ========== 3. 鏌辩姸鍥撅細鏈堝害搴旀敹/搴斾粯鏁版嵁 ==========
+        Map<String, BigDecimal> monthReceivableMap = new HashMap<>();
+        Map<String, BigDecimal> monthPayableMap = new HashMap<>();
+        // 鏈堝害搴旀敹锛堥攢鍞嚭搴�-閫�璐э級
+        salesOutboundVos.forEach(item -> {
+            String month = item.getShippingDate().format(monthFormatter);
+            monthReceivableMap.put(month, monthReceivableMap.getOrDefault(month, BigDecimal.ZERO)
+                    .add(Optional.ofNullable(item.getOutboundAmount()).orElse(BigDecimal.ZERO)));
+        });
+        salesReturnVos.forEach(item -> {
+            String month = item.getMakeTime().format(monthFormatter);
+            monthReceivableMap.put(month, monthReceivableMap.getOrDefault(month, BigDecimal.ZERO)
+                    .subtract(Optional.ofNullable(item.getRefundAmount()).orElse(BigDecimal.ZERO)));
+        });
+
+        // 鏈堝害搴斾粯锛堥噰璐叆搴�-閫�璐э級
+        purchaseInboundVos.forEach(item -> {
+            String month = item.getInboundDate().format(monthFormatter);
+            monthPayableMap.put(month, monthPayableMap.getOrDefault(month, BigDecimal.ZERO)
+                    .add(Optional.ofNullable(item.getInboundAmount()).orElse(BigDecimal.ZERO)));
+        });
+        purchaseReturnVos.forEach(item -> {
+            String month = item.getPreparedAt().format(monthFormatter);
+            monthPayableMap.put(month, monthPayableMap.getOrDefault(month, BigDecimal.ZERO)
+                    .subtract(Optional.ofNullable(item.getTotalAmount()).orElse(BigDecimal.ZERO)));
+        });
+        // 缁勮搴旀敹搴斾粯鏁版嵁
+        List<AccountReportVo.ReceivablePayableVO> rpList = new ArrayList<>();
+        for (String month : monthList) {
+            AccountReportVo.ReceivablePayableVO rp = new AccountReportVo.ReceivablePayableVO();
+            rp.setMonth(month);
+            rp.setReceivable(monthReceivableMap.getOrDefault(month, BigDecimal.ZERO));
+            rp.setPayable(monthPayableMap.getOrDefault(month, BigDecimal.ZERO));
+            rpList.add(rp);
+        }
+        accountReportVo.setReceivablePayableList(rpList);
+        return accountReportVo;
+    }
 }

--
Gitblit v1.9.3