1
0
mirror of synced 2026-02-12 15:17:51 +08:00

🆕 #3618 【微信支付】增加境外微信支付的支持

This commit is contained in:
Copilot
2025-10-04 01:44:56 +08:00
committed by GitHub
parent a6825a62bb
commit ca567ce310
7 changed files with 508 additions and 0 deletions

View File

@@ -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"));
}
}
}

View File

@@ -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;
}
}