From eb987323e1235de746769582e97cae7a499f9e67 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Thu, 24 Jul 2025 15:35:44 +0800 Subject: [PATCH 1/4] =?UTF-8?q?:art:=20=E4=BF=AE=E5=A4=8D=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E7=9A=84=E5=8F=98=E9=87=8F=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java | 4 ++-- .../wxpay/bean/notify/WxPayRefundNotifyResultTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java index ae86b8c854..8615a2e461 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java @@ -273,7 +273,7 @@ public String toString() { * */ @XStreamAlias("refund_recv_accout") - private String refundRecvAccout; + private String refundRecvAccount; /** *
@@ -324,7 +324,7 @@ public void loadXML(Document d) {
       settlementRefundFee = readXmlInteger(d, "settlement_refund_fee");
       refundStatus = readXmlString(d, "refund_status");
       successTime = readXmlString(d, "success_time");
-      refundRecvAccout = readXmlString(d, "refund_recv_accout");
+      refundRecvAccount = readXmlString(d, "refund_recv_accout");
       refundAccount = readXmlString(d, "refund_account");
       refundRequestSource = readXmlString(d, "refund_request_source");
     }
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
index 963afb2618..e7a22ee6cd 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
@@ -119,7 +119,7 @@ public void testFromXMLFastMode() throws WxPayException {
       refundNotifyResult.loadReqInfo(xmlDecryptedReqInfo);
       assertEquals(refundNotifyResult.getReqInfo().getRefundFee().intValue(), 15);
       assertEquals(refundNotifyResult.getReqInfo().getRefundStatus(), "SUCCESS");
-      assertEquals(refundNotifyResult.getReqInfo().getRefundRecvAccout(), "用户零钱");
+      assertEquals(refundNotifyResult.getReqInfo().getRefundRecvAccount(), "用户零钱");
       System.out.println(refundNotifyResult);
     } finally {
       XmlConfig.fastMode = false;

From 04ed5723496b0bbbc853fdde7e1a9b1b26e1b47e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 24 Jul 2025 07:43:18 +0000
Subject: [PATCH 2/4] Initial plan


From b56e6d7625323c713a684418c722f71fe97e0395 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 24 Jul 2025 07:59:36 +0000
Subject: [PATCH 3/4] Add overseas WeChat Pay support with GlobalTradeTypeEnum
 and WxPayUnifiedOrderV3GlobalRequest

Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com>
---
 .../WxPayUnifiedOrderV3GlobalRequest.java     | 57 ++++++++++++
 .../result/enums/GlobalTradeTypeEnum.java     | 36 ++++++++
 .../wxpay/service/WxPayService.java           | 22 +++++
 .../service/impl/BaseWxPayServiceImpl.java    | 31 +++++++
 .../impl/BaseWxPayServiceGlobalImplTest.java  | 89 +++++++++++++++++++
 5 files changed, 235 insertions(+)
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3GlobalRequest.java
 create mode 100644 weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/GlobalTradeTypeEnum.java
 create mode 100644 weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceGlobalImplTest.java

diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3GlobalRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3GlobalRequest.java
new file mode 100644
index 0000000000..296d3a8646
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3GlobalRequest.java
@@ -0,0 +1,57 @@
+package com.github.binarywang.wxpay.bean.request;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 
+ * 境外微信支付统一下单请求参数对象.
+ * 参考文档:https://pay.weixin.qq.com/doc/global/v3/zh/4013014223
+ * 
+ * + * @author Binary Wang + */ +@Data +@NoArgsConstructor +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +public class WxPayUnifiedOrderV3GlobalRequest extends WxPayUnifiedOrderV3Request implements Serializable { + private static final long serialVersionUID = 1L; + + /** + *
+   * 字段名:交易类型
+   * 变量名:trade_type
+   * 是否必填:是
+   * 类型:string[1,16]
+   * 描述:
+   *  交易类型,取值如下:
+   *  JSAPI--JSAPI支付
+   *  NATIVE--Native支付
+   *  APP--APP支付
+   *  H5--H5支付
+   *  示例值:JSAPI
+   * 
+ */ + @SerializedName(value = "trade_type") + private String tradeType; + + /** + *
+   * 字段名:商户类目
+   * 变量名:merchant_category_code
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  商户类目,境外商户必填
+   *  示例值:5812
+   * 
+ */ + @SerializedName(value = "merchant_category_code") + private String merchantCategoryCode; +} \ No newline at end of file diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/GlobalTradeTypeEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/GlobalTradeTypeEnum.java new file mode 100644 index 0000000000..fd33b240f1 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/GlobalTradeTypeEnum.java @@ -0,0 +1,36 @@ +package com.github.binarywang.wxpay.bean.result.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 境外微信支付方式 + * Overseas WeChat Pay trade types with global endpoints + * + * @author Binary Wang + */ +@Getter +@AllArgsConstructor +public enum GlobalTradeTypeEnum { + /** + * APP + */ + APP("/global/v3/transactions/app"), + /** + * JSAPI 或 小程序 + */ + JSAPI("/global/v3/transactions/jsapi"), + /** + * NATIVE + */ + NATIVE("/global/v3/transactions/native"), + /** + * H5 + */ + H5("/global/v3/transactions/h5"); + + /** + * 境外下单url + */ + private final String url; +} \ No newline at end of file diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index 8ceac2b6ba..c73fb843e8 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -6,6 +6,7 @@ import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; +import com.github.binarywang.wxpay.bean.result.enums.GlobalTradeTypeEnum; import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult; import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.constant.WxPayConstants; @@ -640,6 +641,17 @@ public interface WxPayService { */ T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException; + /** + * 境外微信支付调用统一下单接口,并组装生成支付所需参数对象. + * + * @param 请使用{@link WxPayUnifiedOrderV3Result}里的内部类或字段 + * @param tradeType the global trade type + * @param request 境外统一下单请求参数 + * @return 返回 {@link WxPayUnifiedOrderV3Result}里的内部类或字段 + * @throws WxPayException the wx pay exception + */ + T createOrderV3Global(GlobalTradeTypeEnum tradeType, WxPayUnifiedOrderV3GlobalRequest request) throws WxPayException; + /** * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" * @@ -660,6 +672,16 @@ public interface WxPayService { */ WxPayUnifiedOrderV3Result unifiedOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException; + /** + * 境外微信支付在发起支付前,需要调用统一下单接口,获取"预支付交易会话标识" + * + * @param tradeType the global trade type + * @param request 境外请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置) + * @return the wx pay unified order result + * @throws WxPayException the wx pay exception + */ + WxPayUnifiedOrderV3Result unifiedOrderV3Global(GlobalTradeTypeEnum tradeType, WxPayUnifiedOrderV3GlobalRequest request) throws WxPayException; + /** *
    * 合单支付API(APP支付、JSAPI支付、H5支付、NATIVE支付).
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
index 5057ef2b6b..4177a54cd5 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
@@ -11,6 +11,7 @@
 import com.github.binarywang.wxpay.bean.request.*;
 import com.github.binarywang.wxpay.bean.result.*;
 import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
+import com.github.binarywang.wxpay.bean.result.enums.GlobalTradeTypeEnum;
 import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult;
 import com.github.binarywang.wxpay.config.WxPayConfig;
 import com.github.binarywang.wxpay.config.WxPayConfigHolder;
@@ -746,6 +747,14 @@ public  T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOr
     return result.getPayInfo(tradeType, appId, request.getSubMchId(), this.getConfig().getPrivateKey());
   }
 
+  @Override
+  public  T createOrderV3Global(GlobalTradeTypeEnum tradeType, WxPayUnifiedOrderV3GlobalRequest request) throws WxPayException {
+    WxPayUnifiedOrderV3Result result = this.unifiedOrderV3Global(tradeType, request);
+    // Convert GlobalTradeTypeEnum to TradeTypeEnum for getPayInfo method
+    TradeTypeEnum domesticTradeType = TradeTypeEnum.valueOf(tradeType.name());
+    return result.getPayInfo(domesticTradeType, request.getAppid(), request.getMchid(), this.getConfig().getPrivateKey());
+  }
+
   @Override
   public WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException {
     if (StringUtils.isBlank(request.getSpAppid())) {
@@ -790,6 +799,28 @@ public WxPayUnifiedOrderV3Result unifiedOrderV3(TradeTypeEnum tradeType, WxPayUn
     return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class);
   }
 
+  @Override
+  public WxPayUnifiedOrderV3Result unifiedOrderV3Global(GlobalTradeTypeEnum tradeType, WxPayUnifiedOrderV3GlobalRequest request) throws WxPayException {
+    if (StringUtils.isBlank(request.getAppid())) {
+      request.setAppid(this.getConfig().getAppId());
+    }
+    if (StringUtils.isBlank(request.getMchid())) {
+      request.setMchid(this.getConfig().getMchId());
+    }
+    if (StringUtils.isBlank(request.getNotifyUrl())) {
+      request.setNotifyUrl(this.getConfig().getNotifyUrl());
+    }
+    if (StringUtils.isBlank(request.getTradeType())) {
+      request.setTradeType(tradeType.name());
+    }
+
+    // Use global WeChat Pay base URL for overseas payments
+    String globalBaseUrl = "https://apihk.mch.weixin.qq.com";
+    String url = globalBaseUrl + tradeType.getUrl();
+    String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
+    return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class);
+  }
+
   @Override
   public CombineTransactionsResult combine(TradeTypeEnum tradeType, CombineTransactionsRequest request) throws WxPayException {
     if (StringUtils.isBlank(request.getCombineAppid())) {
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceGlobalImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceGlobalImplTest.java
new file mode 100644
index 0000000000..c648c8a171
--- /dev/null
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceGlobalImplTest.java
@@ -0,0 +1,89 @@
+package com.github.binarywang.wxpay.service.impl;
+
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3GlobalRequest;
+import com.github.binarywang.wxpay.bean.result.enums.GlobalTradeTypeEnum;
+import com.github.binarywang.wxpay.constant.WxPayConstants;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import me.chanjar.weixin.common.util.RandomUtils;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+/**
+ * 境外微信支付测试类
+ *
+ * @author Binary Wang
+ */
+public class BaseWxPayServiceGlobalImplTest {
+
+  private static final Gson GSON = new GsonBuilder().create();
+
+  @Test
+  public void testWxPayUnifiedOrderV3GlobalRequest() {
+    // Test that the new request class has the required fields
+    WxPayUnifiedOrderV3GlobalRequest request = new WxPayUnifiedOrderV3GlobalRequest();
+    
+    // Set basic order information
+    String outTradeNo = RandomUtils.getRandomStr();
+    request.setOutTradeNo(outTradeNo);
+    request.setDescription("Test overseas payment");
+    request.setNotifyUrl("https://api.example.com/notify");
+    
+    // Set amount
+    WxPayUnifiedOrderV3GlobalRequest.Amount amount = new WxPayUnifiedOrderV3GlobalRequest.Amount();
+    amount.setCurrency(WxPayConstants.CurrencyType.CNY);
+    amount.setTotal(100); // 1 yuan in cents
+    request.setAmount(amount);
+    
+    // Set payer
+    WxPayUnifiedOrderV3GlobalRequest.Payer payer = new WxPayUnifiedOrderV3GlobalRequest.Payer();
+    payer.setOpenid("test_openid");
+    request.setPayer(payer);
+    
+    // Set the new required fields for global payments
+    request.setTradeType("JSAPI");
+    request.setMerchantCategoryCode("5812"); // Example category code
+    
+    // Assert that all fields are properly set
+    assertNotNull(request.getTradeType());
+    assertNotNull(request.getMerchantCategoryCode());
+    assertEquals("JSAPI", request.getTradeType());
+    assertEquals("5812", request.getMerchantCategoryCode());
+    assertEquals(outTradeNo, request.getOutTradeNo());
+    assertEquals("Test overseas payment", request.getDescription());
+    assertEquals(100, request.getAmount().getTotal());
+    assertEquals("test_openid", request.getPayer().getOpenid());
+    
+    // Test JSON serialization contains the new fields
+    String json = GSON.toJson(request);
+    assertTrue(json.contains("trade_type"));
+    assertTrue(json.contains("merchant_category_code"));
+    assertTrue(json.contains("JSAPI"));
+    assertTrue(json.contains("5812"));
+  }
+
+  @Test
+  public void testGlobalTradeTypeEnum() {
+    // Test that all trade types have the correct global endpoints
+    assertEquals("/global/v3/transactions/app", GlobalTradeTypeEnum.APP.getUrl());
+    assertEquals("/global/v3/transactions/jsapi", GlobalTradeTypeEnum.JSAPI.getUrl());
+    assertEquals("/global/v3/transactions/native", GlobalTradeTypeEnum.NATIVE.getUrl());
+    assertEquals("/global/v3/transactions/h5", GlobalTradeTypeEnum.H5.getUrl());
+  }
+
+  @Test
+  public void testGlobalTradeTypeEnumValues() {
+    // Test that we have all the main trade types
+    GlobalTradeTypeEnum[] tradeTypes = GlobalTradeTypeEnum.values();
+    assertEquals(4, tradeTypes.length);
+    
+    // Test that we can convert between enum name and TradeTypeEnum
+    for (GlobalTradeTypeEnum globalType : tradeTypes) {
+      // This tests that the enum names match between Global and regular TradeTypeEnum
+      String name = globalType.name();
+      assertNotNull(name);
+      assertTrue(name.equals("APP") || name.equals("JSAPI") || name.equals("NATIVE") || name.equals("H5"));
+    }
+  }
+}
\ No newline at end of file

From 67a94c7abff2e58832aa9f26942e42919dfb4c34 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 24 Jul 2025 08:03:36 +0000
Subject: [PATCH 4/4] Add complete overseas WeChat Pay implementation with
 examples and documentation

Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com>
---
 weixin-java-pay/OVERSEAS_PAY.md               | 120 ++++++++++++++
 .../service/impl/OverseasWxPayExample.java    | 153 ++++++++++++++++++
 2 files changed, 273 insertions(+)
 create mode 100644 weixin-java-pay/OVERSEAS_PAY.md
 create mode 100644 weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/OverseasWxPayExample.java

diff --git a/weixin-java-pay/OVERSEAS_PAY.md b/weixin-java-pay/OVERSEAS_PAY.md
new file mode 100644
index 0000000000..b9da9814f9
--- /dev/null
+++ b/weixin-java-pay/OVERSEAS_PAY.md
@@ -0,0 +1,120 @@
+# 境外微信支付(Overseas WeChat Pay)支持
+
+本次更新添加了境外微信支付的支持,解决了 [Issue #3618](https://github.com/binarywang/WxJava/issues/3618) 中提到的问题。
+
+## 问题背景
+
+境外微信支付需要使用新的API接口地址和额外的参数:
+- 使用不同的基础URL: `https://apihk.mch.weixin.qq.com` 
+- 需要额外的参数: `trade_type` 和 `merchant_category_code`
+- 使用不同的API端点: `/global/v3/transactions/*`
+
+## 新增功能
+
+### 1. GlobalTradeTypeEnum
+新的枚举类,定义了境外支付的交易类型和对应的API端点:
+- `APP`: `/global/v3/transactions/app`
+- `JSAPI`: `/global/v3/transactions/jsapi`
+- `NATIVE`: `/global/v3/transactions/native`
+- `H5`: `/global/v3/transactions/h5`
+
+### 2. WxPayUnifiedOrderV3GlobalRequest
+扩展的请求类,包含境外支付必需的额外字段:
+- `trade_type`: 交易类型 (JSAPI, APP, NATIVE, H5)
+- `merchant_category_code`: 商户类目代码(境外商户必填)
+
+### 3. 新的服务方法
+- `createOrderV3Global()`: 创建境外支付订单
+- `unifiedOrderV3Global()`: 境外统一下单接口
+
+## 使用示例
+
+### JSAPI支付示例
+```java
+// 创建境外支付请求
+WxPayUnifiedOrderV3GlobalRequest request = new WxPayUnifiedOrderV3GlobalRequest();
+request.setOutTradeNo(RandomUtils.getRandomStr());
+request.setDescription("境外商品购买");
+request.setNotifyUrl("https://your-domain.com/notify");
+
+// 设置金额
+WxPayUnifiedOrderV3GlobalRequest.Amount amount = new WxPayUnifiedOrderV3GlobalRequest.Amount();
+amount.setCurrency(WxPayConstants.CurrencyType.CNY);
+amount.setTotal(100); // 1元,单位为分
+request.setAmount(amount);
+
+// 设置支付者
+WxPayUnifiedOrderV3GlobalRequest.Payer payer = new WxPayUnifiedOrderV3GlobalRequest.Payer();
+payer.setOpenid("用户的openid");
+request.setPayer(payer);
+
+// 设置境外支付必需的参数
+request.setTradeType("JSAPI");
+request.setMerchantCategoryCode("5812"); // 商户类目代码
+
+// 调用境外支付接口
+WxPayUnifiedOrderV3Result.JsapiResult result = payService.createOrderV3Global(
+    GlobalTradeTypeEnum.JSAPI, 
+    request
+);
+```
+
+### APP支付示例
+```java
+WxPayUnifiedOrderV3GlobalRequest request = new WxPayUnifiedOrderV3GlobalRequest();
+// ... 设置基础信息 ...
+
+request.setTradeType("APP");
+request.setMerchantCategoryCode("5812");
+request.setPayer(new WxPayUnifiedOrderV3GlobalRequest.Payer()); // APP支付不需要openid
+
+WxPayUnifiedOrderV3Result.AppResult result = payService.createOrderV3Global(
+    GlobalTradeTypeEnum.APP, 
+    request
+);
+```
+
+### NATIVE支付示例
+```java
+WxPayUnifiedOrderV3GlobalRequest request = new WxPayUnifiedOrderV3GlobalRequest();
+// ... 设置基础信息 ...
+
+request.setTradeType("NATIVE");
+request.setMerchantCategoryCode("5812");
+request.setPayer(new WxPayUnifiedOrderV3GlobalRequest.Payer());
+
+String codeUrl = payService.createOrderV3Global(
+    GlobalTradeTypeEnum.NATIVE, 
+    request
+);
+```
+
+## 配置说明
+
+境外支付使用相同的 `WxPayConfig` 配置,无需特殊设置:
+
+```java
+WxPayConfig config = new WxPayConfig();
+config.setAppId("你的AppId");
+config.setMchId("你的境外商户号");
+config.setMchKey("你的商户密钥");
+config.setNotifyUrl("https://your-domain.com/notify");
+
+// V3相关配置
+config.setPrivateKeyPath("你的私钥文件路径");
+config.setCertSerialNo("你的商户证书序列号");
+config.setApiV3Key("你的APIv3密钥");
+```
+
+**注意**: 境外支付会自动使用 `https://apihk.mch.weixin.qq.com` 作为基础URL,无需手动设置。
+
+## 兼容性
+
+- 完全向后兼容,不影响现有的国内支付功能
+- 使用相同的配置类和结果类
+- 遵循现有的代码风格和架构模式
+
+## 参考文档
+
+- [境外微信支付文档](https://pay.weixin.qq.com/doc/global/v3/zh/4013014223)
+- [原始Issue #3618](https://github.com/binarywang/WxJava/issues/3618)
\ No newline at end of file
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/OverseasWxPayExample.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/OverseasWxPayExample.java
new file mode 100644
index 0000000000..ccccf9c803
--- /dev/null
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/OverseasWxPayExample.java
@@ -0,0 +1,153 @@
+package com.github.binarywang.wxpay.service.impl;
+
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3GlobalRequest;
+import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
+import com.github.binarywang.wxpay.bean.result.enums.GlobalTradeTypeEnum;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.constant.WxPayConstants;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
+import me.chanjar.weixin.common.util.RandomUtils;
+
+/**
+ * 境外微信支付使用示例
+ * Example usage for overseas WeChat Pay
+ *
+ * @author Binary Wang
+ */
+public class OverseasWxPayExample {
+
+  /**
+   * 境外微信支付JSAPI下单示例
+   * Example for overseas WeChat Pay JSAPI order creation
+   */
+  public void createOverseasJsapiOrder(WxPayService payService) throws WxPayException {
+    // 创建境外支付请求对象
+    WxPayUnifiedOrderV3GlobalRequest request = new WxPayUnifiedOrderV3GlobalRequest();
+    
+    // 设置基础订单信息
+    request.setOutTradeNo(RandomUtils.getRandomStr()); // 商户订单号
+    request.setDescription("境外商品购买"); // 商品描述
+    request.setNotifyUrl("https://your-domain.com/notify"); // 支付通知地址
+    
+    // 设置金额信息
+    WxPayUnifiedOrderV3GlobalRequest.Amount amount = new WxPayUnifiedOrderV3GlobalRequest.Amount();
+    amount.setCurrency(WxPayConstants.CurrencyType.CNY); // 币种
+    amount.setTotal(100); // 金额,单位为分
+    request.setAmount(amount);
+    
+    // 设置支付者信息
+    WxPayUnifiedOrderV3GlobalRequest.Payer payer = new WxPayUnifiedOrderV3GlobalRequest.Payer();
+    payer.setOpenid("用户的openid"); // 用户openid
+    request.setPayer(payer);
+    
+    // 设置境外支付必需的参数
+    request.setTradeType("JSAPI"); // 交易类型
+    request.setMerchantCategoryCode("5812"); // 商户类目代码,境外商户必填
+    
+    // 可选:设置场景信息
+    WxPayUnifiedOrderV3GlobalRequest.SceneInfo sceneInfo = new WxPayUnifiedOrderV3GlobalRequest.SceneInfo();
+    sceneInfo.setPayerClientIp("用户IP地址");
+    request.setSceneInfo(sceneInfo);
+    
+    // 调用境外支付接口
+    WxPayUnifiedOrderV3Result.JsapiResult result = payService.createOrderV3Global(
+        GlobalTradeTypeEnum.JSAPI, 
+        request
+    );
+    
+    // 返回的result包含前端需要的支付参数
+    System.out.println("支付参数:" + result);
+  }
+
+  /**
+   * 境外微信支付APP下单示例
+   * Example for overseas WeChat Pay APP order creation
+   */
+  public void createOverseasAppOrder(WxPayService payService) throws WxPayException {
+    WxPayUnifiedOrderV3GlobalRequest request = new WxPayUnifiedOrderV3GlobalRequest();
+    
+    // 设置基础信息
+    request.setOutTradeNo(RandomUtils.getRandomStr());
+    request.setDescription("境外APP商品购买");
+    request.setNotifyUrl("https://your-domain.com/notify");
+    
+    // 设置金额
+    WxPayUnifiedOrderV3GlobalRequest.Amount amount = new WxPayUnifiedOrderV3GlobalRequest.Amount();
+    amount.setCurrency(WxPayConstants.CurrencyType.CNY);
+    amount.setTotal(200); // 2元
+    request.setAmount(amount);
+    
+    // APP支付不需要设置payer.openid,但需要设置空的payer对象
+    request.setPayer(new WxPayUnifiedOrderV3GlobalRequest.Payer());
+    
+    // 境外支付必需参数
+    request.setTradeType("APP");
+    request.setMerchantCategoryCode("5812");
+    
+    // 调用境外APP支付接口
+    WxPayUnifiedOrderV3Result.AppResult result = payService.createOrderV3Global(
+        GlobalTradeTypeEnum.APP, 
+        request
+    );
+    
+    System.out.println("APP支付参数:" + result);
+  }
+
+  /**
+   * 境外微信支付NATIVE下单示例
+   * Example for overseas WeChat Pay NATIVE order creation  
+   */
+  public void createOverseasNativeOrder(WxPayService payService) throws WxPayException {
+    WxPayUnifiedOrderV3GlobalRequest request = new WxPayUnifiedOrderV3GlobalRequest();
+    
+    request.setOutTradeNo(RandomUtils.getRandomStr());
+    request.setDescription("境外扫码支付");
+    request.setNotifyUrl("https://your-domain.com/notify");
+    
+    // 设置金额
+    WxPayUnifiedOrderV3GlobalRequest.Amount amount = new WxPayUnifiedOrderV3GlobalRequest.Amount();
+    amount.setCurrency(WxPayConstants.CurrencyType.CNY);
+    amount.setTotal(300); // 3元
+    request.setAmount(amount);
+    
+    // NATIVE支付不需要设置payer.openid
+    request.setPayer(new WxPayUnifiedOrderV3GlobalRequest.Payer());
+    
+    // 境外支付必需参数
+    request.setTradeType("NATIVE");
+    request.setMerchantCategoryCode("5812");
+    
+    // 调用境外NATIVE支付接口
+    String result = payService.createOrderV3Global(
+        GlobalTradeTypeEnum.NATIVE, 
+        request
+    );
+    
+    System.out.println("NATIVE支付二维码链接:" + result);
+  }
+
+  /**
+   * 配置示例
+   * Configuration example
+   */
+  public WxPayConfig createOverseasConfig() {
+    WxPayConfig config = new WxPayConfig();
+    
+    // 基础配置
+    config.setAppId("你的AppId");
+    config.setMchId("你的境外商户号");
+    config.setMchKey("你的商户密钥");
+    config.setNotifyUrl("https://your-domain.com/notify");
+    
+    // 境外支付使用的是全球API,在代码中会自动使用 https://apihk.mch.weixin.qq.com 作为基础URL
+    // 无需额外设置payBaseUrl,方法内部会自动处理
+    
+    // V3相关配置(境外支付也使用V3接口)
+    config.setPrivateKeyPath("你的私钥文件路径");
+    config.setCertSerialNo("你的商户证书序列号");
+    config.setApiV3Key("你的APIv3密钥");
+    
+    return config;
+  }
+}
\ No newline at end of file