package com.prolog.rdc.tms.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.prolog.framework.core.exception.PrologException;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.product.core.framework.entity.UserEntity;
import com.prolog.rdc.tms.constant.BmsConstant;
import com.prolog.rdc.tms.constant.enums.LogTypeEnum;
import com.prolog.rdc.tms.dao.mapper.*;
import com.prolog.rdc.tms.model.dto.CheckConditionDTO;
import com.prolog.rdc.tms.model.dto.LoadingBillPriceDTO;
import com.prolog.rdc.tms.model.dto.ShipBillPriceDTO;
import com.prolog.rdc.tms.model.entity.*;
import com.prolog.rdc.tms.service.BillIncomeCostStrategyService;
import com.prolog.rdc.tms.service.strategy.IncomeExecuteStrategyServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.plugin.PluginException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 单据匹配合同收入费用服务层实现层
 *
 * @author lhb
 * @since 2023/4/15 9:47
 */
@Service
@Slf4j
public class BillIncomeCostStrategyServiceImpl implements BillIncomeCostStrategyService {

    @Autowired
    private IncomeExecuteStrategyServiceImpl strategyService;
    @Autowired
    private LogisticsContractMapper logisticsContractMapper;
    @Autowired
    private FreightPriceMapper freightPriceMapper;
    @Autowired
    private BmsFreightPriceConditionMapper conditionMapper;
    @Autowired
    private ShipBillFeeTemporaryDetailMapper temporaryDetailMapper;
    @Autowired
    private BmsBillIncomeFeeHeaderMapper bmsBillIncomeFeeHeaderMapper;
    @Autowired
    private BmsBillIncomeFeeDetailMapper bmsBillIncomeFeeDetailMapper;
    @Autowired
    private BmsLogOperationMapper logOperationMapper;

