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

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

import cn.hutool.core.util.StrUtil;
import com.prolog.rdc.tms.model.entity.BmsBillIncomeFeeDetailModel;
import com.prolog.rdc.tms.model.entity.BmsBillPayFeeDetailModel;
import com.prolog.rdc.tms.service.BmsBillIncomeFeeService;
import com.prolog.rdc.tms.service.BmsBillPayFeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;
import com.prolog.common.util.ToolKits;
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.Order;
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.BusinessTypeEnum;
import com.prolog.rdc.tms.dao.mapper.BmsBillIncomeFeeHeaderMapper;
import com.prolog.rdc.tms.dao.mapper.BmsBillPayFeeHeaderMapper;
import com.prolog.rdc.tms.dao.mapper.LoadingBillHeadMapper;
import com.prolog.rdc.tms.dao.mapper.ShipBillDetailMapper;
import com.prolog.rdc.tms.dao.mapper.ShipBillHeadMapper;
import com.prolog.rdc.tms.model.dto.loadingbill.BmsLoadingBillDTO;
import com.prolog.rdc.tms.model.dto.shipbill.BmsShipBillDTO;
import com.prolog.rdc.tms.model.entity.BmsBillIncomeFeeHeaderModel;
import com.prolog.rdc.tms.model.entity.BmsBillPayFeeHeaderModel;
import com.prolog.rdc.tms.model.entity.BmsLoadingBillHeaderModel;
import com.prolog.rdc.tms.model.entity.BmsShipBillDetailModel;
import com.prolog.rdc.tms.model.entity.BmsShipBillHeaderModel;
import com.prolog.rdc.tms.model.entity.SysRefdatadModel;
import com.prolog.rdc.tms.model.vo.CalculateBillFeeVO;
import com.prolog.rdc.tms.model.vo.CalculateFeeShipBillVO;
import com.prolog.rdc.tms.model.vo.loadingbill.BmsLoadingBillQueryVO;
import com.prolog.rdc.tms.model.vo.loadingbill.BmsLoadingBillVO;
import com.prolog.rdc.tms.model.vo.shipbill.BmsShipBillVO;
import com.prolog.rdc.tms.proxy.MainDataProxy;
import com.prolog.rdc.tms.service.BillDownloadService;
import com.prolog.rdc.tms.service.BmsLoadingBillService;
import com.prolog.rdc.tms.service.BmsShipBillService;
import com.prolog.rdc.tms.util.ConvertorUtil;

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 cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @author hongbo.pan
 * @date 2023/4/13
 */
@Slf4j
@Service
public class BmsLoadingBillServiceImpl implements BmsLoadingBillService {

	@Autowired
	private LoadingBillHeadMapper loadingBillHeadMapper;

	@Autowired
	private BmsShipBillService shipBillService;

	@Autowired
	private ShipBillHeadMapper shipBillHeadMapper;

	@Autowired
	private MainDataProxy mainDataProxy;

	@Autowired
	private BmsBillIncomeFeeHeaderMapper incomeFeeHeaderMapper;

	@Autowired
	private ConvertorUtil convertorUtil;

	@Autowired
	private BillDownloadService billDownloadService;

	@Autowired
	private ShipBillDetailMapper shipBillDetailMapper;

	@Autowired
	private BmsBillPayFeeHeaderMapper payFeeHeaderMapper;

	@Autowired
	private BmsBillPayFeeService bmsBillPayFeeService;

	@Autowired
	private BmsBillIncomeFeeService bmsBillIncomeFeeService;

