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

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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.rdc.tms.constant.enums.DriverReceiveStatusEnum;
import com.prolog.rdc.tms.constant.enums.ShipBillTypeEnum;
import com.prolog.rdc.tms.constant.enums.SignInStatusEnum;
import com.prolog.rdc.tms.constant.enums.intelligent.IntelligentLockEnum;
import com.prolog.rdc.tms.dao.mapper.*;
import com.prolog.rdc.tms.model.dto.LoadingScanDTO;
import com.prolog.rdc.tms.model.dto.ScanDispatchBillDTO;
import com.prolog.rdc.tms.model.dto.ScanDispatchDetailDTO;
import com.prolog.rdc.tms.model.dto.basicData.ItemCheckDTO;
import com.prolog.rdc.tms.model.dto.message.SendMessageDTO;
import com.prolog.rdc.tms.model.entity.*;
import com.prolog.rdc.tms.model.enums.MessageOrderTypeEnum;
import com.prolog.rdc.tms.model.enums.MessageTypeEnum;
import com.prolog.rdc.tms.model.vo.*;
import com.prolog.rdc.tms.model.vo.basicData.ItemCheckVO;
import com.prolog.rdc.tms.proxy.MainDataProxy;
import com.prolog.rdc.tms.service.*;
import com.prolog.rdc.tms.util.ConvertorUtil;
import com.prolog.rdc.tms.util.MessageUtil;
import lombok.extern.slf4j.Slf4j;
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.BizException;
import com.prolog.framework.core.exception.PrologException;
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.product.core.framework.entity.UserEntity;
import com.prolog.product.core.framework.util.PlgFxUsrUtils;
import com.prolog.rdc.tms.constant.BussinessConstant;
import com.prolog.rdc.tms.constant.DataDictionaryConstant;
import com.prolog.rdc.tms.constant.SeriaNnumberConstant;
import com.prolog.rdc.tms.constant.StatusConstant;
import com.prolog.rdc.tms.model.dto.ScanDispatchShipbillDTO;
import com.prolog.rdc.tms.model.dto.basicConfigure.ShipbillFitBusinessFlowDTO;
import com.prolog.rdc.tms.model.dto.basicConfigure.SignconfigPopDTO;
import com.prolog.rdc.tms.model.vo.basicConfigure.BusinessFlowShipbillVO;
import com.prolog.rdc.tms.model.vo.basicConfigure.SignconfigPopVO;
import com.prolog.rdc.tms.rmi.feign.MaindataFeign;
import com.prolog.rdc.tms.util.BusinessFlowUtil;
import com.prolog.rdc.tms.util.PublicMethods;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;

import javax.jws.WebParam;

/**
 * 扫描派车实现层
 *
 * @author lhb
 * @since 2022-04-26 14:45:00
 */
@Service
@Slf4j
public class ScanDispatchServiceImpl implements ScanDispatchService {

    @Autowired
    private TmsShipbillHeaderMapper tmsShipbillHeaderMapper;

    @Autowired
    private TmsShipbillDetailMapper tmsShipbillDetailMapper;

    @Autowired
    private MaindataFeign maindataTmsResource;

    @Autowired
    private PendingDispatchService pendingDispatchService;

    @Autowired
    private TmsLoadingBillDetailMapper tmsLoadingBillDetailMapper;

    @Autowired
    private ShipbillNodeTrackingService shipbillNodeTrackingService;

    @Autowired
    private ShipbillOperateLogService shipbillOperateLogService;

    @Autowired
    private TmsShipbillTransportLogMapper tmsShipbillTransportLogMapper;

    @Autowired
    private MainDataProxy mainDataProxy;

    @Autowired
    private ConvertorUtil convertorUtil;

    /**
     * 单号扫描
     *
     * @param vo
     * @return
     */
    @Override
    public ScanDispatchBillDTO scanBill(BillScanVO vo) {
        ToolKits.isParamNull(vo, "单号扫描查询请求不为空");

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

        String scanDispatchMethod = mainDataProxy.getSystemParamByCode(DataDictionaryConstant.SCAN_DISPATCH_METHOD);
        ScanDispatchBillDTO scanDispatchBillDTO = null;
        if (DataDictionaryConstant.SCAN_DISPATCH_METHOD_ORDER_ITEM.equals(scanDispatchMethod)) {
            String orderNo = vo.getOrderNo();
            vo.setOrderNo(vo.getBillCode());
            scanDispatchBillDTO = getShipbill(vo, user);
            if (ToolKits.isEmpty(scanDispatchBillDTO)) {
                if (ToolKits.isEmpty(orderNo)) {
                    throw new BizException("订单号不为空");
                }
                vo.setOrderNo(null);
                vo.setOrderNos(Arrays.stream(orderNo.split(",")).collect(Collectors.toList()));
                scanDispatchBillDTO = getShipbillDetail(vo,user);
            }
        } else if (DataDictionaryConstant.SCAN_DISPATCH_METHOD_SHIPBILL_ITEM.equals(scanDispatchMethod)) {
            String shipbillNo = vo.getShipbillNo();
            vo.setShipbillNo(vo.getBillCode());
            scanDispatchBillDTO = getShipbill(vo, user);
            if (ToolKits.isEmpty(scanDispatchBillDTO)) {
                if (ToolKits.isEmpty(shipbillNo)) {
                    throw new BizException("运单号不为空");
                }
                vo.setShipbillNo(null);
                vo.setShipbillNos(Arrays.stream(shipbillNo.split(",")).collect(Collectors.toList()));
                scanDispatchBillDTO = getShipbillDetail(vo,user);
            }
        } else {
            throw new BizException("不支持的扫描派车类型");
        }
        if (ToolKits.isEmpty(scanDispatchBillDTO)) {
            throw new BizException("扫描单据不存在");
        }
        return scanDispatchBillDTO;
    }

