package com.sunda.spmsoversea.service.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
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.spmscommon.utils.OAMainUtils;
import com.sunda.spmsoversea.constant.CommonConstant;
import com.sunda.spmsoversea.dto.OverseaInvCheckActionPrintDTO;
import com.sunda.spmsoversea.dto.OverseaInvCheckActionSearchDTO;
import com.sunda.spmsoversea.entity.*;
import com.sunda.spmsoversea.enums.OverseaInvCheckActionPrintEnum;
import com.sunda.spmsoversea.mapper.OverseaInvCheckActionMapper;
import com.sunda.spmsoversea.mapper.OverseaInvCheckMapper;
import com.sunda.spmsoversea.mapper.ZOaOrgClientMapper;
import com.sunda.spmsoversea.service.*;
import com.sunda.spmsuser.entity.SpmsUser;

import localhost.services.ExtHrmresources.ExtHrmresourcesPortTypeProxy;
import localhost.services.RequestService.RequestServicePortTypeProxy;
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 weaver.soa.workflow.request.*;

import java.rmi.RemoteException;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.sunda.spmscommon.Constans.*;
import static com.sunda.spmscommon.constant.OaConstant.BUSINESS_TYPE_INV_CHECK;
import static com.sunda.spmsoversea.constant.CommonConstant.INVALID_DATE;
import static com.sunda.spmsoversea.constant.CommonConstant.oaLog;
import static com.sunda.spmsoversea.constant.SapConstant.SAP_SUCCESS;
import static com.sunda.spmsoversea.constant.WhsStorageInventoryConstant.ADD;
import static com.sunda.spmsoversea.constant.WhsStorageInventoryConstant.SUB;

/**
 * <p>
 * 仓库盘盈盘亏 服务实现类
 * </p>
 *
 * @author Wayne
 * @since 2021-05-10
 */
