zss
6 天以前 3e5315bf1913ec325697f22104fcd2758c98891a
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -3,8 +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.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;
@@ -104,6 +108,7 @@
    private final AccountPurchasePaymentMapper accountPurchasePaymentMapper;
    private final AccountSalesCollectionMapper accountSalesCollectionMapper;
    private final AccountStatementMapper accountStatementMapper;
    private final ProductionAccountMapper productionAccountMapper;
@@ -394,43 +399,21 @@
     */
    @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 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) {
@@ -1239,102 +1222,58 @@
    @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)) {
        long overdueNum = receivableStatements.stream()
                .filter(item -> item.getStatementMonth() != null && item.getStatementMonth().compareTo(currentMonthText) < 0)
                .filter(item -> defaultDecimal(item.getClosingBalance()).compareTo(BigDecimal.ZERO) > 0)
                .count();
        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();
        dto.setMonthlyIncome(scaleMoney(monthlyIncome));
        dto.setCollectionRate(collectionRate);
        dto.setOverdueNum(BigDecimal.valueOf(overdueNum));
        dto.setOverdueRate(overdueRate);
            return dto;
        }
        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);
        // 采购台账(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(toRateString(monthlyExpenditure, payableBase));
        dto.setGrossProfit(scaleMoney(grossProfit));
        dto.setProfitMarginRate(toRateString(grossProfit, monthlyIncome));
        return dto;
    }
@@ -2331,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;
    }