    @Override
    public Integer loadingBillCostStrategy(BmsLoadingBillHeaderModel loadingModel, String source, UserEntity user) {
        Integer rs = 200;
        log.info("派车单:" + JSON.toJSONString(loadingModel));
        // 先删除所有的费用
        this.deleteFeeDtl(loadingModel.getLoadingBillNo(), loadingModel.getId(), user, source);

        BmsBillIncomeFeeHeaderModel feeHeaderModel = new BmsBillIncomeFeeHeaderModel();
        feeHeaderModel.setBillNo(loadingModel.getLoadingBillNo());
        feeHeaderModel.setBillId(loadingModel.getId());
        feeHeaderModel.setBillType(20);
        feeHeaderModel.setSettlementDepartment(loadingModel.getSettlementDepartment());
        feeHeaderModel.setSettlementDepartmentId(loadingModel.getSettlementDepartmentId());
        feeHeaderModel.setSettlementDepartmentCode(loadingModel.getSettlementDepartmentCode());
        feeHeaderModel.setCheckStatus(0);
        feeHeaderModel.setSettlementStatus(0);

        try {
            // 1.获取承运合同配置
            Criteria criteriaContract = Criteria.forClass(BmsLogisticsContractModel.class);
            Restriction r1 = Restrictions.eq(BmsLogisticsContractModel::getFirstPartyCode, loadingModel.getCargoOwnerCode());
            Restriction r2 = Restrictions.le(BmsLogisticsContractModel::getEffectiveDate, loadingModel.getStartDate());
            Restriction r3 = Restrictions.ge(BmsLogisticsContractModel::getExpiryDate, loadingModel.getStartDate());
            Restriction r4 = Restrictions.eq(BmsLogisticsContractModel::getEnterpriseId, user.getEnterpriseId());
            Restriction r5 = Restrictions.eq(BmsLogisticsContractModel::getStatus, 1);
            Restriction r6 = Restrictions.eq(BmsLogisticsContractModel::getSecondPartyCode, loadingModel.getSettlementDepartmentCode());
            Restriction r7 = Restrictions.eq(BmsLogisticsContractModel::getContractMode, 2);
            criteriaContract.setRestriction(Restrictions.and(r1, r2, r3, r4, r5, r6, r7));
            List<BmsLogisticsContractModel> contractModels = logisticsContractMapper.findByCriteria(criteriaContract);
            if (ObjectUtil.isEmpty(contractModels)) {
                log.info("派车单{}匹配不到承运合同,请先创建合同", JSON.toJSONString(loadingModel));
                throw new PrologException(StrUtil.format("派车单{}匹配不到承运合同,请先创建合同", loadingModel.getLoadingBillNo()));
            }
            log.info("匹配到的合同:" + JSON.toJSONString(contractModels));

            // 获取所有合同的价格表
            List<String> contractNoList = contractModels.stream().map(BmsLogisticsContractModel::getContractNo).collect(Collectors.toList());
            Criteria fCriteria = Criteria.forClass(BmsFreightPriceModel.class);
            Restriction r8 = Restrictions.in(BmsFreightPriceModel::getContractNo, contractNoList.stream().toArray(String[]::new));
            Restriction r9 = Restrictions.eq(BmsFreightPriceModel::getEnterpriseId, user.getEnterpriseId());
            Restriction r10 = Restrictions.eq(BmsFreightPriceModel::getStatus, 1);
            Restriction r11 = Restrictions.eq(BmsFreightPriceModel::getSettlementOrderType, 2);
            fCriteria.setRestriction(Restrictions.and(r8, r9, r10, r11));
            List<BmsFreightPriceModel> allPriceModelList = freightPriceMapper.findByCriteria(fCriteria);
            if (ObjectUtil.isEmpty(allPriceModelList)) {
                log.info(StrUtil.format("合同{}价格表不存在，请先创建价格表", contractNoList.stream().collect(Collectors.joining(","))));
                throw new PrologException(StrUtil.format("合同{}价格表不存在，请先创建价格表", contractNoList.stream().collect(Collectors.joining(","))));
            }
            log.info("获取所有合同的价格表:" + JSON.toJSONString(allPriceModelList));

            // 满足条件的价格表
            List<BmsFreightPriceModel> matchedCntPriceModelList = Lists.newArrayList();
            for (BmsFreightPriceModel priceModel : allPriceModelList) {
                // 3.查询匹配条件
                Criteria dCriteria = Criteria.forClass(BmsFreightPriceConditionModel.class);
                Restriction r12 = Restrictions.eq(BmsFreightPriceConditionModel::getPriceNo, priceModel.getPriceNo());
                Restriction r13 = Restrictions.eq(BmsFreightPriceConditionModel::getEnterpriseId, user.getEnterpriseId());
                dCriteria.setRestriction(Restrictions.and(r12, r13));
                List<BmsFreightPriceConditionModel> conditionList = conditionMapper.findByCriteria(dCriteria);
                if (ObjectUtil.isNotEmpty(conditionList)) {
                    // 不是空，需要判断条件是否满足
                    try {
                        CheckConditionDTO dto = this.checkLoadingPriceCondition(conditionList, loadingModel);
                        if (!dto.getFlag()) {
                            log.info("匹配价格表的满足条件校验失败:{}", dto.getMessage());
                            continue;
                        } else {
                            matchedCntPriceModelList.add(priceModel);
                        }
                    } catch (Exception e) {
                        log.info("匹配价格表的满足条件失败:{}", ExceptionUtil.stacktraceToString(e));
                        throw new PrologException("匹配价格表的满足条件失败");
                    }
                } else {
                    matchedCntPriceModelList.add(priceModel);
                }
            }
            log.info("匹配到满足条件的价格表:" + JSON.toJSONString(matchedCntPriceModelList));

            if (ObjectUtil.isEmpty(matchedCntPriceModelList)) {
                throw new PrologException("派车单没有匹配到价格表");
            }
            Map<String, List<BmsFreightPriceModel>> contractListMap = matchedCntPriceModelList.stream().collect(Collectors.groupingBy(BmsFreightPriceModel::getContractNo));
            if (contractListMap.size() > 1) {
                throw new PrologException("派车单匹配到多个合同:" + contractListMap.keySet().stream().collect(Collectors.joining(",")));
            }
            Map<String, List<BmsFreightPriceModel>> priceListMap = matchedCntPriceModelList.stream().collect(Collectors.groupingBy(BmsFreightPriceModel::getExpenseName));
            if (priceListMap.size() != matchedCntPriceModelList.size()) {
                throw new PrologException("派车单匹配到重复的价格表");
            }

            String matchedPriceTblContractNo = matchedCntPriceModelList.get(0).getContractNo();
            List<BmsLogisticsContractModel> contractModel = contractModels.stream().filter(contract -> contract.getContractNo().equals(matchedPriceTblContractNo)).collect(Collectors.toList());
            if (ObjectUtil.isEmpty(contractModel)) {
                throw new PrologException("价格表对应的合同不在合同数据中");
            }

            List<LoadingBillPriceDTO> allList = Lists.newArrayList();
            for (BmsFreightPriceModel priceModel : matchedCntPriceModelList) {
                try {
                    Integer settlementModel = priceModel.getSettlementModel();
                    // 1.获取运费
                    List<LoadingBillPriceDTO> list = strategyService.executeStrategyLoading(contractModel.get(0), priceModel, settlementModel, loadingModel, source, user);
                    allList.addAll(list);
                } catch (Exception e) {
                    log.info("派车单:{},收入费用计算失败:{}", JSON.toJSONString(loadingModel), ExceptionUtil.stacktraceToString(e));

                    throw new PluginException("费用计算失败");
                }
            }
            for (LoadingBillPriceDTO priceDTO : allList) {
                feeHeaderModel.setCostContract(priceDTO.getCostContract());
                feeHeaderModel.setCostDate(DateUtil.date());
                feeHeaderModel.setSettlementCompanyId(priceDTO.getFirstPartyId());
                feeHeaderModel.setSettlementCompanyCode(priceDTO.getFirstPartyCode());
                feeHeaderModel.setSettlementCompany(priceDTO.getFirstPartyName());
                feeHeaderModel.setAbnormalStatus(0);
                feeHeaderModel.setCostStatus(1);

                BmsLogOperationModel feeVo = new BmsLogOperationModel();
                feeVo.setCreatetime(DateUtil.date());
                feeVo.setCreateperson(user.getNickname());
                feeVo.setEnterpriseId(user.getEnterpriseId());
                feeVo.setEnterpriseName(user.getEnterpriseName());
                feeVo.setOrderNo(loadingModel.getLoadingBillNo());
                feeVo.setLogMemo("运单匹配价格表" + priceDTO.getCostPriceTable());
                feeVo.setLogType(LogTypeEnum.SHIP_BILL.getCode());
                logOperationMapper.save(feeVo);
            }
            // 支出总价 类型为收入的含税金额
            BigDecimal incomeAmount = getShipbillTaxAmt(loadingModel.getId(), loadingModel.getLoadingBillNo(), null);
            feeHeaderModel.setIncomeAmount(incomeAmount);
            // 类型为收入的来源是价格表生成 含税金额
            BigDecimal contractIncomeAmount = getShipbillTaxAmt(loadingModel.getId(), loadingModel.getLoadingBillNo(), 1);
            feeHeaderModel.setContractIncomeAmount(contractIncomeAmount);
        } catch (PluginException e) {
            log.info("派车单收入价格计费失败:{}", ExceptionUtil.stacktraceToString(e));
            feeHeaderModel.setCostFailReason(e.getMessage());
            feeHeaderModel.setAbnormalStatus(1);
            feeHeaderModel.setCostStatus(2);
            rs = 255;
        } catch (Exception e) {
            log.info("派车单收入价格计费失败:{}", ExceptionUtil.stacktraceToString(e));
            feeHeaderModel.setCostFailReason(e.getMessage());
            feeHeaderModel.setAbnormalStatus(1);
            feeHeaderModel.setCostStatus(2);
            rs = 255;
        }
        feeHeaderModel.setCreateperson(user.getNickname());
        feeHeaderModel.setCreatetime(DateUtil.date());
        feeHeaderModel.setUpdateperson(user.getNickname());
        feeHeaderModel.setUpdatetime(DateUtil.date());
        feeHeaderModel.setEnterpriseId(user.getEnterpriseId());
        feeHeaderModel.setEnterpriseName(user.getEnterpriseName());
        feeHeaderModel.setSettlementStatus(BmsConstant.SETTLEMENT_STATUS_0);

        bmsBillIncomeFeeHeaderMapper.save(feeHeaderModel);

        return rs;
    }

