🎨 #4120 【小程序】新增个人主体虚拟支付参数支持
This commit is contained in:
@@ -51,6 +51,18 @@ public interface WxMaXPayService {
|
||||
*/
|
||||
WxMaXPayCancelCurrencyPayResponse cancelCurrencyPay(WxMaXPayCancelCurrencyPayRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 生成调起 wx.requestVirtualPayment 所需的支付参数。
|
||||
*
|
||||
* @param request 虚拟支付调起参数
|
||||
* @param sigParams 签名参数对象
|
||||
* @return 支付参数
|
||||
*/
|
||||
default WxMaXPayRequestVirtualPaymentData createRequestVirtualPaymentData(WxMaXPayRequestVirtualPaymentRequest request,
|
||||
WxMaXPaySigParams sigParams) {
|
||||
return request.createPayData(sigParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知发货。
|
||||
*
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package cn.binarywang.wx.miniapp.bean;
|
||||
|
||||
import cn.binarywang.wx.miniapp.bean.xpay.WxMaXPayGoodsInfo;
|
||||
import cn.binarywang.wx.miniapp.bean.xpay.WxMaXPayTeamInfo;
|
||||
import cn.binarywang.wx.miniapp.bean.xpay.WxMaXPayWeChatPayInfo;
|
||||
import cn.binarywang.wx.miniapp.config.WxMaConfig;
|
||||
import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils;
|
||||
import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
|
||||
@@ -213,6 +215,31 @@ public class WxMaMessage implements Serializable {
|
||||
@XStreamAlias("SubscribeMsgSentEvent")
|
||||
private WxMaSubscribeMsgEvent.SubscribeMsgSentEvent subscribeMsgSentEvent;
|
||||
|
||||
/**
|
||||
* 商户订单号.
|
||||
* xpay_goods_deliver_notify
|
||||
*/
|
||||
@SerializedName("OutTradeNo")
|
||||
@XStreamAlias("OutTradeNo")
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String outTradeNo;
|
||||
|
||||
/**
|
||||
* 微信支付信息.
|
||||
* xpay_goods_deliver_notify
|
||||
*/
|
||||
@SerializedName("WeChatPayInfo")
|
||||
@XStreamAlias("WeChatPayInfo")
|
||||
private WxMaXPayWeChatPayInfo weChatPayInfo;
|
||||
|
||||
/**
|
||||
* 道具信息.
|
||||
* xpay_goods_deliver_notify
|
||||
*/
|
||||
@SerializedName("GoodsInfo")
|
||||
@XStreamAlias("GoodsInfo")
|
||||
private WxMaXPayGoodsInfo goodsInfo;
|
||||
|
||||
// 小程序基本信息
|
||||
|
||||
//region 小程序基本信息 infoType=notify_3rd_wxa_auth_and_icp
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.binarywang.wx.miniapp.bean.xpay;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import com.thoughtworks.xstream.annotations.XStreamConverter;
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* xpay_goods_deliver_notify 推送中的道具信息。
|
||||
*/
|
||||
@Data
|
||||
public class WxMaXPayGoodsInfo implements Serializable {
|
||||
private static final long serialVersionUID = 7495157056049312108L;
|
||||
|
||||
@SerializedName("ProductId")
|
||||
@XStreamAlias("ProductId")
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String productId;
|
||||
|
||||
@SerializedName("Quantity")
|
||||
@XStreamAlias("Quantity")
|
||||
private Integer quantity;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package cn.binarywang.wx.miniapp.bean.xpay;
|
||||
|
||||
import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 调用 wx.requestVirtualPayment 所需的支付参数。
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WxMaXPayRequestVirtualPaymentData implements Serializable {
|
||||
private static final long serialVersionUID = 7495157056049312108L;
|
||||
|
||||
/**
|
||||
* 支付模式,个人主体虚拟支付固定为 short_series_goods。
|
||||
*/
|
||||
@SerializedName("mode")
|
||||
private String mode;
|
||||
|
||||
/**
|
||||
* 下单签名原文,需与计算 paySig 和 signature 时使用的字符串完全一致。
|
||||
*/
|
||||
@SerializedName("signData")
|
||||
private String signData;
|
||||
|
||||
/**
|
||||
* 使用 AppKey 对 requestVirtualPayment&signData 计算得到的签名。
|
||||
*/
|
||||
@SerializedName("paySig")
|
||||
private String paySig;
|
||||
|
||||
/**
|
||||
* 使用 session_key 对 signData 计算得到的签名。
|
||||
*/
|
||||
@SerializedName("signature")
|
||||
private String signature;
|
||||
|
||||
public String toJson() {
|
||||
return WxMaGsonBuilder.create().toJson(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package cn.binarywang.wx.miniapp.bean.xpay;
|
||||
|
||||
import cn.binarywang.wx.miniapp.constant.WxMaConstants;
|
||||
import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 个人主体虚拟支付调起 wx.requestVirtualPayment 的签名原文参数。
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WxMaXPayRequestVirtualPaymentRequest implements Serializable {
|
||||
private static final long serialVersionUID = 7495157056049312108L;
|
||||
|
||||
/**
|
||||
* 支付应用 ID。
|
||||
*/
|
||||
@SerializedName("offerId")
|
||||
private String offerId;
|
||||
|
||||
/**
|
||||
* 购买数量。
|
||||
*/
|
||||
@SerializedName("buyQuantity")
|
||||
private Integer buyQuantity;
|
||||
|
||||
/**
|
||||
* 环境,个人主体虚拟支付固定为 0。
|
||||
*/
|
||||
@SerializedName("env")
|
||||
private Integer env;
|
||||
|
||||
/**
|
||||
* 币种,个人主体虚拟支付固定为 CNY。
|
||||
*/
|
||||
@SerializedName("currencyType")
|
||||
private String currencyType;
|
||||
|
||||
/**
|
||||
* 道具 ID。
|
||||
*/
|
||||
@SerializedName("productId")
|
||||
private String productId;
|
||||
|
||||
/**
|
||||
* 道具单价,单位为分。
|
||||
*/
|
||||
@SerializedName("goodsPrice")
|
||||
private Integer goodsPrice;
|
||||
|
||||
/**
|
||||
* 商户订单号,8 到 32 位且不能以下划线开头。
|
||||
*/
|
||||
@SerializedName("outTradeNo")
|
||||
private String outTradeNo;
|
||||
|
||||
/**
|
||||
* 商户透传数据。
|
||||
*/
|
||||
@SerializedName("attach")
|
||||
private String attach;
|
||||
|
||||
public WxMaXPayRequestVirtualPaymentData createPayData(WxMaXPaySigParams sigParams) {
|
||||
final String signData = this.toJson();
|
||||
return WxMaXPayRequestVirtualPaymentData.builder()
|
||||
.mode(WxMaConstants.XPayPaymentMode.GOODS)
|
||||
.signData(signData)
|
||||
.paySig(sigParams.calcPaySig(WxMaConstants.XPayWxApiSigUri.WXAPI, signData))
|
||||
.signature(sigParams.calcSig(signData))
|
||||
.build();
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
return WxMaGsonBuilder.create().toJson(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.binarywang.wx.miniapp.bean.xpay;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
import com.thoughtworks.xstream.annotations.XStreamConverter;
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* xpay_goods_deliver_notify 推送中的微信支付信息。
|
||||
*/
|
||||
@Data
|
||||
public class WxMaXPayWeChatPayInfo implements Serializable {
|
||||
private static final long serialVersionUID = 7495157056049312108L;
|
||||
|
||||
@SerializedName("MchOrderNo")
|
||||
@XStreamAlias("MchOrderNo")
|
||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
||||
private String mchOrderNo;
|
||||
}
|
||||
@@ -397,6 +397,77 @@ public class WxMaMessageTest {
|
||||
assertEquals(teamInfo.getTeamAction(), new Integer(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* 个人主体虚拟支付发货通知事件 xpay_goods_deliver_notify 测试用例(XML格式)。
|
||||
*/
|
||||
@Test
|
||||
public void testXPayGoodsDeliverNotifyFromXml() {
|
||||
String xml = "<xml>\n" +
|
||||
" <ToUserName><![CDATA[gh_abcdefg]]></ToUserName>\n" +
|
||||
" <FromUserName><![CDATA[oABCDEFG]]></FromUserName>\n" +
|
||||
" <CreateTime>1700000000</CreateTime>\n" +
|
||||
" <MsgType><![CDATA[event]]></MsgType>\n" +
|
||||
" <Event><![CDATA[xpay_goods_deliver_notify]]></Event>\n" +
|
||||
" <OpenId><![CDATA[oABCDEFG]]></OpenId>\n" +
|
||||
" <OutTradeNo><![CDATA[order12345]]></OutTradeNo>\n" +
|
||||
" <WeChatPayInfo>\n" +
|
||||
" <MchOrderNo><![CDATA[wx_order_123]]></MchOrderNo>\n" +
|
||||
" </WeChatPayInfo>\n" +
|
||||
" <GoodsInfo>\n" +
|
||||
" <ProductId><![CDATA[product_001]]></ProductId>\n" +
|
||||
" <Quantity>2</Quantity>\n" +
|
||||
" </GoodsInfo>\n" +
|
||||
" <RetryTimes>0</RetryTimes>\n" +
|
||||
"</xml>";
|
||||
|
||||
WxMaMessage msg = WxMaMessage.fromXml(xml);
|
||||
|
||||
checkXPayGoodsDeliverNotifyMessage(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 个人主体虚拟支付发货通知事件 xpay_goods_deliver_notify 测试用例(JSON格式)。
|
||||
*/
|
||||
@Test
|
||||
public void testXPayGoodsDeliverNotifyFromJson() {
|
||||
String json = "{\n" +
|
||||
" \"ToUserName\": \"gh_abcdefg\",\n" +
|
||||
" \"FromUserName\": \"oABCDEFG\",\n" +
|
||||
" \"CreateTime\": 1700000000,\n" +
|
||||
" \"MsgType\": \"event\",\n" +
|
||||
" \"Event\": \"xpay_goods_deliver_notify\",\n" +
|
||||
" \"OpenId\": \"oABCDEFG\",\n" +
|
||||
" \"OutTradeNo\": \"order12345\",\n" +
|
||||
" \"WeChatPayInfo\": {\n" +
|
||||
" \"MchOrderNo\": \"wx_order_123\"\n" +
|
||||
" },\n" +
|
||||
" \"GoodsInfo\": {\n" +
|
||||
" \"ProductId\": \"product_001\",\n" +
|
||||
" \"Quantity\": 2\n" +
|
||||
" },\n" +
|
||||
" \"RetryTimes\": 0\n" +
|
||||
"}";
|
||||
|
||||
WxMaMessage msg = WxMaMessage.fromJson(json);
|
||||
checkXPayGoodsDeliverNotifyMessage(msg);
|
||||
}
|
||||
|
||||
private void checkXPayGoodsDeliverNotifyMessage(WxMaMessage msg) {
|
||||
assertEquals(msg.getToUser(), "gh_abcdefg");
|
||||
assertEquals(msg.getFromUser(), "oABCDEFG");
|
||||
assertEquals(msg.getCreateTime(), new Integer(1700000000));
|
||||
assertEquals(msg.getMsgType(), WxConsts.XmlMsgType.EVENT);
|
||||
assertEquals(msg.getEvent(), WxMaConstants.XPayNotifyEvent.GOODS_DELIVER);
|
||||
assertEquals(msg.getOpenId(), "oABCDEFG");
|
||||
assertEquals(msg.getOutTradeNo(), "order12345");
|
||||
assertNotNull(msg.getWeChatPayInfo());
|
||||
assertEquals(msg.getWeChatPayInfo().getMchOrderNo(), "wx_order_123");
|
||||
assertNotNull(msg.getGoodsInfo());
|
||||
assertEquals(msg.getGoodsInfo().getProductId(), "product_001");
|
||||
assertEquals(msg.getGoodsInfo().getQuantity(), new Integer(2));
|
||||
assertEquals(msg.getRetryTimes(), new Integer(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* 虚拟支付投诉推送事件 xpay_complaint_notify 测试用例(XML格式)
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package cn.binarywang.wx.miniapp.bean.xpay;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.api.impl.WxMaXPayServiceImpl;
|
||||
import cn.binarywang.wx.miniapp.constant.WxMaConstants;
|
||||
import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* 验证个人主体虚拟支付调起 wx.requestVirtualPayment 所需参数。
|
||||
*/
|
||||
public class WxMaXPayRequestVirtualPaymentTest {
|
||||
|
||||
@Test
|
||||
public void testCreatePayData() {
|
||||
WxMaXPayRequestVirtualPaymentRequest request = WxMaXPayRequestVirtualPaymentRequest.builder()
|
||||
.offerId("1450019686")
|
||||
.buyQuantity(1)
|
||||
.env(0)
|
||||
.currencyType(WxMaConstants.XPayCurrencyType.CNY)
|
||||
.productId("product_001")
|
||||
.goodsPrice(100)
|
||||
.outTradeNo("order12345")
|
||||
.attach("attach中文")
|
||||
.build();
|
||||
WxMaXPaySigParams sigParams = WxMaXPaySigParams.builder()
|
||||
.appKey("app_key_123")
|
||||
.sessionKey("session_key_123")
|
||||
.build();
|
||||
|
||||
WxMaXPayRequestVirtualPaymentData payData = request.createPayData(sigParams);
|
||||
|
||||
assertEquals(payData.getMode(), WxMaConstants.XPayPaymentMode.GOODS);
|
||||
assertEquals(payData.getSignData(),
|
||||
"{\"offerId\":\"1450019686\",\"buyQuantity\":1,\"env\":0,\"currencyType\":\"CNY\","
|
||||
+ "\"productId\":\"product_001\",\"goodsPrice\":100,\"outTradeNo\":\"order12345\","
|
||||
+ "\"attach\":\"attach中文\"}");
|
||||
assertEquals(payData.getPaySig(), "52b0abda3c933b0273d328b5c5102ee9ab9249309474ddcdf5e9ce0f80b23532");
|
||||
assertEquals(payData.getSignature(), "602f76d9cadf36c232f7f6c1faa5fe295b0f955d188049997d0df699c0619c86");
|
||||
|
||||
JsonObject jsonObject = WxMaGsonBuilder.create().fromJson(payData.toJson(), JsonObject.class);
|
||||
assertEquals(jsonObject.get("mode").getAsString(), WxMaConstants.XPayPaymentMode.GOODS);
|
||||
assertEquals(jsonObject.get("paySig").getAsString(), payData.getPaySig());
|
||||
assertEquals(jsonObject.get("signature").getAsString(), payData.getSignature());
|
||||
assertEquals(jsonObject.get("signData").getAsString(), payData.getSignData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatePayDataByService() {
|
||||
WxMaXPayRequestVirtualPaymentRequest request = WxMaXPayRequestVirtualPaymentRequest.builder()
|
||||
.offerId("1450019686")
|
||||
.buyQuantity(1)
|
||||
.env(0)
|
||||
.currencyType(WxMaConstants.XPayCurrencyType.CNY)
|
||||
.productId("product_001")
|
||||
.goodsPrice(100)
|
||||
.outTradeNo("order12345")
|
||||
.attach("attach中文")
|
||||
.build();
|
||||
WxMaXPaySigParams sigParams = WxMaXPaySigParams.builder()
|
||||
.appKey("app_key_123")
|
||||
.sessionKey("session_key_123")
|
||||
.build();
|
||||
|
||||
WxMaXPayRequestVirtualPaymentData payData = new WxMaXPayServiceImpl(mock(WxMaService.class))
|
||||
.createRequestVirtualPaymentData(request, sigParams);
|
||||
|
||||
assertEquals(payData.getMode(), WxMaConstants.XPayPaymentMode.GOODS);
|
||||
assertEquals(payData.getPaySig(), "52b0abda3c933b0273d328b5c5102ee9ab9249309474ddcdf5e9ce0f80b23532");
|
||||
assertEquals(payData.getSignature(), "602f76d9cadf36c232f7f6c1faa5fe295b0f955d188049997d0df699c0619c86");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user