shiyunteng
2026-08-26 b967d23ae6c1f7761feb3c5328e3b591df6a735d
feat:进行中合同导入
9个文件已修改
4个文件已添加
429 ■■■■■ 已修改文件
platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/dto/ContracQueryDTO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/entity/Contract.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/vo/ContractDetailVo.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/vo/ContractExceVO.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/vo/ContractPaymentScheduleExceVO.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/vo/ContractSubjectMatterExceVO.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/controller/ContractController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/ContractService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/impl/ContractPaymentScheduleProcessServiceImpl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/impl/ContractServiceImpl.java 236 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/impl/OutBoundServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/utils/BatchInsertListener.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
platformx-business-finance-biz/src/main/resources/mapper/ContractMapper.xml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/dto/ContracQueryDTO.java
@@ -10,6 +10,8 @@
@Data
public class ContracQueryDTO extends HomeQueryDTO{
    private String contractNo;
    @Schema(description = "合同名称")
    private String contractName;
platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/entity/Contract.java
@@ -176,7 +176,7 @@
    private String salesModel;
    @Schema(description = "已付款金额")
    @Column(columnDefinition = "decimal(20,2) comment '已付款金额'")
    @Column(columnDefinition = "decimal(20,2) default '0.00' comment '已付款金额'")
    private BigDecimal paidAmount;
    @Schema(description = "合同分类")
platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/vo/ContractDetailVo.java
@@ -249,6 +249,8 @@
    @Schema(description = "开票类型")
    private String invoiceType;
    private BigDecimal paidAmount;
    private List<ContractPaymentSchedule> contractPaymentSchedule;
    private List<ContractSubjectMatter> contractSubjectMatter;
platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/vo/ContractExceVO.java
New file
@@ -0,0 +1,45 @@
package com.by4cloud.platformx.business.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
@Data
public class ContractExceVO {
    @ExcelProperty("合同名称")
    private String contractName;
    @ExcelProperty("合同编号*")
    private String contractNo;
    @ExcelProperty("合同服务属性*")
    private String contractAttribute;
    @ExcelProperty("经济事项*")
    private String economicMatters;
    @ExcelProperty("供应属性*")
    private String supplyAttribute;
    @ExcelProperty("客户编码(erpcode)*")
    private String bcErpCode;
    @ExcelProperty("签署日期*")
    private String signDate;
    @ExcelProperty("到期日期*")
    private String expirationDate;
    @ExcelProperty("所属行业*")
    private String industryCode;
    @ExcelProperty("合同金额*")
    private String amount;
    @ExcelProperty("已收款金额*")
    private String paidAmount;
    @ExcelProperty("已开票金额*")
    private String billingAmout;
}
platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/vo/ContractPaymentScheduleExceVO.java
New file
@@ -0,0 +1,23 @@
package com.by4cloud.platformx.business.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class ContractPaymentScheduleExceVO {
    @ExcelProperty("合同编号*")
    private String contractNo;
    @ExcelProperty("阶段名称*")
    private String stageName;
    @ExcelProperty("约定天数*")
    private String agreedDays;
    @ExcelProperty("付款比例*")
    private String paymentRatio;
}
platformx-business-finance-api/src/main/java/com/by4cloud/platformx/business/vo/ContractSubjectMatterExceVO.java
New file
@@ -0,0 +1,36 @@
package com.by4cloud.platformx.business.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
@Data
public class ContractSubjectMatterExceVO {
    @ExcelProperty("合同编号*")
    private String contractNo;
    @ExcelProperty("标的物名称")
    private String materialName;
    @ExcelProperty("产品编码(erpcode)*")
    private String materialCode;
    @ExcelProperty("产品名称(erpname)")
    private String materialInternalName;
    @ExcelProperty("客户编码(erpcode)*")
    private String bcErpCode;
    @ExcelProperty("规格型号")
    private String specification;
    @ExcelProperty("单价*")
    private String unitPrice;
    @ExcelProperty("数量*")
    private String quantity;
    @ExcelProperty("出库数量*")
    private String deliveredQuantity;
}
platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/controller/ContractController.java
@@ -25,6 +25,7 @@
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.math.BigDecimal;
import java.util.List;
@@ -361,4 +362,12 @@
    public R fourAssociation(@ParameterObject Page page,@ParameterObject ContractQueryDTO queryDTO) {
        return R.ok(contractService.fourAssociation(page,queryDTO));
    }
    @PostMapping("/importContractMultiSheet")
    public R importContractMultiSheet(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return R.failed("文件不能为空");
        }
        return contractService.importContractMultiSheet(file);
    }
}
platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/ContractService.java
@@ -8,6 +8,7 @@
import com.by4cloud.platformx.common.core.util.R;
import com.by4cloud.platformx.common.data.mybatis.IIService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.multipart.MultipartFile;
/**
 * @author 28254
@@ -68,4 +69,6 @@
    R addSimple(ContractAddDTO addDTO);
    R pushCenter(Long id);
    R importContractMultiSheet(MultipartFile file);
}
platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/impl/ContractPaymentScheduleProcessServiceImpl.java
@@ -138,7 +138,8 @@
                                PaymentConfirm contractLastConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId,completeContract.getId())
                                        .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1"));
                                //查询客户付款完成合同中最后明细金额 有预收转入当前合同
                                if (contractLastConfirm.getTotalAmount().compareTo(new BigDecimal("0"))>0){
                                if (contractLastConfirm.getTotalAmount().compareTo(new BigDecimal("0"))>0&&
                                contract.getContractNo().startsWith("ZB-")){
                                    //新增完成付款合同 资金转出
                                    PaymentConfirm outConfirm = BeanUtil.copyProperties(contractLastConfirm,PaymentConfirm.class,"id","transationAmount",
                                            "advanceAmount","receivableAmount","overdueAmount","totalAmount");
@@ -167,13 +168,16 @@
                                    }else if (inConfirm.getTotalAmount().compareTo(new BigDecimal("0"))<0){
                                        inConfirm.setReceivableAmount(inConfirm.getTotalAmount().multiply(new BigDecimal("-1")));
                                    }
                                    if (contract.getContractNo().startsWith("ZB-")) {
                                    paymentConfirmMapper.insert(inConfirm);
                                }
                            }
                        }
                    }
                    }
                    currentConfim.setTotalAmount(lastTotal.subtract(currentConfim.getReceivableAmount()));
                    if (schedule.getPaymentRatio().compareTo(new BigDecimal("0")) > 0) {
                    if (schedule.getPaymentRatio().compareTo(new BigDecimal("0")) > 0&&
                            contract.getContractNo().startsWith("ZB-")) {
                        paymentConfirmMapper.insert(currentConfim);
                        //更新当前阶段付款情况
                        if (lastTotal.compareTo(new BigDecimal("0"))>0){
@@ -222,7 +226,7 @@
                                lastNewTotal = lastNewConfirm.getTotalAmount();
                            }
                            newConfim.setTotalAmount(lastNewTotal.subtract(newConfim.getReceivableAmount()));
                            if (endSchedule.getPaymentRatio().compareTo(new BigDecimal("0")) > 0) {
                            if (endSchedule.getPaymentRatio().compareTo(new BigDecimal("0")) > 0&&contract.getContractNo().startsWith("ZB-")){
                                paymentConfirmMapper.insert(newConfim);
                            }
@@ -276,7 +280,7 @@
                lastTotal = lastConfirm.getTotalAmount();
            }
            currentConfim.setTotalAmount(lastTotal.subtract(currentConfim.getReceivableAmount()));
            if (schedule.getPaymentRatio().compareTo(new BigDecimal("0")) > 0) {
            if (schedule.getPaymentRatio().compareTo(new BigDecimal("0")) > 0&&contract.getContractNo().startsWith("ZB-")){
                paymentConfirmMapper.insert(currentConfim);
                //更新当前阶段付款情况
                if (lastTotal.compareTo(new BigDecimal("0"))>0){
@@ -388,7 +392,7 @@
                lastNewTotal = lastNewConfirm.getTotalAmount();
            }
            newConfim.setTotalAmount(lastNewTotal.subtract(newConfim.getReceivableAmount()));
            if (schedule.getPaymentRatio().compareTo(new BigDecimal("0")) > 0) {
            if (schedule.getPaymentRatio().compareTo(new BigDecimal("0")) > 0&&contract.getContractNo().startsWith("ZB-")) {
                paymentConfirmMapper.insert(newConfim);
                //更新当前阶段付款情况
                if (lastNewTotal.compareTo(new BigDecimal("0"))>0){
platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/impl/ContractServiceImpl.java
@@ -11,25 +11,28 @@
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.by4cloud.platformx.admin.api.entity.SysDept;
import com.by4cloud.platformx.admin.api.entity.SysDictItem;
import com.by4cloud.platformx.admin.api.feign.RemoteDeptService;
import com.by4cloud.platformx.admin.api.feign.RemoteDictService;
import com.by4cloud.platformx.business.api.feign.RemoteFlowProcessService;
import com.by4cloud.platformx.business.constant.FlowNameEnum;
import com.by4cloud.platformx.business.dto.*;
import com.by4cloud.platformx.business.entity.*;
import com.by4cloud.platformx.business.mapper.*;
import com.by4cloud.platformx.business.service.ContractService;
import com.by4cloud.platformx.business.utils.BatchInsertListener;
import com.by4cloud.platformx.business.utils.ItemGeneratorUtil;
import com.by4cloud.platformx.business.utils.NetworkFileToBase64;
import com.by4cloud.platformx.business.vo.ContractDetailVo;
import com.by4cloud.platformx.business.vo.ContractInvoiceVo;
import com.by4cloud.platformx.business.vo.ContractSlipVo;
import com.by4cloud.platformx.business.vo.FourAssociationPageVo;
import com.by4cloud.platformx.business.vo.*;
import com.by4cloud.platformx.common.core.util.R;
import com.by4cloud.platformx.common.data.datascope.DataScope;
import com.by4cloud.platformx.common.security.util.SecurityUtils;
@@ -45,6 +48,7 @@
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.OutputStream;
@@ -84,6 +88,7 @@
    private final ContractInvoiceMapper contractInvoiceMapper;
    private final StringRedisTemplate redisTemplate;
    private final ContractOutBoundMapper contractOutBoundMapper;
    private final RemoteDictService remoteDictService;
    @Value("${erp.ymj}")
    private String ymjErp;
@@ -1704,7 +1709,10 @@
        if (ObjUtil.isNotNull(addDTO.getDeliveryCycle())){
            contract.setExpirationDate(DateUtil.offsetDay(addDTO.getSignDate(),addDTO.getDeliveryCycle()));
        }
        if (ObjUtil.isNotNull(contract.getSignDate()) && ObjUtil.isNotNull(contract.getExpirationDate())) {
            Long bd = DateUtil.betweenDay(contract.getExpirationDate(), contract.getSignDate(), true);
            contract.setDeliveryCycle(bd.intValue());
        }
        contract.setContractNo(generateGYBContractNo());
        if (!StrUtil.equals(addDTO.getContractCategory(), "water_house")){
@@ -1899,6 +1907,7 @@
    /**
     * 判断付款阶段列表是否符合标准
     *
     * @param scheduleList 付款阶段列表
     * @return true 如果包含且仅包含标准的五个阶段,false 否则
     */
