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.OverseaWhsMoveSearchDTO;
import com.sunda.spmsoversea.dto.OverseaWhsMoveUpdateDTO;
import com.sunda.spmsoversea.entity.OverseaWhsMove;
import com.sunda.spmsoversea.entity.OverseaWhsMoveDtl;
import com.sunda.spmsoversea.entity.WhsStorageInventory;
import com.sunda.spmsoversea.mapper.OverseaWhsMoveMapper;
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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.sunda.spmsoversea.constant.CommonConstant.SUCCESS;
import static com.sunda.spmsoversea.constant.CommonConstant.sapLog;
import static com.sunda.spmsoversea.constant.SapConstant.SAP_SUCCESS;
import static com.sunda.spmsoversea.constant.WhsStorageInventoryConstant.*;
import static com.sunda.spmsoversea.enums.OverseaWhsDumpEnum.WHS_DUMP_MDM;
import static com.sunda.spmsoversea.enums.OverseaWhsMoveEnum.*;

/**
 * <p>
 * 海外仓调拨业务 服务实现类
 * </p>
 *
 * @author Wayne
 * @since 2022-01-20
 */
@Slf4j
@Service
public class OverseaWhsMoveServiceImpl extends ServiceImpl<OverseaWhsMoveMapper, OverseaWhsMove> implements IOverseaWhsMoveService {

    @Autowired
    IFeignServiceCommon iFeignServiceCommon;

    @Autowired
    IFormatDataToSapService iFormatDataToSapService;

    @Autowired
    IWhsStorageInventoryService iWhsStorageInventoryService;

    @Autowired
    IWhsOperateLogService iWhsOperateLogService;

    @Autowired
    IOverseaOperateLogService iOverseaOperateLogService;

    @Autowired
    IOverseaWhsMoveDtlService iOverseaWhsMoveDtlService;
    
    @Autowired
    ZSapOrgClientMapper zSapOrgClientMapper;

    /** 获取海外仓调拨任务表头分页列表 */
    @Override
    public IPage getOverseaWhsMovePage(OverseaWhsMoveSearchDTO overseaWhsMoveSearchDTO) {
        IPage iPage = overseaWhsMoveSearchDTO.getPage();
        List<Map<String, Object>> mapList = this.baseMapper.getOverseaWhsMovePage(iPage, overseaWhsMoveSearchDTO);
        iPage.setRecords(mapList);
        return iPage;
    }

    /** 获取海外仓调拨任务一条明细 */
    @Override
    public Map<String, Object> getOverseaWhsMoveByUuid(String uuid) {
        if (StringUtils.isEmpty(uuid)){
            return null;
        }
        return this.baseMapper.getOverseaWhsMoveByUuid(uuid);
    }

    /** 获取海外仓调拨任务详细明细信息 */
    @Override
    public List<Map<String, Object>> getOverseaWhsMoveDtlList(String uuid) {
        if (StringUtils.isEmpty(uuid)){
            return null;
        }
        return iOverseaWhsMoveDtlService.getOverseaWhsMoveDtlList(uuid);
    }

    /** 更新或新建海外仓调拨任务及明细，目标状态：1新建或更新；2提交SPMS更新两边仓库库存； */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult updateOverseaWhsMove(OverseaWhsMoveUpdateDTO overseaWhsMoveUpdateDTO, String userId) throws Exception {
//        try {
            ResponseResult checkUpdate = checkUpdateParam(overseaWhsMoveUpdateDTO);
            if (checkUpdate.getCode() != SUCCESS){
                return checkUpdate;
            }
            String uuid = "";
            String spmsStatus = overseaWhsMoveUpdateDTO.getSpmsStatus();
            if (StringUtils.isEmpty(overseaWhsMoveUpdateDTO.getUuid())){
                // 新建
                uuid = UUID.randomUUID().toString().replaceAll("-", "").toLowerCase();
                int createHead = createOverseaWhsMove(overseaWhsMoveUpdateDTO, uuid, userId);
                if (createHead < 1){
                    log.info("=======updateOverseaWhsMove RuntimeException=========\n");
                    throw new RuntimeException("创建海外仓调拨任务错误");
                }
                int createItem = createOverseaWhsMoveDtl(overseaWhsMoveUpdateDTO, uuid);
                if (createItem < 1){
                    log.info("=======updateOverseaWhsMove RuntimeException=========\n");
                    throw new RuntimeException("创建海外仓调拨任务明细错误");
                }
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OVERSEA_WHS_MOVE_CREATE.getDescZh(), OVERSEA_WHS_MOVE_CREATE.getDescEn(), "", OVERSEA_WHS_MOVE_CREATE.getDescRu());
            } else {
                // 更新
                uuid = overseaWhsMoveUpdateDTO.getUuid();
                int updateHead = updateOverseaWhsMoveHead(overseaWhsMoveUpdateDTO, uuid);
                if (updateHead < 1){
                    log.info("=======updateOverseaWhsMove RuntimeException=========\n");
                    throw new RuntimeException("更新海外仓调拨任务错误");
                }
                QueryWrapper<OverseaWhsMoveDtl> queryWrapperDtl = new QueryWrapper<OverseaWhsMoveDtl>().eq("UUID", uuid);
                iOverseaWhsMoveDtlService.remove(queryWrapperDtl);
                int createItem = createOverseaWhsMoveDtl(overseaWhsMoveUpdateDTO, uuid);
                if (createItem < 1){
                    log.info("=======updateOverseaWhsMove RuntimeException=========\n");
                    throw new RuntimeException("创建海外仓调拨任务明细错误");
                }
                if (OVERSEA_WHS_MOVE_UPDATE.getCode().equals(spmsStatus)){
                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OVERSEA_WHS_MOVE_UPDATE.getDescZh(), OVERSEA_WHS_MOVE_UPDATE.getDescEn(), "", OVERSEA_WHS_MOVE_UPDATE.getDescRu());
                }
                if (OVERSEA_WHS_MOVE_SUBMIT.getCode().equals(spmsStatus)){
                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OVERSEA_WHS_MOVE_SUBMIT.getDescZh(), OVERSEA_WHS_MOVE_SUBMIT.getDescEn(), "", OVERSEA_WHS_MOVE_SUBMIT.getDescRu());
                }
            }
            if (OVERSEA_WHS_MOVE_SUBMIT.getCode().equals(spmsStatus)){
                // 更新库存，isCancel: 是否为冲销业务的库存更新操作，正常提交业务传值 false；冲销操作库存更新传值 true；
                ResponseResult updateStorageInventory = updateWhsStorageInventory(uuid, userId, false);
                if (updateStorageInventory.getCode() != SUCCESS){
                    log.info("=======RuntimeException=========\n" + updateStorageInventory.getMsg());
                    throw new RuntimeException("储位库存更新错误\n" + updateStorageInventory.getMsg());
                }
            }
            return ResponseResult.success().add("overseaWhsMove", getOverseaWhsMoveByUuid(uuid))
                    .add("overseaWhsMoveDtl", getOverseaWhsMoveDtlList(uuid));
