🎨 #2653 【微信支付】支付分相关接口增加服务商支持

This commit is contained in:
高岩 2022-05-22 21:14:49 +08:00 committed by GitHub
parent 4de09fa565
commit 529f786814
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 724 additions and 7 deletions

View File

@ -1,6 +1,8 @@
package com.github.binarywang.wxpay.bean.ecommerce;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -17,7 +19,9 @@ import java.util.List;
* @author cloudX
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PartnerTransactionsRequest implements Serializable {
private static final long serialVersionUID = -1550405819444680465L;
@ -277,6 +281,7 @@ public class PartnerTransactionsRequest implements Serializable {
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Amount implements Serializable {
private static final long serialVersionUID = -4967636398225864273L;
@ -312,6 +317,7 @@ public class PartnerTransactionsRequest implements Serializable {
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Payer implements Serializable {
private static final long serialVersionUID = -3946401119476159971L;

View File

@ -1,5 +1,7 @@
package com.github.binarywang.wxpay.bean.ecommerce;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -10,7 +12,9 @@ import java.io.Serializable;
* 文档地址: https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/qian-ming-yan-zheng
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SignatureHeader implements Serializable {
private static final long serialVersionUID = -6958015499416059949L;
/**

View File

@ -1,5 +1,7 @@
package com.github.binarywang.wxpay.bean.notify;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -10,7 +12,9 @@ import java.io.Serializable;
* 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SignatureHeader implements Serializable {
private static final long serialVersionUID = -1L;
/**

View File

@ -0,0 +1,39 @@
package com.github.binarywang.wxpay.bean.payscore;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
/**
* @author hallkk
* @date 2022/05/18
*/
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class WxPartnerPayScoreRequest extends WxPayScoreRequest {
private static final long serialVersionUID = 6269843192878112955L;
public String toJson() {
return WxGsonBuilder.create().toJson(this);
}
@SerializedName("sub_appid")
private String subAppid;
@SerializedName("sub_mchid")
private String subMchid;
@SerializedName("out_apply_no")
private String outApplyNo;
@SerializedName("result_notify_url")
private String resultNotifyUrl;
}

View File

@ -0,0 +1,42 @@
package com.github.binarywang.wxpay.bean.payscore;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
/**
* @author hallkk
* @date 2022/05/18
*/
@Data
@NoArgsConstructor
public class WxPartnerPayScoreResult extends WxPayScoreResult {
private static final long serialVersionUID = 718267574622164410L;
public static WxPartnerPayScoreResult fromJson(String json) {
return WxGsonBuilder.create().fromJson(json, WxPartnerPayScoreResult.class);
}
@SerializedName("sub_appid")
private String subAppid;
@SerializedName("sub_mchid")
private String subMchid;
@SerializedName("sub_openid")
private String subOpenId;
@SerializedName("out_apply_no")
private String outApplyNo;
@SerializedName("result_notify_url")
private String resultNotifyUrl;
@SerializedName("apply_state")
private String applyState;
@SerializedName("reject_reason")
private String rejectReason;
}

View File

@ -10,6 +10,7 @@ import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
/**
@ -17,7 +18,7 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder;
* @date 2020/5/12 16:36
*/
@Data
@Builder
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@ -82,6 +83,6 @@ public class WxPayScoreRequest implements Serializable {
@SerializedName("detail")
private Detail detail;
@SerializedName("authorization_code")
private String authorizationCode;
private String authorizationCode;
}

View File

@ -85,20 +85,23 @@ public class WxPayScoreResult implements Serializable {
@SerializedName("payScoreSignInfo")
private Map<String, String> payScoreSignInfo;
@SerializedName("openid")
private String openId;
@SerializedName("apply_permissions_token")
private String applyPermissionsToken;
private String applyPermissionsToken;
@SerializedName("authorization_code")
private String authorizationCode;
private String authorizationCode;
@SerializedName("authorization_state")
private String authorizationState;
private String authorizationState;
@SerializedName("cancel_authorization_time")
private String cancelAuthorizationTime;
private String cancelAuthorizationTime;
@SerializedName("authorization_success_time")
private String authorizationSuccessTime;
private String authorizationSuccessTime;
@SerializedName("openid")
private String openid;

View File

@ -0,0 +1,277 @@
package com.github.binarywang.wxpay.service;
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader;
import com.github.binarywang.wxpay.bean.payscore.PayScoreNotifyData;
import com.github.binarywang.wxpay.bean.payscore.UserAuthorizationStatusNotifyResult;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreRequest;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreResult;
import com.github.binarywang.wxpay.exception.WxPayException;
/**
* <pre>
* 服务商支付分相关服务类.
* 微信支付分是对个人的身份特质支付行为使用历史等情况的综合计算分值旨在为用户提供更简单便捷的生活方式
* 微信用户可以在具体应用场景中开通微信支付分开通后用户可以在微信>钱包>支付分中查看分数和使用记录
* 即需在应用场景中使用过一次钱包才会出现支付分入口
*
* @author hallkk
* @date 2022/05/18
*/
public interface PartnerPayScoreService {
/**
* <pre>
* 支付分商户预授权API
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore_partner/chapter5_1.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/payscore/partner/permissions
* </pre>
*
* @param request 请求对象
* @return WxPartnerPayScoreResult wx partner payscore result
* @throws WxPayException the wx pay exception
*/
WxPartnerPayScoreResult permissions(WxPartnerPayScoreRequest request) throws WxPayException;
/**
* <pre>
* 支付分查询与用户授权记录授权协议号API
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore_partner/chapter5_2.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/payscore/partner/permissions/authorization-code/{authorization_code}
* </pre>
*
* @param serviceId
* @param subMchid
* @param authorizationCode
* @return WxPayScoreResult wx partner payscore result
* @throws WxPayException the wx pay exception
*/
WxPartnerPayScoreResult permissionsQueryByAuthorizationCode(String serviceId, String subMchid,
String authorizationCode) throws WxPayException;
/**
* <pre>
* 解除用户授权关系授权协议号API
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore_partner/chapter5_4.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/payscore/partner/permissions/authorization-code/{authorization_code}/terminate
* </pre>
*
* @param serviceId
* @param subMchid
* @param authorizationCode
* @param reason
* @return WxPartnerPayScoreResult wx partner payscore result
* @throws WxPayException the wx pay exception
*/
WxPartnerPayScoreResult permissionsTerminateByAuthorizationCode(String serviceId, String subMchid,
String authorizationCode, String reason) throws WxPayException;
/**
* <pre>
* 支付分查询与用户授权记录openidAPI
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore_partner/chapter5_3.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/payscore/partner/permissions/search
* </pre>
*
* @param serviceId
* @param subMchid
* @param subAppid
* @param openId
* @param subOpenid
* @return WxPayScoreResult wx partner payscore result
* @throws WxPayException the wx pay exception
*/
WxPartnerPayScoreResult permissionsQueryByOpenId(String serviceId, String appId, String subMchid, String subAppid,
String openId, String subOpenid) throws WxPayException;
/**
* <pre>
* 解除用户授权关系openidAPI
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore_partner/chapter5_5.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/payscore/partner/permissions/openid/{openid}/terminate
* </pre>
*
* @param serviceId
* @param subMchid
* @param subAppid
* @param openId
* @param subOpenid
* @param reason
* @return WxPayScoreResult wx partner payscore result
* @throws WxPayException the wx pay exception
*/
WxPartnerPayScoreResult permissionsTerminateByOpenId(String serviceId, String appId, String subMchid, String subAppid,
String openId, String subOpenid, String reason) throws WxPayException;
/**
* <pre>
* 支付分创建订单API.
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore_partner/chapter3_1.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/payscore/partner/serviceorder
* </pre>
*
* @param request 请求对象
* @return WxPayScoreResult wx partner payscore result
* @throws WxPayException the wx pay exception
*/
WxPartnerPayScoreResult createServiceOrder(WxPartnerPayScoreRequest request) throws WxPayException;
/**
* <pre>
* 支付分查询订单API.
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore_partner/chapter3_2.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/payscore/partner/serviceorder
* </pre>
*
* @param serviceId
* @param subMchid
* @param outOrderNo the out order no
* @param queryId the query id
* @return the wx pay score result
* @throws WxPayException the wx pay exception
*/
WxPartnerPayScoreResult queryServiceOrder(String serviceId, String subMchid,
String outOrderNo, String queryId) throws WxPayException;
/**
* <pre>
* 支付分取消订单API.
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore_partner/chapter3_3.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/payscore/partner/serviceorder/{out_order_no}/cancel
* </pre>
* <p>
*
* @param serviceId
* @param subMchid
* @param outOrderNo the out order no
* @param reason the reason
* @return com.github.binarywang.wxpay.bean.payscore.WxPayScoreResult wx pay score result
* @throws WxPayException the wx pay exception
*/
WxPartnerPayScoreResult cancelServiceOrder(String serviceId, String appId, String subMchid,
String outOrderNo, String reason) throws WxPayException;
/**
* <pre>
* 支付分修改订单金额API.
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore_partner/chapter3_4.shtml
* 接口链接https://api.mch.weixin.qq.com/v3/payscore/partner/serviceorder/{out_order_no}/modify
* </pre>
* <p>
*
* @param request the request
* @return the wx pay score result
* @throws WxPayException the wx pay exception
*/
WxPartnerPayScoreResult modifyServiceOrder(WxPartnerPayScoreRequest request) throws WxPayException;
/**
* <pre>
* 支付分完结订单API.
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore_partner/chapter3_5.shtml
* 请求URLhttps://api.mch.weixin.qq.com/v3/payscore/partner/serviceorder/{out_order_no}/complete
* </pre>
*
* @param request the request
* @return the wx pay score result
* @throws WxPayException the wx pay exception
*/
void completeServiceOrder(WxPartnerPayScoreRequest request) throws WxPayException;
/**
* <pre>
* 商户发起催收扣款API.
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore_partner/chapter3_6.shtml
* 请求URLhttps://api.mch.weixin.qq.com/v3/payscore/partner/serviceorder/{out_order_no}/pay
*
* </pre>
*
* @param serviceId
* @param subMchid
* @param outOrderNo the out order no
* @return the wx pay score result
* @throws WxPayException the wx pay exception
*/
WxPartnerPayScoreResult payServiceOrder(String serviceId, String appId, String subMchid, String outOrderNo) throws WxPayException;
/**
* <pre>
* 支付分订单收款API.
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore_partner/chapter3_7.shtml
* 请求URL https://api.mch.weixin.qq.com/v3/payscore/partner/serviceorder/{out_order_no}/sync
* </pre>
*
* @param request the request
* @return the wx pay score result
* @throws WxPayException the wx pay exception
*/
WxPartnerPayScoreResult syncServiceOrder(WxPartnerPayScoreRequest request) throws WxPayException;
/**
* <pre>
* 收付通子商户申请绑定支付分服务API.
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore_partner/chapter9_1.shtml
* 请求URL https://api.mch.weixin.qq.com/v3/payscore/partner/service-account-applications
* </pre>
*
* @param request the request
* @return the wx pay score result
* @throws WxPayException the wx pay exception
*/
WxPartnerPayScoreResult applyServiceAccount(WxPartnerPayScoreRequest request) throws WxPayException;
/**
* <pre>
* 查询收付通子商户服务绑定结果API.
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore_partner/chapter9_2.shtml
* 请求URL https://api.mch.weixin.qq.com/v3/payscore/partner/service-account-applications/{out_apply_no}
* </pre>
*
* @param outApplyNo 商户申请绑定单号
* @return the wx pay score result
* @throws WxPayException the wx pay exception
*/
WxPartnerPayScoreResult queryServiceAccountState(String outApplyNo) throws WxPayException;
/**
* <pre>
* 授权/解除授权服务回调数据处理
* 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore/chapter4_4.shtml
* </pre>
*
* @param notifyData 通知数据
* @param header 通知头部数据不传则表示不校验头
* @return 解密后通知数据 return user authorization status notify result
* @throws WxPayException the wx pay exception
*/
UserAuthorizationStatusNotifyResult parseUserAuthorizationStatusNotifyResult(String notifyData, SignatureHeader header) throws WxPayException;
/**
* <pre>
* 支付分回调内容解析方法
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore/chapter5_2.shtml
* </pre>
*
* @param data the data
* @return the wx pay score result
*/
PayScoreNotifyData parseNotifyData(String data, SignatureHeader header) throws WxPayException;
/**
* <pre>
* 支付分回调NotifyData解密resource
* 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/payscore/chapter5_2.shtml
* </pre>
*
* @param data the data
* @return the wx pay score result
* @throws WxPayException the wx pay exception
*/
WxPartnerPayScoreResult decryptNotifyDataResource(PayScoreNotifyData data) throws WxPayException;
}

View File

@ -0,0 +1,341 @@
package com.github.binarywang.wxpay.service.impl;
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader;
import com.github.binarywang.wxpay.bean.payscore.PayScoreNotifyData;
import com.github.binarywang.wxpay.bean.payscore.UserAuthorizationStatusNotifyResult;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreRequest;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.PartnerPayScoreService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.v3.util.AesUtils;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIBuilder;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* @author hallkk
* @date 2022/05/18
*/
@RequiredArgsConstructor
public class PartnerPayScoreServiceImpl implements PartnerPayScoreService {
private static final Gson GSON = new GsonBuilder().create();
private final WxPayService payService;
@Override
public WxPartnerPayScoreResult permissions(WxPartnerPayScoreRequest request) throws WxPayException {
String url = this.payService.getPayBaseUrl() + "/v3/payscore/partner/permissions";
request.setAppid(request.getAppid());
request.setServiceId(request.getServiceId());
WxPayConfig config = this.payService.getConfig();
String permissionNotifyUrl = config.getPayScorePermissionNotifyUrl();
if (StringUtils.isBlank(permissionNotifyUrl)) {
throw new WxPayException("授权回调地址未配置");
}
String authorizationCode = request.getAuthorizationCode();
if (StringUtils.isBlank(authorizationCode)) {
throw new WxPayException("authorizationCode不允许为空");
}
request.setNotifyUrl(permissionNotifyUrl);
String result = this.payService.postV3(url, request.toJson());
return WxPartnerPayScoreResult.fromJson(result);
}
@Override
public WxPartnerPayScoreResult permissionsQueryByAuthorizationCode(String serviceId, String subMchid, String authorizationCode)
throws WxPayException {
if (StringUtils.isBlank(authorizationCode)) {
throw new WxPayException("authorizationCode不允许为空");
}
String url = String.format("%s/v3/payscore/partner/permissions/authorization-code/%s", this.payService.getPayBaseUrl(), authorizationCode);
URIBuilder uriBuilder;
try {
uriBuilder = new URIBuilder(url);
} catch (URISyntaxException e) {
throw new WxPayException("未知异常!", e);
}
uriBuilder.setParameter("service_id", serviceId);
uriBuilder.setParameter("sub_mchid", subMchid);
try {
String result = payService.getV3(uriBuilder.build().toString());
return WxPartnerPayScoreResult.fromJson(result);
} catch (URISyntaxException e) {
throw new WxPayException("未知异常!", e);
}
}
@Override
public WxPartnerPayScoreResult permissionsTerminateByAuthorizationCode(String serviceId, String subMchid,
String authorizationCode, String reason) throws WxPayException {
if (StringUtils.isBlank(authorizationCode)) {
throw new WxPayException("authorizationCode不允许为空");
}
String url = String.format(
"%s/v3/payscore/partner/permissions/authorization-code/%s/terminate",
this.payService.getPayBaseUrl(),
authorizationCode
);
Map<String, Object> map = new HashMap<>(4);
map.put("service_id", serviceId);
map.put("sub_mchid", subMchid);
map.put("reason", reason);
String result = payService.postV3(url, WxGsonBuilder.create().toJson(map));
return WxPartnerPayScoreResult.fromJson(result);
}
@Override
public WxPartnerPayScoreResult permissionsQueryByOpenId(String serviceId, String appId, String subMchid,
String subAppid, String openId, String subOpenid) throws WxPayException {
if (StringUtils.isAllEmpty(openId, subOpenid) || !StringUtils.isAnyEmpty(openId, subOpenid)) {
throw new WxPayException("open_id,sub_openid不允许都填写或都不填写");
}
if (StringUtils.isBlank(subMchid)) {
throw new WxPayException("sub_mchid不允许都为空");
}
String url = String.format("%s/v3/payscore/partner/permissions/openid/%s", this.payService.getPayBaseUrl(), openId);
URIBuilder uriBuilder;
try {
uriBuilder = new URIBuilder(url);
} catch (URISyntaxException e) {
throw new WxPayException("未知异常!", e);
}
uriBuilder.setParameter("appid", appId);
uriBuilder.setParameter("service_id", serviceId);
uriBuilder.setParameter("sub_mchid", subMchid);
uriBuilder.setParameter("sub_appid", subAppid);
uriBuilder.setParameter("openid", openId);
uriBuilder.setParameter("sub_openid", subOpenid);
if (StringUtils.isNotEmpty(openId)) {
uriBuilder.setParameter("openid", openId);
}
if (StringUtils.isNotEmpty(subOpenid)) {
uriBuilder.setParameter("sub_openid", subOpenid);
}
try {
String result = payService.getV3(uriBuilder.build().toString());
return WxPartnerPayScoreResult.fromJson(result);
} catch (URISyntaxException e) {
throw new WxPayException("未知异常!", e);
}
}
@Override
public WxPartnerPayScoreResult permissionsTerminateByOpenId(String serviceId, String appId, String subMchid, String subAppid, String openId, String subOpenid, String reason) throws WxPayException {
if (StringUtils.isAllEmpty(openId, subOpenid) || !StringUtils.isAnyEmpty(openId, subOpenid)) {
throw new WxPayException("open_id,sub_openid不允许都填写或都不填写");
}
String url = String.format("%s/v3/payscore/partner/permissions/openid/%s/terminate", this.payService.getPayBaseUrl(), openId);
Map<String, Object> map = new HashMap<>(4);
map.put("appid", appId);
map.put("sub_appid", subAppid);
map.put("service_id", serviceId);
if (StringUtils.isNotEmpty(openId)) {
map.put("openid", openId);
}
if (StringUtils.isNotEmpty(subOpenid)) {
map.put("sub_openid", subOpenid);
}
map.put("sub_mchid", subMchid);
map.put("reason", reason);
String result = payService.postV3(url, WxGsonBuilder.create().toJson(map));
return WxPartnerPayScoreResult.fromJson(result);
}
@Override
public WxPartnerPayScoreResult createServiceOrder(WxPartnerPayScoreRequest request) throws WxPayException {
String url = this.payService.getPayBaseUrl() + "/v3/payscore/partner/serviceorder";
WxPayConfig config = this.payService.getConfig();
request.setNotifyUrl(config.getPayScoreNotifyUrl());
String result = this.payService.postV3(url, request.toJson());
return WxPartnerPayScoreResult.fromJson(result);
}
@Override
public WxPartnerPayScoreResult queryServiceOrder(String serviceId, String subMchid, String outOrderNo,
String queryId) throws WxPayException {
String url = this.payService.getPayBaseUrl() + "/v3/payscore/partner/serviceorder";
URIBuilder uriBuilder;
try {
uriBuilder = new URIBuilder(url);
} catch (URISyntaxException e) {
throw new WxPayException("未知异常!", e);
}
uriBuilder.setParameter("service_id", serviceId);
uriBuilder.setParameter("sub_mchid", subMchid);
if (StringUtils.isAllEmpty(outOrderNo, queryId) || !StringUtils.isAnyEmpty(outOrderNo, queryId)) {
throw new WxPayException("out_order_no,query_id不允许都填写或都不填写");
}
if (StringUtils.isNotEmpty(outOrderNo)) {
uriBuilder.setParameter("out_order_no", outOrderNo);
}
if (StringUtils.isNotEmpty(queryId)) {
uriBuilder.setParameter("query_id", queryId);
}
try {
String result = payService.getV3(uriBuilder.build().toString());
return WxPartnerPayScoreResult.fromJson(result);
} catch (URISyntaxException e) {
throw new WxPayException("未知异常!", e);
}
}
@Override
public WxPartnerPayScoreResult cancelServiceOrder(String serviceId, String appId, String subMchid, String outOrderNo, String reason) throws WxPayException {
String url = String.format("%s/v3/payscore/partner/serviceorder/%s/cancel", this.payService.getPayBaseUrl(), outOrderNo);
Map<String, Object> map = new HashMap<>(4);
map.put("appid", appId);
map.put("service_id", serviceId);
map.put("sub_mchid", subMchid);
map.put("reason", reason);
if (StringUtils.isAnyEmpty(appId, serviceId, subMchid, reason)) {
throw new WxPayException("appid, service_id, sub_mchid, reason都不能为空");
}
String result = payService.postV3(url, WxGsonBuilder.create().toJson(map));
return WxPartnerPayScoreResult.fromJson(result);
}
@Override
public WxPartnerPayScoreResult modifyServiceOrder(WxPartnerPayScoreRequest request) throws WxPayException {
String outOrderNo = request.getOutOrderNo();
String url = String.format("%s/v3/payscore/partner/serviceorder/%s/modify", this.payService.getPayBaseUrl(), outOrderNo);
request.setAppid(this.payService.getConfig().getAppId());
request.setOutOrderNo(null);
String result = payService.postV3(url, request.toJson());
return WxPartnerPayScoreResult.fromJson(result);
}
@Override
public void completeServiceOrder(WxPartnerPayScoreRequest request) throws WxPayException {
String outOrderNo = request.getOutOrderNo();
String url = String.format("%s/v3/payscore/partner/serviceorder/%s/complete", this.payService.getPayBaseUrl(), outOrderNo);
request.setAppid(request.getAppid());
request.setServiceId(request.getServiceId());
request.setOutOrderNo(null);
request.setSubMchid(request.getSubMchid());
this.payService.postV3(url, request.toJson());
}
@Override
public WxPartnerPayScoreResult payServiceOrder(String serviceId, String appId, String subMchid, String outOrderNo) throws WxPayException {
String url = String.format("%s/v3/payscore/partner/serviceorder/%s/pay", this.payService.getPayBaseUrl(), outOrderNo);
Map<String, Object> map = new HashMap<>(3);
map.put("appid", appId);
map.put("service_id", serviceId);
map.put("sub_mchid", subMchid);
if (StringUtils.isAnyEmpty(appId, serviceId, subMchid)) {
throw new WxPayException("appid, service_id, sub_mchid都不能为空");
}
String result = payService.postV3(url, WxGsonBuilder.create().toJson(map));
return WxPartnerPayScoreResult.fromJson(result);
}
@Override
public WxPartnerPayScoreResult syncServiceOrder(WxPartnerPayScoreRequest request) throws WxPayException {
String outOrderNo = request.getOutOrderNo();
String url = String.format("%s/v3/payscore/partner/serviceorder/%s/sync", this.payService.getPayBaseUrl(), outOrderNo);
request.setAppid(this.payService.getConfig().getAppId());
request.setOutOrderNo(null);
String result = payService.postV3(url, request.toJson());
return WxPartnerPayScoreResult.fromJson(result);
}
@Override
public WxPartnerPayScoreResult applyServiceAccount(WxPartnerPayScoreRequest request) throws WxPayException {
String url = String.format("%s/v3/payscore/partner/service-account-applications", this.payService.getPayBaseUrl());
Map<String, String> params = Maps.newHashMap();
params.put("service_id", request.getServiceId());
params.put("appid", request.getAppid());
params.put("sub_mchid", request.getSubMchid());
params.put("sub_appid", request.getSubAppid());
params.put("out_apply_no", request.getOutApplyNo());
params.put("result_notify_url", request.getResultNotifyUrl());
String result = payService.postV3(url, WxGsonBuilder.create().toJson(params));
return WxPartnerPayScoreResult.fromJson(result);
}
@Override
public WxPartnerPayScoreResult queryServiceAccountState(String outApplyNo) throws WxPayException {
String url = String.format("%s/v3/payscore/partner/service-account-applications/%s", this.payService.getPayBaseUrl(), outApplyNo);
String result = payService.getV3(url);
return WxPartnerPayScoreResult.fromJson(result);
}
@Override
public UserAuthorizationStatusNotifyResult parseUserAuthorizationStatusNotifyResult(String notifyData, SignatureHeader header) throws WxPayException {
PayScoreNotifyData response = parseNotifyData(notifyData, header);
PayScoreNotifyData.Resource resource = response.getResource();
String cipherText = resource.getCipherText();
String associatedData = resource.getAssociatedData();
String nonce = resource.getNonce();
String apiV3Key = this.payService.getConfig().getApiV3Key();
try {
String result = AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key);
UserAuthorizationStatusNotifyResult notifyResult = GSON.fromJson(result, UserAuthorizationStatusNotifyResult.class);
notifyResult.setRawData(response);
return notifyResult;
} catch (GeneralSecurityException | IOException e) {
throw new WxPayException("解析报文异常!", e);
}
}
@Override
public PayScoreNotifyData parseNotifyData(String data, SignatureHeader header) throws WxPayException {
if (Objects.nonNull(header) && !this.verifyNotifySign(header, data)) {
throw new WxPayException("非法请求,头部信息验证失败");
}
return GSON.fromJson(data, PayScoreNotifyData.class);
}
@Override
public WxPartnerPayScoreResult decryptNotifyDataResource(PayScoreNotifyData data) throws WxPayException {
PayScoreNotifyData.Resource resource = data.getResource();
String cipherText = resource.getCipherText();
String associatedData = resource.getAssociatedData();
String nonce = resource.getNonce();
String apiV3Key = this.payService.getConfig().getApiV3Key();
try {
return WxPartnerPayScoreResult.fromJson(AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key));
} catch (GeneralSecurityException | IOException e) {
throw new WxPayException("解析报文异常!", e);
}
}
/**
* 校验通知签名
*
* @param header 通知头信息
* @param data 通知数据
* @return true:校验通过 false:校验不通过
*/
private boolean verifyNotifySign(SignatureHeader header, String data) {
String beforeSign = String.format("%s\n%s\n%s\n", header.getTimeStamp(), header.getNonce(), data);
return this.payService.getConfig().getVerifier().verify(
header.getSerialNo(),
beforeSign.getBytes(StandardCharsets.UTF_8),
header.getSigned()
);
}
}