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

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.codingapi.tx.annotation.TxTransaction;
import com.prolog.rdc.tms.app.model.vo.business.*;
import com.prolog.rdc.tms.app.service.business.*;
import com.prolog.rdc.tms.app.util.CommonUtil;
import com.prolog.rdc.tms.app.util.ConvertorUtil;
import com.prolog.rdc.tms.app.util.MessageUtil;
import com.prolog.rdc.tms.model.dto.message.SendMessageDTO;
import com.prolog.rdc.tms.model.entity.SysRefdatadModel;
import com.prolog.rdc.tms.model.enums.MessageOrderTypeEnum;
import com.prolog.rdc.tms.model.enums.MessageTypeEnum;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.prolog.common.util.ToolKits;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.PrologException;
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.app.constant.BussinessConstant;
import com.prolog.rdc.tms.app.constant.DataDictionaryConstant;
import com.prolog.rdc.tms.app.constant.SeriaNnumberConstant;
import com.prolog.rdc.tms.app.dao.mapper.TmsLoadingBillDetailMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsLoadingBillHeaderMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsShipbillDetailMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsShipbillHeaderMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsShipbillNodeTrackingMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsShipbillPackageMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsShipbillTransportLogMapper;
import com.prolog.rdc.tms.app.model.dto.business.DispatchCheckPackageDTO;
import com.prolog.rdc.tms.app.model.dto.business.DispatchCheckQueryDTO;
import com.prolog.rdc.tms.app.model.dto.business.DispatchCheckShipBillDtlDTO;
import com.prolog.rdc.tms.app.model.dto.business.TrailerQueryDTO;
import com.prolog.rdc.tms.app.model.entity.ShipbillNodeTracking;
import com.prolog.rdc.tms.app.model.entity.TmsLoadingBillDetailModel;
import com.prolog.rdc.tms.app.model.entity.TmsLoadingBillHeaderModel;
import com.prolog.rdc.tms.app.model.entity.TmsShipbillDetailModel;
import com.prolog.rdc.tms.app.model.entity.TmsShipbillHeaderModel;
import com.prolog.rdc.tms.app.model.entity.TmsShipbillPackageModel;
import com.prolog.rdc.tms.app.model.entity.TmsShipbillTransLogModel;
import com.prolog.rdc.tms.app.util.BusinessFlowUtil;
import com.prolog.rdc.tms.model.dto.basicConfigure.ShipbillFitBusinessFlowDTO;
import com.prolog.rdc.tms.model.dto.basicData.CustomerCarrierDTO;
import com.prolog.rdc.tms.model.vo.basicConfigure.ApprovalOpenVO;
import com.prolog.rdc.tms.model.vo.basicConfigure.BusinessFlowShipbillVO;
import com.prolog.rdc.tms.model.vo.basicData.CustomerCarrierVO;
import com.prolog.rdc.tms.rmi.feign.MaindataFeign;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;

/**
 * 已托运实现层
 * <p>
 * Company: 湖北普罗格科技股份有限公司
 *
 * @author zhangsj
 * @since 2022/4/18 12:43
 */
@Service
public class TrailerServiceImpl implements TrailerService {

	@Autowired
	private TmsLoadingBillHeaderMapper tmsLoadingBillHeaderMapper;

	@Autowired
	private TmsLoadingBillDetailMapper tmsLoadingBillDetailMapper;

	@Autowired
	private MaindataFeign maindataTmsResource;

	@Autowired
	private TmsShipbillHeaderMapper tmsShipbillHeaderMapper;

	@Autowired
	private ShipbillOperateLogService shipbillOperateLogService;

	@Autowired
	private ShipbillNodeTrackingService shipbillNodeTrackingService;

	@Autowired
	private TmsShipbillNodeTrackingMapper tmsShipbillNodeTrackingMapper;

	@Autowired
	private BusinessFlowUtil businessFlowUtil;

	@Autowired
	private TmsShipbillTransportLogMapper tmsShipbillTransportLogMapper;

	@Autowired
	private TmsShipbillDetailMapper tmsShipbillDetailMapper;

	@Autowired
	private TmsShipbillPackageMapper tmsShipbillPackageMapper;

	@Autowired
	private LoadingBillService loadingBillService;

	@Autowired
	private ConvertorUtil convertorUtil;

	@Autowired
	private CommonUtil commonUtil;

	@Autowired
	private BookingService bookingService;

	/**
	 * 已托运分页查询
	 *
	 * @param trailerQueryVO
	 * @return
	 */
	@SuppressWarnings("resource")
	@Override
	public Page<TrailerQueryDTO> loadingBillQuery(TrailerQueryVO trailerQueryVO) {
		ToolKits.isParamNull(trailerQueryVO, "已托运查询请求不为空");
		ToolKits.isParamNull(trailerQueryVO.getPageNum(), "当前页码不为空");
		ToolKits.isParamNull(trailerQueryVO.getPageSize(), "每页条数不为空");

		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");

		List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[] {
				DataDictionaryConstant.LOADING_BILL_STATUS, // 派车单状态
				DataDictionaryConstant.VEHICLE_TYPE_CATEGORY// 车辆类别
		});

