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

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

import cn.hutool.core.util.StrUtil;
import com.prolog.rdc.tms.app.util.DataUtils;
import com.prolog.rdc.tms.app.util.MessageUtil;
import com.prolog.rdc.tms.app.util.StrategyUtil;
import com.prolog.rdc.tms.model.dto.basicConfigure.ShipbillMatchLineDTO;
import com.prolog.rdc.tms.model.dto.message.SendMessageDTO;
import com.prolog.rdc.tms.model.enums.MessageOrderTypeEnum;
import com.prolog.rdc.tms.model.enums.MessageTypeEnum;
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.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.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.TmsShipbillDetailTempMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsShipbillHeaderMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsShipbillHeaderTempMapper;
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.PendingSubmitQueryDTO;
import com.prolog.rdc.tms.app.model.dto.business.PendingSubmitQueryItemDTO;
import com.prolog.rdc.tms.app.model.dto.business.PendingSubmitQueryPackageDTO;
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.TmsShipbillDetailTempModel;
import com.prolog.rdc.tms.app.model.entity.TmsShipbillHeaderModel;
import com.prolog.rdc.tms.app.model.entity.TmsShipbillHeaderTempModel;
import com.prolog.rdc.tms.app.model.entity.TmsShipbillPackageModel;
import com.prolog.rdc.tms.app.model.entity.TmsShipbillTransLogModel;
import com.prolog.rdc.tms.app.model.vo.business.PendingSubmitQueryVO;
import com.prolog.rdc.tms.app.model.vo.business.ShipbillNodeTrackingSaveNewVO;
import com.prolog.rdc.tms.app.model.vo.business.ShipbillOperateLogSaveNewVO;
import com.prolog.rdc.tms.app.model.vo.business.ShipbillOperateLogSaveVO;
import com.prolog.rdc.tms.app.service.business.PendingReviewService;
import com.prolog.rdc.tms.app.service.business.PendingSubmitService;
import com.prolog.rdc.tms.app.service.business.ShipbillNodeTrackingService;
import com.prolog.rdc.tms.app.service.business.ShipbillOperateLogService;
import com.prolog.rdc.tms.app.util.PublicMethods;
import com.prolog.rdc.tms.model.dto.VehicleCheckDTO;
import com.prolog.rdc.tms.model.vo.basicConfigure.ApprovalOpenVO;
import com.prolog.rdc.tms.model.vo.fleetManagement.VehicleCheckVO;
import com.prolog.rdc.tms.rmi.feign.MaindataFeign;

import cn.hutool.core.date.DateUtil;

/**
 * Company: 湖北普罗格科技股份有限公司
 *
 * @author zhangsj
 * @since 2022/7/20 16:00
 */
@Service
public class PendingSubmitServiceImpl implements PendingSubmitService {

	@Autowired
	private TmsShipbillHeaderMapper tmsShipbillHeaderMapper;

	@Autowired
	private MaindataFeign maindataTmsResource;

	@Autowired
	private TmsShipbillDetailMapper tmsShipbillDetailMapper;

	@Autowired
	private TmsShipbillPackageMapper tmsShipbillPackageMapper;

	@Autowired
	private ShipbillOperateLogService shipbillOperateLogService;

	@Autowired
	private ShipbillNodeTrackingService shipbillNodeTrackingService;

	@Autowired
	private TmsShipbillHeaderTempMapper tmsShipbillHeaderTempMapper;

	@Autowired
	private TmsShipbillDetailTempMapper tmsShipbillDetailTempMapper;

	@Autowired
	private TmsLoadingBillDetailMapper tmsLoadingBillDetailMapper;

	@Autowired
	private TmsLoadingBillHeaderMapper tmsLoadingBillHeaderMapper;

	@Autowired
	private PendingReviewService pendingReviewService;

	@Autowired
	private TmsShipbillTransportLogMapper tmsShipbillTransportLogMapper;

	@Autowired
	private StrategyUtil strategyUtil;

	/**
	 * 查询运单
	 *
	 * @return
	 */
	@SuppressWarnings("resource")
	@Override
	public Page<PendingSubmitQueryDTO> queryShipbillData(PendingSubmitQueryVO pendingSubmitQueryVO) {
		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");
		ToolKits.isParamNull(pendingSubmitQueryVO.getPageNum(), "当前页码不为空");
		ToolKits.isParamNull(pendingSubmitQueryVO.getPageSize(), "每页条数不为空");

		// 数据字典翻译数据集合

		List<Map<String, Object>> data6 = Lists.newArrayList();
		List<Map<String, Object>> data7 = Lists.newArrayList();
		List<Map<String, Object>> data8 = Lists.newArrayList();
		List<Map<String, Object>> data9 = Lists.newArrayList();

		// 发货方类型
		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();
		}

