CRK 1 mese fa
parent
commit
ffae09d5f5

+ 39 - 0
mjava-wlduijie/src/main/java/com/malk/model/h3yun/H3yunInventoryFields.java

@@ -0,0 +1,39 @@
+package com.malk.model.h3yun;
+
+/**
+ * 氚云盘点表单字段编码定义
+ *
+ * 表单编码:D293655safw79e8odkyyvqessgs9
+ *
+ * 业务说明:氚云采用批量盘点模式,主表记录盘点单据头信息,
+ * 明细子表记录各物料的盘点明细行,一个盘点单可包含多个物料明细。
+ */
+public final class H3yunInventoryFields {
+
+    private H3yunInventoryFields() {}
+
+    /** 氚云盘点表单编码 */
+    public static final String SCHEMA_CODE = "D293655safw79e8odkyyvqessgs9";
+
+    // ==================== 主表字段编码 ====================
+
+    /** 仓库编号 */
+    public static final String FIELD_WAREHOUSE_NO = "F0000001";
+
+    /** 盘点备注 */
+    public static final String FIELD_REMARK = "F0000002";
+
+    // ==================== 明细子表字段编码 ====================
+
+    /** 物料编码/商家编码 */
+    public static final String DETAIL_FIELD_SPEC_NO = "F0000001";
+
+    /** 盘点数量 */
+    public static final String DETAIL_FIELD_NEW_NUM = "F0000002";
+
+    /** 是否残次品 */
+    public static final String DETAIL_FIELD_DEFECT = "F0000003";
+
+    /** 明细备注 */
+    public static final String DETAIL_FIELD_REMARK = "F0000004";
+}

+ 25 - 9
mjava-wlh3tok3/src/main/java/com/malk/config/H3tok3Config.java

@@ -154,20 +154,30 @@ public class H3tok3Config {
      * API地址:https://api.wangdian.cn/openapi2/
      * API地址:https://api.wangdian.cn/openapi2/
      */
      */
     public static class WangdianConfig {
     public static class WangdianConfig {
-        /** 旺店通API基础地址 */
-        private String baseUrl = "https://api.wangdian.cn/openapi2/";
-        
-        /** 应用Key,用于API认证 */
+        /** 旺店通API基础地址(openapi2,用于RestTemplate方式调用),由配置文件注入 */
+        private String baseUrl;
+
+        /** 应用Key,用于API认证(openapi2) */
         private String appkey;
         private String appkey;
-        
-        /** 店铺ID,用于API认证 */
+
+        /** 店铺ID/卖家标识,用于API认证 */
         private String sid;
         private String sid;
-        
-        /** 应用密钥,用于生成签名 */
+
+        /** 应用密钥,用于生成签名(openapi2) */
         private String secret;
         private String secret;
 
 
+        // ========== SDK(openapi v1.0)配置 ==========
+        /** 旺店通ERP开放API服务器地址,SDK会在此基础上拼接 /openapi */
+        private String erpUrl = "http://wdt.wangdian.cn/";
+
+        /** 旺店通ERP开放API Key(openapi key) */
+        private String erpKey;
+
+        /** 旺店通ERP开放API Secret,格式:secret:salt */
+        private String erpSecret;
+
         // ==================== getter/setter ====================
         // ==================== getter/setter ====================
-        
+
         public String getBaseUrl() { return baseUrl; }
         public String getBaseUrl() { return baseUrl; }
         public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; }
         public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; }
         public String getAppkey() { return appkey; }
         public String getAppkey() { return appkey; }
@@ -176,5 +186,11 @@ public class H3tok3Config {
         public void setSid(String sid) { this.sid = sid; }
         public void setSid(String sid) { this.sid = sid; }
         public String getSecret() { return secret; }
         public String getSecret() { return secret; }
         public void setSecret(String secret) { this.secret = secret; }
         public void setSecret(String secret) { this.secret = secret; }
+        public String getErpUrl() { return erpUrl; }
+        public void setErpUrl(String erpUrl) { this.erpUrl = erpUrl; }
+        public String getErpKey() { return erpKey; }
+        public void setErpKey(String erpKey) { this.erpKey = erpKey; }
+        public String getErpSecret() { return erpSecret; }
+        public void setErpSecret(String erpSecret) { this.erpSecret = erpSecret; }
     }
     }
 }
 }

