package com.sunda.spmswms.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunda.spmscommon.ResponseResult;
import com.sunda.spmscommon.feign.IFeignServiceCommon;
import com.sunda.spmscommon.service.ISysLogMqService;
import com.sunda.spmswms.entity.*;
import com.sunda.spmswms.mapper.SapPackageBoxMapper;
import com.sunda.spmswms.mapper.SapPackageListDtlMapper;
import com.sunda.spmswms.mapper.SapPackageListMapper;
import com.sunda.spmswms.mapper.WhsOutMapper;
import com.sunda.spmswms.service.*;

import org.apache.commons.collections4.CollectionUtils;
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.*;
import java.util.stream.Collectors;

import static com.sunda.spmscommon.Constans.*;

/**
 * <p>
 * SAP装箱单表抬头 服务实现类
 * </p>
 *
 * @author Wayne
 * @since 2021-04-22
 */
@Service
public class SapPackageListServiceImpl extends ServiceImpl<SapPackageListMapper, SapPackageList> implements ISapPackageListService {

    @Autowired
    ISapPackageListDtlService iSapPackageListDtlService;

    @Autowired
    WhsOutMapper whsOutMapper;

    @Autowired
    ISapPackageBoxService iSapPackageBoxService;
    
    @Autowired
    ISysLogMqService iSysLogMqService;

    @Autowired
    ISapDeliveryNoteLogService iSapDeliveryNoteLogService;

    @Autowired
    IFeignServiceCommon iFeignServiceCommon;

    @Autowired
    SapPackageListDtlMapper sapPackageListDtlMapper;

    @Autowired
    SapPackageBoxMapper sapPackageBoxMapper;

    @Autowired
    ISapBoxNoteService iSapBoxNoteService;
    
    @Autowired
    ISapBoxNoteDtlService iSapBoxNoteDtlService;
    
    @Autowired
    ISapPackageListCabinetNumberService iSapPackageListCabinetNumberService;

    @Override
    public List<Map<String, Object>> getSapPackageList(String userId, String packageList, String spmsStatus) {
        packageList = StringUtils.isNotEmpty(packageList) ? packageList : null;
        spmsStatus = StringUtils.isNotEmpty(spmsStatus) ? spmsStatus : null;
        return this.baseMapper.getSapPackageList(userId, packageList, spmsStatus);
    }

    @Override
    public Page<Map<String, Object>> getSapPackageListPage(String userId, String packageList, String spmsStatus,
    		String planLoadingDateStart, String planLoadingDateEnd, int pageNo, int pageSize, String werks, String whsLocationCode) {
        pageNo = pageNo <= 0 ? 1 : pageNo;
        pageSize = pageSize <= 0 ? 20 : pageSize;
        packageList = StringUtils.isNotEmpty(packageList) ? packageList : null;
        spmsStatus = StringUtils.isNotEmpty(spmsStatus) ? spmsStatus : null;
        werks = StringUtils.isNotEmpty(werks) ? werks : null;
        whsLocationCode = StringUtils.isNotEmpty(whsLocationCode) ? whsLocationCode : null;
        planLoadingDateStart = StringUtils.isNotEmpty(planLoadingDateStart) ? planLoadingDateStart : null;
        planLoadingDateEnd = StringUtils.isNotEmpty(planLoadingDateEnd) ? planLoadingDateEnd : null;
        Page<Map<String, Object>> pages = new Page<>(pageNo, pageSize);
        List<Map<String, Object>> pageMaData = this.baseMapper.getSapPackageListPage(pages, userId, packageList, spmsStatus, planLoadingDateStart, planLoadingDateEnd, werks, whsLocationCode);
        pages.setRecords(pageMaData);
        return pages;
    }

    @Override
    public List<Map<String, Object>> getSapPackageListDtl(String packageList, String goodsType) {
        return iSapPackageListDtlService.getSapPackageList(packageList, goodsType);
    }