    @Override
    public Integer shipBillCostStrategy(BmsShipBillHeaderModel model, List<BmsShipBillDetailModel> detailDTOS, String source, UserEntity user) {
        log.info("运单:" + JSON.toJSONString(model));
        Integer rs = 200;
        // 删除费用
        this.deleteFeeDtl(model.getShipbillNo(), model.getId(), user, source);

        BmsBillIncomeFeeHeaderModel feeHeaderModel = new BmsBillIncomeFeeHeaderModel();
        feeHeaderModel.setBillNo(model.getShipbillNo());
        feeHeaderModel.setBillId(model.getId());
        feeHeaderModel.setBillType(10);
        feeHeaderModel.setSettlementDepartment(model.getSettlementDepartment());
        feeHeaderModel.setSettlementDepartmentId(model.getSettlementDepartmentId());
        feeHeaderModel.setSettlementDepartmentCode(model.getSettlementDepartmentCode());
        feeHeaderModel.setCheckStatus(0);
        feeHeaderModel.setSettlementStatus(0);

        try {
            // 1.获取承运合同配置
            Criteria criteriaContract = Criteria.forClass(BmsLogisticsContractModel.class);
            Restriction r1 = Restrictions.eq(BmsLogisticsContractModel::getFirstPartyCode, model.getCargoOwnerCode());
            Restriction r2 = Restrictions.le(BmsLogisticsContractModel::getEffectiveDate, model.getStartDate());
            Restriction r3 = Restrictions.ge(BmsLogisticsContractModel::getExpiryDate, model.getStartDate());
            Restriction r4 = Restrictions.eq(BmsLogisticsContractModel::getEnterpriseId, user.getEnterpriseId());
            Restriction r5 = Restrictions.eq(BmsLogisticsContractModel::getStatus, 1);
            Restriction r6 = Restrictions.eq(BmsLogisticsContractModel::getSecondPartyCode, model.getSettlementDepartmentCode());
            Restriction r7 = Restrictions.eq(BmsLogisticsContractModel::getContractMode, 2);
            criteriaContract.setRestriction(Restrictions.and(r1, r2, r3, r4, r5, r6, r7));
            List<BmsLogisticsContractModel> contractModels = logisticsContractMapper.findByCriteria(criteriaContract);
            if (ObjectUtil.isEmpty(contractModels)) {
                log.info("运单{}匹配不到承运合同,请先创建合同", JSON.toJSONString(model));
                throw new PrologException(StrUtil.format("运单{}匹配不到承运合同,请先创建合同", model.getShipbillNo()));
            }
            log.info("匹配到的合同:" + JSON.toJSONString(contractModels));

            // 获取所有合同的价格表
            List<String> contractNoList = contractModels.stream().map(BmsLogisticsContractModel::getContractNo).collect(Collectors.toList());
            Criteria fCriteria = Criteria.forClass(BmsFreightPriceModel.class);
            Restriction r8 = Restrictions.in(BmsFreightPriceModel::getContractNo, contractNoList.stream().toArray(String[]::new));
            Restriction r9 = Restrictions.eq(BmsFreightPriceModel::getEnterpriseId, user.getEnterpriseId());
            Restriction r10 = Restrictions.eq(BmsFreightPriceModel::getStatus, 1);
            Restriction r11 = Restrictions.eq(BmsFreightPriceModel::getSettlementOrderType, 1);
            fCriteria.setRestriction(Restrictions.and(r8, r9, r10, r11));
            List<BmsFreightPriceModel> allPriceModelList = freightPriceMapper.findByCriteria(fCriteria);
            if (ObjectUtil.isEmpty(allPriceModelList)) {
                throw new PrologException(StrUtil.format("合同{}的价格表不存在，请先创建价格表", contractNoList.stream().collect(Collectors.joining(","))));
            }
            log.info("获取所有合同的价格表:" + JSON.toJSONString(allPriceModelList));

            // 满足条件的价格表
            List<BmsFreightPriceModel> matchedCntPriceModelList = Lists.newArrayList();
            for (BmsFreightPriceModel priceModel : allPriceModelList) {
                // 3.查询匹配条件
                Criteria dCriteria = Criteria.forClass(BmsFreightPriceConditionModel.class);
                Restriction r12 = Restrictions.eq(BmsFreightPriceConditionModel::getPriceNo, priceModel.getPriceNo());
                Restriction r13 = Restrictions.eq(BmsFreightPriceConditionModel::getEnterpriseId, user.getEnterpriseId());
                dCriteria.setRestriction(Restrictions.and(r12, r13));
                List<BmsFreightPriceConditionModel> conditionList = conditionMapper.findByCriteria(dCriteria);
                if (ObjectUtil.isNotEmpty(conditionList)) {
                    // 不是空，需要判断条件是否满足
                    try {
                        CheckConditionDTO dto = this.checkShipBillPriceCondition(conditionList, model, detailDTOS);
                        if (!dto.getFlag()) {
                            log.info("匹配价格表的满足条件校验失败:{}", dto.getMessage());
                            continue;
                        } else {
                            matchedCntPriceModelList.add(priceModel);
                        }
                    } catch (Exception e) {
                        log.info("匹配价格表的满足条件失败:{}", ExceptionUtil.stacktraceToString(e));
                        throw new PrologException("匹配价格表的满足条件失败");
                    }
                } else {
                    matchedCntPriceModelList.add(priceModel);
                }
            }
            log.info("匹配到满足条件的价格表:" + JSON.toJSONString(matchedCntPriceModelList));
            if (ObjectUtil.isEmpty(matchedCntPriceModelList)) {
                throw new PrologException("运单没有匹配到价格表");
            }

            Map<String, List<BmsFreightPriceModel>> contractListMap = matchedCntPriceModelList.stream().collect(Collectors.groupingBy(BmsFreightPriceModel::getContractNo));
            if (contractListMap.size() > 1) {
                throw new PrologException("运单匹配到多个合同:" + contractListMap.keySet().stream().collect(Collectors.joining(",")));
            }
            Map<String, List<BmsFreightPriceModel>> priceListMap = matchedCntPriceModelList.stream().collect(Collectors.groupingBy(BmsFreightPriceModel::getExpenseName));
            if (priceListMap.size() != matchedCntPriceModelList.size()) {
                throw new PrologException("运单匹配到重复的价格表");
            }
            String matchedPriceTblContractNo = matchedCntPriceModelList.get(0).getContractNo();
            List<BmsLogisticsContractModel> contractModel = contractModels.stream().filter(contract -> contract.getContractNo().equals(matchedPriceTblContractNo)).collect(Collectors.toList());
            if (ObjectUtil.isEmpty(contractModel)) {
                throw new PrologException("价格表对应的合同不在合同数据中");
            }
            List<ShipBillPriceDTO> allList = Lists.newArrayList();
            for (BmsFreightPriceModel priceModel : matchedCntPriceModelList) {
                try {
                    Integer settlementModel = priceModel.getSettlementModel();
                    // 1.获取运费
                    List<ShipBillPriceDTO> list = strategyService.executeStrategy(contractModel.get(0), priceModel, settlementModel, model, source, user);
                    allList.addAll(list);
                } catch (Exception e) {
                    log.info("运单:{},收入费用计算失败:{}", JSON.toJSONString(model), ExceptionUtil.stacktraceToString(e));
                    throw new PluginException("费用计算失败");
                }
            }
            for (ShipBillPriceDTO priceDTO : allList) {
                feeHeaderModel.setCostContract(priceDTO.getCostContract());
                feeHeaderModel.setCostDate(DateUtil.date());
                feeHeaderModel.setSettlementCompanyId(priceDTO.getFirstPartyId());
                feeHeaderModel.setSettlementCompanyCode(priceDTO.getFirstPartyCode());
                feeHeaderModel.setSettlementCompany(priceDTO.getFirstPartyName());
                feeHeaderModel.setAbnormalStatus(0);
                feeHeaderModel.setCostStatus(1);

                BmsLogOperationModel feeVo = new BmsLogOperationModel();
                feeVo.setCreatetime(DateUtil.date());
                feeVo.setCreateperson(user.getNickname());
                feeVo.setEnterpriseId(user.getEnterpriseId());
                feeVo.setEnterpriseName(user.getEnterpriseName());
                feeVo.setOrderNo(model.getShipbillNo());
                feeVo.setLogMemo("匹配价格表" + priceDTO.getCostPriceTable());
                feeVo.setLogType(LogTypeEnum.LOADING_BILL.getCode());
                logOperationMapper.save(feeVo);
            }
            // 收入总价 类型为收入的含税金额
            BigDecimal incomeAmount = getShipbillTaxAmt(model.getId(), model.getShipbillNo(), null);
            feeHeaderModel.setIncomeAmount(incomeAmount);
            // 类型为收入的来源是价格表生成 含税金额
            BigDecimal contractIncomeAmount = getShipbillTaxAmt(model.getId(), model.getShipbillNo(), 1);
            feeHeaderModel.setContractIncomeAmount(contractIncomeAmount);
        } catch (PluginException e) {
            log.info("运单收入价格计费失败:{}", ExceptionUtil.stacktraceToString(e));
            feeHeaderModel.setCostFailReason(e.getMessage());
            feeHeaderModel.setAbnormalStatus(1);
            feeHeaderModel.setCostStatus(2);
            rs = 255;
        } catch (Exception e) {
            log.info("运单收入价格计费失败:{}", ExceptionUtil.stacktraceToString(e));
            feeHeaderModel.setCostFailReason(e.getMessage());
            feeHeaderModel.setAbnormalStatus(1);
            feeHeaderModel.setCostStatus(2);
            rs = 255;
        }
        feeHeaderModel.setCreateperson(user.getNickname());
        feeHeaderModel.setCreatetime(DateUtil.date());
        feeHeaderModel.setUpdateperson(user.getNickname());
        feeHeaderModel.setUpdatetime(DateUtil.date());
        feeHeaderModel.setEnterpriseId(user.getEnterpriseId());
        feeHeaderModel.setEnterpriseName(user.getEnterpriseName());
        feeHeaderModel.setSettlementStatus(BmsConstant.SETTLEMENT_STATUS_0);

        bmsBillIncomeFeeHeaderMapper.save(feeHeaderModel);

        return rs;
    }

