Skip to content

服务商模式URL修改,增加服务商模式关闭订单方法 #3063

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,6 @@
@Accessors(chain = true)
public class WxPayPartnerRefundV3Request extends WxPayRefundV3Request implements Serializable {
private static final long serialVersionUID = -1L;
/**
* <pre>
* 字段名:子商户的商户号
* 变量名:sub_mchid
* 是否必填:是
* 类型:string[1, 32]
* 描述:
* 子商户商户号,由微信支付生成并下发。
* 示例值:1230000109
* </pre>
*/
@SerializedName(value = "sub_mchid")
private String subMchId;
/**
* <pre>
* 字段名:退款资金来源
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,17 @@ public static class GoodsDetail implements Serializable {
private Integer refundQuantity;
}

/**
* <pre>
* 字段名:子商户的商户号
* 变量名:sub_mchid
* 是否必填:是
* 类型:string[1, 32]
* 描述:
* 子商户商户号,由微信支付生成并下发。
* 示例值:1230000109
* </pre>
*/
@SerializedName(value = "sub_mchid")
private String subMchid;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
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.v3.util.SignUtils;
import com.google.gson.annotations.SerializedName;
Expand Down Expand Up @@ -132,4 +133,32 @@ public <T> T getPayInfo(TradeTypeEnum tradeType, String appId, String mchId, Pri
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("不支持的支付类型");
}
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.github.binarywang.wxpay.bean.notify.*;
import com.github.binarywang.wxpay.bean.request.*;
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.config.WxPayConfig;
import com.github.binarywang.wxpay.constant.WxPayConstants;
Expand Down Expand Up @@ -477,6 +478,23 @@ public interface WxPayService {
*/
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>
* 关闭订单
Expand All @@ -494,6 +512,23 @@ public interface WxPayService {
*/
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>
* 合单关闭订单API
Expand Down Expand Up @@ -559,7 +594,7 @@ public interface WxPayService {
* @return 返回 {@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段
* @throws WxPayException the wx pay exception
*/
<T> T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException;
<T> T createPartnerOrderV3(PartnerTradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException;

/**
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
Expand All @@ -569,7 +604,7 @@ public interface WxPayService {
* @return the wx pay unified order result
* @throws WxPayException the wx pay exception
*/
WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException;
WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(PartnerTradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException;

/**
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult;
import com.github.binarywang.wxpay.bean.request.*;
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.config.WxPayConfig;
import com.github.binarywang.wxpay.config.WxPayConfigHolder;
Expand Down Expand Up @@ -538,6 +539,16 @@ public void closeOrderV3(String outTradeNo) throws WxPayException {
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
public void closeOrderV3(WxPayOrderCloseV3Request request) throws WxPayException {
if (StringUtils.isBlank(request.getMchid())) {
Expand All @@ -547,6 +558,18 @@ public void closeOrderV3(WxPayOrderCloseV3Request request) throws WxPayException
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
public void closeCombine(CombineCloseRequest request) throws WxPayException {
String url = String.format("%s/v3/combine-transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getCombineOutTradeNo());
Expand Down Expand Up @@ -664,34 +687,19 @@ public <T> T createOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request r
}

@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);
//获取应用ID
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
public WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException {
if (StringUtils.isBlank(request.getSpAppid())) {
request.setSpAppid(this.getConfig().getAppId());
}
if (StringUtils.isBlank(request.getSpMchId())) {
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);
public WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(PartnerTradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException {
WxPayUnifiedOrderV3Result result = this.unifiedPartnerOrderV3(tradeType, request);
//获取应用ID
String appId = StringUtils.isBlank(request.getSubAppid()) ? request.getSpAppid() : request.getSubAppid();
return result.getPartnerPayInfo(tradeType, appId, request.getSubMchId(), this.getConfig().getPrivateKey());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7% of developers fix this issue

THREAD_SAFETY_VIOLATION: Read/Write race. Non-private method BaseWxPayServiceImpl.unifiedPartnerOrderV3(...) indirectly reads without synchronization from this.configMap. Potentially races with write in method BaseWxPayServiceImpl.addConfig(...).
Reporting because another access to the same memory occurs on a background thread, although this access may not.


ℹ️ Expand to see all @sonatype-lift commands

You can reply with the following commands. For example, reply with @sonatype-lift ignoreall to leave out all findings.

Command Usage
@sonatype-lift ignore Leave out the above finding from this PR
@sonatype-lift ignoreall Leave out all the existing findings from this PR
@sonatype-lift exclude <file|issue|path|tool> Exclude specified file|issue|path|tool from Lift findings by updating your config.toml file

Note: When talking to LiftBot, you need to refresh the page to see its response.
Click here to add LiftBot to another repo.

}

@Override
Expand Down