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.vo.AccountRequestFundsDetailVo;
import com.fjhx.account.entity.account.vo.AccountRunningWaterVo;
import com.fjhx.account.entity.tax.po.TaxRefundDetails;
import com.fjhx.account.service.account.AccountManagementService;
import com.fjhx.account.service.account.AccountPaymentService;
import com.fjhx.account.service.account.AccountRequestFundsDetailService;
import com.fjhx.account.service.tax.TaxRefundDetailsService;
import com.fjhx.area.service.SetCustomizeAreaId;
import com.fjhx.area.utils.CustomizeAreaUtil;
import com.fjhx.common.constant.SourceConstant;
import com.fjhx.common.entity.contract.po.ContractTemplate;
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.FlowStatusEnum1;
import com.fjhx.common.service.contract.ContractTemplateService;
import com.fjhx.common.service.corporation.CorporationService;
import com.fjhx.common.service.currency.CurrencyRateService;
import com.fjhx.common.service.documentary.GetDocumentaryBusinessTemplate;
import com.fjhx.common.utils.Assert;
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.file.entity.FileInfoVo;
import com.fjhx.file.utils.ObsFileUtil;
import com.fjhx.flow.service.flow.FlowExampleService;
import com.fjhx.item.entity.product.dto.ProductInfoSelectDto;
import com.fjhx.item.entity.product.po.ProductInfo;
import com.fjhx.item.service.product.ProductInfoService;
import com.fjhx.purchase.entity.arrival.po.ArrivalDetail;
import com.fjhx.purchase.entity.purchase.po.Purchase;
import com.fjhx.purchase.entity.purchase.po.PurchaseDetail;
import com.fjhx.purchase.entity.purchase.vo.PurchaseDetailVo;
import com.fjhx.purchase.entity.quality.po.QualityDetail;
import com.fjhx.purchase.service.arrival.ArrivalDetailService;
import com.fjhx.purchase.service.pay.PayDetailService;
import com.fjhx.purchase.service.pay.PayService;
import com.fjhx.purchase.service.purchase.PurchaseDetailService;
import com.fjhx.purchase.service.purchase.PurchaseService;
import com.fjhx.purchase.service.quality.QualityDetailService;
import com.fjhx.sale.entity.claim.po.ClaimContract;
import com.fjhx.sale.entity.contract.bo.ContractCurrencyRate;
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.dto.DecisionAidDto;
import com.fjhx.sale.entity.contract.dto.PayDecisionAidDto;
import com.fjhx.sale.entity.contract.po.Contract;
import com.fjhx.sale.entity.contract.po.ContractProduct;
import com.fjhx.sale.entity.contract.po.ContractProject;
import com.fjhx.sale.entity.contract.po.ContractShipment;
import com.fjhx.sale.entity.contract.vo.*;
import com.fjhx.sale.entity.purchase.po.EhsdPurchase;
import com.fjhx.sale.entity.purchase.vo.EhsdPurchaseProductVo;
import com.fjhx.sale.entity.sale.vo.SaleQuotationVo;
import com.fjhx.sale.mapper.contract.ContractMapper;
import com.fjhx.sale.service.claim.ClaimContractService;
import com.fjhx.sale.service.contract.ContractProductService;
import com.fjhx.sale.service.contract.ContractProjectService;
import com.fjhx.sale.service.contract.ContractService;
import com.fjhx.sale.service.contract.ContractShipmentService;
import com.fjhx.sale.service.purchase.EhsdPurchaseProductService;
import com.fjhx.sale.service.purchase.EhsdPurchaseService;
import com.fjhx.tenant.entity.dict.dto.DictTenantDataSelectDto;
import com.fjhx.tenant.entity.dict.vo.DictTenantDataVo;
import com.fjhx.tenant.service.dict.DictTenantDataService;
import com.ruoyi.common.core.domain.BaseIdPo;
import com.ruoyi.common.core.domain.BasePo;
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 com.ruoyi.system.utils.UserUtil;
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 org.springframework.transaction.annotation.Transactional;

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 EhsdPurchaseService ehsdPurchaseService;

    @Autowired
    private PurchaseDetailService purchaseDetailService;

    @Autowired
    private CurrencyRateService currencyRateService;

    @Autowired
    private ClaimContractService claimContractService;

    @Autowired
    private AccountRequestFundsDetailService accountRequestFundsDetailService;

    @Autowired
    private ContractProjectService contractProjectService;

    @Autowired
    private ContractService contractService;

    @Autowired
    private PurchaseService purchaseService;

    @Autowired
    private ArrivalDetailService arrivalDetailService;

    @Autowired
    private QualityDetailService qualityDetailService;

    @Autowired
    private FlowExampleService flowExampleService;

    @Autowired
    private ContractShipmentService contractShipmentService;

    @Autowired
    private DictTenantDataService dictTenantDataService;

    @Autowired
    private ContractTemplateService contractTemplateService;

    @Autowired
    private TaxRefundDetailsService taxRefundDetailsService;

    @Autowired
    private PayDetailService payDetailService;

    /**
     * 合同和样品单 下拉分页
     */
    @Override
    public Page<ContractVo> getContractAndSamplePage(ContractSelectDto dto) {
        IWrapper<Contract> wrapper = getWrapper();
        if (StringUtils.isNotEmpty(dto.getKeyword())) {
            //归属公司
            List<Long> corporationIds = corporationService.listObject(Corporation::getId, q -> q.like(Corporation::getName, dto.getKeyword()));
            List<Long> customerIds = customerService.listObject(Customer::getId, q -> q.like(Customer::getName, dto.getKeyword()));
            wrapper.and(q -> q
                    .like("t1", Contract::getCode, dto.getKeyword())
                    .or().in("t1", Contract::getSellCorporationId, corporationIds)
                    .or().in("t1", Contract::getBuyCorporationId, customerIds)
            );
        }
        Page<ContractVo> contractAndSamplePage = baseMapper.getContractAndSamplePagez(dto.getPage(), wrapper);
        List<ContractVo> records = contractAndSamplePage.getRecords();
        //赋值原卖方公司名称 多公司
        DynamicDataSourceContextHolder.push(SourceConstant.COMMON);
        corporationService.attributeAssign(records, ContractVo::getSellCorporationId, (item, corporation) -> {
            item.setSellCorporationName(corporation.getName());
        });
        DynamicDataSourceContextHolder.poll();
        //赋值客户名称
        customerService.attributeAssign(records, ContractVo::getBuyCorporationId, (item, customer) -> {
            item.setBuyCorporationName(customer.getName());
        });
        return contractAndSamplePage;
    }

    /**
     * 分页
     *
     * @param dto
     * @return
     */
    @Override
    public Page<ContractVo> getPage(ContractSelectDto dto) {

        List<Long> authIdList = customerService.getAuthIdList();

        if (authIdList.size() == 0) {
            return new Page<>();
        }

        IWrapper<Contract> wrapper = getWrapper();
        wrapper.in("t1", Contract::getBuyCorporationId, authIdList);

        return pageCommon(dto, wrapper);
    }

    /**
     * 不过滤权限的分页接口
     */
    @Override
    public Page<ContractVo> getPage1(ContractSelectDto dto) {
        IWrapper<Contract> wrapper = getWrapper();
        return pageCommon(dto, wrapper);
    }

    /**
     * 分页公共代码抽取
     */
    private Page<ContractVo> pageCommon(ContractSelectDto dto, IWrapper<Contract> wrapper) {
        wrapper.orderByDesc("t1", Contract::getCreateTime);
        wrapper.eq("t1", Contract::getIsChange, "0");//列表只展示未变更得数据
        wrapper.between("t1", Contract::getStatus, FlowStatusEnum1.DRAFT.getKey(), FlowStatusEnum1.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.in("t1.refundStatusNew", Arrays.asList(dto.getRefundStatusNew().split(",")));
        }
        if (StringUtils.isNotEmpty(dto.getKeyword())) {
            //归属公司
            List<Long> corporationIds = corporationService.listObject(Corporation::getId, q -> q.like(Corporation::getName, dto.getKeyword()));
            List<Long> customerIds = customerService.listObject(Customer::getId, q -> q.like(Customer::getName, dto.getKeyword()));
            wrapper.and(q -> q
                    .like("t1", Contract::getCode, dto.getKeyword())
                    .or().in("t1", Contract::getSellCorporationId, corporationIds)
                    .or().in("t1", Contract::getBuyCorporationId, customerIds)
            );
        }

        //过滤合同类型
        wrapper.eq("t1.contract_type", dto.getContractType());

        Page<ContractVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);
        List<ContractVo> list = page.getRecords();
        if (CollectionUtils.isNotEmpty(list)) {
            //获取合同类型字典内容
            DynamicDataSourceContextHolder.push(SourceConstant.BASE);
            DictTenantDataSelectDto dictTenantDataSelectDto = new DictTenantDataSelectDto();
            dictTenantDataSelectDto.setDictCode("contract_type");
            List<DictTenantDataVo> dictTenantDataVoList = dictTenantDataService.getList(dictTenantDataSelectDto);
            Map<String, String> contractTypeStatusDic = dictTenantDataVoList.stream().collect(Collectors.toMap(DictTenantDataVo::getDictKey, DictTenantDataVo::getDictValue));
            DynamicDataSourceContextHolder.poll();

            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);
                }

                //获取合同类型字典内容
                p.setContractTypeVal(contractTypeStatusDic.get(p.getContractType()));

            }

            // 赋值流程id
            flowExampleService.setFlowId(list, ContractVo::setFlowId);
            //赋值原卖方公司名称 多公司
            corporationService.attributeAssign(list, ContractVo::getSellCorporationId, (item, corporation) -> {
                item.setSellCorporationName(corporation.getName());
            });
        }
        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, FlowStatusEnum1.PASS.getKey(), FlowStatusEnum1.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));
            //通过合同ID查询到退税数据
            List<TaxRefundDetails> refundDetails = taxRefundDetailsService.getSumMoneyByContractIds(contractIds);
            Map<Long, List<TaxRefundDetails>> refundDetailsMap = refundDetails.stream().collect(Collectors.groupingBy(TaxRefundDetails::getContractId));

            //取出默认汇率