    /***
     * @param userId
     * @param packageList
     * @param targetStatus
     * @param currentStatus
     * @return
     *
     * 1.更新装箱单表头。更新前该装箱单状态必须为 0待处理，否则不让更新；
     * 2.更新装箱单表表头状态为目标状态；
     * 3.更新装箱单明细表对应的行状态；
     * 4.装箱单更新成功后，执行 generateWhsOutTask 方法，按 装柜地点、货物类型、柜序号、可装柜日期 四个维度拆分出库任务；
     * 5.装箱单明细逐行遍历转换成出库任务：如果出库任务已经存在，则将该出库任务的 任务uuid 写入 装箱单明细对应行；
     *                                如果出库任务不存在，则新建一个出库任务，同时将 出库任务uuid 写入 装箱单明细对应行；
     * 6.记录装箱单操作日志；
     * 7.记录出库任务日志；
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized int updateSapPackageList(String userId, String packageList, String targetStatus, String currentStatus)throws Exception {
        if (StringUtils.isEmpty(packageList) || StringUtils.isEmpty(targetStatus) || StringUtils.isEmpty(currentStatus)){
            return -1;
        }
        QueryWrapper<SapPackageList> queryWrapper = new QueryWrapper<SapPackageList>().eq("PACKAGE_LIST", packageList);
        SapPackageList sapPackageList = this.baseMapper.selectOne(queryWrapper);
        if (sapPackageList != null){
            // 装箱单单据当前状态 跟前端 请求时的当前状态一致时才能执行更新操作；任务在SPMS状态(0待处理；1处理中；2处理完成)
            if (currentStatus.equals(sapPackageList.getSpmsStatus())){
                SapPackageList sapPackageList1 = new SapPackageList();
                sapPackageList1.setSpmsStatus(targetStatus);
                // 更新装箱单状态；更新装箱单行项目状态
                int result =  this.baseMapper.update(sapPackageList1, queryWrapper);
                iSapPackageListDtlService.updateSapPackageListDtl(packageList, targetStatus);
                // 记录 更新装箱单 日志
                if ("1".equals(targetStatus)){
                    iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(packageList, userId, UPDATE_SAP_PACKAGE_LIST);
                }
                // 当装箱单表头更新成功且目标状态 targetStatus 为 1 时，告知SAP装箱单已开始处理，调用装箱单上锁接口，生成出库任务及明细 
                if (result == 1 && "1".equals(targetStatus)){
                	// 生成出库任务
                    this.generateWhsOutTask(packageList, userId);
                    //记录 装箱单生成出库任务 日志
                    iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(packageList, userId, SAP_PACKAGE_LIST_TO_WHS_OUT_TASK);
                }
                if ("2".equals(targetStatus)){
                    iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(packageList, userId, CLOSE_SAP_PACKAGE_LIST);
                }
                return result;
            }
        }
        return -2;
    }

    private void generateWhsOutTask(String packageList, String userId){
    	QueryWrapper<SapPackageList> sapWrapper = new QueryWrapper<SapPackageList>().eq("PACKAGE_LIST", packageList);
        SapPackageList sapPackageList = this.baseMapper.selectOne(sapWrapper);
    	// 查询装箱单行明细
    	List<Map<String, Object>> getSapPackageList = iSapPackageListDtlService.getSapPackageList(packageList, null);
    	if (CollectionUtils.isNotEmpty(getSapPackageList)) {
    		// 根据发货主体、发货工厂、装柜仓库、柜序号、货物类型（贸易货、备件货）进行分组生成不同的出库任务
    		Map<String, List<Map<String, Object>>> outMaps = getSapPackageList.stream().collect(Collectors.groupingBy(e -> 
    		e.get("shipper").toString()+"_"+e.get("loadingWhsLocationCode").toString()+"_"+
    				e.get("cabinetSerialNumber").toString()+"_"+e.get("goodsType").toString()+"_"+
    				e.get("loadingWerks").toString()));
    		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String createDate = sdf.format(new Date());
    		for (String key : outMaps.keySet()) {
    			List<Map<String, Object>> list = outMaps.get(key);
    			String[] split = key.split("_");
    			// 任务如果不存在则新建出库任务，更新装箱单明细 出库任务uuid 字段；如果存在则将该任务的 uuid 更新到装箱单明细 出库任务uuid 字段
    			QueryWrapper<WhsOut> outQuery = new QueryWrapper<WhsOut>().eq("SHIPPER", split[0]).eq("PACKAGE_LIST", packageList)
    					.eq("WHS_LOCATION_CODE", split[1]).eq("GOODS_TYPE", split[3]).eq("CABINET_SERIAL_NUMBER", split[2])
    					.eq("WERKS", split[4]);
    			// 贸易货计算同个出库任务下相同物料的最大包装件数
    			if ("M".equals(split[3])) {
    				// 根据物料号分组
    				Map<String, List<Map<String, Object>>> materialNoMaps = list.stream().collect(Collectors.groupingBy(o -> o.get("materialNo").toString()));
    				for (String materialNo : materialNoMaps.keySet()) {
    					BigDecimal allSaleQuantity = BigDecimal.ZERO;
    					List<Map<String, Object>> materialList = materialNoMaps.get(materialNo);
    					for (Map<String, Object> map : materialList) {
    						if (map.get("plannedPackingNumber") != null) {
    							allSaleQuantity = allSaleQuantity.add(new BigDecimal(map.get("plannedPackingNumber").toString()));
    						}
    					}
    					// 将最大包装件数更新到装箱单行中
    					for (Map<String, Object> map : materialList) {
    						QueryWrapper<SapPackageListDtl> eq = new QueryWrapper<SapPackageListDtl>().eq("PACKAGE_LIST", map.get("packageList").toString())
    								.eq("ITEM", map.get("item").toString()).eq("SPMS_ITEM_NO", map.get("spmsItemNo").toString())
    								.eq("LOADING_WERKS", map.get("loadingWerks")).eq("GOODS_TYPE", map.get("goodsType").toString())
    								.eq("MATERIAL_NO", map.get("materialNo").toString());
    						SapPackageListDtl dtl = new SapPackageListDtl();
    						dtl.setPackageQuantityMax(allSaleQuantity.stripTrailingZeros().toPlainString());
    						dtl.setPackageUnitMax(map.get("packingUnit").toString());
    						iSapPackageListDtlService.update(dtl, eq);
    					}
    				}
    			} else {
    				// 备件货：统计在一个出库任务中一个物料存在箱码的数量
    				Map<String, List<Map<String, Object>>> materialNoMaps = list.stream().filter(m -> m.get("materialNo") != null).collect(Collectors.groupingBy(o -> o.get("materialNo").toString()));
    				for (String materialNo : materialNoMaps.keySet()) {
    					List<Map<String, Object>> materialList = materialNoMaps.get(materialNo);
    					// 将最大包装件数更新到装箱单行中
    					for (Map<String, Object> map : materialList) {
    						if (map.get("packageCode") == null) {
    							continue;
    						}
    						QueryWrapper<SapBoxNoteDtl> eq = new QueryWrapper<SapBoxNoteDtl>().eq("BOX_NOTE", map.get("packageCode").toString())
    								.eq("MATERIAL_NO", map.get("materialNo").toString());
    						SapBoxNoteDtl dtl = new SapBoxNoteDtl();
    						dtl.setPackageQuantityMax(String.valueOf(materialList.size()));
    						dtl.setPackageUnitMax("PCS");
    						iSapBoxNoteDtlService.update(dtl, eq);
    					}
    				}
    			}
    			WhsOut whsOut = whsOutMapper.selectOne(outQuery);
    			String uuid = UUID.randomUUID().toString().replaceAll("-","").toLowerCase();
    			if (whsOut == null){
                    WhsOut whsOut1 = new WhsOut();
                    whsOut1.setUuid(uuid);
                    whsOut1.setWerks(split[4]);
                    whsOut1.setWhsLocationCode(split[1]);
                    whsOut1.setPackageList(packageList);
                    whsOut1.setGoodsType(split[3]);
                    whsOut1.setDateOfLoading(sapPackageList.getPlanLoadingDate());
                    whsOut1.setCabinetSerialNumber(split[2]);
                    whsOut1.setCreateUserid(userId);
                    whsOut1.setCreateDate(createDate);
                    whsOut1.setCabinetModel(StringUtils.isNotEmpty(sapPackageList.getCabinetModel()) ? sapPackageList.getCabinetModel() : list.get(0).get("cabinetModel").toString());
//                    whsOut1.setCabinetNumber(list.get(0).get("cabinetNumber") != null ? list.get(0).get("cabinetNumber").toString() : "");
                    whsOut1.setShipper(split[0]);
                    //给出库任务一个初始状态：0待执行
                    whsOut1.setTaskStatus("0");
                    // 数据来源
                    whsOut1.setDataSource(sapPackageList.getDataSource());
                    whsOutMapper.insert(whsOut1);
                    // 记录日志-出库任务初始化
                    iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(uuid, userId, WHS_OUT_TASK_GENERATE);
                }
    			// 将出库任务的 uuid 回写到 SAP装箱单任务明细 对应的行中
    			for (Map<String, Object> map : list) {
    				SapPackageListDtl sapPackageListDtl = new SapPackageListDtl();
    		        sapPackageListDtl.setWhsOutUuid(whsOut == null ? uuid : whsOut.getUuid());
    		        sapPackageListDtl.setSpmsStatus("1");
    		        QueryWrapper<SapPackageListDtl> queryWrapper = new QueryWrapper<SapPackageListDtl>().eq("PACKAGE_LIST", packageList).eq("SPMS_ITEM_NO", map.get("oldSpmsItemNo").toString());
    		        iSapPackageListDtlService.update(sapPackageListDtl, queryWrapper);
    		        // 更新装箱单跟箱码关系表的出库任务UUID
//    		        SapPackageBox box = new SapPackageBox();
//    		        box.setWhsOutUuid(whsOut == null ? uuid : whsOut.getUuid());
//    		        QueryWrapper<SapPackageBox> boxWrapper = new QueryWrapper<SapPackageBox>().eq("PACKAGE_LIST", packageList).eq("ITEM", map.get("item").toString());
//    		        sapPackageBoxMapper.update(box, boxWrapper);
    			}
    		}
    	}
    }

    @Override
    public List<Map<String, Object>> getSapPackageListDtlM(String packageList) {
        return iSapPackageListDtlService.getSapPackageListDtlM(packageList);
    }

    @Override
    public JSONObject lockSapPackageList(String packageList) {
        if (StringUtils.isEmpty(packageList)){
            return null;
        }
        JSONObject dataToSap = formatDataToSapLock(packageList);
        JSONObject sapReturnedData = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
        JSONObject doc = new JSONObject();
        doc.put("dataToSap", dataToSap);
        doc.put("sapReturnedData", sapReturnedData);
        return doc;
    }

    @Override
    public ResponseResult getSapPackageListRest(String packageList,String userId) {
        try {
            if (StringUtils.isEmpty(packageList)){
                return ResponseResult.error("请求参数错误");
            }

            JSONObject sapPackageList = new JSONObject();
            JSONArray sapPackageListDtl = new JSONArray();
            //装箱单表头信息，表头信息结构是数组，只会有一条
            Page<Map<String, Object>> pages = new Page<>(1, 20);
            //查询已完成的装箱单
            List<Map<String, Object>> pageMaData = this.baseMapper.getSapPackageListPage(pages, userId, packageList, "2", null, null, null, null);
            if(pageMaData!=null && pageMaData.size()>0){

            }else{
                return ResponseResult.error("未查询到符合条件的装箱单数据！No qualified packing list data is found");
            }
            Map<String, Object> headData = pageMaData.get(0);
            sapPackageList.put("packageList", headData.get("packageList"));//装箱单号
            sapPackageList.put("plannedCabinetsQty", headData.get("plannedCabinetsQty"));//计划柜量
            sapPackageList.put("customer", headData.get("customer"));//客户号
            sapPackageList.put("spareParts", headData.get("spareParts"));//是否杂货
            sapPackageList.put("fromPort", headData.get("fromPort"));//起运港
            sapPackageList.put("toPort", headData.get("toPort"));//目的港
            sapPackageList.put("shipCompany", "");//
            sapPackageList.put("cabinetModel", headData.get("cabinetModel"));//柜型
            //sapPackageList.put("createDate", headData.get("CRDAT"));//生成日期
            //sapPackageList.put("actualCabinetQty",  headData.get("ACONT"));//实际柜量
            //sapPackageList.put("userId", headData.get("SALE_USR"));//业务员代码

            //装箱单表行项目信息
            List<Map<String, Object>> dtlList = iSapPackageListDtlService.getSapPackageList(packageList, null);
            for (int i = 0; i < dtlList.size(); i++){
                Map<String, Object> dtl = dtlList.get(i);
                JSONObject object = new JSONObject();

                String materialNo = dtl.get("materialNo").toString();//物料编号
                object.put("packageList", dtl.get("packageList"));//装箱单号
                object.put("item", String.valueOf(Integer.parseInt(dtl.get("item").toString().trim())));//装箱单行号
                object.put("loadingWerks", dtl.get("loadingWerks"));//工厂
                object.put("loadingWhsLocationCode", dtl.get("loadingWhsLocationCode"));//计划出货仓库
                object.put("cabinetSerialNumber", dtl.get("cabinetSerialNumber"));//柜序号
                object.put("materialNo", materialNo);//物料编号
                object.put("basicUnit", dtl.get("basicUnit"));//基本计量单位
                object.put("plannedPackingQty", dtl.get("plannedPackingQty"));//计划装箱数量
                object.put("packingUnit", dtl.get("packingUnit"));//销售单位
                object.put("plannedPackingNumber", dtl.get("plannedPackingNumber"));//计划装箱件数
                object.put("actualOperateQty", dtl.get("actualOperateQty"));//实际装箱数量
                object.put("actualPackingNumber", dtl.get("actualPackingNumber"));//实际装箱件数
                object.put("boxNote", dtl.get("boxNote"));//箱码
                //object.put("directMark", dtl.get("PKMAK"));//直装标识

                Map<String, Object> materialSap = this.baseMapper.getNumeratorDenominator(materialNo);
                if (materialSap != null){
                    object.put("numerator", Double.parseDouble(materialSap.get("numerator").toString()));
                    object.put("denominator", Double.parseDouble(materialSap.get("denominator").toString()));
                    object.put("materialZhDesc", materialSap.get("materialZhDesc")==null?"":materialSap.get("materialZhDesc"));
                    object.put("materialEnDesc", materialSap.get("materialEnDesc")==null?"":materialSap.get("materialEnDesc"));
                }
                sapPackageListDtl.add(object);
            }

            return ResponseResult.success().add("sapPackageList", sapPackageList)
                    .add("sapPackageListDtl", sapPackageListDtl);
//
//            JSONObject dataToSap = formatDataToSapRest(packageList);
//            JSONObject sapReturnedData = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
//            JSONObject RETURN_DATA = sapReturnedData.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
//            if (StringUtils.isEmpty(RETURN_DATA.getString("O_TYPE")) || !"S".equals(RETURN_DATA.getString("O_TYPE"))){
//                return ResponseResult.error().add("dataToSap", dataToSap).add("sapReturnedData", sapReturnedData);
//            }
//            return formatReturnedData(RETURN_DATA);
        }catch (Exception e){
            e.printStackTrace();
            return ResponseResult.error().add("error", e.getMessage());
        }
    }

    JSONObject formatDataToSapRest(String packageList){
        JSONObject doc = new JSONObject();

        JSONObject REQUEST = new JSONObject();
        JSONObject ESB_ATTRS = new JSONObject();
        JSONObject REQUEST_DATA = new JSONObject();
        JSONObject Head = new JSONObject();

        ESB_ATTRS.put("App_ID", "SPMS");
        ESB_ATTRS.put("Application_ID", "00020000000002");
        ESB_ATTRS.put("Transaction_ID", UUID.randomUUID().toString());

        Head.put("iXdnum", packageList);

        REQUEST_DATA.put("Head", Head);
        REQUEST_DATA.put("Operation", "Z_SPMS_CHECK_PL");
        REQUEST_DATA.put("Type", "CHECK_PL");

        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
        REQUEST.put("REQUEST_DATA", REQUEST_DATA);

        doc.put("REQUEST", REQUEST);
        return doc;

    }

    JSONObject formatDataToSapLock(String packageList){
        JSONObject doc = new JSONObject();

        JSONObject REQUEST = new JSONObject();
        JSONObject ESB_ATTRS = new JSONObject();
        JSONObject REQUEST_DATA = new JSONObject();
        JSONObject Head = new JSONObject();

        ESB_ATTRS.put("App_ID", "SPMS");
        ESB_ATTRS.put("Application_ID", "00020000000002");
        ESB_ATTRS.put("Transaction_ID", UUID.randomUUID().toString());

        Head.put("iXdnum", packageList);
        Head.put("iFlag", "X");

        REQUEST_DATA.put("Head", Head);
        REQUEST_DATA.put("Operation", "Z_SPMS_SET_ZXD_1120");
        REQUEST_DATA.put("Type", "SET_ZXD_1120");

        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
        REQUEST.put("REQUEST_DATA", REQUEST_DATA);

        doc.put("REQUEST", REQUEST);
        return doc;
    }

    ResponseResult formatReturnedData(JSONObject doc){
        JSONObject sapPackageList = new JSONObject();
        JSONArray sapPackageListDtl = new JSONArray();
        JSONArray sapPackageListOperateRecord = new JSONArray();
        //装箱单表头信息，表头信息结构是数组，只会有一条
        JSONArray IT_ZXDTKO = doc.getJSONArray("IT_ZXDTKO");
        if (IT_ZXDTKO != null && IT_ZXDTKO.size() > 0){
            sapPackageList = getSapPackageList(IT_ZXDTKO.getJSONObject(0));
        }

        //装箱单表行项目信息
        JSONArray IT_ZXDTPO = doc.getJSONArray("IT_ZXDTPO");
        if (IT_ZXDTPO != null && IT_ZXDTPO.size() > 0){
            sapPackageListDtl = getSapPackageListDtl(IT_ZXDTPO);
        }

        //装箱单状态变化记录
        JSONArray IT_ZXDTSU = doc.getJSONArray("IT_ZXDTSU");
        if (IT_ZXDTSU != null && IT_ZXDTSU.size() > 0){
            sapPackageListOperateRecord = getSapPackageListOperateRecord(IT_ZXDTSU);
        }
        //暂不显示
        //JSONObject IT_TVKNT = doc.getJSONObject("IT_TVKNT");
        return ResponseResult.success().add("sapPackageList", sapPackageList)
                .add("sapPackageListDtl", sapPackageListDtl)
                .add("sapPackageListOperateRecord", sapPackageListOperateRecord);
    }

    JSONObject getSapPackageList(JSONObject IT_ZXDTKO){
        JSONObject doc = new JSONObject();
        doc.put("packageList", IT_ZXDTKO.getString("XDNUM"));//装箱单号
        doc.put("plannedCabinetsQty", IT_ZXDTKO.getString("PCONT"));//计划柜量
        doc.put("customer", IT_ZXDTKO.getString("KUNNR"));//客户号
        doc.put("spareParts", IT_ZXDTKO.getString("ZHBS"));//是否杂货
        doc.put("fromPort", IT_ZXDTKO.getString("SPORT"));//起运港
        doc.put("toPort", IT_ZXDTKO.getString("EPORT"));//目的港
        doc.put("shipCompany", IT_ZXDTKO.getString(""));//
        doc.put("cabinetModel", IT_ZXDTKO.getString("MAGRV"));//柜型
        doc.put("createDate", IT_ZXDTKO.getString("CRDAT"));//生成日期
        doc.put("actualCabinetQty",  IT_ZXDTKO.getString("ACONT"));//实际柜量
        doc.put("userId", IT_ZXDTKO.getString("SALE_USR"));//业务员代码
        return doc;
    }

    JSONArray getSapPackageListDtl(JSONArray IT_ZXDTPO){
        JSONArray doc = new JSONArray();
        for (int i = 0; i < IT_ZXDTPO.size(); i++){
            JSONObject dtl = IT_ZXDTPO.getJSONObject(i);
            JSONObject object = new JSONObject();
            String materialNo = dtl.getString("MATNR").replaceFirst("^0*", "");//物料编号
            object.put("packageList", dtl.getString("XDNUM"));//装箱单号
            object.put("item", String.valueOf(Integer.parseInt(dtl.getString("POSNR").trim())));//装箱单行号
            object.put("loadingWerks", dtl.getString("WERKS"));//工厂
            object.put("loadingWhsLocationCode", dtl.getString("LGORT"));//计划出货仓库
            object.put("cabinetSerialNumber", dtl.getString("CABIN"));//柜序号
            object.put("materialNo", materialNo);//物料编号
            object.put("basicUnit", dtl.getString("MEINS"));//基本计量单位
            object.put("plannedPackingQty", dtl.getString("PMENG"));//计划装箱数量
            object.put("packingUnit", dtl.getString("VRKME"));//销售单位
            object.put("plannedPackingNumber", dtl.getString("PEMNG"));//计划装箱件数
            object.put("actualOperateQty", dtl.getString("AMENG"));//实际装箱数量
            object.put("actualPackingNumber", dtl.getString("AEMNG"));//实际装箱件数
            object.put("directMark", dtl.getString("PKMAK"));//直装标识

            Map<String, Object> materialSap = this.baseMapper.getNumeratorDenominator(materialNo);
            if (materialSap != null){
                object.put("numerator", Double.parseDouble(materialSap.get("numerator").toString()));
                object.put("denominator", Double.parseDouble(materialSap.get("denominator").toString()));
                object.put("materialZhDesc", materialSap.get("materialZhDesc").toString());
                object.put("materialEnDesc", materialSap.get("materialEnDesc").toString());
            }
            doc.add(object);
        }
        return doc;
    }

    JSONArray getSapPackageListOperateRecord(JSONArray IT_ZXDTSU){
        JSONArray doc = new JSONArray();
        for (int i = 0; i < IT_ZXDTSU.size(); i++){
            JSONObject item = IT_ZXDTSU.getJSONObject(i);
            JSONObject object = new JSONObject();
            object.put("packageList", item.getString("XDNUM"));
            object.put("linkSerialNumber", item.getString("SUINX"));    //环节序号
            object.put("operateStatus", item.getString("OPSTU"));   //操作状态
            object.put("currentStatus", item.getString("CURTU"));    //当前状态
            object.put("confirm", item.getString("CLRIM"));    //确认
            object.put("orderClose", item.getString("CLSTY"));    //订单关闭
            object.put("stepCancel", item.getString("XLZKE"));    //步骤取消
            object.put("operateDate", item.getString("DATUM"));    //日期
            object.put("operateTime", item.getString("UZEIT"));    //时间
            object.put("userId", item.getString("USERN"));    //用户
            object.put("type", item.getString("KTOKD"));    //类型
            doc.add(object);
        }
        return doc;
    }

    /**
     * 1.装箱单没有明细行（目前没发生），系统提示错误；
     * 2.装箱单明细 货物类型 字段为‘M’和‘X’以外的值 SAP_PACKAGE_LIST_DTL，系统提示错误（目前没发生）；
     * 3.装箱单备件明细行，没有装箱明细箱码关系数据 SAP_PACKAGE_BOX，系统提示错误；
     * 4.装箱单备件明细行，有装箱单明细箱码关系的情况下，再判断明细中的箱码在 箱码信息表 是否存在，不存在则系统提示错误（目前没发生）；
     * 5.装箱单贸易货明细行，如果存在装箱单明细箱码关系 SAP_PACKAGE_BOX，系统提示错误；
     * */
    @Override
    public ResponseResult checkSapPackageListCanBeSplit(String packageList) {
        if (StringUtils.isEmpty(packageList)){
            return ResponseResult.error("请求参数错误请重试");
        }
        SapPackageList sapPackageList = this.baseMapper.selectOne(new QueryWrapper<SapPackageList>().eq("PACKAGE_LIST", packageList));
        if (sapPackageList == null){
            return ResponseResult.error("装箱号单查询不存在");
        }
        if (!"0".equals(sapPackageList.getSpmsStatus())){
            return ResponseResult.error("装箱单(SAP_PACKAGE_LIST)状态为 已拆分 或 已完成，不能拆分出库任务");
        }
        List<SapPackageListDtl> dtlList = sapPackageListDtlMapper.selectList(new QueryWrapper<SapPackageListDtl>().eq("PACKAGE_LIST", packageList));
        if (dtlList == null || dtlList.size() == 0){
            return ResponseResult.error("装箱单明细数据(SAP_PACKAGE_LIST_DTL)缺失，数据错误不能拆分出库任务");
        }
        for (int i = 0; i < dtlList.size(); i++){
            SapPackageListDtl dtl = dtlList.get(i);
            String dtlPackageList = dtl.getPackageList();
            String item = dtl.getItem();
//            QueryWrapper<SapPackageBox> boxQueryWrapper = new QueryWrapper<SapPackageBox>().eq("PACKAGE_LIST", dtlPackageList).eq("ITEM", item);
            if ("M".equals(dtl.getGoodsType())){
//                List<SapPackageBox> boxList = sapPackageBoxMapper.selectList(boxQueryWrapper);
//                if (boxList != null && boxList.size() > 0){
//                    return ResponseResult.error("装箱单" + dtlPackageList + " 贸易货行号 " + item + " 存在箱码信息(SAP_PACKAGE_LIST_DTL, SAP_PACKAGE_BOX)，数据错误无法拆分出库任务")
//                            .add("sapPackageList", sapPackageList.toString())
//                            .add("sapPackageListDtl", dtl.toString())
//                            .add("sapPackageBox", boxList.toString());
//                }
            } else if ("X".equals(dtl.getGoodsType())){
            	/***********以下注释2023-11-15 xzp update**************/
//            	SapBoxNote sapBoxNote = iSapBoxNoteService.getByBoxNote(dtl.getPackageCode());
//                if (sapBoxNote == null){
//                    return ResponseResult.error("装箱单" + dtlPackageList + " 备件货行号 " + item + " 箱码在箱码信息表(SAP_BOX_NOTE)中数据不存在，数据错误无法拆分出库任务")
//                            .add("sapPackageList", sapPackageList.toString())
//                            .add("sapPackageListDtl", dtl.toString())
//                            .add("boxNote", dtl.getPackageCode());
//                }
            	/*************结束*****************/
//                List<SapPackageBox> boxList = sapPackageBoxMapper.selectList(boxQueryWrapper);
//                if (boxList == null || boxList.size() == 0){
//                    return ResponseResult.error("装箱单" + dtlPackageList + " 备件货行号 " + item + " 不存在装箱单明细箱码关系数据(SAP_PACKAGE_LIST_DTL, SAP_PACKAGE_BOX)，数据错误无法拆分出库任务")
//                            .add("sapPackageList", sapPackageList.toString())
//                            .add("sapPackageListDtl", dtl.toString())
//                            .add("sapPackageBox", boxList);
//                } else {
//                    for (int j = 0; j < boxList.size(); j++){
//                        SapPackageBox sapPackageBox = boxList.get(j);
//                        String boxNote = sapPackageBox.getBoxNote();
//                        if (StringUtils.isEmpty(boxNote)){
//                            return ResponseResult.error("装箱单" + dtlPackageList + " 备件货行号 " + item + " 装箱单明细箱码关系数据中箱码信息错误(SAP_PACKAGE_BOX)，数据错误无法拆分出库任务")
//                                    .add("sapPackageList", sapPackageList.toString())
//                                    .add("sapPackageListDtl", dtl.toString())
//                                    .add("sapPackageBox", sapPackageBox);
//                        }
//                        SapBoxNote sapBoxNote = iSapBoxNoteService.getByBoxNote(boxNote);
//                        if (sapBoxNote == null){
//                            return ResponseResult.error("装箱单" + dtlPackageList + " 备件货行号 " + item + " 装箱单明细箱码关系数据中箱码存在(SAP_PACKAGE_LIST_DTL, SAP_PACKAGE_BOX)，但箱码在箱码信息表(SAP_BOX_NOTE)中数据不存在，数据错误无法拆分出库任务")
//                                    .add("sapPackageList", sapPackageList.toString())
//                                    .add("sapPackageListDtl", dtl.toString())
//                                    .add("sapPackageBox", sapPackageBox)
//                                    .add("boxNote", boxNote);
//                        }
//                    }
//                }
            } else {
                return ResponseResult.error("装箱单明细数据(SAP_PACKAGE_LIST_DTL)不合要求，数据错误无法拆分出库任务")
                        .add("sapPackageList", sapPackageList.toString())
                        .add("sapPackageListDtl", dtl.toString());
            }
        }
        return ResponseResult.success("数据正确，能进行出库任务拆分");
    }