    private ScanDispatchBillDTO getShipbill(BillScanVO vo, UserEntity user) {
        vo.setDeliveryMethodType(DataDictionaryConstant.DELIVERY_METHOD_TYPE_SEND);
        vo.setEnterpriseId(user.getEnterpriseId());
        vo.setUserType(user.getUserType());
        // 权限控制
        if (ObjectUtil.equal(user.getUserType(), BussinessConstant.USER_TYPE_ZY)) {
            if (user.getOwnedAllDataAuthFlag().equals(BussinessConstant.USER_DEPARTMENT_AUTH_Y)) {
                vo.setDepts(user.getDepts().stream().toArray(String[]::new));
                vo.setIsDept(StatusConstant.IS_DEPT_YES);
            } else {
                vo.setDepts(user.getDepts().stream().toArray(String[]::new));
                vo.setIsDept(StatusConstant.IS_DEPT_NO);
                // 货主
                vo.setConsignors(user.getConsignors().stream().toArray(Long[]::new));
                // 客户
                vo.setCustomers(user.getCustomers().stream().toArray(Long[]::new));
                // 供应商
                vo.setSuppliers(user.getSuppliers().stream().toArray(Long[]::new));
                // 仓库
                vo.setWsarehouses(user.getWarehouses().stream().toArray(Long[]::new));
            }
        } else if (ObjectUtil.equal(user.getUserType(), BussinessConstant.USER_TYPE_CYS)) {

            vo.setUnitId(Long.valueOf(user.getLoginUserCompanyInfo().getId()));
        } else {
            throw new PrologException("当前人员没有操作权限！");
        }
        List<ScanDispatchShipbillDTO> tmsShipbillHeaderModels = tmsShipbillHeaderMapper.scanDispatchShipbill(vo);

        if (ToolKits.isEmpty(tmsShipbillHeaderModels)) {
            return null;
        }
        // 数据字典翻译数据集合
        List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[]{DataDictionaryConstant.CONSIGNEE_TYPE, // 收货方类型
                DataDictionaryConstant.SHIPPER_TYPE, //发货方类型
                DataDictionaryConstant.TEMPERATURE_REQUIREMENT, //温度要求
                DataDictionaryConstant.DELIVERY_METHOD_TYPE,  // 配送方式
                DataDictionaryConstant.TRANSPORT_TYPE, // 运输类型
                DataDictionaryConstant.ORDER_TYPE, // 订单类型
                DataDictionaryConstant.ORDER_BUSINESS_TYPE, // 订单业务类型
                DataDictionaryConstant.SHIPBILL_STATUS
        });
        ScanDispatchBillDTO billDTO = new ScanDispatchBillDTO();
        tmsShipbillHeaderModels.stream().forEach(model -> {
            if (ToolKits.isNotEmpty(model.getConsigneeLongitude()) && ToolKits.isNotEmpty(model.getConsigneeLatitude())) {
                model.setConsigneePositioning(StatusConstant.POSITIONING_YDW);
            } else {
                model.setConsigneePositioning(StatusConstant.POSITIONING_WDW);
            }
            // 发货方位置(经纬度判断)
            if (ToolKits.isNotEmpty(model.getShipperLongitude()) && ToolKits.isNotEmpty(model.getShipperLatitude())) {
                model.setShipperPositioning(StatusConstant.POSITIONING_YDW);
            } else {
                model.setShipperPositioning(StatusConstant.POSITIONING_WDW);
            }

            StringBuffer consigneeProvinceCityDistrict = new StringBuffer();
            // 目的地
            consigneeProvinceCityDistrict.append(model.getConsigneeProvinceName());
            consigneeProvinceCityDistrict.append(model.getConsigneeCityName());
            consigneeProvinceCityDistrict.append(model.getConsigneeDistrictName());
            model.setConsigneeProvinceCityDistrict(consigneeProvinceCityDistrict.toString());
            // 始发地
            StringBuffer shipperProvinceCityDistrict = new StringBuffer();
            shipperProvinceCityDistrict.append(model.getShipperProvinceName());
            shipperProvinceCityDistrict.append(model.getShipperCityName());
            shipperProvinceCityDistrict.append(model.getShipperDistrictName());
            model.setShipperProvinceCityDistrict(shipperProvinceCityDistrict.toString());
            // 类型翻译
            model.setOrderTypeName(ConvertorUtil.getName(dicData, DataDictionaryConstant.ORDER_TYPE, String.valueOf(model.getOrderType())));
            model.setOrderBusinessTypeName(ConvertorUtil.getName(dicData, DataDictionaryConstant.ORDER_BUSINESS_TYPE, String.valueOf(model.getOrderBusinessType())));
            model.setDeliveryMethodTypeName(ConvertorUtil.getName(dicData, DataDictionaryConstant.DELIVERY_METHOD_TYPE, String.valueOf(model.getDeliveryMethodType())));
            model.setTransportTypeName(ConvertorUtil.getName(dicData, DataDictionaryConstant.TRANSPORT_TYPE, String.valueOf(model.getTransportType())));
            model.setTemperatureRequirementName(ConvertorUtil.getName(dicData, DataDictionaryConstant.TEMPERATURE_REQUIREMENT, String.valueOf(model.getTemperatureRequirement())));
            model.setShipperTypeName(ConvertorUtil.getName(dicData, DataDictionaryConstant.SHIPPER_TYPE, String.valueOf(model.getShipperType())));
            model.setConsigneeTypeName(ConvertorUtil.getName(dicData, DataDictionaryConstant.CONSIGNEE_TYPE, String.valueOf(model.getConsigneeType())));
        });
        billDTO.setScannedShipbillList(tmsShipbillHeaderModels);
        billDTO.setCodeType("1");