//        } catch (Exception e){
//            e.printStackTrace();
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//            return ResponseResult.error().add("error", e.getMessage());
//        }
    }

    /** isCancel: 是否为冲销业务的库存更新操作，正常提交业务传值 false；冲销操作库存更新传值 true； */
    synchronized ResponseResult updateWhsStorageInventory(String uuid, String userId, boolean isCancel){
        OverseaWhsMove overseaWhsMove = this.baseMapper.selectOne(new QueryWrapper<OverseaWhsMove>().eq("UUID", uuid));
        List<OverseaWhsMoveDtl> dtlList = iOverseaWhsMoveDtlService.list(new QueryWrapper<OverseaWhsMoveDtl>().eq("UUID", uuid));
        String werksOut = overseaWhsMove.getWerksMoveOut();
        String whsLocationCodeOut = overseaWhsMove.getWhsLocationCodeMoveOut();
        String werksIn = overseaWhsMove.getWerksMoveIn();
        String whsLocationCodeIn = overseaWhsMove.getWhsLocationCodeMoveIn();
        String movementType = overseaWhsMove.getMovementType();
        for (OverseaWhsMoveDtl dtl : dtlList){
            String materialNo = dtl.getMaterialNo();
            String itemNo = dtl.getItemNo();
            double actualQtyBasicUnit = dtl.getActualQtyMoveOut();
            if (actualQtyBasicUnit > 0){
                // 正向业务的出库储位扣减库存，冲销业务为增加库存储位
                JSONArray storageInfoArray = JSONArray.parseArray(dtl.getActualStorageInfoMoveOut());
                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){
                        if (!isCancel){
                            ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo, qty, SUB);
                            if (updateInventory.getCode() != SUCCESS){
                                return updateInventory;
                            }
                            /** 海外仓调拨出库 **/
                            String comments = "海外仓调拨出库";
                            iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, qty, OPERATION_TYPE3, uuid, comments, userId, "海外仓调拨", werksOut, whsLocationCodeOut, movementType, itemNo);
                        } else {
                            ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo, qty, ADD);
                            if (updateInventory.getCode() != SUCCESS){
                                return updateInventory;
                            }
                            /** 海外仓调拨出库撤销 **/
                            String comments = "海外仓调拨出库撤销";
                            iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, qty, OPERATION_TYPE2, uuid, comments, userId, "海外仓调拨撤销", werksOut, whsLocationCodeOut, movementType, itemNo);
                        }
                    }
                }
                // 正向业务的入库储位增加库存，冲销业务为扣减库存储位
                JSONArray storageInfoArrayIn = JSONArray.parseArray(dtl.getActualStorageInfoMoveIn());
                for (int i = 0; i < storageInfoArrayIn.size(); i ++){
                    JSONObject storageInfoObj = storageInfoArrayIn.getJSONObject(i);
                    String storageUuid = storageInfoObj.getString("storageUuid");
                    double qty = storageInfoObj.getDoubleValue("qty");
                    if (qty > 0){
                        if (!isCancel){
                            ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo, qty, ADD);
                            if (updateInventory.getCode() != SUCCESS){
                                return updateInventory;
                            }
                            /** 海外仓调拨入库 **/
                            String comments = "海外仓调拨入库";
                            iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, qty, OPERATION_TYPE2, uuid, comments, userId, "海外仓调拨", werksIn, whsLocationCodeIn, movementType, itemNo);
                        } else {
                            ResponseResult updateInventory = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo, qty, SUB);
                            if (updateInventory.getCode() != SUCCESS){
                                return updateInventory;
                            }
                            /** 海外仓调拨入库撤销 **/
                            String comments = "海外仓调拨入库撤销";
                            iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, qty, OPERATION_TYPE3, uuid, comments, userId, "海外仓调拨撤销", werksIn, whsLocationCodeIn, movementType, itemNo);
                        }
                    }
                }
            }
        }
        return ResponseResult.success();
    }

    ResponseResult checkUpdateParam(OverseaWhsMoveUpdateDTO overseaWhsMoveUpdateDTO){
        if (overseaWhsMoveUpdateDTO == null){
            return ResponseResult.error("请求参数不能为空");
        }
        String spmsStatus = overseaWhsMoveUpdateDTO.getSpmsStatus();
        if (StringUtils.isEmpty(spmsStatus)){
            return ResponseResult.error("请求参数目标状态不能为空");
        }
        String uuid = overseaWhsMoveUpdateDTO.getUuid();
        if (StringUtils.isEmpty(uuid)){
            //新建
            if (StringUtils.isEmpty(overseaWhsMoveUpdateDTO.getCreateDate())){
                return ResponseResult.error("新建订单创建日期不允许为空");
            }
            if (StringUtils.isEmpty(overseaWhsMoveUpdateDTO.getWerksMoveOut()) || StringUtils.isEmpty(overseaWhsMoveUpdateDTO.getWerksMoveIn())){
                return ResponseResult.error("新建订单调入调出工厂不允许为空");
            }
            if (StringUtils.isEmpty(overseaWhsMoveUpdateDTO.getWhsLocationCodeMoveOut()) ||
                    StringUtils.isEmpty(overseaWhsMoveUpdateDTO.getWhsLocationCodeMoveIn())){
                return ResponseResult.error("新建订单调入调出仓库不允许为空");
            }
        } else {
            //更新
            Integer dataVersion = overseaWhsMoveUpdateDTO.getDataVersion();
            OverseaWhsMove overseaWhsMove = this.baseMapper.selectOne(new QueryWrapper<OverseaWhsMove>().eq("UUID", uuid));
            if (overseaWhsMove == null){
                return ResponseResult.error("更新调拨任务不存在");
            }
            if (!dataVersion.equals(overseaWhsMove.getDataVersion())){
                return ResponseResult.error("请求调拨任务已更新，请刷新重试");
            }
        }
        if (OVERSEA_WHS_MOVE_SUBMIT.getCode().equals(spmsStatus)){
            //直接扣库存，检查库存是否够扣减
            ResponseResult checkInv = checkInventory(overseaWhsMoveUpdateDTO);
            if (checkInv.getCode() != SUCCESS){
                return checkInv;
            }
        }
        return ResponseResult.success();
    }

    ResponseResult checkInventory(OverseaWhsMoveUpdateDTO overseaWhsMoveUpdateDTO){
        List<OverseaWhsMoveDtl> overseaWhsMoveDtlList = overseaWhsMoveUpdateDTO.getOverseaWhsMoveDtlList();
        if (overseaWhsMoveDtlList == null || overseaWhsMoveDtlList.size() == 0){
            return ResponseResult.error("调拨明细信息不能为空");
        }
        for (int k = 0; k < overseaWhsMoveDtlList.size(); k ++){
            OverseaWhsMoveDtl overseaWhsMoveDtl = overseaWhsMoveDtlList.get(k);
            String item = overseaWhsMoveDtl.getItemNo();
            String materialNo = overseaWhsMoveDtl.getMaterialNo();
            String storageInfo = overseaWhsMoveDtl.getActualStorageInfoMoveOut();
            double actualQtyBasicUnit = overseaWhsMoveDtl.getActualQtyMoveOut();
            if (actualQtyBasicUnit > 0){
                if (StringUtils.isEmpty(storageInfo)){
                    return ResponseResult.error("实出数量大于0的行:" + item + "，料号:" + materialNo + "储位信息无效");
                }
                //storageInfoArray 结构参考：[{"storageUuid":"cbd9576a4e53461fe0530101007f3e24","qty":5,"storageNo":"A010101","unitValue":5}]
                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 + "可用库存不足");
                        }
                    }
                }
            }
        }
        return ResponseResult.success();
    }

    int createOverseaWhsMove(OverseaWhsMoveUpdateDTO dto, String uuid, String userId){
        OverseaWhsMove overseaWhsMove = new OverseaWhsMove();
        overseaWhsMove.setUuid(uuid);
        overseaWhsMove.setSubject(dto.getSubject());
        overseaWhsMove.setCreateDate(dto.getCreateDate());
        overseaWhsMove.setSpmsStatus(StringUtils.isEmpty(dto.getSpmsStatus()) ? "1" : dto.getSpmsStatus());
        overseaWhsMove.setMovementType(dto.getMovementType());
        overseaWhsMove.setWerksMoveOut(dto.getWerksMoveOut());
        overseaWhsMove.setWhsLocationCodeMoveOut(dto.getWhsLocationCodeMoveOut());
        overseaWhsMove.setRemarkMoveOut(dto.getRemarkMoveOut());
        overseaWhsMove.setWerksMoveIn(dto.getWerksMoveIn());
        overseaWhsMove.setWhsLocationCodeMoveIn(dto.getWhsLocationCodeMoveIn());
        overseaWhsMove.setRemarkMoveIn(dto.getRemarkMoveIn());
        overseaWhsMove.setRelateDocument(dto.getRelateDocument());
        overseaWhsMove.setCreateUserid(userId);
        return this.baseMapper.insert(overseaWhsMove);
    }

    int createOverseaWhsMoveDtl(OverseaWhsMoveUpdateDTO overseaWhsMoveUpdateDTO, String uuid){
        List<OverseaWhsMoveDtl> overseaWhsMoveDtlList = overseaWhsMoveUpdateDTO.getOverseaWhsMoveDtlList();
        int result = 0;
        for (int i = 0; i < overseaWhsMoveDtlList.size(); i ++){
            OverseaWhsMoveDtl overseaWhsMoveDtl = overseaWhsMoveDtlList.get(i);
            OverseaWhsMoveDtl dtl = new OverseaWhsMoveDtl();
            dtl.setUuid(uuid);
            dtl.setItemNo(String.valueOf((i + 1) * 10));
            dtl.setMaterialNo(overseaWhsMoveDtl.getMaterialNo());
            dtl.setQtyMoveOut(overseaWhsMoveDtl.getQtyMoveOut());
            dtl.setStorageInfoMoveOut(overseaWhsMoveDtl.getStorageInfoMoveOut());
            dtl.setActualQtyMoveOut(overseaWhsMoveDtl.getActualQtyMoveOut());
            dtl.setActualStorageInfoMoveOut(overseaWhsMoveDtl.getActualStorageInfoMoveOut());
            dtl.setRemarkMoveOut(overseaWhsMoveDtl.getRemarkMoveOut());
            dtl.setActualQtyMoveIn(overseaWhsMoveDtl.getActualQtyMoveIn());
            dtl.setActualStorageInfoMoveIn(overseaWhsMoveDtl.getActualStorageInfoMoveIn());
            dtl.setRemarkMoveIn(overseaWhsMoveDtl.getRemarkMoveIn());
            dtl.setSupplierNo(overseaWhsMoveDtl.getSupplierNo());
            if (iOverseaWhsMoveDtlService.save(dtl)){
                result += 1;
            }
        }
        return result;
    }

    int updateOverseaWhsMoveHead(OverseaWhsMoveUpdateDTO dto, String uuid){
        QueryWrapper<OverseaWhsMove> queryWrapper = new QueryWrapper<OverseaWhsMove>().eq("UUID", uuid);
        OverseaWhsMove overseaWhsMove = this.baseMapper.selectOne(queryWrapper);
        overseaWhsMove.setSubject(dto.getSubject());
        overseaWhsMove.setSpmsStatus(dto.getSpmsStatus());
        overseaWhsMove.setRemarkMoveOut(dto.getRemarkMoveOut());
        overseaWhsMove.setRemarkMoveIn(dto.getRemarkMoveIn());
        overseaWhsMove.setRelateDocument(dto.getRelateDocument());
        return this.baseMapper.update(overseaWhsMove, queryWrapper);
    }

    /** 海外仓调拨任务提交SAP：2——3、2——4 或 3——4 */
    @SuppressWarnings("unchecked")
	@Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult submitOverseaWhsMoveSap(String uuid, String postingDate, Integer dataVersion, String userId) throws Exception {
//        try {
            ResponseResult checkSubmit = checkSubmitSap(uuid, postingDate, dataVersion);
            if (checkSubmit.getCode() != SUCCESS){
                return checkSubmit;
            }
            QueryWrapper<OverseaWhsMove> queryWrapper = new QueryWrapper<OverseaWhsMove>().eq("UUID", uuid);
            Map<String, Object> submitSapHead = this.baseMapper.submitSapHead(uuid, postingDate);
            List<Map<String, Object>> submitSapItem = this.baseMapper.submitSapItem(uuid);
            if (submitSapHead == null || submitSapItem == null || submitSapItem.size() == 0){
                return ResponseResult.error("查询无可提交SAP项目");
            }
            JSONObject dataToSap = iFormatDataToSapService.formatDataToSap(submitSapHead, submitSapItem, "Z_SPMS_ANOMALY_POST", "ANOMALY_POST");
            // 根据工厂查询对应的SAP Clinet
            List<ZSapOrgClient> selectList = zSapOrgClientMapper.selectList(new QueryWrapper<ZSapOrgClient>().eq("WERKS", submitSapHead.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("工厂："+submitSapHead.get("werks")+"未找到对应的SAP Clinet");
            }
            log.info("=======海外仓调拨任务请求SAP dataToSap=========\n" + dataToSap);
            JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
            log.info("=======海外仓调拨任务请求SAP响应结果 message=========\n" + message);
            JSONObject RETURN_DATA_Undercharged = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
            OverseaWhsMove overseaWhsMove = new OverseaWhsMove();
            if (SAP_SUCCESS.equals(RETURN_DATA_Undercharged.getString("O_TYPE"))) {
                String sapVoucherNumber = RETURN_DATA_Undercharged.getString("O_MBLNR").trim();
                String sapVoucherYear = RETURN_DATA_Undercharged.getString("O_MJAHR").trim();
                overseaWhsMove.setPostingDate(postingDate);
                overseaWhsMove.setSapVoucherNumber(sapVoucherNumber);
                overseaWhsMove.setSapVoucherYear(sapVoucherYear);
                overseaWhsMove.setSpmsStatus(OVERSEA_WHS_MOVE_SUBMIT_SAP.getCode());
                this.baseMapper.update(overseaWhsMove, queryWrapper);
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OVERSEA_WHS_MOVE_SUBMIT_SAP.getDescZh() + ":" + sapVoucherNumber,
                        OVERSEA_WHS_MOVE_SUBMIT_SAP.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "海外仓调拨提交SAP成功", OVERSEA_WHS_MOVE_SUBMIT_SAP.getDescRu());
                try {
                	JSONArray costArray = RETURN_DATA_Undercharged.getJSONArray("IT_COST");
                	if (costArray != null && costArray.size() > 0) {
                		List<OverseaWhsMoveDtl> itemList = new ArrayList<OverseaWhsMoveDtl>();
                		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) {
                				OverseaWhsMoveDtl dtl = new OverseaWhsMoveDtl();
                				String zeile = (String) map.get("ZEILE1");
                				String zeileRepla = zeile.replaceAll("^(0+)", "");
                				dtl.setUuid(uuid);
                				dtl.setItemNo(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<OverseaWhsMoveDtl>> partition = Lists.partition(itemList, 1000);
                				for (List<OverseaWhsMoveDtl> pa : partition) {
                					this.baseMapper.updateBatchDtl(pa);
                				}
                			} else {
                				this.baseMapper.updateBatchDtl(itemList);
                			}
                		}
                	}
                } catch (Exception e) {
                }
                
                return ResponseResult.success("海外仓调拨任务提交SAP成功")
                        .add("overseaWhsMove", getOverseaWhsMoveByUuid(uuid));
            } else {
                overseaWhsMove.setPostingDate(postingDate);
                overseaWhsMove.setSpmsStatus(OVERSEA_WHS_MOVE_SUBMIT_SAP_ERROR.getCode());
                this.baseMapper.update(overseaWhsMove, queryWrapper);
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OVERSEA_WHS_MOVE_SUBMIT_SAP_ERROR.getDescZh(),
                        OVERSEA_WHS_MOVE_SUBMIT_SAP_ERROR.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "海外仓调拨提交SAP失败", OVERSEA_WHS_MOVE_SUBMIT_SAP_ERROR.getDescRu());
                return ResponseResult.error("海外仓调拨任务提交SAP失败")
                        .add("sapReturnedMessage", message)
                        .add("dataToSap", dataToSap)
                        .add("overseaWhsMove", getOverseaWhsMoveByUuid(uuid));
            }
