package com.fjhx.sale.service.contract.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
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.fjhx.account.controller.utils.DateUtils;
import com.fjhx.account.entity.account.po.AccountManagement;
import com.fjhx.account.entity.account.po.AccountRequestFundsDetail;
import com.fjhx.account.entity.account.vo.AccountRequestFundsDetailVo;
import com.fjhx.account.service.account.AccountManagementService;
import com.fjhx.account.service.account.AccountRequestFundsDetailService;
import com.fjhx.area.service.SetCustomizeAreaId;
import com.fjhx.area.utils.CustomizeAreaUtil;
import com.fjhx.common.constant.SourceConstant;
import com.fjhx.common.entity.corporation.po.Corporation;
import com.fjhx.common.entity.currency.po.CurrencyRate;
import com.fjhx.common.entity.documentary.bo.DocumentaryData;
import com.fjhx.common.enums.FlowStatusEnum;
import com.fjhx.common.service.corporation.CorporationService;
import com.fjhx.common.service.currency.CurrencyRateService;
import com.fjhx.common.service.documentary.GetDocumentaryBusinessTemplate;
import com.fjhx.customer.entity.customer.dto.CustomerDto;
import com.fjhx.customer.entity.customer.po.Customer;
import com.fjhx.customer.service.customer.CustomerService;
import com.fjhx.sale.entity.claim.po.Claim;
import com.fjhx.sale.entity.claim.po.ClaimContract;
import com.fjhx.sale.entity.contract.bo.ContractCurrencyRate;
import com.fjhx.sale.entity.purchase.po.EhsdPurchaseProduct;
import com.fjhx.sale.entity.purchase.vo.EhsdPurchaseProductVo;
import com.fjhx.sale.entity.serviceContract.po.ServiceContract;
import com.fjhx.sale.service.claim.ClaimContractService;
import com.fjhx.sale.service.purchase.EhsdPurchaseProductService;
import com.fjhx.file.entity.FileInfoVo;
import com.fjhx.file.utils.ObsFileUtil;
import com.fjhx.item.entity.product.dto.ProductInfoSelectDto;
import com.fjhx.item.service.product.ProductInfoService;
import com.fjhx.purchase.entity.purchase.vo.PurchaseDetailVo;
import com.fjhx.purchase.service.purchase.PurchaseDetailService;
import com.fjhx.sale.entity.contract.bo.ContractDocumentaryBo;
import com.fjhx.sale.entity.contract.dto.ContractDto;
import com.fjhx.sale.entity.contract.dto.ContractSelectDto;
import com.fjhx.sale.entity.contract.po.Contract;
import com.fjhx.sale.entity.contract.po.ContractProduct;
import com.fjhx.sale.entity.contract.vo.ContractBudgetVo;
import com.fjhx.sale.entity.contract.vo.ContractDocumentaryVo;
import com.fjhx.sale.entity.contract.vo.ContractPdfInfoVo;
import com.fjhx.sale.entity.contract.vo.ContractVo;
import com.fjhx.sale.entity.sale.vo.SaleQuotationVo;
import com.fjhx.sale.mapper.contract.ContractMapper;
import com.fjhx.sale.service.contract.ContractProductService;
import com.fjhx.sale.service.contract.ContractService;
import com.ruoyi.common.core.domain.BaseSelectDto;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.wrapper.IWrapper;
import com.ruoyi.common.utils.wrapper.SqlField;
import com.ruoyi.framework.config.ThreadPoolConfig;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;


/**
 * <p>
 * 外销合同表 服务实现类
 * </p>
 *
 * @author
 * @since 2023-04-17
 */
