package com.sunda.spmsoversea.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.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
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.spmsoversea.dto.*;
import com.sunda.spmsoversea.entity.*;
import com.sunda.spmsoversea.mapper.OverseaDnMapper;
import com.sunda.spmsoversea.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.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import static com.sunda.spmscommon.constant.OperationTypeConstant.OVERSEA_GET_BOX_NOTE;
import static com.sunda.spmsoversea.constant.CommonConstant.SUCCESS;
import static com.sunda.spmsoversea.constant.CommonConstant.sapLog;
import static com.sunda.spmsoversea.constant.MovementTypeConstant.M643;
import static com.sunda.spmsoversea.constant.MovementTypeConstant.M644;
import static com.sunda.spmsoversea.constant.OverseaWhsInConstant.GET_BOX_NOTE;
import static com.sunda.spmsoversea.constant.SapConstant.*;
import static com.sunda.spmsoversea.constant.WhsStorageInventoryConstant.*;
import static com.sunda.spmsoversea.enums.OverseaDnEnum.*;

/**
 * <p>
 * 海外仓交货单表(空运人带/转储/本地采购) 服务实现类
 * </p>
 *
 * @author Wayne
 * @since 2021-12-14
 */
@Slf4j
@Service
public class OverseaDnServiceImpl extends ServiceImpl<OverseaDnMapper, OverseaDn> implements IOverseaDnService {

    @Autowired
    IFeignServiceCommon iFeignServiceCommon;

    @Autowired
    IFormatDataToSapService iFormatDataToSapService;

    @Autowired
    IOverseaDnDtlService iOverseaDnDtlService;

    @Autowired
    IOverseaPurchaseOrderService iOverseaPurchaseOrderService;

    @Autowired
    IOverseaPurchaseOrderDtlService iOverseaPurchaseOrderDtlService;

    @Autowired
    IWhsStorageInventoryService iWhsStorageInventoryService;

    @Autowired
    IWhsOperateLogService iWhsOperateLogService;

    @Autowired
    IOverseaOperateLogService iOverseaOperateLogService;
    
    @Autowired
    ZSapOrgClientMapper zSapOrgClientMapper;
    
    @Value("${zxd.sap.client}")
    private String zxdSapClient;

    /** 获取转储交货单表头分页列表 */
    @Override
    public IPage getDnPage(OverseaDnSearchDTO overseaDnSearchDTO) {
        IPage iPage = overseaDnSearchDTO.getPage();
        List<Map<String, Object>> mapList = this.baseMapper.getDnPage(iPage, overseaDnSearchDTO);
        iPage.setRecords(mapList);
        return iPage;
    }

    /** 根据交货单号获取交货单表头信息 */
    @Override
    public OverseaDn getDn(String sapDeliveryNote) {
        return this.baseMapper.selectOne(new QueryWrapper<OverseaDn>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote));
    }

    /** 根据交货单号获取交货单表头详细信息 */
    @Override
    public Map<String, Object> getDnInfo(String sapDeliveryNote) {
        return this.baseMapper.getDnInfo(sapDeliveryNote);
    }

    /** 根据交货单号获取交货单明细信息 */
    @Override
    public List<Map<String, Object>> getDnDtlList(String sapDeliveryNote) {
        return iOverseaDnDtlService.getDnDtlList(sapDeliveryNote);
    }

    /** 确认到货，更新收货仓库，锁定DN、DN明细、PO、PO明细 四张表数据不再被更新；0-1； */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult confirmArrival(OverseaDnConfirmDTO overseaDnConfirmDTO, String userId)throws Exception  {
//        try {
            if (overseaDnConfirmDTO == null){
                return ResponseResult.error("请求参数错误");
            }
            String sapDeliveryNote = overseaDnConfirmDTO.getSapDeliveryNote();
            String arrivalDate = overseaDnConfirmDTO.getArrivalDate();
            String sapPurchaseOrder = overseaDnConfirmDTO.getSapPurchaseOrder();
            String whsLocationCodeReceive = overseaDnConfirmDTO.getWhsLocationCodeReceive();
            Integer dataVersion = overseaDnConfirmDTO.getDataVersion();

            if (StringUtils.isEmpty(sapDeliveryNote)   || dataVersion == null
                    || StringUtils.isEmpty(whsLocationCodeReceive) || StringUtils.isEmpty(arrivalDate)){
                return ResponseResult.error("请求参数错误");
            }
            QueryWrapper<OverseaDn> queryWrapper = new QueryWrapper<OverseaDn>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote);
            OverseaDn overseaDn = getDn(sapDeliveryNote);
            if (overseaDn == null){
                return ResponseResult.error("查询交货单不存在");
            }
            if (!dataVersion.equals(overseaDn.getDataVersion())){
                return ResponseResult.error("交货单信息已更新请刷新后重试");
            }
            if (!DN_WAITING.getCode().equals(overseaDn.getSpmsStatus())){
                return ResponseResult.error("交货单当前状态禁止此操作");
            }
            overseaDn.setWhsLocationCodeReceive(whsLocationCodeReceive);
            overseaDn.setSpmsStatus(DN_RECEIVING.getCode());
            overseaDn.setArrivalDate(arrivalDate);
            overseaDn.setDataStatus(DATA_STATUS_1);
            this.baseMapper.update(overseaDn, queryWrapper);

            OverseaDnDtl overseaDnDtl = new OverseaDnDtl();
            QueryWrapper<OverseaDnDtl> dnDtlQueryWrapper = new QueryWrapper<OverseaDnDtl>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote);
            overseaDnDtl.setWhsLocationCodeReceive(whsLocationCodeReceive);
            overseaDnDtl.setDataStatus(DATA_STATUS_1);
            iOverseaDnDtlService.update(overseaDnDtl, dnDtlQueryWrapper);

            lockOrUnlockDataStatus(sapPurchaseOrder, DATA_STATUS_1);

            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_RECEIVING.getDescZh(), DN_RECEIVING.getDescEn(), "", DN_RECEIVING.getDescRu());

            return ResponseResult.success("确认到货成功")
                    .add("overseaDn", getDnInfo(sapDeliveryNote))
                    .add("overseaDnDtlList", getDnDtlList(sapDeliveryNote));
//        } catch (Exception e){
//            e.printStackTrace();
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//            return ResponseResult.error("请求更新错误 Exception").add("error", e.getMessage());
//        }
    }

    /** dataStatus = 0，解除数据锁定，SAP可更新PO数据；dataStatus = 1，锁定数据，SAP不再更新PO数据； */
    void lockOrUnlockDataStatus(String sapPurchaseOrder, String dataStatus){
        OverseaPurchaseOrder overseaPurchaseOrder = new OverseaPurchaseOrder();
        overseaPurchaseOrder.setDataStatus(dataStatus);
        QueryWrapper<OverseaPurchaseOrder> purchaseOrderQueryWrapper =
                new QueryWrapper<OverseaPurchaseOrder>().eq("SAP_PURCHASE_ORDER", sapPurchaseOrder);
        iOverseaPurchaseOrderService.update(overseaPurchaseOrder, purchaseOrderQueryWrapper);

        OverseaPurchaseOrderDtl overseaPurchaseOrderDtl = new OverseaPurchaseOrderDtl();
        overseaPurchaseOrderDtl.setDataStatus(dataStatus);
        QueryWrapper<OverseaPurchaseOrderDtl> purchaseOrderDtlQueryWrapper =
                new QueryWrapper<OverseaPurchaseOrderDtl>().eq("SAP_PURCHASE_ORDER", sapPurchaseOrder);
        iOverseaPurchaseOrderDtlService.update(overseaPurchaseOrderDtl, purchaseOrderDtlQueryWrapper);
    }

    /** 交货单关闭成废单；0-10；1-10； */
    @Override
    public synchronized ResponseResult closeDn(String sapDeliveryNote, Integer dataVersion, String userId, String cancelReason) {
        if (StringUtils.isEmpty(sapDeliveryNote) || dataVersion == null){
            return ResponseResult.error("请求参数错误");
        }
        if (StringUtils.isEmpty(cancelReason)){
        	return ResponseResult.error("请填写作废原因");
        }
        QueryWrapper<OverseaDn> queryWrapper = new QueryWrapper<OverseaDn>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote);
        OverseaDn overseaDn = getDn(sapDeliveryNote);
        if (overseaDn == null){
            return ResponseResult.error("查询交货单不存在");
        }
        if (!dataVersion.equals(overseaDn.getDataVersion())){
            return ResponseResult.error("交货单信息已更新请刷新后重试");
        }
        if (!DN_WAITING.getCode().equals(overseaDn.getSpmsStatus()) &&
                !DN_RECEIVING.getCode().equals(overseaDn.getSpmsStatus())){
            return ResponseResult.error("交货单当前状态禁止此操作");
        }
        overseaDn.setSpmsStatus(DN_DELETE.getCode());
        overseaDn.setDataStatus(DATA_STATUS_1);
        overseaDn.setCancelReason(cancelReason);
        this.baseMapper.update(overseaDn, queryWrapper);
        iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_DELETE.getDescZh(), DN_DELETE.getDescEn(), "", DN_DELETE.getDescRu());

        return ResponseResult.success("交货单关闭成功")
                .add("overseaDn", getDnInfo(sapDeliveryNote));
    }

    /** 交货单 保存 1-1、入库完成/提交审批 1-2、审批通过 2-3(SPMS按实收入库加库存) */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult updateDn(OverseaDnUpdateDTO overseaDnUpdateDTO, String userId) throws Exception {
//        try {
            ResponseResult checkResult = checkUpdateDn(overseaDnUpdateDTO);
            if (checkResult.getCode() != SUCCESS){
                return checkResult;
            }
            /** 空运人带/转储/本地采购————更新交货单表头 */
            String sapDeliveryNote = overseaDnUpdateDTO.getSapDeliveryNote();
            String targetStatus = overseaDnUpdateDTO.getSpmsStatus();
            OverseaDn overseaDn = getDn(sapDeliveryNote);
            overseaDn.setSpmsStatus(targetStatus);
            if (DN_WHS_IN_DONE.getCode().equals(targetStatus)){
                overseaDn.setOperateUser(userId);
            }
            overseaDn.setRemarks(StringUtils.isEmpty(overseaDnUpdateDTO.getRemarks()) ? "-" : overseaDnUpdateDTO.getRemarks());
            overseaDn.setCostCenter(StringUtils.isNotEmpty(overseaDnUpdateDTO.getCostCenter()) ? overseaDnUpdateDTO.getCostCenter() : "");
            overseaDn.setPdaSN(StringUtils.isNotEmpty(overseaDnUpdateDTO.getPdaSN()) ? overseaDnUpdateDTO.getPdaSN() : "");
            overseaDn.setPdaTime(StringUtils.isNotEmpty(overseaDnUpdateDTO.getPdaTime()) ? overseaDnUpdateDTO.getPdaTime() : "");
            this.baseMapper.update(overseaDn, new QueryWrapper<OverseaDn>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote));

            /** 空运人带/转储/本地采购————更新交货单明细 */
            List<OverseaDnDtlUpdateDTO> dnDtlItem = overseaDnUpdateDTO.getOverseaDnDtlItem();
            for (OverseaDnDtlUpdateDTO dnDtl : dnDtlItem){
                String sapDeliveryNoteItem = dnDtl.getSapDeliveryNoteItem();
                QueryWrapper<OverseaDnDtl> queryWrapper = new QueryWrapper<OverseaDnDtl>().eq("SAP_DELIVERY_NOTE",
                        sapDeliveryNote).eq("SAP_DELIVERY_NOTE_ITEM", sapDeliveryNoteItem);
                OverseaDnDtl overseaDnDtl = new OverseaDnDtl();
                overseaDnDtl.setActualQtyBasicUnit(dnDtl.getActualQtyBasicUnit());
                overseaDnDtl.setActualQtyUnitSales(dnDtl.getActualQtyUnitSales());
                overseaDnDtl.setRemarks(StringUtils.isEmpty(dnDtl.getRemarks()) ? "-" : dnDtl.getRemarks());
                overseaDnDtl.setStorageInfo(dnDtl.getStorageInfo());
                iOverseaDnDtlService.update(overseaDnDtl, queryWrapper);
            }

            /** 空运人带/转储/本地采购————海外收货 审批通过 增加库存 */
            if (DN_APPROVED.getCode().equals(targetStatus)){
                ResponseResult updateStorageInventory = updateWhsStorageInventory(sapDeliveryNote, ADD, userId, OPERATION_TYPE2,
                        overseaDn.getWerksReceive(), overseaDn.getWhsLocationCodeReceive(), M643, "转储收货入库");
                if (updateStorageInventory.getCode() != SUCCESS){
                    log.info("=======RuntimeException=========\n" + updateStorageInventory.getMsg());
                    throw new RuntimeException("储位库存更新错误\n" + updateStorageInventory.getMsg());
                }
            }

            /** 空运人带/转储/本地采购————记录箱码海外到货日志，一个箱码多个明细，只记录一次到货 */
            addWhsOperateLog(iOverseaDnDtlService.getDnDtls(sapDeliveryNote), userId);

            if (DN_RECEIVING.getCode().equals(targetStatus)){
                iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_RECEIVING.getDescZh(), DN_RECEIVING.getDescEn(), "", DN_RECEIVING.getDescRu());
            }
            if (DN_WHS_IN_DONE.getCode().equals(targetStatus)){
                iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_WHS_IN_DONE.getDescZh(), DN_WHS_IN_DONE.getDescEn(), "", DN_WHS_IN_DONE.getDescRu());
            }
            if (DN_APPROVED.getCode().equals(targetStatus)) {
                iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_APPROVED.getDescZh(), DN_APPROVED.getDescEn(), "", DN_APPROVED.getDescRu());
            }
            return ResponseResult.success("确认到货成功")
                    .add("overseaDn", getDnInfo(sapDeliveryNote))
                    .add("overseaDnDtlList", getDnDtlList(sapDeliveryNote));
