mirror of
https://gitee.com/egzosn/pay-java-parent.git
synced 2026-05-22 18:11:39 +08:00
微信V3实现合单支付
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
package com.egzosn.pay.wx.v3.api;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.egzosn.pay.common.bean.CloseOrder;
|
||||
import com.egzosn.pay.common.bean.Order;
|
||||
import com.egzosn.pay.common.bean.OrderParaStructure;
|
||||
import com.egzosn.pay.common.bean.PayMessage;
|
||||
import com.egzosn.pay.common.bean.PayOrder;
|
||||
import com.egzosn.pay.common.bean.result.PayException;
|
||||
import com.egzosn.pay.common.exception.PayErrorException;
|
||||
import com.egzosn.pay.common.http.HttpConfigStorage;
|
||||
import com.egzosn.pay.common.util.DateUtils;
|
||||
import com.egzosn.pay.common.util.MapGen;
|
||||
import com.egzosn.pay.common.util.str.StringUtils;
|
||||
import com.egzosn.pay.wx.v3.bean.WxTransactionType;
|
||||
import com.egzosn.pay.wx.v3.bean.combine.CombinePayMessage;
|
||||
import com.egzosn.pay.wx.v3.utils.WxConst;
|
||||
|
||||
/**
|
||||
* 微信合单支付服务
|
||||
*
|
||||
* @author egan
|
||||
* <pre>
|
||||
* email egzosn@gmail.com
|
||||
* date 2016-5-18 14:09:01
|
||||
* </pre>
|
||||
*/
|
||||
public class WxCombinePayService extends WxPayService {
|
||||
|
||||
/**
|
||||
* 创建支付服务
|
||||
*
|
||||
* @param payConfigStorage 微信对应的支付配置
|
||||
*/
|
||||
public WxCombinePayService(WxPayConfigStorage payConfigStorage) {
|
||||
super(payConfigStorage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建支付服务
|
||||
*
|
||||
* @param payConfigStorage 微信对应的支付配置
|
||||
* @param configStorage 微信对应的网络配置,包含代理配置、ssl证书配置
|
||||
*/
|
||||
public WxCombinePayService(WxPayConfigStorage payConfigStorage, HttpConfigStorage configStorage) {
|
||||
super(payConfigStorage, configStorage);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取公共参数
|
||||
*
|
||||
* @return 公共参数
|
||||
*/
|
||||
public Map<String, Object> getPublicParameters() {
|
||||
Map<String, Object> parameters = new LinkedHashMap<>();
|
||||
parameters.put(WxConst.COMBINE_APPID, payConfigStorage.getAppId());
|
||||
parameters.put(WxConst.COMBINE_MCH_ID, payConfigStorage.getMchId());
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化通知URL必须为直接可访问的URL,不允许携带查询串,要求必须为https地址。
|
||||
*
|
||||
* @param parameters 订单参数
|
||||
* @param order 订单信息
|
||||
* @return 订单参数
|
||||
*/
|
||||
public void initNotifyUrl(Map<String, Object> parameters, Order order) {
|
||||
OrderParaStructure.loadParameters(parameters, WxConst.NOTIFY_URL, payConfigStorage.getNotifyUrl());
|
||||
OrderParaStructure.loadParameters(parameters, WxConst.NOTIFY_URL, order);
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信统一下单接口
|
||||
*
|
||||
* @param order 支付订单集
|
||||
* @return 下单结果
|
||||
*/
|
||||
public JSONObject unifiedOrder(PayOrder order) {
|
||||
|
||||
//统一下单
|
||||
Map<String, Object> parameters = getPublicParameters();
|
||||
|
||||
// 订单号
|
||||
parameters.put(WxConst.COMBINE_OUT_TRADE_NO, order.getOutTradeNo());
|
||||
|
||||
OrderParaStructure.loadDateParameters(parameters, WxConst.TIME_START, order, DateUtils.YYYY_MM_DD_T_HH_MM_SS);
|
||||
OrderParaStructure.loadDateParameters(parameters, WxConst.TIME_EXPIRE, order, DateUtils.YYYY_MM_DD_T_HH_MM_SS);
|
||||
initNotifyUrl(parameters, order);
|
||||
//支付场景描述
|
||||
OrderParaStructure.loadParameters(parameters, WxConst.SCENE_INFO, order);
|
||||
//子单信息 最多支持子单条数:50
|
||||
OrderParaStructure.loadParameters(parameters, WxConst.SUB_ORDERS, order);
|
||||
//支付者信息
|
||||
if (StringUtils.isNotEmpty(order.getOpenid())) {
|
||||
parameters.put("combine_payer_info", new MapGen<>("openid", order.getOpenid()).getAttr());
|
||||
}
|
||||
|
||||
return getAssistService().doExecute(parameters, order);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 交易查询接口
|
||||
*
|
||||
* @param transactionId 微信支付平台订单号
|
||||
* @param outTradeNo 商户单号
|
||||
* @return 返回查询回来的结果集,支付方原值返回
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> query(String transactionId, String outTradeNo) {
|
||||
return getAssistService().doExecute("", WxTransactionType.COMBINE_TRANSACTION, outTradeNo);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 交易关闭接口
|
||||
*
|
||||
* @param transactionId 支付平台订单号
|
||||
* @param outTradeNo 商户单号
|
||||
* @return 返回支付方交易关闭后的结果
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> close(String transactionId, String outTradeNo) {
|
||||
throw new PayErrorException(new PayException("failure", "合单关闭必须要有子单"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 交易关闭接口
|
||||
*
|
||||
* @param closeOrder 关闭订单
|
||||
* @return 返回支付方交易关闭后的结果
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> close(CloseOrder closeOrder) {
|
||||
Map<String, Object> parameters = new MapGen<String, Object>(WxConst.COMBINE_APPID, payConfigStorage.getAppId())
|
||||
.keyValue(WxConst.SUB_ORDERS, closeOrder.getAttr(WxConst.SUB_ORDERS))
|
||||
.getAttr();
|
||||
String requestBody = JSON.toJSONString(parameters, SerializerFeature.WriteMapNullValue);
|
||||
return getAssistService().doExecute(requestBody, WxTransactionType.COMBINE_CLOSE, closeOrder.getOutTradeNo());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建消息
|
||||
*
|
||||
* @param message 支付平台返回的消息
|
||||
* @return 支付消息对象
|
||||
*/
|
||||
@Override
|
||||
public PayMessage createMessage(Map<String, Object> message) {
|
||||
return CombinePayMessage.create(message);
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.egzosn.pay.common.api.BasePayService;
|
||||
import com.egzosn.pay.common.bean.BillType;
|
||||
import com.egzosn.pay.common.bean.CloseOrder;
|
||||
import com.egzosn.pay.common.bean.CurType;
|
||||
import com.egzosn.pay.common.bean.MethodType;
|
||||
import com.egzosn.pay.common.bean.NoticeParams;
|
||||
@@ -81,27 +82,13 @@ public class WxPayService extends BasePayService<WxPayConfigStorage> {
|
||||
/**
|
||||
* 辅助api
|
||||
*/
|
||||
private volatile WxPayAssistService wxPayAssistService;
|
||||
private volatile WxPayAssistService assistService;
|
||||
|
||||
/**
|
||||
* 微信参数构造器
|
||||
*/
|
||||
private volatile WxParameterStructure wxParameterStructure;
|
||||
|
||||
|
||||
public WxPayAssistService getAssistService() {
|
||||
if (null == wxPayAssistService) {
|
||||
wxPayAssistService = new DefaultWxPayAssistService(this);
|
||||
//在这预先进行初始化
|
||||
wxPayAssistService.refreshCertificate();
|
||||
}
|
||||
return wxPayAssistService;
|
||||
}
|
||||
|
||||
public void setAssistService(WxPayAssistService wxPayAssistService) {
|
||||
this.wxPayAssistService = wxPayAssistService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建支付服务
|
||||
*
|
||||
@@ -123,26 +110,24 @@ public class WxPayService extends BasePayService<WxPayConfigStorage> {
|
||||
|
||||
|
||||
/**
|
||||
* 初始化之后执行
|
||||
* 辅助api
|
||||
* @return 辅助api
|
||||
*/
|
||||
@Override
|
||||
protected void initAfter() {
|
||||
new Thread(() -> {
|
||||
payConfigStorage.loadCertEnvironment();
|
||||
wxParameterStructure = new WxParameterStructure(payConfigStorage);
|
||||
public WxPayAssistService getAssistService() {
|
||||
if (null == assistService) {
|
||||
assistService = new DefaultWxPayAssistService(this);
|
||||
//在这预先进行初始化
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
|
||||
}
|
||||
getAssistService();
|
||||
}).start();
|
||||
|
||||
|
||||
assistService.refreshCertificate();
|
||||
}
|
||||
return assistService;
|
||||
}
|
||||
|
||||
public void setAssistService(WxPayAssistService assistService) {
|
||||
this.assistService = assistService;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 设置api服务器地址
|
||||
*
|
||||
@@ -154,6 +139,14 @@ public class WxPayService extends BasePayService<WxPayConfigStorage> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getApiServerUrl() {
|
||||
return apiServerUrl;
|
||||
}
|
||||
|
||||
public WxParameterStructure getWxParameterStructure() {
|
||||
return wxParameterStructure;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据交易类型获取url
|
||||
*
|
||||
@@ -323,6 +316,7 @@ public class WxPayService extends BasePayService<WxPayConfigStorage> {
|
||||
* @param is 请求流
|
||||
* @return 获得回调的请求参数
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public Map<String, Object> getParameter2Map(Map<String, String[]> parameterMap, InputStream is) {
|
||||
throw new PayErrorException(new WxPayError(FAILURE, "微信V3不支持方式"));
|
||||
@@ -350,7 +344,7 @@ public class WxPayService extends BasePayService<WxPayConfigStorage> {
|
||||
noticeParams.setBody(JSON.parseObject(data));
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error("获取回调参数异常", e);
|
||||
throw new PayErrorException(new WxPayError(FAILURE, "获取回调参数异常"), e);
|
||||
}
|
||||
Map<String, List<String>> headers = new HashMap<>();
|
||||
Enumeration<String> headerNames = request.getHeaderNames();
|
||||
@@ -457,8 +451,20 @@ public class WxPayService extends BasePayService<WxPayConfigStorage> {
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> close(String transactionId, String outTradeNo) {
|
||||
return close(new CloseOrder(outTradeNo));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 交易关闭接口
|
||||
*
|
||||
* @param closeOrder 关闭订单
|
||||
* @return 返回支付方交易关闭后的结果
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> close(CloseOrder closeOrder) {
|
||||
String parameters = wxParameterStructure.getSpParameters();
|
||||
return getAssistService().doExecute(parameters, WxTransactionType.CLOSE, outTradeNo);
|
||||
return getAssistService().doExecute(parameters, WxTransactionType.CLOSE, closeOrder.getOutTradeNo());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,11 +25,14 @@ public enum WxTransactionType implements TransactionType {
|
||||
/**
|
||||
* 获取证书.
|
||||
*/
|
||||
CERT("certificates", MethodType.GET),
|
||||
CERT("/v3/certificates", MethodType.GET),
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//以下为直连与服务商支付方式
|
||||
/**
|
||||
* 公众号支付
|
||||
* 微信公众号支付或者小程序支付
|
||||
*/
|
||||
JSAPI("pay{partner}/transactions/jsapi", MethodType.POST) {
|
||||
JSAPI("/v3/pay{partner}/transactions/jsapi", MethodType.POST) {
|
||||
@Override
|
||||
public void setAttribute(Map<String, Object> parameters, PayOrder order) {
|
||||
String key = parameters.containsKey("sub_mchid") ? "sub_openid" : "openid";
|
||||
@@ -40,15 +43,15 @@ public enum WxTransactionType implements TransactionType {
|
||||
/**
|
||||
* 二维码支付
|
||||
*/
|
||||
NATIVE("pay{partner}/transactions/native", MethodType.POST, true),
|
||||
NATIVE("/v3/pay{partner}/transactions/native", MethodType.POST, true),
|
||||
/**
|
||||
* 移动支付
|
||||
*/
|
||||
APP("pay{partner}/transactions/app", MethodType.POST),
|
||||
APP("/v3/pay{partner}/transactions/app", MethodType.POST),
|
||||
/**
|
||||
* H5支付
|
||||
*/
|
||||
H5("pay{partner}/transactions/h5", MethodType.POST, true) {
|
||||
H5("/v3/pay{partner}/transactions/h5", MethodType.POST, true) {
|
||||
@Override
|
||||
public void setAttribute(Map<String, Object> parameters, PayOrder order) {
|
||||
Object sceneInfoObj = parameters.get(WxConst.SCENE_INFO);
|
||||
@@ -79,7 +82,7 @@ public enum WxTransactionType implements TransactionType {
|
||||
* 兼容 后期会抛弃
|
||||
*/
|
||||
@Deprecated
|
||||
MWEB("pay{partner}/transactions/h5", MethodType.POST, true) {
|
||||
MWEB("/v3/pay{partner}/transactions/h5", MethodType.POST, true) {
|
||||
@Override
|
||||
public void setAttribute(Map<String, Object> parameters, PayOrder order) {
|
||||
H5.setAttribute(parameters, order);
|
||||
@@ -91,35 +94,64 @@ public enum WxTransactionType implements TransactionType {
|
||||
* 查询订单
|
||||
* 兼容V2的方式,通过入参来决定
|
||||
*/
|
||||
QUERY("pay{partner}/transactions/", MethodType.GET),
|
||||
QUERY("/v3/pay{partner}/transactions/", MethodType.GET),
|
||||
/**
|
||||
* 微信支付订单号查询
|
||||
*/
|
||||
QUERY_TRANSACTION_ID("pay{partner}/transactions/id/{transaction_id}", MethodType.GET),
|
||||
QUERY_TRANSACTION_ID("/v3/pay{partner}/transactions/id/{transaction_id}", MethodType.GET),
|
||||
/**
|
||||
* 商户订单号查询
|
||||
*/
|
||||
QUERY_OUT_TRADE_NO("pay{partner}/transactions/out-trade-no/{out_trade_no}", MethodType.GET),
|
||||
QUERY_OUT_TRADE_NO("/v3/pay{partner}/transactions/out-trade-no/{out_trade_no}", MethodType.GET),
|
||||
/**
|
||||
* 关闭订单
|
||||
*/
|
||||
CLOSE("pay{partner}/transactions/out-trade-no/{out_trade_no}/close", MethodType.POST),
|
||||
CLOSE("/v3/pay{partner}/transactions/out-trade-no/{out_trade_no}/close", MethodType.POST),
|
||||
/**
|
||||
* 申请退款
|
||||
*/
|
||||
REFUND("refund/domestic/refunds", MethodType.POST),
|
||||
REFUND("/v3/refund/domestic/refunds", MethodType.POST),
|
||||
/**
|
||||
* 查询退款
|
||||
*/
|
||||
REFUND_QUERY("refund/domestic/refunds/{out_refund_no}", MethodType.GET),
|
||||
REFUND_QUERY("/v3/refund/domestic/refunds/{out_refund_no}", MethodType.GET),
|
||||
/**
|
||||
* 申请交易账单
|
||||
*/
|
||||
TRADE_BILL("bill/tradebill", MethodType.GET),
|
||||
TRADE_BILL("/v3/bill/tradebill", MethodType.GET),
|
||||
/**
|
||||
* 申请资金账单
|
||||
*/
|
||||
FUND_FLOW_BILL("bill/fundflowbill", MethodType.GET)
|
||||
FUND_FLOW_BILL("/v3/bill/fundflowbill", MethodType.GET),
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//以下为合并支付
|
||||
/**
|
||||
* 合单下单-APP支付API.
|
||||
*/
|
||||
COMBINE_APP("/v3/combine-transactions/app", MethodType.POST),
|
||||
|
||||
/**
|
||||
* 合单下单-微信公众号支付或者小程序支付.
|
||||
*/
|
||||
COMBINE_JSAPI("/v3/combine-transactions/jsapi", MethodType.POST),
|
||||
/**
|
||||
* 合单下单-H5支付API.
|
||||
*/
|
||||
COMBINE_H5("/v3/combine-transactions/h5", MethodType.POST, true),
|
||||
/**
|
||||
* 合单下单-Native支付API.
|
||||
*/
|
||||
COMBINE_NATIVE("/v3/combine-transactions/native", MethodType.POST, true),
|
||||
/**
|
||||
* 合单查询订单API.
|
||||
*/
|
||||
COMBINE_TRANSACTION("/v3/combine-transactions/out-trade-no/{combine_out_trade_no}", MethodType.GET),
|
||||
|
||||
/**
|
||||
* 合单关闭订单API.
|
||||
*/
|
||||
COMBINE_CLOSE("/v3/combine-transactions/out-trade-no/{combine_out_trade_no}/close", MethodType.POST),
|
||||
;
|
||||
|
||||
WxTransactionType(String type, MethodType method) {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.egzosn.pay.wx.v3.bean.combine;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.egzosn.pay.wx.v3.bean.response.order.Amount;
|
||||
|
||||
/**
|
||||
* 合单支付订单金额信息.
|
||||
*
|
||||
* @author Egan
|
||||
* <pre>
|
||||
* email egan@egzosn.com
|
||||
* date 2021/10/5
|
||||
* </pre>
|
||||
*/
|
||||
public class CombineAmount extends Amount {
|
||||
|
||||
/**
|
||||
* 子单金额,单位为分,必填
|
||||
* 境外场景下,标价金额要超过商户结算币种的最小单位金额,例如结算币种为美元,则标价金额必须大于1美分
|
||||
*/
|
||||
@JSONField(name = "total_amount")
|
||||
private Integer totalAmount;
|
||||
|
||||
|
||||
public Integer getTotalAmount() {
|
||||
return totalAmount;
|
||||
}
|
||||
|
||||
public void setTotalAmount(Integer totalAmount) {
|
||||
this.totalAmount = totalAmount;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.egzosn.pay.wx.v3.bean.combine;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.egzosn.pay.common.bean.CloseOrder;
|
||||
import com.egzosn.pay.wx.v3.utils.WxConst;
|
||||
|
||||
/**
|
||||
* 微信合单关闭订单
|
||||
* @author Egan
|
||||
* @email egan@egzosn.com
|
||||
* @date 2021/10/6
|
||||
*/
|
||||
public class CombineCloseOrder extends CloseOrder {
|
||||
|
||||
/**
|
||||
* 子单信息,必填,最多50单
|
||||
*/
|
||||
private List<CombineSubOrder> subOrders;
|
||||
|
||||
|
||||
public List<CombineSubOrder> getSubOrders() {
|
||||
return subOrders;
|
||||
}
|
||||
|
||||
public void setSubOrders(List<CombineSubOrder> subOrders) {
|
||||
this.subOrders = subOrders;
|
||||
addAttr(WxConst.SUB_ORDERS, subOrders);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package com.egzosn.pay.wx.v3.bean.combine;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.egzosn.pay.common.bean.PayMessage;
|
||||
import com.egzosn.pay.wx.v3.bean.order.SceneInfo;
|
||||
import com.egzosn.pay.wx.v3.bean.response.order.Payer;
|
||||
import com.egzosn.pay.wx.v3.utils.WxConst;
|
||||
|
||||
/**
|
||||
* 合单支付回调消息,兼容退款回调
|
||||
* @author Egan
|
||||
* <pre>
|
||||
* email egan@egzosn.com
|
||||
* date 2021/10/4
|
||||
* </pre>
|
||||
*/
|
||||
public class CombinePayMessage extends PayMessage {
|
||||
|
||||
|
||||
/**
|
||||
* 合单商户appid,即合单发起方的appid
|
||||
*/
|
||||
@JSONField(name = WxConst.COMBINE_APPID)
|
||||
private String combineAppid;
|
||||
|
||||
/**
|
||||
* 合单商户号.
|
||||
*/
|
||||
@JSONField(name = WxConst.COMBINE_MCH_ID)
|
||||
private String combineMchid;
|
||||
|
||||
/**
|
||||
* 合单商户订单号.
|
||||
*/
|
||||
@JSONField(name = WxConst.COMBINE_OUT_TRADE_NO)
|
||||
private String combineOutTradeNo;
|
||||
|
||||
|
||||
/**
|
||||
* 支付者信息
|
||||
*/
|
||||
@JSONField(name = "combine_payer_info")
|
||||
private Payer combinePayerInfo;
|
||||
|
||||
/**
|
||||
* 场景信息,合单支付回调只返回device_id
|
||||
*/
|
||||
@JSONField(name = WxConst.SCENE_INFO)
|
||||
private SceneInfo sceneInfo;
|
||||
|
||||
/**
|
||||
* 合单支付回调子订单.
|
||||
*/
|
||||
@JSONField(name = WxConst.SUB_ORDERS)
|
||||
private List<CombineSubOrder> subOrders;
|
||||
|
||||
public String getCombineAppid() {
|
||||
return combineAppid;
|
||||
}
|
||||
|
||||
public void setCombineAppid(String combineAppid) {
|
||||
this.combineAppid = combineAppid;
|
||||
}
|
||||
|
||||
public String getCombineMchid() {
|
||||
return combineMchid;
|
||||
}
|
||||
|
||||
public void setCombineMchid(String combineMchid) {
|
||||
this.combineMchid = combineMchid;
|
||||
}
|
||||
|
||||
public String getCombineOutTradeNo() {
|
||||
return combineOutTradeNo;
|
||||
}
|
||||
|
||||
public void setCombineOutTradeNo(String combineOutTradeNo) {
|
||||
this.combineOutTradeNo = combineOutTradeNo;
|
||||
}
|
||||
|
||||
public Payer getCombinePayerInfo() {
|
||||
return combinePayerInfo;
|
||||
}
|
||||
|
||||
public void setCombinePayerInfo(Payer combinePayerInfo) {
|
||||
this.combinePayerInfo = combinePayerInfo;
|
||||
}
|
||||
|
||||
public SceneInfo getSceneInfo() {
|
||||
return sceneInfo;
|
||||
}
|
||||
|
||||
public void setSceneInfo(SceneInfo sceneInfo) {
|
||||
this.sceneInfo = sceneInfo;
|
||||
}
|
||||
|
||||
public List<CombineSubOrder> getSubOrders() {
|
||||
return subOrders;
|
||||
}
|
||||
|
||||
public void setSubOrders(List<CombineSubOrder> subOrders) {
|
||||
this.subOrders = subOrders;
|
||||
}
|
||||
|
||||
public static final CombinePayMessage create(Map<String, Object> message) {
|
||||
CombinePayMessage payMessage = new JSONObject(message).toJavaObject(CombinePayMessage.class);
|
||||
// payMessage.setPayType("");
|
||||
payMessage.setPayMessage(message);
|
||||
return payMessage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.egzosn.pay.wx.v3.bean.combine;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.egzosn.pay.common.bean.PayOrder;
|
||||
import com.egzosn.pay.wx.v3.bean.order.SceneInfo;
|
||||
import com.egzosn.pay.wx.v3.bean.order.SubOrder;
|
||||
import com.egzosn.pay.wx.v3.utils.WxConst;
|
||||
|
||||
/**
|
||||
* 合并支付订单
|
||||
*
|
||||
* @author Egan
|
||||
* <pre>
|
||||
* email egan@egzosn.com
|
||||
* date 2021/10/5
|
||||
* </pre>
|
||||
*/
|
||||
public class CombinePayOrder extends PayOrder {
|
||||
|
||||
/**
|
||||
* 子单信息,必填,最多50单
|
||||
*/
|
||||
private List<SubOrder> subOrders;
|
||||
/**
|
||||
* 交易起始时间,选填
|
||||
*/
|
||||
private Date timeStart;
|
||||
|
||||
/**
|
||||
* 交易结束时间,选填
|
||||
*/
|
||||
private Date timeExpire;
|
||||
|
||||
/**
|
||||
* 支付场景信息描述
|
||||
*/
|
||||
private SceneInfo sceneInfo;
|
||||
|
||||
public List<SubOrder> getSubOrders() {
|
||||
return subOrders;
|
||||
}
|
||||
|
||||
public void setSubOrders(List<SubOrder> subOrders) {
|
||||
this.subOrders = subOrders;
|
||||
addAttr(WxConst.SUB_ORDERS, subOrders);
|
||||
}
|
||||
|
||||
public Date getTimeStart() {
|
||||
return timeStart;
|
||||
}
|
||||
|
||||
public void setTimeStart(Date timeStart) {
|
||||
this.timeStart = timeStart;
|
||||
addAttr(WxConst.TIME_START, timeStart);
|
||||
}
|
||||
|
||||
public Date getTimeExpire() {
|
||||
return timeExpire;
|
||||
}
|
||||
|
||||
public void setTimeExpire(Date timeExpire) {
|
||||
this.timeExpire = timeExpire;
|
||||
addAttr(WxConst.TIME_EXPIRE, timeExpire);
|
||||
}
|
||||
|
||||
/**
|
||||
* 合单支付总订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一 。
|
||||
* @return 合单支付总订单号
|
||||
*/
|
||||
public String getCombineOutTradeNo() {
|
||||
return getOutTradeNo();
|
||||
}
|
||||
|
||||
/**
|
||||
* 合单支付总订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一 。
|
||||
* @param combineOutTradeNo 合单支付总订单号
|
||||
*/
|
||||
public void setCombineOutTradeNo(String combineOutTradeNo) {
|
||||
setOutTradeNo(combineOutTradeNo);
|
||||
}
|
||||
|
||||
public SceneInfo getSceneInfo() {
|
||||
return sceneInfo;
|
||||
}
|
||||
|
||||
public void setSceneInfo(SceneInfo sceneInfo) {
|
||||
this.sceneInfo = sceneInfo;
|
||||
addAttr(WxConst.SCENE_INFO, sceneInfo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.egzosn.pay.wx.v3.bean.combine;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
|
||||
/**
|
||||
* 子单信息,最多50单.
|
||||
* @author Egan
|
||||
* <pre>
|
||||
* email egan@egzosn.com
|
||||
* date 2021/10/5
|
||||
* </pre>
|
||||
*/
|
||||
public class CombineSubOrder {
|
||||
|
||||
/**
|
||||
* 子单发起方商户号,必填,必须与发起方appid有绑定关系。
|
||||
*/
|
||||
private String mchid;
|
||||
|
||||
/**
|
||||
* 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
|
||||
* 示例值:20150806125346
|
||||
*/
|
||||
@JSONField(name = "out_trade_no")
|
||||
private String outTradeNo;
|
||||
|
||||
public String getMchid() {
|
||||
return mchid;
|
||||
}
|
||||
|
||||
public void setMchid(String mchid) {
|
||||
this.mchid = mchid;
|
||||
}
|
||||
|
||||
public String getOutTradeNo() {
|
||||
return outTradeNo;
|
||||
}
|
||||
|
||||
public void setOutTradeNo(String outTradeNo) {
|
||||
this.outTradeNo = outTradeNo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.egzosn.pay.wx.v3.bean.order;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
|
||||
/**
|
||||
* 结算信息
|
||||
* @author Egan
|
||||
* <pre>
|
||||
* email egan@egzosn.com
|
||||
* date 2021/10/5
|
||||
* </pre>
|
||||
*/
|
||||
public class SettleInfo {
|
||||
/**
|
||||
* 是否指定分账,枚举值
|
||||
* true:是
|
||||
* false:否
|
||||
* 示例值:true
|
||||
*/
|
||||
@JSONField(name = "profit_sharing")
|
||||
private Boolean profitSharing;
|
||||
/**
|
||||
* 补差金额
|
||||
* SettleInfo.profit_sharing为true时,该金额才生效。
|
||||
* 注意:单笔订单最高补差金额为5000元
|
||||
*/
|
||||
@JSONField(name = "subsidy_amount")
|
||||
private Integer subsidyAmount;
|
||||
|
||||
public Boolean getProfitSharing() {
|
||||
return profitSharing;
|
||||
}
|
||||
|
||||
public void setProfitSharing(Boolean profitSharing) {
|
||||
this.profitSharing = profitSharing;
|
||||
}
|
||||
|
||||
public Integer getSubsidyAmount() {
|
||||
return subsidyAmount;
|
||||
}
|
||||
|
||||
public void setSubsidyAmount(Integer subsidyAmount) {
|
||||
this.subsidyAmount = subsidyAmount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
package com.egzosn.pay.wx.v3.bean.order;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.egzosn.pay.wx.v3.bean.WxTransactionType;
|
||||
import com.egzosn.pay.wx.v3.bean.combine.CombineAmount;
|
||||
import com.egzosn.pay.wx.v3.bean.combine.CombineSubOrder;
|
||||
import com.egzosn.pay.wx.v3.bean.response.order.PromotionDetail;
|
||||
import com.egzosn.pay.wx.v3.bean.response.order.TradeState;
|
||||
|
||||
/**
|
||||
* 子单信息,最多50单.
|
||||
*
|
||||
* @author Egan
|
||||
* <pre>
|
||||
* email egan@egzosn.com
|
||||
* date 2021/10/5
|
||||
* </pre>
|
||||
*/
|
||||
public class SubOrder extends CombineSubOrder {
|
||||
/**
|
||||
* 合单支付订单金额信息,必填。
|
||||
*/
|
||||
private CombineAmount amount;
|
||||
|
||||
|
||||
/**
|
||||
* 商品描述,必填,需传入应用市场上的APP名字-实际商品名称,例如:天天爱消除-游戏充值。
|
||||
*/
|
||||
private String description;
|
||||
|
||||
|
||||
/**
|
||||
* 二级商户商户号,由微信支付生成并下发。
|
||||
* <p>
|
||||
* 服务商子商户的商户号,被合单方。
|
||||
* <p>
|
||||
* 直连商户不用传二级商户号。
|
||||
*/
|
||||
@JSONField(name = "sub_mchid")
|
||||
private String subMchid;
|
||||
|
||||
/**
|
||||
* 结算信息,选填
|
||||
*/
|
||||
@JSONField(name = "settle_info")
|
||||
private SettleInfo settleInfo;
|
||||
|
||||
|
||||
/**
|
||||
* 银行类型,采用字符串类型的银行标识。
|
||||
* 银行标识请参考 <a target= "_blank" href= "https://pay.weixin.qq.com/wiki/doc/apiv3/terms_definition/chapter1_1_3.shtml#part-6">《银行类型对照表》</a>
|
||||
* 示例值:CMC
|
||||
*/
|
||||
@JSONField(name = "bank_type")
|
||||
private String bankType;
|
||||
|
||||
/**
|
||||
* 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用
|
||||
*/
|
||||
private String attach;
|
||||
|
||||
/**
|
||||
* 支付完成时间|| 退款完成时间,遵循rfc3339标准格式,
|
||||
* 格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,
|
||||
* TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
|
||||
* 例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒。
|
||||
* 示例值:2018-06-08T10:34:56+08:00
|
||||
*/
|
||||
@JSONField(name = "success_time", format = "yyyy-MM-dd'T'HH:mm:ssXXX")
|
||||
private Date successTime;
|
||||
|
||||
/**
|
||||
* 交易状态
|
||||
*/
|
||||
@JSONField(name = "trade_state")
|
||||
private TradeState tradeState;
|
||||
|
||||
/**
|
||||
* 交易类型
|
||||
*/
|
||||
@JSONField(name = "trade_type")
|
||||
private WxTransactionType tradeType;
|
||||
|
||||
/**
|
||||
* 微信支付侧订单号
|
||||
*/
|
||||
@JSONField(name = "transaction_id")
|
||||
private String transactionId;
|
||||
|
||||
/**
|
||||
* 优惠功能,子单有核销优惠券时有返回
|
||||
*/
|
||||
@JSONField(name = "promotion_detail")
|
||||
private List<PromotionDetail> promotionDetail;
|
||||
|
||||
public CombineAmount getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(CombineAmount amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
|
||||
public String getSubMchid() {
|
||||
return subMchid;
|
||||
}
|
||||
|
||||
public void setSubMchid(String subMchid) {
|
||||
this.subMchid = subMchid;
|
||||
}
|
||||
|
||||
public SettleInfo getSettleInfo() {
|
||||
return settleInfo;
|
||||
}
|
||||
|
||||
public void setSettleInfo(SettleInfo settleInfo) {
|
||||
this.settleInfo = settleInfo;
|
||||
}
|
||||
|
||||
public String getBankType() {
|
||||
return bankType;
|
||||
}
|
||||
|
||||
public void setBankType(String bankType) {
|
||||
this.bankType = bankType;
|
||||
}
|
||||
|
||||
public String getAttach() {
|
||||
return attach;
|
||||
}
|
||||
|
||||
public void setAttach(String attach) {
|
||||
this.attach = attach;
|
||||
}
|
||||
|
||||
public Date getSuccessTime() {
|
||||
return successTime;
|
||||
}
|
||||
|
||||
public void setSuccessTime(Date successTime) {
|
||||
this.successTime = successTime;
|
||||
}
|
||||
|
||||
public TradeState getTradeState() {
|
||||
return tradeState;
|
||||
}
|
||||
|
||||
public void setTradeState(TradeState tradeState) {
|
||||
this.tradeState = tradeState;
|
||||
}
|
||||
|
||||
public WxTransactionType getTradeType() {
|
||||
return tradeType;
|
||||
}
|
||||
|
||||
public void setTradeType(WxTransactionType tradeType) {
|
||||
this.tradeType = tradeType;
|
||||
}
|
||||
|
||||
public String getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
public void setTransactionId(String transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
|
||||
public List<PromotionDetail> getPromotionDetail() {
|
||||
return promotionDetail;
|
||||
}
|
||||
|
||||
public void setPromotionDetail(List<PromotionDetail> promotionDetail) {
|
||||
this.promotionDetail = promotionDetail;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import com.egzosn.pay.wx.v3.bean.response.order.PromotionDetail;
|
||||
import com.egzosn.pay.wx.v3.bean.response.order.TradeState;
|
||||
|
||||
/**
|
||||
* 支付回调消息
|
||||
* 支付回调消息,兼容退款回调
|
||||
* @author Egan
|
||||
* <pre>
|
||||
* email egan@egzosn.com
|
||||
@@ -99,8 +99,36 @@ public class WxPayMessage extends PayMessage {
|
||||
*/
|
||||
@JSONField(name = "trade_state")
|
||||
private TradeState tradeState;
|
||||
|
||||
|
||||
/**
|
||||
* 商户退款单号
|
||||
*/
|
||||
@JSONField(name = "out_refund_no")
|
||||
private String outRefundNo;
|
||||
/**
|
||||
* 微信退款单号
|
||||
*/
|
||||
@JSONField(name = "refund_id")
|
||||
private String refundId;
|
||||
/**
|
||||
* 退款状态,枚举值:
|
||||
* SUCCESS:退款成功
|
||||
* CLOSE:退款关闭
|
||||
* ABNORMAL:退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往【商户平台—>交易中心】,手动处理此笔退款
|
||||
* 示例值:SUCCESS
|
||||
*/
|
||||
@JSONField(name = "refund_status")
|
||||
private TradeState refundStatus;
|
||||
/**
|
||||
* 退款入账账户
|
||||
* 取当前退款单的退款入账方。
|
||||
* 1、退回银行卡:{银行名称}{卡类型}{卡尾号}
|
||||
* 2、退回支付用户零钱: 支付用户零钱
|
||||
* 3、退还商户: 商户基本账户、商户结算银行账户
|
||||
* 4、退回支付用户零钱通:支付用户零钱通
|
||||
* 示例值:招商银行信用卡0403
|
||||
*/
|
||||
@JSONField(name = "user_received_account")
|
||||
private String userReceivedAccount;
|
||||
/**
|
||||
* 交易状态描述
|
||||
* 示例值:支付成功
|
||||
@@ -121,7 +149,7 @@ public class WxPayMessage extends PayMessage {
|
||||
private String attach;
|
||||
|
||||
/**
|
||||
* 支付完成时间,遵循rfc3339标准格式,
|
||||
* 支付完成时间|| 退款完成时间,遵循rfc3339标准格式,
|
||||
* 格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE,YYYY-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,
|
||||
* TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
|
||||
* 例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒。
|
||||
@@ -301,6 +329,37 @@ public class WxPayMessage extends PayMessage {
|
||||
return BigDecimal.valueOf(getAmount().getTotal());
|
||||
}
|
||||
|
||||
public String getOutRefundNo() {
|
||||
return outRefundNo;
|
||||
}
|
||||
|
||||
public void setOutRefundNo(String outRefundNo) {
|
||||
this.outRefundNo = outRefundNo;
|
||||
}
|
||||
|
||||
public String getRefundId() {
|
||||
return refundId;
|
||||
}
|
||||
|
||||
public void setRefundId(String refundId) {
|
||||
this.refundId = refundId;
|
||||
}
|
||||
|
||||
public TradeState getRefundStatus() {
|
||||
return refundStatus;
|
||||
}
|
||||
|
||||
public void setRefundStatus(TradeState refundStatus) {
|
||||
this.refundStatus = refundStatus;
|
||||
}
|
||||
|
||||
public String getUserReceivedAccount() {
|
||||
return userReceivedAccount;
|
||||
}
|
||||
|
||||
public void setUserReceivedAccount(String userReceivedAccount) {
|
||||
this.userReceivedAccount = userReceivedAccount;
|
||||
}
|
||||
|
||||
public static final WxPayMessage create(Map<String, Object> message) {
|
||||
WxPayMessage payMessage = new JSONObject(message).toJavaObject(WxPayMessage.class);
|
||||
|
||||
@@ -2,25 +2,41 @@ package com.egzosn.pay.wx.v3.bean.response.order;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
|
||||
/**
|
||||
* 回调中的订单金额信息
|
||||
*
|
||||
* @author Egan
|
||||
* <pre>
|
||||
* email egan@egzosn.com
|
||||
* date 2021/10/4
|
||||
* </pre>
|
||||
*/
|
||||
public class Amount extends com.egzosn.pay.wx.v3.bean.order.Amount{
|
||||
public class Amount extends com.egzosn.pay.wx.v3.bean.order.Amount {
|
||||
|
||||
/**
|
||||
* 用户支付金额,单位为分。
|
||||
*/
|
||||
@JSONField(name = "payer_total")
|
||||
private BigDecimal payerTotal;
|
||||
/**
|
||||
* 用户支付币种
|
||||
*/
|
||||
@JSONField(name = "payer_currency")
|
||||
private String payerCurrency;
|
||||
|
||||
/**
|
||||
* 退款金额,单位为分
|
||||
*/
|
||||
private Integer refund;
|
||||
|
||||
/**
|
||||
* 退款给用户的金额,单位为分,不包含所有优惠券金额
|
||||
*/
|
||||
@JSONField(name = "payer_refund")
|
||||
private Integer payerRefund;
|
||||
|
||||
public BigDecimal getPayerTotal() {
|
||||
return payerTotal;
|
||||
}
|
||||
@@ -36,4 +52,20 @@ public class Amount extends com.egzosn.pay.wx.v3.bean.order.Amount{
|
||||
public void setPayerCurrency(String payerCurrency) {
|
||||
this.payerCurrency = payerCurrency;
|
||||
}
|
||||
|
||||
public Integer getRefund() {
|
||||
return refund;
|
||||
}
|
||||
|
||||
public void setRefund(Integer refund) {
|
||||
this.refund = refund;
|
||||
}
|
||||
|
||||
public Integer getPayerRefund() {
|
||||
return payerRefund;
|
||||
}
|
||||
|
||||
public void setPayerRefund(Integer payerRefund) {
|
||||
this.payerRefund = payerRefund;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ package com.egzosn.pay.wx.v3.bean.response.order;
|
||||
public class Payer {
|
||||
/**
|
||||
* 用户在直连商户appid下的唯一标识。
|
||||
* 使用合单appid获取的对应用户openid。是用户在商户appid下的唯一标识。
|
||||
*/
|
||||
private String openid;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package com.egzosn.pay.wx.v3.bean.response.order;
|
||||
|
||||
/**
|
||||
* 微信侧返回交易状态
|
||||
* 微信侧返回交易状态,兼容退款状态
|
||||
*
|
||||
* @author Egan
|
||||
* <pre>
|
||||
* email egan@egzosn.com
|
||||
@@ -11,31 +12,28 @@ package com.egzosn.pay.wx.v3.bean.response.order;
|
||||
public enum TradeState {
|
||||
/**
|
||||
* 支付成功
|
||||
*
|
||||
*
|
||||
* 退款成功
|
||||
*/
|
||||
SUCCESS,
|
||||
/**
|
||||
* 转入退款
|
||||
*
|
||||
*
|
||||
*/
|
||||
REFUND,
|
||||
/**
|
||||
* 未支付
|
||||
*
|
||||
*
|
||||
*/
|
||||
NOTPAY,
|
||||
/**
|
||||
* 已关闭
|
||||
*
|
||||
*
|
||||
* 退款关闭
|
||||
*/
|
||||
CLOSED,
|
||||
/**
|
||||
* 退款异常.
|
||||
*/
|
||||
ABNORMAL,
|
||||
/**
|
||||
* 已撤销(付款码支付)
|
||||
*
|
||||
*/
|
||||
REVOKED,
|
||||
/**
|
||||
@@ -48,7 +46,6 @@ public enum TradeState {
|
||||
PAYERROR,
|
||||
/**
|
||||
* 已接收,等待扣款
|
||||
*
|
||||
*/
|
||||
ACCEPT,
|
||||
}
|
||||
@@ -17,7 +17,7 @@ public final class WxConst {
|
||||
/**
|
||||
* 微信默认请求地址
|
||||
*/
|
||||
public static final String URI = "https://api.mch.weixin.qq.com/v3/";
|
||||
public static final String URI = "https://api.mch.weixin.qq.com";
|
||||
/**
|
||||
* 证书别名
|
||||
*/
|
||||
@@ -31,12 +31,20 @@ public final class WxConst {
|
||||
* 沙箱
|
||||
*/
|
||||
public static final String SANDBOXNEW = "sandboxnew/";
|
||||
public static final String COMBINE = "combine_";
|
||||
public static final String APPID = "appid";
|
||||
|
||||
public static final String COMBINE_APPID = COMBINE + APPID;
|
||||
public static final String MCH_ID = "mchid";
|
||||
public static final String COMBINE_MCH_ID = COMBINE + MCH_ID;
|
||||
public static final String SUB_MCH_ID = "sub_mchid";
|
||||
public static final String SP_MCH_ID = "sp_mchid";
|
||||
public static final String OUT_TRADE_NO = "out_trade_no";
|
||||
public static final String COMBINE_OUT_TRADE_NO = COMBINE + OUT_TRADE_NO;
|
||||
public static final String NOTIFY_URL = "notify_url";
|
||||
public static final String TIME_START = "time_start";
|
||||
public static final String TIME_EXPIRE = "time_expire";
|
||||
public static final String SUB_ORDERS = "sub_orders";
|
||||
|
||||
public static final String TOKEN_PATTERN = "mchid=\"%s\",nonce_str=\"%s\",timestamp=\"%d\",serial_no=\"%s\",signature=\"%s\"";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user