package com.malk.mc.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.malk.core.McProject;
import com.malk.mc.service.McYdService;
import com.malk.server.aliwork.YDConf;
import com.malk.server.aliwork.YDParam;
import com.malk.server.common.McException;
import com.malk.server.common.McR;
import com.malk.server.dingtalk.DDConf;
import com.malk.server.dingtalk.DDR;
import com.malk.server.dingtalk.DDR_New;
import com.malk.service.aliwork.YDClient;
import com.malk.service.aliwork.YDService;
import com.malk.service.dingtalk.DDClient;
import com.malk.service.dingtalk.DDClient_Contacts;
import com.malk.service.dingtalk.DDClient_Notice;
import com.malk.service.dingtalk.DDClient_Workflow;
import com.malk.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;

@Slf4j
@Service
public class McYdServiceImpl implements McYdService {
    @Autowired
    private YDClient ydClient;
    @Autowired
    private DDClient ddClient;
    @Autowired
    private DDConf ddConf;
    @Autowired
    private YDConf ydConf;
    @Autowired
    private DDClient_Workflow ddClientWorkflow;

    @Autowired
    private DDClient_Notice ddClientNotice;

    @Autowired
    private DDClient_Contacts ddClient_contacts;

    @Override
    @Async
    public void updateFormDataVersion(Map map) {
        try {
            String pid = Objects.nonNull(map.get("pid")) ? map.get("pid").toString() : "";
            String formInstId = Objects.nonNull(map.get("formInstId")) ? map.get("formInstId").toString() : "";
            String formUuid = Objects.nonNull(map.get("formUuid")) ? map.get("formUuid").toString() : "";

            if (Strings.isNotBlank(pid)){
                MDC.put("MDC_KEY_PID",pid);
                if (Strings.isNotBlank(formInstId) && Strings.isBlank(formUuid)){
                    ydClient.operateData(YDParam.builder()
                            .formInstId(formInstId)
                            .useLatestVersion(true)
                            .updateFormDataJson("{}").build(), YDConf.FORM_OPERATION.update);
                }else if (Strings.isBlank(formInstId) && Strings.isNotBlank(formUuid)){
                    int i = 1;
                    int pageSize = 10;
                    DDR_New ddrNew = null;
                    do {
                        int i1 =1 ;
                        boolean flag1 = false;
                        while (i1<=5 && !flag1) {
                            try {
                                ddrNew = ydClient.queryData(YDParam.builder()
                                        .formUuid(formUuid)
                                        .pageNumber(i)
                                        .pageSize(pageSize)
                                        .build(), YDConf.FORM_QUERY.retrieve_search_form_id);

                                List<String> formInstIdList = (List<String>) ddrNew.getData();

                                //noExecuteExpression字段不传或传false  传true会导致实例版本不更新或滞后更新
                                ydClient.operateData(YDParam.builder()
                                        .formInstanceIdList(formInstIdList)
                                        .formUuid(formUuid)
                                        .useLatestFormSchemaVersion(true)
                                        .updateFormDataJson("{}")
                                        .noExecuteExpression(false)
                                        .asynchronousExecution(false)
                                        .build(),YDConf.FORM_OPERATION.multi_update);

                                i++;
                                flag1 = true;
                            }catch (Exception e){
                                log.error("更新表单实例版本失败:{}, 重试次数:{}",e.getMessage(),i1);
                                try {
                                    Thread.sleep(3000);
                                } catch (InterruptedException ex) {
                                    throw new RuntimeException(ex);
                                }
                                i1++;
                            }
                        }
                        if (i1 > 5){
                            throw new RuntimeException("更新表单实例版本失败，超过最大重试次数！");
                        }

                    }while (ddrNew.getTotalCount() > ddrNew.getPageNumber() * pageSize);
                }

                //发送工作通知给当前登陆人
                if (Objects.nonNull(map.get("userId"))){
                    //获取当前时间 精确到秒
                    String time = DateUtil.format(new Date(),"yyyy-MM-dd HH:mm:ss");
                    sendDdMsg(ddClient.getAccessToken(),ddConf.getAgentId(),map.get("userId").toString(),"表单实例版本已更新  时间：" + time);
                }
            }
        }catch (Exception e){
            //发送工作通知
            if (Objects.nonNull(map.get("userId"))){
                String time = DateUtil.format(new Date(),"yyyy-MM-dd HH:mm:ss");//获取当前时间 精确到秒
                sendDdMsg(ddClient.getAccessToken(),ddConf.getAgentId(),map.get("userId").toString(),"更新表单实例版本异常：" + e.getMessage() + "  时间：" + time);
            }

            throw new RuntimeException(e);
        }

    }

    //发送工作通知
    public void sendDdMsg(String access_token,Number agent_id, String userid_list, String content){
        if (Objects.nonNull(userid_list)){
            Map param2 = new HashMap();
            param2.put("access_token",access_token);
            Map body3 = new HashMap();
            body3.put("agent_id",agent_id);
            body3.put("userid_list",userid_list);
            Map msg = new HashMap();
            msg.put("msgtype","text");
            //获取当前时间 精确到秒
            String time = DateUtil.format(new Date(),"yyyy-MM-dd HH:mm:ss");
            msg.put("text", UtilMap.map("content",content));
            body3.put("msg",msg);
            UtilHttp.doPost("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2",null,param2,body3);
        }
    }

    @Override
    public McR initiateApproval(Map map) {
        String pid = getString(map.get("pid"));
        String formUuid = getString(map.get("formUuid"));
        String processCode = getString(map.get("processCode"));
        String userId = getString(map.get("userId"));
        Map formData = (Map) map.get("formData");
        Map processData = new HashMap();
        if (Objects.nonNull(map.get("processData"))){
            processData = (Map) map.get("processData");
        }

        if (Strings.isNotBlank(pid)){
            //发起审批
            String[] yida = McProject.getYida(pid);
            Map<String,Object> body = new HashMap<>();
            if (!PublicUtil.isNull(pid) && yida != null && yida.length >= 2) {
                body.put("appType",yida[0]);
                body.put("systemToken",yida[1]);
            }
            body.put("userId",userId);
            body.put("formUuid",formUuid);
            body.put("processCode",processCode);
            body.put("formDataJson", JSONObject.toJSONString(formData));
            if (Objects.nonNull(processData) && processData.size() > 0){
                body.put("processData", JSONObject.toJSONString(processData));
            }

            UtilHttp.doPost("https://api.dingtalk.com/v1.0/yida/processes/instances/start", ddClient.initTokenHeader(), null, body, DDR_New.class);
            return McR.success();
        }
        return McR.errorParam("参数缺失！");
    }

    @Override
    public McR convertSubTableNumber(Map map) {
        String formInstId = getString(map.get("formInstId"));
        String tableField = getString(map.get("tableField"));
        String numberFieldCode = getString(map.get("numFileCodes"));
        String textFieldCode = getString(map.get("textFieldCodes"));

        if (Strings.isNotBlank(formInstId)){
            DDR_New ddrNew = ydClient.queryData(YDParam.builder()
                    .formInstId(formInstId)
                    .build(), YDConf.FORM_QUERY.retrieve_id);
            Map formData = ddrNew.getFormData();
            Map updateMap=new HashMap();
            if (!PublicUtil.isNull(tableField)&&tableField.startsWith("tableField_")) {
                List<Map<String, ?>> table = UtilMap.getList( formData,(tableField));
                for (Map item : table) {
                    String[] numberFieldCodes=numberFieldCode.split(",");
                    String[] textFieldCodes=textFieldCode.split(",");
                    for (int i = 0; i < numberFieldCodes.length; i++) {
                        String numstr=UtilMap.getNumberStr(item,numberFieldCodes[i]);
                        if(PublicUtil.isNull(numstr)||numstr.equals("0")){
                            updateMap.put(textFieldCodes[i],"0.00");
                            continue;
                        }
                        BigDecimal number = NumberUtil.toBigDecimal(numstr);
                        // 创建一个 DecimalFormat 实例，指定千位分隔符模式
                        DecimalFormat df = new DecimalFormat("#,###.00");
                        // 格式化 double 数值
                        String formattedText = df.format(number);
                        item.put(textFieldCodes[i],formattedText);
                    }
                }
                updateMap.put(tableField,getTableData(table)); // 添加一层过滤
            }

            if(!PublicUtil.isNull(map,"mainNumKeys","mainTextKeys")){
                String[] mainNumKeys=UtilMap.getString(map,"mainNumKeys").split(",");
                String[] mainTextKeys=UtilMap.getString(map,"mainTextKeys").split(",");
                for (int i = 0; i < mainNumKeys.length; i++) {
                    String numstr=UtilMap.getNumberStr(formData,(mainNumKeys[i]));
                    if(PublicUtil.isNull(numstr)||numstr.equals("0")){
                        updateMap.put(mainTextKeys[i],"0.00");
                        continue;
                    }
                    BigDecimal number = NumberUtil.toBigDecimal(numstr);
                    // 创建一个 DecimalFormat 实例，指定千位分隔符模式
                    DecimalFormat df = new DecimalFormat("#,###.00");
                    // 格式化 double 数值
                    String formattedText = df.format(number);
                    updateMap.put(mainTextKeys[i],formattedText);
                }
            }

            ydClient.operateData(YDParam.builder()
                    .formInstId(formInstId)
                    .useLatestVersion(true)
                    .updateFormDataJson(JSONObject.toJSONString(updateMap))
                    .build(), YDConf.FORM_OPERATION.update);
        }

        return McR.success();
    }

