mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-08-24 16:18:51 +08:00
🆕 #3063 【微信支付】增加服务商模式关闭订单的接口
This commit is contained in:
parent
cb7efb79cf
commit
10b1e4db73
@ -0,0 +1,61 @@
|
|||||||
|
package com.github.binarywang.wxpay.bean.request;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务商关闭订单请求对象类
|
||||||
|
* 文档见:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_3.shtml
|
||||||
|
*
|
||||||
|
* @author Guo Shuai
|
||||||
|
* @version 1.0
|
||||||
|
* @date 2023/3/2
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class WxPayPartnerOrderCloseV3Request implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:服务商商户号
|
||||||
|
* 变量名:sp_mchid
|
||||||
|
* 是否必填:是
|
||||||
|
* 类型:string[1,32]
|
||||||
|
* 描述:
|
||||||
|
* 服务商商户号,由微信支付生成并下发。
|
||||||
|
* 示例值:1230000109
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "sp_mchid")
|
||||||
|
private String spMchId;
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:特约商户商户号
|
||||||
|
* 变量名:sp_mchid
|
||||||
|
* 是否必填:是
|
||||||
|
* 类型:string[1,32]
|
||||||
|
* 描述:
|
||||||
|
* 特约商户商户号,由微信支付生成并下发。
|
||||||
|
* 示例值:1230000109
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "sub_mchid")
|
||||||
|
private String subMchId;
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:商户订单号
|
||||||
|
* 变量名:out_trade_no
|
||||||
|
* 是否必填:是
|
||||||
|
* 类型:string[6,32]
|
||||||
|
* 描述:
|
||||||
|
* 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一
|
||||||
|
* 示例值:1217752501201407033233368018
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
private transient String outTradeNo;
|
||||||
|
}
|
@ -21,19 +21,6 @@ import java.util.List;
|
|||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class WxPayPartnerRefundV3Request extends WxPayRefundV3Request implements Serializable {
|
public class WxPayPartnerRefundV3Request extends WxPayRefundV3Request implements Serializable {
|
||||||
private static final long serialVersionUID = -1L;
|
private static final long serialVersionUID = -1L;
|
||||||
/**
|
|
||||||
* <pre>
|
|
||||||
* 字段名:子商户的商户号
|
|
||||||
* 变量名:sub_mchid
|
|
||||||
* 是否必填:是
|
|
||||||
* 类型:string[1, 32]
|
|
||||||
* 描述:
|
|
||||||
* 子商户商户号,由微信支付生成并下发。
|
|
||||||
* 示例值:1230000109
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
@SerializedName(value = "sub_mchid")
|
|
||||||
private String subMchId;
|
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* <pre>
|
||||||
* 字段名:退款资金来源
|
* 字段名:退款资金来源
|
||||||
|
@ -238,6 +238,17 @@ public class WxPayRefundV3Request implements Serializable {
|
|||||||
private Integer refundQuantity;
|
private Integer refundQuantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:子商户的商户号
|
||||||
|
* 变量名:sub_mchid
|
||||||
|
* 是否必填:是
|
||||||
|
* 类型:string[1, 32]
|
||||||
|
* 描述:
|
||||||
|
* 子商户商户号,由微信支付生成并下发。
|
||||||
|
* 示例值:1230000109
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
@SerializedName(value = "sub_mchid")
|
@SerializedName(value = "sub_mchid")
|
||||||
private String subMchid;
|
private String subMchid;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.github.binarywang.wxpay.bean.result;
|
package com.github.binarywang.wxpay.bean.result;
|
||||||
|
|
||||||
|
import com.github.binarywang.wxpay.bean.result.enums.PartnerTradeTypeEnum;
|
||||||
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
|
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
|
||||||
import com.github.binarywang.wxpay.v3.util.SignUtils;
|
import com.github.binarywang.wxpay.v3.util.SignUtils;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
@ -132,4 +133,32 @@ public class WxPayUnifiedOrderV3Result implements Serializable {
|
|||||||
throw new WxRuntimeException("不支持的支付类型");
|
throw new WxRuntimeException("不支持的支付类型");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <T> T getPartnerPayInfo(PartnerTradeTypeEnum tradeType, String appId, String mchId, PrivateKey privateKey) {
|
||||||
|
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||||
|
String nonceStr = SignUtils.genRandomStr();
|
||||||
|
switch (tradeType) {
|
||||||
|
case JSAPI:
|
||||||
|
JsapiResult jsapiResult = new JsapiResult();
|
||||||
|
jsapiResult.setAppId(appId).setTimeStamp(timestamp)
|
||||||
|
.setPackageValue("prepay_id=" + this.prepayId).setNonceStr(nonceStr)
|
||||||
|
//签名类型,默认为RSA,仅支持RSA。
|
||||||
|
.setSignType("RSA").setPaySign(SignUtils.sign(jsapiResult.getSignStr(), privateKey));
|
||||||
|
return (T) jsapiResult;
|
||||||
|
case H5:
|
||||||
|
return (T) this.h5Url;
|
||||||
|
case APP:
|
||||||
|
AppResult appResult = new AppResult();
|
||||||
|
appResult.setAppid(appId).setPrepayId(this.prepayId).setPartnerId(mchId)
|
||||||
|
.setNoncestr(nonceStr).setTimestamp(timestamp)
|
||||||
|
//暂填写固定值Sign=WXPay
|
||||||
|
.setPackageValue("Sign=WXPay")
|
||||||
|
.setSign(SignUtils.sign(appResult.getSignStr(), privateKey));
|
||||||
|
return (T) appResult;
|
||||||
|
case NATIVE:
|
||||||
|
return (T) this.codeUrl;
|
||||||
|
default:
|
||||||
|
throw new WxRuntimeException("不支持的支付类型");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.github.binarywang.wxpay.bean.result.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付方式
|
||||||
|
*
|
||||||
|
* @author thinsstar
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum PartnerTradeTypeEnum {
|
||||||
|
/**
|
||||||
|
* APP
|
||||||
|
*/
|
||||||
|
APP("/v3/pay/partner/transactions/app", "/v3/combine-transactions/app"),
|
||||||
|
/**
|
||||||
|
* JSAPI 或 小程序
|
||||||
|
*/
|
||||||
|
JSAPI("/v3/pay/partner/transactions/jsapi", "/v3/combine-transactions/jsapi"),
|
||||||
|
/**
|
||||||
|
* NATIVE
|
||||||
|
*/
|
||||||
|
NATIVE("/v3/pay/partner/transactions/native", "/v3/combine-transactions/native"),
|
||||||
|
/**
|
||||||
|
* H5
|
||||||
|
*/
|
||||||
|
H5("/v3/pay/partner/transactions/h5", "/v3/combine-transactions/h5");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单独下单url
|
||||||
|
*/
|
||||||
|
private final String partnerUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并下单url
|
||||||
|
*/
|
||||||
|
private final String combineUrl;
|
||||||
|
}
|
@ -5,6 +5,7 @@ import com.github.binarywang.wxpay.bean.coupon.*;
|
|||||||
import com.github.binarywang.wxpay.bean.notify.*;
|
import com.github.binarywang.wxpay.bean.notify.*;
|
||||||
import com.github.binarywang.wxpay.bean.request.*;
|
import com.github.binarywang.wxpay.bean.request.*;
|
||||||
import com.github.binarywang.wxpay.bean.result.*;
|
import com.github.binarywang.wxpay.bean.result.*;
|
||||||
|
import com.github.binarywang.wxpay.bean.result.enums.PartnerTradeTypeEnum;
|
||||||
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
|
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
|
||||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||||
import com.github.binarywang.wxpay.constant.WxPayConstants;
|
import com.github.binarywang.wxpay.constant.WxPayConstants;
|
||||||
@ -477,6 +478,23 @@ public interface WxPayService {
|
|||||||
*/
|
*/
|
||||||
void closeOrderV3(String outTradeNo) throws WxPayException;
|
void closeOrderV3(String outTradeNo) throws WxPayException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 服务商关闭订单
|
||||||
|
* 应用场景
|
||||||
|
* 以下情况需要调用关单接口:
|
||||||
|
* 1、商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;
|
||||||
|
* 2、系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。
|
||||||
|
* 注意:关单没有时间限制,建议在订单生成后间隔几分钟(最短5分钟)再调用关单接口,避免出现订单状态同步不及时导致关单失败。
|
||||||
|
* 接口地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_3.shtml
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param outTradeNo 商户系统内部的订单号
|
||||||
|
* @return the wx pay order close result
|
||||||
|
* @throws WxPayException the wx pay exception
|
||||||
|
*/
|
||||||
|
void closePartnerOrderV3(String outTradeNo) throws WxPayException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* <pre>
|
||||||
* 关闭订单
|
* 关闭订单
|
||||||
@ -494,6 +512,23 @@ public interface WxPayService {
|
|||||||
*/
|
*/
|
||||||
void closeOrderV3(WxPayOrderCloseV3Request request) throws WxPayException;
|
void closeOrderV3(WxPayOrderCloseV3Request request) throws WxPayException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 服务商关闭订单
|
||||||
|
* 应用场景
|
||||||
|
* 以下情况需要调用关单接口:
|
||||||
|
* 1、商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;
|
||||||
|
* 2、系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。
|
||||||
|
* 注意:关单没有时间限制,建议在订单生成后间隔几分钟(最短5分钟)再调用关单接口,避免出现订单状态同步不及时导致关单失败。
|
||||||
|
* 接口地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_3.shtml
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param request 关闭订单请求对象
|
||||||
|
* @return the wx pay order close result
|
||||||
|
* @throws WxPayException the wx pay exception
|
||||||
|
*/
|
||||||
|
void closePartnerOrderV3(WxPayPartnerOrderCloseV3Request request) throws WxPayException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* <pre>
|
||||||
* 合单关闭订单API
|
* 合单关闭订单API
|
||||||
@ -559,7 +594,7 @@ public interface WxPayService {
|
|||||||
* @return 返回 {@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段
|
* @return 返回 {@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段
|
||||||
* @throws WxPayException the wx pay exception
|
* @throws WxPayException the wx pay exception
|
||||||
*/
|
*/
|
||||||
<T> T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException;
|
<T> T createPartnerOrderV3(PartnerTradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
|
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
|
||||||
@ -569,7 +604,7 @@ public interface WxPayService {
|
|||||||
* @return the wx pay unified order result
|
* @return the wx pay unified order result
|
||||||
* @throws WxPayException the wx pay exception
|
* @throws WxPayException the wx pay exception
|
||||||
*/
|
*/
|
||||||
WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException;
|
WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(PartnerTradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
|
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
|
||||||
|
@ -10,6 +10,7 @@ import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
|
|||||||
import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult;
|
import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult;
|
||||||
import com.github.binarywang.wxpay.bean.request.*;
|
import com.github.binarywang.wxpay.bean.request.*;
|
||||||
import com.github.binarywang.wxpay.bean.result.*;
|
import com.github.binarywang.wxpay.bean.result.*;
|
||||||
|
import com.github.binarywang.wxpay.bean.result.enums.PartnerTradeTypeEnum;
|
||||||
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
|
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
|
||||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||||
import com.github.binarywang.wxpay.config.WxPayConfigHolder;
|
import com.github.binarywang.wxpay.config.WxPayConfigHolder;
|
||||||
@ -538,6 +539,16 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
|||||||
this.closeOrderV3(request);
|
this.closeOrderV3(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closePartnerOrderV3(String outTradeNo) throws WxPayException {
|
||||||
|
if (StringUtils.isBlank(outTradeNo)) {
|
||||||
|
throw new WxPayException("out_trade_no不能为空");
|
||||||
|
}
|
||||||
|
WxPayPartnerOrderCloseV3Request request = new WxPayPartnerOrderCloseV3Request();
|
||||||
|
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
|
||||||
|
this.closePartnerOrderV3(request);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeOrderV3(WxPayOrderCloseV3Request request) throws WxPayException {
|
public void closeOrderV3(WxPayOrderCloseV3Request request) throws WxPayException {
|
||||||
if (StringUtils.isBlank(request.getMchid())) {
|
if (StringUtils.isBlank(request.getMchid())) {
|
||||||
@ -547,6 +558,18 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
|||||||
this.postV3(url, GSON.toJson(request));
|
this.postV3(url, GSON.toJson(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void closePartnerOrderV3(WxPayPartnerOrderCloseV3Request request) throws WxPayException {
|
||||||
|
if (StringUtils.isBlank(request.getSpMchId())) {
|
||||||
|
request.setSpMchId(this.getConfig().getMchId());
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(request.getSubMchId())) {
|
||||||
|
request.setSubMchId(this.getConfig().getSubMchId());
|
||||||
|
}
|
||||||
|
String url = String.format("%s/v3/pay/partner/transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getOutTradeNo());
|
||||||
|
this.postV3(url, GSON.toJson(request));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeCombine(CombineCloseRequest request) throws WxPayException {
|
public void closeCombine(CombineCloseRequest request) throws WxPayException {
|
||||||
String url = String.format("%s/v3/combine-transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getCombineOutTradeNo());
|
String url = String.format("%s/v3/combine-transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getCombineOutTradeNo());
|
||||||
@ -664,34 +687,19 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException {
|
public <T> T createPartnerOrderV3(PartnerTradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException {
|
||||||
WxPayUnifiedOrderV3Result result = this.unifiedPartnerOrderV3(tradeType, request);
|
WxPayUnifiedOrderV3Result result = this.unifiedPartnerOrderV3(tradeType, request);
|
||||||
//获取应用ID
|
//获取应用ID
|
||||||
String appId = StringUtils.isBlank(request.getSubAppid()) ? request.getSpAppid() : request.getSubAppid();
|
String appId = StringUtils.isBlank(request.getSubAppid()) ? request.getSpAppid() : request.getSubAppid();
|
||||||
return result.getPayInfo(tradeType, appId, request.getSubMchId(), this.getConfig().getPrivateKey());
|
return result.getPartnerPayInfo(tradeType, appId, request.getSubMchId(), this.getConfig().getPrivateKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException {
|
public WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(PartnerTradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException {
|
||||||
if (StringUtils.isBlank(request.getSpAppid())) {
|
WxPayUnifiedOrderV3Result result = this.unifiedPartnerOrderV3(tradeType, request);
|
||||||
request.setSpAppid(this.getConfig().getAppId());
|
//获取应用ID
|
||||||
}
|
String appId = StringUtils.isBlank(request.getSubAppid()) ? request.getSpAppid() : request.getSubAppid();
|
||||||
if (StringUtils.isBlank(request.getSpMchId())) {
|
return result.getPartnerPayInfo(tradeType, appId, request.getSubMchId(), this.getConfig().getPrivateKey());
|
||||||
request.setSpMchId(this.getConfig().getMchId());
|
|
||||||
}
|
|
||||||
if (StringUtils.isBlank(request.getNotifyUrl())) {
|
|
||||||
request.setNotifyUrl(this.getConfig().getNotifyUrl());
|
|
||||||
}
|
|
||||||
if (StringUtils.isBlank(request.getSubAppid())) {
|
|
||||||
request.setSubAppid(this.getConfig().getSubAppId());
|
|
||||||
}
|
|
||||||
if (StringUtils.isBlank(request.getSubMchId())) {
|
|
||||||
request.setSubMchId(this.getConfig().getSubMchId());
|
|
||||||
}
|
|
||||||
|
|
||||||
String url = this.getPayBaseUrl() + tradeType.getPartnerUrl();
|
|
||||||
String response = this.postV3(url, GSON.toJson(request));
|
|
||||||
return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user