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.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.AvailableStockBo;
import com.fjhx.common.entity.contract.po.ContractTemplate;
import com.fjhx.common.entity.corporation.po.Corporation;
import com.fjhx.common.entity.documentary.bo.DocumentaryData;
import com.fjhx.common.enums.FlowStatusEnum1;
import com.fjhx.common.enums.PushBusinessTypeEnum;
import com.fjhx.common.service.contract.ContractTemplateService;
import com.fjhx.common.service.corporation.CorporationService;
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.FileInfo;
import com.fjhx.file.entity.FileInfoVo;
import com.fjhx.file.service.FileInfoService;
import com.fjhx.file.utils.ObsFileUtil;
import com.fjhx.flow.entity.flow.po.FlowExample;
import com.fjhx.flow.enums.FlowStatusEnum;
import com.fjhx.flow.service.flow.FlowExampleService;
import com.fjhx.item.entity.product.bo.ProductAnalysisBo;
import com.fjhx.item.entity.product.dto.ProductInfoDto;
import com.fjhx.item.entity.product.dto.ProductInfoSelectDto;
import com.fjhx.item.entity.product.po.ProductInfo;
import com.fjhx.item.enums.ProductAvailableRecordType;
import com.fjhx.item.service.product.ProductInfoService;
import com.fjhx.purchase.entity.arrival.po.ArrivalDetail;
import com.fjhx.purchase.entity.pay.po.Pay;
import com.fjhx.purchase.entity.quality.po.QualityDetail;
import com.fjhx.purchase.entity.subscribe.po.SubscribeDetail;
import com.fjhx.purchase.mapper.subscribe.SubscribeDetailMapper;
import com.fjhx.purchase.service.arrival.ArrivalDetailService;
import com.fjhx.purchase.service.pay.PayDetailService;
import com.fjhx.purchase.service.quality.QualityDetailService;
import com.fjhx.purchase.service.subscribe.SubscribeDetailService;
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.*;
import com.fjhx.sale.entity.contract.vo.*;
import com.fjhx.sale.entity.purchase.po.EhsdPurchase;
import com.fjhx.sale.entity.purchase.po.EhsdPurchaseProduct;
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.mapper.contract.ContractProductBomMapper;
import com.fjhx.sale.service.claim.ClaimContractService;
import com.fjhx.sale.service.contract.*;
import com.fjhx.sale.service.purchase.EhsdPurchaseProductService;
import com.fjhx.sale.service.purchase.EhsdPurchaseService;
import com.fjhx.socket.core.PushTypeEnum;
import com.fjhx.socket.core.WebSocketPush;
import com.fjhx.supply.service.supplier.SupplierInfoService;
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.fjhx.tenant.utils.DictUtils;
import com.fjhx.wms.entity.stock.emums.JournalType;
import com.fjhx.wms.entity.stock.po.StockWait;
import com.fjhx.wms.entity.stock.po.StockWaitDetails;
import com.fjhx.wms.service.stock.StockWaitDetailsService;
import com.fjhx.wms.service.stock.StockWaitService;
import com.ruoyi.common.annotation.TenantIgnore;
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.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
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.service.ISysDeptService;
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 org.springframework.web.bind.annotation.RequestBody;

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.function.Function;
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 SupplierInfoService supplierInfoService;

    @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 ClaimContractService claimContractService;

    @Autowired
    private AccountRequestFundsDetailService accountRequestFundsDetailService;

    @Autowired
    private ContractProjectService contractProjectService;

    @Autowired
    private ContractService contractService;

    @Autowired
    private ContractDocumentaryService contractDocumentaryService;

    @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;

    @Autowired
    private FileInfoService fileInfoService;

    @Autowired
    private ISysDeptService deptService;
    @Autowired
    private ContractProductBomService contractProductBomService;

    @Autowired
    private SubscribeDetailService subscribeDetailService;
    @Autowired
    private SubscribeDetailMapper subscribeDetailMapper;
    @Autowired
    private ContractProductBomMapper contractProductBomMapper;
    @Autowired
    private StockWaitService stockWaitService;
    @Autowired
    private StockWaitDetailsService stockWaitDetailsService;

    /**
     * 合同和样品单 下拉分页
     */
    @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());
        });

        //计算合同未到账（未结清）金额
        for (ContractVo contractVo : records) {
            contractVo.setSumContractNotClaimMoney(contractVo.getAmount().subtract(contractVo.getSumContractClaimMoney()));
        }
        return contractAndSamplePage;
    }

    /**
     * 头部统计
     *
     * @param dto
     * @return
     */
    @Override
    public Map<String, Object> getHeadStatistic(ContractSelectDto dto) {
        IWrapper<Contract> wrapper = getWrapper();
        setContractParam(dto, wrapper);
        SysUser sysUser = UserUtil.getUserInfo();

        Map<String, Object> map = new HashMap<>();
        map.put("customerList", "");
        map.put("count", BigDecimal.ZERO);
        map.put("customerCount", BigDecimal.ZERO);
        map.put("sumAmount", BigDecimal.ZERO);
        map.put("sumClaimMoney", BigDecimal.ZERO);

        if (StringUtils.isEmpty(sysUser.getUserCode())) {//不是业务员看所有
            map = baseMapper.getHeadStatistic(wrapper);
        } else {//是业务员
            List<Long> authIdList = customerService.getAuthIdList();
            if (authIdList.size() == 0) {
                return map;
            }
            wrapper.in("t1", Contract::getBuyCorporationId, authIdList);
            map = baseMapper.getHeadStatistic(wrapper);
        }
        if (MapUtils.isNotEmpty(map)) {
            String customers = map.getOrDefault("customerList", "").toString();
            int customerCount = customers.split(",").length;
            map.put("customerCount", customerCount);
        }
        return map;
    }


    /**
     * 分页
     *
     * @param dto
     * @return
     */
    @Override
    @TenantIgnore
    public Page<ContractVo> getPage(ContractSelectDto dto) {
        IWrapper<Contract> wrapper = getWrapper();
        setContractParam(dto, wrapper);
        SysUser sysUser = UserUtil.getUserInfo();
        if (StringUtils.isEmpty(sysUser.getUserCode())) {//不是业务员看所有
            return pageCommon(dto, wrapper);
        } else {//是业务员
            List<Long> authIdList = customerService.getAuthIdList();
            if (authIdList.size() == 0) {
                return new Page<>();
            }
            wrapper.in("t1", Contract::getBuyCorporationId, authIdList);
            return pageCommon(dto, wrapper);
        }
    }

    /**
     * 赋值查询参数
     *
     * @param dto
     * @param wrapper
     */
    private void setContractParam(ContractSelectDto dto, IWrapper<Contract> wrapper) {
        wrapper.orderByDesc("t1", Contract::getCreateTime);
        if (StringUtils.isNotEmpty(dto.getStatus())) {
            wrapper.eq("t1", Contract::getStatus, dto.getStatus());
        } else {
            wrapper.eq("t1", Contract::getIsChange, "0");//列表只展示未变更得数据
            wrapper.ne("t1", Contract::getIsShow, 1);
            wrapper.between("t1", Contract::getStatus, FlowStatusEnum1.DRAFT.getKey(), FlowStatusEnum1.CANCELLATION.getKey() - 1);
        }
        if (StringUtils.isNotEmpty(dto.getUserId())) {
            wrapper.eq("t1.salesmanId", dto.getUserId());
        }
        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(",")));
        }
        //生产公司id过滤
        wrapper.eq("t1", Contract::getCompanyId, dto.getCompanyId());
        //销售部门id过滤
        wrapper.eq("t1", Contract::getDeptId, dto.getDeptId());

        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().like("t1", Contract::getUserName, dto.getUserName())
                    .or().in("t1", Contract::getSellCorporationId, corporationIds)
                    .or().in("t1", Contract::getBuyCorporationId, customerIds)
            );
        }

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

        //客户名称
        if (StringUtils.isNotEmpty(dto.getCustomerName())) {
            wrapper.like("t1.customerName", dto.getCustomerName());
        }
        //业务员
        if (StringUtils.isNotEmpty(dto.getUserName())) {
            wrapper.like("t1.salesmanName", dto.getUserName());
        }
        //销售合同编号
        if (StringUtils.isNotEmpty(dto.getContractCode())) {
            wrapper.like("t1", Contract::getCode, dto.getContractCode());
        }
        //时间范围过滤
        wrapper.ge("t1", Contract::getCreateTime, dto.getBeginTime());
        wrapper.le("t1", Contract::getCreateTime, dto.getEndTime());

        //产品id过滤
        if (ObjectUtil.isNotEmpty(dto.getProductId())) {
            List<Long> contractIds = contractProductService.listObject(ContractProduct::getContractId, q -> q.eq(ContractProduct::getProductId, dto.getProductId()));
            contractIds.add(-1L);
            contractIds = contractIds.stream().distinct().collect(Collectors.toList());
            wrapper.in("t1.id", contractIds);
        }

        //是否结清过滤
        wrapper.eq("t1", Contract::getIsSettled, dto.getIsSettled());

        //过滤作废的数据
        wrapper.ne("t1", Contract::getStatus, FlowStatusEnum1.CANCELLATION.getKey());

        //交期时间范围过滤
        wrapper.ge("t1", Contract::getDeliveryTime, dto.getDeliveryTimeSta());
        wrapper.le("t1", Contract::getDeliveryTime, dto.getDeliveryTimeEnd());

        //订单类型过滤
        wrapper.eq("t1", Contract::getType, dto.getType());
    }

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

    /**
     * 分页公共代码抽取
     */
    private Page<ContractVo> pageCommon(ContractSelectDto dto, IWrapper<Contract> wrapper) {
        Page<ContractVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);
        List<ContractVo> list = page.getRecords();
        if (CollectionUtils.isEmpty(list)) {
            return page;
        }
        //获取部门列表
        List<SysDept> companyList = deptService.list();
        Map<Long, String> companyMap = companyList.stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getDeptName));

        //获取合同类型字典内容
        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);

        //获取合同产品明细
        List<ContractProduct> productList = contractProductService.list(q -> q.in(ContractProduct::getContractId, ids));
        List<ContractProductVo> contractProductVos = BeanUtil.copyToList(productList, ContractProductVo.class);
        //赋值物料信息
        productInfoService.attributeAssign(contractProductVos, ContractProduct::getProductId, (item, productInfo) -> {
            item.setProductCode(productInfo.getCustomCode());
            item.setProductName(productInfo.getName());
            item.setProductLength(productInfo.getLength());
            item.setProductWidth(productInfo.getWidth());
            item.setProductHeight(productInfo.getHeight());
            item.setProductColor(productInfo.getColor());
        });
        //赋值产品图片信息
        List<Long> productIds = contractProductVos.stream().map(ContractProduct::getProductId).distinct().collect(Collectors.toList());
        Map<Long, List<FileInfoVo>> productFileMap = ObsFileUtil.getFileMap(productIds, 0);
        for (ContractProductVo contractProductVo : contractProductVos) {
            List<FileInfoVo> fileInfoVoList = productFileMap.get(contractProductVo.getProductId());
            if (ObjectUtil.isNotEmpty(fileInfoVoList)) {
                FileInfoVo fileInfoVo = fileInfoVoList.get(0);
                contractProductVo.setProductImgUrl(fileInfoVo.getFileUrl());
            }
        }


        Map<Long, List<ContractProductVo>> cpMap = contractProductVos.stream().collect(Collectors.groupingBy(ContractProduct::getContractId));


        // 获取包装附件
        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());
                //赋值业务员
                p.setUserName(p.getSalesmanName());
            }

            // 赋值交接单附件
            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()));

            //赋值生产公司
            p.setCompanyName(companyMap.get(p.getCompanyId()));

            //赋值销售部门
            p.setDeptName(companyMap.get(p.getDeptId()));

            //赋值产品明细
            p.setContractProductList(cpMap.get(p.getId()));

        }

        // 赋值流程id
        List<ContractVo> collect = list.stream().filter(item -> Objects.isNull(item.getFlowId())).collect(Collectors.toList());
        flowExampleService.setFlowId(collect, ContractVo::setFlowId);
        //赋值原卖方公司名称 多公司
        corporationService.attributeAssign(list, ContractVo::getSellCorporationId, (item, corporation) -> {
            item.setSellCorporationName(corporation.getName());
        });

        return page;
    }

    /**
     * 利润预算表公共条件
     */
    private IWrapper<Contract> getProfitBudgetPageWrapper(ContractSelectDto dto) {
        IWrapper<Contract> wrapper = getWrapper();
        wrapper.orderByDesc("t1", Contract::getCreateTime);
        wrapper.eq("t1", Contract::getIsChange, "0");//列表只展示未变更得数据
        wrapper.ne("t1", Contract::getIsShow, 1);
        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"));
        }

        //客户名称
        if (StringUtils.isNotEmpty(dto.getCustomerName())) {
            wrapper.like("t1.name", dto.getCustomerName());
        }
        //业务员
        if (StringUtils.isNotEmpty(dto.getUserName())) {
            wrapper.like("t1.nick_name", dto.getUserName());
        }
        //销售合同编号
        if (StringUtils.isNotEmpty(dto.getContractCode())) {
            wrapper.like("t1", Contract::getCode, dto.getContractCode());
        }
        //时间范围过滤
        wrapper.ge("t1", Contract::getCreateTime, dto.getBeginTime());
        wrapper.le("t1", Contract::getCreateTime, dto.getEndTime());

        //销售合同id过滤
        wrapper.eq("t1.contractId", dto.getId());

        //是否结清过滤
        wrapper.eq("t1", Contract::getIsSettled, dto.getIsSettled());

        //是否亏损过滤
        Integer isLoss = dto.getIsLoss();
        if (ObjectUtil.isNotEmpty(isLoss)) {
            if (Objects.equals(isLoss, 1)) {
                wrapper.apply("(t1.amount*t1.rate)<t1.sumPurchaseContractMoney");
            } else {
                wrapper.apply("(t1.amount*t1.rate)>=t1.sumPurchaseContractMoney");
            }
        }

        return wrapper;
    }

    /**
     * 利润预算
     *
     * @param dto
     * @return
     */
    @Override
    public Page<ContractBudgetVo> getProfitBudgetPage(ContractSelectDto dto) {
        IWrapper<Contract> wrapper = getProfitBudgetPageWrapper(dto);
        return getProfitBudgetPage(dto, wrapper);
    }

    @Override
    public Page<ContractBudgetVo> getProfitBudgetPage(ContractSelectDto dto, IWrapper<Contract> wrapper) {

        Page<ContractBudgetVo> page = this.baseMapper.getProfitBudgetPage(dto.getPage(), wrapper);
        List<ContractBudgetVo> list = page.getRecords();
        if (ObjectUtil.isEmpty(list)) {
            return page;
        }

        //计数预算信息
        statisticCommon(list);

        //计数历史毛利率图
        setGrossProfitInfoList(list);

        //添加采购列表
        List<Long> ids = list.stream().map(ContractBudgetVo::getContractId).collect(Collectors.toList());
        Map<Long, List<EhsdPurchase>> map = ehsdPurchaseService.mapKGroup(EhsdPurchase::getDataResourceId,
                q -> q.in(EhsdPurchase::getDataResourceId, ids).in(EhsdPurchase::getStatus, 12, 30, 60));
        list.forEach(item -> item.setPurchasesList(map.get(item.getContractId())));

        for (ContractBudgetVo contractBudgetVo : list) {
            //赋值采购列表
            contractBudgetVo.setPurchasesList(map.get(contractBudgetVo.getContractId()));
//            //赋值是否亏损
//            BigDecimal ehsdSumAmount = contractBudgetVo.getEhsdSumAmount();
//            ehsdSumAmount = ObjectUtil.isEmpty(ehsdSumAmount)?BigDecimal.ZERO:ehsdSumAmount;
//            contractBudgetVo.setIsLoss(contractBudgetVo.getRmbContractAmount().compareTo(ehsdSumAmount)<0?1:0);
        }

        return page;
    }


    /**
     * 获取合同历史版本毛利信息
     */
    private void setGrossProfitInfoList(List<ContractBudgetVo> list) {
        List<Long> contractIds = list.stream().map(ContractBudgetVo::getContractId).collect(Collectors.toList());
        List<Contract> contractList = recursionOldContract(contractIds);
        List<Long> allContractIds = contractList.stream().map(Contract::getId).collect(Collectors.toList());
        Map<Long, Contract> contractMap = contractList.stream().collect(Collectors.groupingBy(Contract::getId,
                Collectors.collectingAndThen(Collectors.toList(), value -> value.get(0))));

        List<EhsdPurchase> ehsdPurchaseList = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(allContractIds)) {
            ehsdPurchaseList = ehsdPurchaseService.list(q -> q.in(EhsdPurchase::getDataResourceId, allContractIds)
                    .in(EhsdPurchase::getStatus, 10, 30, 60, 70));
        }

        for (ContractBudgetVo contractBudgetVo : list) {
            Long contractId = contractBudgetVo.getContractId();

            //递归出所有子合同
            List<Contract> arr = new ArrayList<>();
            Long oldContractId = contractId;
            while (ObjectUtil.isNotEmpty(oldContractId)) {
                Contract contract = contractMap.get(oldContractId);
                if (ObjectUtil.isNotEmpty(contract)) {
                    oldContractId = contract.getOldContractId();
                    arr.add(contract);
                } else {
                    oldContractId = null;
                }
            }

            List<Long> collect = arr.stream().map(Contract::getId).collect(Collectors.toList());
            List<EhsdPurchase> ehsdPurchaseList1 = ehsdPurchaseList.stream()
                    .filter(item -> collect.contains(item.getDataResourceId())).collect(Collectors.toList());

            //合并两个结果
            List<ContractBudgetVo.GrossProfitInfo> grossProfitInfoList = new ArrayList<>();
            for (Contract contract : arr) {
                ContractBudgetVo.GrossProfitInfo grossProfitInfo = new ContractBudgetVo.GrossProfitInfo();
                grossProfitInfo.setContractAmount(contract.getAmount());
                grossProfitInfo.setContractCurrency(contract.getCurrency());
                grossProfitInfo.setContractRmbAmount(contract.getAmount().multiply(contract.getRate()));
                grossProfitInfo.setCreateTime(contract.getCreateTime());
                grossProfitInfo.setId(contract.getId());
                grossProfitInfo.setType(1);
                grossProfitInfoList.add(grossProfitInfo);
            }
            for (EhsdPurchase ehsdPurchase : ehsdPurchaseList1) {
                ContractBudgetVo.GrossProfitInfo grossProfitInfo = new ContractBudgetVo.GrossProfitInfo();
                grossProfitInfo.setPurchaseAmount(ehsdPurchase.getAmount());
                grossProfitInfo.setCreateTime(ehsdPurchase.getCreateTime());
                grossProfitInfo.setId(ehsdPurchase.getId());
                grossProfitInfo.setOldPurchaseId(ehsdPurchase.getOldPurchaseId());
                grossProfitInfo.setType(2);
                grossProfitInfoList.add(grossProfitInfo);
            }
            //按时间升序
            grossProfitInfoList = grossProfitInfoList.stream()
                    .sorted(Comparator.comparing(ContractBudgetVo.GrossProfitInfo::getCreateTime)).collect(Collectors.toList());

            //计数采购价格
            BigDecimal lastContractAmount = BigDecimal.ZERO;
            String lastContractCurrency = "";
            BigDecimal lastContractRmbAmount = BigDecimal.ZERO;
            BigDecimal lastPurchaseAmount = BigDecimal.ZERO;
            for (ContractBudgetVo.GrossProfitInfo grossProfitInfo : grossProfitInfoList) {
                if (grossProfitInfo.getType() == 2) {
                    //如果是采购节点
                    BigDecimal purchaseAmount = BigDecimal.ZERO;
                    //获取当前节点之前的节点，并过滤出有效的数据
//                    List<EhsdPurchase> oldPurchase = ehsdPurchaseService.list(q -> q
//                            .eq(EhsdPurchase::getDataResourceId,contractBudgetVo.getContractId())
//                            .lt(EhsdPurchase::getCreateTime, grossProfitInfo.getCreateTime())
//                            .in(EhsdPurchase::getStatus, 10, 30, 60, 70));

                    List<EhsdPurchase> oldPurchase = ehsdPurchaseList.stream()
                            .filter(item -> item.getCreateTime().before(grossProfitInfo.getCreateTime()))
                            .filter(item -> item.getDataResourceId().equals(contractBudgetVo.getContractId()))
                            .sorted(Comparator.comparing(EhsdPurchase::getCreateTime))
                            .collect(Collectors.toList());

                    List<Long> oldIds = oldPurchase.stream().map(EhsdPurchase::getOldPurchaseId).collect(Collectors.toList());
                    for (EhsdPurchase ehsdPurchase : oldPurchase) {
                        //过滤掉历史节点中非有效节点 和 非当前节点父节点的数据
                        if (!oldIds.contains(ehsdPurchase.getId()) && !Objects.equals(ehsdPurchase.getId(), grossProfitInfo.getOldPurchaseId())) {
                            purchaseAmount = purchaseAmount.add(ehsdPurchase.getAmount());
                        }
                    }
                    //当前节点采购金额加上之前的有效采购金额
                    purchaseAmount = purchaseAmount.add(grossProfitInfo.getPurchaseAmount());

                    grossProfitInfo.setContractAmount(lastContractAmount);
                    grossProfitInfo.setContractCurrency(lastContractCurrency);
                    grossProfitInfo.setContractRmbAmount(lastContractRmbAmount);

                    grossProfitInfo.setPurchaseAmount(purchaseAmount);
                    lastPurchaseAmount = purchaseAmount;
                } else {
                    //销售合同节点
                    lastContractAmount = grossProfitInfo.getContractAmount();
                    lastContractRmbAmount = grossProfitInfo.getContractRmbAmount();
                    lastContractCurrency = grossProfitInfo.getContractCurrency();
                    grossProfitInfo.setPurchaseAmount(lastPurchaseAmount);
                }
//            }
//
//            //赋值信息
//            BigDecimal lastContractAmount = BigDecimal.ZERO;
//            String lastContractCurrency = "";
//            BigDecimal lastContractRmbAmount = BigDecimal.ZERO;
//            BigDecimal lastPurchaseAmount = BigDecimal.ZERO;
//            for (ContractBudgetVo.GrossProfitInfo grossProfitInfo : grossProfitInfoList) {
//                BigDecimal contractRmbAmount = grossProfitInfo.getContractRmbAmount();
//                BigDecimal purchaseAmount = grossProfitInfo.getPurchaseAmount();
//                if (ObjectUtil.isEmpty(contractRmbAmount)) {
//                    grossProfitInfo.setContractAmount(lastContractAmount);
//                    grossProfitInfo.setContractCurrency(lastContractCurrency);
//                    grossProfitInfo.setContractRmbAmount(lastContractRmbAmount);
//                }
//                //赋值上次金额
//                lastContractRmbAmount = grossProfitInfo.getContractRmbAmount();
//                lastContractAmount = grossProfitInfo.getContractAmount();
//                lastContractCurrency = grossProfitInfo.getContractCurrency();
//                lastPurchaseAmount = grossProfitInfo.getPurchaseAmount();


                //计数毛利

                //退税金额
                BigDecimal refundableAmount = contractBudgetVo.getRefundableAmount();
                //总收入
                BigDecimal incomeAmount = grossProfitInfo.getContractRmbAmount().add(refundableAmount);

                //计算支出总计 除合同金额(转人民币)+应退税金额(转人民币) 其他金额相加
                BigDecimal expenditureAmount = (contractBudgetVo.getTrailerFee() == null ? BigDecimal.ZERO : contractBudgetVo.getTrailerFee())
                        .add(contractBudgetVo.getCustomsFee() == null ? BigDecimal.ZERO : contractBudgetVo.getCustomsFee())
                        .add(contractBudgetVo.getAgencyFee() == null ? BigDecimal.ZERO : contractBudgetVo.getAgencyFee())
                        .add(contractBudgetVo.getPortMixedFee() == null ? BigDecimal.ZERO : contractBudgetVo.getPortMixedFee())
                        .add(contractBudgetVo.getInspectionRedPack() == null ? BigDecimal.ZERO : contractBudgetVo.getInspectionRedPack())
                        .add(contractBudgetVo.getCommission() == null ? BigDecimal.ZERO : contractBudgetVo.getCommission())
                        .add(contractBudgetVo.getOther() == null ? BigDecimal.ZERO : contractBudgetVo.getOther());
                expenditureAmount = expenditureAmount.add(grossProfitInfo.getPurchaseAmount() == null ? BigDecimal.ZERO : grossProfitInfo.getPurchaseAmount());

                BigDecimal grossProfit = incomeAmount.subtract(expenditureAmount);
                grossProfitInfo.setGross(grossProfit.setScale(2, BigDecimal.ROUND_HALF_UP));

            }
            contractBudgetVo.setGrossProfitInfoList(grossProfitInfoList);
        }
    }

    /**
     * 递归合同历史版本
     *
     * @return
     */
    private List<Contract> recursionOldContract(List<Long> contractIds) {
        List<Contract> contract = this.list(q -> q.in(Contract::getId, contractIds).in(Contract::getStatus, 10, 30, 60, 70));
        List<Long> contractIds1 = contract.stream().map(Contract::getOldContractId).distinct()
                .filter(item -> ObjectUtil.isNotEmpty(item)).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(contractIds1)) {
            List<Contract> contractList = recursionOldContract(contractIds1);
            contract.addAll(contractList);
        }
        return contract;
    }

    /**
     * 利润预算表头部统计
     *
     * @param dto
     * @return
     */
    @Override
    public Map<String, Object> getProfitBudgetHeadStatistic(ContractSelectDto dto) {
        IWrapper<Contract> wrapper = getProfitBudgetPageWrapper(dto);

        List<ContractBudgetVo> list = this.baseMapper.getProfitBudgetHeadStatistic(wrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            statisticCommon(list);
        }
        //统计金额
        return sumStatistic(list);
    }

    /**
     * 利润预算表统计公共方法
     *
     * @param list
     */
    private void statisticCommon(List<ContractBudgetVo> list) {
        //取出EHSD采购所有金额和货币-通过合同ID分组
        List<Long> contractIds = list.stream().map(ContractBudgetVo::getContractId).collect(Collectors.toList());

        //获取合同对应的采购信息
        Map<Long, List<EhsdPurchase>> ehsdPurchaseMap = ehsdPurchaseService.mapKGroup(EhsdPurchase::getDataResourceId, q -> q
                .in(EhsdPurchase::getStatus, 10, 30)
                .in(EhsdPurchase::getDataResourceId, contractIds)
        );

        List<EhsdPurchaseProductVo> ehsdAmountList = ehsdPurchaseProductService.getPurchaseByContractId(contractIds);
        Map<Long, List<EhsdPurchaseProductVo>> ehsdAmountMap = ehsdAmountList.stream().collect(Collectors.groupingBy(EhsdPurchaseProductVo::getDataResourceId));
        for (ContractBudgetVo v : list) {
            BigDecimal purchaseAmount = BigDecimal.ZERO;
            BigDecimal peritectoidAmount = BigDecimal.ZERO;
            BigDecimal accessoriesAmount = BigDecimal.ZERO;
            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));
                /**
                 * 处理应付款金额-包材金额-配件金额
                 */
                List<EhsdPurchaseProductVo> pList = ehsdAmountMap.getOrDefault(v.getContractId(), null);
                if (CollectionUtils.isNotEmpty(pList)) {
                    for (EhsdPurchaseProductVo e : pList) {
                        //获取汇率
                        BigDecimal rate = map.getOrDefault(e.getCurrency(), BigDecimal.ONE);
                        // 获取认领金额
                        BigDecimal money = e.getAmount();
                        //总金额
                        BigDecimal amount = rate.multiply(money);
//                        purchaseAmount = purchaseAmount.add(amount);
                        if (ObjectUtil.isNotEmpty(e.getProductCategoryIds())) {
                            if (e.getProductCategoryIds().contains("1685534140512616449") || e.getProductCategoryId() == 1685534140512616449L) {//包材
                                peritectoidAmount = peritectoidAmount.add(amount);
                            }
                            if (e.getProductCategoryIds().contains("1685534141821239297") || e.getProductCategoryId() == 1685534141821239297L) {//配件
                                accessoriesAmount = accessoriesAmount.add(amount);
                            }
                        }
                    }

                    //赋值采购金额
                    List<EhsdPurchase> contractPurchasesList = ehsdPurchaseMap.get(v.getContractId());
                    for (EhsdPurchase ehsdPurchase : contractPurchasesList) {
                        //获取汇率
                        BigDecimal rate = map.getOrDefault(ehsdPurchase.getCurrency(), BigDecimal.ONE);
                        // 获取认领金额
                        BigDecimal money = ehsdPurchase.getAmount();
                        //总金额
                        BigDecimal amount = rate.multiply(money);
                        purchaseAmount = purchaseAmount.add(amount);
                    }

                    v.setEhsdSumAmount(purchaseAmount);
                    v.setPeritectoidAmount(peritectoidAmount);
                    v.setAccessoriesAmount(accessoriesAmount);
                }
                //计算支出总计 除合同金额(转人民币)+应退税金额(转人民币) 其他金额相加
                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 {//没有汇率取默认汇率
                /**
                 * 处理应付款金额-包材金额-配件金额
                 */
                List<EhsdPurchaseProductVo> pList = ehsdAmountMap.getOrDefault(v.getContractId(), null);
                if (CollectionUtils.isNotEmpty(pList)) {
                    for (EhsdPurchaseProductVo e : pList) {
                        //获取汇率
                        BigDecimal rate = e.getRate();
                        // 获取认领金额
                        BigDecimal money = e.getAmount();
                        //总金额
                        BigDecimal amount = rate.multiply(money);
//                        purchaseAmount = purchaseAmount.add(amount);
                        if (ObjectUtil.isNotEmpty(e.getProductCategoryIds())) {
                            if (e.getProductCategoryIds().contains("1685534140512616449") || e.getProductCategoryId() == 1685534140512616449L) {//包材
                                peritectoidAmount = peritectoidAmount.add(amount);
                            }
                            if (e.getProductCategoryIds().contains("1685534141821239297") || e.getProductCategoryId() == 1685534141821239297L) {//配件
                                accessoriesAmount = accessoriesAmount.add(amount);
                            }
                        }
                    }

                    //赋值采购金额
                    List<EhsdPurchase> contractPurchasesList = ehsdPurchaseMap.get(v.getContractId());
                    for (EhsdPurchase ehsdPurchase : contractPurchasesList) {
                        //获取汇率
                        BigDecimal rate = ehsdPurchase.getRate();
                        // 获取认领金额
                        BigDecimal money = ehsdPurchase.getAmount();
                        //总金额
                        BigDecimal amount = rate.multiply(money);
                        purchaseAmount = purchaseAmount.add(amount);
                    }

                    v.setEhsdSumAmount(purchaseAmount);
                    v.setPeritectoidAmount(peritectoidAmount);
                    v.setAccessoriesAmount(accessoriesAmount);
                }
                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
     */
    private Map<String, Object> sumStatistic(List<ContractBudgetVo> list) {
        Map<String, Object> map = new HashMap<>();
        BigDecimal contractSumAmount = BigDecimal.ZERO;
        BigDecimal taxReturnMoneySumAmount = BigDecimal.ZERO;
        BigDecimal purchaseSumAmount = BigDecimal.ZERO;
        BigDecimal peritectoidSumAmount = BigDecimal.ZERO;
        BigDecimal accessoriesSumAmount = BigDecimal.ZERO;
        BigDecimal trailerFeeSumAmount = BigDecimal.ZERO;
        BigDecimal customsFeeSumAmount = BigDecimal.ZERO;
        BigDecimal agencyFeeSumAmount = BigDecimal.ZERO;
        BigDecimal portMixedFeeSumAmount = BigDecimal.ZERO;
        BigDecimal inspectionRedPackSumAmount = BigDecimal.ZERO;
        BigDecimal commissionSumAmount = BigDecimal.ZERO;
        BigDecimal otherSumAmount = BigDecimal.ZERO;
        BigDecimal totalIncomeSumAmount = BigDecimal.ZERO;
        BigDecimal totalExpensesSumAmount = BigDecimal.ZERO;
        BigDecimal grossProfitMargin = BigDecimal.ZERO;
        for (ContractBudgetVo p : list) {
            contractSumAmount = contractSumAmount.add(ObjectUtil.isEmpty(p.getRmbContractAmount()) ? BigDecimal.ZERO : p.getRmbContractAmount());//合同金额
            taxReturnMoneySumAmount = taxReturnMoneySumAmount.add(ObjectUtil.isEmpty(p.getRefundableAmount()) ? BigDecimal.ZERO : p.getRefundableAmount());//退税
            purchaseSumAmount = purchaseSumAmount.add(ObjectUtil.isEmpty(p.getEhsdSumAmount()) ? BigDecimal.ZERO : p.getEhsdSumAmount());//采购金额
            peritectoidSumAmount = peritectoidSumAmount.add(ObjectUtil.isEmpty(p.getPeritectoidAmount()) ? BigDecimal.ZERO : p.getPeritectoidAmount());//包材
            accessoriesSumAmount = accessoriesSumAmount.add(ObjectUtil.isEmpty(p.getAccessoriesAmount()) ? BigDecimal.ZERO : p.getAccessoriesAmount());//配件
            trailerFeeSumAmount = trailerFeeSumAmount.add(ObjectUtil.isEmpty(p.getTrailerFee()) ? BigDecimal.ZERO : p.getTrailerFee());//拖车费
            customsFeeSumAmount = customsFeeSumAmount.add(ObjectUtil.isEmpty(p.getCustomsFee()) ? BigDecimal.ZERO : p.getCustomsFee());//报关费
            agencyFeeSumAmount = agencyFeeSumAmount.add(ObjectUtil.isEmpty(p.getAgencyFee()) ? BigDecimal.ZERO : p.getAgencyFee());//代理费
            portMixedFeeSumAmount = portMixedFeeSumAmount.add(ObjectUtil.isEmpty(p.getProfitAgencyFee()) ? BigDecimal.ZERO : p.getProfitAgencyFee());//港杂费
            inspectionRedPackSumAmount = inspectionRedPackSumAmount.add(ObjectUtil.isEmpty(p.getInspectionRedPack()) ? BigDecimal.ZERO : p.getInspectionRedPack());//验货红包
            commissionSumAmount = commissionSumAmount.add(ObjectUtil.isEmpty(p.getCommission()) ? BigDecimal.ZERO : p.getCommission());//佣金
            otherSumAmount = otherSumAmount.add(ObjectUtil.isEmpty(p.getOther()) ? BigDecimal.ZERO : p.getOther());//其他
            totalIncomeSumAmount = totalIncomeSumAmount.add(ObjectUtil.isEmpty(p.getIncomeAmount()) ? BigDecimal.ZERO : p.getIncomeAmount());//总收入
            totalExpensesSumAmount = totalExpensesSumAmount.add(ObjectUtil.isEmpty(p.getExpenditureAmount()) ? BigDecimal.ZERO : p.getExpenditureAmount());//总支出
        }
        //计算总毛利和总毛利率
        BigDecimal grossProfitSum = totalIncomeSumAmount.subtract(totalExpensesSumAmount);//毛利
        if (totalIncomeSumAmount.compareTo(BigDecimal.ZERO) > 0) {
            grossProfitMargin = new BigDecimal("100").multiply(grossProfitSum).divide(totalIncomeSumAmount, 2, RoundingMode.HALF_UP);//毛利率
        }
        map.put("contractSumAmount", contractSumAmount.setScale(2, RoundingMode.HALF_UP));
        map.put("taxReturnMoneySumAmount", taxReturnMoneySumAmount.setScale(2, RoundingMode.HALF_UP));
        map.put("purchaseSumAmount", purchaseSumAmount.setScale(2, RoundingMode.HALF_UP));
        map.put("peritectoidSumAmount", peritectoidSumAmount.setScale(2, RoundingMode.HALF_UP));
        map.put("accessoriesSumAmount", accessoriesSumAmount.setScale(2, RoundingMode.HALF_UP));
        map.put("trailerFeeSumAmount", trailerFeeSumAmount.setScale(2, RoundingMode.HALF_UP));
        map.put("customsFeeSumAmount", customsFeeSumAmount.setScale(2, RoundingMode.HALF_UP));
        map.put("agencyFeeSumAmount", agencyFeeSumAmount.setScale(2, RoundingMode.HALF_UP));
        map.put("portMixedFeeSumAmount", portMixedFeeSumAmount.setScale(2, RoundingMode.HALF_UP));
        map.put("inspectionRedPackSumAmount", inspectionRedPackSumAmount.setScale(2, RoundingMode.HALF_UP));
        map.put("commissionSumAmount", commissionSumAmount.setScale(2, RoundingMode.HALF_UP));
        map.put("otherSumAmount", otherSumAmount.setScale(2, RoundingMode.HALF_UP));
        map.put("totalIncomeSumAmount", totalIncomeSumAmount.setScale(2, RoundingMode.HALF_UP));
        map.put("totalExpensesSumAmount", totalExpensesSumAmount.setScale(2, RoundingMode.HALF_UP));
        map.put("grossProfitMargin", grossProfitMargin.setScale(2, RoundingMode.HALF_UP));
        map.put("grossProfitSum", grossProfitSum.setScale(2, RoundingMode.HALF_UP));
        return map;
    }

    /**
     * 利润结算表分页
     *
     * @param dto
     * @return
     */
    @Override
    public Page<ContractBudgetVo> getProfitClearingPage(ContractSelectDto dto) {
        IWrapper<Contract> wrapper = getWrapper();
        wrapper.orderByDesc("t1", Contract::getCreateTime);
        wrapper.eq("t1", Contract::getIsChange, "0");//列表只展示未变更得数据
        wrapper.ne("t1", Contract::getIsShow, 1);
        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"));
        }

        //客户名称
        if (StringUtils.isNotEmpty(dto.getCustomerName())) {
            wrapper.like("t1.name", dto.getCustomerName());
        }
        //业务员
        if (StringUtils.isNotEmpty(dto.getUserName())) {
            wrapper.like("t1.nick_name", dto.getUserName());
        }
        //销售合同编号
        if (StringUtils.isNotEmpty(dto.getContractCode())) {
            wrapper.like("t1", Contract::getCode, dto.getContractCode());
        }
        //时间范围过滤
        wrapper.ge("t1", Contract::getCreateTime, dto.getBeginTime());
        wrapper.le("t1", Contract::getCreateTime, dto.getEndTime());

        //销售合同id过滤
        wrapper.eq("t1", Contract::getId, dto.getId());

        //是否结清过滤
        wrapper.eq("t1", Contract::getIsSettled, dto.getIsSettled());

        //是否亏损过滤
        Integer isLoss = dto.getIsLoss();
        if (ObjectUtil.isNotEmpty(isLoss)) {
            if (Objects.equals(isLoss, 1)) {
                wrapper.apply("(t1.amount*t1.rate)<t1.sumPurchaseContractMoney");
            } else {
                wrapper.apply("(t1.amount*t1.rate)>=t1.sumPurchaseContractMoney");
            }
        }

        Page<ContractBudgetVo> page = this.baseMapper.getProfitClearingPage(dto.getPage(), wrapper);
        List<ContractBudgetVo> list = page.getRecords();
        if (ObjectUtil.isEmpty(list)) {
            return page;
        }
        // 赋值客户名称
        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)
                .in(EhsdPurchase::getStatus, FlowStatusEnum1.UNDER_REVIEW.getKey(), FlowStatusEnum1.PASS.getKey())
        );
        Map<Long, List<EhsdPurchase>> purchaseMap = purchaseList.stream().collect(Collectors.groupingBy(EhsdPurchase::getDataResourceId));
        for (ContractBudgetVo v : list) {
            v.setOtherIncomeAmount(BigDecimal.ZERO);//暂时先设置其他收入为0

            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)));
            //采购合同总金额
            getSumPurchaseContractMoney(v, purchaseMap.getOrDefault(v.getContractId(), null));
            //支出费用
            this.getGroupTypeMoney(v);

            //计算收入总计=合同金额(转人民币)+应退税金额(转人民币)+其他收入(转人民币)
            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.getAgencyFee()).add
                    (v.getProfitAgencyFee()));
            //计算毛利 收入-支出
            v.setGross(v.getIncomeAmount().subtract(v.getExpenditureAmount()));
            //计算毛利率 毛利/收入
            if (v.getGross().compareTo(BigDecimal.ZERO) == 0) {
                v.setGrossRate(BigDecimal.ZERO);
            } else {
                BigDecimal grossRate = BigDecimal.ZERO;
                if (v.getIncomeAmount().compareTo(BigDecimal.ZERO) != 0) {
                    v.getGross().divide(v.getIncomeAmount(), RoundingMode.CEILING).multiply(new BigDecimal("100"));
                }
                v.setGrossRate(grossRate);
            }

            //赋值采购列表
            v.setPurchasesList(purchaseMap.get(v.getContractId()));
        }
        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));
        List<ContractProductVo> contractProductVos = BeanUtil.copyToList(contractProductList, ContractProductVo.class);
        List<Long> contractProductIds = contractProductVos.stream().map(ContractProduct::getId).collect(Collectors.toList());


        //赋值产品BOM
        Map<Long, List<ContractProductBomVo>> cpbMap = new HashMap<>();
        if (ObjectUtil.isNotEmpty(contractProductIds)) {
            List<ContractProductBom> bomList = contractProductBomService.list(q -> q.in(ContractProductBom::getContractProductId, contractProductIds));
            List<ContractProductBomVo> contractProductBomVos = BeanUtil.copyToList(bomList, ContractProductBomVo.class);
            //赋值物料信息
            productInfoService.attributeAssign(contractProductBomVos, ContractProductBom::getMaterialId, (item, productInfo) -> {
                item.setProductCode(productInfo.getCustomCode());
                item.setProductName(productInfo.getName());
                item.setProductLength(productInfo.getLength());
                item.setProductWidth(productInfo.getWidth());
                item.setProductHeight(productInfo.getHeight());
                item.setProductColor(productInfo.getColor());
            });
            cpbMap = contractProductBomVos.stream().collect(Collectors.groupingBy(ContractProductBom::getContractProductId));
        }

        //赋值产品BOM
        for (ContractProductVo cp : contractProductVos) {
            cp.setContractProductBomList(cpbMap.get(cp.getId()));
        }

        productInfoService.attributeAssign(contractProductVos, ContractProduct::getProductId, (item, product) -> {
            item.setProductCnName(product.getName());
            item.setProductCode(product.getCustomCode());
            item.setProductUnit(product.getUnit());

            item.setProductLength(product.getLength());
            item.setProductWidth(product.getWidth());
            item.setProductHeight(product.getHeight());
            item.setProductColor(product.getColor());
        });
        //重新赋值待采购数量
        List<EhsdPurchaseProduct> purchaseProducts = ehsdPurchaseProductService.getPurchaseProductByContractProductIds(contractProductIds);
        if (ObjectUtil.isNotEmpty(purchaseProducts)) {
            Map<Long, List<EhsdPurchaseProduct>> collect = purchaseProducts.stream()
                    .filter(item -> ObjectUtil.isNotEmpty(item.getDataResourceId()))
                    .collect(Collectors.groupingBy(EhsdPurchaseProduct::getDataResourceId));
            for (ContractProduct contractProduct : contractProductVos) {
                List<EhsdPurchaseProduct> ehsdPurchaseProductList = collect.get(contractProduct.getId());
                if (ObjectUtil.isEmpty(ehsdPurchaseProductList)) {
                    contractProduct.setExpendQuantity(BigDecimal.ZERO);
                    continue;
                }
                BigDecimal purchaseQuantity = ehsdPurchaseProductList.stream().map(EhsdPurchaseProduct::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal subtract = contractProduct.getQuantity().subtract(purchaseQuantity);
                contractProduct.setExpendQuantity(subtract);
            }
        }
        result.setContractProductList(contractProductVos);

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

        //赋值历史毛利图信息
        IWrapper<Contract> wrapper = IWrapper.<Contract>getWrapper().eq("t1.contractId", result.getId());
        Page<ContractBudgetVo> profitBudgetPage = getProfitBudgetPage(new ContractSelectDto(), wrapper);

        List<ContractBudgetVo> records = profitBudgetPage.getRecords();
        if (ObjectUtil.isNotEmpty(records)) {
            ContractBudgetVo contractBudgetVo = records.get(0);
            List<ContractBudgetVo.GrossProfitInfo> grossProfitInfoList = contractBudgetVo.getGrossProfitInfoList();
            result.setGrossProfitInfoList(grossProfitInfoList);
        }

        //赋值归属公司
        SysDept company = deptService.getById(result.getCompanyId());
        if (ObjectUtil.isNotEmpty(company)) {
            result.setCompanyName(company.getDeptName());
        }

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

    @DSTransactional
    @Override
    public void cancellation(ContractDto contractDto) {
        Long id = contractDto.getId();
        Contract contract = getById(id);
        Assert.notEmpty(contract, "查询不到合同信息");

        //修改流程审批状态
        flowExampleService.update(q -> q
                .eq(FlowExample::getId, contract.getFlowId())
                .in(FlowExample::getStatus, 0, 1)
                .set(FlowExample::getStatus, FlowStatusEnum.CANCELLATION.getKey())
                .set(BasePo::getUpdateTime, new Date())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
        );

        //如果审批中作废
        if (Objects.equals(FlowStatusEnum1.UNDER_REVIEW.getKey(), contract.getStatus())) {
            contractService.update(q -> q
                    .eq(Contract::getId, id)
                    .set(Contract::getStatus, FlowStatusEnum1.CANCELLATION.getKey())
                    .set(BasePo::getUpdateTime, new Date())
                    .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
            );

            //恢复原合同
            Long oldContractId = contract.getOldContractId();
            if (ObjectUtil.isNotEmpty(oldContractId)) {
                contractService.update(q -> q
                        .eq(Contract::getId, contract.getOldContractId())
                        .set(Contract::getStatus, FlowStatusEnum1.PASS.getKey())
                        .set(Contract::getUpdateTime, new Date())
                        .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
                );
            }
            return;
        }


        contractService.update(q -> q
                .eq(Contract::getId, id)
                .set(Contract::getStatus, FlowStatusEnum1.CANCELLATION.getKey())
                .set(BasePo::getUpdateTime, new Date())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
        );


        contractCancelEditAvailableQuantity(contract);
    }

    /**
     * 合同作废修改可用库存 //可用库存=可用库存-((待采购量-已采购量)-合同量)
     */
    private void contractCancelEditAvailableQuantity(Contract contract) {
        Long businessId = contract.getId();

        //获取待采购量Map
        List<SubscribeDetail> subscribeDetailList = subscribeDetailService.list(q -> q.eq(SubscribeDetail::getContractId, businessId));
        Map<Long, List<SubscribeDetail>> subscribeDetailMap = subscribeDetailList.stream().collect(Collectors.groupingBy(SubscribeDetail::getProductId));

        //获取已采购数量Map
        List<Long> sdIds = subscribeDetailList.stream().map(SubscribeDetail::getId).collect(Collectors.toList());
        List<SubscribeDetail> purchaseCountByIds = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(sdIds)) {
            purchaseCountByIds = subscribeDetailMapper.getPurchaseCountByIds(sdIds);

            //存在已采购数据禁止作废
            List<EhsdPurchase> ehsdPurchaseList = ehsdPurchaseService.list(q -> q.eq(EhsdPurchase::getDataResourceId, businessId).eq(EhsdPurchase::getStatus, 30));
            if (ObjectUtil.isNotEmpty(ehsdPurchaseList)) {
                String codes = ehsdPurchaseList.stream().map(EhsdPurchase::getCode).collect(Collectors.joining("，"));
                throw new ServiceException("该订单存在审批通过的采购合同,请先作废采购合同,采购合同号：" + codes);
            }
        }
        Map<Long, BigDecimal> purchaseCountMap = purchaseCountByIds.stream().collect(Collectors.toMap(SubscribeDetail::getId, SubscribeDetail::getCount));

        List<AvailableStockBo> inOutBoList = new ArrayList<>();

        //获取产品BOM列表
        List<ContractProductBomVo> contractProductBomList = contractProductBomMapper.getContractProductBomQuantitySum(businessId);
        for (ContractProductBom contractProductBom : contractProductBomList) {
            Long materialId = contractProductBom.getMaterialId();
            //获取待采购量
            List<SubscribeDetail> subscribeDetailList1 = subscribeDetailMap.getOrDefault(materialId, new ArrayList<>());
            BigDecimal subscribeDetailCount = subscribeDetailList1.stream().map(SubscribeDetail::getCount).reduce(BigDecimal.ZERO, BigDecimal::add);
            //获取已采购量
            BigDecimal purchaseCount = BigDecimal.ZERO;
            for (SubscribeDetail subscribeDetail : subscribeDetailList1) {
                purchaseCount.add(purchaseCountMap.getOrDefault(subscribeDetail.getProductId(), BigDecimal.ZERO));
            }
            //获取合同量
            //可用库存=可用库存-((待采购量-已采购量)-合同量)
            BigDecimal subtract = subscribeDetailCount.subtract(purchaseCount);
            BigDecimal subtract1 = subtract.subtract(contractProductBom.getQuantity());

            AvailableStockBo inOutBo = new AvailableStockBo();
            inOutBo.setProductId(materialId);
            inOutBo.setQuantity(subtract1);
            inOutBoList.add(inOutBo);
        }

        //修改申购明细状态
        if (ObjectUtil.isNotEmpty(sdIds)) {
            subscribeDetailService.update(q -> q
                    .in(SubscribeDetail::getId, sdIds)
                    .set(SubscribeDetail::getStatus, 88)
            );
        }

        //作废审批中的采购合同
        ehsdPurchaseService.update(q -> q
                .eq(EhsdPurchase::getDataResourceId, businessId)
                .eq(EhsdPurchase::getStatus, 10)
                .set(EhsdPurchase::getStatus, FlowStatusEnum1.CANCELLATION.getKey())
                .set(BasePo::getUpdateTime, new Date())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
        );
        List<Long> flowIds = ehsdPurchaseService.listObject(EhsdPurchase::getFlowId, q -> q.eq(EhsdPurchase::getDataResourceId, businessId));
        if (ObjectUtil.isNotEmpty(flowIds)) {
            //修改流程审批状态
            flowExampleService.update(q -> q
                    .in(FlowExample::getId, flowIds)
                    .in(FlowExample::getStatus, 0, 1)
                    .set(FlowExample::getStatus, FlowStatusEnum.CANCELLATION.getKey())
                    .set(BasePo::getUpdateTime, new Date())
                    .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
            );
        }


        //修改可用库存 可用库存=可用库存-((待采购量-已采购量)-合同量)
        productInfoService.editAvailableQuantity(
                inOutBoList,
                businessId,
                ProductAvailableRecordType.SALE_CANCEL, contract.getCompanyId()
        );

        //修改合同审批状态
        flowExampleService.update(q -> q
                .eq(FlowExample::getId, contract.getFlowId())
                .in(FlowExample::getStatus, 0, 1)
                .set(FlowExample::getStatus, FlowStatusEnum.CANCELLATION.getKey())
                .set(BasePo::getUpdateTime, new Date())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
        );

        //作废生产相关数据 订单、排除、任务、备料
        long count = baseMapper.getProductionOrderCount(IWrapper.getWrapper()
                .in("po.produce_status", 1, 2)
                .eq("po.contract_id", contract.getId())
        );
        if (count > 0) {
            throw new ServiceException("该销售订单存在,生产中或生产完成的生产订单信息，禁止作废！");
        }
        baseMapper.removeProductionOrderByContractId(contract.getId());
        baseMapper.removeProductionOrderDetailByContractId(contract.getId());
        baseMapper.removeMaterialPreparationoByContractId(contract.getId());
    }

    @Override
    public void modifyAgencyFee(ContractDto contractDto) {
        this.update(q -> q
                .eq(Contract::getId, contractDto.getId())
                .set(Contract::getProfitAgencyFee, contractDto.getProfitAgencyFee())
                .set(BasePo::getUpdateTime, new Date())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
        );
    }

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

        setExportContractInfo(contractPdfInfoVo, contract);

        return contractPdfInfoVo;
    }

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

    /**
     * 查询销售额（合同总金额）
     *
     * @param id (买方公司ID)
     */
    @Override
    public Page<ContractVo> getSalesTotalList(Page<Object> page, Long id) {
        return baseMapper.getSalesTotalList(page, 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);

        //刷新合同是否有样品单附件状态
        DynamicDataSourceContextHolder.push(SourceConstant.BASE);
        long count = fileInfoService.count(q -> q.eq(FileInfo::getBusinessId, dto.getId()).eq(FileInfo::getBusinessType, 1));
        DynamicDataSourceContextHolder.poll();
        Integer isDeliveryFile = (count > 0) ? 1 : 0;
        contractService.update(q -> q
                .eq(Contract::getId, dto.getId())
                .set(Contract::getIsDeliveryFile, isDeliveryFile)
                .set(Contract::getUpdateTime, new Date())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
        );
    }

    /**
     * 合同销售统计（合同列表）
     */
    @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<EhsdPurchase> purchaseList = ehsdPurchaseService.listByIds(purchaseIdList);
        List<EhsdPurchaseProduct> purchaseDetailList = ehsdPurchaseProductService.list(q -> q.in(EhsdPurchaseProduct::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<EhsdPurchase> purchaseList, List<EhsdPurchaseProduct> purchaseDetailList) {

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

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

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

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

            for (EhsdPurchaseProduct purchaseDetail : itemList) {
                PayDecisionAidVo.PurchaseInfo purchaseInfo = new PayDecisionAidVo.PurchaseInfo();
                purchaseInfo.setPurchaseId(purchase.getId());
                purchaseInfo.setPurchaseCode(purchase.getCode());
                purchaseInfo.setPurchaseDetailsId(purchaseDetail.getId());
                purchaseInfo.setProductId(purchaseDetail.getProductId());
                purchaseInfo.setPurchaseQuantity(purchaseDetail.getQuantity());
                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<EhsdPurchase> purchaseList) {

        List<Long> contractIdList = purchaseList.stream()
                .filter(item -> Objects.equals(item.getDataResource(), 1))
                .map(EhsdPurchase::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> 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);

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

        CompletableFuture.allOf(
                setBuyCorporationFuture,
                setAreaFuture,
                setProductListFuture
        ).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();
        SysUser sysUser = UserUtil.getUserInfo();
        if (StringUtils.isNotEmpty(sysUser.getUserCode())) {//是业务员
            List<Long> authIdList = customerService.getAuthIdList();
            if (authIdList.size() == 0) {
                return new Page<>();
            }
            wrapper.in(Contract::getBuyCorporationId, authIdList);
        }

        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.setBuyCorporationFax(customer.getFax());
        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.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.setCreateTime(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());
        contractPdfInfoVo.setPaymentMethod(contract.getPaymentMethod());

        contractPdfInfoVo.setTemplateContent(contract.getTemplateContent());


        //赋值创建人名称
        Map<Long, SysUser> nickNameMapByIds = UserUtil.getMapByIds(Arrays.asList(contract.getCreateUser()));
        SysUser sysUser = nickNameMapByIds.get(contract.getCreateUser());
        if (ObjectUtil.isNotEmpty(sysUser)) {
            contractPdfInfoVo.setCreateUserName(sysUser.getNickName());//联系人名称
            contractPdfInfoVo.setCreateUserPhone(sysUser.getPhonenumber());//联系方式
        }

        //赋值收费项目
        List<ContractProject> contractProjectList = contractProjectService.list(q -> q.eq(ContractProject::getContractId, contract.getId()));
        contractPdfInfoVo.setContractProjectList(contractProjectList);
    }

    /**
     * 赋值商品列表信息
     */
    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());
        List<ProductInfo> productInfoList0 = productInfoService.list(q -> q.in(ProductInfo::getId, pids));
        Map<Long, ProductInfo> productInfoMap = productInfoList0.stream().collect(Collectors.toMap(ProductInfo::getId, Function.identity()));
        //获取原材料信息
        List<Long> rawMaterialIds = productInfoList0.stream().map(ProductInfo::getRawMaterialId).collect(Collectors.toList());
        Map<Long, ProductInfo> rawMaterialMap = productInfoService.mapKEntity(ProductInfo::getId, q -> q.in(ProductInfo::getId, rawMaterialIds));

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

            ContractPdfInfoVo.ProductInfo productIndo = new ContractPdfInfoVo.ProductInfo();
            //赋值合同产品信息
            productIndo.setProductId(item.getProductId());
//            productIndo.setProductName(item.getProductName());
//            productIndo.setProductLength(item.getProductLength());
//            productIndo.setProductWidth(item.getProductWidth());
//            productIndo.setProductHeight(item.getProductHeight());
            productIndo.setProductRemark(item.getRemark());
            productIndo.setProductQuantity(item.getQuantity());
            productIndo.setProductPrice(item.getPrice());
            productIndo.setAmount(item.getAmount());
            //赋值物料信息
            if (ObjectUtil.isNotEmpty(rawMaterial)) {
                productIndo.setFrontalTexture(rawMaterial.getFrontalTexture());
                productIndo.setReverseTexture(rawMaterial.getReverseTexture());
                productIndo.setProductColor(rawMaterial.getColor());
                productIndo.setProductUnit(rawMaterial.getUnit());
            }
            //赋值产品信息
            if (ObjectUtil.isNotEmpty(productInfo)) {
//                productIndo.setProductSpec(productInfo.getSpec());
                productIndo.setProductName(productInfo.getName());
                productIndo.setProductLength(productInfo.getLength());
                productIndo.setProductWidth(productInfo.getWidth());
                productIndo.setProductHeight(productInfo.getHeight());
            }

            return productIndo;
        }).collect(Collectors.toList());

        contractPdfInfoVo.setProductInfoList(productInfoList);
    }

