From 25c2c9961fa433203a9df936ad27583047261d60 Mon Sep 17 00:00:00 2001
From: zss <zss@example.com>
Date: 星期六, 17 一月 2026 16:10:03 +0800
Subject: [PATCH] Merge branch 'jtwy' into dev_New

---
 src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java |  292 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 292 insertions(+), 0 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
new file mode 100644
index 0000000..e9a586f
--- /dev/null
+++ b/src/main/java/com/ruoyi/account/service/impl/AccountingServiceImpl.java
@@ -0,0 +1,292 @@
+package com.ruoyi.account.service.impl;
+
+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.extension.plugins.pagination.Page;
+import com.ruoyi.account.dto.DeviceTypeDetail;
+import com.ruoyi.account.dto.DeviceTypeDistributionVO;
+import com.ruoyi.account.mapper.BorrowInfoMapper;
+import com.ruoyi.account.pojo.BorrowInfo;
+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.pojo.CustomStorage;
+import com.ruoyi.procurementrecord.pojo.ProcurementRecordOut;
+import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
+import com.ruoyi.procurementrecord.service.impl.ProcurementRecordOutServiceImpl;
+import com.ruoyi.procurementrecord.service.impl.ProcurementRecordServiceImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.Year;
+import java.time.temporal.ChronoUnit;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author :yys
+ * @date : 2026/1/17 10:41
+ */
+@Service
+@Slf4j
+public class AccountingServiceImpl {
+
+    @Autowired
+    private DeviceLedgerMapper deviceLedgerMapper;
+
+    @Autowired
+    private BorrowInfoMapper borrowInfoMapper;
+
+    @Autowired
+    private CustomStorageMapper customStorageMapper;
+
+    @Autowired
+    private ProcurementRecordMapper procurementRecordMapper;
+
+    @Autowired
+    private ProcurementRecordOutMapper procurementRecordOutMapper;
+
+    public AjaxResult total(Integer year) {
+        Map<String,Object> map = new HashMap<>();
+        map.put("deprAmount",0); // 鎶樻棫閲戦
+        map.put("deviceTotal",0); // 璁惧鎬绘暟
+        map.put("deviceAmount",0); // 璁惧璧勪骇鍘熷��
+        map.put("netValue",0); // 鍑�鍊�
+        map.put("debt",0); // 璐熷��
+        map.put("inventoryValue",0); // 搴撳瓨璧勪骇
+        LambdaQueryWrapper<DeviceLedger> deviceLedgerLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        deviceLedgerLambdaQueryWrapper.like(DeviceLedger::getCreateTime,year);
+        List<DeviceLedger> deviceLedgers = deviceLedgerMapper.selectList(deviceLedgerLambdaQueryWrapper);
+        if(CollectionUtils.isNotEmpty(deviceLedgers)){
+            map.put("deviceTotal",deviceLedgers.size());
+            BigDecimal reduce = deviceLedgers.stream()
+                    .map(DeviceLedger::getTaxIncludingPriceTotal)
+                    .filter(Objects::nonNull)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            map.put("deviceAmount",reduce);
+            List<DeviceLedger> collect = deviceLedgers.stream().filter(deviceLedger -> deviceLedger.getIsDepr() != null && deviceLedger.getIsDepr() == 1).collect(Collectors.toList());
+            // 鏍规嵁褰撳墠骞翠唤鍜岃澶囧綍鍏ユ椂闂村勾浠芥瘮杈� * 姣忓勾鎶樻棫閲戦 = 璁惧鎶樻棫閲戦
+            BigDecimal total = new BigDecimal(0);
+            if(CollectionUtils.isNotEmpty(collect)){
+                for (DeviceLedger deviceLedger : collect) {
+                    BigDecimal totalDepreciation = calculatePreciseDepreciation(deviceLedger);
+                    total = total.add(totalDepreciation);
+                }
+                map.put("deprAmount",total);
+            }
+            // 鍑�鍊� = 璁惧璧勪骇鍘熷�� - 璁惧绱鎶樻棫閲戦
+            map.put("netValue",reduce.subtract(total));
+        }
+        // 璐熷��
+        LambdaQueryWrapper<BorrowInfo> borrowInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        borrowInfoLambdaQueryWrapper.like(BorrowInfo::getCreateTime,year)
+                .eq(BorrowInfo::getStatus,1);
+        List<BorrowInfo> borrowInfos = borrowInfoMapper.selectList(borrowInfoLambdaQueryWrapper);
+        if(CollectionUtils.isNotEmpty(borrowInfos)){
+            BigDecimal reduce = borrowInfos.stream()
+                    .map(BorrowInfo::getBorrowAmount)
+                    .filter(Objects::nonNull)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            map.put("debt",reduce);
+        }
+        // 搴撳瓨璧勪骇
+        LambdaQueryWrapper<ProcurementRecordStorage> procurementRecordStorageLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        procurementRecordStorageLambdaQueryWrapper.like(ProcurementRecordStorage::getCreateTime,year);
+        List<ProcurementRecordStorage> procurementRecordStorages = procurementRecordMapper.selectList(procurementRecordStorageLambdaQueryWrapper);
+        BigDecimal procurementRecordTotal = new BigDecimal(0);
+        if(CollectionUtils.isNotEmpty(procurementRecordStorages)){
+            // 鑾峰彇鍑哄簱鏁版嵁
+            LambdaQueryWrapper<ProcurementRecordOut> procurementRecordOutLambdaQueryWrapper = new LambdaQueryWrapper<>();
+            procurementRecordOutLambdaQueryWrapper.like(ProcurementRecordOut::getCreateTime,year)
+                    .in(ProcurementRecordOut::getProcurementRecordStorageId, procurementRecordStorages
+                            .stream()
+                            .map(ProcurementRecordStorage::getId)
+                            .collect(Collectors.toList()))
+                    .in(ProcurementRecordOut::getType,Arrays.asList(1,2));
+            List<ProcurementRecordOut> procurementRecordOuts = procurementRecordOutMapper.selectList(procurementRecordOutLambdaQueryWrapper);
+            for (ProcurementRecordStorage procurementRecordStorage : procurementRecordStorages) {
+                // 閲囪喘锛岀敓浜у叆搴撴�讳环鍊�
+                procurementRecordTotal.add(procurementRecordStorage.getUnitPrice().multiply(procurementRecordStorage.getInboundNum()));
+                // 閫氳繃鍏ュ簱id锛岀被鍨嬭幏鍙栧嚭搴撴暟鎹�
+                List<ProcurementRecordOut> procurementRecordOutsByStorageId = procurementRecordOuts.stream()
+                        .filter(procurementRecordOut -> procurementRecordOut.getProcurementRecordStorageId().equals(procurementRecordStorage.getId())
+                        && procurementRecordOut.getType().equals(procurementRecordStorage.getType()))
+                        .collect(Collectors.toList());
+                if(CollectionUtils.isNotEmpty(procurementRecordOutsByStorageId)){
+                    for (ProcurementRecordOut procurementRecordOut : procurementRecordOutsByStorageId) {
+                        // 閲囪喘锛岀敓浜у嚭搴撴�讳环鍊�
+                        procurementRecordTotal.subtract(procurementRecordStorage.getUnitPrice().multiply(procurementRecordOut.getInboundNum()));
+                    }
+                }
+
+            }
+
+
+        }
+        LambdaQueryWrapper<CustomStorage> customStorageLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        customStorageLambdaQueryWrapper.like(CustomStorage::getInboundDate,year);
+        List<CustomStorage> customStorages = customStorageMapper.selectList(customStorageLambdaQueryWrapper);
+        BigDecimal customStorageTotal = new BigDecimal(0);
+        if(CollectionUtils.isNotEmpty(customStorages)){
+            // 鑾峰彇鍑哄簱鏁版嵁
+            LambdaQueryWrapper<ProcurementRecordOut> procurementRecordOutLambdaQueryWrapper = new LambdaQueryWrapper<>();
+            procurementRecordOutLambdaQueryWrapper.like(ProcurementRecordOut::getCreateTime,year)
+                    .in(ProcurementRecordOut::getProcurementRecordStorageId, customStorages
+                            .stream()
+                            .map(CustomStorage::getId)
+                            .collect(Collectors.toList()))
+                    .eq(ProcurementRecordOut::getType,3);
+            List<ProcurementRecordOut> procurementRecordOuts = procurementRecordOutMapper.selectList(procurementRecordOutLambdaQueryWrapper);
+            customStorages.forEach(customStorage -> {
+                // 鑷畾涔夊叆搴撴�讳环鍊�
+                customStorageTotal.add(customStorage.getTaxInclusiveUnitPrice().multiply(customStorage.getInboundNum()));
+                // 閫氳繃鍏ュ簱id锛岀被鍨嬭幏鍙栧嚭搴撴暟鎹�
+                List<ProcurementRecordOut> procurementRecordOutsByStorageId = procurementRecordOuts.stream()
+                        .filter(procurementRecordOut -> procurementRecordOut.getProcurementRecordStorageId().equals(customStorage.getId()))
+                        .collect(Collectors.toList());
+                if(CollectionUtils.isNotEmpty(procurementRecordOutsByStorageId)){
+                    for (ProcurementRecordOut procurementRecordOut : procurementRecordOutsByStorageId) {
+                        // 鑷畾涔夊嚭搴撴�讳环鍊�
+                        customStorageTotal.subtract(procurementRecordOut.getInboundNum().multiply(customStorage.getTaxInclusiveUnitPrice()));
+                    }
+                }
+            });
+        }
+        map.put("inventoryValue",procurementRecordTotal.add(customStorageTotal));
+        return AjaxResult.success( map);
+    }
+
+    /**
+     * 璁$畻璁惧绱鎶樻棫閲戦
+     * @param deviceLedger 璁惧鍙拌处瀹炰綋
+     * @return 绱鎶樻棫閲戦锛圔igDecimal锛屼繚鐣�2浣嶅皬鏁帮級
+     */
+    public static BigDecimal calculateTotalDepreciation(DeviceLedger deviceLedger) {
+        // 1. 绌哄�兼牎楠�
+        if (deviceLedger == null) {
+            return BigDecimal.ZERO;
+        }
+
+        // 2. 鍒ゆ柇鏄惁寮�鍚姌鏃э紝鏈紑鍚垯鎶樻棫閲戦涓�0
+        Integer isDepr = deviceLedger.getIsDepr();
+        if (isDepr == null || isDepr != 1) { // 1-鏄� 2-鍚�
+            return BigDecimal.ZERO;
+        }
+
+        // 3. 鑾峰彇姣忓勾鎶樻棫閲戦锛屼负绌哄垯杩斿洖0
+        BigDecimal annualDepreciation = deviceLedger.getAnnualDepreciationAmount();
+        if (annualDepreciation == null || annualDepreciation.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+
+        // 4. 鑾峰彇璁惧褰曞叆鏃堕棿锛屼负绌哄垯杩斿洖0
+        LocalDateTime createTime = deviceLedger.getCreateTime();
+        if (createTime == null) {
+            return BigDecimal.ZERO;
+        }
+
+        // 5. 璁$畻骞翠唤宸��
+        int currentYear = Year.now().getValue(); // 褰撳墠骞翠唤
+        int createYear = createTime.getYear();    // 璁惧褰曞叆骞翠唤
+        int yearDiff = currentYear - createYear;
+
+        // 6. 澶勭悊骞翠唤宸�间负璐熸暟鐨勬儏鍐碉紙褰曞叆鏃堕棿鍦ㄦ湭鏉ワ級
+        if (yearDiff < 0) {
+            return BigDecimal.ZERO;
+        }
+
+        // 7. 璁$畻鎬绘姌鏃ч噾棰� = 骞翠唤宸�� * 姣忓勾鎶樻棫閲戦
+        BigDecimal totalDepreciation = annualDepreciation.multiply(BigDecimal.valueOf(yearDiff));
+
+        // 8. 杩斿洖淇濈暀2浣嶅皬鏁扮殑缁撴灉锛堥噾棰濊鑼冿級
+        return totalDepreciation.setScale(2, BigDecimal.ROUND_HALF_UP);
+    }
+
+    /**
+     * 銆愯繘闃剁増銆戞寜瀹為檯澶╂暟璁$畻鎶樻棫锛堟洿绮惧噯锛�
+     * @param deviceLedger 璁惧鍙拌处瀹炰綋
+     * @return 绱鎶樻棫閲戦
+     */
+    public static BigDecimal calculatePreciseDepreciation(DeviceLedger deviceLedger) {
+        if (deviceLedger == null) {
+            return BigDecimal.ZERO;
+        }
+
+        // 鍒ゆ柇鏄惁寮�鍚姌鏃�
+        Integer isDepr = deviceLedger.getIsDepr();
+        if (isDepr == null || isDepr != 1) {
+            return BigDecimal.ZERO;
+        }
+
+        // 鑾峰彇姣忓勾鎶樻棫閲戦
+        BigDecimal annualDepreciation = deviceLedger.getAnnualDepreciationAmount();
+        if (annualDepreciation == null || annualDepreciation.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+
+        // 鑾峰彇璁惧褰曞叆鏃堕棿
+        LocalDateTime createTime = deviceLedger.getCreateTime();
+        if (createTime == null) {
+            return BigDecimal.ZERO;
+        }
+
+        // 褰撳墠鏃堕棿
+        LocalDateTime now = LocalDateTime.now();
+
+        // 濡傛灉褰曞叆鏃堕棿鍦ㄦ湭鏉ワ紝杩斿洖0
+        if (createTime.isAfter(now)) {
+            return BigDecimal.ZERO;
+        }
+
+        // 璁$畻鎬诲ぉ鏁�
+        long days = ChronoUnit.DAYS.between(createTime, now);
+
+        // 鎸夋瘡骞�365澶╄绠楁姌鏃ч噾棰�
+        BigDecimal dailyDepreciation = annualDepreciation.divide(BigDecimal.valueOf(365), 6, BigDecimal.ROUND_HALF_UP);
+        BigDecimal totalDepreciation = dailyDepreciation.multiply(BigDecimal.valueOf(days));
+
+        return totalDepreciation.setScale(2, BigDecimal.ROUND_HALF_UP);
+    }
+
+    public AjaxResult deviceTypeDistribution(Integer year) {
+        // 2. 缁勮杩斿洖VO
+       DeviceTypeDistributionVO vo = new DeviceTypeDistributionVO();
+       List<DeviceTypeDetail> details = deviceLedgerMapper.getDeviceTypeDistributionByYear( year);
+        vo.setDetails(details);
+       if(CollectionUtils.isNotEmpty(details)){
+           // 3. 鎻愬彇鍥捐〃鎵�闇�鐨勫垎绫诲拰鏁版嵁
+           vo.setCategories(details.stream()
+                   .map(DeviceTypeDetail::getType)
+                   .collect(Collectors.toList()));
+
+           vo.setCountData(details.stream()
+                   .map(DeviceTypeDetail::getCount)
+                   .collect(Collectors.toList()));
+
+           vo.setAmountData(details.stream()
+                   .map(DeviceTypeDetail::getAmount)
+                   .collect(Collectors.toList()));
+           vo.setTotalCount(vo.getCategories().size());
+       }
+        return AjaxResult.success(vo);
+    }
+
+    public AjaxResult calculateDepreciation(Page page, Integer year) {
+        LambdaQueryWrapper<DeviceLedger> deviceLedgerLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        deviceLedgerLambdaQueryWrapper.like(DeviceLedger::getCreateTime,year)
+                .eq(DeviceLedger::getIsDepr,1);
+        IPage<DeviceLedger> deviceLedgerIPage = deviceLedgerMapper.selectPage(page, deviceLedgerLambdaQueryWrapper);
+        for (DeviceLedger record : deviceLedgerIPage.getRecords()) {
+            record.setDeprAmount(calculatePreciseDepreciation(record));
+            record.setNetValue(record.getTaxIncludingPriceTotal().subtract(record.getDeprAmount()));
+        }
+        return AjaxResult.success(deviceLedgerIPage);
+    }
+}

--
Gitblit v1.9.3