package com.sunda.spmswms.service.impl;

import com.alibaba.fastjson.JSON;
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.entity.ZSapOrgClient;
import com.sunda.spmscommon.feign.IFeignServiceCommon;
import com.sunda.spmscommon.mapper.ZSapOrgClientMapper;
import com.sunda.spmswms.entity.SapBoxNote;
import com.sunda.spmswms.entity.SapBoxNoteDtl;
import com.sunda.spmswms.entity.SapPackageNote;
import com.sunda.spmswms.entity.Werks;
import com.sunda.spmswms.entity.WhsDump;
import com.sunda.spmswms.entity.WhsDumpDtl;
import com.sunda.spmswms.entity.WhsInventoryInfo;
import com.sunda.spmswms.entity.WhsStorage;
import com.sunda.spmswms.entity.WhsStorageInventory;
import com.sunda.spmswms.mapper.WhsDumpMapper;
import com.sunda.spmswms.service.*;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.Map.Entry;

import static com.sunda.spmscommon.Constans.*;
import static com.sunda.spmscommon.constant.CommonConstant.WHS_DUMP_DELETE;
import static com.sunda.spmscommon.constant.CommonConstant.WHS_DUMP_DONE;
import static com.sunda.spmscommon.constant.CommonConstant.*;

/**
 * <p>
 * 转储任务表 服务实现类
 * </p>
 *
 * @author Wayne
 * @since 2021-06-29
 */
@Slf4j
@Service
public class WhsDumpServiceImpl extends ServiceImpl<WhsDumpMapper, WhsDump> implements IWhsDumpService {

    @Autowired
    IWhsStorageInventoryService iWhsStorageInventoryService;

    @Autowired
    IWhsInventoryInfoService iWhsInventoryInfoService;
    
    @Autowired
    IWhsStorageService iWhsStorageService;
    
    @Autowired
    ISapBoxNoteService iSapBoxNoteService;
    
    @Autowired
    ISapPackageNoteService iSapPackageNoteService;
    
    @Autowired
    ISapBoxNoteDtlService iSapBoxNoteDtlService;

    @Autowired
    IWhsOperateLogService iWhsOperateLogService;

    @Autowired
    ISapDeliveryNoteLogService iSapDeliveryNoteLogService;

    @Autowired
    IWhsDumpDtlService iWhsDumpDtlService;

    @Autowired
    IFeignServiceCommon iFeignServiceCommon;
    
    @Autowired
    IWerksService iWerksService;
    
    @Autowired
    ZSapOrgClientMapper zSapOrgClientMapper;
    
    @Value("${zxd.sap.client}")
    private String zxdSapClient;

    @Override
    public WhsDump getWhsDumpByUuid(String whsDumpUuid) {
        if (StringUtils.isEmpty(whsDumpUuid)){
            return null;
        }
        return this.baseMapper.selectOne(new QueryWrapper<WhsDump>().eq("WHS_DUMP_UUID", whsDumpUuid));
    }

