|
|
@@ -0,0 +1,954 @@
|
|
|
+package com.malk.service.h3yun;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.malk.config.H3tok3Config;
|
|
|
+import com.malk.model.H3yunResponse;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.io.*;
|
|
|
+import java.net.HttpURLConnection;
|
|
|
+import java.net.URL;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 氚云 API 客户端服务
|
|
|
+ *
|
|
|
+ * 功能说明:提供氚云系统的API调用能力,实现数据从金蝶同步至氚云
|
|
|
+ *
|
|
|
+ * 对接方式:
|
|
|
+ * - API调用:CreateBizObject/UpdateFormData/QueryBizObjects
|
|
|
+ * - 认证方式:Header携带EngineCode和EngineSecret
|
|
|
+ *
|
|
|
+ * API地址:https://www.h3yun.com/OpenApi/Invoke
|
|
|
+ *
|
|
|
+ * 氚云表单编码(需求文档3.2.3):
|
|
|
+ * | 业务对象 | 表单编码(SchemaCode) | 说明 |
|
|
|
+ * | 采购入库单 | D293655srqj5uui3keso9oraeqm | 金蝶->氚云 |
|
|
|
+ * | 采购退料单 | D293655sjfn3c62rluwju0mozl3r | 金蝶->氚云 |
|
|
|
+ * | 销售出库单 | D293655suomjudbplkoxrgs42dqj | 金蝶->氚云 |
|
|
|
+ * | 销售退货单 | D293655sejcxgmmjpemkhfns2sv | 金蝶->氚云 |
|
|
|
+ *
|
|
|
+ * 状态回写字段(需求文档4.5):
|
|
|
+ * | 控件名称 | 控件编码 | 类型 | 说明 |
|
|
|
+ * | 同步状态 | F_SyncStatus | 单选框/下拉框 | 未同步/同步中/同步成功/同步失败 |
|
|
|
+ * | 返回信息 | F_ResultMsg | 多行文本框 | 错误详情或第三方单号 |
|
|
|
+ * | 第三方单号 | F_ThirdBillNo | 文本框 | 金蝶/旺店通单号 |
|
|
|
+ * | 同步时间 | F_SyncTime | 日期时间 | 最后同步时间 |
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class H3yunService {
|
|
|
+
|
|
|
+ // @Autowired
|
|
|
+// private H3yunService h3yunService;
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(H3yunService.class);
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private H3tok3Config config;
|
|
|
+
|
|
|
+ /** 连接超时时间(毫秒) */
|
|
|
+ private static final int CONNECT_TIMEOUT = 30000;
|
|
|
+
|
|
|
+ /** 读取超时时间(毫秒) */
|
|
|
+ private static final int READ_TIMEOUT = 60000;
|
|
|
+
|
|
|
+ // 氚云表单编码常量
|
|
|
+ /** 采购入库单表单编码 */
|
|
|
+ public static final String SCHEMA_PURCHASE_INSTOCK = "D293655srqj5uui3keso9oraeqm";
|
|
|
+ /** 采购退料单表单编码 */
|
|
|
+ public static final String SCHEMA_PURCHASE_RETURN = "D293655sjfn3c62rluwju0mozl3r";
|
|
|
+ /** 销售出库单表单编码 */
|
|
|
+ public static final String SCHEMA_SALE_OUTSTOCK = "D293655suomjudbplkoxrgs42dqj";
|
|
|
+ /** 销售退货单表单编码 */
|
|
|
+ public static final String SCHEMA_SALE_RETURN = "D293655sejcxgmmjpemkhfns2sv";
|
|
|
+
|
|
|
+ // 同步状态常量
|
|
|
+ /** 同步状态-未同步 */
|
|
|
+ public static final String SYNC_STATUS_PENDING = "未同步";
|
|
|
+ /** 同步状态-同步中 */
|
|
|
+ public static final String SYNC_STATUS_SYNCING = "同步中";
|
|
|
+ /** 同步状态-同步成功 */
|
|
|
+ public static final String SYNC_STATUS_SUCCESS = "同步成功";
|
|
|
+ /** 同步状态-同步失败 */
|
|
|
+ public static final String SYNC_STATUS_FAIL = "同步失败";
|
|
|
+
|
|
|
+ // 对接类型常量(用于氚云->金蝶同步)
|
|
|
+ /** 对接类型-供应商 */
|
|
|
+ public static final String SYNC_TYPE_SUPPLIER = "供应商档案";
|
|
|
+
|
|
|
+ /** 对接类型-客户 */
|
|
|
+ public static final String SYNC_TYPE_CUSTOMER = "客户档案";
|
|
|
+
|
|
|
+ /** 对接类型-物料 */
|
|
|
+ public static final String SYNC_TYPE_MATERIAL = "物料档案";
|
|
|
+
|
|
|
+ /** 对接类型-仓库 */
|
|
|
+ public static final String SYNC_TYPE_STOCK = "仓库档案";
|
|
|
+
|
|
|
+ /** 对接类型-采购申请单 */
|
|
|
+ public static final String SYNC_TYPE_PURCHASE_REQUISITION = "采购订单";
|
|
|
+
|
|
|
+ /** 对接类型-销售订单 */
|
|
|
+ public static final String SYNC_TYPE_SALE_ORDER = "销售订单";
|
|
|
+
|
|
|
+ /** 对接类型-收料通知单 */
|
|
|
+ public static final String SYNC_TYPE_PURCHASE_RECEIVE = "收料通知单";
|
|
|
+
|
|
|
+ /** 对接类型-采购退料申请 */
|
|
|
+ public static final String SYNC_TYPE_PURCHASE_RETURN = "采购退料申请";
|
|
|
+
|
|
|
+ /** 对接类型-发货通知单 */
|
|
|
+ public static final String SYNC_TYPE_DELIVERY_NOTICE = "发货通知单";
|
|
|
+
|
|
|
+ /** 对接类型-销售退货单 */
|
|
|
+ public static final String SYNC_TYPE_RETURN_REQUEST = "退货申请单";
|
|
|
+
|
|
|
+ /** 对接类型-付款申请单 */
|
|
|
+ public static final String SYNC_TYPE_PAYMENT_REQUEST = "采购付款单";
|
|
|
+
|
|
|
+ /** 对接类型-财务应付单 */
|
|
|
+ public static final String SYNC_TYPE_PAYABLE_BILL = "财务应付单";
|
|
|
+
|
|
|
+ /** 对接类型-采购发票 */
|
|
|
+ public static final String SYNC_TYPE_PURCHASE_INVOICE = "采购发票";
|
|
|
+
|
|
|
+ /** 对接类型-销售发票 */
|
|
|
+ public static final String SYNC_TYPE_SALES_INVOICE = "销售发票";
|
|
|
+
|
|
|
+ /** 对接类型-收款单 */
|
|
|
+ public static final String SYNC_TYPE_RECEIVE_BILL = "销售收款单";
|
|
|
+
|
|
|
+ /** 对接类型-开票申请单 */
|
|
|
+ public static final String SYNC_TYPE_INVOICE_APPLY = "开票申请@财务应收单";
|
|
|
+
|
|
|
+ public static final String SYNC_TYPE_PROJECT = "项目立项";
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建业务对象(标准格式)
|
|
|
+ *
|
|
|
+ * 氚云API标准格式:
|
|
|
+ * - ActionName: CreateBizObject
|
|
|
+ * - SchemaCode: 表单编码
|
|
|
+ * - BizObject: 表单数据JSON字符串
|
|
|
+ * - IsSubmit: 是否立即提交(可选)
|
|
|
+ *
|
|
|
+ * @param schemaCode 表单编码
|
|
|
+ * @param formData 表单数据
|
|
|
+ * @param isSubmit 是否立即提交(可选,默认为false)
|
|
|
+ * @return H3yunResponse
|
|
|
+ */
|
|
|
+ public H3yunResponse createBizObject(String schemaCode, Map<String, Object> formData, boolean isSubmit) {
|
|
|
+ try {
|
|
|
+ Map<String, Object> body = new HashMap<>();
|
|
|
+ body.put("ActionName", "CreateBizObject");
|
|
|
+ body.put("SchemaCode", schemaCode);
|
|
|
+ body.put("BizObject", JSON.toJSONString(formData));
|
|
|
+ body.put("IsSubmit", "true");
|
|
|
+
|
|
|
+
|
|
|
+ String response = execute(body);
|
|
|
+ log.info("氚云创建业务对象, schemaCode: {}, isSubmit: {}, 响应: {}", schemaCode, isSubmit, response);
|
|
|
+
|
|
|
+ return JSON.parseObject(response, H3yunResponse.class);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("氚云创建业务对象异常, schemaCode: {}", schemaCode, e);
|
|
|
+ throw new RuntimeException("氚云创建业务对象异常: " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建业务对象(默认不提交)
|
|
|
+ */
|
|
|
+ public H3yunResponse createBizObject(String schemaCode, Map<String, Object> formData) {
|
|
|
+ return createBizObject(schemaCode, formData, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新业务对象(标准格式)
|
|
|
+ *
|
|
|
+ * @param schemaCode 表单编码
|
|
|
+ * @param bizObjectId 业务对象ID
|
|
|
+ * @param formData 表单数据
|
|
|
+ * @param isSubmit 是否立即提交(可选,默认为false)
|
|
|
+ * @return H3yunResponse
|
|
|
+ */
|
|
|
+ public H3yunResponse updateBizObject(String schemaCode, String bizObjectId, Map<String, Object> formData, boolean isSubmit) {
|
|
|
+ try {
|
|
|
+ Map<String, Object> body = new HashMap<>();
|
|
|
+ body.put("ActionName", "UpdateBizObject");
|
|
|
+ body.put("SchemaCode", schemaCode);
|
|
|
+ body.put("BizObjectId", bizObjectId);
|
|
|
+ body.put("BizObject", JSON.toJSONString(formData));
|
|
|
+ if (isSubmit) {
|
|
|
+ body.put("IsSubmit", "true");
|
|
|
+ }
|
|
|
+
|
|
|
+ String response = execute(body);
|
|
|
+ log.info("氚云更新业务对象, schemaCode: {}, bizObjectId: {}, isSubmit: {}, 响应: {}", schemaCode, bizObjectId, isSubmit, response);
|
|
|
+
|
|
|
+ return JSON.parseObject(response, H3yunResponse.class);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("氚云更新业务对象异常, schemaCode: {}, bizObjectId: {}", schemaCode, bizObjectId, e);
|
|
|
+ throw new RuntimeException("氚云更新业务对象异常: " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新业务对象(默认不提交)
|
|
|
+ */
|
|
|
+ public H3yunResponse updateBizObject(String schemaCode, String bizObjectId, Map<String, Object> formData) {
|
|
|
+ return updateBizObject(schemaCode, bizObjectId, formData, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新表单数据(标准格式)
|
|
|
+ *
|
|
|
+ * @param schemaCode 表单编码
|
|
|
+ * @param objectId 业务对象ID
|
|
|
+ * @param data 表单数据
|
|
|
+ * @param isSubmit 是否立即提交(可选,默认为false)
|
|
|
+ * @return H3yunResponse
|
|
|
+ */
|
|
|
+ public H3yunResponse updateFormData(String schemaCode, String objectId, Map<String, Object> data, boolean isSubmit) {
|
|
|
+ try {
|
|
|
+ Map<String, Object> body = new HashMap<>();
|
|
|
+ body.put("SchemaCode", schemaCode);
|
|
|
+ body.put("ActionName", "UpdateBizObject");
|
|
|
+ body.put("BizObjectId", objectId);
|
|
|
+ body.put("BizObject", JSON.toJSONString(data));
|
|
|
+ if (isSubmit) {
|
|
|
+ body.put("IsSubmit", "true");
|
|
|
+ }
|
|
|
+
|
|
|
+ String response = execute(body);
|
|
|
+ log.info("氚云更新表单数据, schemaCode: {}, objectId: {}, isSubmit: {}, 响应: {}", schemaCode, objectId, isSubmit, response);
|
|
|
+
|
|
|
+ return JSON.parseObject(response, H3yunResponse.class);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("氚云更新表单数据异常, schemaCode: {}, objectId: {}", schemaCode, objectId, e);
|
|
|
+ throw new RuntimeException("氚云更新表单数据异常: " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新表单数据(默认不提交)
|
|
|
+ */
|
|
|
+ public H3yunResponse updateFormData(String schemaCode, String objectId, Map<String, Object> data) {
|
|
|
+ return updateFormData(schemaCode, objectId, data, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询业务对象列表
|
|
|
+ */
|
|
|
+ public JSONObject queryBizObjects(String schemaCode, String filter, Integer pageSize, Integer pageIndex) {
|
|
|
+ try {
|
|
|
+ Map<String, Object> body = new HashMap<>();
|
|
|
+ body.put("SchemaCode", schemaCode);
|
|
|
+ body.put("ActionName", "LoadBizObjects");
|
|
|
+
|
|
|
+ // 构建分页和筛选参数
|
|
|
+ Map<String, Object> filterObj = new HashMap<>();
|
|
|
+ if (pageIndex != null && pageSize != null) {
|
|
|
+ filterObj.put("FromRowNum", pageIndex * pageSize);
|
|
|
+ filterObj.put("ToRowNum", pageIndex * pageSize + pageSize);
|
|
|
+ } else {
|
|
|
+ filterObj.put("FromRowNum", 0);
|
|
|
+ filterObj.put("ToRowNum", 500);
|
|
|
+ }
|
|
|
+ filterObj.put("RequireCount", false);
|
|
|
+ filterObj.put("ReturnItems", new JSONArray());
|
|
|
+ filterObj.put("SortByCollection", new JSONArray());
|
|
|
+
|
|
|
+ // 如果有自定义 filter,解析 Matcher 部分
|
|
|
+ if (filter != null && !filter.isEmpty()) {
|
|
|
+ // filter 格式: "F_SyncStatus = '未同步'"
|
|
|
+ // 转换为 Matcher 格式
|
|
|
+ filterObj.put("Matcher", parseSimpleFilterToMatcher(filter));
|
|
|
+ } else {
|
|
|
+ filterObj.put("Matcher", new JSONObject());
|
|
|
+ }
|
|
|
+
|
|
|
+ body.put("Filter", JSON.toJSONString(filterObj));
|
|
|
+
|
|
|
+ String response = execute(body);
|
|
|
+ log.info("氚云查询业务对象, schemaCode: {}, 响应: {}", schemaCode, response);
|
|
|
+
|
|
|
+ return JSON.parseObject(response);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("氚云查询业务对象异常, schemaCode: {}", schemaCode, e);
|
|
|
+ throw new RuntimeException("氚云查询业务对象异常: " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将简单 filter 转换为氚云 Matcher 格式
|
|
|
+ * 支持格式: "F_SyncStatus = '未同步'" 或 "F_SyncStatus = '未同步' OR F_SyncStatus = '同步失败'"
|
|
|
+ */
|
|
|
+ private JSONObject parseSimpleFilterToMatcher(String filter) {
|
|
|
+ JSONObject matcher = new JSONObject();
|
|
|
+ if (filter.contains(" OR ")) {
|
|
|
+ // 多个 OR 条件
|
|
|
+ matcher.put("Type", "Or");
|
|
|
+ JSONArray matchers = new JSONArray();
|
|
|
+ String[] conditions = filter.split(" OR ");
|
|
|
+ for (String condition : conditions) {
|
|
|
+ matchers.add(parseSingleCondition(condition.trim()));
|
|
|
+ }
|
|
|
+ matcher.put("Matchers", matchers);
|
|
|
+ } else if (filter.contains(" AND ")) {
|
|
|
+ // 多个 AND 条件
|
|
|
+ matcher.put("Type", "And");
|
|
|
+ JSONArray matchers = new JSONArray();
|
|
|
+ String[] conditions = filter.split(" AND ");
|
|
|
+ for (String condition : conditions) {
|
|
|
+ matchers.add(parseSingleCondition(condition.trim()));
|
|
|
+ }
|
|
|
+ matcher.put("Matchers", matchers);
|
|
|
+ } else {
|
|
|
+ // 单个条件
|
|
|
+ matcher.put("Type", "And");
|
|
|
+ JSONArray matchers = new JSONArray();
|
|
|
+ matchers.add(parseSingleCondition(filter.trim()));
|
|
|
+ matcher.put("Matchers", matchers);
|
|
|
+ }
|
|
|
+ return matcher;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析单个条件为 Matcher Item
|
|
|
+ */
|
|
|
+ private JSONObject parseSingleCondition(String condition) {
|
|
|
+ JSONObject item = new JSONObject();
|
|
|
+ item.put("Type", "Item");
|
|
|
+
|
|
|
+ // 解析 field = 'value' 格式
|
|
|
+ String[] parts = condition.split("=");
|
|
|
+ if (parts.length == 2) {
|
|
|
+ item.put("Name", parts[0].trim());
|
|
|
+ item.put("Operator", 2); // 2 表示等于
|
|
|
+ item.put("Value", parts[1].trim().replace("'", ""));
|
|
|
+ }
|
|
|
+
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查单据是否已存在(幂等性设计)
|
|
|
+ */
|
|
|
+ public boolean checkBillExists(String schemaCode, String billNo, String fieldName) {
|
|
|
+ try {
|
|
|
+ String filter = String.format("%s = '%s'", fieldName, billNo);
|
|
|
+ JSONObject result = queryBizObjects(schemaCode, filter, 1, 0);
|
|
|
+ JSONObject returnData = result.getJSONObject("ReturnData");
|
|
|
+ if (returnData != null) {
|
|
|
+ JSONArray bizObjectArray = returnData.getJSONArray("BizObjectArray");
|
|
|
+ return bizObjectArray != null && bizObjectArray.size() > 0;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("氚云检查单据是否存在异常, schemaCode: {}, billNo: {}", schemaCode, billNo, e);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取已存在的单据ID
|
|
|
+ */
|
|
|
+ public String getExistingBillId(String schemaCode, String billNo, String fieldName) {
|
|
|
+ try {
|
|
|
+ String filter = String.format("%s = '%s'", fieldName, billNo);
|
|
|
+ JSONObject result = queryBizObjects(schemaCode, filter, 1, 0);
|
|
|
+ JSONObject returnData = result.getJSONObject("ReturnData");
|
|
|
+ if (returnData != null) {
|
|
|
+ JSONArray bizObjectArray = returnData.getJSONArray("BizObjectArray");
|
|
|
+ if (bizObjectArray != null && bizObjectArray.size() > 0) {
|
|
|
+ return bizObjectArray.getJSONObject(0).getString("ObjectId");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("氚云获取已存在单据ID异常, schemaCode: {}, billNo: {}", schemaCode, billNo, e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据ObjectId查询单条业务对象
|
|
|
+ *
|
|
|
+ * 功能说明:根据氚云数据ID查询完整的业务对象数据
|
|
|
+ *
|
|
|
+ * @param schemaCode 表单编码
|
|
|
+ * @param objectId 数据对象ID
|
|
|
+ * @return 业务对象JSON数据
|
|
|
+ */
|
|
|
+ public JSONObject getBizObjectById(String schemaCode, String objectId) {
|
|
|
+ try {
|
|
|
+ // 先查询列表,再筛选ObjectId
|
|
|
+ String filter = String.format("ObjectId = '%s'", objectId);
|
|
|
+ JSONObject result = queryBizObjects(schemaCode, filter, 1, 0);
|
|
|
+
|
|
|
+ JSONObject returnData = result.getJSONObject("ReturnData");
|
|
|
+ if (returnData != null) {
|
|
|
+ JSONArray bizObjectArray = returnData.getJSONArray("BizObjectArray");
|
|
|
+ if (bizObjectArray != null && bizObjectArray.size() > 0) {
|
|
|
+ log.info("查询到氚云数据, schemaCode: {}, objectId: {}", schemaCode, objectId);
|
|
|
+ return bizObjectArray.getJSONObject(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.warn("未查询到氚云数据, schemaCode: {}, objectId: {}", schemaCode, objectId);
|
|
|
+ return null;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("查询氚云数据异常, schemaCode: {}, objectId: {}", schemaCode, objectId, e);
|
|
|
+ throw new RuntimeException("查询氚云数据异常: " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取业务对象中的字段值
|
|
|
+ *
|
|
|
+ * @param bizObject 业务对象JSON
|
|
|
+ * @param fieldName 字段名
|
|
|
+ * @return 字段值
|
|
|
+ */
|
|
|
+ public Object getFieldValue(JSONObject bizObject, String fieldName) {
|
|
|
+ if (bizObject == null || fieldName == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return bizObject.get(fieldName);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取氚云业务对象中指定字段的值
|
|
|
+ *
|
|
|
+ * 功能说明:根据表单编码、数据ID、字段编码获取该字段的值
|
|
|
+ *
|
|
|
+ * 使用示例:
|
|
|
+ * <pre>
|
|
|
+ * // 获取采购申请单的单号
|
|
|
+ * Object billNo = h3yunService.getFieldValueById("采购申请单SchemaCode", "objectId", "F0000001");
|
|
|
+ *
|
|
|
+ * // 获取客户名称
|
|
|
+ * Object customerName = h3yunService.getFieldValueById("销售订单SchemaCode", "objectId", "F0000003");
|
|
|
+ * </pre>
|
|
|
+ *
|
|
|
+ * @param schemaCode 表单编码(H3yunFormId)
|
|
|
+ * @param objectId 数据对象ID
|
|
|
+ * @param fieldId 字段编码(如F0000001、F0000002等)
|
|
|
+ * @return 字段值,如果未找到返回null
|
|
|
+ */
|
|
|
+ public Object getFieldValueById(String schemaCode, String objectId, String fieldId) {
|
|
|
+ JSONObject bizObject = getBizObjectById(schemaCode, objectId);
|
|
|
+ return getFieldValue(bizObject, fieldId);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据查询字段和字段值获取ObjectId
|
|
|
+ *
|
|
|
+ * 功能说明:根据表单编码、查询字段名、字段值,查询匹配的数据并返回其ObjectId
|
|
|
+ *
|
|
|
+ * 使用示例:
|
|
|
+ * <pre>
|
|
|
+ * // 根据单据编号查询ObjectId
|
|
|
+ * String objectId = h3yunService.getObjectIdByFieldValue("D293655srqj5uui3keso9oraeqm", "F0000001", "CGRK-001");
|
|
|
+ *
|
|
|
+ * // 根据客户编码查询ObjectId
|
|
|
+ * String objectId = h3yunService.getObjectIdByFieldValue("D293655sxvsttpe7re2tep6gvsdg", "F0000002", "KH001");
|
|
|
+ * </pre>
|
|
|
+ *
|
|
|
+ * @param schemaCode 表单编码
|
|
|
+ * @param fieldName 查询字段名(如F0000001等)
|
|
|
+ * @param fieldValue 查询字段的值
|
|
|
+ * @return 匹配数据的ObjectId,未找到返回null
|
|
|
+ */
|
|
|
+ public String getObjectIdByFieldValue(String schemaCode, String fieldName, String fieldValue) {
|
|
|
+ if (schemaCode == null || fieldName == null || fieldValue == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ String filter = String.format("%s = '%s'", fieldName, fieldValue);
|
|
|
+ JSONObject result = queryBizObjects(schemaCode, filter, 1, 0);
|
|
|
+ JSONObject returnData = result.getJSONObject("ReturnData");
|
|
|
+ if (returnData != null) {
|
|
|
+ JSONArray bizObjectArray = returnData.getJSONArray("BizObjectArray");
|
|
|
+ if (bizObjectArray != null && bizObjectArray.size() > 0) {
|
|
|
+ String objectId = bizObjectArray.getJSONObject(0).getString("ObjectId");
|
|
|
+ log.info("根据字段查询到ObjectId, schemaCode: {}, {}={}, objectId: {}", schemaCode, fieldName, fieldValue, objectId);
|
|
|
+ return objectId;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ log.warn("未查询到匹配数据, schemaCode: {}, {}={}", schemaCode, fieldName, fieldValue);
|
|
|
+ return null;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("根据字段查询ObjectId异常, schemaCode: {}, {}={}", schemaCode, fieldName, fieldValue, e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行氚云API请求
|
|
|
+ */
|
|
|
+ private String execute(Map<String, Object> body) throws IOException {
|
|
|
+ String jsonBody = JSON.toJSONString(body);
|
|
|
+ HttpURLConnection conn = null;
|
|
|
+ BufferedReader br = null;
|
|
|
+ StringBuilder result = new StringBuilder();
|
|
|
+
|
|
|
+ try {
|
|
|
+ URL url = new URL(config.getH3yun().getBaseUrl());
|
|
|
+ conn = (HttpURLConnection) url.openConnection();
|
|
|
+
|
|
|
+ conn.setRequestMethod("POST");
|
|
|
+ conn.setConnectTimeout(CONNECT_TIMEOUT);
|
|
|
+ conn.setReadTimeout(READ_TIMEOUT);
|
|
|
+ conn.setDoOutput(true);
|
|
|
+ conn.setDoInput(true);
|
|
|
+ conn.setUseCaches(false);
|
|
|
+ conn.setRequestProperty("accept", "*/*");
|
|
|
+ conn.setRequestProperty("connection", "Keep-Alive");
|
|
|
+ conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
|
|
|
+ conn.setRequestProperty("EngineCode", config.getH3yun().getEngineCode());
|
|
|
+ conn.setRequestProperty("EngineSecret", config.getH3yun().getEngineSecret());
|
|
|
+
|
|
|
+ conn.connect();
|
|
|
+
|
|
|
+ // 写入请求体
|
|
|
+ log.info("氚云API请求, url: {}, body: {}", config.getH3yun().getBaseUrl(), jsonBody);
|
|
|
+ try (OutputStream os = conn.getOutputStream()) {
|
|
|
+ os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
|
|
|
+ os.flush();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取响应码
|
|
|
+ int responseCode = conn.getResponseCode();
|
|
|
+ log.info("氚云API响应码: {}", responseCode);
|
|
|
+
|
|
|
+ // 根据响应码读取对应流
|
|
|
+ InputStream inputStream;
|
|
|
+ if (responseCode >= 200 && responseCode < 300) {
|
|
|
+ inputStream = conn.getInputStream();
|
|
|
+ } else {
|
|
|
+ inputStream = conn.getErrorStream();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (inputStream != null) {
|
|
|
+ br = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
|
|
|
+ String line;
|
|
|
+ while ((line = br.readLine()) != null) {
|
|
|
+ result.append(line);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ String responseStr = result.toString();
|
|
|
+ log.info("氚云API响应: {}", responseStr);
|
|
|
+
|
|
|
+ // 如果是错误响应,抛出异常
|
|
|
+ if (responseCode >= 400) {
|
|
|
+ throw new RuntimeException("氚云API请求失败, responseCode: " + responseCode + ", response: " + responseStr);
|
|
|
+ }
|
|
|
+
|
|
|
+ return responseStr;
|
|
|
+ } finally {
|
|
|
+ if (br != null) {
|
|
|
+ try {
|
|
|
+ br.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ log.warn("关闭BufferedReader异常", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (conn != null) {
|
|
|
+ conn.disconnect();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新同步状态(通用方法)
|
|
|
+ */
|
|
|
+ public H3yunResponse updateSyncStatus(String schemaCode, String objectId, String status, String message, String thirdBillNo) {
|
|
|
+ return updateSyncStatus(schemaCode, objectId, status, message, thirdBillNo, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新同步状态(带K3ID)
|
|
|
+ */
|
|
|
+ public H3yunResponse updateSyncStatus(String schemaCode, String objectId, String status, String message, String thirdBillNo, String k3Id) {
|
|
|
+ Map<String, Object> data = new HashMap<>();
|
|
|
+ data.put("SyncStatus", status);
|
|
|
+ data.put("ResultMsg", message);
|
|
|
+ data.put("ThirdBillNo", thirdBillNo);
|
|
|
+ data.put("SyncTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
|
|
|
+ if (k3Id != null) {
|
|
|
+ data.put("K3id", k3Id);
|
|
|
+ }
|
|
|
+
|
|
|
+ return updateFormData(schemaCode, objectId, data);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建采购入库单
|
|
|
+ */
|
|
|
+ public H3yunResponse createPurchaseInstock(String billNo, String billtypeId, JSONObject webhookData, String finalBilltypeName) {
|
|
|
+ Map<String, Object> formData = new HashMap<>();
|
|
|
+ formData.put("F0000041", billNo);
|
|
|
+ formData.put("F0000038", billtypeId);
|
|
|
+ formData.put("F0000023", finalBilltypeName);
|
|
|
+ formData.put("F0000028", webhookData.getString("biztime"));//业务日期 *
|
|
|
+ formData.put("F0000031", webhookData.getString("bookdate"));//记账日期
|
|
|
+ JSONObject org = webhookData.getJSONObject("bizorg");//采购组织
|
|
|
+ String orgNumber = org != null ? org.getString("number") : null;
|
|
|
+
|
|
|
+
|
|
|
+ formData.put("F0000030", this.getObjectIdByFieldValue("D29365537feb4e5e8644b21b7fd938dd322dab3", "F0000002", orgNumber));
|
|
|
+ formData.put("F0000024", this.getObjectIdByFieldValue("D29365537feb4e5e8644b21b7fd938dd322dab3", "F0000002", orgNumber));
|
|
|
+ //根据编号获取氚云集团公司ID
|
|
|
+ JSONObject supplier = webhookData.getJSONObject("supplier");//供货供应商
|
|
|
+ String supplierrNumber = supplier != null ? supplier.getString("number") : null;
|
|
|
+ formData.put("F0000029", this.getObjectIdByFieldValue("D293655b4a0a34e44914aee9613a7bd3957df83", "SeqNo", supplierrNumber));//根据编号获取氚云供应商ID
|
|
|
+
|
|
|
+
|
|
|
+ JSONArray billentry = webhookData.getJSONArray("billentry");//采购明细
|
|
|
+ List<Map<String, Object>> detailList = new ArrayList<>();
|
|
|
+ if (billentry != null && !billentry.isEmpty()) {
|
|
|
+ for (int i = 0; i < billentry.size(); i++) {
|
|
|
+ JSONObject entry = billentry.getJSONObject(i);
|
|
|
+ Map<String, Object> detail = new LinkedHashMap<>();
|
|
|
+ detail.put("F0000042", entry.getString("id"));//id
|
|
|
+ // 采购单
|
|
|
+ detail.put("F0000040", this.getObjectIdByFieldValue("D2936559700b1d66a0e4ee69a84e13da8dbbe95", "SeqNo", entry.getString("mainbillnumber")));
|
|
|
+
|
|
|
+ // 数量
|
|
|
+ Double qty = entry.getDouble("qty");
|
|
|
+ detail.put("F0000021", qty != null ? qty : 0);
|
|
|
+ detail.put("F0000036", qty != null ? qty : 0);
|
|
|
+ // 单位编码
|
|
|
+ detail.put("F0000043", entry.getString("actualtaxprice"));//单价
|
|
|
+ detail.put("F0000044", entry.getString("amountandtax"));//价税合计金额
|
|
|
+ JSONObject unit = entry.getJSONObject("unit");
|
|
|
+ detail.put("F0000034", unit != null ? this.getObjectIdByFieldValue("D293655248b1d9bf6c448f0a291341ec58bb943", "F0000001", unit.getString("number")) : null);
|
|
|
+ detail.put("F0000035", unit != null ? this.getObjectIdByFieldValue("D293655248b1d9bf6c448f0a291341ec58bb943", "F0000001", unit.getString("number")) : null);
|
|
|
+
|
|
|
+ // 仓库编码
|
|
|
+ JSONObject warehouse = entry.getJSONObject("warehouse");
|
|
|
+ detail.put("F0000037", warehouse != null ? this.getObjectIdByFieldValue("D293655scvrhqr64jemxdkqk6gf", "SeqNo", warehouse.getString("number")) : null);
|
|
|
+ String id = this.getObjectIdByFieldValue("D293655fc1a38f7956f400a886f376911a54a30", "K3id", entry.getString("materialmasterid"));
|
|
|
+ // 物料ID
|
|
|
+ detail.put("F0000032", id);
|
|
|
+ detail.put("F0000005", this.getFieldValueById("D293655fc1a38f7956f400a886f376911a54a30", id, "SeqNo"));
|
|
|
+ // 物料名称
|
|
|
+ detail.put("F0000004", entry.getString("materialname"));
|
|
|
+ detailList.add(detail);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ formData.put("D293655sdbobhrfwjkqhpapod1d3", detailList);
|
|
|
+
|
|
|
+
|
|
|
+ // 先创建采购入库单
|
|
|
+ H3yunResponse returnResponse = createBizObject(SCHEMA_PURCHASE_INSTOCK, formData);
|
|
|
+
|
|
|
+
|
|
|
+ return returnResponse;
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建采购退料单(金蝶->氚云)
|
|
|
+ */
|
|
|
+ public H3yunResponse createPurchaseReturn(String billNo, String billtypeId, JSONObject webhookData, String finalBilltypeName) {
|
|
|
+ Map<String, Object> formData = new HashMap<>();
|
|
|
+ // 1. 单据基本信息
|
|
|
+ formData.put("F0000042", billNo); // 单据编号
|
|
|
+ formData.put("K3id", billtypeId); // 单据ID
|
|
|
+ formData.put("F0000038", finalBilltypeName); // 单据类型名称
|
|
|
+ formData.put("F0000028", webhookData.getString("biztime")); // 业务日期
|
|
|
+
|
|
|
+ formData.put("F0000044", webhookData.getString("bookdate")); // 记账日期
|
|
|
+
|
|
|
+ // 2. 采购组织(从bizorg获取)
|
|
|
+ JSONObject org = webhookData.getJSONObject("bizorg");
|
|
|
+ String orgNumber = org != null ? org.getString("number") : null;
|
|
|
+ formData.put("F0000030", this.getObjectIdByFieldValue("D29365537feb4e5e8644b21b7fd938dd322dab3", "F0000002", orgNumber));
|
|
|
+ formData.put("F0000024", this.getObjectIdByFieldValue("D29365537feb4e5e8644b21b7fd938dd322dab3", "F0000002", orgNumber));
|
|
|
+
|
|
|
+ // 3. 供应商(从supplier获取)
|
|
|
+ JSONObject supplier = webhookData.getJSONObject("supplier");
|
|
|
+ String supplierNumber = supplier != null ? supplier.getString("number") : null;
|
|
|
+ formData.put("F0000029", this.getObjectIdByFieldValue("D293655b4a0a34e44914aee9613a7bd3957df83", "SeqNo", supplierNumber));
|
|
|
+
|
|
|
+ // 4. 业务类型
|
|
|
+ JSONObject biztype = webhookData.getJSONObject("biztype");
|
|
|
+ if (biztype != null) {
|
|
|
+ if (biztype.getString("number").equals("1101")) {
|
|
|
+ formData.put("F0000039", biztype.getString("number")); // 业务类型编码
|
|
|
+ } else {
|
|
|
+ formData.put("F0000039", biztype.getString("number")); // 业务类型编码
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+// // 5. 单据状态
|
|
|
+// formData.put("F0000044", webhookData.getString("billstatus")); // 单据状态
|
|
|
+
|
|
|
+ // 6. 明细行数据
|
|
|
+ JSONArray billentry = webhookData.getJSONArray("billentry");
|
|
|
+ List<Map<String, Object>> detailList = new ArrayList<>();
|
|
|
+ if (billentry != null && !billentry.isEmpty()) {
|
|
|
+ for (int i = 0; i < billentry.size(); i++) {
|
|
|
+ JSONObject entry = billentry.getJSONObject(i);
|
|
|
+ Map<String, Object> detail = new LinkedHashMap<>();
|
|
|
+ detail.put("F0000046", entry.getString("id"));//id
|
|
|
+ // 6.1 物料信息
|
|
|
+ JSONObject material = entry.getJSONObject("material");
|
|
|
+ String materialMasterId = entry.getString("materialmasterid");
|
|
|
+ if (materialMasterId != null) {
|
|
|
+ // 根据materialMasterId获取氚云物料ID
|
|
|
+ String materialId = this.getObjectIdByFieldValue("D293655fc1a38f7956f400a886f376911a54a30", "K3id", materialMasterId);
|
|
|
+ detail.put("F0000032", materialId); // 物料ID
|
|
|
+ detail.put("F0000005", this.getFieldValueById("D293655fc1a38f7956f400a886f376911a54a30", materialId, "SeqNo")); // 物料编码
|
|
|
+ }
|
|
|
+ // 物料名称
|
|
|
+ detail.put("F0000004", entry.getString("materialname"));
|
|
|
+ detail.put("F0000045", this.getObjectIdByFieldValue("D293655sdqwl9gil5u6s48bnv5f", "SeqNo", entry.getString("srcbillnumber")));
|
|
|
+
|
|
|
+ // 6.2 数量(退料数量为负数)
|
|
|
+ Double qty = entry.getDouble("qty");
|
|
|
+ detail.put("F0000043", qty != null ? qty : 0);
|
|
|
+ detail.put("F0000036", qty != null ? qty : 0);
|
|
|
+
|
|
|
+ // 6.3 单位
|
|
|
+ JSONObject unit = entry.getJSONObject("unit");
|
|
|
+ if (unit != null) {
|
|
|
+ String unitNumber = unit.getString("number");
|
|
|
+ detail.put("F0000034", this.getObjectIdByFieldValue("D293655248b1d9bf6c448f0a291341ec58bb943", "F0000001", unitNumber));
|
|
|
+ detail.put("F0000035", this.getObjectIdByFieldValue("D293655248b1d9bf6c448f0a291341ec58bb943", "F0000001", unitNumber));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6.4 仓库
|
|
|
+ JSONObject warehouse = entry.getJSONObject("warehouse");
|
|
|
+ if (warehouse != null) {
|
|
|
+ String warehouseNumber = warehouse.getString("number");
|
|
|
+ detail.put("F0000037", this.getObjectIdByFieldValue("D293655scvrhqr64jemxdkqk6gf", "SeqNo", warehouseNumber));
|
|
|
+ }
|
|
|
+
|
|
|
+// // 6.5 供应商(明细行供应商)
|
|
|
+// JSONObject invoiceSupplier = entry.getJSONObject("invoicesupplier");
|
|
|
+// if (invoiceSupplier != null) {
|
|
|
+// String invoiceSupplierNumber = invoiceSupplier.getString("number");
|
|
|
+// detail.put("F0000045", this.getObjectIdByFieldValue("D293655b4a0a34e44914aee9613a7bd3957df83", "SeqNo", invoiceSupplierNumber));
|
|
|
+// }
|
|
|
+
|
|
|
+// // 6.6 批次相关信息
|
|
|
+// detail.put("F0000046", entry.getString("lotnumber")); // 批次号
|
|
|
+// detail.put("F0000047", entry.getString("serialnumber")); // 序列号
|
|
|
+//
|
|
|
+// // 6.7 金额信息
|
|
|
+// detail.put("F0000048", entry.getDouble("amount")); // 金额
|
|
|
+// detail.put("F0000049", entry.getDouble("taxamount")); // 税额
|
|
|
+
|
|
|
+ detailList.add(detail);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 采购退料标明细(需要确认实际的子表字段编码)
|
|
|
+ formData.put("D293655sai676rs7hecwmz3mxdvf", detailList);
|
|
|
+
|
|
|
+ return createBizObject(SCHEMA_PURCHASE_RETURN, formData);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建销售出库单(金蝶->氚云)
|
|
|
+ */
|
|
|
+ public H3yunResponse createSaleOutstock(String billNo, String billtypeId, JSONObject webhookData, String finalBilltypeName) {
|
|
|
+ Map<String, Object> formData = new HashMap<>();
|
|
|
+ // 1. 单据基本信息
|
|
|
+ formData.put("F0000053", billNo); // 单据编号
|
|
|
+ formData.put("K3id", billtypeId); // 单据ID
|
|
|
+ formData.put("F0000054", finalBilltypeName); // 单据类型名称
|
|
|
+ formData.put("F0000021", webhookData.getString("biztime")); // 业务日期
|
|
|
+ // formData.put("F0000044", webhookData.getString("bookdate")); // 记账日期
|
|
|
+
|
|
|
+ // 2. 销售组织(从bizorg获取)
|
|
|
+ JSONObject org = webhookData.getJSONObject("bizorg");
|
|
|
+ String orgNumber = org != null ? org.getString("number") : null;
|
|
|
+ formData.put("F0000018", this.getObjectIdByFieldValue("D29365537feb4e5e8644b21b7fd938dd322dab3", "F0000002", orgNumber));
|
|
|
+ formData.put("F0000049", this.getObjectIdByFieldValue("D29365537feb4e5e8644b21b7fd938dd322dab3", "F0000002", orgNumber));
|
|
|
+
|
|
|
+ // 3. 客户(从customer获取,使用客户档案表)
|
|
|
+ JSONObject customer = webhookData.getJSONObject("customer");
|
|
|
+ String customerNumber = customer != null ? customer.getString("number") : null;
|
|
|
+ formData.put("F0000024", this.getObjectIdByFieldValue("D293655shuyz9ttzgkgmhaa4rglr", "SeqNo", customerNumber));
|
|
|
+ // 3. 店铺(从customer获取,使用客户档案表)
|
|
|
+ JSONObject Dianpu = webhookData.getJSONObject("al95_customer");
|
|
|
+ String al95_customer = Dianpu != null ? Dianpu.getString("number") : null;
|
|
|
+ formData.put("F0000023", this.getObjectIdByFieldValue("D293655shuyz9ttzgkgmhaa4rglr", "SeqNo", al95_customer));
|
|
|
+ // 4. 业务类型
|
|
|
+ JSONObject biztype = webhookData.getJSONObject("biztype");
|
|
|
+ if (biztype != null) {
|
|
|
+ formData.put("F0000055", biztype.getString("name")); // 业务类型
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 明细行数据
|
|
|
+ JSONArray billentry = webhookData.getJSONArray("billentry");
|
|
|
+ List<Map<String, Object>> detailList = new ArrayList<>();
|
|
|
+ if (billentry != null && !billentry.isEmpty()) {
|
|
|
+ for (int i = 0; i < billentry.size(); i++) {
|
|
|
+ JSONObject entry = billentry.getJSONObject(i);
|
|
|
+ Map<String, Object> detail = new LinkedHashMap<>();
|
|
|
+ detail.put("F0000061", entry.getString("id"));//id
|
|
|
+ // 5.1 物料信息
|
|
|
+ String materialMasterId = entry.getString("materialmasterid");
|
|
|
+ String materialname = entry.getString("materialname");
|
|
|
+ if (materialMasterId != null) {
|
|
|
+ String materialId = this.getObjectIdByFieldValue("D293655fc1a38f7956f400a886f376911a54a30", "K3id", materialMasterId);
|
|
|
+ detail.put("F0000027", materialId); // 物料ID
|
|
|
+ detail.put("F0000058", this.getFieldValueById("D293655fc1a38f7956f400a886f376911a54a30", materialId, "SeqNo")); // 物料编码
|
|
|
+ detail.put("F0000028", materialname); // 物料名称
|
|
|
+ detail.put("F0000029", this.getFieldValueById("D293655fc1a38f7956f400a886f376911a54a30", materialId, "F0000010")); // 物料规格型号
|
|
|
+//
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 5.2 源单关联(销售订单)
|
|
|
+ String srcbillnumber = entry.getString("srcbillnumber");
|
|
|
+ if (srcbillnumber != null && !srcbillnumber.isEmpty()) {
|
|
|
+ detail.put("F0000059", this.getObjectIdByFieldValue("D293655sv9ijeqmiakgclnrk7cwq", "SeqNo", srcbillnumber));
|
|
|
+ detail.put("F0000063", srcbillnumber);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5.3 数量
|
|
|
+ Double qty = entry.getDouble("qty");
|
|
|
+ detail.put("F0000031", qty != null ? qty : 0);
|
|
|
+ detail.put("F0000062", qty != null ? qty : 0);
|
|
|
+
|
|
|
+ // 5.4 单位
|
|
|
+ JSONObject unit = entry.getJSONObject("unit");
|
|
|
+ if (unit != null) {
|
|
|
+ String unitNumber = unit.getString("number");
|
|
|
+ detail.put("F0000030", this.getObjectIdByFieldValue("D293655248b1d9bf6c448f0a291341ec58bb943", "F0000001", unitNumber));
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5.5 仓库
|
|
|
+ JSONObject warehouse = entry.getJSONObject("warehouse");
|
|
|
+ if (warehouse != null) {
|
|
|
+ String warehouseNumber = warehouse.getString("number");
|
|
|
+ detail.put("F0000060", this.getObjectIdByFieldValue("D293655scvrhqr64jemxdkqk6gf", "SeqNo", warehouseNumber));
|
|
|
+ }
|
|
|
+
|
|
|
+ detailList.add(detail);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ formData.put("D293655sn7kin8gllkybwjwvmksy", detailList);
|
|
|
+
|
|
|
+ // 先创建销售出库单
|
|
|
+ H3yunResponse returnResponse = createBizObject(SCHEMA_SALE_OUTSTOCK, formData);
|
|
|
+
|
|
|
+
|
|
|
+ return returnResponse;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建销售退货单(金蝶->氚云)
|
|
|
+ */
|
|
|
+ public H3yunResponse createSaleReturn(String billNo, String billtypeId, JSONObject webhookData, String finalBilltypeName) {
|
|
|
+ Map<String, Object> formData = new HashMap<>();
|
|
|
+ // 1. 单据基本信息
|
|
|
+ formData.put("F0000063", billNo); // 单据编号
|
|
|
+ formData.put("K3id", billtypeId); // 单据ID
|
|
|
+ formData.put("F0000059", finalBilltypeName); // 单据类型名称
|
|
|
+ formData.put("F0000021", webhookData.getString("biztime")); // 业务日期
|
|
|
+
|
|
|
+
|
|
|
+ // 2. 销售组织(从bizorg获取)
|
|
|
+ JSONObject org = webhookData.getJSONObject("bizorg");
|
|
|
+ String orgNumber = org != null ? org.getString("number") : null;
|
|
|
+ formData.put("F0000018", this.getObjectIdByFieldValue("D29365537feb4e5e8644b21b7fd938dd322dab3", "F0000002", orgNumber));
|
|
|
+ formData.put("F0000049", this.getObjectIdByFieldValue("D29365537feb4e5e8644b21b7fd938dd322dab3", "F0000002", orgNumber));
|
|
|
+
|
|
|
+ // 3. 客户(从customer获取,使用客户档案表)
|
|
|
+ JSONObject customer = webhookData.getJSONObject("customer");
|
|
|
+ String customerNumber = customer != null ? customer.getString("number") : null;
|
|
|
+ formData.put("F0000024", this.getObjectIdByFieldValue("D293655shuyz9ttzgkgmhaa4rglr", "SeqNo", customerNumber));
|
|
|
+
|
|
|
+ // 4. 店铺(从al95_customer获取,使用客户档案表)
|
|
|
+ JSONObject al95Customer = webhookData.getJSONObject("al95_customer");
|
|
|
+ String al95CustomerNumber = al95Customer != null ? al95Customer.getString("number") : null;
|
|
|
+ formData.put("F0000023", this.getObjectIdByFieldValue("D293655shuyz9ttzgkgmhaa4rglr", "SeqNo", al95CustomerNumber));
|
|
|
+
|
|
|
+ // 5. 业务类型
|
|
|
+ JSONObject biztype = webhookData.getJSONObject("biztype");
|
|
|
+ if (biztype != null) {
|
|
|
+ formData.put("F0000060", biztype.getString("name")); // 业务类型
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6. 明细行数据
|
|
|
+ JSONArray billentry = webhookData.getJSONArray("billentry");
|
|
|
+ List<Map<String, Object>> detailList = new ArrayList<>();
|
|
|
+ if (billentry != null && !billentry.isEmpty()) {
|
|
|
+ for (int i = 0; i < billentry.size(); i++) {
|
|
|
+ JSONObject entry = billentry.getJSONObject(i);
|
|
|
+ Map<String, Object> detail = new LinkedHashMap<>();
|
|
|
+ detail.put("F0000067", entry.getString("id"));//id
|
|
|
+ // 6.1 物料信息
|
|
|
+ String materialMasterId = entry.getString("materialmasterid");
|
|
|
+ String materialName = entry.getString("materialname");
|
|
|
+ if (materialMasterId != null) {
|
|
|
+ String materialId = this.getObjectIdByFieldValue("D293655fc1a38f7956f400a886f376911a54a30", "K3id", materialMasterId);
|
|
|
+ detail.put("F0000027", materialId); // 物料ID
|
|
|
+ detail.put("F0000065", this.getFieldValueById("D293655fc1a38f7956f400a886f376911a54a30", materialId, "SeqNo")); // 物料编码
|
|
|
+ detail.put("F0000028", materialName); // 物料名称
|
|
|
+ detail.put("F0000029", this.getFieldValueById("D293655fc1a38f7956f400a886f376911a54a30", materialId, "F0000010")); // 物料规格型号
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6.2 源单关联(退货申请单)
|
|
|
+ String srcBillNumber = entry.getString("srcbillnumber");
|
|
|
+ if (srcBillNumber != null && !srcBillNumber.isEmpty()) {
|
|
|
+ detail.put("F0000066", this.getObjectIdByFieldValue("D293655sidsnhobdgeq6aauvwpu", "SeqNo", srcBillNumber));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6.3 数量(销售退货数量通常为负数)
|
|
|
+ Double qty = entry.getDouble("qty");
|
|
|
+ detail.put("F0000031", qty != null ? qty : 0);
|
|
|
+
|
|
|
+ // 6.4 单位
|
|
|
+ JSONObject unit = entry.getJSONObject("unit");
|
|
|
+ if (unit != null) {
|
|
|
+ String unitNumber = unit.getString("number");
|
|
|
+ detail.put("F0000030", this.getObjectIdByFieldValue("D293655248b1d9bf6c448f0a291341ec58bb943", "F0000001", unitNumber));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6.5 仓库
|
|
|
+ JSONObject warehouse = entry.getJSONObject("warehouse");
|
|
|
+ if (warehouse != null) {
|
|
|
+ String warehouseNumber = warehouse.getString("number");
|
|
|
+ detail.put("F0000062", this.getObjectIdByFieldValue("D293655scvrhqr64jemxdkqk6gf", "SeqNo", warehouseNumber));
|
|
|
+ }
|
|
|
+
|
|
|
+ detailList.add(detail);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // TODO: 请确认销售退货单明细子表的实际SchemaCode
|
|
|
+ formData.put("D293655sdverxsph60edltzkvgwg", detailList);
|
|
|
+
|
|
|
+ // 先创建销售退货单
|
|
|
+ H3yunResponse returnResponse = createBizObject(SCHEMA_SALE_RETURN, formData);
|
|
|
+
|
|
|
+
|
|
|
+ return returnResponse;
|
|
|
+
|
|
|
+ }
|
|
|
+}
|