	@Override
	@Transactional(rollbackFor = Exception.class)
	public ResponseResult openSapPackageList(String packageList, String userId) {
		if (StringUtils.isEmpty(packageList)){
            return ResponseResult.error("请求参数错误请重试");
        }
        SapPackageList sapPackageList = this.baseMapper.selectOne(new QueryWrapper<SapPackageList>().eq("PACKAGE_LIST", packageList));
        if (sapPackageList == null){
            return ResponseResult.error("装箱号单查询不存在");
        }
        if (!"3".equals(sapPackageList.getSpmsStatus())){
            return ResponseResult.error("装箱单(SAP_PACKAGE_LIST)状态不是已关闭，不能进行打开操作");
        }
        List<SapPackageListDtl> dtlList = sapPackageListDtlMapper.selectList(new QueryWrapper<SapPackageListDtl>().eq("PACKAGE_LIST", packageList));
        if (dtlList == null || dtlList.size() == 0){
            return ResponseResult.error("装箱单明细数据(SAP_PACKAGE_LIST_DTL)缺失，数据错误不能进行打开操作");
        }
        // 打开操作后将装箱单状态变为待处理，同时删除此装箱单下的全部出库任务
        QueryWrapper<SapPackageList> queryWrapper = new QueryWrapper<SapPackageList>().eq("PACKAGE_LIST", packageList);
        SapPackageList sapPackageList1 = new SapPackageList();
        sapPackageList1.setSpmsStatus("0");
        int result =  this.baseMapper.update(sapPackageList1, queryWrapper);
        iSapPackageListDtlService.updateSapPackageListDtl(packageList, "0");
        //记录 更新装箱单 日志
        if (result == 1){
        	iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(packageList, userId, OPEN_SAP_PACKAGE_LIST);
        }
        // 根据装箱单号查询出库任务
        List<Map<String, Object>> whsOutList = this.baseMapper.selectWhsOutList(packageList);
        // 删除出库任务
        this.baseMapper.deleteWhsOutListByPackageList(packageList);
        // 保存日志
        if (CollectionUtils.isNotEmpty(whsOutList)) {
        	iSapDeliveryNoteLogService.insertSapRequestRecord(packageList, userId, OPEN_SAP_PACKAGE_LIST, null, JSONObject.toJSONString(whsOutList));
        }
		return ResponseResult.success("装箱单打开操作成功");
	}