    /**
     {
     "beginDate": "2021-08-10",
     "endDate": "2021-08-14",
     "whsDumpNo": "",
     "goodsType": "",
     "werksDumpOut": "",
     "whsLocationCodeDumpOut": "",
     "spmsStatus": "",
     "sapDumpOutNo": "",
     "sapDeliveryNote": "",
     "werksDumpIn": "",
     "whsLocationCodeDumpIn": "",
     "pageNo": 1,
     "pageSize": 20
     }
     * @param doc
     * @return
     */
    @Override
    public Page<Map<String, Object>> getWhsDumpListPage(JSONObject doc) {
        try {
            int pageNo = StringUtils.isEmpty(doc.getString("pageNo")) ? 1 : doc.getInteger("pageNo");
            int pageSize = StringUtils.isEmpty(doc.getString("pageSize")) ? 20 : doc.getInteger("pageSize");
            String whsDumpNo = StringUtils.isEmpty(doc.getString("whsDumpNo")) ? null : doc.getString("whsDumpNo");
            String goodsType = StringUtils.isEmpty(doc.getString("goodsType")) ? null : doc.getString("goodsType");
            String werksDumpOut = StringUtils.isEmpty(doc.getString("werksDumpOut")) ? null : doc.getString("werksDumpOut");
            String whsLocationCodeDumpOut = StringUtils.isEmpty(doc.getString("whsLocationCodeDumpOut")) ? null : doc.getString("whsLocationCodeDumpOut");
            String spmsStatus = StringUtils.isEmpty(doc.getString("spmsStatus")) ? null : doc.getString("spmsStatus");
            String sapDumpOutNo = StringUtils.isEmpty(doc.getString("sapDumpOutNo")) ? null : doc.getString("sapDumpOutNo");
            String sapDeliveryNote = StringUtils.isEmpty(doc.getString("sapDeliveryNote")) ? null : doc.getString("sapDeliveryNote");
            String werksDumpIn = StringUtils.isEmpty(doc.getString("werksDumpIn")) ? null : doc.getString("werksDumpIn");
            String whsLocationCodeDumpIn = StringUtils.isEmpty(doc.getString("whsLocationCodeDumpIn")) ? null : doc.getString("whsLocationCodeDumpIn");
            String transportType = StringUtils.isEmpty(doc.getString("transportType")) ? null : doc.getString("transportType");
            String beginDate = StringUtils.isEmpty(doc.getString("beginDate")) ? null : doc.getString("beginDate");
            String endDate = StringUtils.isEmpty(doc.getString("endDate")) ? null : doc.getString("endDate");
            Page<Map<String, Object>> pages = new Page<>(pageNo, pageSize);
            List<Map<String, Object>> pageMaData = this.baseMapper.pageWhsDumpDataMap(pages, whsDumpNo, goodsType, werksDumpOut, whsLocationCodeDumpOut,
                    spmsStatus, sapDumpOutNo, sapDeliveryNote, werksDumpIn, whsLocationCodeDumpIn, beginDate, endDate, transportType);
            pages.setRecords(pageMaData);
            return pages;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * SPMS转储单据状态（0删除；1草稿；2转出可执行；3转出完成；4提交SAP获取PO成功；5提交SAP获取PO失败；
     * 6提交SAP获取DN成功；7提交SAP获取DN失败；8转出已撤销；）
     * 当前状态：1，2，5 可调用此接口
     * @param doc
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult saveWhsDump(JSONObject doc, String userId) throws Exception{
        ResponseResult checkResult = checkDataValidate(doc);
        if (checkResult.getCode() != 200){
            return checkResult;
        }
        JSONObject whsDumpObject = doc.getJSONObject("whsDump");
        JSONArray whsDumpArray = doc.getJSONArray("whsDumpDtl");
        String whsDumpUuid = whsDumpObject.getString("whsDumpUuid");
        String targetStatus = whsDumpObject.getString("targetStatus");
        WhsDump whsDump = whsDumpObject.toJavaObject(WhsDump.class);
        if (StringUtils.isEmpty(whsDumpUuid)){
            whsDumpUuid = UUID.randomUUID().toString().toLowerCase().replaceAll("-","");
            int resp = createWhsDumpAndDtl(whsDumpUuid, whsDump, whsDumpArray, targetStatus, userId);
            if (resp < 0){
                throw new RuntimeException("转储任务创建失败");
            }
            return ResponseResult.success()
                    .add("whsDumpList", getWhsDumpByUuid(whsDumpUuid))
                    .add("whsDumpDtl", iWhsDumpDtlService.getWhsDumpDtlList(whsDumpUuid));
        }else {
            if ("1".equals(targetStatus) || "2".equals(targetStatus)
                    || "3".equals(targetStatus) || "5".equals(targetStatus)){
                int resp = updateWhsDumpAndDtl(whsDump, whsDumpArray, targetStatus, userId);
                if (resp < 0){
                    throw new RuntimeException("转储任务更新失败");
                }
                return ResponseResult.success()
                        .add("whsDumpList", getWhsDumpByUuid(whsDumpUuid))
                        .add("whsDumpDtl", iWhsDumpDtlService.getWhsDumpDtlList(whsDumpUuid));
            }
            return ResponseResult.error("当前状态禁止此操作");
        }
    }

    private ResponseResult sendPackageDataToSAP(WhsDump whsDump, List<WhsDumpDtl> whsDumpDtlList) {
    	// 一个包装码调用一次接口
    	Map<String, List<WhsDumpDtl>> packageNoteMaps = new HashMap<>();
    	if (whsDumpDtlList.size() > 0){
            for (int i = 0; i < whsDumpDtlList.size(); i++){
            	WhsDumpDtl whsDumpDtl = whsDumpDtlList.get(i);
                if (whsDumpDtl.getActualOutQty() != null && whsDumpDtl.getActualOutQty() > 0) {
                	SapBoxNote byBoxNote = iSapBoxNoteService.getByBoxNote(whsDumpDtl.getBoxNote());
                	if (byBoxNote != null) {
                		if (CollectionUtils.isEmpty(packageNoteMaps.get(byBoxNote.getPackageNote()))) {
                			List<WhsDumpDtl> li = new ArrayList<WhsDumpDtl>();
                			li.add(whsDumpDtl);
                			packageNoteMaps.put(byBoxNote.getPackageNote(), li);
                		} else {
                			List<WhsDumpDtl> list = packageNoteMaps.get(byBoxNote.getPackageNote());
                			list.add(whsDumpDtl);
                			packageNoteMaps.put(byBoxNote.getPackageNote(), list);
                		}
                	}
                }
            }
        }
    	if (packageNoteMaps != null && !packageNoteMaps.isEmpty()) {
    		for (Entry<String, List<WhsDumpDtl>> entry : packageNoteMaps.entrySet()) {
    			String packageNote = entry.getKey();
    			List<WhsDumpDtl> list = entry.getValue();
    			QueryWrapper<SapPackageNote> qw = new QueryWrapper<SapPackageNote>().eq("PACKAGE_NOTE", packageNote);
    			SapPackageNote sapPackageNote = iSapPackageNoteService.getOne(qw);
    			// 设置IT_HEAD数据
    			Map<String, Object> itHead = new HashMap<>();
    			this.setItHeadData(sapPackageNote, itHead);
    			// 设置IT_XHEAD数据
    			JSONArray array = new JSONArray();
    			this.setItXheadData(list, array, whsDump);
    			// 设置IT_ITEM数据
    			List<Map<String, Object>> itItem = new ArrayList<>();
    			this.setItItemData(whsDump, list, itItem);
    			// 调用接口同步SAP
    			JSONObject doc = new JSONObject();
    	        JSONObject REQUEST = new JSONObject();
    	        JSONObject ESB_ATTRS = new JSONObject();
    	        JSONObject REQUEST_DATA = new JSONObject();
    	        ESB_ATTRS.put("App_ID", "SPMS");
    	        ESB_ATTRS.put("Application_ID", "00020000000002");
    	        ESB_ATTRS.put("Transaction_ID", UUID.randomUUID().toString());
    	        JSONObject tables = new JSONObject();
    	        List<Map<String, Object>> it_head = new ArrayList<>();
    	        it_head.add(itHead);
    	        tables.put("IT_HEAD", it_head);
    	        tables.put("IT_XHEAD", array);
    	        tables.put("IT_ITME", itItem);
    	        List<ZSapOrgClient> clinetList = zSapOrgClientMapper.selectList(new QueryWrapper<ZSapOrgClient>().eq("WERKS", whsDump.getWerksDumpOut()));
                if (CollectionUtils.isNotEmpty(clinetList)) {
                	ESB_ATTRS.put("Target_ID", "SAP-"+clinetList.get(0).getZmandt());
                } else {
                	return ResponseResult.error("工厂："+whsDump.getWerksDumpOut()+"未找到对应的SAP Clinet");
                }
                REQUEST_DATA.put("tables", tables);
    	        REQUEST_DATA.put("Operation", "Z_SPMS_SETBOXCODE");
    	        REQUEST_DATA.put("Type", "SETBOXCODE");
    	        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
    	        REQUEST.put("REQUEST_DATA", REQUEST_DATA);
    	        doc.put("REQUEST", REQUEST);
    	        JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(doc));
    	        log.info("\n=====国内空运人带箱码推送SAP数据：======\n" + doc + "\n=====国内仓空运人带箱码SAP返回数据：======\n" + message);
    	        if (!"S".equals(message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getString("O_TYPE"))) {
    	        	return ResponseResult.error("箱码信息同步SAP调用接口失败："+message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getString("O_MSTXT"));
    	        }
    		}
    	}
    	return ResponseResult.success();
	}

	private void setItItemData(WhsDump whsDump, List<WhsDumpDtl> list, List<Map<String, Object>> itItem) {
		for (WhsDumpDtl dtl : list) {
			WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getBoxNoteStorage(dtl.getBoxNote());
			WhsStorage whsStorage = iWhsStorageService.getWhsStorageByUuid(whsStorageInventory.getUuid());
            Werks werks = iWerksService.getOne(new QueryWrapper<Werks>().eq("WERKS", whsStorage.getWerks()));
			List<SapBoxNoteDtl> sapBoxNoteDtlList = iSapBoxNoteDtlService.getSapBoxNoteDtlList(dtl.getBoxNote());
			for (SapBoxNoteDtl sapBoxNoteDtl : sapBoxNoteDtlList) {
				Map<String, Object> map = new HashMap<>();
	            map.put("PACKAGE_NO", sapBoxNoteDtl.getPackageNote());
	            map.put("SERIAL", sapBoxNoteDtl.getItem().toString());
	            map.put("PACKAGE_CODE", sapBoxNoteDtl.getBoxNote());
	            map.put("PACKAGE_POSNR", sapBoxNoteDtl.getPackagePosnr() != null ? sapBoxNoteDtl.getPackagePosnr().toString() : "");
	            map.put("MATNR", sapBoxNoteDtl.getMaterialNo());
	            map.put("SPECS", sapBoxNoteDtl.getSpecs() != null ? sapBoxNoteDtl.getSpecs() : "");
	            map.put("MENGE", sapBoxNoteDtl.getQuantity() != null ? sapBoxNoteDtl.getQuantity().toString() : "0");
	            map.put("MEINS", sapBoxNoteDtl.getBasicUnit());
	            map.put("SRM_CONTRACT_NO", sapBoxNoteDtl.getSrmContractNo() != null ? sapBoxNoteDtl.getSrmContractNo() : "");
	            map.put("EBELN", sapBoxNoteDtl.getPurchaseNo() != null ? sapBoxNoteDtl.getPurchaseNo() : "");
	            map.put("EBELP", sapBoxNoteDtl.getPurchaseNoItem() != null ? sapBoxNoteDtl.getPurchaseNoItem().toString() : "");
	            map.put("VBELN", sapBoxNoteDtl.getDeliveryNoteSap() != null ? sapBoxNoteDtl.getDeliveryNoteSap() : "");
	            map.put("POSNR", sapBoxNoteDtl.getDeliveryNoteSapItem() != null ? sapBoxNoteDtl.getDeliveryNoteSapItem().toString() : "");
	            map.put("DEMAND_NO", sapBoxNoteDtl.getDemandNo() != null ? sapBoxNoteDtl.getDemandNo() : "");
	            map.put("DEMAND_POSNR", sapBoxNoteDtl.getDemandNoItem() != null ? sapBoxNoteDtl.getDemandNoItem().toString() : "");
	            map.put("DEMANDER", sapBoxNoteDtl.getDemander() != null ? sapBoxNoteDtl.getDemander() : "");
	            map.put("MARK", sapBoxNoteDtl.getRemark() != null ? sapBoxNoteDtl.getRemark() : "");
	            map.put("BRGEW", sapBoxNoteDtl.getGrossWeight() != null ? sapBoxNoteDtl.getGrossWeight().toString() : "0");
	            map.put("NTGEW", sapBoxNoteDtl.getNetWeight() != null ? sapBoxNoteDtl.getNetWeight().toString() : "0");
	            map.put("GNSHSL", sapBoxNoteDtl.getDomesticQtyReceivable() != null ? sapBoxNoteDtl.getDomesticQtyReceivable().toString() : "0");
	            map.put("GNSJSL", sapBoxNoteDtl.getDomesticQtyReceived() != null ? sapBoxNoteDtl.getDomesticQtyReceived().toString() : "0");
	            map.put("HWSHSL", sapBoxNoteDtl.getOverseaQtyReceived() != null ? sapBoxNoteDtl.getOverseaQtyReceived().toString() : "0");
	            if (werks != null) {
	            	map.put("BUKRS", werks.getCompanyCode());
	            }
	            itItem.add(map);
			}
		}
	}

	private void setItXheadData(List<WhsDumpDtl> list, JSONArray array, WhsDump whsDump) {
		for (WhsDumpDtl dtl : list) {
			SapBoxNote sapBoxNote = this.iSapBoxNoteService.getByBoxNote(dtl.getBoxNote());
			Map<String, Object> map = new HashMap<>();
			map.put("PACKAGE_NO", sapBoxNote.getPackageNote());
			map.put("PACKAGE_CODE", sapBoxNote.getBoxNote());
			map.put("OUTER_BOX_TEXTURE", sapBoxNote.getBoxMaterialName());
			map.put("TOTAL_QTY", sapBoxNote.getTotalQty() != null ? String.valueOf(sapBoxNote.getTotalQty()) : "");
			map.put("BOX_BRGEW", sapBoxNote.getBoxGrossWeight() != null ? sapBoxNote.getBoxGrossWeight().toString() : "");
			map.put("BOX_VOLUM", sapBoxNote.getBoxVolume() != null ? sapBoxNote.getBoxVolume().toString() : "");
			map.put("LENGTH", sapBoxNote.getBoxLength() != null ? sapBoxNote.getBoxLength().toString() : "");
			map.put("WIDTH", sapBoxNote.getBoxWidth() != null ? sapBoxNote.getBoxWidth().toString() : "");
			map.put("HEIGHT", sapBoxNote.getBoxHeight() != null ? sapBoxNote.getBoxHeight().toString() : "");
			map.put("COLOR", sapBoxNote.getBoxColor());
			WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getBoxNoteStorage(dtl.getBoxNote());
			WhsStorage whsStorage = iWhsStorageService.getWhsStorageByUuid(whsStorageInventory.getUuid());
			map.put("WERKS_CF", whsStorage.getWerks());
			map.put("LGORT_CF", whsStorage.getWhsLocationCode());
			// 箱码状态
			map.put("STATSU_PKCODE", "2");
			// 箱码类型：运输方式是空运=0的传2，人带=1的传3
			if ("0".equals(whsDump.getTransportType())) {
				map.put("CODE_TYPE", "2");
			} else {
				map.put("CODE_TYPE", "3");
			}
			array.add(map);
		}
	}

	private void setItHeadData(SapPackageNote sapPackageNote, Map<String, Object> itHead) {
		itHead.put("PACKAGE_NO", sapPackageNote.getPackageNote());
		itHead.put("SRM_DN", sapPackageNote.getDeliveryNoteSrm());
		itHead.put("SAP_DN", sapPackageNote.getDeliveryNoteSap());
		itHead.put("LIFNR", sapPackageNote.getSupplierCode());
		itHead.put("VOLUM_T", sapPackageNote.getTotalVolume() != null ? sapPackageNote.getTotalVolume().toString() : "");
		itHead.put("BRGEW_T", sapPackageNote.getTotalWeight() != null ? sapPackageNote.getTotalWeight().toString() : "");
		itHead.put("ZXDATE_F", sapPackageNote.getLoadBeginTime());
		itHead.put("ZXDATE_T", sapPackageNote.getLoadEndTime());
		itHead.put("YSR", sapPackageNote.getTransporter());
		itHead.put("CYRLXFS", sapPackageNote.getContractorInfo());
		itHead.put("SHR", sapPackageNote.getReceiver());
		itHead.put("SHRLXFS", sapPackageNote.getReceiverInfo());
		itHead.put("SHDZ", sapPackageNote.getReceivingAddress());
		itHead.put("SPMS_CONTRACT_NO", sapPackageNote.getSpmsContractNote());
		itHead.put("SPMS_FLG", "S");
	}

	int updateWhsDumpAndDtl(WhsDump whsDump, JSONArray whsDumpArray, String targetStatus, String userId){
        try {
            String whsDumpUuid = whsDump.getWhsDumpUuid();
            QueryWrapper<WhsDump> queryWrapper = new QueryWrapper<WhsDump>().eq("WHS_DUMP_UUID", whsDumpUuid);
            whsDump.setSpmsStatus(targetStatus);
            this.baseMapper.update(whsDump, queryWrapper);
            if (whsDumpArray.size() > 0){
                iWhsDumpDtlService.deleteWhsDumpDtl(whsDumpUuid);
                for (int i = 0; i < whsDumpArray.size(); i++){
                    JSONObject whsDumpDtlObject = whsDumpArray.getJSONObject(i);
                    WhsDumpDtl whsDumpDtl = whsDumpDtlObject.toJavaObject(WhsDumpDtl.class);
                    whsDumpDtl.setActualOutStorage(StringUtils.isNotEmpty(whsDumpDtlObject.getString("actualOutStorage"))? whsDumpDtlObject.getJSONArray("actualOutStorage").toJSONString():"[]");
                    whsDumpDtl.setActualInStorage(StringUtils.isNotEmpty(whsDumpDtlObject.getString("actualInStorage"))? whsDumpDtlObject.getJSONArray("actualInStorage").toJSONString():"[]");
                    whsDumpDtl.setWhsDumpUuid(whsDumpUuid);
                    iWhsDumpDtlService.createWhsDumpDtl(whsDumpDtl);
                }
            }
            addWhsDumpOperateLog(whsDumpUuid, userId, targetStatus);
            return 1;
        }catch (Exception e){
            e.printStackTrace();
            return -1;
        }
    }

    int createWhsDumpAndDtl(String whsDumpUuid, WhsDump whsDump, JSONArray whsDumpArray, String targetStatus, String userId){
        try {
            whsDump.setSpmsStatus(targetStatus);
            whsDump.setWhsDumpUuid(whsDumpUuid);
            this.baseMapper.insert(whsDump);
            if (whsDumpArray.size() > 0){
                for (int i = 0; i < whsDumpArray.size(); i++){
                    JSONObject whsDumpDtlObject = whsDumpArray.getJSONObject(i);
                    WhsDumpDtl whsDumpDtl = whsDumpDtlObject.toJavaObject(WhsDumpDtl.class);
                    whsDumpDtl.setActualOutStorage(StringUtils.isNotEmpty(whsDumpDtlObject.getString("actualOutStorage"))? whsDumpDtlObject.getJSONArray("actualOutStorage").toJSONString():"[]");
                    whsDumpDtl.setActualInStorage(StringUtils.isNotEmpty(whsDumpDtlObject.getString("actualInStorage"))? whsDumpDtlObject.getJSONArray("actualInStorage").toJSONString():"[]");
                    whsDumpDtl.setWhsDumpUuid(whsDumpUuid);
                    iWhsDumpDtlService.createWhsDumpDtl(whsDumpDtl);
                }
            }
            iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(whsDumpUuid, userId, WHS_DUMP_CREATE);
            return 1;
        }catch (Exception e){
            e.printStackTrace();
            return -1;
        }
    }

    ResponseResult checkDataValidate(JSONObject doc){
        try {
            JSONObject whsDumpObject = doc.getJSONObject("whsDump");
            JSONArray whsDumpArray = doc.getJSONArray("whsDumpDtl");
            String whsDumpUuid = whsDumpObject.getString("whsDumpUuid");
            String currentStatus = whsDumpObject.getString("currentStatus");
            String targetStatus = whsDumpObject.getString("targetStatus");
            WhsDump whsDump = whsDumpObject.toJavaObject(WhsDump.class);
            if (StringUtils.isNotEmpty(whsDumpUuid)){
                if (!("1".equals(currentStatus) || "2".equals(currentStatus) || "5".equals(currentStatus))){
                    return ResponseResult.error("当前状态禁止此操作");
                }
                QueryWrapper<WhsDump> queryWrapper = new QueryWrapper<WhsDump>().eq("WHS_DUMP_UUID", whsDumpUuid);
                WhsDump whsDumpEntity = this.baseMapper.selectOne(queryWrapper);
                if (!currentStatus.equals(whsDumpEntity.getSpmsStatus())){
                    return ResponseResult.error("单据状态已更新请刷新后重试");
                }
                if (WHS_DUMP_EXECUTE.equals(targetStatus) || WHS_DUMP_GET_PO_ERROR.equals(targetStatus)){
                    if (whsDumpArray.size() == 0 || StringUtils.isEmpty(whsDump.getWerksDumpOut()) || StringUtils.isEmpty(whsDump.getWhsLocationCodeDumpOut())){
                        return ResponseResult.error("请求参数错误");
                    }
                    for (int i = 0; i < whsDumpArray.size(); i++){
                        JSONObject whsDumpDtlObject = whsDumpArray.getJSONObject(i);
                        WhsDumpDtl whsDumpDtl = whsDumpDtlObject.toJavaObject(WhsDumpDtl.class);
                        whsDumpDtl.setActualOutStorage(StringUtils.isNotEmpty(whsDumpDtlObject.getString("actualOutStorage"))? whsDumpDtlObject.getJSONArray("actualOutStorage").toJSONString():"[]");
                        //whsDumpDtl.setActualInStorage(StringUtils.isNotEmpty(whsDumpDtlObject.getString("actualInStorage"))? whsDumpDtlObject.getJSONArray("actualInStorage").toJSONString():"[]");
                        double actualOutQty = whsDumpDtl.getActualOutQty() != null ? whsDumpDtl.getActualOutQty() : 0;
                        if (actualOutQty > 0){
                            JSONArray storageInfo = JSONArray.parseArray(whsDumpDtl.getActualOutStorage());
                            if (storageInfo == null || storageInfo.size() == 0){
                                return ResponseResult.error("请求参数错误");
                            }
                            if ("X".equals(whsDump.getGoodsType())) {
                            	String boxNote = whsDumpDtl.getBoxNote();
                            	String storageUuid = storageInfo.getJSONObject(0).getString("storageUuid");
                            	String storageNo = storageInfo.getJSONObject(0).getString("storageNo");
                            	if (StringUtils.isEmpty(storageUuid) || StringUtils.isEmpty(boxNote)){
                            		return ResponseResult.error("请求参数错误");
                            	}
                            	WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getStorageBoxNote(storageUuid, boxNote);
                            	if (null == whsStorageInventory){
                            		return ResponseResult.error("箱码" + boxNote + "在储位" + storageUuid + "-" + storageNo + "不存在");
                            	}
                            	WhsInventoryInfo whsInventoryInfo = iWhsInventoryInfoService.getWhsInventoryInfoByBoxNote(boxNote, whsDump.getWerksDumpOut(), whsDump.getWhsLocationCodeDumpOut());
                            	if (null == whsInventoryInfo){
                            		return ResponseResult.error("箱码" + boxNote + "在仓库" + whsDump.getWerksDumpOut() + "-" + whsDump.getWhsLocationCodeDumpOut() + "不存在");
                            	}
                            } else if ("M".equals(whsDump.getGoodsType())) {
                            	String storageUuid = storageInfo.getJSONObject(0).getString("storageUuid");
                            	String storageNo = storageInfo.getJSONObject(0).getString("storageNo");
                            	if (StringUtils.isEmpty(storageUuid) || StringUtils.isEmpty(storageNo)){
                            		return ResponseResult.error("储位请求参数错误");
                            	}
                            	WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getStorageMaterialNo(storageUuid, whsDumpDtl.getMaterialNo());
                            	if (null == whsStorageInventory){
                            		return ResponseResult.error("物料" + whsDumpDtl.getMaterialNo() + "在储位" + storageUuid + "-" + storageNo + "库存为空");
                            	}
                            }
                        }
                    }
                }
            }
            return ResponseResult.success();
        }catch (Exception e){
            e.printStackTrace();
            return ResponseResult.error(e.getMessage());
        }
    }
    // SPMS转储单据状态(0删除；1草稿；2转出可执行；3转出完成；4提交SAP获取PO成功；5提交SAP获取PO失败；
    // 6提交SAP获取DN成功；7提交SAP获取DN失败；8转出已撤销；)
    void addWhsDumpOperateLog(String whsDumpUuid, String userId, String targetStatus){
        if (WHS_DUMP_DELETE.equals(targetStatus)){
            iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(whsDumpUuid, userId, WHS_DUMP_DELETE_MSG);
        }
        if (WHS_DUMP_SAVE.equals(targetStatus)){
            iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(whsDumpUuid, userId, WHS_DUMP_SAVE_MSG);
        }
        if (WHS_DUMP_EXECUTE.equals(targetStatus)){
            iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(whsDumpUuid, userId, WHS_DUMP_EXECUTE_MSG);
        }
        if (WHS_DUMP_DONE.equals(targetStatus)){
            iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(whsDumpUuid, userId, WHS_DUMP_DONE_MSG);
        }
        if (WHS_DUMP_GET_PO.equals(targetStatus)){
            iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(whsDumpUuid, userId, WHS_DUMP_GET_PO_MSG);
        }
        if (WHS_DUMP_GET_PO_ERROR.equals(targetStatus)){
            iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(whsDumpUuid, userId, WHS_DUMP_GET_PO_ERROR_MSG);
        }
        if (WHS_DUMP_GET_DN.equals(targetStatus)){
            iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(whsDumpUuid, userId, WHS_DUMP_GET_DN_MSG);
        }
        if (WHS_DUMP_GET_DN_ERROR.equals(targetStatus)){
            iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(whsDumpUuid, userId, WHS_DUMP_GET_DN_ERROR_MSG);
        }
        if (WHS_DUMP_CANCEL.equals(targetStatus)){
            iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(whsDumpUuid, userId, WHS_DUMP_CANCEL_MSG);
        }

    }

    /***
     * SPMS_STATUS: SPMS转储单据状态（0删除；1草稿；2转出可执行；3转出完成；4转出提交SAP成功-计算库存-获取sap采购订单号；5转出提交SAP失败；
     * 6转入可执行；7转入完成；8转入提交SAP成功-计算库存；9转入提交SAP失败；10完成；11转出提交SAP成功-获取sap交货单号）
     *
     * 0删除；1草稿；2转出可执行；3转出完成；4提交SAP获取PO成功；5提交SAP获取PO失败；6提交SAP获取DN成功；7提交SAP获取DN失败；8转出已撤销；
     * WHS_DUMP_UUID = ef1cf3d2a4ad4fb4a79284a52f32f1c8
     * @param whsDumpUuid
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult whsDumpOutToSap(String whsDumpUuid, String dumpOutSapDate, String userId) throws Exception{
        ResponseResult checkResult = checkWhsDumpOut(whsDumpUuid, dumpOutSapDate);
        if (checkResult.getCode() != 200){
            return checkResult;
        }
        WhsDump whsDump = this.baseMapper.selectOne(new QueryWrapper<WhsDump>().eq("WHS_DUMP_UUID", whsDumpUuid));
        List<WhsDumpDtl> whsDumpDtlList = iWhsDumpDtlService.getWhsDumpDtlListByUuid(whsDumpUuid);
        String spmsStatus = whsDump.getSpmsStatus();
        String werks = whsDump.getWerksDumpOut();
        String whsLocationCode = whsDump.getWhsLocationCodeDumpOut();
        if (WHS_DUMP_DONE.equals(spmsStatus) || WHS_DUMP_GET_PO_ERROR.equals(spmsStatus)){
        	// 创建备件类型的空运人带，需将箱码信息更新到SAP，箱码信息先同步SAP后再扣减库存，如果先扣减库存，箱码信息同步SAP时查询不到箱码储位信息而报错
//            if ("X".equals(whsDump.getGoodsType())) {
//            	try {
//            		ResponseResult packageDataToSAP = this.sendPackageDataToSAP(whsDump, whsDumpDtlList);
//            		if (packageDataToSAP.getCode() != 200) {
//            			log.error("空运人带箱码信息同步SAP失败："+packageDataToSAP.getMsg());
//            		}
//            	} catch (Exception e) {
//            		log.error("空运人带箱码信息同步SAP失败："+e);
//            	}
//            }
        	// 扣减库存
        	for (WhsDumpDtl dumpDtl : whsDumpDtlList){
        		String actualOutStorage = dumpDtl.getActualOutStorage();
        		JSONArray storageArray = JSON.parseArray(actualOutStorage);
        		Integer item = dumpDtl.getItem();
        		// 存在备件货和贸易货，所以扣减库存不同
        		if ("X".equals(whsDump.getGoodsType())) {
        			// 备件货
        			String boxNote = dumpDtl.getBoxNote();
        			String storageUuid = storageArray.getJSONObject(0).getString("storageUuid");
        			ResponseResult updateWhsStorageInventory = iWhsStorageInventoryService.updateStorageInvX(storageUuid, boxNote, 1, "sub");
        			if (updateWhsStorageInventory.getCode() != 200){
        				throw new Exception("whsDumpOutToSap 转储任务移出更新储位库存出错：" + updateWhsStorageInventory.toString());
        			}
        			iWhsOperateLogService.insertWhsOperateLog("2", storageUuid, "", boxNote, 1,"16", whsDumpUuid, SPARE_PARTS_OUT_STORAGE, userId, "转储任务箱码出储位", werks, whsLocationCode, item+"");
        			ResponseResult updateWhsInventory = iWhsInventoryInfoService.updateWhsInventoryX(werks, whsLocationCode, boxNote, 1, "sub", userId);
        			if (updateWhsInventory.getCode() != 200){
        				throw new Exception("whsDumpOutToSap 转储任务移出更新仓库库存出错：" + updateWhsInventory.toString());
        			}
        			iWhsOperateLogService.insertWhsOperateLog("1", "", "", boxNote, 1,"15", whsDumpUuid, SPARE_PARTS_OUT_WHS, userId, "转储任务箱码出仓库", werks, whsLocationCode, item+"");
        		} else {
        			// 贸易货
        			String materialNo = dumpDtl.getMaterialNo();
        			for (int i = 0; i < storageArray.size(); i ++){
                        JSONObject storageInfoObj = storageArray.getJSONObject(i);
                        String storageUuid = storageInfoObj.getString("storageUuid");
                        double qty = storageInfoObj.getDoubleValue("qty");
//                        String storageNo = storageInfoObj.getString("storageNo");
                        if (qty > 0){
                            ResponseResult storageInventoryM = iWhsStorageInventoryService.updateStorageInventoryM(storageUuid, materialNo, qty, "sub");
                            if (storageInventoryM.getCode() != 200) {
                            	throw new Exception("物料："+materialNo+"，转储任务移出更新储位库存出错：" + storageInventoryM.toString());
                            }
                            iWhsOperateLogService.insertWhsOperateLog("2", storageUuid, materialNo, "", qty, "16", whsDumpUuid, GOODS_OUT_STORAGE, userId, "转储任务物料出储位", werks, whsLocationCode, item+"");
                        }
                    }
        		}
            }
        	// 调用接口ZZXD_IF_SPMS_13同步SAP
        	// 组装头行信息
        	Map<String, Object> headMap = this.setHeadData(whsDump,null);
        	List<Map<String, Object>> itemsMap = this.setItemListData(whsDump, whsDumpDtlList);
            JSONObject dataToSapGetPOJson = this.setDataToSapCreatePo(headMap, itemsMap);
            JSONObject sapReturnedData = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSapGetPOJson));
            JSONObject RETURN_DATA = sapReturnedData.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
            JSONObject T_RETURN = RETURN_DATA.getJSONObject("E_RETURN");
            if (!"S".equals(T_RETURN.getString("TYPE"))){
            	throw new Exception("转储任务提交SAP获取PO失败："+RETURN_DATA);
            }
            // PO、DN、销售单号由SAP调用14号接口返回SPMS
            // 更新转储单状态
            whsDump.setSpmsStatus(WHS_DUMP_GET_PO);
            whsDump.setDumpOutSapDate(dumpOutSapDate);
            this.baseMapper.update(whsDump, new QueryWrapper<WhsDump>().eq("WHS_DUMP_UUID", whsDumpUuid));
            iSapDeliveryNoteLogService.insertSapRequestRecord(whsDumpUuid, userId, WHS_DUMP_GET_DN_MSG, sapReturnedData.toJSONString(), dataToSapGetPOJson.toJSONString());
            return ResponseResult.success()
                    .add("sapReturnedData", sapReturnedData)
                    .add("dataToSap", dataToSapGetPOJson)
                    .add("whsDump", this.baseMapper.selectOne(new QueryWrapper<WhsDump>().eq("WHS_DUMP_UUID", whsDumpUuid)));
        }
        return ResponseResult.error().add("error", "单据当前状态禁止此操作");
    }

    private List<Map<String, Object>> setItemListData(WhsDump whsDump, List<WhsDumpDtl> whsDumpDtlList) {
    	List<Map<String, Object>> itemsMap = new ArrayList<>();
    	for (WhsDumpDtl dtl : whsDumpDtlList) {
    		if ("X".equals(whsDump.getGoodsType())) {
    			// 查询箱码下的物料数量
    			List<Map<String,Object>> dnMaterialDtl = iSapBoxNoteService.getDnMaterialDtl(dtl.getBoxNote());
    			if (CollectionUtils.isNotEmpty(dnMaterialDtl)) {
    				for (Map<String,Object> dnMap : dnMaterialDtl) {
    					if (dnMap.get("domesticQtyReceived") != null && BigDecimal.ZERO.compareTo(new BigDecimal(dnMap.get("domesticQtyReceived").toString())) != 0) {
    						Map<String, Object> map = new HashMap<>();
    						// 来源单号
    						map.put("LYDJH", whsDump.getWhsDumpNo());
    						// 行号
    						map.put("PONSR_S", String.valueOf(dtl.getItem())+dnMap.get("item").toString());
    						// 物料编码
    						map.put("MATNR", dnMap.get("materialNo").toString());
    						// 箱码
    						map.put("PACKAGE_CODE", dtl.getBoxNote());
    						// 数量
    						map.put("AMENG", dnMap.get("domesticQtyReceived").toString());
    						// 基本单位
    						map.put("MEINS", dnMap.get("basicUnit").toString());
    						// 批次
    						map.put("CHARG", "");
    						// 件数
    						map.put("PEMNG", "");
    						// 销售单位
    						map.put("VRKME", "");
    						// 备注
    						map.put("REMARKS", dtl.getDumpInRemark());
    						map.put("PACKAGE_POSNR", dnMap.get("item")==null?"":dnMap.get("item").toString());//箱码序号
    						itemsMap.add(map);
    					}
    				}
    			}
        	} else {
        		if (dtl.getActualOutQty() > 0) {
        			Map<String, Object> map = new HashMap<>();
        			// 来源单号
        			map.put("LYDJH", whsDump.getWhsDumpNo());
        			// 行号
        			map.put("PONSR_S", String.valueOf(dtl.getItem()));
        			// 物料编码
        			map.put("MATNR", dtl.getMaterialNo());
        			// 箱码
        			map.put("PACKAGE_CODE", "");
        			// 数量
        			map.put("AMENG", String.valueOf(dtl.getActualOutQty()));
        			// 基本单位
        			if (StringUtils.isNotEmpty(dtl.getBasicUnit())) {
        				map.put("MEINS", dtl.getBasicUnit());
        			} else {
        				Map<String, Object> material = this.baseMapper.selectMaterial(dtl.getMaterialNo());
        				map.put("MEINS", material.get("basicUnit").toString());
        			}
        			// 批次
        			map.put("CHARG", "");
        			// 件数
        			map.put("PEMNG", "");
        			// 销售单位
        			map.put("VRKME", "");
        			// 备注
        			map.put("REMARKS", dtl.getDumpInRemark());
        			itemsMap.add(map);
        		}
        	}
    	}
		return itemsMap;
	}

	private Map<String, Object> setHeadData(WhsDump whsDump,String cancelPostingDate) {
    	Map<String, Object> headMap = new HashMap<>();
    	// 查询转出工厂、转入工厂的公司代码
    	Werks outWerks = iWerksService.getOne(new QueryWrapper<Werks>().eq("WERKS", whsDump.getWerksDumpOut()));
    	Werks inWerks = iWerksService.getOne(new QueryWrapper<Werks>().eq("WERKS", whsDump.getWerksDumpIn()));
    	// 来源单据号
    	headMap.put("LYDJH", whsDump.getWhsDumpNo());
    	// 发货公司
    	headMap.put("BUKRS_S", outWerks != null ? outWerks.getCompanyCode() : "");
    	// 发货工厂
    	headMap.put("WERKS_S", whsDump.getWerksDumpOut());
    	// 发货仓库
    	headMap.put("LGORT_S", whsDump.getWhsLocationCodeDumpOut());
    	// 收货公司
    	headMap.put("BUKRS_R", inWerks != null ? inWerks.getCompanyCode() : "");
    	// 收货工厂
    	headMap.put("WERKS_R", whsDump.getWerksDumpIn());
    	// 收货仓库
    	headMap.put("LGORT_R", whsDump.getWhsLocationCodeDumpIn());
    	// 作业人
    	headMap.put("S_USER", whsDump.getCreateUserid());
    	// 创建日期
        if(cancelPostingDate!=null){//撤销日期
            headMap.put("DATE_CR", cancelPostingDate.replaceAll("-", ""));
        }else{
            headMap.put("DATE_CR", StringUtils.isNotEmpty(whsDump.getCreateDate()) ? whsDump.getCreateDate().replaceAll("-", "") : "");
        }
    	// 单据类型
    	headMap.put("TYPE_D", "01");
    	// 发运方式:海运10/空运20/人带30/陆运40，国内转储全部陆运
    	String type_t = "";
    	if ("2".equals(whsDump.getTransportType())) {
    		type_t = "40";
    	} else if ("1".equals(whsDump.getTransportType())) {
    		type_t = "30";
    	} else if ("0".equals(whsDump.getTransportType())) {
    		type_t = "20";
    	}
    	headMap.put("TYPE_T", type_t);
    	// 备注
    	headMap.put("REMARKS", whsDump.getOaNumber());
		return headMap;
	}

	private JSONObject setDataToSapCreatePo(Map<String, Object> headMap, List<Map<String, Object>> itemsMap) {
    	JSONObject doc = new JSONObject();
        JSONObject REQUEST = new JSONObject();
        JSONObject ESB_ATTRS = new JSONObject();
        JSONObject REQUEST_DATA = new JSONObject();
        ESB_ATTRS.put("App_ID", "SPMS");
        ESB_ATTRS.put("Target_ID", zxdSapClient);
        ESB_ATTRS.put("Application_ID", "00020000000002");
        ESB_ATTRS.put("Transaction_ID", UUID.randomUUID().toString());
//        SimpleDateFormat simp = new SimpleDateFormat("yyyy:MM:ddHH:mm:ss:SS");//月日时分秒 毫秒
//        String serialNumber=simp.format(new Date()).replace(":","" );
//        Head.put("SPMSID", "SPMS"+serialNumber);
        Map<String, Object> structures = new HashMap<>();
        structures.put("IS_HEAD", headMap);
        REQUEST_DATA.put("structures", structures);
        Map<String, Object> tables = new HashMap<>();
        tables.put("IT_ITEM", itemsMap);
        REQUEST_DATA.put("tables", tables);
        REQUEST_DATA.put("Operation", "ZZXD_IF_SPMS_13");
        REQUEST_DATA.put("Type", "ZZXD_IF_SPMS_13");
        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
        REQUEST.put("REQUEST_DATA", REQUEST_DATA);
        doc.put("REQUEST", REQUEST);
        return doc;
	}

	/** 0删除；1草稿；2转出可执行；3转出完成；4提交SAP获取PO成功；5提交SAP获取PO失败；
     * 6提交SAP获取DN成功；7提交SAP获取DN失败；8转出已撤销；
     */
    ResponseResult checkWhsDumpOut (String whsDumpUuid, String dumpOutSapDate){
        if (StringUtils.isEmpty(whsDumpUuid)){
            return ResponseResult.error().add("error", "请求参数不能为空.");
        }
        WhsDump whsDump = this.baseMapper.selectOne(new QueryWrapper<WhsDump>().eq("WHS_DUMP_UUID", whsDumpUuid));
        if (whsDump == null || !(WHS_DUMP_DONE.equals(whsDump.getSpmsStatus()) || WHS_DUMP_GET_PO_ERROR.equals(whsDump.getSpmsStatus()))){
            return ResponseResult.error().add("error", "当前状态禁止提交SAP.");
        }
        String spmsStatus = whsDump.getSpmsStatus();
        String werks = whsDump.getWerksDumpOut();
        String whsLocationCode = whsDump.getWhsLocationCodeDumpOut();
        List<WhsDumpDtl> whsDumpDtlList = iWhsDumpDtlService.getWhsDumpDtlListByUuid(whsDumpUuid);
        if (whsDumpDtlList == null || whsDumpDtlList.size() == 0){
            return ResponseResult.error().add("error", "转储申请不存在或没有实际操作数量大于0的行");
        }
        if (WHS_DUMP_GET_PO.equals(spmsStatus)){
            if (StringUtils.isEmpty(dumpOutSapDate) || "Invalid date".equals(dumpOutSapDate)){
                return ResponseResult.error().add("error", "过账日期不合法或不能为空 dumpOutSapDate：" + dumpOutSapDate);
            }
        }
        if (WHS_DUMP_DONE.equals(spmsStatus) || WHS_DUMP_GET_PO_ERROR.equals(spmsStatus)){
            for (WhsDumpDtl dumpDtl : whsDumpDtlList){
                String boxNote = dumpDtl.getBoxNote();
                String materialNo = dumpDtl.getMaterialNo();
                String actualOutStorage = dumpDtl.getActualOutStorage();
                if ((StringUtils.isEmpty(boxNote) && "X".equals(whsDump.getGoodsType())) || StringUtils.isEmpty(actualOutStorage)){
                    return ResponseResult.error().add("error", "行数据箱码或实出储位信息不正确");
                }
                if ((StringUtils.isEmpty(materialNo) && "M".equals(whsDump.getGoodsType())) || StringUtils.isEmpty(actualOutStorage)){
                	return ResponseResult.error().add("error", "行数据物料编码或实出储位信息不正确");
                }
                JSONArray storageArray = JSON.parseArray(actualOutStorage);
                if (storageArray.size() == 0){
                    ResponseResult.error().add("error", "行数据实出储位信息不正确");
                }
                if ("X".equals(whsDump.getGoodsType())) {
                	String storageUuid = storageArray.getJSONObject(0).getString("storageUuid");
                	String storageNo = storageArray.getJSONObject(0).getString("storageNo");
                	if (StringUtils.isEmpty(storageUuid)){
                		ResponseResult.error().add("error", "行数据实出储位信息不正确");
                	}
                	String whsInventoryQty = iWhsInventoryInfoService.getQuantityByBoxNote(werks, whsLocationCode, boxNote);
                	if (StringUtils.isEmpty(whsInventoryQty)){
                		return ResponseResult.error().add("error", "箱码" + boxNote + "在仓库" + werks + whsLocationCode + "库存不足，转出失败");
                	}
                	String whsStorageInventoryQty = iWhsStorageInventoryService.getAvailableQtyByUuidBoxNote(storageUuid, boxNote);
                	if (StringUtils.isEmpty(whsStorageInventoryQty)){
                		return ResponseResult.error().add("error", "箱码" + boxNote + "在储位" + werks + whsLocationCode + storageNo + "库存不足，转出失败");
                	}
                } else {
                    for (int i = 0; i < storageArray.size(); i ++){
                        JSONObject storageInfoObj = storageArray.getJSONObject(i);
                        String storageUuid = storageInfoObj.getString("storageUuid");
                        double qty = storageInfoObj.getDoubleValue("qty");
                        String storageNo = storageInfoObj.getString("storageNo");
                        if (StringUtils.isEmpty(storageUuid)){
                    		ResponseResult.error().add("error", "行数据实出储位信息不正确");
                    	}
                        if (qty > 0){
                            WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getStorageMaterialNo(storageUuid, materialNo);
                            if (whsStorageInventory == null){
                                return ResponseResult.error("物料号" + materialNo + "在储位" + storageNo + "无可用库存");
                            }
                            if (qty > whsStorageInventory.getAvailableQty()){
                                return ResponseResult.error("物料号" + materialNo + "在储位" + storageNo + "可用库存不足");
                            }
                        }
                    }
                }
            }
        }
        return ResponseResult.success();
    }

    JSONObject dataToSapGetPO (Map<String, Object> Head, List<Map<String, Object>> IT_XHEAD, List<Map<String, Object>> IT_POITEM){
        JSONObject doc = new JSONObject();

        JSONObject REQUEST = new JSONObject();
        JSONObject ESB_ATTRS = new JSONObject();
        JSONObject REQUEST_DATA = new JSONObject();
        JSONObject MapItems = new JSONObject();

        ESB_ATTRS.put("App_ID", "SPMS");
        ESB_ATTRS.put("Application_ID", "00020000000002");
        ESB_ATTRS.put("Transaction_ID", UUID.randomUUID().toString());

        MapItems.put("IT_POITEM", IT_POITEM);
        MapItems.put("IT_XHEAD", IT_XHEAD);

        SimpleDateFormat simp = new SimpleDateFormat("yyyy:MM:ddHH:mm:ss:SS");//月日时分秒 毫秒
        String serialNumber=simp.format(new Date()).replace(":","" );
        Head.put("SPMSID", "SPMS"+serialNumber);

        REQUEST_DATA.put("Head", Head);
        REQUEST_DATA.put("MapItems", MapItems);
        REQUEST_DATA.put("Operation", "Z_SPMS_CREATE_STO");
        REQUEST_DATA.put("Type", "CREATE_STO");

        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
        REQUEST.put("REQUEST_DATA", REQUEST_DATA);

        doc.put("REQUEST", REQUEST);
        return doc;
    }

    /** iFlag = I 新增，D 删除；postingDate 过账日期；purchaseOrder 采购订单号；deliveryNote DN交货单号； */
    JSONObject dataToSapGetDN(String iFlag, String postingDate, String purchaseOrder, String deliveryNote, String whsLocationCodeDumpOut){
        JSONObject obj = 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("iFlag", iFlag);
        Head.put("iBudat", postingDate.replaceAll("-", ""));
        Head.put("iEbeln", StringUtils.isEmpty(purchaseOrder) ? "" : purchaseOrder);
        Head.put("iVbeln", StringUtils.isEmpty(deliveryNote) ? "" : deliveryNote);
        Head.put("iLgort", StringUtils.isEmpty(whsLocationCodeDumpOut) ? "" : whsLocationCodeDumpOut);

        REQUEST_DATA.put("Head", Head);
        REQUEST_DATA.put("Operation", "Z_SPMS_DN_POST");
        REQUEST_DATA.put("Type", "DN_POST");

        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
        REQUEST.put("REQUEST_DATA", REQUEST_DATA);
        obj.put("REQUEST", REQUEST);
        return obj;
    }

    /**
     * @param whsDumpUuid
     * @param targetStatus
     */
    public void updateWhsDumpStatus (String whsDumpUuid, String targetStatus, String sapPurchaseOrder, String sapDeliveryNote,
                                     String postingDate, String sapWhsOutNo, String sapWhsOutYear){
        WhsDump whsDump = new WhsDump();
        whsDump.setSpmsStatus(targetStatus);
        if (StringUtils.isNotEmpty(sapPurchaseOrder)){
            whsDump.setSapDumpOutNo(sapPurchaseOrder);
        }
        if (StringUtils.isNotEmpty(sapDeliveryNote)){
            whsDump.setSapDeliveryNote(sapDeliveryNote);
        }
        if (StringUtils.isNotEmpty(postingDate)){
            whsDump.setDumpOutSapDate(postingDate);
        }
        if (StringUtils.isNotEmpty(sapWhsOutNo)){
            whsDump.setSapWhsOutNo(sapWhsOutNo);
        }
        if (StringUtils.isNotEmpty(sapWhsOutYear)){
            whsDump.setSapWhsOutYear(sapWhsOutYear);
        }
        this.baseMapper.update(whsDump, new QueryWrapper<WhsDump>().eq("WHS_DUMP_UUID", whsDumpUuid));
    }

    @Override
    public ResponseResult deleteWhsDump(String whsDumpUuid, String userId) {
        if (StringUtils.isEmpty(whsDumpUuid)){
            return ResponseResult.error("请求参数不能为空");
        }
        QueryWrapper<WhsDump> queryWrapper = new QueryWrapper<WhsDump>().eq("WHS_DUMP_UUID", whsDumpUuid);
        WhsDump whsDump = this.baseMapper.selectOne(queryWrapper);
        String currentStatus = whsDump.getSpmsStatus();
        if (whsDump == null || currentStatus == null){
            return ResponseResult.error("空运人带任务查询不存在");
        }
        if (WHS_DUMP_DELETE.equals(currentStatus)){
            return ResponseResult.success("转储任务已删除");
        }
        if (!WHS_DUMP_SAVE.equals(currentStatus) && !WHS_DUMP_EXECUTE.equals(currentStatus)
                && !WHS_DUMP_DONE.equals(currentStatus) && !WHS_DUMP_GET_PO_ERROR.equals(currentStatus)){
            return ResponseResult.error("当前任务状态不能删除");
        }
        whsDump.setSpmsStatus(WHS_DUMP_DELETE);
        this.baseMapper.update(whsDump, queryWrapper);
        iSapDeliveryNoteLogService.insertSapDeliveryNoteLogM(whsDumpUuid, userId, WHS_DUMP_DELETE_MSG);
        return ResponseResult.success();
    }

    /**
     * 空运人带任务从SAP撤销。0删除；1草稿；2转出可执行；3转出完成；4提交SAP获取PO成功；5提交SAP获取PO失败；
     * 6提交SAP获取DN成功；7提交SAP获取DN失败；8转出已撤销；
     * 1.只有 4，6，7 状态任务才可从SAP撤销；
     * 2.对于 4，7 撤销，PO 不能为空；对于 6 撤销，PO，DN 都不能为空
     * 3.撤销成功 更新状态为8；撤销失败不更新状态；
     * @param whsDumpUuid
     * @param userId
     * @return
     */
    @Override
    @Transactional
    public ResponseResult cancelWhsDump(String whsDumpUuid, String cancelPostingDate, String userId) throws Exception {
        ResponseResult checkResult = checkCancelValidate(whsDumpUuid, cancelPostingDate);
        if (checkResult.getCode() != SUCCESS){
            return checkResult;
        }
        QueryWrapper<WhsDump> queryWrapper = new QueryWrapper<WhsDump>().eq("WHS_DUMP_UUID", whsDumpUuid);
        WhsDump whsDump = this.baseMapper.selectOne(queryWrapper);
        List<WhsDumpDtl> whsDumpDtlList = iWhsDumpDtlService.getWhsDumpDtlListByUuid(whsDumpUuid);
        String spmsStatus = whsDump.getSpmsStatus();
        if (WHS_DUMP_GET_PO.equals(spmsStatus) || WHS_DUMP_GET_NUMBER.equals(spmsStatus)) {
        	// 增加库存
        	ResponseResult updateInventory = cancelWhsDumpUpdateInventory(whsDump, userId);
        	if (updateInventory.getCode() != SUCCESS) {
        		throw new Exception("转储撤销增加库出错："+updateInventory.getMsg());
        	}
        	// 调用接口ZZXD_IF_SPMS_13进行撤销
        	Map<String, Object> headMap = this.setHeadData(whsDump,cancelPostingDate);
        	headMap.put("LOEKZ", "X");
        	List<Map<String, Object>> itemsMap = this.setItemListData(whsDump, whsDumpDtlList);
            JSONObject dataToSapGetPOJson = this.setDataToSapCreatePo(headMap, itemsMap);
            JSONObject sapReturnedData = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSapGetPOJson));
            JSONObject RETURN_DATA = sapReturnedData.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
            JSONObject T_RETURN = RETURN_DATA.getJSONObject("E_RETURN");
            if (!"S".equals(T_RETURN.getString("TYPE"))){
            	throw new Exception("转储任务撤销提交SAP失败："+RETURN_DATA);
            }
            // 更新转储单状态
            whsDump.setSpmsStatus(WHS_DUMP_CANCEL);
            whsDump.setCancelPostingDate(cancelPostingDate);
//            whsDump.setCancelVoucherNumber(RETURN_DATA.getJSONObject("ES_RETURN").getString("EBELN"));
//            whsDump.setCancelVoucherYear(RETURN_DATA.getJSONObject("ES_RETURN").getString("EBELN"));
            this.baseMapper.update(whsDump, queryWrapper);
            iSapDeliveryNoteLogService.insertSapRequestRecord(whsDumpUuid, userId, WHS_DUMP_GET_DN_MSG, sapReturnedData.toJSONString(), dataToSapGetPOJson.toJSONString());
            return ResponseResult.success()
                    .add("sapReturnedData", sapReturnedData)
                    .add("dataToSap", dataToSapGetPOJson)
                    .add("whsDump", this.baseMapper.selectOne(new QueryWrapper<WhsDump>().eq("WHS_DUMP_UUID", whsDumpUuid)));
        }
        return ResponseResult.error("撤销失败");
    }