@@ -2215,7 +2224,6 @@
        map.put("buyerPart", contract.getBuyerPart());
        //标的物
        List<Map<String, Object>> items = new ArrayList<>();
        subjectMatterList.stream().forEach(contractSubjectMatter -> {
@@ -2381,4 +2389,220 @@
        }
        return R.ok();
    }
    @Override
    public R importContractMultiSheet(MultipartFile file) {
        // 用于收集所有 Sheet 解析后的最终结果(如果需要统一返回或处理)
        // 注意:如果数据量极大,建议在 Listener 中直接入库,不要全部加载到内存 List 中
        List<ContractExceVO> baseList = new ArrayList<>();
        List<ContractPaymentScheduleExceVO> scheduleList = new ArrayList<>();
        List<ContractSubjectMatterExceVO> matterList = new ArrayList<>();
        try (ExcelReader excelReader = EasyExcel.read(file.getInputStream()).build()) {
            // 1. 构建第一个 Sheet 的读取配置
            ReadSheet sheet0 = EasyExcel.readSheet(0)
                    .headRowNumber(1) // 表头行数
                    .head(ContractExceVO.class) // 指定实体类
                    .registerReadListener(new BatchInsertListener<ContractExceVO>(data -> {
                        baseList.addAll(data);
                        // 建议:在这里直接调用 service 保存,而不是 addTo List,除非数据量很小
                        // contractService.saveBaseInfo(data);
                    }))
                    .build();
            // 2. 构建第二个 Sheet 的读取配置
            ReadSheet sheet1 = EasyExcel.readSheet(1)
                    .headRowNumber(1)
                    .head(ContractSubjectMatterExceVO.class)
                    .registerReadListener(new BatchInsertListener<ContractSubjectMatterExceVO>(data -> {
                        matterList.addAll(data);
                        // contractService.saveSchedule(data);
                    }))
                    .build();
            // 3. 构建第三个 Sheet 的读取配置
            ReadSheet sheet2 = EasyExcel.readSheet(2)
                    .headRowNumber(1)
                    .head(ContractPaymentScheduleExceVO.class) // 注意:这里你原代码写的是 ContractPaymentScheduleExceVO,但变量是 matterList,需确认实体类是否一致
                    .registerReadListener(new BatchInsertListener<ContractPaymentScheduleExceVO>(data -> {
                        scheduleList.addAll(data);
                        // contractService.saveMatter(data);
                    }))
                    .build();
            // 4. 依次执行读取
            // 注意:excelReader.read(sheet) 会复用同一个输入流,所以必须用 try-with-resources 确保流管理正确
            excelReader.read(sheet0);
            excelReader.read(sheet1);
            excelReader.read(sheet2);
            // 后续处理 baseList, scheduleList, matterList
            log.info("主表数据量: " + baseList.size());
            log.info("进度表数据量: " + scheduleList.size());
            log.info("标的物数据量: " + matterList.size());
            List<Map<String, String>> errList = new ArrayList<>();
            for (int i = 0; i < baseList.size(); i++) {
                ContractExceVO contractExceVO = baseList.get(i);
                if (StrUtil.isBlank(contractExceVO.getContractNo())) {
                    Map<String, String> map = new HashMap<String, String>();
                    map.put("lineNum", "第" + (i + 1) + "行");
                    map.put("errors", "合同编号为空");
                    errList.add(map);
                    continue;
                }
                BusinessCustomer bc = businessCustomerMapper.selectOne(Wrappers.<BusinessCustomer>lambdaQuery()
                        .eq(BusinessCustomer::getErpCompanyCode, contractExceVO.getBcErpCode()));
                if (ObjUtil.isNull(bc)) {
                    Map<String, String> map = new HashMap<String, String>();
                    map.put("lineNum", "第" + (i + 1) + "行");
                    map.put("errors", "客户erp编码不存在");
                    errList.add(map);
                    continue;
                }
                R<List<SysDictItem>> rem = remoteDictService.getDictByType("economic_matters");
                if (!rem.isOk()) {
                    return R.failed("经济事项字典查询异常");
                }
                List<SysDictItem> itemList = rem.getData();
                for (SysDictItem dictItem : itemList
                ) {
                    if (StrUtil.equals(contractExceVO.getEconomicMatters(), dictItem.getLabel())) {
                        contractExceVO.setEconomicMatters(dictItem.getItemValue());
                        break;
                    }
                }
                R<List<SysDictItem>> rsa = remoteDictService.getDictByType("supply_attribute");
                if (!rsa.isOk()) {
                    return R.failed("供应属性字典查询异常");
                }
                for (SysDictItem dictItem : rsa.getData()
                ) {
                    if (StrUtil.equals(contractExceVO.getSupplyAttribute().replace(" ", ""), dictItem.getLabel())) {
                        contractExceVO.setSupplyAttribute(dictItem.getItemValue());
                        break;
                    }
                }
                R<List<SysDictItem>> rssa = remoteDictService.getDictByType("server_attribute");
                if (!rssa.isOk()) {
                    return R.failed("服务属性字典查询异常");
                }
                for (SysDictItem dictItem : rssa.getData()
                ) {
                    if (StrUtil.equals(contractExceVO.getContractAttribute().replace(" ", ""), dictItem.getLabel())) {
                        contractExceVO.setContractAttribute(dictItem.getItemValue());
                        break;
                    }
                }
                R<List<SysDictItem>> ris = remoteDictService.getDictByType("industry_sector");
                if (!ris.isOk()) {
                    return R.failed("服务属性字典查询异常");
                }
                for (SysDictItem dictItem : ris.getData()
                ) {
                    if (StrUtil.equals(contractExceVO.getIndustryCode(), dictItem.getLabel())) {
                        contractExceVO.setIndustryCode(dictItem.getItemValue());
                        break;
                    }
                }
                List<Contract> contractList = baseMapper.selectList(Wrappers.<Contract>lambdaQuery()
                        .eq(Contract::getContractNo, contractExceVO.getContractNo()));
                if (CollUtil.isNotEmpty(contractList)) {
                    Map<String, String> map = new HashMap<String, String>();
                    map.put("lineNum", "第" + (i + 1) + "行");
                    map.put("errors", "合同编号已存在");
                    errList.add(map);
                    continue;
                }
                Contract contract = BeanUtil.copyProperties(contractExceVO, Contract.class);
                if (ObjUtil.isNotNull(contract.getSignDate()) && ObjUtil.isNotNull(contract.getExpirationDate())) {
                    Long bd = DateUtil.betweenDay(contract.getExpirationDate(), contract.getSignDate(), true);
                    contract.setDeliveryCycle(bd.intValue());
                }
                contract.setPartyA(bc.getCompanyName());
                contract.setPartyAId(bc.getId());
                contract.setPartyB(SecurityUtils.getUser().getCompName());
                contract.setPartyBId(SecurityUtils.getUser().getCompId());
                contract.setContractStatus(2);
                contract.setPaidAmount(ObjUtil.isNotNull(contract.getPaidAmount())?
                        contract.getPaidAmount():new BigDecimal("0"));
                contract.setBillingAmout(ObjUtil.isNotNull(contract.getBillingAmout())?
                        contract.getBillingAmout():new BigDecimal("0"));
                contract.setBillingStatus("1");
                baseMapper.insert(contract);
                BigDecimal remainAmount = ObjUtil.isNotNull(contract.getPaidAmount())?contract.getPaidAmount():new BigDecimal("0");
                List<ContractSubjectMatterExceVO> resultMatter = matterList.stream().filter(item ->
                        StrUtil.isNotBlank(item.getMaterialCode()) &&
                                StrUtil.equals(item.getContractNo(), contract.getContractNo())).collect(Collectors.toList());
                if (CollUtil.isNotEmpty(resultMatter)) {
                    for (ContractSubjectMatterExceVO subMatEx : resultMatter
                    ) {
                        ContractSubjectMatter subjectMatter = BeanUtil.copyProperties(subMatEx, ContractSubjectMatter.class);
                        subjectMatter.setContractId(contract.getId());
                        subjectMatter.setDeliveredQuantity(StrUtil.isBlank(subMatEx.getDeliveredQuantity())
                                ? new BigDecimal("0") : new BigDecimal(subMatEx.getDeliveredQuantity()));
                        subjectMatter.setRemainingQuantity(subjectMatter.getQuantity().subtract(subjectMatter.getDeliveredQuantity()));
                        subjectMatter.setDeliveryStatus(subjectMatter.getRemainingQuantity().compareTo(subjectMatter.getQuantity()) == 0 ? 0
                                : subjectMatter.getRemainingQuantity().compareTo(new BigDecimal("0")) > 0 ? 1 : 2);
                        contractSubjectMatterMapper.insert(subjectMatter);
                    }
                }
                List<ContractPaymentScheduleExceVO> resultSchedule = scheduleList.stream().filter(item ->
                        StrUtil.equals(item.getContractNo(), contract.getContractNo())).collect(Collectors.toList());
                if (CollUtil.isNotEmpty(resultSchedule)) {
                    for (int j = 0; j < resultSchedule.size(); j++) {
                        ContractPaymentSchedule schedule = new ContractPaymentSchedule();
                        schedule.setStageName(resultSchedule.get(j).getStageName());
                        schedule.setContractId(contract.getId());
                        schedule.setPaymentRatio(StrUtil.isBlank(resultSchedule.get(j).getPaymentRatio())
                                ? new BigDecimal("0") : new BigDecimal(resultSchedule.get(j).getPaymentRatio()));
                        schedule.setAgreedDays(StrUtil.isBlank(resultSchedule.get(j).getAgreedDays())
                                ? 0 : Integer.valueOf(resultSchedule.get(j).getPaymentRatio()));
                        schedule.setPlannedAmount(contract.getAmount().multiply(schedule.getPaymentRatio())
                                .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP));
                        schedule.setPaymentStatus(0);
                        schedule.setStageOrder(j + 1);
                        if (remainAmount.compareTo(new BigDecimal("0"))>0&&schedule.getPlannedAmount().compareTo(new BigDecimal("0"))>0){
                            remainAmount = remainAmount.subtract(schedule.getPlannedAmount());
                            if (remainAmount.compareTo(new BigDecimal("0"))>=0){
                                schedule.setPaymentStatus(2);
                                schedule.setActualAmount(schedule.getPlannedAmount());
                            }
                            if (remainAmount.compareTo(new BigDecimal("0"))<0){
                                schedule.setPaymentStatus(1);
                                schedule.setActualAmount(schedule.getPlannedAmount().add(remainAmount));
                            }
                        }
                        contractPaymentScheduleMapper.insert(schedule);
                        if (schedule.getStageName().equals("质保金")&&contract.getAmount().subtract(ObjUtil.isNotNull(contract.getPaidAmount())?
                                contract.getPaidAmount():new BigDecimal("0")).compareTo(new BigDecimal("0"))>0){
                            PaymentConfirm confirm = new PaymentConfirm();
                            confirm.setBusGuestId(contract.getPartyAId());
                            confirm.setBusGuestName(contract.getPartyA());
                            confirm.setBusinessType("质保金应收");
                            confirm.setConfirmTime(new Date());
                            confirm.setContractId(contract.getId());
                            confirm.setContractName(contract.getContractName());
                            confirm.setContractNo(contract.getContractNo());
                            confirm.setScheduleId(schedule.getId());
                            confirm.setScheduleName(schedule.getStageName());
                            confirm.setTransationAmount(contract.getAmount().subtract(ObjUtil.isNotNull(contract.getPaidAmount())?
                                    contract.getPaidAmount():new BigDecimal("0")));
                            confirm.setReceivableAmount(confirm.getTransationAmount());
                            confirm.setTotalAmount(confirm.getTransationAmount().multiply(new BigDecimal("-1")));
                            paymentConfirmMapper.insert(confirm);
                        }
                    }
                }
            }
            if (CollUtil.isNotEmpty(errList)) {
                return R.failed(errList);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return R.failed("文件解析失败: " + e.getMessage());
        }
        return R.ok();
    }
}
platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/service/impl/OutBoundServiceImpl.java
@@ -590,7 +590,7 @@
                .eq(ContractSubjectMatter::getContractId, contract.getId()).ne(ContractSubjectMatter::getDeliveryStatus, 0));
        //查询合同是否有出库阶段
        ContractPaymentSchedule schedule = scheduleMapper.selectOne(Wrappers.<ContractPaymentSchedule>lambdaQuery().eq(ContractPaymentSchedule::getContractId, contract.getId())
                .eq(ContractPaymentSchedule::getStageName, "发货前"));
                .eq(ContractPaymentSchedule::getStageName, "发货前").gt(ContractPaymentSchedule::getPaymentRatio,0).last("limit 1"));
        //存在出库阶段
        if (ObjUtil.isNotNull(schedule)) {
            //当前出库金额
@@ -611,6 +611,8 @@
                contract.setBillingStatus("3");
                contractMapper.updateById(contract);
            }
            //导入数据不生成应收
            if (targetContractNo.startsWith("ZB-")) {
            //计算发货前应收更新资金明细
            PaymentConfirm paymentConfirm = new PaymentConfirm();
            paymentConfirm.setBusinessType("发货前应收");
@@ -700,6 +702,7 @@
                    }
                }
            }
            }
            //更新发货前收款生效时间
            if (ObjUtil.isNull(schedule.getEffectiveDate())) {
platformx-business-finance-biz/src/main/java/com/by4cloud/platformx/business/utils/BatchInsertListener.java
New file
@@ -0,0 +1,49 @@
package com.by4cloud.platformx.business.utils;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class BatchInsertListener<T> extends AnalysisEventListener<T> {
    private final List<T> cachedDataList = new ArrayList<>();
    private final static int BATCH_COUNT = 1000;
    private final ServiceCallback<T> callback;
    // 函数式接口,用于回调业务逻辑
    @FunctionalInterface
    public interface ServiceCallback<T> {
        void invoke(List<T> data);
    }
    public BatchInsertListener(ServiceCallback<T> callback) {
        this.callback = callback;
    }
    @Override
    public void invoke(T data, AnalysisContext context) {
        cachedDataList.add(data);
        // 达到阈值,执行一次数据库操作
        if (cachedDataList.size() >= BATCH_COUNT) {
            saveData();
            cachedDataList.clear();
        }
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 处理剩余数据
        saveData();
        log.info("所有数据解析完成!");
    }
    private void saveData() {
        if (!cachedDataList.isEmpty()) {
            // 调用外部传入的业务逻辑进行保存
            callback.invoke(cachedDataList);
        }
    }
}
platformx-business-finance-biz/src/main/resources/mapper/ContractMapper.xml
@@ -1106,6 +1106,9 @@
        <if test="queryDTO.contractName !=null and queryDTO.contractName !=''">
            AND contract_name LIKE CONCAT('%', #{queryDTO.contractName}, '%')
        </if>
        <if test="queryDTO.contractNo !=null and queryDTO.contractNo !=''">
            AND contract_no LIKE CONCAT('%', #{queryDTO.contractNo}, '%')
        </if>
        <if test="queryDTO.partyA !=null and queryDTO.partyA !=''">
            AND party_a LIKE CONCAT('%', #{queryDTO.partyA}, '%')
        </if>