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 3e53a250d..318ab3cbc 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 @@ -290,4 +290,44 @@ public class EmisSettleInvoiceRecordController extends BaseController { } return AjaxResult.success("操作成功"); } + + /** + * 批量发票延期 + */ + @PreAuthorize("@ss.hasPermi('emis:emisSettleInvoiceRecord:delay')") + @Log(title = "批量发票延期", businessType = BusinessType.UPDATE) + @PostMapping("/batchDelayInvoice/{ids}") + public AjaxResult batchDelayInvoice(@PathVariable Long[] ids) { + try { + return toAjax(emisSettleInvoiceRecordService.batchDelayInvoice(ids)); + } catch (Exception ex) { + ex.printStackTrace(); + // 返回子定义异常 + if (ex instanceof EmisBizError) { + return AjaxResult.error(ex.getMessage(), ((EmisBizError) ex).getErrorCode()); + } + + return AjaxResult.error("延期操作异常,联系客服"); + } + } + + /** + * 批量取消发票延期 + */ + @PreAuthorize("@ss.hasPermi('emis:emisSettleInvoiceRecord:cancelDelay')") + @Log(title = "批量取消发票延期", businessType = BusinessType.UPDATE) + @PostMapping("/batchCancelDelayInvoice/{ids}") + public AjaxResult batchCancelDelayInvoice(@PathVariable Long[] ids) { + try { + return toAjax(emisSettleInvoiceRecordService.batchCancelDelayInvoice(ids)); + } catch (Exception ex) { + ex.printStackTrace(); + // 返回子定义异常 + if (ex instanceof EmisBizError) { + return AjaxResult.error(ex.getMessage(), ((EmisBizError) ex).getErrorCode()); + } + + return AjaxResult.error("取消延期操作异常,联系客服"); + } + } } 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 63e5c6878..de3a005b3 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 @@ -134,6 +134,17 @@ public class EmisSettleInvoiceRecord extends BaseEntity private String openChStatusDesc; /* 使用的开票企业代码 */ private String openComCode; + /* 开票主体 */ + private String salerCompanyName; + /* 是否延期 0-不延期 1-延期 */ + private String blDelay; + /* 发票延期操作人编码 */ + private String delayOpManCode; + /* 发票延期操作人名称 */ + private String delayOpManName; + /* 发票延期操作时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date delayOpDate; // 扩展信息 /* 申请 */ diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisSettleInvoiceRecordMapper.java b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisSettleInvoiceRecordMapper.java index 74d47e9c8..79e0b81ab 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisSettleInvoiceRecordMapper.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisSettleInvoiceRecordMapper.java @@ -120,4 +120,21 @@ public interface EmisSettleInvoiceRecordMapper extends BaseMapper selectSimpleInvoiceRecordList( EmisSettleInvoiceRecord emisSettleInvoiceRecord); + /** + * 批量发票延期 + * + * @param ids 发票记录ID数组 + * @param delayOpManCode 延期操作人 + * @return 结果 + */ + public int batchDelayInvoice(@Param("ids") Long[] ids, @Param("delayOpManCode") String delayOpManCode); + + /** + * 批量取消发票延期 + * + * @param ids 发票记录ID数组 + * @return 结果 + */ + public int batchCancelDelayInvoice(@Param("ids") Long[] ids); + } diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisSettlePayRelMapper.java b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisSettlePayRelMapper.java index df93e2948..72c821999 100644 --- a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisSettlePayRelMapper.java +++ b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisSettlePayRelMapper.java @@ -1,10 +1,10 @@ -/** +/** * @Project: emis * @Title: EmisSettlePayRelMapper.java * @author linfso * @date 2024-07-21 13:31:24 * @Copyright: ShangHai Doitinfo 2022 All rights reserved. - * @version v1.0 + * @version v1.0 * @Description:

支付子账单关联表 Mapper 接口

* Warning : This file is generate by ai tools,don't edit!!! */ @@ -16,6 +16,7 @@ import java.util.Map; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.xdadan.erp.emis.domain.EmisSettleInvoiceRel; import com.xdadan.erp.emis.domain.EmisSettlePayRel; +import org.apache.ibatis.annotations.Param; /** * @ClassName EmisSettlePayRelMapper * @Description

支付子账单关联表 Mapper 接口

@@ -27,18 +28,26 @@ public interface EmisSettlePayRelMapper extends BaseMapper /** * 主键查询 * @param id - * @return + * @return */ public EmisSettlePayRel selectEmisSettlePayRelById(Long id); public List selectHasPayListBySettleBillNo(String settleBillNo); + /** + * 根据账单号列表查询支付关联记录 + * + * @param settleBillNoList 账单号列表 + * @return 支付关联记录列表 + */ + public List selectHasPayListBySettleBillNoList(@Param("settleBillNoList") List settleBillNoList); + public List selectHasPayMapList(String settleBillNo); /** * 查询列表 - * - * @param emisSettlePayRel + * + * @param emisSettlePayRel * @return 集合 */ public List selectEmisSettlePayRelList(EmisSettlePayRel emisSettlePayRel); @@ -46,32 +55,32 @@ public interface EmisSettlePayRelMapper extends BaseMapper /** * 检查是否重复 - * - * @param emisSettlePayRel + * + * @param emisSettlePayRel * @return 数量 */ public int checkUnique(EmisSettlePayRel emisSettlePayRel); - + /** - * 新增 - * + * 新增 + * * @param emisSettlePayRel - * @return + * @return */ public int insertEmisSettlePayRel(EmisSettlePayRel emisSettlePayRel); /** * 修改 - * - * @param emisSettlePayRel - * @return + * + * @param emisSettlePayRel + * @return */ public int updateEmisSettlePayRel(EmisSettlePayRel emisSettlePayRel); /** * 删除 - * + * * @param id 主键 * @return 结果 */ @@ -79,7 +88,7 @@ public interface EmisSettlePayRelMapper extends BaseMapper /** * 批量删除 - * + * * @param ids 需要删除的数据主键集合 * @return 结果 */ 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 dca5e7162..d0f3ab5df 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 @@ -106,4 +106,22 @@ public interface IEmisSettleInvoiceRecordService { public List selectCustomExportList( EmisSettleInvoiceRecord emisSettleInvoiceRecord); + /** + * 批量发票延期 + * + * @param ids 发票记录ID数组 + * @return 结果 + * @throws EmisBizError + */ + public int batchDelayInvoice(Long[] ids) throws EmisBizError; + + /** + * 批量取消发票延期 + * + * @param ids 发票记录ID数组 + * @return 结果 + * @throws EmisBizError + */ + public int batchCancelDelayInvoice(Long[] ids) throws EmisBizError; + } 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 899a8b4bf..08f3c8ffd 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 @@ -42,6 +42,10 @@ import com.xdadan.erp.emis.mapper.EmisSettleInvoiceRecordMapper; import com.xdadan.erp.emis.service.IEmisSettleInvoiceRecordService; import org.springframework.transaction.annotation.Transactional; import com.xdadan.erp.emis.mapper.EmisSettlePayRecordMapper; +import com.github.pagehelper.PageHelper; +import org.springframework.beans.factory.annotation.Qualifier; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; /** * 开票记录表Service业务层处理 @@ -83,6 +87,40 @@ public class EmisSettleInvoiceRecordServiceImpl extends EmisBaseService implemen @Autowired private EmisSettlePayBillRelMapper emisSettlePayBillRelMapper; + @Autowired(required = false) + @Qualifier("dataQueryExecutor") + private ThreadPoolExecutor dataQueryExecutor; + + /** + * 获取或创建线程池 + * 如果未注入线程池,则创建默认线程池 + */ + private ThreadPoolExecutor getExecutor() { + if (dataQueryExecutor != null) { + return dataQueryExecutor; + } + // 如果未注入,创建默认线程池 + int processors = Runtime.getRuntime().availableProcessors(); + return new ThreadPoolExecutor( + Math.max(2, processors), // 核心线程数 + processors, // 最大线程数 + 60L, // 空闲线程存活时间 + TimeUnit.SECONDS, // 时间单位 + new LinkedBlockingQueue<>(500), // 工作队列 + new ThreadFactory() { + private final AtomicInteger threadNumber = new AtomicInteger(1); + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r, "invoice-export-query-" + threadNumber.getAndIncrement()); + t.setDaemon(true); + return t; + } + }, + new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略 + ); + } + /** * 查询开票记录表 * @@ -403,23 +441,69 @@ public class EmisSettleInvoiceRecordServiceImpl extends EmisBaseService implemen @Override public List selectCustomExportList( EmisSettleInvoiceRecord emisSettleInvoiceRecord) { - // 查询开票记录列表 - List invoiceRecordList = emisSettleInvoiceRecordMapper - .selectSimpleInvoiceRecordList(emisSettleInvoiceRecord); - + // 分页查询开票记录列表 + List invoiceRecordList = queryInvoiceRecordListByPage(emisSettleInvoiceRecord); if (CollectionUtils.isEmpty(invoiceRecordList)) { return new ArrayList<>(); } - List exportList = new ArrayList<>(); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); + // 收集所有需要批量查询的数据 + Set allSettleBillNoSet = collectSettleBillNos(invoiceRecordList); + Set allPayIdSet = new HashSet<>(); + Set allBillNoSet = new HashSet<>(); - // 第一步:收集所有需要批量查询的数据 - Set allSettleBillNoSet = new HashSet<>(); // 所有账单号 - Set allPayIdSet = new HashSet<>(); // 所有支付ID - Set allBillNoSet = new HashSet<>(); // 所有运单号 + // 查询支付关联记录并建立映射关系 + Map> settleBillNoToPayRelListMap = queryPayRelListAndBuildMapping( + allSettleBillNoSet, allPayIdSet, allBillNoSet, invoiceRecordList); - // 收集所有账单号 + // 并行批量查询账单、收款记录、运单信息 + QueryDataMaps queryDataMaps = parallelQueryRelatedData(allSettleBillNoSet, allPayIdSet, allBillNoSet); + + // 组装导出数据 + return buildExportDataList(invoiceRecordList, settleBillNoToPayRelListMap, queryDataMaps); + } + + /** + * 分页查询开票记录列表,每次查询1000条 + * + * @param emisSettleInvoiceRecord 查询条件 + * @return 开票记录列表 + */ + private List queryInvoiceRecordListByPage( + EmisSettleInvoiceRecord emisSettleInvoiceRecord) { + List invoiceRecordList = new ArrayList<>(); + int pageSize = 1000; + int pageNum = 1; + boolean hasMore = true; + + while (hasMore) { + PageHelper.startPage(pageNum, pageSize); + List pageList = emisSettleInvoiceRecordMapper + .selectSimpleInvoiceRecordList(emisSettleInvoiceRecord); + + if (CollectionUtils.isEmpty(pageList)) { + hasMore = false; + } else { + invoiceRecordList.addAll(pageList); + // 如果查询结果少于pageSize,说明已经是最后一页 + if (pageList.size() < pageSize) { + hasMore = false; + } else { + pageNum++; + } + } + } + return invoiceRecordList; + } + + /** + * 收集所有账单号 + * + * @param invoiceRecordList 开票记录列表 + * @return 账单号集合 + */ + private Set collectSettleBillNos(List invoiceRecordList) { + Set allSettleBillNoSet = new HashSet<>(); for (EmisSettleInvoiceRecord record : invoiceRecordList) { if (StringUtils.isNotBlank(record.getSettleBillNo())) { String[] settleBillNoArr = record.getSettleBillNo().split(","); @@ -430,348 +514,576 @@ public class EmisSettleInvoiceRecordServiceImpl extends EmisBaseService implemen } } } + return allSettleBillNoSet; + } - // 批量查询所有支付关联记录(一次性查询所有settleBillNo对应的支付关联记录) + /** + * 查询支付关联记录并建立映射关系 + * + * @param allSettleBillNoSet 账单号集合 + * @param allPayIdSet 支付ID集合(输出参数) + * @param allBillNoSet 运单号集合(输出参数) + * @param invoiceRecordList 开票记录列表 + * @return 账单号到支付关联记录的映射 + */ + private Map> queryPayRelListAndBuildMapping( + Set allSettleBillNoSet, Set allPayIdSet, Set allBillNoSet, + List invoiceRecordList) { Map> settleBillNoToPayRelListMap = new HashMap<>(); - // 建立 payId -> Set 的映射关系 Map> payIdToSettleBillNoSetMap = new HashMap<>(); - if (!allSettleBillNoSet.isEmpty()) { - // 一次性查询所有支付关联记录(合并所有settleBillNo) - String allSettleBillNoStr = String.join(",", allSettleBillNoSet); - List allPayRelList = emisSettlePayRelMapper - .selectHasPayListBySettleBillNo(allSettleBillNoStr); + if (allSettleBillNoSet.isEmpty()) { + return settleBillNoToPayRelListMap; + } + + ThreadPoolExecutor executor = null; + try { + executor = getExecutor(); + // 分批并行查询所有支付关联记录 + List allPayRelList = batchQueryPayRelList(executor, allSettleBillNoSet); // 收集所有payId和billNo - for (EmisSettlePayRel payRel : allPayRelList) { - if (StringUtils.isNotBlank(payRel.getPayId())) { - allPayIdSet.add(payRel.getPayId()); - } - if (StringUtils.isNotBlank(payRel.getBillNo())) { - allBillNoSet.add(payRel.getBillNo()); - } - } + collectPayIdAndBillNo(allPayRelList, allPayIdSet, allBillNoSet); - // 查询 payId 到 settleBillNo 的映射关系 + // 查询并建立 payId 到 settleBillNo 的映射关系 if (!allPayIdSet.isEmpty() && !allSettleBillNoSet.isEmpty()) { - // 根据allSettleBillNoSet批量查询相关的支付账单关联记录 - List settleBillNoList = new ArrayList<>(allSettleBillNoSet); - List payBillRelList = emisSettlePayBillRelMapper - .selectEmisSettlePayBillRelListBySettleBillNos(settleBillNoList); - - // 建立 payId -> Set 的映射(只处理相关的payId和settleBillNo) - for (EmisSettlePayBillRel payBillRel : payBillRelList) { - if (StringUtils.isNotBlank(payBillRel.getPayId()) - && StringUtils.isNotBlank(payBillRel.getSettleBillNo()) - && allPayIdSet.contains(payBillRel.getPayId()) - && allSettleBillNoSet.contains(payBillRel.getSettleBillNo())) { - payIdToSettleBillNoSetMap.computeIfAbsent(payBillRel.getPayId(), k -> new HashSet<>()) - .add(payBillRel.getSettleBillNo()); - } - } + queryPayBillRelMapping(executor, allSettleBillNoSet, allPayIdSet, payIdToSettleBillNoSetMap); } // 根据每个记录的settleBillNo过滤对应的payRelList - for (EmisSettleInvoiceRecord record : invoiceRecordList) { - if (StringUtils.isNotBlank(record.getSettleBillNo())) { - // 解析该记录的settleBillNo(可能是逗号分隔的多个) - Set recordSettleBillNoSet = new HashSet<>(); - String[] settleBillNoArr = record.getSettleBillNo().split(","); - for (String settleBillNo : settleBillNoArr) { - if (StringUtils.isNotBlank(settleBillNo)) { - recordSettleBillNoSet.add(settleBillNo.trim()); + buildSettleBillNoToPayRelMap(invoiceRecordList, allPayRelList, payIdToSettleBillNoSetMap, + settleBillNoToPayRelListMap); + } finally { + // 关闭线程池 + if (executor != null && executor != dataQueryExecutor) { + executor.shutdown(); + } + } + + return settleBillNoToPayRelListMap; + } + + /** + * 分批并行查询支付关联记录 + */ + private List batchQueryPayRelList(ThreadPoolExecutor executor, Set allSettleBillNoSet) { + List allPayRelList = Collections.synchronizedList(new ArrayList<>()); + List settleBillNoList = new ArrayList<>(allSettleBillNoSet); + int batchSize = 1000; + List> futures = new ArrayList<>(); + + for (int i = 0; i < settleBillNoList.size(); i += batchSize) { + final int start = i; + final int end = Math.min(i + batchSize, settleBillNoList.size()); + Future future = executor.submit(() -> { + List batch = settleBillNoList.subList(start, end); + List batchPayRelList = emisSettlePayRelMapper + .selectHasPayListBySettleBillNoList(batch); + if (CollectionUtils.isNotEmpty(batchPayRelList)) { + allPayRelList.addAll(batchPayRelList); + } + }); + futures.add(future); + } + + // 等待所有任务完成 + waitForFutures(futures, "查询支付关联记录异常"); + return allPayRelList; + } + + /** + * 收集payId和billNo + */ + private void collectPayIdAndBillNo(List allPayRelList, Set allPayIdSet, + Set allBillNoSet) { + for (EmisSettlePayRel payRel : allPayRelList) { + if (StringUtils.isNotBlank(payRel.getPayId())) { + allPayIdSet.add(payRel.getPayId()); + } + if (StringUtils.isNotBlank(payRel.getBillNo())) { + allBillNoSet.add(payRel.getBillNo()); + } + } + } + + /** + * 查询支付账单关联映射 + */ + private void queryPayBillRelMapping(ThreadPoolExecutor executor, Set allSettleBillNoSet, + Set allPayIdSet, Map> payIdToSettleBillNoSetMap) { + List payBillRelList = Collections.synchronizedList(new ArrayList<>()); + List payBillRelSettleBillNoList = new ArrayList<>(allSettleBillNoSet); + int payBillRelBatchSize = 1000; + List> payBillRelFutures = new ArrayList<>(); + + for (int i = 0; i < payBillRelSettleBillNoList.size(); i += payBillRelBatchSize) { + final int start = i; + final int end = Math.min(i + payBillRelBatchSize, payBillRelSettleBillNoList.size()); + Future future = executor.submit(() -> { + List batch = payBillRelSettleBillNoList.subList(start, end); + List batchPayBillRelList = emisSettlePayBillRelMapper + .selectEmisSettlePayBillRelListBySettleBillNos(batch); + if (CollectionUtils.isNotEmpty(batchPayBillRelList)) { + payBillRelList.addAll(batchPayBillRelList); + } + }); + payBillRelFutures.add(future); + } + + waitForFutures(payBillRelFutures, "查询支付账单关联记录异常"); + + // 建立 payId -> Set 的映射 + for (EmisSettlePayBillRel payBillRel : payBillRelList) { + if (StringUtils.isNotBlank(payBillRel.getPayId()) + && StringUtils.isNotBlank(payBillRel.getSettleBillNo()) + && allPayIdSet.contains(payBillRel.getPayId()) + && allSettleBillNoSet.contains(payBillRel.getSettleBillNo())) { + payIdToSettleBillNoSetMap.computeIfAbsent(payBillRel.getPayId(), k -> new HashSet<>()) + .add(payBillRel.getSettleBillNo()); + } + } + } + + /** + * 建立账单号到支付关联记录的映射 + */ + private void buildSettleBillNoToPayRelMap(List invoiceRecordList, + List allPayRelList, Map> payIdToSettleBillNoSetMap, + Map> settleBillNoToPayRelListMap) { + for (EmisSettleInvoiceRecord record : invoiceRecordList) { + if (StringUtils.isNotBlank(record.getSettleBillNo())) { + Set recordSettleBillNoSet = parseSettleBillNos(record.getSettleBillNo()); + List recordPayRelList = filterPayRelListBySettleBillNo( + allPayRelList, recordSettleBillNoSet, payIdToSettleBillNoSetMap); + settleBillNoToPayRelListMap.put(record.getSettleBillNo(), recordPayRelList); + } + } + } + + /** + * 解析账单号字符串为集合 + */ + private Set parseSettleBillNos(String settleBillNoStr) { + Set recordSettleBillNoSet = new HashSet<>(); + String[] settleBillNoArr = settleBillNoStr.split(","); + for (String settleBillNo : settleBillNoArr) { + if (StringUtils.isNotBlank(settleBillNo)) { + recordSettleBillNoSet.add(settleBillNo.trim()); + } + } + return recordSettleBillNoSet; + } + + /** + * 根据账单号过滤支付关联记录 + */ + private List filterPayRelListBySettleBillNo(List allPayRelList, + Set recordSettleBillNoSet, Map> payIdToSettleBillNoSetMap) { + List recordPayRelList = new ArrayList<>(); + for (EmisSettlePayRel payRel : allPayRelList) { + if (StringUtils.isNotBlank(payRel.getPayId())) { + Set payRelSettleBillNoSet = payIdToSettleBillNoSetMap.get(payRel.getPayId()); + if (payRelSettleBillNoSet != null) { + for (String settleBillNo : recordSettleBillNoSet) { + if (payRelSettleBillNoSet.contains(settleBillNo)) { + recordPayRelList.add(payRel); + break; } } + } + } + } + return recordPayRelList; + } - // 过滤出属于该记录的payRelList - List recordPayRelList = new ArrayList<>(); - for (EmisSettlePayRel payRel : allPayRelList) { - if (StringUtils.isNotBlank(payRel.getPayId())) { - Set payRelSettleBillNoSet = payIdToSettleBillNoSetMap.get(payRel.getPayId()); - if (payRelSettleBillNoSet != null) { - // 判断该payRel的payId关联的settleBillNo是否包含在当前记录的settleBillNo中 - boolean belongsToRecord = false; - for (String settleBillNo : recordSettleBillNoSet) { - if (payRelSettleBillNoSet.contains(settleBillNo)) { - belongsToRecord = true; - break; + /** + * 并行批量查询相关数据(账单、收款记录、运单信息) + */ + private QueryDataMaps parallelQueryRelatedData(Set allSettleBillNoSet, Set allPayIdSet, + Set allBillNoSet) { + QueryDataMaps queryDataMaps = new QueryDataMaps(); + ThreadPoolExecutor executor = null; + try { + executor = getExecutor(); + List> futures = new ArrayList<>(); + + // 并行查询账单 + if (!allSettleBillNoSet.isEmpty()) { + submitBatchQueryTasks(executor, futures, new ArrayList<>(allSettleBillNoSet), 1000, + (batch) -> { + List batchSettleBillList = emisSettleBillMapper + .selectSimpleBillsByNos(batch); + if (CollectionUtils.isNotEmpty(batchSettleBillList)) { + for (EmisSettleBill settleBill : batchSettleBillList) { + if (StringUtils.isNotBlank(settleBill.getSettleBillNo())) { + queryDataMaps.settleBillMap.put(settleBill.getSettleBillNo(), settleBill); } } - if (belongsToRecord) { - recordPayRelList.add(payRel); + } + }); + } + + // 并行查询收款记录 + if (!allPayIdSet.isEmpty()) { + submitBatchQueryTasks(executor, futures, new ArrayList<>(allPayIdSet), 1000, + (batch) -> { + List batchPayRecordList = emisSettlePayRecordMapper + .selectEmisSettlePayRecordListByPayIds(batch); + if (CollectionUtils.isNotEmpty(batchPayRecordList)) { + for (EmisSettlePayRecord payRecord : batchPayRecordList) { + if (StringUtils.isNotBlank(payRecord.getPayId())) { + queryDataMaps.payRecordMap.putIfAbsent(payRecord.getPayId(), payRecord); + } } } - } - } - settleBillNoToPayRelListMap.put(record.getSettleBillNo(), recordPayRelList); - } + }); + } + + // 并行查询运单信息 + if (!allBillNoSet.isEmpty()) { + submitBatchQueryTasks(executor, futures, new ArrayList<>(allBillNoSet), 1000, + (batch) -> { + List batchWaybillList = emisWaybillMapper.selectWaybillsByBillCodes(batch); + if (CollectionUtils.isNotEmpty(batchWaybillList)) { + for (EmisWaybill waybill : batchWaybillList) { + if (StringUtils.isNotBlank(waybill.getBillCode())) { + queryDataMaps.waybillMap.put(waybill.getBillCode(), waybill); + } + } + } + }); + } + + waitForFutures(futures, "并行查询数据异常"); + } finally { + // 关闭线程池 + if (executor != null && executor != dataQueryExecutor) { + executor.shutdown(); } } - // 第二步:批量查询所有数据 - // 批量查询账单 - Map settleBillMap = new HashMap<>(); - if (!allSettleBillNoSet.isEmpty()) { - List settleBillNoList = new ArrayList<>(allSettleBillNoSet); - List settleBillList = emisSettleBillMapper - .selectSimpleBillsByNos(settleBillNoList); - for (EmisSettleBill settleBill : settleBillList) { - if (StringUtils.isNotBlank(settleBill.getSettleBillNo())) { - settleBillMap.put(settleBill.getSettleBillNo(), settleBill); - } + return queryDataMaps; + } + + /** + * 提交批量查询任务 + */ + private void submitBatchQueryTasks(ThreadPoolExecutor executor, List> futures, + List dataList, int batchSize, java.util.function.Consumer> task) { + for (int i = 0; i < dataList.size(); i += batchSize) { + final int start = i; + final int end = Math.min(i + batchSize, dataList.size()); + Future future = executor.submit(() -> { + List batch = dataList.subList(start, end); + task.accept(batch); + }); + futures.add(future); + } + } + + /** + * 等待所有Future完成 + */ + private void waitForFutures(List> futures, String errorMsg) { + for (Future future : futures) { + try { + future.get(); + } catch (Exception e) { + log.error(errorMsg, e); } } + } - // 批量查询收款记录 - Map payRecordMap = new HashMap<>(); - if (!allPayIdSet.isEmpty()) { - List payIdList = new ArrayList<>(allPayIdSet); - List payRecordList = emisSettlePayRecordMapper - .selectEmisSettlePayRecordListByPayIds(payIdList); - for (EmisSettlePayRecord payRecord : payRecordList) { - if (StringUtils.isNotBlank(payRecord.getPayId())) { - // 如果同一个payId有多条记录,取第一条(已按create_time desc排序) - payRecordMap.putIfAbsent(payRecord.getPayId(), payRecord); - } - } - } + /** + * 组装导出数据列表 + */ + private List buildExportDataList( + List invoiceRecordList, + Map> settleBillNoToPayRelListMap, + QueryDataMaps queryDataMaps) { + List exportList = new ArrayList<>(); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); - // 批量查询运单信息 - Map waybillMap = new HashMap<>(); - if (!allBillNoSet.isEmpty()) { - List billNoList = new ArrayList<>(allBillNoSet); - List waybillList = emisWaybillMapper.selectWaybillsByBillCodes(billNoList); - for (EmisWaybill waybill : waybillList) { - if (StringUtils.isNotBlank(waybill.getBillCode())) { - waybillMap.put(waybill.getBillCode(), waybill); - } - } - } - - // 第三步:处理每个开票记录,组装导出数据 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 = settleBillMap.get(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())) { - // 从缓存中获取该记录对应的支付关联记录 - List payRelList = settleBillNoToPayRelListMap.get(record.getSettleBillNo()); - if (CollectionUtils.isEmpty(payRelList)) { - // 如果缓存中没有,则查询(这种情况应该不会发生,但为了安全保留) - payRelList = emisSettlePayRelMapper.selectHasPayListBySettleBillNo(record.getSettleBillNo()); - } - - if (!CollectionUtils.isEmpty(payRelList)) { - // 遍历支付关联记录,按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 = waybillMap.get(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公司) - // 按日期从小到大排序 - List sortedPaymentGroups = new ArrayList<>(paymentGroupMap.values()); - sortedPaymentGroups.sort((g1, g2) -> { - if (g1.date == null && g2.date == null) { - return 0; - } - if (g1.date == null) { - return -1; - } - if (g2.date == null) { - return 1; - } - return g1.date.compareTo(g2.date); - }); - for (PaymentGroup group : sortedPaymentGroups) { - 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公司) - // 按日期从小到大排序 - List sortedRegisterGroups = new ArrayList<>(registerGroupMap.values()); - sortedRegisterGroups.sort((g1, g2) -> { - if (g1.date == null && g2.date == null) { - return 0; - } - if (g1.date == null) { - return -1; - } - if (g2.date == null) { - return 1; - } - return g1.date.compareTo(g2.date); - }); - for (PaymentGroup group : sortedRegisterGroups) { - 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)); - } - + EmisSettleInvoiceRecordExportVO exportVO = buildExportVO(record, settleBillNoToPayRelListMap, + queryDataMaps, dateFormat); exportList.add(exportVO); } return exportList; } + /** + * 构建单个导出VO对象 + */ + private EmisSettleInvoiceRecordExportVO buildExportVO(EmisSettleInvoiceRecord record, + Map> settleBillNoToPayRelListMap, + QueryDataMaps queryDataMaps, SimpleDateFormat dateFormat) { + EmisSettleInvoiceRecordExportVO exportVO = new EmisSettleInvoiceRecordExportVO(); + + // 设置基础字段 + setBasicFields(exportVO, record); + + // 处理账单类型 + Set settleTypeSet = processBillTypes(exportVO, record, queryDataMaps.settleBillMap); + + // 处理支付关联记录和分组 + List customerNameList = new ArrayList<>(); + List paymentDateList = new ArrayList<>(); + List registerDateList = new ArrayList<>(); + + processPaymentGroups(record, settleBillNoToPayRelListMap, queryDataMaps, dateFormat, + customerNameList, paymentDateList, registerDateList); + + // 设置分组后的数据 + setGroupedFields(exportVO, customerNameList, paymentDateList, registerDateList, settleTypeSet); + + return exportVO; + } + + /** + * 设置基础字段 + */ + private void setBasicFields(EmisSettleInvoiceRecordExportVO exportVO, EmisSettleInvoiceRecord record) { + 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()); + exportVO.setInvoiceStatusDesc(getInvoiceStatusDesc(record.getInvoiceStatus())); + exportVO.setRecedMoney(record.getRecedMoney()); + exportVO.setPaymentStatusDesc(getPaymentStatusDesc(record.getPaymentStatus())); + } + + /** + * 获取开票状态描述 + */ + private String getInvoiceStatusDesc(String invoiceStatus) { + if ("0".equals(invoiceStatus)) { + return "未开票"; + } else if ("1".equals(invoiceStatus)) { + return "开票中"; + } else if ("2".equals(invoiceStatus)) { + return "已开票"; + } else if ("3".equals(invoiceStatus)) { + return "开票异常"; + } + return ""; + } + + /** + * 获取收款状态描述 + */ + private String getPaymentStatusDesc(String paymentStatus) { + if ("0".equals(paymentStatus)) { + return "未收款"; + } else if ("1".equals(paymentStatus)) { + return "已收款"; + } else if ("2".equals(paymentStatus)) { + return "部分收款"; + } + return ""; + } + + /** + * 处理账单类型 + */ + private Set processBillTypes(EmisSettleInvoiceRecordExportVO exportVO, + EmisSettleInvoiceRecord record, Map settleBillMap) { + Set settleTypeSet = new HashSet<>(); + 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 = settleBillMap.get(settleBillNo.trim()); + if (settleBill != null && StringUtils.isNotBlank(settleBill.getSettleType())) { + if ("1".equals(settleBill.getSettleType())) { + settleTypeSet.add("现金账单"); + } else if ("2".equals(settleBill.getSettleType())) { + settleTypeSet.add("月结账单"); + } + } + } + } + } + return settleTypeSet; + } + + /** + * 处理支付分组 + */ + private void processPaymentGroups(EmisSettleInvoiceRecord record, + Map> settleBillNoToPayRelListMap, + QueryDataMaps queryDataMaps, SimpleDateFormat dateFormat, + List customerNameList, List paymentDateList, List registerDateList) { + if (StringUtils.isBlank(record.getSettleBillNo())) { + return; + } + + List payRelList = settleBillNoToPayRelListMap.get(record.getSettleBillNo()); + if (CollectionUtils.isEmpty(payRelList)) { + payRelList = emisSettlePayRelMapper.selectHasPayListBySettleBillNoList( + Collections.singletonList(record.getSettleBillNo())); + } + + if (CollectionUtils.isEmpty(payRelList)) { + return; + } + + Map paymentGroupMap = new HashMap<>(); + Map registerGroupMap = new HashMap<>(); + + for (EmisSettlePayRel payRel : payRelList) { + if (payRel.getPayMoney() == null || payRel.getPayMoney().compareTo(BigDecimal.ZERO) <= 0) { + continue; + } + + String billNo = payRel.getBillNo(); + if (StringUtils.isBlank(billNo)) { + continue; + } + + // 获取客户名称 + String custName = getCustomerName(billNo, queryDataMaps.waybillMap, customerNameList); + + // 获取收款记录 + EmisSettlePayRecord payRecord = queryDataMaps.payRecordMap.get(payRel.getPayId()); + if (payRecord == null) { + continue; + } + + // 处理付款日期分组 + processPaymentDateGroup(payRecord.getTradeDate(), custName, payRel.getPayMoney(), + paymentGroupMap, dateFormat); + + // 处理登记日期分组 + processRegisterDateGroup(payRecord.getCreateTime(), custName, payRel.getPayMoney(), + registerGroupMap, dateFormat); + } + + // 格式化并排序 + formatPaymentGroups(paymentGroupMap, paymentDateList, dateFormat, "付款"); + formatPaymentGroups(registerGroupMap, registerDateList, dateFormat, "登记"); + } + + /** + * 获取客户名称 + */ + private String getCustomerName(String billNo, Map waybillMap, + List customerNameList) { + EmisWaybill waybill = waybillMap.get(billNo); + String custName = ""; + if (waybill != null && StringUtils.isNotBlank(waybill.getCustName())) { + custName = waybill.getCustName(); + if (!customerNameList.contains(custName)) { + customerNameList.add(custName); + } + } + return custName; + } + + /** + * 处理付款日期分组 + */ + private void processPaymentDateGroup(Date tradeDate, String custName, BigDecimal payMoney, + Map paymentGroupMap, SimpleDateFormat dateFormat) { + if (tradeDate != null) { + String tradeDateStr = dateFormat.format(tradeDate); + String paymentKey = (StringUtils.isNotBlank(custName) ? custName : "") + "_" + tradeDateStr; + PaymentGroup paymentGroup = paymentGroupMap.computeIfAbsent(paymentKey, k -> { + PaymentGroup group = new PaymentGroup(); + group.custName = custName != null ? custName : ""; + group.date = tradeDate; + group.dateStr = tradeDateStr; + group.totalMoney = BigDecimal.ZERO; + return group; + }); + paymentGroup.totalMoney = paymentGroup.totalMoney.add(payMoney); + } + } + + /** + * 处理登记日期分组 + */ + private void processRegisterDateGroup(Date createTime, String custName, BigDecimal payMoney, + Map registerGroupMap, SimpleDateFormat dateFormat) { + if (createTime != null) { + String createTimeStr = dateFormat.format(createTime); + String registerKey = (StringUtils.isNotBlank(custName) ? custName : "") + "_" + createTimeStr; + PaymentGroup registerGroup = registerGroupMap.computeIfAbsent(registerKey, k -> { + PaymentGroup group = new PaymentGroup(); + group.custName = custName != null ? custName : ""; + group.date = createTime; + group.dateStr = createTimeStr; + group.totalMoney = BigDecimal.ZERO; + return group; + }); + registerGroup.totalMoney = registerGroup.totalMoney.add(payMoney); + } + } + + /** + * 格式化支付分组 + */ + private void formatPaymentGroups(Map groupMap, List dateList, + SimpleDateFormat dateFormat, String type) { + List sortedGroups = new ArrayList<>(groupMap.values()); + sortedGroups.sort((g1, g2) -> { + if (g1.date == null && g2.date == null) { + return 0; + } + if (g1.date == null) { + return -1; + } + if (g2.date == null) { + return 1; + } + return g1.date.compareTo(g2.date); + }); + + for (PaymentGroup group : sortedGroups) { + BigDecimal strippedMoney = group.totalMoney.stripTrailingZeros(); + String dateStr = group.dateStr + " " + type + strippedMoney.toPlainString() + "元"; + if (StringUtils.isNotBlank(group.custName)) { + dateStr += " " + group.custName; + } + dateList.add(dateStr); + } + } + + /** + * 设置分组后的字段 + */ + private void setGroupedFields(EmisSettleInvoiceRecordExportVO exportVO, List customerNameList, + List paymentDateList, List registerDateList, Set settleTypeSet) { + 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)); + } + } + + /** + * 查询数据映射内部类 + */ + private static class QueryDataMaps { + Map settleBillMap = new ConcurrentHashMap<>(); + Map payRecordMap = new ConcurrentHashMap<>(); + Map waybillMap = new ConcurrentHashMap<>(); + } + /** * 付款分组内部类 */ @@ -782,4 +1094,67 @@ public class EmisSettleInvoiceRecordServiceImpl extends EmisBaseService implemen BigDecimal totalMoney; } + /** + * 批量发票延期 + * + * @param ids 发票记录ID数组 + * @return 结果 + * @throws EmisBizError + */ + @Override + @Transactional + public int batchDelayInvoice(Long[] ids) throws EmisBizError { + if (ids == null || ids.length == 0) { + throw new EmisBizError(EmisBizErrorType.FAIL, "请选择要延期的发票记录"); + } + + // 验证所有记录是否都是未开票状态 + for (Long id : ids) { + EmisSettleInvoiceRecord record = emisSettleInvoiceRecordMapper.selectEmisSettleInvoiceRecordById(id); + if (record == null) { + throw new EmisBizError(EmisBizErrorType.FAIL, "发票记录不存在,ID: " + id); + } + if (!"0".equals(record.getInvoiceStatus())) { + throw new EmisBizError(EmisBizErrorType.FAIL, + "只能对未开票状态的发票进行延期操作,申请序号: " + record.getApplySeqNo()); + } + } + + // 获取当前操作人 + String delayOpManCode = getCurrentUser().getEmpCode(); + + // 执行批量延期 + return emisSettleInvoiceRecordMapper.batchDelayInvoice(ids, delayOpManCode); + } + + /** + * 批量取消发票延期 + * + * @param ids 发票记录ID数组 + * @return 结果 + * @throws EmisBizError + */ + @Override + @Transactional + public int batchCancelDelayInvoice(Long[] ids) throws EmisBizError { + if (ids == null || ids.length == 0) { + throw new EmisBizError(EmisBizErrorType.FAIL, "请选择要取消延期的发票记录"); + } + + // 验证所有记录是否都是已延期状态 + for (Long id : ids) { + EmisSettleInvoiceRecord record = emisSettleInvoiceRecordMapper.selectEmisSettleInvoiceRecordById(id); + if (record == null) { + throw new EmisBizError(EmisBizErrorType.FAIL, "发票记录不存在,ID: " + id); + } + if (!"1".equals(record.getBlDelay())) { + throw new EmisBizError(EmisBizErrorType.FAIL, + "只能对已延期的发票进行取消延期操作,申请序号: " + record.getApplySeqNo()); + } + } + + // 执行批量取消延期 + return emisSettleInvoiceRecordMapper.batchCancelDelayInvoice(ids); + } + } diff --git a/emis-biz/src/main/resources/mapper/EmisSettleInvoiceRecordMapper.xml b/emis-biz/src/main/resources/mapper/EmisSettleInvoiceRecordMapper.xml index 633392810..e3bf1bacc 100644 --- a/emis-biz/src/main/resources/mapper/EmisSettleInvoiceRecordMapper.xml +++ b/emis-biz/src/main/resources/mapper/EmisSettleInvoiceRecordMapper.xml @@ -52,6 +52,10 @@ + + + + @@ -62,6 +66,7 @@ + @@ -88,12 +93,12 @@ - select id, apply_seq_no, apply_date, apply_man_code, apply_site_code, customer_code, customer_name, settle_bill_no, settle_bill_name, apply_money, invoice_type, openbill_scope, company_name, company_tax_no, company_tel, company_address, invioce_remark, bank_name, bank_acc_no, contact, phone, real_tax_type, orig_open_money, add_tax_rate, add_open_money, open_money_max, open_money, invoice_no, reced_money, payment_status, invoice_status, invoice_status_desc, recieve_address, email, file_path, remark, bl_audit, audit_date, audit_man_code, audit_site_code, audit_note, op_man_code, op_date, op_site_code, open_ch_id, open_ch_status, open_ch_status_desc, open_com_code, del_flag, create_by, create_time, update_by, update_time, create_site, update_site from emis_settle_invoice_record + select id, apply_seq_no, apply_date, apply_man_code, apply_site_code, customer_code, customer_name, settle_bill_no, settle_bill_name, apply_money, invoice_type, openbill_scope, company_name, company_tax_no, company_tel, company_address, invioce_remark, bank_name, bank_acc_no, contact, phone, real_tax_type, orig_open_money, add_tax_rate, add_open_money, open_money_max, open_money, invoice_no, reced_money, payment_status, invoice_status, invoice_status_desc, recieve_address, email, file_path, remark, bl_audit, audit_date, audit_man_code, audit_site_code, audit_note, op_man_code, op_date, op_site_code, open_ch_id, open_ch_status, open_ch_status_desc, open_com_code, bl_delay, delay_op_man_code, delay_op_date, del_flag, create_by, create_time, update_by, update_time, create_site, update_site from emis_settle_invoice_record @@ -512,6 +524,9 @@ open_ch_status, open_ch_status_desc, open_com_code, + bl_delay, + delay_op_man_code, + delay_op_date, del_flag, create_by, create_time, @@ -568,6 +583,9 @@ #{openChStatus}, #{openChStatusDesc}, #{openComCode}, + #{blDelay}, + #{delayOpManCode}, + #{delayOpDate}, #{delFlag}, #{createBy}, #{createTime}, @@ -637,6 +655,9 @@ open_ch_status = #{openChStatus}, open_ch_status_desc = #{openChStatusDesc}, open_com_code = #{openComCode}, + bl_delay = #{blDelay}, + delay_op_man_code = #{delayOpManCode}, + delay_op_date = #{delayOpDate}, del_flag = #{delFlag}, create_by = #{createBy}, create_time = #{createTime}, @@ -686,4 +707,31 @@ #{id} + + + + update emis_settle_invoice_record + set bl_delay = '1', + delay_op_man_code = #{delayOpManCode}, + delay_op_date = now() + where id in + + #{id} + + and invoice_status = '0' + and (bl_delay is null or bl_delay = '0') + + + + + update emis_settle_invoice_record + set bl_delay = '0', + delay_op_man_code = null, + delay_op_date = null + where id in + + #{id} + + and bl_delay = '1' + diff --git a/emis-biz/src/main/resources/mapper/EmisSettlePayRelMapper.xml b/emis-biz/src/main/resources/mapper/EmisSettlePayRelMapper.xml index 675fd9e78..f775c8e74 100644 --- a/emis-biz/src/main/resources/mapper/EmisSettlePayRelMapper.xml +++ b/emis-biz/src/main/resources/mapper/EmisSettlePayRelMapper.xml @@ -79,6 +79,26 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ) + +