		// 添加查询条件
		Criteria criteria = Criteria.forClass(TmsLoadingBillHeaderModel.class);
		Restriction r1 = ToolKits.isEmpty(trailerQueryVO.getCreateStartTime()) ? null : Restrictions.ge("createtime", trailerQueryVO.getCreateStartTime());
		Restriction r2 = ToolKits.isEmpty(trailerQueryVO.getCreateEndTime()) ? null : Restrictions.le("createtime", trailerQueryVO.getCreateEndTime());
		Restriction r3 = Restrictions.eq("carrierType", DataDictionaryConstant.LINE_CARRIER_TYPE_CYF);
		Restriction r4 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
		Restriction r5 = null;
		if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
			r5 = Restrictions.eq("scheduleType", DataDictionaryConstant.SCHEDULE_TYPE_ZY);

		} else if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
			r5 = Restrictions.eq("scheduleType", DataDictionaryConstant.SCHEDULE_TYPE_CYS);
		}

		criteria.setRestriction(Restrictions.and(r1, r2, r3, r4, r5));
		criteria.setOrder(Order.newInstance().desc(new String[] { "updatetime" }));

		PageUtils.startPage(trailerQueryVO.getPageNum(), trailerQueryVO.getPageSize());
		List<TmsLoadingBillHeaderModel> tmsLoadingBillHeaderModels = tmsLoadingBillHeaderMapper.findByCriteria(criteria);

		List<TrailerQueryDTO> trailerPageDTOS = Lists.newArrayList();
		for (TmsLoadingBillHeaderModel tmsLoadingBillHeaderModel : tmsLoadingBillHeaderModels) {
			TrailerQueryDTO dto = new TrailerQueryDTO();
			BeanUtils.copyProperties(tmsLoadingBillHeaderModel, dto);

			dto.setStatusName(ConvertorUtil.getName(dicData, DataDictionaryConstant.LOADING_BILL_STATUS, String.valueOf(dto.getStatus())));
			dto.setVehicleTypeCategoryName(ConvertorUtil.getName(dicData, DataDictionaryConstant.VEHICLE_TYPE_CATEGORY, String.valueOf(dto.getVehicleTypeCategory())));
			Criteria loadDetailCriteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
			Restriction loadDetailRestriction = Restrictions.eq(TmsLoadingBillDetailModel::getLoadingBillId, tmsLoadingBillHeaderModel.getLoadingBillId());
			loadDetailCriteria.setRestriction(loadDetailRestriction);
			List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModelList = tmsLoadingBillDetailMapper.findByCriteria(loadDetailCriteria);
			dto.setShipBillIdList(tmsLoadingBillDetailModelList.stream().
					filter(model -> StrUtil.isNotBlank(model.getShipbillId())).
					map(TmsLoadingBillDetailModel::getShipbillId).distinct().collect(Collectors.joining(",")));
			dto.setColdShipBillIdList(tmsLoadingBillDetailModelList.stream().
					filter(model -> ObjectUtil.isNotNull(model.getTemperatureRequirement()) &&
							!DataDictionaryConstant.TEMPERATURE_REQUIREMENT_CW.equals(model.getTemperatureRequirement()) &&
							StrUtil.isNotBlank(model.getShipbillId())).
					map(TmsLoadingBillDetailModel::getShipbillId).distinct().collect(Collectors.joining(",")));
			dto.setUrgentShipBillIdList(tmsLoadingBillDetailModelList.stream().
					filter(model -> ObjectUtil.isNotNull(model.getOrderType()) &&
							!DataDictionaryConstant.ORDER_TYPE_P.equals(model.getOrderType()) &&
							StrUtil.isNotBlank(model.getShipbillId())).
					map(TmsLoadingBillDetailModel::getShipbillId).distinct().collect(Collectors.joining(",")));
			trailerPageDTOS.add(dto);
		}
		// 分页重组
		Page<TrailerQueryDTO> page = PageUtils.getPage(trailerPageDTOS);
		if (tmsLoadingBillHeaderModels instanceof com.github.pagehelper.Page) {
			com.github.pagehelper.Page<TmsLoadingBillHeaderModel> p0 = (com.github.pagehelper.Page<TmsLoadingBillHeaderModel>) tmsLoadingBillHeaderModels;
			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;
	}

	/**
	 * 已托运审核
	 *
	 * @param ids
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void trailerAuditData(List<String> ids) {
		ToolKits.isParamNull(ids, "托运单ID不为空");

		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");
		Date date = DateUtil.date();

		autoTrailerAuditData(ids, user, date);
	}

	/**
	 * 自动已托运审核
	 *
	 * @param ids
	 */
	@Override
	public void autoTrailerAuditData(List<String> ids, UserEntity user, Date date) {
		List<TmsLoadingBillHeaderModel> tmsLoadingBillHeaderModels = tmsLoadingBillHeaderMapper.findByIds(TmsLoadingBillHeaderModel.class, ids.toArray(), null);
		// 判断托运单是否已审核
		String str = tmsLoadingBillHeaderModels.stream().filter(o -> o.getStatus().intValue() != DataDictionaryConstant.LOADING_BILL_STATUS_WSH.intValue()).map(TmsLoadingBillHeaderModel::getLoadingBillNo).collect(Collectors.joining(","));

		if (ToolKits.isNotEmpty(str)) {
			throw new RuntimeException("托运单[" + str + "]不是待审核状态,不能调度审核!");
		}

		List<String> receiveObjs = Lists.newArrayList();
		for (TmsLoadingBillHeaderModel tmsLoadingBillHeaderModel : tmsLoadingBillHeaderModels) {

			// 更改运单状态
			Criteria criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
			Restriction r1 = Restrictions.eq("loadingBillId", tmsLoadingBillHeaderModel.getLoadingBillId());
			Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
			criteria.setRestriction(Restrictions.and(r1, r2));
			List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModels = tmsLoadingBillDetailMapper.findByCriteria(criteria);

			// 记录运单日志
			int shipperTypeCnt = 0;
			int consigneeType = 0;

			Boolean matched = false;
			// 匹配调度审核审批流程
			for (TmsLoadingBillDetailModel loadingBillDetailModel : tmsLoadingBillDetailModels) {
				TmsShipbillHeaderModel tmsShipbillHeaderModel = tmsShipbillHeaderMapper.findById(loadingBillDetailModel.getShipbillId(), TmsShipbillHeaderModel.class);
				Assert.isTrue(null != tmsShipbillHeaderModel, "运单【" + tmsShipbillHeaderModel.getShipbillNo() + "】运单不存在,审核失败");
				if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
					matched = approvalOpen(tmsLoadingBillHeaderModel, tmsShipbillHeaderModel, DataDictionaryConstant.APPROVAL_FLOW_TYPE_DISPATCH, user);
				} else {
					matched = approvalOpen(tmsLoadingBillHeaderModel, tmsShipbillHeaderModel, DataDictionaryConstant.APPROVAL_FLOW_TYPE_DISPATCH_CARRIER, user);
				}
				if (matched) {
					break;
				}
			}
			if (matched) {
				tmsLoadingBillHeaderModel.setStatus(DataDictionaryConstant.LOADING_BILL_STATUS_DIS_APPROVAL);
			} else {
				tmsLoadingBillHeaderModel.setStatus(DataDictionaryConstant.LOADING_BILL_STATUS_YSH);
			}

			for (TmsLoadingBillDetailModel detailModel : tmsLoadingBillDetailModels) {
				if (DataDictionaryConstant.SHIPPER_TYPE_CK.equals(detailModel.getShipperType())) {
					shipperTypeCnt++;
				}
				if (DataDictionaryConstant.CONSIGNEE_TYPE_CK.equals(detailModel.getConsigneeType())) {
					consigneeType++;
				}
				ShipbillNodeTrackingSaveVO shipbillNodeTrackingSaveVO = new ShipbillNodeTrackingSaveVO();
				ShipbillOperateLogSaveVO shipbillOperateLogSaveVO = new ShipbillOperateLogSaveVO();
				Map<String, Object> mapUpdateShipbillHeader = Maps.newHashMap();
				Map<String, Object> mapUpdateLoadingDetail = Maps.newHashMap();

				mapUpdateShipbillHeader.put("updateperson", user.getNickname());
				mapUpdateShipbillHeader.put("updatetime", date);
				mapUpdateLoadingDetail.put("updateperson", user.getNickname());
				mapUpdateLoadingDetail.put("updatetime", date);
				if (!matched) {
					// 没有匹配到调度审核的审批流程
					if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
						if (ToolKits.isNotEmpty(detailModel.getCarrierFlowConfig())) {
							// 自有账号
							int status = DataDictionaryConstant.SHIPBILL_STATUS_DISPATCH_CHECK;

							mapUpdateLoadingDetail.put("status", status);
							mapUpdateShipbillHeader.put("status", status);
							mapUpdateLoadingDetail.put("carrierShipbillStatus", DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_WAIT_RECEIVE);
							mapUpdateShipbillHeader.put("carrierShipbillStatus", DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_WAIT_RECEIVE);

							shipbillNodeTrackingSaveVO.setStatus(status);
							shipbillNodeTrackingSaveVO.setNodeEvent(DataDictionaryConstant.SHIPBILL_NODE_STATUSNAME_TY);
							shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.SHIPBILL_NODE_STATUSNAME_TY);
							shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.SHIPBILL_STATUS_DISPATCH);
							shipbillOperateLogSaveVO.setNewStatus(status);

							// 承运商是否开启接单拒绝
							if (!detailModel.getCarrierFlowConfig().contains(DataDictionaryConstant.FLOW_CONFIG_REJECT_RECEIVE)) {
								receiveObjs.add(detailModel.getShipbillId());
							}
						} else {
							// 判定下一步流程
							int status = businessFlowUtil.judgmentNextFlowSts(detailModel.getFlowConfig(), DataDictionaryConstant.FLOW_CONFIG_CHECK);
							mapUpdateLoadingDetail.put("status", status);
							mapUpdateShipbillHeader.put("status", status);
							mapUpdateLoadingDetail.put("carrierShipbillStatus", DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED_CHECK);
							mapUpdateShipbillHeader.put("carrierShipbillStatus", DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED_CHECK);

							shipbillNodeTrackingSaveVO.setStatus(status);
							shipbillNodeTrackingSaveVO.setNodeEvent(DataDictionaryConstant.SHIPBILL_NODE_STATUSNAME_TY);
							shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.SHIPBILL_NODE_STATUSNAME_TY);
							shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.SHIPBILL_STATUS_DISPATCH);
							shipbillOperateLogSaveVO.setNewStatus(status);
						}
					} else if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
						// 承运商账号
						// 判定下一步流程
						int status = DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED_CHECK;

						mapUpdateLoadingDetail.put("carrierShipbillStatus", status);
						mapUpdateShipbillHeader.put("carrierShipbillStatus", status);
						shipbillNodeTrackingSaveVO.setStatus(status);
						shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
						shipbillOperateLogSaveVO.setNewStatus(status);

						shipbillNodeTrackingSaveVO.setNodeEvent(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_TY);
						shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_TY);
					}

					// 更新运输记录表的调度审核时间
					Criteria criteriaTransLog = Criteria.forClass(TmsShipbillTransLogModel.class);
					Restriction r3 = Restrictions.eq(TmsShipbillTransLogModel::getShipbillId, detailModel.getShipbillId());
					Restriction r4 = Restrictions.eq(TmsShipbillTransLogModel::getEnterpriseId, user.getEnterpriseId());
					criteriaTransLog.setRestriction(Restrictions.and(r3, r4));

					Map<String, Object> mapUpdate = Maps.newHashMap();
					mapUpdate.put("updateperson", user.getNickname());
					mapUpdate.put("updatetime", date);
					mapUpdate.put("disCheckDt", date);
					tmsShipbillTransportLogMapper.updateMapByCriteria(mapUpdate, criteriaTransLog);
				} else {
					if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {

						mapUpdateLoadingDetail.put("status", DataDictionaryConstant.SHIPBILL_STATUS_DISPATCH_CHECK_APPROVAL);
						mapUpdateShipbillHeader.put("status", DataDictionaryConstant.SHIPBILL_STATUS_DISPATCH_CHECK_APPROVAL);
						mapUpdateLoadingDetail.put("carrierShipbillStatus", DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED_APPROVAL);
						mapUpdateShipbillHeader.put("carrierShipbillStatus", DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED_APPROVAL);

						shipbillNodeTrackingSaveVO.setStatus(DataDictionaryConstant.SHIPBILL_STATUS_DISPATCH_CHECK_APPROVAL);
						shipbillNodeTrackingSaveVO.setNodeEvent(DataDictionaryConstant.SHIPBILL_NODE_STATUSNAME_DIS_APPROVAL);
						shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.SHIPBILL_NODE_STATUSNAME_DIS_APPROVAL);
						shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.SHIPBILL_STATUS_DISPATCH);
						shipbillOperateLogSaveVO.setNewStatus(DataDictionaryConstant.SHIPBILL_STATUS_DISPATCH_CHECK_APPROVAL);
					} else if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
						// 承运商账号
						int status = DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED_APPROVAL;
						mapUpdateLoadingDetail.put("carrierShipbillStatus", status);
						mapUpdateShipbillHeader.put("carrierShipbillStatus", status);

						shipbillNodeTrackingSaveVO.setStatus(status);
						shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
						shipbillOperateLogSaveVO.setNewStatus(status);

						shipbillNodeTrackingSaveVO.setNodeEvent(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_DIS_APPROVAL);
						shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_DIS_APPROVAL);
					}
				}
				// 调度司机
				if (DataDictionaryConstant.LINE_CARRIER_TYPE_SJ.equals(detailModel.getCarrierType())) {
					mapUpdateShipbillHeader.put("vehicleTypeCategory", tmsLoadingBillHeaderModel.getVehicleTypeCategory());
					mapUpdateLoadingDetail.put("vehicleTypeCategory", tmsLoadingBillHeaderModel.getVehicleTypeCategory());
					// 冷藏冷冻恒温的运单
					if (!DataDictionaryConstant.TEMPERATURE_REQUIREMENT_CW.equals(detailModel.getTemperatureRequirement())) {
						mapUpdateShipbillHeader.put("vehicleDeviceId", tmsLoadingBillHeaderModel.getVehicleDeviceId());
						mapUpdateShipbillHeader.put("vehicleDeviceCode", tmsLoadingBillHeaderModel.getVehicleDeviceCode());
						mapUpdateShipbillHeader.put("vehicleDeviceName", tmsLoadingBillHeaderModel.getVehicleDeviceName());
						mapUpdateLoadingDetail.put("vehicleDeviceId", tmsLoadingBillHeaderModel.getVehicleDeviceId());
						mapUpdateLoadingDetail.put("vehicleDeviceCode", tmsLoadingBillHeaderModel.getVehicleDeviceCode());
						mapUpdateLoadingDetail.put("vehicleDeviceName", tmsLoadingBillHeaderModel.getVehicleDeviceName());
					}
				}
				//更新运单计划发货件数
				Criteria shipBillCriteria = Criteria.forClass(TmsShipbillDetailModel.class);
				Restriction shipBillRestriction = Restrictions.eq("shipbillId", detailModel.getShipbillId());
				shipBillCriteria.setRestriction(shipBillRestriction);
				List<TmsShipbillDetailModel> tmsShipbillDetailModelList = tmsShipbillDetailMapper.findByCriteria(shipBillCriteria);
				if (CollectionUtil.isNotEmpty(tmsShipbillDetailModelList)) {
					tmsShipbillDetailModelList.forEach(tmsShipbillDetailModel -> {
						tmsShipbillDetailModel.setPlanDeliveryPcs(tmsShipbillDetailModel.getPcs());
						tmsShipbillDetailModel.setUpdateperson(user.getNickname());
						tmsShipbillDetailModel.setUpdatetime(date);
						tmsShipbillDetailMapper.update(tmsShipbillDetailModel);
					});
				}
				// 更改运单状态
				tmsShipbillHeaderMapper.updateMapById(detailModel.getShipbillId(), mapUpdateShipbillHeader, TmsShipbillHeaderModel.class);
				// 更新托运单明细状态
				tmsLoadingBillDetailMapper.updateMapById(detailModel.getId(), mapUpdateLoadingDetail, TmsLoadingBillDetailModel.class);
				// 新增节点信息
				shipbillNodeTrackingSaveVO.setShipbillId(detailModel.getShipbillId());
				shipbillNodeTrackingSaveVO.setShipbillNo(detailModel.getShipbillNo());
				shipbillNodeTrackingService.addShipbillNodeTrackingData(shipbillNodeTrackingSaveVO);

				// 新增日志信息
				shipbillOperateLogSaveVO.setShipbillId(detailModel.getShipbillId());
				shipbillOperateLogSaveVO.setShipbillNo(detailModel.getShipbillNo());
				shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.SHIPBILL_NODE_STATUSNAME_PC);
				shipbillOperateLogService.addShipbillOperateLogData(shipbillOperateLogSaveVO);
			}

			// 更改托运单状态
			// 装车单类型
			if (shipperTypeCnt == tmsLoadingBillDetailModels.size()) {
				tmsLoadingBillHeaderModel.setLoadingBillType(DataDictionaryConstant.LOADING_BILL_TYPE_CK);
			} else if (consigneeType == tmsLoadingBillDetailModels.size()) {
				tmsLoadingBillHeaderModel.setLoadingBillType(DataDictionaryConstant.LOADING_BILL_TYPE_RK);
			} else {
				tmsLoadingBillHeaderModel.setLoadingBillType(DataDictionaryConstant.LOADING_BILL_TYPE_QT);
			}
			tmsLoadingBillHeaderModel.setUpdateperson(user.getNickname());
			tmsLoadingBillHeaderModel.setUpdatetime(date);
			tmsLoadingBillHeaderMapper.update(tmsLoadingBillHeaderModel);
			MessageTypeEnum messageTypeEnum = MessageTypeEnum.SELF_DISPATCH_AUDIT;
			if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
				messageTypeEnum = MessageTypeEnum.CARRIER_DISPATCH_AUDIT;
			}
			MessageUtil.addMessage(new SendMessageDTO(MessageOrderTypeEnum.LOADING_NO.getCode(), messageTypeEnum.getCode(), Lists.newArrayList(tmsLoadingBillHeaderModel.getLoadingBillId())));
		}
		loadingBillService.updateStationByLoadingBillIdList(ids);
		// 承运商自动接单
		if (ToolKits.isNotEmpty(receiveObjs)) {
			autoReceiveShipbillData(receiveObjs, date);
		}
	}

	/**
	 * 已托运运单撤销
	 *
	 * @param ids
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void trailerUndoData(List<String> ids) {
		ToolKits.isParamNull(ids, "托运单ID不为空");

		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");

		List<TmsLoadingBillHeaderModel> tmsLoadingBillHeaderModels = tmsLoadingBillHeaderMapper.findByIds(TmsLoadingBillHeaderModel.class, ids.toArray(), null);

		String str = tmsLoadingBillHeaderModels.stream().filter(o -> o.getStatus().intValue() > DataDictionaryConstant.LOADING_BILL_STATUS_WSH.intValue()).map(TmsLoadingBillHeaderModel::getLoadingBillNo).collect(Collectors.joining(","));
		if (ToolKits.isNotEmpty(str)) {
			throw new RuntimeException("托运单[" + str + "]已审核,不能撤销!");
		}

		// 查询明细内容
		Criteria criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
		Restriction r1 = Restrictions.in("loadingBillId", ids.toArray());
		Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
		criteria.setRestriction(Restrictions.and(r1, r2));

		List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModels = tmsLoadingBillDetailMapper.findByCriteria(criteria);

		for (TmsLoadingBillDetailModel tmsLoadingBillDetailModel : tmsLoadingBillDetailModels) {

			TmsShipbillHeaderModel tmsShipbillHeaderModel = tmsShipbillHeaderMapper.findById(tmsLoadingBillDetailModel.getShipbillId(), TmsShipbillHeaderModel.class);

			ShipbillOperateLogSaveVO shipbillOperateLogSaveVO = new ShipbillOperateLogSaveVO();
			// 运单状态回退
			Restriction r4 = null;
			if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
				Assert.isTrue(tmsShipbillHeaderModel.getStatus().intValue() <= DataDictionaryConstant.SHIPBILL_STATUS_DISPATCH.intValue(), "当前运单已调度不可回退");

				tmsShipbillHeaderModel.setStatus(DataDictionaryConstant.SHIPBILL_STATUS_REVIEW);

				shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.SHIPBILL_STATUSNAME_REVOKE_TRAILER);
				shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.SHIPBILL_STATUS_DISPATCH);
				shipbillOperateLogSaveVO.setNewStatus(DataDictionaryConstant.SHIPBILL_STATUS_REVIEW);
				r4 = Restrictions.eq("status", DataDictionaryConstant.SHIPBILL_STATUS_DISPATCH);
			} else if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
				Assert.isTrue(tmsShipbillHeaderModel.getCarrierShipbillStatus().intValue() <= DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED.intValue(), "当前运单已调度不可回退");

				tmsShipbillHeaderModel.setCarrierShipbillStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_AUDITED);

				shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.CARRIER_SHIPBILL_STATUSNAME_REVOKE_TRAILER);
				shipbillOperateLogSaveVO.setOldCarrierShipbillStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
				shipbillOperateLogSaveVO.setNewCarrierShipbillStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_AUDITED);
				r4 = Restrictions.eq("status", DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
			}
			tmsShipbillHeaderModel.setCarrierId(null);
			tmsShipbillHeaderModel.setCarrierCode(null);
			tmsShipbillHeaderModel.setCarrierName(null);
			tmsShipbillHeaderModel.setCarrierType(null);
			tmsShipbillHeaderModel.setCarrierFlowConfig(null);
			tmsShipbillHeaderModel.setUpdatetime(DateUtil.date());
			tmsShipbillHeaderModel.setUpdateperson(user.getNickname());
			tmsShipbillHeaderMapper.update(tmsShipbillHeaderModel);

			// 运单操作日志保存
			shipbillOperateLogSaveVO.setShipbillId(tmsLoadingBillDetailModel.getShipbillId());
			shipbillOperateLogSaveVO.setShipbillNo(tmsLoadingBillDetailModel.getShipbillNo());
			shipbillOperateLogService.addShipbillOperateLogData(shipbillOperateLogSaveVO);

			// 删除调度的节点信息
			Criteria criteriaNode = Criteria.forClass(ShipbillNodeTracking.class);
			Restriction r3 = Restrictions.eq("shipbillId", tmsLoadingBillDetailModel.getShipbillId());
			Restriction r5 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
			criteria.setRestriction(Restrictions.and(r3, r4, r5));
			tmsShipbillNodeTrackingMapper.deleteByCriteria(criteriaNode);
		}

		// 删除明细内容
		criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
		r1 = Restrictions.in("loadingBillId", ids.toArray());
		r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
		criteria.setRestriction(Restrictions.and(r1, r2));
		tmsLoadingBillDetailMapper.deleteByCriteria(criteria);

		tmsLoadingBillHeaderMapper.deleteByIds(ids.toArray(), TmsLoadingBillHeaderModel.class);
	}

	/**
	 * 自动运单接单
	 *
	 * @param ids
	 * @throws Exception
	 */
	public void autoReceiveShipbillData(List<String> ids, Date date) {
		ToolKits.isParamNull(ids, "运单接单请求不为空");
		Assert.isTrue(ids.size() > 0, "运单接单请求不为空");

		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");
		// 当前时间
		List<String> commitObjs = Lists.newArrayList();
		for (String id : ids) {
			ToolKits.isParamNull(id, "运单ID不为空");
			// 更新
			TmsShipbillHeaderModel tmsShipbillHeaderModel = tmsShipbillHeaderMapper.findById(id, TmsShipbillHeaderModel.class);
			Assert.isTrue(tmsShipbillHeaderModel.getCarrierShipbillStatus() != DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_RECEIVED, "运单【" + id + "】已接单!");

			// 运单状态更新
			tmsShipbillHeaderModel.setCarrierShipbillStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_RECEIVED);
			tmsShipbillHeaderModel.setUpdateperson(user.getNickname());
			tmsShipbillHeaderModel.setUpdatetime(date);
			tmsShipbillHeaderMapper.update(tmsShipbillHeaderModel);

			// 承运商运单操作日志保存
			ShipbillOperateLogSaveVO shipbillOperateLogSaveVO = new ShipbillOperateLogSaveVO();
			shipbillOperateLogSaveVO.setShipbillId(id);
			shipbillOperateLogSaveVO.setShipbillNo(id);
			shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_RECEIVED);
			shipbillOperateLogSaveVO.setOldStatus(tmsShipbillHeaderModel.getCarrierShipbillStatus());
			shipbillOperateLogSaveVO.setNewStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_RECEIVED);
			shipbillOperateLogService.addShipbillOperateLogData(shipbillOperateLogSaveVO);

			if (tmsShipbillHeaderModel.getCarrierFlowConfig().contains(DataDictionaryConstant.FLOW_CONFIG_RECEIVE_COMMIT)) {
				commitObjs.add(id);
			}
			MessageUtil.addMessage(new SendMessageDTO(MessageOrderTypeEnum.SHIP_NO.getCode(), MessageTypeEnum.CARRIER_RECEIVE.getCode(), Lists.newArrayList(id)));
		}
		if (ToolKits.isNotEmpty(commitObjs)) {
			try {
				// 调用提交处理
				submitShipbillData(commitObjs, date);
			} catch (Exception e) {
				throw new PrologException("运单保存自动提交处理失败", e);
			}
		}
	}

	/**
	 * 提交处理
	 *
	 * @param ids
	 * @throws Exception
	 */
	public void submitShipbillData(List<String> ids, Date date) throws Exception {
		ToolKits.isParamNull(ids, "运单批量提交请求不为空");

		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");

		List<String> reviewObjs = Lists.newArrayList();
		for (String id : ids) {
			ToolKits.isParamNull(id, "运单ID不为空");

			// 更新
			TmsShipbillHeaderModel tmsShipbillHeaderModel = tmsShipbillHeaderMapper.findById(id, TmsShipbillHeaderModel.class);

			Assert.isTrue(tmsShipbillHeaderModel.getCarrierShipbillStatus() != DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_COMMIT, "运单【" + tmsShipbillHeaderModel.getShipbillNo() + "】已提交");

			tmsShipbillHeaderModel.setCarrierShipbillStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_COMMIT);

			tmsShipbillHeaderModel.setUpdateperson(user.getNickname());
			tmsShipbillHeaderModel.setUpdatetime(date);
			// 运单汇总表更新
			tmsShipbillHeaderMapper.update(tmsShipbillHeaderModel);

			// 节点保存
			ShipbillNodeTrackingSaveVO shipbillNodeTrackingSaveVO = new ShipbillNodeTrackingSaveVO();
			shipbillNodeTrackingSaveVO.setShipbillId(tmsShipbillHeaderModel.getShipbillId());
			shipbillNodeTrackingSaveVO.setShipbillNo(tmsShipbillHeaderModel.getShipbillNo());
			shipbillNodeTrackingSaveVO.setStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_COMMIT);
			shipbillNodeTrackingSaveVO.setNodeDate(date);
			shipbillNodeTrackingSaveVO.setNodeEvent(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_TJ);
			shipbillNodeTrackingService.addShipbillNodeTrackingData(shipbillNodeTrackingSaveVO);

			// 日志保存
			ShipbillOperateLogSaveVO shipbillOperateLogSaveVO = new ShipbillOperateLogSaveVO();
			shipbillOperateLogSaveVO.setShipbillId(tmsShipbillHeaderModel.getShipbillId());
			shipbillOperateLogSaveVO.setShipbillNo(tmsShipbillHeaderModel.getShipbillNo());
			shipbillOperateLogSaveVO.setOperateDate(date);
			shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.CARRIER_SHIPBILL_STATUSNAME_YTJ);
			shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_RECEIVED);
			shipbillOperateLogSaveVO.setNewStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_COMMIT);
			shipbillOperateLogService.addShipbillOperateLogData(shipbillOperateLogSaveVO);

			// 判定提交后是否自动审核
			if (tmsShipbillHeaderModel.getCarrierFlowConfig().contains(DataDictionaryConstant.FLOW_CONFIG_COMMIT_REVIEW)) {
				reviewObjs.add(id);
			}

			// 更新运输记录表的审核时间
			Criteria criteriaTransLog = Criteria.forClass(TmsShipbillTransLogModel.class);
			Restriction r1 = Restrictions.eq(TmsShipbillTransLogModel::getShipbillId, tmsShipbillHeaderModel.getShipbillId());
			Restriction r2 = Restrictions.eq(TmsShipbillTransLogModel::getEnterpriseId, user.getEnterpriseId());
			criteriaTransLog.setRestriction(Restrictions.and(r1, r2));

			Map<String, Object> mapUpdate = Maps.newHashMap();
			mapUpdate.put("updateperson", user.getNickname());
			mapUpdate.put("updatetime", date);
			mapUpdate.put("commitDt", date);
			tmsShipbillTransportLogMapper.updateMapByCriteria(mapUpdate, criteriaTransLog);
			MessageUtil.addMessage(new SendMessageDTO(MessageOrderTypeEnum.SHIP_NO.getCode(), MessageTypeEnum.CARRIER_SUBMIT.getCode(), Lists.newArrayList(id)));
		}
		// 提交后，调用自动审核处理
		if (ToolKits.isNotEmpty(reviewObjs)) {
			reviewShipbillData(reviewObjs, date);
		}
	}

	/**
	 * 自动审核处理
	 *
	 * @param shipbillIds
	 * @throws Exception
	 */
	public void reviewShipbillData(List<String> shipbillIds, Date date) {
		ToolKits.isParamNull(shipbillIds, "运单审核请求不为空");

		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");

		for (String id : shipbillIds) {
			ToolKits.isParamNull(id, "运单ID不为空");
			// 更新
			TmsShipbillHeaderModel tmsShipbillHeaderModel = tmsShipbillHeaderMapper.findById(id, TmsShipbillHeaderModel.class);
			ShipbillNodeTrackingSaveVO shipbillNodeTrackingSaveVO = new ShipbillNodeTrackingSaveVO();
			ShipbillOperateLogSaveVO shipbillOperateLogSaveVO = new ShipbillOperateLogSaveVO();
			if (!DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_COMMIT.equals(tmsShipbillHeaderModel.getCarrierShipbillStatus())) {
				throw new PrologException("运单【" + tmsShipbillHeaderModel.getShipbillNo() + "】非待审核状态,审核失败");
			}
			tmsShipbillHeaderModel.setCarrierShipbillStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_AUDITED);
			shipbillNodeTrackingSaveVO.setNodeEvent(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_RE);
			shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_RE);

			// 运单审核
			tmsShipbillHeaderModel.setUpdateperson(user.getNickname());
			tmsShipbillHeaderModel.setUpdatetime(date);
			tmsShipbillHeaderMapper.update(tmsShipbillHeaderModel);

			// 运单节点保存
			shipbillNodeTrackingSaveVO.setNodeDate(date);
			shipbillNodeTrackingSaveVO.setShipbillId(tmsShipbillHeaderModel.getShipbillId());
			shipbillNodeTrackingSaveVO.setShipbillNo(tmsShipbillHeaderModel.getShipbillNo());
			shipbillNodeTrackingSaveVO.setStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_AUDITED);
			shipbillNodeTrackingService.addShipbillNodeTrackingData(shipbillNodeTrackingSaveVO);

			// 运单日志保存
			shipbillOperateLogSaveVO.setOperateDate(date);
			shipbillOperateLogSaveVO.setShipbillId(tmsShipbillHeaderModel.getShipbillId());
			shipbillOperateLogSaveVO.setShipbillNo(tmsShipbillHeaderModel.getShipbillNo());
			shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.SHIPBILL_STATUS_YTJ);
			shipbillOperateLogSaveVO.setNewStatus(DataDictionaryConstant.SHIPBILL_STATUS_REVIEW);
			shipbillOperateLogService.addShipbillOperateLogData(shipbillOperateLogSaveVO);

			// 更新运输记录表的审核时间
			Criteria criteriaTransLog = Criteria.forClass(TmsShipbillTransLogModel.class);
			Restriction r1 = Restrictions.eq(TmsShipbillTransLogModel::getShipbillId, tmsShipbillHeaderModel.getShipbillId());
			Restriction r2 = Restrictions.eq(TmsShipbillTransLogModel::getEnterpriseId, user.getEnterpriseId());
			criteriaTransLog.setRestriction(Restrictions.and(r1, r2));

			Map<String, Object> mapUpdate = Maps.newHashMap();
			mapUpdate.put("updateperson", user.getNickname());
			mapUpdate.put("updatetime", date);
			mapUpdate.put("reviewDt", date);
			tmsShipbillTransportLogMapper.updateMapByCriteria(mapUpdate, criteriaTransLog);

			// 运单匹配唯一承运方是否自动调度
			TmsShipbillHeaderModel shipbillHeaderModel = tmsShipbillHeaderMapper.findById(id, TmsShipbillHeaderModel.class);
			boolean autoDispatch = false;
			if (shipbillHeaderModel.getCarrierFlowConfig().contains(DataDictionaryConstant.FLOW_CONFIG_REVIEW_DISPATCH)) {
				autoDispatch = true;
			}
			if (autoDispatch) {
				// 收货方类型是客户时，自动调度
				if (!DataDictionaryConstant.CONSIGNEE_TYPE_KH.equals(shipbillHeaderModel.getConsigneeType())) {
					return;
				}
				CustomerCarrierVO carrierVO = new CustomerCarrierVO();
				carrierVO.setConsigneeId(shipbillHeaderModel.getConsigneeId());
				RestMessage<CustomerCarrierDTO> restRs = maindataTmsResource.customerCarrierExecute(carrierVO);
				if (!restRs.isSuccess()) {
					throw new PrologException("调用maindata服务,客户收货方匹配唯一承运方失败");
				}
				CustomerCarrierDTO carrierDTO = restRs.getData();
				PendingDispatchVO pendingDispatchVO = new PendingDispatchVO();

				if (ToolKits.isNotEmpty(carrierDTO) && ToolKits.isNotEmpty(carrierDTO.getCarrierId())) {
					// 唯一匹配承运方
					// 承运方类型
					pendingDispatchVO.setCarrierType(carrierDTO.getCarrierType());
					if (DataDictionaryConstant.LINE_CARRIER_TYPE_SJ.equals(carrierDTO.getCarrierType())) {
						// 司机ID
						pendingDispatchVO.setDriverId(String.valueOf(carrierDTO.getCarrierId()));
						pendingDispatchVO.setDriverCode(carrierDTO.getCarrierCode());
						pendingDispatchVO.setDriverName(carrierDTO.getCarrierName());
					} else {
						// 承运商ID
						pendingDispatchVO.setCarrierId(carrierDTO.getCarrierId());
						pendingDispatchVO.setCarrierCode(carrierDTO.getCarrierCode());
						pendingDispatchVO.setCarrierName(carrierDTO.getCarrierName());
					}
					// 司机手机号
					pendingDispatchVO.setDriverPhoneNumber(carrierDTO.getCarrierPhoneNumber());
					// 车牌号
					pendingDispatchVO.setVehiclePlateNumber(carrierDTO.getVehiclePlateNumber());

					pendingDispatchVO.setVehicleId(carrierDTO.getVehicleId());
					pendingDispatchVO.setVehicleCode(carrierDTO.getVehicleCode());
					pendingDispatchVO.setVehicleName(carrierDTO.getVehicleName());
					List<String> ids = Lists.newArrayList();
					ids.add(tmsShipbillHeaderModel.getShipbillId());
					pendingDispatchVO.setShipbillIds(ids);
					// 自动调度
					autoDispatch(pendingDispatchVO, date);
				}
			}
			MessageUtil.addMessage(new SendMessageDTO(MessageOrderTypeEnum.SHIP_NO.getCode(), MessageTypeEnum.CARRIER_AUDIT.getCode(), Lists.newArrayList(id)));
		}
	}

	/**
	 * 调度
	 *
	 * @param dispatchVO
	 * @return
	 */
	public void autoDispatch(PendingDispatchVO dispatchVO, Date date) {
		ToolKits.isParamNull(dispatchVO, "运单调度请求不为空");
		ToolKits.isParamNull(dispatchVO.getCarrierType(), "承运方类型不为空");

		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");

		// 装车单明细
		List<String> shipbillIds = dispatchVO.getShipbillIds();

		// 装车单汇总保存
		// 获取装车单ID
		RestMessage<String> restMessage1 = maindataTmsResource.getCodeNumberByCode(SeriaNnumberConstant.TMS_LOADING_BILL_HEADER_ID, "L");
		if (!restMessage1.isSuccess()) {
			throw new RuntimeException("生成装车单ID失败");
		}

		String loadingBillId = restMessage1.getData();
		TmsLoadingBillHeaderModel loadingBillHeaderModel = new TmsLoadingBillHeaderModel();
		BeanUtils.copyProperties(dispatchVO, loadingBillHeaderModel);

		if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
			loadingBillHeaderModel.setScheduleType(DataDictionaryConstant.SCHEDULE_TYPE_ZY);
		} else {
			loadingBillHeaderModel.setScheduleType(DataDictionaryConstant.SCHEDULE_TYPE_CYS);
		}

		loadingBillHeaderModel.setLoadingBillId(loadingBillId);
		loadingBillHeaderModel.setLoadingBillNo(loadingBillId);
		loadingBillHeaderModel.setStatus(DataDictionaryConstant.LOADING_BILL_STATUS_WSH);
		loadingBillHeaderModel.setEnterpriseId(user.getEnterpriseId());
		loadingBillHeaderModel.setEnterpriseName(user.getEnterpriseName());
		loadingBillHeaderModel.setCreateperson(user.getNickname());
		loadingBillHeaderModel.setCreatetime(date);
		loadingBillHeaderModel.setUpdateperson(user.getNickname());
		loadingBillHeaderModel.setUpdatetime(date);

		loadingBillHeaderModel.setLoadingBillDate(date);
		// 解析司机名称
		String driverName = this.getFirstStr(dispatchVO.getDriverName());
		// 解析送货员
		String deliverymanName = this.getFirstStr(dispatchVO.getDeliverymanName());
		if (DataDictionaryConstant.LINE_CARRIER_TYPE_SJ.equals(dispatchVO.getCarrierType())) {
			// 解析司机ID
			String driverId = this.getFirstStr(dispatchVO.getDriverId());
			// 解析司机编号
			String driverCode = this.getFirstStr(dispatchVO.getDriverCode());
			// 解析司机手机号
			String phoneNumber = this.getFirstStr(dispatchVO.getDriverPhoneNumber());
			// 司机信息
			loadingBillHeaderModel.setDriverId(driverId == null ? null : Long.valueOf(driverId));
			loadingBillHeaderModel.setDriverCode(driverCode == null ? null : driverCode);
			loadingBillHeaderModel.setDriverName(driverName == null ? null : driverName);
			loadingBillHeaderModel.setDriverPhoneNumber(phoneNumber == null ? null : phoneNumber);
			// 副司机信息
			String viceDriverId = this.subArrToString(String.valueOf(dispatchVO.getDriverId()));
			loadingBillHeaderModel.setViceDriverId(viceDriverId == null ? null : viceDriverId);
			String viceDriverCode = this.subArrToString(dispatchVO.getDriverCode());
			loadingBillHeaderModel.setViceDriverCode(viceDriverCode == null ? null : viceDriverCode);
			String viceDriverName = this.subArrToString(dispatchVO.getDriverName());
			loadingBillHeaderModel.setViceDriverName(viceDriverName == null ? null : viceDriverName);
			String vicephoneNumber = this.subArrToString(dispatchVO.getDriverPhoneNumber());
			loadingBillHeaderModel.setViceDriverPhoneNumber(vicephoneNumber == null ? null : vicephoneNumber);
			// 送货员信息
			// 解析送货员ID
			String deliverymanId = this.getFirstStr(dispatchVO.getDeliverymanId());
			// 解析送货员编号
			String deliverymanCode = this.getFirstStr(dispatchVO.getDeliverymanCode());
			// 解析送货员手机号
			String deliverymanPhoneNumber = this.getFirstStr(dispatchVO.getDeliverymanPhoneNumber());
			loadingBillHeaderModel.setDeliverymanId(deliverymanId == null ? null : Long.valueOf(deliverymanId));
			loadingBillHeaderModel.setDeliverymanCode(deliverymanCode == null ? null : deliverymanCode);
			loadingBillHeaderModel.setDeliverymanName(deliverymanName == null ? null : deliverymanName);
			loadingBillHeaderModel.setDeliverymanPhoneNumber(deliverymanPhoneNumber == null ? null : deliverymanPhoneNumber);
			// 副送货员信息
			String viceDeliverymanId = this.subArrToString(dispatchVO.getDeliverymanId());
			loadingBillHeaderModel.setViceDriverId(viceDeliverymanId == null ? null : viceDeliverymanId);
			String viceDeliverymanCode = this.subArrToString(dispatchVO.getDeliverymanCode());
			loadingBillHeaderModel.setViceDriverCode(viceDeliverymanCode == null ? null : viceDeliverymanCode);
			String viceDeliverymanName = this.subArrToString(dispatchVO.getDeliverymanName());
			loadingBillHeaderModel.setViceDeliverymanName(viceDeliverymanName == null ? null : viceDeliverymanName);
			String viceDeliverymanphoneNumber = this.subArrToString(dispatchVO.getDeliverymanPhoneNumber());
			loadingBillHeaderModel.setViceDeliverymanPhoneNumber(viceDeliverymanphoneNumber == null ? null : viceDeliverymanphoneNumber);
		}

		BigDecimal totalWholePiece = BigDecimal.valueOf(0);
		BigDecimal totalLclPiece= BigDecimal.valueOf(0);
		BigDecimal totalPcs = BigDecimal.valueOf(0);
		BigDecimal totalVolume = BigDecimal.valueOf(0);
		BigDecimal totalWeight = BigDecimal.valueOf(0);
		boolean autoDispatchCheck = false;
		List<TmsShipbillHeaderModel> shipbillHeaderModels = tmsShipbillHeaderMapper.findByIds(TmsShipbillHeaderModel.class, shipbillIds.stream().toArray(String[]::new), null);
		if (ToolKits.isEmpty(shipbillHeaderModels)) {
			throw new PrologException("运单信息不存在，调度失败");
		}
		int order = 1;
		for (TmsShipbillHeaderModel shipbillHeaderModel : shipbillHeaderModels) {
			// 装车单明细保存
			// 获取装车单明细ID
			RestMessage<String> restMessage2 = maindataTmsResource.getCodeNumberByCode(SeriaNnumberConstant.TMS_LOADING_BILL_DETAIL_ID, "L");
			if (!restMessage2.isSuccess()) {
				throw new RuntimeException("生成装车单明细ID失败");
			}
			String loadingBillDetailId = restMessage2.getData();
			TmsLoadingBillDetailModel loadingBillDetailModel = new TmsLoadingBillDetailModel();
			BeanUtils.copyProperties(shipbillHeaderModel, loadingBillDetailModel);

			ShipbillNodeTrackingSaveVO shipbillNodeTrackingSaveVO = new ShipbillNodeTrackingSaveVO();
			ShipbillOperateLogSaveVO shipbillOperateLogSaveVO = new ShipbillOperateLogSaveVO();
			// 节点内容
			StringBuffer nodeEvent = new StringBuffer();
			if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
				// 自有账号
				if (!DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_AUDITED.equals(shipbillHeaderModel.getCarrierShipbillStatus())) {
					throw new PrologException("运单【" + shipbillHeaderModel.getShipbillNo() + "】非待调度状态,调度失败");
				}
				loadingBillDetailModel.setCarrierShipbillStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
				shipbillHeaderModel.setCarrierShipbillStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
				shipbillNodeTrackingSaveVO.setStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
				shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_AUDITED);
				shipbillOperateLogSaveVO.setNewStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
				nodeEvent.append(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_DI);
				// 判定是否调度后审核
				if (!autoDispatchCheck && shipbillHeaderModel.getCarrierFlowConfig().contains(DataDictionaryConstant.FLOW_CONFIG_DISPATCH_CHECK)) {
					autoDispatchCheck = true;
				}
			} else if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
				// 承运商账号
				if (!DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_AUDITED.equals(shipbillHeaderModel.getCarrierShipbillStatus())) {
					throw new PrologException("运单【" + shipbillHeaderModel.getShipbillNo() + "】非待调度状态,调度失败");
				}
				loadingBillDetailModel.setCarrierShipbillStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
				shipbillHeaderModel.setCarrierShipbillStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
				shipbillNodeTrackingSaveVO.setStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
				shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_AUDITED);
				shipbillOperateLogSaveVO.setNewStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
				nodeEvent.append(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_DI);
				// 判定是否调度后审核
				if (!autoDispatchCheck && shipbillHeaderModel.getCarrierFlowConfig().contains(DataDictionaryConstant.FLOW_CONFIG_DISPATCH_CHECK)) {
					autoDispatchCheck = true;
				}
			}

			loadingBillDetailModel.setId(loadingBillDetailId);
			loadingBillDetailModel.setLoadingBillId(loadingBillId);
			loadingBillDetailModel.setLoadingBillNo(loadingBillId);
			loadingBillDetailModel.setEnterpriseId(user.getEnterpriseId());
			loadingBillDetailModel.setEnterpriseName(user.getEnterpriseName());
			loadingBillDetailModel.setCreateperson(user.getNickname());
			loadingBillDetailModel.setCreatetime(date);
			loadingBillDetailModel.setUpdateperson(user.getNickname());
			loadingBillDetailModel.setUpdatetime(date);
			loadingBillDetailModel.setCarrierType(dispatchVO.getCarrierType());

			loadingBillDetailModel.setSource(shipbillHeaderModel.getSource());
			nodeEvent.append(" ");
			if (DataDictionaryConstant.LINE_CARRIER_TYPE_CYF.equals(dispatchVO.getCarrierType())) {
				// 承运商
				nodeEvent.append(ToolKits.isEmpty(dispatchVO.getCarrierName()) ? null : dispatchVO.getCarrierName());
				ShipbillFitBusinessFlowDTO flowData = shipbillMatchBusinessFlow(shipbillHeaderModel);
				shipbillHeaderModel.setCarrierFlowConfig(flowData.getFlowConfig());

				loadingBillDetailModel.setCarrierId(dispatchVO.getCarrierId());
				loadingBillDetailModel.setCarrierCode(dispatchVO.getCarrierCode());
				loadingBillDetailModel.setCarrierName(dispatchVO.getCarrierName());

				shipbillHeaderModel.setCarrierId(dispatchVO.getCarrierId());
				shipbillHeaderModel.setCarrierCode(dispatchVO.getCarrierCode());
				shipbillHeaderModel.setCarrierName(dispatchVO.getCarrierName());

			} else if (DataDictionaryConstant.LINE_CARRIER_TYPE_SJ.equals(dispatchVO.getCarrierType())) {
				// 司机
				nodeEvent.append(ToolKits.isEmpty(driverName) ? "" : driverName);
				nodeEvent.append(" ");
				// 送货员名称
				nodeEvent.append(ToolKits.isEmpty(deliverymanName) ? "" : deliverymanName);
				nodeEvent.append(" ");
				// 车牌号
				nodeEvent.append(ToolKits.isEmpty(dispatchVO.getVehiclePlateNumber()) ? "" : dispatchVO.getVehiclePlateNumber());
			}
			// 保存调度单明细
			loadingBillDetailModel.setFlowConfig(shipbillHeaderModel.getFlowConfig());
			loadingBillDetailModel.setCarrierFlowConfig(shipbillHeaderModel.getCarrierFlowConfig());
			loadingBillDetailModel.setShippingOrder(order);
			order++;
			tmsLoadingBillDetailMapper.save(loadingBillDetailModel);
			// 运单调度
			shipbillHeaderModel.setUpdateperson(user.getNickname());
			shipbillHeaderModel.setUpdatetime(date);

			shipbillHeaderModel.setCarrierType(dispatchVO.getCarrierType());
			tmsShipbillHeaderMapper.update(shipbillHeaderModel);
			// 运单节点保存
			shipbillNodeTrackingSaveVO.setShipbillId(shipbillHeaderModel.getShipbillId());
			shipbillNodeTrackingSaveVO.setShipbillNo(shipbillHeaderModel.getShipbillNo());
			shipbillNodeTrackingSaveVO.setNodeEvent(nodeEvent.toString());
			shipbillNodeTrackingService.addShipbillNodeTrackingData(shipbillNodeTrackingSaveVO);

			// 运单日志保存
			shipbillOperateLogSaveVO.setShipbillId(shipbillHeaderModel.getShipbillId());
			shipbillOperateLogSaveVO.setShipbillNo(shipbillHeaderModel.getShipbillNo());
			shipbillOperateLogSaveVO.setOperateEvent(nodeEvent.toString());
			shipbillOperateLogService.addShipbillOperateLogData(shipbillOperateLogSaveVO);

			// 更新运输记录表的调度时间
			Criteria criteriaTransLog = Criteria.forClass(TmsShipbillTransLogModel.class);
			Restriction r1 = Restrictions.eq(TmsShipbillTransLogModel::getShipbillId, shipbillHeaderModel.getShipbillId());
			Restriction r2 = Restrictions.eq(TmsShipbillTransLogModel::getEnterpriseId, user.getEnterpriseId());
			criteriaTransLog.setRestriction(Restrictions.and(r1, r2));

			Map<String, Object> mapUpdate = Maps.newHashMap();
			mapUpdate.put("updateperson", user.getNickname());
			mapUpdate.put("updatetime", date);
			mapUpdate.put("disDt", date);
			mapUpdate.put("loadingBillDetailId", loadingBillDetailId);
			tmsShipbillTransportLogMapper.updateMapByCriteria(mapUpdate, criteriaTransLog);

			totalWholePiece = NumberUtil.add(totalWholePiece,shipbillHeaderModel.getPackageWholePiece());
			totalLclPiece = NumberUtil.add(totalLclPiece, shipbillHeaderModel.getPackageLclPiece());
			totalPcs = NumberUtil.add(totalPcs,shipbillHeaderModel.getTotalPcs());
			totalWeight = NumberUtil.add(totalWeight,shipbillHeaderModel.getTotalWeight());
			totalVolume = NumberUtil.add(totalVolume,shipbillHeaderModel.getTotalVolume());
		}
		// 运单数
		loadingBillHeaderModel.setShipbillNumber(shipbillHeaderModels.size());
		// 客户数
		int customerCnt = shipbillHeaderModels.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(TmsShipbillHeaderModel::getConsigneeUnitId))), ArrayList::new)).size();
		loadingBillHeaderModel.setCustomerNumber(customerCnt);
		// 总站点数
		int siteCnt = shipbillHeaderModels.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(TmsShipbillHeaderModel::getConsigneeId))), ArrayList::new)).size();
		loadingBillHeaderModel.setSiteNumber(siteCnt);
		// 总件数
		loadingBillHeaderModel.setTotalPcs(totalPcs);
		loadingBillHeaderModel.setActualTotalPcs(totalPcs);
		// 总重量
		loadingBillHeaderModel.setTotalWeight(totalWeight);
		loadingBillHeaderModel.setActualTotalWeight(totalWeight);
		// 总体积
		loadingBillHeaderModel.setTotalVolume(totalVolume);
		loadingBillHeaderModel.setActualTotalVolume(totalVolume);
		// 总整件数
		loadingBillHeaderModel.setTotalWholePiece(totalWholePiece);
		// 总拼箱数
		loadingBillHeaderModel.setTotalLclPiece(totalLclPiece);

		loadingBillHeaderModel.setScanStatus(DataDictionaryConstant.SCAN_STATUS_INIT);
		tmsLoadingBillHeaderMapper.save(loadingBillHeaderModel);
		MessageUtil.addMessage(new SendMessageDTO(MessageOrderTypeEnum.SHIP_NO.getCode(), MessageTypeEnum.CARRIER_DISPATCH.getCode(), shipbillIds));
		// 调度后自动审核
		if (autoDispatchCheck) {
			List<String> ids = Lists.newArrayList();
			ids.add(loadingBillId);
			if (DataDictionaryConstant.LINE_CARRIER_TYPE_SJ.equals(dispatchVO.getCarrierType())) {
				// 调用派车单审核
				autoSendcarAuditData(ids, date);
			} else {
				// 调用托运单审核
				autoTrailerAuditData(ids, date);
			}
		}
	}

	/**
	 * 已派车审核
	 *
	 * @param ids
	 */
	public void autoSendcarAuditData(List<String> ids, Date date) {
		ToolKits.isParamNull(ids, "派车单ID不为空");

		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");

		List<TmsLoadingBillHeaderModel> tmsLoadingBillHeaderModels = tmsLoadingBillHeaderMapper.findByIds(TmsLoadingBillHeaderModel.class, ids.toArray(), null);

		// 判断派车单是否已审核
		String str = tmsLoadingBillHeaderModels.stream().filter(o -> DataDictionaryConstant.LOADING_BILL_STATUS_YSH.equals(o.getStatus())).map(TmsLoadingBillHeaderModel::getLoadingBillNo).collect(Collectors.joining(","));

		if (ToolKits.isNotEmpty(str)) {
			throw new RuntimeException("派车单[" + str + "]已审核!");
		}

		for (TmsLoadingBillHeaderModel tmsLoadingBillHeaderModel : tmsLoadingBillHeaderModels) {

			Criteria criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
			Restriction r1 = Restrictions.eq("loadingBillId", tmsLoadingBillHeaderModel.getLoadingBillId());
			criteria.setRestriction(r1);
			List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModels = tmsLoadingBillDetailMapper.findByCriteria(criteria);

			int shipperTypeCnt = 0;
			int consigneeType = 0;
			for (TmsLoadingBillDetailModel detailModel : tmsLoadingBillDetailModels) {
				if (DataDictionaryConstant.SHIPPER_TYPE_CK.equals(detailModel.getShipperType())) {
					shipperTypeCnt++;
				}
				if (DataDictionaryConstant.CONSIGNEE_TYPE_CK.equals(detailModel.getConsigneeType())) {
					consigneeType++;
				}
				ShipbillNodeTrackingSaveVO shipbillNodeTrackingSaveVO = new ShipbillNodeTrackingSaveVO();
				ShipbillOperateLogSaveVO shipbillOperateLogSaveVO = new ShipbillOperateLogSaveVO();
				Map<String, Object> mapUpdateShipbillHeader = Maps.newHashMap();
				Map<String, Object> mapUpdateLoadingDetail = Maps.newHashMap();

				mapUpdateShipbillHeader.put("updateperson", user.getNickname());
				mapUpdateShipbillHeader.put("updatetime", date);
				mapUpdateLoadingDetail.put("updateperson", user.getNickname());
				mapUpdateLoadingDetail.put("updatetime", date);

				// 承运商账号
				// 判定下一步流程
				int status = businessFlowUtil.judgmentNextFlowSts(detailModel.getCarrierFlowConfig(), DataDictionaryConstant.FLOW_CONFIG_CHECK);

				mapUpdateLoadingDetail.put("carrierShipbillStatus", DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED_CHECK);
				mapUpdateLoadingDetail.put("status", status);

				mapUpdateShipbillHeader.put("carrierShipbillStatus", DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED_CHECK);
				mapUpdateShipbillHeader.put("status", status);

				shipbillNodeTrackingSaveVO.setStatus(status);
				shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
				shipbillOperateLogSaveVO.setNewStatus(status);

				shipbillNodeTrackingSaveVO.setNodeEvent(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_PC);
				shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_PC);

				// 更改运单状态
				tmsShipbillHeaderMapper.updateMapById(detailModel.getShipbillId(), mapUpdateShipbillHeader, TmsShipbillHeaderModel.class);
				// 更新派车单明细状态
				tmsLoadingBillDetailMapper.updateMapById(detailModel.getId(), mapUpdateLoadingDetail, TmsLoadingBillDetailModel.class);
				// 新增节点信息
				shipbillNodeTrackingSaveVO.setShipbillId(detailModel.getShipbillId());
				shipbillNodeTrackingSaveVO.setShipbillNo(detailModel.getShipbillNo());
				shipbillNodeTrackingService.addShipbillNodeTrackingData(shipbillNodeTrackingSaveVO);

				// 新增日志信息
				shipbillOperateLogSaveVO.setShipbillId(detailModel.getShipbillId());
				shipbillOperateLogSaveVO.setShipbillNo(detailModel.getShipbillNo());
				shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.SHIPBILL_NODE_STATUSNAME_PC);
				shipbillOperateLogService.addShipbillOperateLogData(shipbillOperateLogSaveVO);

				// 更新运输记录表的调度审核时间
				Criteria criteriaTransLog = Criteria.forClass(TmsShipbillTransLogModel.class);
				Restriction r3 = Restrictions.eq(TmsShipbillTransLogModel::getShipbillId, detailModel.getShipbillId());
				Restriction r4 = Restrictions.eq(TmsShipbillTransLogModel::getEnterpriseId, user.getEnterpriseId());
				criteriaTransLog.setRestriction(Restrictions.and(r3, r4));

				Map<String, Object> mapUpdate = Maps.newHashMap();
				mapUpdate.put("updateperson", user.getNickname());
				mapUpdate.put("updatetime", date);
				mapUpdate.put("disCheckDt", date);
				tmsShipbillTransportLogMapper.updateMapByCriteria(mapUpdate, criteriaTransLog);

			}
			// 更改派车单状态
			// 装车单类型
			if (shipperTypeCnt == tmsLoadingBillDetailModels.size()) {
				tmsLoadingBillHeaderModel.setLoadingBillType(DataDictionaryConstant.LOADING_BILL_TYPE_CK);
			} else if (consigneeType == tmsLoadingBillDetailModels.size()) {
				tmsLoadingBillHeaderModel.setLoadingBillType(DataDictionaryConstant.LOADING_BILL_TYPE_RK);
			} else {
				tmsLoadingBillHeaderModel.setLoadingBillType(DataDictionaryConstant.LOADING_BILL_TYPE_QT);
			}
			tmsLoadingBillHeaderModel.setUpdateperson(user.getNickname());
			tmsLoadingBillHeaderModel.setUpdatetime(date);
			tmsLoadingBillHeaderModel.setStatus(DataDictionaryConstant.LOADING_BILL_STATUS_YSH);
			tmsLoadingBillHeaderMapper.update(tmsLoadingBillHeaderModel);
			MessageUtil.addMessage(new SendMessageDTO(MessageOrderTypeEnum.LOADING_NO.getCode(), MessageTypeEnum.CARRIER_DISPATCH_AUDIT.getCode(), Lists.newArrayList(tmsLoadingBillHeaderModel.getLoadingBillId())));
		}
	}

	/**
	 * 已托运审核
	 *
	 * @param ids
	 */
	public void autoTrailerAuditData(List<String> ids, Date date) {
		ToolKits.isParamNull(ids, "托运单ID不为空");

		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");

		List<TmsLoadingBillHeaderModel> tmsLoadingBillHeaderModels = tmsLoadingBillHeaderMapper.findByIds(TmsLoadingBillHeaderModel.class, ids.toArray(), null);

		// 判断托运单是否已审核
		String str = tmsLoadingBillHeaderModels.stream().filter(o -> DataDictionaryConstant.LOADING_BILL_STATUS_YSH.equals(o.getStatus())).map(TmsLoadingBillHeaderModel::getLoadingBillNo).collect(Collectors.joining(","));

		if (ToolKits.isNotEmpty(str)) {
			throw new RuntimeException("托运单[" + str + "]已审核!");
		}

		for (TmsLoadingBillHeaderModel tmsLoadingBillHeaderModel : tmsLoadingBillHeaderModels) {

			// 更改运单状态
			Criteria criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
			Restriction r1 = Restrictions.eq("loadingBillId", tmsLoadingBillHeaderModel.getLoadingBillId());
			Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
			criteria.setRestriction(Restrictions.and(r1, r2));
			List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModels = tmsLoadingBillDetailMapper.findByCriteria(criteria);

			// 记录运单日志
			int shipperTypeCnt = 0;
			int consigneeType = 0;
			for (TmsLoadingBillDetailModel detailModel : tmsLoadingBillDetailModels) {
				if (DataDictionaryConstant.SHIPPER_TYPE_CK.equals(detailModel.getShipperType())) {
					shipperTypeCnt++;
				}
				if (DataDictionaryConstant.CONSIGNEE_TYPE_CK.equals(detailModel.getConsigneeType())) {
					consigneeType++;
				}
				ShipbillNodeTrackingSaveVO shipbillNodeTrackingSaveVO = new ShipbillNodeTrackingSaveVO();
				ShipbillOperateLogSaveVO shipbillOperateLogSaveVO = new ShipbillOperateLogSaveVO();
				Map<String, Object> mapUpdateShipbillHeader = Maps.newHashMap();
				Map<String, Object> mapUpdateLoadingDetail = Maps.newHashMap();

				mapUpdateShipbillHeader.put("updateperson", user.getNickname());
				mapUpdateShipbillHeader.put("updatetime", date);
				mapUpdateLoadingDetail.put("updateperson", user.getNickname());
				mapUpdateLoadingDetail.put("updatetime", date);

				int status = DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED_CHECK;

				mapUpdateLoadingDetail.put("carrierShipbillStatus", status);
				mapUpdateShipbillHeader.put("carrierShipbillStatus", status);

				shipbillNodeTrackingSaveVO.setStatus(status);
				shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
				shipbillOperateLogSaveVO.setNewStatus(status);

				shipbillNodeTrackingSaveVO.setNodeEvent(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_TY);
				shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_TY);

				// 更改运单状态
				tmsShipbillHeaderMapper.updateMapById(detailModel.getShipbillId(), mapUpdateShipbillHeader, TmsShipbillHeaderModel.class);
				// 更新托运单明细状态
				tmsLoadingBillDetailMapper.updateMapById(detailModel.getId(), mapUpdateLoadingDetail, TmsLoadingBillDetailModel.class);
				// 新增节点信息
				shipbillNodeTrackingSaveVO.setShipbillId(detailModel.getShipbillId());
				shipbillNodeTrackingSaveVO.setShipbillNo(detailModel.getShipbillNo());
				shipbillNodeTrackingService.addShipbillNodeTrackingData(shipbillNodeTrackingSaveVO);

				// 新增日志信息
				shipbillOperateLogSaveVO.setShipbillId(detailModel.getShipbillId());
				shipbillOperateLogSaveVO.setShipbillNo(detailModel.getShipbillNo());
				shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.SHIPBILL_NODE_STATUSNAME_PC);
				shipbillOperateLogService.addShipbillOperateLogData(shipbillOperateLogSaveVO);

				// 更新运输记录表的调度审核时间
				Criteria criteriaTransLog = Criteria.forClass(TmsShipbillTransLogModel.class);
				Restriction r3 = Restrictions.eq(TmsShipbillTransLogModel::getShipbillId, detailModel.getShipbillId());
				Restriction r4 = Restrictions.eq(TmsShipbillTransLogModel::getEnterpriseId, user.getEnterpriseId());
				criteriaTransLog.setRestriction(Restrictions.and(r3, r4));

				Map<String, Object> mapUpdate = Maps.newHashMap();
				mapUpdate.put("updateperson", user.getNickname());
				mapUpdate.put("updatetime", date);
				mapUpdate.put("disCheckDt", date);
				tmsShipbillTransportLogMapper.updateMapByCriteria(mapUpdate, criteriaTransLog);

			}

			// 更改托运单状态
			// 装车单类型
			if (shipperTypeCnt == tmsLoadingBillDetailModels.size()) {
				tmsLoadingBillHeaderModel.setLoadingBillType(DataDictionaryConstant.LOADING_BILL_TYPE_CK);
			} else if (consigneeType == tmsLoadingBillDetailModels.size()) {
				tmsLoadingBillHeaderModel.setLoadingBillType(DataDictionaryConstant.LOADING_BILL_TYPE_RK);
			} else {
				tmsLoadingBillHeaderModel.setLoadingBillType(DataDictionaryConstant.LOADING_BILL_TYPE_QT);
			}
			tmsLoadingBillHeaderModel.setUpdateperson(user.getNickname());
			tmsLoadingBillHeaderModel.setUpdatetime(date);
			tmsLoadingBillHeaderModel.setStatus(DataDictionaryConstant.LOADING_BILL_STATUS_YSH);
			tmsLoadingBillHeaderMapper.update(tmsLoadingBillHeaderModel);
			MessageUtil.addMessage(new SendMessageDTO(MessageOrderTypeEnum.LOADING_NO.getCode(), MessageTypeEnum.CARRIER_DISPATCH_AUDIT.getCode(), Lists.newArrayList(tmsLoadingBillHeaderModel.getLoadingBillId())));
		}
	}

	/**
	 * 运单查询
	 *
	 * @param shipbillQueryVO
	 */
	@SuppressWarnings("resource")
	public Page<DispatchCheckQueryDTO> shipbillQuery(ShipbillQueryVO shipbillQueryVO) {
		ToolKits.isParamNull(shipbillQueryVO, "待调度查询请求不为空");
		ToolKits.isParamNull(shipbillQueryVO.getPageNum(), "当前页码不为空");
		ToolKits.isParamNull(shipbillQueryVO.getPageSize(), "每页条数不为空");
		ToolKits.isParamNull(shipbillQueryVO.getLoadingBillId(), "装车单ID不为空");

		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");

		if (!user.getUserType().equals(BussinessConstant.USER_TYPE_ZY) && !user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
			ToolKits.isParamNull(user, "当前人员没有操作权限");
		}

		// 添加查询条件
		Criteria criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
		Restriction r1 = Restrictions.eq(TmsLoadingBillDetailModel::getLoadingBillId, shipbillQueryVO.getLoadingBillId());
		criteria.setRestriction(Restrictions.and(r1));

		PageUtils.startPage(shipbillQueryVO.getPageNum(), shipbillQueryVO.getPageSize());
		List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModels = tmsLoadingBillDetailMapper.findByCriteria(criteria);

		// 响应对象集合
		List<DispatchCheckQueryDTO> pendingDispatchDTOs = Lists.newArrayList();

		for (TmsLoadingBillDetailModel loadingBillDetailModel : tmsLoadingBillDetailModels) {
			DispatchCheckQueryDTO pendingDispatchDTO = new DispatchCheckQueryDTO();
			BeanUtils.copyProperties(loadingBillDetailModel, pendingDispatchDTO);

			StringBuffer consigneeProvinceCityDistrict = new StringBuffer();
			// 目的地
			consigneeProvinceCityDistrict.append(ToolKits.isEmpty(loadingBillDetailModel.getConsigneeProvinceName()) ? "" : loadingBillDetailModel.getConsigneeProvinceName());
			consigneeProvinceCityDistrict.append(ToolKits.isEmpty(loadingBillDetailModel.getConsigneeCityName()) ? "" : loadingBillDetailModel.getConsigneeCityName());
			consigneeProvinceCityDistrict.append(ToolKits.isEmpty(loadingBillDetailModel.getConsigneeDistrictName()) ? "" : loadingBillDetailModel.getConsigneeDistrictName());
			pendingDispatchDTO.setConsigneeProvinceCityDistrict(consigneeProvinceCityDistrict.toString());
			// 始发地
			StringBuffer shipperProvinceCityDistrict = new StringBuffer();
			shipperProvinceCityDistrict.append(ToolKits.isEmpty(loadingBillDetailModel.getShipperProvinceName()) ? "" : loadingBillDetailModel.getShipperProvinceName());
			shipperProvinceCityDistrict.append(ToolKits.isEmpty(loadingBillDetailModel.getShipperCityName()) ? "" : loadingBillDetailModel.getShipperCityName());
			shipperProvinceCityDistrict.append(ToolKits.isEmpty(loadingBillDetailModel.getShipperDistrictName()) ? "" : loadingBillDetailModel.getShipperDistrictName());
			pendingDispatchDTO.setShipperProvinceCityDistrict(shipperProvinceCityDistrict.toString());

			// 发货方类型
			if (DataDictionaryConstant.SHIPPER_TYPE_KH.equals(pendingDispatchDTO.getShipperType())) {
				// 发货方名称
				pendingDispatchDTO.setShipperName(pendingDispatchDTO.getShipperUnitName() + DataDictionaryConstant.Line_SYMBOL + pendingDispatchDTO.getShipperName());
			}

			// 收货方电话
			StringBuffer tel = new StringBuffer();
			if (ToolKits.isNotEmpty(pendingDispatchDTO.getConsigneeLandlineNumber()) && ToolKits.isNotEmpty(pendingDispatchDTO.getConsigneePhoneNumber())) {
				tel.append(pendingDispatchDTO.getConsigneeLandlineNumber());
				tel.append(DataDictionaryConstant.Line_SYMBOL);
				tel.append(pendingDispatchDTO.getConsigneePhoneNumber());
			} else if (ToolKits.isNotEmpty(pendingDispatchDTO.getConsigneeLandlineNumber())) {
				tel.append(pendingDispatchDTO.getConsigneeLandlineNumber());
			} else if (ToolKits.isNotEmpty(pendingDispatchDTO.getConsigneePhoneNumber())) {
				tel.append(pendingDispatchDTO.getConsigneePhoneNumber());
			}
			if (ToolKits.isNotEmpty(tel.toString())) {
				pendingDispatchDTO.setConsigneeTel(tel.toString());
			}

			// 收货方类型
			if (DataDictionaryConstant.CONSIGNEE_TYPE_KH.equals(pendingDispatchDTO.getConsigneeType())) {
				// 收货方名称
				pendingDispatchDTO.setConsigneeName(pendingDispatchDTO.getConsigneeUnitName() + DataDictionaryConstant.Line_SYMBOL + pendingDispatchDTO.getConsigneeName());
			} else if (DataDictionaryConstant.CONSIGNEE_TYPE_GYS.equals(pendingDispatchDTO.getConsigneeType())) {
				// 收货方名称
				pendingDispatchDTO.setConsigneeName(pendingDispatchDTO.getConsigneeName() + DataDictionaryConstant.Line_SYMBOL + pendingDispatchDTO.getShipperName());
			}

			// 获取包裹信息
			Criteria criteriaPkg = Criteria.forClass(TmsShipbillPackageModel.class);
			Restriction r29 = Restrictions.eq(TmsShipbillPackageModel::getShipbillId, pendingDispatchDTO.getShipbillId());
			Restriction r30 = Restrictions.eq(TmsShipbillPackageModel::getEnterpriseId, user.getEnterpriseId());
			criteriaPkg.setRestriction(Restrictions.and(r29, r30));
			criteriaPkg.setOrder(Order.newInstance().desc(new String[] { "updatetime" }));

			List<TmsShipbillPackageModel> tmsShipbillPackageModels = tmsShipbillPackageMapper.findByCriteria(criteriaPkg);

			List<DispatchCheckPackageDTO> loadingPackageDTOList = Lists.newArrayList();
			for (TmsShipbillPackageModel packageModel : tmsShipbillPackageModels) {
				DispatchCheckPackageDTO packageDTO = new DispatchCheckPackageDTO();
				BeanUtils.copyProperties(packageModel, packageDTO);
				loadingPackageDTOList.add(packageDTO);
			}
			pendingDispatchDTO.setDisPackageDTOS(loadingPackageDTOList);

			if (loadingPackageDTOList.size() == 0) {
				// 获取商品信息
				Criteria criteriaDetail = Criteria.forClass(TmsShipbillDetailModel.class);
				criteriaDetail.setRestriction(Restrictions.and(r29, r30));
				criteriaDetail.setOrder(Order.newInstance().desc(new String[] { "updatetime" }));
				List<TmsShipbillDetailModel> tmsShipbillDetailModels = tmsShipbillDetailMapper.findByCriteria(criteriaDetail);

				List<DispatchCheckShipBillDtlDTO> detailDTOList = Lists.newArrayList();
				for (TmsShipbillDetailModel detailModel : tmsShipbillDetailModels) {
					DispatchCheckShipBillDtlDTO detailDTO = new DispatchCheckShipBillDtlDTO();
					BeanUtils.copyProperties(detailModel, detailDTO);
					detailDTOList.add(detailDTO);
				}
				// 商品信息
				pendingDispatchDTO.setShipBillDetailDTOS(detailDTOList);
			}
			pendingDispatchDTOs.add(pendingDispatchDTO);
		}
		// 分页重组
		Page<DispatchCheckQueryDTO> page = PageUtils.getPage(pendingDispatchDTOs);
		if (tmsLoadingBillDetailModels instanceof com.github.pagehelper.Page) {
			com.github.pagehelper.Page<TmsLoadingBillDetailModel> p0 = (com.github.pagehelper.Page<TmsLoadingBillDetailModel>) tmsLoadingBillDetailModels;
			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;
	}

	/**
	 * 获得第一个字符
	 *
	 * @param str
	 * @return
	 */
	public String getFirstStr(String str) {
		if (ToolKits.isEmpty(str)) {
			return null;
		}
		String[] arr1 = str.split(",");
		return arr1[0];
	}

	/**
	 * 去掉数组第一个元素
	 *
	 * @param str
	 * @return
	 */
	public String subArrToString(String str) {
		if (ToolKits.isEmpty(str)) {
			return null;
		}
		String[] arr1 = str.split(",");
		if (null == arr1) {
			return null;
		} else if (1 == arr1.length) {
			return null;
		} else if (1 < arr1.length) {
			String[] arr2 = (String[]) ArrayUtils.subarray(arr1, 1, arr1.length);
			return Arrays.stream(arr2).collect(Collectors.joining(","));
		}
		return null;
	}

	/**
	 * 运单匹配业务流程
	 *
	 * @param model
	 * @return
	 */
	public ShipbillFitBusinessFlowDTO shipbillMatchBusinessFlow(TmsShipbillHeaderModel model) {
		// 新增后自动提交判定
		BusinessFlowShipbillVO matchFlowVO = new BusinessFlowShipbillVO();
		// 流程类型 承运商
		matchFlowVO.setFlowType(1);
		// 配送方式
		matchFlowVO.setDeliveryMethodType(model.getDeliveryMethodType());
		// 发货方类型
		matchFlowVO.setShipperType(model.getShipperType());
		// 发货方单位ID
		matchFlowVO.setShipperUnitId(model.getShipperUnitId());
		// 收货方类型
		matchFlowVO.setConsigneeType(model.getConsigneeType());
		// 收货方单位ID
		matchFlowVO.setConsigneeUnitId(model.getConsigneeUnitId());
		// 订单类型
		matchFlowVO.setOrderType(model.getOrderType());
		// 订单业务类型
		matchFlowVO.setOrderBusinessType(model.getOrderBusinessType());
		// 运输模式
		matchFlowVO.setTransportType(model.getTransportType());
		// 温度要求
		matchFlowVO.setTemperatureRequirement(model.getTemperatureRequirement());
		// 货主ID
		matchFlowVO.setCargoOwnerId(model.getCargoOwnerId());
		RestMessage<ShipbillFitBusinessFlowDTO> matchRs = maindataTmsResource.shipbillMatchFlowQuery(matchFlowVO);
		if (!matchRs.isSuccess()) {
			throw new PrologException("运单【" + model.getShipbillNo() + "】调用maindata服务运单匹配业务流程失败");
		}
		Assert.isTrue(ToolKits.isNotEmpty(matchRs.getData().getFlowConfig()), "运单【" + model.getShipbillNo() + "】没有匹配到承运商业务流程，请配置承运商业务流程");
		return matchRs.getData();
	}

	// 调度审核匹配审批流程
	public Boolean approvalOpen(TmsLoadingBillHeaderModel loadingBillHeaderModel, TmsShipbillHeaderModel model, Integer approvalFlowType, UserEntity user) {
		// 封装判断所需数据
		ApprovalOpenVO approvalOpenVO = new ApprovalOpenVO();
		approvalOpenVO.setApprovalFlowType(approvalFlowType);
		approvalOpenVO.setApprovalObjectId(loadingBillHeaderModel.getLoadingBillId());
		approvalOpenVO.setApprovalObjectCode(loadingBillHeaderModel.getLoadingBillNo());
		approvalOpenVO.setApprovalObjectName(loadingBillHeaderModel.getLoadingBillNo());
		approvalOpenVO.setInitiatedUserId(user.getUserid());
		approvalOpenVO.setInitiatedUserName(user.getNickname());

		// 配送方式
		approvalOpenVO.setDeliveryMethodType(model.getDeliveryMethodType());
		// 发货方类型
		approvalOpenVO.setShipperType(model.getShipperType());
		// 发货方单位ID
		approvalOpenVO.setShipperUnitId(model.getShipperUnitId());
		// 收货方类型
		approvalOpenVO.setConsigneeType(model.getConsigneeType());
		// 收货方单位ID
		approvalOpenVO.setConsigneeUnitId(model.getConsigneeUnitId());
		// 订单类型
		approvalOpenVO.setOrderType(model.getOrderType());
		// 订单业务类型
		approvalOpenVO.setOrderBusinessType(model.getOrderBusinessType());
		// 运输模式
		approvalOpenVO.setTransportType(model.getTransportType());
		// 温度要求
		approvalOpenVO.setTemperatureRequirement(model.getTemperatureRequirement());
		// 货主ID
		approvalOpenVO.setCargoOwnerId(model.getCargoOwnerId());
		// 部门ID
		approvalOpenVO.setDepartmentId(model.getDepartmentId());

		RestMessage<Boolean> restMessage1 = maindataTmsResource.openExecute(approvalOpenVO);
		if (!restMessage1.isSuccess()) {
			throw new RuntimeException("调用maindata服务是否开启审批流接口失败:" + restMessage1.getMessage());
		}
		return restMessage1.getData();
	}

	/**
	 * 已托运配载运单剔除
	 *
	 * @param trailerDeleteDetailVO
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteDetailTrailerData(TrailerDeleteDetailVO trailerDeleteDetailVO) {
		ToolKits.isParamNull(trailerDeleteDetailVO.getLoadingBillId(), "托运单ID不为空");
		ToolKits.isParamNull(trailerDeleteDetailVO.getShipbillIds(), "运单ID不为空");

		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");

		TmsLoadingBillHeaderModel tmsLoadingBillHeaderModel = tmsLoadingBillHeaderMapper.findById(trailerDeleteDetailVO.getLoadingBillId(), TmsLoadingBillHeaderModel.class);
		if (ToolKits.isEmpty(tmsLoadingBillHeaderModel)) {
			throw new PrologException(StrUtil.format("托运单{}不存在",trailerDeleteDetailVO.getLoadingBillId()));
		}
		if (ToolKits.isEmpty(tmsLoadingBillHeaderModel.getStatus()) || DataDictionaryConstant.LOADING_BILL_STATUS_ZC_CONFIRM.intValue() < tmsLoadingBillHeaderModel.getStatus().intValue()  ) {
			throw new PrologException(StrUtil.format("托运单{}已启运，请不要剔除运单", trailerDeleteDetailVO.getLoadingBillId()));
		}

		Criteria criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
		Restriction r1 = Restrictions.eq(TmsLoadingBillDetailModel::getLoadingBillId, trailerDeleteDetailVO.getLoadingBillId());
		Restriction r2 = Restrictions.in(TmsLoadingBillDetailModel::getShipbillId, trailerDeleteDetailVO.getShipbillIds().stream().toArray());
		Restriction r3 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
		criteria.setRestriction(Restrictions.and(r1, r2,r3));
		List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModels = tmsLoadingBillDetailMapper.findByCriteria(criteria);

		// 修改配送顺序以及总重量体积件数等数据
		for (TmsLoadingBillDetailModel tmsLoadingBillDetailModel : tmsLoadingBillDetailModels) {

			// 修改配送顺序
			r1 = Restrictions.eq("loadingBillId", tmsLoadingBillDetailModel.getLoadingBillId());
			r2 = Restrictions.ne("shipbillId", tmsLoadingBillDetailModel.getShipbillId());
			criteria.setRestriction(Restrictions.and(r1, r2, r3));
			List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModelList = tmsLoadingBillDetailMapper.findByCriteria(criteria);
			for (TmsLoadingBillDetailModel loadingBillDetailModel : tmsLoadingBillDetailModelList) {
				if (ToolKits.isEmpty(loadingBillDetailModel.getShippingOrder()) || ToolKits.isEmpty(tmsLoadingBillDetailModel.getShippingOrder())) {
					continue;
				}
				if (loadingBillDetailModel.getShippingOrder() > tmsLoadingBillDetailModel.getShippingOrder()) {
					loadingBillDetailModel.setShippingOrder(loadingBillDetailModel.getShippingOrder() - 1);
				}
				tmsLoadingBillDetailMapper.update(loadingBillDetailModel);
			}

			// 删除明细内容
			tmsLoadingBillDetailMapper.deleteById(tmsLoadingBillDetailModel.getId(), TmsLoadingBillDetailModel.class);

			ShipbillOperateLogSaveVO shipbillOperateLogSaveVO = new ShipbillOperateLogSaveVO();
			ShipbillNodeTrackingSaveVO shipbillNodeTrackingSaveVO = new ShipbillNodeTrackingSaveVO();
			if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
				shipbillOperateLogSaveVO.setOperateEvent("从托运单" + tmsLoadingBillHeaderModel.getLoadingBillId() + "中剔除");
				shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.SHIPBILL_STATUS_DISPATCH);
				shipbillOperateLogSaveVO.setNewStatus(DataDictionaryConstant.SHIPBILL_STATUS_REVIEW);

				shipbillNodeTrackingSaveVO.setStatus(DataDictionaryConstant.SHIPBILL_STATUS_REVIEW);
				shipbillNodeTrackingSaveVO.setNodeEvent("从托运单" + tmsLoadingBillHeaderModel.getLoadingBillId() + "中剔除");
			} else if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
				shipbillOperateLogSaveVO.setOperateEvent("承运商 从托运单" + tmsLoadingBillHeaderModel.getLoadingBillId() + "中剔除");
				shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED);
				shipbillOperateLogSaveVO.setNewStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_AUDITED);

				shipbillNodeTrackingSaveVO.setStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_AUDITED);
				shipbillNodeTrackingSaveVO.setNodeEvent("承运商 从托运单" + tmsLoadingBillHeaderModel.getLoadingBillId() + "中剔除");
			}
			// 运单操作日志保存
			shipbillOperateLogSaveVO.setShipbillId(tmsLoadingBillDetailModel.getShipbillId());
			shipbillOperateLogSaveVO.setShipbillNo(tmsLoadingBillDetailModel.getShipbillNo());
			shipbillOperateLogService.addShipbillOperateLogData(shipbillOperateLogSaveVO);

			// 运单节点保存
			shipbillNodeTrackingSaveVO.setShipbillId(tmsLoadingBillDetailModel.getShipbillId());
			shipbillNodeTrackingSaveVO.setShipbillNo(tmsLoadingBillDetailModel.getShipbillNo());
			shipbillNodeTrackingService.addShipbillNodeTrackingData(shipbillNodeTrackingSaveVO);
		}

		// 重新计算
		calculateLoadingData(tmsLoadingBillHeaderModel);

		// 计算装载率
		if (ToolKits.isNotEmpty(tmsLoadingBillHeaderModel.getVehicleId())) {
			Map<String, String> map = commonUtil.calculateLoadingRate(tmsLoadingBillHeaderModel.getVehicleId(), tmsLoadingBillHeaderModel.getTotalWeight(), tmsLoadingBillHeaderModel.getTotalVolume());
			tmsLoadingBillHeaderModel.setVolumeLoadingRate(map.get("volume"));
			tmsLoadingBillHeaderModel.setWeightLoadingRate(map.get("weight"));
		}
		Date date = DateUtil.date();
		// 修改汇总表
		tmsLoadingBillHeaderModel.setUpdatetime(date);
		tmsLoadingBillHeaderModel.setUpdateperson(user.getNickname());
		tmsLoadingBillHeaderMapper.update(tmsLoadingBillHeaderModel);

		// 运单状态回退
		criteria = Criteria.forClass(TmsShipbillHeaderModel.class);
		r1 = Restrictions.in("shipbillId", trailerDeleteDetailVO.getShipbillIds().toArray());
		criteria.setRestriction(r1);

		Map<String, Object> map = Maps.newHashMap();
		map.put("updateperson", user.getNickname());
		map.put("updatetime", date);
		if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
			map.put("carrierFlowConfig", null);
			map.put("carrierId", null);
			map.put("carrierCode", null);
			map.put("carrierName", null);
			map.put("carrierType", null);
			map.put("status", DataDictionaryConstant.SHIPBILL_STATUS_REVIEW);
		} else if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
			map.put("carrierFlowConfig", null);
			map.put("carrierId", null);
			map.put("carrierCode", null);
			map.put("carrierName", null);
			map.put("carrierType", null);
			map.put("carrierShipbillStatus", DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_AUDITED);
		}
		tmsShipbillHeaderMapper.updateMapByCriteria(map, criteria);

		bookingService.cancelAppointment(trailerDeleteDetailVO.getShipbillIds());
	}

	/**
	 * 计算派车单统计数据
	 *
	 * @param tmsLoadingBillHeaderModel
	 * @return
	 */
	private void calculateLoadingData(TmsLoadingBillHeaderModel tmsLoadingBillHeaderModel) {
		// 重新计算
		Criteria criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
		Restriction r1 = Restrictions.eq(TmsLoadingBillDetailModel::getLoadingBillId, tmsLoadingBillHeaderModel.getLoadingBillId());
		criteria.setRestriction(Restrictions.and(r1));
		List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModelList = tmsLoadingBillDetailMapper.findByCriteria(criteria);
		if (ToolKits.isEmpty(tmsLoadingBillDetailModelList)) {
			// 货主数
			tmsLoadingBillHeaderModel.setCargoOwnerNumber(Long.valueOf(0));
			// 客户数
			tmsLoadingBillHeaderModel.setCustomerNumber(0);
			// 运单数
			tmsLoadingBillHeaderModel.setShipbillNumber(0);
			// 总提货点数
			tmsLoadingBillHeaderModel.setPickupStations(Long.valueOf(0));
			// 总配送点数
			tmsLoadingBillHeaderModel.setDeliveryStations(Long.valueOf(0));
			// 总站数
			tmsLoadingBillHeaderModel.setTotalStations(Long.valueOf(0));
			tmsLoadingBillHeaderModel.setSiteNumber(tmsLoadingBillHeaderModel.getTotalStations().intValue());
			// 冷链运单数
			tmsLoadingBillHeaderModel.setColdShipbillNumber(Long.valueOf(0));

			// 紧急加急运单数
			tmsLoadingBillHeaderModel.setUrgentShipbillNumber(Long.valueOf(0));

			// 商品/包裹 总件数
			tmsLoadingBillHeaderModel.setTotalPcs(BigDecimal.ZERO);
			tmsLoadingBillHeaderModel.setTotalLclPiece(BigDecimal.ZERO);
			tmsLoadingBillHeaderModel.setTotalWholePiece(BigDecimal.ZERO);
			// 商品/包裹 总重量
			tmsLoadingBillHeaderModel.setTotalWeight(BigDecimal.ZERO);
			// 商品/包裹 总体积
			tmsLoadingBillHeaderModel.setTotalVolume(BigDecimal.ZERO);

			tmsLoadingBillHeaderModel.setActualTotalPcs(tmsLoadingBillHeaderModel.getTotalPcs());
			tmsLoadingBillHeaderModel.setActualTotalWeight(tmsLoadingBillHeaderModel.getTotalWeight());
			tmsLoadingBillHeaderModel.setActualTotalVolume(tmsLoadingBillHeaderModel.getTotalVolume());;
			tmsLoadingBillHeaderModel.setTotalMileage(BigDecimal.ZERO);
		} else {
			// 货主数
			tmsLoadingBillHeaderModel.setCargoOwnerNumber(Long.valueOf(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getCargoOwnerName).distinct().collect(Collectors.toList()).size()));
			// 客户数
			tmsLoadingBillHeaderModel.setCustomerNumber(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getConsigneeUnitName).distinct().collect(Collectors.toList()).size());
			// 运单数
			tmsLoadingBillHeaderModel.setShipbillNumber(tmsLoadingBillDetailModelList.size());
			// 总提货点数
			tmsLoadingBillHeaderModel.setPickupStations(Long.valueOf(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getShipperAddress).distinct().collect(Collectors.toList()).size()));
			// 总配送点数
			tmsLoadingBillHeaderModel.setDeliveryStations(Long.valueOf(tmsLoadingBillDetailModelList.stream().map(TmsLoadingBillDetailModel::getConsigneeAddress).distinct().collect(Collectors.toList()).size()));
			// 总站数
			tmsLoadingBillHeaderModel.setTotalStations(tmsLoadingBillHeaderModel.getPickupStations().longValue() + tmsLoadingBillHeaderModel.getDeliveryStations().longValue());
			tmsLoadingBillHeaderModel.setSiteNumber(tmsLoadingBillHeaderModel.getTotalStations().intValue());
			// 冷链运单数
			long coldChainShipbillQty = tmsLoadingBillDetailModelList.stream().filter(s -> ToolKits.isNotEmpty(s.getTemperatureRequirement()) && s.getTemperatureRequirement().intValue() > 1).collect(Collectors.toList()).size();
			tmsLoadingBillHeaderModel.setColdShipbillNumber(coldChainShipbillQty);

			// 紧急加急运单数
			long urgentShipbillQty = tmsLoadingBillDetailModelList.stream().filter(s -> ToolKits.isNotEmpty(s.getOrderType()) && s.getOrderType().intValue() > 1).collect(Collectors.toList()).size();
			tmsLoadingBillHeaderModel.setUrgentShipbillNumber(urgentShipbillQty);

			BigDecimal pcs1 = tmsLoadingBillDetailModelList.stream().filter(dto -> ToolKits.isNotEmpty(dto.getTotalPcs())).map(TmsLoadingBillDetailModel::getTotalPcs).reduce(BigDecimal.ZERO, BigDecimal::add);
			BigDecimal pcs2 = tmsLoadingBillDetailModelList.stream().filter(dto -> ToolKits.isNotEmpty(dto.getPackageLclPiece())).map(TmsLoadingBillDetailModel::getPackageLclPiece).reduce(BigDecimal.ZERO, BigDecimal::add);
			BigDecimal pcs3 = tmsLoadingBillDetailModelList.stream().filter(dto -> ToolKits.isNotEmpty(dto.getPackageWholePiece())).map(TmsLoadingBillDetailModel::getPackageWholePiece).reduce(BigDecimal.ZERO, BigDecimal::add);
			BigDecimal weigth1 = tmsLoadingBillDetailModelList.stream().filter(dto -> ToolKits.isNotEmpty(dto.getTotalWeight())).map(TmsLoadingBillDetailModel::getTotalWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
			BigDecimal weigth2 = tmsLoadingBillDetailModelList.stream().filter(dto -> ToolKits.isNotEmpty(dto.getPackageTotalWeight())).map(TmsLoadingBillDetailModel::getPackageTotalWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
			BigDecimal volume1 = tmsLoadingBillDetailModelList.stream().filter(dto -> ToolKits.isNotEmpty(dto.getTotalVolume())).map(TmsLoadingBillDetailModel::getTotalVolume).reduce(BigDecimal.ZERO, BigDecimal::add);
			BigDecimal volume2 = tmsLoadingBillDetailModelList.stream().filter(dto -> ToolKits.isNotEmpty(dto.getPackageTotalVolume())).map(TmsLoadingBillDetailModel::getPackageTotalVolume).reduce(BigDecimal.ZERO, BigDecimal::add);

			// 商品/包裹 总件数
			tmsLoadingBillHeaderModel.setTotalPcs(pcs1);
			tmsLoadingBillHeaderModel.setTotalLclPiece(pcs2);
			tmsLoadingBillHeaderModel.setTotalWholePiece(pcs3);
			// 商品/包裹 总重量
			tmsLoadingBillHeaderModel.setTotalWeight(weigth1.add(weigth2));
			// 商品/包裹 总体积
			tmsLoadingBillHeaderModel.setTotalVolume(volume1.add(volume2));

			tmsLoadingBillHeaderModel.setActualTotalPcs(tmsLoadingBillHeaderModel.getTotalPcs());
			tmsLoadingBillHeaderModel.setActualTotalWeight(tmsLoadingBillHeaderModel.getTotalWeight());
			tmsLoadingBillHeaderModel.setActualTotalVolume(tmsLoadingBillHeaderModel.getTotalVolume());
		}
	}

}
