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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.google.common.collect.Lists;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.pojo.Page;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.product.core.framework.entity.UserEntity;
import com.prolog.product.core.framework.util.PlgFxUsrUtils;
import com.prolog.rdc.tms.constant.BmsConstant;
import com.prolog.rdc.tms.constant.enums.LogTypeEnum;
import com.prolog.rdc.tms.dao.mapper.BmsBillIncomeFeeDetailMapper;
import com.prolog.rdc.tms.dao.mapper.BmsBillIncomeFeeHeaderMapper;
import com.prolog.rdc.tms.dao.mapper.ShipBillHeadMapper;
import com.prolog.rdc.tms.model.dto.SySParameterDTO;
import com.prolog.rdc.tms.model.dto.income.BmsBillIncomeFeeDTO;
import com.prolog.rdc.tms.model.dto.income.BmsBillIncomeFeeDetailDTO;
import com.prolog.rdc.tms.model.dto.income.BmsBillIncomeFeeInfoDTO;
import com.prolog.rdc.tms.model.dto.income.BmsLoadingBillIncomeFeeInfoDTO;
import com.prolog.rdc.tms.model.dto.income.BmsLoadingBillIncomeFeeDTO;
import com.prolog.rdc.tms.model.dto.income.BmsShipBillIncomeFeeInfoDTO;
import com.prolog.rdc.tms.model.dto.income.BmsShipBillIncomeFeeDTO;
import com.prolog.rdc.tms.model.dto.loadingbill.BmsLoadingBillDTO;
import com.prolog.rdc.tms.model.dto.shipbill.BmsLogOperationDTO;
import com.prolog.rdc.tms.model.dto.shipbill.BmsShipBillDTO;
import com.prolog.rdc.tms.model.dto.shipbill.BmsShipBillDetailDTO;
import com.prolog.rdc.tms.model.dto.shipbill.BmsShipBillPackageDTO;
import com.prolog.rdc.tms.model.entity.BmsBillIncomeFeeDetailModel;
import com.prolog.rdc.tms.model.entity.BmsBillIncomeFeeHeaderModel;
import com.prolog.rdc.tms.model.entity.BmsShipBillHeaderModel;
import com.prolog.rdc.tms.model.entity.SysRefdatadModel;
import com.prolog.rdc.tms.model.vo.income.BmsIncomeFeeAddVO;
import com.prolog.rdc.tms.model.vo.income.BmsIncomeFeeDetailAddVO;
import com.prolog.rdc.tms.model.vo.income.BmsIncomeQueryVO;
import com.prolog.rdc.tms.proxy.MainDataProxy;
import com.prolog.rdc.tms.service.BmsBillLogService;
import com.prolog.rdc.tms.service.BmsBillIncomeFeeService;
import com.prolog.rdc.tms.service.BmsLoadingBillService;
import com.prolog.rdc.tms.service.BmsShipBillService;
import com.prolog.rdc.tms.util.ConvertorUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Collectors;

/**
 * @author hongbo.pan
 * @date 2023/4/13
 */
@Service
public class BmsBillIncomeFeeServiceImpl implements BmsBillIncomeFeeService {

    @Autowired
    private BmsShipBillService shipBillService;

    @Autowired
    private BmsLoadingBillService loadingBillService;

    @Autowired
    private BmsBillLogService logService;

    @Autowired
    private BmsBillIncomeFeeHeaderMapper incomeFeeHeaderMapper;

    @Autowired
    private BmsBillIncomeFeeDetailMapper incomeFeeDetailMapper;

    @Autowired
    private MainDataProxy mainDataProxy;

    @Autowired
    private ConvertorUtil convertorUtil;

    @Autowired
    private ShipBillHeadMapper shipBillHeadMapper;