        return billDTO;
    }

    private ScanDispatchBillDTO getShipbillDetail(BillScanVO vo,UserEntity user) {
        ScanDispatchBillDTO shipbillDTO= this.getShipbill(vo,user);
        if (ToolKits.isEmpty(shipbillDTO) || ToolKits.isEmpty(shipbillDTO.getScannedShipbillList())) {
            return null;
        }
        vo.setShipbillNos(shipbillDTO.getScannedShipbillList().stream().map(ScanDispatchShipbillDTO::getShipbillNo).collect(Collectors.toList()));
        List<ScanDispatchDetailDTO> tmsShipbillDetailModels = tmsShipbillHeaderMapper.scanDispatchShipbillDetail(vo);
        if (ToolKits.isEmpty(tmsShipbillDetailModels)) {
            return null;
        }
        // 数据字典翻译数据集合
        List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[]{DataDictionaryConstant.PACK_TYPE, // 包装类型
                DataDictionaryConstant.CARGO_THERMOSPHERE //货物温层
        });
        ScanDispatchBillDTO billDTO = new ScanDispatchBillDTO();
        tmsShipbillDetailModels.stream().forEach(detail -> {
            // 类型翻译
            detail.setPackTypeName(ConvertorUtil.getName(dicData, DataDictionaryConstant.PACK_TYPE, String.valueOf(detail.getPackType())));
            detail.setCargoThermosphereName(ConvertorUtil.getName(dicData, DataDictionaryConstant.CARGO_THERMOSPHERE, String.valueOf(detail.getCargoThermosphere())));
            detail.setApplyPcs(detail.getPcs());
        });
        billDTO.setScannedShipbillDetailList(tmsShipbillDetailModels);
        billDTO.setCodeType("3");

        return billDTO;
    }

    /**
     * 扫描派车调度
     *
     * @param vo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void dispatch(ScanDispatchVO vo) {
        ToolKits.isParamNull(vo, "扫描派车调度请求不为空");

        if (ToolKits.isEmpty(vo.getLoadingBillHeaderVO())) {
            throw new PrologException("司机,车俩信息不为空");
        }
        if (ToolKits.isEmpty(vo.getLoadingBillDetailVO())
                || vo.getLoadingBillDetailVO().stream().anyMatch(d -> ToolKits.isEmpty(d.getShipbillId()))) {
            throw new PrologException("运单信息不为空");
        }
        if (ToolKits.isEmpty(vo.getShipbillDetailVO())
                || vo.getShipbillDetailVO().stream().anyMatch(d -> ToolKits.isEmpty(d.getShipbillId())
                || ToolKits.isEmpty(d.getId())
                || ToolKits.isEmpty(d.getPcs())
                || ToolKits.isEmpty(d.getApplyPcs()))) {
            throw new PrologException("商品信息不为空");
        }
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        ToolKits.isParamNull(user, "当前人员没有操作权限");

        // 当前时间
        Date date = DateUtil.date();
        // 装车单明细
        List<LoadingBillDetailVO> shipbillVOS = vo.getLoadingBillDetailVO();
        List<ShipbillDetailVO> shipbillDetailVOS = vo.getShipbillDetailVO();
        List<String> shipbillIds = shipbillDetailVOS.stream().map(ShipbillDetailVO::getShipbillId).collect(Collectors.toList());

        List<String> dispatchShipbills = Lists.newArrayList();
        List<String> splitShipbills = Lists.newArrayList();
        for (LoadingBillDetailVO shipbill : shipbillVOS) {
            TmsShipbillHeaderModel shipbillHeaderModel = tmsShipbillHeaderMapper.findById(shipbill.getShipbillId(), TmsShipbillHeaderModel.class);
            if (ToolKits.isEmpty(shipbillHeaderModel)) {
                throw new PrologException(StrUtil.format("运单{}不存在", shipbill.getShipbillId()));
            }
            // 获取商品信息
            Criteria criteriaShipbillDetail = Criteria.forClass(TmsShipbillDetailModel.class);
            Restriction r1 = Restrictions.eq("shipbillId", shipbill.getShipbillId());
            Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
            criteriaShipbillDetail.setRestriction(Restrictions.and(r1, r2));
            List<TmsShipbillDetailModel> shipbillDetailModels = tmsShipbillDetailMapper.findByCriteria(criteriaShipbillDetail);
            if (ToolKits.isEmpty(shipbillDetailModels)) {
                dispatchShipbills.add(shipbill.getShipbillId());
                continue;
            }
            if (!shipbillIds.contains(shipbill.getShipbillId())) {
                throw new PrologException(StrUtil.format("运单{}的商品未扫描,不能调度", shipbill.getShipbillId()));
            }
            List<ShipbillDetailVO> disShipbillDetails = Lists.newArrayList();
            List<ShipbillDetailVO> noDisShipbillDetails = Lists.newArrayList();
            List<ShipbillDetailVO> scannedShipbillDetailVOS = shipbillDetailVOS.stream()
                                                                               .filter(d -> d.getShipbillId().equals(shipbill.getShipbillId()))
                                                                               .collect(Collectors.toList());
            List<TmsShipbillDetailModel> noDisShipbillDetailModels = shipbillDetailModels.stream()
                                                                                         .filter(d -> !scannedShipbillDetailVOS.stream().map(ShipbillDetailVO::getId)
                                                                                                                               .collect(Collectors.toList())
                                                                                                                               .contains(d.getId()))
                                                                                         .collect(Collectors.toList());
            noDisShipbillDetailModels.stream().forEach(d -> {
                ShipbillDetailVO noDisDetail = BeanUtil.copyProperties(d, ShipbillDetailVO.class);
                noDisShipbillDetails.add(noDisDetail);
            });
            for (ShipbillDetailVO detailVO : scannedShipbillDetailVOS) {
                if (NumberUtil.equals(BigDecimal.ZERO, detailVO.getApplyPcs())) {
                    noDisShipbillDetails.add(detailVO);
                    continue;
                }
                TmsShipbillDetailModel currShipbillDetail = shipbillDetailModels.stream()
                                                                                .filter(d -> d.getId().equals(detailVO.getId()))
                                                                                .collect(Collectors.toList()).get(0);
                if (NumberUtil.equals(currShipbillDetail.getPcs(), detailVO.getApplyPcs())) {
                    disShipbillDetails.add(detailVO);
                    continue;
                }
                if (NumberUtil.isGreater(currShipbillDetail.getPcs(), detailVO.getApplyPcs())) {
                    ShipbillDetailVO tmpDetailVO = BeanUtil.copyProperties(detailVO,ShipbillDetailVO.class);
                    tmpDetailVO.setPcs(detailVO.getApplyPcs());
                    disShipbillDetails.add(tmpDetailVO);

                    detailVO.setPcs(NumberUtil.sub(currShipbillDetail.getPcs(), tmpDetailVO.getPcs()));
                    noDisShipbillDetails.add(detailVO);
                    continue;
                }
                if (NumberUtil.isLess(currShipbillDetail.getPcs(), detailVO.getApplyPcs())) {
                    throw new PrologException(StrUtil.format("运单{}商品{}的件数大于实际件数", shipbill.getShipbillId(), currShipbillDetail.getItemName()));
                }
            }
            if (ToolKits.isEmpty(disShipbillDetails)) {
                throw new PrologException(StrUtil.format("运单{}没有扫描商品", shipbill.getShipbillId()));
            }
            // 按商品拆分运单
            if (ToolKits.isNotEmpty(disShipbillDetails) && ToolKits.isNotEmpty(noDisShipbillDetails)) {
                DispatchSplitVO splitVO = new DispatchSplitVO();
                splitVO.setShipbillId(shipbill.getShipbillId());
                Map<String, List<ShipbillDetailVO>> goodsMap = Maps.newHashMap();
                goodsMap.put("disReg", disShipbillDetails);
                goodsMap.put("disRegNo", noDisShipbillDetails);

                splitVO.setSplitGoodsMap(goodsMap);
                // 拆分处理
                splitShipbills.addAll(goodsSplit(splitVO, date, user));
            }

            if (ToolKits.isEmpty(splitShipbills)) {
                dispatchShipbills.add(shipbill.getShipbillId());
            } else {
                dispatchShipbills.addAll(splitShipbills);
            }
        }
        PendingDispatchVO dispatchVO = new PendingDispatchVO();
        dispatchVO.setLoadingBillHeaderVO(vo.getLoadingBillHeaderVO());
        List<LoadingBillDetailVO> shipbills = Lists.newArrayList();
        dispatchShipbills.stream().forEach(id -> {
            LoadingBillDetailVO billDetailVO = new LoadingBillDetailVO();
            billDetailVO.setShipbillId(id);
            shipbills.add(billDetailVO);
        });
        dispatchVO.setLoadingBillDetailVO(shipbills);
        pendingDispatchService.autoDispatch(dispatchVO, user, date, "");
    }

    // 商品拆分
    public List<String> goodsSplit(DispatchSplitVO splitVO, Date date, UserEntity user) {
        List<String> dispatchShipbills = Lists.newArrayList();
        // 原运单更新
        TmsShipbillHeaderModel tmsShipbillHeaderModel = tmsShipbillHeaderMapper.findById(splitVO.getShipbillId(), TmsShipbillHeaderModel.class);
        Map<String, Object> mapShipbillHeadUpdate = Maps.newHashMap();
        Restriction r23 = null;
        if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
            if (tmsShipbillHeaderModel.getSplitOrderStatus().equals(DataDictionaryConstant.SPLIT_ORDER_STATUS_ED)) {
                throw new PrologException("运单【" + tmsShipbillHeaderModel.getShipbillId() + "】已拆分");
            }
            r23 = Restrictions.eq(TmsShipbillHeaderModel::getSplitOrderStatus, DataDictionaryConstant.SPLIT_ORDER_STATUS_UN);

            tmsShipbillHeaderModel.setSplitOrderStatus(DataDictionaryConstant.SPLIT_ORDER_STATUS_ED);
            mapShipbillHeadUpdate.put("splitOrderStatus", DataDictionaryConstant.SPLIT_ORDER_STATUS_ED);
            // 原始主单被拆分时，拆单类型更新为2拆分主单，子单被拆分时，不更新拆单类型
            if (ToolKits.isEmpty(tmsShipbillHeaderModel.getSplitOrderType()) || tmsShipbillHeaderModel.getSplitOrderType().equals(DataDictionaryConstant.SPLIT_ORDER_TYPE_UN)) {
                tmsShipbillHeaderModel.setSplitOrderType(DataDictionaryConstant.SPLIT_ORDER_TYPE_SPLIT_MASTER);
                mapShipbillHeadUpdate.put("splitOrderType", DataDictionaryConstant.SPLIT_ORDER_TYPE_SPLIT_MASTER);
            }
        } else if (user.getUserType().equals(BussinessConstant.USER_TYPE_CYS)) {
            if (tmsShipbillHeaderModel.getCarrierSplitOrderStatus().equals(DataDictionaryConstant.CARRIER_SPLIT_ORDER_STATUS_ED)) {
                throw new PrologException("运单【" + tmsShipbillHeaderModel.getShipbillId() + "】已拆分");
            }
            r23 = Restrictions.eq(TmsShipbillHeaderModel::getCarrierSplitOrderStatus, DataDictionaryConstant.CARRIER_SPLIT_ORDER_STATUS_UN);

            mapShipbillHeadUpdate.put("carrierSplitOrderStatus", DataDictionaryConstant.CARRIER_SPLIT_ORDER_STATUS_ED);
            tmsShipbillHeaderModel.setCarrierSplitOrderStatus(DataDictionaryConstant.CARRIER_SPLIT_ORDER_STATUS_ED);
            // 原始主单被拆分时，拆单类型更新为2拆分主单，子单被拆分时，不更新拆单类型
            if (ToolKits.isEmpty(tmsShipbillHeaderModel.getCarrierSplitOrderType()) || tmsShipbillHeaderModel.getCarrierSplitOrderType().equals(DataDictionaryConstant.CARRIER_SPLIT_ORDER_TYPE_UN)) {
                tmsShipbillHeaderModel.setCarrierSplitOrderType(DataDictionaryConstant.CARRIER_SPLIT_ORDER_TYPE_SPLIT_MASTER);
                mapShipbillHeadUpdate.put("carrierSplitOrderType", DataDictionaryConstant.CARRIER_SPLIT_ORDER_TYPE_SPLIT_MASTER);
            }
            // 更新装车单明细
            Map<String, Object> mapLoadingDetailUpdate = Maps.newHashMap();
            mapLoadingDetailUpdate.put("updateperson", user.getNickname());
            mapLoadingDetailUpdate.put("updatetime", date);
            mapLoadingDetailUpdate.put("carrierSplitOrderStatus", DataDictionaryConstant.CARRIER_SPLIT_ORDER_STATUS_ED);
            if (ToolKits.isEmpty(tmsShipbillHeaderModel.getCarrierSplitOrderType()) || tmsShipbillHeaderModel.getCarrierSplitOrderType().equals(DataDictionaryConstant.CARRIER_SPLIT_ORDER_TYPE_UN)) {
                mapLoadingDetailUpdate.put("carrierSplitOrderType", DataDictionaryConstant.CARRIER_SPLIT_ORDER_TYPE_SPLIT_MASTER);
            }
            Criteria criteriaLoadingDetail = Criteria.forClass(TmsLoadingBillDetailModel.class);
            Restriction r21 = Restrictions.ge(TmsLoadingBillDetailModel::getCarrierShipbillStatus, DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_WAIT_RECEIVE);
            Restriction r22 = Restrictions.eq(TmsLoadingBillDetailModel::getShipbillId, tmsShipbillHeaderModel.getShipbillId());
            criteriaLoadingDetail.setRestriction(Restrictions.and(r21, r22));
            tmsLoadingBillDetailMapper.updateMapByCriteria(mapLoadingDetailUpdate, criteriaLoadingDetail);
        }
        // 更新运单
        Criteria criteriaHead = Criteria.forClass(TmsShipbillHeaderModel.class);
        Restriction r24 = Restrictions.eq(TmsShipbillHeaderModel::getShipbillId, tmsShipbillHeaderModel.getShipbillId());
        criteriaHead.setRestriction(Restrictions.and(r23, r24));
        mapShipbillHeadUpdate.put("updateperson", user.getNickname());
        mapShipbillHeadUpdate.put("updatetime", date);
        long upCnt = tmsShipbillHeaderMapper.updateMapByCriteria(mapShipbillHeadUpdate, criteriaHead);
        if (upCnt == 0) {
            log.info("运单【" + tmsShipbillHeaderModel.getShipbillId() + "】已拆分,或者已调度");
            throw new PrologException("运单【" + tmsShipbillHeaderModel.getShipbillId() + "】已拆分,或者已调度");
        }
        // 原运单日志保存
        ShipbillOperateLogSaveNewVO shipbillOperateLogSaveVO = new ShipbillOperateLogSaveNewVO();
        shipbillOperateLogSaveVO.setShipbillId(tmsShipbillHeaderModel.getShipbillId());
        shipbillOperateLogSaveVO.setShipbillNo(tmsShipbillHeaderModel.getShipbillNo());
        shipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.SHIPBILL_EVENT_NAME_SPLIT);
        shipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.SHIPBILL_STATUS_REVIEW);
        shipbillOperateLogSaveVO.setNewStatus(DataDictionaryConstant.SHIPBILL_STATUS_REVIEW);
        shipbillOperateLogSaveVO.setOperateDate(date);
        shipbillOperateLogSaveVO.setUserId(user.getUserid());
        shipbillOperateLogSaveVO.setUserName(user.getNickname());
        shipbillOperateLogSaveVO.setEnterpriseId(user.getEnterpriseId());
        shipbillOperateLogSaveVO.setEnterpriseName(user.getEnterpriseName());
        shipbillOperateLogService.addShipbillOperateLogNewData(shipbillOperateLogSaveVO);

        // 拆分成多个子单
        RestMessage<SysParamConfigModel> restMessageShipbillId = maindataTmsResource.getValue(DataDictionaryConstant.SHIPBILL_ID_CREATE_RULE);
        if (!restMessageShipbillId.isSuccess()) {
            throw new RuntimeException("获取运单ID生成规则的系统参数失败!");
        }
        SysParamConfigModel sysParamConfigModel = restMessageShipbillId.getData();
        int index = 1;
        Map<String, List<ShipbillDetailVO>> maps = splitVO.getSplitGoodsMap();
        for (String splitType : maps.keySet()) {
            // 运单汇总ID
            String subShipbillId = "";
            // 运单ID生成规则
            if (DataDictionaryConstant.SHIPBILL_ID_CREATE_RULE_AUTO.equals(sysParamConfigModel.getValue())) {
                // 获取运单汇总ID
                RestMessage<String> restMessageAutoCreateShipbillId = maindataTmsResource.getCodeNumberByCode(SeriaNnumberConstant.TMS_SHIPBILL_HEADER_ID, "L");
                if (!restMessageAutoCreateShipbillId.isSuccess()) {
                    throw new RuntimeException("生成运单汇总ID失败");
                }
                subShipbillId = restMessageAutoCreateShipbillId.getData();
            } else {
                StringBuffer buffNo1 = new StringBuffer(splitVO.getShipbillId());
                buffNo1.append(DataDictionaryConstant.SUB_SHIPBILL_NO);
                buffNo1.append(DataDictionaryConstant.SPLIT_SHIPBILL_NO);
                buffNo1.append(index);

                subShipbillId = buffNo1.toString();
            }
            // 商品总件数
            BigDecimal goodsTotalPcs = new BigDecimal(0);
            // 商品总体积
            BigDecimal goodsTotalVolume = new BigDecimal(0);
            // 商品总重量
            BigDecimal goodsTotalWeight = new BigDecimal(0);

            BigDecimal zero = new BigDecimal(0);

            // 保存每个子单中的明细信息
            for (ShipbillDetailVO splitGoodsDetailVO : maps.get(splitType)) {
                TmsShipbillDetailModel subTmsShipbillDetailModel = new TmsShipbillDetailModel();
                // 运单明细ID
                RestMessage<String> restMessage2 = maindataTmsResource.getCodeNumberByCode(SeriaNnumberConstant.TMS_SHIPBILL_DETAIL_ID, "L");
                if (!restMessage2.isSuccess()) {
                    throw new RuntimeException("生成运单明细ID失败");
                }
                String subShipbillDetailId = restMessage2.getData();

                TmsShipbillDetailModel detailModel = tmsShipbillDetailMapper.findById(splitGoodsDetailVO.getId(), TmsShipbillDetailModel.class);
                if (ToolKits.isEmpty(detailModel)) {
                    throw new PrologException("运单【" + splitVO.getShipbillId() + "】的商品【" + splitGoodsDetailVO.getId() + "】信息不存在");
                }
                // 取商品资料
                ItemCheckVO itemCheckVO = new ItemCheckVO();
                itemCheckVO.setItemId(detailModel.getItemId());
                RestMessage<ItemCheckDTO> restMessage3 = maindataTmsResource.getItem(itemCheckVO);
                if (!restMessage3.isSuccess()) {
                    throw new RuntimeException("取商品资料信息失败:" + restMessage3.getMessage());
                }
                ItemCheckDTO rsItemInfo = restMessage3.getData();

                BeanUtils.copyProperties(detailModel, subTmsShipbillDetailModel);
                // ID
                subTmsShipbillDetailModel.setId(subShipbillDetailId);
                // 运单ID
                subTmsShipbillDetailModel.setShipbillId(subShipbillId);
                // 运单编号
                subTmsShipbillDetailModel.setShipbillNo(subShipbillId);

                subTmsShipbillDetailModel.setPcs(splitGoodsDetailVO.getPcs());
                subTmsShipbillDetailModel.setWeight(splitGoodsDetailVO.getPcs().multiply(rsItemInfo.getWeight() == null ? BigDecimal.ZERO : rsItemInfo.getWeight()));
                subTmsShipbillDetailModel.setVolume(splitGoodsDetailVO.getPcs().multiply(rsItemInfo.getVolume() == null ? BigDecimal.ZERO : rsItemInfo.getVolume()));
                subTmsShipbillDetailModel.setEnterpriseId(user.getEnterpriseId());
                subTmsShipbillDetailModel.setEnterpriseName(user.getEnterpriseName());

                subTmsShipbillDetailModel.setCreateperson(user.getNickname());
                subTmsShipbillDetailModel.setCreatetime(date);
                subTmsShipbillDetailModel.setUpdateperson(user.getNickname());
                subTmsShipbillDetailModel.setUpdatetime(date);

                subTmsShipbillDetailModel.setOrigPcs(subTmsShipbillDetailModel.getPcs());
                subTmsShipbillDetailModel.setClosingPcs(BigDecimal.valueOf(0));
                subTmsShipbillDetailModel.setDeliveryPcs(BigDecimal.valueOf(0));
                subTmsShipbillDetailModel.setFatherId(detailModel.getId());
                subTmsShipbillDetailModel.setScanStatus(DataDictionaryConstant.SCAN_STATUS_INIT);
                tmsShipbillDetailMapper.save(subTmsShipbillDetailModel);

                goodsTotalPcs = goodsTotalPcs.add(subTmsShipbillDetailModel.getPcs());
                goodsTotalVolume = goodsTotalVolume.add(ToolKits.isEmpty(subTmsShipbillDetailModel.getVolume()) ? BigDecimal.ZERO : subTmsShipbillDetailModel.getVolume());
                goodsTotalWeight = goodsTotalWeight.add(ToolKits.isEmpty(subTmsShipbillDetailModel.getWeight()) ? BigDecimal.ZERO : subTmsShipbillDetailModel.getWeight());
            }

            // 保存拆分子单的运单汇总
            TmsShipbillHeaderModel subTmsShipbillHeaderModel = new TmsShipbillHeaderModel();
            BeanUtils.copyProperties(tmsShipbillHeaderModel, subTmsShipbillHeaderModel);

            subTmsShipbillHeaderModel.setShipbillNo(subShipbillId);
            subTmsShipbillHeaderModel.setShipbillId(subShipbillId);
            if (user.getUserType().equals(BussinessConstant.USER_TYPE_ZY)) {
                // 拆单状态 0未拆单
                subTmsShipbillHeaderModel.setSplitOrderStatus(DataDictionaryConstant.SPLIT_ORDER_STATUS_UN);
                // 拆单类型 3拆分子单
                subTmsShipbillHeaderModel.setSplitOrderType(DataDictionaryConstant.SPLIT_ORDER_TYPE_SPLIT_SUB);

                // 拆单状态 0未拆单
                subTmsShipbillHeaderModel.setCarrierSplitOrderStatus(DataDictionaryConstant.CARRIER_SPLIT_ORDER_STATUS_UN);
                // 拆单类型 3拆分子单
                subTmsShipbillHeaderModel.setCarrierSplitOrderType(DataDictionaryConstant.CARRIER_SPLIT_ORDER_TYPE_UN);
            } else {
                // 拆单状态 0未拆单
                subTmsShipbillHeaderModel.setCarrierSplitOrderStatus(DataDictionaryConstant.CARRIER_SPLIT_ORDER_STATUS_UN);
                // 拆单类型 3拆分子单
                subTmsShipbillHeaderModel.setCarrierSplitOrderType(DataDictionaryConstant.CARRIER_SPLIT_ORDER_TYPE_SPLIT_SUB);

                subTmsShipbillHeaderModel.setSplitOrderStatus(DataDictionaryConstant.SPLIT_ORDER_STATUS_UN);
                // 拆单类型 3拆分子单
                subTmsShipbillHeaderModel.setSplitOrderType(DataDictionaryConstant.SPLIT_ORDER_TYPE_UN);
            }
            // 父级运单ID
            subTmsShipbillHeaderModel.setFatherShipbillId(tmsShipbillHeaderModel.getShipbillId());
            // 父级运单编号
            subTmsShipbillHeaderModel.setFatherShipbillNo(tmsShipbillHeaderModel.getShipbillNo());
            // 原始运单ID
            String originalShipbillId = tmsShipbillHeaderModel.getOriginalShipbillId() == null ? tmsShipbillHeaderModel.getShipbillId() :
                    tmsShipbillHeaderModel.getOriginalShipbillId();
            subTmsShipbillHeaderModel.setOriginalShipbillId(originalShipbillId);
            // 原始运单编号
            String originalShipbillNo = tmsShipbillHeaderModel.getOriginalShipbillNo() == null ? tmsShipbillHeaderModel.getShipbillNo() :
                    tmsShipbillHeaderModel.getOriginalShipbillNo();
            subTmsShipbillHeaderModel.setOriginalShipbillNo(originalShipbillNo);
            // 总件数
            subTmsShipbillHeaderModel.setTotalPcs(goodsTotalPcs);
            // 总体积
            subTmsShipbillHeaderModel.setTotalVolume(goodsTotalVolume);
            // 总重量
            subTmsShipbillHeaderModel.setTotalWeight(goodsTotalWeight);
            // 实际总件数
            subTmsShipbillHeaderModel.setActualTotalPcs(goodsTotalPcs);
            // 实际总体积
            subTmsShipbillHeaderModel.setActualTotalVolume(goodsTotalVolume);
            // 实际总重量
            subTmsShipbillHeaderModel.setActualTotalWeight(goodsTotalWeight);
            // 包裹整件数
            subTmsShipbillHeaderModel.setPackageWholePiece(zero);
            // 包裹拼箱数
            subTmsShipbillHeaderModel.setPackageLclPiece(zero);
            // 包裹总体积
            subTmsShipbillHeaderModel.setPackageTotalVolume(zero);
            // 包裹总重量
            subTmsShipbillHeaderModel.setPackageTotalWeight(zero);

            subTmsShipbillHeaderModel.setCreateperson(user.getNickname());
            subTmsShipbillHeaderModel.setCreatetime(date);
            subTmsShipbillHeaderModel.setUpdateperson(user.getNickname());
            subTmsShipbillHeaderModel.setUpdatetime(date);
            subTmsShipbillHeaderModel.setShipbillType(ShipBillTypeEnum.NORMAL.getCode());
            subTmsShipbillHeaderModel.setSignInStatus(SignInStatusEnum.NOT_SIGN.getCode());
            subTmsShipbillHeaderModel.setDriverReceiveStatus(DriverReceiveStatusEnum.N.getCode());
            subTmsShipbillHeaderModel.setIntelligentLock(IntelligentLockEnum.UN_LOCK.getCode());
            tmsShipbillHeaderMapper.save(subTmsShipbillHeaderModel);

            // 运输记录
            saveTransportLog(subTmsShipbillHeaderModel.getShipbillId(), date, subTmsShipbillHeaderModel.getEstimatedPickupStartTime());

            // 子运单日志保存
            ShipbillOperateLogSaveNewVO subShipbillOperateLogSaveVO = new ShipbillOperateLogSaveNewVO();
            subShipbillOperateLogSaveVO.setShipbillId(subTmsShipbillHeaderModel.getShipbillId());
            subShipbillOperateLogSaveVO.setShipbillNo(subTmsShipbillHeaderModel.getShipbillNo());
            subShipbillOperateLogSaveVO.setOperateEvent(DataDictionaryConstant.SHIPBILL_EVENT_NAME_SPLIT_SUB);
            subShipbillOperateLogSaveVO.setOldStatus(DataDictionaryConstant.SHIPBILL_STATUS_REVIEW);
            subShipbillOperateLogSaveVO.setNewStatus(DataDictionaryConstant.SHIPBILL_STATUS_REVIEW);
            subShipbillOperateLogSaveVO.setOperateDate(date);
            subShipbillOperateLogSaveVO.setUserId(user.getUserid());
            subShipbillOperateLogSaveVO.setUserName(user.getNickname());
            subShipbillOperateLogSaveVO.setEnterpriseId(user.getEnterpriseId());
            subShipbillOperateLogSaveVO.setEnterpriseName(user.getEnterpriseName());
            shipbillOperateLogService.addShipbillOperateLogNewData(subShipbillOperateLogSaveVO);

            // 运单节点保存
            ShipbillNodeTrackingSaveNewVO shipbillNodeTrackingSaveVO = new ShipbillNodeTrackingSaveNewVO();
            shipbillNodeTrackingSaveVO.setShipbillId(subShipbillId);
            shipbillNodeTrackingSaveVO.setShipbillNo(subShipbillId);
            shipbillNodeTrackingSaveVO.setStatus(DataDictionaryConstant.SHIPBILL_STATUS_REVIEW);
            shipbillNodeTrackingSaveVO.setNodeEvent(DataDictionaryConstant.SHIPBILL_STATUSNAME_REW);
            shipbillNodeTrackingSaveVO.setNodeDate(date);
            shipbillNodeTrackingSaveVO.setUserId(user.getUserid());
            shipbillNodeTrackingSaveVO.setUserName(user.getNickname());
            shipbillNodeTrackingSaveVO.setEnterpriseId(user.getEnterpriseId());
            shipbillNodeTrackingSaveVO.setEnterpriseName(user.getEnterpriseName());
            shipbillNodeTrackingService.addShipbillNodeTrackingNewData(shipbillNodeTrackingSaveVO);
            index++;

            if (splitType.equals("disReg")) {
                dispatchShipbills.add(subTmsShipbillHeaderModel.getShipbillId());
            }
        }
        List<String> shipbillIds = Lists.newArrayList();
        shipbillIds.add(splitVO.getShipbillId());
        pendingDispatchService.updatePlanBill(shipbillIds,user);
        return dispatchShipbills;
    }

    /**
     * 生成运输记录表
     */
    public void saveTransportLog(String shipbillId, Date date, Date pickUpStartDt) {
        TmsShipbillTransLogModel logModel = new TmsShipbillTransLogModel();
        RestMessage<String> restMessage = maindataTmsResource.getCodeNumberByCode(SeriaNnumberConstant.TMS_SHIPBILL_TRANSPORT_LOG_ID, "L");
        if (!restMessage.isSuccess()) {
            throw new RuntimeException("生成运输记录ID失败");
        }
        String id = restMessage.getData();
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        logModel.setId(id);
        logModel.setShipbillId(shipbillId);
        logModel.setShipbillNo(shipbillId);

        logModel.setOrderDt(date);
        logModel.setCommitDt(date);
        logModel.setReviewDt(date);

        logModel.setEstimatedPickupStartTime(pickUpStartDt);
        logModel.setEnterpriseId(user.getEnterpriseId());
        logModel.setEnterpriseName(user.getEnterpriseName());
        logModel.setCreateperson(user.getNickname());
        logModel.setCreatetime(date);
        logModel.setUpdateperson(user.getNickname());
        logModel.setUpdatetime(date);

        tmsShipbillTransportLogMapper.save(logModel);
    }
}