@Service
public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract>
        implements ContractService, GetDocumentaryBusinessTemplate {

    private static final SimpleDateFormat sdf = new SimpleDateFormat("dd/MMM/yyyy", Locale.ENGLISH);

    @Qualifier(ThreadPoolConfig.threadPoolTaskExecutor)
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private CustomerService customerService;

    @Autowired
    private CorporationService corporationService;

    @Autowired
    private ContractProductService contractProductService;

    @Autowired
    private ProductInfoService productInfoService;

    @Autowired
    private AccountManagementService accountManagementService;

    @Autowired
    private EhsdPurchaseProductService ehsdPurchaseProductService;

    @Autowired
    private PurchaseDetailService purchaseDetailService;

    @Autowired
    private CurrencyRateService currencyRateService;

    @Autowired
    private ClaimContractService claimContractService;

    @Autowired
    private AccountRequestFundsDetailService accountRequestFundsDetailService;

    /**
     * 分页
     *
     * @param dto
     * @return
     */
    @Override
    public Page<ContractVo> getPage(ContractSelectDto dto) {
        IWrapper<Contract> wrapper = getWrapper();
        wrapper.orderByDesc("t1", Contract::getCreateTime);
        wrapper.between("t1", Contract::getStatus, FlowStatusEnum.DRAFT.getKey(), FlowStatusEnum.CANCELLATION.getKey() - 1);
        if (StringUtils.isNotEmpty(dto.getStatus())) {
            wrapper.eq("t1", Contract::getStatus, dto.getStatus());
        }
        if (StringUtils.isNotEmpty(dto.getSellCorporationId())) {
            wrapper.eq("t1", Contract::getSellCorporationId, dto.getSellCorporationId());
        }
        if (StringUtils.isNotEmpty(dto.getRefundStatusNew())) {
            wrapper.eq("t1.refundStatusNew", dto.getRefundStatusNew());
        }
        if (StringUtils.isNotEmpty(dto.getKeyword())) {
            wrapper.keyword(dto.getKeyword(), new SqlField("t1", Contract::getCode));
        }
        Page<ContractVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);
        List<ContractVo> list = page.getRecords();
        if(CollectionUtils.isNotEmpty(list)){
            List<Long> customerIds = list.stream().map(Contract::getBuyCorporationId).collect(Collectors.toList());
            List<Customer> customerList = customerService.list(Wrappers.<Customer>query().lambda().in(Customer::getId, customerIds));
            Map<Long, List<Customer>> cusMap = customerList.stream().distinct().collect(Collectors.groupingBy(Customer::getId));

            List<Long> ids = list.stream().map(ContractVo::getId).collect(Collectors.toList());
            //获取交接单附件
            Map<Long, List<FileInfoVo>> fileMap = ObsFileUtil.getFileMap(ids, 1);

            //获取包装附件
            Map<Long, List<FileInfoVo>> packageFileMap = ObsFileUtil.getFileMap(ids, 2);
            for (ContractVo p : list) {
                if (MapUtils.isNotEmpty(cusMap)) {//客户
                    List<Customer> customers = cusMap.getOrDefault(p.getBuyCorporationId(), null);
                    p.setBuyCorporationName(customers == null ? null : customers.get(0).getName());
                    //赋值客户标签
                    p.setTag(customers == null ? null : customers.get(0).getTag());
                }

                //赋值交接单附件
                if (MapUtils.isNotEmpty(fileMap)){
                    List<FileInfoVo> fileInfoVos = fileMap.get(p.getId());
                    p.setFileInfoVos(fileInfoVos);
                }

                //赋值包装附件信息
                if (MapUtils.isNotEmpty(packageFileMap)){
                    List<FileInfoVo>  packageFileInfoVOList= packageFileMap.get(p.getId());
                    p.setPackageFileInfoVOList(packageFileInfoVOList);
                }

            }
        }
        return page;
    }

    /**
     * 利润预算
     * @param dto
     * @return
     */
    @Override
    public Page<ContractBudgetVo> getProfitBudgetPage(ContractSelectDto dto) {
        IWrapper<Contract> wrapper = getWrapper();
        wrapper.orderByDesc("t1", Contract::getCreateTime);
        wrapper.between("t1", Contract::getStatus, FlowStatusEnum.PASS.getKey(), FlowStatusEnum.CANCELLATION.getKey() - 1);
        if(StringUtils.isNotEmpty(dto.getCustomerId())){
            wrapper.eq("t1",Contract::getBuyCorporationId,dto.getCustomerId());
        }
        if(StringUtils.isNotEmpty(dto.getUserId())){
            wrapper.eq("t1",Contract::getCreateUser,dto.getUserId());
        }
        if(StringUtils.isNotEmpty(dto.getKeyword())){
            wrapper.keyword(dto.getKeyword(),new SqlField("t1.code"));
        }
        Page<ContractBudgetVo> page = this.baseMapper.getProfitBudgetPage(dto.getPage(), wrapper);
        List<ContractBudgetVo> list = page.getRecords();
        if(CollectionUtils.isNotEmpty(list)){
            // 赋值客户名称
            customerService.attributeAssign(list, Contract::getBuyCorporationId, (item, customer) -> {
                item.setCustomerName(customer.getName());
            });
            //取出EHSD采购所有金额和货币-通过合同ID分组
            List<Long> contractIds = list.stream().map(ContractBudgetVo::getContractId).collect(Collectors.toList());
            List<EhsdPurchaseProductVo> ehsdAmountList = ehsdPurchaseProductService.getGroupSumAmount(contractIds);
            //取出采购所有金额和货币-通过合同ID分组
            Map<Long,String> ehsdAmountMap = ehsdAmountList.stream().collect(Collectors.toMap(EhsdPurchaseProductVo::getContractId,EhsdPurchaseProductVo::getCurrencyAmount));
            List<PurchaseDetailVo> otherAmountList = purchaseDetailService.getSumCountInDataResourceIds(contractIds);
            Map<Long,String> otherAmountMap = otherAmountList.stream().collect(Collectors.toMap(PurchaseDetailVo::getDataResourceId,PurchaseDetailVo::getSumAmountCurrency));
            //取出默认汇率
            List<CurrencyRate> currencyRateList = currencyRateService.getList();
            Map<String,BigDecimal> currencyRateMap = currencyRateList.stream().collect(Collectors.toMap(CurrencyRate::getType,CurrencyRate::getRate));
            for(ContractBudgetVo v : list){
                if(StringUtils.isNotEmpty(v.getCurrencyRateJson())){//如果此条合同有汇率了
                    List<ContractCurrencyRate> contractCurrencyRates = JSON.parseArray(v.getCurrencyRateJson(), ContractCurrencyRate.class);
                    Map<String,BigDecimal> map = contractCurrencyRates.stream().collect(Collectors.toMap(ContractCurrencyRate::getType,ContractCurrencyRate::getRate));
                    v.setRefundableAmount(BigDecimal.ZERO);//暂时先设置退税金额为0
                    if(MapUtils.isNotEmpty(ehsdAmountMap)){    //计算EHSD租户应付货款
                        String concatAmountCurrency = ehsdAmountMap.getOrDefault(v.getContractId(),null);
                        if(StringUtils.isNotEmpty(concatAmountCurrency)){
                            BigDecimal amount = new BigDecimal(concatAmountCurrency.split("-")[0]);
                            String currency = concatAmountCurrency.split("-")[1];
                            BigDecimal rate = map.getOrDefault(currency,BigDecimal.ONE);
                            v.setEhsdSumAmount(amount.multiply(rate));
                        }else{
                            v.setEhsdSumAmount(BigDecimal.ZERO);
                        }
                    }
                    //计算收入总计=合同金额(转人民币)+应退税金额(转人民币)
                    v.setIncomeAmount(v.getAmount().multiply(new BigDecimal(map.getOrDefault(v.getCurrency(), BigDecimal.ONE).toString())).add(v.getRefundableAmount()));
                    //计算支出总计 除合同金额(转人民币)+应退税金额(转人民币) 其他金额相加
                    v.setExpenditureAmount(v.getTrailerFee()==null?BigDecimal.ZERO:v.getTrailerFee().multiply(new BigDecimal(map.getOrDefault(v.getTrailerFeeCurrency(),BigDecimal.ONE).toString())).add
                            (v.getCustomsFee()==null?BigDecimal.ZERO:v.getCustomsFee().multiply(new BigDecimal(map.getOrDefault(v.getCustomsFeeCurrency(),BigDecimal.ONE).toString()))).add
                            (v.getAgencyFee()==null?BigDecimal.ZERO:v.getAgencyFee().multiply(new BigDecimal(map.getOrDefault(v.getAgencyFeeCurrency(),BigDecimal.ONE).toString()))).add
                            (v.getPortMixedFee()==null?BigDecimal.ZERO:v.getPortMixedFee().multiply(new BigDecimal(map.getOrDefault(v.getPortMixedFeeCurrency(),BigDecimal.ONE).toString()))).add
                            (v.getInspectionRedPack()==null?BigDecimal.ZERO:v.getInspectionRedPack().multiply(new BigDecimal(map.getOrDefault(v.getInspectionRedPackCurrency(),BigDecimal.ONE).toString()))).add
                            (v.getCommission()==null?BigDecimal.ZERO:v.getCommission().multiply(new BigDecimal(map.getOrDefault(v.getCommissionCurrency(),BigDecimal.ONE).toString()))).add
                            (v.getOther()==null?BigDecimal.ZERO:v.getOther().multiply(new BigDecimal(map.getOrDefault(v.getOtherCurrency(),BigDecimal.ONE).toString()))).add
                            (v.getEhsdSumAmount()==null?BigDecimal.ZERO:v.getEhsdSumAmount()).add
                            (v.getOtherSumAmount()==null?BigDecimal.ZERO:v.getOtherSumAmount()));
                }else{//没有汇率取默认汇率
                    v.setRefundableAmount(BigDecimal.ZERO);//暂时先设置退税金额为0
                    if(MapUtils.isNotEmpty(ehsdAmountMap)){    //计算EHSD租户应付货款
                        String concatAmountCurrency = ehsdAmountMap.getOrDefault(v.getContractId(),null);
                        if(StringUtils.isNotEmpty(concatAmountCurrency)){
                            BigDecimal amount = new BigDecimal(concatAmountCurrency.split("-")[0]);
                            String currency = concatAmountCurrency.split("-")[1];
                            BigDecimal rate = currencyRateMap.getOrDefault(currency,BigDecimal.ONE);
                            v.setEhsdSumAmount(amount.multiply(rate));
                        }else{
                            v.setEhsdSumAmount(BigDecimal.ZERO);
                        }
                    }
                    //计算收入总计=合同金额(转人民币)+应退税金额(转人民币)
                    v.setIncomeAmount(v.getAmount().multiply(currencyRateMap.getOrDefault(v.getContractId(),new BigDecimal("1"))).add(v.getRefundableAmount()));
                    //计算支出总计 除合同金额(转人民币)+应退税金额(转人民币) 其他金额相加
                    v.setExpenditureAmount(v.getTrailerFee()==null?BigDecimal.ZERO:v.getTrailerFee().multiply(new BigDecimal(currencyRateMap.getOrDefault(v.getTrailerFeeCurrency(),BigDecimal.ONE).toString())).add
                            (v.getCustomsFee()==null?BigDecimal.ZERO:v.getCustomsFee().multiply(new BigDecimal(currencyRateMap.getOrDefault(v.getCustomsFeeCurrency(),BigDecimal.ONE).toString()))).add
                            (v.getAgencyFee()==null?BigDecimal.ZERO:v.getAgencyFee().multiply(new BigDecimal(currencyRateMap.getOrDefault(v.getAgencyFeeCurrency(),BigDecimal.ONE).toString()))).add
                            (v.getPortMixedFee()==null?BigDecimal.ZERO:v.getPortMixedFee().multiply(new BigDecimal(currencyRateMap.getOrDefault(v.getPortMixedFeeCurrency(),BigDecimal.ONE).toString()))).add
                            (v.getInspectionRedPack()==null?BigDecimal.ZERO:v.getInspectionRedPack().multiply(new BigDecimal(currencyRateMap.getOrDefault(v.getInspectionRedPackCurrency(),BigDecimal.ONE).toString()))).add
                            (v.getCommission()==null?BigDecimal.ZERO:v.getCommission().multiply(new BigDecimal(currencyRateMap.getOrDefault(v.getCommissionCurrency(),BigDecimal.ONE).toString()))).add
                            (v.getOther()==null?BigDecimal.ZERO:v.getOther().multiply(new BigDecimal(currencyRateMap.getOrDefault(v.getOtherCurrency(),BigDecimal.ONE).toString()))).add
                            (v.getEhsdSumAmount()==null?BigDecimal.ZERO:v.getEhsdSumAmount()).add
                            (v.getOtherSumAmount()==null?BigDecimal.ZERO:v.getOtherSumAmount()));
                }
                //计算毛利 收入-支出
                v.setGross(v.getIncomeAmount().subtract(v.getExpenditureAmount()));
                //计算毛利率 毛利/收入
                v.setGrossRate(v.getGross().divide(v.getIncomeAmount(), RoundingMode.CEILING));
            }
        }
        return page;
    }

    /**
     * 利润结算表分页
     * @param dto
     * @return
     */
    @Override
    public Page<ContractBudgetVo> getProfitClearingPage(ContractSelectDto dto) {
        IWrapper<Contract> wrapper = getWrapper();
        wrapper.orderByDesc("t1", Contract::getCreateTime);
        wrapper.between("t1", Contract::getStatus, FlowStatusEnum.PASS.getKey(), FlowStatusEnum.CANCELLATION.getKey() - 1);
        if(StringUtils.isNotEmpty(dto.getCustomerId())){
            wrapper.eq("t1",Contract::getBuyCorporationId,dto.getCustomerId());
        }
        if(StringUtils.isNotEmpty(dto.getUserId())){
            wrapper.eq("t1",Contract::getCreateUser,dto.getUserId());
        }
        if(StringUtils.isNotEmpty(dto.getKeyword())){
            wrapper.keyword(dto.getKeyword(),new SqlField("t1.code"));
        }
        Page<ContractBudgetVo> page = this.baseMapper.getProfitClearingPage(dto.getPage(), wrapper);
        List<ContractBudgetVo> list = page.getRecords();
        //取出默认汇率
        List<CurrencyRate> defaultCurrencyRateList = currencyRateService.getList();
        Map<String,BigDecimal> defaultCurrencyRateMap = defaultCurrencyRateList.stream().collect(Collectors.toMap(CurrencyRate::getType,CurrencyRate::getRate));
        for(ContractBudgetVo v : list){
            v.setRefundableAmount(BigDecimal.ZERO);//暂时先设置退税金额为0
            v.setOtherIncomeAmount(BigDecimal.ZERO);//暂时先设置其他收入为0
            v.setAccountPaid(BigDecimal.ZERO);//暂时先设置已付货款为0
            // 赋值客户名称
            customerService.attributeAssign(list, Contract::getBuyCorporationId, (item, customer) -> {
                item.setCustomerName(customer.getName());
            });
            if(StringUtils.isNotEmpty(v.getCurrencyRateJson())) {//如果此条合同有汇率了
                //取出汇率
                List<CurrencyRate> assignCurrencyRatesList = JSON.parseArray(v.getCurrencyRateJson(), CurrencyRate.class);
                Map<String,BigDecimal> assignCurrencyRatesMap = assignCurrencyRatesList.stream().collect(Collectors.toMap(CurrencyRate::getType,CurrencyRate::getRate));
                v.setRmbContractAmount(v.getAmount().multiply(assignCurrencyRatesMap.getOrDefault(v.getCurrency(),BigDecimal.ONE)));//计算汇算人民币
                //到账金额
                v.setSumClaimMoney(this.getSumClaimMoney(v,assignCurrencyRatesMap));
                //采购合同总金额
                v.setSumPurchaseContractMoney(this.getSumPurchaseContractMoney(v,assignCurrencyRatesMap));
                //支出费用
                this.getGroupTypeMoney(v,assignCurrencyRatesMap);
            }else{//没有取默认的汇率
                v.setRmbContractAmount(v.getAmount().multiply(defaultCurrencyRateMap.getOrDefault(v.getCurrency(),BigDecimal.ONE)));//计算汇算人民币
                //到账金额
                v.setSumClaimMoney(this.getSumClaimMoney(v,defaultCurrencyRateMap));
                //采购合同总金额
                v.setSumPurchaseContractMoney(this.getSumPurchaseContractMoney(v,defaultCurrencyRateMap));
                //支出费用
                this.getGroupTypeMoney(v,defaultCurrencyRateMap);
            }
            //计算收入总计=合同金额(转人民币)+应退税金额(转人民币)+其他收入(转人民币)
            v.setIncomeAmount(v.getRmbContractAmount()==null?BigDecimal.ZERO:v.getRmbContractAmount().add(v.getRefundableAmount()).add(v.getOtherIncomeAmount()));
            //计算支出总计 除合同金额(转人民币)+应退税金额(转人民币)+其他收入(转人民币) 其他金额相加
            v.setExpenditureAmount(v.getTrailerFee().add
                    (v.getCustomsFee()).add
                    (v.getPortMixedFee()).add
                    (v.getInspectionRedPack()).add
                    (v.getCommission()).add
                    (v.getOther()).add
                    (v.getCheckout()).add
                    (v.getInspectionCharge()).add
                    (v.getFreight()).add
                    (v.getCertificateOfOrigin()).add
                    (v.getAccountPaid()).add
                    (v.getProfitAgencyFee()));
            //计算毛利 收入-支出
            v.setGross(v.getIncomeAmount().subtract(v.getExpenditureAmount()));
            //计算毛利率 毛利/收入
            v.setGrossRate(v.getGross().divide(v.getIncomeAmount(), RoundingMode.CEILING));

        }
        return page;
    }

    @Override
    public ContractVo detail(Long id) {
        Contract Contract = this.getById(id);
        ContractVo result = BeanUtil.toBean(Contract, ContractVo.class);
        return result;
    }

    @DSTransactional
    @Override
    public void add(ContractDto contractDto) {
        setAreaId(contractDto);
        this.save(contractDto);
    }

    @DSTransactional
    @Override
    public void edit(ContractDto contractDto) {
        setAreaId(contractDto);
        this.updateById(contractDto);
    }

    @Override
    public void delete(Long id) {
        this.removeById(id);
    }

    /**
     * 根据客户ID查询未包装的订单
     *
     * @param customerId
     * @return
     */
    @Override
    public List<ContractVo> getNoPackContractByCustomerId(String customerId) {
        return baseMapper.getNoPackContractByCustomerId(customerId);
    }

    /**
     * 根据合同id集合查询合同列表
     *
     * @param ids
     * @return
     */
    @Override
    public List<Contract> getByIds(List<Long> ids) {
        List<Contract> list = this.list(Wrappers.<Contract>query().lambda().in(Contract::getId, ids));
        return list;
    }

    @Override
    public ContractPdfInfoVo getContractPdfInfo(Long id) {

        if (ObjectUtil.isEmpty(id)) {
            throw new ServiceException("销售合同id不能为空");
        }

        Contract contract = getById(id);
        if (ObjectUtil.isEmpty(contract)) {
            throw new ServiceException("没有找到销售合同");
        }

        ContractPdfInfoVo contractPdfInfoVo = new ContractPdfInfoVo();

        Integer contractType = contract.getContractType();
        if (contractType == null) {
            throw new ServiceException("销售合同类型为空");
        }

        switch (contractType) {
            // 外销合同
            case 1:
                setExportContractInfo(contractPdfInfoVo, contract);
                break;
            // 内销合同
            case 2:
                // todo 内销合同实现逻辑
                break;
            default:
                throw new ServiceException("未知销售合同类型");
        }

        return contractPdfInfoVo;
    }

    /**
     * 查询销售额（合同总金额）
     *
     * @param id (买方公司ID)
     */
    @Override
    public ContractVo getSalesTotal(Long id) {
        return baseMapper.getSalesTotal(id);
    }

    /**
     * 查询指定客户的每月合同总额
     *
     * @param dto
     */
    @Override
    public List<ContractVo> getAmount(CustomerDto dto) {

        return baseMapper.getAmount(dto);
    }

    /**
     * 查询成交单统计（合同）
     *
     * @param query
     * @return
     */
    @Override
    public List<SaleQuotationVo> contractStatistics(QueryWrapper<Object> query) {
        return baseMapper.contractStatistics(query);
    }

    /**
     * 销售趋势（数据看板-产品分析页面）
     *
     * @param productInfoDto
     */
    @Override
    public List<Map<String, Object>> saleTrend(ProductInfoSelectDto productInfoDto) {
        //存放每月的月度销售额与月度销售量的列表
        List<Map<String, Object>> list = new ArrayList<>();

        List<String> monthList = DateUtils.getMonthBetweenDate(productInfoDto.getBeginTime(), productInfoDto.getEndTime());
        //查询月度销售额与月度销售量
        QueryWrapper<ContractProduct> query = Wrappers.query();
        String beginTime = DateUtil.format(productInfoDto.getBeginTime(), "yyyy-MM");
        String endTime = DateUtil.format(productInfoDto.getEndTime(), "yyyy-MM");
        query.ge("DATE_FORMAT(create_time,'%Y-%m')", beginTime);
        query.le("DATE_FORMAT(create_time,'%Y-%m')", endTime);
        query.select("DATE_FORMAT(create_time,'%Y-%m') time,ifnull(SUM(amount),0) contractAmount," +
                "ifnull(SUM(quantity),0) contractQuantity");
        query.groupBy("time");
        List<ContractProduct> contractList = contractProductService.list(query);
        Map<String, List<ContractProduct>> contractMap = contractList.stream().collect(Collectors.groupingBy(ContractProduct::getTime));

        //给每月赋值月度销售额与月度销售量的值
        for (String month : monthList) {
            //存放每月的月度销售额与月度销售量的值
            Map<String, Object> map = new HashMap<>();
            //赋值初使值
            map.put("month", month);
            map.put("contractAmount", new BigDecimal(0));
            map.put("contractQuantity", new BigDecimal(0));

            //赋值
            List<ContractProduct> contracts = contractMap.get(month);
            if (ObjectUtil.isNotEmpty(contracts)) {
                map.put("contractAmount", contracts.get(0).getContractAmount());
                map.put("contractQuantity", contracts.get(0).getContractQuantity());
            }
            list.add(map);
        }

        return list;
    }

    /**
     * 销售统计(数据看板-销售分析页面开发)
     */
    @Override
    public Map<String, Object> salesStatistics(ContractDto dto) {
        //添加查询条件
        QueryWrapper<Contract> query = Wrappers.<Contract>query();
        selectTime(query, dto);
        query.select("sum(amount) amount");

        //查询销售额
        Contract contract = baseMapper.selectOne(query);
        query.clear();
        //查询订单数
        selectTime(query, dto);

        Long count = baseMapper.selectCount(query);

        //查询下单的客户人数
        query.clear();
        selectTime(query, dto);
        query.select("count(DISTINCT(buy_corporation_id)) count");
        Contract contract1 = baseMapper.selectOne(query);

        //存放销售统计数据
        Map<String, Object> map = new HashMap<>();
        //初始化数据
        map.put("amount", new BigDecimal(0));
        map.put("contractCount", count);
        map.put("customerCount", new BigDecimal(0));

        //赋值
        if (ObjectUtil.isNotEmpty(contract)) {
            map.put("amount", contract.getAmount());
        }

        if (ObjectUtil.isNotEmpty(contract1)) {
            map.put("customerCount", contract1.getCount());
        }
        return map;
    }

    /**
     * 国家销售统计(数据看板-销售分析页面开发)
     */
    @Override
    public List<ContractDto> countrySalesStatistics(ContractDto dto) {
        QueryWrapper<Object> query = Wrappers.query();
        query.ge("DATE_FORMAT(cc.create_time,'%Y-%m')", dto.getBeginTime());
        query.le("DATE_FORMAT(cc.create_time,'%Y-%m')", dto.getEndTime());
        query.groupBy("cc.buy_country_id");
        query.orderByDesc("amount");
        //查询销售国家统计信息
        List<ContractDto> contractDtoList = baseMapper.countrySalesStatistics(query);
        return contractDtoList;
    }

    /**
     * 客户销售统计(数据看板-销售分析页面开发)
     */
    @Override
    public List<ContractDto> customSalesStatistics(ContractDto dto) {
        QueryWrapper<Object> query = Wrappers.query();
        query.ge("DATE_FORMAT(cc.create_time,'%Y-%m')", dto.getBeginTime());
        query.le("DATE_FORMAT(cc.create_time,'%Y-%m')", dto.getEndTime());
        query.groupBy("cc.buy_corporation_id");
        query.orderByDesc("amount");
        //查询销售国家统计信息
        List<ContractDto> contractDtoList = baseMapper.customSalesStatistics(query);
        return contractDtoList;
    }

    /**
     * 业务员销售统计(数据看板-销售分析页面开发)
     */
    @Override
    public List<ContractDto> salesmanSalesStatistics(ContractDto dto) {
        QueryWrapper<Object> query = Wrappers.query();
        query.ge("DATE_FORMAT(cc.create_time,'%Y-%m')", dto.getBeginTime());
        query.le("DATE_FORMAT(cc.create_time,'%Y-%m')", dto.getEndTime());
        query.groupBy("cc.create_user");
        query.orderByDesc("amount");
        //查询销售国家统计信息
        List<ContractDto> contractDtoList = baseMapper.salesmanSalesStatistics(query);
        return contractDtoList;
    }

    /**
     * 产品销售统计(数据看板-销售分析页面开发)
     */
    @Override
    public List<ContractDto> productSalesStatistics(ContractDto dto) {
        QueryWrapper<Object> query = Wrappers.query();
        query.ge("DATE_FORMAT(cp.create_time,'%Y-%m')", dto.getBeginTime());
        query.le("DATE_FORMAT(cp.create_time,'%Y-%m')", dto.getEndTime());
        query.groupBy("cp.product_id");
        query.orderByDesc("amount");
        //查询销售国家统计信息
        List<ContractDto> contractDtoList = baseMapper.productSalesStatistics(query);
        return contractDtoList;
    }

    /**
     * 产品销售量统计(数据看板-销售分析页面开发)
     */
    @Override
    public List<ContractDto> salesVolumeStatistics(ContractDto dto) {
        QueryWrapper<Object> query = Wrappers.query();
        query.ge("DATE_FORMAT(cp.create_time,'%Y-%m')", dto.getBeginTime());
        query.le("DATE_FORMAT(cp.create_time,'%Y-%m')", dto.getEndTime());
        query.groupBy("cp.product_id");
        query.orderByDesc("quantity");
        //查询销售商品统计信息
        List<ContractDto> contractDtoList = baseMapper.salesVolumeStatistics(query);
        return contractDtoList;
    }

    /**
     * 合同交接单
     */
    @Override
    public void contractHandover(ContractDto dto) {
        ObsFileUtil.editFile(dto.getFileList(),dto.getId(),1);
        ObsFileUtil.editFile(dto.getPackageFileList(),dto.getId(),2);
    }

    /**
     * 合同销售统计（合同列表）
     */
    @Override
    public Map<String, Object> covenantStatistics(ContractDto dto) {
        Map<String, Object> map = new HashMap<>();

        QueryWrapper<Contract> query = Wrappers.query();
        query.select("count(*) count,ifnull(sum(amount),0) amount,sell_corporation_id sellCorporationId");
        query.groupBy("sell_corporation_id");
        query.eq("status",30);
        List<Contract> contractList = baseMapper.selectList(query);

        //计算合计数量
        Integer countAmount = contractList.stream().map(Contract::getCount).reduce(Integer::sum).orElse(0);
        //计算合计金额
        BigDecimal amount = contractList.stream().map(Contract::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        map.put("countAmount",countAmount);
        map.put("amount",amount);

        //赋值归属公司名称
        DynamicDataSourceContextHolder.push(SourceConstant.COMMON);
        corporationService.attributeAssign(contractList, Contract::getSellCorporationId, (item, corporation) -> {
            item.setSellCorporationName(corporation.getName());
        });
        DynamicDataSourceContextHolder.poll();

        //过滤掉卖方公司为null的数据（因为如果归属公司为null说明服务合同表的是没有数据）
        contractList = contractList.stream().filter(serviceContract -> ObjectUtil
                .isNotEmpty(serviceContract.getSellCorporationId())).collect(Collectors.toList());

        map.put("serviceContractList",contractList);
        return map;
    }


    /**
     * 赋值外销合同信息
     *
     * @param contractPdfInfoVo param
     * @param contract          合同信息
     */
    private void setExportContractInfo(ContractPdfInfoVo contractPdfInfoVo, Contract contract) {

        SecurityContext context = SecurityContextHolder.getContext();

        // 赋值卖方公司基本信息
        CompletableFuture<Void> setSellCorporationInfoFuture = CompletableFuture.runAsync(
                () -> {
                    SecurityContextHolder.setContext(context);
                    setSellCorporationInfo(contractPdfInfoVo, contract);
                }, threadPoolExecutor);

        // 赋值买方公司基本信息
        CompletableFuture<Void> setBuyCorporationFuture = CompletableFuture.runAsync(
                () -> {
                    SecurityContextHolder.setContext(context);
                    setBuyCorporation(contractPdfInfoVo, contract);
                }, threadPoolExecutor);

        // 赋值买卖方公司地址
        CompletableFuture<Void> setAreaFuture = CompletableFuture.runAsync(
                () -> {
                    SecurityContextHolder.setContext(context);
                    setArea(contractPdfInfoVo, contract);
                }, threadPoolExecutor);

        // 赋值商品列表信息
        CompletableFuture<Void> setProductListFuture = CompletableFuture.runAsync(
                () -> {
                    SecurityContextHolder.setContext(context);
                    setProductList(contractPdfInfoVo, contract);
                }, threadPoolExecutor);

        // 设置收款账号
        CompletableFuture<Void> setAccountManagementFuture = CompletableFuture.runAsync(
                () -> {
                    SecurityContextHolder.setContext(context);
                    setAccountManagement(contractPdfInfoVo, contract);
                }, threadPoolExecutor);

        // 赋值合同基本信息
        setInfo(contractPdfInfoVo, contract);

        CompletableFuture.allOf(
                setSellCorporationInfoFuture,
                setBuyCorporationFuture,
                setAreaFuture,
                setProductListFuture,
                setAccountManagementFuture
        ).join();

    }

    @Override
    public Page<? extends DocumentaryData> getDocumentaryPage(JSONObject selectData, BaseSelectDto dto, List<Long> excludeBusinessId) {

        ContractDocumentaryBo bo = selectData.toJavaObject(ContractDocumentaryBo.class);

        IWrapper<Contract> wrapper = IWrapper.getWrapper();
        wrapper.like(Contract::getCode, bo.getCode());
        wrapper.eq(Contract::getCreateUser, bo.getUserId());
        wrapper.eq(Contract::getStatus, 30);
        wrapper.notIn(Contract::getId, excludeBusinessId);
        wrapper.orderByDesc(Contract::getId);

        Page<Contract> itemPage = page(dto.getPage(), wrapper);
        Page<ContractDocumentaryVo> page = PageUtils.copyPage(itemPage, ContractDocumentaryVo.class);
        List<ContractDocumentaryVo> records = page.getRecords();

        if (records.size() == 0) {
            return page;
        }

        // 赋值客户名称
        customerService.attributeAssign(records, Contract::getBuyCorporationId, (item, customer) -> {
            item.setCustomerName(customer.getName());
        });

        return page;
    }

    /**
     * 赋值卖方公司基本信息
     */
    private void setSellCorporationInfo(ContractPdfInfoVo contractPdfInfoVo, Contract contract) {
        // 卖方公司信息
        Corporation corporation = corporationService.getById(contract.getSellCorporationId());
        if (corporation == null) {
            throw new ServiceException("卖方公司信息为空");
        }
        contractPdfInfoVo.setSellCorporationNameEn(corporation.getNameEn());
        contractPdfInfoVo.setSellContactName(contract.getSellContactName());
        contractPdfInfoVo.setSellContactNumber(contract.getSellContactNumber());
    }

    /**
     * 赋值买方公司基本信息
     */
    private void setBuyCorporation(ContractPdfInfoVo contractPdfInfoVo, Contract contract) {
        Customer customer = customerService.getById(contract.getBuyCorporationId());
        if (customer == null) {
            throw new ServiceException("买方公司信息为空");
        }
        contractPdfInfoVo.setBuyCorporationName(customer.getName());
        contractPdfInfoVo.setBuyContactName(contract.getBuyContactName());
        contractPdfInfoVo.setBuyContactNumber(contract.getBuyContactNumber());
    }

    /**
     * 赋值买卖公司地址
     */
    private void setArea(ContractPdfInfoVo contractPdfInfoVo, Contract contract) {

        List<Long> areaIdList = Arrays.asList(
                contract.getBuyCountryId(),
                contract.getBuyProvinceId(),
                contract.getBuyCityId()
        );

        Map<Long, String> areaMap = CustomizeAreaUtil.getAreaMapByIds(areaIdList);
        contractPdfInfoVo.setSellCountryName(areaMap.get(contract.getSellCountryId()));
        contractPdfInfoVo.setSellProvinceName(areaMap.get(contract.getSellProvinceId()));
        contractPdfInfoVo.setSellCityName(areaMap.get(contract.getSellCityId()));
        contractPdfInfoVo.setSellDetailedAddress(contract.getSellAddress());
        contractPdfInfoVo.setBuyCountryName(areaMap.get(contract.getBuyCountryId()));
        contractPdfInfoVo.setBuyProvinceName(areaMap.get(contract.getBuyProvinceId()));
        contractPdfInfoVo.setBuyCityName(areaMap.get(contract.getBuyCityId()));
        contractPdfInfoVo.setBuyDetailedAddress(contract.getBuyAddress());
    }

    /**
     * 赋值合同基本信息
     */
    private void setInfo(ContractPdfInfoVo contractPdfInfoVo, Contract contract) {
        contractPdfInfoVo.setContractCode(contract.getCode());
        contractPdfInfoVo.setCreateTimeEn(sdf.format(contract.getCreateTime()));
        contractPdfInfoVo.setTransportRemark(contract.getTransportRemark());
        contractPdfInfoVo.setTradeMethods(contract.getTradeMethods());
        contractPdfInfoVo.setRemark(contract.getRemark());
        contractPdfInfoVo.setCurrency(contract.getCurrency());
        contractPdfInfoVo.setDeliveryTime(contract.getDeliveryTime());
        contractPdfInfoVo.setTransportMethod(contract.getTransportMethod());
        contractPdfInfoVo.setShroffAccountId(contract.getShroffAccountId());
    }

    /**
     * 赋值商品列表信息
     */
    private void setProductList(ContractPdfInfoVo contractPdfInfoVo, Contract contract) {

        contractPdfInfoVo.setTotalAmount(BigDecimal.ZERO);

        List<ContractProduct> list = contractProductService.list(q -> q.eq(ContractProduct::getContractId, contract.getId()));

        if (list.size() == 0) {
            return;
        }

        List<ContractPdfInfoVo.ProductInfo> productInfoList = list.stream().map(item -> {
            contractPdfInfoVo.setTotalAmount(contractPdfInfoVo.getTotalAmount().add(item.getAmount()));

            ContractPdfInfoVo.ProductInfo productIndo = new ContractPdfInfoVo.ProductInfo();
            productIndo.setProductId(item.getProductId());
            productIndo.setProductQuantity(item.getQuantity());
            productIndo.setProductPrice(item.getPrice());
            productIndo.setAmount(item.getAmount());
            productIndo.setProductName(item.getProductName());
            return productIndo;
        }).collect(Collectors.toList());

        contractPdfInfoVo.setProductInfoList(productInfoList);

        // 产品属性
        productInfoService.attributeAssign(productInfoList, ContractPdfInfoVo.ProductInfo::getProductId, (item, product) -> {
            item.setProductUnit(product.getUnit());
        });

    }

    private void setAccountManagement(ContractPdfInfoVo contractPdfInfoVo, Contract contract) {
        Long shroffAccountId = contract.getShroffAccountId();
        AccountManagement accountManagement = accountManagementService.getById(shroffAccountId);
        if (accountManagement == null) {
            return;
        }

        contractPdfInfoVo.setBeneficiaryName(accountManagement.getBeneficiaryName());
        contractPdfInfoVo.setBeneficiaryBank(accountManagement.getBeneficiaryBank());
        contractPdfInfoVo.setBeneficiaryBankAddress(accountManagement.getBeneficiaryBankAddress());
        contractPdfInfoVo.setBeneficiaryAccountNumber(accountManagement.getBeneficiaryAccountNumber());
        contractPdfInfoVo.setSwiftCode(accountManagement.getSwiftCode());
        contractPdfInfoVo.setBeneficiaryAddress(accountManagement.getBeneficiaryAddress());
    }

    // 添加时间的查询条件
    private void selectTime(QueryWrapper<Contract> query, ContractDto dto) {
        query.ge("DATE_FORMAT(create_time,'%Y-%m')", dto.getBeginTime());
        query.le("DATE_FORMAT(create_time,'%Y-%m')", dto.getEndTime());
    }

    private void setAreaId(ContractDto contractDto) {

        SetCustomizeAreaId setCustomizeAreaId1 = new SetCustomizeAreaId() {

            @Override
            public void setProvinceId(Long provinceId) {
                contractDto.setBuyProvinceId(provinceId);
            }

            @Override
            public void setCityId(Long cityId) {
                contractDto.setBuyCityId(cityId);
            }

            @Override
            public Long getCountryId() {
                return contractDto.getBuyCountryId();
            }

            @Override
            public Long getProvinceId() {
                return contractDto.getBuyProvinceId();
            }

            @Override
            public String getProvinceName() {
                return contractDto.getBuyProvinceName();
            }

            @Override
            public Long getCityId() {
                return contractDto.getBuyCityId();
            }

            @Override
            public String getCityName() {
                return contractDto.getBuyCityName();
            }
        };

        SetCustomizeAreaId setCustomizeAreaId2 = new SetCustomizeAreaId() {

            @Override
            public void setProvinceId(Long provinceId) {
                contractDto.setSellProvinceId(provinceId);
            }

            @Override
            public void setCityId(Long cityId) {
                contractDto.setSellCityId(cityId);
            }

            @Override
            public Long getCountryId() {
                return contractDto.getSellCountryId();
            }

            @Override
            public Long getProvinceId() {
                return contractDto.getSellProvinceId();
            }

            @Override
            public String getProvinceName() {
                return contractDto.getSellProvinceName();
            }

            @Override
            public Long getCityId() {
                return contractDto.getSellCityId();
            }

            @Override
            public String getCityName() {
                return contractDto.getSellCityName();
            }
        };

        CustomizeAreaUtil.setAreaId(Arrays.asList(setCustomizeAreaId1, setCustomizeAreaId2));


        CustomizeAreaUtil.setAreaId(Arrays.asList(setCustomizeAreaId1));

    }

    /**
     * 统计到账认领总金额
     * @param v
     * @param currencyRatesMap 汇率JSON
     * @return
     */
    private BigDecimal getSumClaimMoney(ContractBudgetVo v,Map<String,BigDecimal> currencyRatesMap){
        List<ClaimContract> claimContractList = claimContractService.list(Wrappers.<ClaimContract>query().lambda().eq(ClaimContract::getContractId,v.getContractId()));
        BigDecimal sumClaimMOney = BigDecimal.ZERO;
        if(CollectionUtils.isNotEmpty(claimContractList)){
            for(ClaimContract c:claimContractList){
                sumClaimMOney = sumClaimMOney.add(c.getMoney().multiply(currencyRatesMap.getOrDefault(c.getCurrency(),BigDecimal.ONE)));
            }
            return sumClaimMOney;
        }else{
            return BigDecimal.ZERO;
        }
    }

    /**
     * 统采购合同总金额
     * @param v
     * @param currencyRatesMap 汇率JSON
     * @return
     */
    private BigDecimal getSumPurchaseContractMoney(ContractBudgetVo v,Map<String,BigDecimal> currencyRatesMap){
        List<EhsdPurchaseProductVo> list = ehsdPurchaseProductService.getListByContractId(v.getContractId());
        BigDecimal sumPurchaseContractMoney = BigDecimal.ZERO;
        if(CollectionUtils.isNotEmpty(list)){
            for(EhsdPurchaseProductVo c:list){
                sumPurchaseContractMoney = sumPurchaseContractMoney.add(c.getAmount().multiply(currencyRatesMap.getOrDefault(c.getCurrency(),BigDecimal.ONE)));
            }
            return sumPurchaseContractMoney;
        }else{
            return BigDecimal.ZERO;
        }
    }

    /**
     * 统计支出各种费用
     * @param v
     * @param currencyRatesMap 汇率JSON
     * @return
     */
    private void getGroupTypeMoney(ContractBudgetVo v,Map<String,BigDecimal> currencyRatesMap){
        List<AccountRequestFundsDetailVo> list = accountRequestFundsDetailService.getListByContractId(v.getContractId());
        /**
         * 拖车费
         */
        BigDecimal trailerFee = BigDecimal.ZERO;

        /**
         * 报关费
         */
        BigDecimal customsFee = BigDecimal.ZERO;

        /**
         * 港杂费
         */
        BigDecimal portMixedFee = BigDecimal.ZERO;

        /**
         * 验货红包
         */
        BigDecimal inspectionRedPack = BigDecimal.ZERO;

        /**
         * 佣金
         */
        BigDecimal commission = BigDecimal.ZERO;

        /**
         * 检验费
         */
        BigDecimal checkout = BigDecimal.ZERO;

        /**
         * 验货费
         */
        BigDecimal inspectionCharge = BigDecimal.ZERO;

        /**
         * 运费
         */
        BigDecimal freight = BigDecimal.ZERO;

        /**
         * 产地证费
         */
        BigDecimal certificateOfOrigin = BigDecimal.ZERO;

        /**
         * 其他费用
         */
        BigDecimal other  = BigDecimal.ZERO;

        if(CollectionUtils.isNotEmpty(list)){
            for(AccountRequestFundsDetailVo c:list){
                switch (c.getCostType()){
                    case "1"://拖车费
                        trailerFee = trailerFee.add(c.getAmount().multiply(currencyRatesMap.getOrDefault(c.getCurrency(),BigDecimal.ONE)));
                        break;
                    case "2"://报关费
                        customsFee = customsFee.add(c.getAmount().multiply(currencyRatesMap.getOrDefault(c.getCurrency(),BigDecimal.ONE)));
                        break;
                    case "3"://港杂费
                        portMixedFee = portMixedFee.add(c.getAmount().multiply(currencyRatesMap.getOrDefault(c.getCurrency(),BigDecimal.ONE)));
                        break;
                    case "4"://验收红包
                        inspectionRedPack = inspectionRedPack.add(c.getAmount().multiply(currencyRatesMap.getOrDefault(c.getCurrency(),BigDecimal.ONE)));
                        break;
                    case "5"://佣金
                        commission = commission.add(c.getAmount().multiply(currencyRatesMap.getOrDefault(c.getCurrency(),BigDecimal.ONE)));
                        break;
                    case "6"://检测费
                        checkout = checkout.add(c.getAmount().multiply(currencyRatesMap.getOrDefault(c.getCurrency(),BigDecimal.ONE)));
                        break;
                    case "7"://验货费
                        inspectionCharge = inspectionCharge.add(c.getAmount().multiply(currencyRatesMap.getOrDefault(c.getCurrency(),BigDecimal.ONE)));
                        break;
                    case "8"://运费
                        freight = freight.add(c.getAmount().multiply(currencyRatesMap.getOrDefault(c.getCurrency(),BigDecimal.ONE)));
                        break;
                    case "9"://产地证费
                        certificateOfOrigin = certificateOfOrigin.add(c.getAmount().multiply(currencyRatesMap.getOrDefault(c.getCurrency(),BigDecimal.ONE)));
                        break;
                    default:
                        other = other.add(c.getAmount().multiply(currencyRatesMap.getOrDefault(c.getCurrency(),BigDecimal.ONE)));
                        break;
                }
            }
        }
        v.setTrailerFee(trailerFee);
        v.setCustomsFee(customsFee);
        v.setPortMixedFee(portMixedFee);
        v.setInspectionRedPack(inspectionRedPack);
        v.setCommission(commission);
        v.setCheckout(checkout);
        v.setInspectionCharge(inspectionCharge);
        v.setFreight(freight);
        v.setCertificateOfOrigin(certificateOfOrigin);
        v.setOther(other);
    }
}
