package com.trade.client.trade.purchasecontract.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.trade.client.enterprise.customer.domain.model.LoginUserInfo;
import com.trade.client.trade.purchasecontract.dto.PurchaseContractSearchDto;
import com.trade.client.trade.purchasecontract.dto.PurchaseContractUploadDto;
import com.trade.client.trade.purchasecontract.service.PurchaseContractService;
import com.trade.client.security.utils.UserUtils;
import com.trade.common.constant.HttpStatus;
import com.trade.common.core.page.GridPage;
import com.trade.common.exception.ServiceException;
import com.trade.common.exception.ValidatorException;
import com.trade.common.utils.ConstantUtil;
import com.trade.common.utils.DateUtils;
import com.trade.common.utils.bean.BeanCopyUtils;
import com.trade.common.validate.ValidatorGroup;
import com.trade.common.validate.ValidatorUtil;
import com.trade.service.DictConstants;
import com.trade.service.TransStruct;
import com.trade.service.contract.constant.ContractConstant;
import com.trade.service.contract.dto.*;
import com.trade.service.contract.service.ContractService;
import com.trade.service.contract.util.esign.ESignConstant;
import com.trade.service.enterprise.customer.domain.EnterpriseRelatedPerson;
import com.trade.service.enterprise.customer.service.EnterpriseRelatedPersonBaseService;
import com.trade.service.filestorage.dto.FileAbstractDto;
import com.trade.service.filestorage.enums.FileTypeEnum;
import com.trade.service.enterprise.companyrelated.domain.VendorEntity;
import com.trade.service.enterprise.companyrelated.service.IVendorEntityService;
import com.trade.service.enterprise.customer.domain.Enterprise;
import com.trade.service.enterprise.customer.service.EnterpriseBaseService;
import com.trade.service.filestorage.entity.BusinessRelateFile;
import com.trade.service.filestorage.entity.TFileStorage;
import com.trade.service.filestorage.service.BusinessRelateFileBaseService;
import com.trade.service.filestorage.service.TFileStorageService;
import com.trade.service.trade.purchasecontract.domain.PurchaseCommodity;
import com.trade.service.trade.purchasecontract.domain.PurchaseContract;
import com.trade.service.trade.purchasecontract.dto.*;
import com.trade.service.trade.purchasecontract.service.PurchaseCommodityBaseService;
import com.trade.service.trade.purchasecontract.service.PurchaseContractBaseService;
import com.trade.service.trade.purchaseorder.service.PurchaseOrderService;
import com.trade.service.trade.salescontract.domain.ContractFile;
import com.trade.service.trade.salescontract.domain.ContractTerms;
import com.trade.service.trade.salescontract.domain.ContractTermsExtend;
import com.trade.service.trade.salescontract.dto.ContractCommodityDto;
import com.trade.service.trade.salescontract.dto.ContractTermsDto;
import com.trade.service.trade.salescontract.dto.SalesCommodityDto;
import com.trade.service.trade.salescontract.dto.SalesContractDto;
import com.trade.service.trade.salescontract.service.ContractFileService;
import com.trade.service.trade.salescontract.service.ContractTermsExtendService;
import com.trade.service.trade.salescontract.service.ContractTermsService;
import com.trade.service.trade.salescontract.service.SalesContractService;
import com.trade.service.trade.salescontract.vo.SalesContractInfoVo;
import com.trade.service.serialNum.service.SerialNumberGenerator;
import com.trade.service.tradingplatform.domain.TradingPlatform;
import com.trade.service.tradingplatform.service.impl.TradingPlatformBaseServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 采购合同表基础表服务实现类
 *
 * @author hlb
 * @since 2024-09-07 16:30:11
 */
@Service("purchaseContractService")
public class PurchaseContractServiceImpl implements PurchaseContractService {