	@Override
	public Page<BmsLoadingBillDTO> findByCondition(BmsLoadingBillQueryVO vo) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		Criteria criteria = Criteria.forClass(BmsLoadingBillHeaderModel.class);
		Restriction r1 = ToolKits.isEmpty(vo.getLoadingBillNo()) ? null : Restrictions.like(BmsLoadingBillHeaderModel::getLoadingBillNo, "%" + vo.getLoadingBillNo() + "%");
		Restriction r2 = ToolKits.isEmpty(vo.getStartDate()) ? null : Restrictions.ge(BmsLoadingBillHeaderModel::getCreatetime, vo.getStartDate());
		Restriction r3 = ToolKits.isEmpty(vo.getEndDate()) ? null : Restrictions.le(BmsLoadingBillHeaderModel::getCreatetime, vo.getEndDate());
		Restriction r4 = Restrictions.eq(BmsLoadingBillHeaderModel::getEnterpriseId, user.getEnterpriseId());
		Restriction r5 = ToolKits.isEmpty(vo.getIdList()) ? null : Restrictions.in(BmsLoadingBillHeaderModel::getId, vo.getIdList());
		Restriction r6 = ToolKits.isEmpty(vo.getCarrierName()) ? null : Restrictions.like(BmsLoadingBillHeaderModel::getCarrierName, "%" + vo.getCarrierName() + "%");
		Restriction r7 = ToolKits.isEmpty(vo.getDriverName()) ? null : Restrictions.like(BmsLoadingBillHeaderModel::getDriverName, "%" + vo.getDriverName() + "%");
		Restriction r8 = ToolKits.isEmpty(vo.getVehiclePlateNumber()) ? null : Restrictions.like(BmsLoadingBillHeaderModel::getVehiclePlateNumber, "%" + vo.getVehiclePlateNumber() + "%");
		Restriction r9 = ToolKits.isEmpty(vo.getCargoOwnerName()) ? null : Restrictions.like(BmsLoadingBillHeaderModel::getCargoOwnerName, "%" + vo.getCargoOwnerName() + "%");
		Restriction r10 = ToolKits.isEmpty(user.getDepts()) ? null : Restrictions.in(BmsLoadingBillHeaderModel::getSettlementDepartmentId, user.getDepts());
		criteria.setRestriction(Restrictions.and(r1, r2, r3, r4, r5, r6, r7, r8, r9, r10));
		criteria.setOrder(Order.newInstance().desc("updatetime"));
		PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
		List<BmsLoadingBillHeaderModel> modelList = loadingBillHeadMapper.findByCriteria(criteria);
		List<BmsLoadingBillDTO> dtoList = Lists.newArrayList();
		if (CollectionUtil.isNotEmpty(modelList)) {
			List<SysRefdatadModel> dicData = getDic();
			dtoList = modelList.stream().map(model -> {
				BmsLoadingBillDTO dto = modelToBmsLoadingBillDTO(model, dicData);
				dto.setSettlementCompany(dto.getSettlementDepartment());
				dto.setSettlementCompanyId(dto.getSettlementDepartmentId());
				dto.setSettlementCompanyCode(dto.getSettlementDepartmentCode());
				if (BusinessTypeEnum.INCOME.getCode().equals(vo.getBusinessTypeHidden())) {
					dto = fillIncomeFee(dto, dicData);
				} else {
					dto = fillPayFee(dto, dicData);
				}
				dto.setSettlementStatusName(ConvertorUtil.getName(dicData, BmsConstant.SETTLEMENT_STATUS, String.valueOf(dto.getSettlementStatus())));
				dto.setCheckStatusName(ConvertorUtil.getName(dicData, BmsConstant.CHECK_STATUS, String.valueOf(dto.getCheckStatus())));
				return dto;
			}).collect(Collectors.toList());
		}
		Page<BmsLoadingBillDTO> page = PageUtils.getPage(dtoList);
		if (modelList instanceof com.github.pagehelper.Page) {
			com.github.pagehelper.Page<BmsLoadingBillHeaderModel> p0 = (com.github.pagehelper.Page<BmsLoadingBillHeaderModel>) modelList;
			page.setPageCount(p0.getPages());
			page.setPageNum(p0.getPageNum());
			page.setPageSize(p0.getPageSize());
			page.setTotalCount(p0.getTotal());
			page.setStartRow(p0.getStartRow());
			page.setEndRow(p0.getEndRow());
		}
		return page;
	}

	@Override
	public BmsLoadingBillDTO detailById(Long id) {
		BmsLoadingBillHeaderModel model = loadingBillHeadMapper.findById(id, BmsLoadingBillHeaderModel.class);
		List<SysRefdatadModel> dicData = getDic();
		BmsLoadingBillDTO dto = modelToBmsLoadingBillDTO(model, dicData);
		dto.setShipBillList(getShipBill(id));
		return dto;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void saveOrUpdate(BmsLoadingBillVO vo) {
		if (ObjectUtil.isNotNull(vo.getId())) {
			if (BusinessTypeEnum.INCOME.getCode().equals(vo.getBusinessTypeHidden())) {
				checkIncomeCheckStatus(vo.getId());
			} else {
				checkPayCheckStatus(vo.getId());
			}
			updateBmsLoadingBill(vo);
		} else {
			addBmsLoadingBill(vo);
		}
	}

	@Override
	public List<BmsShipBillDTO> getShipBill(Long id) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		Criteria criteria = Criteria.forClass(BmsShipBillHeaderModel.class);
		Restriction r1 = Restrictions.eq(BmsShipBillHeaderModel::getLoadingId, id);
		Restriction r2 = Restrictions.eq(BmsShipBillHeaderModel::getEnterpriseId, user.getEnterpriseId());
		criteria.setRestriction(Restrictions.and(r1, r2));
		List<BmsShipBillHeaderModel> modelList = shipBillHeadMapper.findByCriteria(criteria);
		return shipBillService.findByIdList(modelList.stream().map(BmsShipBillHeaderModel::getId).collect(Collectors.toList()));
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void calculate(List<Long> idList, BusinessTypeEnum businessTypeEnum) {
		idList.forEach(id -> {
			BmsLoadingBillHeaderModel headerModel = loadingBillHeadMapper.findById(id, BmsLoadingBillHeaderModel.class);
			if (BmsConstant.SYNCHRONOUS_STATUS_FAILED.equals(headerModel.getSynchronousStatus())) {
				throw new BizException("派车单" + headerModel.getLoadingBillNo() + "同步失败，不能核算！");
			}
			if (BusinessTypeEnum.INCOME.getCode().equals(businessTypeEnum.getCode())) {
				calIncome(headerModel);
			} else {
				calPay(headerModel);
			}
		});
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void submit(List<Long> idList, BusinessTypeEnum businessTypeEnum) {
		List<BmsLoadingBillHeaderModel> modelList = loadingBillHeadMapper.findByIds(BmsLoadingBillHeaderModel.class, idList.toArray(), null);
		modelList.forEach(headerModel -> {
			if (BusinessTypeEnum.INCOME.getCode().equals(businessTypeEnum.getCode())) {
				submitIncome(headerModel);
			} else {
				submitPay(headerModel);
			}
		});
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public Integer reIncomeCalculate(Long id) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		CalculateBillFeeVO calculateBillFeeVO = generateBillFee(id);
		Integer feeCltType = BmsConstant.FEE_CLT_TYPE_NO_MATCH;
		try {
			feeCltType = billDownloadService.calculateBillFee(calculateBillFeeVO);
		} catch (Exception e) {
			log.error("收入核算错误", e);
		}
		Integer finalFeeCltType = feeCltType;
		calculateBillFeeVO.getShipBillModels().forEach(shipBillVO -> {
			BmsShipBillHeaderModel shipBillHeaderModel = shipBillVO.getShipBillHeaderModel();
			shipBillHeaderModel.setFeeCltType(finalFeeCltType);
			shipBillHeaderModel.setUpdateperson(user.getNickname());
			shipBillHeaderModel.setUpdatetime(DateUtil.date());
			shipBillHeadMapper.update(shipBillHeaderModel);
		});
		BmsLoadingBillHeaderModel headerModel = calculateBillFeeVO.getLoadingBillHeaderModel();
		headerModel.setFeeCltType(finalFeeCltType);
		headerModel.setUpdateperson(user.getNickname());
		headerModel.setUpdatetime(DateUtil.date());
		loadingBillHeadMapper.update(headerModel);
		return feeCltType;
	}

	@Override
	public Integer rePayCalculate(Long id) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		CalculateBillFeeVO calculateBillFeeVO = generateBillFee(id);
		Integer feeCltType = BmsConstant.FEE_CLT_TYPE_NO_MATCH;
		try {
			feeCltType = billDownloadService.calculatePayBillFee(calculateBillFeeVO);
		} catch (Exception e) {
			log.error("支出核算错误", e);
		}
		Integer finalFeeCltType = feeCltType;
		calculateBillFeeVO.getShipBillModels().forEach(shipBillVO -> {
			BmsShipBillHeaderModel shipBillHeaderModel = shipBillVO.getShipBillHeaderModel();
			shipBillHeaderModel.setPayFeeCltType(finalFeeCltType);
			shipBillHeaderModel.setUpdateperson(user.getNickname());
			shipBillHeaderModel.setUpdatetime(DateUtil.date());
			shipBillHeadMapper.update(shipBillHeaderModel);
		});
//		BmsLoadingBillHeaderModel headerModel = calculateBillFeeVO.getLoadingBillHeaderModel();
//		headerModel.setPayFeeCltType(finalFeeCltType);
//		headerModel.setUpdateperson(user.getNickname());
//		headerModel.setUpdatetime(DateUtil.date());
//		loadingBillHeadMapper.update(headerModel);
		return feeCltType;
	}

	/**
	 * modelToBmsLoadingBillDTO
	 * 
	 * @param model
	 * @return
	 */
	private BmsLoadingBillDTO modelToBmsLoadingBillDTO(BmsLoadingBillHeaderModel model, List<SysRefdatadModel> dicData) {
		BmsLoadingBillDTO dto = BeanUtil.copyProperties(model, BmsLoadingBillDTO.class);
		dto.setVehicleTypeCategoryName(ConvertorUtil.getName(dicData, BmsConstant.VEHICLE_TYPE_CATEGORY, String.valueOf(dto.getVehicleTypeCategory())));
		dto.setFeeCltTypeName(ConvertorUtil.getName(dicData, BmsConstant.FEE_CLT_TYPE, String.valueOf(dto.getFeeCltType())));
		dto.setCarrierTypeName(ConvertorUtil.getName(dicData, BmsConstant.LINE_CARRIER_TYPE, String.valueOf(dto.getCarrierType())));
		dto.setStatusName(ConvertorUtil.getName(dicData, BmsConstant.LOADING_BILL_STATUS, String.valueOf(model.getStatus())));
		dto.setSourceName(ConvertorUtil.getName(dicData, BmsConstant.SOURCE, String.valueOf(model.getSource())));
		dto.setSynchronousStatusName(ConvertorUtil.getName(dicData, BmsConstant.SYNCHRONOUS_STATUS, String.valueOf(model.getSynchronousStatus())));
		dto.setVehicleAscriptionName(ConvertorUtil.getName(dicData, BmsConstant.VEHICLE_TYPE, String.valueOf(model.getVehicleAscription())));
		dto.setPayFeeCltTypeName(ConvertorUtil.getName(dicData, BmsConstant.FEE_CLT_TYPE, String.valueOf(dto.getPayFeeCltType())));
		return dto;
	}

	/**
	 * addBmsLoadingBill
	 * 
	 * @param vo
	 */
	private void addBmsLoadingBill(BmsLoadingBillVO vo) {
		String loadingBillNo = mainDataProxy.getCodeNumberByCode(BmsConstant.LOADING_BILL_HEAD_ID);
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		BmsLoadingBillHeaderModel model = BeanUtil.copyProperties(vo, BmsLoadingBillHeaderModel.class);
		model.setLoadingBillNo(loadingBillNo);
		model.setFeeCltType(BmsConstant.FEE_CLT_TYPE_NO_MATCH);
		model.setPayFeeCltType(BmsConstant.FEE_CLT_TYPE_NO_MATCH);
		model.setOrganizationId(user.getOrganizationId());
		model.setOrganizationCode(String.valueOf(user.getOrganizationId()));
		model.setOrganizationName(user.getOrgnaizationName());
		model.setDepartmentId(String.valueOf(user.getOrganizationId()));
		model.setDepartmentCode(String.valueOf(user.getOrganizationId()));
		model.setDepartmentName(user.getOrgnaizationName());
		model.setCreateperson(user.getNickname());
		model.setCreatetime(DateUtil.date());
		model.setUpdateperson(user.getNickname());
		model.setUpdatetime(DateUtil.date());
		model.setEnterpriseId(user.getEnterpriseId());
		model.setEnterpriseName(user.getEnterpriseName());
		model.setSource(BmsConstant.SOURCE_ADD);
		model.setTotalMileage(NumberUtil.null2Zero(model.getTotalMileage()));
		model.setTotalPcs(NumberUtil.null2Zero(model.getTotalPcs()));
		model.setTotalWeight(NumberUtil.null2Zero(model.getTotalWeight()));
		model.setTotalVolume(NumberUtil.null2Zero(model.getTotalVolume()));
		model.setTotalPayMileage(NumberUtil.null2Zero(model.getTotalPayMileage()));
		model.setTotalPayMileageMap(NumberUtil.null2Zero(model.getTotalPayMileageMap()));
		model.setTotalPayPcs(NumberUtil.null2Zero(model.getTotalPayPcs()));
		model.setTotalPayWeight(NumberUtil.null2Zero(model.getTotalPayWeight()));
		model.setTotalPayVolume(NumberUtil.null2Zero(model.getTotalPayVolume()));
		model.setActualTotalPcs(model.getTotalPcs());
		model.setActualTotalWeight(model.getTotalWeight());
		model.setActualTotalVolume(model.getTotalVolume());
		if (CollectionUtil.isNotEmpty(vo.getShipBillList())) {
			model.setShipbillNoList(vo.getShipBillList().stream().map(BmsShipBillVO::getShipbillNo).distinct().collect(Collectors.joining(",")));
			model.setTotalLclPiece(vo.getShipBillList().stream().map(BmsShipBillVO::getPackageLclPiece).reduce(BigDecimal.ZERO, NumberUtil::add));
			model.setTotalWholePiece(vo.getShipBillList().stream().map(BmsShipBillVO::getPackageWholePiece).reduce(BigDecimal.ZERO, NumberUtil::add));
		}
		loadingBillHeadMapper.save(model);
		buildRelation(vo, model);
	}

	/**
	 * updateBmsLoadingBill
	 * 
	 * @param vo
	 */
	private void updateBmsLoadingBill(BmsLoadingBillVO vo) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		BmsLoadingBillHeaderModel model = loadingBillHeadMapper.findById(vo.getId(), BmsLoadingBillHeaderModel.class);
		BeanUtil.copyProperties(vo, model);
		model.setUpdateperson(user.getNickname());
		model.setUpdatetime(DateUtil.date());
//        Criteria criteria = Criteria.forClass(BmsShipBillHeaderModel.class);
//        Restriction r1 = Restrictions.eq(BmsShipBillHeaderModel::getLoadingId, vo.getId());
//        Restriction r2 = Restrictions.eq(BmsShipBillHeaderModel::getEnterpriseId, user.getEnterpriseId());
//        criteria.setRestriction(Restrictions.and(r1, r2));
//        List<BmsShipBillHeaderModel> modelList = shipBillHeadMapper.findByCriteria(criteria);
//        if (CollectionUtil.isNotEmpty(modelList)) {
//            modelList.forEach(model1 -> {
//                model1.setLoadingId(null);
//                model1.setUpdateperson(user.getNickname());
//                model1.setUpdatetime(DateUtil.date());
//                shipBillHeadMapper.update(model1);
//            });
//        }
//        buildRelation(vo, model);
		loadingBillHeadMapper.update(model);
		if (BusinessTypeEnum.INCOME.getCode().equals(vo.getBusinessTypeHidden())) {
			reIncomeCalculate(model.getId());
		} else {
			rePayCalculate(model.getId());
		}
	}

	/**
	 * buildRelation
	 * 
	 * @param vo
	 * @param model
	 */
	private void buildRelation(BmsLoadingBillVO vo, BmsLoadingBillHeaderModel model) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		if (CollectionUtil.isNotEmpty(vo.getShipBillList())) {
			vo.getShipBillList().forEach(bmsShipBillVO -> {
				BmsShipBillHeaderModel model1 = shipBillHeadMapper.findById(bmsShipBillVO.getId(), BmsShipBillHeaderModel.class);
				model1.setLoadingId(model.getId());
				model1.setUpdateperson(user.getNickname());
				model1.setUpdatetime(DateUtil.date());
				shipBillHeadMapper.update(model1);
			});
		}
	}

	/**
	 * fillIncomeFee
	 * 
	 * @param dto
	 * @return
	 */
	private BmsLoadingBillDTO fillIncomeFee(BmsLoadingBillDTO dto, List<SysRefdatadModel> dicData) {
		List<BmsBillIncomeFeeHeaderModel> modelList = getIncomeByLoadingBill(dto.getId(), dto.getEnterpriseId());
		if (CollectionUtil.isNotEmpty(modelList)) {
			BmsBillIncomeFeeHeaderModel model = modelList.get(0);
			dto.setSettlementDate(model.getSettlementDate());
			dto.setCostDate(model.getCostDate());
			dto.setCostContract(model.getCostContract());
			dto.setCostStatus(model.getCostStatus());
			dto.setCostFailReason(model.getCostFailReason());
			dto.setSettlementStatus(model.getSettlementStatus());
			dto.setCostStatusName(ConvertorUtil.getName(dicData, BmsConstant.COST_STATUS, String.valueOf(dto.getCostStatus())));
			dto.setCheckStatus(model.getCheckStatus());
			dto.setIncomeAmount(NumberUtil.null2Zero(model.getIncomeAmount()));
			dto.setContractIncomeAmount(NumberUtil.null2Zero(model.getContractIncomeAmount()));

			List<BmsBillIncomeFeeDetailModel> detailModelList = bmsBillIncomeFeeService.findDetailModel(model);
			if (CollectionUtil.isNotEmpty(detailModelList)) {
				dto.setIncomeBillingPrice(detailModelList.stream().map(BmsBillIncomeFeeDetailModel::getBillingPrice).filter(StrUtil::isNotBlank).distinct().collect(Collectors.joining(",")));
			}
		} else {
			dto.setSettlementStatus(BmsConstant.SETTLEMENT_STATUS_0);
			dto.setCheckStatus(BmsConstant.CHECK_STATUS_0);
			dto.setIncomeAmount(BigDecimal.ZERO);
			dto.setContractIncomeAmount(BigDecimal.ZERO);
		}
		return dto;
	}

	/**
	 * fillPayFee
	 * 
	 * @param dto
	 * @return
	 */
	private BmsLoadingBillDTO fillPayFee(BmsLoadingBillDTO dto, List<SysRefdatadModel> dicData) {

		List<BmsBillPayFeeHeaderModel> modelList = getPayByLoadingBill(dto.getId(), dto.getEnterpriseId());
		if (CollectionUtil.isNotEmpty(modelList)) {
			BmsBillPayFeeHeaderModel model = modelList.get(0);
			dto.setSettlementDate(model.getSettlementDate());
			dto.setCostDate(model.getCostDate());
			dto.setCostContract(model.getCostContract());
			dto.setCostStatus(model.getCostStatus());
			dto.setCostFailReason(model.getCostFailReason());
			dto.setSettlementStatus(model.getSettlementStatus());
			dto.setCostStatusName(ConvertorUtil.getName(dicData, BmsConstant.COST_STATUS, String.valueOf(dto.getCostStatus())));
			dto.setCheckStatus(model.getCheckStatus());
			dto.setPayAmount(NumberUtil.null2Zero(model.getPayAmount()));
			dto.setContractPayAmount(NumberUtil.null2Zero(model.getContractPayAmount()));

			List<BmsBillPayFeeDetailModel> detailModelList = bmsBillPayFeeService.findDetailModel(model);
			if (CollectionUtil.isNotEmpty(detailModelList)) {
				dto.setPayBillingPrice(detailModelList.stream().map(BmsBillPayFeeDetailModel::getBillingPrice).filter(StrUtil::isNotBlank).distinct().collect(Collectors.joining(",")));
			}
		} else {
			dto.setSettlementStatus(BmsConstant.SETTLEMENT_STATUS_0);
			dto.setCheckStatus(BmsConstant.CHECK_STATUS_0);
			dto.setPayAmount(BigDecimal.ZERO);
			dto.setContractPayAmount(BigDecimal.ZERO);
		}
		return dto;
	}

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

	/**
	 * getIncomeByLoadingBill
	 * 
	 * @param id
	 * @param enterpriseId
	 * @return
	 */
	private List<BmsBillIncomeFeeHeaderModel> getIncomeByLoadingBill(Long id, Long enterpriseId) {
		Criteria criteria = Criteria.forClass(BmsBillIncomeFeeHeaderModel.class);
		Restriction r1 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getBillId, id);
		Restriction r2 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getBillType, 20);
		Restriction r3 = Restrictions.eq(BmsBillIncomeFeeHeaderModel::getEnterpriseId, enterpriseId);
		criteria.setRestriction(Restrictions.and(r1, r2, r3));
		return incomeFeeHeaderMapper.findByCriteria(criteria);
	}

	/**
	 * getPayByLoadingBill
	 * 
	 * @param id
	 * @param enterpriseId
	 * @return
	 */
	private List<BmsBillPayFeeHeaderModel> getPayByLoadingBill(Long id, Long enterpriseId) {
		Criteria criteria = Criteria.forClass(BmsBillPayFeeHeaderModel.class);
		Restriction r1 = Restrictions.eq(BmsBillPayFeeHeaderModel::getBillId, id);
		Restriction r2 = Restrictions.eq(BmsBillPayFeeHeaderModel::getBillType, 20);
		Restriction r3 = Restrictions.eq(BmsBillPayFeeHeaderModel::getEnterpriseId, enterpriseId);
		criteria.setRestriction(Restrictions.and(r1, r2, r3));
		return payFeeHeaderMapper.findByCriteria(criteria);
	}

	/**
	 * calIncome
	 * 
	 * @param headerModel
	 */
	private void calIncome(BmsLoadingBillHeaderModel headerModel) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		if (BmsConstant.FEE_CLT_TYPE_SHIP_BILL.equals(headerModel.getFeeCltType())) {
			throw new BizException("运单计费不支持派车单收入核算");
		}
		List<BmsBillIncomeFeeHeaderModel> incomeFeeHeaderModelList = getIncomeByLoadingBill(headerModel.getId(), user.getEnterpriseId());
		if (CollectionUtil.isNotEmpty(incomeFeeHeaderModelList)) {
			BmsBillIncomeFeeHeaderModel incomeFeeHeaderModel = incomeFeeHeaderModelList.get(0);
			if (BmsConstant.SETTLEMENT_STATUS_1.equals(incomeFeeHeaderModel.getSettlementStatus()) || BmsConstant.SETTLEMENT_STATUS_2.equals(incomeFeeHeaderModel.getSettlementStatus())) {
				throw new BizException("派车单" + headerModel.getLoadingBillNo() + "正在收入核算中！");
			}
			if (!BmsConstant.CHECK_STATUS_0.equals(incomeFeeHeaderModel.getCheckStatus())) {
				throw new BizException("派车单" + headerModel.getLoadingBillNo() + "已收入结算！");
			}
		}
		reIncomeCalculate(headerModel.getId());
		incomeFeeHeaderModelList = getIncomeByLoadingBill(headerModel.getId(), user.getEnterpriseId());
		if (CollectionUtil.isNotEmpty(incomeFeeHeaderModelList)) {
			BmsBillIncomeFeeHeaderModel incomeFeeHeaderModel = incomeFeeHeaderModelList.get(0);
			if (BmsConstant.COST_STATUS_FAILED.equals(incomeFeeHeaderModel.getCostStatus())) {
				incomeFeeHeaderModel.setSettlementStatus(BmsConstant.SETTLEMENT_STATUS_0);
			} else {
				incomeFeeHeaderModel.setSettlementStatus(BmsConstant.SETTLEMENT_STATUS_1);
			}
			incomeFeeHeaderModel.setUpdateperson(user.getNickname());
			incomeFeeHeaderModel.setUpdatetime(DateUtil.date());
			incomeFeeHeaderMapper.update(incomeFeeHeaderModel);
		}
	}

	/**
	 * calPay
	 * 
	 * @param headerModel
	 */
	private void calPay(BmsLoadingBillHeaderModel headerModel) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		if (BmsConstant.FEE_CLT_TYPE_SHIP_BILL.equals(headerModel.getPayFeeCltType())) {
			throw new BizException("运单计费不支持派车单支出核算");
		}
		List<BmsBillPayFeeHeaderModel> payFeeHeaderModelList = getPayByLoadingBill(headerModel.getId(), user.getEnterpriseId());
		if (CollectionUtil.isNotEmpty(payFeeHeaderModelList)) {
			BmsBillPayFeeHeaderModel payFeeHeaderModel = payFeeHeaderModelList.get(0);
			if (BmsConstant.SETTLEMENT_STATUS_1.equals(payFeeHeaderModel.getSettlementStatus()) || BmsConstant.SETTLEMENT_STATUS_2.equals(payFeeHeaderModel.getSettlementStatus())) {
				throw new BizException("派车单" + headerModel.getLoadingBillNo() + "正在支出核算中！");
			}
			if (!BmsConstant.CHECK_STATUS_0.equals(payFeeHeaderModel.getCheckStatus())) {
				throw new BizException("派车单" + headerModel.getLoadingBillNo() + "已支出结算！");
			}
		}
		rePayCalculate(headerModel.getId());
		payFeeHeaderModelList = getPayByLoadingBill(headerModel.getId(), user.getEnterpriseId());
		if (CollectionUtil.isNotEmpty(payFeeHeaderModelList)) {
			BmsBillPayFeeHeaderModel payFeeHeaderModel = payFeeHeaderModelList.get(0);
			if (BmsConstant.COST_STATUS_FAILED.equals(payFeeHeaderModel.getCostStatus())) {
				payFeeHeaderModel.setSettlementStatus(BmsConstant.SETTLEMENT_STATUS_0);
			} else {
				payFeeHeaderModel.setSettlementStatus(BmsConstant.SETTLEMENT_STATUS_1);
			}
			payFeeHeaderModel.setUpdateperson(user.getNickname());
			payFeeHeaderModel.setUpdatetime(DateUtil.date());
			payFeeHeaderMapper.update(payFeeHeaderModel);
		}
	}

	/**
	 * submitIncome
	 * 
	 * @param headerModel
	 */
	private void submitIncome(BmsLoadingBillHeaderModel headerModel) {
		if (BmsConstant.FEE_CLT_TYPE_SHIP_BILL.equals(headerModel.getFeeCltType())) {
			throw new BizException("运单计费不支持派车单收入提交");
		}
		checkIncomeCheckStatus(headerModel.getId());
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		List<BmsBillIncomeFeeHeaderModel> incomeFeeHeaderModelList = getIncomeByLoadingBill(headerModel.getId(), user.getEnterpriseId());
		if (CollectionUtil.isNotEmpty(incomeFeeHeaderModelList)) {
			BmsBillIncomeFeeHeaderModel incomeFeeHeaderModel = incomeFeeHeaderModelList.get(0);
			if (BmsConstant.COST_STATUS_FAILED.equals(incomeFeeHeaderModel.getCostStatus())) {
				throw new BizException("计费失败，不能提交");
			}
			if (!BmsConstant.SETTLEMENT_STATUS_1.equals(incomeFeeHeaderModel.getSettlementStatus())) {
				throw new BizException("不为核算待提交，不能提交");
			}
			incomeFeeHeaderModel.setSettlementStatus(BmsConstant.SETTLEMENT_STATUS_3);
			incomeFeeHeaderModel.setSettlementDate(DateUtil.date());
			incomeFeeHeaderModel.setUpdateperson(user.getNickname());
			incomeFeeHeaderModel.setUpdatetime(DateUtil.date());
			incomeFeeHeaderMapper.update(incomeFeeHeaderModel);
		}
	}

	/**
	 * submitPay
	 * 
	 * @param headerModel
	 */
	private void submitPay(BmsLoadingBillHeaderModel headerModel) {
		if (BmsConstant.FEE_CLT_TYPE_SHIP_BILL.equals(headerModel.getPayFeeCltType())) {
			throw new BizException("运单计费不支持派车单支出提交");
		}
		checkPayCheckStatus(headerModel.getId());
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		List<BmsBillPayFeeHeaderModel> payFeeHeaderModelList = getPayByLoadingBill(headerModel.getId(), user.getEnterpriseId());
		if (CollectionUtil.isNotEmpty(payFeeHeaderModelList)) {
			BmsBillPayFeeHeaderModel payFeeHeaderModel = payFeeHeaderModelList.get(0);
			if (BmsConstant.COST_STATUS_FAILED.equals(payFeeHeaderModel.getCostStatus())) {
				throw new BizException("计费失败，不能提交");
			}
			if (!BmsConstant.SETTLEMENT_STATUS_1.equals(payFeeHeaderModel.getSettlementStatus())) {
				throw new BizException("不为核算待提交，不能提交");
			}
			payFeeHeaderModel.setSettlementStatus(BmsConstant.SETTLEMENT_STATUS_3);
			payFeeHeaderModel.setSettlementDate(DateUtil.date());
			payFeeHeaderModel.setUpdateperson(user.getNickname());
			payFeeHeaderModel.setUpdatetime(DateUtil.date());
			payFeeHeaderMapper.update(payFeeHeaderModel);
		}
	}

	/**
	 * generateBillFee
	 * 
	 * @param id
	 * @return
	 */
	private CalculateBillFeeVO generateBillFee(Long id) {
		CalculateBillFeeVO calculateBillFeeVO = new CalculateBillFeeVO();
//		BmsLoadingBillHeaderModel headerModel = loadingBillHeadMapper.findById(id, BmsLoadingBillHeaderModel.class);
//		Criteria criteria = Criteria.forClass(BmsShipBillHeaderModel.class);
//		Restriction r1 = Restrictions.eq(BmsShipBillHeaderModel::getLoadingId, headerModel.getId());
//		Restriction r2 = Restrictions.eq(BmsShipBillHeaderModel::getEnterpriseId, headerModel.getEnterpriseId());
//		criteria.setRestriction(Restrictions.and(r1, r2));
		BmsShipBillHeaderModel headerModel = shipBillHeadMapper.findById(id, BmsShipBillHeaderModel.class);
		List<BmsShipBillHeaderModel> shipBillHeaderModelList = Lists.newArrayList(headerModel);

		List<CalculateFeeShipBillVO> shipBillVOList = Lists.newArrayList();
		shipBillHeaderModelList.forEach(shipBillHeaderModel -> {
			CalculateFeeShipBillVO shipBillVO = new CalculateFeeShipBillVO();
			Criteria criteria1 = Criteria.forClass(BmsShipBillDetailModel.class);
			Restriction r11 = Restrictions.eq(BmsShipBillDetailModel::getShipbillNo, shipBillHeaderModel.getShipbillNo());
			Restriction r12 = Restrictions.eq(BmsShipBillDetailModel::getEnterpriseId, shipBillHeaderModel.getEnterpriseId());
			criteria1.setRestriction(Restrictions.and(r11, r12));
			List<BmsShipBillDetailModel> shipBillDetailModelList = shipBillDetailMapper.findByCriteria(criteria1);
			shipBillVO.setShipBillHeaderModel(shipBillHeaderModel);
			shipBillVO.setDetailModels(shipBillDetailModelList);
			shipBillVOList.add(shipBillVO);
		});
//		calculateBillFeeVO.setLoadingBillHeaderModel(headerModel);
		calculateBillFeeVO.setShipBillModels(shipBillVOList);
		return calculateBillFeeVO;
	}

	/**
	 * checkIncomeCheckStatus
	 * 
	 * @param id
	 */
	private void checkIncomeCheckStatus(Long id) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		List<BmsBillIncomeFeeHeaderModel> modelList = getIncomeByLoadingBill(id, user.getEnterpriseId());
		if (CollectionUtil.isNotEmpty(modelList)) {
			BmsBillIncomeFeeHeaderModel model = modelList.get(0);
			if (!BmsConstant.CHECK_STATUS_0.equals(model.getCheckStatus())) {
				throw new BizException("派车单" + model.getBillNo() + "已收入结算！");
			}
		}
	}

	/**
	 * checkPayCheckStatus
	 * 
	 * @param id
	 */
	private void checkPayCheckStatus(Long id) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		List<BmsBillPayFeeHeaderModel> modelList = getPayByLoadingBill(id, user.getEnterpriseId());
		if (CollectionUtil.isNotEmpty(modelList)) {
			BmsBillPayFeeHeaderModel model = modelList.get(0);
			if (!BmsConstant.CHECK_STATUS_0.equals(model.getCheckStatus())) {
				throw new BizException("派车单" + model.getBillNo() + "已支出结算！");
			}
		}
	}
}