    @Override
    public McR saveApproverToForm(Map map) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        String key = UtilMap.getString(map,"key");
        String formInstId = UtilMap.getString(map,"formInstId");
        JSONArray jsonArray=(JSONArray) ydClient.queryData(YDParam.builder().processInstanceId(formInstId).build(),YDConf.FORM_QUERY.retrieve_approval_record).getResult();
        List<String> userIds = new ArrayList<>();
        extractOperatorIds(jsonArray,userIds);
        ydClient.operateData(YDParam.builder().updateFormDataJson(JSONObject.toJSONString(UtilMap.map(key, userIds))).formInstId(formInstId).build(), YDConf.FORM_OPERATION.update);
        return McR.success();
    }

    @Override
    public McR multiLocationOutbound(Map map) {
        String formInstId = UtilMap.getString(map,"formInstId");//实例id(出库单)
        log.info("出库单实例id：" + formInstId);
        Map d = ydClient.queryData(YDParam.builder().formInstId(formInstId)
                .formUuid("FORM-3208DFE5463549A9A57FB94358A75E80PV5F")
                .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                .userId("332051151139376769").build(),YDConf.FORM_QUERY.retrieve_id).getFormData();
        System.out.println("出库单数据："+d);
        List<Map> mapList = (List<Map>)d.get("tableField_m8mo8506");
        System.out.println("出库单明细数据："+mapList);
        ArrayList<Object> entries = new ArrayList<>();
        for(Map map1 : mapList){
            String LBJId = map1.get("textField_ma1usp6o").toString();//零部件的实例id
            entries.add(LBJId);
            System.out.println("物料名称："+map1.get("textField_m99kztjo").toString());
            BigDecimal InventoryCount = BigDecimal.valueOf(0);//库存数量
            BigDecimal OutboundQuantity = BigDecimal.valueOf(0);//
            if(!map1.get("numberField_m9qdwvu1_value").toString().isEmpty()){
                InventoryCount = new BigDecimal( map1.get("numberField_m9qdwvu1").toString());
            }
            BigDecimal numberFieldM9qdwvu1 = InventoryCount.subtract( new BigDecimal( map1.get("numberField_m8mo8508").toString()));//存库数量 - 出库数量
            System.out.println("出库后数量："+numberFieldM9qdwvu1);

            Map d1 = ydClient.queryData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .userId("332051151139376769").build(),YDConf.FORM_QUERY.retrieve_id).getFormData();
            System.out.println(map1.get("textField_m99kztjo").toString()+"的数据明细："+ d1.get("tableField_m96gje14").toString());

            String s = d1.get("tableField_m96gje14").toString();
            String warehouse = JSON.parseArray(s).getJSONObject(0).get("selectField_m88f1qi8").toString();//所属仓库
            String WarehouseLocation = JSON.parseArray(s).getJSONObject(0).get("textField_m8mnxgql").toString();//所属库位
            String SafetyValue = JSON.parseArray(s).getJSONObject(0).get("numberField_m8873fn4").toString();//安全库存值

            ArrayList<Map<String,String>> maps_YD = new ArrayList<>();
            Map sss=new HashMap<>();
            sss.put("selectField_m88f1qi8",warehouse);//所属仓库
            sss.put("textField_m8mnxgql",WarehouseLocation);//所属库位
            sss.put("numberField_m8873fn4",SafetyValue);//安全库存值
            sss.put("numberField_m9c8n9go",numberFieldM9qdwvu1);//仓库数量
            maps_YD.add(sss);

            ydClient.operateData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("tableField_m96gje14",maps_YD)))
                    .userId("332051151139376769").build(),YDConf.FORM_OPERATION.update);
            BigDecimal InventoryQuantity = new BigDecimal( d1.get("numberField_m8obn6wk").toString());//库存数量
            BigDecimal FreezeQuantity = null;
            if(!d1.get("numberField_m8obn6wl_value").toString().isEmpty()){
                FreezeQuantity = new BigDecimal( d1.get("numberField_m8obn6wl").toString());//冻结数量
            }else {
                FreezeQuantity = BigDecimal.valueOf(0);
            }
            System.out.println("--------------------零部件子表数据修改完毕！---------------------");
            BigDecimal FreezeQuantity_AAA = FreezeQuantity.add( new BigDecimal( map1.get("numberField_m8mo8508").toString()));//冻结数量（新）
            BigDecimal AvailableQuantity_AAA = numberFieldM9qdwvu1;//可用存库数量（新）
            ydClient.operateData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("numberField_m8obn6wl, numberField_m8gz97nk",FreezeQuantity_AAA,AvailableQuantity_AAA)))
                    .userId("332051151139376769")
                    .build(),YDConf.FORM_OPERATION.update);
            System.out.println("----------------------零部件主表数据修改完毕！------------------");
        }

        return McR.success();
    }

    @Override
    public McR multiLocationOutboundAI(Map map) {
        String formInstId = UtilMap.getString(map, "formInstId");
        log.info("出库单实例id：" + formInstId);

        // 查询出库单主数据（支持重试）
        Map d = executeWithRetry(() -> ydClient.queryData(YDParam.builder()
                                .formInstId(formInstId)
                                .formUuid("FORM-3208DFE5463549A9A57FB94358A75E80PV5F")
                                .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                                .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                                .userId("332051151139376769").build(),
                        YDConf.FORM_QUERY.retrieve_id).getFormData(),
                "查询出库单主数据", 3, 1000);

        System.out.println("出库单数据：" + d);
        List<Map> mapList = (List<Map>) d.get("tableField_m8mo8506");
        System.out.println("出库单明细数据：" + mapList);

        for (Map map1 : mapList) {
            String componentInstId = map1.get("textField_ma1usp6o").toString();
            BigDecimal outQuantity = new BigDecimal(map1.get("numberField_m8mo8508").toString());
            processOutboundComponent(componentInstId, map1, outQuantity);
        }
        return McR.success();
    }

    private void processOutboundComponent(String componentInstId, Map detailRow, BigDecimal outQuantity) {
        String componentName = detailRow.get("textField_m99kztjo").toString();
        executeWithRetry(() -> {
            // 1. 查询零部件当前完整数据
            Map partData = ydClient.queryData(YDParam.builder()
                            .formInstId(componentInstId)
                            .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                            .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                            .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                            .userId("332051151139376769").build(),
                    YDConf.FORM_QUERY.retrieve_id).getFormData();

            // 2. 获取当前可用库存（正确字段：numberField_m8gz97nk）
            BigDecimal currentAvailable = parseBigDecimal(partData.get("numberField_m8gz97nk"));
            // 计算出库后数量（应该 = currentAvailable - outQuantity）
            BigDecimal newAvailable = currentAvailable.subtract(outQuantity);
            System.out.println("当前可用库存：" + currentAvailable + "，出库后数量：" + newAvailable);

            // 3. 解析子表仓库信息（取第一条）
            String subTableJson = partData.get("tableField_m96gje14").toString();
            JSONArray subArray = JSON.parseArray(subTableJson);
            if (subArray == null || subArray.isEmpty()) {
                throw new RuntimeException("零部件[" + componentName + "]子表数据为空，无法更新库存");
            }
            JSONObject warehouseObj = subArray.getJSONObject(0);
            String warehouse = warehouseObj.getString("selectField_m88f1qi8");
            String warehouseLocation = warehouseObj.getString("textField_m8mnxgql");
            String safetyValue = warehouseObj.getString("numberField_m8873fn4");
            BigDecimal currentWarehouseQty = parseBigDecimal(warehouseObj.getString("numberField_m9c8n9go"));
            BigDecimal newWarehouseQty = currentWarehouseQty.subtract(outQuantity);
            System.out.println("当前仓库数量：" + currentWarehouseQty + "，出库后仓库数量：" + newWarehouseQty);

            // 4. 获取冻结数量（字段：numberField_m8obn6wl）并计算新冻结数量
            BigDecimal currentFreeze = parseBigDecimal(partData.get("numberField_m8obn6wl"));
            BigDecimal newFreeze = currentFreeze.add(outQuantity);
            System.out.println("当前冻结数量：" + currentFreeze + "，新冻结数量：" + newFreeze);

            // 5. 构建子表更新数据（完整替换）
            List<Map<String, Object>> newSubTable = new ArrayList<>();
            Map<String, Object> newRow = new HashMap<>();
            newRow.put("selectField_m88f1qi8", warehouse);
            newRow.put("textField_m8mnxgql", warehouseLocation);
            newRow.put("numberField_m8873fn4", safetyValue);
            newRow.put("numberField_m9c8n9go", newWarehouseQty);   // 仓库数量更新为出库后数量
            newSubTable.add(newRow);

            // 6. 构建主表更新字段
            Map<String, Object> updateData = new HashMap<>();
            updateData.put("tableField_m96gje14", newSubTable);
            updateData.put("numberField_m8obn6wl", newFreeze);      // 冻结数量累加
            updateData.put("numberField_m8gz97nk", newAvailable);   // 可用库存更新为出库后数量

            // 7. 执行原子更新（一次调用同时修改主表和子表）
            ydClient.operateData(YDParam.builder()
                            .formInstId(componentInstId)
                            .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                            .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                            .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                            .updateFormDataJson(JSONObject.toJSONString(updateData))
                            .userId("332051151139376769").build(),
                    YDConf.FORM_OPERATION.update);

            System.out.println("----------------------零部件[" + componentName + "]主表及子表数据原子更新完毕！------------------");
            return null;
        }, "处理出库零部件[" + componentName + "]实例[" + componentInstId + "]", 3, 1000);
    }

    @Override
    public McR WarehouseStorage(Map map) {
        String formInstId = UtilMap.getString(map,"formInstId");//实例id(入库单)
        log.info("入库单实例id："+formInstId);
        Map d = ydClient.queryData(YDParam.builder().formInstId(formInstId)
                .formUuid("FORM-6DED8EB4CF0446DB8841C7798E106F2886OH")
                .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                .userId("332051151139376769").build(),YDConf.FORM_QUERY.retrieve_id).getFormData();
        System.out.println("入库单数据："+d);
        List<Map> mapList = (List<Map>)d.get("tableField_m8mseubi");
        System.out.println("入库单明细数据："+mapList);
        ArrayList<Object> entries = new ArrayList<>();
        for(Map map1 : mapList){
            String LBJId = map1.get("textField_ma3jhnpr").toString();//零部件的实例id
            entries.add(LBJId);
            System.out.println("物料名称："+map1.get("textField_m9b1vd2w").toString());

            BigDecimal numberFieldM9qdwvu1 = new BigDecimal( map1.get("numberField_ma3jwnr3").toString() ).add(new BigDecimal( map1.get("numberField_m8mseubm").toString()));//存库数量 + 入库数量
            System.out.println("入库后数量："+numberFieldM9qdwvu1);

            Map d1 = ydClient.queryData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .userId("332051151139376769").build(),YDConf.FORM_QUERY.retrieve_id).getFormData();
            System.out.println(map1.get("textField_m9b1vd2w").toString()+"的数据明细："+ d1.get("tableField_m96gje14").toString());

            String s = d1.get("tableField_m96gje14").toString();
            String warehouse = JSON.parseArray(s).getJSONObject(0).get("selectField_m88f1qi8").toString();//所属仓库
            String WarehouseLocation = JSON.parseArray(s).getJSONObject(0).get("textField_m8mnxgql").toString();//所属库位
            String SafetyValue = JSON.parseArray(s).getJSONObject(0).get("numberField_m8873fn4").toString();//安全库存值

            ArrayList<Map<String,String>> maps_YD = new ArrayList<>();
            Map sss=new HashMap<>();
            sss.put("selectField_m88f1qi8",warehouse);//所属仓库
            sss.put("textField_m8mnxgql",WarehouseLocation);//所属库位
            sss.put("numberField_m8873fn4",SafetyValue);//安全库存值
            sss.put("numberField_m9c8n9go",numberFieldM9qdwvu1);//仓库数量
            maps_YD.add(sss);

            ydClient.operateData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("tableField_m96gje14",maps_YD)))
                    .userId("332051151139376769").build(),YDConf.FORM_OPERATION.update);
            BigDecimal InventoryQuantity = null;
            if(!d1.get("numberField_m8gz97nk").toString().isEmpty()){
                InventoryQuantity = new BigDecimal( d1.get("numberField_m8gz97nk").toString());//可用库存数量
            }else {
                InventoryQuantity = BigDecimal.valueOf(0);
            }
            BigDecimal VirtualQuantity = null;
            if(!d1.get("numberField_m8obn6wq_value").toString().isEmpty()){
                VirtualQuantity = new BigDecimal( d1.get("numberField_m8obn6wq").toString());//虚拟数量
            }else {
                VirtualQuantity = BigDecimal.valueOf(0);
            }

            System.out.println("--------------------零部件子表数据修改完毕！---------------------");

            BigDecimal VirtualQuantity_AAA = VirtualQuantity.add( new BigDecimal( map1.get("numberField_m8mseubm").toString()));//虚拟数量（新）
            BigDecimal AvailableQuantity_AAA = InventoryQuantity .add (new BigDecimal( map1.get("numberField_m8mseubm").toString()));//可用存库数量（新）
            ydClient.operateData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("numberField_m8obn6wq, numberField_m8gz97nk",VirtualQuantity_AAA,AvailableQuantity_AAA)))
                    .userId("332051151139376769")
                    .build(),YDConf.FORM_OPERATION.update);
            System.out.println("----------------------零部件主表数据修改完毕！------------------");
        }
        return McR.success();
    }


    @Override
    public McR WarehouseStorageAI(Map map) {
        String formInstId = UtilMap.getString(map, "formInstId");
        log.info("入库单实例id：" + formInstId);

        Map d = executeWithRetry(() -> ydClient.queryData(YDParam.builder()
                                .formInstId(formInstId)
                                .formUuid("FORM-6DED8EB4CF0446DB8841C7798E106F2886OH")
                                .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                                .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                                .userId("332051151139376769").build(),
                        YDConf.FORM_QUERY.retrieve_id).getFormData(),
                "查询入库单主数据", 3, 1000);

        System.out.println("入库单数据：" +   d);
        List<Map> mapList = (List<Map>) d.get("tableField_m8mseubi");
        System.out.println("入库单明细数据：" + mapList);

        for (Map map1 : mapList) {
            String componentInstId = map1.get("textField_ma3jhnpr").toString();
            BigDecimal inQuantity = new BigDecimal(map1.get("numberField_m8mseubm").toString());
            processComponent(componentInstId, map1, inQuantity);
        }
        return McR.success();
    }

    private void processComponent(String componentInstId, Map detailRow, BigDecimal inQuantity) {
        String componentName = detailRow.get("textField_m9b1vd2w").toString();
        executeWithRetry(() -> {
            Map partData = ydClient.queryData(YDParam.builder()
                            .formInstId(componentInstId)
                            .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                            .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                            .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                            .userId("332051151139376769").build(),
                    YDConf.FORM_QUERY.retrieve_id).getFormData();

            String subTableJson = partData.get("tableField_m96gje14").toString();
            JSONArray subArray = JSON.parseArray(subTableJson);
            if (subArray == null || subArray.isEmpty()) {
                // 改用 RuntimeException，此类业务错误不应重试
                throw new RuntimeException("零部件[" + componentName + "]子表数据为空，无法更新库存");
            }
            JSONObject warehouseObj = subArray.getJSONObject(0);
            String warehouse = warehouseObj.getString("selectField_m88f1qi8");
            String warehouseLocation = warehouseObj.getString("textField_m8mnxgql");
            String safetyValue = warehouseObj.getString("numberField_m8873fn4");
            BigDecimal currentWarehouseQty = parseBigDecimal(warehouseObj.getString("numberField_m9c8n9go"));

            BigDecimal currentVirtual = parseBigDecimal(partData.get("numberField_m8obn6wq"));
            BigDecimal currentAvailable = parseBigDecimal(partData.get("numberField_m8gz97nk"));

            BigDecimal newWarehouseQty = currentWarehouseQty.add(inQuantity);
            BigDecimal newVirtual = currentVirtual.add(inQuantity);
            BigDecimal newAvailable = currentAvailable.add(inQuantity);

            List<Map<String, Object>> newSubTable = new ArrayList<>();
            Map<String, Object> newRow = new HashMap<>();
            newRow.put("selectField_m88f1qi8", warehouse);
            newRow.put("textField_m8mnxgql", warehouseLocation);
            newRow.put("numberField_m8873fn4", safetyValue);
            newRow.put("numberField_m9c8n9go", newWarehouseQty);
            newSubTable.add(newRow);

            Map<String, Object> updateData = new HashMap<>();
            updateData.put("tableField_m96gje14", newSubTable);
            updateData.put("numberField_m8obn6wq", newVirtual);
            updateData.put("numberField_m8gz97nk", newAvailable);

            ydClient.operateData(YDParam.builder()
                            .formInstId(componentInstId)
                            .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                            .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                            .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                            .updateFormDataJson(JSONObject.toJSONString(updateData))
                            .userId("332051151139376769").build(),
                    YDConf.FORM_OPERATION.update);

            System.out.println("----------------------零部件[" + componentName + "]主表及子表数据原子更新完毕！------------------");
            return null;
        }, "处理零部件[" + componentName + "]实例[" + componentInstId + "]", 3, 1000);
    }

    private <T> T executeWithRetry(Supplier<T> action, String operationName, int maxRetries, long initialDelayMs) {
        int attempt = 0;
        while (true) {
            try {
                return action.get();
            } catch (McException e) {
                boolean isTemporary = e.getMessage() != null && e.getMessage().contains("temporary failure");
                if (!isTemporary || attempt >= maxRetries) {
                    log.error("操作[{}]失败，非临时异常或已达最大重试次数({})，异常信息：", operationName, maxRetries, e);
                    throw e;
                }
                attempt++;
                long delay = initialDelayMs * (1L << (attempt - 1));
                log.warn("操作[{}]遇到临时故障，第{}次重试，等待{}ms", operationName, attempt, delay);
                try {
                    Thread.sleep(delay);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    // 重试被中断，改为抛出 RuntimeException，避免编译错误
                    throw new RuntimeException("重试被中断", ie);
                }
            } catch (RuntimeException e) {
                // 业务异常（如子表为空）直接抛出，不重试
                log.error("操作[{}]遇到业务异常，不重试", operationName, e);
                throw e;
            } catch (Exception e) {
                log.error("操作[{}]遇到非McException异常，不重试", operationName, e);
                throw e;
            }
        }
    }


    private BigDecimal parseBigDecimal(Object value) {
        if (value == null) return BigDecimal.ZERO;
        String str = value.toString().trim();
        if (str.isEmpty()) return BigDecimal.ZERO;
        try {
            return new BigDecimal(str);
        } catch (NumberFormatException e) {
            log.warn("解析BigDecimal失败，值：{}，返回0", str);
            return BigDecimal.ZERO;
        }
    }

    @Override
    public McR ProductReturn(Map map) {
        String formInstId = UtilMap.getString(map,"formInstId");//实例id(退货单)
        log.info("退货单实例id："+formInstId);
        Map data = ydClient.queryData(YDParam.builder().formInstId(formInstId)
                .formUuid("FORM-E40A23253F2F43FEAF0E40F274A67B34OQC9")
                .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                .userId("332051151139376769").build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
        System.out.println("退货单："+data);
        List<Map> mapList = (List<Map>)data.get("tableField_m99koj01");
        System.out.println("退货单明细数据："+mapList);
        ArrayList<Object> entries = new ArrayList<>();
        for (Map map1 : mapList){
            String LBJId = map1.get("textField_maki4tqo").toString();//零部件的实例id
            System.out.println("物料名称："+map1.get("textField_m99koj02").toString());//物料名称
            System.out.println("所属库位："+map1.get("textField_maki4tqp").toString());//产品库位
            System.out.println("退货数量："+map1.get("numberField_ma0e13js").toString());//退货数量


            Map data1 = ydClient.queryData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .userId("332051151139376769").build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
            System.out.println(map1.get("textField_m99koj02")+"明细表数据："+data1.get("tableField_m96gje14"));//零部件明细
            String s = data1.get("tableField_m96gje14").toString();
            String warehouse = JSON.parseArray(s).getJSONObject(0).get("selectField_m88f1qi8").toString();//所属仓库
            String WarehouseLocation = JSON.parseArray(s).getJSONObject(0).get("textField_m8mnxgql").toString();//所属库位
            String SafetyValue = JSON.parseArray(s).getJSONObject(0).get("numberField_m8873fn4").toString();//安全库存值
            BigDecimal numberFieldM9c8n9go = new BigDecimal(JSON.parseArray(s).getJSONObject(0).get("numberField_m9c8n9go").toString());//仓库数量

            BigDecimal numm = new BigDecimal(map1.get("numberField_ma0e13js").toString()).add(numberFieldM9c8n9go); //退货后的库存数量 =  退货数量 + 仓库数量（子）

            ArrayList<Map<String,String>> maps_YD = new ArrayList<>();
            Map sss=new HashMap<>();
            sss.put("selectField_m88f1qi8",warehouse);//所属仓库
            sss.put("textField_m8mnxgql",WarehouseLocation);//所属库位
            sss.put("numberField_m8873fn4",SafetyValue);//安全库存值
            sss.put("numberField_m9c8n9go",numm);//仓库数量
            maps_YD.add(sss);

            ydClient.operateData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("tableField_m96gje14",maps_YD)))
                    .userId("332051151139376769").build(),YDConf.FORM_OPERATION.update);

            BigDecimal InventoryQuantity = null;
            if(!data1.get("numberField_m8gz97nk_value").toString().isEmpty()){
                InventoryQuantity = new BigDecimal( data1.get("numberField_m8gz97nk").toString());//可用库存数量
            }else {
                InventoryQuantity = BigDecimal.valueOf(0);
            }

            BigDecimal FreezeQuantity = null;
            if(!data1.get("numberField_m8obn6wl_value").toString().isEmpty()){
                FreezeQuantity = new BigDecimal( data1.get("numberField_m8obn6wl").toString());//冻结数量
            }else {
                FreezeQuantity = BigDecimal.valueOf(0);
            }
            System.out.println("---------------------------------------零部件子表数据修改完毕--------------------------------");

            BigDecimal FreezeQuantity_AAA = FreezeQuantity.subtract( new BigDecimal( map1.get("numberField_ma0e13js").toString()));//冻结数量（新） = 冻结数量 - 退货数量
            BigDecimal AvailableQuantity_AAA = InventoryQuantity.add(new BigDecimal( map1.get("numberField_ma0e13js").toString()));//可用存库数量（新） = 可用库存数量 + 退货数量
            ydClient.operateData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("numberField_m8obn6wl, numberField_m8gz97nk",FreezeQuantity_AAA,AvailableQuantity_AAA)))
                    .userId("332051151139376769")
                    .build(),YDConf.FORM_OPERATION.update);
            System.out.println("----------------------零部件主表数据修改完毕！------------------");

        }
        return McR.success();
    }

    @Override
    public McR allocateTransfer(Map map) {
        String formInstId = UtilMap.getString(map,"formInstId");//实例id(调拨流程)
        log.info("调拨流程实例id:"+formInstId);
        Map data = ydClient.queryData(YDParam.builder().formInstId(formInstId)
                .formUuid("FORM-C6360F0CA28543E8BA99A1DDCF90964FSJEM")
                .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                .userId("332051151139376769").build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
        System.out.println("调拨单："+data);
        List<Map> mapList = (List<Map>)data.get("tableField_m9grj2ih");
        System.out.println("调拨明细数据："+mapList);
        ArrayList<Object> entries = new ArrayList<>();
        for (Map map1 : mapList){
            //TODO:1、调出零部件处理
            String LBJId = map1.get("textField_mawbt28t").toString();//（调出）零部件的实例id
            System.out.println("调出的所属库位："+map1.get("textField_m9grj2il").toString());//产品库位
            System.out.println("调出的所属仓库："+map1.get("textField_m9grj2ik").toString());//产品仓库
            System.out.println("调拨前数量："+map1.get("numberField_m9gs7k82").toString());//调拨前数量


            Map data1 = ydClient.queryData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .userId("332051151139376769").build(), YDConf.FORM_QUERY.retrieve_id).getFormData();

            String s = data1.get("tableField_m96gje14").toString();
            String warehouse = JSON.parseArray(s).getJSONObject(0).get("selectField_m88f1qi8").toString();//所属仓库
            String WarehouseLocation = JSON.parseArray(s).getJSONObject(0).get("textField_m8mnxgql").toString();//所属库位
            String SafetyValue = JSON.parseArray(s).getJSONObject(0).get("numberField_m8873fn4").toString();//安全库存值
            BigDecimal numberFieldM9c8n9go = new BigDecimal(JSON.parseArray(s).getJSONObject(0).get("numberField_m9c8n9go").toString());//仓库数量

            BigDecimal numm = numberFieldM9c8n9go.subtract(new BigDecimal(map1.get("numberField_m9grj2ij").toString())); //调拨后的库存数量 =  仓库数量 - 调拨数量

            ArrayList<Map<String,String>> maps_YD = new ArrayList<>();
            Map sss=new HashMap<>();
            sss.put("selectField_m88f1qi8",warehouse);//所属仓库
            sss.put("textField_m8mnxgql",WarehouseLocation);//所属库位
            sss.put("numberField_m8873fn4",SafetyValue);//安全库存值
            sss.put("numberField_m9c8n9go",numm);//仓库数量
            maps_YD.add(sss);

            ydClient.operateData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("tableField_m96gje14",maps_YD)))
                    .userId("332051151139376769").build(),YDConf.FORM_OPERATION.update);

            //TODO:2、调入零部件处理
            String LBJId2 = map1.get("textField_maxendgs").toString();//（调入）零部件的实例id
            System.out.println("调入的所属库位："+map1.get("textField_m9grj2il").toString());//产品库位
            System.out.println("调入的所属仓库："+map1.get("textField_m9grj2ik").toString());//产品仓库
            System.out.println("调拨前数量："+map1.get("numberField_maz574d0").toString());//调拨前数量

            Map data2 = ydClient.queryData(YDParam.builder().formInstId(LBJId2)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .userId("332051151139376769").build(), YDConf.FORM_QUERY.retrieve_id).getFormData();

            String s1 = data2.get("tableField_m96gje14").toString();
            String warehouse1 = JSON.parseArray(s1).getJSONObject(0).get("selectField_m88f1qi8").toString();//所属仓库
            String WarehouseLocation1 = JSON.parseArray(s1).getJSONObject(0).get("textField_m8mnxgql").toString();//所属库位
            String SafetyValue1 = JSON.parseArray(s1).getJSONObject(0).get("numberField_m8873fn4").toString();//安全库存值
            BigDecimal numberFieldM9c8n9go1 = new BigDecimal(JSON.parseArray(s1).getJSONObject(0).get("numberField_m9c8n9go").toString());//仓库数量

            BigDecimal numm1 = numberFieldM9c8n9go1.add(new BigDecimal(map1.get("numberField_m9grj2ij").toString())); //调拨后的库存数量 =  仓库数量 + 调拨数量

            ArrayList<Map<String,String>> maps_YD1 = new ArrayList<>();
            Map sss1=new HashMap<>();
            sss1.put("selectField_m88f1qi8",warehouse1);//所属仓库
            sss1.put("textField_m8mnxgql",WarehouseLocation1);//所属库位
            sss1.put("numberField_m8873fn4",SafetyValue1);//安全库存值
            sss1.put("numberField_m9c8n9go",numm1);//仓库数量
            maps_YD1.add(sss1);

            ydClient.operateData(YDParam.builder().formInstId(LBJId2)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("tableField_m96gje14",maps_YD1)))
                    .userId("332051151139376769").build(),YDConf.FORM_OPERATION.update);


            BigDecimal AvailableInventoryQuantity_AAA = null;
            BigDecimal InventoryQuantity_AAA = null;
            if(!data1.get("numberField_m8gz97nk_value").toString().isEmpty()){
                AvailableInventoryQuantity_AAA = new BigDecimal( data1.get("numberField_m8gz97nk").toString());//可用库存数量
            }else {
                AvailableInventoryQuantity_AAA = BigDecimal.valueOf(0);
            }
            if(!data1.get("numberField_m8obn6wk_value").toString().isEmpty()){
                InventoryQuantity_AAA = new BigDecimal(data1.get("numberField_m8obn6wk").toString());//存库数量
            }else {
                InventoryQuantity_AAA = BigDecimal.valueOf(0);
            }

            BigDecimal AvailableInventoryQuantity_BBB = null;
            BigDecimal InventoryQuantity_BBB = null;
            if(!data2.get("numberField_m8gz97nk_value").toString().isEmpty()){
                AvailableInventoryQuantity_BBB = new BigDecimal( data2.get("numberField_m8gz97nk").toString());//可用库存数量
            }else {
                AvailableInventoryQuantity_BBB = BigDecimal.valueOf(0);
            }
            if(!data2.get("numberField_m8obn6wk_value").toString().isEmpty()){
                InventoryQuantity_BBB = new BigDecimal(data2.get("numberField_m8obn6wk").toString());//可用库存数量
            }else {
                InventoryQuantity_BBB = BigDecimal.valueOf(0);
            }


            System.out.println("---------------------------------------零部件子表数据修改完毕--------------------------------");