	@Override
	public ResponseResult zSapPackageListToSpms(JSONObject doc) {
		if (doc == null) {
			return ResponseResult.error("装柜安排信息推送SPMS失败，推送数据为空").add("STATUS", "E");
		}
//		JSONObject sendData = doc.getJSONObject("SendData");
		// 装箱单抬头
		JSONObject headDoc = doc.getJSONObject("head");
		// 装箱单行
		JSONArray itemJsons = doc.getJSONArray("itemList");
		if (headDoc == null || itemJsons == null || itemJsons.size() == 0) {
			return ResponseResult.error("装柜安排信息推送SPMS失败，缺少装箱单抬头或行数据").add("STATUS", "E");
		}
		// 设置装箱单头信息
		this.setPackHeadData(headDoc);
		// 设置装箱单行信息
		this.setpackItemData(itemJsons);
		return ResponseResult.success("装柜安排信息推送SPMS成功").add("STATUS", "S");
	}

	private void setpackItemData(JSONArray itemJsons) {
        List<SapPackageListDtl> itemList = new ArrayList<>();
        for (int i = 0; i < itemJsons.size(); i ++) {
            JSONObject doc = itemJsons.getJSONObject(i);
            if (StringUtils.isNotEmpty(doc.toString())) {
                SapPackageListDtl sapPackageListDtl = new SapPackageListDtl();
                // 装箱单号
                sapPackageListDtl.setPackageList(doc.getString("XDNUM"));
                // 行号去除多余空格，去除行号前面多余补 0.
                sapPackageListDtl.setItem(String.valueOf(Integer.parseInt(doc.getString("POSNR").trim())));
                // 发货工厂
                sapPackageListDtl.setLoadingWerks(doc.getString("WERKS_PO"));
                // 发货仓库
                sapPackageListDtl.setLoadingWhsLocationCode(doc.getString("LGORT"));
                // 收货工厂
                sapPackageListDtl.setReceivingWerks(doc.getString("WERKS"));
                sapPackageListDtl.setActualReceivingWerks(doc.getString("WERKS"));
                // 柜型
                sapPackageListDtl.setCabinetModel(doc.getString("MAGRV"));
                // 柜序号
                sapPackageListDtl.setCabinetSerialNumber(doc.getString("CABIN").trim());
                // 货物类型：SAP传值为空是贸易货
                if (StringUtils.isNotEmpty(doc.getString("Z_SPMSFLAG")) && "X".equals(doc.getString("Z_SPMSFLAG"))) {
                	sapPackageListDtl.setGoodsType(doc.getString("Z_SPMSFLAG"));
                } else {
                	sapPackageListDtl.setGoodsType("M");
                }
                // 物料编码
                if (StringUtils.isNotEmpty(doc.getString("MATNR"))) {
                	doc.getString("MATNR").trim().replaceAll("^(0+)", "");
                }
                sapPackageListDtl.setMaterialNo(doc.getString("MATNR").trim());
                // 箱码
                sapPackageListDtl.setPackageCode(doc.getString("PACKAGE_CODE"));
                // 体积
                sapPackageListDtl.setCabinetVolume(StringUtils.isEmpty(doc.getString("PVOLUM")) ? null : Double.parseDouble(doc.getString("PVOLUM")));
                // 体积单位
                sapPackageListDtl.setVolumeUnit(doc.getString("VOLEH"));
                // 净重
                sapPackageListDtl.setNetWeight(StringUtils.isEmpty(doc.getString("PNTGEW")) ? null : Double.parseDouble(doc.getString("PNTGEW")));
                // 毛重
                sapPackageListDtl.setCabinetWeight(StringUtils.isEmpty(doc.getString("PBRGEW")) ? null : Double.parseDouble(doc.getString("PBRGEW")));
                // 重量单位
                sapPackageListDtl.setWeightUnit(doc.getString("GEWEI"));
                // 发货主体
                sapPackageListDtl.setShipper(doc.getString("SDCUS"));
                // 收货主体
                sapPackageListDtl.setConsignee(doc.getString("SDSUS"));
                // 分公司
                sapPackageListDtl.setBukrs(doc.getString("C_BUKRS"));
                // 装柜位置
                sapPackageListDtl.setContainerLoadingPosition(doc.getString("ZZGWZ"));
                // 计划装箱数量
                sapPackageListDtl.setPlannedPackingQty(Double.parseDouble(doc.getString("PMENG").trim()));
                // 基本计量单位
                sapPackageListDtl.setBasicUnit(doc.getString("MEINS"));
                // 计划装箱件数
                sapPackageListDtl.setPlannedPackingNumber(Double.parseDouble(doc.getString("PEMNG").trim()));
                // 销售单位
                sapPackageListDtl.setPackingUnit(doc.getString("VRKME"));
                // 装柜仓库简称
                sapPackageListDtl.setLoadingWhsLocationName(doc.getString("LGOBE"));
                // 备注
                sapPackageListDtl.setRemarks(doc.getString("REMARKS"));
                /** 给默认状态 0，不为0的不允许更新 */
                sapPackageListDtl.setSpmsStatus("0");
                itemList.add(sapPackageListDtl);
            }
        }
        if (CollectionUtils.isNotEmpty(itemList)) {
        	// 根据装箱单号分组
        	Map<String, List<SapPackageListDtl>> packageMaps = itemList.stream().collect(Collectors.groupingBy(SapPackageListDtl::getPackageList));
        	for (String packageNumber : packageMaps.keySet()) {
        		List<SapPackageListDtl> list = packageMaps.get(packageNumber);
        		// 查询装箱单状态
        		QueryWrapper<SapPackageList> queryWrapper = new QueryWrapper<SapPackageList>().eq("PACKAGE_LIST", packageNumber);
                SapPackageList packageList = this.baseMapper.selectOne(queryWrapper);
                if (packageList != null && "0".equals(packageList.getSpmsStatus())) {
                    QueryWrapper<SapPackageListDtl> sapPackageListDtlQueryWrapper = new QueryWrapper<SapPackageListDtl>().eq("PACKAGE_LIST", packageNumber);
                    sapPackageListDtlMapper.delete(sapPackageListDtlQueryWrapper);
                    // 删除装箱单跟箱码关系表
//                    QueryWrapper<SapPackageBox> sapPackageBoxQueryWrapper = new QueryWrapper<SapPackageBox>().eq("PACKAGE_LIST", packageNumber);
//                    sapPackageBoxMapper.delete(sapPackageBoxQueryWrapper);
                    // 生成装箱单行数据
                    int sort = 1;
//                    int sort2 = 1;
                    for (SapPackageListDtl dtl : list) {
                    	dtl.setSpmsItemNo(sort+"");
                    	++sort;
                    	sapPackageListDtlMapper.insert(dtl);
//                    	if ("X".equals(dtl.getGoodsType())) {
//                    		// 备件货生成装箱单与箱码关系数据
//                    		SapPackageBox sapPackageBox1 = new SapPackageBox();
//                    		sapPackageBox1.setPackageList(dtl.getPackageList());
//                    		sapPackageBox1.setItem(dtl.getItem());
//                    		sapPackageBox1.setBoxNote(dtl.getPackageCode());
//                    		sapPackageBox1.setSpmsItemNo(sort2+"");
//                    		sapPackageBoxMapper.insert(sapPackageBox1);
//                    		++sort2;
//                    	}
                    }
                } else if (packageList != null) {
                	for (SapPackageListDtl dtl : list) {
                		QueryWrapper<SapPackageListDtl> qw = new QueryWrapper<SapPackageListDtl>()
                                .eq("PACKAGE_LIST", dtl.getPackageList())
                                .eq("ITEM", dtl.getItem()).eq("MATERIAL_NO", dtl.getMaterialNo());
                		if ("X".equals(dtl.getGoodsType())) {
                			qw.eq("PACKAGE_CODE", dtl.getPackageCode());
                		}
                        SapPackageListDtl packageListDtl = sapPackageListDtlMapper.selectOne(qw);
                        if (packageListDtl != null){
                            if ("0".equals(packageListDtl.getSpmsStatus()) || StringUtils.isEmpty(packageListDtl.getSpmsStatus())){
                                sapPackageListDtlMapper.update(dtl, qw);
                            }
                        } else {
                        	// 查询这个装箱单下当前最大的SPMS行项目号
                        	int maxNo = iSapPackageListDtlService.selectMaxSpmsItemNo(packageNumber);
                        	dtl.setSpmsItemNo(String.valueOf(maxNo+1));
                            sapPackageListDtlMapper.insert(dtl);
//                            if ("X".equals(dtl.getGoodsType())) {
//                            	// 生成装箱单跟箱码关系数据
//                            	SapPackageBox sapPackageBox1 = new SapPackageBox();
//                            	sapPackageBox1.setPackageList(dtl.getPackageList());
//                            	sapPackageBox1.setItem(dtl.getItem());
//                            	sapPackageBox1.setBoxNote(dtl.getPackageCode());
//                            	sapPackageBoxMapper.insert(sapPackageBox1);
//                            }
                        }
                	}
                }
        	}
        }
	}