+ 90 - 0
mjava-wlh3tok3/src/main/java/com/malk/controller/WangdianSyncController.java

@@ -1,6 +1,8 @@
 package com.malk.controller;
 package com.malk.controller;
 
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.malk.model.SyncResult;
 import com.malk.model.WangdianResponse;
 import com.malk.model.WangdianResponse;
 import com.malk.service.h3yun.H3yunService;
 import com.malk.service.h3yun.H3yunService;
 import com.malk.service.sync.SyncService;
 import com.malk.service.sync.SyncService;
@@ -13,6 +15,9 @@ import org.springframework.web.bind.annotation.*;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 
 /**
 /**
  * 旺店通同步控制器
  * 旺店通同步控制器
@@ -36,6 +41,9 @@ public class WangdianSyncController {
 
 
     private static final Logger log = LoggerFactory.getLogger(WangdianSyncController.class);
     private static final Logger log = LoggerFactory.getLogger(WangdianSyncController.class);
 
 
+    /** 异步任务执行器 */
+    private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(4);
+
     @Autowired
     @Autowired
     private SyncService syncService;
     private SyncService syncService;
 
 
@@ -174,6 +182,87 @@ public class WangdianSyncController {
         }
         }
     }
     }
 
 
+    /**
+     * 氚云->旺店通 盘点单同步接口(通过SDK)
+     *
+     * 功能说明:根据氚云数据ID查询盘点表单数据,映射后通过SDK调用
+     *           wms.StockPd.stockSyncByPd 接口创建旺店通盘点单,
+     *           并将结果回写至氚云表单。
+     *
+     * 请求参数(JSON Body):
+     * - schemaCode: 氚云表单编码(盘点单表单)
+     * - objectId: 氚云数据ID
+     *
+     * 流程:
+     * 1. 立即返回"请求已接收"
+     * 2. 2秒后异步执行:
+     *    a. 更新氚云状态为"同步中"
+     *    b. 根据objectId查询氚云数据
+     *    c. 映射氚云数据为旺店通盘点单请求
+     *    d. 调用SDK的 wms.StockPd.stockSyncByPd 创建盘点单
+     *    e. 将结果(成功/失败、盘点单号)回写至氚云
+     *
+     * @return 立即返回接收结果,异步执行同步
+     */
+    @PostMapping("/h3yun-to-wangdian-pd")
+    public Map<String, Object> syncH3yunToWangdianPd(@RequestBody Map<String, String> data) {
+        final String schemaCode = data.get("schemaCode");
+        final String objectId = data.get("objectId");
+
+        log.info("收到氚云->旺店通盘点单同步请求, schemaCode: {}, objectId: {}, 2秒后异步执行", schemaCode, objectId);
+
+        // 立即返回成功
+        Map<String, Object> immediateResponse = new HashMap<>();
+        immediateResponse.put("success", true);
+        immediateResponse.put("message", "请求已接收,2秒后异步执行");
+        immediateResponse.put("schemaCode", schemaCode);
+        immediateResponse.put("objectId", objectId);
+
+        // 异步执行同步任务
+        executor.schedule(() -> {
+            try {
+                log.info("开始执行氚云->旺店通盘点单异步同步, objectId: {}", objectId);
+
+                // 1. 更新氚云数据状态为"同步中"
+                h3yunService.updateSyncStatus(schemaCode, objectId,
+                        H3yunService.SYNC_STATUS_SYNCING, "同步中", null);
+
+                // 2. 根据objectId查询氚云数据
+                JSONObject bizData = h3yunService.getBizObjectById(schemaCode, objectId);
+                if (bizData == null) {
+                    log.error("未查询到氚云数据, schemaCode: {}, objectId: {}", schemaCode, objectId);
+                    h3yunService.updateSyncStatus(schemaCode, objectId,
+                            H3yunService.SYNC_STATUS_FAIL, "未查询到氚云数据", null);
+                    return;
+                }
+
+                // 3. 映射氚云数据并调用SDK创建盘点单
+                SyncResult result = wangdianService.syncPdOrderFromH3yun(bizData, schemaCode);
+
+                // 4. 回写同步结果到氚云
+                if (result.isSuccess()) {
+                    h3yunService.updateSyncStatus(schemaCode, objectId,
+                            H3yunService.SYNC_STATUS_SUCCESS, "Success", result.getThirdBillNo());
+                    log.info("氚云->旺店通盘点单同步成功, objectId: {}, pdNo: {}", objectId, result.getThirdBillNo());
+                } else {
+                    h3yunService.updateSyncStatus(schemaCode, objectId,
+                            H3yunService.SYNC_STATUS_FAIL, result.getMessage(), null);
+                    log.error("氚云->旺店通盘点单同步失败, objectId: {}, error: {}", objectId, result.getMessage());
+                }
+            } catch (Exception e) {
+                log.error("异步同步盘点单任务异常, objectId: {}", objectId, e);
+                try {
+                    h3yunService.updateSyncStatus(schemaCode, objectId,
+                            H3yunService.SYNC_STATUS_FAIL, e.getMessage(), null);
+                } catch (Exception ex) {
+                    log.error("回写失败状态异常, objectId: {}", objectId, ex);
+                }
+            }
+        }, 2, TimeUnit.SECONDS);
+
+        return immediateResponse;
+    }
+
     /**
     /**
      * 回写同步状态到氚云
      * 回写同步状态到氚云
      */
      */