		// 运单状态
		RestMessage<List<Map<String, Object>>> restMessage8 = maindataTmsResource.getDropDownById(DataDictionaryConstant.SHIPBILL_STATUS, null, null, null);
		if (!restMessage8.isSuccess()) {
			throw new RuntimeException("运单状态翻译失败!");
		} else {
			data8 = restMessage8.getData();
		}

		// 承运商运单状态
		RestMessage<List<Map<String, Object>>> restMessage9 = maindataTmsResource.getDropDownById(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS, null, null, null);
		if (!restMessage9.isSuccess()) {
			throw new RuntimeException("承运商运单状态翻译失败!");
		} else {
			data9 = restMessage9.getData();
		}

		// 添加查询条件
		Criteria criteria = Criteria.forClass(TmsShipbillHeaderModel.class);

		Restriction r1 = Restrictions.eq("enterpriseId", user.getEnterpriseId());

		// 权限控制
		Restriction r2 = null;
		Restriction r3 = null;
		Restriction r4 = null;
		Restriction r5 = null;
		Restriction r6 = null;
		Restriction r7 = null;
		Restriction r8 = null;
		Restriction r29 = null;
		// 判断账号类型
		if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
			// 自有账号
			// 拆单状态 0未拆单
			Restriction r30 = Restrictions.eq("splitOrderStatus", DataDictionaryConstant.SPLIT_ORDER_STATUS_UN);
			// 承运商拆单类型 1未拆单
			Restriction r31 = Restrictions.eq("carrierSplitOrderType", DataDictionaryConstant.CARRIER_SPLIT_ORDER_TYPE_UN);
			Restriction r32 = Restrictions.and(r30, r31);
			// 承运商拆单类型 2拆分主单
			Restriction r33 = Restrictions.eq("carrierSplitOrderType", DataDictionaryConstant.CARRIER_SPLIT_ORDER_TYPE_SPLIT_MASTER);
			// 承运商拆单类型 2中转主单
			Restriction r34 = Restrictions.eq("carrierSplitOrderType", DataDictionaryConstant.CARRIER_SPLIT_ORDER_TYPE_TRANSIT_MASTER);
			r29 = Restrictions.or(r32, r33, r34);