//        } 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(String uuid, String postingDate, Integer dataVersion){
        if (StringUtils.isEmpty(uuid)){
            return ResponseResult.error("请求参数错误");
        }
        if (StringUtils.isEmpty(postingDate) || dataVersion == null){
            return ResponseResult.error("请求参数错误");
        }
        OverseaWhsMove overseaWhsMove = this.baseMapper.selectOne(new QueryWrapper<OverseaWhsMove>().eq("UUID", uuid));
        if (overseaWhsMove == null){
            return ResponseResult.error("更新调拨任务不存在");
        }
        if (!dataVersion.equals(overseaWhsMove.getDataVersion())){
            return ResponseResult.error("请求调拨任务已更新，请刷新重试");
        }
        String spmsStatus = overseaWhsMove.getSpmsStatus();
        if (!OVERSEA_WHS_MOVE_SUBMIT.getCode().equals(spmsStatus) &&
                !OVERSEA_WHS_MOVE_SUBMIT_SAP_ERROR.getCode().equals(spmsStatus)){
            return ResponseResult.error("请求调拨任务当前状态禁止此操作");
        }
        return ResponseResult.success();
    }

    /** 海外仓调拨任务关闭 1-0；*/
    @Override
    public synchronized ResponseResult closeOverseaWhsMoveTask(String uuid, Integer dataVersion, String userId) {
        if (StringUtils.isEmpty(uuid) || dataVersion == null){
            return ResponseResult.error("请求参数错误");
        }
        QueryWrapper<OverseaWhsMove> queryWrapper = new QueryWrapper<OverseaWhsMove>().eq("UUID", uuid);
        OverseaWhsMove overseaWhsMove = this.baseMapper.selectOne(queryWrapper);
        if (overseaWhsMove == null){
            return ResponseResult.error("更新调拨任务不存在");
        }
        if (!dataVersion.equals(overseaWhsMove.getDataVersion())){
            return ResponseResult.error("请求调拨任务已更新，请刷新重试");
        }
        String spmsStatus = overseaWhsMove.getSpmsStatus();
        if (!OVERSEA_WHS_MOVE_CREATE.getCode().equals(spmsStatus)){
            return ResponseResult.error("请求调拨任务当前状态禁止此操作");
        }
        overseaWhsMove.setSpmsStatus(OVERSEA_WHS_MOVE_CLOSE.getCode());
        this.baseMapper.update(overseaWhsMove, queryWrapper);
        iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OVERSEA_WHS_MOVE_CLOSE.getDescZh(), OVERSEA_WHS_MOVE_CLOSE.getDescEn(), "", OVERSEA_WHS_MOVE_CLOSE.getDescRu());
        return ResponseResult.success().add("overseaWhsMove", getOverseaWhsMoveByUuid(uuid));
    }

    /** 调拨任务撤销，状态变化：2——1，3——1，4——1，都要更新库存 */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult cancelOverseaWhsMove(String uuid, Integer dataVersion, String cancelPostingDate, String userId) throws Exception {
//        try {
            ResponseResult checkCancel = checkCancel(uuid, dataVersion, cancelPostingDate);
            if (checkCancel.getCode() != SUCCESS){
                return checkCancel;
            }
            QueryWrapper<OverseaWhsMove> queryWrapper = new QueryWrapper<OverseaWhsMove>().eq("UUID", uuid);
            OverseaWhsMove overseaWhsMove = this.baseMapper.selectOne(queryWrapper);
            String spmsStatus = overseaWhsMove.getSpmsStatus();
            if (OVERSEA_WHS_MOVE_SUBMIT.getCode().equals(spmsStatus) || OVERSEA_WHS_MOVE_SUBMIT_SAP_ERROR.getCode().equals(spmsStatus)){
                ResponseResult updateInv = updateWhsStorageInventory(uuid, userId, true);
                if (updateInv.getCode() != SUCCESS){
                    log.info("=======RuntimeException=========\n" + updateInv.getMsg());
                    throw new RuntimeException("储位库存更新错误\n" + updateInv.getMsg());
                }
                overseaWhsMove.setSpmsStatus(OVERSEA_WHS_MOVE_UPDATE.getCode());
                this.baseMapper.update(overseaWhsMove, queryWrapper);
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OVERSEA_WHS_MOVE_CANCEL.getDescZh(), OVERSEA_WHS_MOVE_CANCEL.getDescEn(), "", OVERSEA_WHS_MOVE_CANCEL.getDescRu());
                return ResponseResult.success().add("overseaWhsMove", getOverseaWhsMoveByUuid(uuid))
                        .add("overseaWhsMoveDtl", getOverseaWhsMoveDtlList(uuid));
            } else if (OVERSEA_WHS_MOVE_SUBMIT_SAP.getCode().equals(spmsStatus)){
                Map<String, Object> dataHeadAnomaly = this.baseMapper.dataHeadCancelAnomaly(uuid, cancelPostingDate);
                JSONObject dataToSapCancelAnomaly = iFormatDataToSapService.formatDataToSap(dataHeadAnomaly, null, "Z_SPMS_CANCEL", "SPMS_CANCEL");
                // 根据工厂查询对应的SAP Clinet
                List<ZSapOrgClient> clinetList = zSapOrgClientMapper.selectList(new QueryWrapper<ZSapOrgClient>().eq("WERKS", overseaWhsMove.getWerksMoveIn()));
                if (!CollectionUtils.isEmpty(clinetList)) {
                	JSONObject esbObj = dataToSapCancelAnomaly.getJSONObject("REQUEST").getJSONObject("ESB_ATTRS");
                	esbObj.put("Target_ID", "SAP-"+clinetList.get(0).getZmandt());
                } else {
                	return ResponseResult.error("工厂："+overseaWhsMove.getWerksMoveIn()+"未找到对应的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 cancelVoucherNumber = RETURN_DATA_Anomaly.getString("0_MBLNR");
                    overseaWhsMove.setCancelPostingDate(cancelPostingDate);
                    overseaWhsMove.setCancelVoucherNumber(cancelVoucherNumber);
                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OVERSEA_WHS_MOVE_CANCEL_SAP.getDescZh() + ":" + cancelVoucherNumber,
                            OVERSEA_WHS_MOVE_CANCEL_SAP.getDescEn(), sapLog, dataToSapCancelAnomaly.toJSONString(), messageCancelAnomaly.toJSONString(), "", OVERSEA_WHS_MOVE_CANCEL_SAP.getDescRu());

                    ResponseResult updateInv = updateWhsStorageInventory(uuid, userId, true);
                    if (updateInv.getCode() != SUCCESS){
                        log.info("=======RuntimeException=========\n" + updateInv.getMsg());
                        throw new RuntimeException("储位库存更新错误\n" + updateInv.getMsg());
                    }
                    overseaWhsMove.setSpmsStatus(OVERSEA_WHS_MOVE_UPDATE.getCode());
                    this.baseMapper.update(overseaWhsMove, queryWrapper);
                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OVERSEA_WHS_MOVE_CANCEL.getDescZh(), OVERSEA_WHS_MOVE_CANCEL.getDescEn(), "", OVERSEA_WHS_MOVE_CANCEL.getDescRu());
                    return ResponseResult.success().add("overseaWhsMove", getOverseaWhsMoveByUuid(uuid))
                            .add("overseaWhsMoveDtl", getOverseaWhsMoveDtlList(uuid));
                } else {
                    overseaWhsMove.setCancelPostingDate(cancelPostingDate);
                    this.baseMapper.update(overseaWhsMove, queryWrapper);
                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, OVERSEA_WHS_MOVE_CANCEL_ERROR.getDescZh(),
                            OVERSEA_WHS_MOVE_CANCEL_ERROR.getDescEn(), sapLog, dataToSapCancelAnomaly.toJSONString(), messageCancelAnomaly.toJSONString(), "", OVERSEA_WHS_MOVE_CANCEL_ERROR.getDescRu());
                    return ResponseResult.error().add("overseaWhsMove", getOverseaWhsMoveByUuid(uuid))
                            .add("overseaWhsMoveDtl", getOverseaWhsMoveDtlList(uuid))
                            .add("sapReturnedMessage", messageCancelAnomaly)
                            .add("dataToSap", dataToSapCancelAnomaly);
                }
            } else {
                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 checkCancel(String uuid, Integer dataVersion, String cancelPostingDate){
        if (StringUtils.isEmpty(uuid) || dataVersion == null){
            return ResponseResult.error("请求参数uuid或数据版本号不允许为空");
        }
        OverseaWhsMove overseaWhsMove = this.baseMapper.selectOne(new QueryWrapper<OverseaWhsMove>().eq("UUID", uuid));
        if (overseaWhsMove == null){
            return ResponseResult.error("请求调拨任务不存在");
        }
        if (!dataVersion.equals(overseaWhsMove.getDataVersion())){
            return ResponseResult.error("请求调拨任务已更新，请刷新重试");
        }
        String spmsStatus = overseaWhsMove.getSpmsStatus();
        if (!OVERSEA_WHS_MOVE_SUBMIT.getCode().equals(spmsStatus) &&
                !OVERSEA_WHS_MOVE_SUBMIT_SAP_ERROR.getCode().equals(spmsStatus) &&
                !OVERSEA_WHS_MOVE_SUBMIT_SAP.getCode().equals(spmsStatus)){
            return ResponseResult.error("请求调拨任务当前状态禁止此操作");
        }
        if (OVERSEA_WHS_MOVE_SUBMIT_SAP.getCode().equals(spmsStatus)){
            if (StringUtils.isEmpty(cancelPostingDate)){
                return ResponseResult.error("撤销过账日期不允许为空");
            }
        }
        List<OverseaWhsMoveDtl> overseaWhsMoveDtlList = iOverseaWhsMoveDtlService.list(new QueryWrapper<OverseaWhsMoveDtl>().eq("UUID", uuid));
        for (int k = 0; k < overseaWhsMoveDtlList.size(); k ++){
            OverseaWhsMoveDtl overseaWhsMoveDtl = overseaWhsMoveDtlList.get(k);
            String item = overseaWhsMoveDtl.getItemNo();
            String materialNo = overseaWhsMoveDtl.getMaterialNo();
            String storageInfo = overseaWhsMoveDtl.getActualStorageInfoMoveIn();
            double actualQtyBasicUnit = overseaWhsMoveDtl.getActualQtyMoveIn();
            if (actualQtyBasicUnit > 0){
                if (StringUtils.isEmpty(storageInfo)){
                    return ResponseResult.error("实际调入数量大于0的行:" + item + "，料号:" + materialNo + "储位信息无效");
                }
                //storageInfoArray 结构参考：[{"storageUuid":"cbd9576a4e53461fe0530101007f3e24","qty":5,"storageNo":"A010101","unitValue":5}]
                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 + "可用库存不足");
                        }
                    }
                }
            }
        }
        return ResponseResult.success();
    }

	@Override
	public ResponseResult getOverseaWhsMoveHead(String spmsId) {
		if (StringUtils.isEmpty(spmsId)) {
			ResponseResult.error("SPMS单号为空，请求失败");
		}
		// 查询头信息
		QueryWrapper<OverseaWhsMove> queryWrapperDtl = new QueryWrapper<OverseaWhsMove>().eq("WHS_MOVE_NO", spmsId);
		OverseaWhsMove headVO = this.baseMapper.selectOne(queryWrapperDtl);
		// 查询行项目
		List<Map<String, Object>> dtlList = iOverseaWhsMoveDtlService.getOverseaWhsMoveDtlList(headVO != null ? headVO.getUuid() : "");
		return ResponseResult.success().add("headVO", headVO).add("itemList", dtlList);
	}


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult whsMoveToMdM(String uuid,String userId) throws Exception {
        QueryWrapper<OverseaWhsMove> queryWrapper = new QueryWrapper<OverseaWhsMove>().eq("UUID", uuid);
        OverseaWhsMove headVO = this.baseMapper.selectOne(queryWrapper);

        QueryWrapper<OverseaWhsMoveDtl> queryWrapperDtl = new QueryWrapper<OverseaWhsMoveDtl>().eq("UUID", uuid);
        List<OverseaWhsMoveDtl> dtlList = iOverseaWhsMoveDtlService.list(queryWrapperDtl);

        JSONObject dataToSap = new JSONObject();
        JSONObject REQUEST = new JSONObject();
        JSONObject ESB_ATTRS = new JSONObject();
        JSONObject REQUEST_DATA = new JSONObject();
        Map<String, Object> sendData = new HashMap<String, Object>();

        List<String> materialList = dtlList.stream().map(OverseaWhsMoveDtl::getMaterialNo).filter(o -> StringUtils.isNotEmpty(o))
                .distinct().collect(Collectors.toList());

        List<Map<String, String>> mapItems = new ArrayList<Map<String, String>>();
        for (int i = 0; i < materialList.size(); i ++){
            Map<String, String> itemIn = new HashMap<String, String>();
            itemIn.put("MATNR", materialList.get(i));
            itemIn.put("WERKS", headVO.getWerksMoveIn());

            Map<String, String> itemOut = new HashMap<String, String>();
            itemOut.put("MATNR", materialList.get(i));
            itemOut.put("WERKS", headVO.getWerksMoveOut());

            mapItems.add(itemIn);
            mapItems.add(itemOut);
        }

        String transaction_ID = UUID.randomUUID().toString();
        sendData.put("App_ID", "SPMS");
        sendData.put("Transaction_ID", transaction_ID);
        sendData.put("MapItems", mapItems);

        REQUEST_DATA.put("SendData", sendData);
        REQUEST_DATA.put("Operation", "Z_WL_WERKS");
        REQUEST_DATA.put("Type", "Z_WL_WERKS");
        ESB_ATTRS.put("App_ID", "SPMS");
        ESB_ATTRS.put("Target_ID", "MDM");
        ESB_ATTRS.put("Application_ID", "00020000000002");
        ESB_ATTRS.put("Transaction_ID", transaction_ID);
        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
        REQUEST.put("REQUEST_DATA", REQUEST_DATA);
        dataToSap.put("REQUEST", REQUEST);

        log.info("=======dataToSap get whsDumpToMDMFormat=========\n" + dataToSap);
        JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
        log.info("=======message get whsDumpToMDMFormat=========\n" + message);

        iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, WHS_DUMP_MDM.getDescZh(),
                WHS_DUMP_MDM.getDescEn(), sapLog, dataToSap.toJSONString(), message.toJSONString(), "调拨任务详情推送工厂与物料到MDM", WHS_DUMP_MDM.getDescRu());

        return ResponseResult.success("调拨任务详情推送工厂与物料到MDM成功")
                .add("sapReturnedMessage", message);

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult werksToMdM(String werks,String materialNumbers,String userId) throws Exception {
        JSONObject dataToSap = new JSONObject();
        JSONObject REQUEST = new JSONObject();
        JSONObject ESB_ATTRS = new JSONObject();
        JSONObject REQUEST_DATA = new JSONObject();
        Map<String, Object> sendData = new HashMap<String, Object>();

        String[] materialList = materialNumbers.split(",");
        List<Map<String, String>> mapItems = new ArrayList<Map<String, String>>();
        for (int i = 0; i < materialList.length; i ++){
            Map<String, String> itemIn = new HashMap<String, String>();
            itemIn.put("MATNR", materialList[i].trim());
            itemIn.put("WERKS", werks);
            mapItems.add(itemIn);
        }
        String transaction_ID = UUID.randomUUID().toString();
        sendData.put("App_ID", "SPMS");
        sendData.put("Transaction_ID", transaction_ID);
        sendData.put("MapItems", mapItems);
        REQUEST_DATA.put("SendData", sendData);
        REQUEST_DATA.put("Operation", "Z_WL_WERKS");
        REQUEST_DATA.put("Type", "Z_WL_WERKS");
        ESB_ATTRS.put("App_ID", "SPMS");
        ESB_ATTRS.put("Target_ID", "MDM");
        ESB_ATTRS.put("Application_ID", "00020000000002");
        ESB_ATTRS.put("Transaction_ID", transaction_ID);
        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
        REQUEST.put("REQUEST_DATA", REQUEST_DATA);
        dataToSap.put("REQUEST", REQUEST);

        log.info("=======dataToSap get whsDumpToMDMFormat=========\n" + dataToSap);
        JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(dataToSap));
        log.info("=======message get whsDumpToMDMFormat=========\n" + message);

        return ResponseResult.success("推送工厂与物料到MDM成功")
                .add("sapReturnedMessage", message);

    }

}



