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

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.prolog.common.util.DateUtils;
import com.prolog.common.util.ToolKits;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.BizException;
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.StatusConstant;
import com.prolog.rdc.tms.app.dao.mapper.*;
import com.prolog.rdc.tms.app.model.dto.AppointmentBillQueryForCarrierDTO;
import com.prolog.rdc.tms.app.model.dto.business.*;
import com.prolog.rdc.tms.app.model.entity.*;
import com.prolog.rdc.tms.app.model.vo.AppointmentBillQueryForCarrierVO;
import com.prolog.rdc.tms.app.model.vo.business.*;
import com.prolog.rdc.tms.app.service.business.BookingService;
import com.prolog.rdc.tms.app.service.business.ShipbillOperateLogService;
import com.prolog.rdc.tms.app.util.*;
import com.prolog.rdc.tms.model.dto.DeviceByOneDTO;
import com.prolog.rdc.tms.model.dto.basicConfigure.SignconfigPopDTO;
import com.prolog.rdc.tms.model.dto.basicData.TmsBaseBranchApTimeDTO;
import com.prolog.rdc.tms.model.dto.basicData.TmsBaseBranchDTO;
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 com.prolog.rdc.tms.model.vo.basicConfigure.SignconfigPopVO;
import com.prolog.rdc.tms.model.vo.basicData.AppointTimeQueryVO;
import com.prolog.rdc.tms.rmi.feign.MaindataFeign;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 园区管理-预约管理实现层
 * <p>
 * Company: 湖北普罗格科技股份有限公司
 *
 * @author xiaoyf
 * @since 2022/7/5 10:30
 */
@Service
public class BookingServiceImpl implements BookingService {

	@Autowired
	private TmsAppointmentHeaderMapper tmsAppointmentHeaderMapper;

	@Autowired
	private TmsAppointmentDetailMapper tmsAppointmentDetailMapper;

	@Autowired
	private MaindataFeign maindataTmsResource;

	@Autowired
	private TmsShipbillHeaderMapper tmsShipbillHeaderMapper;

	@Autowired
	private TmsShipbillDetailMapper tmsShipbillDetailMapper;

	@Autowired
	private TmsShipbillPackageMapper tmsShipbillPackageMapper;

	@Autowired
	private ShipbillOperateLogService shipbillOperateLogService;

	@Autowired
	private TmsLoadingBillDetailMapper tmsLoadingBillDetailMapper;

	@Autowired
	private ConvertorUtil convertorUtil;

	@Autowired
	private BusinessFlowUtil businessFlowUtil;

	/**
	 * 主界面分页查询
	 *
	 * @param
	 * @return
	 */
	@SuppressWarnings("resource")
	@Override
	public Page<BookingQueryDTO> queryPage(BookingQueryVO vo) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");

		if (!user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
			throw new PrologException("当前人员没有操作权限");
		}

		List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[] { DataDictionaryConstant.APPOINTMENT_STATUS // 预约单状态
		});

		Criteria criteria = Criteria.forClass(TmsAppointmentHeaderModel.class);
		Restriction r1 = Restrictions.in("branchId", vo.getBranchId().split(","));
		Restriction r2 = Restrictions.eq("status", DataDictionaryConstant.APPOINTMENT_STATUS_DSH);
		Restriction r3 = Restrictions.eq("enterpriseId", user.getEnterpriseId());

		PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
		criteria.setRestriction(Restrictions.and(r1, r2, r3));
		criteria.setOrder(Order.newInstance().asc(new String[] { "reserveNumber" }));

		List<BookingQueryDTO> dtos = Lists.newArrayList();
		List<TmsAppointmentHeaderModel> list = tmsAppointmentHeaderMapper.findByCriteria(criteria);

		for (TmsAppointmentHeaderModel tmsAppointmentHeaderModel : list) {
			BookingQueryDTO dto = new BookingQueryDTO();
			BeanUtils.copyProperties(tmsAppointmentHeaderModel, dto);
			dto.setStatusName(ConvertorUtil.getName(dicData, DataDictionaryConstant.APPOINTMENT_STATUS, String.valueOf(dto.getStatus())));
			Criteria loadBillCriteria = Criteria.forClass(TmsAppointmentDetailModel.class);
			Restriction loadBillRestriction = Restrictions.eq(TmsAppointmentDetailModel::getAppointmentId, tmsAppointmentHeaderModel.getAppointmentId());
			loadBillCriteria.setRestriction(Restrictions.and(loadBillRestriction));
			List<TmsAppointmentDetailModel> tmsAppointmentDetailModels = tmsAppointmentDetailMapper.findByCriteria(loadBillCriteria);
			//设置预约单的派车单
			dto.setLoadingBillIds(DataUtils.getLoadingBillIds(tmsAppointmentDetailModels));
			dtos.add(dto);
		}

		// 分页重组
		Page<BookingQueryDTO> page = PageUtils.getPage(dtos);
		if (list instanceof com.github.pagehelper.Page) {
			com.github.pagehelper.Page<TmsAppointmentHeaderModel> p0 = (com.github.pagehelper.Page<TmsAppointmentHeaderModel>) list;
			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 Page<AppointmentBillQueryForCarrierDTO> pageForCarrier(AppointmentBillQueryForCarrierVO carrierVO) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");
		if (!user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
			throw new BizException("当前人员不是承运商");
		}
		carrierVO.setBranchIdList(Lists.newArrayList(carrierVO.getBranchId().split(",")));
		carrierVO.setEnterpriseId(user.getEnterpriseId());
		List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[] {
				DataDictionaryConstant.APPOINTMENT_STATUS, // 预约单状态
				DataDictionaryConstant.TALLY_STATUS // 理货状态
		});
		PageUtils.startPage(carrierVO.getPageNum(), carrierVO.getPageSize());
		List<AppointmentBillQueryForCarrierDTO> list = tmsAppointmentHeaderMapper.queryForCarrier(carrierVO);
		list.forEach(dto -> {
			dto.setStatusName(ConvertorUtil.getName(dicData, DataDictionaryConstant.APPOINTMENT_STATUS, String.valueOf(dto.getStatus())));
			dto.setTallyStatusName(ConvertorUtil.getName(dicData, DataDictionaryConstant.TALLY_STATUS, String.valueOf(dto.getTallyStatus())));
		});
		return PageUtils.getPage(list);
	}

	/**
	 * 预约明细查询
	 *
	 * @param bookingGetShipbillVO
	 * @return
	 */
	@SuppressWarnings("resource")
	@Override
	public Page<BookingGetShipbillDTO> getShipbillData(BookingGetShipbillVO bookingGetShipbillVO) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");
		// 权限控制 仅支持自有账号操作