    private static final Logger logger = LoggerFactory.getLogger(PurchaseContractServiceImpl.class);
    @Resource
    private SalesContractService salesContractService;
    @Resource
    private PurchaseContractBaseService purchaseContractBaseService;
    @Resource
    private PurchaseCommodityBaseService purchaseCommodityBaseService;
    @Resource
    private SerialNumberGenerator serialNumberGenerator;
    @Resource
    private EnterpriseBaseService enterpriseBaseService;
    @Resource
    private IVendorEntityService vendorEntityService;
    @Resource
    private ContractTermsService contractTermsService;
    @Resource
    private ContractTermsExtendService contractTermsExtendService;
    @Resource
    private TFileStorageService fileStorageService;
    @Resource
    private BusinessRelateFileBaseService businessRelateFileBaseService;
    @Resource
    private ContractService contractService;
    @Resource
    private EnterpriseRelatedPersonBaseService enterpriseRelatedPersonBaseService;
    @Autowired
    private TradingPlatformBaseServiceImpl tradingPlatformBaseService;
    @Autowired
    private TransStruct transStruct;
    @Resource
    private ContractFileService contractFileService;
    @Resource
    private PurchaseOrderService purchaseOrderService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createPurchaseContract(Long salesContractId) {
        LoginUserInfo loginUserInfo = UserUtils.getLoginUser();
        Long customerUserId = loginUserInfo.getCustomerUserId();
        Enterprise enterprise = enterpriseBaseService.getEnterpriseByCustomerId(customerUserId);
        if (enterprise == null) {
            throw new ServiceException("用户未完成认证（用户id：" + customerUserId + "）", HttpStatus.BAD_REQUEST);
        }
        // “自营出口”的“生产企业”,不生成采购合同
        if (DictConstants.EXPORT_TYPE_SELF.equals(enterprise.getExportType())
                && (DictConstants.ENTERPRISE_TYPE_PRODUCE.equals(enterprise.getEnterpriseType())
                        || DictConstants.ENTERPRISE_TYPE_PRODUCE_EXTERNAL.equals(enterprise.getEnterpriseType()))) {
            return;
        }
        if (salesContractId == null) {
            throw new ServiceException("销售合同id不能为空", HttpStatus.BAD_REQUEST);
        }
        SalesContractInfoVo contractInfoVo = salesContractService.getSalesContractDetails(salesContractId);
        if (contractInfoVo == null) {
            throw new ServiceException("未找到该销售合同（销售合同id：" + salesContractId + "）", HttpStatus.BAD_REQUEST);
        }
        PurchaseContractDetailDto purchaseContractDetailDto = purchaseContractBaseService
                .findBySaleContractNo(customerUserId, contractInfoVo.getSalesContract().getContractNo(), null);
        if (purchaseContractDetailDto != null) {
            throw new ServiceException(
                    "该销售合同已生成采购合同（销售合同编号：" + contractInfoVo.getSalesContract().getContractNo() + "）请勿重复提交",
                    HttpStatus.BAD_REQUEST);
        }
        SalesContractDto salesContract = contractInfoVo.getSalesContract();
        if (salesContract == null) {
            throw new ServiceException("销售合同基本信息缺失（销售合同id：" + salesContractId + "）", HttpStatus.BAD_REQUEST);
        }
        List<SalesCommodityDto> salesCommodities = contractInfoVo.getSalesCommoditys();
        if (CollUtil.isEmpty(salesCommodities)) {
            throw new ServiceException("销售合同商品信息缺失（销售合同编号：" + salesContract.getContractNo() + "）",
                    HttpStatus.BAD_REQUEST);
        }
        Map<String, List<SalesCommodityDto>> commodityMap = salesCommodities.stream()
                .collect(Collectors.groupingBy(SalesCommodityDto::getEntityNo));
        for (Map.Entry<String, List<SalesCommodityDto>> entry : commodityMap.entrySet()) {
            String vendorEntityNo = entry.getKey();
            List<SalesCommodityDto> commodityList = entry.getValue();
            VendorEntity vendorEntity = null;
            if (DictConstants.EXPORT_TYPE_SELF.equals(enterprise.getExportType())) {
                if (StrUtil.isEmpty(vendorEntityNo)) {
                    throw new ServiceException("供应商编号不能为空（销售合同编号：" + salesContract.getContractNo() + "）",
                            HttpStatus.BAD_REQUEST);
                }
                vendorEntity = vendorEntityService.getByEntityNo(vendorEntityNo);
                if (vendorEntity == null) {
                    throw new ServiceException("供应商不存在（供应商编号：" + vendorEntityNo + "）", HttpStatus.BAD_REQUEST);
                }
            }
            PurchaseContract purchaseContract = buildPurchaseContract(salesContract, vendorEntityNo,
                    isUsingStandardContractTemplate(enterprise), customerUserId,
                    loginUserInfo.getCustomerUser().getNickname());
            // 保存采购合同基本信息
            purchaseContractBaseService.save(purchaseContract);
            List<PurchaseCommodity> purchaseCommodities = buildPurchaseCommodities(enterprise,
                    purchaseContract.getContractCurrency(), purchaseContract.getId(), vendorEntityNo, commodityList,
                    salesContract.getExchangeRate());
            // 保存采购合同商品信息
            purchaseCommodityBaseService.saveBatch(purchaseCommodities);
            ContractTerms purchaseContractTerms = buildContractTerms(purchaseContract,
                    contractInfoVo.getContractTermsDto(), vendorEntity);
            // 保存采购合同条款信息
            contractTermsService.save(purchaseContractTerms);
            if (DictConstants.EXPORT_TYPE_PROXY.equals(enterprise.getExportType())
                    && DictConstants.DISTRICT_CN_MAINLAND.equals(enterprise.getProxyDistrictCode())) {
                // 代理出口、大陆贸易平台,则直接从销售合同中获取付款信息
                List<ContractTermsExtend> contractTermsExtends = new ArrayList<>();
                for (ContractTermsExtend extend : contractInfoVo.getContractTermsDto().getPaymentInfo()) {
                    ContractTermsExtend contractTermsExtend = BeanCopyUtils.copy(extend, ContractTermsExtend.class);
                    contractTermsExtend.setId(null);
                    contractTermsExtend.setContractTermsId(purchaseContractTerms.getId());
                    contractTermsExtend.setGmtCreate(null);
                    contractTermsExtend.setGmtModified(null);
                    contractTermsExtends.add(contractTermsExtend);
                }
                contractTermsExtendService.saveBatch(contractTermsExtends);
            }
            // 代理出口、大陆贸易平台，则更新合同金额(含税金额)
            if (DictConstants.EXPORT_TYPE_PROXY.equals(enterprise.getExportType())
                    && DictConstants.DISTRICT_CN_MAINLAND.equals(enterprise.getProxyDistrictCode())) {
                BigDecimal totalAmount = purchaseCommodities.stream().map(PurchaseCommodity::getTotalAmount)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                purchaseContractBaseService.lambdaUpdate().eq(PurchaseContract::getId, purchaseContract.getId())
                        .set(PurchaseContract::getContractAmount, totalAmount).update();
            }
        }
    }

    /**
     * 创建采购合同基本
     * 
     * @param salesContract
     * @param vendorEntityNo 供应商编号
     * @param isUsingStandardContractTemplate 是否使用标准合同模板
     * @param customerUserId
     * @return
     */
    private PurchaseContract buildPurchaseContract(SalesContractDto salesContract, String vendorEntityNo,
            boolean isUsingStandardContractTemplate, Long customerUserId, String loginName) {
        PurchaseContract purchaseContract = new PurchaseContract();
        purchaseContract.setCustomerUserId(customerUserId);
        purchaseContract.setSalesContractNo(salesContract.getContractNo());
        purchaseContract.setTemplateType(isUsingStandardContractTemplate);
        if (isUsingStandardContractTemplate) {
            String contractNo = serialNumberGenerator.nextValue(ConstantUtil.PURCHASE_CONTRACT_CODE);
            purchaseContract.setContractNo(contractNo);
        }
        purchaseContract.setVendorEntityNo(vendorEntityNo);
        purchaseContract.setDraft(Boolean.TRUE);
        purchaseContract.setStatus(DictConstants.PURCHASE_CONTRACT_STATUS_DRAFT);
        purchaseContract.setContractCurrency("CNY");
        purchaseContract.setCreateBy(loginName);
        return purchaseContract;
    }

    /**
     * 创建采购合同商品信息
     * 
     * @param purchaseContractId
     * @param vendorEntityNo
     * @param salesCommodities
     * @return
     */
    private List<PurchaseCommodity> buildPurchaseCommodities(Enterprise enterprise, String currency,
            Long purchaseContractId, String vendorEntityNo, List<SalesCommodityDto> salesCommodities,
            BigDecimal exchangeRate) {
        boolean autoCalculatePrice = DictConstants.EXPORT_TYPE_PROXY.equals(enterprise.getExportType())
                && DictConstants.DISTRICT_CN_MAINLAND.equals(enterprise.getProxyDistrictCode());
        return salesCommodities.stream().filter(sc -> StrUtil.equals(vendorEntityNo, sc.getEntityNo())).map(sc -> {
            PurchaseCommodity purchaseCommodity = new PurchaseCommodity();
            purchaseCommodity.setPurchaseContractId(purchaseContractId);
            purchaseCommodity.setSalesCommodityId(sc.getId());
            purchaseCommodity.setSalesContractId(sc.getSalesContractId());
            purchaseCommodity.setCurrency(currency);
            purchaseCommodity.setNumber(sc.getNumber());
            if (autoCalculatePrice) {
                // （1）采购单价 (不含税) = （销售单价 * 汇率 - 价差）/ (1 + 增值税税率 - 增值税退税率）。
                // （2）汇率：取“销售合同签署日”当日银行间市场汇率牌价的实时结汇汇率。
                // （3）价差（即，印花税）= 销售单价 * 汇率 * 0.07%；
                // 总结：采购单价 = 销售单价 * 汇率 * 0.9993% / (1 + 增值税税率 - 增值税退税率)。
                BigDecimal priceUnit = sc.getPriceUnit().multiply(exchangeRate).multiply(new BigDecimal("0.9993"))
                        .divide(BigDecimal.ONE.add(new BigDecimal(sc.getAddedTaxRate()))
                                .subtract(new BigDecimal(sc.getExportTaxRebateRate())), 2, RoundingMode.HALF_UP);
                BigDecimal amount = priceUnit.multiply(sc.getNumber());
                purchaseCommodity.setAmount(amount);
                purchaseCommodity
                        .setTotalAmount(amount.multiply(BigDecimal.ONE.add(new BigDecimal(sc.getAddedTaxRate()))));
                purchaseCommodity.setPriceUnit(priceUnit);
            }
            return purchaseCommodity;
        }).collect(Collectors.toList());
    }