	private void setPackHeadData(JSONObject headDoc) {
		if (StringUtils.isNotEmpty(headDoc.toString())){
            SapPackageList sapPackageList = new SapPackageList();
            // 装箱单号
            sapPackageList.setPackageList(headDoc.getString("XDNUM"));
            // 是否杂货
            sapPackageList.setSpareParts(headDoc.getString("ZHBS"));
            // 起运港
            sapPackageList.setFromPort(headDoc.getString("SPORT"));
            // 起运港名称
            sapPackageList.setFromPortName(headDoc.getString("BEZEI"));
            // 目的港
            sapPackageList.setToPort(headDoc.getString("EPORT"));
            // 目的港名称
            sapPackageList.setToPortName(headDoc.getString("EBEZEI"));
            // 装柜员
            sapPackageList.setLoader(headDoc.getString("MERCH"));
            // 计划员
            sapPackageList.setPlanner(headDoc.getString("CRUSR"));
            // 计划员名称
            sapPackageList.setPlannerName(headDoc.getString("BNAME"));
            // 计划柜量
            sapPackageList.setPlannedCabinetsQty(StringUtils.isNotEmpty(headDoc.getString("PCONT")) ? Integer.parseInt(headDoc.getString("PCONT").trim()) : 0);
            // 要求装柜日期
            sapPackageList.setPlanLoadingDate(headDoc.getString("CZDAT"));
            // SPMS状态-默认待处理0
            sapPackageList.setSpmsStatus("0");
            // 数据来源：1SAP推送，2手动创建
            sapPackageList.setDataSource("1");
            QueryWrapper<SapPackageList> queryWrapper = new QueryWrapper<SapPackageList>().eq("PACKAGE_LIST", sapPackageList.getPackageList());
            SapPackageList packageList = this.baseMapper.selectOne(queryWrapper);
            if (packageList != null){
                if ("0".equals(packageList.getSpmsStatus()) || StringUtils.isEmpty(packageList.getSpmsStatus())){
                    this.baseMapper.update(sapPackageList, queryWrapper);
                }
            }else {
                this.baseMapper.insert(sapPackageList);
            }
        }
	}

