🆕 #2257【微信支付】增加微信签约代扣相关接口

This commit is contained in:
po
2021-08-13 17:53:01 +08:00
committed by GitHub
parent ed6bd016f5
commit 3f42a162c2
22 changed files with 3014 additions and 0 deletions

View File

@@ -0,0 +1,157 @@
package com.github.binarywang.wxpay.service;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.exception.WxPayException;
/**
* <pre>
* 微信签约代扣相关接口.
* https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter2_8.shtml
* </pre>
*
* @author chenliang
* @date 2021-08-02 4:50 下午
*/
public interface WxEntrustPapService {
/**
*
* <pre>
* 获取公众号纯签约链接,
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_1.shtml
* 该接口返回一个签约链接,该链接只能在微信内打开
* </pre>
*
* @param wxMpEntrustRequest
* @return
* @throws WxPayException
*/
String mpSign(WxMpEntrustRequest wxMpEntrustRequest) throws WxPayException;
/**
*
* <pre>
* 获取小程序纯签约参数json
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_3.shtml
* 返回一个json 前端用来拉起一个新的签约小程序进行签约
* </pre>
*
*
* @param wxMaEntrustRequest
* @return
* @throws WxPayException
*/
String maSign(WxMaEntrustRequest wxMaEntrustRequest) throws WxPayException;
/**
*
* <pre>
* 获取h5纯签约支付跳转链接
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_4.shtml
* 返回一个签约链接 在浏览器请求链接拉起微信
* </pre>
*
* @param wxH5EntrustRequest
* @return
* @throws WxPayException
*/
WxH5EntrustResult h5Sign(WxH5EntrustRequest wxH5EntrustRequest) throws WxPayException;
/**
*
* <pre>
* 支付中签约
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_5.shtml
* 请求微信 若微信内请求 需要构造json返回
* 若h5请求 直接使用mweb_url 链接即可拉起微信
* </pre>
*
* @param wxPayEntrustRequest
* @return
* @throws WxPayException
*/
WxPayEntrustResult paySign(WxPayEntrustRequest wxPayEntrustRequest) throws WxPayException;
/**
* 申请扣款
* <pre>
* 申请扣款
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_8.shtml
* 请求微信发起委托扣款,扣款额度和次数由使用的签约模板限制,
* 该扣款接口是立即扣款 无延时 扣款前无消息通知。
*
* • 特殊情况周期扣费为通知后24小时扣费方式情况下如果用户为首次签约包含解约后重新签约
* 从用户签约成功时间开始算商户在12小时内发起的扣款会被立即执行无延迟。商户超过12小时以后发起的扣款都按24小时扣费规则执行
* </pre>
*
* @param wxWithholdRequest
* @return
* @throws WxPayException
*/
WxWithholdResult withhold(WxWithholdRequest wxWithholdRequest) throws WxPayException;
/**
* 预扣费通知
* <pre>
* 预扣费接口
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_10.shtml
* 商户进行委托代扣扣费前需要在可通知时间段内调用「预扣费通知」的接口为用户发送扣费提醒,
* 并设定扣费持续天数和预计扣费金额,经过扣费等待期后,在可扣费期内可发起扣费,扣款金额不能高于预计扣费金额,
* 扣费失败可主动发起重试扣费(重试次数由其他规则限制),直到扣费成功,或者可扣费期结束。
* 商户只能在北京时间每天 6:0022:00调用「预扣费通知」
* </pre>
*
* @param wxPreWithholdRequest
* @return
* @throws WxPayException
*/
String preWithhold(WxPreWithholdRequest wxPreWithholdRequest) throws WxPayException;
/**
* 签约状态查询
* <pre>
* 签约状态查询
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_7.shtml
* 查询签约关系接口提供单笔签约关系查询。
* </pre>
*
* @param wxSignQueryRequest
* @return
* @throws WxPayException
*/
WxSignQueryResult querySign(WxSignQueryRequest wxSignQueryRequest) throws WxPayException;
/**
* 申请解约
* <pre>
* 申请解约
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_9.shtml
* 商户与用户的签约关系有误或者商户主动要求与用户解除之前的签约协议时可调用此接口完成解约。
* 商户可以在商户后台pay.weixin.qq.com设置解约回调地址当发生解约关系的时候微信服务器会向此地址通知解约信息内容与签约返回一致
* </pre>
*
* @param wxTerminatedContractRequest
* @return
* @throws WxPayException
*/
WxTerminationContractResult terminationContract(WxTerminatedContractRequest wxTerminatedContractRequest) throws WxPayException;
/**
*
* <pre>
* 查询代扣订单
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter4_5.shtml
* 该接口仅提供微信扣款服务申请扣款接口创建的订单进行查询,商户可以通过该接口主动查询微信代扣订单状态,完成下一步的业务逻辑。
* ACCEPT等待扣款为24小时延时扣费场景下独有的当没有达到24小时前一直是这种状态
* NOTPAY未支付系统已经启动扣款流程这个状态只是瞬间状态很快会进入终态SUCCESS、PAY_FAIL
*
* </pre>
*
* @param wxWithholdOrderQueryRequest
* @return
* @throws WxPayException
*/
WxWithholdOrderQueryResult papOrderQuery(WxWithholdOrderQueryRequest wxWithholdOrderQueryRequest) throws WxPayException;
}