//        } catch (Exception e){
//            e.printStackTrace();
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//            return ResponseResult.error("请求更新错误 Exception").add("error", e.getMessage());
//        }
    }

    /** 记录箱码海外到货日志，一个箱码多个明细，只记录一次到货 */
    void addWhsOperateLog(List<OverseaDnDtl> overseaDnDtlList, String userId){
        Set set = new HashSet();
        for (OverseaDnDtl overseaDnDtl : overseaDnDtlList){
            String boxNote = overseaDnDtl.getBoxNote();
            String sapDeliveryNoteItem = overseaDnDtl.getSapDeliveryNoteItem();
            if (overseaDnDtl.getActualQtyBasicUnit() > 0 && StringUtils.isNotEmpty(boxNote) && !set.contains(boxNote)){
                String sapDeliveryNote = overseaDnDtl.getSapDeliveryNote();
                String werks = overseaDnDtl.getWerksReceive();
                String whsLocationCode = overseaDnDtl.getWhsLocationCodeReceive();
                iWhsOperateLogService.recordGetBoxNote(boxNote, OVERSEA_GET_BOX_NOTE, sapDeliveryNote, sapDeliveryNote, GET_BOX_NOTE,
                        userId, "", werks, whsLocationCode, M643, sapDeliveryNoteItem);
                set.add(boxNote);
            }
        }
    }

    /** 交货单 保存 1-1、入库完成/提交审批 1-2、审批通过 2-3(SPMS按实收入库加库存) */
    ResponseResult checkUpdateDn (OverseaDnUpdateDTO overseaDnUpdateDTO){
        String sapDeliveryNote = overseaDnUpdateDTO.getSapDeliveryNote();
        String targetStatus = overseaDnUpdateDTO.getSpmsStatus();
        Integer dataVersion = overseaDnUpdateDTO.getDataVersion();
        if (StringUtils.isEmpty(sapDeliveryNote) || StringUtils.isEmpty(targetStatus) || dataVersion == null){
            return ResponseResult.error("请求参数错误");
        }
        OverseaDn overseaDn = getDn(sapDeliveryNote);
        if (overseaDn == null){
            return ResponseResult.error("查询交货单不存在");
        }
        if (!dataVersion.equals(overseaDn.getDataVersion())){
            return ResponseResult.error("交货单信息已更新请刷新后重试");
        }
        String spmsStatus = overseaDn.getSpmsStatus();
        if (spmsStatus.equals(DN_RECEIVING.getCode())){
            if (!DN_RECEIVING.getCode().equals(targetStatus)
                    && !DN_WHS_IN_DONE.getCode().equals(targetStatus)){
                return ResponseResult.error("交货单目标状态错误");
            }
        } else if (spmsStatus.equals(DN_WHS_IN_DONE.getCode())){
            if (!DN_APPROVED.getCode().equals(targetStatus)){
                return ResponseResult.error("交货单目标状态错误");
            }
        } else {
            return ResponseResult.error("交货单当前状态禁止此操作");
        }
        List<OverseaDnDtlUpdateDTO> dnDtlItem = overseaDnUpdateDTO.getOverseaDnDtlItem();
        if (dnDtlItem == null || dnDtlItem.size() == 0){
            return ResponseResult.error("请求参数交货单明细不能为空");
        }
        return ResponseResult.success();
    }


    synchronized ResponseResult updateWhsStorageInventory(String sapDeliveryNote, String operateType, String userId, String logType, String werks, String whsLocationCode, String movementType, String remark){
        List<OverseaDnDtl> overseaDnDtlList = iOverseaDnDtlService.getDnDtls(sapDeliveryNote);
        if (overseaDnDtlList == null || overseaDnDtlList.size() == 0){
            return ResponseResult.error("入库任务明细数据查询不存在");
        }
        for (OverseaDnDtl overseaDnDtl : overseaDnDtlList){
            String materialNo = overseaDnDtl.getMaterialNo();
            String sapDeliveryNoteItem = overseaDnDtl.getSapDeliveryNoteItem();
            double actualQtyBasicUnit = overseaDnDtl.getActualQtyBasicUnit() == null ? 0 : overseaDnDtl.getActualQtyBasicUnit();
            if (actualQtyBasicUnit > 0){
                //storageInfoArray 结构参考：[{"storageUuid":"f17e13b4d9ad4d39ba55548eff544391","qty":100,"storageNo":"C010101"}]
                JSONArray storageInfoArray = JSONArray.parseArray(overseaDnDtl.getStorageInfo());
                for (int i = 0; i < storageInfoArray.size(); i ++){
                    JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                    String storageUuid = storageInfoObj.getString("storageUuid");
                    double qty = storageInfoObj.getDoubleValue("qty");
                    if (qty > 0){
                        ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo, qty, operateType);
                        if (updateInventory.getCode() != SUCCESS){
                            return updateInventory;
                        }
                        String comments = operateType.equals(ADD) ? WHS_OPERATE_LOG_ADD : WHS_OPERATE_LOG_SUB;
                        iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, qty, logType, sapDeliveryNote, comments, userId, remark, werks, whsLocationCode, movementType, sapDeliveryNoteItem);
                    }
                }
            }
        }
        return ResponseResult.success();
    }

    /**
     3审批通过/5按应收提交SAP失败
        提交SAP —— 按应收数量提交SAP
            失败 —— 审批通过后点击提交SAP失败 3-5/5-5；
            成功
                i.不存在少收 3-4-8-9/5-4-8-9；
                ii.存在少收，系统自动提交少收
                    少收提交成功 3-4-7-8-9/5-4-7-8-9；
                    少收提交失败 3-4-6/5-4-6；
     4按应收提交SAP成功/6收货少收提交SAP失败
        提交SAP
            i.不存在少收
                4-8-9；
            ii.存在少收，则将少收信息重新提交SAP
                成功 4-7-8-9/6-7-8-9；
                失败 4-6/6-6；
     本地采购提交SAP单独一套逻辑，按实收提交，无多收少收：
        3审批通过/5按实收提交SAP失败
            提交SAP —— 按实收数量提交SAP
                 失败 —— 审批通过后点击提交SAP失败 3-5/5-5；
                 成功 —— 3-8-9/5-8-9；
     * */
    @SuppressWarnings("unchecked")
	@Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult submitDnSap(OverseaDnSapDTO overseaDnSapDTO, String userId)  throws Exception {
//        try {
            ResponseResult checkResult = checkSubmitSap(overseaDnSapDTO);
            if (checkResult.getCode() != SUCCESS){
                return checkResult;
            }
            String sapDeliveryNote = overseaDnSapDTO.getSapDeliveryNote();
            String postingDate = overseaDnSapDTO.getPostingDate();
            String underPostingDate = overseaDnSapDTO.getUnderPostingDate() == null ? "" : overseaDnSapDTO.getUnderPostingDate();
            String costCenter = overseaDnSapDTO.getCostCenter() == null ? "" : overseaDnSapDTO.getCostCenter();

            QueryWrapper<OverseaDn> queryWrapper = new QueryWrapper<OverseaDn>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote);
            OverseaDn overseaDn = this.baseMapper.selectOne(queryWrapper);
            String businessType = overseaDn.getBusinessType();
            String spmsStatus = overseaDn.getSpmsStatus();
            // 02——本地采购，提交SAP时，按实收提交SAP即可，允许多收少收不单独提交SAP；不需要成本中心字段；
            if ("02".equals(businessType)){
                if (spmsStatus.equals(DN_APPROVED.getCode()) || spmsStatus.equals(DN_SUBMIT_SAP_ERROR.getCode())){
                    Map<String, Object> dataHead = this.baseMapper.dataHead(sapDeliveryNote, postingDate, userId);
                    List<Map<String, Object>> dataItems = this.baseMapper.actualDataItems(sapDeliveryNote);
                    if (dataHead != null && dataItems != null && dataItems.size() > 0){
                    	// 根据工厂获取MANDT
                    	if(dataItems.get(0).get("WERKS")!=null){
                            // 根据工厂查询对应的SAP Clinet
                            List<ZSapOrgClient> selectList = zSapOrgClientMapper.selectList(new QueryWrapper<ZSapOrgClient>().eq("WERKS", dataItems.get(0).get("WERKS")));
                            if (CollectionUtils.isNotEmpty(selectList)) {
                            	dataHead.put("MANDT_PO", selectList.get(0).getZmandt());
                            	dataHead.put("MANDT_DN", selectList.get(0).getZmandt());
                            } else {
                                throw new RuntimeException("工厂："+dataItems.get(0).get("werks")+"未找到对应的SAP Clinet");
                            }
                        }
                        JSONObject dataToSap = iFormatDataToSapService.formatDataToSap(dataHead, dataItems, "ZZXD_IF_SPMS_04", "ZZXD_IF_SPMS_04");
                        log.info("=======海外本地采购交货单按 实收收货入库请求SAP dataToSap=========\n" + dataToSap);
                        JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
                        log.info("=======海外本地采购交货单按 实收收货入库请求SAP message=========\n" + message);
                        JSONObject RETURN_DATA = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
                        if (SAP_SUCCESS.equals(RETURN_DATA.getJSONArray("T_R_HEAD").getJSONObject(0).getString("TYPE"))) {
//                            String sapVoucherNumber = RETURN_DATA.getJSONArray("IT_MSG").getJSONObject(0).getString("MBLNR");
//                            String sapVoucherYear = RETURN_DATA.getJSONArray("IT_MSG").getJSONObject(0).getString("MJAHR");

                            String sapVoucherNumber = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getJSONArray("T_R_HEAD").getJSONObject(0).getString("MBLNR");
                            String sapVoucherYear = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getJSONArray("T_R_HEAD").getJSONObject(0).getString("MJAHR");


                            overseaDn.setSpmsStatus(DN_SUBMIT_SAP_DONE.getCode());
                            overseaDn.setPostingDate(postingDate);
                            overseaDn.setSapVoucherNumber(sapVoucherNumber);
                            overseaDn.setSapVoucherYear(sapVoucherYear);
                            this.baseMapper.update(overseaDn, queryWrapper);
                            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_SUBMIT_SAP_DONE.getDescZh() + ":" + sapVoucherNumber,
                                    DN_SUBMIT_SAP_DONE.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "按应收提交SAP成功", DN_SUBMIT_SAP_DONE.getDescRu());

                            overseaDn.setSpmsStatus(DN_COMPLETED.getCode());
                            this.baseMapper.update(overseaDn, queryWrapper);
                            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_COMPLETED.getDescZh(), DN_COMPLETED.getDescEn(), "", DN_COMPLETED.getDescRu());
                            try {
            	                JSONArray costJson =  message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getJSONArray("T_R_ITEM");
            	                if (costJson != null && costJson.size() > 0) {
                            		List<OverseaDnDtl> itemList = new ArrayList<OverseaDnDtl>();
                            		for (int i = 0; i < costJson.size(); i++) {
                            			Map<String, Object> map = (Map<String, Object>) costJson.get(i);
                            			if (map.get("ZEILE") != null && map.get("DMBTR") != null) {
                            				OverseaDnDtl dtl = new OverseaDnDtl();
                            				String zeile = (String) map.get("ZEILE");
                            				String zeileRepla = zeile.replaceAll("^(0+)", "");
                            				dtl.setSapDeliveryNote(sapDeliveryNote);
                            				dtl.setSapDeliveryNoteItem(zeileRepla);
                            				dtl.setDmbtr(map.get("DMBTR").toString());
                            				dtl.setWaers(map.get("WAERS") != null ? map.get("WAERS").toString() : "");
                            				itemList.add(dtl);
                            			}
                            		}
                            		if (CollectionUtils.isNotEmpty(itemList)) {
                            			if (itemList.size() > 1000) {
                            				List<List<OverseaDnDtl>> partition = Lists.partition(itemList, 1000);
                            				for (List<OverseaDnDtl> pa : partition) {
                            					this.baseMapper.updateBatchDtl(pa);
                            				}
                            			} else {
                            				this.baseMapper.updateBatchDtl(itemList);
                            			}
                            		}
                            	}
                            } catch (Exception e) {
                            }
                            return ResponseResult.success("交货单完成收货提交SAP成功")
                                    .add("overseaDn", getDnInfo(sapDeliveryNote));
                        } else {
                            overseaDn.setSpmsStatus(DN_SUBMIT_SAP_ERROR1.getCode());
                            overseaDn.setPostingDate(postingDate);
                            this.baseMapper.update(overseaDn, queryWrapper);
                            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_SUBMIT_SAP_ERROR1.getDescZh(),
                                    DN_SUBMIT_SAP_ERROR1.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "按实收提交SAP失败", DN_SUBMIT_SAP_ERROR1.getDescRu());
                            return ResponseResult.error("交货单完成收货提交SAP错误")
                                    .add("sapReturnedMessage", message)
                                    .add("dataToSap", dataToSap)
                                    .add("overseaDn", getDnInfo(sapDeliveryNote));
                        }
                    } else {
                        return ResponseResult.error("交货单号" + sapDeliveryNote + "获取提交SAP信息结构错误");
                    }
                } else {
                    return ResponseResult.error("本地采购交货单状态错误");
                }
            }
            if ("01".equals(businessType) || "04".equals(businessType) || "03".equals(businessType)){
                if (spmsStatus.equals(DN_APPROVED.getCode()) || spmsStatus.equals(DN_SUBMIT_SAP_ERROR.getCode())){
                    Map<String, Object> dataHead = this.baseMapper.dataHead(sapDeliveryNote, postingDate, userId);
                    List<OverseaDn> ovdnList = this.baseMapper.selectList(new QueryWrapper<OverseaDn>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote));
                    if("03".equals(ovdnList.get(0).getBusinessType())){
                        dataHead.put("XBLNR", sapDeliveryNote);
                        dataHead.put("VBELN_IM", ovdnList.get(0).getSapDeliveryNoteRela());
                        dataHead.put("VBELN", ovdnList.get(0).getSapDeliveryNoteRela());
                        dataHead.put("LYDJH", sapDeliveryNote);
                    }
                    dataHead.put("SHLX", "");
                    QueryWrapper<OverseaDnDtl> qw = new QueryWrapper<OverseaDnDtl>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote);
                    List<OverseaDnDtl> dnList = iOverseaDnDtlService.list(qw);
                    dataHead.put("MANDT_PO", dnList != null ? dnList.get(0).getMandtPo() : "");
                    dataHead.put("MANDT_DN", dnList != null ? dnList.get(0).getMandtDn() : "");
                    List<Map<String, Object>> dataItems = this.baseMapper.dataItems(sapDeliveryNote);
                    if("03".equals(ovdnList.get(0).getBusinessType())){
                        for (int i = 0; i < dataItems.size(); i++) {
                            Map<String, Object> map = (Map<String, Object>) dataItems.get(i);
                            map.put("VBELN_IM", ovdnList.get(0).getSapDeliveryNoteRela());
                        }
                    }

                    if (dataHead != null && dataItems != null && dataItems.size() > 0){
                        JSONObject dataToSap = iFormatDataToSapService.formatDataToSap(dataHead, dataItems, "ZZXD_IF_SPMS_04", "ZZXD_IF_SPMS_04");
                        log.info("=======海外转储收货交货单按应收收货入库请求SAP dataToSap=========\n" + dataToSap);
                        JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
                        log.info("=======海外转储收货交货单按应收收货入库请求SAP message=========\n" + message);
                        JSONObject RETURN_DATA = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
                        if (RETURN_DATA.getJSONArray("T_R_HEAD").size() > 0 && SAP_SUCCESS.equals(RETURN_DATA.getJSONArray("T_R_HEAD").getJSONObject(0).getString("TYPE"))) {
                            //String sapVoucherNumber = RETURN_DATA.getJSONArray("IT_MSG").getJSONObject(0).getString("MBLNR");
                            //String sapVoucherYear = RETURN_DATA.getJSONArray("IT_MSG").getJSONObject(0).getString("MJAHR");

                            String sapVoucherNumber = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getJSONArray("T_R_HEAD").getJSONObject(0).getString("MBLNR");
                            String sapVoucherYear = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getJSONArray("T_R_HEAD").getJSONObject(0).getString("MJAHR");

                            overseaDn.setSpmsStatus(DN_SUBMIT_SAP.getCode());
                            overseaDn.setPostingDate(postingDate);
                            overseaDn.setSapVoucherNumber(sapVoucherNumber);
                            overseaDn.setSapVoucherYear(sapVoucherYear);
                            this.baseMapper.update(overseaDn, queryWrapper);

                            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_SUBMIT_SAP.getDescZh() + ":" + sapVoucherNumber,
                                    DN_SUBMIT_SAP.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "按应收提交SAP成功", DN_SUBMIT_SAP.getDescRu());
                            try {
                                JSONArray costJson =  message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getJSONArray("T_R_ITEM");
            	                if (costJson != null && costJson.size() > 0) {
                            		List<OverseaDnDtl> itemList = new ArrayList<OverseaDnDtl>();
                            		for (int i = 0; i < costJson.size(); i++) {
                            			Map<String, Object> map = (Map<String, Object>) costJson.get(i);
                            			if (map.get("ZEILE") != null && map.get("DMBTR") != null) {
                            				OverseaDnDtl dtl = new OverseaDnDtl();
                            				String zeile = (String) map.get("ZEILE");
                            				String zeileRepla = zeile.replaceAll("^(0+)", "");
                            				dtl.setSapDeliveryNote(sapDeliveryNote);
                            				dtl.setSapDeliveryNoteItem(zeileRepla);
                            				dtl.setDmbtr(map.get("DMBTR").toString());
                            				dtl.setWaers(map.get("WAERS") != null ? map.get("WAERS").toString() : "");
                            				itemList.add(dtl);
                            			}
                            		}
                            		if (CollectionUtils.isNotEmpty(itemList)) {
                            			if (itemList.size() > 1000) {
                            				List<List<OverseaDnDtl>> partition = Lists.partition(itemList, 1000);
                            				for (List<OverseaDnDtl> pa : partition) {
                            					this.baseMapper.updateBatchDtl(pa);
                            				}
                            			} else {
                            				this.baseMapper.updateBatchDtl(itemList);
                            			}
                            		}
                            	}
                            } catch (Exception e) {
                            }
                            /** 按应收入库提交SAP成功后，检查是否存在 少收行，存在则将少收提交SAP；不存在则更新状态记录日志； */
                            List<Map<String, Object>> dataItemsUndercharged = this.baseMapper.dataItemsAnomalyPost(sapDeliveryNote, costCenter);
                            if (dataItemsUndercharged != null && dataItemsUndercharged.size() > 0){
                            	// 以下注释为存货损益需求
                                Map<String, Object> dataHeadUndercharged = this.baseMapper.dataHeadAnomalyPost(sapDeliveryNote, underPostingDate);
                                JSONObject dataToSapUndercharged = iFormatDataToSapService.formatDataToSap(dataHeadUndercharged, dataItemsUndercharged, "Z_SPMS_ANOMALY_POST", "ANOMALY_POST");
                                // 根据工厂查询对应的SAP Clinet
                                List<ZSapOrgClient> selectList = zSapOrgClientMapper.selectList(new QueryWrapper<ZSapOrgClient>().eq("WERKS", dataHeadUndercharged.get("WERKS")));
                                if (CollectionUtils.isNotEmpty(selectList)) {
                                    JSONObject obj = dataToSap.getJSONObject("REQUEST").getJSONObject("ESB_ATTRS");
                                    obj.put("Target_ID", "SAP-"+selectList.get(0).getZmandt());
                                } else {
                                    return ResponseResult.error("工厂："+dataToSapUndercharged.get("werks")+"未找到对应的SAP Clinet");
                                }
                                log.info("=======海外转储收货交货单少收成本中心入库请求SAP dataToSap=========\n" + dataToSapUndercharged);
                                JSONObject messageUndercharged = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSapUndercharged));
                                log.info("=======海外转储收货交货单少收成本中心入库请求SAP响应结果 message=========\n" + messageUndercharged);
                                JSONObject RETURN_DATA_Undercharged = messageUndercharged.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
                                if (SAP_SUCCESS.equals(RETURN_DATA_Undercharged.getString("O_TYPE"))){
                                    String underVoucherNumber = RETURN_DATA_Undercharged.getString("O_MBLNR").trim();
                                    String underVoucherYear = RETURN_DATA_Undercharged.getString("O_MJAHR").trim();

                                    overseaDn.setUnderPostingDate(underPostingDate);
                                    overseaDn.setCostCenter(costCenter);
                                    overseaDn.setUnderVoucherNumber(underVoucherNumber);
                                    overseaDn.setUnderVoucherYear(underVoucherYear);
                                    overseaDn.setSpmsStatus(DN_UNDERCHARGED_TO_SAP.getCode());
                                    this.baseMapper.update(overseaDn, queryWrapper);

                                    iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_UNDERCHARGED_TO_SAP.getDescZh() + ":" + underVoucherNumber,
                                            DN_UNDERCHARGED_TO_SAP.getDescEn(), sapLog, dataToSapUndercharged.toJSONString(), messageUndercharged.toJSONString(), "收货少收提交SAP成功", DN_UNDERCHARGED_TO_SAP.getDescRu());

                                    overseaDn.setSpmsStatus(DN_SUBMIT_SAP_DONE.getCode());
                                    this.baseMapper.update(overseaDn, queryWrapper);
                                    iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_SUBMIT_SAP_DONE.getDescZh(), DN_SUBMIT_SAP_DONE.getDescEn(), "", DN_SUBMIT_SAP_DONE.getDescRu());

                                    overseaDn.setSpmsStatus(DN_COMPLETED.getCode());
                                    this.baseMapper.update(overseaDn, queryWrapper);
                                    iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_COMPLETED.getDescZh(), DN_COMPLETED.getDescEn(), "", DN_COMPLETED.getDescRu());
                                    
                                    try {
                                    	JSONArray costArray = RETURN_DATA_Undercharged.getJSONArray("IT_COST");
                                    	if (costArray != null && costArray.size() > 0) {
                                    		List<OverseaDnDtl> itemList = new ArrayList<OverseaDnDtl>();
                                    		for (int i = 0; i < costArray.size(); i++) {
                                    			Map<String, Object> map = (Map<String, Object>) costArray.get(i);
                                    			if (map.get("ZEILE1") != null && map.get("DMBTR") != null) {
                                    				OverseaDnDtl dtl = new OverseaDnDtl();
                                    				String zeile = (String) map.get("ZEILE1");
                                    				String zeileRepla = zeile.replaceAll("^(0+)", "");
                                    				dtl.setSapDeliveryNote(sapDeliveryNote);
                                    				dtl.setSapDeliveryNoteItem(zeileRepla);
                                    				dtl.setDmbtr(map.get("DMBTR").toString());
                                    				dtl.setWaers(map.get("WAERS") != null ? map.get("WAERS").toString() : "");
                                    				itemList.add(dtl);
                                    			}
                                    		}
                                    		if (CollectionUtils.isNotEmpty(itemList)) {
                                    			if (itemList.size() > 1000) {
                                    				List<List<OverseaDnDtl>> partition = Lists.partition(itemList, 1000);
                                    				for (List<OverseaDnDtl> pa : partition) {
                                    					this.baseMapper.updateBatchDtl(pa);
                                    				}
                                    			} else {
                                    				this.baseMapper.updateBatchDtl(itemList);
                                    			}
                                    		}
                                    	}
                                    } catch (Exception e) {
                                    }
                                } else {
                                    overseaDn.setCostCenter(costCenter);
                                    overseaDn.setUnderPostingDate(underPostingDate);
                                    overseaDn.setSpmsStatus(DN_UNDERCHARGED_TO_SAP_ERROR.getCode());
                                    this.baseMapper.update(overseaDn, queryWrapper);

                                    iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_UNDERCHARGED_TO_SAP_ERROR.getDescZh(),
                                            DN_UNDERCHARGED_TO_SAP_ERROR.getDescEn(), sapLog, dataToSapUndercharged.toJSONString(), messageUndercharged.toJSONString(), "收货少收提交SAP失败", DN_UNDERCHARGED_TO_SAP_ERROR.getDescRu());

                                    return ResponseResult.error("交货单完成收货提交SAP完成，少收部分提交SAP错误")
                                            .add("sapReturnedMessage", messageUndercharged)
                                            .add("dataToSap", dataToSapUndercharged)
                                            .add("overseaDn", getDnInfo(sapDeliveryNote));

                                }
                            } else {
	                            overseaDn.setSpmsStatus(DN_SUBMIT_SAP_DONE.getCode());
	                            this.baseMapper.update(overseaDn, queryWrapper);
	                            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_SUBMIT_SAP_DONE.getDescZh(), DN_SUBMIT_SAP_DONE.getDescEn(), "", DN_SUBMIT_SAP_DONE.getDescRu());
	
	                            overseaDn.setSpmsStatus(DN_COMPLETED.getCode());
	                            this.baseMapper.update(overseaDn, queryWrapper);
	                            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_COMPLETED.getDescZh(), DN_COMPLETED.getDescEn(), "", DN_COMPLETED.getDescRu());
                            }

                            return ResponseResult.success("交货单完成收货提交SAP成功")
                                    .add("overseaDn", getDnInfo(sapDeliveryNote));
                        } else {
                            overseaDn.setSpmsStatus(DN_SUBMIT_SAP_ERROR.getCode());
                            overseaDn.setPostingDate(postingDate);
                            this.baseMapper.update(overseaDn, queryWrapper);
                            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_SUBMIT_SAP_ERROR.getDescZh(),
                                    DN_SUBMIT_SAP_ERROR.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "按应收提交SAP失败", DN_SUBMIT_SAP_ERROR.getDescRu());
                            return ResponseResult.error("交货单完成收货提交SAP错误")
                                    .add("sapReturnedMessage", message)
                                    .add("dataToSap", dataToSap)
                                    .add("overseaDn", getDnInfo(sapDeliveryNote));
                        }
                    } else {
                        return ResponseResult.error("交货单号" + sapDeliveryNote + "获取提交SAP信息结构错误");
                    }
                }
                if (spmsStatus.equals(DN_SUBMIT_SAP.getCode()) || spmsStatus.equals(DN_UNDERCHARGED_TO_SAP_ERROR.getCode())){
                	// 以下注释是存货损益需求
                    List<Map<String, Object>> dataItemsUndercharged = this.baseMapper.dataItemsAnomalyPost(sapDeliveryNote, costCenter);
                    if (dataItemsUndercharged != null && dataItemsUndercharged.size() > 0){
                        Map<String, Object> dataHeadUndercharged = this.baseMapper.dataHeadAnomalyPost(sapDeliveryNote, underPostingDate);
                        JSONObject dataToSapUndercharged = iFormatDataToSapService.formatDataToSap(dataHeadUndercharged, dataItemsUndercharged, "Z_SPMS_ANOMALY_POST", "ANOMALY_POST");
                        // 根据工厂查询对应的SAP Clinet
                        List<ZSapOrgClient> selectList = zSapOrgClientMapper.selectList(new QueryWrapper<ZSapOrgClient>().eq("WERKS", dataHeadUndercharged.get("WERKS")));
                        if (CollectionUtils.isNotEmpty(selectList)) {
                            JSONObject obj = dataToSapUndercharged.getJSONObject("REQUEST").getJSONObject("ESB_ATTRS");
                            obj.put("Target_ID", "SAP-"+selectList.get(0).getZmandt());
                        } else {
                            return ResponseResult.error("工厂："+dataToSapUndercharged.get("werks")+"未找到对应的SAP Clinet");
                        }
                        log.info("=======海外转储收货交货单少收成本中心入库请求SAP dataToSap=========\n" + dataToSapUndercharged);
                        JSONObject messageUndercharged = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSapUndercharged));
                        log.info("=======海外转储收货交货单少收成本中心入库请求SAP响应结果 message=========\n" + messageUndercharged);
                        JSONObject RETURN_DATA_Undercharged = messageUndercharged.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
                        if (SAP_SUCCESS.equals(RETURN_DATA_Undercharged.getString("O_TYPE"))) {
                            String underVoucherNumber = RETURN_DATA_Undercharged.getString("O_MBLNR").trim();
                            String underVoucherYear = RETURN_DATA_Undercharged.getString("O_MJAHR").trim();

                            overseaDn.setUnderPostingDate(underPostingDate);
                            overseaDn.setCostCenter(costCenter);
                            overseaDn.setUnderVoucherNumber(underVoucherNumber);
                            overseaDn.setUnderVoucherYear(underVoucherYear);
                            overseaDn.setSpmsStatus(DN_UNDERCHARGED_TO_SAP.getCode());
                            this.baseMapper.update(overseaDn, queryWrapper);

                            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_UNDERCHARGED_TO_SAP.getDescZh() + ":" + underVoucherNumber,
                                    DN_UNDERCHARGED_TO_SAP.getDescEn(), sapLog, dataToSapUndercharged.toJSONString(), messageUndercharged.toJSONString(), "收货少收提交SAP成功", DN_UNDERCHARGED_TO_SAP.getDescRu());

                            overseaDn.setSpmsStatus(DN_SUBMIT_SAP_DONE.getCode());
                            this.baseMapper.update(overseaDn, queryWrapper);
                            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_SUBMIT_SAP_DONE.getDescZh(), DN_SUBMIT_SAP_DONE.getDescEn(), "", DN_SUBMIT_SAP_DONE.getDescRu());

                            overseaDn.setSpmsStatus(DN_COMPLETED.getCode());
                            this.baseMapper.update(overseaDn, queryWrapper);
                            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_COMPLETED.getDescZh(), DN_COMPLETED.getDescEn(), "", DN_COMPLETED.getDescRu());
                            try {
                            	JSONArray costArray = RETURN_DATA_Undercharged.getJSONArray("IT_COST");
                            	if (costArray != null && costArray.size() > 0) {
                            		List<OverseaDnDtl> itemList = new ArrayList<OverseaDnDtl>();
                            		for (int i = 0; i < costArray.size(); i++) {
                            			Map<String, Object> map = (Map<String, Object>) costArray.get(i);
                            			if (map.get("ZEILE1") != null && map.get("DMBTR") != null) {
                            				OverseaDnDtl dtl = new OverseaDnDtl();
                            				String zeile = (String) map.get("ZEILE1");
                            				String zeileRepla = zeile.replaceAll("^(0+)", "");
                            				dtl.setSapDeliveryNote(sapDeliveryNote);
                            				dtl.setSapDeliveryNoteItem(zeileRepla);
                            				dtl.setDmbtr(map.get("DMBTR").toString());
                            				dtl.setWaers(map.get("WAERS") != null ? map.get("WAERS").toString() : "");
                            				itemList.add(dtl);
                            			}
                            		}
                            		if (CollectionUtils.isNotEmpty(itemList)) {
                            			if (itemList.size() > 1000) {
                            				List<List<OverseaDnDtl>> partition = Lists.partition(itemList, 1000);
                            				for (List<OverseaDnDtl> pa : partition) {
                            					this.baseMapper.updateBatchDtl(pa);
                            				}
                            			} else {
                            				this.baseMapper.updateBatchDtl(itemList);
                            			}
                            		}
                            	}
                            } catch (Exception e) {
                            }
                        } else {
                            overseaDn.setCostCenter(costCenter);
                            overseaDn.setUnderPostingDate(underPostingDate);
                            overseaDn.setSpmsStatus(DN_UNDERCHARGED_TO_SAP_ERROR.getCode());
                            this.baseMapper.update(overseaDn, queryWrapper);

                            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_UNDERCHARGED_TO_SAP_ERROR.getDescZh(),
                                    DN_UNDERCHARGED_TO_SAP_ERROR.getDescEn(), sapLog, dataToSapUndercharged.toJSONString(), messageUndercharged.toJSONString(), "收货少收提交SAP失败", DN_UNDERCHARGED_TO_SAP_ERROR.getDescRu());

                            return ResponseResult.error("交货单完成收货提交SAP完成，少收部分提交SAP错误")
                                    .add("sapReturnedMessage", messageUndercharged)
                                    .add("dataToSap", dataToSapUndercharged)
                                    .add("overseaDn", getDnInfo(sapDeliveryNote));
                        }
                    } else {
	                    overseaDn.setSpmsStatus(DN_SUBMIT_SAP_DONE.getCode());
	                    this.baseMapper.update(overseaDn, queryWrapper);
	                    iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_SUBMIT_SAP_DONE.getDescZh(), DN_SUBMIT_SAP_DONE.getDescEn(), "", DN_SUBMIT_SAP_DONE.getDescRu());
	
	                    overseaDn.setSpmsStatus(DN_COMPLETED.getCode());
	                    this.baseMapper.update(overseaDn, queryWrapper);
	                    iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_COMPLETED.getDescZh(), DN_COMPLETED.getDescEn(), "", DN_COMPLETED.getDescRu());
                    }
                    return ResponseResult.success("交货单完成收货提交SAP成功")
                            .add("overseaDn", getDnInfo(sapDeliveryNote));
                }
            }
            return ResponseResult.error("交货单业务类型错误");