	@Override
	public ResponseResult zsapCabinetNumberToSpms(JSONObject doc) {
		if (doc == null) {
			return ResponseResult.error("柜号信息推送SPMS失败，推送数据为空").add("STATUS", "E");
		}
//		JSONObject sendData = doc.getJSONObject("SendData");
		// 装箱单行
		JSONArray itemJsons = doc.getJSONArray("itemList");
		if (itemJsons == null || itemJsons.size() == 0) {
			return ResponseResult.error("柜号信息推送SPMS失败，推送数据为空").add("STATUS", "E");
		}
		// 设置柜号信息
		this.setCabinetNumberData(itemJsons);
		
		return ResponseResult.success("柜号信息推送SPMS成功").add("STATUS", "S");
	}

	private void setCabinetNumberData(JSONArray itemJsons) {
		Date nowDate = new Date();
		List<SapPackageListCabinetNumber> insertList = new ArrayList<>();
		for (int i = 0; i < itemJsons.size(); i ++) {
            JSONObject doc = itemJsons.getJSONObject(i);
            if (StringUtils.isNotEmpty(doc.toString())) {
            	SapPackageListCabinetNumber item = new SapPackageListCabinetNumber();
                // 装箱单号
            	item.setPackageList(doc.getString("XDNUM"));
            	// 柜型
            	item.setCabinetModel(doc.getString("MAGRV"));
            	// 柜序号
            	item.setCabinetSerialNumber(doc.getString("CABIN"));
            	// 柜号
            	item.setCabinetNumber(doc.getString("ZDECABNO"));
            	// 推送日期 AEDAT
            	item.setPushDate(doc.getString("AEDAT"));
            	// 推送人 AENAM
            	item.setPushPerson(doc.getString("AENAM"));
            	QueryWrapper<SapPackageListCabinetNumber> queryWrapper = new QueryWrapper<SapPackageListCabinetNumber>()
            			.eq("PACKAGE_LIST", item.getPackageList()).eq("CABINET_SERIAL_NUMBER", item.getCabinetSerialNumber());
            	int count = iSapPackageListCabinetNumberService.count(queryWrapper);
            	if (count > 0) {
            		item.setUpdateTime(nowDate);
            		// 如果存在，先删除，再新增
            		iSapPackageListCabinetNumberService.update(item, queryWrapper);
            	} else {
            		item.setCreateTime(nowDate);
            		insertList.add(item);
            	}
            }
		}
		if (CollectionUtils.isNotEmpty(insertList)) {
			iSapPackageListCabinetNumberService.saveBatch(insertList);
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public ResponseResult getSapDataToCreatePackageList(String userId, String packageList, String werks,
			String whsLocationCode, String cabinetSerialNumber, String goodsType) throws Exception {
		if (StringUtils.isEmpty(packageList) || StringUtils.isEmpty(werks) || StringUtils.isEmpty(whsLocationCode) ||
				StringUtils.isEmpty(cabinetSerialNumber) || StringUtils.isEmpty(goodsType)) {
			ResponseResult.error("参数：装箱单号、装柜工厂、装柜仓库、柜序号、货物类型不能为空");
		}
		// 调用接口ZZXD_IF_SPMS_14接口获取SAP装箱单头信息
		JSONObject toSapData = null;
        JSONObject dataToSap = JSONObject.parseObject(toSapData.toString());
        JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon((dataToSap)));
        // 保存接口日志
        iSysLogMqService.addSysLogMq(SEND_MSG, "ZZXD_IF_SPMS_14", "SPMS获取SAP装箱单数据创建出库任务接口", "ZZXD_IF_SPMS_14", dataToSap.toJSONString(), message.toString(), null);
        JSONObject RETURN_DATA = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
        JSONArray ET_RET = RETURN_DATA.getJSONArray("ET_RET");
        if (ET_RET.size() > 0 && "S".equals(ET_RET.getJSONObject(0).getString("TYPE"))) {
            // SAP会返回装柜实际行项目，需要进行更新
            for (int i = 0; i < ET_RET.size(); i++) {
            	JSONObject objs = ET_RET.getJSONObject(i);
            	// 装箱单号
            	String xdnum = objs.getString("XDNUM");
            	// 装箱单行号
            	String posnr_2 = objs.getString("POSNR_2").replaceAll("^(0+)", "");
            	// SPMS行项目号
            	String spmsPosnr = objs.getString("SPMS_POSNR").replaceAll("^(0+)", "");
//            	QueryWrapper<SapPackageListDtl> eq = new QueryWrapper<SapPackageListDtl>().eq("PACKAGE_LIST", whsOut.getPackageList())
//            			.eq("WHS_OUT_UUID", whsOut.getUuid()).eq("ITEM", posnr_2);
//            	List<SapPackageListDtl> dtlList = iSapPackageListDtlService.list(eq);
            	
            }
            // 创建装箱单
            iSapDeliveryNoteLogService.insertSapRequestRecord(packageList, userId, CREATE_SAP_PACKAGE_LIST, null, JSONObject.toJSONString(message));
            //记录 装箱单生成出库任务 日志
            iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(packageList, userId, SAP_PACKAGE_LIST_TO_WHS_OUT_TASK);
            // 记录日志-出库任务初始化
//            iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(uuid, userId, WHS_OUT_TASK_GENERATE);
        } else {
        	throw new Exception("创建出库任务获取SAP装箱单数据失败："+message.toJSONString());
        }
        return ResponseResult.success();
	}

	@Override
	public ResponseResult selectReceivingWerks(String userId, String packageList, String werks) {
		// 根据装箱单号、装柜工厂查询出库任务
		QueryWrapper<WhsOut> eq = new QueryWrapper<WhsOut>().eq("WERKS", werks).eq("PACKAGE_LIST", packageList);
		List<WhsOut> outList = whsOutMapper.selectList(eq);
		SapPackageListDtl dtl = new SapPackageListDtl();
		if (CollectionUtils.isNotEmpty(outList)) {
			for (WhsOut out : outList) {
				// 根据出库任务UUID查询出库任务行明细
				QueryWrapper<SapPackageListDtl> query = new QueryWrapper<SapPackageListDtl>().eq("WHS_OUT_UUID", out.getUuid())
						.eq("PACKAGE_LIST", packageList);
				List<SapPackageListDtl> list = iSapPackageListDtlService.list(query);
				if (CollectionUtils.isNotEmpty(list)) {
					dtl = list.get(0);
					break;
				}
			}
		} 
		return ResponseResult.success().add("sapPackageListDtl", dtl);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public synchronized int updateSapPackageListByPda(String userId, JSONObject obj) throws Exception {
		JSONObject packageObj = obj.getJSONObject("sapPackageList");
		JSONArray dtlArray = obj.getJSONArray("sapPackageListDtl");
		if (packageObj == null || dtlArray == null || dtlArray.size() == 0) {
			return -1;
		}
		String packageList = packageObj.getString("packageList");
        QueryWrapper<SapPackageList> queryWrapper = new QueryWrapper<SapPackageList>().eq("PACKAGE_LIST", packageList);
        SapPackageList sapPackageList = this.baseMapper.selectOne(queryWrapper);
        if (sapPackageList != null){
        	String currentStatus = "0";
        	String targetStatus = "1";
            // 装箱单单据当前状态 跟前端 请求时的当前状态一致时才能执行更新操作；任务在SPMS状态(0待处理；1处理中；2处理完成)
            if (currentStatus.equals(sapPackageList.getSpmsStatus())){
                SapPackageList sapPackageList1 = new SapPackageList();
                sapPackageList1.setSpmsStatus(targetStatus);
                // 更新装箱单状态；更新装箱单行项目状态
                int result =  this.baseMapper.update(sapPackageList1, queryWrapper);
                iSapPackageListDtlService.updateSapPackageListDtl(packageList, targetStatus);
                // 记录 更新装箱单 日志
                if ("1".equals(targetStatus)){
                    iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(packageList, userId, UPDATE_SAP_PACKAGE_LIST);
                }
                // 当装箱单表头更新成功且目标状态 targetStatus 为 1 时，告知SAP装箱单已开始处理，调用装箱单上锁接口，生成出库任务及明细 
                if (result == 1 && "1".equals(targetStatus)){
                	// 生成出库任务
                    this.generateWhsOutTaskPda(packageList, userId, dtlArray);
                    //记录 装箱单生成出库任务 日志
                    iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(packageList, userId, SAP_PACKAGE_LIST_TO_WHS_OUT_TASK);
                }
                if ("2".equals(targetStatus)){
                    iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(packageList, userId, CLOSE_SAP_PACKAGE_LIST);
                }
                return result;
            }
        }
        return -2;
	}

	@SuppressWarnings("unchecked")
	private void generateWhsOutTaskPda(String packageList, String userId, JSONArray dtlArray) {
		// PDA只操作备件行项目，所以PDA传到后台的行项目都是备件行项目
		for (int i = 0; i < dtlArray.size(); i++) {
			Map<String, Object> map = (Map<String, Object>) dtlArray.get(i);
			QueryWrapper<SapPackageListDtl> dtlWrapper = new QueryWrapper<SapPackageListDtl>().eq("PACKAGE_LIST", packageList)
					.eq("ITEM", map.get("item").toString()).eq("SPMS_ITEM_NO", map.get("oldSpmsItemNo").toString()).eq("GOODS_TYPE", map.get("goodsType").toString());
			SapPackageListDtl dtl = new SapPackageListDtl();
			dtl.setShipper(map.get("shipper").toString());
			dtl.setLoadingWerks(map.get("loadingWerks").toString());
			dtl.setLoadingWhsLocationCode(map.get("loadingWhsLocationCode").toString());
			dtl.setActualOperateQty(map.get("actualOperateQty") != null ? Double.valueOf(map.get("actualOperateQty").toString()) : 0);
			dtl.setActualPackingNumber(map.get("actualPackingNumber") != null ? Double.valueOf(map.get("actualPackingNumber").toString()) : 0);
			iSapPackageListDtlService.update(dtl, dtlWrapper);
		}
		QueryWrapper<SapPackageList> sapWrapper = new QueryWrapper<SapPackageList>().eq("PACKAGE_LIST", packageList);
        SapPackageList sapPackageList = this.baseMapper.selectOne(sapWrapper);
    	// 查询装箱单行明细中贸易货
    	List<Map<String, Object>> getSapPackageList = iSapPackageListDtlService.getSapPackageList(packageList, null);
    	if (CollectionUtils.isNotEmpty(getSapPackageList)) {
    		// 根据发货主体、发货工厂、装柜仓库、柜序号、货物类型（贸易货、备件货）进行分组生成不同的出库任务
    		Map<String, List<Map<String, Object>>> outMaps = getSapPackageList.stream().collect(Collectors.groupingBy(e -> 
    		e.get("shipper").toString()+"_"+e.get("loadingWhsLocationCode").toString()+"_"+
    				e.get("cabinetSerialNumber").toString()+"_"+e.get("goodsType").toString()+"_"+
    				e.get("loadingWerks").toString()));
    		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String createDate = sdf.format(new Date());
    		for (String key : outMaps.keySet()) {
    			List<Map<String, Object>> list = outMaps.get(key);
    			String[] split = key.split("_");
    			// 任务如果不存在则新建出库任务，更新装箱单明细 出库任务uuid 字段；如果存在则将该任务的 uuid 更新到装箱单明细 出库任务uuid 字段
    			QueryWrapper<WhsOut> outQuery = new QueryWrapper<WhsOut>().eq("SHIPPER", split[0]).eq("PACKAGE_LIST", packageList)
    					.eq("WHS_LOCATION_CODE", split[1]).eq("GOODS_TYPE", split[3]).eq("CABINET_SERIAL_NUMBER", split[2])
    					.eq("WERKS", split[4]);
    			// 贸易货计算同个出库任务下相同物料的最大包装件数
    			if ("M".equals(split[3])) {
    				// 根据物料号分组
    				Map<String, List<Map<String, Object>>> materialNoMaps = list.stream().collect(Collectors.groupingBy(o -> o.get("materialNo").toString()));
    				for (String materialNo : materialNoMaps.keySet()) {
    					BigDecimal allSaleQuantity = BigDecimal.ZERO;
    					List<Map<String, Object>> materialList = materialNoMaps.get(materialNo);
    					for (Map<String, Object> map : materialList) {
    						if (map.get("plannedPackingNumber") != null) {
    							allSaleQuantity = allSaleQuantity.add(new BigDecimal(map.get("plannedPackingNumber").toString()));
    						}
    					}
    					// 将最大包装件数更新到装箱单行中
    					for (Map<String, Object> map : materialList) {
    						QueryWrapper<SapPackageListDtl> eq = new QueryWrapper<SapPackageListDtl>().eq("PACKAGE_LIST", map.get("packageList").toString())
    								.eq("ITEM", map.get("item").toString()).eq("SPMS_ITEM_NO", map.get("spmsItemNo").toString())
    								.eq("LOADING_WERKS", map.get("loadingWerks")).eq("GOODS_TYPE", map.get("goodsType").toString())
    								.eq("MATERIAL_NO", map.get("materialNo").toString());
    						SapPackageListDtl dtl = new SapPackageListDtl();
    						dtl.setPackageQuantityMax(allSaleQuantity.stripTrailingZeros().toPlainString());
    						dtl.setPackageUnitMax(map.get("packingUnit").toString());
    						iSapPackageListDtlService.update(dtl, eq);
    					}
    				}
    			} else {
    				// 备件货：统计在一个出库任务中一个物料存在箱码的数量
    				Map<String, List<Map<String, Object>>> materialNoMaps = list.stream().filter(m -> m.get("materialNo") != null).collect(Collectors.groupingBy(o -> o.get("materialNo").toString()));
    				for (String materialNo : materialNoMaps.keySet()) {
    					List<Map<String, Object>> materialList = materialNoMaps.get(materialNo);
    					// 将最大包装件数更新到装箱单行中
    					for (Map<String, Object> map : materialList) {
    						if (map.get("packageCode") == null) {
    							continue;
    						}
    						QueryWrapper<SapBoxNoteDtl> eq = new QueryWrapper<SapBoxNoteDtl>().eq("BOX_NOTE", map.get("packageCode").toString())
    								.eq("MATERIAL_NO", map.get("materialNo").toString());
    						SapBoxNoteDtl dtl = new SapBoxNoteDtl();
    						dtl.setPackageQuantityMax(String.valueOf(materialList.size()));
    						dtl.setPackageUnitMax("PCS");
    						iSapBoxNoteDtlService.update(dtl, eq);
    					}
    				}
    			}
    			WhsOut whsOut = whsOutMapper.selectOne(outQuery);
    			String uuid = UUID.randomUUID().toString().replaceAll("-","").toLowerCase();
    			if (whsOut == null){
                    WhsOut whsOut1 = new WhsOut();
                    whsOut1.setUuid(uuid);
                    whsOut1.setWerks(split[4]);
                    whsOut1.setWhsLocationCode(split[1]);
                    whsOut1.setPackageList(packageList);
                    whsOut1.setGoodsType(split[3]);
                    whsOut1.setDateOfLoading(sapPackageList.getPlanLoadingDate());
                    whsOut1.setCabinetSerialNumber(split[2]);
                    whsOut1.setCreateUserid(userId);
                    whsOut1.setCreateDate(createDate);
                    whsOut1.setCabinetModel(StringUtils.isNotEmpty(sapPackageList.getCabinetModel()) ? sapPackageList.getCabinetModel() : list.get(0).get("cabinetModel").toString());
//                    whsOut1.setCabinetNumber(list.get(0).get("cabinetNumber") != null ? list.get(0).get("cabinetNumber").toString() : "");
                    whsOut1.setShipper(split[0]);
                    //给出库任务一个初始状态：0待执行
                    whsOut1.setTaskStatus("0");
                    // 数据来源
                    whsOut1.setDataSource(sapPackageList.getDataSource());
                    whsOutMapper.insert(whsOut1);
                    // 记录日志-出库任务初始化
                    iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(uuid, userId, WHS_OUT_TASK_GENERATE);
                }
    			// 将出库任务的 uuid 回写到 SAP装箱单任务明细 对应的行中
    			for (Map<String, Object> map : list) {
    				SapPackageListDtl sapPackageListDtl = new SapPackageListDtl();
    		        sapPackageListDtl.setWhsOutUuid(whsOut == null ? uuid : whsOut.getUuid());
    		        sapPackageListDtl.setSpmsStatus("1");
    		        QueryWrapper<SapPackageListDtl> queryWrapper = new QueryWrapper<SapPackageListDtl>().eq("PACKAGE_LIST", packageList).eq("SPMS_ITEM_NO", map.get("oldSpmsItemNo").toString());
    		        iSapPackageListDtlService.update(sapPackageListDtl, queryWrapper);
    		        // 更新装箱单跟箱码关系表的出库任务UUID
//    		        SapPackageBox box = new SapPackageBox();
//    		        box.setWhsOutUuid(whsOut == null ? uuid : whsOut.getUuid());
//    		        QueryWrapper<SapPackageBox> boxWrapper = new QueryWrapper<SapPackageBox>().eq("PACKAGE_LIST", packageList).eq("ITEM", map.get("item").toString());
//    		        sapPackageBoxMapper.update(box, boxWrapper);
    			}
    		}
    	}
		
	}

	@Override
	public Page<Map<String, Object>> getSapPackageListPageByPda(String userId, String packageList, String spmsStatus,
			String planLoadingDateStart, String planLoadingDateEnd, int pageNo, int pageSize, String werks,
			String whsLocationCode) {
		pageNo = pageNo <= 0 ? 1 : pageNo;
        pageSize = pageSize <= 0 ? 20 : pageSize;
        packageList = StringUtils.isNotEmpty(packageList) ? packageList : null;
        spmsStatus = StringUtils.isNotEmpty(spmsStatus) ? spmsStatus : null;
        werks = StringUtils.isNotEmpty(werks) ? werks : null;
        whsLocationCode = StringUtils.isNotEmpty(whsLocationCode) ? whsLocationCode : null;
        planLoadingDateStart = StringUtils.isNotEmpty(planLoadingDateStart) ? planLoadingDateStart : null;
        planLoadingDateEnd = StringUtils.isNotEmpty(planLoadingDateEnd) ? planLoadingDateEnd : null;
        Page<Map<String, Object>> pages = new Page<>(pageNo, pageSize);
        List<Map<String, Object>> pageMaData = this.baseMapper.getSapPackageListPageByPda(pages, userId, packageList, spmsStatus, planLoadingDateStart, planLoadingDateEnd, werks, whsLocationCode);
        pages.setRecords(pageMaData);
        return pages;
	}
}