View File

@@ -173,6 +173,12 @@ public interface WxPayService {
*/
InputStream downloadV3(String url) throws WxPayException;
/**
* 获取微信签约代扣服务类
* @return entrust service
*/
WxEntrustPapService getWxEntrustPapService();
/**
* 获取企业付款服务类.
*

View File

@@ -74,6 +74,8 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
private final MarketingMediaService marketingMediaService = new MarketingMediaServiceImpl(this);
private final MarketingFavorService marketingFavorService = new MarketingFavorServiceImpl(this);
private final MarketingBusiFavorService marketingBusiFavorService = new MarketingBusiFavorServiceImpl(this);
private final WxEntrustPapService wxEntrustPapService = new WxEntrustPapServiceImpl(this);
protected Map<String, WxPayConfig> configMap;
@@ -137,6 +139,11 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
this.entPayService = entPayService;
}
@Override
public WxEntrustPapService getWxEntrustPapService() {
return wxEntrustPapService;
}
@Override
public WxPayConfig getConfig() {
if (this.configMap.size() == 1) {

View File

@@ -0,0 +1,139 @@
package com.github.binarywang.wxpay.service.impl;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxEntrustPapService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import java.net.URLEncoder;
/**
* @author chenliang
* @date 2021-08-02 4:53 下午
*/
@Slf4j
@RequiredArgsConstructor
public class WxEntrustPapServiceImpl implements WxEntrustPapService {
private final WxPayService payService;
@Override
public String mpSign(WxMpEntrustRequest wxMpEntrustRequest) throws WxPayException {
StringBuilder signStrTemp = new StringBuilder(payService.getPayBaseUrl() + "/papay/entrustweb");
signStrTemp.append("?appid=").append(wxMpEntrustRequest.getAppid());
signStrTemp.append("&contract_code=").append(wxMpEntrustRequest.getContractCode());
signStrTemp.append("&contract_display_account=").append(URLEncoder.encode(wxMpEntrustRequest.getContractDisplayAccount()));
signStrTemp.append("&mch_id=").append(wxMpEntrustRequest.getMchId()).append("&notify_url=").append(URLEncoder.encode(wxMpEntrustRequest.getNotifyUrl()));
signStrTemp.append("&plan_id=").append(wxMpEntrustRequest.getPlanId()).append("&outerid=").append(URLEncoder.encode(wxMpEntrustRequest.getOuterId()));
signStrTemp.append("&request_serial=").append(wxMpEntrustRequest.getRequestSerial()).append("&timestamp=").append(wxMpEntrustRequest.getTimestamp());
signStrTemp.append("&version=").append(wxMpEntrustRequest.getVersion()).append("&return_web=").append(wxMpEntrustRequest.getReturnWeb()).append("&sign=").append(wxMpEntrustRequest.getSign());
return signStrTemp.toString();
}
@Override
public String maSign(WxMaEntrustRequest wxMaEntrustRequest) throws WxPayException {
wxMaEntrustRequest.checkAndSign(payService.getConfig());
wxMaEntrustRequest.setNotifyUrl(URLEncoder.encode(wxMaEntrustRequest.getNotifyUrl()));
return wxMaEntrustRequest.toString();
}
@Override
public WxH5EntrustResult h5Sign(WxH5EntrustRequest wxH5EntrustRequest) throws WxPayException {
wxH5EntrustRequest.checkAndSign(payService.getConfig());
String sign = SignUtils.createSign(wxH5EntrustRequest, WxPayConstants.SignType.HMAC_SHA256, payService.getConfig().getMchKey(), null);
/**
* https://api.mch.weixin.qq.com/papay/h5entrustweb?appid=wxxxxx&contract_code=001
* &contract_display_account=name1&mch_id=1223816102&notify_url=www.qq.com%2Ftest%2Fpapay&plan_id=106
* &request_serial=123&return_appid= wxcbda96de0b165542&clientip=12.1.1.12&timestamp=1414488825
* &version=1.0&sign= 130C7B07DD3B8074F7BF8BEF5C9A86487A1C57478F8C55587876B9C782F72036
*/
String url = payService.getPayBaseUrl() + "/papay/h5entrustweb";
StringBuilder strBuilder = new StringBuilder(url);
strBuilder.append("?appid=").append(wxH5EntrustRequest.getAppid());
strBuilder.append("&contract_code=").append(wxH5EntrustRequest.getContractCode());
strBuilder.append("&contract_display_account=").append(URLEncoder.encode(wxH5EntrustRequest.getContractDisplayAccount()));
strBuilder.append("&mch_id=").append(wxH5EntrustRequest.getMchId()).append("&notify_url=").append(URLEncoder.encode(wxH5EntrustRequest.getNotifyUrl()));
strBuilder.append("&plan_id=").append(wxH5EntrustRequest.getPlanId()).append("&outerid=").append(URLEncoder.encode(wxH5EntrustRequest.getOuterId()));
strBuilder.append("&return_appid=").append(wxH5EntrustRequest.getReturnAppid());
strBuilder.append("&clientip=").append(wxH5EntrustRequest.getClientIp());
strBuilder.append("&request_serial=").append(wxH5EntrustRequest.getRequestSerial()).append("&timestamp=").append(wxH5EntrustRequest.getTimestamp());
strBuilder.append("&version=").append(wxH5EntrustRequest.getVersion()).append("&sign=").append(sign);
log.debug("h5纯签约请求URL{}", strBuilder.toString());
String responseContent = payService.getV3(strBuilder.toString());
WxH5EntrustResult result = BaseWxPayResult.fromXML(responseContent, WxH5EntrustResult.class);
result.checkResult(payService, wxH5EntrustRequest.getSignType(), true);
return result;
}
@Override
public WxPayEntrustResult paySign(WxPayEntrustRequest wxPayEntrustRequest) throws WxPayException {
wxPayEntrustRequest.checkAndSign(payService.getConfig());
String url = payService.getPayBaseUrl() + "/pay/contractorder";
String responseContent = payService.post(url, wxPayEntrustRequest.toXML(), false);
WxPayEntrustResult result = BaseWxPayResult.fromXML(responseContent, WxPayEntrustResult.class);
result.checkResult(payService, wxPayEntrustRequest.getSignType(), true);
return result;
}
@Override
public WxWithholdResult withhold(WxWithholdRequest wxWithholdRequest) throws WxPayException {
wxWithholdRequest.checkAndSign(payService.getConfig());
String url = payService.getPayBaseUrl() + "/pay/pappayapply";
String responseContent = payService.post(url, wxWithholdRequest.toXML(), false);
WxWithholdResult result = BaseWxPayResult.fromXML(responseContent, WxWithholdResult.class);
result.checkResult(payService, wxWithholdRequest.getSignType(), true);
return result;
}
@Override
public String preWithhold(WxPreWithholdRequest wxPreWithholdRequest) throws WxPayException {
String requestParam = WxGsonBuilder.create().toJson(wxPreWithholdRequest);
String url = payService.getPayBaseUrl() + "/v3/papay/contracts/%s/notify"; // %s为{contract_id}
String httpResponse = payService.postV3(String.format(url, wxPreWithholdRequest.getContractId()), requestParam);
return httpResponse;
}
@Override
public WxSignQueryResult querySign(WxSignQueryRequest wxSignQueryRequest) throws WxPayException {
wxSignQueryRequest.checkAndSign(payService.getConfig());
String url = payService.getPayBaseUrl() + "/papay/querycontract";
String responseContent = payService.post(url, wxSignQueryRequest.toXML(), false);
WxSignQueryResult result = BaseWxPayResult.fromXML(responseContent, WxSignQueryResult.class);
result.checkResult(payService, wxSignQueryRequest.getSignType(), true);
return result;
}
@Override
public WxTerminationContractResult terminationContract(WxTerminatedContractRequest wxTerminatedContractRequest) throws WxPayException {
wxTerminatedContractRequest.checkAndSign(payService.getConfig());
String url = payService.getPayBaseUrl() + "/papay/deletecontract";
String responseContent = payService.post(url, wxTerminatedContractRequest.toXML(), false);
WxTerminationContractResult terminationContractResult = BaseWxPayResult.fromXML(responseContent, WxTerminationContractResult.class);
terminationContractResult.checkResult(payService, wxTerminatedContractRequest.getSignType(), true);
return terminationContractResult;
}
@Override
public WxWithholdOrderQueryResult papOrderQuery(WxWithholdOrderQueryRequest wxWithholdOrderQueryRequest) throws WxPayException {
wxWithholdOrderQueryRequest.checkAndSign(payService.getConfig());
String url = payService.getPayBaseUrl() + "/pay/paporderquery";
String responseContent = payService.post(url, wxWithholdOrderQueryRequest.toXML(), false);
WxWithholdOrderQueryResult wxWithholdOrderQueryResult = BaseWxPayResult.fromXML(responseContent, WxWithholdOrderQueryResult.class);
wxWithholdOrderQueryResult.checkResult(payService, wxWithholdOrderQueryRequest.getSignType(), true);
return wxWithholdOrderQueryResult;
}
}