    /**
     * 创建采购合同条款信息
     *
     * @param purchaseContract
     * @param salesContractTerms
     * @return
     */
    private ContractTerms buildContractTerms(PurchaseContract purchaseContract, ContractTermsDto salesContractTerms,
            VendorEntity vendorEntity) {
        ContractTerms purchaseContractTerms = new ContractTerms();
        purchaseContractTerms.setContractId(purchaseContract.getId());
        purchaseContractTerms.setContractType(ConstantUtil.PURCHASE_CONTRACT_CODE);
        purchaseContractTerms.setContractNo(purchaseContract.getContractNo());
        purchaseContractTerms.setSettlementCycle(salesContractTerms.getSettlementCycle());
        // 有供应商说明是自营模式而不是代理模式（自营：取供应商的账号，代理：录入客户自己的）
        purchaseContractTerms
                .setAccountName(Optional.ofNullable(vendorEntity).map(VendorEntity::getAcctName).orElse(null));
        purchaseContractTerms
                .setAccountNumber(Optional.ofNullable(vendorEntity).map(VendorEntity::getAcctNo).orElse(null));
        purchaseContractTerms
                .setOpeningBank(Optional.ofNullable(vendorEntity).map(VendorEntity::getAcctOpenBank).orElse(null));
        return purchaseContractTerms;
    }

    /**
     * 判断是否使用标准合同模板
     * 
     * @param enterprise
     * @return
     */
    boolean isUsingStandardContractTemplate(Enterprise enterprise) {
        return DictConstants.EXPORT_TYPE_PROXY.equals(enterprise.getExportType())
                && DictConstants.DISTRICT_CN_MAINLAND.equals(enterprise.getProxyDistrictCode());
    }

    @Override
    public GridPage<PurchaseContractDto> getPurchaseContractBySearch(PurchaseContractSearchDto searchDto) {
        Long customerUserId = UserUtils.getLoginUser().getCustomerUserId();
        PurchaseContractSearchBaseDto searchBaseDto = new PurchaseContractSearchBaseDto();
        searchBaseDto.setCustomerUserId(customerUserId);
        searchBaseDto.setPoint(true);
        searchBaseDto.setContractStatus(searchDto.getContractStatus());
        searchBaseDto.setContractInfo(searchDto.getContractInfo());
        searchBaseDto.setVendorEntityNo(searchDto.getVendorEntityNo());
        searchBaseDto.setAgencyCertNo(searchDto.getAgencyCertNo());
        searchBaseDto.setSalesContractNo(searchDto.getSalesContractNo());
        searchBaseDto.setTimeStart(searchDto.getGmtCreateStart());
        searchBaseDto.setTimeEnd(searchDto.getGmtCreateEnd());
        GridPage<PurchaseContractDto> page = purchaseContractBaseService.getPurchaseContractBySearch(searchBaseDto);
        if (CollUtil.isNotEmpty(page.getRows())) {
            for (PurchaseContractDto purchaseContractDto : page.getRows()) {
                businessRelateFileBaseService.fillBizObjFiles(purchaseContractDto, purchaseContractDto.getId(),
                        ConstantUtil.PURCHASE_CONTRACT, FileTypeEnum.PURCHASE_CONTRACT.getCode());
            }
        }
        return page;
    }