@@ -195,4 +284,5 @@ public class WangdianSyncController {
         result.put("message", message);
         result.put("message", message);
         return result;
         return result;
     }
     }
+
 }
 }

+ 18 - 18
mjava-wlh3tok3/src/main/java/com/malk/schedule/InventorySyncTask.java

@@ -194,19 +194,19 @@ public class InventorySyncTask {
     /**
     /**
      * 应用启动完成后立即执行一次金蝶库存汇总同步
      * 应用启动完成后立即执行一次金蝶库存汇总同步
      */
      */
-    @EventListener(ApplicationReadyEvent.class)
-    public void runInventorySyncOnStartup() {
-        log.info("应用启动完成,立即执行一次金蝶库存汇总同步任务");
-        executeKingdeeInventorySync();
-    }
+//    @EventListener(ApplicationReadyEvent.class)
+//    public void runInventorySyncOnStartup() {
+//        log.info("应用启动完成,立即执行一次金蝶库存汇总同步任务");
+//        executeKingdeeInventorySync();
+//    }
 
 
     /**
     /**
      * 每30分钟全量同步一次金蝶库存汇总到氚云分仓库存表
      * 每30分钟全量同步一次金蝶库存汇总到氚云分仓库存表
      */
      */
-    @Scheduled(cron = "0 0/20 * * * ?")
-    public void syncKingdeeInventorySumToH3yun() {
-        executeKingdeeInventorySync();
-    }
+//    @Scheduled(cron = "0 0/20 * * * ?")
+//    public void syncKingdeeInventorySumToH3yun() {
+//        executeKingdeeInventorySync();
+//    }
 
 
     /**
     /**
      * 每60分钟全量同步一次金蝶银行行名行号到氚云表
      * 每60分钟全量同步一次金蝶银行行名行号到氚云表
@@ -216,15 +216,15 @@ public class InventorySyncTask {
 //        executeKingdeeBankSync();
 //        executeKingdeeBankSync();
 //    }
 //    }
 
 
-    private void executeKingdeeInventorySync() {
-        log.info("开始执行金蝶库存汇总同步任务");
-        try {
-            Map<String, Object> result = syncService.syncKingdeeInventorySumToH3yun();
-            log.info("金蝶库存汇总同步完成, result: {}", JSONObject.toJSONString(result));
-        } catch (Exception e) {
-            log.error("执行金蝶库存汇总同步任务异常", e);
-        }
-    }
+//    private void executeKingdeeInventorySync() {
+//        log.info("开始执行金蝶库存汇总同步任务");
+//        try {
+//            Map<String, Object> result = syncService.syncKingdeeInventorySumToH3yun();
+//            log.info("金蝶库存汇总同步完成, result: {}", JSONObject.toJSONString(result));
+//        } catch (Exception e) {
+//            log.error("执行金蝶库存汇总同步任务异常", e);
+//        }
+//    }
 
 
     /**
     /**
      * 应用启动完成后立即执行一次金蝶银行行名行号同步
      * 应用启动完成后立即执行一次金蝶银行行名行号同步

+ 188 - 13
mjava-wlh3tok3/src/main/java/com/malk/service/wangdian/WangdianService.java

@@ -1,8 +1,17 @@
 package com.malk.service.wangdian;
 package com.malk.service.wangdian;
 
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.malk.config.H3tok3Config;
 import com.malk.config.H3tok3Config;
+import com.malk.model.SyncResult;
 import com.malk.model.WangdianResponse;
 import com.malk.model.WangdianResponse;
+import cn.wangdian.erp.sdk.Client;
+import cn.wangdian.erp.sdk.WdtErpException;
+import cn.wangdian.erp.sdk.api.wms.StockAPI;
+import cn.wangdian.erp.sdk.api.wms.dto.PdOrderCreateRequest;
+import cn.wangdian.erp.sdk.impl.ApiFactory;
+import cn.wangdian.erp.sdk.impl.DefaultClient;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -13,24 +22,24 @@ import java.util.*;
 
 
 /**
 /**
  * 旺店通 API 客户端服务
  * 旺店通 API 客户端服务
- * 
+ *
  * 功能说明:提供旺店通ERP系统的API调用能力,实现数据从氚云同步至旺店通
  * 功能说明:提供旺店通ERP系统的API调用能力,实现数据从氚云同步至旺店通
- * 
+ *
  * 对接方式:API调用(盘盈盘亏单)
  * 对接方式:API调用(盘盈盘亏单)
  * 认证方式:MD5签名认证
  * 认证方式:MD5签名认证
- * 
+ *
  * API地址:https://api.wangdian.cn/openapi2/
  * API地址:https://api.wangdian.cn/openapi2/
- * 
+ *
  * 签名算法:
  * 签名算法:
  * 1. 将所有参数(除sign外)按key升序排列
  * 1. 将所有参数(除sign外)按key升序排列
  * 2. 拼接成字符串:key1value1key2value2... + secret
  * 2. 拼接成字符串:key1value1key2value2... + secret
  * 3. MD5加密后转大写
  * 3. MD5加密后转大写
- * 
+ *
  * 接口清单(需求文档3.3.1):
  * 接口清单(需求文档3.3.1):
  * | 业务对象 | 源系统 | 目标接口  | 方法 | 核心字段映射                    |
  * | 业务对象 | 源系统 | 目标接口  | 方法 | 核心字段映射                    |
  * | 盘盈单   | 氚云   | stock_pd_add | POST | 仓库编码->warehouse_no, 物料编码->spec_no, 盈余数量->num, order_type->1 |
  * | 盘盈单   | 氚云   | stock_pd_add | POST | 仓库编码->warehouse_no, 物料编码->spec_no, 盈余数量->num, order_type->1 |
  * | 盘亏单   | 氚云   | stock_pd_add | POST | 仓库编码->warehouse_no, 物料编码->spec_no, 亏损数量->num, order_type->2 |
  * | 盘亏单   | 氚云   | stock_pd_add | POST | 仓库编码->warehouse_no, 物料编码->spec_no, 亏损数量->num, order_type->2 |
- * 
+ *
  * 使用场景:
  * 使用场景:
  * - 氚云盘点表单审核后,根据差异结果同步至旺店通ERP
  * - 氚云盘点表单审核后,根据差异结果同步至旺店通ERP
  * - 盘盈单调整库存增加,盘亏单调整库存减少
  * - 盘盈单调整库存增加,盘亏单调整库存减少
@@ -50,16 +59,19 @@ public class WangdianService {
     /** 盘亏单类型 */
     /** 盘亏单类型 */
     public static final int ORDER_TYPE_LOSS = 2;
     public static final int ORDER_TYPE_LOSS = 2;
 
 
+    /** SDK 客户端(懒加载缓存) */
+    private volatile StockAPI stockAPI;
+
     /**
     /**
      * 创建盘盈盘亏单(单个物料)
      * 创建盘盈盘亏单(单个物料)
      */
      */
-    public WangdianResponse stockPdAdd(String warehouseNo, Integer orderType, 
+    public WangdianResponse stockPdAdd(String warehouseNo, Integer orderType,
                                        String specNo, Integer num, String remark) {
                                        String specNo, Integer num, String remark) {
         try {
         try {
             TreeMap<String, Object> params = new TreeMap<>();
             TreeMap<String, Object> params = new TreeMap<>();
             params.put("warehouse_no", warehouseNo);
             params.put("warehouse_no", warehouseNo);
             params.put("order_type", orderType);
             params.put("order_type", orderType);
-            
+
             Map<String, Object> item = new HashMap<>();
             Map<String, Object> item = new HashMap<>();
             item.put("spec_no", specNo);
             item.put("spec_no", specNo);
             item.put("num", num);
             item.put("num", num);
@@ -69,9 +81,9 @@ public class WangdianService {
             params.put("items", JSON.toJSONString(new Object[]{item}));
             params.put("items", JSON.toJSONString(new Object[]{item}));
 
 
             String response = execute("stock_pd_add", params);
             String response = execute("stock_pd_add", params);
-            log.info("旺店通盘盈盘亏单, warehouseNo: {}, orderType: {}, 响应: {}", 
+            log.info("旺店通盘盈盘亏单, warehouseNo: {}, orderType: {}, 响应: {}",
                     warehouseNo, orderType, response);
                     warehouseNo, orderType, response);
-            
+
             return JSON.parseObject(response, WangdianResponse.class);
             return JSON.parseObject(response, WangdianResponse.class);
         } catch (Exception e) {
         } catch (Exception e) {
             log.error("旺店通盘盈盘亏单异常, warehouseNo: {}, orderType: {}", warehouseNo, orderType, e);
             log.error("旺店通盘盈盘亏单异常, warehouseNo: {}, orderType: {}", warehouseNo, orderType, e);
@@ -134,7 +146,7 @@ public class WangdianService {
      */
      */
     private String execute(String method, Map<String, Object> params) {
     private String execute(String method, Map<String, Object> params) {
         long timestamp = System.currentTimeMillis();
         long timestamp = System.currentTimeMillis();
-        
+
         // 构建签名前的参数(包含认证参数和业务参数)
         // 构建签名前的参数(包含认证参数和业务参数)
         TreeMap<String, Object> signParams = new TreeMap<>();
         TreeMap<String, Object> signParams = new TreeMap<>();
         signParams.put("appkey", config.getWangdian().getAppkey());
         signParams.put("appkey", config.getWangdian().getAppkey());
@@ -143,7 +155,7 @@ public class WangdianService {
         signParams.put("timestamp", timestamp);
         signParams.put("timestamp", timestamp);
         signParams.put("v", 1);
         signParams.put("v", 1);
         signParams.putAll(params);
         signParams.putAll(params);
-        
+
         // 生成签名
         // 生成签名
         String sign = generateSign(signParams);
         String sign = generateSign(signParams);
 
 
@@ -172,7 +184,7 @@ public class WangdianService {
         }
         }
         // 追加密钥
         // 追加密钥
         sb.append(config.getWangdian().getSecret());
         sb.append(config.getWangdian().getSecret());
-        
+
         try {
         try {
             java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
             java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
             byte[] digest = md.digest(sb.toString().getBytes("UTF-8"));
             byte[] digest = md.digest(sb.toString().getBytes("UTF-8"));
@@ -189,4 +201,167 @@ public class WangdianService {
             throw new RuntimeException("MD5签名异常", e);
             throw new RuntimeException("MD5签名异常", e);
         }
         }
     }
     }
+
+    // ==================== SDK(openapi v1.0)方式调用 ====================
+
+    /**
+     * 获取SDK的StockAPI代理对象(懒加载,线程安全)
+     */
+    private StockAPI getStockAPI() {
+        if (stockAPI == null) {
+            synchronized (this) {
+                if (stockAPI == null) {
+                    H3tok3Config.WangdianConfig wc = config.getWangdian();
+                    log.info("初始化旺店通SDK客户端, sid: {}, erpUrl: {}, erpKey: {}", wc.getSid(), wc.getErpUrl(), wc.getErpKey());
+                    Client client = DefaultClient.get(wc.getSid(), wc.getErpUrl(), wc.getErpKey(), wc.getErpSecret());
+                    stockAPI = ApiFactory.get(client, StockAPI.class);
+                }
+            }
+        }
+        return stockAPI;
+    }
+
+    /**
+     * 通过SDK调用 wms.StockPd.stockSyncByPd 接口创建盘点单
+     *
+     * @param warehouseNo 仓库编号
+     * @param remark      盘点单备注
+     * @param detailList  盘点明细列表
+     * @return 旺店通返回结果(包含盘点单号等信息)
+     */
+    public Map<String, Object> createPdOrderBySdk(String warehouseNo, String remark,
+                                                  List<PdOrderCreateRequest.DetailDto> detailList) {
+        PdOrderCreateRequest.OrderDto orderDto = new PdOrderCreateRequest.OrderDto();
+        orderDto.setWarehouseNo(warehouseNo);
+        orderDto.setDefectMode(PdOrderCreateRequest.OrderDto.DEFECT_MODE_NORMAL);
+        orderDto.setRemark(remark);
+
+        log.info("SDK创建盘点单, warehouseNo: {}, remark: {}, detailCount: {}", warehouseNo, remark, detailList.size());
+        Map<String, Object> result = getStockAPI().createPdOrder(orderDto, detailList);
+        log.info("SDK创建盘点单响应: {}", result);
+        return result;
+    }
+
+    /**
+     * 从氚云数据映射并同步盘点单到旺店通(通过SDK)
+     *
+     * 功能说明:
+     * 1. 从氚云盘点表单JSON中提取仓库编码、明细行数据
+     * 2. 映射为旺店通 PdOrderCreateRequest 结构
+     * 3. 调用SDK的 wms.StockPd.stockSyncByPd 接口创建盘点单
+     *
+     * 氚云字段映射(请根据实际氚云表单字段编码调整):
+     * | 氚云字段        | 旺店通字段             | 说明           |
+     * | F_WAREHOUSE_NO  | OrderDto.warehouseNo  | 仓库编号       |
+     * | F_REMARK        | OrderDto.remark       | 盘点单备注     |
+     * | 明细.F_SPEC_NO  | DetailDto.specNo      | 商家编码/物料编码 |
+     * | 明细.F_NEW_NUM  | DetailDto.newNum      | 盘点数量       |
+     * | 明细.F_DEFECT   | DetailDto.defect      | 是否残次品     |
+     * | 明细.F_DETAIL_REMARK | DetailDto.remark | 明细备注       |
+     *
+     * @param bizData    氚云业务对象数据
+     * @param schemaCode 氚云表单编码(用于识别明细子表key)
+     * @return 同步结果
+     */
+    public SyncResult syncPdOrderFromH3yun(JSONObject bizData, String schemaCode) {
+        try {
+            // TODO: 请根据实际氚云盘点表单字段编码调整以下常量
+            // 主表字段编码
+            String FIELD_WAREHOUSE_NO = "F0000068";   // 仓库编号
+            String FIELD_REMARK = "F0000069";          // 盘点备注
+            // 明细子表字段编码
+            String DETAIL_FIELD_SPEC_NO = "F0000028";  // 物料编码/商家编码
+            String DETAIL_FIELD_NEW_NUM = "F0000064";  // 盘点数量
+            String DETAIL_FIELD_DEFECT = "F0000070";   // 是否残次品
+            String DETAIL_FIELD_REMARK = "F0000004";   // 明细备注
+            // 1. 提取主表数据
+            String warehouseNo = bizData.getString(FIELD_WAREHOUSE_NO);
+            String remark = bizData.getString(FIELD_REMARK);
+
+            // 盘点物料明细
+            JSONArray billentryArray = bizData.getJSONArray("D293655safw79e8odkyyvqessgs9");
+            // 3. 映射为旺店通盘点单明细
+            List<PdOrderCreateRequest.DetailDto> detailList = new ArrayList<>();
+            for (int i = 0; i < billentryArray.size(); i++) {
+                JSONObject detail = billentryArray.getJSONObject(i);
+                PdOrderCreateRequest.DetailDto detailDto = new PdOrderCreateRequest.DetailDto();
+
+                String specNo = detail.getString(DETAIL_FIELD_SPEC_NO);
+                if (specNo == null || specNo.trim().isEmpty()) {
+                    log.warn("第{}行明细物料编码为空, 跳过", i + 1);
+                    continue;
+                }
+                detailDto.setSpecNo(specNo);
+
+                String newNum = detail.getString(DETAIL_FIELD_NEW_NUM);
+                if (newNum == null) {
+                    newNum = "0";
+                }
+                detailDto.setNewNum(newNum);
+
+                String defect = detail.getString(DETAIL_FIELD_DEFECT);
+                defect = defect == "是" ? "true" : "false";
+                detailDto.setDefect(Boolean.valueOf(defect));
+
+                detailDto.setRemark(detail.getString(DETAIL_FIELD_REMARK));
+
+                detailList.add(detailDto);
+            }
+
+            if (detailList.isEmpty()) {
+                return SyncResult.fail("映射后明细行为空, 无有效物料编码");
+            }
+
+            // 4. 调用SDK创建盘点单
+            Map<String, Object> response = createPdOrderBySdk(warehouseNo, remark, detailList);
+
+            // 5. 解析结果
+            // SDK返回的Map中通常包含盘点单号等信息
+            String pdNo = null;
+            if (response != null) {
+                pdNo = response.get("pd_no") != null ? response.get("pd_no").toString() : null;
+                if (pdNo == null) {
+                    pdNo = response.get("order_no") != null ? response.get("order_no").toString() : null;
+                }
+            }
+
+            log.info("氚云数据同步盘点单到旺店通成功, warehouseNo: {}, pdNo: {}", warehouseNo, pdNo);
+            return SyncResult.success("同步成功", pdNo);
+
+        } catch (Exception e) {
+            String errorMsg = e.getMessage();
+            if (e.getCause() instanceof WdtErpException) {
+                WdtErpException wdtEx = (WdtErpException) e.getCause();
+                errorMsg = "旺店通返回错误[code=" + wdtEx.getCode() + "]: " + wdtEx.getMessage();
+                log.error("SDK调用旺店通盘点单异常, 错误码: {}, 消息: {}", wdtEx.getCode(), wdtEx.getMessage(), e);
+            } else {
+                log.error("同步盘点单到旺店通异常", e);
+            }
+            return SyncResult.fail(errorMsg);
+        }
+    }
+
+    /**
+     * 从氚云业务对象中查找明细子表数据
+     * 氚云的明细行数据通常以子表SchemaCode为key存储为JSONArray
+     */
+    private JSONArray findDetailArray(JSONObject bizData, String schemaCode) {
+        // 优先用schemaCode作为key查找
+        JSONArray arr = bizData.getJSONArray(schemaCode);
+        if (arr != null && !arr.isEmpty()) {
+            return arr;
+        }
+        // 遍历所有字段,找到第一个非空的JSONArray作为明细
+        for (String key : bizData.keySet()) {
+            Object val = bizData.get(key);
+            if (val instanceof JSONArray) {
+                JSONArray jsonArray = (JSONArray) val;
+                if (!jsonArray.isEmpty() && jsonArray.getJSONObject(0) != null) {
+                    log.info("通过key: {} 找到明细子表数据, 共{}行", key, jsonArray.size());
+                    return jsonArray;
+                }
+            }
+        }
+        return null;
+    }
 }
 }

+ 8 - 4
mjava-wlh3tok3/src/main/resources/application-dev.yml

@@ -31,10 +31,14 @@ h3tok3:
 
 
   # 旺店通配置(开发环境)
   # 旺店通配置(开发环境)
   wangdian:
   wangdian:
-    baseUrl: https://api.wangdian.cn/openapi2/
-    appkey: dev_appkey
-    sid: dev_sid
-    secret: dev_secret
+    baseUrl: http://47.92.239.46/openapi
+    appkey: wuliu03-gw
+    sid: wuliu03
+    secret: ff535fc6ad990f23cd922ccb730262fd:131258992040277018df44512822fc1d
+    # SDK(openapi v1.0)配置:创建盘点单等使用SDK调用
+    erpUrl: http://47.92.239.46/openapi
+    erpKey: wuliu03-gw
+    erpSecret: ff535fc6ad990f23cd922ccb730262fd:131258992040277018df44512822fc1d
 
 
   # 定时任务配置
   # 定时任务配置
   schedule:
   schedule:

+ 4 - 0
mjava-wlh3tok3/src/main/resources/application.yml

@@ -49,6 +49,10 @@ h3tok3:
     sid: your_sid
     sid: your_sid
     # 应用密钥
     # 应用密钥
     secret: your_secret
     secret: your_secret
+    # SDK(openapi v1.0)配置:创建盘点单等使用SDK调用
+    erpUrl: http://wdt.wangdian.cn/
+    erpKey: your_erp_key
+    erpSecret: your_erp_secret:your_erp_salt
 
 
   # 定时任务配置
   # 定时任务配置
 #  schedule:
 #  schedule: