3 커밋 1c06f3d021 ... bafef3afda

작성자 SHA1 메시지 날짜
  ct bafef3afda add:旺店通erp 2 주 전
  ct 7c1c68d9ff Merge remote-tracking branch 'origin/master' 2 주 전
  ct a59e044ace add:旺店通erp 2 주 전
63개의 변경된 파일7450개의 추가작업 그리고 23개의 파일을 삭제
  1. 16 0
      fs-service/pom.xml
  2. 138 0
      fs-service/src/main/java/com/fs/erp/converter/ErpWdtToErpOrderMapper.java
  3. 4 0
      fs-service/src/main/java/com/fs/erp/domain/ErpGoods.java
  4. 1 0
      fs-service/src/main/java/com/fs/erp/domain/ErpOrder.java
  5. 2 0
      fs-service/src/main/java/com/fs/erp/domain/ErpOrderQuery.java
  6. 72 0
      fs-service/src/main/java/com/fs/erp/domain/FsErpFinishPush.java
  7. 2 2
      fs-service/src/main/java/com/fs/erp/dto/ErpOrderResponse.java
  8. 154 0
      fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/api/WdtClient.java
  9. 128 0
      fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/AfterSaleStatusEnum.java
  10. 39 0
      fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/DeliveryTerm.java
  11. 36 0
      fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/FenxiaoType.java
  12. 41 0
      fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/PaymentStatus.java
  13. 46 0
      fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/RefundStatus.java
  14. 122 0
      fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/RefundTypeEnum.java
  15. 69 0
      fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/TradeStatus.java
  16. 146 0
      fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/utils/FileItem.java
  17. 129 0
      fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/utils/StringUtils.java
  18. 562 0
      fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/utils/WebUtils.java
  19. 179 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtApiRefund.java
  20. 40 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtApiResponse.java
  21. 63 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtBarcodeDto.java
  22. 42 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtBaseResponseDTO.java
  23. 32 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtBusinessRequestParams.java
  24. 36 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtCommonRequestParams.java
  25. 81 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtDiscountListDTO.java
  26. 227 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtGoodsDto.java
  27. 489 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtGoodsInfo.java
  28. 257 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtGoodsListDTO.java
  29. 100 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtOrder.java
  30. 20 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtRefundBusinessRequestParams.java
  31. 47 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtRefundOrder.java
  32. 35 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtRefundRequest.java
  33. 408 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtSpecDto.java
  34. 19 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtStockDTO.java
  35. 37 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtStockRespDTO.java
  36. 194 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtTrade.java
  37. 395 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtTradeDTO.java
  38. 910 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtTradeInfo.java
  39. 128 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtTradeQueryRequest.java
  40. 52 0
      fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtTradeQueryResponse.java
  41. 100 0
      fs-service/src/main/java/com/fs/erp/mapper/FsErpFinishPushMapper.java
  42. 1 0
      fs-service/src/main/java/com/fs/erp/service/IErpOrderService.java
  43. 5 0
      fs-service/src/main/java/com/fs/erp/service/impl/ErpOrderServiceImpl.java
  44. 119 0
      fs-service/src/main/java/com/fs/erp/service/impl/WdtErpGoodsServiceImpl.java
  45. 876 0
      fs-service/src/main/java/com/fs/erp/service/impl/WdtErpOrderServiceImpl.java
  46. 10 0
      fs-service/src/main/java/com/fs/his/config/FsSysConfig.java
  47. 6 0
      fs-service/src/main/java/com/fs/his/domain/FsStoreOrder.java
  48. 81 0
      fs-service/src/main/java/com/fs/his/domain/FsStoreProductGroup.java
  49. 22 0
      fs-service/src/main/java/com/fs/his/dto/StoreProductGroupDTO.java
  50. 73 0
      fs-service/src/main/java/com/fs/his/mapper/FsStoreProductGroupMapper.java
  51. 2 0
      fs-service/src/main/java/com/fs/his/mapper/FsStoreProductMapper.java
  52. 3 0
      fs-service/src/main/java/com/fs/his/service/IFsStoreOrderItemService.java
  53. 11 0
      fs-service/src/main/java/com/fs/his/service/IFsStoreOrderService.java
  54. 65 0
      fs-service/src/main/java/com/fs/his/service/IFsStoreProductGroupService.java
  55. 2 0
      fs-service/src/main/java/com/fs/his/service/IFsStoreProductService.java
  56. 1 1
      fs-service/src/main/java/com/fs/his/service/impl/FsExpressServiceImpl.java
  57. 7 0
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderItemServiceImpl.java
  58. 392 20
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  59. 99 0
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreProductGroupServiceImpl.java
  60. 5 0
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreProductServiceImpl.java
  61. 67 0
      fs-service/src/main/resources/mapper/his/FsStoreProductGroupMapper.xml
  62. 4 0
      fs-service/src/main/resources/mapper/his/FsStoreProductMapper.xml
  63. 1 0
      pom.xml

+ 16 - 0
fs-service/pom.xml

@@ -253,6 +253,22 @@
             <version>0.2.16</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct</artifactId>