//    private JSONObject setDataToSapDelPo(Map<String, Object> whsHead, List<Map<String, Object>> sapPoCancelDtl) {
//        JSONObject doc = new JSONObject();
//        JSONObject request = new JSONObject();
//        JSONObject esbAttrs = new JSONObject();
//        JSONObject requestData = new JSONObject();
//        esbAttrs.put("App_ID", "SPMS");
//        esbAttrs.put("Application_ID", "00020000000002");
//        esbAttrs.put("Transaction_ID", UUID.randomUUID().toString());
//
//        SimpleDateFormat simp = new SimpleDateFormat("yyyy:MM:ddHH:mm:ss:SS");//月日时分秒 毫秒
//        String serialNumber=simp.format(new Date()).replace(":","" );
//        whsHead.put("ZID", "SPMS"+serialNumber);
//
//        whsHead.put("ZDEL", "X");
//        requestData.put("Head", whsHead);
//        if (CollectionUtils.isNotEmpty(sapPoCancelDtl)) {
//            requestData.put("Items", sapPoCancelDtl);
//        }
//        requestData.put("Operation", "Z_POS_PO_CREATE");
//        requestData.put("Type", "ZZD");
//
//        request.put("ESB_ATTRS", esbAttrs);
//        request.put("REQUEST_DATA", requestData);
//
//        doc.put("REQUEST", request);
//        return doc;
//    }

    ResponseResult checkCancelValidate(String whsDumpUuid, String postingDate){
        if (StringUtils.isEmpty(whsDumpUuid) || StringUtils.isEmpty(postingDate)){
            return ResponseResult.error("请求参数错误");
        }
        WhsDump whsDump = this.baseMapper.selectOne(new QueryWrapper<WhsDump>().eq("WHS_DUMP_UUID", whsDumpUuid));
        if (whsDump == null){
            return ResponseResult.error("查询转储任务不存在");
        }
        String spmsStatus = whsDump.getSpmsStatus();
        if (StringUtils.isEmpty(spmsStatus)){
            return ResponseResult.error("查询转储任务不存在");
        }
        if(WHS_DUMP_GET_PO.equals(spmsStatus) || WHS_DUMP_GET_NUMBER.equals(spmsStatus)){
//        	if (StringUtils.isEmpty(whsDump.getSapDumpOutNo())){
//        		return ResponseResult.error("单据采购订单号PO为空，禁止撤销操作");
//        	}
//            if (StringUtils.isEmpty(whsDump.getSapDeliveryNote())){
//                return ResponseResult.error("单据交货单号DN为空，禁止撤销操作");
//            }
        }else {
            return ResponseResult.error("当前转储任务状态不可撤销");
        }
        return ResponseResult.success();
    }

    /** 空运人带任务撤销成功之后，将任务明细中的箱数据，加到对应的仓库 和 储位 */
    ResponseResult cancelWhsDumpUpdateInventory(WhsDump whsDump, String userId){
        String werks = whsDump.getWerksDumpOut();
        String whsLocationCode = whsDump.getWhsLocationCodeDumpOut();
        String whsDumpUuid = whsDump.getWhsDumpUuid();
        List<WhsDumpDtl> whsDumpDtlList = iWhsDumpDtlService.getWhsDumpDtlListByUuid(whsDumpUuid);
        if (whsDumpDtlList != null && whsDumpDtlList.size() > 0){
            for (WhsDumpDtl whsDumpDtl : whsDumpDtlList){
            	Integer item = whsDumpDtl.getItem();
            	JSONArray storageInfo = JSONArray.parseArray(whsDumpDtl.getActualOutStorage());
            	if ("X".equals(whsDump.getGoodsType())) {
            		// 备件货
            		String boxNote = whsDumpDtl.getBoxNote();
            		if (storageInfo != null && storageInfo.size() > 0){
            			/** 备件空运人带的储位信息数组，有效值长度只会是 1，此处不做遍历*/
            			// [{"storageUuid":"142d26caaf53404f87b6d0a59f64f7f2","qty":1,"storageNo":"A010101"}]
            			String storageUuid = storageInfo.getJSONObject(0).getString("storageUuid");
            			double qty = storageInfo.getJSONObject(0).getDoubleValue("qty");
            			// 更新仓库库存
            			iWhsInventoryInfoService.updateWhsInventoryX(werks, whsLocationCode, boxNote, qty, "add", userId);
            			iWhsOperateLogService.insertOperateLog("1", "", "", boxNote, qty, "17", whsDumpUuid, "转储撤销入仓库", userId, "转储撤销", werks, whsLocationCode, item+"");
            			// 更新储位库存
            			iWhsStorageInventoryService.updateStorageInvX(storageUuid, boxNote, qty, "add");
            			iWhsOperateLogService.insertOperateLog("2", storageUuid, "", boxNote, qty, "18", whsDumpUuid, "转储撤销入储位", userId, "转储撤销", werks, whsLocationCode, item+"");
            		}
            	} else {
            		// 贸易货
            		String materialNo = whsDumpDtl.getMaterialNo();
        			for (int i = 0; i < storageInfo.size(); i ++){
                        JSONObject storageInfoObj = storageInfo.getJSONObject(i);
                        String storageUuid = storageInfoObj.getString("storageUuid");
                        double qty = storageInfoObj.getDoubleValue("qty");
                        if (qty > 0){
                            iWhsStorageInventoryService.updateStorageInventoryM(storageUuid, materialNo, qty, "add");
                            iWhsOperateLogService.insertWhsOperateLog("2", storageUuid, materialNo, "", qty, "18", whsDumpUuid, "转储撤销入储位", userId, "转储撤销", werks, whsLocationCode, item+"");
                        }
                    }
            	}
            }
            return ResponseResult.success();
        } else {
            return ResponseResult.error("实际操作数量大于0的行不存在");
        }
    }

	@Override
	public ResponseResult zSapStoOrPoToSpms(JSONObject doc) {
		if (doc == null) {
			return ResponseResult.error("订单和交货单号回传SPMS失败，推送数据为空").add("STATUS", "E");
		}
		JSONObject sendData = doc.getJSONObject("head");
		if (sendData == null) {
			return ResponseResult.error("订单和交货单号回传SPMS失败，推送数据为空").add("STATUS", "E");
		}
		// 设置信息
		if (StringUtils.isNotEmpty(sendData.toString())) {
			WhsDump dump = new WhsDump();
			dump.setWhsDumpNo(sendData.getString("LYDJH"));
			// 采购凭证号
			dump.setSapDumpOutNo(sendData.getString("EBELN"));
            // 采购凭证客户端
			dump.setOrderSapClient(sendData.getString("MANDT_PO"));
			// 交货单号
            dump.setSapDeliveryNote(StringUtils.isNotEmpty(sendData.getString("VBELN_VL")) ? sendData.getString("VBELN_VL") : sendData.getString("IN_VBELN_VL"));
            dump.setSapWhsOutNo(StringUtils.isNotEmpty(sendData.getString("VBELN_VL")) ? sendData.getString("VBELN_VL") : sendData.getString("IN_VBELN_VL"));
            // 交货单客户端
            dump.setDnSapClient(StringUtils.isNotEmpty(sendData.getString("MANDT_DN")) ? sendData.getString("MANDT_DN") : sendData.getString("IN_CLIENT"));
            // 销售单号
            dump.setSalesOrderNumber(sendData.getString("VBELN"));
            // 销售单客户端
            dump.setSalesSapClient(sendData.getString("SO_CLIENT"));
            // 状态：已返回单号
            dump.setSpmsStatus(WHS_DUMP_GET_NUMBER);
            this.baseMapper.update(dump, new QueryWrapper<WhsDump>().eq("WHS_DUMP_NO", sendData.getString("LYDJH")));
		}
		return ResponseResult.success("订单和交货单号回传SPMS成功").add("STATUS", "S");
	}

}