@Slf4j
@Service
public class OverseaInvCheckActionServiceImpl extends ServiceImpl<OverseaInvCheckActionMapper, OverseaInvCheckAction>
        implements IOverseaInvCheckActionService {

    @Autowired
    IOverseaInvCheckActionDtlService iOverseaInvCheckActionDtlService;

    @Autowired
    IFeignServiceCommon iFeignServiceCommon;

    @Autowired
    IOverseaOperateLogService iOverseaOperateLogService;

    @Autowired
    IWhsStorageInventoryService iWhsStorageInventoryService;

    @Value("${oa.workflow.id3168}")
    String workflow3168;
    @Value("${oa.new.workflow.id3168}")
    String workflow3168_new;
    @Value("${oa.ipo.workflow.id3168}")
    String workflow3168_ipo;
    @Value("${oa.new.url}")
    String oaUrl;

    @Autowired OverseaInvCheckMapper overseaInvCheckMapper;

    @Autowired
    IWhsOperateLogService iWhsOperateLogService;
    
    @Autowired
    private ZSapOrgClientMapper zSapOrgClientMapper;

    @Autowired
    private ZOaOrgClientMapper zOaOrgClientMapper;

    @Override
    public List<OverseaInvCheckAction> getInvChkAcByInvChkId(String invChkId) {
        return this.baseMapper.selectList(new QueryWrapper<OverseaInvCheckAction>().eq("INVENTORY_CHECK_ID", invChkId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult getInvCheckAcWithDtl(String uuid) throws Exception {
//        try {
            QueryWrapper<OverseaInvCheckAction> queryWrapper = new QueryWrapper<OverseaInvCheckAction>().eq("UUID",
                    uuid);
            OverseaInvCheckAction inventoryCheckAction = this.baseMapper.selectOne(queryWrapper);
            if (null == inventoryCheckAction) {
                throw new Exception("Could not find Inventory Check Action for uuid: " + uuid);
            }

            ResponseResult res = iOverseaInvCheckActionDtlService.getInvCheckAcDtl(uuid);
            if (res.getCode() != 200) {
                throw new Exception(res.getMsg());
            }

            return res.add("invCheckAc", inventoryCheckAction);

//        } catch (Exception e) {
//            e.printStackTrace();
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//            return ResponseResult.error(e.getMessage());
//        }
    }

    /**
     * 获取库存盘点任务列表 { "werks":["CN01","CM31"], "whsLocationCode":["1011","1061"],
     * "inventoryCheckCategory":"1", //盘点类别 1-日常盘点 2-月度盘点 3-动态盘点 4-其它盘点
     * "createDate":["20210401","20210501"], "inventoryCheckId":"CN01-20210511-INV",
     * "spmsStatus":"1", 任务状态：1-草稿;2-提交OA成功；3-提交OA失败；4-OA审批不通过；5-OA审批通过待上传SAP;
     * 6-上传SAP失败 7 -上传SAP成功 8 - 已撤销
     */
    @Override
    public ResponseResult getInvCheckAcList(JSONObject InvCheckFilter) {
        List<String> werks = InvCheckFilter.containsKey("werks") ? (List) InvCheckFilter.getJSONArray("werks") : null;
        List<String> whsLocationCode = InvCheckFilter.containsKey("whsLocationCode")
                ? (List) InvCheckFilter.getJSONArray("whsLocationCode")
                : null;
        String inventoryCheckCategory = InvCheckFilter.containsKey("inventoryCheckCategory")
                ? InvCheckFilter.getString("inventoryCheckCategory")
                : null;
        String natureOfTheFactory = InvCheckFilter.containsKey("natureOfTheFactory")
                ? InvCheckFilter.getString("natureOfTheFactory")
                : null;
        String spmsStatus = InvCheckFilter.containsKey("spmsStatus") ? InvCheckFilter.getString("spmsStatus") : null;
        String inventoryCheckId = InvCheckFilter.containsKey("inventoryCheckId")
                ? InvCheckFilter.getString("inventoryCheckId")
                : null;
        String spmsId = InvCheckFilter.containsKey("spmsId") ? InvCheckFilter.getString("spmsId") : null;
        String startDate = null, endDate = null;
        if (InvCheckFilter.containsKey("createDate")) {
            List<String> datePeriod = (List) InvCheckFilter.getJSONArray("createDate");
            if (datePeriod.size() == 2) {
                startDate = datePeriod.get(0);
                endDate = datePeriod.get(1);
            }
        }
        QueryWrapper<OverseaInvCheckAction> queryWrapper = new QueryWrapper<OverseaInvCheckAction>();
        if (null != werks && werks.size() > 0) {
            queryWrapper.in("WERKS", werks);
        }
        if (null != whsLocationCode && whsLocationCode.size() > 0) {
            queryWrapper.in("WHS_LOCATION_CODE", whsLocationCode);
        }

        if (StringUtils.isNotEmpty(inventoryCheckCategory)) {
            queryWrapper.eq("INVENTORY_CHECK_CATEGORY", inventoryCheckCategory);
        }
        if (StringUtils.isNotEmpty(natureOfTheFactory)) {
            queryWrapper.eq("NATURE_OF_THE_FACTORY", natureOfTheFactory);
        }
        if (StringUtils.isNotEmpty(inventoryCheckId)) {
            queryWrapper.eq("INVENTORY_CHECK_ID", inventoryCheckId);
        }
        if (StringUtils.isNotEmpty(spmsId)) {
            queryWrapper.eq("SPMS_ID", spmsId);
        }
        if (StringUtils.isNotEmpty(spmsStatus)) {
            queryWrapper.eq("SPMS_STATUS", spmsStatus);
        }
        if (StringUtils.isNotEmpty(startDate)) {
            queryWrapper.between("CREATE_DATE", startDate, endDate);
        }
        try {
            return ResponseResult.success().add("invCheckAcList",
                    this.baseMapper.selectList(queryWrapper.orderByDesc("CREATE_TIME")));
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.error("Failed when query Inventory Check Action");
        }
    }

    /**
     * 新建盘盈亏单据 1. 有uuid 更新 2. 无uuid 新建
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult updateInvCheckAc(JSONObject InvCheckDoc, String userId)throws Exception  {
//        try {
            JSONObject invCheckAc = InvCheckDoc.containsKey("invCheckAc") ? InvCheckDoc.getJSONObject("invCheckAc")
                    : null;
            JSONArray invCheckAcDtls = InvCheckDoc.containsKey("invCheckAcDtls")
                    ? InvCheckDoc.getJSONArray("invCheckAcDtls")
                    : null;
            if (null == invCheckAc || null == invCheckAcDtls) {
                throw new Exception(
                        "Error, invCheckAc or invCheckAcDtls missed from the parameters, please double check");
            }
            OverseaInvCheckAction inventoryCheckAction = invCheckAc.toJavaObject(OverseaInvCheckAction.class);
            if (StringUtils.isNotEmpty(inventoryCheckAction.getUuid())) {
                ResponseResult checkStatusValidateResp = checkStatusValidate(invCheckAc);
                if (200 != checkStatusValidateResp.getCode()) {
                    return checkStatusValidateResp;
                }
                // 更新
                QueryWrapper<OverseaInvCheckAction> queryWrapper = new QueryWrapper<OverseaInvCheckAction>().eq("UUID",
                        inventoryCheckAction.getUuid());
                ResponseResult res = iOverseaInvCheckActionDtlService.updateInvCheckDtl(inventoryCheckAction.getUuid(),
                        invCheckAcDtls);
                if (res.getCode() == 200) {
                    this.baseMapper.update(inventoryCheckAction, queryWrapper);
                    iOverseaOperateLogService.addOverseaOperateLog(userId, inventoryCheckAction.getUuid(),
                            "701".equals(inventoryCheckAction.getInventoryActionType()) ? INV_CHECK_ACTION_PY_UPDATE
                                    : INV_CHECK_ACTION_PK_UPDATE,
                            "701".equals(inventoryCheckAction.getInventoryActionType()) ? "InvCheck Profit Update"
                                    : "InvCheck Loss Update",
                            "1",
                            "701".equals(inventoryCheckAction.getInventoryActionType()) ? "Обновление результатов"
                                    : "Обновление результатов проверки");
                    return res.add("invCheckAc", this.baseMapper.selectOne(queryWrapper));
                }
                throw new Exception(res.getMsg());
            } else {
                // 新建
                String uuid = UUID.randomUUID().toString().replaceAll("-", "").toLowerCase();
                inventoryCheckAction.setUuid(uuid);
                ResponseResult res = iOverseaInvCheckActionDtlService.updateInvCheckDtl(uuid, invCheckAcDtls);
                if (res.getCode() == 200) {
                    this.baseMapper.insert(inventoryCheckAction);
                    iOverseaOperateLogService.addOverseaOperateLog(userId, uuid,
                            "701".equals(inventoryCheckAction.getInventoryActionType()) ? INV_CHECK_ACTION_PY_UPDATE
                                    : INV_CHECK_ACTION_PK_UPDATE,
                            "701".equals(inventoryCheckAction.getInventoryActionType()) ? "InvCheck Profit Initial"
                                    : "InvCheck Loss Initial",
                            "1",
                            "701".equals(inventoryCheckAction.getInventoryActionType()) ? "Обновление результатов"
                                    : "Обновление результатов проверки");
                    QueryWrapper<OverseaInvCheckAction> queryWrapper = new QueryWrapper<OverseaInvCheckAction>()
                            .eq("UUID", uuid);
                    return res.add("invCheckAc", this.baseMapper.selectOne(queryWrapper));
                }
                throw new Exception(res.getMsg());
            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//            return ResponseResult.error().add("error", e.getMessage());
//        }
    }

    /** 更新之前检验当前数据状态是否和 currentStatus 一致，不一致要防止重复提交导致的更新操作 */
    ResponseResult checkStatusValidate(JSONObject invCheckAc) {
        try {
            String uuid = invCheckAc.getString("uuid");
            String currentStatus = invCheckAc.getString("currentStatus");
            if (StringUtils.isEmpty(uuid) || StringUtils.isEmpty(currentStatus)) {
                return ResponseResult.error().add("error", "更新单据uuid 或 currentStatus不能为空");
            }
            OverseaInvCheckAction checkAction = this.baseMapper
                    .selectOne(new QueryWrapper<OverseaInvCheckAction>().eq("UUID", uuid));
            if (checkAction == null || !currentStatus.equals(checkAction.getSpmsStatus())) {
                return ResponseResult.error().add("error", "单据状态已更新请刷新后重试");
            }
            return ResponseResult.success();
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.error().add("error", e.getMessage());
        }
    }

    /**
     * 根据任务uuid，获取盘盈盘亏结果提交SAP；状态为 5OA审批通过，6提交SAP失败 才能被提交，其余状态返回错误信息。 1.先检查数据是否都可操作；
     * 2.计算仓库库存，计算储位库存，记录仓库库存、储位库存操作日志； 3.提交SAP成功，更新单据状态为
     * 4提交SAP成功，记录返回信息，记录日志；提交SAP失败，更新状态为6提交SAP失败，记录日志； 4.重新提交SAP时，不执行库存计算过程。
     * 任务状态：1-草稿;2-提交OA成功；3-提交OA失败；4-OA审批不通过；5-OA审批通过待上传SAP; 6-上传SAP失败 7 -上传SAP成功 8
     * - 已撤销
     */
    @SuppressWarnings("unchecked")
	@Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult getInventoryCheckActionToSap(String uuid, String postingDate, String userId,
            String remarks, String currentStatus) throws Exception  {
        if (StringUtils.isEmpty(postingDate) || StringUtils.isEmpty(uuid)) {
            return ResponseResult.error().add("error", "请求参数错误请重试");
        }
        if (StringUtils.isEmpty(remarks)) {
            remarks = "";
        }
        OverseaInvCheckAction inventoryCheckAction = this.baseMapper
                .selectOne(new QueryWrapper<OverseaInvCheckAction>().eq("UUID", uuid));
        if (inventoryCheckAction == null) {
            return ResponseResult.error().add("error", "此盘盈盘亏单据不存在");
        }
        if (!currentStatus.equals(inventoryCheckAction.getSpmsStatus())) {
            return ResponseResult.error().add("error", "单据状态已更新请刷新后重试");
        }
        if (!"5".equals(inventoryCheckAction.getSpmsStatus()) && !"6".equals(inventoryCheckAction.getSpmsStatus())) {
            return ResponseResult.error().add("error", "此状态禁止提交SAP");
        }
        Map<String, Object> Head = formatHeadData(inventoryCheckAction, postingDate);
        List<Map<String, Object>> Items = new ArrayList<>();

        Items = formatItemsDataM(uuid);

        if (Head == null || Items.size() == 0) {
            return ResponseResult.error();
        }
        /**
         * 合规数据提交SAP，先更新SPMS仓库库存、储位库存，更新成功后再提交SAP；更新失败返回错误信息。
         * 4-提交SAP成功，获取提交返回结果；6-提交SAP失败；
         */
//        try {
            /** 首次提交SAP时计算库存；提交SAP失败单据重新提交SAP忽略库存计算。 */
            if ("5".equals(inventoryCheckAction.getSpmsStatus())) {
                ResponseResult updateInventoryResult = updateInventory(inventoryCheckAction, uuid, userId);
                if (updateInventoryResult.getCode() != 200) {
                    throw new Exception("库存更新过程出错："+updateInventoryResult.getMsg());
                    // return updateInventoryResult;
                }
            }
            JSONObject dataToSap = formatDataToSap(Head, Items);
            JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon((dataToSap)));

            if (message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").containsKey("O_TYPE")
                    && "S".equals(message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getString("O_TYPE"))) {

                String O_MBLNR = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getString("O_MBLNR")
                        .trim();
                String O_MJAHR = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getString("O_MJAHR")
                        .trim();
                this.baseMapper.updateInventoryCheckActionStatus(uuid, "7", O_MBLNR, O_MJAHR, postingDate, remarks);
                iOverseaOperateLogService.addOverseaOperateLog(userId, uuid,
                        "701".equals(inventoryCheckAction.getInventoryActionType()) ? INV_CHECK_ACTION_PY_SAP
                                : INV_CHECK_ACTION_PK_SAP,
                        "701".equals(inventoryCheckAction.getInventoryActionType()) ? "InvChk Profit SAP success"
                                : "InvChk Loss SAP Success",
                        "2", dataToSap.toJSONString(), message.toJSONString(), "盘点任务提交SAP", 
                        "701".equals(inventoryCheckAction.getInventoryActionType()) ? "Успешно представлен SAP"
                                : "Успешное завершение SAP");
                
                try {
	                JSONArray costJson = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA").getJSONArray("IT_COST");
	                if (costJson != null && costJson.size() > 0) {
                		List<OverseaInvCheckActionDtl> itemList = new ArrayList<OverseaInvCheckActionDtl>();
                		for (int i = 0; i < costJson.size(); i++) {
                			Map<String, Object> map = (Map<String, Object>) costJson.get(i);
                			if (map.get("ZEILE1") != null && map.get("DMBTR") != null) {
                				OverseaInvCheckActionDtl dtl = new OverseaInvCheckActionDtl();
                				String zeile = (String) map.get("ZEILE1");
                				String zeileRepla = zeile.replaceAll("^(0+)", "");
                				dtl.setUuid(uuid);
                				dtl.setTaskRowId(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<OverseaInvCheckActionDtl>> partition = Lists.partition(itemList, 1000);
                				for (List<OverseaInvCheckActionDtl> pa : partition) {
                					this.baseMapper.updateBatchDtl(pa);
                				}
                			} else {
                				this.baseMapper.updateBatchDtl(itemList);
                			}
                		}
                	}
                } catch (Exception e) {
                }
                return ResponseResult.success().add("sapReturnedMessage", message)
                        .add("invCheckAc",
                                this.baseMapper.selectOne(new QueryWrapper<OverseaInvCheckAction>().eq("UUID", uuid)))
                        .add("invCheckAcDtls", iOverseaInvCheckActionDtlService.getICADList(uuid))
                        .add("dataToSap", dataToSap);
            }
            this.baseMapper.updateInventoryCheckActionStatus(uuid, "6", "", "", postingDate, remarks);
            iOverseaOperateLogService.addOverseaOperateLog(userId, uuid,
                    "701".equals(inventoryCheckAction.getInventoryActionType()) ? INV_CHECK_ACTION_PY_SAP_ERROR
                            : INV_CHECK_ACTION_PK_SAP_ERROR,
                    "701".equals(inventoryCheckAction.getInventoryActionType()) ? "InvChk Profit SAP Failure"
                            : "InvChk Loss SAP Falure",
                    "2", dataToSap.toJSONString(), message.toJSONString(), "盘点任务提交SAP",
                    "701".equals(inventoryCheckAction.getInventoryActionType()) ? "Ошибка подачи SAP"
                            : "Ошибка подачи SAP");
            return ResponseResult.error().add("sapReturnedMessage", message).add("dataToSap", dataToSap);

//        } catch (Exception e) {
//            e.printStackTrace();
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//            return ResponseResult.error("请求ESB出错");
//        }
    }

    /**
     * 701 盘盈，计算备件货仓库库存、储位库存；计算贸易货储位库存； 702 盘亏，计算备件货仓库库存、储位库存；计算贸易货储位库存；
     * 
     * @param inventoryCheckAction
     * @param uuid
     * @return
     */
    ResponseResult updateInventory(OverseaInvCheckAction inventoryCheckAction, String uuid, String userId) {
        try {
            String moveType = inventoryCheckAction.getInventoryActionType();
            String operateType = moveType.equals("701") ? ADD : SUB;
            List<Map<String, Object>> inventoryDtl = this.baseMapper.getInventoryCheckActionAndDtl(uuid);
            ResponseResult checkResult = checkDataValidate(inventoryCheckAction, inventoryDtl);
            if (checkResult.getCode() != 200) {
                return checkResult;
            }
            for (int i = 0; i < inventoryDtl.size(); i++) {
                String materialNo = inventoryDtl.get(i).get("materialNo") == null ? null
                        : inventoryDtl.get(i).get("materialNo").toString();
                double discrepancy = Math.abs(Double.parseDouble(inventoryDtl.get(i).get("discrepancy").toString()));
                String taskRowId = inventoryDtl.get(i).get("taskRowId").toString();
                String storageUuid = inventoryDtl.get(i).get("storageUuid").toString();
                ResponseResult result = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo,
                        discrepancy, operateType);
                if (result.getCode() != 200) {
                    return result;
                }
                /** 海外仓盘盈盘亏储位库存操作添加库存操作日志 —— Wayne 20220422 */
                String comments = operateType.equals(ADD) ? "盘盈入储位" : "盘亏出储位";
                String logType = operateType.equals(ADD) ? "7" : "8";
                iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, discrepancy, logType, inventoryCheckAction.getUuid(),
                        comments, userId, "海外仓盘盈盘亏", inventoryCheckAction.getWerks(), inventoryCheckAction.getWhsLocationCode(), moveType, taskRowId);
            }
            return ResponseResult.success();
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.error();
        }
    }

    ResponseResult checkDataValidate(OverseaInvCheckAction inventoryCheckAction,
            List<Map<String, Object>> inventoryDtl) {
        try {
            /** 701-盘盈加库存，可忽略判断；702-盘亏需要扣减库存，需检查对应库存是否够扣减。 */
            if ("702".equals(inventoryCheckAction.getInventoryActionType())) {
                if (inventoryDtl == null || inventoryDtl.size() == 0) {
                    return ResponseResult.error("请求盘盈盘亏结果查询不存在");
                }
                for (int i = 0; i < inventoryDtl.size(); i++) {
                    String storageUuid = inventoryDtl.get(i).get("storageUuid").toString();
                    if (storageUuid == null) {
                        return ResponseResult.error("盘点结果信息对应储位信息不能为空");
                    }
                    double discrepancy = Double.parseDouble(inventoryDtl.get(i).get("discrepancy").toString());
                    String materialNo = inventoryDtl.get(i).get("materialNo").toString();
                    WhsStorageInventory materialOnStorage = iWhsStorageInventoryService
                            .getWhsStorageInventory(storageUuid, materialNo);
                    if (materialOnStorage == null || discrepancy > materialOnStorage.getAvailableQty()) {
                        return ResponseResult.error(materialNo + " 盘亏数量大于对应储位库存数量，请检查数据后重试");
                    }
                }
            }
            return ResponseResult.success();
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.error("库存校验出错");
        }
    }

    JSONObject formatDataToSap(Map<String, Object> Head, List<Map<String, Object>> Items) throws Exception {
        JSONObject object = new JSONObject();
        JSONObject ESB_ATTRS = new JSONObject();
        JSONObject REQUEST_DATA = new JSONObject();
        JSONObject REQUEST = new JSONObject();

        ESB_ATTRS.put("App_ID", "SPMS");
        ESB_ATTRS.put("Application_ID", "00020000000002");
        ESB_ATTRS.put("Transaction_ID", UUID.randomUUID().toString());
        // 根据工厂查询对应的SAP Clinet
        List<ZSapOrgClient> selectList = zSapOrgClientMapper.selectList(new QueryWrapper<ZSapOrgClient>().eq("WERKS", Head.get("WERKS").toString()));
        if (CollectionUtils.isNotEmpty(selectList)) {
        	ESB_ATTRS.put("Target_ID", "SAP-"+selectList.get(0).getZmandt());
        } else {
        	throw new Exception("工厂："+Head.get("werks").toString()+"未找到对应的SAP Clinet");
        }
        SimpleDateFormat simp = new SimpleDateFormat("yyyy:MM:ddHH:mm:ss:SS");//月日时分秒 毫秒
        String serialNumber=simp.format(new Date()).replace(":","" );
        Map<String, Object> fileds = new HashMap<>();
    	fileds.put("SPMSID", "SPMS"+serialNumber);
    	REQUEST_DATA.put("fileds", fileds);
    	Map<String, Object> structures = new HashMap<>();
        structures.put("I_HEADER", Head);
        REQUEST_DATA.put("structures", structures);
        Map<String, Object> tables = new HashMap<>();
        tables.put("IT_ITME", Items);
        REQUEST_DATA.put("tables", tables);
        REQUEST_DATA.put("Operation", "Z_SPMS_SKU_CHECK");
        REQUEST_DATA.put("Type", "SKU_CHECK");
        REQUEST.put("REQUEST_DATA", REQUEST_DATA);
        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
        object.put("REQUEST", REQUEST);
        return object;
    }

    Map<String, Object> formatHeadData(OverseaInvCheckAction inventoryCheckAction, String postingDate) {
        Map<String, Object> map = new HashMap<>();
        map.put("BLDAT", inventoryCheckAction.getCreateDate().replaceAll("-", ""));
        map.put("BUDAT", postingDate.replaceAll("-", ""));
        map.put("BWART", inventoryCheckAction.getInventoryActionType());
        //701盘盈 702盘亏
        //Z52盘盈 Z51盘亏
        // 生产工厂盘亏、盘盈传值调整，盘亏702，盘盈701 2023-06-13 xzp update 
//        if("2".equals(inventoryCheckAction.getNatureOfTheFactory())){//如果工厂性质为生产工厂,修改盘盈盘亏类型
//            if("702".equals( inventoryCheckAction.getInventoryActionType())){
//                map.put("bwart","Z51");
//            }else if("701".equals( inventoryCheckAction.getInventoryActionType())){
//                map.put("bwart","Z52");
//            }
//        }
        map.put("WERKS", inventoryCheckAction.getWerks());
        map.put("LGORT", inventoryCheckAction.getWhsLocationCode());
        map.put("BKTXT", inventoryCheckAction.getVoucherText() == null ? "" : inventoryCheckAction.getVoucherText());
        return map;
    }

    List<Map<String, Object>> formatItemsDataM(String uuid) {
        try {
            List<Map<String, Object>> checkActionDtlList = iOverseaInvCheckActionDtlService.getInventoryActionDtl(uuid);
            if (checkActionDtlList.size() == 0) {
                return null;
            }
            List<Map<String, Object>> mapList = new ArrayList<>();
            for (Map<String, Object> obj : checkActionDtlList) {
                Map<String, Object> map = new HashMap<>();
                map.put("ZEILE", obj.get("taskRowId").toString());
                map.put("MATNR", obj.get("materialNo").toString());
                map.put("MENGE", obj.get("discrepancy").toString());
                map.put("MEINS", obj.get("basicUnit").toString());
                map.put("LIFNR", obj.get("relateAccount") == null ? "" : obj.get("relateAccount").toString());
                map.put("KOSTL", obj.get("costCenter") == null ? "" : obj.get("costCenter").toString());
                map.put("SGTXT", obj.get("voucherItemText") == null ? "" : obj.get("voucherItemText").toString());
                map.put("WERKS", obj.get("werks").toString());
                map.put("LGORT", obj.get("whsLocationCode").toString());
                mapList.add(map);
            }
            return mapList;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public List<Map<String, Object>> getICALogs(String uuid) {
        return iOverseaOperateLogService.getByDocumentNumber(uuid);
    }

     /** 检查并关闭盘点单 */
    public ResponseResult checkAndCloseInvChk(String inventoryCheckId) {
        OverseaInvCheck inventoryCheck=overseaInvCheckMapper.selectOne(new QueryWrapper<OverseaInvCheck>().eq("INVENTORY_CHECK_ID",inventoryCheckId));
        if(null==inventoryCheck){
            return ResponseResult.error("The give invcheck id is not exist: " + inventoryCheckId);
        }
        List<OverseaInvCheckAction> inventoryCheckActions=getInvChkAcByInvChkId(inventoryCheckId);
        boolean isCoseable=true;
        if(null!=inventoryCheckActions && inventoryCheckActions.size()>0){
            for(int i=0;i<inventoryCheckActions.size();i++){
                if(!inventoryCheckActions.get(i).getSpmsStatus().equals("7")){
                    isCoseable=false;
                }
            }
        }

        if(isCoseable){
            inventoryCheck.setSpmsStatus("5");
            overseaInvCheckMapper.update(inventoryCheck,new QueryWrapper<OverseaInvCheck>().eq("INVENTORY_CHECK_ID",inventoryCheckId));
        }

        return ResponseResult.success().add("inventoryCheck",inventoryCheck);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult updateOverseaInvChkAcByOa(String userId, String oaBianhao, String oaStatus)  throws Exception {
        if (StringUtils.isEmpty(oaBianhao) || StringUtils.isEmpty(oaStatus)) {
            return ResponseResult.error("OA Bianmao is empty");
        }

        //try {
            OverseaInvCheckAction overseaInvChkAc = this.baseMapper
                    .selectOne(new QueryWrapper<OverseaInvCheckAction>().eq("OA_BIANHAO", oaBianhao));
            if (overseaInvChkAc == null) {
                return ResponseResult.error("failed to select Oversea Inv Chk Ac by OA Bianhao:" + oaBianhao);
            }
            if (!"2".equals(overseaInvChkAc.getSpmsStatus())) {
                return ResponseResult.error("状态禁止OA回写: spmsStatus:" + overseaInvChkAc.getSpmsStatus());
            }
            if ("S".equals(oaStatus)) {
                // OA 审批通过,更新状态
                OverseaInvCheckAction ovAc = new OverseaInvCheckAction();
                ovAc.setSpmsStatus("5");
                ovAc.setUuid(overseaInvChkAc.getUuid());
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                String oaApprovalDate = sdf.format(new Date());
                ovAc.setOaApprovalDate(oaApprovalDate);
                this.baseMapper.update(ovAc,
                        new UpdateWrapper<OverseaInvCheckAction>().eq("UUID", overseaInvChkAc.getUuid()));
                iOverseaOperateLogService.addOverseaOperateLog(userId, overseaInvChkAc.getUuid(), "OA审批通过",
                        "OA Approved", "1", "", "", "盘点任务OA审批", "Одобрение ОА прошло");
                // 提交SAP
                //try {
                    ResponseResult submitSapResult = getInventoryCheckActionToSap(overseaInvChkAc.getUuid(),
                            overseaInvChkAc.getPostingDate(), userId, overseaInvChkAc.getRemarks(), "5");
                    if (SUCCESS.equals(submitSapResult.getCode())) {
                        /** 检查并关闭盘点单 */
                        ResponseResult invChkRes = checkAndCloseInvChk(overseaInvChkAc.getInventoryCheckId());
                        if (invChkRes.getCode() == 200) {
                            return ResponseResult.success("SPMS更新成功，结果提交SAP成功");
                        }else{
                            return ResponseResult.success("揭交SAP成功,更新上游盘点单据失败:"+invChkRes.getMsg());
                        }
                    } else {
                        return ResponseResult.success("SPMS更新成功，结果提交SAP失败");
                    }
//                } catch (Exception e) {
//                    e.printStackTrace();
//                    return ResponseResult.success("SPMS更新成功，结果提交SAP失败");
//                }
            } else {
                // OA 审批退回,更新状态
                OverseaInvCheckAction ovAc = new OverseaInvCheckAction();
                ovAc.setSpmsStatus("4");
                ovAc.setUuid(overseaInvChkAc.getUuid());
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                String oaApprovalDate = sdf.format(new Date());
                ovAc.setOaApprovalDate(oaApprovalDate);
                this.baseMapper.update(ovAc,
                        new UpdateWrapper<OverseaInvCheckAction>().eq("UUID", overseaInvChkAc.getUuid()));
                iOverseaOperateLogService.addOverseaOperateLog(userId, overseaInvChkAc.getUuid(), "OA审批退回",
                        "OA Rejected", "1", "", "", "盘点任务OA审批", "OA Вернуть назад");
                return ResponseResult.success();
            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            return ResponseResult.error(e.getMessage());
//        }
    }

    /**
     * 盘盈盘亏提交OA 1.拼接提交OA信息，
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ResponseResult overseaInvChkAcToOa(JSONObject invCheckAc, SpmsUser spmsUser,
            JSONArray invCheckAcDtls,boolean newOa)throws Exception  {
//        try {
            String uuid = invCheckAc.getString("uuid");
            QueryWrapper<OverseaInvCheckAction> queryWrapper = new QueryWrapper<OverseaInvCheckAction>().eq("UUID",
                    uuid);
            OverseaInvCheckAction overseaInvChkAc = this.baseMapper.selectOne(queryWrapper);
            if (overseaInvChkAc == null) {
                return ResponseResult.error("请求盘盈亏单不存在");
            }
            // 将前端传入的参数合并入overseaInvChkAc
            overseaInvChkAc.setSubmitOaDate(invCheckAc.getString("submitOaDate"));
            overseaInvChkAc.setRemarks(invCheckAc.getString("remarks"));
            overseaInvChkAc.setPostingDate(invCheckAc.getString("postingDate"));
            // 检查是否可以提交OA
            ResponseResult checkDataToOa = checkDataToOa(overseaInvChkAc);
            if (checkDataToOa.getCode() != CommonConstant.SUCCESS) {
                return checkDataToOa;
            }

            // 更新行明细上的remarks
            ResponseResult dtlUpdateRes = iOverseaInvCheckActionDtlService.updateInvCheckDtl(uuid, invCheckAcDtls);
            if (dtlUpdateRes.getCode() != 200) {
                return dtlUpdateRes;
            }

            // SPMS生成OA单据号参考：3168-2021-11-001，提交成功需存入 OA_FIELD 字段中；
            // String oaOrderNo = generateOaOrderNo(overseaInvChkAc.getSubmitOaDate());
            // 提交OA
            int dnDataToOaResult = dnDataToOa(overseaInvChkAc, spmsUser,newOa);
            String oaClient = "OA";
            List<ZOaOrgClient> selectList = zOaOrgClientMapper.selectList(new QueryWrapper<ZOaOrgClient>().eq("WERK", overseaInvChkAc.getWerks()));
            if (CollectionUtils.isNotEmpty(selectList)) {
                String oaUl =  selectList.get(0).getOa();
                if(oaUl.contains("fm-oa") || oaUl.contains("oa-ipo")){
                    oaClient = "FM-OA";
                }
            } else {
                throw new RuntimeException("工厂："+overseaInvChkAc.getWerks()+"未找到对应的OA服务");
            }

            if (dnDataToOaResult > 0) {
                // TODO 提交成功，更新交货单状态，OA单据号，编号字段更新，记录提交日志；
                invCheckAc.put("spmsStatus", "2");
                invCheckAc.put("oaWorkflow", "3168");
                invCheckAc.put("oaBianhao", String.valueOf(dnDataToOaResult));
                OverseaInvCheckAction ovInvCheckAction = invCheckAc.toJavaObject(OverseaInvCheckAction.class);
                ovInvCheckAction.setOaClient(oaClient);
                this.baseMapper.update(ovInvCheckAction, queryWrapper);
                return ResponseResult.success()
                        .add("invCheckAc",
                                this.baseMapper.selectOne(queryWrapper))
                        .add("invCheckAcDtls", iOverseaInvCheckActionDtlService.getICADList(uuid));
            } else if (dnDataToOaResult == -2) {
                // 提交失败
                invCheckAc.put("spmsStatus", "3");
                invCheckAc.put("oaWorkflow", "3168");
                OverseaInvCheckAction ovInvCheckAction = invCheckAc.toJavaObject(OverseaInvCheckAction.class);
                this.baseMapper.update(ovInvCheckAction, queryWrapper);
                return ResponseResult.error("-2 用户没有流程创建权限，盘盈盘亏提交OA审批失败")
                        .add("invCheckAc",
                                this.baseMapper.selectOne(queryWrapper))
                        .add("invCheckAcDtls", iOverseaInvCheckActionDtlService.getICADList(uuid));
            } else {
                invCheckAc.put("spmsStatus", "3");
                invCheckAc.put("oaWorkflow", "3168");
                OverseaInvCheckAction ovInvCheckAction = invCheckAc.toJavaObject(OverseaInvCheckAction.class);
                this.baseMapper.update(ovInvCheckAction, queryWrapper);

                return ResponseResult.error("盘盈盘亏提交OA审批失败")
                        .add("invCheckAc",
                                this.baseMapper.selectOne(queryWrapper))
                        .add("invCheckAcDtls", iOverseaInvCheckActionDtlService.getICADList(uuid));
            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//            return ResponseResult.error("提交SAP失败 Exception").add("error", e.getMessage());
//        }
    }

    String generateOaOrderNo(String submitOaDate) {
        String currentNo = this.baseMapper.getOaOrderNo(submitOaDate);
        String tempStr = "00" + (Integer.parseInt(currentNo) + 1);
        String nextNo = tempStr.substring(tempStr.length() - 3);
        return "3168-" + submitOaDate.substring(0, 7) + nextNo;
    }

    ResponseResult checkDataToOa(OverseaInvCheckAction overseaInvChkAc) {
        String submitOaDate = overseaInvChkAc.getSubmitOaDate();
        if (StringUtils.isEmpty(submitOaDate)) {
            return ResponseResult.error("请求提交OA日期不能为空");
        }
        String postingDate = overseaInvChkAc.getPostingDate();
        if (StringUtils.isEmpty(postingDate)) {
            return ResponseResult.error("SAP过账日期不能为空");
        }
        if (INVALID_DATE.equals(submitOaDate)) {
            return ResponseResult.error("提交OA日期格式错误请重试");
        }
        if (INVALID_DATE.equals(postingDate)) {
            return ResponseResult.error("SAP过账日期格式错误请重试");
        }
        String spmsStatus = overseaInvChkAc.getSpmsStatus();
        if (!"1".equals(spmsStatus) && !"3".equals(spmsStatus) && !"4".equals(spmsStatus)) {
            return ResponseResult.error("当前状态不可提交OA");
        }

        List<OverseaInvCheckActionDtl> dtlList = iOverseaInvCheckActionDtlService
                .getICADList(overseaInvChkAc.getUuid());
        if (dtlList.size() <= 0) {
            return ResponseResult.error("盘盈亏任务没有行项");
        }
        return ResponseResult.success();
    }

    /**
     * 新流程的requestid 如果小于等于0表示失败 -1：创建流程失败 -2：用户没有流程创建权限 -3：创建流程基本信息失败 -4：保存表单主表信息失败
     * -5：更新紧急程度失败 -6：流程操作者失败 -7：流转至下一节点失败 -8：节点附加操作失败
     * 
     * @param overseaInvChkAc
     * @param spmsUser
     * @return
     */
    int dnDataToOa(OverseaInvCheckAction overseaInvChkAc, SpmsUser spmsUser,boolean newOa) {

        List<Map<String, Object>> dtlList = iOverseaInvCheckActionDtlService
                .getOverseaInvChkDtls(overseaInvChkAc.getUuid());
        ExtHrmresourcesPortTypeProxy proxy = new ExtHrmresourcesPortTypeProxy();
        RequestServicePortTypeProxy wfproxy = new RequestServicePortTypeProxy();
        try {
            RequestInfo reqinfo = new RequestInfo();
            reqinfo.setCreatorid(spmsUser.getWorkId()); // OAID 提交人
            reqinfo.setWorkflowid(workflow3168);// workflowid 为测试系统ID
            reqinfo.setRequestlevel("0");// 紧急程度 默认
            reqinfo.setRemindtype("0"); // 默认
            reqinfo.setIsNextFlow("1"); // 默认
            reqinfo.setDescription("海外备件仓盘盈盘亏结果审批 SPMS单号:" + overseaInvChkAc.getSpmsId()); // 自定义

            Map<String, Object> mapHead = new HashMap<>();
            mapHead.put("bianhao", "");
            mapHead.put("workcode", spmsUser.getUserId());
            mapHead.put("workflowdate", overseaInvChkAc.getSubmitOaDate());
            mapHead.put("requestuserid", spmsUser.getWorkId());
            mapHead.put("dep", spmsUser.getDeptId() == null ? "" : spmsUser.getDeptId());
            mapHead.put("jobtitle", spmsUser.getPositionId() == null ? "" : spmsUser.getPositionId());
            mapHead.put("sub", spmsUser.getCompany() == null ? "" : spmsUser.getCompany());
            // 根据工厂查询对应的OA Clinet
            String oaUl = oaUrl;
            QueryWrapper<OverseaInvCheckAction> queryWrapper = new QueryWrapper<OverseaInvCheckAction>().eq("UUID",
                    overseaInvChkAc.getUuid());
            OverseaInvCheckAction inventoryCheckAction = this.baseMapper.selectOne(queryWrapper);
            if (null == inventoryCheckAction) {
                throw new Exception("Could not find Inventory Check Action for uuid: " + overseaInvChkAc.getUuid());
            }
            String tableDBName="formtable_main_416_dt1";
            List<ZOaOrgClient> selectList = zOaOrgClientMapper.selectList(new QueryWrapper<ZOaOrgClient>().eq("WERK", inventoryCheckAction.getWerks()));
            if (CollectionUtils.isNotEmpty(selectList)) {
                oaUl =  selectList.get(0).getOa();
                if(oaUl.contains("fm-oa") || oaUl.contains("oa-ipo")){
                    mapHead.put("fd", spmsUser.getBranchPoint() == null ? "" : spmsUser.getBranchPoint());
                }else{
                    mapHead.put("fendian", spmsUser.getBranchPoint() == null ? "" : spmsUser.getBranchPoint());
                }
            } else {
                throw new RuntimeException("工厂："+inventoryCheckAction.getWerks()+"未找到对应的OA服务");
            }


            mapHead.put("joblevel", "");
            mapHead.put("area", "");
            mapHead.put("tzremark", "调账说明");
            mapHead.put("additional", "1");
            mapHead.put("Executivepersonnel", spmsUser.getWorkId());
            mapHead.put("posdh", overseaInvChkAc.getSpmsId());
            mapHead.put("spmsordernum", overseaInvChkAc.getSpmsId());
            mapHead.put("businessType", BUSINESS_TYPE_INV_CHECK);

            MainTableInfo wmi = new MainTableInfo();
            Property[] wrti = new Property[mapHead.size()];
            int i = 0;
            for (Map.Entry<String, Object> entry : mapHead.entrySet()) {
                wrti[i] = new Property();
                wrti[i].setName(entry.getKey());
                wrti[i].setValue(entry.getValue().toString());
                i++;
            }
            wmi.setProperty(wrti);

            List<Map<String, Object>> mapList = new ArrayList<>();
            for (int j = 0; j < dtlList.size(); j++) {
                Map<String, Object> itemDTO = dtlList.get(j);
                double discrepancy = Double.parseDouble(itemDTO.get("discrepancy").toString());
                Map<String, Object> map = new HashMap<>();
                map.put("xh", String.valueOf(j));
                map.put("wlid", itemDTO.get("materialNo"));
                map.put("wltext", itemDTO.get("materialZhDesc"));
                map.put("wlunit", itemDTO.get("basicUnit"));

                /** 盘盈 则按出库类型 10 */
                if (discrepancy > 0) {
                    map.put("wlquantity", Math.abs(discrepancy));
                    map.put("stocktype", 10);
                }
                /** 盘亏 则按出库类型 12 */
                if (discrepancy < 0) {
                    map.put("wlquantity", Math.abs(discrepancy));
                    map.put("stocktype", 12);
                }
                map.put("area", "");
                map.put("colorno", "");
                map.put("causeofbroken", itemDTO.get("remarks"));

                mapList.add(map);
            }

            DetailTableInfo dtsInfo = new DetailTableInfo();
            // DetailTable[] dts = new DetailTable[mapList.size()];
            DetailTable[] dts = new DetailTable[1];
            dts[0] = new DetailTable();
            dts[0].setId("1");
            Row[] rows = new Row[mapList.size()];
            for (int k = 0; k < mapList.size(); k++) {
                Map<String, Object> item = mapList.get(k);

                rows[k] = new Row();
                rows[k].setId(String.valueOf(k));
                Cell[] cl = { new Cell(), new Cell(), new Cell(), new Cell(), new Cell(), new Cell(), new Cell(),
                        new Cell(), new Cell() };
                int x = 0;
                for (Map.Entry<String, Object> entry : item.entrySet()) {
                    cl[x].setName(entry.getKey());
                    cl[x].setValue(entry.getValue() == null ? "" : entry.getValue().toString());
                    x++;
                }
                rows[k].setCell(cl);
            }
            dts[0].setRow(rows);
            dtsInfo.setDetailTable(dts);

            reqinfo.setMainTableInfo(wmi);
            reqinfo.setDetailTableInfo(dtsInfo);

            System.out.println("==========海外盘盈盘亏提交OA reqinfo==========\n" + JSON.toJSONString(reqinfo));

            int reqid = 0;
            if(newOa){
                Map<String, Object> rl = new HashMap<String, Object>();
                rl.put("requestName", "海外备件仓盘盈盘亏结果审批 SPMS单号:" + overseaInvChkAc.getSpmsId());

                if (CollectionUtils.isNotEmpty(selectList)) {
                    oaUl =  selectList.get(0).getOa();
                    if(oaUl.contains("fm-oa") || oaUl.contains("oa-ipo")){
                        rl.put("workflowId", workflow3168_ipo);
                        //tableDBName="formtable_main_566_dt1";
                        tableDBName="formtable_main_659_dt1";
                    }else{
                        rl.put("workflowId", workflow3168_new);
                    }
                } else {
                    throw new RuntimeException("工厂："+inventoryCheckAction.getWerks()+"未找到对应的OA服务");
                }
                rl.put("requestlevel", "0");// 紧急程度 默认
                rl.put("remindtype", "0");
                rl.put("isNextFlow", "1");
                rl.put("description","海外备件仓盘盈盘亏结果审批 SPMS单号:" + overseaInvChkAc.getSpmsId());

                List<Map<String, Object>> aas = new ArrayList<Map<String, Object>>();
                for (Map.Entry<String, Object> entry : mapHead.entrySet()){
                    Map<String, Object> ol = new HashMap<String, Object>();
                    ol.put("fieldName", entry.getKey());
                    ol.put("fieldValue", entry.getValue().toString());
                    aas.add(ol);
                }
                rl.put("mainData", JSONUtil.parseArray(aas).toString());

                List<Map<String, Object>> aasDetailList = new ArrayList<>();
                Map<String, Object> aasDetail = new HashMap<>();
                List<Map<String, Object>> detailTableDb = new ArrayList<Map<String, Object>>();
                for (int k = 0; k < mapList.size(); k++) {
                    Map<String, Object> item = mapList.get(k);
                    Map<String, Object> workflowRequestTableRecord = new HashMap<>();
                    workflowRequestTableRecord.put("recordOrder", 0);
                    List<Map<String, Object>> detailTable = new ArrayList<Map<String, Object>>();
                    for (Map.Entry<String, Object> entry : item.entrySet()) {
                        Map<String, Object> ol = new HashMap<String, Object>();
                        ol.put("fieldName", entry.getKey());
                        ol.put("fieldValue", entry.getValue() == null ? "" : entry.getValue().toString());
                        detailTable.add(ol);
                    }
                    workflowRequestTableRecord.put("workflowRequestTableFields", detailTable);
                    detailTableDb.add(workflowRequestTableRecord);
                }
                //明细表
                aasDetail.put("workflowRequestTableRecords", detailTableDb);
                aasDetail.put("tableDBName", tableDBName);
                aasDetailList.add(aasDetail);
                rl.put("detailData", JSONUtil.parseArray(aasDetailList).toString());


                String jsonParams = JSONUtil.parseObj(rl).toString();
                OAMainUtils oaMainUtils = new OAMainUtils();

                String message =  oaMainUtils.oaRestFul(oaUl, "/api/workflow/paService/doCreateRequest", rl,spmsUser.getUserId());
                JSONObject messageDoc = JSONObject.parseObject(message);
                String reqidStr = "";
                if("SUCCESS".equals(messageDoc.getString("code"))){
                    String data = messageDoc.getString("data");
                    JSONObject dataJson = JSONObject.parseObject(data);
                    reqid = Integer.parseInt(dataJson.getString("requestid"));
                }else{
                    throw new Exception("保存异常：" + messageDoc.getString("errMsg"));
                }
            }else{
                // 生成待办 ，返回待办id
                reqid = Integer.parseInt(wfproxy.createRequest(reqinfo));
            }
            // 返回大于0 的数字则调用成功
            System.out.println("海外盘盈盘亏提交OA审批，返回 reqid:" + reqid);
            if (reqid > 0) {
                iOverseaOperateLogService.addOverseaOperateLog(spmsUser.getUserId(), overseaInvChkAc.getUuid(),
                        "海外盘盈盘亏提交OA成功", "Oversea InvChk submit OA Successed", oaLog, JSON.toJSONString(reqinfo),
                        String.valueOf(reqid), "", "Зарубежные убытки представлены успешно");
            } else {
                iOverseaOperateLogService.addOverseaOperateLog(spmsUser.getUserId(), overseaInvChkAc.getUuid(),
                        "海外盘盈盘亏提交OA失败", "Oversea InvChk submit OA Failure", oaLog, JSON.toJSONString(reqinfo),
                        String.valueOf(reqid), "", "Ошибка подачи оффшорной отчетности OA");
            }
            return reqid;
        } catch (RemoteException remoteException) {
            remoteException.printStackTrace();
            System.out.println("=========海外盘盈盘亏提交OA连接错误=========" + remoteException.getMessage());
            return 0;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("========海外盘盈盘亏提交OA信息请求参数：" + overseaInvChkAc.toString() + "\n请求提交OA异常=========\n"
                    + e.getMessage());
            return 0;
        }
    }

    /** 获取海外仓盘盈盘亏任务，带明细不分页报表 */
    @Override
    public ResponseResult getOverseaInvCheckAction(OverseaInvCheckActionSearchDTO overseaInvCheckActionSearchDTO) {
        return ResponseResult.success().add("overseaInvCheckActionList", this.baseMapper.getOverseaInvCheckAction(overseaInvCheckActionSearchDTO));
    }

	@Override
	public ResponseResult getOverseaInvCheckHead(String spmsId) {
		if (StringUtils.isEmpty(spmsId)) {
			ResponseResult.error("SPMS单号为空，请求失败");
		}
		// 根据单据号查询盘盈盘亏头信息
		Map<String, Object> headMap = this.baseMapper.selectInvCheckByNo(spmsId);
		// 查询行项目
		List<Map<String, Object>> items = this.baseMapper.selectInvCheckDltList(headMap != null ? headMap.get("uuid").toString() : "");
		return ResponseResult.success().add("headVO", headMap).add("itemList", items);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public synchronized ResponseResult cancel(String userId, JSONObject invCheckDoc) throws Exception {
		if (invCheckDoc == null || StringUtils.isEmpty(invCheckDoc.getString("uuid"))) {
            return ResponseResult.error().add("error", "请求参数错误请重试");
        }
		String uuid = invCheckDoc.getString("uuid");
        OverseaInvCheckAction inventoryCheckAction = this.baseMapper
                .selectOne(new QueryWrapper<OverseaInvCheckAction>().eq("UUID", uuid));
        if (inventoryCheckAction == null) {
            return ResponseResult.error().add("error", "此盘盈盘亏单据不存在");
        }
        if ("8".equals(inventoryCheckAction.getSpmsStatus()) || "1".equals(inventoryCheckAction.getSpmsStatus()) || "2".equals(inventoryCheckAction.getSpmsStatus())) {
            return ResponseResult.error().add("error", "此状态禁止撤销");
        }
        // 提交SAP成功、提交SAP失败撤销需扣减或增加库存数量
        if ("7".equals(inventoryCheckAction.getSpmsStatus()) || "6".equals(inventoryCheckAction.getSpmsStatus())) {
        	// 扣减库存
        	ResponseResult updateInventoryResult = updateInventoryDeduction(inventoryCheckAction, uuid, userId);
            if (updateInventoryResult.getCode() != 200) {
                throw new Exception("库存更新过程出错："+updateInventoryResult.getMsg());
            }
        }
        OverseaInvCheckAction head = new OverseaInvCheckAction();
        head.setUuid(uuid);
        if ("7".equals(inventoryCheckAction.getSpmsStatus())) {
        	// 提交SAP成功撤销需调接口Z_SPMS_CANCEL同步SAP
        	this.deSendSapData(inventoryCheckAction, head);
        	head.setSpmsStatus("5");
        } else {
        	head.setSpmsStatus("1");
        }
        this.updateById(head);
        iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, "盘亏盘盈撤销成功",
        		"OverseaInvCheck Revoke Success", "2", invCheckDoc.toJSONString(), invCheckDoc.toJSONString(), "盘亏盘盈撤销", "Отмена убытков успешно");
        return ResponseResult.success().add("invCheckAc",
                        this.baseMapper.selectOne(new QueryWrapper<OverseaInvCheckAction>().eq("UUID", uuid)))
                .add("invCheckAcDtls", iOverseaInvCheckActionDtlService.getICADList(uuid));
	}

	private void deSendSapData(OverseaInvCheckAction inventoryCheckAction, OverseaInvCheckAction updateHead) throws Exception {
		JSONObject doc = new JSONObject();

        JSONObject REQUEST = new JSONObject();
        JSONObject ESB_ATTRS = new JSONObject();
        JSONObject REQUEST_DATA = new JSONObject();
        JSONObject Head = new JSONObject();

        ESB_ATTRS.put("App_ID", "SPMS");
        ESB_ATTRS.put("Application_ID", "00020000000002");
        ESB_ATTRS.put("Transaction_ID", UUID.randomUUID().toString());
        // 根据工厂查询对应的SAP Clinet
        List<ZSapOrgClient> clinetList = zSapOrgClientMapper.selectList(new QueryWrapper<ZSapOrgClient>().eq("WERKS", inventoryCheckAction.getWerks()));
        if (!CollectionUtils.isEmpty(clinetList)) {
        	ESB_ATTRS.put("Target_ID", "SAP-"+clinetList.get(0).getZmandt());
        } else {
        	throw new Exception("工厂："+inventoryCheckAction.getWerks()+"未找到对应的SAP Clinet");
        }
        Head.put("I_MBLNR", inventoryCheckAction.getSapVoucherNumber());
        Head.put("I_MJAHR", inventoryCheckAction.getSapVoucherYear());
        Head.put("I_BUDAT", inventoryCheckAction.getPostingDate().replaceAll("-", ""));
        REQUEST_DATA.put("fileds", Head);
        REQUEST_DATA.put("Operation", "Z_SPMS_CANCEL");
        REQUEST_DATA.put("Type", "SPMS_CANCEL");
        REQUEST.put("ESB_ATTRS", ESB_ATTRS);
        REQUEST.put("REQUEST_DATA", REQUEST_DATA);
        doc.put("REQUEST", REQUEST);
        log.info("=======海外仓盘亏盘盈撤销同步SAP dataToSap=========\n" + doc);
        JSONObject message = JSONObject.parseObject(iFeignServiceCommon.sendRestToSapCommon(doc));
        log.info("=======海外仓盘亏盘盈撤销同步SAP响应结果 message=========\n" + message);
        JSONObject RETURN_DATA = message.getJSONObject("RESPONSE").getJSONObject("RETURN_DATA");
        String maessage = RETURN_DATA.getString("O_MSTXT");
        if (SAP_SUCCESS.equals(RETURN_DATA.getString("O_TYPE"))) {
        	String cancelUnderVoucherNumber = RETURN_DATA.getString("0_MBLNR");
        	updateHead.setCancelVoucherNumber(cancelUnderVoucherNumber);
        } else {
        	throw new Exception("盘亏盘盈撤销同步SAP失败："+maessage);
        }
	}

	private ResponseResult updateInventoryDeduction(OverseaInvCheckAction inventoryCheckAction, String uuid,
			String userId) {
		try {
            String moveType = inventoryCheckAction.getInventoryActionType();
            String operateType = moveType.equals("701") ? SUB : ADD;
            List<Map<String, Object>> inventoryDtl = this.baseMapper.getInventoryCheckActionAndDtl(uuid);
            ResponseResult checkResult = checkDataValidate(inventoryCheckAction, inventoryDtl);
            if (checkResult.getCode() != 200) {
                return checkResult;
            }
            for (int i = 0; i < inventoryDtl.size(); i++) {
                String materialNo = inventoryDtl.get(i).get("materialNo") == null ? null
                        : inventoryDtl.get(i).get("materialNo").toString();
                double discrepancy = Math.abs(Double.parseDouble(inventoryDtl.get(i).get("discrepancy").toString()));
                String taskRowId = inventoryDtl.get(i).get("taskRowId").toString();
                String storageUuid = inventoryDtl.get(i).get("storageUuid").toString();
                ResponseResult result = iWhsStorageInventoryService.updateWhsStorageInventory(storageUuid, materialNo,
                        discrepancy, operateType);
                if (result.getCode() != 200) {
                    return result;
                }
                /** 海外仓盘盈盘亏储位库存操作添加库存操作日志 —— Wayne 20220422 */
                String comments = operateType.equals(ADD) ? "盘亏撤销入储位" : "盘盈撤销出储位";
                String logType = operateType.equals(ADD) ? "7" : "8";
                iWhsOperateLogService.insertWhsOperateLog(storageUuid, materialNo, discrepancy, logType, inventoryCheckAction.getUuid(),
                        comments, userId, "海外仓盘盈盘亏", inventoryCheckAction.getWerks(), inventoryCheckAction.getWhsLocationCode(), moveType, taskRowId);
            }
            return ResponseResult.success();
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseResult.error();
        }
	}

	@Override
	public ResponseResult closeInvCheck(String userId, JSONObject invCheckDoc) throws Exception {
		if (invCheckDoc == null || StringUtils.isEmpty(invCheckDoc.getString("uuid"))) {
            return ResponseResult.error().add("error", "请求参数错误请重试");
        }
//		if (StringUtils.isEmpty(invCheckDoc.getString("cancelReason"))) {
//			return ResponseResult.error().add("error", "请填写关闭原因");
//		}
		String uuid = invCheckDoc.getString("uuid");
        OverseaInvCheckAction inventoryCheckAction = this.baseMapper
                .selectOne(new QueryWrapper<OverseaInvCheckAction>().eq("UUID", uuid));
        if (inventoryCheckAction == null) {
            return ResponseResult.error().add("error", "此盘盈盘亏单据不存在");
        }
        if (!"1".equals(inventoryCheckAction.getSpmsStatus())) {
            return ResponseResult.error().add("error", "此状态禁止关闭");
        }
//        if ("7".equals(inventoryCheckAction.getSpmsStatus()) || "6".equals(inventoryCheckAction.getSpmsStatus())) {
//        	// 扣减库存
//        	ResponseResult updateInventoryResult = updateInventoryDeduction(inventoryCheckAction, uuid, userId);
//            if (updateInventoryResult.getCode() != 200) {
//                throw new Exception("库存更新过程出错："+updateInventoryResult.getMsg());
//            }
//        }
        OverseaInvCheckAction head = new OverseaInvCheckAction();
        head.setUuid(uuid);
        head.setSpmsStatus("8");
        this.updateById(head);
        iOverseaOperateLogService.addOverseaOperateLog(userId, uuid, "盘亏盘盈关闭成功",
        		"OverseaInvCheck Closed Success", "2", invCheckDoc.toJSONString(), invCheckDoc.toJSONString(), "盘亏盘盈撤销", "Закрытие успешно");
        return ResponseResult.success().add("invCheckAc",
                        this.baseMapper.selectOne(new QueryWrapper<OverseaInvCheckAction>().eq("UUID", uuid)))
                .add("invCheckAcDtls", iOverseaInvCheckActionDtlService.getICADList(uuid));
	}
	
	public List<OverseaInvCheckActionPrintDTO> inCheckActionPrint(String dsName,String datasetName,Map<String,Object> parameters) {
		String uuid = (String) parameters.get("uuid");
		String language = (String) parameters.get("language");
		// 查询头信息
		Map<String, Object> headMap = this.baseMapper.queryInvCheckByUuid(uuid);
		List<Map<String, Object>> itemList = iOverseaInvCheckActionDtlService.getOverseaInvChkDtls(uuid);
		List<OverseaInvCheckActionPrintDTO> returnList = new ArrayList<OverseaInvCheckActionPrintDTO>();
		for (Map<String, Object> item : itemList) {
			OverseaInvCheckActionPrintDTO dto = new OverseaInvCheckActionPrintDTO();
			// 盘点单号
			dto.setSpmsId(headMap.get("spmsId").toString());
			// 日期
			dto.setCreateDate(headMap.get("createDate") != null ? headMap.get("createDate").toString() : "");
			// 盘点人
			dto.setCreateUserName(headMap.get("createUserName") != null ? headMap.get("createUserName").toString() : "");
			// 部门
			dto.setDepartName(headMap.get("departName") != null ? headMap.get("departName").toString() : "");
			// 仓库
			dto.setWarehouse(headMap.get("whsLocationCode") != null ? headMap.get("whsLocationCode").toString() : "");
			// 盘点结果
			if ("zh-CN".equals(language) && headMap.get("inventoryCheckResult") != null) {
				if ("1".equals(headMap.get("inventoryCheckResult").toString())) {
					dto.setInventoryCheckResult("账实相符");
				} else if ("2".equals(headMap.get("inventoryCheckResult").toString())) {
					dto.setInventoryCheckResult("盘盈");
				} else if ("3".equals(headMap.get("inventoryCheckResult").toString())) {
					dto.setInventoryCheckResult("盘亏");
				} else if ("4".equals(headMap.get("inventoryCheckResult").toString())) {
					dto.setInventoryCheckResult("盘盈盘亏");
				}
			} else if ("en-US".equals(language)  && headMap.get("inventoryCheckResult") != null) {
				if ("1".equals(headMap.get("inventoryCheckResult").toString())) {
					dto.setInventoryCheckResult("账实相符");
				} else if ("2".equals(headMap.get("inventoryCheckResult").toString())) {
					dto.setInventoryCheckResult("盘盈");
				} else if ("3".equals(headMap.get("inventoryCheckResult").toString())) {
					dto.setInventoryCheckResult("盘亏");
				} else if ("4".equals(headMap.get("inventoryCheckResult").toString())) {
					dto.setInventoryCheckResult("盘盈盘亏");
				}
			}
			// 盘点方式
			if ("zh-CN".equals(language) && headMap.get("inventoryCheckCategory") != null) {
				if ("1".equals(headMap.get("inventoryCheckCategory").toString())) {
					dto.setInventoryCheckCategory("动态盘点");
				} else if ("2".equals(headMap.get("inventoryCheckCategory").toString())) {
					dto.setInventoryCheckCategory("静态盘点");
				}
			} else if ("en-US".equals(language)  && headMap.get("inventoryCheckCategory") != null) {
				if ("1".equals(headMap.get("inventoryCheckCategory").toString())) {
					dto.setInventoryCheckCategory("Daily InvChk");
				} else if ("2".equals(headMap.get("inventoryCheckCategory").toString())) {
					dto.setInventoryCheckCategory("Monthly InvChk");
				}
			}
			// 盘点类型
			if ("zh-CN".equals(language) && headMap.get("inventoryCheckMold") != null) {
				if ("1".equals(headMap.get("inventoryCheckMold").toString())) {
					dto.setInventoryCheckCategory("明盘");
				} else if ("2".equals(headMap.get("inventoryCheckMold").toString())) {
					dto.setInventoryCheckCategory("盲盘");
				}
			} else if ("en-US".equals(language) && headMap.get("inventoryCheckMold") != null) {
				if ("1".equals(headMap.get("inventoryCheckMold").toString())) {
					dto.setInventoryCheckCategory("InentoryCheck");
				} else if ("2".equals(headMap.get("inventoryCheckMold").toString())) {
					dto.setInventoryCheckCategory("InvChk");
				}
			}
			// 状态
			dto.setSpmsStatus(headMap.get("spmsStatus") != null ? OverseaInvCheckActionPrintEnum.getDescByValue(headMap.get("spmsStatus").toString(), language) : "");
			// 备注
			dto.setHeadRemarks(headMap.get("remarks") != null ? headMap.get("remarks").toString() : "");
			// TODO 盘点差额 (待补充)
			dto.setInventoryTotalAmount("");
			// TODO 币种 (待补充)
			dto.setCurrency("");
			// TODO 盘点周期 (待补充)
			dto.setInventoryCheckCycle("");
			// 行号
			dto.setTaskRowId(item.get("taskRowId") != null ? item.get("taskRowId").toString() : "");
			// 物料编码
			dto.setMaterialNo(item.get("materialNo") != null ? item.get("materialNo").toString() : "");
			// 物料描述
			if ("zh-CN".equals(language)) {
				dto.setMaterialName(item.get("materialZhDesc") != null ? item.get("materialZhDesc").toString() : "");
			} else if ("en-US".equals(language)) {
				dto.setMaterialName(item.get("materialEnDesc") != null ? item.get("materialEnDesc").toString() : "");
			}
			// 库存数量
			dto.setInventoryQuantity(item.get("inventoryQuantity") != null ? item.get("inventoryQuantity").toString() : "");
			// 基本单位
			dto.setBasicUnit(item.get("basicUnit") != null ? item.get("basicUnit").toString() : "");
			// 储位
			dto.setStorageCode(item.get("storageNo") != null ? item.get("storageNo").toString() : "");
			// 盘点数量
			dto.setCheckQuantity(item.get("checkQuantity") != null ? item.get("checkQuantity").toString() : "");
			// 差异
			dto.setDiscrepancy(item.get("discrepancy") != null ? item.get("discrepancy").toString() : "");
			// TODO 差额 (待补充)
			dto.setDifferencesAmount("");
			// 盘点原因
			dto.setItemRemarks(item.get("remarks") != null ? item.get("remarks").toString() : "");
			returnList.add(dto);
		}
		return returnList;
	}
}
