| | |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.ruoyi.account.dto.AccountDto; |
| | | import com.ruoyi.account.dto.AccountDto2; |
| | | import com.ruoyi.account.dto.AccountDto3; |
| | | import com.ruoyi.account.mapper.AccountExpenseMapper; |
| | | import com.ruoyi.account.mapper.AccountFileMapper; |
| | | import com.ruoyi.account.mapper.AccountIncomeMapper; |
| | | import com.ruoyi.account.pojo.AccountExpense; |
| | | import com.ruoyi.account.pojo.AccountIncome; |
| | | import com.ruoyi.account.service.AccountExpenseService; |
| | | import com.ruoyi.account.service.AccountIncomeService; |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.dto.DateQueryDto; |
| | | import com.ruoyi.project.system.domain.SysDictData; |
| | | import com.ruoyi.project.system.mapper.SysDictDataMapper; |
| | | import lombok.AllArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.time.DayOfWeek; |
| | | import java.time.LocalDate; |
| | | import java.time.ZoneId; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @AllArgsConstructor |
| | | @Service |
| | |
| | | private AccountExpenseMapper accountExpenseMapper; |
| | | |
| | | private AccountIncomeMapper accountIncomeMapper; |
| | | |
| | | private SysDictDataMapper sysDictDataMapper; |
| | | |
| | | |
| | | //分页查询 |
| | |
| | | AccountDto accountDto = new AccountDto(); |
| | | //获取该段时间内的所有收入 |
| | | List<AccountDto2> accountIncomes =accountIncomeMapper.report(dateQueryDto); |
| | | accountDto.setIncomeType(accountIncomes); |
| | | |
| | | Long incomeNumber = accountIncomeMapper.selectCount(Wrappers.<AccountIncome>lambdaQuery() |
| | | .between(AccountIncome::getIncomeDate, dateQueryDto.getEntryDateStart(), dateQueryDto.getEntryDateEnd())); |
| | | accountDto.setIncomeNumber(incomeNumber); |
| | | BigDecimal totalIncome = accountIncomes.stream().map(AccountDto2::getAccount).reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | accountDto.setTotalIncome(totalIncome); |
| | | accountIncomes.stream().forEach(accountDto2 -> { |
| | | accountDto2.setProportion(accountDto2.getAccount().divide(totalIncome,2,BigDecimal.ROUND_HALF_UP)); |
| | | }); |
| | | accountDto.setIncomeType(accountIncomes); |
| | | //获取该段时间内的所有支出 |
| | | List<AccountDto2> accountExpenses =accountExpenseMapper.report(dateQueryDto); |
| | | accountDto.setExpenseType(accountExpenses); |
| | |
| | | accountDto.setExpenseNumber(expenseNumber); |
| | | BigDecimal totalExpense = accountExpenses.stream().map(AccountDto2::getAccount).reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | accountDto.setTotalExpense(totalExpense); |
| | | accountExpenses.stream().forEach(accountDto2 -> { |
| | | accountDto2.setProportion(accountDto2.getAccount().divide(totalExpense,2,BigDecimal.ROUND_HALF_UP)); |
| | | }); |
| | | accountDto.setExpenseType(accountExpenses); |
| | | //净收入 |
| | | BigDecimal netRevenue = totalIncome.subtract(totalExpense); |
| | | accountDto.setNetRevenue(netRevenue); |
| | | return accountDto; |
| | | } |
| | | |
| | | //财务报表年查询 |
| | | @Override |
| | | public List<AccountDto3> reportExpense() { |
| | | List<AccountDto3> accountDto3s = new ArrayList<>(); |
| | | //先查询收入类型有哪些 |
| | | List<SysDictData> incomeTypes = sysDictDataMapper.selectDictDataByType("expense_types"); |
| | | DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); |
| | | int currentYear = LocalDate.now().getYear(); // 获取当前年份(如2025) |
| | | for (SysDictData incomeType : incomeTypes) { |
| | | AccountDto3 accountDto3 = new AccountDto3(); |
| | | accountDto3.setTypeName(incomeType.getDictLabel());//类型 |
| | | List<BigDecimal> account=new ArrayList<>(); |
| | | for (int i = 1; i <= 12; i++) { |
| | | // 当月第一天:年份为当前年,月份为i,日期为1 |
| | | LocalDate firstDay = LocalDate.of(currentYear, i, 1); |
| | | DateQueryDto dateQueryDto = new DateQueryDto(); |
| | | dateQueryDto.setEntryDateStart(firstDay.format(formatter)); |
| | | // 当月最后一天:第一天的月份的最后一天 |
| | | dateQueryDto.setEntryDateEnd(firstDay.plusMonths(1).minusDays(1).format(formatter)); |
| | | account.add(accountExpenseMapper.report1(dateQueryDto,incomeType.getDictValue())); |
| | | } |
| | | accountDto3.setAccount(account);//类型 |
| | | accountDto3s.add(accountDto3); |
| | | } |
| | | return accountDto3s; |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, List<String>> analysis() { |
| | | // 获取最近四个月(当前月 + 前3个月)的时间范围 |
| | | LocalDate today = LocalDate.now(); |
| | | DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM"); // 年月格式化器 |
| | | Map<String, List<String>> result = new HashMap<>(); |
| | | List<String> months = new ArrayList<>(); // 存储年月(如 2025-12、2025-11) |
| | | List<String> totalIncomeList = new ArrayList<>(); // 每月总收入 |
| | | List<String> totalExpenseList = new ArrayList<>(); // 每月总支出 |
| | | List<String> netIncomeList = new ArrayList<>(); // 每月净收入(收入-支出) |
| | | |
| | | // 步骤1:计算近4个月的年月列表(当前月、前1月、前2月、前3月) |
| | | List<String> targetMonths = new ArrayList<>(); |
| | | for (int i = 0; i < 4; i++) { |
| | | LocalDate currentMonth = today.minusMonths(i); |
| | | String monthStr = currentMonth.format(monthFormatter); |
| | | targetMonths.add(monthStr); |
| | | } |
| | | // 反转列表,确保顺序为「前3月 → 当前月」(可选,按需求调整顺序) |
| | | Collections.reverse(targetMonths); |
| | | |
| | | // 步骤2:一次性查询近4个月所有收入数据,按“年月”分组汇总 |
| | | LocalDate fourMonthsAgo = today.minusMonths(3).withDayOfMonth(1); // 近4个月起始日(前3月1号) |
| | | LocalDate currentMonthEnd = today.withDayOfMonth(today.lengthOfMonth()); // 当前月结束日 |
| | | ZoneId zoneId = ZoneId.of("Asia/Shanghai"); |
| | | // 查询近4个月所有收入 |
| | | List<AccountIncome> allIncomes = accountIncomeMapper.selectList( |
| | | Wrappers.<AccountIncome>lambdaQuery() |
| | | .ge(AccountIncome::getIncomeDate, fourMonthsAgo.toString()) // 大于等于起始日 |
| | | .le(AccountIncome::getIncomeDate, currentMonthEnd.toString()) // 小于等于结束日 |
| | | ); |
| | | |
| | | // 收入按“年月”分组汇总(key:年月字符串,value:当月总收入) |
| | | Map<String, BigDecimal> monthlyIncomeMap = allIncomes.stream() |
| | | .filter(income -> income.getIncomeMoney() != null) // 过滤空金额 |
| | | .collect(Collectors.groupingBy( |
| | | income -> { |
| | | // 将输入时间(字符串)转换为LocalDate,再格式化为年月 |
| | | LocalDate inputDate = income.getIncomeDate().toInstant().atZone(zoneId).toLocalDate(); |
| | | return inputDate.format(monthFormatter); |
| | | }, |
| | | Collectors.reducing(BigDecimal.ZERO, AccountIncome::getIncomeMoney, BigDecimal::add) |
| | | )); |
| | | |
| | | // 步骤3:一次性查询近4个月所有支出数据,按“年月”分组汇总 |
| | | List<AccountExpense> allExpenses = accountExpenseMapper.selectList( |
| | | Wrappers.<AccountExpense>lambdaQuery() |
| | | .ge(AccountExpense::getExpenseDate, fourMonthsAgo.toString()) |
| | | .le(AccountExpense::getExpenseDate, currentMonthEnd.toString()) |
| | | ); |
| | | |
| | | // 支出按“年月”分组汇总 |
| | | Map<String, BigDecimal> monthlyExpenseMap = allExpenses.stream() |
| | | .filter(expense -> expense.getExpenseMoney() != null) // 过滤空金额 |
| | | .collect(Collectors.groupingBy( |
| | | expense -> { |
| | | LocalDate inputDate = expense.getExpenseDate().toInstant().atZone(zoneId).toLocalDate(); |
| | | return inputDate.format(monthFormatter); |
| | | }, |
| | | Collectors.reducing(BigDecimal.ZERO, AccountExpense::getExpenseMoney, BigDecimal::add) |
| | | )); |
| | | |
| | | // 步骤4:循环4个目标月份,填充统计数据(无数据时默认为0) |
| | | for (String month : targetMonths) { |
| | | // 当月总收入(无数据则为0) |
| | | BigDecimal totalIncome = monthlyIncomeMap.getOrDefault(month, BigDecimal.ZERO); |
| | | // 当月总支出(无数据则为0) |
| | | BigDecimal totalExpense = monthlyExpenseMap.getOrDefault(month, BigDecimal.ZERO); |
| | | // 当月净收入(收入 - 支出) |
| | | BigDecimal netIncome = totalIncome.subtract(totalExpense); |
| | | |
| | | // 填充列表 |
| | | months.add(month); |
| | | totalIncomeList.add(totalIncome.toString()); |
| | | totalExpenseList.add(totalExpense.toString()); |
| | | netIncomeList.add(netIncome.toString()); |
| | | } |
| | | |
| | | // 组装结果 |
| | | result.put("days", months); // 年月(如 ["2025-09", "2025-10", "2025-11", "2025-12"]) |
| | | result.put("totalIncome", totalIncomeList); // 对应月份总收入 |
| | | result.put("totalExpense", totalExpenseList); // 对应月份总支出 |
| | | result.put("netIncome", netIncomeList); // 对应月份净收入 |
| | | |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public AccountExpense getByInvoiceNumber(String purchaseContractNumber) { |
| | | return accountExpenseMapper.selectOne(Wrappers.<AccountExpense>lambdaQuery() |
| | | .eq(AccountExpense::getInvoiceNumber, purchaseContractNumber)); |
| | | } |
| | | |
| | | @Override |
| | | public List<AccountExpense> getByInvoiceNumberList(String purchaseContractNumber) { |
| | | return accountExpenseMapper.selectList(Wrappers.<AccountExpense>lambdaQuery() |
| | | .eq(AccountExpense::getInvoiceNumber, purchaseContractNumber)); |
| | | } |
| | | |
| | | |
| | | } |