package com.ruoyi.account.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.account.mapper.FinanceAccountMapper; import com.ruoyi.account.mapper.FinanceCashflowPlanMapper; import com.ruoyi.account.pojo.FinanceCashflowPlan; import com.ruoyi.account.service.FinanceCashflowPlanService; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; import java.time.LocalDate; import java.time.ZoneId; import java.util.ArrayList; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @Service public class FinanceCashflowPlanServiceImpl extends ServiceImpl implements FinanceCashflowPlanService { @Resource private FinanceAccountMapper financeAccountMapper; @Override public Map forecast(Integer days, BigDecimal safetyLine) { int window = days == null ? 30 : Math.max(1, Math.min(days, 30)); BigDecimal threshold = safetyLine == null ? financeAccountMapper.selectTotalSafetyLine() : safetyLine; if (threshold == null) threshold = BigDecimal.ZERO; LocalDate today = LocalDate.now(); LocalDate lastDay = today.plusDays(window - 1L); Date begin = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant()); Date end = Date.from(lastDay.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant()); List plans = list(new QueryWrapper() .eq("status", "0").ge("plan_date", begin).lt("plan_date", end).orderByAsc("plan_date")); BigDecimal currentBalance = financeAccountMapper.selectTotalBalance(); if (currentBalance == null) currentBalance = BigDecimal.ZERO; List> points = new ArrayList<>(); BigDecimal balance = currentBalance; for (int offset = 0; offset < window; offset++) { LocalDate date = today.plusDays(offset); BigDecimal income = BigDecimal.ZERO; BigDecimal expense = BigDecimal.ZERO; for (FinanceCashflowPlan plan : plans) { LocalDate planDate = plan.getPlanDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); if (!date.equals(planDate)) continue; BigDecimal amount = plan.getExpectedAmount() == null ? BigDecimal.ZERO : plan.getExpectedAmount(); if ("0".equals(plan.getPlanType())) income = income.add(amount); else expense = expense.add(amount); } balance = balance.add(income).subtract(expense); Map point = new LinkedHashMap<>(); point.put("date", date.toString()); point.put("income", income); point.put("expense", expense); point.put("balance", balance); point.put("signal", balance.signum() < 0 ? "gap" : (balance.compareTo(threshold) > 0 ? "surplus" : "safe")); points.add(point); } Map result = new LinkedHashMap<>(); result.put("currentBalance", currentBalance); result.put("safetyLine", threshold); result.put("days", window); result.put("points", points); result.put("finalBalance", balance); result.put("signal", balance.signum() < 0 ? "gap" : (balance.compareTo(threshold) > 0 ? "surplus" : "safe")); return result; } }