//        }catch (FeignException feignException){
//            feignException.printStackTrace();
//            return ResponseResult.error("请求SAP失败 FeignException").add("error", feignException.getMessage());
//        }catch (Exception e){
//            e.printStackTrace();
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//            return ResponseResult.error("收货完成更新单据或提交SAP失败 Exception").add("error", e.getMessage());
//        }
    }

    ResponseResult checkSubmitSap(OverseaDnSapDTO overseaDnSapDTO){
        if (overseaDnSapDTO == null){
            return ResponseResult.error("请求参数错误");
        }
        String sapDeliveryNote = overseaDnSapDTO.getSapDeliveryNote();
        String postingDate = overseaDnSapDTO.getPostingDate();
        String underPostingDate = overseaDnSapDTO.getUnderPostingDate();
        Integer dataVersion = overseaDnSapDTO.getDataVersion();
        String costCenter = overseaDnSapDTO.getCostCenter();
        if (StringUtils.isEmpty(sapDeliveryNote) || dataVersion == null){
            return ResponseResult.error("请求参数错误");
        }
//        if (StringUtils.isEmpty(costCenter)){
//            return ResponseResult.error("成本中心不允许为空");
//        }
        OverseaDn overseaDn = getDn(sapDeliveryNote);
        if (overseaDn == null){
            return ResponseResult.error("请求交货单不存在");
        }
        if (!dataVersion.equals(overseaDn.getDataVersion())){
            return ResponseResult.error("请求交货单数据已更新，请刷新后重试");
        }
        if (overseaDn.getBusinessType() == null){
            return ResponseResult.error("请求交货单业务类型为空");
        }
        String spmsStatus = overseaDn.getSpmsStatus();
        if (spmsStatus.equals(DN_APPROVED.getCode()) || spmsStatus.equals(DN_SUBMIT_SAP_ERROR.getCode())){
            if (StringUtils.isEmpty(postingDate)){
                return ResponseResult.error("收货过账日期不允许为空");
            }
        } else if (spmsStatus.equals(DN_SUBMIT_SAP.getCode()) || spmsStatus.equals(DN_UNDERCHARGED_TO_SAP_ERROR.getCode())){
        	// 存货损益修改-以下需注释
            if (StringUtils.isEmpty(underPostingDate)){
                return ResponseResult.error("少收收货过账日期不允许为空");
            }
        } else {
            return ResponseResult.error("当前状态禁止此操作");
        }
        return ResponseResult.success();
    }

    /***
     交货单撤销功能：
     0待到货;
     1入库中/审批不通过;
        撤回 —— 撤回到待到货 1-0；
     2入库完成/待审批;
        审批不通过 —— 退回到入库中 2-1；
     3审批通过/SPMS按实收入库存;
        撤回 —— 撤回到入库中，SPMS按实收撤回入库减库存 3-1；
     4按应收提交SAP成功;
        撤回 —— 按应收提交的入库凭证从SAP撤销
             撤回成功 4-3；
             撤回失败 4-4；
     5按应收提交SAP失败;
        撤回 —— 撤回到入库中，SPMS按实收撤回入库减库存 5-1；
     6收货少收提交SAP失败;
        撤回 —— 按应收提交的入库凭证从SAP撤销
             撤回成功 6-3；
             撤回失败 6-6；
     7收货少收提交SAP成功; —— 中间状态
     8提交SAP完成; —— 中间状态
     9收货完成/完结状态;
        不存在少收，撤回则按应收入库凭证从SAP撤销
             成功 9-3；
             失败 9-9；
        存在少收，先从SAP撤回少收凭证
             失败 9-9；
             成功 9-4；
                从SAP撤回按应收提交的入库凭证
                     成功 4-3；
                     失败 4-4；
     10关闭/废单;
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult cancelDn(OverseaDnSapDTO overseaDnSapDTO, String userId)  throws Exception  {
        ResponseResult checkCancelResult = checkCancel(overseaDnSapDTO);
        if (checkCancelResult.getCode() != SUCCESS){
            return checkCancelResult;
        }
        String sapDeliveryNote = overseaDnSapDTO.getSapDeliveryNote();
        String cancelPostingDate = overseaDnSapDTO.getCancelPostingDate();
        String cancelUnderPostingDate = overseaDnSapDTO.getCancelUnderPostingDate() != null ? overseaDnSapDTO.getCancelUnderPostingDate() : "";

        QueryWrapper<OverseaDn> queryWrapper = new QueryWrapper<OverseaDn>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote);
        OverseaDn overseaDn = this.baseMapper.selectOne(queryWrapper);
        String spmsStatus = overseaDn.getSpmsStatus();
        String businessType = overseaDn.getBusinessType();
        // 本地采购撤销需校验是否存在未关闭的分批收货单据
        if ("02".equals(businessType)){
        	int lossCount = this.baseMapper.getBatchReceiptNotDeleteCount(sapDeliveryNote, overseaDn.getWerksReceive());
            if (lossCount > 0){
                return ResponseResult.error("交货单存在关联的未关闭收货任务，请先关闭收货任务后再撤销");
            }
        }
        if (DN_RECEIVING.getCode().equals(spmsStatus)){
            overseaDn.setSpmsStatus(DATA_STATUS_0);
            this.baseMapper.update(overseaDn, queryWrapper);
            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_CANCEL_TO_WAITING.getDescZh(), DN_CANCEL_TO_WAITING.getDescEn(), "", DN_CANCEL_TO_WAITING.getDescRu());

            QueryWrapper<OverseaDnDtl> dnDtlQueryWrapper = new QueryWrapper<OverseaDnDtl>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote);
            OverseaDnDtl overseaDnDtl = new OverseaDnDtl();
            overseaDnDtl.setDataStatus(DATA_STATUS_0);
            iOverseaDnDtlService.update(overseaDnDtl, dnDtlQueryWrapper);

            List<OverseaDnDtl> overseaDnDtlList = iOverseaDnDtlService.getDnDtls(sapDeliveryNote);
            String sapPurchaseOrder = overseaDnDtlList.get(0).getSapPurchaseOrder();
            lockOrUnlockDataStatus(sapPurchaseOrder, DATA_STATUS_0);

            return ResponseResult.success("撤销到待到货，交货单已更新")
                    .add("overseaDn", getDnInfo(sapDeliveryNote))
                    .add("overseaDnDtlList", getDnDtlList(sapDeliveryNote));
        }
        if (DN_WHS_IN_DONE.getCode().equals(spmsStatus)){
            overseaDn.setSpmsStatus(DN_REJECT.getCode());
            this.baseMapper.update(overseaDn, queryWrapper);

            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_REJECT.getDescZh(), DN_REJECT.getDescEn(), "", DN_REJECT.getDescRu());
            return ResponseResult.success("审批不通过，交货单已更新").add("overseaDn", getDnInfo(sapDeliveryNote));
        }
        if (DN_APPROVED.getCode().equals(spmsStatus) || DN_SUBMIT_SAP_ERROR.getCode().equals(spmsStatus)){
            ResponseResult updateInventory = updateWhsStorageInventory(sapDeliveryNote, SUB, userId, OPERATION_TYPE3, overseaDn.getWerksReceive(), overseaDn.getWhsLocationCodeReceive(), M644, "转储入库撤销");
            if (updateInventory.getCode() != SUCCESS){
                log.info("=======RuntimeException=========\n" + updateInventory.getMsg());
                throw new RuntimeException("储位库存更新错误\n" + updateInventory.getMsg());
            }
            overseaDn.setSpmsStatus(DN_CANCEL_TO_RECEIVING.getCode());
            this.baseMapper.update(overseaDn, queryWrapper);

            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_CANCEL_TO_RECEIVING.getDescZh(), DN_CANCEL_TO_RECEIVING.getDescEn(), "", DN_CANCEL_TO_RECEIVING.getDescRu());
            return ResponseResult.success("撤销到收货中，交货单已更新").add("overseaDn", getDnInfo(sapDeliveryNote));
        }
        // 非本地采购撤销需判断是否有未关闭的存货损益
        if (!"02".equals(businessType)){
        	int lossCount = this.baseMapper.getLossValidateTask(sapDeliveryNote);
            if (lossCount > 0){
                return ResponseResult.error("交货单存在关联存货损益单据，请先关闭存货损益单据");
            }
        }
        if (DN_SUBMIT_SAP.getCode().equals(spmsStatus) || DN_UNDERCHARGED_TO_SAP_ERROR.getCode().equals(spmsStatus)){
            Map<String, Object> dataHead = this.baseMapper.dataHeadCancelMigo(sapDeliveryNote, cancelPostingDate);
            dataHead.put("SHLX", "");
            dataHead.put("VBELN", sapDeliveryNote);
            if ("03".equals(businessType)) {
            	List<OverseaDn> ovdnList = this.baseMapper.selectList(new QueryWrapper<OverseaDn>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote));
            	dataHead.put("VBELN", CollectionUtils.isNotEmpty(ovdnList) ? ovdnList.get(0).getSapDeliveryNoteRela() : sapDeliveryNote);
            }
            // 根据工厂查询SAP Clinet
            String sapClinet = "";
            List<ZSapOrgClient> selectList = zSapOrgClientMapper.selectList(new QueryWrapper<ZSapOrgClient>().eq("WERKS", overseaDn.getWerksReceive()));
            if (CollectionUtils.isNotEmpty(selectList)) {
            	sapClinet = selectList.get(0).getZmandt();
            } else {
            	return ResponseResult.error("工厂："+overseaDn.getWerksReceive()+"未找到对应的SAP Clinet");
            }
            dataHead.put("DN_MANDT", sapClinet);
            JSONObject dataToSap = this.setToSapData(dataHead);
            log.info("=======海外转储收货交货单入库撤销请求SAP dataToSap=========\n" + dataToSap);
            JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
            log.info("=======海外转储收货交货单入库撤销请求SAP响应结果 message=========\n" + message);
            JSONObject RETURN_DATA = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
            JSONObject E_DATA = RETURN_DATA.getJSONObject("E_DATA");
    		if (E_DATA != null && SAP_SUCCESS.equals(E_DATA.getString("TYPE"))) {
                String cancelVoucherNumber = E_DATA.getString("MBLNR");
                overseaDn.setCancelPostingDate(cancelPostingDate);
                overseaDn.setCancelVoucherNumber(cancelVoucherNumber);
                overseaDn.setSpmsStatus(DN_CANCEL_TO_APPROVED.getCode());
                this.baseMapper.update(overseaDn, queryWrapper);

                iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_CANCEL_TO_APPROVED.getDescZh() + ":" + cancelVoucherNumber,
                        DN_CANCEL_TO_APPROVED.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "交货单入库撤销提交SAP", DN_CANCEL_TO_APPROVED.getDescRu());
                return ResponseResult.success("撤销到审批通过，交货单已更新").add("overseaDn", getDnInfo(sapDeliveryNote));
            } else {
                overseaDn.setCancelPostingDate(cancelPostingDate);
                this.baseMapper.update(overseaDn, queryWrapper);

                iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_CANCEL_ERROR.getDescZh(),
                        DN_CANCEL_ERROR.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "交货单入库撤销失败", DN_CANCEL_ERROR.getDescRu());
                return ResponseResult.error("交货单入库撤销失败")
                        .add("overseaDn", getDnInfo(sapDeliveryNote))
                        .add("sapReturnedMessage", message)
                        .add("dataToSap", dataToSap);
            }
        }
        if (DN_COMPLETED.getCode().equals(spmsStatus)){
            /** 02——本地采购，提交SAP时，按实收提交SAP即可，多收少收不单独提交SAP；撤销状态变化 9-3，直接撤销凭证即可 */
            if ("02".equals(businessType)){
                Map<String, Object> dataHead = this.baseMapper.dataHeadCancelMigo(sapDeliveryNote, cancelPostingDate);
                dataHead.put("SHLX", "A");
                dataHead.put("VBELN", sapDeliveryNote);
                // 根据工厂查询SAP Clinet
                String sapClinet = "";
                List<ZSapOrgClient> selectList = zSapOrgClientMapper.selectList(new QueryWrapper<ZSapOrgClient>().eq("WERKS", overseaDn.getWerksReceive()));
                if (CollectionUtils.isNotEmpty(selectList)) {
                	sapClinet = selectList.get(0).getZmandt();
                } else {
                	return ResponseResult.error("工厂："+overseaDn.getWerksReceive()+"未找到对应的SAP Clinet");
                }
                dataHead.put("DN_MANDT", sapClinet);
                JSONObject dataToSap = this.setToSapData(dataHead);
                log.info("=======海外本地采购 交货单入库撤销请求SAP dataToSap=========\n" + dataToSap);
                JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
                log.info("=======海外本地采购 交货单入库撤销请求SAP响应结果 message=========\n" + message);
                JSONObject RETURN_DATA = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
                JSONObject E_DATA = RETURN_DATA.getJSONObject("E_DATA");
        		if (E_DATA != null && SAP_SUCCESS.equals(E_DATA.getString("TYPE"))) {
                    String cancelVoucherNumber = E_DATA.getString("MBLNR");
                    overseaDn.setCancelPostingDate(cancelPostingDate);
                    overseaDn.setCancelVoucherNumber(cancelVoucherNumber);
                    overseaDn.setSpmsStatus(DN_CANCEL_TO_APPROVED.getCode());
                    this.baseMapper.update(overseaDn, queryWrapper);

                    iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_CANCEL_TO_APPROVED.getDescZh() + ":" + cancelVoucherNumber,
                            DN_CANCEL_TO_APPROVED.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "交货单入库撤销提交SAP", DN_CANCEL_TO_APPROVED.getDescRu());
                    return ResponseResult.success("撤销到审批通过，交货单已更新").add("overseaDn", getDnInfo(sapDeliveryNote));
                } else {
                    overseaDn.setCancelPostingDate(cancelPostingDate);
                    this.baseMapper.update(overseaDn, queryWrapper);

                    iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_CANCEL_ERROR.getDescZh(),
                            DN_CANCEL_ERROR.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "交货单入库撤销失败", DN_CANCEL_ERROR.getDescRu());
                    return ResponseResult.error("交货单入库撤销失败")
                            .add("overseaDn", getDnInfo(sapDeliveryNote))
                            .add("sapReturnedMessage", message)
                            .add("dataToSap", dataToSap);
                }
            } else {
            	// 以下注释为存货损益需求
                String costCenter = StringUtils.isEmpty(overseaDn.getCostCenter()) ? "" : overseaDn.getCostCenter();
                List<Map<String, Object>> dataItemsUndercharged = this.baseMapper.dataItemsAnomalyPost(sapDeliveryNote, costCenter);
                if (dataItemsUndercharged != null && dataItemsUndercharged.size() > 0){
                    /** 存在少收，先调用接口Z_SPMS_CANCEL撤销少收凭证，再撤销入库凭证 */
                	Map<String, Object> dataHeadAnomaly = this.baseMapper.dataHeadCancelAnomaly(sapDeliveryNote, cancelUnderPostingDate);
                	JSONObject dataToSapCancelAnomaly = iFormatDataToSapService.formatDataToSap(dataHeadAnomaly, null, "Z_SPMS_CANCEL", "SPMS_CANCEL");
                	// 根据工厂查询对应的SAP Clinet
                    List<ZSapOrgClient> selectList = zSapOrgClientMapper.selectList(new QueryWrapper<ZSapOrgClient>().eq("WERKS", overseaDn.getWerksReceive()));
                    if (CollectionUtils.isNotEmpty(selectList)) {
                    	JSONObject obj = dataToSapCancelAnomaly.getJSONObject("REQUEST").getJSONObject("ESB_ATTRS");
                    	obj.put("Target_ID", "SAP-"+selectList.get(0).getZmandt());
                    } else {
                    	return ResponseResult.error("工厂："+overseaDn.getWerksReceive()+"未找到对应的SAP Clinet");
                    }
                    log.info("=======海外转储收货交货单少收凭证撤销请求SAP dataToSap=========\n" + dataToSapCancelAnomaly);
                    JSONObject messageCancelAnomaly = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSapCancelAnomaly));
                    log.info("=======海外转储收货交货单少收凭证撤销请求SAP响应结果 message=========\n" + messageCancelAnomaly);
                    JSONObject RETURN_DATA_Anomaly = messageCancelAnomaly.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
                    if (SAP_SUCCESS.equals(RETURN_DATA_Anomaly.getString("O_TYPE"))){
                    	String cancelUnderVoucherNumber = RETURN_DATA_Anomaly.getString("0_MBLNR");
                        overseaDn.setCancelUnderPostingDate(cancelUnderPostingDate);
                        overseaDn.setCancelUnderVoucherNumber(cancelUnderVoucherNumber);
                        overseaDn.setSpmsStatus(DN_CANCEL_TO_SUBMIT_SAP.getCode());
                        this.baseMapper.update(overseaDn, queryWrapper);
                        iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_CANCEL_TO_SUBMIT_SAP.getDescZh() + ":" + cancelUnderVoucherNumber,
                                DN_CANCEL_TO_SUBMIT_SAP.getDescEn(), sapLog, dataToSapCancelAnomaly.toJSONString(), messageCancelAnomaly.toJSONString(), "交货单少收凭证撤销提交SAP", DN_CANCEL_TO_SUBMIT_SAP.getDescRu());
                        // 少收撤销同步SAP成功后再调用05接口进行收货撤销
                        Map<String, Object> dataHead = this.baseMapper.dataHeadCancelMigo(sapDeliveryNote, cancelPostingDate);
                        dataHead.put("SHLX", "");
                        dataHead.put("VBELN", sapDeliveryNote);
                        if ("03".equals(businessType)) {
                        	List<OverseaDn> ovdnList = this.baseMapper.selectList(new QueryWrapper<OverseaDn>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote));
                        	dataHead.put("VBELN", CollectionUtils.isNotEmpty(ovdnList) ? ovdnList.get(0).getSapDeliveryNoteRela() : sapDeliveryNote);
                        }
                        // 根据工厂查询SAP Clinet
                        String sapClinet2 = "";
                        List<ZSapOrgClient> selectList2 = zSapOrgClientMapper.selectList(new QueryWrapper<ZSapOrgClient>().eq("WERKS", overseaDn.getWerksReceive()));
                        if (CollectionUtils.isNotEmpty(selectList2)) {
                        	sapClinet2 = selectList2.get(0).getZmandt();
                        } else {
                        	return ResponseResult.error("工厂："+overseaDn.getWerksReceive()+"未找到对应的SAP Clinet");
                        }
                        dataHead.put("DN_MANDT", sapClinet2);
                        JSONObject dataToSap = this.setToSapData(dataHead);
                        log.info("=======海外转储收货交货单入库撤销请求SAP dataToSap=========\n" + dataToSap);
                        JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
                        log.info("=======海外转储收货交货单入库撤销请求SAP响应结果 message=========\n" + message);
                        JSONObject RETURN_DATA = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
                        JSONObject E_DATA2 = RETURN_DATA.getJSONObject("E_DATA");
                		if (E_DATA2 != null && SAP_SUCCESS.equals(E_DATA2.getString("TYPE"))) {
                            String cancelVoucherNumber = E_DATA2.getString("MBLNR");
                            overseaDn.setCancelPostingDate(cancelPostingDate);
                            overseaDn.setCancelVoucherNumber(cancelVoucherNumber);
                            overseaDn.setSpmsStatus(DN_CANCEL_TO_APPROVED.getCode());
                            this.baseMapper.update(overseaDn, queryWrapper);

                            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_CANCEL_TO_APPROVED.getDescZh() + ":" + cancelVoucherNumber,
                                    DN_CANCEL_TO_APPROVED.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "交货单入库撤销提交SAP", DN_CANCEL_TO_APPROVED.getDescRu());
                            return ResponseResult.success("撤销到审批通过，交货单已更新").add("overseaDn", getDnInfo(sapDeliveryNote));
                        } else {
                            overseaDn.setCancelPostingDate(cancelPostingDate);
                            this.baseMapper.update(overseaDn, queryWrapper);

                            iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_CANCEL_ERROR.getDescZh(),
                                    DN_CANCEL_ERROR.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "交货单入库撤销失败", DN_CANCEL_ERROR.getDescRu());
                            return ResponseResult.error("交货单入库撤销失败")
                                    .add("overseaDn", getDnInfo(sapDeliveryNote))
                                    .add("sapReturnedMessage", message)
                                    .add("dataToSap", dataToSap);
                        }
                    } else {
                    	overseaDn.setCancelUnderPostingDate(cancelUnderPostingDate);
                        this.baseMapper.update(overseaDn, queryWrapper);
                        iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_CANCEL_ERROR.getDescZh(),
                                DN_CANCEL_ERROR.getDescEn(), sapLog, dataToSapCancelAnomaly.toJSONString(), messageCancelAnomaly.toJSONString(), "交货单少收凭证撤销失败", DN_CANCEL_ERROR.getDescRu());
                        return ResponseResult.error("交货单少收凭证撤销失败")
                                .add("overseaDn", getDnInfo(sapDeliveryNote))
                                .add("sapReturnedMessage", messageCancelAnomaly)
                                .add("dataToSap", dataToSapCancelAnomaly);
                    }
                } else {
                // 以上注释为存货损益需求
	                Map<String, Object> dataHead = this.baseMapper.dataHeadCancelMigo(sapDeliveryNote, cancelPostingDate);
	                dataHead.put("SHLX","");
	                dataHead.put("VBELN", sapDeliveryNote);
	                if ("03".equals(businessType)) {
	                	List<OverseaDn> ovdnList = this.baseMapper.selectList(new QueryWrapper<OverseaDn>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote));
	                	dataHead.put("VBELN", CollectionUtils.isNotEmpty(ovdnList) ? ovdnList.get(0).getSapDeliveryNoteRela() : sapDeliveryNote);
	                }
	                // 根据工厂查询SAP Clinet
	                String sapClinet2 = "";
	                List<ZSapOrgClient> selectList2 = zSapOrgClientMapper.selectList(new QueryWrapper<ZSapOrgClient>().eq("WERKS", overseaDn.getWerksReceive()));
	                if (CollectionUtils.isNotEmpty(selectList2)) {
	                	sapClinet2 = selectList2.get(0).getZmandt();
	                } else {
	                	return ResponseResult.error("工厂："+overseaDn.getWerksReceive()+"未找到对应的SAP Clinet");
	                }
	                dataHead.put("DN_MANDT", sapClinet2);
	                JSONObject dataToSap = this.setToSapData(dataHead);
	                log.info("=======海外转储收货交货单入库撤销请求SAP dataToSap=========\n" + dataToSap);
	                JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
	                log.info("=======海外转储收货交货单入库撤销请求SAP响应结果 message=========\n" + message);
	                JSONObject RETURN_DATA = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
	                JSONObject E_DATA2 = RETURN_DATA.getJSONObject("E_DATA");
	        		if (E_DATA2 != null && SAP_SUCCESS.equals(E_DATA2.getString("TYPE"))) {
	                    String cancelVoucherNumber = E_DATA2.getString("MBLNR");
	                    overseaDn.setCancelPostingDate(cancelPostingDate);
	                    overseaDn.setCancelVoucherNumber(cancelVoucherNumber);
	                    overseaDn.setSpmsStatus(DN_CANCEL_TO_APPROVED.getCode());
	                    this.baseMapper.update(overseaDn, queryWrapper);
	
	                    iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_CANCEL_TO_APPROVED.getDescZh() + ":" + cancelVoucherNumber,
	                            DN_CANCEL_TO_APPROVED.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "交货单入库撤销提交SAP", DN_CANCEL_TO_APPROVED.getDescRu());
	                    return ResponseResult.success("撤销到审批通过，交货单已更新").add("overseaDn", getDnInfo(sapDeliveryNote));
	                } else {
	                    overseaDn.setCancelPostingDate(cancelPostingDate);
	                    this.baseMapper.update(overseaDn, queryWrapper);
	
	                    iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_CANCEL_ERROR.getDescZh(),
	                            DN_CANCEL_ERROR.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "交货单入库撤销失败", DN_CANCEL_ERROR.getDescRu());
	                    return ResponseResult.error("交货单入库撤销失败")
	                            .add("overseaDn", getDnInfo(sapDeliveryNote))
	                            .add("sapReturnedMessage", message)
	                            .add("dataToSap", dataToSap);
	                }
                }
            }
        }
        return ResponseResult.error("交货单当前状态禁止此操作");
    }

    private JSONObject setToSapData(Map<String, Object> dataHead) {
    	JSONObject doc = new JSONObject();
        JSONObject request = new JSONObject();
        JSONObject esbAttrs = new JSONObject();
        JSONObject requestData = new JSONObject();
        esbAttrs.put("App_ID", "SPMS");
        esbAttrs.put("Target_ID", zxdSapClient);
        esbAttrs.put("Application_ID", "00020000000002");
        esbAttrs.put("Transaction_ID", UUID.randomUUID().toString());
        Map<String, Object> fileds = new HashMap<>();
        requestData.put("fileds", fileds);
        Map<String, Object> structures = new HashMap<>();
//        SimpleDateFormat simp = new SimpleDateFormat("yyyy:MM:ddHH:mm:ss:SS");//月日时分秒 毫秒
//        String serialNumber=simp.format(new Date()).replace(":","" );
//        dataHead.put("SPMID", "SPMS"+serialNumber);
        structures.put("I_DATA", dataHead);
        requestData.put("structures", structures);
        Map<String, Object> tables = new HashMap<>();
        requestData.put("tables", tables);
        requestData.put("Operation", "ZZXD_IF_SPMS_05");
        requestData.put("Type", "ZZXD_IF_SPMS_05");
        request.put("ESB_ATTRS", esbAttrs);
        request.put("REQUEST_DATA", requestData);
        doc.put("REQUEST", request);
        return doc;
	}

	ResponseResult checkCancel(OverseaDnSapDTO overseaDnSapDTO){
        if (overseaDnSapDTO == null){
            return ResponseResult.error("请求参数错误");
        }
        String sapDeliveryNote = overseaDnSapDTO.getSapDeliveryNote();
        Integer dataVersion = overseaDnSapDTO.getDataVersion();
        String cancelPostingDate = overseaDnSapDTO.getCancelPostingDate();
        String cancelUnderPostingDate = overseaDnSapDTO.getCancelUnderPostingDate();
        if (StringUtils.isEmpty(sapDeliveryNote) || dataVersion == null){
            return ResponseResult.error("请求参数错误");
        }
        OverseaDn overseaDn = getDn(sapDeliveryNote);
        if (overseaDn == null){
            return ResponseResult.error("请求交货单不存在");
        }
        if (!dataVersion.equals(overseaDn.getDataVersion())){
            return ResponseResult.error("请求交货单数据已更新，请刷新后重试");
        }
        String spmsStatus = overseaDn.getSpmsStatus();
        String businessType = overseaDn.getBusinessType();
        List<OverseaDnDtl> overseaDnDtlList = iOverseaDnDtlService.getDnDtls(sapDeliveryNote);
        if (overseaDnDtlList == null || overseaDnDtlList.size() == 0){
            return ResponseResult.error("交货单关联明细行数据为空");
        }
        if (DN_APPROVED.getCode().equals(spmsStatus) || DN_SUBMIT_SAP_ERROR.getCode().equals(spmsStatus)){
            for (OverseaDnDtl overseaDnDtl : overseaDnDtlList){
                String sapDeliveryNoteItem = overseaDnDtl.getSapDeliveryNoteItem();
                String materialNo = overseaDnDtl.getMaterialNo();
                String storageInfo = overseaDnDtl.getStorageInfo();
                double actualQtyBasicUnit = overseaDnDtl.getActualQtyBasicUnit();
                if (actualQtyBasicUnit > 0){
                    if (StringUtils.isEmpty(storageInfo)){
                        return ResponseResult.error("实收数量大于0的行:" + sapDeliveryNoteItem + "，料号:" + materialNo + "储位信息无效");
                    }
                    //storageInfoArray 结构参考：[{"storageUuid":"f17e13b4d9ad4d39ba55548eff544391","qty":100,"storageNo":"C010101"}]
                    JSONArray storageInfoArray = JSONArray.parseArray(storageInfo);
                    for (int i = 0; i < storageInfoArray.size(); i ++){
                        JSONObject storageInfoObj = storageInfoArray.getJSONObject(i);
                        String storageUuid = storageInfoObj.getString("storageUuid");
                        double qty = storageInfoObj.getDoubleValue("qty");
                        String storageNo = storageInfoObj.getString("storageNo");
                        if (qty > 0){
                            WhsStorageInventory whsStorageInventory = iWhsStorageInventoryService.getWhsStorageInventory(storageUuid, materialNo);
                            if (whsStorageInventory == null){
                                return ResponseResult.error("物料号" + materialNo + "在储位" + storageNo + "无可用库存");
                            }
                            if (qty > whsStorageInventory.getAvailableQty()){
                                return ResponseResult.error("物料号" + materialNo + "在储位" + storageNo + "可用库存不足");
                            }
                        }
                    }
                }
            }
        }
        if (DN_SUBMIT_SAP.getCode().equals(spmsStatus) || DN_UNDERCHARGED_TO_SAP_ERROR.getCode().equals(spmsStatus)){
            if (StringUtils.isEmpty(cancelPostingDate)){
                return ResponseResult.error("入库凭证撤销过账日期不能为空");
            }
            if (StringUtils.isEmpty(overseaDn.getSapVoucherNumber())){
                return ResponseResult.error("交货单上入库凭证值为空，无法撤销");
            }
        }
        if (DN_COMPLETED.getCode().equals(spmsStatus)){
            if ("01".equals(businessType) || "04".equals(businessType)){
//                if (StringUtils.isEmpty(cancelPostingDate)){
                if (StringUtils.isEmpty(cancelUnderPostingDate) || StringUtils.isEmpty(cancelPostingDate)){
                    return ResponseResult.error("入库凭证撤销过账日期不能为空");
                }
            }
            if (StringUtils.isEmpty(overseaDn.getSapVoucherNumber())){
                return ResponseResult.error("交货单上入库凭证值为空，无法撤销");
            }
        }
        if (DN_WAITING.getCode().equals(spmsStatus) || DN_DELETE.getCode().equals(spmsStatus)){
            return ResponseResult.error("当前状态禁止此操作");
        }
        return ResponseResult.success();
    }

	@Override
	public ResponseResult getOverseaDnHead(String spmsId) {
		if (StringUtils.isEmpty(spmsId)) {
			return ResponseResult.error("SPMS单号为空，请求失败");
		}
		// 查询头信息
		OverseaDn headVO = this.baseMapper.selectOne(new QueryWrapper<OverseaDn>().eq("SAP_DELIVERY_NOTE", spmsId));
		// 查询行信息
		List<Map<String, Object>> dnDtlList = iOverseaDnDtlService.getDnDtlList(headVO != null ? headVO.getSapDeliveryNote() : "");
		return ResponseResult.success().add("headVO", headVO).add("itemList", dnDtlList);
	}

	@Override
	public ResponseResult completeReceipt(String sapDeliveryNote, String userId) {
		if (StringUtils.isEmpty(sapDeliveryNote)) {
			return ResponseResult.error("SAP交货单号为空，请求失败");
		}
		QueryWrapper<OverseaDn> query = new QueryWrapper<OverseaDn>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote);
		OverseaDn selectDn = this.baseMapper.selectOne(query);
		if (DN_COMPLETED.getCode().equals(selectDn.getSpmsStatus()) || DN_DELETE.getCode().equals(selectDn.getSpmsStatus())) {
			return ResponseResult.error("当前状态不能执行此操作");
		}
		// 根据SAP交货单号查询分批收货任务下是否存在除删除、提交SAP成功状态以外的任务，如果存在则提示，如果不存在，其他收货状态改为完成收货
		int count = this.baseMapper.selectCountByBatchReceipt(sapDeliveryNote);
		if (count == 0) {
			// 更新状态为收货完成
			OverseaDn dn = new OverseaDn();
			dn.setSpmsStatus(DN_COMPLETED.getCode());
			this.baseMapper.update(dn, query);
		} else {
			return ResponseResult.error("有关联的收货任务未完成，请先处理!");
		}
		iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, DN_COMPLETED.getDescZh(), DN_COMPLETED.getDescEn(), "", DN_COMPLETED.getDescRu());
		return ResponseResult.success().add("overseaDn", getDnInfo(sapDeliveryNote)).add("overseaDnDtlList", getDnDtlList(sapDeliveryNote));
	}

	@Override
	public ResponseResult openAgain(String sapDeliveryNote, String userId) {
		if (StringUtils.isEmpty(sapDeliveryNote)) {
			return ResponseResult.error("SAP交货单号为空，请求失败");
		}
		QueryWrapper<OverseaDn> query = new QueryWrapper<OverseaDn>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote);
		OverseaDn selectDn = this.baseMapper.selectOne(query);
		if (!DN_COMPLETED.getCode().equals(selectDn.getSpmsStatus()) && !DN_DELETE.getCode().equals(selectDn.getSpmsStatus())) {
//		if (!DN_DELETE.getCode().equals(selectDn.getSpmsStatus())) {
			return ResponseResult.error("当前状态不能执行此操作");
		}
		// 将单据状态改为收货中
		OverseaDn dn = new OverseaDn();
		dn.setSpmsStatus(DN_WAITING.getCode());
		this.baseMapper.update(dn, query);
		iOverseaOperateLogService.addOverseaOperateLog(userId, sapDeliveryNote, "重新打开", "Open Again", "", "Открыть заново");
		return ResponseResult.success().add("overseaDn", getDnInfo(sapDeliveryNote)).add("overseaDnDtlList", getDnDtlList(sapDeliveryNote));
	}
	
	public List<OverseaWhsInPrintDTO> requistionPrint(String dsName,String datasetName,Map<String,Object> parameters) {
		String sapDeliveryNote = (String) parameters.get("sapDeliveryNote");
		String items = (String) parameters.get("itemNoList");
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		// 查询交货单信息
		QueryWrapper<OverseaDn> query = new QueryWrapper<OverseaDn>().eq("SAP_DELIVERY_NOTE", sapDeliveryNote);
		OverseaDn head = this.baseMapper.selectOne(query);
		List<Map<String,Object>> dnDtlList = iOverseaDnDtlService.getDnDtlList(sapDeliveryNote);
		List<OverseaWhsInPrintDTO> list = new ArrayList<OverseaWhsInPrintDTO>();
		if (CollectionUtils.isNotEmpty(dnDtlList)) {
			if (StringUtils.isEmpty(items)) {
				for (Map<String,Object> map : dnDtlList) {
					OverseaWhsInPrintDTO dto = new OverseaWhsInPrintDTO();
					dto.setMaterialNo(map.get("materialNo").toString());
					dto.setMaterialZhName(map.get("materialZhDesc") != null ? map.get("materialZhDesc").toString() : "");
					dto.setMaterialEnName(map.get("materialZhDesc") != null ? map.get("materialZhDesc").toString() : "");
					dto.setSapDeliveryNote(sapDeliveryNote);
					dto.setCreateDate(head.getCreateTime() != null ? sdf.format(head.getCreateTime()) : "");
					list.add(dto);
				}
			} else {
				String[] split = items.split(",");
				List<String> asList = Arrays.asList(split);
				for (Map<String,Object> map : dnDtlList) {
					if (asList.contains(map.get("sapDeliveryNoteItem").toString())) {
						OverseaWhsInPrintDTO dto = new OverseaWhsInPrintDTO();
						dto.setMaterialNo(map.get("materialNo").toString());
						dto.setMaterialZhName(map.get("materialZhDesc") != null ? map.get("materialZhDesc").toString() : "");
						dto.setMaterialEnName(map.get("materialZhDesc") != null ? map.get("materialZhDesc").toString() : "");
						dto.setSapDeliveryNote(sapDeliveryNote);
						dto.setCreateDate(head.getCreateTime() != null ? sdf.format(head.getCreateTime()) : "");
						list.add(dto);
					}
				}
			}
		}
		return list;
	}
}


