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

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Order;
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.dao.mapper.*;
import com.prolog.rdc.tms.model.dto.ShipBillPriceDTO;
import com.prolog.rdc.tms.model.dto.SySParameterDTO;
import com.prolog.rdc.tms.model.entity.*;
import com.prolog.rdc.tms.rmi.feign.MaindataFeign;
import com.prolog.rdc.tms.service.strategy.AbstractSplitStrategyRuleHandler;
import com.prolog.rdc.tms.service.strategy.CostStrategyRuleHandler;
import org.apache.ibatis.plugin.PluginException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Component
@CostStrategyRuleHandler(BmsConstant.LADDER_COST)
public class LadderPriceStrategy extends AbstractSplitStrategyRuleHandler {

    private final Logger logger = LoggerFactory.getLogger(LadderPriceStrategy.class);

    @Autowired
    private LadderCostStrategyMapper strategyMapper;
    @Autowired
    private TimeBillStrategyMapper timeBillStrategyMapper;
    @Autowired
    private MaindataFeign maindataTmsResource;
    @Autowired
    private BmsBillPayFeeDetailMapper bmsBillPayFeeDetailMapper;
    @Autowired
    private ShipBillFeeTemporaryDetailMapper temporaryDetailMapper;
    @Autowired
    private ExpenseManagementMapper managementMapper;
    @Autowired
    private ExpenseAccountMapper expenseAccountMapper;
    @Autowired
    private TimeBillStrategyLadderMapper timeBillStrategyLadderMapper;