+            <version>${org.mapstruct.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct-processor</artifactId>
+            <version>${org.mapstruct.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.hc</groupId>
+            <artifactId>openapi</artifactId>
+            <version>1.0</version>
+        </dependency>
+
     </dependencies>
 
 </project>

+ 138 - 0
fs-service/src/main/java/com/fs/erp/converter/ErpWdtToErpOrderMapper.java

@@ -0,0 +1,138 @@
+package com.fs.erp.converter;
+
+import cn.hutool.core.collection.CollectionUtil;
+import com.fs.erp.domain.ErpDeliverys;
+import com.fs.erp.domain.ErpOrderQuery;
+import com.fs.erp.dto.ErpOrderQueryResponse;
+import com.fs.erp.dto.wdt.ErpWdtTradeDTO;
+import com.fs.erp.dto.wdt.ErpWdtTradeInfo;
+import com.fs.erp.dto.wdt.ErpWdtTradeQueryResponse;
+import org.mapstruct.*;
+import org.mapstruct.factory.Mappers;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * ERP 订单查询 DTO 映射器.
+ * <p>
+ * 负责将 网店通(WDT)的订单查询响应 DTO 结构 {@link ErpWdtTradeQueryResponseDTO} 映射到
+ * 内部 ERP 订单查询响应 DTO 结构 {@link ErpOrderQueryResponse}。
+ * </p>
+ * <p>
+ * 主要映射逻辑包括:
+ * <ul>
+ *     <li>顶层响应状态和消息的映射。</li>
+ *     <li>将 WDT 订单列表 {@code trades} 映射到内部订单列表 {@code orders}。</li>
+ *     <li>将单个 WDT 订单 {@link ErpWdtTradeDTO} 映射到内部订单 {@link ErpOrderQuery}。</li>
+ *     <li>根据 WDT 订单状态推导内部订单的布尔状态字段(如:approve, cancle)。</li>
+ *     <li>处理数值类型转换(如:BigDecimal 到 Integer/Double)。</li>
+ *     <li>处理日期字符串到 Date 对象的转换。</li>
+ *     <li>将 WDT 订单的物流信息映射到一个包含单个元素的内部发货列表 {@code deliverys}。</li>
+ * </ul>
+ *
+ * @author xdd
+ * @since 2025-02-27
+ */
+@Mapper
+public interface ErpWdtToErpOrderMapper {
+
+    /**
+     * Mapper 实例,用于非 Spring 环境。
+     */
+    ErpWdtToErpOrderMapper INSTANCE = Mappers.getMapper(ErpWdtToErpOrderMapper.class);
+
+    /**
+     * 将网店通订单查询响应 DTO 映射到内部 ERP 订单查询响应 DTO。
+     *
+     * @param source 源对象,网店通订单查询响应 DTO ({@link ErpWdtTradeQueryResponse})。
+     * @return 目标对象,内部 ERP 订单查询响应 DTO ({@link ErpOrderQueryResponse})。
+     *         如果源对象为 null,则返回 null。
+     */
+
+    default ErpOrderQueryResponse toErpOrderQueryResponse(ErpWdtTradeQueryResponse source){
+        ErpOrderQueryResponse response = new ErpOrderQueryResponse();
+        List<ErpOrderQuery> erpOrderQueryList = new ArrayList<>();
+        if(CollectionUtil.isNotEmpty(source.getTrades())){
+            List<ErpWdtTradeInfo> trades = source.getTrades();
+            for (ErpWdtTradeInfo trade : trades) {
+                ErpOrderQuery erpOrderQuery = toErpOrderQuery(trade);
+                erpOrderQueryList.add(erpOrderQuery);
+            }
+        }
+        response.setOrders(erpOrderQueryList);
+        return response;
+    }
+
+    /**
+     * 将单个网店通订单 DTO 映射到内部 ERP 订单查询 DTO。
+     *
+     * @param source 源对象,单个网店通订单 DTO ({@link ErpWdtTradeDTO})。
+     * @return 目标对象,内部 ERP 订单查询 DTO ({@link ErpOrderQuery})。
+     *         如果源对象为 null,则返回 null。
+     */
+    default ErpOrderQuery toErpOrderQuery(ErpWdtTradeInfo source){
+        ErpOrderQuery erpOrderQuery = new ErpOrderQuery();
+        // 订单号
+        if(source.getSrcTids() != null) {
+            erpOrderQuery.setCode(source.getSrcTids());
+        }
+        // 商品数量
+        if(source.getGoodsCount() != null) {
+            erpOrderQuery.setQty(source.getGoodsCount().intValue());
+        }
+        // 商品金额
+        if(source.getGoodsAmount() != null){
+            erpOrderQuery.setAmount(source.getGoodsAmount().doubleValue());
+        }
+        // 支付金额
+        if(source.getPaid() != null){
+            erpOrderQuery.setPayment(source.getPaid().doubleValue());
+        }
+        // 快递编号
+        if(source.getLogisticsCode() != null){
+            erpOrderQuery.setExpress_code(source.getLogisticsCode());
+        }
+        // 快递名称
+        if(source.getLogisticsName() != null) {
+            erpOrderQuery.setExpress_name(source.getLogisticsName());
+        }
+
+        // 收货人
+        if(source.getReceiverName() != null) {
+            erpOrderQuery.setReceiver_name(source.getReceiverName());
+        }
+
+        // 电话
+        if(source.getReceiverMobile() != null) {
+            erpOrderQuery.setReceiver_mobile(source.getReceiverMobile());
+        }
+
+        //地址
+        if(source.getReceiverAddress() != null) {
+            erpOrderQuery.setReceiver_address(source.getReceiverAddress());
+        }
+
+        // 运单号
+        if(source.getLogisticsNo() != null){
+            erpOrderQuery.setExpress_code(source.getLogisticsNo());
+        }
+
+        // 订单状态
+        if(source.getTradeStatus() != null) {
+            erpOrderQuery.setDelivery_state(source.getTradeStatus());
+        }
+
+        ErpDeliverys erpDeliverys = new ErpDeliverys();
+        erpDeliverys.setExpress_code(source.getLogisticsCode());
+        erpDeliverys.setExpress_name(source.getLogisticsName());
+        erpDeliverys.setMail_no(source.getLogisticsNo());
+        erpDeliverys.setDelivery(true);
+
+        erpOrderQuery.setDeliverys(new ArrayList<>(Collections.singletonList(erpDeliverys)));
+        return erpOrderQuery;
+    }
+
+
+}

+ 4 - 0
fs-service/src/main/java/com/fs/erp/domain/ErpGoods.java

@@ -2,6 +2,7 @@ package com.fs.erp.domain;
 
 import lombok.Data;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 @Data
@@ -12,6 +13,9 @@ public class ErpGoods {
     String category_code;
     Integer item_add_attribute;
     Boolean combine;
+    BigDecimal cost_price;
+    BigDecimal sales_price;
+    BigDecimal purchase_price;
     String stock_status_code;
     List<ErpGoodsSku> skus;
     List<ErpCombineItem> combine_item;

+ 1 - 0
fs-service/src/main/java/com/fs/erp/domain/ErpOrder.java

@@ -30,5 +30,6 @@ public class ErpOrder {
     String receiver_address;
     String deal_datetime;
 
+    Integer isPackage;
     List<ErpOrderPayment> payments;
 }

+ 2 - 0
fs-service/src/main/java/com/fs/erp/domain/ErpOrderQuery.java

@@ -28,6 +28,8 @@ public class ErpOrderQuery {
     String receiver_address;
     Integer delivery_state;
 
+
+
     List<ErpDeliverys> deliverys;
 
 

+ 72 - 0
fs-service/src/main/java/com/fs/erp/domain/FsErpFinishPush.java

@@ -0,0 +1,72 @@
+package com.fs.erp.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+/**
+ * erp订单完成状态推送
+ *
+ * @author AutoGenerated
+ * @date CurrentDateTime  // 这里通常会是生成日期
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class FsErpFinishPush {
+
+    /**
+     * 主键,自增
+     */
+    private Long id;
+
+    /**
+     * 订单id,唯一标识订单
+     */
+    private Long orderId;
+
+    /**
+     * 任务状态:0-待处理,1-成功,2-失败,3-正在处理,4-已取消
+     */
+    private Integer taskStatus; // 或者使用 Byte
+
+    /**
+     * 重试次数,默认为 0
+     */
+    private Integer retryCount;
+
+    /**
+     * 上次执行时间,用于记录任务执行的最后时间
+     */
+    private Date lastExecuteTime;
+
+    /**
+     * 记录创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 记录更新时间
+     */
+    private Date updateTime;
+
+    /**
+     * 调用接口时传入的参数(JSON 格式)
+     */
+    private String params;
+
+    /**
+     * 调用接口返回的结果(JSON 格式)
+     */
+    private String result;
+
+    /**
+     * 错误信息(记录失败原因)
+     */
+    private String errorMessage;
+
+}

+ 2 - 2
fs-service/src/main/java/com/fs/erp/dto/ErpOrderResponse.java

@@ -4,6 +4,6 @@ import lombok.Data;
 
 @Data
 public class ErpOrderResponse extends BaseResponse {
-
-
+    private String requestRawData;
+    private String responseRawData;
 }

+ 154 - 0
fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/api/WdtClient.java

@@ -0,0 +1,154 @@
+package com.fs.erp.dto.sdk.wangdian.api;
+
+
+import com.fs.erp.dto.sdk.wangdian.utils.WebUtils;
+import com.fs.his.utils.ConfigUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * Wdt客户端
+ */
+@Component
+@Slf4j
+public class WdtClient {
+	@Autowired
+	ConfigUtil configUtil;
+
+
+
+	private String getAppKey() {
+		return configUtil.getSysConfig().getErpWdAppKey();
+	}
+
+	private String getAppsecret() {
+		return configUtil.getSysConfig().getErpWdAppsecret();
+	}
+	private String getSid() {
+		return configUtil.getSysConfig().getErpWdSid();
+	}
+	private String getBaseUrl() {
+		return configUtil.getSysConfig().getErpWdBaseUrl();
+	}
+
+	private int connectTimeout = 3000;//3秒
+	private int readTimeout = 15000;//15秒
+
+
+	private WdtClient(){}
+
+
+	private static String getStringFromException(Throwable e) {
+		String result = "";
+		ByteArrayOutputStream bos = new ByteArrayOutputStream();
+		PrintStream ps = new PrintStream(bos);
+		e.printStackTrace(ps);
+		try {
+			result = bos.toString("UTF-8");
+		} catch (IOException ioe) {
+		}
+		return result;
+	}
+
+	private static byte[] encryptMD5(String data) throws IOException {
+		byte[] bytes = null;
+		try {
+			MessageDigest md = MessageDigest.getInstance("MD5");
+			bytes = md.digest(data.getBytes("UTF-8"));
+		} catch (GeneralSecurityException gse) {
+			String msg = getStringFromException(gse);
+			throw new IOException(msg);
+		}
+		return bytes;
+	}
+
+	private static String byte2hex(byte[] bytes) {
+		StringBuilder sign = new StringBuilder();
+		for (int i = 0; i < bytes.length; i++) {
+			String hex = Integer.toHexString(bytes[i] & 0xFF);
+			if (hex.length() == 1) {
+				//保证所有的16进制都是两位:00-ff,其中[80~ff]代表[-128,-1]
+				sign.append("0");
+			}
+			sign.append(hex);
+		}
+		return sign.toString();
+	}
+
+	/**
+	 * 给TOP请求签名。
+	 *
+	 * @param params 所有字符型的TOP请求参数
+	 * @param appsecret 签名密钥
+	 * @return 签名
+	 * @throws IOException
+	 */
+	public static String signRequest(Map<String, String> params, String appsecret) throws IOException {
+		// 第一步:检查参数是否已经排序
+		String[] keys = params.keySet().toArray(new String[0]);
+		Arrays.sort(keys);
+
+		// 第二步:把所有参数名和参数值串在一起
+		StringBuilder query = new StringBuilder();
+		for (String key : keys) {
+			if("sign".equals(key))
+				continue;
+
+			if(query.length() > 0)
+				query.append(';');
+
+			int len = key.length();
+			query.append(String.format("%02d", len)).append('-').append(key).append(':');
+
+			String value = params.get(key);
+
+			len = value.length();
+			query.append(String.format("%04d", len)).append('-').append(value);
+
+		}
+
+		query.append(appsecret);
+
+		// 第三步:使用MD5加密
+		byte[] bytes = encryptMD5(query.toString());
+
+		// 第四步:把二进制转化为大写的十六进制
+		return byte2hex(bytes);
+	}
+
+	public String execute(String relativeUrl, Map<String, String> params) throws IOException {
+		String appkey = getAppKey();
+		String appsecret = getAppsecret();
+		String sid = getSid();
+		String baseUrl = getBaseUrl();
+
+		log.info("开始执行请求,相对路径:{},请求参数:{}", relativeUrl, params);
+
+
+		params.put("appkey", appkey);
+		params.put("sid", sid);
+		params.put("timestamp", Long.toString(System.currentTimeMillis()/1000));
+
+		String sign = signRequest(params, appsecret);
+		params.put("sign", sign);
+		log.info("计算签名完成, 签名为:{}",sign);
+		String url = baseUrl + relativeUrl;
+		long startTime = System.currentTimeMillis();
+		String response = WebUtils.doPost(url, params, "UTF-8", connectTimeout, readTimeout, null);
+		long endTime = System.currentTimeMillis();
+		long costTime = endTime - startTime;
+		// 打印 HTTP 请求的详细信息
+		log.info("请求URL: {}, 请求体: {}, 请求头: {}, 响应体: {}, 耗时: {} ms", url, params, null, response, costTime);
+		return response;
+	}
+}

+ 128 - 0
fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/AfterSaleStatusEnum.java

@@ -0,0 +1,128 @@
+package com.fs.erp.dto.sdk.wangdian.enums;
+
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 平台售后状态枚举
+ * <p>
+ * 该枚举定义了平台售后流程中的各个主要状态及其对应的编码和中文描述。
+ * 用于标识和管理售后订单的处理进度。
+ * </p>
+ * <ul>
+ *     <li>{@link #WAIT_SELLER_AGREE} - 申请退款/售后,等待商家处理</li>
+ *     <li>{@link #SELLER_REFUSE} - 商家拒绝</li>
+ *     <li>{@link #CLOSED} - 售后关闭</li>
+ *     <li>{@link #GOODS_RETURNING} - 买家待退货</li>
+ *     <li>{@link #GOODS_RECEIVING} - 商家待收货</li>
+ *     <li>{@link #SUCCESS} - 售后成功</li>
+ * </ul>
+ *
+ * @author xdd
+ * @since 2025-02-27
+ * @version 1.0
+ */
+@Getter // Lombok注解,自动为所有final字段生成getter方法
+public enum AfterSaleStatusEnum {
+
+    /**
+     * code: wait_seller_agree
+     * <p>
+     * 状态描述: 申请退款。买家已发起售后申请,等待商家审核同意。
+     * </p>
+     */
+    WAIT_SELLER_AGREE("wait_seller_agree", "申请退款"),
+
+    /**
+     * code: seller_refuse
+     * <p>
+     * 状态描述: 拒绝退款。商家审核后,不同意买家的售后申请。
+     * </p>
+     */
+    SELLER_REFUSE("seller_refuse", "拒绝退款"),
+
+    /**
+     * code: closed
+     * <p>
+     * 状态描述: 退款关闭。售后流程结束,可能由买家撤销、超时未处理、双方协商一致等原因导致关闭。
+     * </p>
+     */
+    CLOSED("closed", "退款关闭"),
+
+    /**
+     * code: goods_returning
+     * <p>
+     * 状态描述: 待退货。商家同意退货后,等待买家填写物流单号并寄回商品。
+     * </p>
+     */
+    GOODS_RETURNING("goods_returning", "待退货"),
+
+    /**
+     * code: goods_receiving
+     * <p>
+     * 状态描述: 待收货。买家已发货,等待商家确认收到退回的商品。
+     * </p>
+     */
+    GOODS_RECEIVING("goods_receiving", "待收货"),
+
+    /**
+     * code: success
+     * <p>
+     * 状态描述: 退款成功。售后流程已成功完成,款项已退还给买家或换货/维修已处理完毕。
+     * </p>
+     */
+    SUCCESS("success", "退款成功");
+
+    /**
+     * 状态编码
+     * <p>
+     * 对应平台内部或接口传输时使用的状态标识符。
+     * </p>
+     */
+    private final String code;
+
+    /**
+     * 状态描述
+     * <p>
+     * 对售后状态的中文解释,用于界面展示或日志记录。
+     * </p>
+     */
+    private final String description;
+
+    /**
+     * 枚举构造函数
+     *
+     * @param code        状态编码 (String)
+     * @param description 状态描述 (String)
+     */
+    AfterSaleStatusEnum(String code, String description) {
+        this.code = code;
+        this.description = description;
+    }
+
+    /**
+     * 根据状态编码获取对应的枚举实例
+     * <p>
+     * 提供一个便捷的方法,通过字符串编码查找对应的枚举常量。
+     * 比较时忽略大小写。
+     * </p>
+     *
+     * @param code 状态编码 (String)
+     * @return 对应的 {@code AfterSaleStatusEnum} 实例,如果 code 为 {@code null} 或未找到匹配项,则返回 {@code null}
+     */
+    public static AfterSaleStatusEnum getByCode(String code) {
+        if (code == null) {
+            return null; // 处理null输入
+        }
+        // 使用 Stream API 进行查找,忽略大小写进行匹配
+        return Arrays.stream(AfterSaleStatusEnum.values())
+                .filter(enumInstance -> enumInstance.getCode().equalsIgnoreCase(code)) // 忽略大小写比较
+                .findFirst() // 找到第一个匹配的
+                .orElse(null); // 如果找不到,返回null
+    }
+
+    // Lombok 的 @Getter 会自动生成以下公共方法:
+    // public String getCode() { return this.code; }
+    // public String getDescription() { return this.description; }
+}

+ 39 - 0
fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/DeliveryTerm.java

@@ -0,0 +1,39 @@
+package com.fs.erp.dto.sdk.wangdian.enums;
+
+public enum DeliveryTerm {
+    PAYMENT_BEFORE_DELIVERY(1, "款到发货"),
+    CASH_ON_DELIVERY(2, "货到付款(包含部分货到付款)"),
+    INSTALLMENT_PAYMENT(3, "分期付款"),
+    CREDIT_ACCOUNT(4, "挂账");
+
+    private final int value;
+    private final String description;
+
+    DeliveryTerm(int value, String description) {
+        this.value = value;
+        this.description = description;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * 根据状态值获取枚举实例
+     *
+     * @param value 状态值
+     * @return 对应的枚举实例,如果找不到则返回 null
+     */
+    public static DeliveryTerm fromValue(int value) {
+        for (DeliveryTerm term : DeliveryTerm.values()) {
+            if (term.value == value) {
+                return term;
+            }
+        }
+        return null;
+    }
+}

+ 36 - 0
fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/FenxiaoType.java

@@ -0,0 +1,36 @@
+package com.fs.erp.dto.sdk.wangdian.enums;
+
+public enum FenxiaoType {
+    DAIXIAO(1, "代销"),
+    JINGXIAO(2, "经销");
+
+    private final int value;
+    private final String description;
+
+    FenxiaoType(int value, String description) {
+        this.value = value;
+        this.description = description;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * 根据类型值获取枚举实例
+     * @param value 类型值
+     * @return 对应的枚举实例, 如果找不到则返回 null
+     */
+     public static FenxiaoType fromValue(int value){
+         for(FenxiaoType type : FenxiaoType.values()){
+             if(type.value == value){
+                 return  type;
+             }
+         }
+         return null;
+     }
+}

+ 41 - 0
fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/PaymentStatus.java

@@ -0,0 +1,41 @@
+package com.fs.erp.dto.sdk.wangdian.enums;
+
+/**
+ * 支付状态枚举类
+ */
+public enum PaymentStatus {
+    UNPAID(0, "未付款"),
+    PARTIALLY_PAID(1, "部分付款"),
+    FULLY_PAID(2, "已付款");
+
+    private final int value;
+    private final String description;
+
+    PaymentStatus(int value, String description) {
+        this.value = value;
+        this.description = description;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+     /**
+     * 根据状态值获取枚举实例
+     *
+     * @param value 状态值
+     * @return 对应的枚举实例,如果找不到则返回 null
+     */
+    public static PaymentStatus fromValue(int value) {
+        for (PaymentStatus status : PaymentStatus.values()) {
+            if (status.value == value) {
+                return status;
+            }
+        }
+        return null;
+    }
+}

+ 46 - 0
fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/RefundStatus.java

@@ -0,0 +1,46 @@
+package com.fs.erp.dto.sdk.wangdian.enums;
+
+public enum RefundStatus {
+    NO_REFUND(0, "无退款"),
+    CANCELED_REFUND(1, "取消退款"),
+    REFUND_APPLIED(2, "已申请退款"),
+    WAITING_FOR_RETURN(3, "等待退货"),
+    WAITING_FOR_RECEIPT(4, "等待收货"),
+    REFUND_SUCCESSFUL(5, "退款成功");
+
+    private final int value;
+    private final String description;
+
+    RefundStatus(int value, String description) {
+        this.value = value;
+        this.description = description;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * 根据状态值获取枚举实例
+     *
+     * @param value 状态值
+     * @return 对应的枚举实例,如果找不到则返回 null
+     */
+    public static RefundStatus fromValue(int value) {
+        for (RefundStatus status : RefundStatus.values()) {
+            if (status.value == value) {
+                return status;
+            }
+        }
+        return null;
+    }
+
+    // 可选:添加售前退款场景的特定方法(如果需要更精细的控制)
+    // 例如,可以根据具体的售前退款场景,提供一个方法来获取对应的 RefundStatus
+    // public static RefundStatus fromPreSaleScenario(PreSaleRefundScenario scenario) { ... }
+
+}

+ 122 - 0
fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/RefundTypeEnum.java

@@ -0,0 +1,122 @@
+package com.fs.erp.dto.sdk.wangdian.enums;
+
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * 退款类型枚举
+ * <p>
+ * 该枚举定义了系统支持的几种主要退款类型及其对应的编码和描述。
+ * 主要用于区分订单在不同状态或场景下的退款处理方式。
+ * </p>
+ * <ul>
+ *     <li>{@link #REFUND_BEFORE_SHIPPING} - 未发货仅退款</li>
+ *     <li>{@link #REFUND_WITHOUT_RETURN} - 已发货仅退款(无需退货)</li>
+ *     <li>{@link #RETURN_AND_REFUND} - 退货退款</li>
+ * </ul>
+ *
+ * @author xdd
+ * @since 2025-02-27
+ * @version 1.0
+ */
+@Getter // Lombok注解,自动为所有final字段生成getter方法
+public enum RefundTypeEnum {
+
+    /**
+     * type=1:退款(未发货退款)
+     * <p>
+     * 适用于买家已付款,但商家尚未发货的场景下,买家申请退款。
+     * </p>
+     */
+    REFUND_BEFORE_SHIPPING(1, "未发货退款"),
+
+    /**
+     * type=2:退款不退货
+     * <p>
+     * 适用于商家已发货,但由于特定原因(如商品无需寄回、商家协商同意等),
+     * 买家仅申请退款而无需退回货物。
+     * </p>
+     */
+    REFUND_WITHOUT_RETURN(2, "退款不退货"),
+
+    /**
+     * type=3:退货退款
+     * <p>
+     * 适用于商家已发货,买家收到货后因商品问题或其他原因需要退回商品并申请退款。
+     * (用户原始描述为 "退货",在此明确为包含退款流程)
+     * </p>
+     */
+    RETURN_AND_REFUND(3, "退货退款");
+
+    /**
+     * 类型编码
+     * <p>
+     * 与数据库或接口中表示退款类型的字段值对应。
+     * </p>
+     */
+    private final int code;
+
+    /**
+     * 类型描述
+     * <p>
+     * 对退款类型的中文说明,方便理解和展示。
+     * </p>
+     */
+    private final String description;
+
+    /**
+     * 枚举构造函数
+     *
+     * @param code        类型编码
+     * @param description 类型描述
+     */
+    RefundTypeEnum(int code, String description) {
+        this.code = code;
+        this.description = description;
+    }
+
+    /**
+     * 根据 code 获取对应的枚举实例
+     * <p>
+     * 提供一个便捷的方法,通过整数编码查找对应的枚举常量。
+     * </p>
+     *
+     * @param code 类型编码 (int)
+     * @return 对应的 {@code RefundTypeEnum} 实例,如果找不到则返回 {@code null}
+     */
+    public static RefundTypeEnum getByCode(int code) {
+        // 遍历枚举常量
+        for (RefundTypeEnum type : RefundTypeEnum.values()) {
+            if (type.getCode() == code) {
+                return type; // 找到匹配的code,返回对应的枚举实例
+            }
+        }
+        return null; // 没有找到匹配的code,返回null
+    }
+
+    /**
+     * 根据 code 获取对应的枚举实例 (Integer版本)
+     * <p>
+     * 提供一个处理 {@code Integer} 类型 code 的重载方法,增强兼容性。
+     * </p>
+     *
+     * @param code 类型编码 ({@code Integer})
+     * @return 对应的 {@code RefundTypeEnum} 实例,如果 code 为 {@code null} 或找不到则返回 {@code null}
+     */
+    public static RefundTypeEnum getByCode(Integer code) {
+        if (code == null) {
+            return null; // 处理null输入
+        }
+        // 使用 Java 8 Stream API 进行查找,更简洁
+        return Arrays.stream(RefundTypeEnum.values())
+                .filter(enumInstance -> Objects.equals(enumInstance.getCode(), code)) // 使用Objects.equals避免潜在的NullPointerException,虽然这里code已检查非null
+                .findFirst() // 找到第一个匹配的
+                .orElse(null); // 如果找不到,返回null
+    }
+
+    // Lombok 的 @Getter 会自动生成以下公共方法:
+    // public int getCode() { return this.code; }
+    // public String getDescription() { return this.description; }
+}

+ 69 - 0
fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/enums/TradeStatus.java

@@ -0,0 +1,69 @@
+package com.fs.erp.dto.sdk.wangdian.enums;
+
+public enum TradeStatus {
+
+    UNCONFIRMED(10, "未确认"),
+    WAITING_FOR_FINAL_PAYMENT(20, "待尾款"),
+    PAID_WAITING_FOR_SHIPMENT(30, "已付款待发货"),
+    PARTIALLY_SHIPPED(40, "部分发货"),
+    SHIPPED(50, "已发货"),
+    COMPLETED(70, "已完成"),
+    REFUNDED(80, "已退款"),
+    CLOSED(90, "已关闭");
+
+    private final int value;
+    private final String description;
+
+    TradeStatus(int value, String description) {
+        this.value = value;
+        this.description = description;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * 检查状态是否可以更新到新的状态
+     * @param newStatus 新的状态
+     * @return 是否可以更新
+     */
+    public boolean canUpdateTo(TradeStatus newStatus) {
+        // 状态值仅限从小向大更新,不支持逆向更新
+        if (this.value >= newStatus.value) {
+            return false;
+        }
+
+        // 特殊规则:30 只能变更为 70 或 80
+        if (this == PAID_WAITING_FOR_SHIPMENT &&
+            newStatus != COMPLETED && newStatus != REFUNDED) {
+            return false;
+        }
+
+        //已发货状态,在自建商城可以直接到完成状态70
+        if(this == SHIPPED && newStatus == COMPLETED){
+            return  true;
+        }
+
+        return true;
+    }
+
+     /**
+     * 根据状态值获取枚举实例
+     *
+     * @param value 状态值
+     * @return 对应的枚举实例,如果找不到则返回 null
+     */
+    public static TradeStatus fromValue(int value) {
+        for (TradeStatus status : TradeStatus.values()) {
+            if (status.value == value) {
+                return status;
+            }
+        }
+        return null;
+    }
+}

+ 146 - 0
fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/utils/FileItem.java

@@ -0,0 +1,146 @@
+package com.fs.erp.dto.sdk.wangdian.utils;
+
+import java.io.*;
+
+
+/**
+ * 文件元数据。
+ *
+ */
+public class FileItem {
+
+	private String fileName;
+	private String mimeType;
+	private byte[] content;
+	private File file;
+
+	/**
+	 * 基于本地文件的构造器。
+	 *
+	 * @param file 本地文件
+	 */
+	public FileItem(File file) {
+		this.file = file;
+	}
+
+	/**
+	 * 基于文件绝对路径的构造器。
+	 *
+	 * @param filePath 文件绝对路径
+	 */
+	public FileItem(String filePath) {
+		this(new File(filePath));
+	}
+
+	/**
+	 * 基于文件名和字节流的构造器。
+	 *
+	 * @param fileName 文件名
+	 * @param content 文件字节流
+	 */
+	public FileItem(String fileName, byte[] content) {
+		this.fileName = fileName;
+		this.content = content;
+	}
+
+	/**
+	 * 基于文件名、字节流和媒体类型的构造器。
+	 *
+	 * @param fileName 文件名
+	 * @param content 文件字节流
+	 * @param mimeType 媒体类型
+	 */
+	public FileItem(String fileName, byte[] content, String mimeType) {
+		this(fileName, content);
+		this.mimeType = mimeType;
+	}
+
+	public String getFileName() {
+		if (this.fileName == null && this.file != null && this.file.exists()) {
+			this.fileName = file.getName();
+		}
+		return this.fileName;
+	}
+
+	public String getMimeType() throws IOException {
+		if (this.mimeType == null) {
+			this.mimeType = getMimeType(getContent());
+		}
+		return this.mimeType;
+	}
+
+	/**
+	 * 获取文件的真实后缀名。目前只支持JPG, GIF, PNG, BMP四种图片文件。
+	 *
+	 * @param bytes 文件字节流
+	 * @return JPG, GIF, PNG or null
+	 */
+	public static String getFileSuffix(byte[] bytes) {
+		if (bytes == null || bytes.length < 10) {
+			return null;
+		}
+
+		if (bytes[0] == 'G' && bytes[1] == 'I' && bytes[2] == 'F') {
+			return "GIF";
+		} else if (bytes[1] == 'P' && bytes[2] == 'N' && bytes[3] == 'G') {
+			return "PNG";
+		} else if (bytes[6] == 'J' && bytes[7] == 'F' && bytes[8] == 'I' && bytes[9] == 'F') {
+			return "JPG";
+		} else if (bytes[0] == 'B' && bytes[1] == 'M') {
+			return "BMP";
+		} else {
+			return null;
+		}
+	}
+
+	/**
+	 * 获取文件的真实媒体类型。目前只支持JPG, GIF, PNG, BMP四种图片文件。
+	 *
+	 * @param bytes 文件字节流
+	 * @return 媒体类型(MEME-TYPE)
+	 */
+	public static String getMimeType(byte[] bytes) {
+		String suffix = getFileSuffix(bytes);
+		String mimeType;
+
+		if ("JPG".equals(suffix)) {
+			mimeType = "image/jpeg";
+		} else if ("GIF".equals(suffix)) {
+			mimeType = "image/gif";
+		} else if ("PNG".equals(suffix)) {
+			mimeType = "image/png";
+		} else if ("BMP".equals(suffix)) {
+			mimeType = "image/bmp";
+		}else {
+			mimeType = "application/octet-stream";
+		}
+
+		return mimeType;
+	}
+
+	public byte[] getContent() throws IOException {
+		if (this.content == null && this.file != null && this.file.exists()) {
+			InputStream in = null;
+			ByteArrayOutputStream out = null;
+
+			try {
+				in = new FileInputStream(this.file);
+				out = new ByteArrayOutputStream();
+				int ch;
+				while ((ch = in.read()) != -1) {
+					out.write(ch);
+				}
+				this.content = out.toByteArray();
+			} finally {
+				if (out != null) {
+					out.close();
+				}
+				if (in != null) {
+					in.close();
+				}
+			}
+		}
+		return this.content;
+	}
+
+}

+ 129 - 0
fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/utils/StringUtils.java

@@ -0,0 +1,129 @@
+package com.fs.erp.dto.sdk.wangdian.utils;
+
+
+/**
+ * 字符串工具类。
+ *
+ */
+public abstract class StringUtils {
+
+	private StringUtils() {}
+
+	/**
+	 * 检查指定的字符串是否为空。
+	 * <ul>
+	 * <li>SysUtils.isEmpty(null) = true</li>
+	 * <li>SysUtils.isEmpty("") = true</li>
+	 * <li>SysUtils.isEmpty("   ") = true</li>
+	 * <li>SysUtils.isEmpty("abc") = false</li>
+	 * </ul>
+	 *
+	 * @param value 待检查的字符串
+	 * @return true/false
+	 */
+	public static boolean isEmpty(String value) {
+		int strLen;
+		if (value == null || (strLen = value.length()) == 0) {
+			return true;
+		}
+		for (int i = 0; i < strLen; i++) {
+			if ((Character.isWhitespace(value.charAt(i)) == false)) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * 检查对象是否为数字型字符串,包含负数开头的。
+	 */
+	public static boolean isNumeric(Object obj) {
+		if (obj == null) {
+			return false;
+		}
+		char[] chars = obj.toString().toCharArray();
+		int length = chars.length;
+		if(length < 1)
+			return false;
+
+		int i = 0;
+		if(length > 1 && chars[0] == '-')
+			i = 1;
+
+		for (; i < length; i++) {
+			if (!Character.isDigit(chars[i])) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * 检查指定的字符串列表是否不为空。
+	 */
+	public static boolean areNotEmpty(String... values) {
+		boolean result = true;
+		if (values == null || values.length == 0) {
+			result = false;
+		} else {
+			for (String value : values) {
+				result &= !isEmpty(value);
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * 把通用字符编码的字符串转化为汉字编码。
+	 */
+	public static String unicodeToChinese(String unicode) {
+		StringBuilder out = new StringBuilder();
+		if (!isEmpty(unicode)) {
+			for (int i = 0; i < unicode.length(); i++) {
+				out.append(unicode.charAt(i));
+			}
+		}
+		return out.toString();
+	}
+
+	public static String toUnderlineStyle(String name) {
+		StringBuilder newName = new StringBuilder();
+		for (int i = 0; i < name.length(); i++) {
+			char c = name.charAt(i);
+			if (Character.isUpperCase(c)) {
+				if (i > 0) {
+					newName.append("_");
+				}
+				newName.append(Character.toLowerCase(c));
+			} else {
+				newName.append(c);
+			}
+		}
+		return newName.toString();
+	}
+
+	public static String convertString(byte[] data, int offset, int length) {
+		if (data == null) {
+			return null;
+		} else {
+			try {
+				return new String(data, offset, length, "UTF-8");
+			} catch (Exception e) {
+				throw new RuntimeException(e);
+			}
+		}
+	}
+
+	public static byte[] convertBytes(String data) {
+		if (data == null) {
+			return null;
+		} else {
+			try {
+				return data.getBytes("UTF-8");
+			} catch (Exception e) {
+				throw new RuntimeException(e);
+			}
+		}
+	}
+
+}

+ 562 - 0
fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/utils/WebUtils.java

@@ -0,0 +1,562 @@
+package com.fs.erp.dto.sdk.wangdian.utils;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+//import javax.net.ssl.HostnameVerifier;
+//import javax.net.ssl.HttpsURLConnection;
+//import javax.net.ssl.SSLContext;
+//import javax.net.ssl.SSLSession;
+//import javax.net.ssl.TrustManager;
+//import javax.net.ssl.X509TrustManager;
+
+
+/**
+ * 网络工具类。
+ *
+ */
+public abstract class WebUtils {
+
+	private static final String DEFAULT_CHARSET = "UTF-8";
+	private static final String METHOD_POST = "POST";
+	private static final String METHOD_GET = "GET";
+	//private static final Certificate verisign; // 根证书
+	//private static boolean ignoreSSLCheck; // 忽略SSL检查
+
+//	static {
+//		InputStream input = null;
+//		try {
+//			CertificateFactory cf = CertificateFactory.getInstance("X.509");
+//			input = WebUtils.class.getResourceAsStream("/verisign.crt");
+//			verisign = cf.generateCertificate(input);
+//		} catch (Exception e) {
+//			throw new RuntimeException(e);
+//		} finally {
+//			if (input != null) {
+//				try {
+//					input.close();
+//				} catch (IOException e) {
+//				}
+//			}
+//		}
+//	}
+
+//	public static class VerisignTrustManager implements X509TrustManager {
+//		public X509Certificate[] getAcceptedIssuers() {
+//			return null;
+//		}
+//
+//		public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+//		}
+//
+//		public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+//			Exception exp = null;
+//
+//			for (X509Certificate cert : chain) {
+//				cert.checkValidity(); // 验证证书有效期
+//				try {
+//					cert.verify(verisign.getPublicKey());// 验证签名
+//					exp = null;
+//					break;
+//				} catch (Exception e) {
+//					exp = e;
+//				}
+//			}
+//
+//			if (exp != null) {
+//				throw new CertificateException(exp);
+//			}
+//		}
+//	}
+//
+//	public static class TrustAllTrustManager implements X509TrustManager {
+//		public X509Certificate[] getAcceptedIssuers() {
+//			return null;
+//		}
+//
+//		public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+//		}
+//
+//		public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+//		}
+//	}
+
+	private WebUtils() {
+	}
+
+//	public static void setIgnoreSSLCheck(boolean ignoreSSLCheck) {
+//		WebUtils.ignoreSSLCheck = ignoreSSLCheck;
+//	}
+
+	/**
+	 * 执行HTTP POST请求。
+	 *
+	 * @param url 请求地址
+	 * @param params 请求参数
+	 * @return 响应字符串
+	 */
+	public static String doPost(String url, Map<String, String> params, int connectTimeout, int readTimeout) throws IOException {
+		return doPost(url, params, DEFAULT_CHARSET, connectTimeout, readTimeout);
+	}
+
+	/**
+	 * 执行HTTP POST请求。
+	 *
+	 * @param url 请求地址
+	 * @param params 请求参数
+	 * @param charset 字符集,如UTF-8, GBK, GB2312
+	 * @return 响应字符串
+	 */
+	public static String doPost(String url, Map<String, String> params, String charset, int connectTimeout, int readTimeout) throws IOException {
+		return doPost(url, params, charset, connectTimeout, readTimeout, null);
+	}
+
+	public static String doPost(String url, Map<String, String> params, String charset, int connectTimeout, int readTimeout, Map<String, String> headerMap) throws IOException {
+		String ctype = "application/x-www-form-urlencoded;charset=" + charset;
+		String query = buildQuery(params, charset);
+		byte[] content = {};
+		if (query != null) {
+			content = query.getBytes(charset);
+		}
+		return _doPost(url, ctype, content, connectTimeout, readTimeout, headerMap);
+	}
+
+	/**
+	 * 执行HTTP POST请求。
+	 *
+	 * @param url 请求地址
+	 * @param ctype 请求类型
+	 * @param content 请求字节数组
+	 * @return 响应字符串
+	 */
+	public static String doPost(String url, String ctype, byte[] content, int connectTimeout, int readTimeout) throws IOException {
+		return _doPost(url, ctype, content, connectTimeout, readTimeout, null);
+	}
+
+	private static String _doPost(String url, String ctype, byte[] content, int connectTimeout, int readTimeout, Map<String, String> headerMap) throws IOException {
+		HttpURLConnection conn = null;
+		OutputStream out = null;
+		String rsp = null;
+		try {
+			conn = getConnection(new URL(url), METHOD_POST, ctype, headerMap);
+			conn.setConnectTimeout(connectTimeout);
+			conn.setReadTimeout(readTimeout);
+
+			out = conn.getOutputStream();
+			out.write(content);
+
+			rsp = getResponseAsString(conn);
+		} finally {
+			if (out != null) {
+				out.close();
+			}
+			if (conn != null) {
+				conn.disconnect();
+			}
+		}
+
+		return rsp;
+	}
+
+	/**
+	 * 执行带文件上传的HTTP POST请求。
+	 *
+	 * @param url 请求地址
+	 * @param textParams 文本请求参数
+	 * @param fileParams 文件请求参数
+	 * @return 响应字符串
+	 */
+	public static String doPost(String url, Map<String, String> params, Map<String, FileItem> fileParams, int connectTimeout, int readTimeout) throws IOException {
+		if (fileParams == null || fileParams.isEmpty()) {
+			return doPost(url, params, DEFAULT_CHARSET, connectTimeout, readTimeout);
+		} else {
+			return doPost(url, params, fileParams, DEFAULT_CHARSET, connectTimeout, readTimeout);
+		}
+	}
+
+	public static String doPost(String url, Map<String, String> params, Map<String, FileItem> fileParams, String charset, int connectTimeout, int readTimeout) throws IOException {
+		return doPost(url, params, fileParams, charset, connectTimeout, readTimeout, null);
+	}
+
+	/**
+	 * 执行带文件上传的HTTP POST请求。
+	 *
+	 * @param url 请求地址
+	 * @param textParams 文本请求参数
+	 * @param fileParams 文件请求参数
+	 * @param charset 字符集,如UTF-8, GBK, GB2312
+	 * @param headerMap 需要传递的header头,可以为空
+	 * @return 响应字符串
+	 */
+	public static String doPost(String url, Map<String, String> params, Map<String, FileItem> fileParams, String charset,
+			int connectTimeout, int readTimeout, Map<String, String> headerMap) throws IOException {
+		if (fileParams == null || fileParams.isEmpty()) {
+			return doPost(url, params, charset, connectTimeout, readTimeout, headerMap);
+		} else {
+			return _doPostWithFile(url, params, fileParams, charset, connectTimeout, readTimeout, headerMap);
+		}
+	}
+
+	private static String _doPostWithFile(String url, Map<String, String> params, Map<String, FileItem> fileParams,
+			String charset, int connectTimeout, int readTimeout, Map<String, String> headerMap) throws IOException {
+		String boundary = String.valueOf(System.nanoTime()); // 随机分隔线
+		HttpURLConnection conn = null;
+		OutputStream out = null;
+		String rsp = null;
+		try {
+			String ctype = "multipart/form-data;charset=" + charset + ";boundary=" + boundary;
+			conn = getConnection(new URL(url), METHOD_POST, ctype, headerMap);
+			conn.setConnectTimeout(connectTimeout);
+			conn.setReadTimeout(readTimeout);
+
+			out = conn.getOutputStream();
+			byte[] entryBoundaryBytes = ("\r\n--" + boundary + "\r\n").getBytes(charset);
+
+			// 组装文本请求参数
+			Set<Entry<String, String>> textEntrySet = params.entrySet();
+			for (Entry<String, String> textEntry : textEntrySet) {
+				byte[] textBytes = getTextEntry(textEntry.getKey(), textEntry.getValue(), charset);
+				out.write(entryBoundaryBytes);
+				out.write(textBytes);
+			}
+
+			// 组装文件请求参数
+			Set<Entry<String, FileItem>> fileEntrySet = fileParams.entrySet();
+			for (Entry<String, FileItem> fileEntry : fileEntrySet) {
+				FileItem fileItem = fileEntry.getValue();
+				if (fileItem.getContent() == null) {
+					continue;
+				}
+				byte[] fileBytes = getFileEntry(fileEntry.getKey(), fileItem.getFileName(), fileItem.getMimeType(), charset);
+				out.write(entryBoundaryBytes);
+				out.write(fileBytes);
+				out.write(fileItem.getContent());
+			}
+
+			// 添加请求结束标志
+			byte[] endBoundaryBytes = ("\r\n--" + boundary + "--\r\n").getBytes(charset);
+			out.write(endBoundaryBytes);
+			rsp = getResponseAsString(conn);
+
+		} finally {
+			if (out != null) {
+				out.close();
+			}
+			if (conn != null) {
+				conn.disconnect();
+			}
+		}
+
+		return rsp;
+	}
+
+	private static byte[] getTextEntry(String fieldName, String fieldValue, String charset) throws IOException {
+		StringBuilder entry = new StringBuilder();
+		entry.append("Content-Disposition:form-data;name=\"");
+		entry.append(fieldName);
+		entry.append("\"\r\nContent-Type:text/plain\r\n\r\n");
+		entry.append(fieldValue);
+		return entry.toString().getBytes(charset);
+	}
+
+	private static byte[] getFileEntry(String fieldName, String fileName, String mimeType, String charset) throws IOException {
+		StringBuilder entry = new StringBuilder();
+		entry.append("Content-Disposition:form-data;name=\"");
+		entry.append(fieldName);
+		entry.append("\";filename=\"");
+		entry.append(fileName);
+		entry.append("\"\r\nContent-Type:");
+		entry.append(mimeType);
+		entry.append("\r\n\r\n");
+		return entry.toString().getBytes(charset);
+	}
+
+	/**
+	 * 执行HTTP GET请求。
+	 *
+	 * @param url 请求地址
+	 * @param params 请求参数
+	 * @return 响应字符串
+	 */
+	public static String doGet(String url, Map<String, String> params) throws IOException {
+		return doGet(url, params, DEFAULT_CHARSET);
+	}
+
+	/**
+	 * 执行HTTP GET请求。
+	 *
+	 * @param url 请求地址
+	 * @param params 请求参数
+	 * @param charset 字符集,如UTF-8, GBK, GB2312
+	 * @return 响应字符串
+	 */
+	public static String doGet(String url, Map<String, String> params, String charset) throws IOException {
+		HttpURLConnection conn = null;
+		String rsp = null;
+
+		try {
+			String ctype = "application/x-www-form-urlencoded;charset=" + charset;
+			String query = buildQuery(params, charset);
+
+			conn = getConnection(buildGetUrl(url, query), METHOD_GET, ctype, null);
+
+			rsp = getResponseAsString(conn);
+
+		} finally {
+			if (conn != null) {
+				conn.disconnect();
+			}
+		}
+
+		return rsp;
+	}
+
+	private static HttpURLConnection getConnection(URL url, String method, String ctype, Map<String, String> headerMap) throws IOException {
+		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+//		if (conn instanceof HttpsURLConnection) {
+//			HttpsURLConnection connHttps = (HttpsURLConnection) conn;
+//			if (ignoreSSLCheck) {
+//				try {
+//					SSLContext ctx = SSLContext.getInstance("TLS");
+//					ctx.init(null, new TrustManager[] { new TrustAllTrustManager() }, new SecureRandom());
+//					connHttps.setSSLSocketFactory(ctx.getSocketFactory());
+//					connHttps.setHostnameVerifier(new HostnameVerifier() {
+//						public boolean verify(String hostname, SSLSession session) {
+//							return true;
+//						}
+//					});
+//				} catch (Exception e) {
+//					throw new IOException(e);
+//				}
+//			} else {
+//				try {
+//					SSLContext ctx = SSLContext.getInstance("TLS");
+//					ctx.init(null, new TrustManager[] { new VerisignTrustManager() }, new SecureRandom());
+//					connHttps.setSSLSocketFactory(ctx.getSocketFactory());
+//				} catch (Exception e) {
+//					throw new IOException(e);
+//				}
+//			}
+//			conn = connHttps;
+//		}
+
+		conn.setRequestMethod(method);
+		conn.setDoInput(true);
+		conn.setDoOutput(true);
+		conn.setRequestProperty("Accept", "*/*");
+		conn.setRequestProperty("User-Agent", "wdt-java-sdk");
+		conn.setRequestProperty("Content-Type", ctype);
+		if (headerMap != null) {
+			for (Entry<String, String> entry : headerMap.entrySet()) {
+				conn.setRequestProperty(entry.getKey(), entry.getValue());
+			}
+		}
+		return conn;
+	}
+
+	private static URL buildGetUrl(String strUrl, String query) throws IOException {
+		URL url = new URL(strUrl);
+		if (StringUtils.isEmpty(query)) {
+			return url;
+		}
+
+		if (StringUtils.isEmpty(url.getQuery())) {
+			if (strUrl.endsWith("?")) {
+				strUrl = strUrl + query;
+			} else {
+				strUrl = strUrl + "?" + query;
+			}
+		} else {
+			if (strUrl.endsWith("&")) {
+				strUrl = strUrl + query;
+			} else {
+				strUrl = strUrl + "&" + query;
+			}
+		}
+
+		return new URL(strUrl);
+	}
+
+	public static String buildQuery(Map<String, String> params, String charset) throws IOException {
+		if (params == null || params.isEmpty()) {
+			return null;
+		}
+
+		StringBuilder query = new StringBuilder();
+		Set<Entry<String, String>> entries = params.entrySet();
+		boolean hasParam = false;
+
+		for (Entry<String, String> entry : entries) {
+			String name = entry.getKey();
+			String value = entry.getValue();
+			// 忽略参数名或参数值为空的参数
+			if (StringUtils.areNotEmpty(name, value)) {
+				if (hasParam) {
+					query.append("&");
+				} else {
+					hasParam = true;
+				}
+
+				query.append(name).append("=").append(URLEncoder.encode(value, charset));
+			}
+		}
+
+		return query.toString();
+	}
+
+	protected static String getResponseAsString(HttpURLConnection conn) throws IOException {
+		String charset = getResponseCharset(conn.getContentType());
+		InputStream es = conn.getErrorStream();
+		if (es == null) {
+			return getStreamAsString(conn.getInputStream(), charset);
+		} else {
+			String msg = getStreamAsString(es, charset);
+			if (StringUtils.isEmpty(msg)) {
+				throw new IOException(conn.getResponseCode() + ":" + conn.getResponseMessage());
+			} else {
+				throw new IOException(msg);
+			}
+		}
+	}
+
+	private static String getStreamAsString(InputStream stream, String charset) throws IOException {
+		try {
+			Reader reader = new InputStreamReader(stream, charset);
+			StringBuilder response = new StringBuilder();
+
+			final char[] buff = new char[1024];
+			int read = 0;
+			while ((read = reader.read(buff)) > 0) {
+				// 一次读取1024个字符
+				response.append(buff, 0, read);
+			}
+
+			return response.toString();
+		} finally {
+			if (stream != null) {
+				stream.close();
+			}
+		}
+	}
+
+	private static String getResponseCharset(String ctype) {
+		String charset = DEFAULT_CHARSET;
+
+		if (!StringUtils.isEmpty(ctype)) {
+			String[] params = ctype.split(";");
+			for (String param : params) {
+				param = param.trim();
+				if (param.startsWith("charset")) {
+					String[] pair = param.split("=", 2);
+					if (pair.length == 2) {
+						if (!StringUtils.isEmpty(pair[1])) {
+							charset = pair[1].trim();
+						}
+					}
+					break;
+				}
+			}
+		}
+
+		return charset;
+	}
+
+	/**
+	 * 使用默认的UTF-8字符集反编码请求参数值。
+	 *
+	 * @param value 参数值
+	 * @return 反编码后的参数值
+	 */
+	public static String decode(String value) {
+		return decode(value, DEFAULT_CHARSET);
+	}
+
+	/**
+	 * 使用默认的UTF-8字符集编码请求参数值。
+	 *
+	 * @param value 参数值
+	 * @return 编码后的参数值
+	 */
+	public static String encode(String value) {
+		return encode(value, DEFAULT_CHARSET);
+	}
+
+	/**
+	 * 使用指定的字符集反编码请求参数值。
+	 *
+	 * @param value 参数值
+	 * @param charset 字符集
+	 * @return 反编码后的参数值
+	 */
+	public static String decode(String value, String charset) {
+		String result = null;
+		if (!StringUtils.isEmpty(value)) {
+			try {
+				result = URLDecoder.decode(value, charset);
+			} catch (IOException e) {
+				throw new RuntimeException(e);
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * 使用指定的字符集编码请求参数值。
+	 *
+	 * @param value 参数值
+	 * @param charset 字符集
+	 * @return 编码后的参数值
+	 */
+	public static String encode(String value, String charset) {
+		String result = null;
+		if (!StringUtils.isEmpty(value)) {
+			try {
+				result = URLEncoder.encode(value, charset);
+			} catch (IOException e) {
+				throw new RuntimeException(e);
+			}
+		}
+		return result;
+	}
+
+	public static Map<String, String> getParamsFromUrl(String url) {
+		Map<String, String> map = null;
+		if (url != null && url.indexOf('?') != -1) {
+			map = splitUrlQuery(url.substring(url.indexOf('?') + 1));
+		}
+		if (map == null) {
+			map = new HashMap<String, String>();
+		}
+		return map;
+	}
+
+	/**
+	 * 从URL中提取所有的参数。
+	 *
+	 * @param query URL地址
+	 * @return 参数映射
+	 */
+	public static Map<String, String> splitUrlQuery(String query) {
+		Map<String, String> result = new HashMap<String, String>();
+
+		String[] pairs = query.split("&");
+		if (pairs != null && pairs.length > 0) {
+			for (String pair : pairs) {
+				String[] param = pair.split("=", 2);
+				if (param != null && param.length == 2) {
+					result.put(param[0], param[1]);
+				}
+			}
+		}
+
+		return result;
+	}
+
+}

+ 179 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtApiRefund.java

@@ -0,0 +1,179 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * ERP旺店通单个退款单信息 DTO
+ * <p>
+ * 代表一个具体的平台售后退款/退货单据。
+ * </p>
+ *
+ * @author xdd
+ * @since 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtApiRefund {
+
+    /**
+     * 平台ID
+     * <p>
+     * 输入固定值127。
+     * 必须: 是
+     * 类型: smallint(6)
+     * </p>
+     */
+    @JsonProperty("platform_id")
+    private Integer platformId;
+
+    /**
+     * 店铺编号
+     * <p>
+     * 代表店铺所有属性的唯一编码,用于店铺区分,ERP内支持自定义(ERP店铺界面设置),用于推送指定店铺原始退款单据信息。
+     * 必须: 是
+     * 类型: varchar
+     * </p>
+     */
+    @JsonProperty("shop_no")
+    private String shopNo;
+
+    /**
+     * 平台销售订单号
+     * <p>
+     * 平台订单单号(与推送trade_push的tid保持一致,对应旺店通ERP内原始单号)。
+     * 必须: 是
+     * 类型: varchar
+     * </p>
+     */
+    @JsonProperty("tid")
+    private String tid;
+
+    /**
+     * 平台退款/退货单号
+     * <p>
+     * 平台退款/退货单单号,保证唯一。
+     * 必须: 是
+     * 类型: varchar(40)
+     * </p>
+     */
+    @JsonProperty("refund_no")
+    private String refundNo;
+
+    /**
+     * 平台售后类型
+     * <p>
+     * type=1:退款(未发货退款);type=2:退款不退货;type=3:退货。
+     * 必须: 是
+     * 类型: int
+     * </p>
+     */
+    @JsonProperty("type")
+    private Integer type;
+
+    /**
+     * 平台售后状态
+     * <p>
+     * 可选值:wait_seller_agree(申请退款),seller_refuse(拒绝退款),closed(退款关闭),goods_returning(待退货),goods_receiving(待收货),success(退款成功)。
+     * 必须: 是
+     * 类型: varchar
+     * </p>
+     */
+    @JsonProperty("status")
+    private String status;
+
+    /**
+     * 退款金额
+     * <p>
+     * 退款的总金额。
+     * 必须: 否
+     * 类型: decimal(19,4)
+     * </p>
+     */
+    @JsonProperty("refund_fee")
+    private BigDecimal refundFee;
+
+    /**
+     * 买家昵称
+     * <p>
+     * 买家昵称(不传该字段,默认取原始订单上客户网名)。
+     * 必须: 是
+     * 类型: varchar(100)
+     * </p>
+     */
+    @JsonProperty("buyer_nick")
+    private String buyerNick;
+
+    /**
+     * 单据创建时间
+     * <p>
+     * 单据创建时间, 时间格式:yyyy-MM-dd HH:mm:ss。
+     * 必须: 是
+     * 类型: datetime
+     * </p>
+     */
+    @JsonProperty("refund_time")
+    private String refundTime; // 使用String类型以匹配指定的格式
+
+    /**
+     * 退款原因
+     * <p>
+     * 客户申请退款的原因。
+     * 必须: 否
+     * 类型: varchar(255)
+     * </p>
+     */
+    @JsonProperty("reason")
+    private String reason;
+
+    /**
+     * 备注
+     * <p>
+     * 退款单相关的备注信息。
+     * 必须: 否
+     * 类型: varchar(255)
+     * </p>
+     */
+    @JsonProperty("desc")
+    private String desc; // 注意:'desc' 在某些场景下可能是关键字,但这里保持与JSON一致
+
+    /**
+     * 物流单号
+     * <p>
+     * 退货时的物流单号(如需维护退货物流单号,与logistics_name物流公司名称同时使用)。
+     * 必须: 否
+     * 类型: varchar(40)
+     * </p>
+     */
+    @JsonProperty("logistics_no")
+    private String logisticsNo;
+
+    /**
+     * 物流公司名称
+     * <p>
+     * 退货时的物流公司名称。
+     * 必须: 否
+     * 类型: varchar(40)
+     * </p>
+     */
+    @JsonProperty("logistics_name")
+    private String logisticsName;
+
+    /**
+     * 售后子订单列表
+     * <p>
+     * 包含该退款单涉及的子订单信息。
+     * 必须: 是
+     * </p>
+     */
+    @JsonProperty("order_list")
+    private List<ErpWdtRefundOrder> orderList;
+}

+ 40 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtApiResponse.java

@@ -0,0 +1,40 @@
+package com.fs.erp.dto.wdt;
+
+import lombok.Data;
+import org.apache.commons.lang3.StringEscapeUtils;
+
+/**
+ * 旺店通开放平台 API 响应 DTO
+ * @author xdd
+ * @date 2025-02-27
+ */
+@Data
+public class ErpWdtApiResponse {
+
+    /**
+     * 错误码
+     * <p>状态码:0表示成功,其他表示失败</p>
+     */
+    private Integer code;
+
+    /**
+     * 错误原因
+     */
+    private String message;
+
+    public String getMessage() {
+        return StringEscapeUtils.unescapeJava(message);
+    }
+
+    /**
+     * 返回的新增订单个数
+     * <p>有单据新增时不为0(新建的原始单据)</p>
+     */
+    private Integer newCount;
+
+    /**
+     * 返回的更新订单个数
+     * <p>有单据更新时不为0(在已有的原始单据上进行修改)</p>
+     */
+    private Integer chgCount;
+}

+ 63 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtBarcodeDto.java

@@ -0,0 +1,63 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 条码信息 DTO
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtBarcodeDto {
+
+    /**
+     * 货品ID
+     */
+    @JsonProperty("goods_id")
+    private String goodsId;
+
+    /**
+     * 规格ID
+     */
+    @JsonProperty("spec_id")
+    private String specId;
+
+    /**
+     * 条码信息
+     */
+    @JsonProperty("barcode")
+    private String barcode;
+
+    /**
+     * target_id的类型 1普通规格 2组合装
+     */
+    @JsonProperty("type")
+    private String type;
+
+    /**
+     * 是否为主条码 0 否 1 是
+     */
+    @JsonProperty("is_master")
+    private String isMaster;
+
+    /**
+     * 扫码一次对应出库数量
+     */
+    @JsonProperty("out_target_num")
+    private String outTargetNum;
+
+    /**
+     * 扫码一次对应入库货品数量
+     */
+    @JsonProperty("target_num")
+    private String targetNum;
+
+    /**
+     * 最后修改时间
+     */
+    @JsonProperty("modified")
+    private String modified;
+}

+ 42 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtBaseResponseDTO.java

@@ -0,0 +1,42 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * Base API Response Structure
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtBaseResponseDTO {
+
+    /**
+     * 状态码:0表示成功,其他表示失败
+     */
+    @JsonProperty("code")
+    private Integer code;
+
+    /**
+     * 错误描述
+     */
+    @JsonProperty("message")
+    private String message;
+
+    /**
+     * 符合条件的数据条数,用来分页 当page_no = 0时返回
+     */
+    @JsonProperty("total_count")
+    private Integer totalCount;
+
+    /**
+     * 货品节点列表
+     */
+    @JsonProperty("goods_list")
+    private List<ErpWdtGoodsDto> goodsList;
+
+}

+ 32 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtBusinessRequestParams.java

@@ -0,0 +1,32 @@
+package com.fs.erp.dto.wdt;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 旺店通开放平台 API 业务请求参数 DTO
+ * @author xdd
+ * @date 2025-02-27
+ */
+@Data
+public class ErpWdtBusinessRequestParams {
+
+    /**
+     * 店铺编号
+     * <p>代表店铺所有属性的唯一编码,用于店铺区分,ERP内支持自定义(ERP店铺界面设置,查看路径ERP→设置→基本设置→店铺→店铺列表),用于创建指定店铺单据信息,测试环境店铺编号信息同接口账号。ERP内shop_no对应的“店铺平台”必须为“自有/其它”。正式环境店铺创建成功后ERP会自动授权,如果自动授权失败,在ERP店铺界面(路径ERP→设置→基本设置→店铺→店铺列表)选中授权失败的店铺,点击店铺界面提供的店铺授权按钮重新授权。</p>
+     */
+    private String shopNo;
+
+    /**
+     * 模式
+     * <p>0:非严格模式,1:严格模式,默认1。严格模式详情介绍单击这里</p>
+     */
+    private Integer switchMode;
+
+    /**
+     * 订单列表节点
+     * <p>请求参数的1级数据节点,包含销售订单所有属性信息的数据节点,节点下数据字段详见下述“trade_list”</p>
+     */
+    private List<ErpWdtTrade> tradeList;
+}

+ 36 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtCommonRequestParams.java

@@ -0,0 +1,36 @@
+package com.fs.erp.dto.wdt;
+
+import lombok.Data;
+
+/**
+ * 旺店通开放平台 API 公共请求参数 DTO
+ * @author xdd
+ * @date 2025-02-27
+ */
+@Data
+public class ErpWdtCommonRequestParams {
+
+    /**
+     * 卖家账号
+     * <p>购买ERP时由旺店通分配给ERP购买方,请从ERP购买方获取。</p>
+     */
+    private String sid;
+
+    /**
+     * 接口账号
+     * <p>本开放平台“自助对接”功能模块内自助申请,获取方式点击这里</p>
+     */
+    private String appkey;
+
+    /**
+     * 时间戳
+     * <p>北京时间1970-01-01 08:00:00起至现在的总秒数,10位int值,旺店通企业版API服务端允许请求最大时间误差为5min,date.timezone = Asia/Shanghai。</p>
+     */
+    private int timestamp;
+
+    /**
+     * 签名
+     * <p>API输入参数签名结果,签名算法介绍单击这里</p>
+     */
+    private String sign;
+}

+ 81 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtDiscountListDTO.java

@@ -0,0 +1,81 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * ERP WDT 优惠明细DTO,用于封装订单或子订单中的优惠项信息。
+ *
+ * @author xdd
+ * @date 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtDiscountListDTO {
+
+    /**
+     * 平台id
+     */
+    private Integer platformId;
+
+    /**
+     * 原始单号 (关联主订单)
+     */
+    private String tid;
+
+    /**
+     * 原始子订单编号 (如果优惠关联特定子单)
+     */
+    private String oid;
+
+    /**
+     * 明细主键, 自动增量
+     */
+    private Long recId; // btigin 视为 bigint
+
+    /**
+     * 优惠类别
+     */
+    private String type;
+
+    /**
+     * 是否优惠券
+     * 0: 否, 1: 是 (tinyint 常用表示方式)
+     */
+    private Integer isBonus;
+
+    /**
+     * 创建时间
+     * 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date created;
+
+    /**
+     * 优惠名称
+     */
+    private String name;
+
+    /**
+     * 优惠详情
+     */
+    private String detail;
+
+    /**
+     * 优惠金额
+     */
+    private BigDecimal amount;
+
+    /**
+     * 平台唯一标识 (例如优惠券码、活动ID等)
+     */
+    private String sn;
+}

+ 227 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtGoodsDto.java

@@ -0,0 +1,227 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * 货品节点 (SPU) DTO
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtGoodsDto {
+
+    /**
+     * 货品ID (货品表主键)
+     */
+    @JsonProperty("goods_id")
+    private Integer goodsId;
+
+    /**
+     * 货品编号 (代表SPU所有属性的唯一编号)
+     */
+    @JsonProperty("goods_no")
+    private String goodsNo;
+
+    /**
+     * 货品名称
+     */
+    @JsonProperty("goods_name")
+    private String goodsName;
+
+    /**
+     * 简称
+     */
+    @JsonProperty("short_name")
+    private String shortName;
+
+    /**
+     * 货品别名
+     */
+    @JsonProperty("alias")
+    private String alias;
+
+    /**
+     * 货品类别 0:其它, 1:销售货品, 2:原材料, 3:包装物, 4:周转材料, 5:虚拟商品, 6:固定资产,7:保修配件 8:虚拟代发货品
+     */
+    @JsonProperty("goods_type")
+    private Integer goodsType; // tinyint mapped to Integer
+
+    /**
+     * 规格数
+     */
+    @JsonProperty("spec_count")
+    private Integer specCount;
+
+    /**
+     * 拼音
+     */
+    @JsonProperty("pinyin")
+    private String pinyin;
+
+    /**
+     * 品牌编号
+     */
+    @JsonProperty("brand_no")
+    private String brandNo;
+
+    /**
+     * 品牌名称
+     */
+    @JsonProperty("brand_name")
+    private String brandName;
+
+    /**
+     * 备注
+     */
+    @JsonProperty("remark")
+    private String remark;
+
+    /**
+     * 自定义属性1
+     */
+    @JsonProperty("prop1")
+    private String prop1;
+
+    /**
+     * 自定义属性2
+     */
+    @JsonProperty("prop2")
+    private String prop2;
+
+    /**
+     * 自定义属性3
+     */
+    @JsonProperty("prop3")
+    private String prop3;
+
+    /**
+     * 自定义属性4
+     */
+    @JsonProperty("prop4")
+    private String prop4;
+
+    /**
+     * 自定义属性5
+     */
+    @JsonProperty("prop5")
+    private String prop5;
+
+    /**
+     * 自定义属性6
+     */
+    @JsonProperty("prop6")
+    private String prop6;
+
+    /**
+     * 产地
+     */
+    @JsonProperty("origin")
+    private String origin;
+
+    /**
+     * 分类id
+     */
+    @JsonProperty("class_id")
+    private String classId;
+
+    /**
+     * 分类名称
+     */
+    @JsonProperty("class_name")
+    private String className;
+
+    /**
+     * 品牌ID
+     */
+    @JsonProperty("brand_id")
+    private String brandId;
+
+    /**
+     * 基本单位id
+     */
+    @JsonProperty("unit")
+    private String unit;
+
+    /**
+     * 辅助单位id
+     */
+    @JsonProperty("aux_unit")
+    private String auxUnit;
+
+    /**
+     * 标记
+     */
+    @JsonProperty("flag_id")
+    private String flagId;
+
+    /**
+     * 属性
+     */
+    @JsonProperty("properties")
+    private String properties;
+
+    /**
+     * 版本号,用来检查同时修改的
+     */
+    @JsonProperty("version_id")
+    private String versionId;
+
+    /**
+     * 最后修改时间 格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("modified")
+    private String modified; // Keep as String for direct mapping
+
+    /**
+     * 创建时间 格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("created")
+    private String created; // Keep as String for direct mapping
+
+    /**
+     * 基本单位名称
+     */
+    @JsonProperty("unit_name")
+    private String unitName;
+
+    /**
+     * 辅助单位名称
+     */
+    @JsonProperty("aux_unit_name")
+    private String auxUnitName;
+
+    /**
+     * 标记名称
+     */
+    @JsonProperty("flag_name")
+    private String flagName;
+
+    /**
+     * 创建时间 (ERP客户端需升级至V2.3.8.6及以上版本可获取此字段) 格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("goods_created")
+    private String goodsCreated; // Keep as String
+
+    /**
+     * 最后修改时间 格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("goods_modified")
+    private String goodsModified; // Keep as String
+
+    /**
+     * 是否已删除: 0:未删除 >0代表已删除
+     */
+    @JsonProperty("deleted")
+    private Integer deleted;
+
+    /**
+     * 单品节点列表 (SKU)
+     */
+    @JsonProperty("spec_list")
+    private List<ErpWdtSpecDto> specList;
+}

+ 489 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtGoodsInfo.java

@@ -0,0 +1,489 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+// import java.time.LocalDateTime; // 如果需要反序列化为日期时间对象
+
+/**
+ * ERP 旺店通 订单货品明细 DTO.
+ * 代表订单中单个货品的详细信息。
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtGoodsInfo {
+
+    /**
+     * erp子订单主键
+     */
+    @JsonProperty("rec_id")
+    @NotNull // 必须
+    private Integer recId;
+
+    /**
+     * erp订单主键
+     */
+    @JsonProperty("trade_id")
+    @NotNull // 必须
+    private Integer tradeId;
+
+    /**
+     * erp内商品主键
+     */
+    @JsonProperty("spec_id")
+    @NotNull // 必须
+    private Integer specId;
+
+    /**
+     * 平台ID
+     */
+    @JsonProperty("platform_id")
+    @NotNull // 必须
+    private Integer platformId;
+
+    /**
+     * 原始子订单号
+     */
+    @JsonProperty("src_oid")
+    @NotNull // 必须
+    private String srcOid;
+
+    /**
+     * 平台货品ID
+     */
+    @JsonProperty("platform_goods_id")
+    @NotNull // 必须
+    private String platformGoodsId;
+
+    /**
+     * 平台商品ID
+     */
+    @JsonProperty("platform_spec_id")
+    @NotNull // 必须
+    private String platformSpecId;
+
+    /**
+     * 组合装ID,如果货品是由组合装拆分的,这里组合装ID
+     */
+    @JsonProperty("suite_id")
+    @NotNull // 必须
+    private Integer suiteId;
+
+    /**
+     * 区分子单拆分的唯一性标记,子单拆分时,单品明细都一致,用来区分子单的唯一性
+     */
+    @JsonProperty("flag")
+    @NotNull // 必须
+    private Integer flag;
+
+    /**
+     * 原始订单号
+     */
+    @JsonProperty("src_tid")
+    @NotNull // 必须
+    private String srcTid;
+
+    /**
+     * 是否是赠品 0非赠品 1自动赠送 2手工赠送 3回购自动送赠品  4前N有礼送赠品 6天猫优仓赠品 7淘宝CRM会员送赠
+     */
+    @JsonProperty("gift_type")
+    @NotNull // 必须
+    private Integer giftType;
+
+    /**
+     * 退款状态 0无退款,1取消退款,2已申请退款,3等待退货,4等待收货,5退款成功 6已关闭
+     */
+    @JsonProperty("refund_status")
+    @NotNull // 必须
+    private Integer refundStatus;
+
+    /**
+     * 担保方式 1担保 2非担保 3在线非担保
+     */
+    @JsonProperty("guarantee_mode")
+    @NotNull // 必须
+    private Integer guaranteeMode;
+
+    /**
+     * 发货条件 1款到发货 2货到付款(包含部分货到付款) 3分期付款
+     */
+    @JsonProperty("delivery_term")
+    @NotNull // 必须
+    private Integer deliveryTerm;
+
+    /**
+     * 关联发货
+     */
+    @JsonProperty("bind_oid")
+    @NotNull // 必须
+    private String bindOid;
+
+    /**
+     * 货品数量
+     */
+    @JsonProperty("num")
+    @NotNull // 必须
+    private BigDecimal num;
+
+    /**
+     * 销售单价,手工新建时使用货品属性中的“零售价”
+     */
+    @JsonProperty("price")
+    @NotNull // 必须
+    private BigDecimal price;
+
+    /**
+     * 实发数量,此数量为发货数量,删除操作等于将此值设置为0
+     */
+    @JsonProperty("actual_num")
+    @NotNull // 必须
+    private BigDecimal actualNum;
+
+    /**
+     * 无实际含义
+     */
+    @JsonProperty("refund_num")
+    @NotNull // 必须
+    private BigDecimal refundNum;
+
+    /**
+     * 成交价,原始单折扣及分摊之后的价格
+     */
+    @JsonProperty("order_price")
+    @NotNull // 必须
+    private BigDecimal orderPrice;
+
+    /**
+     * 进入ERP后再次调整的价格,默认值与order_price一致
+     */
+    @JsonProperty("share_price")
+    @NotNull // 必须
+    private BigDecimal sharePrice;
+
+    /**
+     * 手工调整价,正数为加价,负数为减价
+     */
+    @JsonProperty("adjust")
+    @NotNull // 必须
+    private BigDecimal adjust;
+
+    /**
+     * 总折扣金额
+     */
+    @JsonProperty("discount")
+    @NotNull // 必须
+    private BigDecimal discount;
+
+    /**
+     * 分摊后合计应收=share_price * num , share_price 是根据share_amount反推的,因此share_price可能有精度损失
+     */
+    @JsonProperty("share_amount")
+    @NotNull // 必须
+    private BigDecimal shareAmount;
+
+    /**
+     * 分摊邮费
+     */
+    @JsonProperty("share_post")
+    @NotNull // 必须
+    private BigDecimal sharePost;
+
+    /**
+     * 已支付金额
+     */
+    @JsonProperty("paid")
+    @NotNull // 必须
+    private BigDecimal paid;
+
+    /**
+     * 货品名称
+     */
+    @JsonProperty("goods_name")
+    @NotNull // 必须
+    private String goodsName;
+
+    /**
+     * 分类名称
+     */
+    @JsonProperty("class_name")
+    @NotNull // 必须
+    private String className;
+
+    /**
+     * 自定义属性2
+     */
+    @JsonProperty("prop2")
+    @NotNull // 必须
+    private String prop2;
+
+    /**
+     * 分销商id
+     */
+    @JsonProperty("tc_order_id")
+    @NotNull // 必须
+    private String tcOrderId;
+
+    /**
+     * 主条码
+     */
+    @JsonProperty("barcode")
+    @NotNull // 必须
+    private String barcode;
+
+    /**
+     * 货品id
+     */
+    @JsonProperty("goods_id")
+    @NotNull // 必须
+    private Integer goodsId;
+
+    /**
+     * 货品编号,代表货品(spu)所有属性的唯一编号,用于系统货品区分
+     */
+    @JsonProperty("goods_no")
+    @NotNull // 必须
+    private String goodsNo;
+
+    /**
+     * 规格名
+     */
+    @JsonProperty("spec_name")
+    @NotNull // 必须
+    private String specName;
+
+    /**
+     * 商家编码,代表单品(sku)所有属性的唯一编码,用于系统单品区分
+     */
+    @JsonProperty("spec_no")
+    @NotNull // 必须
+    private String specNo;
+
+    /**
+     * 规格码
+     */
+    @JsonProperty("spec_code")
+    @NotNull // 必须
+    private String specCode;
+
+    /**
+     * 组合装编码,代表组合装商品所有属性的唯一编码,用于系统组合装商品的区分
+     */
+    @JsonProperty("suite_no")
+    @NotNull // 必须
+    private String suiteNo;
+
+    /**
+     * 如果是组合装拆分的,此为组合装名称
+     */
+    @JsonProperty("suite_name")
+    @NotNull // 必须
+    private String suiteName;
+
+    /**
+     * 组合装数量
+     */
+    @JsonProperty("suite_num")
+    @NotNull // 必须
+    private BigDecimal suiteNum;
+
+    /**
+     * 组合装分摊后总价
+     */
+    @JsonProperty("suite_amount")
+    @NotNull // 必须
+    private BigDecimal suiteAmount;
+
+    /**
+     * 组合装优惠
+     */
+    @JsonProperty("suite_discount")
+    @NotNull // 必须
+    private BigDecimal suiteDiscount;
+
+    /**
+     * share_amount备份值,退款恢复使用,!可回收 目前会存放分销订单发货回传的分销价
+     */
+    @JsonProperty("share_amount2")
+    @NotNull // 必须
+    private BigDecimal shareAmount2;
+
+    /**
+     * 是否打印组合装 0:组合装明细/1:组合装以及明细/2:组合装
+     */
+    @JsonProperty("is_print_suite")
+    @NotNull // 必须
+    private Integer isPrintSuite;
+
+    /**
+     * 是否允许0成本
+     */
+    @JsonProperty("is_zero_cost")
+    @NotNull // 必须
+    private Integer isZeroCost; // tinyint(1)
+
+    /**
+     * 库存保留情况 0未保留(取消的订单或完成)1无库存记录 2未付款 3已保留待审核 4待发货 5预订单库存
+     */
+    @JsonProperty("stock_reserved")
+    @NotNull // 必须
+    private Integer stockReserved;
+
+    /**
+     * 平台已发货
+     */
+    @JsonProperty("is_consigned")
+    @NotNull // 必须
+    private Integer isConsigned;
+
+    /**
+     * 线上订单,标记是否打款
+     */
+    @JsonProperty("is_received")
+    @NotNull // 必须
+    private Integer isReceived;
+
+    /**
+     * 是否主子订单,为发货算法使用
+     */
+    @JsonProperty("is_master")
+    @NotNull // 必须
+    private Integer isMaster; // tinyint(1)
+
+    /**
+     * 平台货品名称
+     */
+    @JsonProperty("api_goods_name")
+    @NotNull // 必须
+    private String apiGoodsName;
+
+    /**
+     * 平台规格名称
+     */
+    @JsonProperty("api_spec_name")
+    @NotNull // 必须
+    private String apiSpecName;
+
+    /**
+     * 预估单个货品重量(单位:kg)
+     */
+    @JsonProperty("weight")
+    @NotNull // 必须
+    private BigDecimal weight;
+
+    /**
+     * 佣金
+     */
+    @JsonProperty("commission")
+    @NotNull // 必须
+    private BigDecimal commission;
+
+    /**
+     * 货品类别 1销售商品 2原材料 3包装 4周转材料5虚拟商品 0其它
+     */
+    @JsonProperty("goods_type")
+    @NotNull // 必须
+    private Integer goodsType;
+
+    /**
+     * 大件类型 0非大件 1普通大件 2独立大件
+     */
+    @JsonProperty("large_type")
+    @NotNull // 必须
+    private Integer largeType; // tinyint(1)
+
+    /**
+     * 发票类别,0 不需要,1普通发票,2增值税发票
+     */
+    @JsonProperty("invoice_type")
+    @NotNull // 必须
+    private Integer invoiceType;
+
+    /**
+     * 发票内容
+     */
+    @JsonProperty("invoice_content")
+    @NotNull // 必须
+    private String invoiceContent;
+
+    /**
+     * 订单内部来源1手机,2聚划算,4服务子订单,8家装,16二次付款,32开具电子发票,128指定批次,2048当日达,4096次日达,8192预计时效,262144天猫直送/唯品仓中仓,524288‘3PL时效/jitx’,2097152区域零售,4194304预售单,8388608周期购,16777216 同城购(淘宝),268435456 物流升级,536870912 抖店抽奖订单
+     */
+    @JsonProperty("from_mask")
+    @NotNull // 必须
+    private Integer fromMask;
+
+    /**
+     * 类目id
+     */
+    @JsonProperty("cid")
+    @NotNull // 必须
+    private Integer cid;
+
+    /**
+     * 货品明细备注
+     */
+    @JsonProperty("remark")
+    @NotNull // 必须
+    private String remark;
+
+    /**
+     * 最后修改时间 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("modified")
+    @NotNull // 必须
+    private String modified; // 或者 LocalDateTime modified;
+
+    /**
+     * 创建时间 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("created")
+    @NotNull // 必须
+    private String created; // 或者 LocalDateTime created;
+
+    /**
+     * 税率(根据条件使用订单中或单品中税率)
+     */
+    @JsonProperty("tax_rate")
+    private BigDecimal taxRate; // 可选
+
+    /**
+     * 基本单位ID
+     */
+    @JsonProperty("base_unit_id")
+    private Integer baseUnitId; // 可选
+
+    /**
+     * 基本单位名称
+     */
+    @JsonProperty("unit_name")
+    private String unitName; // 可选
+
+    /**
+     * 交易流水单号 (请求参数src传为1时返回)
+     */
+    @JsonProperty("pay_id")
+    private String payId; // 可选
+
+    /**
+     * 子单付款状态 0(未付款),1(部分付款),2(已付款) (请求参数src传为1时返回)
+     */
+    @JsonProperty("pay_status")
+    private Integer payStatus; // 可选
+
+    /**
+     * 子单付款时间 时间格式:yyyy-MM-dd HH:mm:ss (请求参数src传为1时返回)
+     */
+    @JsonProperty("pay_time")
+    private String payTime; // 可选, 或者 LocalDateTime payTime;
+}

+ 257 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtGoodsListDTO.java

@@ -0,0 +1,257 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * ERP WDT 货品明细DTO,用于封装订单中的单个货品项信息。
+ *
+ * @author xdd
+ * @date 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtGoodsListDTO {
+
+    /**
+     * 平台id
+     */
+    private Integer platformId;
+
+    /**
+     * 原始单号 (关联主订单)
+     */
+    private String tid;
+
+    /**
+     * 平台订单货品表主键, 子订单唯一标识
+     * 同一个sid下通过本接口新增订单的oid要保证唯一
+     */
+    private String oid;
+
+    /**
+     * 状态
+     * 10:未确认 20:待尾款 30:待发货 40:部分发货 50:已发货 60:已签收 70:已完成 80:已退款 90:已关闭
+     */
+    private Integer status;
+
+    /**
+     * 系统状态
+     * 10:待递交 15:部分递交 20:已递交 30:部分发货 40:已发货 50:部分结算 60:已完成 70:已取消
+     */
+    private Integer processStatus;
+
+    /**
+     * 退款状态
+     * 0:无退款 1:取消退款 2:已申请退款 3:等待退货 4:等待收货 5:退款成功
+     */
+    private Integer refundStatus;
+
+    /**
+     * 子订单类型
+     * 0:正常货品 1:虚拟货品 2:服务
+     */
+    private Integer orderType;
+
+    /**
+     * 平台货品ID
+     */
+    private String goodsId;
+
+    /**
+     * 平台规格ID
+     */
+    private String specId;
+
+    /**
+     * 平台货品编码
+     */
+    private String goodsNo;
+
+    /**
+     * 平台规格编码
+     */
+    private String specNo;
+
+    /**
+     * 平台货品名称
+     */
+    private String goodsName;
+
+    /**
+     * 平台规格名称
+     */
+    private String specName;
+
+    /**
+     * 数量
+     */
+    private BigDecimal num;
+
+    /**
+     * 单价
+     */
+    private BigDecimal price;
+
+    /**
+     * 调整金额
+     */
+    private BigDecimal adjustAmount;
+
+    /**
+     * 优惠金额
+     */
+    private BigDecimal discount;
+
+    /**
+     * 总价 (price * num + adjust_amount)
+     */
+    private BigDecimal totalAmount;
+
+    /**
+     * 分摊优惠
+     */
+    private BigDecimal shareDiscount;
+
+    /**
+     * 分摊后总价 (total_amount - share_discount)
+     */
+    private BigDecimal shareAmount;
+
+    /**
+     * 分摊邮资
+     */
+    private BigDecimal sharePost;
+
+    /**
+     * 已付金额 (可能指该子订单对应的已付部分)
+     */
+    private BigDecimal paid;
+
+    /**
+     * 发票类别
+     * 0:不需要 1:普通发票 2:普通增值发票 3:专用增值发票
+     */
+    private Integer invoiceType;
+
+    /**
+     * 发票内容
+     */
+    private String invoiceContent;
+
+    /**
+     * 关联子订单 (例如捆绑销售的主商品oid)
+     */
+    private String bindOid;
+
+    /**
+     * 退款单编号
+     */
+    private String refundId;
+
+    /**
+     * 退款金额 (针对此子订单的退款)
+     */
+    private BigDecimal refundAmount;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 物流单号 (代发场景)
+     */
+    private String daifaLogisticsNo;
+
+    /**
+     * 物流类型 (代发场景)
+     */
+    private Integer daifaLogisticsType; // smallint 用 Integer
+
+    /**
+     * 发货时间 (代发场景)
+     * 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date daifaConsignTime;
+
+    /**
+     * 订单完成时间 (代发场景)
+     * 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date daifaEndTime;
+
+    /**
+     * 修改时间
+     * 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date modified;
+
+    /**
+     * 创建时间
+     * 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date created;
+
+    /**
+     * 子单完成时间
+     * 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date endTime;
+
+    /**
+     * 自动增量id
+     */
+    private Long recId;
+
+    /**
+     * 处理退款状态 (默认为'0')
+     * 1:待审核 2:已同意 3:已拒绝 4:待收货 5:已完成 6:已关闭
+     */
+    private Integer processRefundStatus;
+
+    /**
+     * 平台规格码 (默认为'')
+     */
+    private String specCode;
+
+    /**
+     * 佣金 (默认为'0.0000')
+     */
+    private BigDecimal commission;
+
+    /**
+     * 出库单号? (字段名stockout_no,描述是end_time,记录结束时间,这里按字段名推测,默认为'')
+     * 注意:描述与字段名似乎不符,按字段名 stockout_no 解释为出库单号
+     */
+    private String stockoutNo;
+
+    /**
+     * 物流单号 (发货后,默认为'')
+     */
+    private String logisticsNo;
+
+    /**
+     * 子单是否自动流转到wms (默认为'0')
+     * 0: 否, 1: 是
+     */
+    private Integer isAutoWms;
+
+    /**
+     * 类目id
+     */
+    private Integer cid;
+}

+ 100 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtOrder.java

@@ -0,0 +1,100 @@
+package com.fs.erp.dto.wdt;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 旺店通开放平台 API 订单货品明细 DTO
+ * @author xdd
+ * @date 2025-02-27
+ */
+@Data
+public class ErpWdtOrder {
+
+    /**
+     * 子订单编号
+     * <p>平台订单货品表主键,子订单唯一标识,同一个sid下通过本接口新增订单的oid(子订单编号)要保证唯一;如果oid重复,ERP生成系统单(递交)时会提示“订单货品数量不一致xxxxxx”</p>
+     */
+    private String oid;
+
+    /**
+     * 数量
+     * <p>货品数量,订单推送成功以后本字段值不能更改</p>
+     */
+    private BigDecimal num;
+
+    /**
+     * 单价
+     * <p>标价,折扣前的价格,可以推送价格为0的商品。订单推送成功以后本字段值不能更改</p>
+     */
+    private BigDecimal price;
+
+    /**
+     * 状态
+     * <p>平台子订单状态,子订单状态可以和主订单不一样,比如其中一个子订单退款完成,其状态是80,但主订单仍然是待发货,可选值同trade_status</p>
+     */
+    private Integer status;
+
+    /**
+     * 退款状态
+     * <p>0:无退款,1:取消退款,2:已申请退款,3:等待退货,4:等待收货,5:退款成功。本字段在售前退款的时候,根据不同的场景填写不同的值,eg:申请退款值为2,取消退款值为1……</p>
+     */
+    private Integer refundStatus;
+
+    /**
+     * 平台货品ID
+     * <p>平台系统货品(SPU)的唯一标识。goods_id不能为空,goods_id和goods_no区别与SPU、SKU概念介绍,单击这里</p>
+     */
+    private String goodsId;
+
+    /**
+     * 平台规格ID
+     * <p>平台系统单品(SKU)的的唯一标识,尽量不为空,spec_id和spec_no区别与SPU、SKU概念介绍,单击这里</p>
+     */
+    private String specId;
+
+    /**
+     * 货品编码
+     * <p>平台货品SPU编码,对应ERP货品编号,尽量不为空</p>
+     */
+    private String goodsNo;
+
+    /**
+     * 规格编码
+     * <p>平台货品SKU唯一码,对应ERP商家编码,goods_no和spec_no不能同时为空</p>
+     */
+    private String specNo;
+
+    /**
+     * 货品名称
+     */
+    private String goodsName;
+
+    /**
+     * 规格名称
+     */
+    private String specName;
+
+    /**
+     * 调整
+     * <p>客服调整总金额(大于0加价,小于0减价,是折扣来源的一部分,没有传0)</p>
+     */
+    private BigDecimal adjustAmount;
+
+    /**
+     * 优惠
+     * <p>下单总折扣,客户下单时折扣(比如促销打折,不包含客服调整、分摊折扣,没有传0)</p>
+     */
+    private BigDecimal discount;
+
+    /**
+     * 分摊优惠
+     * <p>分摊总折扣,由总订单分摊而来,一般是付款时产生,如使用优惠券,没有传0。分摊优惠传值注意:例如三个商品,优惠10,分摊优惠可以是:3/3/4,或者3.33/3.33/3.34.即最后一个商品的分摊优惠使用减法计算</p>
+     */
+    private BigDecimal shareDiscount;
+
+    private BigDecimal commission;
+    private String remark;
+    private String cid;
+}

+ 20 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtRefundBusinessRequestParams.java

@@ -0,0 +1,20 @@
+package com.fs.erp.dto.wdt;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 旺店通开放平台 API 退款/售后业务请求参数 DTO
+ * @author xdd
+ * @date 2025-02-27
+ */
+@Data
+public class ErpWdtRefundBusinessRequestParams {
+
+    /**
+     * 退款单节点
+     * <p>请求参数的1级数据节点,包含平台售后订单所有属性信息的数据节点,节点下数据字段详见下述“api_refund_list”</p>
+     */
+    private List<ErpWdtApiRefund> apiRefundList;
+}

+ 47 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtRefundOrder.java

@@ -0,0 +1,47 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+
+/**
+ * ERP旺店通售后子订单信息 DTO
+ * <p>
+ * 代表退款单中涉及的具体商品行项目。
+ * </p>
+ *
+ * @author xdd
+ * @since 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtRefundOrder {
+
+    /**
+     * 平台订单子订单编号
+     * <p>
+     * 平台订单子订单编号(与推送trade_push的oid保持一致,对应旺店通ERP内原始子订单编号)。可推送部分子订单。
+     * 必须: 是
+     * 类型: varchar(40)
+     * </p>
+     */
+    @JsonProperty("oid")
+    private String oid;
+
+    /**
+     * 退货货品数量
+     * <p>
+     * 退货货品数量(如果是type=1 退款 或 2 退款不退货类型,此处代表退款数量)。
+     * 必须: 是
+     * 类型: decimal(19,4)
+     * </p>
+     */
+    @JsonProperty("num")
+    private BigDecimal num;
+}

+ 35 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtRefundRequest.java

@@ -0,0 +1,35 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * ERP旺店通退款单推送请求 DTO
+ * <p>
+ * 包含推送给旺店通ERP的退款单据的顶层结构。
+ * </p>
+ *
+ * @author xdd
+ * @since 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtRefundRequest {
+
+    /**
+     * 请求参数的1级数据节点
+     * <p>
+     * 包含平台售后订单所有属性信息的数据节点列表。
+     * 必须: 是
+     * </p>
+     */
+    @JsonProperty("api_refund_list") // 对应JSON字段名
+    private List<ErpWdtApiRefund> apiRefundList;
+}

+ 408 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtSpecDto.java

@@ -0,0 +1,408 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 单品节点 (SKU) DTO
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtSpecDto {
+
+    /**
+     * 规格ID
+     */
+    @JsonProperty("spec_id")
+    private String specId;
+
+    /**
+     * 商家编码 (代表单品(SKU)所有属性的唯一编号)
+     */
+    @JsonProperty("spec_no")
+    private String specNo;
+
+    /**
+     * 规格码
+     */
+    @JsonProperty("spec_code")
+    private String specCode;
+
+    /**
+     * 主条码,单品下如果有多个条码,会随机返回其中一条条码
+     */
+    @JsonProperty("barcode")
+    private String barcode;
+
+    /**
+     * 规格名称
+     */
+    @JsonProperty("spec_name")
+    private String specName;
+
+    /**
+     * 货品ID
+     */
+    @JsonProperty("goods_id")
+    private Integer goodsId;
+
+    /**
+     * 最低价
+     */
+    @JsonProperty("lowest_price")
+    private BigDecimal lowestPrice;
+
+    /**
+     * 零售价
+     */
+    @JsonProperty("retail_price")
+    private BigDecimal retailPrice;
+
+    /**
+     * 批发价
+     */
+    @JsonProperty("wholesale_price")
+    private BigDecimal wholesalePrice;
+
+    /**
+     * 会员价
+     */
+    @JsonProperty("member_price")
+    private BigDecimal memberPrice;
+
+    /**
+     * 市场价
+     */
+    @JsonProperty("market_price")
+    private BigDecimal marketPrice;
+
+    /**
+     * 自定义价格1
+     */
+    @JsonProperty("custom_price1")
+    private BigDecimal customPrice1;
+
+    /**
+     * 自定义价格2
+     */
+    @JsonProperty("custom_price2")
+    private BigDecimal customPrice2;
+
+    /**
+     * 销售积分
+     */
+    @JsonProperty("sale_score")
+    private Integer saleScore;
+
+    /**
+     * 打包积分
+     */
+    @JsonProperty("pack_score")
+    private Integer packScore;
+
+    /**
+     * 拣货积分
+     */
+    @JsonProperty("pick_score")
+    private Integer pickScore;
+
+    /**
+     * 有效期天数 (保质期)
+     */
+    @JsonProperty("validity_days")
+    private Integer validityDays;
+
+    /**
+     * 最佳销售天数
+     */
+    @JsonProperty("sales_days")
+    private Integer salesDays;
+
+    /**
+     * 最佳收获天数
+     */
+    @JsonProperty("receive_days")
+    private Integer receiveDays;
+
+    /**
+     * 重量
+     */
+    @JsonProperty("weight")
+    private BigDecimal weight;
+
+    /**
+     * 长(CM)
+     */
+    @JsonProperty("length")
+    private BigDecimal length;
+
+    /**
+     * 宽(CM)
+     */
+    @JsonProperty("width")
+    private BigDecimal width;
+
+    /**
+     * 高(CM)
+     */
+    @JsonProperty("height")
+    private BigDecimal height;
+
+    /**
+     * 是否启用序列号 0不启用序列号 1强序列号 2弱序列号
+     */
+    @JsonProperty("is_sn_enable")
+    private Integer isSnEnable; // tinyint mapped to Integer
+
+    /**
+     * 是否允许负库存 0(不允许负库存);1(允许负库存)
+     */
+    @JsonProperty("is_allow_neg_stock")
+    private Integer isAllowNegStock; // tinyint mapped to Integer
+
+    /**
+     * 是否出库不验货 0(出库不验货);1(出库必须验货)
+     */
+    @JsonProperty("is_not_need_examine")
+    private Integer isNotNeedExamine; // tinyint mapped to Integer
+
+    /**
+     * 是否允许0成本 0(不允许0成本);1(允许0成本)
+     */
+    @JsonProperty("is_zero_cost")
+    private Integer isZeroCost; // tinyint mapped to Integer
+
+    /**
+     * 是否允许低于成本价 0(不允许低于成本价);1(允许低于成本价)
+     */
+    @JsonProperty("is_lower_cost")
+    private Integer isLowerCost; // tinyint mapped to Integer
+
+    /**
+     * 是否航空禁运 0(航空不禁运) 1(航空禁运)
+     */
+    @JsonProperty("is_not_use_air")
+    private Integer isNotUseAir; // tinyint mapped to Integer
+
+    /**
+     * 税率
+     */
+    @JsonProperty("tax_rate")
+    private BigDecimal taxRate;
+
+    /**
+     * 大件类别 0非大件1普通大件2独立大件
+     */
+    @JsonProperty("large_type")
+    private Integer largeType; // tinyint mapped to Integer
+
+    /**
+     * 备注
+     */
+    @JsonProperty("remark")
+    private String remark;
+
+    /**
+     * 创建时间 格式:YYYY-MM-DD HH:MM:SS
+     */
+    @JsonProperty("spec_created")
+    private String specCreated; // Keep as String
+
+    /**
+     * 最后修改时间 格式:YYYY-MM-DD HH:MM:SS
+     */
+    @JsonProperty("spec_modified")
+    private String specModified; // Keep as String
+
+    /**
+     * 自定义1
+     */
+    @JsonProperty("prop1")
+    private String prop1;
+
+    /**
+     * 自定义2
+     */
+    @JsonProperty("prop2")
+    private String prop2;
+
+    /**
+     * 自定义3
+     */
+    @JsonProperty("prop3")
+    private String prop3;
+
+    /**
+     * 自定义4
+     */
+    @JsonProperty("prop4")
+    private String prop4;
+
+    /**
+     * 自定义5
+     */
+    @JsonProperty("prop5")
+    private String prop5;
+
+    /**
+     * 自定义6
+     */
+    @JsonProperty("prop6")
+    private String prop6;
+
+    /**
+     * 图片url
+     */
+    @JsonProperty("img_url")
+    private String imgUrl;
+
+    /**
+     * 关联税务表税务编码
+     */
+    @JsonProperty("tax_code_id")
+    private String taxCodeId;
+
+    /**
+     * 是否启用同一批次出库 0,不使用同一批次,1,使用同一批次
+     */
+    @JsonProperty("is_single_batch")
+    private Integer isSingleBatch; // tinyint mapped to Integer
+
+    /**
+     * 水洗标
+     */
+    @JsonProperty("washing_label")
+    private String washingLabel;
+
+    /**
+     * 基本单位
+     */
+    @JsonProperty("unit")
+    private String unit;
+
+    /**
+     * 辅助单位
+     */
+    @JsonProperty("aux_unit")
+    private String auxUnit;
+
+    /**
+     * 标记
+     */
+    @JsonProperty("flag_id")
+    private String flagId;
+
+    /**
+     * 图片在外部空间的key 比如说 云盘的一个 外链
+     */
+    @JsonProperty("img_key")
+    private String imgKey;
+
+    /**
+     * 条码个数
+     */
+    @JsonProperty("barcode_count")
+    private Integer barcodeCount; // smallint mapped to Integer
+
+    /**
+     * 平台货品数量(不包含删除的)
+     */
+    @JsonProperty("plat_spec_count")
+    private Integer platSpecCount; // smallint mapped to Integer
+
+    /**
+     * sn自增数
+     */
+    @JsonProperty("postfix_val")
+    private String postfixVal;
+
+    /**
+     * 最后日期 格式:yyyy-MM-dd
+     */
+    @JsonProperty("last_date")
+    private String lastDate; // Keep as String (Date type)
+
+    /**
+     * 补货方式 0持续补货 1不补货 2低于警戒库存补货
+     */
+    @JsonProperty("replenish_type")
+    private Integer replenishType;
+
+    /**
+     * 是否畅销 0非畅销 1畅销
+     */
+    @JsonProperty("is_popular")
+    private Integer isPopular;
+
+    /**
+     * 备注换货匹配码
+     */
+    @JsonProperty("replace_no")
+    private String replaceNo;
+
+    /**
+     * 单品标记二进制位 1同款备注换货虚拟规格 2是否在备注换货界面展示 4递交自动生成货品
+     */
+    @JsonProperty("spec_mask")
+    private String specMask;
+
+    /**
+     * 同款备注换货--虚拟货品换货比例
+     */
+    @JsonProperty("replace_proportion")
+    private String replaceProportion;
+
+    /**
+     * 扩展字段
+     */
+    @JsonProperty("extra_3")
+    private String extra3;
+
+    /**
+     * 税务编码
+     */
+    @JsonProperty("tax_code")
+    private String taxCode;
+
+    /**
+     * 最后修改时间 格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("modified")
+    private String modified; // Keep as String
+
+    /**
+     * 创建时间 格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("created")
+    private String created; // Keep as String
+
+    /**
+     * 基本单位名称
+     */
+    @JsonProperty("spec_unit_name")
+    private String specUnitName;
+
+    /**
+     * 辅助单位名称
+     */
+    @JsonProperty("spec_aux_unit_name")
+    private String specAuxUnitName;
+
+    /**
+     * 是否已删除:0:未删除 >0代表已删除
+     */
+    @JsonProperty("deleted")
+    private Integer deleted;
+
+    /**
+     * 条码列表
+     */
+    @JsonProperty("barcode_list")
+    private List<ErpWdtBarcodeDto> barcodeList;
+}

+ 19 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtStockDTO.java

@@ -0,0 +1,19 @@
+package com.fs.erp.dto.wdt;
+
+import lombok.Data;
+
+@Data
+public class ErpWdtStockDTO {
+    /**
+     * sku
+     */
+    private String sepc_no;
+    /**
+     * 库存量
+     */
+    private String stock_num;
+    /**
+     * 可用库存量
+     */
+    private String avaliable_num;
+}

+ 37 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtStockRespDTO.java

@@ -0,0 +1,37 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class ErpWdtStockRespDTO implements Serializable {
+    /**
+     * 错误码,状态码:0表示成功,其他表示失败
+     */
+    @JsonProperty("code")
+    @NotNull
+    private Integer code;
+
+    /**
+     * 错误描述
+     */
+    @JsonProperty("message")
+    @NotNull
+    private String message;
+
+    /**
+     * 数据条数,只有,page_no = 0 时才返回的符合条件的数据总条数,用来分页
+     */
+    @JsonProperty("total_count")
+    private Integer totalCount;
+
+    /**
+     * 订单列表节点,响应参数的1级数据节点,包含当前页的订单及其明细的数据节点
+     */
+    @JsonProperty("stocks")
+    private List<ErpWdtStockDTO> stocks;
+}

+ 194 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtTrade.java

@@ -0,0 +1,194 @@
+package com.fs.erp.dto.wdt;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 旺店通开放平台 API 订单信息 DTO
+ * @author xdd
+ * @date 2025-02-27
+ */
+@Data
+public class ErpWdtTrade {
+
+    /**
+     * 原始单号
+     * <p>指商城、官网等平台的订单编号,ERP称之为原始单号,同一个sid下通过本接口新增订单的tid保证唯一。</p>
+     */
+    private String tid;
+
+    /**
+     * 平台状态
+     * <p>平台订单状态较多且涉及变更,详情介绍单击这里</p>
+     */
+    private Integer tradeStatus;
+
+    /**
+     * 支付状态
+     * <p>平台订单付款状态:0:未付款,1:部分付款,2:已付款</p>
+     */
+    private Integer payStatus;
+
+    /**
+     * 发货条件
+     * <p>1:款到发货,2:货到付款(包含部分货到付款),3:分期付款,4:挂账</p>
+     */
+    private Integer deliveryTerm;
+
+    /**
+     * 下单时间
+     * <p>平台订单创建时间,时间格式:yyyy-MM-dd HH:mm:ss</p>
+     */
+    private String tradeTime;
+
+    /**
+     * 支付时间
+     * <p>平台订单付款时间,时间格式:yyyy-MM-dd HH:mm:ss,未付款订单为:0000-00-00 00:00:00</p>
+     */
+    private String payTime;
+
+    /**
+     * 分销类别
+     */
+    private Integer fenxiaoType;
+    /**
+     * 采购单ID
+     */
+    private String purchaseId;
+
+    private  String fenxiaoNick;
+    /**
+     * 	客户网名
+     */
+    private String buyerNick;
+
+    private String buyerEmail;
+
+    private String payId;
+    private String payAccount;
+    /**
+     * 支付方式:  1在线支付 2现金,3银行转账,4邮局汇款 5预付款 6刷卡 7支付宝 8微信支付  不传默认为1 在线支付
+     */
+    private Integer payMethod;
+    private String receiverName;
+    private String receiverProvince;
+    private String receiverCity;
+    private String receiverDistrict;
+    private String receiverAddress;
+    private String receiverMobile;
+    private String receiverTelno;
+    private String receiverZip;
+    /**
+     * 物流方式
+     * <p>不传本参数,输入值默认-1,表示由ERP系统策略选择。平台指定订单发货物流可选输入值单击这里</p>
+     */
+    private Integer logisticsType;
+
+    /**
+     * 发票类别
+     * <p>0:不需要,1:普通发票,2:增值税普通发票电子,3:增值税普通发票纸质,4:增值税专用发票</p>
+     */
+    private Integer invoiceKind;
+
+    /**
+     * 发票抬头
+     */
+    private String invoiceTitle;
+
+    /**
+     * 发票内容
+     * <p>常见内容:纳税人识别号、地址、电话、开户银行、银行账户,按照以下格式推送,系统开发票时可解析。</p>
+     * <p>推送格式:纳税人识别号:xxxxxxxxxxx;地址:xxxxxxxx 13888888888;开户银行:银行名称 银行账户;</p>
+     * <p>英文分号以后是地址,地址后面是空格,空格后面是电话,电话后面是英文分号,分号以后是开户行,然后空格,然后是银行账号</p>
+     */
+    private String invoiceContent;
+    /**
+     * 客户备注标旗,取值0至5对应的标旗颜色依次为灰(无标旗)、红、黄、绿、蓝、紫,不传默认0
+     */
+    private Integer remarkFlag;
+
+    /**
+     * 买家备注
+     * <p>买家下单时填写的订单备注</p>
+     */
+    private String buyerMessage;
+
+    /**
+     * 客服备注
+     * <p>商家客服对订单进行的备注内容</p>
+     */
+    private String sellerMemo;
+
+    /**
+     * 标旗
+     * <p>客服标旗,取值0至5对应的标旗颜色依次为灰(无标旗)、红、黄、绿、蓝、紫,不传默认0</p>
+     */
+    private Integer sellerFlag;
+
+    /**
+     * 邮费
+     * <p>商家收取买家的物流或者快递费用</p>
+     */
+    private BigDecimal postAmount;
+
+    /**
+     * 货到付款金额
+     * <p>货到付款金额   cod金额=(price * num + adjust_amount -discount – share_discount)+post_amount+ext_cod_fee-paid</p>
+     */
+    private BigDecimal codAmount;
+
+    /**
+     * 货到付款买家费用
+     * <p>货到付款买家费用,扣除货到付款订单金额后,卖家仍需支付的货到付款其他金额。这个钱卖家收不回来,是快递公司直接收走,但在快递单里是要打印出来,否则快递收款就错了</p>
+     */
+    private BigDecimal extCodFee;
+
+    /**
+     * 其它收费
+     * <p>其它应从买家收取的服务费,其他费用</p>
+     */
+    private BigDecimal otherAmount;
+
+    /**
+     * 已付
+     * <p>订单已付金额,paid计算公式:paid = Σ(price * num + adjust_amount -discount – share_discount)+ post_amount+other_amount,所有金额相关字段推送处理办法,单击这里</p>
+     */
+    private BigDecimal paid;
+
+    /**
+     * 证件类型
+     * <p>1:身份证(不传默认为0,为0时将证件号码置空)</p>
+     */
+    private Integer idCardType;
+
+    /**
+     * 证件号码
+     */
+    private String idCard;
+
+    /**
+     * 自动流转模式
+     * <p>是否为自动流转模式(1:是 0:不是 不传默认0),非自动流转模式一定不要传值。自动流转模式处理办法,”自动流转模式处理办法详解”)单击这里</p>
+     */
+    private Integer isAutoWms;
+
+    /**
+     * 仓库类型
+     * <p>非自动流转模式一定不要传值</p>
+     */
+    private Integer wmsType;
+
+    /**
+     * 仓库编号
+     * <p>ERP内自定义的仓库编号,查看路径ERP→设置→基本设置→仓库→仓库列表,测试环境仓库编号查看测试环境分配邮件。平台订单需指定ERP内仓库时,传哪个仓库的编号,ERP将为订单选择哪个仓库。</p>
+     */
+    private String warehouseNo;
+
+    /**
+     * 订单货品明细节点
+     * <p>货品明细列表(子订单列表)节点</p>
+     */
+    private List<ErpWdtOrder> orderList;
+}

+ 395 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtTradeDTO.java

@@ -0,0 +1,395 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * ERP WDT 交易订单信息DTO,用于封装从API获取的订单详情数据。
+ * 包含订单的基本信息、支付信息、物流信息、买家信息、金额信息以及关联的货品和优惠明细。
+ *
+ * @author xdd
+ * @date 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtTradeDTO {
+
+    /**
+     * 平台id 响应值为代表平台的ID数字
+     * @see <a href="这里应替换为实际的平台ID说明链接">平台ID说明</a>
+     */
+    private Integer platformId;
+
+    /**
+     * 店铺编号
+     */
+    private String shopNo;
+
+    /**
+     * 原始单号
+     */
+    private String tid;
+
+    /**
+     * 平台状态
+     * 10:未确认 20:待尾款 30:待发货 40:部分发货 50:已发货 60:已签收 70:已完成 80:已退款 90:已关闭(付款前取消)
+     */
+    private Integer tradeStatus;
+
+    /**
+     * 担保方式
+     * 1:担保交易 2:非担保交易 3:非担保在线交易
+     */
+    private Integer guaranteeMode;
+
+    /**
+     * 支付状态
+     * 0:未付款 1:部分付款 2:已付款
+     */
+    private Integer payStatus;
+
+    /**
+     * 发货条件
+     * 1:款到发货 2:货到付款 3:分期付款 4:挂账单
+     */
+    private Integer deliveryTerm;
+
+    /**
+     * 支付方式
+     * 1:在线转账 2:现金 3:银行转账 4:邮局汇款 5:预付款 6:刷卡 7:支付宝 8:微信支付
+     */
+    private Integer payMethod;
+
+    /**
+     * 退款状态
+     * 0:无退款 1:申请退款 2:部分退款 3:全部退款
+     */
+    private Integer refundStatus;
+
+    /**
+     * 系统状态
+     * 10:待递交 15:部分递交 20:已递交 30:部分发货 40:已发货 50:部分结算 60:已完成 70:已取消
+     */
+    private Integer processStatus;
+
+    /**
+     * 下单时间
+     * 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date tradeTime;
+
+    /**
+     * 支付时间
+     * 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date payTime;
+
+    /**
+     * 买家留言
+     */
+    private String buyerMessage;
+
+    /**
+     * 客服备注
+     */
+    private String remark;
+
+    /**
+     * 货款
+     */
+    private BigDecimal goodsAmount;
+
+    /**
+     * 邮费
+     */
+    private BigDecimal postAmount;
+
+    /**
+     * 其他费用
+     */
+    private BigDecimal otherAmount;
+
+    /**
+     * 优惠
+     */
+    private BigDecimal discount;
+
+    /**
+     * 已付金额
+     */
+    private BigDecimal paid;
+
+    /**
+     * 平台费用
+     */
+    private BigDecimal platformCost;
+
+    /**
+     * 已收金额
+     */
+    private BigDecimal received;
+
+    /**
+     * 应收金额
+     */
+    private BigDecimal receivable;
+
+    /**
+     * 款到发货金额
+     */
+    private BigDecimal dapAmount;
+
+    /**
+     * 货到付款金额
+     */
+    private BigDecimal codAmount;
+
+    /**
+     * 退款金额
+     */
+    private BigDecimal refundAmount;
+
+    /**
+     * 物流方式
+     * -1表示自由选择
+     */
+    private Integer logisticsType;
+
+    /**
+     * 发票类别
+     * 0:不需要 1:普通发票 2:普通增值发票 3:专用增值发票
+     */
+    private Integer invoiceType;
+
+    /**
+     * 发票抬头
+     */
+    private String invoiceTitle;
+
+    /**
+     * 发票内容
+     */
+    private String invoiceContent;
+
+    /**
+     * 结束时间
+     * 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date endTime;
+
+    /**
+     * 分销方式
+     * 0:非分销订单 1:转供销 2:代销 3:经销
+     */
+    private Integer fenxiaoType;
+
+    /**
+     * 订单来源
+     * 1:API抓单 2:手工建单 3:excel导入 4:现款销售 5:外部推送
+     */
+    private Integer tradeFrom;
+
+    /**
+     * 修改时间
+     * 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date modified;
+
+    /**
+     * 创建时间
+     * 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date created;
+
+    /**
+     * 订单标记位 (按位表示不同状态)
+     * 1:使用智选物流 2:航空禁运 4:预订单自动转审核失败 8:预占用待发货库存 16:订单货品指定批次
+     * 32:自动流转仓库 64:部分发货 128:全部发货 256:已发过签收消息 512:大单锁定仓库 1024:人工转入预订单
+     * 2048:因配置先占用待发货库存 4096:顺丰前置发货 8192:订单批量合并后标记 16384:达到原始单最大合并限制
+     * 32768:物流升级原始单指定物流订单 65536:BIC订单标记 131072:标记货品指定物流
+     * 3554432:前N有礼订单 67108864:预售下沉
+     */
+    private String tradeMask; // 使用String类型存储可能包含多个标记位的组合值
+
+    /**
+     * 买家ID (返回为空)
+     */
+    private String openid;
+
+    /**
+     * 币种
+     */
+    private String currency;
+
+    /**
+     * 积分
+     */
+    private Integer score;
+
+    /**
+     * 交货时间 (默认为'')
+     * 如:周一至周五,预计送货时间,最晚揽收时间 (周期购使用)
+     */
+    private String toDeliverTime;
+
+    /**
+     * 分期付款金额 (默认为'0.0000')
+     */
+    private BigDecimal piAmount;
+
+    /**
+     * 自动增量id
+     */
+    private Long recId;
+
+    /**
+     * 店铺id (默认为'0')
+     */
+    private Integer shopId;
+
+    /**
+     * 子订单个数
+     */
+    private Integer orderCount;
+
+    /**
+     * 货品总数量,用于递交时检验
+     */
+    private BigDecimal goodsCount;
+
+    /**
+     * 客户网名
+     */
+    private String buyerNick;
+
+    /**
+     * 买家姓名(仅返回自有平台、线下平台订单)
+     */
+    private String buyerName;
+
+    /**
+     * 买家区域 (默认为'')
+     */
+    private String buyerArea;
+
+    /**
+     * 客户编号
+     */
+    private String customerNo;
+
+    /**
+     * 收件人姓名(仅返回自有平台、线下平台订单)
+     */
+    private String receiverName;
+
+    /**
+     * 收件人国家 (默认为'0')
+     * @see <a href="这里应替换为实际的国家代码说明链接">国家代码说明</a>
+     */
+    private Integer receiverCountry;
+
+    /**
+     * 收件人省份ID,按照城市代码表中对应城市代码进行返回
+     * @see <a href="这里应替换为实际的城市代码表链接">城市代码表</a>
+     */
+    private Integer receiverProvince;
+
+    /**
+     * 收件人城市ID,按照城市代码表中对应城市代码进行返回
+     * @see <a href="这里应替换为实际的城市代码表链接">城市代码表</a>
+     */
+    private Integer receiverCity;
+
+    /**
+     * 收件人地区ID,按照城市代码表中对应城市代码进行返回
+     * @see <a href="这里应替换为实际的城市代码表链接">城市代码表</a>
+     */
+    private Integer receiverDistrict;
+
+    /**
+     * 收件人手机(仅返回自有平台、线下平台订单)
+     */
+    private String receiverMobile;
+
+    /**
+     * 收件人电话(仅返回自有平台、线下平台订单)
+     */
+    private String receiverTelno;
+
+    /**
+     * 收件人省份名称(仅返回自有平台、线下平台订单)
+     */
+    private String receiverProvinceName;
+
+    /**
+     * 收件人城市名称(仅返回自有平台、线下平台订单)
+     */
+    private String receiverCityName;
+
+    /**
+     * 收件人区县名称(仅返回自有平台、线下平台订单)
+     */
+    private String receiverDistrictName;
+
+    /**
+     * 收件人省市区地址(仅返回自有平台、线下平台订单)
+     */
+    private String receiverArea;
+
+    /**
+     * 收件人详细地址(仅返回自有平台、线下平台订单)
+     */
+    private String receiverAddress;
+
+    /**
+     * 标旗
+     */
+    private String remarkFlag;
+
+    /**
+     * 平台支付订单id,如支付宝的订单号
+     */
+    private String payId;
+
+    /**
+     * 应对消费者开票金额
+     */
+    private BigDecimal invoiceConsumerAmount;
+
+    /**
+     * 应对平台开票金额
+     */
+    private BigDecimal invoicePlatformAmount;
+
+    /**
+     * 主单是否自动流转到wms (默认为'0')
+     * 0: 否, 1: 是
+     */
+    private Integer isAutoWms;
+
+    /**
+     * 货品明细列表
+     * 业务数据的二级节点
+     */
+    private List<ErpWdtGoodsListDTO> goodsList;
+
+    /**
+     * 优惠明细列表
+     * 业务数据的二级节点
+     */
+    private List<ErpWdtDiscountListDTO> discountList;
+}

+ 910 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtTradeInfo.java

@@ -0,0 +1,910 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.List;
+// import java.time.LocalDateTime; // 如果需要反序列化为日期时间对象
+
+/**
+ * ERP 旺店通 订单信息 DTO.
+ * 代表单个订单的详细信息。
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtTradeInfo {
+
+    /**
+     * erp订单表的主键
+     */
+    @JsonProperty("trade_id")
+    @NotNull // 必须
+    private Integer tradeId;
+
+    /**
+     * 订单编号,系统订单编号,默认单号为JY开头,ERP内支持自定义订单编号生成规则(设置路径:设置——编码设置)
+     */
+    @JsonProperty("trade_no")
+    @NotNull // 必须
+    private String tradeNo;
+
+    /**
+     * 平台ID,响应值为代表平台的ID数字,ID对应的平台名称单击这里
+     */
+    @JsonProperty("platform_id")
+    @NotNull // 必须
+    private Integer platformId;
+
+    /**
+     * 店铺平台ID,响应值为代表平台的ID数字,ID对应的平台名称单击这里
+     */
+    @JsonProperty("shop_platform_id")
+    @NotNull // 必须
+    private Integer shopPlatformId;
+
+    /**
+     * 店铺编号,代表店铺所有属性的唯一编码,用于店铺区分,ERP内支持自定义(ERP店铺界面设置)
+     */
+    @JsonProperty("shop_no")
+    @NotNull // 必须
+    private String shopNo;
+
+    /**
+     * 店铺名称
+     */
+    @JsonProperty("shop_name")
+    @NotNull // 必须
+    private String shopName;
+
+    /**
+     * 店铺备注
+     */
+    @JsonProperty("shop_remark")
+    @NotNull // 必须
+    private String shopRemark;
+
+    /**
+     * 仓库类型(0不限 1普通仓库 2自动流传外部 3京东仓储 4科捷 5百世物流 6SKU360 7通天晓 8中联网仓 9顺丰仓储 10网仓2号 11奇门仓储 12旺店通仓储 13心怡仓储 14力威仓储 15京东沧海 16云集仓储 17POS 18虎符 20外部链路型 22抖店云仓 126分销委外仓 127其它)
+     */
+    @JsonProperty("warehouse_type")
+    @NotNull // 必须
+    private Integer warehouseType;
+
+    /**
+     * 仓库编号,代表仓库所有属性的唯一编码,用于仓库区分,ERP内支持自定义(ERP仓库界面设置)(根据编号可查询仓库名称)
+     */
+    @JsonProperty("warehouse_no")
+    @NotNull // 必须
+    private String warehouseNo;
+
+    /**
+     * 原始单号,商城或电商平台的订单编号,合并订单的多个订单编号有逗号隔开
+     */
+    @JsonProperty("src_tids")
+    @NotNull // 必须
+    private String srcTids;
+
+    /**
+     * 订单状态 5已取消 10待付款 12待尾款 13待选仓 15等未付16延时审核 19预订单前处理 20前处理(赠品,合并,拆分)21委外前处理22抢单前处理 25预订单 27待抢单 30待客审 35待财审 40待递交仓库 45递交仓库中 50已递交仓库 53未确认 55已确认(已审核)90发货中  95已发货 105部分打款 110已完成 113异常发货
+     */
+    @JsonProperty("trade_status")
+    @NotNull // 必须
+    private Integer tradeStatus;
+
+    /**
+     * 发货状态,出库状态:0表示无出库状态,1验货 2称重 4出库 8物流同步16分拣 32档口  64拣货 128供销回传成功  256供销回传失败(注意:如果是3,则表示完成了验货和称重“1+2”,如果是15,则表示四个过程都完成了“1+2+4+8”,其他数字以此类推)
+     */
+    @JsonProperty("consign_status")
+    @NotNull // 必须
+    private Integer consignStatus;
+
+    /**
+     * 订单类型 1网店销售 2线下零售 3售后换货 4批发业务 5保修换新 6保修完成 7订单补发 8供销补发   101自定义类型1 102自定义类型2 103自定义类型3 104自定义类型4 105自定义类型5 106自定义类型6 107自定义属性7 108自定义属性8
+     */
+    @JsonProperty("trade_type")
+    @NotNull // 必须
+    private Integer tradeType;
+
+    /**
+     * 发货条件 1款到发货 2货到付款(包含部分货到付款),4挂账
+     */
+    @JsonProperty("delivery_term")
+    @NotNull // 必须
+    private Integer deliveryTerm;
+
+    /**
+     * 冻结原因
+     */
+    @JsonProperty("freeze_reason")
+    @NotNull // 必须
+    private Integer freezeReason;
+
+    /**
+     * 退款状态 0无退款 1申请退款 2部分退款 3全部退款 4未付款关闭或手工关闭
+     */
+    @JsonProperty("refund_status")
+    @NotNull // 必须
+    private Integer refundStatus;
+
+    /**
+     * 分销类别 0非分销订单 1转供销 2代销 3经销
+     */
+    @JsonProperty("fenxiao_type")
+    @NotNull // 必须
+    private Integer fenxiaoType;
+
+    /**
+     * 分销商信息,不同平台单据分销商会存不同格式情况,具体以返回信息为准
+     */
+    @JsonProperty("fenxiao_nick")
+    @NotNull // 必须
+    private String fenxiaoNick;
+
+    /**
+     * 下单时间 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("trade_time")
+    @NotNull // 必须
+    private String tradeTime; // 或者 LocalDateTime tradeTime; 并配置Jackson
+
+    /**
+     * 付款时间 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("pay_time")
+    @NotNull // 必须
+    private String payTime; // 或者 LocalDateTime payTime; 并配置Jackson
+
+    /**
+     * 客户名称
+     */
+    @JsonProperty("customer_name")
+    @NotNull // 必须
+    private String customerName;
+
+    /**
+     * 客户编码
+     */
+    @JsonProperty("customer_no")
+    @NotNull // 必须
+    private String customerNo;
+
+    /**
+     * 买家付款账号
+     */
+    @JsonProperty("pay_account")
+    @NotNull // 必须
+    private String payAccount;
+
+    /**
+     * 客户网名
+     */
+    @JsonProperty("buyer_nick")
+    @NotNull // 必须
+    private String buyerNick;
+
+    /**
+     * 收件人
+     */
+    @JsonProperty("receiver_name")
+    @NotNull // 必须
+    private String receiverName;
+
+    /**
+     * 收件人的省份,按照城市代码表中对应城市代码进行返回
+     */
+    @JsonProperty("receiver_province")
+    @NotNull // 必须
+    private Integer receiverProvince;
+
+    /**
+     * 收件人的城市,按照城市代码表中对应城市代码进行返回
+     */
+    @JsonProperty("receiver_city")
+    @NotNull // 必须
+    private Integer receiverCity;
+
+    /**
+     * 收件人的地区,按照城市代码表中对应城市代码进行返回
+     */
+    @JsonProperty("receiver_district")
+    @NotNull // 必须
+    private Integer receiverDistrict;
+
+    /**
+     * 地址
+     */
+    @JsonProperty("receiver_address")
+    @NotNull // 必须
+    private String receiverAddress;
+
+    /**
+     * 手机
+     */
+    @JsonProperty("receiver_mobile")
+    @NotNull // 必须
+    private String receiverMobile;
+
+    /**
+     * 电话
+     */
+    @JsonProperty("receiver_telno")
+    @NotNull // 必须
+    private String receiverTelno;
+
+    /**
+     * 收件人邮编
+     */
+    @JsonProperty("receiver_zip")
+    @NotNull // 必须
+    private String receiverZip;
+
+    /**
+     * 省市县空格分隔
+     */
+    @JsonProperty("receiver_area")
+    @NotNull // 必须
+    private String receiverArea;
+
+    /**
+     * 收件人区域
+     */
+    @JsonProperty("receiver_ring")
+    @NotNull // 必须
+    private String receiverRing;
+
+    /**
+     * 大头笔
+     */
+    @JsonProperty("receiver_dtb")
+    @NotNull // 必须
+    private String receiverDtb;
+
+    /**
+     * 派送时间 如周一至周五,上午
+     */
+    @JsonProperty("to_deliver_time")
+    @NotNull // 必须
+    private String toDeliverTime;
+
+    /**
+     * 异常订单(bit位), 2地址变化 8仓库变化 16客服备注变化 128拦截赠品 64退款 2048买家留言发生变更
+     */
+    @JsonProperty("bad_reason")
+    @NotNull // 必须
+    private Integer badReason;
+
+    /**
+     * 物流公司ID(系统自增主键id)
+     */
+    @JsonProperty("logistics_id")
+    @NotNull // 必须
+    private Integer logisticsId;
+
+    /**
+     * 物流公司名称
+     */
+    @JsonProperty("logistics_name")
+    @NotNull // 必须
+    private String logisticsName;
+
+    /**
+     * 物流公司编号,代表物流所有属性的唯一编码,用于物流区分,ERP内支持自定义(ERP物流界面设置)
+     */
+    @JsonProperty("logistics_code")
+    @NotNull // 必须
+    private String logisticsCode;
+
+    /**
+     * 物流方式,响应值为代表物流方式的数字,数字对应的物流方式名称单击这里
+     */
+    @JsonProperty("logistics_type")
+    @NotNull // 必须
+    private Integer logisticsType;
+
+    /**
+     * 物流单号
+     */
+    @JsonProperty("logistics_no")
+    @NotNull // 必须
+    private String logisticsNo;
+
+    /**
+     * 店铺id,店铺列表主键
+     */
+    @JsonProperty("shop_id")
+    @NotNull // 必须
+    private Integer shopId;
+
+    /**
+     * 仓库ID
+     */
+    @JsonProperty("warehouse_id")
+    @NotNull // 必须
+    private Integer warehouseId;
+
+    /**
+     * 审核步骤,用于多级审核,特殊值:-100根据预售策略自动转入特殊单,-101人工转入
+     */
+    @JsonProperty("check_step")
+    @NotNull // 必须
+    private Integer checkStep;
+
+    /**
+     * 未合并标记,1有未付款订单,2有同名未合并订单
+     */
+    @JsonProperty("unmerge_mask")
+    @NotNull // 必须
+    private Integer unmergeMask;
+
+    /**
+     * 延迟处理,延时此进一步处理,等未付或延时审核 激活时间 秒级时间戳格式返回
+     */
+    @JsonProperty("delay_to_time")
+    @NotNull // 必须
+    private String delayToTime; // 通常是 Long 类型的时间戳,但描述是 varchar,保持 String
+
+    /**
+     * 客户类型 0普通客户1经销商
+     */
+    @JsonProperty("customer_type")
+    @NotNull // 必须
+    private Integer customerType;
+
+    /**
+     * 买家ID
+     */
+    @JsonProperty("customer_id")
+    @NotNull // 必须
+    private String customerId; // 描述是 varchar(11)
+
+    /**
+     * 收件人国家
+     */
+    @JsonProperty("receiver_country")
+    @NotNull // 必须
+    private Integer receiverCountry;
+
+    /**
+     * 预配送时间,配送中心,未使用
+     */
+    @JsonProperty("pre_charge_time")
+    @NotNull // 必须
+    private String preChargeTime;
+
+    /**
+     * 是否京配(为1时,只能发京邦达)
+     */
+    @JsonProperty("is_prev_notify")
+    @NotNull // 必须
+    private Integer isPrevNotify;
+
+    /**
+     * 便签条数
+     */
+    @JsonProperty("note_count")
+    @NotNull // 必须
+    private Integer noteCount;
+
+    /**
+     * 买家留言条数
+     */
+    @JsonProperty("buyer_message_count")
+    @NotNull // 必须
+    private Integer buyerMessageCount;
+
+    /**
+     * 客服备注条数
+     */
+    @JsonProperty("cs_remark_count")
+    @NotNull // 必须
+    private Integer csRemarkCount;
+
+    /**
+     * 客服备注变化 0,未变化1平台变化,2手工修改,4发票手工修改
+     */
+    @JsonProperty("cs_remark_change_count")
+    @NotNull // 必须
+    private Integer csRemarkChangeCount;
+
+    /**
+     * 优惠变化金额,更新货品和数量
+     */
+    @JsonProperty("discount_change")
+    @NotNull // 必须
+    private BigDecimal discountChange;
+
+    /**
+     * 客户使用的预存款
+     */
+    @JsonProperty("trade_prepay")
+    @NotNull // 必须
+    private BigDecimal tradePrepay;
+
+    /**
+     * 分期付款金额
+     */
+    @JsonProperty("pi_amount")
+    @NotNull // 必须
+    private BigDecimal piAmount;
+
+    /**
+     * 其它成本(目前用作记录货到付款单据的物流佣金)
+     */
+    @JsonProperty("other_cost")
+    @NotNull // 必须
+    private BigDecimal otherCost;
+
+    /**
+     * 体积(单位:cm³)
+     */
+    @JsonProperty("volume")
+    @NotNull // 必须
+    private BigDecimal volume;
+
+    /**
+     * 销售积分,未使用
+     */
+    @JsonProperty("sales_score")
+    @NotNull // 必须
+    private String salesScore; // varchar(11)
+
+    /**
+     * 背景色标记id
+     */
+    @JsonProperty("flag_id")
+    @NotNull // 必须
+    private Integer flagId;
+
+    /**
+     * 不可合并拆分
+     */
+    @JsonProperty("is_sealed")
+    @NotNull // 必须
+    private Integer isSealed; // tinyint(1)
+
+    /**
+     * 赠品标记1已处理过赠品,但没有匹配任何策略2自动赠送4手工赠送6即有自动也有手工
+     */
+    @JsonProperty("gift_mask")
+    @NotNull // 必须
+    private Integer giftMask;
+
+    /**
+     * 拆分订单,原单ID,用于避免自动合并,大件拆分为(原订单的id值),自动拆分为负值(原订单的-id值)
+     */
+    @JsonProperty("split_from_trade_id")
+    @NotNull // 必须
+    private String splitFromTradeId; // varchar(11)
+
+    /**
+     * 物流单模板ID,未使用
+     */
+    @JsonProperty("logistics_template_id")
+    @NotNull // 必须
+    private String logisticsTemplateId; // varchar(11)
+
+    /**
+     * 发货单模板id,未使用
+     */
+    @JsonProperty("sendbill_template_id")
+    @NotNull // 必须
+    private String sendbillTemplateId; // varchar(11)
+
+    /**
+     * 驳回原因
+     */
+    @JsonProperty("revert_reason")
+    @NotNull // 必须
+    private Integer revertReason;
+
+    /**
+     * 取消原因
+     */
+    @JsonProperty("cancel_reason")
+    @NotNull // 必须
+    private Integer cancelReason;
+
+    /**
+     * 催未付款订单消息发送标记
+     */
+    @JsonProperty("is_unpayment_sms")
+    @NotNull // 必须
+    private Integer isUnpaymentSms; // tinyint(1)
+
+    /**
+     * 包装id
+     */
+    @JsonProperty("package_id")
+    @NotNull // 必须
+    private String packageId; // varchar(11)
+
+    /**
+     * 订单标记位 1使用智选物流 2 航空禁运 4 预订单自动转审核失败 8 预占用待发货库存 16 订单货品指定批次 32 自动流转仓库 64 部分发货 128 全部发货 256 已发过签收消息 512 大单锁定仓库 1024 人工转入预订单 2048因配置先占用待发货库存 4096 顺丰前置发货 8192订单批量合并后标记 16384 达到原始单最大合并限制 32768 物流升级原始单指定物流订单 65536 BIC订单标记 131072 标记货品指定物流 3554432前N有礼订单 67108864预售下沉
+     */
+    @JsonProperty("trade_mask")
+    @NotNull // 必须
+    private String tradeMask; // varchar(11),虽然是位标记,但类型是varchar
+
+    /**
+     * 保留
+     */
+    @JsonProperty("reserve")
+    @NotNull // 必须
+    private String reserve;
+
+    /**
+     * 大件类型,包含大件类型,1普通套件2独立套件3分组单发,未使用-1非单发件 取子单中的最大值
+     */
+    @JsonProperty("large_type")
+    @NotNull // 必须
+    private Integer largeType;
+
+    /**
+     * 买家留言
+     */
+    @JsonProperty("buyer_message")
+    @NotNull // 必须
+    private String buyerMessage;
+
+    /**
+     * 客服备注
+     */
+    @JsonProperty("cs_remark")
+    @NotNull // 必须
+    private String csRemark;
+
+    /**
+     * 标旗 0至5对应的标旗颜色依次为灰(无标旗)、红、黄、绿、蓝、紫
+     */
+    @JsonProperty("remark_flag")
+    @NotNull // 必须
+    private String remarkFlag;
+
+    /**
+     * 打印备注
+     */
+    @JsonProperty("print_remark")
+    @NotNull // 必须
+    private String printRemark;
+
+    /**
+     * 货品种类数
+     */
+    @JsonProperty("goods_type_count")
+    @NotNull // 必须
+    private Integer goodsTypeCount;
+
+    /**
+     * 货品总数
+     */
+    @JsonProperty("goods_count")
+    @NotNull // 必须
+    private BigDecimal goodsCount;
+
+    /**
+     * 货品总额(未扣除优惠),sum(share_amount+discount)所得
+     */
+    @JsonProperty("goods_amount")
+    @NotNull // 必须
+    private BigDecimal goodsAmount;
+
+    /**
+     * 邮费
+     */
+    @JsonProperty("post_amount")
+    @NotNull // 必须
+    private BigDecimal postAmount;
+
+    /**
+     * 其它费用,其它从买家的收费(非订单支付金额以及服务费),从原始订单列表继承
+     */
+    @JsonProperty("other_amount")
+    @NotNull // 必须
+    private BigDecimal otherAmount;
+
+    /**
+     * 订单优惠,系统子订单“优惠”求合所得
+     */
+    @JsonProperty("discount")
+    @NotNull // 必须
+    private BigDecimal discount;
+
+    /**
+     * 应收金额,系统订单的(“货品总额”+“邮资”-“折扣”)所得
+     */
+    @JsonProperty("receivable")
+    @NotNull // 必须
+    private BigDecimal receivable;
+
+    /**
+     * 款到发货金额,paid>=dap_amount才可发货
+     */
+    @JsonProperty("dap_amount")
+    @NotNull // 必须
+    private BigDecimal dapAmount;
+
+    /**
+     * COD金额,货到付款订单金额,系统子订单的(“分摊后总价”+“分摊邮费”-“已付”)再求和
+     */
+    @JsonProperty("cod_amount")
+    @NotNull // 必须
+    private BigDecimal codAmount;
+
+    /**
+     * 买家COD费用,货到付款非订单金额,从原始订单继承
+     */
+    @JsonProperty("ext_cod_fee")
+    @NotNull // 必须
+    private BigDecimal extCodFee;
+
+    /**
+     * 货款预估成本
+     */
+    @JsonProperty("goods_cost")
+    @NotNull // 必须
+    private BigDecimal goodsCost;
+
+    /**
+     * 预估邮费成本
+     */
+    @JsonProperty("post_cost")
+    @NotNull // 必须
+    private BigDecimal postCost;
+
+    /**
+     * 已付金额,系统子订单“已付”求合所得
+     */
+    @JsonProperty("paid")
+    @NotNull // 必须
+    private BigDecimal paid;
+
+    /**
+     * 预估重量(单位:kg)
+     */
+    @JsonProperty("weight")
+    @NotNull // 必须
+    private BigDecimal weight;
+
+    /**
+     * 预估毛利
+     */
+    @JsonProperty("profit")
+    @NotNull // 必须
+    private BigDecimal profit;
+
+    /**
+     * 税额
+     */
+    @JsonProperty("tax")
+    @NotNull // 必须
+    private BigDecimal tax;
+
+    /**
+     * 税率
+     */
+    @JsonProperty("tax_rate")
+    @NotNull // 必须
+    private BigDecimal taxRate;
+
+    /**
+     * 佣金
+     */
+    @JsonProperty("commission")
+    @NotNull // 必须
+    private BigDecimal commission;
+
+    /**
+     * 发票类别 0 不需要,1普通发票,2增值普通税发票,3增值专用税发票
+     */
+    @JsonProperty("invoice_type")
+    @NotNull // 必须
+    private Integer invoiceType;
+
+    /**
+     * 发票抬头
+     */
+    @JsonProperty("invoice_title")
+    @NotNull // 必须
+    private String invoiceTitle;
+
+    /**
+     * 发票内容
+     */
+    @JsonProperty("invoice_content")
+    @NotNull // 必须
+    private String invoiceContent;
+
+    /**
+     * 业务员ID
+     */
+    @JsonProperty("salesman_id")
+    @NotNull // 必须
+    private Integer salesmanId;
+
+    /**
+     * 审核员工ID
+     */
+    @JsonProperty("checker_id")
+    @NotNull // 必须
+    private Integer checkerId;
+
+    /**
+     * 业务员姓名
+     */
+    @JsonProperty("fullname")
+    @NotNull // 必须
+    private String fullname;
+
+    /**
+     * 审核员工姓名
+     */
+    @JsonProperty("checker_name")
+    @NotNull // 必须
+    private String checkerName;
+
+    /**
+     * 财审操作员ID
+     */
+    @JsonProperty("fchecker_id")
+    @NotNull // 必须
+    private Integer fcheckerId;
+
+    /**
+     * 签出员工id
+     */
+    @JsonProperty("checkouter_id")
+    @NotNull // 必须
+    private Integer checkouterId;
+
+    /**
+     * 出库单号,内部或外部仓库的订单号
+     */
+    @JsonProperty("stockout_no")
+    @NotNull // 必须
+    private String stockoutNo;
+
+    /**
+     * 背景色标记名称
+     */
+    @JsonProperty("flag_name")
+    @NotNull // 必须
+    private String flagName;
+
+    /**
+     * 订单来源 1API抓单,2手工建单 3excel导入 4现款销售
+     */
+    @JsonProperty("trade_from")
+    @NotNull // 必须
+    private Integer tradeFrom;
+
+    /**
+     * 货品商家编码
+     */
+    @JsonProperty("single_spec_no")
+    @NotNull // 必须
+    private String singleSpecNo;
+
+    /**
+     * 原始货品数量
+     */
+    @JsonProperty("raw_goods_count")
+    @NotNull // 必须
+    private BigDecimal rawGoodsCount;
+
+    /**
+     * 原始货品种类数
+     */
+    @JsonProperty("raw_goods_type_count")
+    @NotNull // 必须
+    private Integer rawGoodsTypeCount;
+
+    /**
+     * 币种
+     */
+    @JsonProperty("currency")
+    @NotNull // 必须
+    private String currency;
+
+    /**
+     * 已拆分包裹数
+     */
+    @JsonProperty("split_package_num")
+    @NotNull // 必须
+    private Integer splitPackageNum;
+
+    /**
+     * 发票ID,0表示未开发票,>0表示已开发票
+     */
+    @JsonProperty("invoice_id")
+    @NotNull // 必须
+    private Integer invoiceId;
+
+    /**
+     * 订单每修改一次,版本号做一次变更
+     */
+    @JsonProperty("version_id")
+    @NotNull // 必须
+    private Integer versionId;
+
+    /**
+     * 最后修改时间 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("modified")
+    @NotNull // 必须
+    private String modified; // 或者 LocalDateTime modified;
+
+    /**
+     * 系统单生成时间 时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("created")
+    @NotNull // 必须
+    private String created; // 或者 LocalDateTime created;
+
+    /**
+     * 证件类别
+     */
+    @JsonProperty("id_card_type")
+    @NotNull // 必须
+    private Integer idCardType;
+
+    /**
+     * 证件号码,仅返回自有平台、线下平台订单
+     */
+    @JsonProperty("id_card")
+    @NotNull // 必须
+    private String idCard;
+
+    /**
+     * 财审人名称
+     */
+    @JsonProperty("fchecker_name")
+    @NotNull // 必须
+    private String fcheckerName;
+
+    /**
+     * 签出人名称
+     */
+    @JsonProperty("checkouter_name")
+    @NotNull // 必须
+    private String checkouterName;
+
+    /**
+     * 冻结原因名称
+     */
+    @JsonProperty("freeze_reason_info")
+    @NotNull // 必须
+    private String freezeReasonInfo;
+
+    /**
+     * 分销原始单号
+     */
+    @JsonProperty("fenxiao_tid")
+    @NotNull // 必须
+    private String fenxiaoTid;
+
+    /**
+     * 订单标签/异常id,具体标签/异常名称查询,需使用查询标签/异常名称接口
+     */
+    @JsonProperty("tags")
+    @NotNull // 必须
+    private String tags;
+
+    /**
+     * 货品列表节点,响应参数的2级数据节点,包含系统订单货品明细所有属性信息的数据节点
+     */
+    @JsonProperty("goods_list")
+    @NotNull // 必须
+    private List<ErpWdtGoodsInfo> goodsList;
+
+}

+ 128 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtTradeQueryRequest.java

@@ -0,0 +1,128 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+/**
+ * ERP 旺店通 订单查询请求 DTO.
+ * 用于封装调用旺店通ERP查询订单接口时的业务请求参数。
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtTradeQueryRequest {
+
+    /**
+     * 订单状态 如果不传该字段则查询所有订单
+     * (传该字段:5已取消 10待付款 12待尾款 13待选仓 15等未付16延时审核 19预订单前处理 20前处理(赠品,合并,拆分)21委外前处理22抢单前处理 25预订单 27待抢单 30待客审 35待财审 40待递交仓库 45递交仓库中 50已递交仓库 53未确认 55已确认(已审核) 95已发货 105部分打款 110已完成 113异常发货)
+     */
+    @JsonProperty("status")
+    private Integer status;
+
+    /**
+     * 开始时间,按最后修改时间增量获取数据, start_time作为开始时间,时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("start_time")
+    @NotNull // 必须
+    private String startTime;
+
+    /**
+     * 结束时间,按最后修改时间增量获取数据, end_time作为结束时间,时间格式:yyyy-MM-dd HH:mm:ss
+     */
+    @JsonProperty("end_time")
+    @NotNull // 必须
+    private String endTime;
+
+    /**
+     * 分页大小,每页返回的数据条数,输入值范围1~100,不传本参数,输入值默认为40
+     */
+    @JsonProperty("page_size")
+    @Min(value = 1, message = "分页大小最小为1")
+    @Max(value = 100, message = "分页大小最大为100")
+    private Integer pageSize;
+
+    /**
+     * 页号,不传值默认从0页开始
+     */
+    @JsonProperty("page_no")
+    @Min(value = 0, message = "页号最小为0")
+    private Integer pageNo;
+
+    /**
+     * 原始单号,如果使用原始单号,其余参数不起效。其余参数可以不传
+     */
+    @JsonProperty("src_tid")
+    @Size(max = 40, message = "原始单号长度不能超过40")
+    private String srcTid;
+
+    /**
+     * 订单编号,系统订单编号,默认单号为JY开头,ERP内支持自定义(设置路径:设置——编码设置)如果使用订单编号,其余参数不起效,其余参数可以不传
+     */
+    @JsonProperty("trade_no")
+    @Size(max = 40, message = "订单编号长度不能超过40")
+    private String tradeNo;
+
+    /**
+     * 店铺编号,代表店铺所有属性的唯一编码,用于店铺区分,ERP内支持自定义(ERP店铺界面设置),用于获取指定店铺单据数据信息
+     */
+    @JsonProperty("shop_no")
+    @Size(max = 40, message = "店铺编号长度不能超过40")
+    private String shopNo;
+
+    /**
+     * 仓库编号,代表仓库所有属性的唯一编码,用于仓库区分,ERP内支持自定义(ERP仓库界面设置),用于获取指定仓库单据数据信息(不支持一次推送多个仓库编码)
+     */
+    @JsonProperty("warehouse_no")
+    @Size(max = 40, message = "仓库编号长度不能超过40")
+    private String warehouseNo;
+
+    /**
+     * 使用税率 0 使用订单中的税率 1 使用单品中的税率(默认0)
+     */
+    @JsonProperty("goodstax")
+    private Integer goodsTax; // 注意:字段名改为 goodsTax 以符合 Java 命名规范
+
+    /**
+     * 物流单号限制 0 没有任何限制(默认值) 1 物流单号不为空才返回 2 只返回物流单号为空的
+     */
+    @JsonProperty("has_logistics_no")
+    private Integer hasLogisticsNo;
+
+    /**
+     * 是否模糊查询 0精确 1模糊  默认为0 (仅在原始单号src_tid查询时生效)
+     */
+    @JsonProperty("is_fuzzy")
+    private Integer isFuzzy;
+
+    /**
+     * 是否返回交易流水号、付款状态、付款时间 1 (返回 ),0 (不返回)(不传默认值0)
+     */
+    @JsonProperty("src")
+    private Integer srcFlag; // 避免与 srcTid 混淆,改名为 srcFlag
+
+    /**
+     * 物流单号,如果使用物流单号,其余参数不起效。其余参数可以不传
+     */
+    @JsonProperty("logistics_no")
+    @Size(max = 40, message = "物流单号长度不能超过40")
+    private String logisticsNo;
+
+    /**
+     * 店铺编号(批量),批量指定店铺获取(多个店铺编号之间用英文逗号隔开,最多指定20个店铺)
+     */
+    @JsonProperty("shop_nos")
+    private String shopNos;
+}

+ 52 - 0
fs-service/src/main/java/com/fs/erp/dto/wdt/ErpWdtTradeQueryResponse.java

@@ -0,0 +1,52 @@
+package com.fs.erp.dto.wdt;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * ERP 旺店通 订单查询响应 DTO.
+ * 包含查询结果的元数据以及订单列表信息。
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ErpWdtTradeQueryResponse {
+
+    /**
+     * 错误码,状态码:0表示成功,其他表示失败
+     */
+    @JsonProperty("code")
+    @NotNull // 必须
+    private Integer code;
+
+    /**
+     * 错误描述
+     */
+    @JsonProperty("message")
+    @NotNull // 必须
+    private String message;
+
+    /**
+     * 数据条数,只有,page_no = 0 时才返回的符合条件的数据总条数,用来分页
+     */
+    @JsonProperty("total_count")
+    private Integer totalCount;
+
+    /**
+     * 订单列表节点,响应参数的1级数据节点,包含当前页的订单及其明细的数据节点
+     */
+    @JsonProperty("trades")
+    private List<ErpWdtTradeInfo> trades;
+}
+

+ 100 - 0
fs-service/src/main/java/com/fs/erp/mapper/FsErpFinishPushMapper.java

@@ -0,0 +1,100 @@
+package com.fs.erp.mapper;
+
+import com.fs.erp.domain.FsErpFinishPush;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+/**
+ * erp订单完成状态推送 Mapper 接口
+ *
+ * @author AutoGenerated
+ * @date CurrentDateTime // 这里通常会是生成日期
+ */
+@Mapper
+public interface FsErpFinishPushMapper {
+
+    /**
+     * 根据主键查询
+     *
+     * @param id 主键
+     * @return FsErpFinishPush 实体对象
+     */
+    @Select("SELECT id, order_id, task_status, retry_count, last_execute_time, create_time, update_time, params, result, error_message FROM fs_erp_finish_push WHERE id = #{id}")
+    FsErpFinishPush selectById(Long id);
+
+    /**
+     * 根据订单号查询
+     *
+     * @param orderId 订单号
+     * @return FsErpFinishPush 实体对象
+     */
+    @Select("SELECT id, order_id, task_status, retry_count, last_execute_time, create_time, update_time, params, result, error_message FROM fs_erp_finish_push WHERE order_id = #{orderId}")
+    FsErpFinishPush selectByOrderId(String orderId);
+
+    /**
+     * 插入记录
+     *
+     * @param push 实体对象
+     * @return 影响行数
+     */
+    @Insert("INSERT INTO fs_erp_finish_push (order_id, task_status, retry_count, last_execute_time, params, result, error_message) " +
+            "VALUES(#{orderId}, #{taskStatus}, #{retryCount}, #{lastExecuteTime}, #{params}, #{result}, #{errorMessage})")
+    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") // 获取自增主键
+    int insert(FsErpFinishPush push);
+
+    /**
+     * 根据主键更新记录 (更新所有字段,除了创建时间)
+     *
+     * @param push 实体对象
+     * @return 影响行数
+     */
+    @Update("UPDATE fs_erp_finish_push SET " +
+            "order_id = #{orderId}, " +
+            "task_status = #{taskStatus}, " +
+            "retry_count = #{retryCount}, " +
+            "last_execute_time = #{lastExecuteTime}, " +
+            // update_time 会自动更新, create_time 一般不更新
+            "params = #{params}, " +
+            "result = #{result}, " +
+            "error_message = #{errorMessage} " +
+            "WHERE id = #{id}")
+    int updateById(FsErpFinishPush push);
+
+    /**
+     * 根据状态和重试次数查询 (示例)
+     *
+     * @param taskStatus 任务状态
+     * @param maxRetryCount 最大重试次数 (查询小于该值的记录)
+     * @return FsErpFinishPush 实体对象列表
+     */
+    @Select("SELECT id, order_id, task_status, retry_count, last_execute_time, create_time, update_time, params, result, error_message FROM fs_erp_finish_push WHERE task_status = #{taskStatus} AND retry_count < #{maxRetryCount}")
+    List<FsErpFinishPush> selectByStatusAndRetryCount(@Param("taskStatus") Integer taskStatus, @Param("maxRetryCount") Integer maxRetryCount);
+
+
+    /**
+     * 查询所有待处理的订单
+     *
+     * @return FsErpFinishPush 实体对象列表
+     */
+    @Select("select * from fs_erp_finish_push where task_status in (0,2) and retry_count<3")
+    List<FsErpFinishPush> queryPenddingOrder();
+
+    @Update("<script> " +
+            " <foreach collection=\"list\" item=\"item\" separator=\";\"> " +
+            "            UPDATE fs_erp_finish_push " +
+            "            SET " +
+            "                order_id = #{item.orderId}, " +
+            "                task_status = #{item.taskStatus}, " +
+            "                retry_count = #{item.retryCount}, " +
+            "                last_execute_time = #{item.lastExecuteTime}, " +
+            "                params = #{item.params}, " +
+            "                result = #{item.result}, " +
+            "                error_message = #{item.errorMessage}, " +
+            "                update_time = NOW() " +
+            "            WHERE " +
+            "                id = #{item.id} " +
+            "        </foreach>" +
+            "</script>")
+    void batchUpdate(List<FsErpFinishPush> fsErpFinishPushes);
+}

+ 1 - 0
fs-service/src/main/java/com/fs/erp/service/IErpOrderService.java

@@ -13,5 +13,6 @@ public interface IErpOrderService
     ErpDeliverysResponse getDeliver(ErpDeliverysRequest param);
     ErpOrderQueryResponse getOrder(ErpOrderQueryRequert param);
     BaseResponse refundUpdate(ErpRefundUpdateRequest param);
+    ErpOrderResponse finishOrder(ErpOrder order);
 }
 

+ 5 - 0
fs-service/src/main/java/com/fs/erp/service/impl/ErpOrderServiceImpl.java

@@ -127,4 +127,9 @@ public class ErpOrderServiceImpl implements IErpOrderService
         ErpOrderResponse response=JSONUtil.toBean(result, ErpOrderResponse.class);
         return response;
     }
+
+    @Override
+    public ErpOrderResponse finishOrder(ErpOrder order) {
+        return null;
+    }
 }

+ 119 - 0
fs-service/src/main/java/com/fs/erp/service/impl/WdtErpGoodsServiceImpl.java

@@ -0,0 +1,119 @@
+package com.fs.erp.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.PropertyNamingStrategy;
+import com.alibaba.fastjson.parser.ParserConfig;
+import com.fs.erp.domain.ErpGoods;
+import com.fs.erp.domain.ErpGoodsStock;
+import com.fs.erp.dto.*;
+import com.fs.erp.dto.sdk.wangdian.api.WdtClient;
+import com.fs.erp.dto.wdt.*;
+import com.fs.erp.service.IErpGoodsService;
+import com.hc.openapi.tool.util.ObjectUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.http.util.Asserts;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service
+@Primary
+public class WdtErpGoodsServiceImpl implements IErpGoodsService {
+    @Autowired
+    private WdtClient client;
+
+    @Override
+    public BaseResponse addGoods(ErpGoods goods) {
+        return null;
+    }
+
+    @Override
+    public ErpGoodsQueryResponse getGoods(ErpGoodsQueryRequert param) {
+        Map<String,String> map = new HashMap<>();
+        map.put("spec_no",param.getCode());
+        Asserts.notNull(param.getCode(),"barcode不能为空!");
+        try {
+            String response = client.execute("goods_query.php", map);
+            ParserConfig config = new ParserConfig();
+            config.propertyNamingStrategy = PropertyNamingStrategy.CamelCase;
+            ErpWdtBaseResponseDTO erpWdtBaseResponseDTO =
+                    JSON.parseObject(response, ErpWdtBaseResponseDTO.class, config);
+            if(ObjectUtils.equals(0, erpWdtBaseResponseDTO.getCode())){
+                List<ErpGoods> list = new ArrayList<>();
+
+                List<ErpWdtGoodsDto> goodsList = erpWdtBaseResponseDTO.getGoodsList();
+                for (ErpWdtGoodsDto goodsDto : goodsList) {
+                    ErpGoods erpGoods = new ErpGoods();
+                    erpGoods.setCode(param.getCode());
+                    erpGoods.setName(goodsDto.getGoodsName());
+                    erpGoods.setSimple_name(goodsDto.getShortName());
+                    erpGoods.setCategory_code(String.valueOf(goodsDto.getGoodsType()));
+                    List<ErpWdtSpecDto> specList = goodsDto.getSpecList();
+                    ErpWdtSpecDto erpWdtSpecDto = specList.get(0);
+
+                    // 市场价
+                    erpGoods.setCost_price(erpWdtSpecDto.getMarketPrice());
+                    // 零售价
+                    erpGoods.setSales_price(erpWdtSpecDto.getRetailPrice());
+                    list.add(erpGoods);
+                }
+
+                ErpGoodsQueryResponse erpGoodsQueryResponse = new ErpGoodsQueryResponse();
+                erpGoodsQueryResponse.setItems(list);
+                return erpGoodsQueryResponse;
+            } else {
+                log.info("获取erp商品失败! 错误原因: {}", JSON.toJSONString(erpWdtBaseResponseDTO));
+                throw new RuntimeException(erpWdtBaseResponseDTO.getMessage());
+            }
+
+        } catch (IOException e) {
+            log.info("获取erp商品失败! 错误原因: {}", ExceptionUtils.getStackTrace(e));
+            throw new RuntimeException(e);
+        }
+
+    }
+
+    @Override
+    public ErpGoodsStockQueryResponse getGoodsStock(ErpGoodsStockQueryRequert param) {
+        String barcode = param.getBarcode();
+        Asserts.notNull(barcode,"barcode不能为空!");
+
+        Map<String,String> map = new HashMap<>();
+        map.put("spec_no",barcode);
+        try {
+            String response = client.execute("stock_query.php", map);
+            ParserConfig config = new ParserConfig();
+            config.propertyNamingStrategy = PropertyNamingStrategy.CamelCase;
+            ErpWdtStockRespDTO erpWdtStockRespDTO = JSON.parseObject(response, ErpWdtStockRespDTO.class,config);
+            List<ErpGoodsStock> list = new ArrayList<>();
+            if(ObjectUtils.equals(0,erpWdtStockRespDTO.getCode())){
+                List<ErpWdtStockDTO> stocks = erpWdtStockRespDTO.getStocks();
+                for (ErpWdtStockDTO stock : stocks) {
+                    ErpGoodsStock erpGoodsStock = new ErpGoodsStock();
+                    erpGoodsStock.setBarcode(barcode);
+                    erpGoodsStock.setQty(stock.getStock_num());
+                    erpGoodsStock.setSalable_qty(stock.getAvaliable_num());
+                    list.add(erpGoodsStock);
+                }
+            } else {
+                log.info("获取erp库存失败! 错误原因: {}", JSON.toJSONString(erpWdtStockRespDTO));
+                throw new RuntimeException(erpWdtStockRespDTO.getMessage());
+            }
+            ErpGoodsStockQueryResponse erpGoodsStockQueryResponse = new ErpGoodsStockQueryResponse();
+            erpGoodsStockQueryResponse.setStocks(list);
+            return erpGoodsStockQueryResponse;
+        } catch (IOException e) {
+            log.info("获取erp库存失败! 错误原因: {}", ExceptionUtils.getStackTrace(e));
+            throw new RuntimeException(e);
+        }
+    }
+}
+

+ 876 - 0
fs-service/src/main/java/com/fs/erp/service/impl/WdtErpOrderServiceImpl.java

@@ -0,0 +1,876 @@
+package com.fs.erp.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.PropertyNamingStrategy;
+import com.alibaba.fastjson.parser.ParserConfig;
+import com.alibaba.fastjson.serializer.SerializeConfig;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.fs.erp.converter.ErpWdtToErpOrderMapper;
+import com.fs.erp.domain.ErpOrder;
+import com.fs.erp.domain.ErpOrderQuery;
+import com.fs.erp.domain.ErpRefundOrder;
+import com.fs.erp.dto.*;
+import com.fs.erp.dto.sdk.wangdian.api.WdtClient;
+import com.fs.erp.dto.sdk.wangdian.enums.*;
+import com.fs.erp.dto.wdt.*;
+import com.fs.erp.service.IErpOrderService;
+import com.fs.his.config.FsSysConfig;
+import com.fs.his.domain.FsStoreOrder;
+import com.fs.his.domain.FsStoreOrderItem;
+import com.fs.his.domain.FsStoreProduct;
+import com.fs.his.service.IFsStoreOrderItemService;
+import com.fs.his.service.IFsStoreOrderService;
+import com.fs.his.service.IFsStoreProductService;
+import com.fs.his.utils.ConfigUtil;
+import com.fs.his.vo.FsStoreOrderItemVO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.http.client.utils.DateUtils;
+import org.apache.http.util.Asserts;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+
+@Slf4j
+@Service
+@Primary
+public class WdtErpOrderServiceImpl implements IErpOrderService {
+
+    @Autowired
+    private IFsStoreOrderService fsStoreOrderService;
+
+    @Autowired
+    private IFsStoreOrderItemService fsStoreOrderItemService;
+
+    @Autowired
+    private IFsStoreProductService fsStoreProductService;
+
+//    @Value("${fsConfig.erpWdShopCode}")
+//    private String shopCode;
+
+    @Autowired
+    ConfigUtil configUtil;
+
+    @Autowired
+    private WdtClient client;
+
+    /**
+     * 普通推送
+     */
+    private static final Integer NORMAL_TYPE = 1;
+    /**
+     * 退款推送
+     */
+    private static final Integer REFUND_TYPE = 2;
+    @Override
+    public ErpOrderResponse addOrder(ErpOrder order) {
+//        if(order.getIsPackage()!=null && order.getIsPackage() == 1){
+//            return getErpPackageOrderResponse(order);
+//        }
+        return getErpOrderResponse(order);
+    }
+
+    /**
+     * 获取erp推送参数
+     * @param order 订单参数
+     * @return
+     */
+    private ErpOrderResponse getErpOrderResponse(ErpOrder order) {
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+        String shopCode = sysConfig.getErpWdShopCode();
+
+        //测试环境sid、appkey、密钥请到旺店通开放平台-自助对接-申请测试环境内查看,测试环境url=https://sandbox.wangdian.cn/openapi2/
+        //调用正式环境时请将sid、appkey、appsecret切换为实际参数,参数在旺店通开放平台-自助对接-应用管理内应用状态为已上线的应用中查看,调用正式环境注意切换正式环境url=https://api.wangdian.cn/openapi2/
+
+        ErpWdtBusinessRequestParams erpWdtBusinessRequestParams = new ErpWdtBusinessRequestParams();
+        erpWdtBusinessRequestParams.setShopNo(shopCode);
+        erpWdtBusinessRequestParams.setSwitchMode(0);
+        ErpWdtTrade erpWdtTrade = new ErpWdtTrade();
+        FsStoreOrder fsStoreOrder = fsStoreOrderService.selectFsStoreOrderByOrderCode(order.getPlatform_code());
+        BigDecimal couponPrice = fsStoreOrder.getCouponPrice();
+        if (couponPrice == null) {
+            couponPrice = BigDecimal.ZERO;
+        }
+
+        // 平台状态
+        erpWdtTrade.setTradeStatus(TradeStatus.PAID_WAITING_FOR_SHIPMENT.getValue());
+
+        // 订单id
+        erpWdtTrade.setTid(order.getPlatform_code());
+
+
+        // 如果是货到付款
+        if("2".equals(fsStoreOrder.getPayType())){
+            // 支付状态
+            erpWdtTrade.setPayStatus(PaymentStatus.PARTIALLY_PAID.getValue());
+            // 发货条件
+            erpWdtTrade.setDeliveryTerm(DeliveryTerm.CASH_ON_DELIVERY.getValue());
+            // 货到付款金额 = 物流代收金额-优惠金额
+            erpWdtTrade.setCodAmount(fsStoreOrder.getPayDelivery().subtract(couponPrice));
+
+        } else if("3".equals(fsStoreOrder.getPayType())){
+            // 支付状态
+            erpWdtTrade.setPayStatus(PaymentStatus.UNPAID.getValue());
+            // 发货条件
+            erpWdtTrade.setDeliveryTerm(DeliveryTerm.CASH_ON_DELIVERY.getValue());
+            // 货到付款金额 = 物流代收金额-优惠金额
+            erpWdtTrade.setCodAmount(fsStoreOrder.getPayDelivery().subtract(couponPrice));
+        } else { // 如果是线上付款
+            // 支付状态
+            erpWdtTrade.setPayStatus(PaymentStatus.FULLY_PAID.getValue());
+            // 发货条件
+            erpWdtTrade.setDeliveryTerm(DeliveryTerm.PAYMENT_BEFORE_DELIVERY.getValue());
+        }
+
+        // 下单时间
+        erpWdtTrade.setTradeTime(order.getDeal_datetime());
+        // 支付时间
+        erpWdtTrade.setPayTime(order.getDeal_datetime());
+        // 分销类别
+        erpWdtTrade.setFenxiaoType(FenxiaoType.JINGXIAO.getValue());
+        // 客户网名
+        erpWdtTrade.setBuyerNick(order.getReceiver_name());
+        // 收件人姓名
+        erpWdtTrade.setReceiverName(order.getReceiver_name());
+        // 省份
+        erpWdtTrade.setReceiverProvince(order.getReceiver_province());
+        // 市
+        erpWdtTrade.setReceiverCity(order.getReceiver_city());
+        // 区
+        erpWdtTrade.setReceiverDistrict(order.getReceiver_district());
+        // 详细地址
+        erpWdtTrade.setReceiverAddress(order.getReceiver_address());
+        // 手机
+        erpWdtTrade.setReceiverMobile(order.getReceiver_mobile());
+        // 固定电话
+        erpWdtTrade.setReceiverTelno(order.getReceiver_mobile());
+        // 买家备注
+        erpWdtTrade.setBuyerMessage(order.getBuyer_memo());
+        // 卖家备注
+        erpWdtTrade.setSellerMemo(order.getSeller_memo());
+        erpWdtTrade.setWarehouseNo(order.getWarehouse_code());
+
+        // 运费金额
+        erpWdtTrade.setPostAmount(fsStoreOrder.getFreightPrice());
+        // 已付金额
+        if(ObjectUtils.isNotNull(fsStoreOrder)){
+            erpWdtTrade.setPaid(fsStoreOrder.getPayMoney());
+        }
+
+        List<FsStoreOrderItem> fsStoreOrderItemVOS = fsStoreOrderItemService.selectFsStoreOrderItemListByOrderId(fsStoreOrder.getOrderId());
+        List<ErpWdtOrder> erpWdtOrderList = new ArrayList<>();
+        // 商品总价
+        BigDecimal totalPrice = fsStoreOrder.getTotalPrice();
+
+        // 总折扣金额 = 优惠券金额 + 折扣金额
+        BigDecimal totalDiscountPrice = BigDecimal.ZERO;
+        // 折扣金额
+        BigDecimal discountPrice = totalPrice.subtract(fsStoreOrder.getPayPrice());
+        totalDiscountPrice = couponPrice.add(discountPrice);
+
+        // 防止除零错误
+        if (totalPrice.compareTo(BigDecimal.ZERO) == 0) {
+            totalPrice = BigDecimal.ONE;
+        }
+
+        for (FsStoreOrderItem fsStoreOrderItem : fsStoreOrderItemVOS) {
+            ErpWdtOrder erpWdtOrder = new ErpWdtOrder();
+            //平台订单货品表主键
+            erpWdtOrder.setOid(String.format("%s%s",fsStoreOrder.getOrderCode(),fsStoreOrderItem.getItemId()));
+            erpWdtOrder.setNum(BigDecimal.valueOf(fsStoreOrderItem.getNum()));
+            FsStoreProduct fsStoreProduct = fsStoreProductService.selectFsStoreProductById(fsStoreOrderItem.getProductId());
+            Asserts.check(ObjectUtils.isNotNull(fsStoreProduct),"该产品不存在! 产品id: {} ",fsStoreOrderItem.getProductId());
+            // 单价
+            erpWdtOrder.setPrice(fsStoreProduct.getPrice());
+            // 状态
+            erpWdtOrder.setStatus(TradeStatus.SHIPPED.getValue());
+            // 退款状态
+            erpWdtOrder.setRefundStatus(RefundStatus.NO_REFUND.getValue());
+
+            // 平台货品ID
+            erpWdtOrder.setGoodsId(String.valueOf(fsStoreProduct.getProductId()));
+            JSONObject jsonObject = JSON.parseObject(fsStoreOrderItem.getJsonInfo());
+            erpWdtOrder.setSpecId(jsonObject.getString("sku"));
+            erpWdtOrder.setGoodsNo(jsonObject.getString("barCode"));
+            erpWdtOrder.setSpecNo(jsonObject.getString("sku"));
+            // 货品名称
+            erpWdtOrder.setGoodsName(fsStoreProduct.getProductName());
+            // 调整
+            erpWdtOrder.setAdjustAmount(BigDecimal.ZERO);
+            // 优惠
+            erpWdtOrder.setDiscount(BigDecimal.ZERO);
+            // 分摊优惠
+            // 分摊比例
+            BigDecimal price = fsStoreProduct.getPrice().multiply(BigDecimal.valueOf(fsStoreOrderItem.getNum()));
+            BigDecimal divide = price.divide(totalPrice, RoundingMode.HALF_UP);
+            erpWdtOrder.setShareDiscount(divide.multiply(totalDiscountPrice));
+
+            erpWdtOrderList.add(erpWdtOrder);
+        }
+
+        // 最后一个商品的分摊优惠等于总优惠减去前面分摊优惠之和
+        Asserts.check(CollectionUtils.isNotEmpty(erpWdtOrderList),"订单 {} 商品不能为空!", order.getPlatform_code());
+        long size = erpWdtOrderList.size();
+        if(size > 1) {
+            ErpWdtOrder erpWdtOrder = erpWdtOrderList.get(erpWdtOrderList.size() - 1);
+            erpWdtOrder.setShareDiscount(totalDiscountPrice.subtract(erpWdtOrderList.stream()
+                    .limit(size - 1L)
+                    .map(item -> Optional.ofNullable(item.getShareDiscount()).orElse(BigDecimal.ZERO))
+                    .reduce(BigDecimal.ZERO, BigDecimal::add)));
+        }
+
+        erpWdtTrade.setOrderList(erpWdtOrderList);
+        erpWdtBusinessRequestParams.setTradeList(new ArrayList<>(Arrays.asList(erpWdtTrade)));
+
+        Map<String,String> map = new HashMap<>();
+        map.put("shop_no",erpWdtBusinessRequestParams.getShopNo());
+        map.put("switch_mode", String.valueOf(erpWdtBusinessRequestParams.getSwitchMode()));
+        map.put("trade_list", convertToSnakeCase(erpWdtBusinessRequestParams.getTradeList()));
+
+
+        try {
+            String response = client.execute("trade_push.php", map);
+            ParserConfig config = new ParserConfig();
+            config.propertyNamingStrategy = PropertyNamingStrategy.CamelCase;
+            ErpWdtApiResponse erpWdtApiResponse = JSON.parseObject(response, ErpWdtApiResponse.class,config);
+            if(ObjectUtil.equal(0,erpWdtApiResponse.getCode())){
+                log.info("订单推送成功: {}", response);
+                ErpOrderResponse erpOrderResponse = new ErpOrderResponse();
+                erpOrderResponse.setCode(order.getPlatform_code());
+                erpOrderResponse.setSuccess(true);
+                erpOrderResponse.setRequestRawData(JSON.toJSONString(map));
+                erpOrderResponse.setResponseRawData(response);
+                return erpOrderResponse;
+            } else {
+                throw new RuntimeException(String.format("订单推送失败,原因: %s",erpWdtApiResponse.getMessage()));
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return new ErpOrderResponse();
+    }
+
+    /**
+     * 获取erp推送参数
+     * @param order 订单参数
+     * @return
+     */
+//    private ErpOrderResponse getErpOrderResponse(ErpOrder order) {
+//        //测试环境sid、appkey、密钥请到旺店通开放平台-自助对接-申请测试环境内查看,测试环境url=https://sandbox.wangdian.cn/openapi2/
+//        //调用正式环境时请将sid、appkey、appsecret切换为实际参数,参数在旺店通开放平台-自助对接-应用管理内应用状态为已上线的应用中查看,调用正式环境注意切换正式环境url=https://api.wangdian.cn/openapi2/
+//
+//        ErpWdtBusinessRequestParams erpWdtBusinessRequestParams = new ErpWdtBusinessRequestParams();
+//        erpWdtBusinessRequestParams.setShopNo(shopCode);
+//        erpWdtBusinessRequestParams.setSwitchMode(0);
+//        ErpWdtTrade erpWdtTrade = new ErpWdtTrade();
+//        FsStoreOrder fsStoreOrder = fsStoreOrderService.selectFsStoreOrderByOrderCode(order.getPlatform_code());
+//        BigDecimal couponPrice = fsStoreOrder.getCouponPrice();
+//
+//        // 平台状态
+//        erpWdtTrade.setTradeStatus(TradeStatus.PAID_WAITING_FOR_SHIPMENT.getValue());
+//
+//        // 订单id
+//        erpWdtTrade.setTid(order.getPlatform_code());
+//
+//
+//        // 如果是货到付款
+//        if("2".equals(fsStoreOrder.getPayType())){
+//            // 支付状态
+//            erpWdtTrade.setPayStatus(PaymentStatus.PARTIALLY_PAID.getValue());
+//            // 发货条件
+//            erpWdtTrade.setDeliveryTerm(DeliveryTerm.CASH_ON_DELIVERY.getValue());
+//            // 货到付款金额 = 物流代收金额-优惠金额
+//            erpWdtTrade.setCodAmount(fsStoreOrder.getPayDelivery().subtract(couponPrice));
+//
+//        } else if("3".equals(fsStoreOrder.getPayType())){
+//            // 支付状态
+//            erpWdtTrade.setPayStatus(PaymentStatus.UNPAID.getValue());
+//            // 发货条件
+//            erpWdtTrade.setDeliveryTerm(DeliveryTerm.CASH_ON_DELIVERY.getValue());
+//            // 货到付款金额 = 物流代收金额-优惠金额
+//            erpWdtTrade.setCodAmount(fsStoreOrder.getPayDelivery().subtract(couponPrice));
+//        } else { // 如果是线上付款
+//            // 支付状态
+//            erpWdtTrade.setPayStatus(PaymentStatus.FULLY_PAID.getValue());
+//            // 发货条件
+//            erpWdtTrade.setDeliveryTerm(DeliveryTerm.PAYMENT_BEFORE_DELIVERY.getValue());
+//        }
+//
+//        // 下单时间
+//        erpWdtTrade.setTradeTime(order.getDeal_datetime());
+//        // 支付时间
+//        erpWdtTrade.setPayTime(order.getDeal_datetime());
+//        // 分销类别
+//        erpWdtTrade.setFenxiaoType(FenxiaoType.JINGXIAO.getValue());
+//        // 客户网名
+//        erpWdtTrade.setBuyerNick(order.getReceiver_name());
+//        // 收件人姓名
+//        erpWdtTrade.setReceiverName(order.getReceiver_name());
+//        // 省份
+//        erpWdtTrade.setReceiverProvince(order.getReceiver_province());
+//        // 市
+//        erpWdtTrade.setReceiverCity(order.getReceiver_city());
+//        // 区
+//        erpWdtTrade.setReceiverDistrict(order.getReceiver_district());
+//        // 详细地址
+//        erpWdtTrade.setReceiverAddress(order.getReceiver_address());
+//        // 手机
+//        erpWdtTrade.setReceiverMobile(order.getReceiver_mobile());
+//        // 固定电话
+//        erpWdtTrade.setReceiverTelno(order.getReceiver_mobile());
+//        // 买家备注
+//        erpWdtTrade.setBuyerMessage(order.getBuyer_memo());
+//        // 卖家备注
+//        erpWdtTrade.setSellerMemo(order.getSeller_memo());
+//        erpWdtTrade.setWarehouseNo(order.getWarehouse_code());
+//
+//
+//        // 运费金额
+//        erpWdtTrade.setPostAmount(fsStoreOrder.getFreightPrice());
+//        // 已付金额
+//        if(ObjectUtils.isNotNull(fsStoreOrder)){
+//            erpWdtTrade.setPaid(fsStoreOrder.getPayMoney());
+//        }
+//
+//        List<FsStoreOrderItemVO> fsStoreOrderItemVOS = fsStoreOrderItemService.selectFsStoreOrderItemListByOrderId(fsStoreOrder.getId());
+//        List<ErpWdtOrder> erpWdtOrderList = new ArrayList<>();
+//        // 商品总价
+//        BigDecimal totalPrice = fsStoreOrder.getTotalPrice();
+//
+//        // 优惠券金额
+//        if (fsStoreOrder.getCouponPrice().compareTo(BigDecimal.ZERO) == 0
+//                && fsStoreOrder.getTotalPrice().compareTo(fsStoreOrder.getPayMoney()) > 0) {
+//            BigDecimal payDelivery = fsStoreOrder.getPayDelivery();
+//            BigDecimal payMoney = fsStoreOrder.getPayMoney();
+//            if(ObjectUtil.isNull(payDelivery)){
+//                payDelivery = BigDecimal.ZERO;
+//            }
+//            if(ObjectUtil.isNull(payMoney)){
+//                payMoney = BigDecimal.ZERO;
+//            }
+//            couponPrice = totalPrice.subtract(payMoney)
+//                    .subtract(payDelivery);
+//        }
+//
+//
+//        for (FsStoreOrderItemVO fsStoreOrderItem : fsStoreOrderItemVOS) {
+//            ErpWdtOrder erpWdtOrder = new ErpWdtOrder();
+//            //平台订单货品表主键
+//            erpWdtOrder.setOid(String.format("%s%s",fsStoreOrderItem.getOrderCode(),fsStoreOrderItem.getItemId()));
+//            erpWdtOrder.setNum(BigDecimal.valueOf(fsStoreOrderItem.getNum()));
+//            FsStoreProduct fsStoreProduct = fsStoreProductService.selectFsStoreProductById(fsStoreOrderItem.getProductId());
+//            Asserts.check(ObjectUtils.isNotNull(fsStoreProduct),"该产品不存在! 产品id: {} ",fsStoreOrderItem.getProductId());
+//            // 单价
+//            erpWdtOrder.setPrice(fsStoreProduct.getPrice());
+//            // 状态
+//            erpWdtOrder.setStatus(TradeStatus.SHIPPED.getValue());
+//            // 退款状态
+//            erpWdtOrder.setRefundStatus(RefundStatus.NO_REFUND.getValue());
+//
+//            // 平台货品ID
+//            erpWdtOrder.setGoodsId(String.valueOf(fsStoreProduct.getProductId()));
+//            JSONObject jsonObject = JSON.parseObject(fsStoreOrderItem.getJsonInfo());
+//            erpWdtOrder.setSpecId(jsonObject.getString("sku"));
+//            erpWdtOrder.setGoodsNo(jsonObject.getString("barCode"));
+//            erpWdtOrder.setSpecNo(jsonObject.getString("sku"));
+//            // 货品名称
+//            erpWdtOrder.setGoodsName(fsStoreProduct.getProductName());
+//            // 调整
+//            erpWdtOrder.setAdjustAmount(BigDecimal.ZERO);
+//            // 优惠
+//            erpWdtOrder.setDiscount(BigDecimal.ZERO);
+//            // 分摊优惠
+//            // 分摊比例
+//            BigDecimal price = fsStoreProduct.getPrice().multiply(BigDecimal.valueOf(fsStoreOrderItem.getNum()));
+//            BigDecimal divide = price.divide(totalPrice, RoundingMode.HALF_UP);
+//            erpWdtOrder.setShareDiscount(divide.multiply(couponPrice));
+//
+//            erpWdtOrderList.add(erpWdtOrder);
+//        }
+//
+//        // 最后一个商品的分摊优惠等于总优惠减去前面分摊优惠之和
+//        Asserts.check(CollectionUtils.isNotEmpty(erpWdtOrderList),"订单 {} 商品不能为空!", order.getPlatform_code());
+//        long size = erpWdtOrderList.size();
+//        if(size > 1) {
+//            ErpWdtOrder erpWdtOrder = erpWdtOrderList.get(erpWdtOrderList.size() - 1);
+//            erpWdtOrder.setShareDiscount(couponPrice.subtract(erpWdtOrderList.stream()
+//                            .limit(size - 1L)
+//                    .map(item -> Optional.ofNullable(item.getShareDiscount()).orElse(BigDecimal.ZERO))
+//                    .reduce(BigDecimal.ZERO, BigDecimal::add)));
+//        }
+//
+//        erpWdtTrade.setOrderList(erpWdtOrderList);
+//        erpWdtBusinessRequestParams.setTradeList(new ArrayList<>(Arrays.asList(erpWdtTrade)));
+//
+//        Map<String,String> map = new HashMap<>();
+//        map.put("shop_no",erpWdtBusinessRequestParams.getShopNo());
+//        map.put("switch_mode", String.valueOf(erpWdtBusinessRequestParams.getSwitchMode()));
+//        map.put("trade_list", convertToSnakeCase(erpWdtBusinessRequestParams.getTradeList()));
+//
+//
+//        try {
+//            String response = client.execute("trade_push.php", map);
+//            ParserConfig config = new ParserConfig();
+//            config.propertyNamingStrategy = PropertyNamingStrategy.CamelCase;
+//            ErpWdtApiResponse erpWdtApiResponse = JSON.parseObject(response, ErpWdtApiResponse.class,config);
+//            if(ObjectUtil.equal(0,erpWdtApiResponse.getCode())){
+//                log.info("订单推送成功: {}", response);
+//                ErpOrderResponse erpOrderResponse = new ErpOrderResponse();
+//                erpOrderResponse.setCode(order.getPlatform_code());
+//                return erpOrderResponse;
+//            } else {
+//                throw new RuntimeException(String.format("订单推送失败,原因: %s",erpWdtApiResponse.getMessage()));
+//            }
+//        } catch (IOException e) {
+//            e.printStackTrace();
+//        }
+//        return new ErpOrderResponse();
+//    }
+
+    /**
+     * 获取erp退款参数
+     * @param order 订单参数
+     * @return
+     */
+    private ErpOrderResponse getErpOrderRefundResponse(ErpOrder order) {
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+        String shopCode = sysConfig.getErpWdShopCode();
+        //测试环境sid、appkey、密钥请到旺店通开放平台-自助对接-申请测试环境内查看,测试环境url=https://sandbox.wangdian.cn/openapi2/
+        //调用正式环境时请将sid、appkey、appsecret切换为实际参数,参数在旺店通开放平台-自助对接-应用管理内应用状态为已上线的应用中查看,调用正式环境注意切换正式环境url=https://api.wangdian.cn/openapi2/
+
+        ErpWdtBusinessRequestParams erpWdtBusinessRequestParams = new ErpWdtBusinessRequestParams();
+        erpWdtBusinessRequestParams.setShopNo(shopCode);
+        erpWdtBusinessRequestParams.setSwitchMode(0);
+        ErpWdtTrade erpWdtTrade = new ErpWdtTrade();
+
+        // 订单id
+        erpWdtTrade.setTid(order.getPlatform_code());
+        // 平台状态
+        erpWdtTrade.setTradeStatus(TradeStatus.REFUNDED.getValue());
+
+        // 支付状态
+        erpWdtTrade.setPayStatus(PaymentStatus.FULLY_PAID.getValue());
+        // 发货条件
+        erpWdtTrade.setDeliveryTerm(DeliveryTerm.PAYMENT_BEFORE_DELIVERY.getValue());
+        // 下单时间
+        erpWdtTrade.setTradeTime(order.getDeal_datetime());
+        // 支付时间
+        erpWdtTrade.setPayTime(order.getDeal_datetime());
+        // 分销类别
+        erpWdtTrade.setFenxiaoType(FenxiaoType.JINGXIAO.getValue());
+        // 客户网名
+        erpWdtTrade.setBuyerNick(order.getReceiver_name());
+        // 收件人姓名
+        erpWdtTrade.setReceiverName(order.getReceiver_name());
+        // 省份
+        erpWdtTrade.setReceiverProvince(order.getReceiver_province());
+        // 市
+        erpWdtTrade.setReceiverCity(order.getReceiver_city());
+        // 区
+        erpWdtTrade.setReceiverDistrict(order.getReceiver_district());
+        // 详细地址
+        erpWdtTrade.setReceiverAddress(order.getReceiver_address());
+        // 手机
+        erpWdtTrade.setReceiverMobile(order.getReceiver_mobile());
+        // 固定电话
+        erpWdtTrade.setReceiverTelno(order.getReceiver_mobile());
+        // 买家备注
+        erpWdtTrade.setBuyerMessage(order.getBuyer_memo());
+        // 卖家备注
+        erpWdtTrade.setSellerMemo(order.getSeller_memo());
+        erpWdtTrade.setWarehouseNo(order.getWarehouse_code());
+
+        // 已付金额
+        FsStoreOrder fsStoreOrder = fsStoreOrderService.selectFsStoreOrderByOrderCode(order.getPlatform_code());
+        // 运费金额
+        erpWdtTrade.setPostAmount(fsStoreOrder.getFreightPrice());
+        if(ObjectUtils.isNotNull(fsStoreOrder)){
+            erpWdtTrade.setPaid(fsStoreOrder.getPayMoney());
+        }
+
+        List<FsStoreOrderItem> fsStoreOrderItemVOS = fsStoreOrderItemService.selectFsStoreOrderItemListByOrderId(fsStoreOrder.getOrderId());
+        List<ErpWdtOrder> erpWdtOrderList = new ArrayList<>();
+
+
+        // 优惠券金额
+        BigDecimal couponPrice = fsStoreOrder.getCouponPrice();
+        if (fsStoreOrder.getCouponPrice().compareTo(BigDecimal.ZERO) == 0
+                && fsStoreOrder.getTotalPrice().compareTo(fsStoreOrder.getPayMoney()) > 0) {
+            couponPrice = fsStoreOrder.getTotalPrice().subtract(fsStoreOrder.getPayMoney());
+        }
+        // 商品总价
+        BigDecimal totalPrice = fsStoreOrder.getTotalPrice();
+
+        for (FsStoreOrderItem fsStoreOrderItem : fsStoreOrderItemVOS) {
+            ErpWdtOrder erpWdtOrder = new ErpWdtOrder();
+            //平台订单货品表主键
+            erpWdtOrder.setOid(String.format("%s%s",fsStoreOrder.getOrderCode(),fsStoreOrderItem.getItemId()));
+            erpWdtOrder.setNum(BigDecimal.valueOf(fsStoreOrderItem.getNum()));
+            FsStoreProduct fsStoreProduct = fsStoreProductService.selectFsStoreProductById(fsStoreOrderItem.getProductId());
+            Asserts.check(ObjectUtils.isNotNull(fsStoreProduct),"该产品不存在! 产品id: {} ",fsStoreOrderItem.getProductId());
+            // 单价
+            erpWdtOrder.setPrice(fsStoreProduct.getPrice());
+            // 状态
+
+            erpWdtOrder.setStatus(TradeStatus.REFUNDED.getValue());
+            // 退款状态
+            erpWdtOrder.setRefundStatus(RefundStatus.REFUND_SUCCESSFUL.getValue());
+
+            // 平台货品ID
+            erpWdtOrder.setGoodsId(String.valueOf(fsStoreProduct.getProductId()));
+            JSONObject jsonObject = JSON.parseObject(fsStoreOrderItem.getJsonInfo());
+            erpWdtOrder.setSpecId(jsonObject.getString("sku"));
+            erpWdtOrder.setGoodsNo(jsonObject.getString("barCode"));
+            erpWdtOrder.setSpecNo(jsonObject.getString("sku"));
+            // 货品名称
+            erpWdtOrder.setGoodsName(fsStoreProduct.getProductName());
+            // 调整
+            erpWdtOrder.setAdjustAmount(BigDecimal.ZERO);
+            // 优惠
+            erpWdtOrder.setDiscount(BigDecimal.ZERO);
+            // 分摊优惠
+            // 分摊比例
+            BigDecimal price = fsStoreProduct.getPrice().multiply(BigDecimal.valueOf(fsStoreOrderItem.getNum()));
+            BigDecimal divide = price.divide(totalPrice, RoundingMode.HALF_UP);
+            erpWdtOrder.setShareDiscount(divide.multiply(couponPrice));
+
+            erpWdtOrderList.add(erpWdtOrder);
+        }
+
+        // 最后一个商品的分摊优惠等于总优惠减去前面分摊优惠之和
+        Asserts.check(CollectionUtils.isNotEmpty(erpWdtOrderList),"订单 {} 商品不能为空!", order.getPlatform_code());
+        long size = erpWdtOrderList.size();
+        if(size > 1) {
+            ErpWdtOrder erpWdtOrder = erpWdtOrderList.get(erpWdtOrderList.size() - 1);
+            erpWdtOrder.setShareDiscount(couponPrice.subtract(erpWdtOrderList.stream()
+                    .limit(size - 1L)
+                    .map(item -> Optional.ofNullable(item.getShareDiscount()).orElse(BigDecimal.ZERO))
+                    .reduce(BigDecimal.ZERO, BigDecimal::add)));
+        }
+
+        erpWdtTrade.setOrderList(erpWdtOrderList);
+        erpWdtBusinessRequestParams.setTradeList(new ArrayList<>(Arrays.asList(erpWdtTrade)));
+
+        Map<String,String> map = new HashMap<>();
+        map.put("shop_no",erpWdtBusinessRequestParams.getShopNo());
+        map.put("switch_mode", String.valueOf(erpWdtBusinessRequestParams.getSwitchMode()));
+        map.put("trade_list", convertToSnakeCase(erpWdtBusinessRequestParams.getTradeList()));
+
+
+        try {
+            String response = client.execute("trade_push.php", map);
+            ParserConfig config = new ParserConfig();
+            config.propertyNamingStrategy = PropertyNamingStrategy.CamelCase;
+             log.info("Erp推送传参: {}", map);
+            ErpWdtApiResponse erpWdtApiResponse = JSON.parseObject(response, ErpWdtApiResponse.class,config);
+            if(ObjectUtil.equal(0,erpWdtApiResponse.getCode())){
+                log.info("订单推送成功: {}", response);
+                ErpOrderResponse erpOrderResponse = new ErpOrderResponse();
+                erpOrderResponse.setCode(order.getPlatform_code());
+                return erpOrderResponse;
+            } else {
+               // throw new RuntimeException(String.format("订单推送失败,原因: %s",erpWdtApiResponse.getMessage()));
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return new ErpOrderResponse();
+    }
+
+    @Override
+    public ErpOrderResponse refundOrder(ErpRefundOrder order) {
+        return null;
+    }
+
+    @Override
+    public ErpDeliverysResponse getDeliver(ErpDeliverysRequest param) {
+        return null;
+    }
+
+    @Override
+    public ErpOrderQueryResponse getOrder(ErpOrderQueryRequert param) {
+        Map<String,String> map = new HashMap<>();
+        map.put("src_tid",param.getCode());
+        try {
+            String execute = client.execute("sales_trade_query.php", map);
+            ParserConfig config = new ParserConfig();
+            config.propertyNamingStrategy = PropertyNamingStrategy.CamelCase;
+            ErpWdtTradeQueryResponse tradeQueryResponseDTO = JSON.parseObject(execute, ErpWdtTradeQueryResponse.class);
+            if(ObjectUtil.equal(0,tradeQueryResponseDTO.getCode())){
+                ErpOrderQueryResponse erpOrderQueryResponse = ErpWdtToErpOrderMapper.INSTANCE.toErpOrderQueryResponse(tradeQueryResponseDTO);
+                log.info("查询订单成功: {}", erpOrderQueryResponse);
+                return erpOrderQueryResponse;
+            } else {
+                throw new RuntimeException(String.format("查询订单失败, 原因: %s", tradeQueryResponseDTO.getMessage()));
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public BaseResponse refundUpdate(ErpRefundUpdateRequest param) {
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+        String shopCode = sysConfig.getErpWdShopCode();
+
+        log.info("退款单更新: {}", param);
+        FsStoreOrder fsStoreOrder = fsStoreOrderService.selectFsStoreOrderByOrderCode(param.getTid());
+
+        ErpOrderQueryRequert request = new ErpOrderQueryRequert();
+        request.setCode(fsStoreOrder.getExtendOrderId());
+
+        Set<Integer> status = new HashSet<>();
+        status.add(95);
+        status.add(105);
+        status.add(110);
+
+        ErpOrderQueryResponse response = getOrder(request);
+        ErpOrderQuery erpOrderQuery = response.getOrders().get(0);
+        Integer deliveryState = erpOrderQuery.getDelivery_state();
+        // 如果是未发货
+        if(!status.contains(deliveryState)){
+            log.info("售前退款 参数: {}",param);
+            try {
+                ErpOrder order = fsStoreOrderService.getErpOrder(fsStoreOrder);
+
+                Asserts.check(ObjectUtils.isNotNull(order),"该订单不存在!");
+
+                return getErpOrderRefundResponse(order);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        //--------------售后退款------------
+        log.info("售后退款 参数: {}", param);
+        Map<String,String> map = new HashMap<>();
+
+
+        Asserts.check(ObjectUtils.isNotNull(fsStoreOrder), "该订单不存在! 订单id: {} ", param.getTid());
+
+        List<FsStoreOrderItem> fsStoreOrderItemVOS = fsStoreOrderItemService.selectFsStoreOrderItemListByOrderId(fsStoreOrder.getOrderId());
+        List<ErpWdtRefundOrder> refundOrders = new ArrayList<>();
+
+        for (FsStoreOrderItem item : fsStoreOrderItemVOS) {
+            refundOrders.add(ErpWdtRefundOrder.builder()
+                    .oid(String.format("%s%s",fsStoreOrder.getOrderCode(),item.getItemId()))
+                    .num(BigDecimal.ONE)
+                    .build());
+        }
+        List<ErpWdtApiRefund> erpWdtApiRefunds = Collections.singletonList(ErpWdtApiRefund.builder()
+                .platformId(127)
+                .shopNo(shopCode)
+                .tid(param.getTid())
+                .refundNo(param.getTid())
+                .type(RefundTypeEnum.REFUND_BEFORE_SHIPPING.getCode())
+                .status(AfterSaleStatusEnum.SUCCESS.getCode())
+                .refundTime(DateUtils.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"))
+                .orderList(refundOrders)
+                .build());
+
+
+        map.put("api_refund_list",convertToSnakeCase(erpWdtApiRefunds));
+        try {
+            String execute = client.execute("sales_refund_push.php", map);
+            ParserConfig config = new ParserConfig();
+            config.propertyNamingStrategy = PropertyNamingStrategy.CamelCase;
+            ErpWdtApiResponse erpWdtApiResponse = JSON.parseObject(execute, ErpWdtApiResponse.class,config);
+            if(ObjectUtil.equal(0, erpWdtApiResponse.getCode())){
+                log.info("退款单更新成功: {}", erpWdtApiResponse);
+                return new BaseResponse();
+            } else {
+                log.info("退款单更新失败: {}", erpWdtApiResponse);
+                throw new RuntimeException(String.format("退款单更新失败, 原因: %s", erpWdtApiResponse.getMessage()));
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public ErpOrderResponse finishOrder(ErpOrder order) {
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+        String shopCode = sysConfig.getErpWdShopCode();
+
+        //测试环境sid、appkey、密钥请到旺店通开放平台-自助对接-申请测试环境内查看,测试环境url=https://sandbox.wangdian.cn/openapi2/
+        //调用正式环境时请将sid、appkey、appsecret切换为实际参数,参数在旺店通开放平台-自助对接-应用管理内应用状态为已上线的应用中查看,调用正式环境注意切换正式环境url=https://api.wangdian.cn/openapi2/
+        ErpWdtBusinessRequestParams erpWdtBusinessRequestParams = new ErpWdtBusinessRequestParams();
+        erpWdtBusinessRequestParams.setShopNo(shopCode);
+        erpWdtBusinessRequestParams.setSwitchMode(0);
+        ErpWdtTrade erpWdtTrade = new ErpWdtTrade();
+        FsStoreOrder fsStoreOrder = fsStoreOrderService.selectFsStoreOrderByOrderCode(order.getPlatform_code());
+        BigDecimal couponPrice = fsStoreOrder.getCouponPrice();
+
+        // 平台状态
+        erpWdtTrade.setTradeStatus(TradeStatus.COMPLETED.getValue());
+
+        // 订单id
+        erpWdtTrade.setTid(order.getPlatform_code());
+
+
+        // 如果是货到付款
+        if("2".equals(fsStoreOrder.getPayType())){
+            // 支付状态
+            erpWdtTrade.setPayStatus(PaymentStatus.PARTIALLY_PAID.getValue());
+            // 发货条件
+            erpWdtTrade.setDeliveryTerm(DeliveryTerm.CASH_ON_DELIVERY.getValue());
+            // 货到付款金额 = 物流代收金额-优惠金额
+            erpWdtTrade.setCodAmount(fsStoreOrder.getPayDelivery().subtract(couponPrice));
+
+        } else if("3".equals(fsStoreOrder.getPayType())){
+            // 支付状态
+            erpWdtTrade.setPayStatus(PaymentStatus.UNPAID.getValue());
+            // 发货条件
+            erpWdtTrade.setDeliveryTerm(DeliveryTerm.CASH_ON_DELIVERY.getValue());
+            // 货到付款金额 = 物流代收金额-优惠金额
+            erpWdtTrade.setCodAmount(fsStoreOrder.getPayDelivery().subtract(couponPrice));
+        } else { // 如果是线上付款
+            // 支付状态
+            erpWdtTrade.setPayStatus(PaymentStatus.FULLY_PAID.getValue());
+            // 发货条件
+            erpWdtTrade.setDeliveryTerm(DeliveryTerm.PAYMENT_BEFORE_DELIVERY.getValue());
+        }
+
+        // 下单时间
+        erpWdtTrade.setTradeTime(order.getDeal_datetime());
+        // 支付时间
+        erpWdtTrade.setPayTime(order.getDeal_datetime());
+        // 分销类别
+        erpWdtTrade.setFenxiaoType(FenxiaoType.JINGXIAO.getValue());
+        // 客户网名
+        erpWdtTrade.setBuyerNick(order.getReceiver_name());
+        // 收件人姓名
+        erpWdtTrade.setReceiverName(order.getReceiver_name());
+        // 省份
+        erpWdtTrade.setReceiverProvince(order.getReceiver_province());
+        // 市
+        erpWdtTrade.setReceiverCity(order.getReceiver_city());
+        // 区
+        erpWdtTrade.setReceiverDistrict(order.getReceiver_district());
+        // 详细地址
+        erpWdtTrade.setReceiverAddress(order.getReceiver_address());
+        // 手机
+        erpWdtTrade.setReceiverMobile(order.getReceiver_mobile());
+        // 固定电话
+        erpWdtTrade.setReceiverTelno(order.getReceiver_mobile());
+        // 买家备注
+        erpWdtTrade.setBuyerMessage(order.getBuyer_memo());
+        // 卖家备注
+        erpWdtTrade.setSellerMemo(order.getSeller_memo());
+        erpWdtTrade.setWarehouseNo(order.getWarehouse_code());
+
+        // 运费金额
+        erpWdtTrade.setPostAmount(fsStoreOrder.getFreightPrice());
+        // 已付金额
+        if(ObjectUtils.isNotNull(fsStoreOrder)){
+            erpWdtTrade.setPaid(fsStoreOrder.getPayMoney());
+        }
+
+        List<FsStoreOrderItem> fsStoreOrderItemVOS = fsStoreOrderItemService.selectFsStoreOrderItemListByOrderId(fsStoreOrder.getOrderId());
+        List<ErpWdtOrder> erpWdtOrderList = new ArrayList<>();
+        // 商品总价
+        BigDecimal totalPrice = fsStoreOrder.getTotalPrice();
+
+        // 总折扣金额 = 优惠券金额 + 折扣金额
+        BigDecimal totalDiscountPrice = BigDecimal.ZERO;
+        // 折扣金额
+        BigDecimal discountPrice = totalPrice.subtract(fsStoreOrder.getPayPrice());
+        totalDiscountPrice = couponPrice.add(discountPrice);
+
+        // 防止除零错误
+        if (totalPrice.compareTo(BigDecimal.ZERO) == 0) {
+            totalPrice = BigDecimal.ONE;
+        }
+
+        for (FsStoreOrderItem fsStoreOrderItem : fsStoreOrderItemVOS) {
+            ErpWdtOrder erpWdtOrder = new ErpWdtOrder();
+            //平台订单货品表主键
+            erpWdtOrder.setOid(String.format("%s%s",fsStoreOrder.getOrderCode(),fsStoreOrderItem.getItemId()));
+            erpWdtOrder.setNum(BigDecimal.valueOf(fsStoreOrderItem.getNum()));
+            FsStoreProduct fsStoreProduct = fsStoreProductService.selectFsStoreProductById(fsStoreOrderItem.getProductId());
+            Asserts.check(ObjectUtils.isNotNull(fsStoreProduct),"该产品不存在! 产品id: {} ",fsStoreOrderItem.getProductId());
+            // 单价
+            erpWdtOrder.setPrice(fsStoreProduct.getPrice());
+            // 状态
+            erpWdtOrder.setStatus(TradeStatus.SHIPPED.getValue());
+            // 退款状态
+            erpWdtOrder.setRefundStatus(RefundStatus.NO_REFUND.getValue());
+
+            // 平台货品ID
+            erpWdtOrder.setGoodsId(String.valueOf(fsStoreProduct.getProductId()));
+            JSONObject jsonObject = JSON.parseObject(fsStoreOrderItem.getJsonInfo());
+            erpWdtOrder.setSpecId(jsonObject.getString("sku"));
+            erpWdtOrder.setGoodsNo(jsonObject.getString("barCode"));
+            erpWdtOrder.setSpecNo(jsonObject.getString("sku"));
+            // 货品名称
+            erpWdtOrder.setGoodsName(fsStoreProduct.getProductName());
+            // 调整
+            erpWdtOrder.setAdjustAmount(BigDecimal.ZERO);
+            // 优惠
+            erpWdtOrder.setDiscount(BigDecimal.ZERO);
+            // 分摊优惠
+            // 分摊比例
+            BigDecimal price = fsStoreProduct.getPrice().multiply(BigDecimal.valueOf(fsStoreOrderItem.getNum()));
+            BigDecimal divide = price.divide(totalPrice, RoundingMode.HALF_UP);
+            erpWdtOrder.setShareDiscount(divide.multiply(totalDiscountPrice));
+
+            erpWdtOrderList.add(erpWdtOrder);
+        }
+
+        // 最后一个商品的分摊优惠等于总优惠减去前面分摊优惠之和
+        Asserts.check(CollectionUtils.isNotEmpty(erpWdtOrderList),"订单 {} 商品不能为空!", order.getPlatform_code());
+        long size = erpWdtOrderList.size();
+        if(size > 1) {
+            ErpWdtOrder erpWdtOrder = erpWdtOrderList.get(erpWdtOrderList.size() - 1);
+            erpWdtOrder.setShareDiscount(totalDiscountPrice.subtract(erpWdtOrderList.stream()
+                    .limit(size - 1L)
+                    .map(item -> Optional.ofNullable(item.getShareDiscount()).orElse(BigDecimal.ZERO))
+                    .reduce(BigDecimal.ZERO, BigDecimal::add)));
+        }
+
+        erpWdtTrade.setOrderList(erpWdtOrderList);
+        erpWdtBusinessRequestParams.setTradeList(new ArrayList<>(Arrays.asList(erpWdtTrade)));
+
+        Map<String,String> map = new HashMap<>();
+        map.put("shop_no",erpWdtBusinessRequestParams.getShopNo());
+        map.put("switch_mode", String.valueOf(erpWdtBusinessRequestParams.getSwitchMode()));
+        map.put("trade_list", convertToSnakeCase(erpWdtBusinessRequestParams.getTradeList()));
+
+
+        try {
+            String response = client.execute("trade_push.php", map);
+            ParserConfig config = new ParserConfig();
+            config.propertyNamingStrategy = PropertyNamingStrategy.CamelCase;
+            ErpWdtApiResponse erpWdtApiResponse = JSON.parseObject(response, ErpWdtApiResponse.class,config);
+            if(ObjectUtil.equal(0,erpWdtApiResponse.getCode())){
+                log.info("订单推送成功: {}", response);
+                ErpOrderResponse erpOrderResponse = new ErpOrderResponse();
+                erpOrderResponse.setCode(order.getPlatform_code());
+                erpOrderResponse.setSuccess(true);
+                erpOrderResponse.setRequestRawData(JSON.toJSONString(map));
+                erpOrderResponse.setResponseRawData(response);
+                return erpOrderResponse;
+            } else {
+                throw new RuntimeException(String.format("订单推送失败,原因: %s",erpWdtApiResponse.getMessage()));
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return new ErpOrderResponse();
+    }
+
+    public static String convertToSnakeCase(Object obj) {
+        SerializeConfig config = new SerializeConfig();
+        config.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
+        return JSON.toJSONString(obj, config);
+    }
+
+}

+ 10 - 0
fs-service/src/main/java/com/fs/his/config/FsSysConfig.java

@@ -12,13 +12,23 @@ public class FsSysConfig {
     //腾讯云IM
     Long sdkAppId;
     String sdkAppKey;
+
     //erp接口
     Integer erpOpen;//是否开启ERP
+    Integer erpType;//1:管易 2:旺店通
     String erpAppKey;
     String erpSessionKey;
     String erpSecret;
     String erpUrl;
     String erpShopCode;//店铺CODE
+    //erp旺店通
+    String erpWdAppKey;
+    String erpWdAppsecret;
+    String erpWdSid;
+    String erpWdShopCode;
+    String erpWdBaseUrl;
+    String erpWarehouseCode;
+
     //支付接口
     Integer payOpen;//是否开启
     String payPartnerId;

+ 6 - 0
fs-service/src/main/java/com/fs/his/domain/FsStoreOrder.java

@@ -54,6 +54,9 @@ public class FsStoreOrder extends BaseEntity
     @Excel(name = "购物车id")
     private String cartId;
 
+    /** 运费金额 */
+    private BigDecimal freightPrice;
+
     /** 订单商品总数 */
     @Excel(name = "订单商品总数")
     private Long totalNum;
@@ -187,6 +190,9 @@ public class FsStoreOrder extends BaseEntity
 
     private Long userCouponId;
 
+    /** 优惠券金额 */
+    private BigDecimal couponPrice;
+
     private Long companyId;
 
     private Long companyUserId;

+ 81 - 0
fs-service/src/main/java/com/fs/his/domain/FsStoreProductGroup.java

@@ -0,0 +1,81 @@
+package com.fs.his.domain;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import com.fs.his.dto.StoreProductGroupDTO;
+
+import java.util.List;
+
+/**
+ * 商品组合对象 fs_store_product_group
+ *
+ * @author fs
+ * @date 2022-11-23
+ */
+public class FsStoreProductGroup extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** ID */
+    private Long groupId;
+
+    /** 商品ID */
+    private String products;
+
+    /** code */
+    @Excel(name = "code")
+    private String barCode;
+
+    /** 名称 */
+    @Excel(name = "名称")
+    private String groupName;
+
+    List<StoreProductGroupDTO> productList;
+
+    public List<StoreProductGroupDTO> getProductList() {
+        return productList;
+    }
+
+    public void setProductList(List<StoreProductGroupDTO> productList) {
+        this.productList = productList;
+    }
+
+    public void setGroupId(Long groupId)
+    {
+        this.groupId = groupId;
+    }
+
+    public Long getGroupId()
+    {
+        return groupId;
+    }
+
+    public String getProducts() {
+        return products;
+    }
+
+    public void setProducts(String products) {
+        this.products = products;
+    }
+
+    public void setBarCode(String barCode)
+    {
+        this.barCode = barCode;
+    }
+
+    public String getBarCode()
+    {
+        return barCode;
+    }
+    public void setGroupName(String groupName)
+    {
+        this.groupName = groupName;
+    }
+
+    public String getGroupName()
+    {
+        return groupName;
+    }
+
+
+}

+ 22 - 0
fs-service/src/main/java/com/fs/his/dto/StoreProductGroupDTO.java

@@ -0,0 +1,22 @@
+package com.fs.his.dto;
+
+import lombok.*;
+
+import java.math.BigDecimal;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class StoreProductGroupDTO {
+
+    private Long id;//属性ID
+    private Integer count;//数量
+    private String sku;
+    private BigDecimal price;
+    private String image;
+    private String barCode;
+    private Long productId;
+    private String productName;
+}

+ 73 - 0
fs-service/src/main/java/com/fs/his/mapper/FsStoreProductGroupMapper.java

@@ -0,0 +1,73 @@
+package com.fs.his.mapper;
+
+import com.fs.his.domain.FsStoreProductGroup;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+
+import java.util.List;
+
+/**
+ * 商品组合Mapper接口
+ *
+ * @author fs
+ * @date 2022-11-23
+ */
+public interface FsStoreProductGroupMapper
+{
+    /**
+     * 查询商品组合
+     *
+     * @param groupId 商品组合ID
+     * @return 商品组合
+     */
+    public FsStoreProductGroup selectFsStoreProductGroupById(Long groupId);
+
+    /**
+     * 查询商品组合列表
+     *
+     * @param fsStoreProductGroup 商品组合
+     * @return 商品组合集合
+     */
+    public List<FsStoreProductGroup> selectFsStoreProductGroupList(FsStoreProductGroup fsStoreProductGroup);
+
+    /**
+     * 新增商品组合
+     *
+     * @param fsStoreProductGroup 商品组合
+     * @return 结果
+     */
+    public int insertFsStoreProductGroup(FsStoreProductGroup fsStoreProductGroup);
+
+    /**
+     * 修改商品组合
+     *
+     * @param fsStoreProductGroup 商品组合
+     * @return 结果
+     */
+    public int updateFsStoreProductGroup(FsStoreProductGroup fsStoreProductGroup);
+
+    /**
+     * 删除商品组合
+     *
+     * @param groupId 商品组合ID
+     * @return 结果
+     */
+    public int deleteFsStoreProductGroupById(Long groupId);
+
+    /**
+     * 批量删除商品组合
+     *
+     * @param groupIds 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteFsStoreProductGroupByIds(Long[] groupIds);
+
+    @Select("select * from fs_store_product_group where bar_code=#{groupBarCode}")
+    FsStoreProductGroup selectFsStoreProductGroupByBarCode(String groupBarCode);
+    @Update({"<script> " +
+            "update fs_store_product_group " +
+            "set products= REPLACE ( products, '\"id\":${oldValId}}' ,'\"id\":${newValId}}' ) " +
+            "</script>"})
+    void updateProducts(@Param("oldValId") Long oldId, @Param("newValId")Long newId);
+}

+ 2 - 0
fs-service/src/main/java/com/fs/his/mapper/FsStoreProductMapper.java

@@ -225,4 +225,6 @@ public interface FsStoreProductMapper
     @Select("select v.*,p.product_name,p.product_type,p.is_drug,p.unit_name,p.prescribe_spec,p.prescribe_code  from fs_store_product_attr_value v inner join fs_store_product p on p.product_id=v.product_id " +
             "where 1=1 and v.product_id=#{productId} limit 1")
     FsStoreProductAttrVO selectFsStoreProductAttrVOByProdId(Long productId);
+
+    FsStoreProduct selectFsStoreProductById(Long productId);
 }

+ 3 - 0
fs-service/src/main/java/com/fs/his/service/IFsStoreOrderItemService.java

@@ -4,6 +4,7 @@ import java.util.List;
 import com.fs.his.domain.FsStoreOrderItem;
 import com.fs.his.vo.FsStoreOrderItemListDVO;
 import com.fs.his.vo.FsStoreOrderItemListUVO;
+import com.fs.his.vo.FsStoreOrderItemVO;
 
 /**
  * 订单详情Service接口
@@ -64,4 +65,6 @@ public interface IFsStoreOrderItemService
     List<FsStoreOrderItemListUVO> selectFsStoreOrderItemListUVOByOrderId(Long orderId);
 
     List<FsStoreOrderItemListDVO> selectFsStoreOrderItemListDVOByOrderId(Long orderId);
+
+    List<FsStoreOrderItem> selectFsStoreOrderItemListByOrderId(Long orderId);
 }

+ 11 - 0
fs-service/src/main/java/com/fs/his/service/IFsStoreOrderService.java

@@ -9,6 +9,7 @@ import com.fs.common.core.domain.R;
 import com.fs.company.param.FsStoreStatisticsParam;
 import com.fs.company.vo.FsStoreOrderStatisticsVO;
 import com.fs.company.vo.FsStoreProductStatisticsVO;
+import com.fs.erp.domain.ErpOrder;
 import com.fs.his.domain.*;
 import com.fs.his.dto.ExpressNotifyDTO;
 import com.fs.his.dto.ExpressResultDTO;
@@ -198,4 +199,14 @@ public interface IFsStoreOrderService
     List<FsStoreOrder> selectFsStoreOrderByOrderIdIn(List<Long> longs);
 
     List<FsStoreOrder> selectFsStoreOrderStatisticsByUserId(List<Long> fsUserIdList);
+
+    FsStoreOrder selectFsStoreOrderByOrderCode(String orderCode);
+
+    /**
+     * 旺店通 查询erp订单
+     * @param order
+     * @return
+     * @throws ParseException
+     */
+    ErpOrder getErpOrder(FsStoreOrder order) throws ParseException;
 }

+ 65 - 0
fs-service/src/main/java/com/fs/his/service/IFsStoreProductGroupService.java

@@ -0,0 +1,65 @@
+package com.fs.his.service;
+
+
+import com.fs.his.domain.FsStoreProductGroup;
+
+import java.util.List;
+
+/**
+ * 商品组合Service接口
+ *
+ * @author fs
+ * @date 2022-11-23
+ */
+public interface IFsStoreProductGroupService
+{
+    /**
+     * 查询商品组合
+     *
+     * @param groupId 商品组合ID
+     * @return 商品组合
+     */
+    public FsStoreProductGroup selectFsStoreProductGroupById(Long groupId);
+
+    /**
+     * 查询商品组合列表
+     *
+     * @param fsStoreProductGroup 商品组合
+     * @return 商品组合集合
+     */
+    public List<FsStoreProductGroup> selectFsStoreProductGroupList(FsStoreProductGroup fsStoreProductGroup);
+
+    /**
+     * 新增商品组合
+     *
+     * @param fsStoreProductGroup 商品组合
+     * @return 结果
+     */
+    public int insertFsStoreProductGroup(FsStoreProductGroup fsStoreProductGroup);
+
+    /**
+     * 修改商品组合
+     *
+     * @param fsStoreProductGroup 商品组合
+     * @return 结果
+     */
+    public int updateFsStoreProductGroup(FsStoreProductGroup fsStoreProductGroup);
+
+    /**
+     * 批量删除商品组合
+     *
+     * @param groupIds 需要删除的商品组合ID
+     * @return 结果
+     */
+    public int deleteFsStoreProductGroupByIds(Long[] groupIds);
+
+    /**
+     * 删除商品组合信息
+     *
+     * @param groupId 商品组合ID
+     * @return 结果
+     */
+    public int deleteFsStoreProductGroupById(Long groupId);
+
+    FsStoreProductGroup selectFsStoreProductGroupByBarCode(String groupBarCode);
+}

+ 2 - 0
fs-service/src/main/java/com/fs/his/service/IFsStoreProductService.java

@@ -88,4 +88,6 @@ public interface IFsStoreProductService
     List<FsStoreProductExcelVO> selectFsStoreProductExcelVO(FsStoreProduct fsStoreProduct);
 
     List<FsStoreProductAttrValueVO> selectFsStoreProductAttrValueListVO(FsProductAttrValueParam param);
+
+    FsStoreProduct selectFsStoreProductById(Long productId);
 }

+ 1 - 1
fs-service/src/main/java/com/fs/his/service/impl/FsExpressServiceImpl.java

@@ -147,7 +147,7 @@ public class FsExpressServiceImpl implements IFsExpressService
             params.put("DataSign", URLEncoder.encode(dataSign, "UTF-8"));
             params.put("DataType", "2");
 
-            String result = HttpUtil.post(sysConfig.getKdnUrl().trim(), params);
+            String result = HttpUtil.post(sysConfig.getKdnAddressUrl().trim(), params);
 
             //根据公司业务处理返回的信息......
             ExpressInfoDTO dto=JSONUtil.toBean(result,ExpressInfoDTO.class);

+ 7 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderItemServiceImpl.java

@@ -1,9 +1,11 @@
 package com.fs.his.service.impl;
 
+import java.util.Collections;
 import java.util.List;
 
 import com.fs.his.vo.FsStoreOrderItemListDVO;
 import com.fs.his.vo.FsStoreOrderItemListUVO;
+import com.fs.his.vo.FsStoreOrderItemVO;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.his.mapper.FsStoreOrderItemMapper;
@@ -103,4 +105,9 @@ public class FsStoreOrderItemServiceImpl implements IFsStoreOrderItemService
     public List<FsStoreOrderItemListDVO> selectFsStoreOrderItemListDVOByOrderId(Long orderId) {
         return fsStoreOrderItemMapper.selectFsStoreOrderItemListDVOByOrderId(orderId);
     }
+
+    @Override
+    public List<FsStoreOrderItem>selectFsStoreOrderItemListByOrderId(Long orderId) {
+        return fsStoreOrderItemMapper.selectFsStoreOrderItemListByOrderId(orderId);
+    }
 }

+ 392 - 20
fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java

@@ -84,6 +84,8 @@ import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
@@ -178,7 +180,12 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
     @Autowired
     private ICompanyDeptService companyDeptService;
     @Autowired
-    private IErpOrderService erpOrderService;
+    @Qualifier("erpOrderServiceImpl")
+    private IErpOrderService gyOrderService;
+
+    @Autowired
+    @Qualifier("wdtErpOrderServiceImpl")
+    private IErpOrderService wdtOrderService;
     @Autowired
     private IFsStoreAfterSalesService fsStoreAfterSalesService;
     @Autowired
@@ -229,6 +236,8 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
     private IFsExportTaskService exportTaskService;
     @Autowired
     private QwUserServiceImpl qwUserServiceImpl;
+    @Autowired
+    private IFsStoreProductGroupService storeProductGroupService;
 
     /**
      * 查询订单
@@ -1591,16 +1600,36 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
         logs.setCompanyId(fsStoreOrderSalesParam.getCompanyId());
         logs.setChangeMessage("平台提交售后");
         fsStoreAfterSalesLogsMapper.insertFsStoreAfterSalesLogs(logs);
-        //管易作废
-        if(StringUtils.isNotEmpty(order.getExtendOrderId())){
-            if (!order.getExtendOrderId().equals("HIS")){
-                ErpRefundUpdateRequest request=new ErpRefundUpdateRequest();
-                request.setTid(order.getOrderCode());
-                request.setOid(order.getOrderCode());
-                request.setRefund_state(1);
-                erpOrderService.refundUpdate(request);
+        //判断是否开启erp
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+        Integer erpOpen = sysConfig.getErpOpen();
+        if (erpOpen != null && erpOpen == 1){
+            //判断erp类型
+            Integer erpType = sysConfig.getErpType();
+            if (erpType != null){
+
+                IErpOrderService erpOrderService = null;
+                if (erpType == 1){
+                    //管易
+                    erpOrderService =  gyOrderService;
+                } else if (erpType == 2){
+                    //旺店通
+                    erpOrderService =  wdtOrderService;
+                }
+                //管易作废
+                if(erpOrderService!= null && StringUtils.isNotEmpty(order.getExtendOrderId())){
+                    if (!order.getExtendOrderId().equals("HIS")){
+                        ErpRefundUpdateRequest request=new ErpRefundUpdateRequest();
+                        request.setTid(order.getOrderCode());
+                        request.setOid(order.getOrderCode());
+                        request.setRefund_state(1);
+                        erpOrderService.refundUpdate(request);
+                    }
+                }
             }
         }
+
+
         order.setStatus(-1);
         order.setRefundStatus(1+"");
         fsStoreOrderMapper.updateFsStoreOrder(order);
@@ -1614,6 +1643,27 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
 
     @Override
     public void createOmsOrder(Long orderId) throws ParseException {
+        //判断是否开启erp
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+        Integer erpOpen = sysConfig.getErpOpen();
+        if (erpOpen==null || erpOpen==0){
+            return;
+        }
+        //判断erp类型
+        Integer erpType = sysConfig.getErpType();
+        if (erpType == null){
+            return;
+        }
+        IErpOrderService erpOrderService = null;
+        if (erpType == 1){
+            //管易
+            erpOrderService =  gyOrderService;
+        } else if (erpType == 2){
+            //旺店通
+            erpOrderService =  wdtOrderService;
+        } else {
+            return;
+        }
         FsStoreOrder order=fsStoreOrderMapper.selectFsStoreOrderByOrderId(orderId);
         if(order!=null&&StringUtils.isEmpty(order.getExtendOrderId())&&order.getStatus()!=2){
             return;
@@ -1633,7 +1683,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
 //        }else{
 //            erpOrder.setWarehouse_code(order.getStoreHouseCode());
 //        }
-        FsSysConfig sysConfig = configUtil.getSysConfig();
+
         erpOrder.setShop_code(sysConfig.getErpShopCode());
         erpOrder.setSeller_memo(order.getRemark());
         List<ErpOrderPayment> payments=new ArrayList<>();
@@ -1925,21 +1975,42 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
         }
         ErpOrderQueryRequert request = new ErpOrderQueryRequert();
         request.setCode(order.getExtendOrderId());
-        ErpOrderQueryResponse response = erpOrderService.getOrder(request);
-        if(response.getOrders()!=null&&response.getOrders().size()>0){
-            for(ErpOrderQuery orderQuery : response.getOrders()){
-                if(orderQuery.getDeliverys()!=null&&orderQuery.getDeliverys().size()>0){
-                    for(ErpDeliverys delivery:orderQuery.getDeliverys()){
-                        if(delivery.getDelivery()&& org.apache.commons.lang3.StringUtils.isNotEmpty(delivery.getMail_no())){
-                            //更新商订单状态 删除REDIS
-                            fsStoreOrderService.deliveryOrder(order.getOrderCode(),delivery.getMail_no(),delivery.getExpress_code(),delivery.getExpress_name());
-                            redisCache.deleteObject("delivery"+":"+order.getExtendOrderId());
+
+        //判断是否开启erp
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+        Integer erpOpen = sysConfig.getErpOpen();
+        if (erpOpen != null && erpOpen == 1){
+            //判断erp类型
+            Integer erpType = sysConfig.getErpType();
+            if (erpType != null){
+
+                IErpOrderService erpOrderService = null;
+                if (erpType == 1){
+                    //管易
+                    erpOrderService =  gyOrderService;
+                } else if (erpType == 2){
+                    //旺店通
+                    erpOrderService =  wdtOrderService;
+                }
+                ErpOrderQueryResponse response = erpOrderService.getOrder(request);
+                if(response.getOrders()!=null&&response.getOrders().size()>0){
+                    for(ErpOrderQuery orderQuery : response.getOrders()){
+                        if(orderQuery.getDeliverys()!=null&&orderQuery.getDeliverys().size()>0){
+                            for(ErpDeliverys delivery:orderQuery.getDeliverys()){
+                                if(delivery.getDelivery()&& org.apache.commons.lang3.StringUtils.isNotEmpty(delivery.getMail_no())){
+                                    //更新商订单状态 删除REDIS
+                                    fsStoreOrderService.deliveryOrder(order.getOrderCode(),delivery.getMail_no(),delivery.getExpress_code(),delivery.getExpress_name());
+                                    redisCache.deleteObject("delivery"+":"+order.getExtendOrderId());
+                                }
+                            }
+
                         }
                     }
-
                 }
+
             }
         }
+
         return R.error("未生成运单信息");
     }
 
@@ -2789,5 +2860,306 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
         return fsStoreOrderMapper.selectFsStoreOrderStatisticsByUserId(fsUserIdList);
     }
 
+    @Override
+    public FsStoreOrder selectFsStoreOrderByOrderCode(String orderCode) {
+        return fsStoreOrderMapper.selectFsStoreOrderByOrderCode(orderCode);
+    }
+
+    /**
+     * 旺店通 查询erp订单
+     * @param order
+     * @return
+     * @throws ParseException
+     */
+    @Override
+    public ErpOrder getErpOrder(FsStoreOrder order) throws ParseException {
+        ErpOrder erpOrder=new ErpOrder();
+        if (order.getCompanyId()!=null){
+            erpOrder.setVip_code(order.getUserId().toString()+ order.getCompanyId().toString());
+        }else {
+            erpOrder.setVip_code(order.getUserId().toString());
+        }
+        erpOrder.setPlatform_code(order.getOrderCode());
+//        if(order.getStoreHouseCode()==null){
+//            erpOrder.setWarehouse_code("CQDS001");
+//        }
+//        else{
+        erpOrder.setWarehouse_code(configUtil.getSysConfig().getErpWarehouseCode());
+//        }
+//        if(order.getStoreHouseCode().equals("YDSP001")){
+//            erpOrder.setShop_code("RunDayWuHan");
+//        }
+//        else{
+        //判断是否开启erp
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+        Integer erpOpen = sysConfig.getErpOpen();
+        if (erpOpen != null && erpOpen == 1){
+            //判断erp类型
+            Integer erpType = sysConfig.getErpType();
+            if (erpType != null){
+                if (erpType == 1){
+                    //管易
+                } else if (erpType == 2){
+                    //旺店通
+                    erpOrder.setShop_code(sysConfig.getErpShopCode());
+                }
+
+            }
+        }
+
+//        }
+//      erpOrder.setPost_fee(order.getTotalPostage().doubleValue());
+        erpOrder.setSeller_memo(order.getRemark());
+        // order.setCurrency_code("JCZD");
+        List<ErpOrderPayment> payments=new ArrayList<>();
+        ErpOrderPayment payment=new ErpOrderPayment();
+        payment.setPay_type_code("weixin");
+        payment.setPayment(order.getPayMoney().doubleValue());
+        //payment.setPaytime(new Timestamp(System.currentTimeMillis()));
+        if(order.getPayTime()!=null){
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            String timeString = sdf.format(order.getPayTime());
+            Date date = sdf.parse(timeString); // 时间格式转为时间戳
+            long timeLong = date.getTime();
+            payment.setPaytime(new Timestamp(timeLong));
+        }
+        payments.add(payment);
+        //1.新疆、西藏、内蒙古、海南的订单(代收+非代收)全部发EMS
+        //2.全款订单选择中通,快递ID 452  ZTO 中通商城标快 ZTBK.17782167502
+        //3.新疆  西藏 内蒙古 海南  全款订单走顺丰丰云配  【非全款】的就根据公司配置那来 配的哪个走哪个快递
+        //4.把现在发中通的规则改成发顺丰风云配 SF.0235402855
+        //5.全款支付且应付金额小于等于100元,快递方式默认中通小件455 ZTO 中通小件 ZTPDD
+        if(order.getCompanyId()!=null&& order.getStoreHouseCode()!=null&& order.getStoreHouseCode().equals("WHSP001")){
+            //杭州家有仙妻实业有限公司 全部订单快递方式设置为商城德邦快递
+            FsExpress express=expressService.selectFsExpressByOmsCode("SF-WHC");
+            erpOrder.setExpress_code(express.getOmsCode());
+            order.setDeliveryName(express.getName());
+            order.setDeliverySn(express.getCode());
+            if(order.getPayDelivery().compareTo(new BigDecimal(0))==0){
+
+            }
+            else{
+                //物流代收金额
+                ErpOrderPayment codPayment=new ErpOrderPayment();
+                codPayment.setPay_type_code("cod");
+                codPayment.setPayment(order.getPayDelivery().doubleValue());
+                payments.add(codPayment);
+                erpOrder.setCod(true);
+            }
+        }
+        else if(order.getCompanyId()!=null){
+            Company company = companyService.selectCompanyById(order.getCompanyId());
+            if (order.getPayDelivery().compareTo(new BigDecimal(0)) == 0) {  //没有物流代收(全款订单)
+                FsExpress express = new FsExpress();
+                //express=expressService.selectFsExpressByOmsCode("SF.0235402855");
+                if(order.getPayPrice().compareTo(new BigDecimal(100))<=0){
+                    express=expressService.selectFsExpressByOmsCode("ZTPDD");
+                }
+                else{
+                    boolean found = containsAddress(order.getUserAddress());
+                    if(found){
+                        express=expressService.selectFsExpressByOmsCode("SF.0235402855");
+                    }
+                    else{
+                        express=expressService.selectFsExpressByOmsCode("SF.0235402855");
+                    }
+                }
+                erpOrder.setExpress_code(express.getOmsCode());
+                order.setDeliveryName(express.getName());
+                order.setDeliverySn(express.getCode());
+            }
+            else {
+                FsExpress express = new FsExpress();
+                boolean found = containsAddress(order.getUserAddress());
+                if(found){
+                    if(StringUtils.isNotEmpty(company.getOmsCode())){
+                        express = expressService.selectFsExpressByOmsCode(company.getOmsCode());
+                    }else{
+                        express=expressService.selectFsExpressByOmsCode("EMS.1");
+                    }
+                }
+                else{
+                    if(StringUtils.isNotEmpty(company.getOmsCode())){
+                        express = expressService.selectFsExpressByOmsCode(company.getOmsCode());
+                    }else{
+                        express = expressService.selectFsExpressByOmsCode("SF.0235402855");
+                    }
+                }
+                erpOrder.setExpress_code(express.getOmsCode());
+                order.setDeliveryName(express.getName());
+                order.setDeliverySn(express.getCode());
+                //物流代收金额
+                ErpOrderPayment codPayment = new ErpOrderPayment();
+                codPayment.setPay_type_code("cod");
+                codPayment.setPayment(order.getPayDelivery().doubleValue());
+                payments.add(codPayment);
+                erpOrder.setCod(true);
+            }
+        }
+        else{
+            if(order.getPayDelivery().compareTo(new BigDecimal(0))==0){  //没有物流代收(全款订单)
+                FsExpress express=new FsExpress();
+                if(order.getPayPrice().compareTo(new BigDecimal(100))<=0){
+                    express=expressService.selectFsExpressByOmsCode("ZTPDD");
+                }else{
+                    boolean found = containsAddress(order.getUserAddress());
+                    if(found){
+                        express=expressService.selectFsExpressByOmsCode("SF.0235402855");
+                    }
+                    else{
+                        express=expressService.selectFsExpressByOmsCode("SF.0235402855");
+                    }
+                }
+                erpOrder.setExpress_code(express.getOmsCode());
+                order.setDeliveryName(express.getName());
+                order.setDeliverySn(express.getCode());
+            }
+            else{
+                ErpOrderPayment codPayment=new ErpOrderPayment();
+                codPayment.setPay_type_code("cod");
+                codPayment.setPayment(order.getPayDelivery().doubleValue());
+                payments.add(codPayment);
+                erpOrder.setCod(true);
+                FsExpress express=new FsExpress();
+                boolean found = containsAddress(order.getUserAddress());
+                if(found){
+                    express=expressService.selectFsExpressByOmsCode("EMS.1");
+                }
+                else {
+                    express=expressService.selectFsExpressByOmsCode("SF.0235402855");
+                }
+                erpOrder.setExpress_code(express.getOmsCode());
+                order.setDeliveryName(express.getName());
+                order.setDeliverySn(express.getCode());
+            }
+        }
+        erpOrder.setPayments(payments);
+        if(order.getCompanyId()!=null){
+            Company company=companyService.selectCompanyById(order.getCompanyId());
+            if(company!=null){
+                erpOrder.setSeller_memo(company.getCompanyName());
+            }
+        }
+        if(order.getCompanyUserId()!=null){
+            CompanyUser companyUser=companyUserService.selectCompanyUserById(order.getCompanyUserId());
+            if(companyUser!=null){
+                CompanyDept dept=companyDeptService.selectCompanyDeptById(companyUser.getDeptId());
+                if(dept!=null){
+                    List<String> names=companyDeptService.selectCompanyDeptNamesByIds(dept.getAncestors());
+                    if(names!=null&&names.size()>0){
+                        //写备注
+                        erpOrder.setSeller_memo(erpOrder.getSeller_memo()+"-"+StringUtils.join(names, ",")+","+dept.getDeptName() );
+                    }
+                }
+                erpOrder.setSeller_memo(erpOrder.getSeller_memo()+"-"+companyUser.getNickName());
+            }
+        }
+
+        if(order.getStoreHouseCode().equals("WHSP001")){
+            //武汉不备注快递史
+            //erpOrder.setSeller_memo(erpOrder.getSeller_memo()+"-"+order.getDeliveryName());
+        }
+        else{
+            erpOrder.setSeller_memo(erpOrder.getSeller_memo()+"-"+ order.getDeliveryName());
+        }
+        ErpRemarkDTO remarkDTO=new ErpRemarkDTO();
+        remarkDTO.setTotalPrice(order.getTotalPrice());
+        remarkDTO.setPayPrice(order.getPayPrice());
+        remarkDTO.setDeliveryMoney(order.getPayDelivery());
+        remarkDTO.setPayMoney(order.getPayMoney());
+        remarkDTO.setCouponMoney(order.getCouponPrice());
+        remarkDTO.setOrderId(order.getOrderCode());
+        remarkDTO.setYdMoney(order.getPayPrice().subtract(order.getPayMoney().subtract(order.getPayDelivery())));
+//        //套餐标题也传过去
+//        if (order.getOrderCreateType() == 2){
+//            JSONObject jsonStr = JSONObject.parseObject(order.getPackageJson());
+//            remarkDTO.setPackageTitle(jsonStr.getString("title"));
+//        }
+
+        if(order.getPayTime()!=null){
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            String format = sdf.format(order.getPayTime());
+            remarkDTO.setPayTime(format);
+        }
+        erpOrder.setSeller_memo(erpOrder.getSeller_memo()+JSONUtil.toJsonStr(remarkDTO));
+
+        erpOrder.setOrder_type_code("order");
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        erpOrder.setDeal_datetime(sdf.format(new Date()));
+        FsStoreOrderItem itemMap=new FsStoreOrderItem();
+        itemMap.setOrderId(order.getOrderId());
+        List<FsStoreOrderItem> orderItems=storeOrderItemService.selectFsStoreOrderItemList(itemMap);
+        List<ErpOrderItem> details=new ArrayList<>();
+        for(FsStoreOrderItem orderItem: orderItems){
+            FsStoreCartDTO cartDTO= JSONUtil.toBean(orderItem.getJsonInfo(),FsStoreCartDTO.class);
+            //如果是组合码,查询出真实的商品数据 然后写入
+            if(StringUtils.isNotEmpty(cartDTO.getGroupBarCode())){
+                FsStoreProductGroup group=storeProductGroupService.selectFsStoreProductGroupByBarCode(cartDTO.getGroupBarCode().trim());
+                if(group!=null){
+                    JSONArray jsonArray=JSONUtil.parseArray(group.getProducts());
+                    List<StoreProductGroupDTO> productGroupDTOS=JSONUtil.toList(jsonArray, StoreProductGroupDTO.class);
+                    if(productGroupDTOS!=null){
+                        for(StoreProductGroupDTO dto:productGroupDTOS){
+                            FsStoreProductAttrValue attrValue=fsStoreProductAttrValueMapper.selectFsStoreProductAttrValueById(dto.getId());
+                            ErpOrderItem item=new ErpOrderItem();
+                            item.setItem_code(attrValue.getBarCode());
+                            item.setPrice(attrValue.getPrice().toString());
+                            item.setQty(dto.getCount()*cartDTO.getNum());
+                            item.setRefund(0);
+                            details.add(item);
+                        }
+                    }
+                }
+            }
+            else{
+                ErpOrderItem item=new ErpOrderItem();
+                item.setItem_code(cartDTO.getBarCode().trim());
+                item.setPrice(cartDTO.getPrice().toString());
+                item.setQty(cartDTO.getNum());
+                item.setRefund(0);
+                details.add(item);
+            }
+        }
+        erpOrder.setDetails(details);
+        erpOrder.setReceiver_name(order.getUserName());
+        if(order.getUserPhone().length()>11){
+            erpOrder.setReceiver_phone(order.getUserPhone());
+        }
+        else{
+            erpOrder.setReceiver_mobile(order.getUserPhone());
+        }
+        String[] address= order.getUserAddress().split(" ");
+        erpOrder.setReceiver_province(address[0]);
+        erpOrder.setReceiver_city(address[1]);
+        erpOrder.setReceiver_district(address[2]);
+        //处理地址多空隔问题
+        if(address.length>3){
+            StringBuffer addrs=new StringBuffer();
+            for(int i=3;i<address.length;i++){
+                addrs.append(address[i]);
+            }
+            erpOrder.setReceiver_address(addrs.toString());
+        }
+        else if(address.length==3){
+            erpOrder.setReceiver_address(address[2]);
+        }
+        //处理地址字符问题
+        erpOrder.setReceiver_address(erpOrder.getReceiver_address().replace("+","加"));
+        erpOrder.setReceiver_address(erpOrder.getReceiver_address().replace("\n",""));
+        return erpOrder;
+    }
+
+    public  boolean containsAddress(String companyName) {
+        String[] items= {"新疆","西藏","内蒙古","海南"};
+        boolean found = false;
+        for (String item : items) {
+            if (companyName.contains(item)) {
+                found = true;
+                break;
+            }
+        }
+        return found;
+    }
+
 
 }

+ 99 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsStoreProductGroupServiceImpl.java

@@ -0,0 +1,99 @@
+package com.fs.his.service.impl;
+
+import com.fs.his.domain.FsStoreProductGroup;
+import com.fs.his.mapper.FsStoreProductGroupMapper;
+import com.fs.his.service.IFsStoreProductGroupService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 商品组合Service业务层处理
+ *
+ * @author fs
+ * @date 2022-11-23
+ */
+@Service
+public class FsStoreProductGroupServiceImpl implements IFsStoreProductGroupService
+{
+    @Autowired
+    private FsStoreProductGroupMapper fsStoreProductGroupMapper;
+
+    /**
+     * 查询商品组合
+     *
+     * @param groupId 商品组合ID
+     * @return 商品组合
+     */
+    @Override
+    public FsStoreProductGroup selectFsStoreProductGroupById(Long groupId)
+    {
+        return fsStoreProductGroupMapper.selectFsStoreProductGroupById(groupId);
+    }
+
+    /**
+     * 查询商品组合列表
+     *
+     * @param fsStoreProductGroup 商品组合
+     * @return 商品组合
+     */
+    @Override
+    public List<FsStoreProductGroup> selectFsStoreProductGroupList(FsStoreProductGroup fsStoreProductGroup)
+    {
+        return fsStoreProductGroupMapper.selectFsStoreProductGroupList(fsStoreProductGroup);
+    }
+
+    /**
+     * 新增商品组合
+     *
+     * @param fsStoreProductGroup 商品组合
+     * @return 结果
+     */
+    @Override
+    public int insertFsStoreProductGroup(FsStoreProductGroup fsStoreProductGroup)
+    {
+        return fsStoreProductGroupMapper.insertFsStoreProductGroup(fsStoreProductGroup);
+    }
+
+    /**
+     * 修改商品组合
+     *
+     * @param fsStoreProductGroup 商品组合
+     * @return 结果
+     */
+    @Override
+    public int updateFsStoreProductGroup(FsStoreProductGroup fsStoreProductGroup)
+    {
+        return fsStoreProductGroupMapper.updateFsStoreProductGroup(fsStoreProductGroup);
+    }
+
+    /**
+     * 批量删除商品组合
+     *
+     * @param groupIds 需要删除的商品组合ID
+     * @return 结果
+     */
+    @Override
+    public int deleteFsStoreProductGroupByIds(Long[] groupIds)
+    {
+        return fsStoreProductGroupMapper.deleteFsStoreProductGroupByIds(groupIds);
+    }
+
+    /**
+     * 删除商品组合信息
+     *
+     * @param groupId 商品组合ID
+     * @return 结果
+     */
+    @Override
+    public int deleteFsStoreProductGroupById(Long groupId)
+    {
+        return fsStoreProductGroupMapper.deleteFsStoreProductGroupById(groupId);
+    }
+
+    @Override
+    public FsStoreProductGroup selectFsStoreProductGroupByBarCode(String groupBarCode) {
+        return fsStoreProductGroupMapper.selectFsStoreProductGroupByBarCode(groupBarCode);
+    }
+}

+ 5 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsStoreProductServiceImpl.java

@@ -768,5 +768,10 @@ public class FsStoreProductServiceImpl implements IFsStoreProductService
         return fsStoreProductMapper.selectFsStoreProductAttrValueListVO(param);
     }
 
+    @Override
+    public FsStoreProduct selectFsStoreProductById(Long productId) {
+        return fsStoreProductMapper.selectFsStoreProductById(productId);
+    }
+
 
 }

+ 67 - 0
fs-service/src/main/resources/mapper/his/FsStoreProductGroupMapper.xml

@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.his.mapper.FsStoreProductGroupMapper">
+
+    <resultMap type="FsStoreProductGroup" id="FsStoreProductGroupResult">
+        <result property="groupId"    column="group_id"    />
+        <result property="products"    column="products"    />
+        <result property="barCode"    column="bar_code"    />
+        <result property="groupName"    column="group_name"    />
+    </resultMap>
+
+    <sql id="selectFsStoreProductGroupVo">
+        select group_id, products, bar_code, group_name from fs_store_product_group
+    </sql>
+
+    <select id="selectFsStoreProductGroupList" parameterType="FsStoreProductGroup" resultMap="FsStoreProductGroupResult">
+        <include refid="selectFsStoreProductGroupVo"/>
+        <where>
+            <if test="barCode != null  and barCode != ''"> and bar_code = #{barCode}</if>
+            <if test="groupName != null  and groupName != ''"> and group_name like concat('%', #{groupName}, '%')</if>
+        </where>
+        order by group_id desc
+    </select>
+
+    <select id="selectFsStoreProductGroupById" parameterType="Long" resultMap="FsStoreProductGroupResult">
+        <include refid="selectFsStoreProductGroupVo"/>
+        where group_id = #{groupId}
+    </select>
+
+    <insert id="insertFsStoreProductGroup" parameterType="FsStoreProductGroup" useGeneratedKeys="true" keyProperty="groupId">
+        insert into fs_store_product_group
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="products != null">products,</if>
+            <if test="barCode != null">bar_code,</if>
+            <if test="groupName != null">group_name,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="products != null">#{products},</if>
+            <if test="barCode != null">#{barCode},</if>
+            <if test="groupName != null">#{groupName},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsStoreProductGroup" parameterType="FsStoreProductGroup">
+        update fs_store_product_group
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="products != null">products = #{products},</if>
+            <if test="barCode != null">bar_code = #{barCode},</if>
+            <if test="groupName != null">group_name = #{groupName},</if>
+        </trim>
+        where group_id = #{groupId}
+    </update>
+
+    <delete id="deleteFsStoreProductGroupById" parameterType="Long">
+        delete from fs_store_product_group where group_id = #{groupId}
+    </delete>
+
+    <delete id="deleteFsStoreProductGroupByIds" parameterType="String">
+        delete from fs_store_product_group where group_id in
+        <foreach item="groupId" collection="array" open="(" separator="," close=")">
+            #{groupId}
+        </foreach>
+    </delete>
+
+</mapper>

+ 4 - 0
fs-service/src/main/resources/mapper/his/FsStoreProductMapper.xml

@@ -94,6 +94,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <include refid="selectFsStoreProductVo"/>
         where product_id = #{productId}
     </select>
+    <select id="selectFsStoreProductById" resultType="com.fs.his.domain.FsStoreProduct">
+        <include refid="selectFsStoreProductVo"/>
+        where product_id = #{productId}
+    </select>
 
     <insert id="insertFsStoreProduct" parameterType="FsStoreProduct" useGeneratedKeys="true" keyProperty="productId">
         insert into fs_store_product

+ 1 - 0
pom.xml

@@ -30,6 +30,7 @@
         <poi.version>4.1.2</poi.version>
         <velocity.version>1.7</velocity.version>
         <jwt.version>0.9.1</jwt.version>
+        <org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
     </properties>
 
     <!-- 依赖声明 -->