//            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));
                    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.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())
                            );
                    //处理退税金额
                    handleRefundTax(v);
                    v.setRmbContractAmount(v.getAmount().multiply(new BigDecimal(map.getOrDefault(v.getCurrency(), BigDecimal.ONE).toString())));
                    //计算收入总计=合同金额(转人民币)+应退税金额(转人民币)
                    v.setIncomeAmount(v.getAmount().multiply(new BigDecimal(map.getOrDefault(v.getCurrency(), BigDecimal.ONE).toString())).add(v.getRefundableAmount()));
                } else {//没有汇率取默认汇率
                    if (MapUtils.isNotEmpty(ehsdAmountMap)) {    //计算EHSD租户应付货款
                        String concatAmountCurrency = ehsdAmountMap.getOrDefault(v.getContractId(), null);
                        if (StringUtils.isNotEmpty(concatAmountCurrency)) {
                            BigDecimal amount = new BigDecimal(concatAmountCurrency.split("-")[0]);
                            String rate = concatAmountCurrency.split("-")[2];
                            BigDecimal DecimalRate = new BigDecimal(rate);
                            v.setEhsdSumAmount(amount.multiply(DecimalRate));
                        } else {
                            v.setEhsdSumAmount(BigDecimal.ZERO);
                        }
                    }
                    BigDecimal rate = v.getRate();

                    //计算支出总计 除合同金额(转人民币)+应退税金额(转人民币) 其他金额相加
                    v.setExpenditureAmount(
                            v.getTrailerFee() == null ? BigDecimal.ZERO : v.getTrailerFee().add
                            (v.getCustomsFee() == null ? BigDecimal.ZERO : v.getCustomsFee()).add
                            (v.getAgencyFee() == null ? BigDecimal.ZERO : v.getAgencyFee()).add
                            (v.getPortMixedFee() == null ? BigDecimal.ZERO : v.getPortMixedFee()).add
                            (v.getInspectionRedPack() == null ? BigDecimal.ZERO : v.getInspectionRedPack()).add
                            (v.getCommission() == null ? BigDecimal.ZERO : v.getCommission()).add
                            (v.getOther() == null ? BigDecimal.ZERO : v.getOther()).add
                            (v.getEhsdSumAmount() == null ? BigDecimal.ZERO : v.getEhsdSumAmount())
                            );
                    //处理退税金额
                    handleRefundTax(v);
                    v.setRmbContractAmount(v.getAmount().multiply(rate));
                    //计算收入总计=合同金额(转人民币)+应退税金额(转人民币)
                    v.setIncomeAmount(v.getAmount().multiply(rate).add(v.getRefundableAmount()));
                }
                //计算毛利 收入-支出
                v.setGross(v.getIncomeAmount().subtract(v.getExpenditureAmount()));
                //计算毛利率 毛利/收入
                v.setGrossRate(v.getGross().divide(v.getIncomeAmount(), RoundingMode.CEILING).multiply(new BigDecimal("100")));
            }
        }
        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, FlowStatusEnum1.PASS.getKey(), FlowStatusEnum1.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();
        // 赋值客户名称
        customerService.attributeAssign(list, Contract::getBuyCorporationId, (item, customer) -> {
            item.setCustomerName(customer.getName());
        });
        List<Long> contractIds = list.stream().map(ContractBudgetVo::getContractId).collect(Collectors.toList());
        //通过合同ID查询到退税数据
        List<TaxRefundDetails> refundDetails = taxRefundDetailsService.getSumMoneyByContractIds(contractIds);
        Map<Long,List<TaxRefundDetails>> refundDetailsMap = refundDetails.stream().collect(Collectors.groupingBy(TaxRefundDetails::getContractId));
        //通过合同ID查询到到账认领数据
        List<ClaimContract> claimContractList = claimContractService.list(Wrappers.<ClaimContract>query().lambda().in(ClaimContract::getContractId,contractIds));
        Map<Long,List<ClaimContract>> claimMap = claimContractList.stream().collect(Collectors.groupingBy(ClaimContract::getContractId));
        //通过合同ID查询到采购合同
        List<EhsdPurchase> purchaseList = ehsdPurchaseService.list(Wrappers.<EhsdPurchase>query().lambda().in(EhsdPurchase::getDataResourceId,contractIds));
        Map<Long,List<EhsdPurchase>> purchaseMap = purchaseList.stream().collect(Collectors.groupingBy(EhsdPurchase::getDataResourceId));
        for (ContractBudgetVo v : list) {
            v.setOtherIncomeAmount(BigDecimal.ZERO);//暂时先设置其他收入为0
            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.setRefundableAmount(BigDecimal.ZERO);
                List<TaxRefundDetails> rList = refundDetailsMap.getOrDefault(v.getContractId(),null);
                if(CollectionUtils.isNotEmpty(rList)){
                    BigDecimal taxReturnMoney = rList.stream().map(taxRefundDetails -> {
                        //获取汇率
                        BigDecimal rate = assignCurrencyRatesMap.getOrDefault(taxRefundDetails.getCurrency(),BigDecimal.ONE);
                        // 获取认领金额
                        BigDecimal money = taxRefundDetails.getAmount();
                        // 返回兑人民币后金额
                        return rate.multiply(money);
                    }).reduce(BigDecimal.ZERO, BigDecimal::add);
                    v.setRefundableAmount(taxReturnMoney);
                }
                //处理到账总金额
                v.setSumClaimMoney(getSumClaimMoney(claimMap.getOrDefault(v.getContractId(),null),assignCurrencyRatesMap));
                //采购合同总金额
                getSumPurchaseContractMoney(v,purchaseMap.getOrDefault(v.getContractId(),null),assignCurrencyRatesMap);
                //支出费用
                this.getGroupTypeMoney(v, assignCurrencyRatesMap);
            } else {
                v.setRmbContractAmount(v.getAmount().multiply(v.getRate()));//计算汇算人民币
                /**
                 * 处理退税金额
                 */
                v.setRefundableAmount(BigDecimal.ZERO);
                List<TaxRefundDetails> rList = refundDetailsMap.getOrDefault(v.getContractId(),null);
                if(CollectionUtils.isNotEmpty(rList)){
                    BigDecimal taxReturnMoney = rList.stream().map(taxRefundDetails -> {
                        //获取汇率
                        BigDecimal rate = taxRefundDetails.getRate();
                        // 获取认领金额
                        BigDecimal money = taxRefundDetails.getAmount();
                        // 返回兑人民币后金额
                        return rate.multiply(money);
                    }).reduce(BigDecimal.ZERO, BigDecimal::add);
                    v.setRefundableAmount(taxReturnMoney);
                }
                //处理到账总金额
                v.setSumClaimMoney(getSumClaimMoney(claimMap.getOrDefault(v.getContractId(),null),null));
                //采购合同总金额
                getSumPurchaseContractMoney(v,purchaseMap.getOrDefault(v.getContractId(),null),null);
                //支出费用
                this.getGroupTypeMoney(v, null);
            }
            //计算收入总计=合同金额(转人民币)+应退税金额(转人民币)+其他收入(转人民币)
            v.setIncomeAmount(v.getSumClaimMoney() == null ? BigDecimal.ZERO : v.getSumClaimMoney().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()));
            //计算毛利率 毛利/收入
            if(v.getGross().compareTo(BigDecimal.ZERO)==0){
                v.setGrossRate(BigDecimal.ZERO);
            }else{
                v.setGrossRate(v.getGross().divide(v.getIncomeAmount(), RoundingMode.CEILING).multiply(new BigDecimal("100")));
            }
        }
        return page;
    }

    @Override
    public ContractVo detail(Long id) {
        Contract contract = this.getById(id);
        Assert.notEmpty(contract, "查询不到合同信息");
        ContractVo result = BeanUtil.toBean(contract, ContractVo.class);

        //赋值模板名称
        ContractTemplate contractTemplate = contractTemplateService.getById(result.getContractTemplateId());
        if (ObjectUtil.isNotEmpty(contractTemplate)) {
            result.setContractTemplateName(contractTemplate.getTemplateName());
        }
        // 卖方信息
        Corporation corporation = corporationService.getById(result.getSellCorporationId());
        if (ObjectUtil.isNotEmpty(corporation)) {
            result.setSellCorporationName(corporation.getName());
        }
        //买方信息
        Customer customer = customerService.getById(result.getBuyCorporationId());
        if (ObjectUtil.isNotEmpty(corporation)) {
            result.setSellCorporationName(corporation.getName());
            result.setBuyCorporationName(customer.getName());
        }
        //赋值收款账号
        AccountManagement accountManagement = accountManagementService.getById(result.getShroffAccountId());
        if (ObjectUtil.isNotEmpty(accountManagement)) {
            result.setShroffAccountName(accountManagement.getName());
        }

        List<ContractProduct> contractProductList = contractProductService.list(q -> q.eq(ContractProduct::getContractId, id));
        productInfoService.attributeAssign(contractProductList, ContractProduct::getProductId, (item, product) -> {
            item.setProductCnName(product.getName());
            item.setProductCode(product.getCode());
            item.setProductUnit(product.getUnit());
        });
        result.setContractProductList(contractProductList);

        List<ContractProject> contractProjectList = contractProjectService.list(q -> q.eq(ContractProject::getContractId, id));
        result.setContractProjectList(contractProjectList);

        List<ContractShipment> contractShipmentList = contractShipmentService.list(q -> q.eq(ContractShipment::getContractId, id));
        productInfoService.attributeAssign(contractShipmentList, ContractShipment::getProductId, (item, product) -> {
            item.setProductCnName(product.getName());
            item.setProductName(product.getName());
            item.setProductCode(product.getCode());
        });
        result.setContractShipmentList(contractShipmentList);
        //赋值国省市名称
        Map<Long, String> areaMapByIds = CustomizeAreaUtil.getAreaMapByIds(Arrays.asList(result.getBuyCountryId(), result.getBuyProvinceId(), result.getBuyCityId()));
        result.setBuyCountryName(areaMapByIds.get(result.getBuyCountryId()));
        result.setBuyProvinceName(areaMapByIds.get(result.getBuyProvinceId()));
        result.setBuyCityName(areaMapByIds.get(result.getBuyCityId()));
        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();

        String 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;
    }

    @Override
    public void toTheAccount(Contract dto) {

        Long contractId = dto.getId();

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

        update(q -> q
                .eq(BaseIdPo::getId, contractId)
                .set(Contract::getRefundStatus, 20)
                .set(BasePo::getUpdateTime, new Date())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
        );

    }

    @Override
    public DecisionAidVo decisionAid(DecisionAidDto dto) {
        DecisionAidVo decisionAidVo = new DecisionAidVo();

        // 最近合同
        Long buyCorporationId = dto.getBuyCorporationId();
        if (buyCorporationId != null) {
            List<Contract> list = list(q -> q
                    .eq(Contract::getBuyCorporationId, buyCorporationId)
                    .eq(Contract::getStatus, FlowStatusEnum1.PASS.getKey())
                    .orderByDesc(BaseIdPo::getId)
                    .last("limit 3")
            );
            decisionAidVo.setLastContractList(list);
        } else {
            decisionAidVo.setLastContractList(Collections.emptyList());
        }

        // 产品价格
        List<Long> productIdList = dto.getProductIdList();
        if (ObjectUtil.isNotEmpty(productIdList)) {

            Map<Long, List<ContractProduct>> map = contractProductService.mapKGroup(ContractProduct::getProductId, q -> q
                    .select(ContractProduct::getProductId, ContractProduct::getPrice)
                    .in(ContractProduct::getProductId, productIdList)
                    .orderByDesc(BaseIdPo::getId)
            );

            List<DecisionAidVo.ProductPrice> productPriceList = new ArrayList<>();

            for (Long productId : productIdList) {
                List<ContractProduct> contractProductList = map.get(productId);
                DecisionAidVo.ProductPrice productPrice = new DecisionAidVo.ProductPrice();
                productPrice.setId(productId);
                if (ObjectUtil.isNotEmpty(contractProductList)) {
                    productPrice.setLastPrice(contractProductList.get(0).getPrice());
                    productPrice.setMaxPrice(contractProductList.stream().map(ContractProduct::getPrice).max(BigDecimal::compareTo).get());
                    productPrice.setMinPrice(contractProductList.stream().map(ContractProduct::getPrice).min(BigDecimal::compareTo).get());
                } else {
                    productPrice.setLastPrice(BigDecimal.ZERO);
                    productPrice.setMaxPrice(BigDecimal.ZERO);
                    productPrice.setMinPrice(BigDecimal.ZERO);
                }
                productPriceList.add(productPrice);

            }

            productInfoService.attributeAssign(productPriceList, DecisionAidVo.ProductPrice::getId, (item, product) -> {
                item.setName(product.getName());
            });

            decisionAidVo.setProductPriceList(productPriceList);
        } else {
            decisionAidVo.setProductPriceList(Collections.emptyList());
        }

        return decisionAidVo;
    }

    @Override
    public PayDecisionAidVo payDecisionAid(PayDecisionAidDto dto) {

        PayDecisionAidVo vo = new PayDecisionAidVo();

        // 采购合同id
        List<Long> purchaseIdList = dto.getPurchaseIdList();

        if (purchaseIdList.size() == 0) {
            return vo;
        }

        // 采购合同
        List<Purchase> purchaseList = purchaseService.listByIds(purchaseIdList);
        List<PurchaseDetail> purchaseDetailList = purchaseDetailService.list(q -> q.in(PurchaseDetail::getPurchaseId, purchaseIdList));

        // 赋值关联销售合同
        setContractInfo(vo, purchaseList);

        // 赋值采购合同数据
        setPurchaseInfo(vo, purchaseList, purchaseDetailList);

        // 赋值到货数据
        List<ArrivalDetail> arrivalDetails = setInvoiceQuantity(vo);

        // 赋值合格率
        setPassRate(vo, arrivalDetails);

        // TODO 赋值退货数量 无法关联


        return vo;
    }

    /**
     * 赋值合格率
     */
    private void setPassRate(PayDecisionAidVo vo, List<ArrivalDetail> arrivalDetails) {
        List<PayDecisionAidVo.PurchaseInfo> purchaseInfoList = vo.getPurchaseInfoList();

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

        // 到货明细通过采购明细id分组
        Map<Long, List<ArrivalDetail>> arrivalDetailMap = arrivalDetails.stream().collect(Collectors.groupingBy(
                ArrivalDetail::getPurchaseDetailId
        ));

        // 通过到货明细查询质检记录
        List<Long> arrivalDetailsIdList = arrivalDetails.stream().map(BaseIdPo::getId).collect(Collectors.toList());
        List<QualityDetail> list = qualityDetailService.list(q -> q.in(QualityDetail::getArrivalDetailId, arrivalDetailsIdList));


        for (PayDecisionAidVo.PurchaseInfo purchaseInfo : purchaseInfoList) {

            List<ArrivalDetail> arrivalDetailsList = arrivalDetailMap.get(purchaseInfo.getPurchaseDetailsId());

            purchaseInfo.setQualifiedCount(BigDecimal.ZERO);
            purchaseInfo.setNoQualifiedCount(BigDecimal.ZERO);

            List<Long> itemArrivalDetailsIdList = arrivalDetailsList.stream().map(BaseIdPo::getId).collect(Collectors.toList());
            for (QualityDetail qualityDetail : list) {
                if (!itemArrivalDetailsIdList.contains(qualityDetail.getArrivalDetailId())) {
                    continue;
                }
                purchaseInfo.setQualifiedCount(purchaseInfo.getQualifiedCount().add(qualityDetail.getQualifiedCount()));
                purchaseInfo.setNoQualifiedCount(purchaseInfo.getNoQualifiedCount().add(qualityDetail.getNoQualifiedCount()));
            }
        }

    }


    /**
     * 赋值到货数据
     */
    private List<ArrivalDetail> setInvoiceQuantity(PayDecisionAidVo vo) {
        List<PayDecisionAidVo.PurchaseInfo> purchaseInfoList = vo.getPurchaseInfoList();

        // 采购明细id列表
        List<Long> purchaseDetailsIdList = purchaseInfoList.stream()
                .map(PayDecisionAidVo.PurchaseInfo::getPurchaseDetailsId).collect(Collectors.toList());

        if (purchaseDetailsIdList.size() == 0) {
            return Collections.emptyList();
        }

        List<ArrivalDetail> list = arrivalDetailService.list(q -> q.eq(ArrivalDetail::getPurchaseDetailId, purchaseDetailsIdList));

        Map<Long, BigDecimal> collect = list.stream().collect(Collectors.toMap(
                ArrivalDetail::getPurchaseDetailId,
                ArrivalDetail::getCount,
                BigDecimal::add
        ));

        for (PayDecisionAidVo.PurchaseInfo purchaseInfo : purchaseInfoList) {
            BigDecimal invoiceQuantity = collect.getOrDefault(purchaseInfo.getPurchaseDetailsId(), BigDecimal.ZERO);
            purchaseInfo.setInvoiceQuantity(invoiceQuantity);
        }

        return list;
    }

    /**
     * 赋值采购合同数据
     */
    private void setPurchaseInfo(PayDecisionAidVo vo, List<Purchase> purchaseList, List<PurchaseDetail> purchaseDetailList) {

        Map<Long, List<PurchaseDetail>> purchaseDetailMap = purchaseDetailList.stream()
                .collect(Collectors.groupingBy(PurchaseDetail::getPurchaseId));

        List<PayDecisionAidVo.PurchaseInfo> list = new ArrayList<>();

        for (Purchase purchase : purchaseList) {
            List<PurchaseDetail> itemList = purchaseDetailMap.get(purchase.getId());

            if (itemList.size() == 0) {
                continue;
            }

            for (PurchaseDetail purchaseDetail : itemList) {
                PayDecisionAidVo.PurchaseInfo purchaseInfo = new PayDecisionAidVo.PurchaseInfo();
                purchaseInfo.setPurchaseId(purchase.getId());
                purchaseInfo.setPurchaseCode(purchase.getCode());
                purchaseInfo.setPurchaseDetailsId(purchaseDetail.getId());
                purchaseInfo.setProductId(purchaseDetail.getBussinessId());
                purchaseInfo.setPurchaseQuantity(purchaseDetail.getCount());
                list.add(purchaseInfo);
            }
        }

        // 赋值产品id
        productInfoService.attributeAssign(list, PayDecisionAidVo.PurchaseInfo::getProductId, (item, product) -> {
            item.setProductName(product.getName());
            item.setProductCode(product.getCode());
        });

        vo.setPurchaseInfoList(list);
    }

    /**
     * 赋值销售合同数据
     */
    private void setContractInfo(PayDecisionAidVo vo, List<Purchase> purchaseList) {

        List<Long> contractIdList = purchaseList.stream()
                .filter(item -> Objects.equals(item.getDataResource(), 1))
                .map(Purchase::getDataResourceId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        if (contractIdList.size() == 0) {
            vo.setContractList(Collections.emptyList());
            return;
        }

        List<Contract> customerList = contractService.list(q -> q.in(BaseIdPo::getId, contractIdList));
        vo.setContractList(customerList);
    }


    /**
     * 赋值外销合同信息
     *
     * @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();
        //销售跟单权限过滤
        List<Long> authUserIdList = UserUtil.getAuthUserIdList();
        wrapper.in(Contract::getCreateUser, authUserIdList);

        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());
        });

        //赋值业务员名称
        UserUtil.assignmentNickName(records, Contract::getCreateUser, Contract::setUserName);

        return page;
    }

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

        //赋值地址中文信息
        List<Long> areaIdList = Arrays.asList(
                corporation.getCountryId(),
                corporation.getProvinceId(),
                corporation.getCityId()
        );
        Map<Long, String> areaMap = CustomizeAreaUtil.getAreaMapByIds(areaIdList);
        contractPdfInfoVo.setSellCountryName(areaMap.get(corporation.getCountryId()));
        contractPdfInfoVo.setSellProvinceName(areaMap.get(corporation.getProvinceId()));
        contractPdfInfoVo.setSellCityName(areaMap.get(corporation.getCityId()));
        contractPdfInfoVo.setSellDetailedAddress(corporation.getAddress());

        //赋值英文名地址信息
        contractPdfInfoVo.setSellCountryNameEn(corporation.getCountryEnStr());
        contractPdfInfoVo.setSellProvinceNameEn(corporation.getProvinceEnStr());
        contractPdfInfoVo.setSellCityNameEn(corporation.getCityEnStr());
        contractPdfInfoVo.setSellDetailedAddressEn(corporation.getAddressEn());
    }

    /**
     * 赋值买方公司基本信息
     */
    private void setBuyCorporation(ContractPdfInfoVo contractPdfInfoVo, Contract contract) {
        Customer customer = customerService.getById(contract.getBuyCorporationId());
        if (customer == null) {
            throw new ServiceException("买方公司信息为空");
        }
        contractPdfInfoVo.setBuyCorporationId(contract.getBuyCorporationId());
        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(contract.getSellCountryName());
//        contractPdfInfoVo.setSellProvinceName(contract.getSellProvinceName());
//        contractPdfInfoVo.setSellCityName(contract.getSellCityName());
//        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());
        contractPdfInfoVo.setAdvanceRatio(contract.getAdvanceRatio());
    }

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

        contractPdfInfoVo.setTotalAmount(contract.getAmount());

        List<ContractProject> contractProjectList = contractProjectService.list(q -> q.eq(ContractProject::getContractId, contract.getId()));
        contractPdfInfoVo.setContractProjectList(contractProjectList);

        List<ContractProduct> contractProductList = contractProductService.list(q -> q.eq(ContractProduct::getContractId, contract.getId()));
        if (contractProductList.size() == 0) {
            return;
        }

        List<Long> pids = contractProductList.stream().map(ContractProduct::getProductId).collect(Collectors.toList());
        Map<Long, ProductInfo> productInfoMap = productInfoService.mapKEntity(ProductInfo::getId, q -> q.in(ProductInfo::getId, pids));

        List<ContractPdfInfoVo.ProductInfo> productInfoList = contractProductList.stream().map(item -> {
            ProductInfo productInfo = productInfoMap.get(item.getProductId());

            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());

            productIndo.setProductModel(item.getProductModel());

            JSONObject ehsdJson = JSONObject.parseObject(item.getEhsdJson());
            if (ObjectUtil.isNotEmpty(ehsdJson)) {
                productIndo.setPackMethod(ehsdJson.getString("packMethod"));
            }

            if (ObjectUtil.isNotEmpty(productInfo)) {
                productIndo.setProductRemark(productInfo.getRemark());
                productIndo.setProductSpec(productInfo.getSpec());
            }

            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());

        contractPdfInfoVo.setBeneficiaryName(contract.getBeneficiaryName());
        contractPdfInfoVo.setBeneficiaryBank(contract.getBeneficiaryBank());
        contractPdfInfoVo.setBeneficiaryBankAddress(contract.getBeneficiaryBankAddress());
        contractPdfInfoVo.setBeneficiaryAccountNumber(contract.getBeneficiaryAccountNumber());
        contractPdfInfoVo.setSwiftCode(contract.getSwiftCode());
        contractPdfInfoVo.setBeneficiaryAddress(contract.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));

    }

    /**
     * 统计到账认领总金额
     *
     * @param claimContractList
     * @param assignCurrencyRatesMap 汇率JSON
     * @return
     */
    private BigDecimal getSumClaimMoney(List<ClaimContract> claimContractList,Map<String, BigDecimal> assignCurrencyRatesMap) {
        BigDecimal sumClaimMoney = BigDecimal.ZERO;
        if(CollectionUtils.isEmpty(claimContractList)){
            return BigDecimal.ZERO;
        }
        if(MapUtils.isNotEmpty(assignCurrencyRatesMap)){
            for (ClaimContract c : claimContractList) {
                sumClaimMoney = sumClaimMoney.add(c.getMoney().multiply(assignCurrencyRatesMap.getOrDefault(c.getCurrency(),BigDecimal.ONE)));
            }
        }else{
            for (ClaimContract c : claimContractList) {
                sumClaimMoney = sumClaimMoney.add(c.getMoney().multiply(c.getRate()));
            }
        }
        return sumClaimMoney;
    }
    /**
     * 统采购合同总金额
     * @param v
     * @param purchaseList
     * @param assignCurrencyRatesMap 汇率JSON
     * @return
     */
    private void getSumPurchaseContractMoney(ContractBudgetVo v,List<EhsdPurchase> purchaseList,Map<String, BigDecimal> assignCurrencyRatesMap) {
        BigDecimal purchaseSumMoney = BigDecimal.ZERO;
        if(CollectionUtils.isEmpty(purchaseList)){
            v.setSumPurchaseContractMoney(BigDecimal.ZERO);
            v.setAccountPaid(BigDecimal.ZERO);
            return;
        }
        if(MapUtils.isNotEmpty(assignCurrencyRatesMap)){
            for (EhsdPurchase c : purchaseList) {
                purchaseSumMoney = purchaseSumMoney.add(c.getAmount().multiply(assignCurrencyRatesMap.getOrDefault(c.getCurrency(),BigDecimal.ONE)));
            }
        }else{
            for (EhsdPurchase c : purchaseList) {
                purchaseSumMoney = purchaseSumMoney.add(c.getAmount().multiply(c.getRate()));
            }
        }
        v.setSumPurchaseContractMoney(purchaseSumMoney);
        List<Long> purchaseIds = purchaseList.stream().map(EhsdPurchase::getId).collect(Collectors.toList());
        v.setAccountPaid(payDetailService.getSumMoney(purchaseIds));
    }

    /**
     * 统计支出各种费用
     *
     * @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;

        for (AccountRequestFundsDetailVo c : list) {
            String costType = c.getCostType() == null ? "" : c.getCostType();
            BigDecimal rate ;
            if(MapUtils.isNotEmpty(currencyRatesMap)){
                rate = currencyRatesMap.getOrDefault(c.getCurrency(),null);
            }else{
                rate = c.getRate();
            }
            switch (costType) {
                case "0"://拖车费
                    trailerFee = trailerFee.add(c.getAmount().multiply(rate));
                    break;
                case "1"://报关费
                    customsFee = customsFee.add(c.getAmount().multiply(rate));
                    break;
                case "2"://代理费
                    customsFee = customsFee.add(c.getAmount().multiply(rate));
                    break;
                case "3"://港杂费
                    portMixedFee = portMixedFee.add(c.getAmount().multiply(rate));
                    break;
                case "4"://验收红包
                    inspectionRedPack = inspectionRedPack.add(c.getAmount().multiply(rate));
                    break;
                case "5"://佣金
                    commission = commission.add(c.getAmount().multiply(rate));
                    break;
                case "6"://检测费
                    other = other.add(c.getAmount().multiply(rate));
                    break;
                case "7"://检测费
                    checkout = checkout.add(c.getAmount().multiply(rate));
                    break;
                case "8"://验货费
                    inspectionCharge = inspectionCharge.add(c.getAmount().multiply(rate));
                    break;
                case "9"://运费
                    freight = freight.add(c.getAmount().multiply(rate));
                    break;
                case "10"://产地证费
                    certificateOfOrigin = certificateOfOrigin.add(c.getAmount().multiply(rate));
                    break;
                default:
                    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);
    }

    /**
     * 获取合同相关的所有版本列表
     */
    @Override
    public List<ContractVo> getVersionList(Long id) {
        List<Contract> contractList = new ArrayList<>();

        while (true) {
            Contract contract = this.getById(id);
            Assert.notEmpty(contract, "查询不到合同信息,id:" + id);
            contractList.add(contract);
            if (ObjectUtil.isEmpty(contract.getOldContractId())) {
                break;
            }
            id = contract.getOldContractId();
        }
        List<ContractVo> contractVos = BeanUtil.copyToList(contractList, ContractVo.class);
        // 赋值流程id
        flowExampleService.setFlowId(contractVos, ContractVo::setFlowId);
        return contractVos;
    }

    /**
     * 获取合同相关的所有采购合同版本列表
     */
    @Override
    public List<Purchase> getPurchaseListByContractId(Long id) {
        return purchaseService.list(q -> q.eq(Purchase::getDataResourceId, id));
    }

    /**
     * 根据合同id获取合同的资金流水信息
     */
    @Override
    public List<AccountRunningWaterVo> getAccountRunningWaterByContractId(Long contractId) {
        return baseMapper.getAccountRunningWaterByContractId(contractId);
    }

    /**
     * 修改合同
     * @param contract
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateContract(Contract contract) {
        baseMapper.updateContract(contract);
    }


    /**
     * 获取应退税金额，应退税金额=付货款 * (税额/100) / (1 + (税额/100))
     *
     * @param v
     */
    private void handleRefundTax(ContractBudgetVo v) {
        // 税额/100
        double d = 0.13;
        //付货款 * 税额
        double d1 = v.getEhsdSumAmount().doubleValue() * d;
        //1 + 税额
        d1 = d1 / (1 + d);

        BigDecimal rt = new BigDecimal(String.valueOf(d1));
        //四舍五入，保留2为
        d1 = rt.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        String s1 = new BigDecimal(String.valueOf(d1)).toPlainString();
        v.setRefundableAmount(new BigDecimal(s1));
    }

}