    public  void deleteFeeDtl(String billNo, Long billId, UserEntity user, String source) {
        // 0：试验，1：非试验
        if (source.equals("0")) {
            Criteria tcriteria = Criteria.forClass(BmsShipBillFeeTemporaryDetailModel.class);
            Restriction r9 = Restrictions.eq("shipbillNo", billNo);
            Restriction r10 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
            tcriteria.setRestriction(Restrictions.and(r9, r10));
            List<BmsShipBillFeeTemporaryDetailModel> tmodels = temporaryDetailMapper.findByCriteria(tcriteria);
            if (ObjectUtil.isNotEmpty(tmodels)) {
                temporaryDetailMapper.deleteByCriteria(tcriteria);
            }
        } else {
            // 价格表
            Criteria criteriaIncomeFeeHeader = Criteria.forClass(BmsBillIncomeFeeHeaderModel.class);
            Restriction r13 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getBillId, billId);
            Restriction r14 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getBillNo, billNo);
            Restriction r15 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getEnterpriseId, user.getEnterpriseId());
            criteriaIncomeFeeHeader.setRestriction(Restrictions.and(r13, r14, r15));
            List<BmsBillIncomeFeeHeaderModel> feeHeaderModels = bmsBillIncomeFeeHeaderMapper.findByCriteria(criteriaIncomeFeeHeader);
            if (ObjectUtil.isNotEmpty(feeHeaderModels)) {
                bmsBillIncomeFeeHeaderMapper.deleteByCriteria(criteriaIncomeFeeHeader);
                log.info(StrUtil.format("费用主表:{}被删除", JSON.toJSONString(feeHeaderModels)));
            }

            // 判断是否存 运单合同 + 价格表 + 来源
            Criteria criteriaIncomeFeeDetail = Criteria.forClass(BmsBillIncomeFeeDetailModel.class);
            Restriction r3 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillId, billId);
            Restriction r4 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillNo, billNo);
            Restriction r5 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getEnterpriseId, user.getEnterpriseId());
            criteriaIncomeFeeDetail.setRestriction(Restrictions.and(r3, r4, r5));
            List<BmsBillIncomeFeeDetailModel> dtlModels = bmsBillIncomeFeeDetailMapper.findByCriteria(criteriaIncomeFeeDetail);
            if (ObjectUtil.isNotEmpty(dtlModels)) {
                bmsBillIncomeFeeDetailMapper.deleteByCriteria(criteriaIncomeFeeDetail);
                log.info(StrUtil.format("费用明细:{}被删除", JSON.toJSONString(dtlModels)));
            }
        }
    }

    private CheckConditionDTO checkLoadingPriceCondition(List<BmsFreightPriceConditionModel> conditionList, BmsLoadingBillHeaderModel costStrategy) throws Exception {
        log.info("价格表满足条件:" + JSON.toJSONString(conditionList));
        log.info("价格表满足条件匹配,派车单:" + JSON.toJSONString(costStrategy));
        String deliveryAreas = costStrategy.getDeliveryAreas();
        BigDecimal totalWeight = costStrategy.getTotalWeight();
        String deliveryLines = costStrategy.getDeliveryLines();
        String stationLines = costStrategy.getStationLines();
        String vehicleTypeCode = costStrategy.getVehicleTypeCode();
        String cargoOwnerCode = costStrategy.getCargoOwnerCode();
        BigDecimal totalMileage = costStrategy.getTotalMileage();

        CheckConditionDTO dto = new CheckConditionDTO();
        dto.setFlag(true);
        for (BmsFreightPriceConditionModel bmsFreightPriceConditionModel : conditionList) {
            log.info("价格表满足条件的明细条件:" + JSON.toJSONString(bmsFreightPriceConditionModel));
            // 条件 8：货主，12:车型, 13：收入重量，14：配送线路，15：站点线路，16：配送区域 18：收入公里数
            Integer conditionType = bmsFreightPriceConditionModel.getConditionType();
            String conditionValue = bmsFreightPriceConditionModel.getConditionValue();
            String unitCode = bmsFreightPriceConditionModel.getUnitCode();
            // 货主
            if (conditionType == 8 && !unitCode.contains(cargoOwnerCode)) {
                dto.setMessage("没有匹配到货主");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 12 && !unitCode.contains(vehicleTypeCode)) {
                dto.setMessage("没有匹配到车型");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 13 && !(NumberUtil.isLessOrEqual(totalWeight, BigDecimal.valueOf(Integer.valueOf(unitCode).intValue()))
                    && NumberUtil.isGreaterOrEqual(totalWeight, BigDecimal.valueOf(Integer.valueOf(conditionValue).intValue())))) {
                dto.setMessage("没有匹配到收入重量");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 14 && ObjectUtil.isNotEmpty(deliveryLines)) {
                List<String> deliveryLineList = Arrays.stream(deliveryLines.split("-")).collect(Collectors.toList());
                for (String line : deliveryLineList) {
                    if (!conditionValue.contains(line)) {
                        dto.setMessage("没有匹配到配送线路");
                        dto.setFlag(false);
                        return dto;
                    }
                }
            } else if (conditionType == 14 && ObjectUtil.isEmpty(deliveryLines)) {
                dto.setMessage("没有匹配到配送线路");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 15 && ObjectUtil.isNotEmpty(stationLines)) {
                List<String> stationLinesList = Arrays.stream(stationLines.split("-")).collect(Collectors.toList());
                for (String station : stationLinesList) {
                    if (!conditionValue.contains(station)) {
                        dto.setMessage("没有匹配到站点线路");
                        dto.setFlag(false);
                        return dto;
                    }
                }
            } else if (conditionType == 15 && ObjectUtil.isEmpty(stationLines)) {
                dto.setMessage("没有匹配到站点线路");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 16 && !conditionValue.contains(deliveryAreas)) {
                dto.setMessage("没有匹配到配送区域");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 18 && !(NumberUtil.isLessOrEqual(totalMileage, BigDecimal.valueOf(Integer.valueOf(unitCode).intValue()))
                    && NumberUtil.isGreaterOrEqual(totalMileage, BigDecimal.valueOf(Integer.valueOf(conditionValue).intValue())))) {
                dto.setMessage("没有匹配到收入公里数");
                dto.setFlag(false);
                return dto;
            }
        }
        return dto;
    }

    private CheckConditionDTO checkShipBillPriceCondition(List<BmsFreightPriceConditionModel> conditionList, BmsShipBillHeaderModel costStrategy, List<BmsShipBillDetailModel> detailDTOS) throws Exception {
        log.info("价格表满足条件:" + JSON.toJSONString(conditionList));
        log.info("价格表满足条件匹配,运单:" + JSON.toJSONString(costStrategy));
        log.info("价格表满足条件匹配,运单明细:" + JSON.toJSONString(detailDTOS));
        Integer deliveryMethodType = costStrategy.getDeliveryMethodType();
        // 1客户 2仓库 3供应商
        Integer shipperType = costStrategy.getShipperType();
        Integer consigneeType = costStrategy.getConsigneeType();
        Integer orderType = costStrategy.getOrderType();
        Integer orderBusinessType = costStrategy.getOrderBusinessType();
        Integer transportType = costStrategy.getTransportType();
        Integer temperatureRequirement = costStrategy.getTemperatureRequirement();
        String cargoOwnerCode = costStrategy.getCargoOwnerCode();
        String shipperUnitCode = costStrategy.getShipperUnitCode();  // 发货放单位
        String consigneeUnitCode = costStrategy.getConsigneeUnitCode();  // 收货放单位
        String departmentCode = costStrategy.getSettlementDepartmentCode();
        String vehicleTypeCode = costStrategy.getVehicleTypeCode();

        String deliveryAreas = costStrategy.getDeliveryAreas();
        String lineCode = costStrategy.getLineCode();
        String deliveryStationCode = costStrategy.getDeliveryStationCode();
        BigDecimal totalWeight = costStrategy.getTotalWeight();

        CheckConditionDTO dto = new CheckConditionDTO();
        dto.setFlag(true);
        for (BmsFreightPriceConditionModel bmsFreightPriceConditionModel : conditionList) {
            log.info("价格表满足条件的明细条件:" + JSON.toJSONString(bmsFreightPriceConditionModel));
            // 条件 1：配送方式，2：发货方类型，3：收货放类型，4：订单类型，5：业务类型，6：运输模式，7：温度要求，8：货主，9：部门，10：商品,11:商品品类 12:车型
            // 13：收入重量，16：配送区域; 17:线路 20:配送站点
            Integer conditionType = bmsFreightPriceConditionModel.getConditionType();
            String conditionValue = bmsFreightPriceConditionModel.getConditionValue();
            String unitCode = bmsFreightPriceConditionModel.getUnitCode();
            String unitName = bmsFreightPriceConditionModel.getUnitName();

            if (conditionType == 13 && !(NumberUtil.isLessOrEqual(totalWeight, BigDecimal.valueOf(Integer.valueOf(unitCode).intValue()))
                    && NumberUtil.isGreaterOrEqual(totalWeight, BigDecimal.valueOf(Integer.valueOf(conditionValue).intValue())))) {
                dto.setMessage("没有匹配到收入重量");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 16 && !conditionValue.contains(deliveryAreas)) {
                dto.setMessage("没有匹配到配送区域");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 17 && !unitCode.contains(lineCode)) {
                dto.setMessage("没有匹配到线路");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 20 && !unitCode.contains(deliveryStationCode)) {
                dto.setMessage("没有匹配到配送站点");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 1 && !Objects.equals(deliveryMethodType.toString(), conditionValue)) {
                dto.setMessage("没有匹配到配送方式对应的类型");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 2 && (!Objects.equals(shipperType.toString(), conditionValue) || !unitCode.contains(shipperUnitCode))) {
                dto.setMessage("没有匹配到发货方对应的类型");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 3 && (!Objects.equals(consigneeType.toString(), conditionValue) || !unitCode.contains(consigneeUnitCode))) {
                dto.setMessage("没有匹配到收货方类型");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 4 && !Objects.equals(orderType.toString(), conditionValue)) {
                dto.setMessage("没有匹配到订单类型");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 5 && !Objects.equals(orderBusinessType.toString(), conditionValue)) {
                dto.setMessage("没有匹配到业务类型");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 6 && !Objects.equals(transportType.toString(), conditionValue)) {
                dto.setMessage("没有匹配到运输类型");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 7 && !Objects.equals(temperatureRequirement.toString(), conditionValue)) {
                dto.setMessage("没有匹配到温度类型");
                dto.setFlag(false);
                return dto;
            }
            // 货主
            if (conditionType == 8 && !unitCode.contains(cargoOwnerCode)) {
                dto.setMessage("没有匹配到货主");
                dto.setFlag(false);
                return dto;
            }
            // 部门
            if (conditionType == 9 && !unitCode.contains(departmentCode)) {
                dto.setMessage("没有匹配到部门");
                dto.setFlag(false);
                return dto;
            }
            if (conditionType == 10) {
                List<String> itemNames = detailDTOS.stream().map(BmsShipBillDetailModel::getItemName).collect(Collectors.toList());
                for (String itemName : itemNames) {
                    if (unitName.contains(itemName)) {
                        dto.setFlag(true);
                        dto.setMessage(null);
                        return dto;
                    } else {
                        dto.setMessage("没有匹配到商品信息");
                        dto.setFlag(false);
                    }
                }
                if (!dto.getFlag()) {
                    return dto;
                }
            }
            if (conditionType == 11) {
                List<String> itemCategoryCode = detailDTOS.stream().map(BmsShipBillDetailModel::getItemCategoryCode).collect(Collectors.toList());
                for (String categoryCode : itemCategoryCode) {
                    if (unitCode.contains(categoryCode)) {
                        dto.setFlag(true);
                        dto.setMessage(null);
                        return dto;
                    } else {
                        dto.setMessage("没有匹配到商品品类信息");
                        dto.setFlag(false);
                    }
                }
                if (!dto.getFlag()) {
                    return dto;
                }
            }
            if (conditionType == 12 && !unitCode.contains(vehicleTypeCode)) {
                dto.setMessage("没有匹配到车型");
                dto.setFlag(false);
                return dto;
            }
        }
        return dto;
    }

    public BigDecimal getShipbillTaxAmt(Long billId, String billNo, Integer billingSource) {
        BigDecimal taxAmt = BigDecimal.ZERO;

        Criteria bmsFeeCriteria = Criteria.forClass(BmsBillIncomeFeeDetailModel.class);
        Restriction r1 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillId, billId);
        Restriction r2 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillNo, billNo);
        Restriction r3 = ObjectUtil.isEmpty(billingSource) ? null : Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillingSource, billingSource);
        bmsFeeCriteria.setRestriction(Restrictions.and(r1, r2, r3));
        List<BmsBillIncomeFeeDetailModel> feeDetailModels = bmsBillIncomeFeeDetailMapper.findByCriteria(bmsFeeCriteria);
        if (ObjectUtil.isNotEmpty(feeDetailModels)) {
            taxAmt = feeDetailModels.stream().filter(dto -> ObjectUtil.isNotEmpty(dto.getTaxAmt())).map(BmsBillIncomeFeeDetailModel::getTaxAmt).reduce(BigDecimal.ZERO, BigDecimal::add);
        }
        return taxAmt;
    }
}