//    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
     * @return
     */
    private BigDecimal getSumClaimMoney(List<ClaimContract> claimContractList) {
        BigDecimal sumClaimMoney = BigDecimal.ZERO;
        if (ObjectUtil.isEmpty(claimContractList)) {
            return BigDecimal.ZERO;
        }
        for (ClaimContract c : claimContractList) {
            BigDecimal moneyCny = c.getMoneyCny();
            if (ObjectUtil.isEmpty(moneyCny)) {
                moneyCny = BigDecimal.ZERO;
            }
            sumClaimMoney = sumClaimMoney.add(moneyCny);
        }
        return sumClaimMoney;
    }

    /**
     * 统采购合同总金额
     *
     * @param v
     * @param purchaseList
     * @return
     */
    private void getSumPurchaseContractMoney(ContractBudgetVo v, List<EhsdPurchase> purchaseList) {
        v.setAccountPaid(BigDecimal.ZERO);
        BigDecimal purchaseSumMoney = BigDecimal.ZERO;
        if (CollectionUtils.isEmpty(purchaseList)) {
            v.setSumPurchaseContractMoney(BigDecimal.ZERO);
            return;
        }
        List<Long> purchaseIds = purchaseList.stream().map(EhsdPurchase::getId).collect(Collectors.toList());
        for (EhsdPurchase c : purchaseList) {
            purchaseSumMoney = purchaseSumMoney.add(c.getAmount());
        }
        v.setSumPurchaseContractMoney(purchaseSumMoney);
        /**
         * 处理支付款金额
         */
        List<Pay> payList = payDetailService.getSumMoney(purchaseIds);
        if (CollectionUtils.isNotEmpty(payList)) {
            BigDecimal payAmount = payList.stream().map(pay -> {
                //获取汇率
                BigDecimal rate = pay.getRate() == null ? BigDecimal.ONE : pay.getRate();
                // 获取认领金额
                BigDecimal money = pay.getMoney();
                // 返回兑人民币后金额
                return rate.multiply(money);
            }).reduce(BigDecimal.ZERO, BigDecimal::add);
            v.setAccountPaid(payAmount);
        }

    }

    /**
     * 统计支出各种费用
     */
    private void getGroupTypeMoney(ContractBudgetVo v) {
        List<AccountRequestFundsDetailVo> list = accountRequestFundsDetailService.getListByContractId(v.getContractId());
        /**
         * 拖车费
         */
        BigDecimal trailerFee = BigDecimal.ZERO;

        /**
         * 报关费
         */
        BigDecimal customsFee = BigDecimal.ZERO;
        /**
         * 代理费
         */
        BigDecimal agencyFee = 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 = c.getRate() == null ? BigDecimal.ONE : 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"://代理费
                    agencyFee = agencyFee.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.setAgencyFee(agencyFee);
        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
        List<ContractVo> collect = contractVos.stream().filter(item -> Objects.isNull(item.getFlowId())).collect(Collectors.toList());
        flowExampleService.setFlowId(collect, ContractVo::setFlowId);
        return contractVos;
    }

    /**
     * 获取合同相关的所有采购合同版本列表
     */
    @Override
    public List<EhsdPurchase> getPurchaseListByContractId(Long id) {
        return ehsdPurchaseService.list(q -> q
                .in(EhsdPurchase::getStatus, 10, 30)
                .eq(EhsdPurchase::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) {
        if (ObjectUtil.isNotEmpty(v.getEhsdSumAmount())) {
            // 税额/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));
        } else {
            v.setRefundableAmount(BigDecimal.ZERO);
        }

    }

    /**
     * 外销跟单分页
     *
     * @param dto
     * @return
     */
    @Override
    public Page<ContractVo> getExportCopyList(ContractSelectDto dto) {
        IWrapper<Contract> wrapper = getWrapper();
        SysUser sysUser = UserUtil.getUserInfo();
        if (StringUtils.isNotEmpty(sysUser.getUserCode())) {//是业务员 过滤权限
            List<Long> authIdList = customerService.getAuthIdList();
            if (authIdList.size() == 0) {
                return new Page<>();
            }
            wrapper.in("t1", Contract::getBuyCorporationId, authIdList);
        }
        wrapper.orderByDesc("t1", Contract::getCreateTime);
        wrapper.eq("t1", Contract::getIsChange, "0");//列表只展示未变更得数据
        wrapper.ne("t1", Contract::getIsShow, 1);
        wrapper.eq("t1", Contract::getStatus, FlowStatusEnum1.PASS.getKey());
        wrapper.eq("t1.orderStatus", dto.getOrderStatus());
        if (dto.getDocumentarySearch() == 1 && ObjectUtil.isNotEmpty(dto.getDocumentaryType())) {//无记录
            wrapper.eq("t1.documentaryCount", 0);
        }
        if (dto.getDocumentarySearch() == 2 && ObjectUtil.isNotEmpty(dto.getDocumentaryType())) {//无记录
            wrapper.gt("t1.documentaryCount", 0);
        }
        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().like("t1", Contract::getUserName, dto.getUserName())
                    .or().like("t1.salesmanName", dto.getKeyword())
                    .or().in("t1", Contract::getSellCorporationId, corporationIds)
                    .or().in("t1", Contract::getBuyCorporationId, customerIds)
            );
        }

        //合同id过滤
        wrapper.eq("t1", Contract::getId, dto.getId());

        Page<ContractVo> page = baseMapper.getExportCopyList(dto.getPage(), wrapper, dto.getDocumentaryType());
        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);
            //合同产品
            List<ContractProduct> contractProductList = contractProductService.list(Wrappers.<ContractProduct>query().lambda().in(ContractProduct::getContractId, ids));
            List<ContractProductVo> contractProductVos = BeanUtil.copyToList(contractProductList, ContractProductVo.class);
            Map<Long, List<ContractProductVo>> contractProductMap = contractProductVos.stream().collect(Collectors.groupingBy(ContractProductVo::getContractId));
            //采购合同
            List<EhsdPurchase> ehsdPurchaseList = ehsdPurchaseService.list(Wrappers.<EhsdPurchase>query().lambda()
                    .in(EhsdPurchase::getDataResourceId, ids)
                    .in(EhsdPurchase::getStatus, 30, 60)//过滤审批通过和变更中的采购单
            );
            List<Long> purchaseIds = ehsdPurchaseList.stream().map(EhsdPurchase::getId).collect(Collectors.toList());
            //查询采购跟单列表
            List<ContractDocumentary> contractDocumentaryList = contractDocumentaryService.list(Wrappers.<ContractDocumentary>query().lambda().in(ContractDocumentary::getBusinessId, CollectionUtils.isEmpty(purchaseIds) ? Arrays.asList("0") : purchaseIds));
            Map<Long, List<ContractDocumentary>> contractDocumentaryMap = contractDocumentaryList.stream().collect(Collectors.groupingBy(ContractDocumentary::getBusinessId));
            //赋值采购合同供应商
            supplierInfoService.attributeAssign(ehsdPurchaseList, EhsdPurchase::getSellCorporationId, (item, supplierInfo) -> {
                item.setSupplyName(supplierInfo.getName());
            });
            Map<Long, List<EhsdPurchase>> ehsdPurchaseMap = ehsdPurchaseList.stream().collect(Collectors.groupingBy(EhsdPurchase::getDataResourceId));
            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);
                }
                // 赋值产品信息
                if (MapUtils.isNotEmpty(contractProductMap)) {
                    List<ContractProductVo> contractProducts = contractProductMap.get(p.getId());
                    p.setContractProductList(contractProducts);
                }
                // 赋值采购单信息
                if (MapUtils.isNotEmpty(ehsdPurchaseMap)) {
                    List<EhsdPurchase> purchases = ehsdPurchaseMap.get(p.getId());
                    if (ObjectUtil.isNotEmpty(purchases)) {
                        for (EhsdPurchase e : purchases) {
                            e.setPurchaseDocumentary(contractDocumentaryMap.getOrDefault(e.getId(), null));
                        }
                    }
                    p.setPurchaseList(purchases);
                }

                p.setAmountCNY(p.getAmount().multiply(p.getRate()));//CNY金额
                p.setFinalPayment(p.getAmountCNY().subtract(p.getSumClaimMoney()));//尾款
            }
        }
        //赋值原卖方公司名称 多公司
        corporationService.attributeAssign(list, ContractVo::getSellCorporationId, (item, corporation) -> {
            item.setSellCorporationName(corporation.getName());
        });
        //查询合同产品
        return page;
    }

    /**
     * 外销跟单添加备注
     *
     * @param contractVo
     */
    @DSTransactional
    @Override
    public void editContractRemark(ContractVo contractVo) {
        this.updateById(contractVo);
        ObsFileUtil.saveFile(contractVo.getRemarkFileList(), contractVo.getId(), 30);
    }

    /**
     * 合同结清
     */
    @Override
    public void settle(ContractDto dto) {
        contractService.update(q -> q
                .eq(Contract::getId, dto.getId())
                .set(Contract::getIsSettled, 1)
                .set(Contract::getUpdateTime, new Date())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
        );
    }

    /**
     * 产品分析
     */
    @Override
    public Page<ProductAnalysisBo> productAnalysis(ContractSelectDto dto) {
        IWrapper<ProductInfo> wrapper = IWrapper.getWrapper();
        Page<ProductAnalysisBo> productAnalysisPage = productInfoService.getProductAnalysisPage(dto.getPage(), wrapper);
        List<ProductAnalysisBo> records = productAnalysisPage.getRecords();
        if (ObjectUtil.isEmpty(records)) {
            return productAnalysisPage;
        }
        List<Long> productIds = records.stream().map(ProductAnalysisBo::getProductId).collect(Collectors.toList());
        List<ProductAnalysisBo> contractProductInfo = baseMapper.getContractProductInfo(IWrapper.getWrapper()
                .in("cp.product_id", productIds)
                .groupBy("cp.product_id")
                .ge("c.create_time", dto.getBeginTime())
                .le("c.create_time", dto.getEndTime())
        );
        Map<Long, ProductAnalysisBo> contractProductInfoMap = contractProductInfo.stream()
                .collect(Collectors.toMap(ProductAnalysisBo::getProductId, Function.identity()));

        List<ProductAnalysisBo> purchaseProductInfo = baseMapper.getPurchaseProductInfo(IWrapper.getWrapper()
                .in("epp.product_id", productIds)
                .groupBy("epp.product_id")
                .ge("ep.create_time", dto.getBeginTime())
                .le("ep.create_time", dto.getEndTime())
        );
        Map<Long, ProductAnalysisBo> purchaseProductInfoMap = purchaseProductInfo.stream()
                .collect(Collectors.toMap(ProductAnalysisBo::getProductId, Function.identity()));

        for (ProductAnalysisBo record : records) {

            //合同统计
            BigDecimal orderCount = BigDecimal.ZERO;
            BigDecimal saleQuantity = BigDecimal.ZERO;
            BigDecimal saleAmount = BigDecimal.ZERO;
            BigDecimal saleAveragePrice = BigDecimal.ZERO;
            BigDecimal saleMinPrice = BigDecimal.ZERO;
            BigDecimal saleMaxPrice = BigDecimal.ZERO;

            ProductAnalysisBo contractProduct = contractProductInfoMap.get(record.getProductId());
            if (ObjectUtil.isNotEmpty(contractProduct)) {
                orderCount = contractProduct.getOrderCount();
                saleQuantity = contractProduct.getSaleQuantity();
                saleAmount = contractProduct.getSaleAmount();
                //计算平均单价
                if (contractProduct.getSaleQuantity().compareTo(BigDecimal.ZERO) != 0) {
                    saleAveragePrice = contractProduct.getSaleAmount()
                            .divide(contractProduct.getSaleQuantity(), 4, RoundingMode.HALF_UP);
                }
                saleMinPrice = contractProduct.getSaleMinPrice();
                saleMaxPrice = contractProduct.getSaleMaxPrice();
            }

            record.setOrderCount(orderCount.setScale(4, RoundingMode.HALF_UP));
            record.setSaleQuantity(saleQuantity.setScale(4, RoundingMode.HALF_UP));
            record.setSaleAmount(saleAmount.setScale(4, RoundingMode.HALF_UP));
            record.setSaleAveragePrice(saleAveragePrice.setScale(4, RoundingMode.HALF_UP));
            record.setSaleMinPrice(saleMinPrice.setScale(4, RoundingMode.HALF_UP));
            record.setSaleMaxPrice(saleMaxPrice.setScale(4, RoundingMode.HALF_UP));

            //采购统计
            BigDecimal purchasesQuantity = BigDecimal.ZERO;
            BigDecimal purchasesAmount = BigDecimal.ZERO;
            BigDecimal purchasesAveragePrice = BigDecimal.ZERO;
            BigDecimal purchasesMinPrice = BigDecimal.ZERO;
            BigDecimal purchasesMaxPrice = BigDecimal.ZERO;

            ProductAnalysisBo purchaseProduct = purchaseProductInfoMap.get(record.getProductId());
            if (ObjectUtil.isNotEmpty(purchaseProduct)) {
                purchasesQuantity = purchaseProduct.getPurchasesQuantity();
                purchasesAmount = purchaseProduct.getPurchasesAmount();
                //计算平均单价
                if (purchaseProduct.getPurchasesQuantity().compareTo(BigDecimal.ZERO) != 0) {
                    purchasesAveragePrice = purchaseProduct.getPurchasesAmount()
                            .divide(purchaseProduct.getPurchasesQuantity(), 4, RoundingMode.HALF_UP);
                }
                purchasesMinPrice = purchaseProduct.getPurchasesMinPrice();
                purchasesMaxPrice = purchaseProduct.getPurchasesMaxPrice();
            }

            record.setPurchasesQuantity(purchasesQuantity.setScale(4, RoundingMode.HALF_UP));
            record.setPurchasesAmount(purchasesAmount.setScale(4, RoundingMode.HALF_UP));
            record.setPurchasesAveragePrice(purchasesAveragePrice.setScale(4, RoundingMode.HALF_UP));
            record.setPurchasesMinPrice(purchasesMinPrice.setScale(4, RoundingMode.HALF_UP));
            record.setPurchasesMaxPrice(purchasesMaxPrice.setScale(4, RoundingMode.HALF_UP));

            //计算总利润
            record.setGrossProfit(record.getSaleAmount().subtract(record.getPurchasesAmount()));
        }
        return productAnalysisPage;
    }

    @Override
    public Map<Long, Map<String, Object>> getProductPriceInfo(ProductInfoDto dto) {
        List<ProductInfo> list = productInfoService.list(q -> q.in(ProductInfo::getId, dto.getProductIds()));
        if (ObjectUtil.isEmpty(list)) {
            return new HashMap<>();
        }
        List<Long> pIds = list.stream().map(ProductInfo::getId).collect(Collectors.toList());

        //获取客户某客户近3条销售价格信息
        Map<Long, List<ContractProductVo>> customerContractProductMap = new HashMap<>();
        Long customerId = dto.getCustomerId();
        if (ObjectUtil.isNotEmpty(customerId)) {
            List<ContractProductVo> customerContractProductList = baseMapper.getProductPriceInfo(IWrapper.getWrapper()
                    .in("cp.product_id", pIds)
                    .eq("c.buy_corporation_id", customerId)
                    .orderByDesc("c.create_time")
                    .orderByDesc("c.id")
                    .last("LIMIT 3")
            );
            customerContractProductMap =
                    customerContractProductList.stream().collect(Collectors.groupingBy(ContractProduct::getProductId));
        }

        //获取产品近20条销售价格信息
        List<ContractProductVo> contractProductList = baseMapper.getProductPriceInfo(IWrapper.getWrapper()
                .in("cp.product_id", pIds)
                .orderByDesc("c.create_time")
                .orderByDesc("c.id")
                .last("LIMIT 20")
        );
        Map<Long, List<ContractProductVo>> contractProductMap =
                contractProductList.stream().collect(Collectors.groupingBy(ContractProduct::getProductId));


        //处理输出数据
        Map<Long, Map<String, Object>> reData = new HashMap<>();
        for (ProductInfo productInfo : list) {
//            ProductInfoEhsdJson ehsdJson = JSONObject.parseObject(productInfo.getEhsdJson(), ProductInfoEhsdJson.class);

            Long productInfoId = productInfo.getId();

            Map<String, Object> data = new HashMap<>();
//            //销售指导价和币种
//            data.put("price", ehsdJson.getPrice());
//            data.put("currency", ehsdJson.getCurrency());
//            //成本价和币种
//            data.put("costPrice", ehsdJson.getCostPrice());
//            data.put("costCurrency", ehsdJson.getCostCurrency());
            //销售给指定客户近3条产品价格
            data.put("customerContractProductList", customerContractProductMap.getOrDefault(productInfoId, new ArrayList<>()));
            //该产品近20条销售价格
            data.put("contractProductList", contractProductMap.getOrDefault(productInfoId, new ArrayList<>()));

            reData.put(productInfoId, data);
        }

        return reData;
    }

    /**
     * 修改合同生产标签
     */
    @DSTransactional
    @Override
    public void updateProductionTag(@RequestBody ContractDto dto) {
        Contract contract = this.getById(dto.getId());
        if (ObjectUtil.isEmpty(contract)) {
            throw new ServiceException("查询不到合同信息!");
        }
        this.update(q -> q
                .eq(Contract::getId, dto.getId())
                .set(Contract::getProdTag, dto.getProdTag())
                .set(Contract::getProdRemark, dto.getProdRemark())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
                .set(BasePo::getUpdateTime, new Date())
        );

        Map<String, String> dictMap = DictUtils.getDictMap("contract_prod_tag");
        String prodTag = contract.getProdTag();
        prodTag = ObjectUtil.isEmpty(prodTag) ? "" : prodTag;
        String[] split = prodTag.split(",");
        List<String> arr = new ArrayList<>();
        for (String s : split) {
            String s1 = dictMap.get(s);
            if (ObjectUtil.isNotEmpty(s1)) {
                arr.add(s1);
            }
        }
        String collect = arr.stream().collect(Collectors.joining(","));
        //消息推送：给归属公司的 子公司总经理
        String title = String.format("合同【%s】发生生产标签变更,变更如下：%s", contract.getCode(), collect);
        JSONObject msg = new JSONObject();
        msg.put("business_id", dto.getId());
        List<Long> generalManagerIds = UserUtil.getUserIdsByRoleKey("subsidiary_gm", dto.getCompanyId());
        for (Long generalManagerId : generalManagerIds) {
            WebSocketPush.byUser(PushTypeEnum.MESSAGE, generalManagerId, title, PushBusinessTypeEnum.CONTRACT_PRODUCTION_TAG_UPDATE.getType(), msg.toString());
        }
    }

    @DSTransactional
    @Override
    public void saleOutbound(Long id) {
        //修改订单出库状态
        this.update(q -> q
                .eq(Contract::getId, id)
                .set(Contract::getOutboundStatus, 1)
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
                .set(BasePo::getUpdateTime, new Date())
        );

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

        //生成待出库数据
        StockWait stockWait = new StockWait();
        stockWait.setType(2);
        stockWait.setBusinessType(JournalType.SALE_OUT.getDetailType());
        stockWait.setBusinessId(id);
        stockWait.setStatus(0);
        stockWaitService.save(stockWait);

        List<StockWaitDetails> stockWaitDetailsList = new ArrayList<>();
        for (ContractProduct contractProduct : productionOrderDetailList) {
            StockWaitDetails stockWaitDetails = new StockWaitDetails();
            stockWaitDetails.setStockWaitId(stockWait.getId());
            stockWaitDetails.setProductId(contractProduct.getProductId());
            stockWaitDetails.setQuantity(contractProduct.getQuantity());
            stockWaitDetails.setReceiptQuantity(BigDecimal.ZERO);
            stockWaitDetailsList.add(stockWaitDetails);
        }
        stockWaitDetailsService.saveBatch(stockWaitDetailsList);
    }

}