    @Override
    public Page<BmsShipBillIncomeFeeDTO> findShipBillFee(BmsIncomeQueryVO vo) {
        PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
        List<BmsShipBillIncomeFeeDTO> dtoList = incomeFeeHeaderMapper.findShipBillFee(vo);
        if (CollectionUtil.isNotEmpty(dtoList)) {
            List<SysRefdatadModel> dicData = getShipBillDic();
            dtoList.forEach(dto -> {
                dto.setOrderTypeName(ConvertorUtil.getName(dicData, BmsConstant.ORDER_TYPE, String.valueOf(dto.getOrderType())));
                dto.setOrderBusinessTypeName(ConvertorUtil.getName(dicData, BmsConstant.ORDER_BUSINESS_TYPE, String.valueOf(dto.getOrderBusinessType())));
                dto.setTemperatureRequirementName(ConvertorUtil.getName(dicData, BmsConstant.TEMPERATURE_REQUIREMENT, String.valueOf(dto.getTemperatureRequirement())));
                dto.setShipperTypeName(ConvertorUtil.getName(dicData, BmsConstant.SHIPPER_TYPE, String.valueOf(dto.getShipperType())));
                dto.setConsigneeTypeName(ConvertorUtil.getName(dicData, BmsConstant.CONSIGNEE_TYPE, String.valueOf(dto.getConsigneeType())));
                dto.setStatusName(ConvertorUtil.getName(dicData, BmsConstant.SHIPBILL_STATUS, String.valueOf(dto.getStatus())));
                dto.setSourceName(ConvertorUtil.getName(dicData, BmsConstant.SOURCE, String.valueOf(dto.getSource())));
                dto.setShipBillStatusName(ConvertorUtil.getName(dicData, BmsConstant.SHIPBILL_STATUS, String.valueOf(dto.getShipBillStatus())));
                dto.setSynchronousStatusName(ConvertorUtil.getName(dicData, BmsConstant.SYNCHRONOUS_STATUS, String.valueOf(dto.getSynchronousStatus())));
                dto.setAbnormalStatusName(ConvertorUtil.getName(dicData, BmsConstant.ABNORMAL_STATUS, String.valueOf(dto.getAbnormalStatus())));
                dto.setDeliveryMethodTypeName(ConvertorUtil.getName(dicData, BmsConstant.DELIVERY_METHOD_TYPE, String.valueOf(dto.getDeliveryMethodType())));
                dto.setTransportTypeName(ConvertorUtil.getName(dicData, BmsConstant.TRANSPORT_TYPE, String.valueOf(dto.getTransportType())));
                dto.setFeeCltTypeName(ConvertorUtil.getName(dicData, BmsConstant.FEE_CLT_TYPE, String.valueOf(dto.getFeeCltType())));
                dto.setCostStatusName(ConvertorUtil.getName(dicData, BmsConstant.COST_STATUS, String.valueOf(dto.getCostStatus())));
                dto.setSettlementStatusName(ConvertorUtil.getName(dicData, BmsConstant.SETTLEMENT_STATUS, String.valueOf(dto.getSettlementStatus())));
                dto.setCheckStatusName(ConvertorUtil.getName(dicData, BmsConstant.CHECK_STATUS, String.valueOf(dto.getCheckStatus())));
                dto.setCarrierTypeName(ConvertorUtil.getName(dicData, BmsConstant.LINE_CARRIER_TYPE, String.valueOf(dto.getCarrierType())));
                if (BmsConstant.LINE_CARRIER_TYPE_SJ.equals(dto.getCarrierType())) {
                    dto.setCarrierName(dto.getDriverName());
                }
            });
        }
        return PageUtils.getPage(dtoList);
    }

    @Override
    public Page<BmsLoadingBillIncomeFeeDTO> findLoadingBillFee(BmsIncomeQueryVO vo) {
        PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
        List<BmsLoadingBillIncomeFeeDTO> dtoList = incomeFeeHeaderMapper.findLoadingBillFee(vo);
        if (CollectionUtil.isNotEmpty(dtoList)) {
            List<SysRefdatadModel> dicData = getLoadingDic();
            dtoList.forEach(dto -> {
                dto.setStatusName(ConvertorUtil.getName(dicData, BmsConstant.LOADING_BILL_STATUS, String.valueOf(dto.getStatus())));
                dto.setSourceName(ConvertorUtil.getName(dicData, BmsConstant.SOURCE, String.valueOf(dto.getSource())));
                dto.setSynchronousStatusName(ConvertorUtil.getName(dicData, BmsConstant.SYNCHRONOUS_STATUS, String.valueOf(dto.getSynchronousStatus())));
                dto.setFeeCltTypeName(ConvertorUtil.getName(dicData, BmsConstant.FEE_CLT_TYPE, String.valueOf(dto.getFeeCltType())));
                dto.setCostStatusName(ConvertorUtil.getName(dicData, BmsConstant.COST_STATUS, String.valueOf(dto.getCostStatus())));
                dto.setSettlementStatusName(ConvertorUtil.getName(dicData, BmsConstant.SETTLEMENT_STATUS, String.valueOf(dto.getSettlementStatus())));
                dto.setCarrierTypeName(ConvertorUtil.getName(dicData, BmsConstant.LINE_CARRIER_TYPE, String.valueOf(dto.getCarrierType())));
                dto.setCheckStatusName(ConvertorUtil.getName(dicData, BmsConstant.CHECK_STATUS, String.valueOf(dto.getCheckStatus())));
                dto.setVehicleAscriptionName(ConvertorUtil.getName(dicData, BmsConstant.VEHICLE_TYPE, String.valueOf(dto.getVehicleAscription())));
            });
        }
        return PageUtils.getPage(dtoList);
    }