//		if (!user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
//			throw new PrologException("当前人员没有操作权限");
//		}
		// 数据字典翻译数据集合
		List<Map<String, Object>> data1 = Lists.newArrayList();
		List<Map<String, Object>> data2 = Lists.newArrayList();
		List<Map<String, Object>> data3 = Lists.newArrayList();
		List<Map<String, Object>> data4 = Lists.newArrayList();
		List<Map<String, Object>> data5 = Lists.newArrayList();
		List<Map<String, Object>> data6 = Lists.newArrayList();
		List<Map<String, Object>> data7 = Lists.newArrayList();
		List<SignconfigPopDTO> data8 = Lists.newArrayList();

		// 订单类型
		RestMessage<List<Map<String, Object>>> restMessage1 = maindataTmsResource.getDropDownById(DataDictionaryConstant.ORDER_TYPE, null, null, null);
		if (!restMessage1.isSuccess()) {
			throw new RuntimeException("订单类型翻译失败!");
		} else {
			data1 = restMessage1.getData();
		}
		// 订单业务类型
		RestMessage<List<Map<String, Object>>> restMessage2 = maindataTmsResource.getDropDownById(DataDictionaryConstant.ORDER_BUSINESS_TYPE, null, null, null);
		if (!restMessage2.isSuccess()) {
			throw new RuntimeException("订单业务类型翻译失败!");
		} else {
			data2 = restMessage2.getData();
		}
		// 配送方式
		RestMessage<List<Map<String, Object>>> restMessage3 = maindataTmsResource.getDropDownById(DataDictionaryConstant.DELIVERY_METHOD_TYPE, null, null, null);
		if (!restMessage3.isSuccess()) {
			throw new RuntimeException("配送方式翻译失败!");
		} else {
			data3 = restMessage3.getData();
		}
		// 运输类型(运输模式)
		RestMessage<List<Map<String, Object>>> restMessage4 = maindataTmsResource.getDropDownById(DataDictionaryConstant.TRANSPORT_TYPE, null, null, null);
		if (!restMessage4.isSuccess()) {
			throw new RuntimeException("运输类型(运输模式)翻译失败!");
		} else {
			data4 = restMessage4.getData();
		}
		// 温度要求
		RestMessage<List<Map<String, Object>>> restMessage5 = maindataTmsResource.getDropDownById(DataDictionaryConstant.TEMPERATURE_REQUIREMENT, null, null, null);
		if (!restMessage5.isSuccess()) {
			throw new RuntimeException("温度要求翻译失败!");
		} else {
			data5 = restMessage5.getData();
		}
		// 发货方类型
		RestMessage<List<Map<String, Object>>> restMessage6 = maindataTmsResource.getDropDownById(DataDictionaryConstant.SHIPPER_TYPE, null, null, null);
		if (!restMessage6.isSuccess()) {
			throw new RuntimeException("发货方类型翻译失败!");
		} else {
			data6 = restMessage6.getData();
		}
		// 收货方类型
		RestMessage<List<Map<String, Object>>> restMessage7 = maindataTmsResource.getDropDownById(DataDictionaryConstant.CONSIGNEE_TYPE, null, null, null);
		if (!restMessage7.isSuccess()) {
			throw new RuntimeException("收货方类型翻译失败!");
		} else {
			data7 = restMessage7.getData();
		}
		// 标记配置
		SignconfigPopVO signconfigPopVO = new SignconfigPopVO();
		RestMessage<List<SignconfigPopDTO>> restMessage8 = maindataTmsResource.getSignConfig(signconfigPopVO);
		if (!restMessage8.isSuccess()) {
			throw new RuntimeException("标记配置查询失败!");
		} else {
			data8 = restMessage8.getData();
		}

		// 封装运单明细
		Criteria criteria = Criteria.forClass(TmsAppointmentDetailModel.class);
		Restriction r1 = Restrictions.eq("appointmentId", bookingGetShipbillVO.getAppointmentId());
		criteria.setRestriction(r1);
		criteria.setOrder(Order.newInstance().asc(new String[] { "orderDate" }));

		PageUtils.startPage(bookingGetShipbillVO.getPageNum(), bookingGetShipbillVO.getPageSize());
		List<TmsAppointmentDetailModel> tmsAppointmentDetailModels = tmsAppointmentDetailMapper.findByCriteria(criteria);

		// 明细集合
		List<BookingGetShipbillDTO> list = Lists.newArrayList();

		for (TmsAppointmentDetailModel model : tmsAppointmentDetailModels) {

			BookingGetShipbillDTO bookingGetShipbillDTO = new BookingGetShipbillDTO();
			BeanUtils.copyProperties(model, bookingGetShipbillDTO);

			// 收货方位置(经纬度判断)
			if (ToolKits.isNotEmpty(model.getConsigneeLongitude()) && ToolKits.isNotEmpty(model.getConsigneeLatitude())) {
				bookingGetShipbillDTO.setConsigneePositioning(StatusConstant.POSITIONING_YDW);
			} else {
				bookingGetShipbillDTO.setConsigneePositioning(StatusConstant.POSITIONING_WDW);
			}
			// 发货方位置(经纬度判断)
			if (ToolKits.isNotEmpty(model.getShipperLongitude()) && ToolKits.isNotEmpty(model.getShipperLatitude())) {
				bookingGetShipbillDTO.setShipperPositioning(StatusConstant.POSITIONING_YDW);
			} else {
				bookingGetShipbillDTO.setShipperPositioning(StatusConstant.POSITIONING_WDW);
			}

			StringBuffer consigneeProvinceCityDistrict = new StringBuffer();
			// 目的地
			consigneeProvinceCityDistrict.append(model.getConsigneeProvinceName());
			consigneeProvinceCityDistrict.append(model.getConsigneeCityName());
			consigneeProvinceCityDistrict.append(model.getConsigneeDistrictName());
			bookingGetShipbillDTO.setConsigneeProvinceCityDistrict(consigneeProvinceCityDistrict.toString());
			// 始发地
			StringBuffer shipperProvinceCityDistrict = new StringBuffer();
			shipperProvinceCityDistrict.append(model.getShipperProvinceName());
			shipperProvinceCityDistrict.append(model.getShipperCityName());
			shipperProvinceCityDistrict.append(model.getShipperDistrictName());
			bookingGetShipbillDTO.setShipperProvinceCityDistrict(shipperProvinceCityDistrict.toString());

			// 类型翻译
			bookingGetShipbillDTO.setOrderTypeName(PublicMethods.change(data1, String.valueOf(model.getOrderType())));
			bookingGetShipbillDTO.setOrderBusinessTypeName(PublicMethods.change(data2, String.valueOf(model.getOrderBusinessType())));
			bookingGetShipbillDTO.setDeliveryMethodTypeName(PublicMethods.change(data3, String.valueOf(model.getDeliveryMethodType())));
			bookingGetShipbillDTO.setTransportTypeName(PublicMethods.change(data4, String.valueOf(model.getTransportType())));
			bookingGetShipbillDTO.setTemperatureRequirementName(PublicMethods.change(data5, String.valueOf(model.getTemperatureRequirement())));
			bookingGetShipbillDTO.setShipperTypeName(PublicMethods.change(data6, String.valueOf(model.getShipperType())));
			bookingGetShipbillDTO.setConsigneeTypeName(PublicMethods.change(data7, String.valueOf(model.getConsigneeType())));

			// 获取背景颜色和字体颜色
			Signconfig: for (SignconfigPopDTO signconfigPopDTO : data8) {
				// 标记类型匹配
				switch (signconfigPopDTO.getType()) {
				case DataDictionaryConstant.SIGNCONFIG_TYPE_DDLX: // 订单类型
					if (ToolKits.isNotEmpty(signconfigPopDTO.getMatching())) {
						// 判断是否匹配
						if (PublicMethods.compare(signconfigPopDTO.getMatching(), ToolKits.isNotEmpty(signconfigPopDTO.getStoredValue()) ? signconfigPopDTO.getStoredValue() : "", ToolKits.isNotEmpty(bookingGetShipbillDTO.getOrderTypeName()) ? bookingGetShipbillDTO.getOrderTypeName() : "")) {
							bookingGetShipbillDTO.setBackground(ToolKits.isEmpty(signconfigPopDTO.getBackground()) ? "" : signconfigPopDTO.getBackground());
							bookingGetShipbillDTO.setColor(ToolKits.isEmpty(signconfigPopDTO.getColor()) ? "" : signconfigPopDTO.getColor());

							bookingGetShipbillDTO.setSignConfigId(signconfigPopDTO.getId());

							// 匹配上结束循环
							break Signconfig;
						}
					}
					break;
				case DataDictionaryConstant.SIGNCONFIG_TYPE_YWLX: // 业务类型
					if (ToolKits.isNotEmpty(signconfigPopDTO.getMatching())) {
						if (PublicMethods.compare(signconfigPopDTO.getMatching(), ToolKits.isNotEmpty(signconfigPopDTO.getStoredValue()) ? signconfigPopDTO.getStoredValue() : "", ToolKits.isNotEmpty(bookingGetShipbillDTO.getOrderBusinessTypeName()) ? bookingGetShipbillDTO.getOrderBusinessTypeName() : "")) {
							bookingGetShipbillDTO.setBackground(ToolKits.isEmpty(signconfigPopDTO.getBackground()) ? "" : signconfigPopDTO.getBackground());
							bookingGetShipbillDTO.setColor(ToolKits.isEmpty(signconfigPopDTO.getColor()) ? "" : signconfigPopDTO.getColor());

							bookingGetShipbillDTO.setSignConfigId(signconfigPopDTO.getId());

							break Signconfig;
						}
					}
					break;
				case DataDictionaryConstant.SIGNCONFIG_TYPE_WDYQ: // 温度要求
					if (ToolKits.isNotEmpty(signconfigPopDTO.getMatching())) {
						if (PublicMethods.compare(signconfigPopDTO.getMatching(), ToolKits.isNotEmpty(signconfigPopDTO.getStoredValue()) ? signconfigPopDTO.getStoredValue() : "", ToolKits.isNotEmpty(bookingGetShipbillDTO.getTemperatureRequirementName()) ? bookingGetShipbillDTO.getTemperatureRequirementName() : "")) {
							bookingGetShipbillDTO.setBackground(ToolKits.isEmpty(signconfigPopDTO.getBackground()) ? "" : signconfigPopDTO.getBackground());
							bookingGetShipbillDTO.setColor(ToolKits.isEmpty(signconfigPopDTO.getColor()) ? "" : signconfigPopDTO.getColor());

							bookingGetShipbillDTO.setSignConfigId(signconfigPopDTO.getId());

							break Signconfig;
						}
					}
					break;
				case DataDictionaryConstant.SIGNCONFIG_TYPE_PSFS: // 配送方式
					if (ToolKits.isNotEmpty(signconfigPopDTO.getMatching())) {
						if (PublicMethods.compare(signconfigPopDTO.getMatching(), ToolKits.isNotEmpty(signconfigPopDTO.getStoredValue()) ? signconfigPopDTO.getStoredValue() : "", ToolKits.isNotEmpty(bookingGetShipbillDTO.getDeliveryMethodTypeName()) ? bookingGetShipbillDTO.getDeliveryMethodTypeName() : "")) {
							bookingGetShipbillDTO.setBackground(ToolKits.isEmpty(signconfigPopDTO.getBackground()) ? "" : signconfigPopDTO.getBackground());
							bookingGetShipbillDTO.setColor(ToolKits.isEmpty(signconfigPopDTO.getColor()) ? "" : signconfigPopDTO.getColor());

							bookingGetShipbillDTO.setSignConfigId(signconfigPopDTO.getId());

							break Signconfig;
						}
					}
					break;
				case DataDictionaryConstant.SIGNCONFIG_TYPE_DDBZ: // 订单备注
					if (ToolKits.isNotEmpty(signconfigPopDTO.getMatching())) {
						if (PublicMethods.compare(signconfigPopDTO.getMatching(), ToolKits.isNotEmpty(signconfigPopDTO.getStoredValue()) ? signconfigPopDTO.getStoredValue() : "", ToolKits.isNotEmpty(bookingGetShipbillDTO.getMemo()) ? bookingGetShipbillDTO.getMemo() : "")) {
							bookingGetShipbillDTO.setBackground(ToolKits.isEmpty(signconfigPopDTO.getBackground()) ? "" : signconfigPopDTO.getBackground());
							bookingGetShipbillDTO.setColor(ToolKits.isEmpty(signconfigPopDTO.getColor()) ? "" : signconfigPopDTO.getColor());

							bookingGetShipbillDTO.setSignConfigId(signconfigPopDTO.getId());

							break Signconfig;
						}
					}
					break;
				}
			}
			// 获取商品信息
			Criteria criteriaDetail = Criteria.forClass(TmsShipbillDetailModel.class);
			Restriction r27 = Restrictions.eq(TmsShipbillPackageModel::getShipbillId, bookingGetShipbillDTO.getShipbillId());
			Restriction r28 = Restrictions.eq(TmsShipbillPackageModel::getEnterpriseId, user.getEnterpriseId());
			criteriaDetail.setRestriction(Restrictions.and(r27, r28));
			criteriaDetail.setOrder(Order.newInstance().desc(new String[] { "updatetime" }));
			List<TmsShipbillDetailModel> tmsShipbillDetailModels = tmsShipbillDetailMapper.findByCriteria(criteriaDetail);

			List<ShipbillManageItemDTO> detailDTOList = Lists.newArrayList();
			for (TmsShipbillDetailModel detailModel : tmsShipbillDetailModels) {
				ShipbillManageItemDTO detailDTO = new ShipbillManageItemDTO();
				BeanUtils.copyProperties(detailModel, detailDTO);
				detailDTOList.add(detailDTO);
			}
			// 商品信息
			bookingGetShipbillDTO.setItemDTOList(detailDTOList);

			list.add(bookingGetShipbillDTO);
		}
		// 分页重组
		Page<BookingGetShipbillDTO> page = PageUtils.getPage(list);
		if (tmsAppointmentDetailModels instanceof com.github.pagehelper.Page) {
			com.github.pagehelper.Page<TmsAppointmentDetailModel> p0 = (com.github.pagehelper.Page<TmsAppointmentDetailModel>) tmsAppointmentDetailModels;
			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 bookingItemDetailVO
	 * @return
	 */
	@SuppressWarnings("resource")
	@Override
	public Page<BookingItemDetailDTO> itemDetailData(BookingItemDetailVO bookingItemDetailVO) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");

		// 权限控制 仅支持自有账号操作
		if (!user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
			throw new PrologException("当前人员没有操作权限");
		}

		// 数据字典翻译数据集合
		List<Map<String, Object>> data1 = Lists.newArrayList();
		List<Map<String, Object>> data2 = Lists.newArrayList();

		// 包装类型
		RestMessage<List<Map<String, Object>>> restMessage1 = maindataTmsResource.getDropDownById(DataDictionaryConstant.PACK_TYPE, null, null, null);
		if (!restMessage1.isSuccess()) {
			throw new RuntimeException("订单类型翻译失败!");
		} else {
			data1 = restMessage1.getData();
		}
		// 货物温层
		RestMessage<List<Map<String, Object>>> restMessage2 = maindataTmsResource.getDropDownById(DataDictionaryConstant.CARGO_THERMOSPHERE, null, null, null);
		if (!restMessage2.isSuccess()) {
			throw new RuntimeException("货物温层翻译失败!");
		} else {
			data2 = restMessage2.getData();
		}

		// 返回数据集
		List<BookingItemDetailDTO> list = Lists.newArrayList();

		// 查询预约单明细
		Criteria criteria = Criteria.forClass(TmsAppointmentDetailModel.class);
		Restriction r1 = Restrictions.eq("appointmentId", bookingItemDetailVO.getAppointmentId());
		criteria.setRestriction(r1);

		List<TmsAppointmentDetailModel> tmsAppointmentDetailModels = tmsAppointmentDetailMapper.findByCriteria(criteria);

		// 根据运单ID查询明细数据
		criteria = Criteria.forClass(TmsShipbillDetailModel.class);
		r1 = Restrictions.in("shipbillId", tmsAppointmentDetailModels.stream().map(TmsAppointmentDetailModel::getShipbillId).distinct().collect(Collectors.toList()).toArray());

		criteria.setRestriction(r1);

		PageUtils.startPage(bookingItemDetailVO.getPageNum(), bookingItemDetailVO.getPageSize());
		List<TmsShipbillDetailModel> tmsShipbillDetailModels = tmsShipbillDetailMapper.findByCriteria(criteria);

		for (TmsShipbillDetailModel tmsShipbillDetailModel : tmsShipbillDetailModels) {
			BookingItemDetailDTO dto = new BookingItemDetailDTO();
			BeanUtils.copyProperties(tmsShipbillDetailModel, dto);

			// 数据字典翻译
			dto.setPackTypeName(PublicMethods.change(data1, String.valueOf(dto.getPackType())));
			dto.setCargoThermosphereName(PublicMethods.change(data2, String.valueOf(dto.getCargoThermosphere())));

			list.add(dto);
		}

		// 分页重组
		Page<BookingItemDetailDTO> page = PageUtils.getPage(list);
		if (tmsShipbillDetailModels instanceof com.github.pagehelper.Page) {
			com.github.pagehelper.Page<TmsShipbillDetailModel> p0 = (com.github.pagehelper.Page<TmsShipbillDetailModel>) tmsShipbillDetailModels;
			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 bookingPackageDetailVO
	 * @return
	 */
	@SuppressWarnings("resource")
	@Override
	public Page<BookingPackageDetailDTO> packageDetailData(BookingPackageDetailVO bookingPackageDetailVO) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");

		// 权限控制 仅支持自有账号操作
		if (!user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
			throw new PrologException("当前人员没有操作权限");
		}

		// 数据字典翻译数据集合
		List<Map<String, Object>> data1 = Lists.newArrayList();

		// 包裹类型
		RestMessage<List<Map<String, Object>>> restMessage1 = maindataTmsResource.getDropDownById(DataDictionaryConstant.PACKAGE_TYPE, null, null, null);
		if (!restMessage1.isSuccess()) {
			throw new RuntimeException("包裹类型翻译失败!");
		} else {
			data1 = restMessage1.getData();
		}

		// 查询预约单明细
		Criteria criteria = Criteria.forClass(TmsAppointmentDetailModel.class);
		Restriction r1 = Restrictions.eq("appointmentId", bookingPackageDetailVO.getAppointmentId());
		criteria.setRestriction(r1);

		List<TmsAppointmentDetailModel> tmsAppointmentDetailModels = tmsAppointmentDetailMapper.findByCriteria(criteria);

		// 根据运单ID查询明细数据
		criteria = Criteria.forClass(TmsShipbillPackageModel.class);
		r1 = Restrictions.in("shipbillId", tmsAppointmentDetailModels.stream().map(TmsAppointmentDetailModel::getShipbillId).distinct().collect(Collectors.toList()).toArray());

		criteria.setRestriction(r1);

		PageUtils.startPage(bookingPackageDetailVO.getPageNum(), bookingPackageDetailVO.getPageSize());
		List<TmsShipbillPackageModel> tmsShipbillPackageModels = tmsShipbillPackageMapper.findByCriteria(criteria);

		// 返回数据集
		List<BookingPackageDetailDTO> list = Lists.newArrayList();

		for (TmsShipbillPackageModel tmsShipbillPackageModel : tmsShipbillPackageModels) {
			BookingPackageDetailDTO dto = new BookingPackageDetailDTO();
			BeanUtils.copyProperties(tmsShipbillPackageModel, dto);

			// 数据字典翻译
			dto.setPackageTypeName(PublicMethods.change(data1, String.valueOf(dto.getPackageType())));

			// 设备类型翻译
			if (ToolKits.isNotEmpty(tmsShipbillPackageModel.getDeviceId())) {
				RestMessage<DeviceByOneDTO> deviceByOneDTORestMessage = maindataTmsResource.deviceGetOne(tmsShipbillPackageModel.getDeviceId());
				if (!deviceByOneDTORestMessage.isSuccess()) {
					throw new RuntimeException("获取设备失败!");
				}
				DeviceByOneDTO data = deviceByOneDTORestMessage.getData();
				ToolKits.isParamNull(data, "获取设备为空");

				dto.setDeviceTypeName(data.getTypeName());
			}

			list.add(dto);
		}

		// 分页重组
		Page<BookingPackageDetailDTO> page = PageUtils.getPage(list);
		if (tmsShipbillPackageModels instanceof com.github.pagehelper.Page) {
			com.github.pagehelper.Page<TmsShipbillPackageModel> p0 = (com.github.pagehelper.Page<TmsShipbillPackageModel>) tmsShipbillPackageModels;
			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 appointmentIds
	 */
	@Override
	public void reviewData(List<String> appointmentIds) {
		ToolKits.isParamNull(appointmentIds, "预约单ID不能为空");

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

		// 权限控制 仅支持自有账号操作
		if (!user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
			throw new PrologException("当前人员没有操作权限");
		}

		// 当前时间
		Date date = DateUtils.nowDate();

		// 查询预约单
		Criteria criteria = Criteria.forClass(TmsAppointmentHeaderModel.class);
		Restriction r1 = Restrictions.in("appointmentId", appointmentIds.toArray());
		criteria.setRestriction(r1);

		List<TmsAppointmentHeaderModel> tmsAppointmentHeaderModels = tmsAppointmentHeaderMapper.findByCriteria(criteria);

		ToolKits.isParamNull(tmsAppointmentHeaderModels, "未找到对应预约单!");

		// 获取是否有不为待审核的预约单
		List<TmsAppointmentHeaderModel> tmsAppointmentHeaderModelList = tmsAppointmentHeaderModels.stream().filter(o -> !DataDictionaryConstant.APPOINTMENT_STATUS_DSH.equals(o.getStatus())).collect(Collectors.toList());

		if (ToolKits.isNotEmpty(tmsAppointmentHeaderModelList)) {
			throw new PrologException("请勾选待审核的预约单审核!");
		}
		for (String appointmentId : appointmentIds) {
			// 预约单对象
			TmsAppointmentHeaderModel tmsAppointmentHeaderModel = tmsAppointmentHeaderModels.stream().filter(item -> item.getAppointmentId().equals(appointmentId)).findAny().orElse(null);

			// 查询预约单明细
			Criteria criteriaAppointment = Criteria.forClass(TmsAppointmentDetailModel.class);
			Restriction appointment = Restrictions.eq(TmsAppointmentDetailModel::getAppointmentId, appointmentId);
			criteriaAppointment.setRestriction(appointment);
			List<TmsAppointmentDetailModel> tmsAppointmentDetailModels = tmsAppointmentDetailMapper.findByCriteria(criteriaAppointment);

			boolean tallyStatus = false;
			boolean hasLoading = false;
			boolean hasTakeNumAndCallNum = false;
			Criteria criteriaLoadingBillDetail = Criteria.forClass(TmsLoadingBillDetailModel.class);
			for (TmsAppointmentDetailModel detailModel : tmsAppointmentDetailModels) {
				if (ToolKits.isNotEmpty(detailModel.getFlowConfig())
						&& detailModel.getFlowConfig().contains(DataDictionaryConstant.FLOW_CONFIG_APPOINTMENT_TN_CN)) {
					hasTakeNumAndCallNum = true;
				}
				int nextStatus = DataDictionaryConstant.SHIPBILL_STATUS_APP_ING;
				if (ToolKits.isNotEmpty(detailModel.getFlowConfig()) && detailModel.getFlowConfig().contains(DataDictionaryConstant.FLOW_CONFIG_ARRANGE_GOODS)) {
					tallyStatus = true;
					nextStatus = DataDictionaryConstant.SHIPBILL_STATUS_LH_START;
				}
				if (ToolKits.isNotEmpty(detailModel.getFlowConfig()) && detailModel.getFlowConfig().contains(DataDictionaryConstant.FLOW_CONFIG_LOAD_UNLOAD)) {
					hasLoading = true;
				}
				int flowStatus = businessFlowUtil.judgmentNextFlowSts(detailModel.getFlowConfig(), DataDictionaryConstant.FLOW_CONFIG_APPOINTMENT);
				if (hasTakeNumAndCallNum &&
						NumberUtil.isGreater(BigDecimal.valueOf(flowStatus),BigDecimal.valueOf(DataDictionaryConstant.SHIPBILL_STATUS_ZX_START))) {
					nextStatus = flowStatus;
				} else if (!hasTakeNumAndCallNum ) {
					nextStatus = flowStatus;
				}

				Map<String, Object> mapAppointmentDetail = Maps.newHashMap();
				mapAppointmentDetail.put("updatetime", date);
				mapAppointmentDetail.put("updateperson", user.getNickname());

				Map<String, Object> mapShipbillHead = Maps.newHashMap();
				mapShipbillHead.put("updatetime", date);
				mapShipbillHead.put("updateperson", user.getNickname());

				// 判断预计提货时间是否为空
				if (ToolKits.isEmpty(detailModel.getEstimatedPickupStartTime())) {
					// 预约日期
					Date appointmentDate = tmsAppointmentHeaderModel.getAppointmentDate();
					// 预约时间段
					String appointmentTime = tmsAppointmentHeaderModel.getAppointmentTime();

					// 更新预约明细信息
					mapAppointmentDetail.put("estimatedPickupStartTime", DateUtil.parseDateTime(DateUtil.formatDate(appointmentDate) + " " + appointmentTime.split("-")[0] + ":00"));
					mapAppointmentDetail.put("estimatedPickupEndTime", DateUtil.parseDateTime(DateUtil.formatDate(appointmentDate) + " " + appointmentTime.split("-")[1] + ":00"));

					// 更新运单信息
					mapShipbillHead.put("estimatedPickupStartTime", DateUtil.parseDateTime(DateUtil.formatDate(appointmentDate) + " " + appointmentTime.split("-")[0] + ":00"));
					mapShipbillHead.put("estimatedPickupEndTime", DateUtil.parseDateTime(DateUtil.formatDate(appointmentDate) + " " + appointmentTime.split("-")[1] + ":00"));
				}
				mapAppointmentDetail.put("status", nextStatus);
				tmsAppointmentDetailMapper.updateMapById(detailModel.getId(), mapAppointmentDetail, TmsAppointmentDetailModel.class);

				mapShipbillHead.put("status", nextStatus);
				tmsShipbillHeaderMapper.updateMapById(detailModel.getShipbillId(), mapShipbillHead, TmsShipbillHeaderModel.class);

				// 更新装车单明细
				Restriction r3 = Restrictions.eq(TmsLoadingBillDetailModel::getShipbillId, detailModel.getShipbillId());
				Restriction r4 = Restrictions.eq(TmsLoadingBillDetailModel::getEnterpriseId, user.getEnterpriseId());
				criteriaLoadingBillDetail.setRestriction(Restrictions.and(r3, r4));
				criteriaLoadingBillDetail.setOrder(Order.newInstance().desc(new String[] { "createtime" }));
				List<TmsLoadingBillDetailModel> tmsLoadingBillDetails = tmsLoadingBillDetailMapper.findByCriteria(criteriaLoadingBillDetail);

				if (ToolKits.isEmpty(tmsLoadingBillDetails)) {
					throw new PrologException("运单【" + detailModel.getShipbillId() + "】查询失败");
				}
				TmsLoadingBillDetailModel billDetailModel = tmsLoadingBillDetails.get(0);
				billDetailModel.setStatus(nextStatus);
				billDetailModel.setUpdateperson(user.getNickname());
				billDetailModel.setUpdatetime(date);
				tmsLoadingBillDetailMapper.update(billDetailModel);

				// 日志表
				ShipbillOperateLogSaveVO shipbillOperateLogSaveVO = new ShipbillOperateLogSaveVO();
				shipbillOperateLogSaveVO.setShipbillId(detailModel.getShipbillId());
				shipbillOperateLogSaveVO.setShipbillNo(detailModel.getShipbillNo());
				shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.SHIPBILL_STATUSNAME_YYSH);
				shipbillOperateLogSaveVO.setOldStatus(detailModel.getStatus());
				shipbillOperateLogSaveVO.setNewStatus(nextStatus);
				shipbillOperateLogService.addShipbillOperateLogData(shipbillOperateLogSaveVO);
			}

			Map<String, Object> map = Maps.newHashMap();
			if (!hasTakeNumAndCallNum) {
				if (tallyStatus) {
					map.put("status", DataDictionaryConstant.APPOINTMENT_STATUS_DLH);
				} else if (hasLoading) {
					map.put("status", DataDictionaryConstant.APPOINTMENT_STATUS_DZX);
				} else {
					map.put("status", DataDictionaryConstant.APPOINTMENT_STATUS_ZXWC);
				}
			} else {
				if (!hasLoading && !tallyStatus) {
					map.put("status", DataDictionaryConstant.APPOINTMENT_STATUS_ZXWC);
				} else {
					map.put("status", DataDictionaryConstant.APPOINTMENT_STATUS_YSH);
				}
			}
			map.put("updatetime", date);
			map.put("updateperson", user.getNickname());

			if (tallyStatus) {
				map.put("tallyStatus", DataDictionaryConstant.TALLY_STATUS_WLH);
			} else {
				map.put("tallyStatus", DataDictionaryConstant.TALLY_STATUS_LHWC);
			}
			// 修改预约单
			tmsAppointmentHeaderMapper.updateMapById(appointmentId, map, TmsAppointmentHeaderModel.class);
			MessageUtil.addMessage(new SendMessageDTO(MessageOrderTypeEnum.APPOINTMENT_NO.getCode(), MessageTypeEnum.APPOINTMENT_AUDIT.getCode(), Lists.newArrayList(appointmentId)));
		}
	}

	/**
	 * 预约单取消
	 *
	 * @param appointmentIds
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void cancelData(List<String> appointmentIds) {
		ToolKits.isParamNull(appointmentIds, "预约单ID不能为空");

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

		// 权限控制 仅支持自有账号操作
//		if (!user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
//			throw new PrologException("当前人员没有操作权限");
//		}

		// 当前时间
		Date date = DateUtils.nowDate();

		// 查询预约单
		Criteria criteria = Criteria.forClass(TmsAppointmentHeaderModel.class);
		Restriction r1 = Restrictions.in("appointmentId", appointmentIds.toArray());
		Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
		criteria.setRestriction(Restrictions.and(r1, r2));
		List<TmsAppointmentHeaderModel> tmsAppointmentHeaderModels = tmsAppointmentHeaderMapper.findByCriteria(criteria);
		ToolKits.isParamNull(tmsAppointmentHeaderModels, "未找到对应预约单!");

		for (TmsAppointmentHeaderModel tmsAppointmentHeader : tmsAppointmentHeaderModels) {
			TmsBaseBranchDTO data = null;
			Integer notCancelDura = null;
			RestMessage<TmsBaseBranchDTO> msg = maindataTmsResource.getOneBranch(tmsAppointmentHeader.getBranchId());
			if (!msg.isSuccess()) {
				throw new PrologException("仓库资料查询失败");
			} else {
				data = msg.getData();
				notCancelDura = data.getAptCanNotCancelDura();// 不可取消的时间范围(小时)
				if (ToolKits.isEmpty(notCancelDura)) {
					continue;
				} else {
					AppointTimeQueryVO appointTimeQueryVO = new AppointTimeQueryVO();
					appointTimeQueryVO.setBranchId(data.getId());
					RestMessage<List<TmsBaseBranchApTimeDTO>> msg2 = maindataTmsResource.queryAppointTime(appointTimeQueryVO);
					if (!msg2.isSuccess()) {
						throw new PrologException("仓库可预约时间段查询失败");
					} else {
						SimpleDateFormat sdf = new SimpleDateFormat();
						sdf.applyPattern("yyyy-MM-dd HH:mm");
						String now = sdf.format(new Date());

						SimpleDateFormat sdf2 = new SimpleDateFormat();
						sdf2.applyPattern("yyyy-MM-dd");
						String now2 = sdf2.format(new Date());

						if (ObjectUtil.notEqual(sdf2.format(tmsAppointmentHeader.getAppointmentDate()), now2)) {
							continue;
						}

						List<TmsBaseBranchApTimeDTO> aptTimes = msg2.getData();
						for (TmsBaseBranchApTimeDTO tmsBaseBranchApTime : aptTimes) {
							// 判断当前时间是否在当前仓库的不可取消范围内
							String appointmentTime = tmsBaseBranchApTime.getStartTime() + "-" + tmsBaseBranchApTime.getEndTime();
							String startHourStr = appointmentTime.split("-")[0].split(":")[0];
							String startMinStr = appointmentTime.split("-")[0].split(":")[1];

							Integer startHour = Integer.parseInt(startHourStr);
							Integer notCancelHour = startHour - notCancelDura;

							Boolean b = false;
							if (notCancelHour < 0) {
								notCancelHour = 24 + notCancelHour;
								b = true;
							}

							String notCancelTime = null;
							if (b) {// 年月日减去一天
								notCancelTime = sdf2.format(new Date(new Date().getTime() - 24 * 60 * 60 * 1000)) + " " + (notCancelHour < 10 ? "0" + String.valueOf(notCancelHour) : String.valueOf(notCancelHour)) + ":" + startMinStr;
							} else {
								notCancelTime = now2 + " " + (notCancelHour < 10 ? "0" + String.valueOf(notCancelHour) : String.valueOf(notCancelHour)) + ":" + startMinStr;
							}

							int compareTo = now.compareTo(notCancelTime);
							String startTime = now2 + " " + startHourStr + ":" + startMinStr;
							int compareTo2 = now.compareTo(startTime);
							if (compareTo > 0 && compareTo2 <= 0) {
								throw new PrologException("预约单【" + tmsAppointmentHeader.getReserveNumber() + "】不可取消,当前时间已进入该预约单的仓库不可取消预约时间段范围内(" + notCancelTime + "至" + startTime + ")");
							}
						}
					}
				}
			}
		}

		// 获取是否有不为待审核的预约单
		List<TmsAppointmentHeaderModel> tmsAppointmentHeaderModelList = tmsAppointmentHeaderModels.stream().filter(o -> !DataDictionaryConstant.APPOINTMENT_STATUS_DSH.equals(o.getStatus())).collect(Collectors.toList());
		if (ToolKits.isNotEmpty(tmsAppointmentHeaderModelList)) {
			throw new PrologException("请勾选待审核的预约单审核!");
		}

		// 查询预约明细
		Criteria appointmentDetail = Criteria.forClass(TmsAppointmentDetailModel.class);
		Restriction r11 = Restrictions.in("appointmentId", appointmentIds.toArray());
		Restriction r12 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
		appointmentDetail.setRestriction(Restrictions.and(r11, r12));
		List<TmsAppointmentDetailModel> tmsAppointmentDetailModels = tmsAppointmentDetailMapper.findByCriteria(appointmentDetail);
		if (ToolKits.isNotEmpty(tmsAppointmentDetailModels)) {
			// 获取运单id
			List<String> shipbillIds = tmsAppointmentDetailModels.stream().filter(o -> ToolKits.isNotEmpty(o.getShipbillId())).map(TmsAppointmentDetailModel::getShipbillId).collect(Collectors.toList());

			// 封装修改数据集
			Map<String, Object> map = Maps.newHashMap();
			map.put("status", DataDictionaryConstant.SHIPBILL_STATUS_PENDING_APP);
			map.put("updatetime", date);
			map.put("updateperson", user.getNickname());

			// 修改运单状态
			Criteria shipbillHeader = Criteria.forClass(TmsShipbillHeaderModel.class);
			Restriction shipbillId = Restrictions.in("shipbillId", shipbillIds.toArray());
			shipbillHeader.setRestriction(shipbillId);
			tmsShipbillHeaderMapper.updateMapByCriteria(map, shipbillHeader);

			Criteria criteriaLoadingBillDetail = Criteria.forClass(TmsLoadingBillDetailModel.class);
			// 运单日志添加
			for (String id : shipbillIds) {
				// 更新装车单明细
				Restriction r3 = Restrictions.eq(TmsLoadingBillDetailModel::getShipbillId, id);
				Restriction r4 = Restrictions.eq(TmsLoadingBillDetailModel::getEnterpriseId, user.getEnterpriseId());
				criteriaLoadingBillDetail.setRestriction(Restrictions.and(r3, r4));
				criteriaLoadingBillDetail.setOrder(Order.newInstance().desc(new String[] { "createtime" }));
				List<TmsLoadingBillDetailModel> tmsLoadingBillDetails = tmsLoadingBillDetailMapper.findByCriteria(criteriaLoadingBillDetail);

				if (ToolKits.isEmpty(tmsLoadingBillDetails)) {
					throw new PrologException("运单【" + id + "】查询失败");
				}
				TmsLoadingBillDetailModel billDetailModel = tmsLoadingBillDetails.get(0);
				billDetailModel.setStatus(DataDictionaryConstant.SHIPBILL_STATUS_PENDING_APP);
				billDetailModel.setUpdateperson(user.getNickname());
				billDetailModel.setUpdatetime(date);
				tmsLoadingBillDetailMapper.update(billDetailModel);

				// 运单操作日志保存
				ShipbillOperateLogSaveNewVO shipbillOperateLogSaveNewVO = new ShipbillOperateLogSaveNewVO();
				shipbillOperateLogSaveNewVO.setShipbillId(id);
				shipbillOperateLogSaveNewVO.setShipbillNo(id);
				shipbillOperateLogSaveNewVO.setOperateDate(date);
				shipbillOperateLogSaveNewVO.setEnterpriseId(user.getEnterpriseId());
				shipbillOperateLogSaveNewVO.setEnterpriseName(user.getEnterpriseName());
				shipbillOperateLogSaveNewVO.setUserId(user.getUserid());
				shipbillOperateLogSaveNewVO.setUserName(user.getNickname());
				shipbillOperateLogSaveNewVO.setOperateEvent(DataDictionaryConstant.SHIPBILL_STATUSNAME_YYQX);
				shipbillOperateLogSaveNewVO.setOldStatus(DataDictionaryConstant.SHIPBILL_STATUS_PENDING_APP);
				shipbillOperateLogSaveNewVO.setNewStatus(DataDictionaryConstant.SHIPBILL_STATUS_PENDING_APP);
				shipbillOperateLogService.addShipbillOperateLogNewData(shipbillOperateLogSaveNewVO);
			}
		}

		// 封装修改参数
		Map<String, Object> map = Maps.newHashMap();
		map.put("status", DataDictionaryConstant.APPOINTMENT_STATUS_QX);
		map.put("updatetime", date);
		map.put("updateperson", user.getNickname());
		// 取消预约单
		tmsAppointmentHeaderMapper.updateMapByCriteria(map, criteria);
		// 取消预约单明细
		tmsAppointmentDetailMapper.updateMapByCriteria(map, appointmentDetail);
	}

	public void cancelAppointment(List<String> shipbillIds) {
		ToolKits.isParamNull(shipbillIds, "运单ID不能为空");

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

		Criteria appointmentDetail = Criteria.forClass(TmsAppointmentDetailModel.class);
		Restriction r1 = Restrictions.in(TmsAppointmentDetailModel::getShipbillId, shipbillIds);
		Restriction r3 = Restrictions.eq(TmsAppointmentDetailModel::getEnterpriseId, user.getEnterpriseId());
		appointmentDetail.setRestriction(Restrictions.and(r1,r3));
		List<TmsAppointmentDetailModel> appointmentDetailModels = tmsAppointmentDetailMapper.findByCriteria(appointmentDetail);
		if (ToolKits.isEmpty(appointmentDetailModels)) {
			return;
		}
		Map<String, List<TmsAppointmentDetailModel>> appointmentGroupmap = Maps.newHashMap();
		appointmentGroupmap = appointmentDetailModels.stream().collect(Collectors.groupingBy(o -> o.getAppointmentId()));

		Map<String, Object> map = Maps.newHashMap();
		map.put("status", DataDictionaryConstant.APPOINTMENT_STATUS_QX);
		map.put("updatetime", DateUtil.date());
		map.put("updateperson", user.getNickname());

		for (String id:appointmentGroupmap.keySet()) {
			List<TmsAppointmentDetailModel> oneAppointmentDetailModels = appointmentGroupmap.get(id);
			r1 = Restrictions.in(TmsAppointmentDetailModel::getId, oneAppointmentDetailModels.stream().map(TmsAppointmentDetailModel::getId).collect(Collectors.toList()));
			appointmentDetail.setRestriction(Restrictions.and(r1));
			tmsAppointmentDetailMapper.deleteByCriteria(appointmentDetail);

			r1 = Restrictions.notIn(TmsAppointmentDetailModel::getId, oneAppointmentDetailModels.stream().map(TmsAppointmentDetailModel::getId).collect(Collectors.toList()));
			r3 = Restrictions.eq(TmsAppointmentDetailModel::getAppointmentId, id);
			appointmentDetail.setRestriction(Restrictions.and(r1,r3));
			List<TmsAppointmentDetailModel> otherAppointmentDetailModels = tmsAppointmentDetailMapper.findByCriteria(appointmentDetail);
			if (ToolKits.isEmpty(otherAppointmentDetailModels)) {
				tmsAppointmentHeaderMapper.updateMapById(id,map,TmsAppointmentHeaderModel.class);
			} else {
				TmsAppointmentHeaderModel appointmentHeaderModel = tmsAppointmentHeaderMapper.findById(id,TmsAppointmentHeaderModel.class);

				if (ToolKits.isEmpty(appointmentHeaderModel)) {
					continue;
				}
				appointmentHeaderModel.setUrgentQuantity(otherAppointmentDetailModels.stream().filter(d->!DataDictionaryConstant.ORDER_TYPE_P.equals(d.getOrderType())).collect(Collectors.toList()).size());
				appointmentHeaderModel.setShipbillQuantity(otherAppointmentDetailModels.size());
				appointmentHeaderModel.setTotalPcs(otherAppointmentDetailModels.stream().filter(d->ToolKits.isNotEmpty(d.getTotalPcs())).map(TmsAppointmentDetailModel::getTotalPcs).reduce(BigDecimal.ZERO,NumberUtil::add));
				appointmentHeaderModel.setTotalWeight(otherAppointmentDetailModels.stream().filter(d->ToolKits.isNotEmpty(d.getTotalWeight())).map(TmsAppointmentDetailModel::getTotalWeight).reduce(BigDecimal.ZERO,NumberUtil::add));
				appointmentHeaderModel.setTotalVolume(otherAppointmentDetailModels.stream().filter(d->ToolKits.isNotEmpty(d.getTotalVolume())).map(TmsAppointmentDetailModel::getTotalVolume).reduce(BigDecimal.ZERO,NumberUtil::add));
				appointmentHeaderModel.setUpdatetime(DateUtil.date());
				appointmentHeaderModel.setUpdateperson(user.getNickname());
				tmsAppointmentHeaderMapper.update(appointmentHeaderModel);
			}
		}
	}

}