package com.malk.zhiwei.service.impl;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.kingdee.bos.webapi.entity.IdentifyInfo;
import com.kingdee.bos.webapi.entity.RepoRet;
import com.kingdee.bos.webapi.sdk.K3CloudApi;
import com.malk.server.aliwork.YDConf;
import com.malk.server.aliwork.YDParam;
import com.malk.server.common.McR;
import com.malk.server.common.VenR;
import com.malk.server.dingtalk.DDConf;
import com.malk.server.dingtalk.DDR;
import com.malk.service.aliwork.YDClient;
import com.malk.service.dingtalk.DDClient;
import com.malk.utils.PublicUtil;
import com.malk.utils.UtilHttp;
import com.malk.utils.UtilMap;
import com.malk.zhiwei.config.KDWebApiConf;
import com.malk.zhiwei.entity.BillQuery;
import com.malk.zhiwei.entity.CustomerModel;
import com.malk.zhiwei.entity.FNumber;
import com.malk.zhiwei.service.ZwService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ZwServiceImpl implements ZwService {

    @Autowired
    private KDWebApiConf kdWebApiConf;
    @Autowired
    private YDConf ydConf;
    @Autowired
    private DDConf ddConf;
    @Autowired
    private DDClient ddClient;

    private static String ERP_URL="http://10.0.0.208:80";
    private static String ERP_NAME="064";
    private static String ERP_PASSWORD="";
    private static String ERP_PILOT="PILOT2001";

    // http://10.0.0.208:30104/MobileService.asmx?op=GETPILOTLIST
    // {"PILOTLIST":[
    // {"NAME":"PILOT2001","ZTNAME":"2001测试"},
    // {"NAME":"PILOT2002","ZTNAME":"2002CS-BYD"},
    // {"NAME":"PILOT2023","ZTNAME":"20232023"},
    // {"NAME":"PILOT2024","ZTNAME":"20242024"}]}
    private static String ERP_LOGIN_KEY="2025062710430311152101098";

    private static String ERP_OP_PRODUCT="Anyv_View_PRODUCT";
    private static String ERP_OP_PRODCLAS="Anyv_View_PRODCLAS";
    private static String ERP_OP_CUSTOMER="Anyv_View_CUSTOMER";

    public static void main(String[] args) {
        // {"CODE":"CP000201","clasName":"成品","CNAME":"MPP-20P","SPEC":"600*500*1.8±0.3"},{"CODE":"CP000809","clasName":"成品","CNAME":"阻燃MPP-25P-灰色","SPEC":"1400*1100*3+1-0.5"},{"CODE":"CP001362","clasName":"成品","CNAME":"阻燃MPP-15P","SPEC":"2480*222*3.5±0.2"},{"CODE":"TCP000023","clasName":"成品","CNAME":"POE05灰(李宁)","SPEC":"1850*800*6"}
        JSONObject jsonObject = queryData(ERP_OP_PRODUCT,"clasName = '成品'",ERP_PILOT);
        // {"CODE":"KH0681","CNAME":"耐玛体育","ABBR":"耐玛体育"},{"CODE":"KH0022","CNAME":"上海浩魁材料科技有限公司","ABBR":"浩魁"}
//        JSONObject jsonObject = queryData(ERP_OP_CUSTOMER,"");
//        saveSaleOrder("{\"CODE\":\"KH0681\",\"SUPP\":\"KH0681\",\"STAFFCODE\":\"admin\",\"VERIFICATION\":\"False\",\"PRODLIST\":[{\"ERI\":\"0GZ29ZUKV401HCBI\",\"CODE\":\"O220902002\",\"CODE1\":\"\",\"PROD\":\"CP000201\",\"GWN\":\"WXYL\",\"VPNO\":\"X220703\",\"QTY\":1,\"confirm\":0}]}");

//        saveDeliveryOrder("{\"CODE\":\"KH0681\",\"STAFFCODE\":\"admin\",\"VERIFICATION\":\"False\",\"PRODLIST\":[{\"ERI\":\"\",\"CODE\":\"O250627010\",\"PROD\":\"CP000201\",\"GWN\":\"WXYL\",\"VPNO\":\"X220703\",\"QTY\":1,\"confirm\":0}]}");
    }

    private static String erpLogin(String erpPilot){
        String xmlResponse=HttpUtil.get(ERP_URL+"/MobileService.asmx/login?name="+ERP_NAME+"&password="+ERP_PASSWORD+"&pilot="+erpPilot);
        int jsonStart = xmlResponse.indexOf("{");
        int jsonEnd = xmlResponse.lastIndexOf("}");
        String jsonStr = xmlResponse.substring(jsonStart, jsonEnd + 1);
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        log.info("登录结果：{}",jsonObject);
        return jsonObject.getJSONObject("USER").getString("Key");
    }

    private static JSONObject queryData(String op,String where,String erpPilot){
        String xmlResponse=HttpUtil.get(ERP_URL+"/MobileService.asmx/"+op+"?KEY="+erpLogin(erpPilot)+"&field=&userid="+ERP_NAME+"&where="+where+"&pilot="+erpPilot);
        int jsonStart = xmlResponse.indexOf("{");
        int jsonEnd = xmlResponse.lastIndexOf("}");
        String jsonStr = xmlResponse.substring(jsonStart, jsonEnd + 1);
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        log.info("查询结果：{}",jsonObject);
        return jsonObject;
    }

    private static JSONObject saveSaleOrder(String data,String erpPilot){
        String xmlResponse=HttpUtil.get(ERP_URL+"/MobileService.asmx/Anyv_GenForm_ORDCORD1?KEY="+erpLogin(erpPilot)+"&userid="+ERP_NAME+"&Data="+data+"&pilot="+erpPilot);
        System.out.println(xmlResponse);
        int jsonStart = xmlResponse.indexOf("{");
        int jsonEnd = xmlResponse.lastIndexOf("}");
        String jsonStr = xmlResponse.substring(jsonStart, jsonEnd + 1);
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        log.info("保存结果：{}",jsonObject);
        return jsonObject;
    }

    @Override
    public JSONObject saveSaleOrder(Map formData) {
        // 数据转换
        JSONObject dataObj = new JSONObject();
        dataObj.put("CODE", UtilMap.getString(formData,"textField_mcefftni"));// 单号
        dataObj.put("SUPP",UtilMap.getString(formData,"textField_mcefftni"));// 客户代码
        dataObj.put("STAFFCODE",UtilMap.getString(formData,"textField_mcefftnj"));
        dataObj.put("VERIFICATION","False");
        List<Map> list=UtilMap.getList(formData,"tableField_mcefftnk");
        List<Map> dataList=new ArrayList<>();
        for (Map map : list) {
            Map tempMap=new HashMap();
            tempMap.put("ERI",""); // 销售订单副档ERI或出货通知单副档ERI
            tempMap.put("CODE", UtilMap.getString(map,"textField_mcefftnl")); // 销售订单编号
            tempMap.put("CODE1", "");// 出货通知单编号
            tempMap.put("PROD", UtilMap.getString(map,"textField_mcefftnn"));// 产品代码
            tempMap.put("GWN", UtilMap.getString(map,"textField_mcefftno"));// 仓库代码
            tempMap.put("VPNO", UtilMap.getString(map,"textField_mcefftnp"));// 产品批号
            tempMap.put("QTY", UtilMap.getString(map,"numberField_mcefftnr"));// 产品数量
            tempMap.put("confirm", "0");
            dataList.add(tempMap);
        }
        dataObj.put("PRODLIST",dataList);
        String data=JSONObject.toJSONString(dataObj);
        log.info("入参：{}",data);
        // 调用接口
        JSONObject result=saveSaleOrder(data,UtilMap.getString(formData,"textField_mdr1v1di"));
        JSONArray codes=result.getJSONArray("page");
        String id=codes.getJSONObject(0).getString("CODE");
        JSONObject result1=new JSONObject();
        result1.put("textField_me17f355",id); // erp单号
        result1.put("result",result);
        return result1;
    }

    private static JSONObject saveDeliveryOrder(String data,String erpPilot){
        String xmlResponse=HttpUtil.get(ERP_URL+"/MobileService.asmx/Anyv_GenForm_STKSHIPNOTE1?KEY="+erpLogin(erpPilot)+"&userid="+ERP_NAME+"&Data="+data+"&pilot="+erpPilot);
        System.out.println(xmlResponse);
        int jsonStart = xmlResponse.indexOf("{");
        int jsonEnd = xmlResponse.lastIndexOf("}");
        String jsonStr = xmlResponse.substring(jsonStart, jsonEnd + 1);
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        log.info("保存结果：{}",jsonObject);
        return jsonObject;
    }

    @Override
    public JSONObject saveDeliveryOrder(Map formData) {
        // 数据转换
        JSONObject dataObj = new JSONObject();
        dataObj.put("CODE", UtilMap.getString(formData,"textField_mcefftni"));// 客户代码
        dataObj.put("STAFFCODE",UtilMap.getString(formData,"textField_mcefftnj"));
        dataObj.put("VERIFICATION","False");
        List<Map> list=UtilMap.getList(formData,"tableField_mcefftnk");
        List<Map> dataList=new ArrayList<>();
        for (Map map : list) {
            Map tempMap=new HashMap();
            tempMap.put("ERI",""); // 销售订单副档ERI或出货通知单副档ERI
            tempMap.put("CODE", UtilMap.getString(map,"textField_mcefftnl")); // 销售订单编号
            tempMap.put("PROD", UtilMap.getString(map,"textField_mcefftnn"));// 产品代码
            tempMap.put("GWN", UtilMap.getString(map,"textField_mcefftno"));// 仓库代码
            tempMap.put("VPNO", UtilMap.getString(map,"textField_mcefftnp"));// 产品批号
            tempMap.put("QTY", UtilMap.getString(map,"numberField_mcefftnr"));// 产品数量
            tempMap.put("confirm", "0");
            dataList.add(tempMap);
        }
        dataObj.put("PRODLIST",dataList);
        String data=JSONObject.toJSONString(dataObj);
        log.info("入参：{}",data);
        JSONObject result=saveDeliveryOrder(data,UtilMap.getString(formData,"textField_mdr1v1di"));
        JSONArray codes=result.getJSONArray("page");
        String id=codes.getJSONObject(0).getString("CODE");
        JSONObject result1=new JSONObject();
        result1.put("textField_me17f355",id); // erp单号
        result1.put("result",result);
        return result1;
//        for (int i = 0; i < list.size(); i++) {
//            Map tempMap=new HashMap();
//            tempMap.put("textField_mdqsatd4",UtilMap.getString(list.get(i),"textField_mdqs9oqa"));
//            tempMap.put("textField_mdwpe4m6","发货");
//            tempMap.put("textField_mdwpe4m7",UtilMap.getString(formData,"textField_mdwqclqh"));
//            if(codes.size() >= i){
//                tempMap.put("textField_mdqsatd5",codes.getJSONObject(i).getString("CODE"));
//            }
//            ydClient.operateData(YDParam.builder().formUuid("FORM-E999482BC03547D89A435F5441A46F1ANR0R").formDataJson(JSONObject.toJSONString(tempMap)).build(), YDConf.FORM_OPERATION.create);
//        }
//        return result;
        // 调用接口
    }

    @Autowired
    private YDClient ydClient;

    @Override
    public void syncProduct(String id,String erpPilot) {
        JSONObject jsonObject = queryData(ERP_OP_PRODUCT,"clasName = '成品'"+ (PublicUtil.isNull(id)?"":("and CODE = '"+id+"'")),erpPilot);
        JSONArray data = jsonObject.getJSONArray("data");
        log.info("data.size()：{}",data.size());
        for (int i = 0; i < data.size(); i++) {
            JSONObject dataObj = data.getJSONObject(i);
            String productId=UtilMap.getString(dataObj,"CODE");
            Map saveMap=UtilMap.map("textField_mcijetil, textField_l43jpnsf, textField_l43jpnsh","selectField_me6qde0j",productId,dataObj.getString("CNAME"),dataObj.getString("SPEC"),erpPilot);
            try {
                ydClient.operateData(YDParam.builder().formUuid("FORM-4A7B1A62CCFC4D758AB98ADE3F97D40COYO2")
                        .searchCondition(JSONObject.toJSONString(UtilMap.map("textField_mcijetil", productId)))
                        .formDataJson(JSONObject.toJSONString(saveMap)).build(), YDConf.FORM_OPERATION.upsert);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    @SneakyThrows
    @Override
    public McR savecustomer(String instanceId) throws JsonProcessingException {
        log.info("客户宜搭实例id:{}",instanceId);
        Map data = (Map) ydClient.queryData(YDParam.builder().formInstId(instanceId)
                .appType(ydConf.getAppType()).systemToken(ydConf.getSystemToken())
                .userId(ddConf.getOperator()).build(), YDConf.FORM_QUERY.retrieve_id).getFormData();

        FNumber zd = new FNumber(data.get("selectField_mnft99ue").toString());//终端
        FNumber syb = new FNumber(data.get("selectField_mnft99ud").toString());//事业部
        FNumber hy = new FNumber(data.get("textField_mnfujcak").toString());//行业
        FNumber sktj = new FNumber(data.get("textField_mnfujcaf").toString());//收款条件
        FNumber xsbm = new FNumber(data.get("textField_mnfujcac").toString());//销售部门
        FNumber xsy = new FNumber(data.get("textField_mnfujcad").toString());//销售员
        String kh = data.get("textField_lqanqe6j").toString();// 客户
        Object empObj = data.get("employeeField_lqanqe6n");
        String ywy = "";//业务员
        if (empObj instanceof JSONArray) {
            JSONArray empArray = (JSONArray) empObj;
            if (!empArray.isEmpty()) {
                ywy = empArray.getString(0);
            }
        } else if (empObj != null) {
            ywy = empObj.toString();
        }
        String nsdjhc = data.get("textField_llujklkq").toString();//纳税登记号
        CustomerModel customerModel = new CustomerModel(kh,sktj,hy,syb,zd,ywy,nsdjhc,xsbm,xsy);
        return saveToAudit("BD_Customer", customerModel);
    }

    @SneakyThrows
    @Override
    public void product() {
        K3CloudApi client = new K3CloudApi(initIden());
        int startRow = 0;
        int limit = 2000;
        BillQuery billQuery = new BillQuery();
        billQuery.setFormId("BD_MATERIAL");//产品信息
        //编码 名称 规格型号 旧物料编码 物料分组 物料属性 基本单位 长 宽 高 体积 面积 密度 标准工时
        billQuery.setFieldKeys("FCreateOrgId.FNumber,FApproveDate,FNumber,FName,FSpecification,FOldNumber,FMaterialGroup,FErpClsID,FBaseUnitId,FLENGTH,FWIDTH,FHEIGHT,FVOLUME,F_UNW_Qty_r03,F_UNW_Qty_6yt,FPerUnitStandHour");
        List<Map> filterString = new ArrayList<>();
        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",3,"","","0"));//审核日期在今天之前N天以后
        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FCreateOrgId.FNumber","67","101","","","0"));//创建组织为101 研发中心
        billQuery.setFilterString(filterString);
        billQuery.setLimit(limit);
        billQuery.setStartRow(startRow);
        String result=client.billQuery(JSONObject.toJSONString(billQuery));
        JSONArray jsonArray = JSONArray.parseArray(result);
        // 遍历每条物料记录
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject item = jsonArray.getJSONObject(i);

            // 取出各个字段（注意类型转换）
            String number = item.getString("FNumber");
            String name = item.getString("FName");
            String spec = item.getString("FSpecification");
            String oldNumber = item.getString("FOldNumber");
            Integer materialGroup = item.getInteger("FMaterialGroup");
            String erpClsId = item.getString("FErpClsID");
            Integer baseUnitId = item.getInteger("FBaseUnitId");
            Double length = item.getDouble("FLENGTH");
            Double width = item.getDouble("FWIDTH");
            Double height = item.getDouble("FHEIGHT");
            Double volume = item.getDouble("FVOLUME");
            Double area = item.getDouble("F_UNW_Qty_r03");
            Double density = item.getDouble("F_UNW_Qty_6yt");
            Double standHour = item.getDouble("FPerUnitStandHour");
            //TODO:向宜搭插入数据
            String sc = "textField_l43jpnsf, textField_mcijetil, textField_l43jpnsh, textField_mnhe1ryw, textField_mnhe1rz1, textField_mnhe1rz2, textField_mnhe1rz7, textField_mnhe1rzm," +
                    " textField_mnhe1rzg, textField_mnhe1rzh, textField_mnhe1rzi, textField_mnhe1rzj, textField_mnhe1rzk, textField_mnhe1rzl";//名称 编码 规格 旧编码 物料分组 物料属性 基本单位 标准工时 长 宽 高 体积 面积 密度
            List<Map> conditions = Arrays.asList(  YDConf.searchCondition_TextFiled("textField_mcijetil", number, "eq"));
            Map formData = UtilMap.map(sc,name,number,spec,oldNumber,materialGroup,erpClsId,baseUnitId,length,width,height,volume,area,density,standHour);
            ydClient.operateData(YDParam.builder()
                    .formUuid("FORM-4A7B1A62CCFC4D758AB98ADE3F97D40COYO2")
                    .searchCondition(JSONObject.toJSONString(conditions))
                    .formDataJson(JSONObject.toJSONString(formData))
                    .build(),YDConf.FORM_OPERATION.upsert);

        }
        log.info("产品信息已同步");
    }

    @SneakyThrows
    @Override
    public void purchaseOrder(){
        K3CloudApi client = new K3CloudApi(initIden());
        int startRow = 0;
        int limit = 2000;
        BillQuery billQuery = new BillQuery();
        billQuery.setFormId("SAL_SaleOrder");//销售订单
        //[主表] FSaleOrgId销售组织 FSaleDeptId销售部门 FBillNo单据编号  FCustId客户 F_UNW_Text_ct1客户订单号 FSettleCurrId结算币别 FSalerId销售员 FDate日期 FRecConditionId收款条件
        //[明细表] FMaterialId物料编码 FMaterialName物料名称 FMaterialModel规格型号 FMapId客户物料编码 F_UNW_BaseProperty_uow客户物料规格 FUnitID销售单位 FQty销售数量 FPriceUnitQty计价数量 FPrice单价 FTaxPrice含税单价 FEntryTaxRate税率 FEntryTaxAmount税额 FAmount金额 FAllAmount价税合计 FDeliveryDate要货日期 FSettleOrgIds结算组织 FIsFree是否赠品
        billQuery.setFieldKeys("FSaleOrgId.FName,FSaleDeptId.FName,FBillNo,FCustId.FName,F_UNW_Text_ct1,FSettleCurrId.FName,FSalerId.FName,FDate,FRecConditionId.FName,FMaterialId.FNumber,FMaterialName,FMaterialModel,FMapId.FNumber,F_UNW_BaseProperty_uow,FUnitID.FName,FQty,FPriceUnitQty,FPrice,FTaxPrice,FEntryTaxRate,FEntryTaxAmount,FAmount,FAllAmount,FDeliveryDate,FSettleOrgIds.FName,FIsFree");
        List<Map> filterString = new ArrayList<>();
        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",1,"","","0"));//审核日期在今天之前N天以后
        billQuery.setFilterString(filterString);
        billQuery.setLimit(limit);
        billQuery.setStartRow(startRow);
        String result=client.billQuery(JSONObject.toJSONString(billQuery));
        JSONArray jsonArray = JSONArray.parseArray(result);

        // 按 FBillNo 分组
        Map<String, List<JSONObject>> groupMap = new LinkedHashMap<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject item = jsonArray.getJSONObject(i);
            String billNo = item.getString("FBillNo");
            groupMap.computeIfAbsent(billNo, k -> new ArrayList<>()).add(item);
        }

        // 组装最终结果
        List<Map<String, Object>> orderList = new ArrayList<>();
        for (Map.Entry<String, List<JSONObject>> entry : groupMap.entrySet()) {
            List<JSONObject> rows = entry.getValue();
            JSONObject firstRow = rows.get(0);

            // 主表 Map
            Map<String, Object> orderMap = new LinkedHashMap<>();
            orderMap.put("textField_mniksrqa", firstRow.getString("FBillNo"));//单据编号
            orderMap.put("textField_mniksrq4", firstRow.getString("FSaleOrgId.FName")); // 销售组织
            orderMap.put("textField_mniksrq5", firstRow.getString("FSaleDeptId.FName")); // 销售组织
            orderMap.put("textField_mniksrqb", firstRow.getString("FCustId.FName")); // 客户
            orderMap.put("textField_mniksrqe", firstRow.getString("F_UNW_Text_ct1")); // 客户订单号
            orderMap.put("textField_mniksrqf", firstRow.getString("FSettleCurrId.FName")); // 结算币别
            orderMap.put("textField_mniksrqk", firstRow.getString("FSalerId.FName")); // 销售员
            String fDateRaw = firstRow.getString("FDate");
            String formattedDate = (fDateRaw != null && fDateRaw.contains("T")) ? fDateRaw.split("T")[0] : fDateRaw;
            orderMap.put("textField_mniksrql", formattedDate); // 日期
            orderMap.put("textField_mniksrqm", firstRow.getString("FRecConditionId.FName")); // 收款条件


            // 明细数组
            List<Map<String, Object>> details = new ArrayList<>();
            for (JSONObject row : rows) {
                Map<String, Object> detailMap = new LinkedHashMap<>();
                detailMap.put("textField_mniksrqo", row.getString("FMaterialId.FNumber"));//物料编码
                detailMap.put("textField_mniksrqp", row.getString("FMaterialName"));//物料名称
                detailMap.put("textField_mniksrqq", row.getString("FMaterialModel"));//规格型号
                detailMap.put("textField_mniksrqr", row.getString("FMapId.FNumber"));//客户物料编码
                detailMap.put("textField_mniksrqs", row.getString("F_UNW_BaseProperty_uow"));//客户物料规格
                detailMap.put("textField_mniksrqt", row.getString("FUnitID.FName"));//销售单位
                detailMap.put("numberField_mniksrqv", row.getString("FQty"));//销售数量
                detailMap.put("numberField_mniksrqw", row.getString("FPriceUnitQty"));//计价数量
                detailMap.put("numberField_mniksrqx", row.getString("FPrice"));//单价
                detailMap.put("numberField_mniksrqy", row.getString("FTaxPrice"));//含税单价
                detailMap.put("numberField_mniksrqz", row.getString("FEntryTaxRate"));//税率
                detailMap.put("numberField_mniksrr0", row.getString("FEntryTaxAmount"));//税额
                detailMap.put("numberField_mniksrr1", row.getString("FAmount"));//金额
                detailMap.put("numberField_mniksrr2", row.getString("FAllAmount"));//价税合计
                String deliveryRaw = row.getString("FDeliveryDate");
                String formattedDelivery = (deliveryRaw != null && deliveryRaw.contains("T")) ? deliveryRaw.split("T")[0] : deliveryRaw;
                detailMap.put("textField_mniksrr3", formattedDelivery);//要货日期
                detailMap.put("textField_mniksrr4", row.getString("FSettleOrgIds.FName"));//结算组织
                detailMap.put("radioField_mniksrr6", row.getString("FAmount").equals("true") ? "是" : "否");//是否赠品
                details.add(detailMap);
            }
            orderMap.put("tableField_mniksrqn", details);

            /*写入宜搭*/
            List<Map> conditions = Arrays.asList(  YDConf.searchCondition_TextFiled("textField_mniksrqa", firstRow.getString("FBillNo"), "eq"));
            ydClient.operateData(YDParam.builder()
                    .formUuid("FORM-7B112A3733EC412FB27D56D8AC242E5BHIL4")
                    .searchCondition(JSONObject.toJSONString(conditions))
                    .formDataJson(JSONObject.toJSONString(orderMap))
                    .build(), YDConf.FORM_OPERATION.upsert).toString();
            orderList.add(orderMap);
        }

        log.info("销售订单已同步");
    }

    @SneakyThrows
    @Override
    public void deliveryOrder() throws JsonProcessingException {
        K3CloudApi client = new K3CloudApi(initIden());
        int startRow = 0;
        int limit = 2000;
        BillQuery billQuery = new BillQuery();
        billQuery.setFormId("SAL_DELIVERYNOTICE");//发货通知单
        //[主表]  FBillNo单据编号 FDate日期 FSettleCurrId结算币别  FSaleOrgId销售组织 FSaleDeptId销售部门   FSalesManID销售员   F_UNW_Base_tr7发货客户  F_UNW_CheckBox_xjs是否委外
        //[明细表] FCustMatName客户物料名称  FCustMatID客户物料编码  FMaterialID物料编码  F_UNW_BaseProperty_3tm客户物料规格型号  FMaterialName物料名称  FMateriaModel型号规格  FUnitID销售单位  FQty销售数量  FIsFree是否赠品  FDeliveryDate要货日期  FDeliveryLoc交货地点 F_UNW_Text_8dq客户订单号
        billQuery.setFieldKeys("FBillNo,FDate,FSettleCurrId.FName,FSaleOrgId.FName,FSaleDeptId.FName,FSalesManID.FName,F_UNW_Base_tr7.FName,F_UNW_CheckBox_xjs,FCustMatName,FCustMatID.FNumber,FMaterialID.FNumber,F_UNW_BaseProperty_3tm,FMaterialName,FMateriaModel,FUnitID.FName,FQty,FIsFree,FDeliveryDate,FDeliveryLoc.FName,F_UNW_Text_8dq");
        List<Map> filterString = new ArrayList<>();
        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",1,"","","0"));//审核日期在今天之前N天以后
        billQuery.setFilterString(filterString);
        billQuery.setLimit(limit);
        billQuery.setStartRow(startRow);
        String result=client.billQuery(JSONObject.toJSONString(billQuery));
        JSONArray jsonArray = JSONArray.parseArray(result);

        // 按 FBillNo 分组
        Map<String, List<JSONObject>> groupMap = new LinkedHashMap<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject item = jsonArray.getJSONObject(i);
            String billNo = item.getString("FBillNo");
            groupMap.computeIfAbsent(billNo, k -> new ArrayList<>()).add(item);
        }

        // 组装最终结果
        List<Map<String, Object>> orderList = new ArrayList<>();
        for (Map.Entry<String, List<JSONObject>> entry : groupMap.entrySet()) {
            List<JSONObject> rows = entry.getValue();
            JSONObject firstRow = rows.get(0);

            // 主表 Map
            Map<String, Object> orderMap = new LinkedHashMap<>();
            orderMap.put("textField_mnj0cqqp", firstRow.getString("FBillNo"));//单据编号
            String fDateRaw = firstRow.getString("FDate");
            String formattedDate = (fDateRaw != null && fDateRaw.contains("T")) ? fDateRaw.split("T")[0] : fDateRaw;
            orderMap.put("textField_mnj0cqqq", formattedDate); // 日期
            orderMap.put("textField_mnj0cqqr", firstRow.getString("FSettleCurrId.FName")); // 结算币别
            orderMap.put("textField_mnj0cqqw", firstRow.getString("FSaleOrgId.FName")); // 销售组织
            orderMap.put("textField_mnj0cqqx", firstRow.getString("FSaleDeptId.FName")); // 销售部门
            orderMap.put("textField_mnj0cqqy", firstRow.getString("FSalesManID.FName")); // 销售员
            orderMap.put("textField_mnj0cqr3", firstRow.getString("F_UNW_Base_tr7.FName")); // 发货客户
            orderMap.put("radioField_mnj0cqr4", firstRow.getString("F_UNW_CheckBox_xjs").equals("true") ? "是" : "否" ); // 是否委外


            // 明细数组
            List<Map<String, Object>> details = new ArrayList<>();
            for (JSONObject row : rows) {
                Map<String, Object> detailMap = new LinkedHashMap<>();
                detailMap.put("textField_mnj0cqr6", row.getString("FCustMatName"));//客户物料名称
                detailMap.put("textField_mnj0cqr7", row.getString("FCustMatID.FNumber"));//客户物料编码
                detailMap.put("textField_mnj0cqr8", row.getString("FMaterialID.FNumber"));//物料编码
                detailMap.put("textField_mnj0cqr9", row.getString("F_UNW_BaseProperty_3tm"));//客户物料规格型号
                detailMap.put("textField_mnj0cqra", row.getString("FMaterialName"));//物料名称
                detailMap.put("textField_mnj0cqrb", row.getString("FMateriaModel"));//规格型号
                detailMap.put("textField_mnj0cqrc", row.getString("FUnitID.FName"));//销售单位
                detailMap.put("numberField_mnj0cqrd", row.getString("FQty"));//销售数量
                detailMap.put("radioField_mnj0cqre", row.getString("FIsFree").equals("true") ? "是" : "否");//是否赠品
                String rawDeliveryDate = row.getString("FDeliveryDate");
                String formattedDeliveryDate = rawDeliveryDate != null ? rawDeliveryDate.replace("T", " ") : null;
                detailMap.put("textField_mnj0cqrf", formattedDeliveryDate);//要货日期
                detailMap.put("textField_mnj0cqrg", row.getString("FDeliveryLoc.FName"));//交货地点
                detailMap.put("textField_mnj0cqrh", row.getString("F_UNW_Text_8dq"));//客户订单号
                details.add(detailMap);
            }
            orderMap.put("tableField_mnj0cqr5", details);

            /*写入宜搭*/
            List<Map> conditions = Arrays.asList(  YDConf.searchCondition_TextFiled("textField_mnj0cqqp", firstRow.getString("FBillNo"), "eq"));
            ydClient.operateData(YDParam.builder()
                    .formUuid("FORM-50CEB72455534364BF9A97C8A49A3A46TBLI")
                    .searchCondition(JSONObject.toJSONString(conditions))
                    .formDataJson(JSONObject.toJSONString(orderMap))
                    .build(), YDConf.FORM_OPERATION.upsert).toString();
            orderList.add(orderMap);
        }

        log.info("发货通知单已同步");
    }

    @SneakyThrows
    @Override
    public void returnForm() throws JsonProcessingException {
        K3CloudApi client = new K3CloudApi(initIden());
        int startRow = 0;
        int limit = 2000;
        BillQuery billQuery = new BillQuery();
        billQuery.setFormId("SAL_RETURNSTOCK");//退货单
        //[主表]  FBillNo单据编号 FDate日期 FRetcustId退货客户  FSettleCurrId结算币别  FSaleOrgId销售组织 FSaledeptid销售部门   FSalesManId销售员
        //[明细表] FMapId客户物料编码  FMapName客户物料名称  FMaterialId物料编码  FMaterialName物料名称  FMaterialModel型号规格  FF100001厚度  FSalUnitID销售单位  FSalUnitQty销售数量  FIsFree是否赠品  FDeliveryDate退货日期  FReturnType退货类型  FPrice单价 FTaxPrice含税单价  FNote备注
        billQuery.setFieldKeys("FBillNo,FDate,FRetcustId.FName,FSettleCurrId.FName,FSaleOrgId.FName,FSaledeptid.FName,FSalesManId.FName,FMapId.FNumber,FMapName,FMaterialId.FNumber,FMaterialName,FMaterialModel,FAuxpropId.FF100001,FSalUnitID.FName,FSalUnitQty,FIsFree,FDeliveryDate,FReturnType.FDataValue,FPrice,FTaxPrice,FNote");
        List<Map> filterString = new ArrayList<>();
        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",30,"","","0"));//审核日期在今天之前N天以后
        billQuery.setFilterString(filterString);
        billQuery.setLimit(limit);
        billQuery.setStartRow(startRow);
        String result=client.billQuery(JSONObject.toJSONString(billQuery));
        JSONArray jsonArray = JSONArray.parseArray(result);

        // 按 FBillNo 分组
        Map<String, List<JSONObject>> groupMap = new LinkedHashMap<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject item = jsonArray.getJSONObject(i);
            String billNo = item.getString("FBillNo");
            groupMap.computeIfAbsent(billNo, k -> new ArrayList<>()).add(item);
        }

        // 组装最终结果
        List<Map<String, Object>> orderList = new ArrayList<>();
        for (Map.Entry<String, List<JSONObject>> entry : groupMap.entrySet()) {
            List<JSONObject> rows = entry.getValue();
            JSONObject firstRow = rows.get(0);

            // 主表 Map
            Map<String, Object> orderMap = new LinkedHashMap<>();
            orderMap.put("textField_mnmru1xp", firstRow.getString("FBillNo"));//单据编号
            String fDateRaw = firstRow.getString("FDate");
            String formattedDate = (fDateRaw != null && fDateRaw.contains("T")) ? fDateRaw.split("T")[0] : fDateRaw;
            orderMap.put("textField_mnmru1xq", formattedDate); // 日期
            orderMap.put("textField_mnmru1xr", firstRow.getString("FRetcustId.FName")); // 退货客户
            orderMap.put("textField_mnmru1y0", firstRow.getString("FSettleCurrId.FName")); // 结算币别
            orderMap.put("textField_mnmru1y1", firstRow.getString("FSaleOrgId.FName")); // 销售组织
            orderMap.put("textField_mnmru1y2", firstRow.getString("FSaledeptid.FName")); // 销售部门
            orderMap.put("textField_mnmru1y3", firstRow.getString("FSalesManId.FName")); // 销售员


            // 明细数组
            List<Map<String, Object>> details = new ArrayList<>();
            for (JSONObject row : rows) {
                Map<String, Object> detailMap = new LinkedHashMap<>();
                detailMap.put("textField_mnmru1y9", row.getString("FMapId.FNumber"));//客户物料编码
                detailMap.put("textField_mnmru1ya", row.getString("FMapName"));//客户物料名称
                detailMap.put("textField_mnmru1yb", row.getString("FMaterialId.FNumber"));//物料编码
                detailMap.put("textField_mnmru1yc", row.getString("FMaterialName"));//物料名称
                detailMap.put("textField_mnmru1yd", row.getString("FMaterialModel"));//规格型号
                detailMap.put("textField_mnmru1ye", row.getString("FAuxpropId.FF100001"));//厚度
                detailMap.put("textField_mnmru1yf", row.getString("FSalUnitID.FName"));//销售单位
                detailMap.put("numberField_mnmru1yg", row.getString("FSalUnitQty"));//销售数量
                detailMap.put("radioField_mnmru1yh", row.getString("FIsFree").equals("true") ? "是" : "否");//是否赠品
                String rawDeliveryDate = row.getString("FDeliveryDate");
                String formattedDeliveryDate = rawDeliveryDate != null ? rawDeliveryDate.replace("T", " ") : null;
                detailMap.put("textField_mnmru1yi", formattedDeliveryDate);//退货日期
                detailMap.put("textField_mnmru1yj", row.getString("FReturnType.FDataValue"));//退货类型
                detailMap.put("numberField_mnmru1yk", row.getString("FPrice"));//单价
                detailMap.put("numberField_mnmru1yl", row.getString("FTaxPrice"));//含税单价
                detailMap.put("textField_mnmru1ym", row.getString("FNote"));//备注
                details.add(detailMap);
            }
            orderMap.put("tableField_mnmru1y8", details);

            /*写入宜搭*/
            List<Map> conditions = Arrays.asList(  YDConf.searchCondition_TextFiled("textField_mnmru1xp", firstRow.getString("FBillNo"), "eq"));
            ydClient.operateData(YDParam.builder()
                    .formUuid("FORM-48ADB8AA7FEF4821929BFE8FE5B623E42OKY")
                    .searchCondition(JSONObject.toJSONString(conditions))
                    .formDataJson(JSONObject.toJSONString(orderMap))
                    .build(), YDConf.FORM_OPERATION.upsert).toString();
            orderList.add(orderMap);
        }

        log.info("退货单已同步");
    }

    @SneakyThrows
    @Override
    public void replenishmentOrder() throws JsonProcessingException {
        K3CloudApi client = new K3CloudApi(initIden());
        int startRow = 0;
        int limit = 2000;
        BillQuery billQuery = new BillQuery();
        billQuery.setFormId("SAL_SaleOrder"); // 销售订单
        // 字段查询与销售订单一致，包含 FIsFree
        billQuery.setFieldKeys("FSaleOrgId.FName,FSaleDeptId.FName,FBillNo,FCustId.FName,F_UNW_Text_ct1,FSettleCurrId.FName,FSalerId.FName,FDate,FRecConditionId.FName,FMaterialId.FNumber,FMaterialName,FMaterialModel,FMapId.FNumber,F_UNW_BaseProperty_uow,FUnitID.FName,FQty,FPriceUnitQty,FPrice,FTaxPrice,FEntryTaxRate,FEntryTaxAmount,FAmount,FAllAmount,FDeliveryDate,FSettleOrgIds.FName,FIsFree");
        List<Map> filterString = new ArrayList<>();
        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic", "FApproveDate", "265", 1, "", "", "0"));
        billQuery.setFilterString(filterString);
        billQuery.setLimit(limit);
        billQuery.setStartRow(startRow);
        String result = client.billQuery(JSONObject.toJSONString(billQuery));
        JSONArray jsonArray = JSONArray.parseArray(result);

        // 按 FBillNo 分组，并过滤出赠品明细
        Map<String, List<JSONObject>> groupMap = new LinkedHashMap<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject item = jsonArray.getJSONObject(i);
            // 判断是否赠品：注意金蝶返回的 FIsFree 可能是布尔值或字符串 "true"/"false"
            boolean isFree = false;
            Object freeObj = item.get("FIsFree");
            if (freeObj instanceof Boolean) {
                isFree = (Boolean) freeObj;
            } else if (freeObj instanceof String) {
                isFree = "true".equalsIgnoreCase((String) freeObj);
            }
            // 只处理赠品行
            if (isFree) {
                String billNo = item.getString("FBillNo");
                groupMap.computeIfAbsent(billNo, k -> new ArrayList<>()).add(item);
            }
        }

        // 组装最终结果（仅包含有赠品行明细的订单）
        List<Map<String, Object>> orderList = new ArrayList<>();
        for (Map.Entry<String, List<JSONObject>> entry : groupMap.entrySet()) {
            List<JSONObject> rows = entry.getValue();
            JSONObject firstRow = rows.get(0); // 取该订单的第一条赠品行（主表字段相同）

            // 主表 Map
            Map<String, Object> orderMap = new LinkedHashMap<>();
            orderMap.put("textField_mniksrqa", firstRow.getString("FBillNo")); // 单据编号
            orderMap.put("textField_mniksrq4", firstRow.getString("FSaleOrgId.FName")); // 销售组织
            orderMap.put("textField_mniksrq5", firstRow.getString("FSaleDeptId.FName")); // 销售部门
            orderMap.put("textField_mniksrqb", firstRow.getString("FCustId.FName")); // 客户
            orderMap.put("textField_mniksrqe", firstRow.getString("F_UNW_Text_ct1")); // 客户订单号
            orderMap.put("textField_mniksrqf", firstRow.getString("FSettleCurrId.FName")); // 结算币别
            orderMap.put("textField_mniksrqk", firstRow.getString("FSalerId.FName")); // 销售员
            String fDateRaw = firstRow.getString("FDate");
            String formattedDate = (fDateRaw != null && fDateRaw.contains("T")) ? fDateRaw.split("T")[0] : fDateRaw;
            orderMap.put("textField_mniksrql", formattedDate); // 日期
            orderMap.put("textField_mniksrqm", firstRow.getString("FRecConditionId.FName")); // 收款条件

            // 明细数组（仅包含赠品行）
            List<Map<String, Object>> details = new ArrayList<>();
            for (JSONObject row : rows) {
                Map<String, Object> detailMap = new LinkedHashMap<>();
                detailMap.put("textField_mniksrqo", row.getString("FMaterialId.FNumber")); // 物料编码
                detailMap.put("textField_mniksrqp", row.getString("FMaterialName")); // 物料名称
                detailMap.put("textField_mniksrqq", row.getString("FMaterialModel")); // 规格型号
                detailMap.put("textField_mniksrqr", row.getString("FMapId.FNumber")); // 客户物料编码
                detailMap.put("textField_mniksrqs", row.getString("F_UNW_BaseProperty_uow")); // 客户物料规格
                detailMap.put("textField_mniksrqt", row.getString("FUnitID.FName")); // 销售单位
                detailMap.put("numberField_mniksrqv", row.getString("FQty")); // 销售数量
                detailMap.put("numberField_mniksrqw", row.getString("FPriceUnitQty")); // 计价数量
                detailMap.put("numberField_mniksrqx", row.getString("FPrice")); // 单价
                detailMap.put("numberField_mniksrqy", row.getString("FTaxPrice")); // 含税单价
                detailMap.put("numberField_mniksrqz", row.getString("FEntryTaxRate")); // 税率
                detailMap.put("numberField_mniksrr0", row.getString("FEntryTaxAmount")); // 税额
                detailMap.put("numberField_mniksrr1", row.getString("FAmount")); // 金额
                detailMap.put("numberField_mniksrr2", row.getString("FAllAmount")); // 价税合计
                String deliveryRaw = row.getString("FDeliveryDate");
                String formattedDelivery = (deliveryRaw != null && deliveryRaw.contains("T")) ? deliveryRaw.split("T")[0] : deliveryRaw;
                detailMap.put("textField_mniksrr3", formattedDelivery); // 要货日期
                detailMap.put("textField_mniksrr4", row.getString("FSettleOrgIds.FName")); // 结算组织
                // 赠品标记：这里明细一定是赠品，直接设为"是"
                detailMap.put("radioField_mniksrr6", "是");
                details.add(detailMap);
            }
            orderMap.put("tableField_mniksrqn", details);

            // 写入宜搭补货单表单
            List<Map> conditions = Arrays.asList(
                    YDConf.searchCondition_TextFiled("textField_mniksrqa", firstRow.getString("FBillNo"), "eq")
            );
            ydClient.operateData(YDParam.builder()
                    .formUuid("FORM-837E203B7DCA4B09A9618AA8F584CC45UDFX")
                    .searchCondition(JSONObject.toJSONString(conditions))
                    .formDataJson(JSONObject.toJSONString(orderMap))
                    .build(), YDConf.FORM_OPERATION.upsert).toString();
            orderList.add(orderMap);
        }

        log.info("补货单已同步，共 {} 个订单包含赠品明细", orderList.size());
    }

    @SneakyThrows
    @Override
    public void invoice() throws JsonProcessingException {
        K3CloudApi client = new K3CloudApi(initIden());
        int startRow = 0;
        int limit = 2000;
        BillQuery billQuery = new BillQuery();
        billQuery.setFormId("AR_receivable");//开票单
        //[主表]  FBillTypeID单据类型  FCUSTOMERID客户  FSALEERID销售员  FSetAccountType立账类型  FBillNo单据编号  FCURRENCYID币别  FSETTLEORGID结算组织  FDATE业务日期  FENDDATE_H到期日  FDocumentStatus单据状态  FPayConditon收款条件  FSALEDEPTID销售部门  F_UNW_Text_u4s发票号
        //[明细表] FMATERIALID 物料编码  FCustMatID客户物料编码  FCustMatName客户物料名称  F_UNW_BaseProperty_lad规格型号 FMaterialName物料名称  FPRICEUNITID计价单位  FPriceQty计价数量  FEntryTaxRate税率  FF100001厚度  FBASICUNITQTY计价基本数量  FLot批号  FORDERNUMBER销售订单号  FORDERENTRYSEQ销售订单行号  FSalQty销售数量  FSalUnitId销售单位  FIsFree是否赠品
        billQuery.setFieldKeys("FBillTypeID.FName,FCUSTOMERID.FName,FSALEERID.FName,FSetAccountType,FBillNo,FCURRENCYID.FName,FSETTLEORGID.FName,FDATE,FENDDATE_H,FDocumentStatus,FPayConditon.FName,FSALEDEPTID.FName,F_UNW_Text_u4s,FMATERIALID.FNumber,FCustMatID.FNumber,FCustMatName,F_UNW_BaseProperty_lad,FMaterialName,FPRICEUNITID.FName,FPriceQty,FEntryTaxRate,FAuxpropId.FF100001,FBASICUNITQTY,FLot.FNumber,FORDERNUMBER,FORDERENTRYSEQ,FSalQty,FSalUnitId.FName,FIsFree");
        List<Map> filterString = new ArrayList<>();
        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",1,"","","0"));//审核日期在今天之前N天以后
        billQuery.setFilterString(filterString);
        billQuery.setLimit(limit);
        billQuery.setStartRow(startRow);
        String result=client.billQuery(JSONObject.toJSONString(billQuery));
        JSONArray jsonArray = JSONArray.parseArray(result);

        // 按 FBillNo 分组
        Map<String, List<JSONObject>> groupMap = new LinkedHashMap<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject item = jsonArray.getJSONObject(i);
            String billNo = item.getString("FBillNo");
            groupMap.computeIfAbsent(billNo, k -> new ArrayList<>()).add(item);
        }

        // 组装最终结果
        List<Map<String, Object>> orderList = new ArrayList<>();
        for (Map.Entry<String, List<JSONObject>> entry : groupMap.entrySet()) {
            List<JSONObject> rows = entry.getValue();
            JSONObject firstRow = rows.get(0);

            // ========== 新增：检查发票号，无发票号则跳过 ==========
            String invoiceNo = firstRow.getString("F_UNW_Text_u4s");
            if (invoiceNo == null || invoiceNo.trim().isEmpty()) {
                log.info("单据编号 {} 无发票号，跳过同步", firstRow.getString("FBillNo"));
                continue;
            }
            // =================================================

            // 主表 Map
            Map<String, Object> orderMap = new LinkedHashMap<>();
            orderMap.put("textField_mno1zcb2", firstRow.getString("FBillTypeID.FName"));//单据类型
            orderMap.put("textField_mno1zcb3", firstRow.getString("FCUSTOMERID.FName")); // 客户
            orderMap.put("textField_mno1zcb4", firstRow.getString("FSALEERID.FName")); // 销售员
            String FSetAccountType = "";
            switch (firstRow.getString("FSetAccountType")){
                case "1":
                    FSetAccountType = "业务应收";break;
                case "2":
                    FSetAccountType = "暂估应收";break;
                case "3":
                    FSetAccountType = "财务应收";break;
            }
            orderMap.put("textField_mno1zcb5", FSetAccountType); // 立账类型
            orderMap.put("textField_mno1zcbb", firstRow.getString("FBillNo")); // 单据编号
            orderMap.put("textField_mno1zcbc", firstRow.getString("FCURRENCYID.FName")); // 币别
            orderMap.put("textField_mno1zcbd", firstRow.getString("FSETTLEORGID.FName")); // 结算组织
            String fDateRaw = firstRow.getString("FDATE");
            String formattedDate = (fDateRaw != null && fDateRaw.contains("T")) ? fDateRaw.split("T")[0] : fDateRaw;
            orderMap.put("textField_mno1zcbe", formattedDate); // 业务日期
            String fDateRaw_A = firstRow.getString("FENDDATE_H");
            String formattedDate_A = (fDateRaw_A != null && fDateRaw_A.contains("T")) ? fDateRaw_A.split("T")[0] : fDateRaw_A;
            orderMap.put("textField_mno1zcbk", formattedDate_A); // 到期日
            orderMap.put("textField_mno1zcbl", firstRow.getString("FPayConditon.FName")); // 收款条件
            String FDocumentStatus = "";
            switch (firstRow.getString("FDocumentStatus")){
                case "A":
                    FDocumentStatus = "创建";break;
                case "B":
                    FDocumentStatus = "审核中";break;
                case "C":
                    FDocumentStatus = "已审核";break;
                case "D":
                    FDocumentStatus = "重新审核";break;
                case "Z":
                    FDocumentStatus = "暂存";break;
            }
            orderMap.put("textField_mno1zcbm", FDocumentStatus); // 单据状态
            orderMap.put("textField_mno1zcbn", firstRow.getString("FSALEDEPTID.FName")); // 销售部门
            orderMap.put("textField_mno1zcbt", invoiceNo); // 发票号（已确保非空）

            // 明细数组
            List<Map<String, Object>> details = new ArrayList<>();
            for (JSONObject row : rows) {
                Map<String, Object> detailMap = new LinkedHashMap<>();
                detailMap.put("textField_mno1zcbv", row.getString("FMATERIALID.FNumber"));//物料编码
                detailMap.put("textField_mno1zcbw", row.getString("FCustMatID.FNumber"));//客户物料编码
                detailMap.put("textField_mno1zcbx", row.getString("FCustMatName"));//客户物料名称
                detailMap.put("textField_mno1zcby", row.getString("F_UNW_BaseProperty_lad"));//规格型号
                detailMap.put("textField_mno1zcbz", row.getString("FMaterialName"));//物料名称
                detailMap.put("textField_mno1zcc0", row.getString("FPRICEUNITID.FName"));//计价单位
                detailMap.put("numberField_mno1zcc2", row.getString("FPriceQty"));//计价数量
                detailMap.put("numberField_mno1zcc3", row.getString("FEntryTaxRate"));//税率（%）
                detailMap.put("textField_mno1zcc5", row.getString("FAuxpropId.FF100001"));//厚度
                detailMap.put("numberField_mno1zcc6", row.getString("FBASICUNITQTY"));//计价基本数量
                detailMap.put("textField_mno1zcc7", row.getString("FLot.FNumber"));//批号
                detailMap.put("textField_mno1zcc8", row.getString("FORDERNUMBER"));//销售订单号
                detailMap.put("textField_mno1zcc9", row.getString("FORDERENTRYSEQ"));//销售订单行号
                detailMap.put("numberField_mno1zcca", row.getString("FSalQty"));//销售数量
                detailMap.put("textField_mno1zccb", row.getString("FSalUnitId.FName"));//销售单位
                detailMap.put("radioField_mno1zccc", row.getString("FIsFree").equals("true") ? "是" : "否");//是否赠品
                details.add(detailMap);
            }
            orderMap.put("tableField_mno1zcbu", details);

            /*写入宜搭*/
            List<Map> conditions = Arrays.asList(YDConf.searchCondition_TextFiled("textField_mno1zcbb", firstRow.getString("FBillNo"), "eq"));
            ydClient.operateData(YDParam.builder()
                    .formUuid("FORM-CEF87B7F64004AE1A1D9A2A3A8EC4986O1VK")
                    .searchCondition(JSONObject.toJSONString(conditions))
                    .formDataJson(JSONObject.toJSONString(orderMap))
                    .build(), YDConf.FORM_OPERATION.upsert).toString();
            orderList.add(orderMap);
        }

        log.info("开票单已同步");
    }

    @SneakyThrows
    @Override
    public void receivableNote() throws JsonProcessingException {
        K3CloudApi client = new K3CloudApi(initIden());
        int startRow = 0;
        int limit = 2000;
        BillQuery billQuery = new BillQuery();
        billQuery.setFormId("AR_receivable"); // 应收单
        billQuery.setFieldKeys("FBillTypeID.FName,FCUSTOMERID.FName,FSALEERID.FName,FSetAccountType,FBillNo,FCURRENCYID.FName,FSETTLEORGID.FName,FDATE,FENDDATE_H,FDocumentStatus,FPayConditon.FName,FSALEDEPTID.FName,F_UNW_Text_u4s,FMATERIALID.FNumber,FCustMatID.FNumber,FCustMatName,F_UNW_BaseProperty_lad,FMaterialName,FPRICEUNITID.FName,FPriceQty,FEntryTaxRate,FAuxpropId.FF100001,FBASICUNITQTY,FLot.FNumber,FORDERNUMBER,FORDERENTRYSEQ,FSalQty,FSalUnitId.FName,FIsFree");
        List<Map> filterString = new ArrayList<>();
        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",1,"","","0")); // 审核日期条件
        billQuery.setFilterString(filterString);
        billQuery.setLimit(limit);
        billQuery.setStartRow(startRow);
        String result = client.billQuery(JSONObject.toJSONString(billQuery));
        JSONArray jsonArray = JSONArray.parseArray(result);

        // 按 FBillNo 分组
        Map<String, List<JSONObject>> groupMap = new LinkedHashMap<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject item = jsonArray.getJSONObject(i);
            String billNo = item.getString("FBillNo");
            groupMap.computeIfAbsent(billNo, k -> new ArrayList<>()).add(item);
        }

        // 组装并同步到宜搭（应收单表单）
        List<Map<String, Object>> orderList = new ArrayList<>();
        for (Map.Entry<String, List<JSONObject>> entry : groupMap.entrySet()) {
            List<JSONObject> rows = entry.getValue();
            JSONObject firstRow = rows.get(0);

            // 二次确认：发票号必须为空（有发票号的跳过）
            String invoiceNo = firstRow.getString("F_UNW_Text_u4s");
            if (invoiceNo != null && !invoiceNo.trim().isEmpty()) {
                log.info("单据编号 {} 含有发票号，不符合应收单同步条件（需要无发票号），跳过", firstRow.getString("FBillNo"));
                continue;
            }

            // 组装主表数据
            Map<String, Object> orderMap = new LinkedHashMap<>();
            orderMap.put("textField_mno1zcb2", firstRow.getString("FBillTypeID.FName"));      // 单据类型
            orderMap.put("textField_mno1zcb3", firstRow.getString("FCUSTOMERID.FName"));     // 客户
            orderMap.put("textField_mno1zcb4", firstRow.getString("FSALEERID.FName"));          // 销售员
            // 立账类型转换
            String FSetAccountType = "";
            switch (firstRow.getString("FSetAccountType")){
                case "1": FSetAccountType = "业务应收"; break;
                case "2": FSetAccountType = "暂估应收"; break;
                case "3": FSetAccountType = "财务应收"; break;
            }
            orderMap.put("textField_mno1zcb5", FSetAccountType);//立账类型
            orderMap.put("textField_mno1zcbb", firstRow.getString("FBillNo"));                 // 单据编号
            orderMap.put("textField_mno1zcbc", firstRow.getString("FCURRENCYID.FName"));     // 币别
            orderMap.put("textField_mno1zcbd", firstRow.getString("FSETTLEORGID.FName"));   // 结算组织
            String fDateRaw = firstRow.getString("FDATE");
            String formattedDate = (fDateRaw != null && fDateRaw.contains("T")) ? fDateRaw.split("T")[0] : fDateRaw;
            orderMap.put("textField_mno1zcbe", formattedDate);                                   // 业务日期
            String fDateRaw_A = firstRow.getString("FENDDATE_H");
            String formattedDate_A = (fDateRaw_A != null && fDateRaw_A.contains("T")) ? fDateRaw_A.split("T")[0] : fDateRaw_A;
            orderMap.put("textField_mno1zcbk", formattedDate_A);                             // 到期日
            orderMap.put("textField_mno1zcbl", firstRow.getString("FPayConditon.FName"));// 收款条件
            // 单据状态转换
            String FDocumentStatus = "";
            switch (firstRow.getString("FDocumentStatus")){
                case "A": FDocumentStatus = "创建"; break;
                case "B": FDocumentStatus = "审核中"; break;
                case "C": FDocumentStatus = "已审核"; break;
                case "D": FDocumentStatus = "重新审核"; break;
                case "Z": FDocumentStatus = "暂存"; break;
            }
            orderMap.put("textField_mno1zcbm", FDocumentStatus);//单据状态
            orderMap.put("textField_mno1zcbn", firstRow.getString("FSALEDEPTID.FName"));     // 销售部门
            orderMap.put("textField_mno1zcbt", "");                                 // 留空

            // 明细数组（字段映射请对应应收单明细表）
            List<Map<String, Object>> details = new ArrayList<>();
            for (JSONObject row : rows) {
                Map<String, Object> detailMap = new LinkedHashMap<>();
                detailMap.put("textField_mno1zcbv", row.getString("FMATERIALID.FNumber"));//物料编码
                detailMap.put("textField_mno1zcbw", row.getString("FCustMatID.FNumber"));//客户物料编码
                detailMap.put("textField_mno1zcbx", row.getString("FCustMatName"));//客户物料名称
                detailMap.put("textField_mno1zcby", row.getString("F_UNW_BaseProperty_lad"));//规格型号
                detailMap.put("textField_mno1zcbz", row.getString("FMaterialName"));//物料名称
                detailMap.put("textField_mno1zcc0", row.getString("FPRICEUNITID.FName"));//计价单位
                detailMap.put("numberField_mno1zcc2", row.getString("FPriceQty"));//计价数量
                detailMap.put("numberField_mno1zcc3", row.getString("FEntryTaxRate"));//税率（%）
                detailMap.put("textField_mno1zcc5", row.getString("FAuxpropId.FF100001"));//厚度
                detailMap.put("numberField_mno1zcc6", row.getString("FBASICUNITQTY"));//计价基本数量
                detailMap.put("textField_mno1zcc7", row.getString("FLot.FNumber"));//批号
                detailMap.put("textField_mno1zcc8", row.getString("FORDERNUMBER"));//销售订单号
                detailMap.put("textField_mno1zcc9", row.getString("FORDERENTRYSEQ"));//销售订单行号
                detailMap.put("numberField_mno1zcca", row.getString("FSalQty"));//销售数量
                detailMap.put("textField_mno1zccb", row.getString("FSalUnitId.FName"));//销售单位
                detailMap.put("radioField_mno1zccc", row.getString("FIsFree").equals("true") ? "是" : "否");//是否赠品
                details.add(detailMap);
            }
            orderMap.put("tableField_mno1zcbu", details);

            // 写入宜搭
            List<Map> conditions = Arrays.asList(
                    YDConf.searchCondition_TextFiled("textField_mno1zcbb", firstRow.getString("FBillNo"), "eq")
            );
            ydClient.operateData(YDParam.builder()
                    .formUuid("FORM-5A0062877EC246959CE85BC7418D1204229L")
                    .searchCondition(JSONObject.toJSONString(conditions))
                    .formDataJson(JSONObject.toJSONString(orderMap))
                    .build(), YDConf.FORM_OPERATION.upsert).toString();
            orderList.add(orderMap);
        }

        log.info("应收单（无发票号）已同步，共处理 {} 张单据", orderList.size());
    }

    @SneakyThrows
    @Override
    public void customer() throws JsonProcessingException {
        K3CloudApi client = new K3CloudApi(initIden());
        int startRow = 0;
        int limit = 2000;
        BillQuery billQuery = new BillQuery();
        billQuery.setFormId("BD_Customer");//客户
        //客户编码 客户名称 业务员 销售员 销售部门 收款条件 行业 事业部 终端 纳税人登记号
        billQuery.setFieldKeys("FNumber,FName,F_UNW_Text_6mb,FSELLER.FName,FSALDEPTID.FName,FRECCONDITIONID.FName,F_UNW_Assistant_mo2.FDataValue,F_UNW_Assistant_9zp.FNumber,F_UNW_Assistant_qov.FNumber,FTAXREGISTERCODE");
        List<Map> filterString = new ArrayList<>();
//        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",3,"","","0"));//审核日期在今天之前N天以后
        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FCreateOrgId.FNumber","67","100","","","0"));//创建组织为100 宁波致微新材料科技有限公司
        billQuery.setFilterString(filterString);
        billQuery.setLimit(limit);
        billQuery.setStartRow(startRow);
        String result=client.billQuery(JSONObject.toJSONString(billQuery));
        JSONArray jsonArray = JSONArray.parseArray(result);
        // 遍历每条物料记录
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject item = jsonArray.getJSONObject(i);

            // 取出各个字段（注意类型转换）
            String bm = item.getString("FNumber");//客户编码
            String khmc = item.getString("FName");//客户名称

            String ywy = item.getString("F_UNW_Text_6mb");//业务员
            Map body = new HashMap();
            body.put("queryWord",ywy);
            body.put("offset",0);
            body.put("size",10);
            body.put("fullMatchField",1);
            String doPost = UtilHttp.doPost("https://api.dingtalk.com/v1.0/contact/users/search", ddClient.initTokenHeader(), null, body);
            JSONObject resp = JSON.parseObject(doPost);
            JSONArray ywy_array = resp != null ? resp.getJSONArray("list") : null;

            String xsbm = item.getString("FSALDEPTID.FName");//销售部门
            Map body_A = new HashMap();
            body_A.put("queryWord",xsbm);
            body_A.put("offset",0);
            body_A.put("size",10);
            // 获取部门搜索结果
            String doPost_A = UtilHttp.doPost("https://api.dingtalk.com/v1.0/contact/departments/search", ddClient.initTokenHeader(), null, body_A);
            JSONObject respA = JSON.parseObject(doPost_A);
            JSONArray aaary = respA != null ? respA.getJSONArray("list") : null;
            List<String> xsbm_array = new ArrayList<>();
            if (aaary != null && !aaary.isEmpty()) {
                xsbm_array = aaary.stream()
                        .map(Object::toString)
                        .collect(Collectors.toList());
            }
// 如果未查到部门，xsbm_array 保持为空列表

            String sktj = item.getString("FRECCONDITIONID.FName");//收款条件
            String hy = item.getString("F_UNW_Assistant_mo2.FDataValue");//行业
            String syb = item.getString("F_UNW_Assistant_9zp.FNumber");//事业部
            String zd = item.getString("F_UNW_Assistant_qov.FNumber");//终端
            String sh = item.getString("FTAXREGISTERCODE");//纳税登记号
            //TODO:向宜搭插入数据
//            String sc = "textField_mnr290ot, employeeField_lqanqe6n_id, employeeField_lqanqe6n_id, departmentSelectField_lympbaya, selectField_mnft99uc, selectField_lqanqe6t, selectField_mnft99ud, selectField_mnft99ue,textField_mn2k7pjl,textField_llujklkq";
            String sc = "textField_mnr290ot, textField_lqanqe6j, employeeField_lqanqe6n, departmentSelectField_lympbaya, selectField_lqanqe6t, selectField_mnft99uc, selectField_mnft99ud, selectField_mnft99ue, textField_mn2k7pjl, textField_llujklkq";
            List<Map> conditions = Arrays.asList( YDConf.searchCondition_TextFiled("textField_lqanqe6j", khmc, "eq"));//根据客户名称
            Map formData = UtilMap.map(sc,bm,khmc,ywy_array,xsbm_array,hy,sktj,syb,zd,sh,sh);
            ydClient.operateData(YDParam.builder()
                    .formUuid("FORM-A4C9F5F35B48419A9C607D3408ECAB02A7FL")
                    .searchCondition(JSONObject.toJSONString(conditions))
                    .formDataJson(JSONObject.toJSONString(formData))
                    .build(),YDConf.FORM_OPERATION.upsert);

        }
        log.info("客户已同步");
    }


    private McR saveToAudit(String formid, Object object) throws Exception {
        JSONObject resultObj = new JSONObject();
        K3CloudApi client = new K3CloudApi(initIden());
        String result=client.save(formid,JSONObject.toJSONString(UtilMap.map("Model",object)));
        resultObj.put("save",result);
        Gson gson = new Gson();
        RepoRet sRet = gson.fromJson(result, RepoRet.class);
        if (sRet.isSuccessfully()) {
            JsonObject jsonData = new JsonObject();
            jsonData.addProperty("Ids", sRet.getResult().getId());
            String result2=client.submit(formid, jsonData.toString());
            resultObj.put("save",result2);
            RepoRet sRet2 = gson.fromJson(result, RepoRet.class);
            if (sRet2.isSuccessfully()) {
                JsonObject jsonData3 = new JsonObject();
                jsonData3.addProperty("Ids", sRet2.getResult().getId());
                String result3 = client.audit(formid, jsonData3.toString());
                RepoRet repoRet3 = gson.fromJson(result3, RepoRet.class);
                if (repoRet3.getResult().getResponseStatus().isIsSuccess()) {
                    log.info("审批通过，新增完成");
                    return McR.success(resultObj);
                }
            }
        }
        return McR.error("203",JSONObject.toJSONString(resultObj));
    }


    private IdentifyInfo initIden(){
        //注意 1：此处不再使用参数形式传入用户名及密码等敏感信息，改为在登录配置文件中设置。
        //注意 2：必须先配置第三方系统登录授权信息后，再进行业务操作，详情参考各语言版本SDK介绍中的登录配置文件说明。
        //读取配置，初始化SDK
        IdentifyInfo iden = new IdentifyInfo();
        iden.setUserName(kdWebApiConf.getXKDApiUserName());
        iden.setAppId(kdWebApiConf.getXKDApiAppID());
        iden.setdCID(kdWebApiConf.getXKDApiAcctID());
        iden.setAppSecret(kdWebApiConf.getXKDApiAppSec());
        iden.setServerUrl(kdWebApiConf.getXKDApiServerUrl());

        return iden;
    }


    /*TODO：钉钉获取应用token*/
    public McR Accesstoken() throws JsonProcessingException{
        HashMap body = new HashMap();
        body.put("appKey","dinga81qkwb0sqxqnviw");
        body.put("appSecret","IvePeLbMMxAzIr228RaGcOxgSSOuJ0trbenX3BbahjeLFA2YeaFv0W9F_6Ar5G0P");
        String doGet = UtilHttp.doPost("https://oapi.dingtalk.com/v1.0/oauth2/accessToken", null, null,body);
        JSONObject jsonObject = JSONObject.parseObject(doGet);
        String accessToken = jsonObject.getString("access_token");
        log.info("accessToken：{}",accessToken);
        return McR.success(accessToken);
    }

}