    @Override
    public BmsBillIncomeFeeInfoDTO detailById(Long id) {
        BmsBillIncomeFeeInfoDTO dto = new BmsBillIncomeFeeInfoDTO();
        BmsBillIncomeFeeHeaderModel headerModel = incomeFeeHeaderMapper.findById(id, BmsBillIncomeFeeHeaderModel.class);
        if (headerModel.getBillType() == 10) {
            dto.setShipBillDTO(shipBillService.detailById(headerModel.getBillId()));
        } else if (headerModel.getBillType() == 20) {
            dto.setLoadingBillDTO(loadingBillService.detailById(headerModel.getBillId()));
        }
        BmsBillIncomeFeeDTO feeDTO = BeanUtil.copyProperties(headerModel, BmsBillIncomeFeeDTO.class);
        feeDTO.setDetailDTOList(getDetail(id));
        dto.setIncomeFeeDTO(feeDTO);
        return dto;
    }

    @Override
    public BmsShipBillIncomeFeeInfoDTO detailShipBillById(Long id) {
        BmsBillIncomeFeeHeaderModel headerModel = incomeFeeHeaderMapper.findById(id, BmsBillIncomeFeeHeaderModel.class);
        BmsBillIncomeFeeDTO feeDTO = BeanUtil.copyProperties(headerModel, BmsBillIncomeFeeDTO.class);
        feeDTO.setDetailDTOList(getDetail(id));
        BmsShipBillDTO shipBillDTO = shipBillService.detailById(headerModel.getBillId());
        BmsShipBillIncomeFeeInfoDTO shipBillFeeDTO = BeanUtil.copyProperties(shipBillDTO, BmsShipBillIncomeFeeInfoDTO.class);
        shipBillFeeDTO.setDetailList(shipBillDTO.getDetailList());
        shipBillFeeDTO.setPackageList(shipBillDTO.getPackageList());
        shipBillFeeDTO.setIncomeFeeDTO(feeDTO);
        return shipBillFeeDTO;
    }

    @Override
    public BmsLoadingBillIncomeFeeInfoDTO detailLoadingBillById(Long id) {
        BmsBillIncomeFeeHeaderModel headerModel = incomeFeeHeaderMapper.findById(id, BmsBillIncomeFeeHeaderModel.class);
        BmsBillIncomeFeeDTO feeDTO = BeanUtil.copyProperties(headerModel, BmsBillIncomeFeeDTO.class);
        feeDTO.setDetailDTOList(getDetail(id));
        BmsLoadingBillDTO loadingBillDTO = loadingBillService.detailById(headerModel.getBillId());
        BmsLoadingBillIncomeFeeInfoDTO loadingBillFeeDTO = BeanUtil.copyProperties(loadingBillDTO, BmsLoadingBillIncomeFeeInfoDTO.class);
        loadingBillFeeDTO.setShipBillList(loadingBillDTO.getShipBillList());
        loadingBillFeeDTO.setIncomeFeeDTO(feeDTO);
        return loadingBillFeeDTO;
    }