    @Override
    public PurchaseContractDetailDto findPurchaseContractDetailById(Long id) {
        return purchaseContractBaseService.findPurchaseContractDetailById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<FileAbstractDto> upsertPurchaseContract(String operate, PurchaseContractDetailDto purchaseContractDto) {
        LoginUserInfo loginUserInfo = UserUtils.getLoginUser();
        Long customerUserId = loginUserInfo.getCustomerUserId();
        Enterprise enterprise = enterpriseBaseService.getEnterpriseByCustomerId(customerUserId);
        if (enterprise == null) {
            throw new ServiceException("用户未完成认证（用户id：" + customerUserId + "）", HttpStatus.BAD_REQUEST);
        }
        // 采购合同是根据销售合同自动生成，所以这个一定是存在id的
        PurchaseContract purchaseContract = purchaseContractBaseService.getById(purchaseContractDto.getId());
        if (purchaseContract == null) {
            throw new ServiceException("采购合同不存在（采购合同id：" + purchaseContractDto.getId() + "）", HttpStatus.BAD_REQUEST);
        }
        if (!purchaseContract.getDraft()) {
            throw new ServiceException("采购合同已提交，不能修改（采购合同编号：" + purchaseContract.getContractNo() + "）",
                    HttpStatus.BAD_REQUEST);
        }
        // 校验参数
        checkPurchaseContractParams(operate, purchaseContractDto, enterprise);
        if (purchaseContractDto.getTemplateType() && !purchaseContract.getTemplateType()) {
            String contractNo = serialNumberGenerator.nextValue(ConstantUtil.PURCHASE_CONTRACT_CODE);
            purchaseContractDto.setContractNo(contractNo);
        }
        purchaseContractDto.setContractAmount(purchaseContract.getContractAmount());
        PurchaseContract purchaseContractNew = buildPurchaseContract(operate, purchaseContractDto, enterprise,
                loginUserInfo);
        // 更新采购合同基本信息
        purchaseContractBaseService.updateById(purchaseContractNew);
        List<PurchaseCommodity> purchaseCommodities = buildPurchaseCommodities(purchaseContractDto.getCommodityList());
        // 更新采购合同商品信息
        purchaseCommodityBaseService.updateBatchById(purchaseCommodities);
        ContractTerms purchaseContractTerms = buildContractTerms(purchaseContractDto.getContractNo(),
                purchaseContractDto.getContractTerms());
        // 更新采购合同条款信息
        contractTermsService.updateById(purchaseContractTerms);
        if (CollUtil.isNotEmpty(purchaseContractDto.getContractTerms().getPaymentInfo())) {
            if (operate.equals(ConstantUtil.OPERATE_TYPE_SUBMIT)) {
                // 付款比例必须为100%
                BigDecimal totalRatio = purchaseContractDto.getContractTerms().getPaymentInfo().stream()
                        .map(ContractTermsExtend::getPaymentRatio).reduce(BigDecimal.ZERO, BigDecimal::add);
                if (totalRatio.compareTo(new BigDecimal("100")) != 0) {
                    throw new ServiceException("付款比例总和必须为100%（采购合同id：" + purchaseContract.getContractNo() + "）",
                            HttpStatus.BAD_REQUEST);
                }
                // 最大付款比例子对应的付款期限必须等于结算账期
                ContractTermsExtend maxContractTermsExtend = purchaseContractDto.getContractTerms().getPaymentInfo()
                        .stream().max(Comparator.comparing(ContractTermsExtend::getPaymentRatio)).orElse(null);
                if (maxContractTermsExtend != null && !purchaseContractTerms.getSettlementCycle()
                        .equals(maxContractTermsExtend.getPaymentTerm())) {
                    throw new ServiceException("付款条款设置错误（采购合同id：" + purchaseContract.getContractNo() + "）,付款期限不满足要求",
                            HttpStatus.BAD_REQUEST);
                }
            }
            List<ContractTermsExtend> contractTermsExtends = buildContractTermExtends(purchaseContractTerms,
                    purchaseContractDto.getContractTerms().getPaymentInfo());
            // 更新采购合同付款信息
            contractTermsExtendService.deleteContractByContractTermId(purchaseContractDto.getContractTerms().getId(),
                    "1");
            contractTermsExtendService.saveBatch(contractTermsExtends);
        }
        if (CollUtil.isNotEmpty(purchaseContractDto.getContractTerms().getTitleInfo())) {
            List<ContractTermsExtend> contractTermsExtends = buildContractTermExtends(purchaseContractTerms,
                    purchaseContractDto.getContractTerms().getTitleInfo());
            // 更新采购合同附加条款信息
            contractTermsExtendService.deleteContractByContractTermId(purchaseContractDto.getContractTerms().getId(),
                    "2");
            contractTermsExtendService.saveBatch(contractTermsExtends);
        }
        if (operate.equals(ConstantUtil.OPERATE_TYPE_SUBMIT) && !purchaseContractDto.getTemplateType()) {
            purchaseOrderService.handleOrder(purchaseContractDto.getId());
        }
        return generateSignFiles(operate, enterprise, purchaseContractDto);
    }

    private List<FileAbstractDto> generateSignFiles(String operate, Enterprise enterprise,
            PurchaseContractDetailDto purchaseContractDto) {
        List<FileAbstractDto> fileAbstractDtos = new ArrayList<>();
        if (!operate.equals(ConstantUtil.OPERATE_TYPE_SUBMIT) || !purchaseContractDto.getTemplateType()) {
            return fileAbstractDtos;
        }
        SalesContractInfoVo contractInfoVo = salesContractService
                .getSalesContractDetails(purchaseContractDto.getSalesContractId());
        if (contractInfoVo == null) {
            return fileAbstractDtos;
        }
        if (DictConstants.EXPORT_TYPE_PROXY.equals(enterprise.getExportType())
                && DictConstants.DISTRICT_CN_MAINLAND.equals(enterprise.getProxyDistrictCode())) {
            // 生成承诺函
            fileAbstractDtos.add(generatePlatformCommitmentLetter(enterprise,
                    contractInfoVo.getSalesContract().getAgencyEnterpriseName(), purchaseContractDto.getId()));
        }
        // 生成采购合同
        fileAbstractDtos.add(generatePurchaseContract(enterprise, purchaseContractDto, contractInfoVo));
        return fileAbstractDtos;
    }

    /**
     * 生成贸易公司承诺函
     * 
     * @param enterprise
     * @param tradingPlatformName
     * @param purchaseContractId
     * @return
     */
    private FileAbstractDto generatePlatformCommitmentLetter(Enterprise enterprise, String tradingPlatformName,
            Long purchaseContractId) {
        ContractGenInputItem inputItem = new ContractGenInputItem();
        inputItem.setTemplateCode(FileTypeEnum.PLATFORM_COMMITMENT_LETTER.getCode());
        inputItem.setContractName("承诺函-贸易公司");
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("tradingPlatform", tradingPlatformName);
        dataMap.put("vendorName", enterprise.getName());
        inputItem.setParams(dataMap);
        ContractGenOutputItem contractGenOutput = contractService.generateSingleContract(inputItem,
                enterprise.getCustomerId());
        if (contractGenOutput == null) {
            throw new ValidatorException(HttpStatus.ERROR, "《承诺函-贸易公司》生成失败！");
        }
        // 保存文件(未签署)
        BusinessRelateFile businessRelateFile = new BusinessRelateFile();
        businessRelateFile.setFileId(contractGenOutput.getFileId());
        businessRelateFile.setBelongId(purchaseContractId);
        businessRelateFile.setBelongType(ConstantUtil.PURCHASE_CONTRACT);
        businessRelateFile.setFileType(FileTypeEnum.PLATFORM_COMMITMENT_LETTER.getCode());
        businessRelateFileBaseService.addBusinessRelateFiles(Collections.singletonList(businessRelateFile));
        return new FileAbstractDto(contractGenOutput.getFileId(), "承诺函-贸易公司.pdf", null, null);
    }

    /**
     * 生成采购合同
     * 
     * @param purchaseContractDto
     * @return
     */
    private FileAbstractDto generatePurchaseContract(Enterprise enterprise,
            PurchaseContractDetailDto purchaseContractDto, SalesContractInfoVo salesContractInfoVo) {
        ContractGenInputItem inputItem = new ContractGenInputItem();
        inputItem.setTemplateCode(FileTypeEnum.PURCHASE_CONTRACT.getCode());
        inputItem.setContractName(purchaseContractDto.getContractName());
        Map<String, Object> dataMap = new HashMap<>();
        SignPartyInfo buyer = getBuyerInfo(enterprise, purchaseContractDto.getAgencyCertNo(),
                salesContractInfoVo.getContractTermsDto());
        SignPartyInfo seller = getSellerInfo(enterprise, purchaseContractDto.getVendorEntityNo(),
                purchaseContractDto.getContractTerms());
        dataMap.put("contractNo", purchaseContractDto.getContractNo());
        dataMap.put("buyer", buyer.getEnterpriseName());
        dataMap.put("buyerBankName", buyer.getEnterpriseCertNo());
        dataMap.put("buyerBankAccount", buyer.getBankAccountNo());
        dataMap.put("buyerContact", buyer.getEnterpriseContactName());
        dataMap.put("buyerPhone", buyer.getEnterpriseContactPhone());
        dataMap.put("buyerEmail", buyer.getEnterpriseContactEmail());
        dataMap.put("buyerAddress", buyer.getEnterpriseContactAddress());
        dataMap.put("buyerLegal", buyer.getLegalPersonName());
        dataMap.put("seller", seller.getEnterpriseName());
        dataMap.put("sellerBankName", seller.getEnterpriseCertNo());
        dataMap.put("sellerBankAccount", seller.getBankAccountNo());
        dataMap.put("sellerContact", seller.getEnterpriseContactName());
        dataMap.put("sellerPhone", seller.getEnterpriseContactPhone());
        dataMap.put("sellerEmail", seller.getEnterpriseContactEmail());
        dataMap.put("sellerAddress", seller.getEnterpriseContactAddress());
        dataMap.put("sellerLegal", seller.getLegalPersonName());
        dataMap.put("paymentTerms", getPaymentInfo(purchaseContractDto.getContractTerms().getPaymentInfo()));
        List<ContractCommodityDto> goods = transStruct
                .transPurchaseCommodityList2ContractCommodityList(purchaseContractDto.getCommodityList());
        dataMap.put("goods", goods);
        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
        inputItem.setConfig(Configure.builder().bind("goods", policy).build());
        BigDecimal total = goods.stream().map(o -> new BigDecimal(o.getAmount())).reduce(BigDecimal.ZERO,
                BigDecimal::add);
        dataMap.put("total", total);
        inputItem.setParams(dataMap);
        ContractGenOutputItem contractGenOutput = contractService.generateSingleContract(inputItem,
                enterprise.getCustomerId());
        if (contractGenOutput == null) {
            throw new ValidatorException(HttpStatus.ERROR, "《采购合同-跨境通》生成失败！");
        }
        // 保存文件(未签署)
        BusinessRelateFile businessRelateFile = new BusinessRelateFile();
        businessRelateFile.setFileId(contractGenOutput.getFileId());
        businessRelateFile.setBelongId(purchaseContractDto.getId());
        businessRelateFile.setBelongType(ConstantUtil.PURCHASE_CONTRACT);
        businessRelateFile.setFileType(FileTypeEnum.PURCHASE_CONTRACT.getCode());
        businessRelateFileBaseService.addBusinessRelateFiles(Collections.singletonList(businessRelateFile));
        return new FileAbstractDto(contractGenOutput.getFileId(), purchaseContractDto.getContractName() + ".pdf", null,
                null);
    }

    /**
     * 获取采购合同买方信息
     * 
     * @param enterprise
     * @param agencyCertNo
     * @param salesContractTermsDto
     * @return
     */
    private SignPartyInfo getBuyerInfo(Enterprise enterprise, String agencyCertNo,
            ContractTermsDto salesContractTermsDto) {
        SignPartyInfo signPartyInfo = null;
        // 自营出口，采购买方为当前企业
        if (DictConstants.EXPORT_TYPE_SELF.equals(enterprise.getExportType())) {
            EnterpriseRelatedPerson contactPerson = enterpriseRelatedPersonBaseService
                    .getContactByChangeRecordId(enterprise.getChangeRecordId());
            if (contactPerson == null) {
                throw new ServiceException("自营出口：买方联系人信息不存在", HttpStatus.BAD_REQUEST);
            }
            EnterpriseRelatedPerson legalPerson = enterpriseRelatedPersonBaseService
                    .getLegalByChangeRecordId(enterprise.getChangeRecordId());
            if (legalPerson == null) {
                throw new ServiceException("自营出口：买方法人人信息不存在", HttpStatus.BAD_REQUEST);
            }
            signPartyInfo = new SignPartyInfo(enterprise, contactPerson, legalPerson);
        } else {
            // 代理出口，采购买方为贸易平台
            TradingPlatform tradingPlatform = tradingPlatformBaseService.findByCertNo(agencyCertNo);
            signPartyInfo = new SignPartyInfo(tradingPlatform);
        }
        // 销售合同的收款账号：自营则是客户企业的、代理则是贸易平台的
        if (salesContractTermsDto != null) {
            signPartyInfo.setOpeningBank(salesContractTermsDto.getOpeningBank());
            signPartyInfo.setBankAccountName(salesContractTermsDto.getAccountName());
            signPartyInfo.setBankAccountNo(salesContractTermsDto.getAccountNumber());
        }
        return signPartyInfo;
    }

    /**
     * 获取采购合同卖方信息
     * 
     * @param enterprise
     * @param vendorEntityNo
     * @param purchaseContractTermsDto
     * @return
     */
    private SignPartyInfo getSellerInfo(Enterprise enterprise, String vendorEntityNo,
            ContractTermsDto purchaseContractTermsDto) {
        SignPartyInfo signPartyInfo = null;
        // 自营出口，采购卖方为供应商
        if (DictConstants.EXPORT_TYPE_SELF.equals(enterprise.getExportType())) {
            VendorEntity vendor = vendorEntityService.getByEntityNo(vendorEntityNo);
            if (vendor == null) {
                throw new ServiceException("供应商不存在（供应商编号：" + vendorEntityNo + "）", HttpStatus.BAD_REQUEST);
            }
            signPartyInfo = new SignPartyInfo(vendor);
        } else {
            // 代理出口，采购卖方为当前企业
            EnterpriseRelatedPerson contactPerson = enterpriseRelatedPersonBaseService
                    .getContactByChangeRecordId(enterprise.getChangeRecordId());
            if (contactPerson == null) {
                throw new ServiceException("代理出口：卖方联系人信息不存在", HttpStatus.BAD_REQUEST);
            }
            EnterpriseRelatedPerson legalPerson = enterpriseRelatedPersonBaseService
                    .getLegalByChangeRecordId(enterprise.getChangeRecordId());
            if (legalPerson == null) {
                throw new ServiceException("代理出口：卖方法人人信息不存在", HttpStatus.BAD_REQUEST);
            }
            signPartyInfo = new SignPartyInfo(enterprise, contactPerson, legalPerson);
        }
        if (purchaseContractTermsDto != null) {
            signPartyInfo.setOpeningBank(purchaseContractTermsDto.getOpeningBank());
            signPartyInfo.setBankAccountName(purchaseContractTermsDto.getAccountName());
            signPartyInfo.setBankAccountNo(purchaseContractTermsDto.getAccountNumber());
        }
        return signPartyInfo;
    }

    /**
     * 获取采购合同付款信息
     * 
     * @param paymentInfos
     * @return
     */
    private String getPaymentInfo(List<ContractTermsExtend> paymentInfos) {
        return paymentInfos.stream()
                .map(o -> o.getPaymentTime() + (o.getPaymentTerm().equals(0) ? ("支付") : (o.getPaymentTerm() + "天支付"))
                        + o.getPaymentRatio() + "%" + o.getPaymentName())
                .collect(Collectors.joining("，"));
    }

    /**
     * 校验采购合同参数
     * 
     * @param operate
     * @param purchaseContractDto
     * @param enterprise
     */
    private void checkPurchaseContractParams(String operate, PurchaseContractDetailDto purchaseContractDto,
            Enterprise enterprise) {
        ValidatorGroup.ValidatorType validatorType = operate.equals(ConstantUtil.OPERATE_TYPE_SAVE)
                ? ValidatorGroup.ValidatorType.ADD
                : ValidatorGroup.ValidatorType.SUBMIT;
        ValidatorUtil.validator(validatorType, purchaseContractDto);
        if (operate.equals(ConstantUtil.OPERATE_TYPE_SUBMIT)) {
            if (!purchaseContractDto.getTemplateType()) {
                if (purchaseContractDto.getPurchaseContractFile() == null) {
                    throw new ServiceException("请上传采购合同附件", HttpStatus.BAD_REQUEST);
                }
                if (StrUtil.isEmpty(purchaseContractDto.getContractNo())) {
                    throw new ServiceException("请填写采购合同编号", HttpStatus.BAD_REQUEST);
                }
                if (purchaseContractDto.getSignDate() == null) {
                    throw new ServiceException("请填写采购合同签署时间", HttpStatus.BAD_REQUEST);
                }
                if (StrUtil.isEmpty(purchaseContractDto.getContractNo())) {
                    throw new ServiceException("请填写采购合同编号", HttpStatus.BAD_REQUEST);
                }
                if (purchaseContractBaseService.lambdaQuery()
                        .eq(PurchaseContract::getContractNo, purchaseContractDto.getContractNo())
                        .eq(PurchaseContract::getCustomerUserId, enterprise.getCustomerId())
                        .ne(Objects.nonNull(purchaseContractDto.getId()), PurchaseContract::getId,
                                purchaseContractDto.getId())
                        .exists()) {
                    throw new ServiceException("采购合同编号已存在", HttpStatus.BAD_REQUEST);
                }
            }
            if (!DictConstants.EXPORT_TYPE_PROXY.equals(enterprise.getExportType())
                    || !DictConstants.DISTRICT_CN_MAINLAND.equals(enterprise.getProxyDistrictCode())) {
                for (PurchaseCommodityDto purchaseCommodityDto : purchaseContractDto.getCommodityList()) {
                    if (purchaseCommodityDto.getPriceUnit() == null
                            || purchaseCommodityDto.getPriceUnit().compareTo(BigDecimal.ZERO) < 1) {
                        throw new ServiceException("请填写采购价格", HttpStatus.BAD_REQUEST);
                    }
                }
            }
            if (StrUtil.isEmpty(purchaseContractDto.getContractTerms().getAccountName())) {
                throw new ServiceException("请填写账户名称", HttpStatus.BAD_REQUEST);
            }
            if (StrUtil.isEmpty(purchaseContractDto.getContractTerms().getAccountNumber())) {
                throw new ServiceException("请填写银行账号", HttpStatus.BAD_REQUEST);
            }
            if (StrUtil.isEmpty(purchaseContractDto.getContractTerms().getOpeningBank())) {
                throw new ServiceException("请填写开户行", HttpStatus.BAD_REQUEST);
            }
        }
        if (!DictConstants.EXPORT_TYPE_PROXY.equals(enterprise.getExportType())) {
            if (purchaseContractDto.getVendorEntityNo() == null) {
                throw new ServiceException("请选择供应商", HttpStatus.BAD_REQUEST);
            }
        }
    }

    /**
     * 构建采购合同实体
     * 
     * @param operate
     * @param purchaseContractDto
     * @param loginUserInfo
     * @return
     */
    private PurchaseContract buildPurchaseContract(String operate, PurchaseContractDetailDto purchaseContractDto,
            Enterprise enterprise, LoginUserInfo loginUserInfo) {
        PurchaseContract purchaseContract = BeanCopyUtils.copy(purchaseContractDto, PurchaseContract.class);
        purchaseContract.setCustomerUserId(loginUserInfo.getCustomerUserId());
        Boolean draft = Boolean.TRUE;
        String status = DictConstants.PURCHASE_CONTRACT_STATUS_DRAFT;
        if (operate.equals(ConstantUtil.OPERATE_TYPE_SUBMIT)) {
            draft = Boolean.FALSE;
            if (purchaseContractDto.getTemplateType()) {
                status = DictConstants.PURCHASE_CONTRACT_STATUS_SUBMIT;
            } else {
                status = DictConstants.PURCHASE_CONTRACT_STATUS_DONE;
                BusinessRelateFile businessRelateFile = new BusinessRelateFile();
                businessRelateFile.setFileId(purchaseContractDto.getPurchaseContractFile().getId());
                businessRelateFile.setBelongId(purchaseContract.getId());
                businessRelateFile.setBelongType(ConstantUtil.PURCHASE_CONTRACT);
                businessRelateFile.setFileType(FileTypeEnum.PURCHASE_CONTRACT.getCode());
                businessRelateFileBaseService.addBusinessRelateFiles(Collections.singletonList(businessRelateFile));
            }
            purchaseContract.setGmtSubmit(new Date());
        }
        purchaseContract.setDraft(draft);
        purchaseContract.setStatus(status);
        purchaseContract.setUpdateBy(loginUserInfo.getCustomerUser().getNickname());
        if (!DictConstants.EXPORT_TYPE_PROXY.equals(enterprise.getExportType())
                || !DictConstants.DISTRICT_CN_MAINLAND.equals(enterprise.getProxyDistrictCode())) {
            // 自营出口或者非大陆贸易平台代理，人工录入采购单价，这里重新计算下商品金额
            purchaseContractDto.getCommodityList().forEach(purchaseCommodityDto -> purchaseCommodityDto.setAmount(
                    purchaseCommodityDto.getPriceUnit().multiply(purchaseCommodityDto.getNumber())));
            // 含税金额 = 采购商品金额 * (1 + 增值税率)
            purchaseContractDto.getCommodityList()
                    .forEach(purchaseCommodityDto -> purchaseCommodityDto.setAmount(purchaseCommodityDto.getAmount()
                            .multiply(BigDecimal.ONE.add(new BigDecimal(purchaseCommodityDto.getAddedTaxRate())))));
            // 合同金额 = 采购商品金额之和
            BigDecimal contractAmount = purchaseContractDto.getCommodityList().stream()
                    .map(PurchaseCommodityDto::getTotalAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            purchaseContract.setContractAmount(contractAmount);
            purchaseContractDto.setContractAmount(contractAmount);
        }
        return purchaseContract;
    }

    /**
     * 构建采购合同商品信息
     * 
     * @param commodityList
     * @return
     */
    private List<PurchaseCommodity> buildPurchaseCommodities(List<PurchaseCommodityDto> commodityList) {
        return commodityList.stream().map(c -> BeanCopyUtils.copy(c, PurchaseCommodity.class))
                .collect(Collectors.toList());
    }

    /**
     * 创建采购合同条款基础信息
     *
     * @param contractNo
     * @param purchaseContractTerms
     * @return
     */
    private ContractTerms buildContractTerms(String contractNo, ContractTermsDto purchaseContractTerms) {
        ContractTerms contractTerms = BeanCopyUtils.copy(purchaseContractTerms, ContractTerms.class);
        contractTerms.setContractNo(contractNo);
        return contractTerms;
    }

    /**
     * 构建采购合同付款信息 或者 附加条款信息
     * 
     * @param contractTerms
     * @param contractTermExtends
     * @return
     */
    private List<ContractTermsExtend> buildContractTermExtends(ContractTerms contractTerms,
            List<ContractTermsExtend> contractTermExtends) {
        contractTermExtends.forEach(extendsContractTerms -> {
            extendsContractTerms.setId(null);
            extendsContractTerms.setContractTermsId(contractTerms.getId());
        });
        return contractTermExtends;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean uploadPurchaseContract(PurchaseContractUploadDto uploadDto) {
        PurchaseContract purchaseContract = purchaseContractBaseService.getById(uploadDto.getContractId());
        if (purchaseContract == null) {
            throw new ServiceException("采购合同不存在（采购合同id：" + uploadDto.getContractId() + "）", HttpStatus.BAD_REQUEST);
        }
        if (!DictConstants.PURCHASE_CONTRACT_STATUS_SUBMIT.equals(purchaseContract.getStatus())) {
            throw new ServiceException("当前状态不允许上传（采购合同id：" + uploadDto.getContractId() + "）", HttpStatus.BAD_REQUEST);
        }
        TFileStorage fileStorage = fileStorageService.getFileStorageById(uploadDto.getFileId());
        if (fileStorage == null) {
            throw new ServiceException("文件不存在（文件id：" + uploadDto.getFileId() + "）", HttpStatus.BAD_REQUEST);
        }
        BusinessRelateFile businessRelateFile = new BusinessRelateFile();
        businessRelateFile.setFileId(uploadDto.getFileId());
        businessRelateFile.setBelongId(purchaseContract.getId());
        businessRelateFile.setBelongType(ConstantUtil.PURCHASE_CONTRACT);
        businessRelateFile.setFileType(FileTypeEnum.PURCHASE_CONTRACT.getCode());
        businessRelateFileBaseService.addBusinessRelateFiles(Collections.singletonList(businessRelateFile));
        // 更新合同状态为“已完成”
        purchaseContractBaseService.lambdaUpdate()
                .set(PurchaseContract::getStatus, DictConstants.PURCHASE_CONTRACT_STATUS_DONE)
                .set(PurchaseContract::getSignDate, uploadDto.getSignDate())
                .eq(PurchaseContract::getId, purchaseContract.getId()).update();
        purchaseOrderService.handleOrder(uploadDto.getContractId());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean esignPurchaseContract(Long purchaseContractId) {
        PurchaseContractDetailDto purchaseContractDetailDto = this.findPurchaseContractDetailById(purchaseContractId);
        if (purchaseContractDetailDto == null) {
            throw new ServiceException("采购合同不存在（采购合同id：" + purchaseContractId + "）", HttpStatus.BAD_REQUEST);
        }
        if (!purchaseContractDetailDto.getTemplateType()) {
            throw new ServiceException("当前采购合同非标准模板合同，不支持电子签章！", HttpStatus.BAD_REQUEST);
        }
        Enterprise enterprise = enterpriseBaseService
                .getEnterpriseByCustomerId(purchaseContractDetailDto.getCustomerUserId());
        ContractSignInput signInput = new ContractSignInput();
        signInput.setBizScene("跨境通-采购合同");
        signInput.setBizType(ContractConstant.SIGN_BIZ_TYPE_PURCHASE_CONTRACT);
        List<ContractSignInfo> signeInfoList = new ArrayList<>();
        if (purchaseContractDetailDto.getPlatformCommitmentLetter() != null) {
            EnterpriseRelatedPerson legalPerson = enterpriseRelatedPersonBaseService
                    .getLegalByChangeRecordId(enterprise.getChangeRecordId());
            // 签署平台承诺函
            Long fileId = purchaseContractDetailDto.getPlatformCommitmentLetter().getId();
            ContractSignInfo contractSignInfo = new ContractSignInfo();
            contractSignInfo.setFileId(fileId);
            contractSignInfo.setFileType(FileTypeEnum.PLATFORM_COMMITMENT_LETTER.getCode());
            ContractSigner signer = new ContractSigner();
            signer.setSigner(legalPerson.getName());
            signer.setSignerIdNo(legalPerson.getPersonalCertNo());
            signer.setSignerIdType(DictConstants.PERSONAL_CERT_TYPE_CN_IDCARD.equals(legalPerson.getPersonalCertType())
                    ? ESignConstant.CRED_PSN_CH_IDCARD
                    : ESignConstant.CRED_PSN_PASSPORT);
            signer.setMobile(legalPerson.getMobile());
            contractSignInfo.setSingleSigner(signer);
            List<ContractSeal> sealInfoList = new ArrayList<>();
            ContractSeal companySeal = new ContractSeal();
            companySeal.setKeyword(ESignConstant.KEYWORD_COMPANY);
            companySeal.setSealIdType(ESignConstant.CRED_ORG_USCC);
            companySeal.setSealName(enterprise.getName());
            companySeal.setSealIdNo(enterprise.getCertNo());
            companySeal.setWithTime(true);
            companySeal.setSigner(signer);
            sealInfoList.add(companySeal);
            contractSignInfo.setSealInfoList(sealInfoList);
            signeInfoList.add(contractSignInfo);
            signInput.setSigneInfoList(signeInfoList);
        }
        if (purchaseContractDetailDto.getPurchaseContractFile() != null) {
            // 签署采购合同
            Long fileId = purchaseContractDetailDto.getPurchaseContractFile().getId();
            ContractSignInfo contractSignInfo = new ContractSignInfo();
            contractSignInfo.setFileId(fileId);
            contractSignInfo.setFileType(FileTypeEnum.PURCHASE_CONTRACT.getCode());
            contractSignInfo.setSealInfoList(new ArrayList<>());
            // 买方（甲方）签署
            SignPartyInfo buyerInfo = getBuyerInfo(enterprise, purchaseContractDetailDto.getAgencyCertNo(), null);
            List<ContractSeal> sealInfoList = getContractSeals(buyerInfo, ESignConstant.KEYWORD_PARTY_A,
                    ESignConstant.KEYWORD_PARTY_3);
            contractSignInfo.getSealInfoList().addAll(sealInfoList);
            // 卖方（乙方）签署
            SignPartyInfo sellerInfo = getSellerInfo(enterprise, purchaseContractDetailDto.getVendorEntityNo(), null);
            sealInfoList = getContractSeals(sellerInfo, ESignConstant.KEYWORD_PARTY_B, ESignConstant.KEYWORD_PARTY_4);
            contractSignInfo.getSealInfoList().addAll(sealInfoList);
            signeInfoList.add(contractSignInfo);
            signInput.setSigneInfoList(signeInfoList);
        }
        ContractSignOutput contractSignOutput = contractService.signContract(signInput);
        if (contractSignOutput == null || CollUtil.isEmpty(contractSignOutput.getItems())) {
            throw new ValidatorException(HttpStatus.ERROR, "授权书签署处理失败！");
        }
        List<ContractFile> contractFileList = contractSignOutput.getItems().stream().map(item -> {
            ContractFile contractFile = new ContractFile();
            contractFile.setOperatorName("C端用户:" + purchaseContractDetailDto.getCustomerUserId());
            contractFile.setCustomerUserId(purchaseContractDetailDto.getCustomerUserId());
            contractFile.setContractNo(purchaseContractDetailDto.getContractNo());
            contractFile.setSignFileType(item.getFileType());
            contractFile.setSignFileId(item.getThirdFileId());
            contractFile.setUnsignFileStorageId(item.getFileId());
            contractFile.setSignFlowId(contractSignOutput.getFlowId());
            return contractFile;
        }).collect(Collectors.toList());
        contractFileService.saveBatch(contractFileList);
        // 更新采购合同状态:签署中
        purchaseContractBaseService.lambdaUpdate().eq(PurchaseContract::getId, purchaseContractDetailDto.getId())
                .set(PurchaseContract::getStatus, DictConstants.PURCHASE_CONTRACT_STATUS_SIGNING).update();
        return true;
    }

    /**
     * 获取合同印章及签署人信息
     * 
     * @param signPartyInfo
     * @param companySignKeyword
     * @param personalSignKeyword
     * @return
     */
    private List<ContractSeal> getContractSeals(SignPartyInfo signPartyInfo, String companySignKeyword,
            String personalSignKeyword) {
        ContractSigner signer = new ContractSigner();
        signer.setSigner(signPartyInfo.getLegalPersonName());
        signer.setSignerIdNo(signPartyInfo.getLegalPersonCertNo());
        signer.setSignerIdType(ESignConstant.CRED_PSN_CH_IDCARD);
        signer.setMobile(signPartyInfo.getLegalPersonPhone());
        List<ContractSeal> sealInfoList = new ArrayList<>();
        ContractSeal companySeal = new ContractSeal();
        companySeal.setSigner(signer);
        companySeal.setKeyword(companySignKeyword);
        companySeal.setSealIdType(ESignConstant.CRED_ORG_USCC);
        companySeal.setSealName(signPartyInfo.getEnterpriseName());
        companySeal.setSealIdNo(signPartyInfo.getEnterpriseCertNo());
        companySeal.setWithTime(true);
        ContractSeal legalSeal = new ContractSeal();
        legalSeal.setSigner(signer);
        legalSeal.setKeyword(personalSignKeyword);
        legalSeal.setWithTime(true);
        sealInfoList.add(companySeal);
        sealInfoList.add(legalSeal);
        return sealInfoList;
    }

    /**
     * 电子签署回调处理
     * 
     * @param bizData
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void process(SignCallback2Biz bizData) {
        String status;
        if (bizData.getSignStatus().equals(ContractConstant.CONTRACT_SIGN_STATUS_UNSIGNED)) {
            return;
        } else if (ContractConstant.CONTRACT_SIGN_STATUS_EXPIRED.equals(bizData.getSignStatus())
                || ContractConstant.CONTRACT_SIGN_STATUS_REJECTED.equals(bizData.getSignStatus())) {
                    status = DictConstants.PURCHASE_CONTRACT_STATUS_SIGNED_FAILED;
                } else
            if (bizData.getSignStatus().equals(ContractConstant.CONTRACT_SIGN_STATUS_SIGNED)) {
                status = DictConstants.PURCHASE_CONTRACT_STATUS_DONE;
            } else {
                throw new ServiceException("未知的签署状态：" + bizData.getSignStatus(), HttpStatus.BAD_REQUEST);
            }
        List<ContractFile> list = contractFileService.selectBySignFlowId(bizData.getSignFlowId());
        String purchaseContractNo = list.get(0).getContractNo();
        Long customerUserId = list.get(0).getCustomerUserId();
        PurchaseContract purchaseContract = purchaseContractBaseService.lambdaQuery()
                .eq(PurchaseContract::getContractNo, purchaseContractNo)
                .eq(PurchaseContract::getCustomerUserId, customerUserId).one();
        if (purchaseContract == null) {
            throw new ServiceException("未找到采购合同信息(采购合同编号：" + purchaseContractNo + ")", HttpStatus.BAD_REQUEST);
        }
        Long purchaseContractId = purchaseContract.getId();
        Map<Long, ContractFile> contractFileMap = list.stream()
                .collect(Collectors.toMap(ContractFile::getUnsignFileStorageId, Function.identity(), (v1, v2) -> v1));
        List<BusinessRelateFile> businessRelateFiles = new ArrayList<>();
        List<ContractFile> updateContractFileList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(bizData.getSignedFiles())) {
            for (SignCallback2Biz.SignedFile2Biz signedFile2Biz : bizData.getSignedFiles()) {
                ContractFile contractFile = contractFileMap.get(signedFile2Biz.getRawFileId());
                if (contractFile == null) {
                    continue;
                }
                BusinessRelateFile businessRelateFile = new BusinessRelateFile();
                businessRelateFile.setBelongId(purchaseContractId);
                businessRelateFile.setBelongType(ConstantUtil.PURCHASE_CONTRACT);
                businessRelateFile.setFileId(signedFile2Biz.getFileId());
                businessRelateFile.setFileType(contractFile.getSignFileType());
                businessRelateFiles.add(businessRelateFile);
                contractFile.setSignedFileStorageId(signedFile2Biz.getFileId());
                updateContractFileList.add(contractFile);
            }
        }
        if (CollUtil.isNotEmpty(updateContractFileList)) {
            contractFileService.updateBatchById(updateContractFileList);
        }
        if (CollUtil.isNotEmpty(businessRelateFiles)) {
            businessRelateFileBaseService.addBusinessRelateFiles(businessRelateFiles);
        }
        if (status.equals(DictConstants.PURCHASE_CONTRACT_STATUS_DONE)) {
            purchaseOrderService.handleOrder(purchaseContract.getId());
        }
        // 更新签署状态
        purchaseContractBaseService.lambdaUpdate().eq(PurchaseContract::getId, purchaseContractId)
                .set(PurchaseContract::getStatus, status)
                .set(status.equals(DictConstants.PURCHASE_CONTRACT_STATUS_DONE), PurchaseContract::getSignDate,
                        DateUtils.parseLocalDateTime2Date(bizData.getSignTime()))
                .update();
    }
}
