|
|
@@ -0,0 +1,329 @@
|
|
|
+package com.yc.ship.module.trade.service.report.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.collection.CollUtil;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.yc.ship.framework.common.pojo.PageResult;
|
|
|
+import com.yc.ship.framework.common.pojo.PageParam;
|
|
|
+import com.yc.ship.framework.excel.core.util.ExcelUtils;
|
|
|
+import com.yc.ship.module.trade.controller.admin.report.vo.BankStatementReportPageReqVO;
|
|
|
+import com.yc.ship.module.trade.controller.admin.report.vo.BankStatementReportRespVO;
|
|
|
+import com.yc.ship.module.trade.dal.dataobject.bill.BillDO;
|
|
|
+import com.yc.ship.module.trade.dal.dataobject.order.TradeOrderPayDO;
|
|
|
+import com.yc.ship.module.trade.dal.mysql.bill.BillMapper;
|
|
|
+import com.yc.ship.module.trade.dal.mysql.order.TradeOrderPayMapper;
|
|
|
+import com.yc.ship.module.trade.service.report.BankStatementReportService;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
+import java.io.IOException;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
+import java.util.*;
|
|
|
+import java.util.function.Function;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 银行对账报表 Service 实现类
|
|
|
+ *
|
|
|
+ * @author auto-generated
|
|
|
+ */
|
|
|
+@Service
|
|
|
+@Slf4j
|
|
|
+public class BankStatementReportServiceImpl implements BankStatementReportService {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private TradeOrderPayMapper tradeOrderPayMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private BillMapper billMapper;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询银行对账报表分页
|
|
|
+ *
|
|
|
+ * @param pageReqVO 分页查询条件
|
|
|
+ * @return 分页结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public PageResult<BankStatementReportRespVO> getBankStatementReportPage(BankStatementReportPageReqVO pageReqVO) {
|
|
|
+ // 1. 构建日期列表
|
|
|
+ List<LocalDate> dateList = buildDateList(pageReqVO.getStartDate(), pageReqVO.getEndDate());
|
|
|
+ if (CollUtil.isEmpty(dateList)) {
|
|
|
+ return new PageResult<>(new ArrayList<>(), 0L);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 分页处理日期列表
|
|
|
+ int pageNo = pageReqVO.getPageNo();
|
|
|
+ int pageSize = pageReqVO.getPageSize();
|
|
|
+ int total = dateList.size();
|
|
|
+ int fromIndex = (pageNo - 1) * pageSize;
|
|
|
+ int toIndex = Math.min(fromIndex + pageSize, total);
|
|
|
+
|
|
|
+ if (fromIndex >= total) {
|
|
|
+ return new PageResult<>(new ArrayList<>(), (long) total);
|
|
|
+ }
|
|
|
+ List<LocalDate> subDateList = new ArrayList<>();
|
|
|
+ if (toIndex == -1) {
|
|
|
+ subDateList = dateList.subList(fromIndex, dateList.size());
|
|
|
+ } else {
|
|
|
+ subDateList = dateList.subList(fromIndex, toIndex);
|
|
|
+ }
|
|
|
+
|
|
|
+ LocalDate startDate = subDateList.get(0);
|
|
|
+ LocalDate endDate = subDateList.get(subDateList.size() - 1);
|
|
|
+
|
|
|
+ // 3. 批量查询当前页日期范围内的所有统计数据(使用数据库聚合)
|
|
|
+ LocalDateTime startDateTime = startDate.atStartOfDay();
|
|
|
+ LocalDateTime endDateTime = endDate.plusDays(1).atStartOfDay();
|
|
|
+
|
|
|
+ // 3.1 批量查询账单还款数据 - 按日期分组汇总
|
|
|
+ LambdaQueryWrapper<BillDO> billWrapper = new LambdaQueryWrapper<>();
|
|
|
+ billWrapper.eq(BillDO::getBillStatus, 1)
|
|
|
+ .between(BillDO::getPayTime, startDateTime, endDateTime)
|
|
|
+ .select(BillDO::getPayTime, BillDO::getPayAmount); // 只查询必要字段
|
|
|
+ List<BillDO> billList = billMapper.selectList(billWrapper);
|
|
|
+
|
|
|
+ // 3.2 批量查询预存款充值数据
|
|
|
+ LambdaQueryWrapper<TradeOrderPayDO> depositWrapper = new LambdaQueryWrapper<>();
|
|
|
+ depositWrapper.eq(TradeOrderPayDO::getPayStatus, 1)
|
|
|
+ .eq(TradeOrderPayDO::getOrderType, 1)
|
|
|
+ .between(TradeOrderPayDO::getPaymentDate, startDateTime, endDateTime)
|
|
|
+ .select(TradeOrderPayDO::getPaymentDate, TradeOrderPayDO::getPayAmount);
|
|
|
+ List<TradeOrderPayDO> depositList = tradeOrderPayMapper.selectList(depositWrapper);
|
|
|
+
|
|
|
+ // 3.3 批量查询订单支付数据
|
|
|
+ LambdaQueryWrapper<TradeOrderPayDO> orderWrapper = new LambdaQueryWrapper<>();
|
|
|
+ orderWrapper.eq(TradeOrderPayDO::getPayStatus, 1)
|
|
|
+ .eq(TradeOrderPayDO::getOrderType, 0)
|
|
|
+ .between(TradeOrderPayDO::getPaymentDate, startDateTime, endDateTime)
|
|
|
+ .select(TradeOrderPayDO::getPaymentDate, TradeOrderPayDO::getPayAmount);
|
|
|
+ List<TradeOrderPayDO> orderPaymentList = tradeOrderPayMapper.selectList(orderWrapper);
|
|
|
+
|
|
|
+ // 4. 按日期分组并计算统计数据
|
|
|
+ Map<LocalDate, BigDecimal> billMap = groupByDateAndSum(billList, BillDO::getPayTime, BillDO::getPayAmount);
|
|
|
+ Map<LocalDate, BigDecimal> depositMap = groupByDateAndSum(depositList, TradeOrderPayDO::getPaymentDate, TradeOrderPayDO::getPayAmount);
|
|
|
+ Map<LocalDate, BigDecimal> orderMap = groupByDateAndSum(orderPaymentList, TradeOrderPayDO::getPaymentDate, TradeOrderPayDO::getPayAmount);
|
|
|
+
|
|
|
+ // 5. 构建结果列表
|
|
|
+ List<BankStatementReportRespVO> resultList = new ArrayList<>(subDateList.size());
|
|
|
+ for (LocalDate tradeDate : subDateList) {
|
|
|
+ BankStatementReportRespVO report = new BankStatementReportRespVO();
|
|
|
+ report.setTradeDate(tradeDate.toString());
|
|
|
+
|
|
|
+ BigDecimal billRepayment = billMap.getOrDefault(tradeDate, BigDecimal.ZERO);
|
|
|
+ BigDecimal depositRecharge = depositMap.getOrDefault(tradeDate, BigDecimal.ZERO);
|
|
|
+ BigDecimal orderPayment = orderMap.getOrDefault(tradeDate, BigDecimal.ZERO);
|
|
|
+
|
|
|
+ report.setBillRepayment(billRepayment);
|
|
|
+ report.setDepositRecharge(depositRecharge);
|
|
|
+ report.setOrderPayment(orderPayment);
|
|
|
+
|
|
|
+ // 商户平台合计 = 账单还款 + 预存款充值 + 订单支付
|
|
|
+ BigDecimal merchantPlatformTotal = billRepayment.add(depositRecharge).add(orderPayment);
|
|
|
+ report.setMerchantPlatformTotal(merchantPlatformTotal);
|
|
|
+
|
|
|
+ // 对公充值预存款 - TODO: 需要根据实际业务逻辑查询对公充值数据
|
|
|
+ BigDecimal publicDepositRecharge = BigDecimal.ZERO;
|
|
|
+ report.setPublicDepositRecharge(publicDepositRecharge);
|
|
|
+
|
|
|
+ // 农行进账合计 = 商户平台合计 + 对公充值预存款
|
|
|
+ BigDecimal agriculturalBankTotal = merchantPlatformTotal.add(publicDepositRecharge);
|
|
|
+ report.setAgriculturalBankTotal(agriculturalBankTotal);
|
|
|
+
|
|
|
+ // 其他银行(手工下账单) - TODO: 根据实际业务逻辑查询其他银行手工下账单数据
|
|
|
+ BigDecimal otherBankManual = BigDecimal.ZERO;
|
|
|
+ report.setOtherBankManual(otherBankManual);
|
|
|
+
|
|
|
+ // 银行进账合计 = 其他银行 + 农行进账合计
|
|
|
+ BigDecimal bankTotal = otherBankManual.add(agriculturalBankTotal);
|
|
|
+ report.setBankTotal(bankTotal);
|
|
|
+
|
|
|
+ resultList.add(report);
|
|
|
+ }
|
|
|
+
|
|
|
+ return new PageResult<>(resultList, (long) total);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按日期分组并求和
|
|
|
+ */
|
|
|
+ private <T> Map<LocalDate, BigDecimal> groupByDateAndSum(List<T> list, Function<T, LocalDateTime> dateExtractor, Function<T, BigDecimal> amountExtractor) {
|
|
|
+ if (CollUtil.isEmpty(list)) {
|
|
|
+ return new HashMap<>();
|
|
|
+ }
|
|
|
+ return list.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ item -> dateExtractor.apply(item).toLocalDate(),
|
|
|
+ Collectors.reducing(BigDecimal.ZERO, amountExtractor, BigDecimal::add)
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 导出银行对账报表 Excel
|
|
|
+ *
|
|
|
+ * @param pageReqVO 查询条件
|
|
|
+ * @param response HTTP响应
|
|
|
+ * @throws IOException IO异常
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void exportBankStatementReportExcel(BankStatementReportPageReqVO pageReqVO, HttpServletResponse response) throws IOException {
|
|
|
+ // 1. 查询所有数据(不分页)
|
|
|
+ pageReqVO.setPageNo(1);
|
|
|
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
|
|
+ PageResult<BankStatementReportRespVO> pageResult = getBankStatementReportPage(pageReqVO);
|
|
|
+ List<BankStatementReportRespVO> list = pageResult.getList();
|
|
|
+
|
|
|
+ // 2. 计算合计行
|
|
|
+ if (CollUtil.isNotEmpty(list)) {
|
|
|
+ BankStatementReportRespVO summary = calculateSummary(list);
|
|
|
+ summary.setTradeDate("合计"); // 合计行日期置空
|
|
|
+ list.add(summary);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 导出 Excel
|
|
|
+ ExcelUtils.write(response, "银行对账报表.xls", "数据", BankStatementReportRespVO.class, list);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建日期列表
|
|
|
+ */
|
|
|
+ private List<LocalDate> buildDateList(LocalDate startDate, LocalDate endDate) {
|
|
|
+ List<LocalDate> dateList = new ArrayList<>();
|
|
|
+ if (startDate == null || endDate == null) {
|
|
|
+ return dateList;
|
|
|
+ }
|
|
|
+ if (startDate.isAfter(endDate)) {
|
|
|
+ return dateList;
|
|
|
+ }
|
|
|
+
|
|
|
+ long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);
|
|
|
+ for (int i = 0; i <= daysBetween; i++) {
|
|
|
+ dateList.add(startDate.plusDays(i));
|
|
|
+ }
|
|
|
+ return dateList;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据日期构建报表数据
|
|
|
+ */
|
|
|
+ private BankStatementReportRespVO buildReportByDate(LocalDate tradeDate) {
|
|
|
+ BankStatementReportRespVO report = new BankStatementReportRespVO();
|
|
|
+ report.setTradeDate(tradeDate.toString());
|
|
|
+
|
|
|
+ LocalDateTime startDateTime = tradeDate.atStartOfDay();
|
|
|
+ LocalDateTime endDateTime = tradeDate.plusDays(1).atStartOfDay();
|
|
|
+
|
|
|
+ // 1. 查询账单还款(扫码) - 从bill表中查询
|
|
|
+ LambdaQueryWrapper<BillDO> billWrapper = new LambdaQueryWrapper<>();
|
|
|
+ billWrapper.eq(BillDO::getBillStatus, 1) // 已支付
|
|
|
+ .between(BillDO::getPayTime, startDateTime, endDateTime);
|
|
|
+ List<BillDO> billList = billMapper.selectList(billWrapper);
|
|
|
+ BigDecimal billRepayment = billList.stream()
|
|
|
+ .map(BillDO::getPayAmount)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+ report.setBillRepayment(billRepayment == null ? BigDecimal.ZERO : billRepayment);
|
|
|
+
|
|
|
+ // 2. 查询预存款充值(扫码) - 从支付表中查询分销商充值订单
|
|
|
+ // TODO: 需要根据实际业务逻辑判断哪些是预存款充值
|
|
|
+ // 这里假设orderType为其他订单的是预存款充值
|
|
|
+ LambdaQueryWrapper<TradeOrderPayDO> depositWrapper = new LambdaQueryWrapper<>();
|
|
|
+ depositWrapper.eq(TradeOrderPayDO::getPayStatus, 1) // 已支付
|
|
|
+ .in(TradeOrderPayDO::getPaymentType, CollUtil.newArrayList(5)) // 支付方式
|
|
|
+ .between(TradeOrderPayDO::getPaymentDate, startDateTime, endDateTime);
|
|
|
+ // TODO: 需要添加具体的判断条件来区分扫码支付方式
|
|
|
+ List<TradeOrderPayDO> depositList = tradeOrderPayMapper.selectList(depositWrapper);
|
|
|
+ BigDecimal depositRecharge = depositList.stream()
|
|
|
+ .map(TradeOrderPayDO::getPayAmount)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+ report.setDepositRecharge(depositRecharge == null ? BigDecimal.ZERO : depositRecharge);
|
|
|
+
|
|
|
+ // 3. 查询订单支付(扫码) - 从支付表中查询交易订单
|
|
|
+ LambdaQueryWrapper<TradeOrderPayDO> orderWrapper = new LambdaQueryWrapper<>();
|
|
|
+ orderWrapper.eq(TradeOrderPayDO::getPayStatus, 1) // 已支付
|
|
|
+ .in(TradeOrderPayDO::getPaymentType, CollUtil.newArrayList(1,2,3)) // 支付方式
|
|
|
+ .between(TradeOrderPayDO::getPaymentDate, startDateTime, endDateTime);
|
|
|
+ // TODO: 需要添加具体的判断条件来区分扫码支付方式
|
|
|
+ List<TradeOrderPayDO> orderPaymentList = tradeOrderPayMapper.selectList(orderWrapper);
|
|
|
+ BigDecimal orderPayment = orderPaymentList.stream()
|
|
|
+ .map(TradeOrderPayDO::getPayAmount)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+ report.setOrderPayment(orderPayment == null ? BigDecimal.ZERO : orderPayment);
|
|
|
+
|
|
|
+ // 4. 商户平台合计 = 账单还款 + 预存款充值 + 订单支付
|
|
|
+ BigDecimal merchantPlatformTotal = report.getBillRepayment()
|
|
|
+ .add(report.getDepositRecharge())
|
|
|
+ .add(report.getOrderPayment());
|
|
|
+ report.setMerchantPlatformTotal(merchantPlatformTotal);
|
|
|
+
|
|
|
+ // 5. 对公充值预存款 - 从支付表中查询对公充值
|
|
|
+ LambdaQueryWrapper<TradeOrderPayDO> publicDepositRechargeWrapper = new LambdaQueryWrapper<>();
|
|
|
+ orderWrapper.eq(TradeOrderPayDO::getPayStatus, 1) // 已支付
|
|
|
+ .in(TradeOrderPayDO::getPaymentType, CollUtil.newArrayList(10)) // 支付方式
|
|
|
+ .between(TradeOrderPayDO::getPaymentDate, startDateTime, endDateTime);
|
|
|
+ // TODO: 需要根据实际业务逻辑查询对公充值数据
|
|
|
+ List<TradeOrderPayDO> publicDepositRechargeList = tradeOrderPayMapper.selectList(publicDepositRechargeWrapper);
|
|
|
+ BigDecimal publicDepositRecharge = publicDepositRechargeList.stream()
|
|
|
+ .map(TradeOrderPayDO::getPayAmount)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+ report.setPublicDepositRecharge(publicDepositRecharge == null ? BigDecimal.ZERO : publicDepositRecharge);
|
|
|
+
|
|
|
+ // 6. 农行进账合计 = 商户平台合计 + 对公充值预存款
|
|
|
+ BigDecimal agriculturalBankTotal = report.getMerchantPlatformTotal()
|
|
|
+ .add(report.getPublicDepositRecharge());
|
|
|
+ report.setAgriculturalBankTotal(agriculturalBankTotal);
|
|
|
+
|
|
|
+ // 7. 其他银行(手工下账单) - 需要根据实际业务逻辑查询
|
|
|
+ // TODO: 根据实际业务逻辑查询其他银行手工下账单数据
|
|
|
+ BigDecimal otherBankManual = BigDecimal.ZERO;
|
|
|
+ report.setOtherBankManual(otherBankManual);
|
|
|
+
|
|
|
+ // 8. 银行进账合计 = 其他银行 + 农行进账合计
|
|
|
+ BigDecimal bankTotal = report.getOtherBankManual()
|
|
|
+ .add(report.getAgriculturalBankTotal());
|
|
|
+ report.setBankTotal(bankTotal);
|
|
|
+
|
|
|
+ return report;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算合计
|
|
|
+ */
|
|
|
+ private BankStatementReportRespVO calculateSummary(List<BankStatementReportRespVO> list) {
|
|
|
+ BankStatementReportRespVO summary = new BankStatementReportRespVO();
|
|
|
+
|
|
|
+ BigDecimal totalBillRepayment = BigDecimal.ZERO;
|
|
|
+ BigDecimal totalDepositRecharge = BigDecimal.ZERO;
|
|
|
+ BigDecimal totalOrderPayment = BigDecimal.ZERO;
|
|
|
+ BigDecimal totalMerchantPlatformTotal = BigDecimal.ZERO;
|
|
|
+ BigDecimal totalPublicDepositRecharge = BigDecimal.ZERO;
|
|
|
+ BigDecimal totalAgriculturalBankTotal = BigDecimal.ZERO;
|
|
|
+ BigDecimal totalOtherBankManual = BigDecimal.ZERO;
|
|
|
+ BigDecimal totalBankTotal = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ for (BankStatementReportRespVO item : list) {
|
|
|
+ totalBillRepayment = totalBillRepayment.add(item.getBillRepayment());
|
|
|
+ totalDepositRecharge = totalDepositRecharge.add(item.getDepositRecharge());
|
|
|
+ totalOrderPayment = totalOrderPayment.add(item.getOrderPayment());
|
|
|
+ totalMerchantPlatformTotal = totalMerchantPlatformTotal.add(item.getMerchantPlatformTotal());
|
|
|
+ totalPublicDepositRecharge = totalPublicDepositRecharge.add(item.getPublicDepositRecharge());
|
|
|
+ totalAgriculturalBankTotal = totalAgriculturalBankTotal.add(item.getAgriculturalBankTotal());
|
|
|
+ totalOtherBankManual = totalOtherBankManual.add(item.getOtherBankManual());
|
|
|
+ totalBankTotal = totalBankTotal.add(item.getBankTotal());
|
|
|
+ }
|
|
|
+
|
|
|
+ summary.setBillRepayment(totalBillRepayment);
|
|
|
+ summary.setDepositRecharge(totalDepositRecharge);
|
|
|
+ summary.setOrderPayment(totalOrderPayment);
|
|
|
+ summary.setMerchantPlatformTotal(totalMerchantPlatformTotal);
|
|
|
+ summary.setPublicDepositRecharge(totalPublicDepositRecharge);
|
|
|
+ summary.setAgriculturalBankTotal(totalAgriculturalBankTotal);
|
|
|
+ summary.setOtherBankManual(totalOtherBankManual);
|
|
|
+ summary.setBankTotal(totalBankTotal);
|
|
|
+
|
|
|
+ return summary;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|