			// 判断是否为部门权限
			r2 = Restrictions.in("status", new Integer[] { DataDictionaryConstant.SHIPBILL_STATUS_CSH, DataDictionaryConstant.SHIPBILL_STATUS_YTH });
			if (user.getOwnedAllDataAuthFlag().equals(BussinessConstant.USER_DEPARTMENT_AUTH_Y)) {
				r3 = Restrictions.in("departmentId", user.getDepts().stream().toArray(String[]::new));
			} else {
				r3 = Restrictions.in("departmentId", user.getDepts().stream().toArray(String[]::new));
				// 其它权限
				// 货主
				r4 = Restrictions.in("cargoOwnerId", user.getConsignors().toArray());
				// 客户
				r5 = Restrictions.in("consigneeUnitId", user.getCustomers().toArray());
				// 供应商
				r6 = Restrictions.in("consigneeUnitId", user.getSuppliers().toArray());
				// 仓库
				r7 = Restrictions.in("consigneeUnitId", user.getWarehouses().toArray());

				Restriction r15 = Restrictions.in(TmsShipbillHeaderModel::getShipperUnitId, user.getWarehouses().stream().toArray(Long[]::new));
				Restriction r16 = Restrictions.in(TmsShipbillHeaderModel::getShipperUnitId, user.getSuppliers().stream().toArray(Long[]::new));
				Restriction r17 = Restrictions.in(TmsShipbillHeaderModel::getShipperUnitId, user.getCustomers().stream().toArray(Long[]::new));

				r8 = Restrictions.or(r5, r6, r7,r15,r16,r17);
			}
		} else if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
			// 运单状态
			r2 = Restrictions.in("status", new Integer[] { DataDictionaryConstant.SHIPBILL_STATUS_DISPATCH_CHECK, DataDictionaryConstant.SHIPBILL_STATUS_CONSIGNMENT_HANDOVER });
			// 承运商账号
			r3 = Restrictions.eq("carrierId", Long.valueOf(user.getLoginUserCompanyInfo().getId()));
			// 承运商运单状态
			r8 = Restrictions.in("carrierShipbillStatus", new Integer[] { DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_ROLLBACK, DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_WAIT_RECEIVE, DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_RECEIVED });
			r29 = Restrictions.eq("carrierSplitOrderStatus", DataDictionaryConstant.CARRIER_SPLIT_ORDER_STATUS_UN);
		} else {
			throw new BizException("当前人员没有操作权限！");
		}

		Restriction r9 = ToolKits.isEmpty(pendingSubmitQueryVO.getOrderBusinessType()) ? null : Restrictions.eq(TmsShipbillHeaderModel::getOrderBusinessType, pendingSubmitQueryVO.getOrderBusinessType());
		Restriction r10 = ToolKits.isEmpty(pendingSubmitQueryVO.getCreateStartTime()) ? null : Restrictions.ge(TmsShipbillHeaderModel::getCreatetime, pendingSubmitQueryVO.getCreateStartTime());
		Restriction r11 = ToolKits.isEmpty(pendingSubmitQueryVO.getCreateEndTime()) ? null : Restrictions.le(TmsShipbillHeaderModel::getCreatetime, pendingSubmitQueryVO.getCreateEndTime());
		Restriction r12 = ToolKits.isEmpty(pendingSubmitQueryVO.getLineName()) ? null : Restrictions.like(TmsShipbillHeaderModel::getLineName, "%" + pendingSubmitQueryVO.getLineName() + "%");
		Restriction r13 = ToolKits.isEmpty(pendingSubmitQueryVO.getEstimatedPickupStartTime()) ? null : Restrictions.ge(TmsShipbillHeaderModel::getEstimatedPickupStartTime, pendingSubmitQueryVO.getEstimatedPickupStartTime());
		Restriction r14 = ToolKits.isEmpty(pendingSubmitQueryVO.getEstimatedPickupEndTime()) ? null : Restrictions.le(TmsShipbillHeaderModel::getEstimatedPickupStartTime, pendingSubmitQueryVO.getEstimatedPickupEndTime());
		Restriction r15 = null;
		if (ToolKits.isNotEmpty(pendingSubmitQueryVO.getCustomerName())) {
			Restriction rr1 = Restrictions.like(TmsShipbillHeaderModel::getShipperUnitName, "%" + pendingSubmitQueryVO.getCustomerName() + "%");
			Restriction rr2 = Restrictions.like(TmsShipbillHeaderModel::getConsigneeUnitName, "%" + pendingSubmitQueryVO.getCustomerName() + "%");
			r15 = Restrictions.or(rr1, rr2);
		}
		Restriction r16 = null;
		if (ToolKits.isNotEmpty(pendingSubmitQueryVO.getShipperLocation())) {
			Restriction rr1 = Restrictions.like(TmsShipbillHeaderModel::getShipperProvinceName, "%" + pendingSubmitQueryVO.getShipperLocation() + "%");
			Restriction rr2 = Restrictions.like(TmsShipbillHeaderModel::getShipperCityName, "%" + pendingSubmitQueryVO.getShipperLocation() + "%");
			Restriction rr3 = Restrictions.like(TmsShipbillHeaderModel::getShipperDistrictName, "%" + pendingSubmitQueryVO.getShipperLocation() + "%");
			r16 = Restrictions.or(rr1, rr2, rr3);
		}
		Restriction r17 = null;
		if (ToolKits.isNotEmpty(pendingSubmitQueryVO.getConsigneeLocation())) {
			Restriction rr1 = Restrictions.like(TmsShipbillHeaderModel::getConsigneeProvinceName, "%" + pendingSubmitQueryVO.getConsigneeLocation() + "%");
			Restriction rr2 = Restrictions.like(TmsShipbillHeaderModel::getConsigneeCityName, "%" + pendingSubmitQueryVO.getConsigneeLocation() + "%");
			Restriction rr3 = Restrictions.like(TmsShipbillHeaderModel::getConsigneeDistrictName, "%" + pendingSubmitQueryVO.getConsigneeLocation() + "%");
			r17 = Restrictions.or(rr1, rr2, rr3);
		}

		criteria.setRestriction(Restrictions.and(r1, r2, r3, r4, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r29));
		criteria.setOrder(Order.newInstance().desc(new String[] { "updatetime" }));

		PageUtils.startPage(pendingSubmitQueryVO.getPageNum(), pendingSubmitQueryVO.getPageSize());
		List<TmsShipbillHeaderModel> tmsShipbillHeaderModels = tmsShipbillHeaderMapper.findByCriteria(criteria);

		List<PendingSubmitQueryDTO> list = Lists.newArrayList();
		for (TmsShipbillHeaderModel model : tmsShipbillHeaderModels) {
			PendingSubmitQueryDTO dto = new PendingSubmitQueryDTO();
			BeanUtils.copyProperties(model, dto);

			// 类型翻译
			dto.setShipperTypeName(PublicMethods.change(data6, String.valueOf(dto.getShipperType())));
			dto.setConsigneeTypeName(PublicMethods.change(data7, String.valueOf(dto.getConsigneeType())));
			if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
				dto.setStatus(model.getCarrierShipbillStatus());
				dto.setStatusName(PublicMethods.change(data9, String.valueOf(model.getCarrierShipbillStatus())));
			} else {
				dto.setStatusName(PublicMethods.change(data8, String.valueOf(dto.getStatus())));
			}

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

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

			if (ToolKits.isNotEmpty(tmsShipbillPackageModels)) {
				List<PendingSubmitQueryPackageDTO> packageDTOList = Lists.newArrayList();
				for (TmsShipbillPackageModel packageModel : tmsShipbillPackageModels) {
					PendingSubmitQueryPackageDTO packageDTO = new PendingSubmitQueryPackageDTO();
					BeanUtils.copyProperties(packageModel, packageDTO);
					packageDTOList.add(packageDTO);
				}
				dto.setPendingSubmitQueryPackageDTOS(packageDTOList);
				list.add(dto);
				continue;
			}

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

			List<PendingSubmitQueryItemDTO> itemDTOList = Lists.newArrayList();
			for (TmsShipbillDetailModel detailModel : tmsShipbillDetailModels) {
				PendingSubmitQueryItemDTO itemDTO = new PendingSubmitQueryItemDTO();
				BeanUtils.copyProperties(detailModel, itemDTO);
				itemDTOList.add(itemDTO);
			}
			// 商品信息
			dto.setPendingSubmitQueryDetailDTOS(itemDTOList);

			list.add(dto);
		}

		// 分页重组
		Page<PendingSubmitQueryDTO> page = PageUtils.getPage(list);
		if (tmsShipbillHeaderModels instanceof com.github.pagehelper.Page) {
			com.github.pagehelper.Page<TmsShipbillHeaderModel> p0 = (com.github.pagehelper.Page<TmsShipbillHeaderModel>) tmsShipbillHeaderModels;
			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 receiveShipbillData(List<String> ids) {
		ToolKits.isParamNull(ids, "运单接单请求不为空");
		Assert.isTrue(ids.size() > 0, "运单接单请求不为空");

		UserEntity user = PlgFxUsrUtils.getUserEntity();
		ToolKits.isParamNull(user, "当前人员没有操作权限");
//        Assert.isTrue(user.getUserType().equals(BussinessConstant.USER_TYPE_CYS), "当前人员没有操作权限");
		// 当前时间
		Date date = DateUtil.date();
		List<String> commitObjs = Lists.newArrayList();
		for (String id : ids) {
			ToolKits.isParamNull(id, "运单ID不为空");
			// 更新
			TmsShipbillHeaderModel tmsShipbillHeaderModel = tmsShipbillHeaderMapper.findById(id, TmsShipbillHeaderModel.class);
			if (!tmsShipbillHeaderModel.getCarrierShipbillStatus().equals(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_WAIT_RECEIVE)){
				throw new PrologException("运单【" + 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 (ToolKits.isNotEmpty(tmsShipbillHeaderModel.getCarrierFlowConfig()) && 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);
			} catch (Exception e) {
				throw new PrologException("运单保存自动提交处理失败", e);
			}
		}
	}

	/**
	 * 运单拒绝
	 *
	 * @param ids
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void rejectShipbillData(List<String> ids) {
		ToolKits.isParamNull(ids, "运单拒绝请求不为空");
		Assert.isTrue(ids.size() > 0, "运单拒绝请求不为空");

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

		// 当前时间
		Date date = DateUtil.date();
		for (String id : ids) {
			// 更新
			TmsShipbillHeaderModel tmsShipbillHeaderModel = tmsShipbillHeaderMapper.findById(id, TmsShipbillHeaderModel.class);

			if (!tmsShipbillHeaderModel.getCarrierShipbillStatus().equals(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_WAIT_RECEIVE)
					&& !tmsShipbillHeaderModel.getCarrierShipbillStatus().equals(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_ROLLBACK)){
				throw new PrologException("运单【" + id + "】不能拒绝!");
			}
			// 运单状态更新
			tmsShipbillHeaderModel.setCarrierShipbillStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_REJECTED);
			tmsShipbillHeaderModel.setUpdateperson(user.getNickname());
			tmsShipbillHeaderModel.setUpdatetime(date);
			tmsShipbillHeaderModel.setCarrierId(null);
			tmsShipbillHeaderModel.setCarrierCode(null);
			tmsShipbillHeaderModel.setCarrierName(null);
			tmsShipbillHeaderMapper.update(tmsShipbillHeaderModel);

			// 承运商运单操作日志保存
			ShipbillOperateLogSaveVO shipbillOperateLogSaveVO = new ShipbillOperateLogSaveVO();
			shipbillOperateLogSaveVO.setShipbillId(id);
			shipbillOperateLogSaveVO.setShipbillNo(id);
			shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.CARRIER_SHIPBILL_NODE_STATUSNAME_REFUSE);
			shipbillOperateLogSaveVO.setOldStatus(tmsShipbillHeaderModel.getCarrierShipbillStatus());
			shipbillOperateLogSaveVO.setNewStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_REJECTED);
			shipbillOperateLogService.addShipbillOperateLogData(shipbillOperateLogSaveVO);
			MessageUtil.addMessage(new SendMessageDTO(MessageOrderTypeEnum.SHIP_NO.getCode(), MessageTypeEnum.CARRIER_REJECT.getCode(), Lists.newArrayList(id)));
		}

		// 运单调用撤销调度
//        dispatchService.undoDispatchData(ids);

		Criteria criteria = Criteria.forClass(TmsLoadingBillDetailModel.class);
		Restriction r1 = Restrictions.in("shipbillId", ids.toArray());
		criteria.setRestriction(r1);
		List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModels = tmsLoadingBillDetailMapper.findByCriteria(criteria);

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

			// 修改配送顺序
			r1 = Restrictions.eq("loadingBillId", tmsLoadingBillDetailModel.getLoadingBillId());
			Restriction r2 = Restrictions.ne("shipbillId", tmsLoadingBillDetailModel.getShipbillId());
			criteria.setRestriction(Restrictions.and(r1, r2));
			List<TmsLoadingBillDetailModel> tmsLoadingBillDetailModelList = tmsLoadingBillDetailMapper.findByCriteria(criteria);
			for (TmsLoadingBillDetailModel loadingBillDetailModel : tmsLoadingBillDetailModelList) {
				if (loadingBillDetailModel.getShippingOrder() > tmsLoadingBillDetailModel.getShippingOrder()) {
					loadingBillDetailModel.setShippingOrder(loadingBillDetailModel.getShippingOrder() - 1);
				}
				tmsLoadingBillDetailMapper.update(loadingBillDetailModel);
			}
			// 修改汇总的数据
			TmsLoadingBillHeaderModel tmsLoadingBillHeaderModel = tmsLoadingBillHeaderMapper.findById(tmsLoadingBillDetailModel.getLoadingBillId(), TmsLoadingBillHeaderModel.class);

			// 客户数
			Integer customerNumber = tmsLoadingBillDetailModelList.stream().filter(o -> ToolKits.isNotEmpty(o.getConsigneeName())).map(TmsLoadingBillDetailModel::getConsigneeName).distinct().collect(Collectors.toList()).size();

			// 站点数
			Integer siteNumber = tmsLoadingBillDetailModelList.stream().filter(o -> ToolKits.isNotEmpty(o.getConsigneeAddress())).map(TmsLoadingBillDetailModel::getConsigneeAddress).distinct().collect(Collectors.toList()).size();

			// 重量体积件数
			tmsLoadingBillHeaderModel.setTotalPcs(tmsLoadingBillHeaderModel.getTotalPcs().subtract(tmsLoadingBillDetailModel.getTotalPcs()));
			tmsLoadingBillHeaderModel.setTotalVolume(tmsLoadingBillHeaderModel.getTotalVolume().subtract(tmsLoadingBillDetailModel.getTotalVolume()));
			tmsLoadingBillHeaderModel.setTotalWeight(tmsLoadingBillHeaderModel.getTotalWeight().subtract(tmsLoadingBillDetailModel.getTotalWeight()));

			// 实际重量体积件数
			tmsLoadingBillHeaderModel.setActualTotalPcs(tmsLoadingBillHeaderModel.getActualTotalPcs().subtract(tmsLoadingBillDetailModel.getActualTotalPcs()));
			tmsLoadingBillHeaderModel.setActualTotalVolume(tmsLoadingBillHeaderModel.getActualTotalVolume().subtract(tmsLoadingBillDetailModel.getActualTotalVolume()));
			tmsLoadingBillHeaderModel.setActualTotalWeight(tmsLoadingBillHeaderModel.getActualTotalWeight().subtract(tmsLoadingBillDetailModel.getActualTotalWeight()));

			// 整件数拼箱数
			tmsLoadingBillHeaderModel.setTotalWholePiece(tmsLoadingBillDetailModel.getPackageWholePiece() == null ? null : tmsLoadingBillHeaderModel.getTotalWholePiece().subtract(tmsLoadingBillDetailModel.getPackageWholePiece()));
			tmsLoadingBillHeaderModel.setTotalLclPiece(tmsLoadingBillDetailModel.getPackageLclPiece() == null ? null : tmsLoadingBillHeaderModel.getTotalLclPiece().subtract(tmsLoadingBillDetailModel.getPackageLclPiece()));

			// 运单数
			tmsLoadingBillHeaderModel.setShipbillNumber(tmsLoadingBillHeaderModel.getShipbillNumber() - 1);

			// 客户数
			tmsLoadingBillHeaderModel.setCustomerNumber(customerNumber);
			// 站点数
			tmsLoadingBillHeaderModel.setSiteNumber(siteNumber);

			// 计算装载率
			if (ToolKits.isNotEmpty(tmsLoadingBillHeaderModel.getVehicleId())) {
				Map<String, String> map = this.calculateLoadingRate(tmsLoadingBillHeaderModel.getVehicleId(), tmsLoadingBillHeaderModel.getTotalWeight(), tmsLoadingBillHeaderModel.getTotalVolume());
				tmsLoadingBillHeaderModel.setVolumeLoadingRate(map.get("volume"));
				tmsLoadingBillHeaderModel.setWeightLoadingRate(map.get("weight"));
			}

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

			// 修改汇总表
			tmsLoadingBillHeaderMapper.update(tmsLoadingBillHeaderModel);

			// 运单操作日志保存
			ShipbillOperateLogSaveVO shipbillOperateLogSaveVO = new ShipbillOperateLogSaveVO();
			shipbillOperateLogSaveVO.setShipbillId(tmsLoadingBillDetailModel.getShipbillId());
			shipbillOperateLogSaveVO.setShipbillNo(tmsLoadingBillDetailModel.getShipbillNo());
			shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.SHIPBILL_STATUSNAME_YTH);
			shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.SHIPBILL_STATUS_DISPATCH);
			shipbillOperateLogSaveVO.setNewStatus(DataDictionaryConstant.SHIPBILL_STATUS_REVIEW);
			shipbillOperateLogService.addShipbillOperateLogData(shipbillOperateLogSaveVO);

		}

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

		Map<String, Object> map = Maps.newHashMap();
		map.put("status", DataDictionaryConstant.SHIPBILL_STATUS_REVIEW);
		map.put("updateperson", user.getNickname());
		map.put("updatetime", DateUtil.date());
		// 如果是承运商操作撤销,还需更新运单【承运商运单状态】为【已撤销】
		if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
			map.put("carrierShipbillStatus", DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_ROLLBACK);
		}
		tmsShipbillHeaderMapper.updateMapByCriteria(map, criteria);
	}

	/**
	 * 运单提交
	 *
	 * @param ids
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void submitShipbillData(List<String> ids) {
		ToolKits.isParamNull(ids, "运单批量提交请求不为空");

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

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

		autoSubmitShipbillData(ids, user, date);
	}

	/**
	 * 自动运单提交
	 *
	 * @param ids
	 */
	@Override
	public void autoSubmitShipbillData(List<String> ids, UserEntity user, Date date) {
		List<String> reviewObjs = Lists.newArrayList();
		for (String id : ids) {
			ToolKits.isParamNull(id, "运单ID不为空");
			// 更新
			TmsShipbillHeaderModel tmsShipbillHeaderModel = tmsShipbillHeaderMapper.findById(id, TmsShipbillHeaderModel.class);

			// 查询明细数据
			Criteria criteria = Criteria.forClass(TmsShipbillDetailModel.class);
			Restriction r1 = Restrictions.eq("shipbillId", id);
			criteria.setRestriction(r1);
			List<TmsShipbillDetailModel> tmsShipbillDetailModels = tmsShipbillDetailMapper.findByCriteria(criteria);

			// 运单匹配线路
			if (StrUtil.isNotBlank(tmsShipbillHeaderModel.getFlowConfig()) && tmsShipbillHeaderModel.getFlowConfig().contains(DataDictionaryConstant.FLOW_CONFIG_COMMIT_LINE_STRATEGY)) {
				ShipbillMatchLineDTO lineData = strategyUtil.shipbillMatchLine(tmsShipbillHeaderModel);
				if (ToolKits.isNotEmpty(lineData) && ToolKits.isNotEmpty(lineData.getLineId())) {
					// 订单绑定线路
					tmsShipbillHeaderModel.setLineId(lineData.getLineId());
					tmsShipbillHeaderModel.setLineCode(lineData.getLineCode());
					tmsShipbillHeaderModel.setLineName(lineData.getLineName());
					tmsShipbillHeaderModel.setLineDirection(lineData.getLineDirection());
					tmsShipbillHeaderModel.setShippingOrder(lineData.getShippingOrder());
					tmsShipbillHeaderModel.setPickUpOrder(lineData.getPickUpOrder());
					DataUtils.setEstimatedTime(tmsShipbillHeaderModel, lineData, "S");
				} else {
					tmsShipbillHeaderModel.setLineDirection(DataDictionaryConstant.LINE_DIRECTION_F);
				}
			}
			// 匹配业务规则
			if (StrUtil.isNotBlank(tmsShipbillHeaderModel.getFlowConfig()) && tmsShipbillHeaderModel.getFlowConfig().contains(DataDictionaryConstant.FLOW_CONFIG_COMMIT_BUSINESS_STRATEGY)) {
				strategyUtil.updateShipbillHeaderByBusinessRule(tmsShipbillHeaderModel, tmsShipbillDetailModels);
			}
			if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
				Assert.isTrue(tmsShipbillHeaderModel.getStatus() != DataDictionaryConstant.SHIPBILL_STATUS_YTJ, "运单【" + tmsShipbillHeaderModel.getShipbillNo() + "】已提交");
				Assert.isTrue(tmsShipbillHeaderModel.getStatus() != DataDictionaryConstant.SHIPBILL_STATUS_DSH, "运单【" + tmsShipbillHeaderModel.getShipbillNo() + "】在审核中");
			} else if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
				Assert.isTrue(tmsShipbillHeaderModel.getStatus() != DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_COMMIT, "运单【" + tmsShipbillHeaderModel.getShipbillNo() + "】已提交");
			}

			Boolean data = false;
			if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
				// 封装判断所需数据
				ApprovalOpenVO approvalOpenVO = new ApprovalOpenVO();
				approvalOpenVO.setApprovalFlowType(DataDictionaryConstant.APPROVAL_FLOW_TYPE_SHIPBILL);
				approvalOpenVO.setApprovalObjectId(id);
				approvalOpenVO.setApprovalObjectCode(tmsShipbillHeaderModel.getShipbillNo());
				approvalOpenVO.setApprovalObjectName(tmsShipbillHeaderModel.getShipbillNo());
				approvalOpenVO.setInitiatedUserId(user.getUserid());
				approvalOpenVO.setInitiatedUserName(user.getNickname());

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

				RestMessage<Boolean> restMessage1 = maindataTmsResource.openExecute(approvalOpenVO);

				if (!restMessage1.isSuccess()) {
					throw new RuntimeException("调用maindata服务是否开启审批流接口失败:" + restMessage1.getMessage());
				}
				data = restMessage1.getData();
			}

			// 声明节点实体
			ShipbillNodeTrackingSaveNewVO shipbillNodeTrackingSaveNewVO = new ShipbillNodeTrackingSaveNewVO();
			// 声明日志实体
			ShipbillOperateLogSaveNewVO shipbillOperateLogSaveNewVO = new ShipbillOperateLogSaveNewVO();

			if (data) {
				// 修改主表状态为待审核
				tmsShipbillHeaderModel.setStatus(DataDictionaryConstant.SHIPBILL_STATUS_DSH);

				tmsShipbillHeaderModel.setUpdateperson(user.getNickname());
				tmsShipbillHeaderModel.setUpdatetime(date);
				// 节点状态
				shipbillNodeTrackingSaveNewVO.setStatus(DataDictionaryConstant.SHIPBILL_STATUS_DSH);
				// 日志状态
				shipbillOperateLogSaveNewVO.setOperateEvent(DataDictionaryConstant.SHIPBILL_STATUSNAME_YTJ_APPROVAL);
				shipbillOperateLogSaveNewVO.setOldStatus(DataDictionaryConstant.SHIPBILL_STATUS_CSH);
				shipbillOperateLogSaveNewVO.setNewStatus(DataDictionaryConstant.SHIPBILL_STATUS_DSH);

				// 封装运单汇总临时表
				TmsShipbillHeaderTempModel tmsShipbillHeaderTempModel = new TmsShipbillHeaderTempModel();
				BeanUtils.copyProperties(tmsShipbillHeaderModel, tmsShipbillHeaderTempModel);

				tmsShipbillHeaderTempMapper.save(tmsShipbillHeaderTempModel);

				// 封装运单明细临时表
				tmsShipbillDetailModels.forEach(o -> {
					TmsShipbillDetailTempModel tmsShipbillDetailTempModel = new TmsShipbillDetailTempModel();
					BeanUtils.copyProperties(o, tmsShipbillDetailTempModel);

					// 运单明细临时表保存
					tmsShipbillDetailTempMapper.save(tmsShipbillDetailTempModel);
				});

				// 运单汇总表更新
				tmsShipbillHeaderMapper.update(tmsShipbillHeaderModel);
			} else {
				// 运单提交
				if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
					tmsShipbillHeaderModel.setStatus(DataDictionaryConstant.SHIPBILL_STATUS_YTJ);

					// 日志状态
					shipbillOperateLogSaveNewVO.setOperateEvent(DataDictionaryConstant.SHIPBILL_STATUSNAME_YTJ);
					shipbillOperateLogSaveNewVO.setOldStatus(DataDictionaryConstant.SHIPBILL_STATUS_CSH);
					shipbillOperateLogSaveNewVO.setNewStatus(DataDictionaryConstant.SHIPBILL_STATUS_YTJ);

					// 节点状态
					shipbillNodeTrackingSaveNewVO.setStatus(DataDictionaryConstant.SHIPBILL_STATUS_YTJ);

					shipbillNodeTrackingSaveNewVO.setNodeEvent(DataDictionaryConstant.SHIPBILL_STATUSNAME_YTJ);

					// 判定提交后是否自动审核
					if (ToolKits.isNotEmpty(tmsShipbillHeaderModel.getFlowConfig()) && tmsShipbillHeaderModel.getFlowConfig().contains(DataDictionaryConstant.FLOW_CONFIG_COMMIT_REVIEW)) {
						reviewObjs.add(id);
					}
				} else if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
					tmsShipbillHeaderModel.setCarrierShipbillStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_COMMIT);
					// 日志状态
					shipbillOperateLogSaveNewVO.setOperateEvent(DataDictionaryConstant.CARRIER_SHIPBILL_STATUSNAME_YTJ);
					shipbillOperateLogSaveNewVO.setOldStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_RECEIVED);
					shipbillOperateLogSaveNewVO.setNewStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_COMMIT);
					// 节点状态
					shipbillNodeTrackingSaveNewVO.setStatus(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_COMMIT);

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

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

				Criteria criteriaTransLog = Criteria.forClass(TmsShipbillTransLogModel.class);
				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);
			}

			// 节点保存
			shipbillNodeTrackingSaveNewVO.setShipbillId(tmsShipbillHeaderModel.getShipbillId());
			shipbillNodeTrackingSaveNewVO.setShipbillNo(tmsShipbillHeaderModel.getShipbillNo());
			shipbillNodeTrackingSaveNewVO.setNodeDate(date);
			shipbillNodeTrackingSaveNewVO.setUserId(user.getUserid());
			shipbillNodeTrackingSaveNewVO.setUserName(user.getNickname());
			shipbillNodeTrackingSaveNewVO.setEnterpriseId(user.getEnterpriseId());
			shipbillNodeTrackingSaveNewVO.setEnterpriseName(user.getEnterpriseName());
			// 节点保存
			shipbillNodeTrackingService.addShipbillNodeTrackingNewData(shipbillNodeTrackingSaveNewVO);

			shipbillOperateLogSaveNewVO.setShipbillId(tmsShipbillHeaderModel.getShipbillId());
			shipbillOperateLogSaveNewVO.setShipbillNo(tmsShipbillHeaderModel.getShipbillNo());
			shipbillOperateLogSaveNewVO.setUserId(user.getUserid());
			shipbillOperateLogSaveNewVO.setUserName(user.getNickname());
			shipbillOperateLogSaveNewVO.setEnterpriseId(user.getEnterpriseId());
			shipbillOperateLogSaveNewVO.setEnterpriseName(user.getEnterpriseName());
			shipbillOperateLogSaveNewVO.setOperateDate(date);
			// 日志保存
			shipbillOperateLogService.addShipbillOperateLogNewData(shipbillOperateLogSaveNewVO);
			MessageTypeEnum messageTypeEnum = MessageTypeEnum.SELF_SUBMIT;
			if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
				messageTypeEnum = MessageTypeEnum.CARRIER_SUBMIT;
			}
			MessageUtil.addMessage(new SendMessageDTO(MessageOrderTypeEnum.SHIP_NO.getCode(), messageTypeEnum.getCode(), Lists.newArrayList(id)));
		}
		// 提交后，调用自动审核处理
		if (ToolKits.isNotEmpty(reviewObjs)) {
			pendingReviewService.autoReviewShipbillData(reviewObjs, user, date);
		}
	}

	/**
	 * 计算装载率
	 *
	 * @param id
	 * @param weight
	 * @param volume
	 * @return
	 */
	private Map<String, String> calculateLoadingRate(Long id, BigDecimal weight, BigDecimal volume) {

		VehicleCheckVO vehicleCheckVO = new VehicleCheckVO();
		vehicleCheckVO.setVehicleId(id);

		RestMessage<VehicleCheckDTO> data = maindataTmsResource.getVehicle(vehicleCheckVO);
		if (!data.isSuccess()) {
			throw new RuntimeException("获取车辆失败");
		}
		VehicleCheckDTO vehicleCheckDTO = data.getData();

		StringBuffer weightStr = new StringBuffer();
		StringBuffer volumeStr = new StringBuffer();

		if (ToolKits.isNotEmpty(weight)) {
			BigDecimal divide = ToolKits.isEmpty(vehicleCheckDTO.getWeight()) ? BigDecimal.ZERO : weight.divide(vehicleCheckDTO.getWeight(), 2, BigDecimal.ROUND_HALF_UP);
			BigDecimal multiply = divide.multiply(new BigDecimal("100"));
			weightStr.append(multiply.intValue());
			weightStr.append("%");
		}
		if (ToolKits.isNotEmpty(volume)) {
			BigDecimal divide = ToolKits.isEmpty(vehicleCheckDTO.getVolume()) ? BigDecimal.ZERO : volume.divide(vehicleCheckDTO.getVolume(), 2, BigDecimal.ROUND_HALF_UP);
			BigDecimal multiply = divide.multiply(new BigDecimal("100"));
			volumeStr.append(multiply.intValue());
			volumeStr.append("%");
		}

		Map<String, String> map = Maps.newHashMap();
		map.put("weight", weightStr.toString());
		map.put("volume", volumeStr.toString());

		return map;
	}
}
