diff --git a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisSettleInvoiceRecordController.java b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisSettleInvoiceRecordController.java index 172b5490d..41c7ec72d 100644 --- a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisSettleInvoiceRecordController.java +++ b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisSettleInvoiceRecordController.java @@ -1,11 +1,11 @@ -/** +/** * @Project: emis * @Title: EmisSettleInvoiceRecordController.java * @author linfso * @date 2024-07-21 13:31:26 * @Copyright: ShangHai Duta 2022 All rights reserved. - * @version v1.0 + * @version v1.0 * @Description:

开票记录表 控制器

*/ @@ -38,18 +38,19 @@ import com.xdadan.erp.common.utils.StringUtils; import com.xdadan.erp.common.utils.poi.ExcelUtil; import com.xdadan.erp.emis.domain.EmisSettleInvoiceRecord; +import com.xdadan.erp.emis.domain.EmisSettleInvoiceRecordExportVO; import com.xdadan.erp.emis.service.IEmisSettleInvoiceRecordService; +import com.xdadan.erp.emis.service.excelCellStrategy.EmisSettleInvoiceRecordCustomExcelUtil; /** * 开票记录表Controller - * + * * @author linfso * @date 2024-07-21 13:31:26 */ @RestController @RequestMapping("/emis/emisSettleInvoiceRecord") -public class EmisSettleInvoiceRecordController extends BaseController -{ +public class EmisSettleInvoiceRecordController extends BaseController { @Autowired private IEmisSettleInvoiceRecordService emisSettleInvoiceRecordService; @@ -83,8 +84,8 @@ public class EmisSettleInvoiceRecordController extends BaseController /** * 检查是否重复 - * - * @param emisSettleInvoiceRecord + * + * @param emisSettleInvoiceRecord * @return 数量 */ @PreAuthorize("@ss.hasPermi('emis:emisSettleInvoiceRecord:list')") @@ -109,6 +110,37 @@ public class EmisSettleInvoiceRecordController extends BaseController util.exportExcel(response, list, "开票记录表数据"); } + /** + * 定制导出开票记录表列表 + * + */ + @PreAuthorize("@ss.hasPermi('emis:emisSettleInvoiceRecord:customExport')") + @Log(title = "开票记录表定制导出", businessType = BusinessType.EXPORT) + @PostMapping("/customExport") + public void customExport(HttpServletResponse response, EmisSettleInvoiceRecord emisSettleInvoiceRecord) { + setPrivParams(emisSettleInvoiceRecord); + + if (!StringUtils.isEmpty(emisSettleInvoiceRecord.getSettleBillNo())) { + emisSettleInvoiceRecord + .setSettleBillNo(WaybillHelper.formatQueryValue(emisSettleInvoiceRecord.getSettleBillNo())); + } + + if (!StringUtils.isEmpty(emisSettleInvoiceRecord.getInvoiceNo())) { + emisSettleInvoiceRecord + .setInvoiceNo(WaybillHelper.formatQueryValue(emisSettleInvoiceRecord.getInvoiceNo())); + } + + if (emisSettleInvoiceRecord.getParams().get("billCode") != null) { + String billCodeStr = WaybillHelper + .formatQueryValue(emisSettleInvoiceRecord.getParams().get("billCode").toString()); + emisSettleInvoiceRecord.getParams().put("billCode", billCodeStr); + } + + List list = emisSettleInvoiceRecordService + .selectCustomExportList(emisSettleInvoiceRecord); + EmisSettleInvoiceRecordCustomExcelUtil.exportCustomExcel(response, list, "开票记录表定制导出数据"); + } + /** * 获取开票记录表详细信息 */ diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisSettleInvoiceRecord.java b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisSettleInvoiceRecord.java index a811b199a..63e5c6878 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisSettleInvoiceRecord.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisSettleInvoiceRecord.java @@ -98,7 +98,7 @@ public class EmisSettleInvoiceRecord extends BaseEntity private BigDecimal recedMoney; /* 付款状态 0-未付款 1-已付款 2-部分付款 */ private String paymentStatus; - /* 开票状态 0-待开票 1-已开票 2-拒绝开票 */ + /* 开票状态 0-未开票 1-开票中 2-已开票 3-开票异常 */ private String invoiceStatus; /* 开票状态描述 */ private String invoiceStatusDesc; diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisSettleInvoiceRecordExportVO.java b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisSettleInvoiceRecordExportVO.java new file mode 100644 index 000000000..5f50b5f50 --- /dev/null +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisSettleInvoiceRecordExportVO.java @@ -0,0 +1,47 @@ +package com.xdadan.erp.emis.domain; + +import lombok.Data; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 开票记录定制导出VO + * + * @author heyu + * @date 2025-11-04 + */ +@Data +public class EmisSettleInvoiceRecordExportVO { + // 发票申请日期 + private Date applyDate; + // 发票申请人 + private String applyManName; + // 申请开票金额 + private BigDecimal applyMoney; + // 开票日期 + private Date opDate; + // 开票人 + private String opManName; + // 开票抬头 + private String companyName; + // 发票号 + private String invoiceNo; + // 账单编号(多个用逗号分隔) + private String billNos; + // 开票状态 + private String invoiceStatusDesc; + // 收款状态 + private String paymentStatusDesc; + // 已收金额 + private BigDecimal recedMoney; + // 客户名称(多个用逗号分隔) + private String customerNames; + // 客户付款日期(多个用逗号分隔,格式:2025/10/30 付款2000元) + private String customerPaymentDates; + // 收款登记日期(多个用逗号分隔,格式:2025/10/30 登记2000元) + private String collectionRegisterDates; + // 账单类型(现金账单,月结账单) + private String billType; +} + + diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisSettleInvoiceRecordService.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisSettleInvoiceRecordService.java index 49b1a2ba1..dca5e7162 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisSettleInvoiceRecordService.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisSettleInvoiceRecordService.java @@ -12,6 +12,7 @@ package com.xdadan.erp.emis.service; import java.util.List; import com.xdadan.erp.emis.domain.EmisSettleInvoiceRecord; import com.xdadan.erp.emis.domain.exception.EmisBizError; +import com.xdadan.erp.emis.domain.EmisSettleInvoiceRecordExportVO; /** * @ClassName EmisSettleInvoiceRecordService @@ -96,4 +97,13 @@ public interface IEmisSettleInvoiceRecordService { */ public List selectInvoiceRecordListByBillCodes(List billCodes); + /** + * 查询开票记录定制导出数据列表 + * + * @param emisSettleInvoiceRecord 开票记录表 + * @return 导出数据列表 + */ + public List selectCustomExportList( + EmisSettleInvoiceRecord emisSettleInvoiceRecord); + } diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/excelCellStrategy/EmisSettleInvoiceRecordCustomExcelUtil.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/excelCellStrategy/EmisSettleInvoiceRecordCustomExcelUtil.java new file mode 100644 index 000000000..c532f4aef --- /dev/null +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/excelCellStrategy/EmisSettleInvoiceRecordCustomExcelUtil.java @@ -0,0 +1,297 @@ +package com.xdadan.erp.emis.service.excelCellStrategy; + +import com.xdadan.erp.emis.domain.EmisSettleInvoiceRecordExportVO; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigDecimal; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.List; + +/** + * 开票记录定制导出Excel工具类 + * + * @author heyu + * @date 2025-11-04 + */ +public class EmisSettleInvoiceRecordCustomExcelUtil { + + private static final String[] HEADERS = { + "发票申请日期", "发票申请人", "申请开票金额", "开票日期", "开票人", "开票抬头", + "发票号", "账单编号", "开票状态", "收款状态", "已收金额", "客户名称", + "客户付款日期", "收款登记日期", "账单类型" + }; + + private static final int[] COLUMN_WIDTHS = { + 20, 15, 15, 20, 15, 30, + 25, 25, 15, 15, 15, 30, + 30, 30, 20 + }; + + /** + * 导出定制Excel + * + * @param response HTTP响应 + * @param dataList 数据列表 + * @param sheetName 工作表名称 + */ + public static void exportCustomExcel(HttpServletResponse response, List dataList, + String sheetName) { + try { + // 创建工作簿 + SXSSFWorkbook workbook = new SXSSFWorkbook(100); + Sheet sheet = workbook.createSheet(sheetName); + + // 创建样式 + CellStyle headerStyle = createHeaderStyle(workbook); + CellStyle dataStyle = createDataStyle(workbook); + CellStyle dateStyle = createDateStyle(workbook); + CellStyle numberStyle = createNumberStyle(workbook); + + // 创建表头 + createHeader(sheet, headerStyle); + + // 填充数据 + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + int rowIndex = 1; + + for (EmisSettleInvoiceRecordExportVO data : dataList) { + Row row = sheet.createRow(rowIndex++); + + // 发票申请日期 + createCell(row, 0, data.getApplyDate() != null ? dateFormat.format(data.getApplyDate()) : "", + dateStyle); + + // 发票申请人 + createCell(row, 1, data.getApplyManName() != null ? data.getApplyManName() : "", dataStyle); + + // 申请开票金额(去除末尾多余的0) + BigDecimal applyMoney = data.getApplyMoney(); + if (applyMoney != null) { + applyMoney = applyMoney.stripTrailingZeros(); + } + createCell(row, 2, applyMoney, numberStyle); + + // 开票日期 + createCell(row, 3, data.getOpDate() != null ? dateFormat.format(data.getOpDate()) : "", dateStyle); + + // 开票人 + createCell(row, 4, data.getOpManName() != null ? data.getOpManName() : "", dataStyle); + + // 开票抬头 + createCell(row, 5, data.getCompanyName() != null ? data.getCompanyName() : "", dataStyle); + + // 发票号 + createCell(row, 6, data.getInvoiceNo() != null ? data.getInvoiceNo() : "", dataStyle); + + // 账单编号 + createCell(row, 7, data.getBillNos() != null ? data.getBillNos() : "", dataStyle); + + // 开票状态 + createCell(row, 8, data.getInvoiceStatusDesc() != null ? data.getInvoiceStatusDesc() : "", dataStyle); + + // 收款状态 + createCell(row, 9, data.getPaymentStatusDesc() != null ? data.getPaymentStatusDesc() : "", dataStyle); + + // 已收金额(去除末尾多余的0) + BigDecimal recedMoney = data.getRecedMoney(); + if (recedMoney != null) { + recedMoney = recedMoney.stripTrailingZeros(); + } + createCell(row, 10, recedMoney, numberStyle); + + // 客户名称 + createCell(row, 11, data.getCustomerNames() != null ? data.getCustomerNames() : "", dataStyle); + + // 客户付款日期 + createCell(row, 12, data.getCustomerPaymentDates() != null ? data.getCustomerPaymentDates() : "", + dataStyle); + + // 收款登记日期 + createCell(row, 13, data.getCollectionRegisterDates() != null ? data.getCollectionRegisterDates() : "", + dataStyle); + + // 账单类型 + createCell(row, 14, data.getBillType() != null ? data.getBillType() : "", dataStyle); + } + + // 设置列宽 + setColumnWidths(sheet); + + // 输出文件 + outputFile(response, workbook, sheetName); + + } catch (Exception e) { + throw new RuntimeException("导出Excel失败:" + e.getMessage(), e); + } + } + + /** + * 创建表头样式 + */ + private static CellStyle createHeaderStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + + // 设置字体 + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short) 12); + font.setBold(true); + style.setFont(font); + + // 设置背景色(绿色) + style.setFillForegroundColor(IndexedColors.LIGHT_GREEN.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + + // 设置边框 + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + + // 设置对齐方式 + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + + return style; + } + + /** + * 创建数据样式 + */ + private static CellStyle createDataStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + + // 设置字体 + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short) 12); + style.setFont(font); + + // 设置边框 + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + + // 设置对齐方式 + style.setAlignment(HorizontalAlignment.LEFT); + style.setVerticalAlignment(VerticalAlignment.CENTER); + + return style; + } + + /** + * 创建日期样式 + */ + private static CellStyle createDateStyle(Workbook workbook) { + CellStyle style = createDataStyle(workbook); + style.setDataFormat(workbook.createDataFormat().getFormat("yyyy-mm-dd hh:mm")); + return style; + } + + /** + * 创建数字样式 + */ + private static CellStyle createNumberStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + + // 设置字体 + Font font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short) 12); + style.setFont(font); + + // 设置边框 + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + + // 设置数字格式 + style.setDataFormat(workbook.createDataFormat().getFormat("#,##0.00")); + + // 设置对齐方式 + style.setAlignment(HorizontalAlignment.RIGHT); + style.setVerticalAlignment(VerticalAlignment.CENTER); + + return style; + } + + /** + * 创建表头 + */ + private static void createHeader(Sheet sheet, CellStyle headerStyle) { + Row headerRow = sheet.createRow(0); + headerRow.setHeightInPoints(25); + + for (int i = 0; i < HEADERS.length; i++) { + Cell cell = headerRow.createCell(i); + cell.setCellValue(HEADERS[i]); + cell.setCellStyle(headerStyle); + } + } + + /** + * 创建单元格 + */ + private static void createCell(Row row, int columnIndex, String value, CellStyle style) { + Cell cell = row.createCell(columnIndex); + cell.setCellValue(value != null ? value : ""); + cell.setCellStyle(style); + } + + /** + * 创建数字单元格(去除末尾多余的0) + */ + private static void createCell(Row row, int columnIndex, BigDecimal value, CellStyle style) { + Cell cell = row.createCell(columnIndex); + // 如果BigDecimal值为null或为0,则设置为空字符串 + if (value == null || value.compareTo(BigDecimal.ZERO) == 0) { + cell.setCellValue(""); + } else { + // 去除末尾多余的0,然后使用toPlainString()避免科学计数法 + BigDecimal stripped = value.stripTrailingZeros(); + // 如果scale为负数,说明有尾随0被移除,需要重新构造 + if (stripped.scale() < 0) { + stripped = stripped.setScale(0); + } + cell.setCellValue(stripped.toPlainString()); + } + cell.setCellStyle(style); + } + + + /** + * 设置列宽 + */ + private static void setColumnWidths(Sheet sheet) { + for (int i = 0; i < COLUMN_WIDTHS.length; i++) { + sheet.setColumnWidth(i, COLUMN_WIDTHS[i] * 256); + } + } + + /** + * 输出文件 + */ + private static void outputFile(HttpServletResponse response, Workbook workbook, String sheetName) + throws IOException { + // 设置响应头 + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + + String fileName = URLEncoder.encode(sheetName + ".xlsx", "UTF-8").replaceAll("\\+", "%20"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName); + + // 输出文件 + try (OutputStream outputStream = response.getOutputStream()) { + workbook.write(outputStream); + workbook.close(); + } + } +} + diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisSettleInvoiceRecordServiceImpl.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisSettleInvoiceRecordServiceImpl.java index 27fc06f9f..8eb2cda3d 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisSettleInvoiceRecordServiceImpl.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisSettleInvoiceRecordServiceImpl.java @@ -11,9 +11,7 @@ package com.xdadan.erp.emis.service.impl; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; +import java.util.*; import com.xdadan.erp.emis.domain.*; import com.xdadan.erp.emis.domain.enumtype.EmisBizErrorType; @@ -22,9 +20,18 @@ import com.xdadan.erp.emis.mapper.EmisSettleBillMapper; import com.xdadan.erp.emis.mapper.EmisSettleInvoiceRelMapper; import com.xdadan.erp.emis.mapper.EmisSettleSubBillMapper; import com.xdadan.erp.emis.mapper.EmisCustomerInvoiceInfoMapper; +import com.xdadan.erp.emis.mapper.EmisWaybillMapper; +import com.xdadan.erp.emis.mapper.EmisSettlePayRelMapper; import com.xdadan.erp.emis.service.EmisBaseService; import com.xdadan.erp.emis.service.IEmisSettleBillService; import com.xdadan.erp.emis.utils.WaybillHelper; +import com.xdadan.erp.emis.domain.EmisSettleInvoiceRecordExportVO; +import com.xdadan.erp.emis.domain.EmisSettlePayRecord; +import com.xdadan.erp.emis.domain.EmisWaybill; +import com.xdadan.erp.emis.domain.EmisSettleBill; +import java.text.SimpleDateFormat; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -66,6 +73,12 @@ public class EmisSettleInvoiceRecordServiceImpl extends EmisBaseService implemen @Autowired private EmisSettlePayRecordMapper emisSettlePayRecordMapper; + @Autowired + private EmisWaybillMapper emisWaybillMapper; + + @Autowired + private EmisSettlePayRelMapper emisSettlePayRelMapper; + /** * 查询开票记录表 * @@ -377,4 +390,250 @@ public class EmisSettleInvoiceRecordServiceImpl extends EmisBaseService implemen return emisSettleInvoiceRecordMapper.selectInvoiceRecordListByBillCodes(billCodes); } + /** + * 查询开票记录定制导出数据列表 + * + * @param emisSettleInvoiceRecord 开票记录表 + * @return 导出数据列表 + */ + @Override + public List selectCustomExportList( + EmisSettleInvoiceRecord emisSettleInvoiceRecord) { + // 查询开票记录列表 + List invoiceRecordList = emisSettleInvoiceRecordMapper + .selectEmisSettleInvoiceRecordList(emisSettleInvoiceRecord); + + List exportList = new ArrayList<>(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); + + for (EmisSettleInvoiceRecord record : invoiceRecordList) { + EmisSettleInvoiceRecordExportVO exportVO = new EmisSettleInvoiceRecordExportVO(); + // 基础字段 + exportVO.setApplyDate(record.getApplyDate()); + exportVO.setApplyManName(record.getApplyManName()); + exportVO.setApplyMoney(record.getApplyMoney()); + exportVO.setOpDate(record.getOpDate()); + exportVO.setOpManName(record.getOpManName()); + exportVO.setCompanyName(record.getCompanyName()); + exportVO.setInvoiceNo(record.getInvoiceNo()); + + // 开票状态(0-未开票 1-开票中 2-已开票 3-开票异常) + String invoiceStatusDesc = ""; + if ("0".equals(record.getInvoiceStatus())) { + invoiceStatusDesc = "未开票"; + } else if ("1".equals(record.getInvoiceStatus())) { + invoiceStatusDesc = "开票中"; + } else if ("2".equals(record.getInvoiceStatus())) { + invoiceStatusDesc = "已开票"; + } else if ("3".equals(record.getInvoiceStatus())) { + invoiceStatusDesc = "开票异常"; + } + exportVO.setInvoiceStatusDesc(invoiceStatusDesc); + exportVO.setRecedMoney(record.getRecedMoney()); + + // 收款状态描述 + String paymentStatusDesc = ""; + if ("0".equals(record.getPaymentStatus())) { + paymentStatusDesc = "未收款"; + } else if ("1".equals(record.getPaymentStatus())) { + paymentStatusDesc = "已收款"; + } else if ("2".equals(record.getPaymentStatus())) { + paymentStatusDesc = "部分收款"; + } + exportVO.setPaymentStatusDesc(paymentStatusDesc); + + List customerNameList = new ArrayList<>(); + List paymentDateList = new ArrayList<>(); + List registerDateList = new ArrayList<>(); + Set settleTypeSet = new HashSet<>(); // 使用Set去重 + + // 查询账单类型(从settle_bill获取) + if (StringUtils.isNotBlank(record.getSettleBillNo())) { + String[] settleBillNoArr = Arrays.stream(record.getSettleBillNo().split(",")).distinct() + .toArray(String[]::new); + exportVO.setBillNos(record.getSettleBillNo()); + for (String settleBillNo : settleBillNoArr) { + if (StringUtils.isNotBlank(settleBillNo)) { + EmisSettleBill settleBill = emisSettleBillService + .selectEmisSettleBillBySettleBillNo(settleBillNo.trim()); + if (settleBill != null && StringUtils.isNotBlank(settleBill.getSettleType())) { + if ("1".equals(settleBill.getSettleType())) { + settleTypeSet.add("现金账单"); + } else if ("2".equals(settleBill.getSettleType())) { + settleTypeSet.add("月结账单"); + } + } + } + } + } + + // 根据发票对应的多个账单号查询emis_settle_pay_rel并关联emis_settle_pay_record、emis_waybill + // 按照cust_name、trade_date分组(客户付款日期) + // 按照cust_name、create_time分组(收款登记日期) + Map paymentGroupMap = new HashMap<>(); // key: custName_tradeDate + Map registerGroupMap = new HashMap<>(); // key: custName_createTime + + // 直接使用settleBillNo(多个用逗号分隔)查询支付关联记录 + if (StringUtils.isNotBlank(record.getSettleBillNo())) { + // 根据settleBillNo查询支付关联记录 + List payRelList = emisSettlePayRelMapper + .selectHasPayListBySettleBillNo(record.getSettleBillNo()); + + if (!CollectionUtils.isEmpty(payRelList)) { + // 获取所有payId + Set payIdSet = payRelList.stream() + .map(EmisSettlePayRel::getPayId) + .filter(StringUtils::isNotBlank) + .distinct() + .collect(Collectors.toSet()); + + // 按payId查询收款记录,建立payId到payRecord的映射 + Map payRecordMap = new HashMap<>(); + for (String payId : payIdSet) { + EmisSettlePayRecord queryPayRecord = new EmisSettlePayRecord(); + queryPayRecord.setPayId(payId); + queryPayRecord.setDelFlag("0"); + List payRecordList = emisSettlePayRecordMapper + .selectEmisSettlePayRecordList(queryPayRecord); + if (!CollectionUtils.isEmpty(payRecordList)) { + // 只处理收款记录(recType = "1"),不包括退款 + EmisSettlePayRecord payRecord = payRecordList.stream() + .filter(pr -> "1".equals(pr.getRecType())) + .findFirst() + .orElse(null); + if (payRecord != null) { + payRecordMap.put(payId, payRecord); + } + } + } + + // 遍历支付关联记录,按billNo查询waybill,按cust_name和trade_date/create_time分组 + for (EmisSettlePayRel payRel : payRelList) { + if (payRel.getPayMoney() == null + || payRel.getPayMoney().compareTo(BigDecimal.ZERO) <= 0) { + continue; + } + + String billNo = payRel.getBillNo(); + if (StringUtils.isBlank(billNo)) { + continue; + } + + // 查询waybill获取客户名称 + String custName = ""; + EmisWaybill waybill = emisWaybillMapper.selectWaybillBaseInfoByBillCode(billNo); + if (waybill != null && StringUtils.isNotBlank(waybill.getCustName())) { + custName = waybill.getCustName(); + // 收集客户名称 + if (!customerNameList.contains(custName)) { + customerNameList.add(custName); + } + } + + // 获取对应的收款记录 + EmisSettlePayRecord payRecord = payRecordMap.get(payRel.getPayId()); + if (payRecord == null) { + continue; + } + + Date tradeDate = payRecord.getTradeDate(); + Date createTime = payRecord.getCreateTime(); + + // 客户付款日期分组(按custName + tradeDate分组) + // 即使custName为空,也要记录付款日期 + if (tradeDate != null) { + String tradeDateStr = dateFormat.format(tradeDate); + String paymentKey = (StringUtils.isNotBlank(custName) ? custName : "") + "_" + tradeDateStr; + PaymentGroup paymentGroup = paymentGroupMap.get(paymentKey); + if (paymentGroup == null) { + paymentGroup = new PaymentGroup(); + paymentGroup.custName = custName != null ? custName : ""; + paymentGroup.date = tradeDate; + paymentGroup.dateStr = tradeDateStr; + paymentGroup.totalMoney = BigDecimal.ZERO; + paymentGroupMap.put(paymentKey, paymentGroup); + } + paymentGroup.totalMoney = paymentGroup.totalMoney.add(payRel.getPayMoney()); + } + + // 收款登记日期分组(按custName + createTime分组) + // 即使custName为空,也要记录登记日期 + if (createTime != null) { + String createTimeStr = dateFormat.format(createTime); + String registerKey = (StringUtils.isNotBlank(custName) ? custName : "") + "_" + + createTimeStr; + PaymentGroup registerGroup = registerGroupMap.get(registerKey); + if (registerGroup == null) { + registerGroup = new PaymentGroup(); + registerGroup.custName = custName != null ? custName : ""; + registerGroup.date = createTime; + registerGroup.dateStr = createTimeStr; + registerGroup.totalMoney = BigDecimal.ZERO; + registerGroupMap.put(registerKey, registerGroup); + } + registerGroup.totalMoney = registerGroup.totalMoney.add(payRel.getPayMoney()); + } + } + } + } + + // 格式化客户付款日期(格式:2025/10/30 付款2000元 A公司) + for (PaymentGroup group : paymentGroupMap.values()) { + BigDecimal strippedMoney = group.totalMoney.stripTrailingZeros(); + String paymentDateStr = group.dateStr + " 付款" + strippedMoney.toPlainString() + "元"; + // 如果客户名称不为空,则追加客户名称 + if (StringUtils.isNotBlank(group.custName)) { + paymentDateStr += " " + group.custName; + } + paymentDateList.add(paymentDateStr); + } + + // 格式化收款登记日期(格式:2025/10/30 登记2000元 A公司) + for (PaymentGroup group : registerGroupMap.values()) { + BigDecimal strippedMoney = group.totalMoney.stripTrailingZeros(); + String registerDateStr = group.dateStr + " 登记" + strippedMoney.toPlainString() + "元"; + // 如果客户名称不为空,则追加客户名称 + if (StringUtils.isNotBlank(group.custName)) { + registerDateStr += " " + group.custName; + } + registerDateList.add(registerDateStr); + } + + // 设置客户名称(多个用逗号分隔) + if (!CollectionUtils.isEmpty(customerNameList)) { + exportVO.setCustomerNames(String.join(",", customerNameList)); + } + + // 设置客户付款日期(多个用逗号分隔) + if (!CollectionUtils.isEmpty(paymentDateList)) { + exportVO.setCustomerPaymentDates(String.join(";", paymentDateList)); + } + + // 设置收款登记日期(多个用逗号分隔) + if (!CollectionUtils.isEmpty(registerDateList)) { + exportVO.setCollectionRegisterDates(String.join(";", registerDateList)); + } + + // 设置账单类型(多个用逗号分隔) + if (!settleTypeSet.isEmpty()) { + List settleTypeList = new ArrayList<>(settleTypeSet); + exportVO.setBillType(String.join(",", settleTypeList)); + } + + exportList.add(exportVO); + } + + return exportList; + } + + /** + * 付款分组内部类 + */ + private static class PaymentGroup { + String custName; + Date date; + String dateStr; + BigDecimal totalMoney; + } + }