    @Override
    public List<BmsBillIncomeFeeDetailDTO> getDetail(Long id) {
        BmsBillIncomeFeeHeaderModel headerModel = incomeFeeHeaderMapper.findById(id, BmsBillIncomeFeeHeaderModel.class);
        List<BmsBillIncomeFeeDetailDTO> dtoList = Lists.newArrayList();
        List<BmsBillIncomeFeeDetailModel> modelList = findDetailModel(headerModel);
        if (CollectionUtil.isNotEmpty(modelList)) {
            List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[]{
                    BmsConstant.EXPENSE_STATUS, // 费用状态
                    BmsConstant.BILLING_STATUS // 计费状态
            });
            dtoList = modelList.stream().map(dto -> {
                BmsBillIncomeFeeDetailDTO detailDTO = BeanUtil.copyProperties(dto, BmsBillIncomeFeeDetailDTO.class);
                detailDTO.setExpenseStatusName(ConvertorUtil.getName(dicData, BmsConstant.EXPENSE_STATUS, String.valueOf(detailDTO.getExpenseStatus())));
                detailDTO.setBillingSourceName(detailDTO.getBillingSource() == 1 ? "价格表生成" : "手工录入");
                detailDTO.setBillingTypeName(detailDTO.getBillingType());
                detailDTO.setBillingStatusName(ConvertorUtil.getName(dicData, BmsConstant.BILLING_STATUS, String.valueOf(detailDTO.getBillingStatus())));
                return detailDTO;
            }).collect(Collectors.toList());
        }
        return dtoList;
    }

    @Override
    public List<BmsLogOperationDTO> getLog(Long id) {
        return logService.getLog(LogTypeEnum.FEE, id.toString());
    }

    @Override
    public void addFee(BmsIncomeFeeAddVO vo) {
        List<BmsBillIncomeFeeHeaderModel> headerModelList = incomeFeeHeaderMapper.findByIds(BmsBillIncomeFeeHeaderModel.class, vo.getIdList().toArray(), null);
        if (CollectionUtil.isEmpty(headerModelList)) {
            throw new BizException("台账不存在");
        }
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        SySParameterDTO parameterData = mainDataProxy.queryParameter();
        Integer costPrecision = parameterData.getCostPrecision();
        Integer costInteger = parameterData.getCostInteger();
        RoundingMode roundingMode = null;
        if (costInteger == 1) {
            roundingMode = RoundingMode.HALF_UP;
        } else if (costInteger == 2) {
            roundingMode = RoundingMode.UP;
        } else if (costInteger == 3){
            roundingMode = RoundingMode.DOWN;
        }
        Integer billType = headerModelList.get(0).getBillType();
        RoundingMode finalRoundingMode = roundingMode;
        List<BmsBillIncomeFeeHeaderModel> loadingFeeModelList = Lists.newArrayList();
        vo.getDetailAddVOList().forEach(detailAddVO -> {
            BigDecimal taxAmt = detailAddVO.getTaxAmt();
            BigDecimal noTaxAmt = NumberUtil.div(taxAmt, NumberUtil.add(BigDecimal.ONE, NumberUtil.div(new BigDecimal(detailAddVO.getTaxPoint()), new BigDecimal("100"))), costPrecision, finalRoundingMode);
            BigDecimal avgTaxAmt = taxAmt;
            BigDecimal avgNoTaxAmt = noTaxAmt;
            if (detailAddVO.getIsShare() == 1) {
                avgTaxAmt = NumberUtil.div(taxAmt, headerModelList.size(), costPrecision, finalRoundingMode);
                avgNoTaxAmt = NumberUtil.div(noTaxAmt, headerModelList.size(), costPrecision, finalRoundingMode);
            }
            BigDecimal tax = NumberUtil.sub(avgTaxAmt, avgNoTaxAmt);
            detailAddVO.setTaxAmt(avgTaxAmt);
            detailAddVO.setTax(tax);
            detailAddVO.setNoTaxAmt(avgNoTaxAmt);
            for (int i = 0; i < headerModelList.size(); i++) {
                if (detailAddVO.getIsShare() == 1 && i == headerModelList.size() - 1) {
                    detailAddVO.setTaxAmt(NumberUtil.sub(taxAmt, NumberUtil.mul(avgTaxAmt, (headerModelList.size() - 1))));
                    detailAddVO.setNoTaxAmt(NumberUtil.sub(noTaxAmt, NumberUtil.mul(avgNoTaxAmt, (headerModelList.size() - 1))));
                    detailAddVO.setTax(NumberUtil.sub(detailAddVO.getTaxAmt(), detailAddVO.getNoTaxAmt()));
                }
                BmsBillIncomeFeeDetailModel shipBillFeeDetail = addDetail(headerModelList.get(i), detailAddVO);
                // 运单台账费用录入同步虚拟派车单台账
                if (billType == 10) {
                    Criteria criteria = Criteria.forClass(BmsBillIncomeFeeDetailModel.class);
                    Restriction r1 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getExpenseNo, shipBillFeeDetail.getExpenseNo());
                    Restriction r2 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getEnterpriseId, shipBillFeeDetail.getEnterpriseId());
                    criteria.setRestriction(Restrictions.and(r1, r2));
                    List<BmsBillIncomeFeeDetailModel> shipBillFeeDetailList = incomeFeeDetailMapper.findByCriteria(criteria);
                    Long originalFeeDetailId = null;
                    if (CollectionUtil.isNotEmpty(shipBillFeeDetailList)) {
                        originalFeeDetailId = shipBillFeeDetailList.get(0).getId();
                    }
                    BmsBillIncomeFeeHeaderModel loadingFeeModel = findLoadingFeeModel(headerModelList.get(i));
                    if (loadingFeeModel != null) {
                        addDetail(loadingFeeModel, detailAddVO, originalFeeDetailId);
                        loadingFeeModelList.add(loadingFeeModel);
                    }
                }
            }
        });
        List<BmsBillIncomeFeeHeaderModel> filterLoadingFeeModelList = loadingFeeModelList.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(BmsBillIncomeFeeHeaderModel::getBillId))), ArrayList::new));
        if (CollectionUtil.isNotEmpty(filterLoadingFeeModelList)) {
            headerModelList.addAll(filterLoadingFeeModelList);
        }
        headerModelList.forEach(headerModel -> {
            List<BmsBillIncomeFeeDetailModel> detailModelList = findDetailModel(headerModel);
            if (CollectionUtil.isNotEmpty(detailModelList)) {
                headerModel.setContractIncomeAmount(detailModelList.stream().filter(bmsBillIncomeFeeDetailModel -> bmsBillIncomeFeeDetailModel.getBillingSource() == 1).map(BmsBillIncomeFeeDetailModel::getTaxAmt).reduce(BigDecimal.ZERO, NumberUtil::add));
                headerModel.setIncomeAmount(detailModelList.stream().map(BmsBillIncomeFeeDetailModel::getTaxAmt).reduce(BigDecimal.ZERO, NumberUtil::add));
            } else {
                headerModel.setContractIncomeAmount(BigDecimal.ZERO);
                headerModel.setIncomeAmount(BigDecimal.ZERO);
            }
            headerModel.setUpdateperson(user.getNickname());
            headerModel.setUpdatetime(DateUtil.date());
            incomeFeeHeaderMapper.update(headerModel);
        });
    }

    @Override
    public List<BmsShipBillDTO> getShipBill(Long id) {
        BmsBillIncomeFeeHeaderModel headerModel = incomeFeeHeaderMapper.findById(id, BmsBillIncomeFeeHeaderModel.class);
        return loadingBillService.getShipBill(headerModel.getBillId());
    }

    @Override
    public List<BmsShipBillDetailDTO> getItem(Long id) {
        List<BmsShipBillDetailDTO> list = Lists.newArrayList();
        List<Long> shipBillIdList = getShipBillIdList(id);
        if (CollectionUtil.isNotEmpty(shipBillIdList)) {
            list = shipBillIdList.stream().flatMap(shipBillId -> shipBillService.getItem(shipBillId).stream()).collect(Collectors.toList());
        }
        return list;
    }

    @Override
    public List<BmsShipBillPackageDTO> getPackage(Long id) {
        List<BmsShipBillPackageDTO> list = Lists.newArrayList();
        List<Long> shipBillIdList = getShipBillIdList(id);
        if (CollectionUtil.isNotEmpty(shipBillIdList)) {
            list = shipBillIdList.stream().flatMap(shipBillId -> shipBillService.getPackage(shipBillId).stream()).collect(Collectors.toList());
        }
        return list;
    }

    @Override
    public List<Object> getAudit(Long id) {
        return Lists.newArrayList();
    }

    @Override
    public void submit(List<Long> idList) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        List<BmsBillIncomeFeeDetailModel> detailModelList = incomeFeeDetailMapper.findByIds(BmsBillIncomeFeeDetailModel.class, idList.toArray(), null);
        detailModelList.forEach(detailModel -> {
            if (BmsConstant.EXPENSE_STATUS_0.equals(detailModel.getExpenseStatus())) {
                detailModel.setExpenseStatus(BmsConstant.EXPENSE_STATUS_2);
                detailModel.setUpdateperson(user.getNickname());
                detailModel.setUpdatetime(DateUtil.date());
                incomeFeeDetailMapper.update(detailModel);
            }
        });
    }

    /**
     * addDetail
     * @param headerModel
     * @param detailAddVO
     * @return
     */
    private BmsBillIncomeFeeDetailModel addDetail(BmsBillIncomeFeeHeaderModel headerModel, BmsIncomeFeeDetailAddVO detailAddVO) {
        return addDetail(headerModel, detailAddVO, null);
    }

    /**
     * addDetail
     * @param headerModel
     * @param detailAddVO
     * @param originalFeeDetailId
     * @return
     */
    private BmsBillIncomeFeeDetailModel addDetail(BmsBillIncomeFeeHeaderModel headerModel, BmsIncomeFeeDetailAddVO detailAddVO, Long originalFeeDetailId) {
        String expenseNo = mainDataProxy.getCodeNumberByCode(BmsConstant.SHIP_BILL_EXPENSE_NO);
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        BmsBillIncomeFeeDetailModel detailModel = new BmsBillIncomeFeeDetailModel();
        detailModel.setBillNo(headerModel.getBillNo());
        detailModel.setBillId(headerModel.getBillId());
        detailModel.setExpenseCode(detailAddVO.getExpenseCode());
        detailModel.setExpenseName(detailAddVO.getExpenseName());
        detailModel.setExpenseType(detailAddVO.getExpenseType());
        detailModel.setExpenseTypeName(detailAddVO.getExpenseTypeName());
        detailModel.setExpenseAccountCode(detailAddVO.getExpenseAccountCode());
        detailModel.setExpenseAccountName(detailAddVO.getExpenseAccountName());
        detailModel.setAmount(detailAddVO.getTaxAmt());
        detailModel.setTaxPoint(detailAddVO.getTaxPoint());
        detailModel.setTaxAmt(detailAddVO.getTaxAmt());
        detailModel.setIsPreTax(detailAddVO.getIsPreTax());
        detailModel.setNoTaxAmt(detailAddVO.getNoTaxAmt());
        detailModel.setTax(detailAddVO.getTax());
        detailModel.setIsShare(detailAddVO.getIsShare().toString());
        detailModel.setMemo(detailAddVO.getMemo());
        detailModel.setExpenseNo(expenseNo);
        detailModel.setExpenseStatus(0);
        detailModel.setCheckStatus(BmsConstant.CHECK_STATUS_0);
        detailModel.setBillingSource(2);
        detailModel.setBillingStatus(1);
        detailModel.setBillingDate(DateUtil.date());
//        detailModel.setBillingContract();
//        detailModel.setBillingPrice();
//        detailModel.setBillingType();
//        detailModel.setBillingFailReason();
        detailModel.setCreateperson(user.getNickname());
        detailModel.setCreatetime(DateUtil.date());
        detailModel.setUpdateperson(user.getNickname());
        detailModel.setUpdatetime(DateUtil.date());
        detailModel.setEnterpriseId(user.getEnterpriseId());
        detailModel.setEnterpriseName(user.getEnterpriseName());
        detailModel.setOriginalFeeDetailId(originalFeeDetailId);
        incomeFeeDetailMapper.save(detailModel);
        return detailModel;
    }

    /**
     * findDetailModel
     * @param headerModel
     * @return
     */
    @Override
    public List<BmsBillIncomeFeeDetailModel> findDetailModel(BmsBillIncomeFeeHeaderModel headerModel) {
        Criteria criteria = Criteria.forClass(BmsBillIncomeFeeDetailModel.class);
        Restriction r1 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillId, headerModel.getBillId());
        Restriction r2 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getBillNo, headerModel.getBillNo());
        Restriction r3 = Restrictions.eq(BmsBillIncomeFeeDetailModel::getEnterpriseId, headerModel.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2, r3));
        return incomeFeeDetailMapper.findByCriteria(criteria);
    }

    /**
     * getDic
     * @return
     */
    private List<SysRefdatadModel> getShipBillDic() {
        return convertorUtil.getDictionary(new String[] {
                BmsConstant.SHIPBILL_STATUS, // 运单状态
                BmsConstant.SHIPPER_TYPE, // 运输状态
                BmsConstant.ABNORMAL_STATUS, // 异常状态
                BmsConstant.ORDER_TYPE, // 订单类型
                BmsConstant.CONSIGNEE_TYPE, // 收货方类型
                BmsConstant.ORDER_BUSINESS_TYPE, // 订单业务类型
                BmsConstant.SETTLEMENT_STATUS, // 核算状态
                BmsConstant.SOURCE, // 来源
                BmsConstant.COST_STATUS, // 计费状态
                BmsConstant.SYNCHRONOUS_STATUS, // 同步状态
                BmsConstant.TEMPERATURE_REQUIREMENT,// 温度要求
                BmsConstant.LINE_CARRIER_TYPE,// 承运方类型
                BmsConstant.DELIVERY_METHOD_TYPE,// 配送方式
                BmsConstant.TRANSPORT_TYPE,// 运输模式
                // 费用计算类型
                BmsConstant.FEE_CLT_TYPE,
                BmsConstant.CHECK_STATUS
        });
    }

    /**
     * getDic
     * @return
     */
    private List<SysRefdatadModel> getLoadingDic() {
        return convertorUtil.getDictionary(new String[] {
                // 核算状态
                BmsConstant.SETTLEMENT_STATUS,
                // 计费状态
                BmsConstant.COST_STATUS,
                // 同步状态
                BmsConstant.SYNCHRONOUS_STATUS,
                // 承运方类型
                BmsConstant.LINE_CARRIER_TYPE,
                // 车辆类别
                BmsConstant.VEHICLE_TYPE_CATEGORY,
                // 费用计算类型
                BmsConstant.FEE_CLT_TYPE,
                // 来源
                BmsConstant.SOURCE,
                BmsConstant.LOADING_BILL_STATUS,
                BmsConstant.VEHICLE_TYPE,
                BmsConstant.CHECK_STATUS
        });
    }

    /**
     * getShipBillIdList
     * @param id
     * @return
     */
    private List<Long> getShipBillIdList(Long id) {
        List<Long> shipBillIdList = Lists.newArrayList();
        BmsBillIncomeFeeHeaderModel headerModel = incomeFeeHeaderMapper.findById(id, BmsBillIncomeFeeHeaderModel.class);
        if (headerModel.getBillType() == 10) {
            shipBillIdList.add(headerModel.getBillId());
        } else {
            Criteria criteria = Criteria.forClass(BmsShipBillHeaderModel.class);
            Restriction r1 = Restrictions.eq(BmsShipBillHeaderModel::getLoadingId, headerModel.getBillId());
            Restriction r2 = Restrictions.eq(BmsShipBillHeaderModel::getEnterpriseId, headerModel.getEnterpriseId());
            criteria.setRestriction(Restrictions.and(r1, r2));
            List<BmsShipBillHeaderModel> modelList = shipBillHeadMapper.findByCriteria(criteria);
            if (CollectionUtil.isNotEmpty(modelList)) {
                shipBillIdList = modelList.stream().map(BmsShipBillHeaderModel::getId).collect(Collectors.toList());
            }
        }
        return shipBillIdList;
    }

    /**
     * findLoadingFeeModel
     * @param headerModel
     * @return
     */
    private BmsBillIncomeFeeHeaderModel findLoadingFeeModel(BmsBillIncomeFeeHeaderModel headerModel) {
        BmsShipBillHeaderModel bmsShipBillHeaderModel = shipBillHeadMapper.findById(headerModel.getBillId(), BmsShipBillHeaderModel.class);
        if (bmsShipBillHeaderModel == null) {
            return null;
        }
        Criteria criteria = Criteria.forClass(BmsBillIncomeFeeHeaderModel.class);
        Restriction r1 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getBillId, bmsShipBillHeaderModel.getLoadingId());
        Restriction r2 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getBillNo, bmsShipBillHeaderModel.getLoadingBillNo());
        Restriction r3 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getBillType, 20);
        Restriction r4 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getEnterpriseId, bmsShipBillHeaderModel.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2, r3, r4));
        List<BmsBillIncomeFeeHeaderModel> modelList = incomeFeeHeaderMapper.findByCriteria(criteria);
        if (CollectionUtil.isNotEmpty(modelList)) {
            return modelList.get(0);
        }
        return null;
    }
}