    /**
     * 执行阶梯计费
     *
     * @param priceModel   计费数据
     * @param costStrategy 运单信息
     */
    @Override
    public List<ShipBillPriceDTO> executeStrategy(BmsLogisticsContractModel contractModel, BmsFreightPriceModel priceModel, BmsShipBillHeaderModel costStrategy, String source,UserEntity user) {
        logger.info("执行阶梯计费开始...." + JSONObject.toJSONString(priceModel));
        Integer ladderType = priceModel.getLadderType();
        // 查询阶梯数据
        Criteria criteria = Criteria.forClass(BmsFreightPriceLadderModel.class);
        Restriction r1 = Restrictions.eq("priceNo", priceModel.getPriceNo());
        Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2));
        List<BmsFreightPriceLadderModel> ladderModels = strategyMapper.findByCriteria(criteria);
        if (ObjectUtil.isEmpty(ladderModels)) {
            throw new PluginException("阶梯信息为空，请先维护");
        }
        // 获取总量
        if (ObjectUtil.isEmpty(costStrategy.getTotalWeight())) {
            throw new PluginException("总重量不能为空");
        }
        RestMessage<SySParameterDTO> parameterModel = maindataTmsResource.queryParameter();
        if (ObjectUtil.isEmpty(parameterModel) || !parameterModel.isSuccess()) {
            throw new PluginException("系统参数未配置");
        }
        SySParameterDTO parameterDTO = parameterModel.getData();

        // 1.通过查询区间 获取单价
        BigDecimal price = BigDecimal.valueOf(0);
        BigDecimal totWeight;
        if (ObjectUtil.isEmpty(costStrategy.getPackageTotalWeight()) || costStrategy.getPackageTotalWeight().compareTo(BigDecimal.valueOf(0)) == 0) {
            totWeight = costStrategy.getTotalWeight();
        } else {
            totWeight = costStrategy.getPackageTotalWeight();
        }
        // 里程
        BigDecimal totalMileage = costStrategy.getTotalMileage();
        if (ObjectUtil.isEmpty(totalMileage) || totalMileage.compareTo(BigDecimal.valueOf(0)) == 0) {
            totalMileage = priceModel.getMileage();
        }
        BigDecimal totalVolume = NumberUtil.null2Zero(costStrategy.getPackageTotalVolume());
        if (NumberUtil.isLessOrEqual(totalVolume, BigDecimal.ZERO)) {
            totalVolume = NumberUtil.null2Zero(costStrategy.getTotalVolume());
        }
        String modelLadderType = null;
        boolean flag = false;
        BmsFreightPriceLadderModel currentLadderModel = new BmsFreightPriceLadderModel();
        for (BmsFreightPriceLadderModel ladderModel : ladderModels) {
            // 1:大于，2：小于等于
            if (ladderType == 1) {
                // 按重量找区间
                Boolean isMatch = matchPriceLadder(ladderModel,totWeight);
                if (Boolean.TRUE.equals(isMatch)) {
                    price = ladderModel.getPrice();
                    modelLadderType = ladderModel.getLadderType();
                    flag = true;
                    break;
                }
            } else if (ladderType == 2) {
                // 按里程找区间
                Boolean isMatch = matchPriceLadder(ladderModel,totalMileage);
                if (Boolean.TRUE.equals(isMatch)) {
                    price = ladderModel.getPrice();
                    modelLadderType = ladderModel.getLadderType();
                    flag = true;
                    break;
                }
            } else if (ladderType == 3) {
                // 按体积找区间
                Boolean isMatch = matchPriceLadder(ladderModel,totalVolume);
                if (Boolean.TRUE.equals(isMatch)) {
                    price = ladderModel.getPrice();
                    modelLadderType = ladderModel.getLadderType();
                    flag = true;
                    break;
                }
            }
        }
        if (!flag) {
            if (ladderType == 3) {
                throw new PluginException("运单号【"+costStrategy.getShipbillNo()+"】体积【"+totalVolume.stripTrailingZeros().toPlainString()+"M3】未找到体积区间，请检查报价！");
            }
            throw new PluginException("没有匹配到阶梯数据");
        }
        BigDecimal totPrice = new BigDecimal(0);
        // 1.按KG
        if (ladderType == 1) {
            if (priceModel.getSettlementType() == 1) {
                // 1.元/kg*公里
                totPrice = this.calculateForMileage(parameterDTO, priceModel, costStrategy, price);
            }
            if (priceModel.getSettlementType() == 2) {
                // 2.元/kg
                totPrice = this.calculateForPrice(parameterDTO, costStrategy, price);
            }
            if (priceModel.getSettlementType() == 3) {
                // 3.元/小时*kg
                totPrice = this.calculateForTime(parameterDTO, priceModel, costStrategy, price,user);
            }
        }
        // 2.按公里
        if (ladderType == 2) {
            if (priceModel.getSettlementType() == 4) {
                // 1.元/公里
                totPrice = this.calculateTwoForMileage(parameterDTO, priceModel, costStrategy, price);
            }
            if (priceModel.getSettlementType() == 5) {
                // 2.元/小时*公里
                totPrice = this.calculateTwoForPrice(parameterDTO, priceModel, costStrategy, price,user);
            }
        }
        // 3.按体积
        if (ladderType == 3) {
            if (priceModel.getSettlementType() == 7) {
                // 7.元/方
                Integer costInteger = parameterDTO.getCostInteger();
                Integer costPrecision = parameterDTO.getCostPrecision();
                RoundingMode roundingMode = RoundingMode.HALF_UP;
                if (costInteger == 2) {
                    roundingMode = RoundingMode.UP;
                }
                if (costInteger == 3) {
                    roundingMode = RoundingMode.DOWN;
                }
                totPrice = NumberUtil.round(NumberUtil.mul(price, totalVolume), costPrecision, roundingMode);
            }
        }
        List<ShipBillPriceDTO> list = Lists.newArrayList();
        ShipBillPriceDTO dto = new ShipBillPriceDTO();
        dto.setPrice(totPrice);
        dto.setShipbillNo(costStrategy.getShipbillNo());
        dto.setCostContract(contractModel.getContractName());
        dto.setCostPriceTable(priceModel.getPriceName());
        dto.setFirstPartyId(contractModel.getFirstPartyId());
        dto.setFirstPartyCode(contractModel.getFirstPartyCode());
        dto.setFirstPartyName(contractModel.getFirstPartyName());

        this.saveFee(costStrategy, contractModel, priceModel, user, modelLadderType, totPrice, source, dto, parameterDTO);
        list.add(dto);
        return list;
    }

    protected void saveFee(BmsShipBillHeaderModel costStrategy, BmsLogisticsContractModel contractModel, BmsFreightPriceModel priceModel, UserEntity user, String modelLadderType, BigDecimal totPrice, String source, ShipBillPriceDTO dto, SySParameterDTO parameterDTO) {
        // 新增费用信息
        BmsBillPayFeeDetailModel feeDetailModel = new BmsBillPayFeeDetailModel();
        RestMessage<String> expenseNo = maindataTmsResource.getCodeNumberByCode(BmsConstant.SHIP_BILL_EXPENSE_NO, "L");
        if (!expenseNo.isSuccess() || ObjectUtil.isEmpty(expenseNo)) {
            throw new PluginException("获取费用单号为空");
        }
        feeDetailModel.setExpenseNo(expenseNo.getData());
        feeDetailModel.setBillNo(costStrategy.getShipbillNo());
        feeDetailModel.setBillId(costStrategy.getId());
        feeDetailModel.setPayFeeType(1);
        feeDetailModel.setExpenseTypeName("运费");
        feeDetailModel.setBillingSource(1);
        feeDetailModel.setBillingStatus(1);
        feeDetailModel.setBillingDate(DateUtil.date());
        feeDetailModel.setBillingContract(contractModel.getContractName());
        feeDetailModel.setBillingPrice(priceModel.getPriceName());
        feeDetailModel.setPackageId(dto.getPackageId());
        //  费用编码、费用名称、费用科目名称、费用科目编码、费用类型 为价格表的费用反写（只有附加费才有）
        String expenseName = priceModel.getExpenseName();
        Criteria forClass = Criteria.forClass(BmsExpenseManagementModel.class);
        Restriction r7 = Restrictions.eq("status", 1);
        Restriction r8 = Restrictions.eq("expenseName", expenseName);
        Restriction r9 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        forClass.setRestriction(Restrictions.and(r7, r8,r9));
        List<BmsExpenseManagementModel> managementModels = managementMapper.findByCriteria(forClass);
        if (ObjectUtil.isEmpty(managementModels)) {
            throw new PluginException("获取费用信息失败");
        }
        BmsExpenseManagementModel managementModel = managementModels.get(0);
        feeDetailModel.setExpenseCode(managementModel.getExpenseCode());
        feeDetailModel.setExpenseName(managementModel.getExpenseName());
        feeDetailModel.setExpenseAccountCode(managementModel.getExpenseAccountCode());
        feeDetailModel.setExpenseAccountName(managementModel.getExpenseAccountName());
        // 支出，收入
        String expenseAccountCode = managementModel.getExpenseAccountCode();
        Criteria aClass = Criteria.forClass(ExpenseAccountModel.class);
        Restriction r11 = Restrictions.eq("expenseCode", expenseAccountCode);
        Restriction r12 = Restrictions.eq("status", 1);
        aClass.setRestriction(Restrictions.and(r11, r12));
        List<ExpenseAccountModel> mapper = expenseAccountMapper.findByCriteria(aClass);
        if (ObjectUtil.isNotEmpty(mapper)) {
            feeDetailModel.setExpenseType(mapper.get(0).getExpenseClassify());
            feeDetailModel.setExpenseTypeName(Objects.equals(mapper.get(0).getExpenseClassify(), 1) ? "收入" : "支出");
        }

        feeDetailModel.setTaxPoint(contractModel.getTaxPoint());
        int taxPoint = Integer.parseInt(contractModel.getTaxPoint());
        // 1：含税，2：未税
        Integer isTax = parameterDTO.getIsTax();
        // 含税金额 = 未税金额（1 + 税点）
        BigDecimal point = BigDecimal.valueOf(taxPoint).divide(BigDecimal.valueOf(100), 5, RoundingMode.HALF_UP).add(BigDecimal.valueOf(1));
        Integer costPrecision = parameterDTO.getCostPrecision();
        Integer costInteger = parameterDTO.getCostInteger();
        if (isTax == 1) {
            // 四舍五入
            if (costInteger == 1) {
                feeDetailModel.setNoTaxAmt(totPrice.divide(point, costPrecision, RoundingMode.HALF_UP));
                feeDetailModel.setTaxAmt(totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP));
            }
            // 向上取整
            if (costInteger == 2) {
                feeDetailModel.setNoTaxAmt(totPrice.divide(point, costPrecision, RoundingMode.UP));
                feeDetailModel.setTaxAmt(totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP));
            }
            // 向下取整
            if (costInteger == 3) {
                feeDetailModel.setNoTaxAmt(totPrice.divide(point, costPrecision, RoundingMode.DOWN));
                feeDetailModel.setTaxAmt(totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN));
            }
            feeDetailModel.setTax(feeDetailModel.getTaxAmt().subtract(feeDetailModel.getNoTaxAmt()));
        } else {
            // 四舍五入
            if (costInteger == 1) {
                feeDetailModel.setNoTaxAmt(totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP));
                feeDetailModel.setTaxAmt(totPrice.multiply(point).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP));
            }
            // 向上取整
            if (costInteger == 2) {
                feeDetailModel.setNoTaxAmt(totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP));
                feeDetailModel.setTaxAmt(totPrice.multiply(point).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP));
            }
            // 向下取整
            if (costInteger == 3) {
                feeDetailModel.setNoTaxAmt(totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN));
                feeDetailModel.setTaxAmt(totPrice.multiply(point).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN));
            }
            feeDetailModel.setTax(feeDetailModel.getTaxAmt().subtract(feeDetailModel.getNoTaxAmt()));
        }
        feeDetailModel.setBillingType(modelLadderType);
        feeDetailModel.setCreateperson(user.getNickname());
        feeDetailModel.setCreatetime(DateUtil.date());
        feeDetailModel.setUpdateperson(user.getNickname());
        feeDetailModel.setUpdatetime(DateUtil.date());
        feeDetailModel.setEnterpriseId(user.getEnterpriseId());
        feeDetailModel.setEnterpriseName(user.getEnterpriseName());
        feeDetailModel.setExpenseStatus(2);
        feeDetailModel.setCheckStatus(0);
        // 0：试验，1：非试验
        if (source.equals("0")) {
            BmsShipBillFeeTemporaryDetailModel temporaryDetailModel = new BmsShipBillFeeTemporaryDetailModel();
            BeanUtils.copyProperties(feeDetailModel, temporaryDetailModel);
            temporaryDetailMapper.save(temporaryDetailModel);
        } else {
            bmsBillPayFeeDetailMapper.save(feeDetailModel);
        }
    }

    private BigDecimal calculateTwoForPrice(SySParameterDTO parameterDTO, BmsFreightPriceModel priceModel, BmsShipBillHeaderModel costStrategy, BigDecimal price,UserEntity user) {
        // 查询时间策略
        BigDecimal hours = this.getHours(costStrategy, priceModel,user);
        // 获取总里程数
        BigDecimal totalMileage = costStrategy.getTotalMileage() == null ? priceModel.getMileage() : costStrategy.getTotalMileage();
        // 计算总金额
        Integer costInteger = parameterDTO.getCostInteger();
        Integer costPrecision = parameterDTO.getCostPrecision();
        // 四舍五入
        BigDecimal totPrice = new BigDecimal(0);
        if (costInteger == 1) {
            totPrice = price.multiply(hours).multiply(totalMileage).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP);
        }
        // 向上取整
        if (costInteger == 2) {
            totPrice = price.multiply(hours).multiply(totalMileage).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP);
        }
        // 向下取整
        if (costInteger == 3) {
            totPrice = price.multiply(hours).multiply(totalMileage).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN);
        }
        return totPrice;
    }

    private BigDecimal calculateTwoForMileage(SySParameterDTO parameterDTO, BmsFreightPriceModel priceModel, BmsShipBillHeaderModel costStrategy, BigDecimal price) {
        // 获取总里程数
        BigDecimal totalMileage = costStrategy.getTotalMileage() == null ? priceModel.getMileage() : costStrategy.getTotalMileage();
        // 计算总金额
        Integer costInteger = parameterDTO.getCostInteger();
        Integer costPrecision = parameterDTO.getCostPrecision();
        BigDecimal totPrice = new BigDecimal(0);
        if (costInteger == 1) {
            totPrice = price.multiply(totalMileage).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP);
        }
        // 向上取整
        if (costInteger == 2) {
            totPrice = price.multiply(totalMileage).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP);
        }
        // 向下取整
        if (costInteger == 3) {
            totPrice = price.multiply(totalMileage).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN);
        }
        return totPrice;
    }

    // 1.元/kg*公里
    private BigDecimal calculateForMileage(SySParameterDTO parameterDTO, BmsFreightPriceModel priceModel, BmsShipBillHeaderModel costStrategy, BigDecimal price) {
        // 总量
        BigDecimal totWeight;
        if (ObjectUtil.isEmpty(costStrategy.getPackageTotalWeight()) || costStrategy.getPackageTotalWeight().compareTo(BigDecimal.valueOf(0)) == 0) {
            totWeight = costStrategy.getTotalWeight();
        } else {
            totWeight = costStrategy.getPackageTotalWeight();
        }

        // 获取总里程数
        BigDecimal totalMileage = costStrategy.getTotalMileage() == null ? priceModel.getMileage() : costStrategy.getTotalMileage();
        // 计算总金额
        Integer costInteger = parameterDTO.getCostInteger();
        Integer costPrecision = parameterDTO.getCostPrecision();
        BigDecimal totPrice = new BigDecimal(0);
        if (costInteger == 1) {
            totPrice = price.multiply(totalMileage).multiply(totWeight).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP);
        }
        // 向上取整
        if (costInteger == 2) {
            totPrice = price.multiply(totalMileage).multiply(totWeight).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP);
        }
        // 向下取整
        if (costInteger == 3) {
            totPrice = price.multiply(totalMileage).multiply(totWeight).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN);
        }
        return totPrice;
    }

    // 2.元/kg
    private BigDecimal calculateForPrice(SySParameterDTO parameterDTO, BmsShipBillHeaderModel costStrategy, BigDecimal price) {
        // 总量
        BigDecimal totWeight;
        if (ObjectUtil.isEmpty(costStrategy.getPackageTotalWeight()) || costStrategy.getPackageTotalWeight().compareTo(BigDecimal.valueOf(0)) == 0) {
            totWeight = costStrategy.getTotalWeight();
        } else {
            totWeight = costStrategy.getPackageTotalWeight();
        }
        // 计算总金额
        Integer costInteger = parameterDTO.getCostInteger();
        Integer costPrecision = parameterDTO.getCostPrecision();

        BigDecimal totPrice = new BigDecimal(0);
        if (costInteger == 1) {
            totPrice = price.multiply(totWeight).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP);
        }
        // 向上取整
        if (costInteger == 2) {
            totPrice = price.multiply(totWeight).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP);
        }
        // 向下取整
        if (costInteger == 3) {
            totPrice = price.multiply(totWeight).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN);
            ;
        }
        return totPrice;
    }

    // 3.元/小时*kg
    private BigDecimal calculateForTime(SySParameterDTO parameterDTO, BmsFreightPriceModel priceModel, BmsShipBillHeaderModel costStrategy, BigDecimal price,UserEntity user) {
        // 总量
        BigDecimal totWeight;
        if (ObjectUtil.isEmpty(costStrategy.getPackageTotalWeight()) || costStrategy.getPackageTotalWeight().compareTo(BigDecimal.valueOf(0)) == 0) {
            totWeight = costStrategy.getTotalWeight();
        } else {
            totWeight = costStrategy.getPackageTotalWeight();
        }
        // 查询时间策略
        BigDecimal hours = this.getHours(costStrategy, priceModel,user);
        // 总金额
        Integer costInteger = parameterDTO.getCostInteger();
        Integer costPrecision = parameterDTO.getCostPrecision();

        BigDecimal totPrice = new BigDecimal(0);
        if (costInteger == 1) {
            totPrice = totWeight.multiply(hours).multiply(price).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP);
        }
        // 向上取整
        if (costInteger == 2) {
            totPrice = totWeight.multiply(hours).multiply(price).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP);
        }
        // 向下取整
        if (costInteger == 3) {
            totPrice = totWeight.multiply(hours).multiply(price).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN);
            ;
        }
        return totPrice;
    }

    // 7.元/小时
    private BigDecimal calculateForHour(SySParameterDTO parameterDTO, BmsFreightPriceModel priceModel, BmsShipBillHeaderModel costStrategy, BmsFreightPriceLadderModel currentLadderModel,UserEntity user) {
        // 查询时间策略
        BigDecimal hours = this.getHours(costStrategy, priceModel,user);

        // 总金额
        Integer costInteger = parameterDTO.getCostInteger();
        Integer costPrecision = parameterDTO.getCostPrecision();

        BigDecimal totPrice = new BigDecimal(0);
        BigDecimal firstHour = currentLadderModel.getFirstHour();
        BigDecimal price = currentLadderModel.getPrice();
        if (costInteger == 1) {
            totPrice = currentLadderModel.getStartingPrice().add(hours.subtract(firstHour).multiply(price)).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP);
        }
        // 向上取整
        if (costInteger == 2) {
            totPrice = currentLadderModel.getStartingPrice().add(hours.subtract(firstHour).multiply(price)).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP);
        }
        // 向下取整
        if (costInteger == 3) {
            totPrice = currentLadderModel.getStartingPrice().add(hours.subtract(firstHour).multiply(price)).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN);
        }
        return totPrice;
    }

    // 8.元/小时*kg
    private BigDecimal calculateForHourKg(SySParameterDTO parameterDTO, BmsFreightPriceModel priceModel, BmsShipBillHeaderModel costStrategy, BmsFreightPriceLadderModel currentLadderModel,UserEntity user) {
        // 总量
        BigDecimal totWeight;
        if (ObjectUtil.isEmpty(costStrategy.getPackageTotalWeight()) || costStrategy.getPackageTotalWeight().compareTo(BigDecimal.valueOf(0)) == 0) {
            totWeight = costStrategy.getTotalWeight();
        } else {
            totWeight = costStrategy.getPackageTotalWeight();
        }
        // 查询时间策略
        BigDecimal hours = this.getHours(costStrategy, priceModel,user);
        // 总金额
        Integer costInteger = parameterDTO.getCostInteger();
        Integer costPrecision = parameterDTO.getCostPrecision();

        BigDecimal totPrice = new BigDecimal(0);
        BigDecimal firstHour = currentLadderModel.getFirstHour();
        BigDecimal price = currentLadderModel.getPrice();
        if (costInteger == 1) {
            totPrice = currentLadderModel.getStartingPrice().add(hours.subtract(firstHour).multiply(price).multiply(totWeight)).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP);
        }
        // 向上取整
        if (costInteger == 2) {
            totPrice = currentLadderModel.getStartingPrice().add(hours.subtract(firstHour).multiply(price).multiply(totWeight)).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP);
        }
        // 向下取整
        if (costInteger == 3) {
            totPrice = currentLadderModel.getStartingPrice().add(hours.subtract(firstHour).multiply(price).multiply(totWeight)).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN);
        }
        return totPrice;
    }

    private BigDecimal getHours(BmsShipBillHeaderModel costStrategy, BmsFreightPriceModel priceModel,UserEntity user) {
        Criteria criteria = Criteria.forClass(BmsTimeBillStrategyModel.class);
        Restriction r1 = Restrictions.eq("status", 1);
        Restriction r2 = Restrictions.eq("id", priceModel.getTimeStrategyId());
        Restriction r3 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2, r3));
        criteria.setOrder(Order.newInstance().desc("updatetime"));
        List<BmsTimeBillStrategyModel> models = timeBillStrategyMapper.findByCriteria(criteria);
        if (ObjectUtil.isEmpty(models)) {
            throw new PluginException("时间策略不存在，请先配置");
        }
        BmsTimeBillStrategyModel strategyModel = models.get(0);
        // 1.实际启运实际，2.实际到达实际 3.实际电子回单时间，4.实际正本回单时间
        int startDate = strategyModel.getStartDate();
        int endDate = strategyModel.getEndDate();
        Date startTime;
        Date endTime;
        // 开始时间
        if (startDate == 1) {
            if (ObjectUtil.isEmpty(costStrategy.getStartDate())) {
                throw new PluginException("启运日期不能为空");
            }
            startTime = costStrategy.getStartDate();
        } else if (startDate == 2) {
            if (ObjectUtil.isEmpty(costStrategy.getDeliveryDate())) {
                throw new PluginException("送达日期不能为空");
            }
            startTime = costStrategy.getDeliveryDate();
        } else if (startDate == 3) {
            if (ObjectUtil.isEmpty(costStrategy.getReceiptDate())) {
                throw new PluginException("回单日期不能为空");
            }
            startTime = costStrategy.getReceiptDate();
        } else {
            if (ObjectUtil.isEmpty(costStrategy.getOriginalBackDate())) {
                throw new PluginException("正本回单日期不能为空");
            }
            startTime = costStrategy.getOriginalBackDate();
        }
        // 结束时间
        if (endDate == 1) {
            if (ObjectUtil.isEmpty(costStrategy.getStartDate())) {
                throw new PluginException("启运日期不能为空");
            }
            endTime = costStrategy.getStartDate();
        } else if (endDate == 2) {
            if (ObjectUtil.isEmpty(costStrategy.getDeliveryDate())) {
                throw new PluginException("送达日期不能为空");
            }
            endTime = costStrategy.getDeliveryDate();
        } else if (endDate == 3) {
            if (ObjectUtil.isEmpty(costStrategy.getReceiptDate())) {
                throw new PluginException("回单日期不能为空");
            }
            endTime = costStrategy.getReceiptDate();
        } else {
            if (ObjectUtil.isEmpty(costStrategy.getOriginalBackDate())) {
                throw new PluginException("正本回单日期不能为空");
            }
            endTime = costStrategy.getOriginalBackDate();
        }

        long time1 = startTime.getTime();
        long time2 = endTime.getTime();

        BigDecimal minutes = BigDecimal.valueOf((time2 - time1) / 1000 / 60);

        // 获取小时
        Integer timeInteger = strategyModel.getTimeInteger();
        Integer timePrecision = strategyModel.getTimePrecision();

        if (timeInteger == 1) {
            minutes = minutes.divide(new BigDecimal(60),timePrecision, RoundingMode.HALF_UP);
        }
        // 向上取整
        if (timeInteger == 2) {
            minutes = minutes.divide(new BigDecimal(60),timePrecision, RoundingMode.UP);
        }
        // 向下取整
        if (timeInteger == 3) {
            minutes = minutes.divide(new BigDecimal(60),timePrecision, RoundingMode.DOWN);
        }

        // 启用阶梯时间换算
        if (strategyModel.getTimeLadderEnable().intValue() == 1) {
            Criteria criteriaLadder = Criteria.forClass(BmsTimeBillStrategyLadderModel.class);
            r2 = Restrictions.eq("timeStrategyId", strategyModel.getId());
            r3 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
            criteriaLadder.setRestriction(Restrictions.and( r2, r3));
            List<BmsTimeBillStrategyLadderModel> ladderModels = timeBillStrategyLadderMapper.findByCriteria(criteriaLadder);
            if (ObjectUtil.isEmpty(ladderModels)) {
                throw new PluginException("启用阶梯时间换算时,阶梯时间换算数据为空");
            }
            boolean flag = false;
            for (BmsTimeBillStrategyLadderModel ladderModel:ladderModels) {
                Boolean isMatch = matchTimeLadder(ladderModel,minutes);
                if (Boolean.TRUE.equals(isMatch)) {
                    minutes = ladderModel.getLadderTime();
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                throw new PluginException("启用阶梯时间换算时,没有匹配到阶梯时间换算数据");
            }
        }
        return minutes;
    }

    // 匹配价格阶梯
    public Boolean matchPriceLadder(BmsFreightPriceLadderModel ladderModel,BigDecimal cmpVal) {
        if (ObjectUtil.isNotEmpty(ladderModel.getSectionDown()) && ObjectUtil.isEmpty(ladderModel.getSectionUp())) {
            if (ladderModel.getSectionDownSymbol() == 1) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) > 0)) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionDownSymbol() == 2) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) >= 0)) {
                    return Boolean.TRUE;
                }
            }
        } else if (ObjectUtil.isEmpty(ladderModel.getSectionDown()) && ObjectUtil.isNotEmpty(ladderModel.getSectionUp())) {
            if (ladderModel.getSectionUpSymbol() == 1) {
                if ((cmpVal.compareTo(ladderModel.getSectionUp()) < 0)) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionUpSymbol() == 2) {
                if ((cmpVal.compareTo(ladderModel.getSectionUp()) <= 0)) {
                    return Boolean.TRUE;
                }
            }
        } else if (ObjectUtil.isNotEmpty(ladderModel.getSectionDown()) && ObjectUtil.isNotEmpty(ladderModel.getSectionUp())) {
            if (ladderModel.getSectionDownSymbol() == 1 && ladderModel.getSectionUpSymbol() == 1) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) > 0) && cmpVal.compareTo(ladderModel.getSectionUp()) < 0) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionDownSymbol() == 1 && ladderModel.getSectionUpSymbol() == 2) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) > 0) && cmpVal.compareTo(ladderModel.getSectionUp()) <= 0) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionDownSymbol() == 2 && ladderModel.getSectionUpSymbol() == 1) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) >= 0) && cmpVal.compareTo(ladderModel.getSectionUp()) < 0) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionDownSymbol() == 2 && ladderModel.getSectionUpSymbol() == 2) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) >= 0) && cmpVal.compareTo(ladderModel.getSectionUp()) <= 0) {
                    return Boolean.TRUE;
                }
            }
        }
        return Boolean.FALSE;
    }

    // 匹配时间阶梯
    public Boolean matchTimeLadder(BmsTimeBillStrategyLadderModel ladderModel,BigDecimal cmpVal) {
        if (ObjectUtil.isNotEmpty(ladderModel.getSectionDown()) && ObjectUtil.isEmpty(ladderModel.getSectionUp())) {
            if (ladderModel.getSectionDownSymbol() == 1) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) > 0)) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionDownSymbol() == 2) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) >= 0)) {
                    return Boolean.TRUE;
                }
            }
        } else if (ObjectUtil.isEmpty(ladderModel.getSectionDown()) && ObjectUtil.isNotEmpty(ladderModel.getSectionUp())) {
            if (ladderModel.getSectionUpSymbol() == 1) {
                if ((cmpVal.compareTo(ladderModel.getSectionUp()) < 0)) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionUpSymbol() == 2) {
                if ((cmpVal.compareTo(ladderModel.getSectionUp()) <= 0)) {
                    return Boolean.TRUE;
                }
            }
        } else if (ObjectUtil.isNotEmpty(ladderModel.getSectionDown()) && ObjectUtil.isNotEmpty(ladderModel.getSectionUp())) {
            if (ladderModel.getSectionDownSymbol() == 1 && ladderModel.getSectionUpSymbol() == 1) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) > 0) && cmpVal.compareTo(ladderModel.getSectionUp()) < 0) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionDownSymbol() == 1 && ladderModel.getSectionUpSymbol() == 2) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) > 0) && cmpVal.compareTo(ladderModel.getSectionUp()) <= 0) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionDownSymbol() == 2 && ladderModel.getSectionUpSymbol() == 1) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) >= 0) && cmpVal.compareTo(ladderModel.getSectionUp()) < 0) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionDownSymbol() == 2 && ladderModel.getSectionUpSymbol() == 2) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) >= 0) && cmpVal.compareTo(ladderModel.getSectionUp()) <= 0) {
                    return Boolean.TRUE;
                }
            }
        }
        return Boolean.FALSE;
    }
}