//            BigDecimal FreezeQuantity_AAA = FreezeQuantity.subtract( new BigDecimal( map1.get("numberField_ma0e13js").toString()));//冻结数量（新） = 冻结数量 - 退货数量
            //TODO:3、调出物料的可用库存
            BigDecimal AvailableQuantity_AAA = AvailableInventoryQuantity_AAA.subtract(new BigDecimal( map1.get("numberField_m9grj2ij").toString()));//可用存库数量（新） = 可用库存数量 - 调拨数量
            BigDecimal Quantity_AAA = InventoryQuantity_AAA.subtract(new BigDecimal(map1.get("numberField_m9grj2ij").toString()));//存库数量（新） = 存库数量 - 调拨数量
            //TODO：4、调入物料的可用库存
            BigDecimal AvailableQuantity_BBB = AvailableInventoryQuantity_BBB.add(new BigDecimal( map1.get("numberField_m9grj2ij").toString()));//可用存库数量（新） = 可用库存数量 + 调拨数量
            BigDecimal Quantity_BBB = InventoryQuantity_BBB.add(new BigDecimal(map1.get("numberField_m9grj2ij").toString()));
            ydClient.operateData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("numberField_m8gz97nk, numberField_m8obn6wk",AvailableQuantity_AAA,Quantity_AAA)))
                    .userId("332051151139376769")
                    .build(),YDConf.FORM_OPERATION.update);

            ydClient.operateData(YDParam.builder().formInstId(LBJId2)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("numberField_m8gz97nk, numberField_m8obn6wk",AvailableQuantity_BBB,Quantity_BBB)))
                    .userId("332051151139376769")
                    .build(),YDConf.FORM_OPERATION.update);
            System.out.println("----------------------零部件主表数据修改完毕！------------------");

        }
        return McR.success();
    }

    @Override
    public McR goodsInandOut(Map map) {
        String formInstId = UtilMap.getString(map,"formInstId");//实例id(进货退货流程)
        log.info("进货退货流程实例id："+formInstId);
        Map data = ydClient.queryData(YDParam.builder().formInstId(formInstId)
                .formUuid("FORM-0D92610ED4AA4B81988CA190EE9A119EX37F")
                .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                .userId("332051151139376769").build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
        System.out.println("进货退货流程："+data);
        List<Map> mapList = (List<Map>)data.get("tableField_ml07z7bh");
        System.out.println("退货单明细数据："+mapList);
        ArrayList<Object> entries = new ArrayList<>();
        for (Map map1 : mapList){
            String LBJId = map1.get("textField_ml09d5ys").toString();//零部件的实例id
            System.out.println("物料名称："+map1.get("textField_ml07z7bi").toString());//物料名称
            System.out.println("所属库位："+map1.get("textField_ml09riy7").toString());//产品库位
            System.out.println("退货数量："+map1.get("numberField_ml07z7bp").toString());//退货数量


            Map data1 = ydClient.queryData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .userId("332051151139376769").build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
            System.out.println(map1.get("textField_ml07z7bi")+"明细表数据："+data1.get("tableField_m96gje14"));//零部件明细
            String s = data1.get("tableField_m96gje14").toString();
            String warehouse = JSON.parseArray(s).getJSONObject(0).get("selectField_m88f1qi8").toString();//所属仓库
            String WarehouseLocation = JSON.parseArray(s).getJSONObject(0).get("textField_m8mnxgql").toString();//所属库位
            String SafetyValue = JSON.parseArray(s).getJSONObject(0).get("numberField_m8873fn4").toString();//安全库存值
            BigDecimal numberFieldM9c8n9go = new BigDecimal(JSON.parseArray(s).getJSONObject(0).get("numberField_m9c8n9go").toString());//仓库数量

//             new BigDecimal(map1.get("numberField_ma0e13js").toString()).add(numberFieldM9c8n9go);
            BigDecimal numm = numberFieldM9c8n9go.subtract(new BigDecimal(map1.get("numberField_ml07z7bp").toString()));//退货后的库存数量 =   仓库数量（子） - 退货数量

            ArrayList<Map<String,String>> maps_YD = new ArrayList<>();
            Map sss=new HashMap<>();
            sss.put("selectField_m88f1qi8",warehouse);//所属仓库
            sss.put("textField_m8mnxgql",WarehouseLocation);//所属库位
            sss.put("numberField_m8873fn4",SafetyValue);//安全库存值
            sss.put("numberField_m9c8n9go",numm);//仓库数量
            maps_YD.add(sss);

            ydClient.operateData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("tableField_m96gje14",maps_YD)))
                    .userId("332051151139376769").build(),YDConf.FORM_OPERATION.update);

            BigDecimal InventoryQuantity = null;
            if(!data1.get("numberField_m8gz97nk_value").toString().isEmpty()){
                InventoryQuantity = new BigDecimal( data1.get("numberField_m8gz97nk").toString());//可用库存数量
            }else {
                InventoryQuantity = BigDecimal.valueOf(0);
            }

            BigDecimal VirtualQuantity1 = null;
            if(!data1.get("numberField_m8obn6wq_value").toString().isEmpty()){
                VirtualQuantity1 = new BigDecimal( data1.get("numberField_m8obn6wq").toString());//虚拟数量
            }else {
                VirtualQuantity1 = BigDecimal.valueOf(0);
            }
            System.out.println("---------------------------------------零部件子表数据修改完毕--------------------------------");

            BigDecimal VirtualQuantity1_AAA = VirtualQuantity1.subtract( new BigDecimal( map1.get("numberField_ml07z7bp").toString()));//虚拟数量（新） = 虚拟数量 - 退货数量
            BigDecimal AvailableQuantity_AAA = InventoryQuantity.subtract(new BigDecimal( map1.get("numberField_ml07z7bp").toString()));//可用存库数量（新） = 可用库存数量 - 退货数量
            ydClient.operateData(YDParam.builder().formInstId(LBJId)
                    .formUuid("FORM-2353BE632D97434DAD55AEBD0866C44DVAT5")
                    .appType("APP_GNQ1RGK68X4JNZUEU8RQ")
                    .systemToken("XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5")
                    .updateFormDataJson(JSONObject.toJSONString(UtilMap.map("numberField_m8obn6wq, numberField_m8gz97nk",VirtualQuantity1_AAA,AvailableQuantity_AAA)))
                    .userId("332051151139376769")
                    .build(),YDConf.FORM_OPERATION.update);
            System.out.println("----------------------零部件主表数据修改完毕！------------------");

        }
        return McR.success();

    }

    // 表单及认证常量
    private static final String FINANCE_FORM_UUID = "FORM-05EDB5C275A448EBBE3A1F2578B2C73CPGSL";
    private static final String INVOICING_FORM_UUID = "FORM-A36B38B28F684590A9C60DA07EF446DD6QXP";
    private static final String RECEIVE_FORM_UUID = "FORM-27421C0D0ACA41DFB85D05A9878161B1SDCE";
    private static final String QUERY_APP_TYPE = "APP_GNQ1RGK68X4JNZUEU8RQ";
    private static final String QUERY_SYSTEM_TOKEN = "XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5";
    private static final String QUERY_USER_ID = "332051151139376769";
    private static final String UPDATE_APP_TYPE = "APP_GNQ1RGK68X4JNZUEU8RQ";
    private static final String UPDATE_SYSTEM_TOKEN = "XH866P81QDOTQ0218TGZM9WCNXOF24WIP488M7A5";
    private static final int ERROR_CODE = 500;  // 通用错误码


    @Override
    public McR Invoicing(Map map) {
        String formInstId = UtilMap.getString(map, "formInstId");
        log.info("开票流程实例ID: {}", formInstId);
        try {
            // 1. 查询开票主表及子表
            YDParam queryMainParam = YDParam.builder()
                    .formInstId(formInstId)
                    .formUuid(INVOICING_FORM_UUID)
                    .appType(QUERY_APP_TYPE)
                    .systemToken(QUERY_SYSTEM_TOKEN)
                    .userId(QUERY_USER_ID)
                    .build();
            Map mainData = ydClient.queryData(queryMainParam, YDConf.FORM_QUERY.retrieve_id).getFormData();
            if (mainData == null || mainData.isEmpty()) {
                log.error("查询开票主表返回空数据，实例ID: {}", formInstId);
                return McR.error(String.valueOf(ERROR_CODE), "未查询到开票主表数据，请检查实例ID");
            }
            List<Map> subList = (List<Map>) mainData.get("tableField_m8wqi75l");
            if (subList == null || subList.isEmpty()) {
                log.warn("开票子表无数据，实例ID: {}", formInstId);
                return McR.success("子表无明细，无需处理");
            }

            // 2. 分页查询全部财务数据（每条记录含 formData 嵌套）
            List<Map> financeList = new ArrayList<>();
            YDParam queryFinanceParam = YDParam.builder()
                    .formUuid(FINANCE_FORM_UUID)
                    .appType(QUERY_APP_TYPE)
                    .systemToken(QUERY_SYSTEM_TOKEN)
                    .userId(QUERY_USER_ID)
                    .build();
            queryFinanceParam.setPageSize(1);
            long totalCount = ydClient.queryData(queryFinanceParam, YDConf.FORM_QUERY.retrieve_search_form).getTotalCount();
            if (totalCount > 0) {
                int pageSize = 100;
                int totalPages = (int) Math.ceil((double) totalCount / pageSize);
                for (int page = 1; page <= totalPages; page++) {
                    queryFinanceParam.setCurrentPage(page);
                    queryFinanceParam.setPageSize(pageSize);
                    List<Map> pageData = (List<Map>) ydClient.queryData(queryFinanceParam, YDConf.FORM_QUERY.retrieve_search_form).getData();
                    if (pageData != null && !pageData.isEmpty()) {
                        financeList.addAll(pageData);
                    }
                }
            }
            log.info("财务数据总条数: {}", financeList.size());

            // 3. 遍历子表，匹配并更新
            for (Map subItem : subList) {
                String productCode = UtilMap.getString(subItem, "textField_m8wqi75n");
                Double saleQtyObj = getDouble(subItem.get("numberField_m8wqi75o"));
                Double salePriceObj = getDouble(subItem.get("numberField_mqgczkw0")); // 折扣后成本（元）作为销售单价
                String month = UtilMap.getString(subItem, "textField_mfkfg5u5");
                if (StringUtils.isBlank(productCode) || saleQtyObj == null || StringUtils.isBlank(month)) {
                    log.warn("子表明细缺少必要字段，跳过: {}", subItem);
                    continue;
                }
                double saleQty = saleQtyObj;
                Double salePrice = (salePriceObj != null) ? salePriceObj : 0.0; // 若单价为空，用0.0
                String trimmedProductCode = productCode.trim();

                // ---- 在财务列表中匹配 ----
                Map matchedRecord = null;      // 整个记录（外层）
                Map matchedFormData = null;    // 内层 formData
                String matchedStatMonth = null;

                // 优先级1：物料编码相同且统计时间等于当前月份 → 累加
                for (Map record : financeList) {
                    Map formData = (Map) record.get("formData");
                    if (formData == null) {
                        continue;
                    }
                    String code = UtilMap.getString(formData, "textField_miy91ty1");
                    String statMonth = UtilMap.getString(formData, "textField_ml0pe9ut");
                    if (code == null) continue;
                    String trimmedCode = code.trim();
                    if (trimmedProductCode.equals(trimmedCode) && month.equals(statMonth)) {
                        matchedRecord = record;
                        matchedFormData = formData;
                        matchedStatMonth = statMonth;
                        break;
                    }
                }

                // 优先级2：物料编码相同且统计时间不等于当前月份（含空） → 首次覆盖
                if (matchedRecord == null) {
                    for (Map record : financeList) {
                        Map formData = (Map) record.get("formData");
                        if (formData == null) {
                            continue;
                        }
                        String code = UtilMap.getString(formData, "textField_miy91ty1");
                        String statMonth = UtilMap.getString(formData, "textField_ml0pe9ut");
                        if (code == null) continue;
                        String trimmedCode = code.trim();
                        if (trimmedProductCode.equals(trimmedCode) && !month.equals(statMonth)) {
                            matchedRecord = record;
                            matchedFormData = formData;
                            matchedStatMonth = statMonth;
                            log.info("找到物料编码相同但月份不同的财务记录，物料: {}, 财务统计时间: {}, 当前月份: {}, 视为首次操作",
                                    trimmedProductCode, statMonth, month);
                            break;
                        }
                    }
                }

                if (matchedRecord == null) {
                    log.warn("未找到物料编码为 {} 的任何财务记录，无法更新", trimmedProductCode);
                    continue;
                }

                // 获取财务记录字段（从 formData 中取）
                String financeInstId = UtilMap.getString(matchedRecord, "formInstanceId");
                if (StringUtils.isBlank(financeInstId)) {
                    log.error("财务记录缺少formInstanceId，跳过更新: {}", matchedRecord);
                    continue;
                }
                double currentSale = getDouble(matchedFormData.get("numberField_mizd11a3"));
                double currentPurchase = getDouble(matchedFormData.get("numberField_mizd11a5"));
                double currentBegin = getDouble(matchedFormData.get("numberField_mizd11a2"));

                // 判断是否为首次
                boolean isFirst = !month.equals(matchedStatMonth);

                double newSale;
                if (isFirst) {
                    newSale = saleQty;
                } else {
                    newSale = currentSale + saleQty;
                }
                double newEnd = currentBegin + currentPurchase - newSale;

                // 构建更新数据（直接更新表单字段）
                Map<String, Object> updateData = new HashMap<>();
                updateData.put("numberField_mizd11a3", newSale);          // 本期销售
                updateData.put("numberField_mizd11a4", newEnd);           // 期末数量
                updateData.put("numberField_mqhqmysl", salePrice);        // 本期销售单价（始终用最新子表单价）
                if (isFirst) {
                    updateData.put("textField_ml0pe9ut", month);          // 统计时间
                }

                String updateJson = JSONObject.toJSONString(updateData);
                YDParam updateParam = YDParam.builder()
                        .appType(UPDATE_APP_TYPE)
                        .systemToken(UPDATE_SYSTEM_TOKEN)
                        .formInstanceId(financeInstId)
                        .updateFormDataJson(updateJson)
                        .build();
                ydClient.operateData(updateParam, YDConf.FORM_OPERATION.update);
                log.info("开票更新财务记录成功，实例ID: {}, 首次: {}, 新销售: {}, 新单价: {}, 新期末: {}, 月份更新为: {}",
                        financeInstId, isFirst, newSale, salePrice, newEnd, isFirst ? month : matchedStatMonth);
            }
            return McR.success("开票处理完成");
        } catch (Exception e) {
            log.error("开票处理异常", e);
            return McR.error(String.valueOf(ERROR_CODE), "开票处理失败：" + e.getMessage());
        }
    }

    @Override
    public McR receiveInvoice(Map map) {
        String formInstId = UtilMap.getString(map, "formInstId");
        log.info("收票流程实例ID: {}", formInstId);
        try {
            // 1. 查询收票主表及子表
            YDParam queryMainParam = YDParam.builder()
                    .formInstId(formInstId)
                    .formUuid(RECEIVE_FORM_UUID)
                    .appType(QUERY_APP_TYPE)
                    .systemToken(QUERY_SYSTEM_TOKEN)
                    .userId(QUERY_USER_ID)
                    .build();
            Map mainData = ydClient.queryData(queryMainParam, YDConf.FORM_QUERY.retrieve_id).getFormData();
            if (mainData == null || mainData.isEmpty()) {
                log.error("查询收票主表返回空数据，实例ID: {}", formInstId);
                return McR.error(String.valueOf(ERROR_CODE), "未查询到收票主表数据，请检查实例ID");
            }
            List<Map> subList = (List<Map>) mainData.get("tableField_m8wtvnvs");
            if (subList == null || subList.isEmpty()) {
                log.warn("收票子表无数据，实例ID: {}", formInstId);
                return McR.success("子表无明细，无需处理");
            }

            // 2. 分页查询全部财务数据
            List<Map> financeList = new ArrayList<>();
            YDParam queryFinanceParam = YDParam.builder()
                    .formUuid(FINANCE_FORM_UUID)
                    .appType(QUERY_APP_TYPE)
                    .systemToken(QUERY_SYSTEM_TOKEN)
                    .userId(QUERY_USER_ID)
                    .build();
            queryFinanceParam.setPageSize(1);
            long totalCount = ydClient.queryData(queryFinanceParam, YDConf.FORM_QUERY.retrieve_search_form).getTotalCount();
            if (totalCount > 0) {
                int pageSize = 100;
                int totalPages = (int) Math.ceil((double) totalCount / pageSize);
                for (int page = 1; page <= totalPages; page++) {
                    queryFinanceParam.setCurrentPage(page);
                    queryFinanceParam.setPageSize(pageSize);
                    List<Map> pageData = (List<Map>) ydClient.queryData(queryFinanceParam, YDConf.FORM_QUERY.retrieve_search_form).getData();
                    if (pageData != null && !pageData.isEmpty()) {
                        financeList.addAll(pageData);
                    }
                }
            }
            log.info("财务数据总条数: {}", financeList.size());

            // 3. 遍历子表，匹配并更新
            for (Map subItem : subList) {
                String productCode = UtilMap.getString(subItem, "textField_mfdo4a28");
                Double purchaseQtyObj = getDouble(subItem.get("numberField_m8wtyd58"));
                Double purchasePriceObj = getDouble(subItem.get("numberField_mqgd5wvl")); // 折扣后成本（元）作为购入单价
                String month = UtilMap.getString(subItem, "textField_mfkfi8ov");
                if (StringUtils.isBlank(productCode) || purchaseQtyObj == null || StringUtils.isBlank(month)) {
                    log.warn("子表明细缺少必要字段，跳过: {}", subItem);
                    continue;
                }
                double purchaseQty = purchaseQtyObj;
                Double purchasePrice = (purchasePriceObj != null) ? purchasePriceObj : 0.0;
                String trimmedProductCode = productCode.trim();

                // ---- 在财务列表中匹配 ----
                Map matchedRecord = null;
                Map matchedFormData = null;
                String matchedStatMonth = null;

                // 优先级1：物料编码相同且统计时间等于当前月份 → 累加
                for (Map record : financeList) {
                    Map formData = (Map) record.get("formData");
                    if (formData == null) continue;
                    String code = UtilMap.getString(formData, "textField_miy91ty1");
                    String statMonth = UtilMap.getString(formData, "textField_ml0pe9ut");
                    if (code == null) continue;
                    String trimmedCode = code.trim();
                    if (trimmedProductCode.equals(trimmedCode) && month.equals(statMonth)) {
                        matchedRecord = record;
                        matchedFormData = formData;
                        matchedStatMonth = statMonth;
                        break;
                    }
                }

                // 优先级2：物料编码相同且统计时间不等于当前月份（含空） → 首次覆盖
                if (matchedRecord == null) {
                    for (Map record : financeList) {
                        Map formData = (Map) record.get("formData");
                        if (formData == null) continue;
                        String code = UtilMap.getString(formData, "textField_miy91ty1");
                        String statMonth = UtilMap.getString(formData, "textField_ml0pe9ut");
                        if (code == null) continue;
                        String trimmedCode = code.trim();
                        if (trimmedProductCode.equals(trimmedCode) && !month.equals(statMonth)) {
                            matchedRecord = record;
                            matchedFormData = formData;
                            matchedStatMonth = statMonth;
                            log.info("找到物料编码相同但月份不同的财务记录，物料: {}, 财务统计时间: {}, 当前月份: {}, 视为首次操作",
                                    trimmedProductCode, statMonth, month);
                            break;
                        }
                    }
                }

                if (matchedRecord == null) {
                    log.warn("未找到物料编码为 {} 的任何财务记录，无法更新", trimmedProductCode);
                    continue;
                }

                String financeInstId = UtilMap.getString(matchedRecord, "formInstanceId");
                if (StringUtils.isBlank(financeInstId)) {
                    log.error("财务记录缺少formInstanceId，跳过更新: {}", matchedRecord);
                    continue;
                }
                double currentSale = getDouble(matchedFormData.get("numberField_mizd11a3"));
                double currentPurchase = getDouble(matchedFormData.get("numberField_mizd11a5"));
                double currentBegin = getDouble(matchedFormData.get("numberField_mizd11a2"));

                boolean isFirst = !month.equals(matchedStatMonth);

                double newPurchase;
                if (isFirst) {
                    newPurchase = purchaseQty;
                } else {
                    newPurchase = currentPurchase + purchaseQty;
                }
                double newEnd = currentBegin + newPurchase - currentSale;

                Map<String, Object> updateData = new HashMap<>();
                updateData.put("numberField_mizd11a5", newPurchase);    // 本期购入
                updateData.put("numberField_mizd11a4", newEnd);         // 期末数量
                updateData.put("numberField_mqhqmysm", purchasePrice);  // 本期购入单价（始终用最新子表单价）
                if (isFirst) {
                    updateData.put("textField_ml0pe9ut", month);        // 统计时间
                }

                String updateJson = JSONObject.toJSONString(updateData);
                YDParam updateParam = YDParam.builder()
                        .appType(UPDATE_APP_TYPE)
                        .systemToken(UPDATE_SYSTEM_TOKEN)
                        .formInstanceId(financeInstId)
                        .updateFormDataJson(updateJson)
                        .build();
                ydClient.operateData(updateParam, YDConf.FORM_OPERATION.update);
                log.info("收票更新财务记录成功，实例ID: {}, 首次: {}, 新购入: {}, 新单价: {}, 新期末: {}, 月份更新为: {}",
                        financeInstId, isFirst, newPurchase, purchasePrice, newEnd, isFirst ? month : matchedStatMonth);
            }
            return McR.success("收票处理完成");
        } catch (Exception e) {
            log.error("收票处理异常", e);
            return McR.error(String.valueOf(ERROR_CODE), "收票处理失败：" + e.getMessage());
        }
    }

    /**
     * 安全转换 Object 为 Double，null 或无效值返回 null
     */
    private Double getDouble(Object value) {
        if (value == null) return null;
        if (value instanceof Number) {
            return ((Number) value).doubleValue();
        }
        try {
            return Double.parseDouble(value.toString());
        } catch (NumberFormatException e) {
            return null;
        }
    }

    @Override
    public McR shareRecord(Map data) {
        String pid = getString(data.get("pid"));
        if (Strings.isNotBlank(pid)){
            //发起审批
            String[] dd = McProject.getDd(pid);
            String appKey = "";
            String appSecret = "";
            String agentId = "";
            if (!PublicUtil.isNull(pid) && dd != null && dd.length >= 3) {
                appKey = dd[0];
                appSecret = dd[1];
                agentId = dd[2];
            }
            String[] yida = McProject.getYida(pid);
            String appType = "";
            String systemToken = "";
            if (!PublicUtil.isNull(pid) && dd != null && dd.length >= 2) {
                appType = yida[0];
                systemToken = yida[1];
            }

            // 执行分享逻辑 [ 拼接后的权限组 ]
            McException.assertParamException_Null(data, "compId, userIds, userId, atUserId, isNotice");
            //开始抓取宜搭对应的子表数据
            String processInstanceId = data.get("processInstanceId").toString();
            List<String> atUserId = (List<String>) data.get("atUserId");

            Map map = new HashMap();
            map.put(UtilMap.getString(data, "compId"),UtilMap.getList(data, "userIds"));

            ydClient.operateData(YDParam.builder()
                    .appType(appType)
                    .systemToken(systemToken)
                    .formInstId(processInstanceId)
                    .updateFormDataJson(JSON.toJSONString(map))
                    .build(), YDConf.FORM_OPERATION.update);

            String userIds = String.valueOf(data.get("atUserId"));
            String[] split = userIds.split(",");
            ArrayList<String> names = new ArrayList<>();
            for(Object auserId : split){
                DDR_New ddrNew = (DDR_New) UtilHttp.doPost("https://oapi.dingtalk.com/topapi/v2/user/get", null, ddClient.initTokenParams(), UtilMap.map("userid", auserId), DDR_New.class);
                Object result = ddrNew.getResult();
                if (result != null) {
                    JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(result));
                    String name = jsonObject.getString("name");
                    names.add(name);
                }
            }
            List<Map> searchCondition = new ArrayList<>();
            searchCondition.addAll(Arrays.asList(
                    YDConf.searchCondition_TextFiled(data.get("processKey").toString(), data.get("processInstanceId").toString(),"eq")
            ));
            String title = UtilMap.getString(data, "content").isEmpty() || !ObjectUtil.isNotNull(UtilMap.getString(data, "content")) ? "单据分享" : UtilMap.getString(data, "content");
            ydClient.operateData(YDParam.builder()
                    .appType(appType)
                    .systemToken(systemToken)
                    .searchCondition(JSON.toJSONString(searchCondition))
                    .formUuid(data.get("formId").toString())
                    .formDataJson(JSON.toJSONString(UtilMap.map(data.get("processKey").toString()+", "+data.get("empKey").toString()+", "+data.get("titleKey").toString(),
                            data.get("processInstanceId").toString(),UtilMap.getList(data, "userIds"),title)))
                    .useLatestVersion(true)
                    .build(), YDConf.FORM_OPERATION.upsert);//upsert_v2
            if (UtilMap.getBoolean(data, "isNotice")) {
//                data.put("content", names.stream().collect(Collectors.joining(",")) + UtilMap.getString(data, "content"));
                String appUrl = data.get("appUrl").toString();
                String pcUrl = data.get("pcUrl").toString();
                if ( !ObjectUtil.isNotNull(UtilMap.getString(data,"sendType")) || UtilMap.getString(data,"sendType").isEmpty() || "工作通知".equals(UtilMap.getString(data,"sendType"))){
                    Map<String, String> contentMap = new HashMap<>();
                    contentMap.put("title",title);
                    contentMap.put("text",title);
                    contentMap.put("picUrl",pcUrl+"/processDetail"+"?procInsId="+processInstanceId);
                    contentMap.put("messageUrl",pcUrl+"/processDetail"+"?procInsId="+processInstanceId);

                    Map<String, Object> msg = new HashMap<>();
                    msg.put("msgtype","link");
                    msg.put("link",contentMap);
                    sendNotification(ddClient.getAccessToken(appKey,appSecret),atUserId,null,false,msg,agentId);

                } else if ("钉钉代办".equals(UtilMap.getString(data, "sendType"))) {
                    /*查询钉钉人员*/
                    ddClientWorkflow.createTBTask(ddClient.getAccessToken(appKey,appSecret),UtilMap.getString(data, "userId"),"流程分享："+UtilMap.getString(data, "content"),UtilMap.getString(data, "content"),
                            UtilDateTime.getLocalDateTimeTimeStamp(LocalDate.now().plusDays(7).atTime(LocalTime.MAX)), atUserId,null
                            ,UtilMap.map("appUrl, pcUrl",appUrl+"/processDetail"+"?procInsId="+processInstanceId,pcUrl+"/processDetail"+"?procInsId="+processInstanceId),false,30,UtilMap.map("dingNotify","1"));
                }
            }
            return McR.success();
        }
        return McR.errorParam("参数缺失！");
    }

    @Override
    public McR approveTask(Map map) {
        String outResult = UtilMap.getString(map, "outResult");
        String userId = UtilMap.getString(map, "userId");

        String processInstanceId = UtilMap.getString(map, "processInstanceId");
        String activityId = UtilMap.getString(map, "activityId");
        long taskId = 0;

        //获取审批记录
        List<Map> result = (List<Map>) ydClient.queryData(YDParam.builder()
                .processInstanceId(processInstanceId)
                .build(),YDConf.FORM_QUERY.retrieve_approval_record).getResult();
        for (Map approveInfo : result) {
            if (activityId.equals(UtilMap.getString(approveInfo, "activityId"))){
                //获取taskId
                taskId = UtilMap.getLong(approveInfo, "taskId");
                break;
            }
        }

        //审批
        Map body = new HashMap();
        body.put("outResult",outResult);//AGREE：同意 DISAGREE：拒绝。
        body.put("appType",ydConf.getAppType());
        body.put("systemToken",ydConf.getSystemToken());
        body.put("remark",outResult);//审批意见
        body.put("processInstanceId",processInstanceId);//审批实例id
        body.put("userId",userId);//用户userid
        body.put("taskId",taskId);//任务id

        UtilHttp.doPost("https://api.dingtalk.com/v1.0/yida/tasks/execute", ddClient.initTokenHeader(), null,body);

        return McR.success();
    }

    @Override
    public McR syncYdAuth(Map map) {
        String matrixId = UtilMap.getString(map, "matrixId");//矩阵id
        String corpId = UtilMap.getString(map, "corpId");//corpId
        String userId = UtilMap.getString(map, "userId");//userId
        String corpToken = UtilMap.getString(map, "corpToken");//corpToken
        String formInstId = UtilMap.getString(map, "formInstId");//实例id
        String[] conditionColumns = UtilMap.getString(map, "conditionColumns").split(",");//矩阵表条件列（名称）
        String[] conditionColumnValues = UtilMap.getString(map, "conditionColumnValues").split(",");;//矩阵表条件列值
        String[] resultColumns = UtilMap.getString(map, "resultColumns").split(",");;//矩阵表角色列（名称）
        String[] resultColumnFields = UtilMap.getString(map, "resultColumnFields").split(",");;//矩阵表角色列值（表单成员组件唯一标识）

        String[] conditionColumnIds = new String[conditionColumns.length];//矩阵表条件列（id）
        String[] resultColumnIds = new String[resultColumns.length];//矩阵表角色列（id）
        List<List<String>> resultColumnValues = new ArrayList<>();//矩阵表角色列值

        //md5加密corpId,userId,corpToken
        String token = DigestUtils.md5Hex(corpId + userId + corpToken).toUpperCase();

        //查询矩阵明细
        Map params = new HashMap();

        int pageSize = 100;
        int pageNumber = 0;

        params.put("pageSize",pageSize);
        params.put("matrixId",matrixId);
        params.put("corpId",corpId);
        params.put("userId",userId);
        params.put("token",token);

        List<Map> data = new ArrayList<>();

        String rowId = "";

        int totalCount = 0;

        //查询矩阵所有明细
        do {
            pageNumber++;
            params.put("pageNumber",pageNumber);
            DDR_New ddrNew = (DDR_New) UtilHttp.doGet("https://api.dingtalk.com/v2.0/yida/forms/resources/matrices", ddClient.initTokenHeader(), params, DDR_New.class);

            Map result = (Map) ddrNew.getResult();

            Map matrixData = UtilMap.getMap(result, "matrixData");

            data.addAll(UtilMap.getList(matrixData, "data"));

            totalCount = UtilMap.getInt(matrixData, "totalCount");

            //查询列id
            if (pageNumber == 1){
                Map matrixTable = UtilMap.getMap(result, "matrixTable");

                List<Map> conditionColumnList = UtilMap.getList(matrixTable, "conditionColumn");
                List<Map> resultColumnList = UtilMap.getList(matrixTable, "resultColumn");

                for (int i = 0; i < conditionColumns.length; i++) {
                    int finalI = i;
                    Map conditionColumn = conditionColumnList.stream().filter(item -> UtilMap.getString(item, "name").equals(conditionColumns[finalI])).findFirst().orElse(null);
                    conditionColumnIds[i] = UtilMap.getString(conditionColumn, "columnId");
                }

                for (int i = 0; i < resultColumns.length; i++) {
                    int finalI = i;
                    Map resultColumn = resultColumnList.stream().filter(item -> UtilMap.getString(item, "name").equals(resultColumns[finalI])).findFirst().orElse(null);
                    resultColumnIds[i] = UtilMap.getString(resultColumn, "columnId");
                }
            }
        }while (pageNumber * pageSize < totalCount);

        //查询实例详情获取矩阵表角色列值
        Map formData = ydClient.queryData(YDParam.builder().formInstId(formInstId).build(), YDConf.FORM_QUERY.retrieve_id).getFormData();

        for (int i = 0; i < resultColumnFields.length; i++) {
            List<String> employees = UtilMap.getList(formData, resultColumnFields[i] + "_id");

            resultColumnValues.add(employees);
        }

        boolean flag = false;
        //查询该矩阵条件是否存在
        for (Map datum : data) {
            for (int i = 0; i < conditionColumnIds.length; i++) {
                if (conditionColumnValues[i].equals(UtilMap.getString(datum, conditionColumnIds[i]))){
                    flag = true;
                }else {
                    flag = false;
                }
            }

            if (flag){
                rowId = UtilMap.getString(datum, "rowId");
                break;
            }
        }

        //更新矩阵明细
        Map matrixData = new HashMap();
        if (Strings.isBlank(rowId)){
            matrixData.put("isNew",1);//新增
        }else {
            matrixData.put("rowId",rowId);//更新
        }
        for (int i = 0; i < conditionColumnIds.length; i++) {
            matrixData.put(conditionColumnIds[i],conditionColumnValues[i]);
        }
        for (int i = 0; i < resultColumnIds.length; i++) {
            matrixData.put(resultColumnIds[i],resultColumnValues.get(i));
        }

        Map body = params;
        body.put("dataJson",JSONObject.toJSONString(Arrays.asList(matrixData)));

        UtilHttp.doPost("https://api.dingtalk.com/v2.0/yida/forms/resources/matrices/upsert", ddClient.initTokenHeader(), null,body, DDR_New.class);

        return McR.success();
    }

    @Override
    public McR delYdAuth(Map map) {
        String matrixId = UtilMap.getString(map, "matrixId");//矩阵id
        String corpId = UtilMap.getString(map, "corpId");//corpId
        String userId = UtilMap.getString(map, "userId");//userId
        String corpToken = UtilMap.getString(map, "corpToken");//corpToken
        String[] conditionColumns = UtilMap.getString(map, "conditionColumns").split(",");//矩阵表条件列（名称）
        String[] conditionColumnValues = UtilMap.getString(map, "conditionColumnValues").split(",");;//矩阵表条件列值

        String[] conditionColumnIds = new String[conditionColumns.length];//矩阵表条件列（id）

        //md5加密corpId,userId,corpToken
        String token = DigestUtils.md5Hex(corpId + userId + corpToken).toUpperCase();

        //查询矩阵明细
        Map params = new HashMap();

        int pageSize = 100;
        int pageNumber = 0;

        params.put("pageSize",pageSize);
        params.put("matrixId",matrixId);
        params.put("corpId",corpId);
        params.put("userId",userId);
        params.put("token",token);

        List<Map> data = new ArrayList<>();

        String rowId = "";

        int totalCount = 0;

        //查询矩阵所有明细
        do {
            pageNumber++;
            params.put("pageNumber",pageNumber);
            DDR_New ddrNew = (DDR_New) UtilHttp.doGet("https://api.dingtalk.com/v2.0/yida/forms/resources/matrices", ddClient.initTokenHeader(), params, DDR_New.class);

            Map result = (Map) ddrNew.getResult();

            Map matrixData = UtilMap.getMap(result, "matrixData");

            data.addAll(UtilMap.getList(matrixData, "data"));

            totalCount = UtilMap.getInt(matrixData, "totalCount");

            //查询列id
            if (pageNumber == 1){
                Map matrixTable = UtilMap.getMap(result, "matrixTable");

                List<Map> conditionColumnList = UtilMap.getList(matrixTable, "conditionColumn");

                for (int i = 0; i < conditionColumns.length; i++) {
                    int finalI = i;
                    Map conditionColumn = conditionColumnList.stream().filter(item -> UtilMap.getString(item, "name").equals(conditionColumns[finalI])).findFirst().orElse(null);
                    conditionColumnIds[i] = UtilMap.getString(conditionColumn, "columnId");
                }
            }
        }while (pageNumber * pageSize < totalCount);

        boolean flag = false;
        //查询该矩阵条件是否存在
        for (Map datum : data) {
            for (int i = 0; i < conditionColumnIds.length; i++) {
                if (conditionColumnValues[i].equals(UtilMap.getString(datum, conditionColumnIds[i]))){
                    flag = true;
                }else {
                    flag = false;
                }
            }

            if (flag){
                rowId = UtilMap.getString(datum, "rowId");
                break;
            }
        }

        //删除矩阵明细
        if (Strings.isBlank(rowId)){
            return McR.errorUnknown("该矩阵条件不存在");
        }else {
            Map body = params;
            body.put("rowIds",rowId);

            UtilHttp.doPost("https://api.dingtalk.com/v2.0/yida/forms/resources/matrices/remove", ddClient.initTokenHeader(), null,body, DDR_New.class);
        }

        return McR.success();
    }

    @Override
    public void getCheckInData(JSONObject eventJson) {
        MDC.put("MDC_KEY_PID","1000");

        String baseId = "YMyQA2dXW7LkEz9LcDgZZDzPVzlwrZgb";//AI表格ID
        String sheetIdOrName = "签到数据";//数据表ID或数据表名称

        int retryCount = 0;
        int maxRetries = 5;

        long timeStamp = roundToNearestThousand(Long.parseLong(eventJson.getString("timeStamp")));//签到时间戳
        String staffId = eventJson.getString("StaffId");//签到人userId
        String eventId = eventJson.getString("eventId");//签到事件id

        while (retryCount <= maxRetries) {
            try {
                //获取签到数据
                Map body = new HashMap();
                body.put("cursor",0);
                body.put("size",100);
                body.put("start_time",timeStamp);
                body.put("end_time",timeStamp);
                body.put("userid_list",staffId);

                //查询用户详情
                DDR_New ddrNew1 = (DDR_New) UtilHttp.doPost("https://oapi.dingtalk.com/topapi/v2/user/get", null, ddClient.initTokenParams(), UtilMap.map("userid", staffId), DDR_New.class);
                Map result1 = (Map) ddrNew1.getResult();
                String userName = UtilMap.getString(result1, "name");
                String unionid = UtilMap.getString(result1, "unionid");

                //查询用户考勤数据
                DDR_New ddrNew = (DDR_New) UtilHttp.doPost("https://oapi.dingtalk.com/topapi/checkin/record/get", null, ddClient.initTokenParams(), body, DDR_New.class);
                Map result = (Map) ddrNew.getResult();
                List list = UtilMap.getList(result, "page_list");

                if (!list.isEmpty()){
                    Map fields = new HashMap();
                    Map checkInData = (Map) list.get(0);
                    Long checkinTime = UtilMap.getLong(checkInData, "checkin_time");
                    String detailPlace = UtilMap.getString(checkInData, "detail_place");
                    String remark = UtilMap.getString(checkInData,"remark");
                    Map user = new HashMap();
                    user.put("unionId",unionid);
                    fields.put("9XFXz5d",Arrays.asList(user));//签到人
                    fields.put("mKUEya0",checkinTime);//签到时间
                    fields.put("mHe1U1b",detailPlace);//签到地点
                    fields.put("CngGPET",remark);//备注

                    Map records = new HashMap();

                    Map fieldsMap = new HashMap();
                    fieldsMap.put("fields",fields);

                    records.put("records",Arrays.asList(fieldsMap));

                    Map param = new HashMap();
                    param.put("operatorId",unionid);

                    UtilHttp.doPost("https://api.dingtalk.com/v1.0/notable/bases/"+baseId+"/sheets/"+sheetIdOrName+"/records",ddClient.initTokenHeader(),param,records);
                }
                break;
            } catch (Exception e) {
                if (retryCount < maxRetries){
                    retryCount++;
                    log.info("eventId：{}，第{}次重试，异常信息：{}",eventId, retryCount, e.getMessage());
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();// 如果线程在等待期间被中断，恢复中断状态
                        throw new RuntimeException("Request interrupted", ie);// 抛出运行时异常，终止重试
                    }
                    continue;
                }
                throw new RuntimeException("eventId：" + eventId + "，超出最大重试次数，异常信息：" + e.getMessage());
            }
        }
    }

    public String sendNotification(String access_token, List<String> userid_list, List<String> dept_id_list, boolean to_all_user, Map msg, String agent_id) {
        Map body = UtilMap.map("agent_id, to_all_user, msg", new Object[]{agent_id, to_all_user, msg});
        if (UtilList.isNotEmpty(userid_list)) {
            body.put("userid_list", String.join(",", userid_list));
        }
        if (UtilList.isNotEmpty(dept_id_list)) {
            body.put("dept_id_list", String.join(",", dept_id_list));
        }

        DDR ddr = DDR.doPost("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2", (Map)null, DDConf.initTokenParams(access_token), body);
        return ddr.getTask_id();
    }

    public long roundToNearestThousand(long timestamp) {
        // 将时间戳除以1000，得到秒级部分（带毫秒的小数部分）
        double seconds = timestamp / 1000.0;

        // 对秒级部分的个位数进行四舍五入（即对毫秒的千位四舍五入）
        long roundedSeconds = Math.round(seconds);

        // 将四舍五入后的秒级部分转换回毫秒时间戳
        return roundedSeconds * 1000;
    }

    @Async
    @Override
    public void batchUpdateSpecifiedQuantityData(Map map) {
        try {
            String pid = UtilMap.getString(map, "pid");
            MDC.put("MDC_KEY_PID",pid);

            String formInstId = UtilMap.getString(map, "formInstId");//当前表实例id

            //查询当前表formData
            Map formData = ydClient.queryData(YDParam.builder()
                    .formInstanceId(formInstId)
                    .build(), YDConf.FORM_QUERY.retrieve_id).getFormData();

            //目标表筛选字段唯一标识
            String[] searchFields = UtilMap.getString(map, "searchFieldStr").split(",");
            //目标表筛选字段值
            String[] searchFieldValues = UtilMap.getString(map, "searchFieldValueStr").split(",");

            Map searchCondition = new HashMap();

            if (searchFields.length == searchFieldValues.length){
                for (int i = 0; i < searchFields.length; i++) {
                    searchCondition.put(searchFields[i],searchFieldValues[i]);
                }
            }else {
                log.info("筛选字段和筛选值数量不一致");
            }

            int quantity = UtilMap.getInt(map, "quantity");//指定更新数量
            if (quantity > 100){
                log.info("更新数量不能大于100");
            }

            String formUuid = UtilMap.getString(map, "formUuid");//目标表uuid

            List<Map> data = (List<Map>) ydClient.queryData(YDParam.builder()
                    .searchCondition(JSONObject.toJSONString(searchCondition))
                    .formUuid(formUuid)
                    .pageSize(quantity)
                    .build(), YDConf.FORM_QUERY.retrieve_list).getData();



            //目标表更新字段唯一标识
            String[] fieldStrs = UtilMap.getString(map, "fieldStr").split(",");
            //当前表字段唯一标识
            String[] currentFieldStrs = UtilMap.getString(map, "currentFieldStrs").split(",");

            Map updateFormData = new HashMap();

            if (fieldStrs.length == currentFieldStrs.length){
                for (int i = 0; i < fieldStrs.length; i++) {
                    updateFormData.put(fieldStrs[i],YDConf.getDataByCompId(formData,currentFieldStrs[i]));
                }
            }else {
                log.info("更新字段和当前表字段数量不一致");
            }

            for (Map datum : data) {
                String formInstanceId = UtilMap.getString(datum, "formInstanceId");

                ydClient.operateData(YDParam.builder()
                        .formInstanceId(formInstanceId)
                        .updateFormDataJson(JSONObject.toJSONString(updateFormData))
                        .build(), YDConf.FORM_OPERATION.update);
            }
            log.info("批量更新成功");
        }catch (Exception e){
            log.info("更新数据失败：{}",e.getMessage());
        }
    }


    private static void extractOperatorIds(JSONArray array, List<String> result) {
        for (Object item : array) {
            JSONObject obj = (JSONObject) item;

            // 提取当前层级的 operatorUserId 或 operator
            String userId = obj.getString("operatorUserId");
            if (userId == null) userId = obj.getString("operator"); // 处理 domainList 中的字段
            if (userId != null) result.add(userId);

            // 递归处理 domainList
            JSONArray domainList = obj.getJSONArray("domainList");
            if (domainList != null && !domainList.isEmpty()) {
                extractOperatorIds(domainList, result);
            }
        }
    }

    private String getString(Object obj){
        return obj == null ? "" : obj.toString();
    }

    private List<Map> getTableData(List<Map<String, ?>> details){
        List<Map> table = new ArrayList<>();
        for (Map detail : details) {
            Map row = UtilMap.empty();
            for (String subId : details.get(0).keySet()) {
                // ppExt: 组件会返回带有_id/_value字段, 关联表单 & 成员组件赋值为原字段 [关联表单仅仅会返回带Id字段, 成员组件不带Id返回姓名过滤]
                if (subId.endsWith("_value") || (subId.startsWith("employeeField_") && !subId.endsWith("_id"))) {
                    continue;
                }
                if (subId.endsWith("_id")) {
                    if (subId.startsWith("employeeField_") || subId.startsWith("associationFormField_")) {
                        subId = subId.replace("_id", "");
                    } else {
                        continue;
                    }
                }
                row.put(subId, YDConf.getDataByCompId(detail, subId));
            }

            table.add(row);
        }
        return table;
    }
}
