微信支付分
一.微信支付分介绍
1.1 什么是微信支付分
微信支付分是对个人的身份特质、支付行为、使用历史等情况的综合计算分值,旨在为用户提供更简单便捷的生活方式。
(1)用户可在具体应用场景中,开通微信支付分,此为最常见的开通方法。开通后,用户可以在【微信 > 我 > 服务 > 钱包 > 支付分】中查看分数和使用记录。
(2)用户可在【微信 > 我 > 服务 > 钱包 > 支付分】直接点击,刷脸开通,此方法开通支付分后,用户仅能查看自己的分数,如需使用应用场景中的服务,仍需在应用场景中开启服务
说明:用户只需在某一个应用场景中开通一次(开通分数+开通免密代扣),即可在其他应用场景使用支付分功能,无需再次开通分数或开通免密代扣。
1.2 微信支付分应用场景
免押租借:适用于物品租借场景,例如共享充电宝、共享雨伞、线上租赁平台等场景,用户支付分达到商户设置的分数门槛,即有机会获得免交押金权益。
免押速住:适用于酒店行业,用户支付分达到商户设置的分数门槛,即有机会获得免住宿押金,免预付房费等权益。
先享后付:适用于需预付费等场景,例如:电商、网约车、寄快递、电动车充电、共享按摩椅等,用户支付分达到商户设置的分数门槛,即有机会获得先享受服务,后付款的权益。
智慧零售:适用于无人零售机柜,用户支付分达到商户设置的分数门槛,即有机会开柜购物。
1.3 商户接入微信支付分意义
设置分数门槛,筛选合适用户的能力,分数达到或超过该分数门槛的用户,才可以享受对应的服务(例如免押金,免预充值等)。
免密代扣能力,服务结束后,进行免密扣款。
催收能力。
二.微信支付分实战
2.1 微信支付分对接流程图
1.微信用户扫描二维码进入购买小程序,此时微信用户没有授权。返回用户登录授权界面。
2.微信用户发启同意授权这个操作。
3.前端获取微信用户授权这个动作。
4.根据用户授权动作去调用微信授权接口。
5.微信返回当前微信用户加密过后的jsCode。
6.前端封装jsCode参数调用后端接口。
7.后端接口通过mchid,appid,jsCode参数调用微信解析用户信息接口。
8.解析成功得到当前微信用户的session_key,openid并存入数据库中。
9.微信用户成功进入到购买小程序中(这里的2到8步骤几乎都是一瞬间就执行的事,现实生活中,微信用户点击用户授权就进入购买小程序中!用户无法感知2到8步骤所执行的流程!)
10.用户使用购买小程序,需要签约微信支付分。
11.前端根据用户信息调用后端接口。
12.后端接口通过用户信息拿到对应的openid调用微信是否签约接口。
13.得到是否签约微信支付分结果。
这里根据签约结果有两种不同的流程走向:
第一种走向 Y:
14.验证已经签约微信支付分,则返回信息给前端。
15.用户即可使用购买小程序进行免密支付!
第二种走向 N:
14.验证当前用户openid没有签约微信支付分,则后端通过openid调用微信签约支付分接口。
15.签约微信支付分接口返回一个sign_token给后端,此时还没有签约成功。
16.后端将sign_token返回给前端。
17.前端通过sign_token调用微信支付分确认签约接口。此时签约成功。
18.微信支付分签约成功后,微信回调后端接口。同时用户即可使用购买小程序进行免密支付!这里两个是异步进行的。
2.2 微信支付分代码实战
单元测试代码:
@SpringBootTest
@Slf4j
public class UserMpApiApplicationTests {
@Resource
private WxPayConfigHandler wxPayConfigHandler;
@Resource
private AppProperties appProperties;
@Resource
private WxMaService wxMaService;
@Resource
private UserService userService;
@Resource
private RedisService redisService;
@Bean(name = "myWxPayService")
public WxPayService wxPayService() {
return new WxPayServiceImpl(
WxPayConfig.builder()
.appId(appProperties.getWxPayScorConfig().getAppId())
.mchId(appProperties.getWxPayScorConfig().getMchId())
.apiV3Key(appProperties.getWxPayScorConfig().getApiV3Key())
.certSerialNo(appProperties.getWxPayScorConfig().getCertSerialNo())
.certPrivateKey(appProperties.getWxPayScorConfig().getCertPrivateKey())
.serviceId(appProperties.getWxPayScorConfig().getServiceId())
.build()
);
}
@Resource
private WxPayService myWxPayService;
// 公司微信支付分流程(文字描述)
// 用户第一次扫描货柜二维码时,需要登录,这个时候前端通过微信接口获取微信用户的jsCode传给后端,后端拿着jsCode通过mchid等参数调用微信解析接口获取到用户手机号,openid等
// 获取到用户手机号,openid存入user表中
// 货柜开门之前,后端需要判断当前用户是否签约微信支付分,如果当前用户没有,则返回用户对应的签约支付分信息给前端,让前端回显给用户签约,这里签约是前端通过参数直接调用微信签约接口,签约成功回调后端接口
// 公司微信支付分流程(代码实现)
// 登录得到jsCode这个需要前端调微信接口 我们通过jsCode调微信接口解析得到用户手机号,openid等
// 微信授权用户登录 获取用户信息
@Test
public void wxUserlogin(String jsCode) throws WxErrorException {
WxMaJscode2SessionResult wxMaJscode2SessionResult = wxMaService.getUserService().getSessionInfo(jsCode);
log.info("解析得到用户信息为:" + wxMaJscode2SessionResult);
}
// 从user表中,取出两个用户的openId
// 手机号 openId 姓名 是否签约支付分
// 187****2275 ow_bf4pMuDRUWEBt9U7BKbBFAxXU 魏* 是
// 150****1233 ow_bf4pkyYlKbQUJfy8DddJa0IrE 冯** 是
// ow_bf4pMuDRUWEBt9U7BKbBFAxXU 验证签约结果为:PayScorePermitQueryResult(appId=wx99bdea96b81e039d, mchId=1607014288, serviceId=00004000000000161536318681131017, openId=ow_bf4pMuDRUWEBt9U7BKbBFAxXU, authorizationCode=20221019185927000016, authorizationState=AVAILABLE, cancelAuthorizationTime=null, authorizationSuccessTime=2022-10-19T18:59:37+08:00)
// ow_bf4pMuDRUWEBt9U7BKbBFAxXU 验证签约结果为:PayScorePermitQueryResult(serviceId=00004000000000161536318681131017, openId=ow_bf4pMuDRUWEBt9U7BKbBFAxXU, authorizationCode=20221019185927000016, authorizationState=UNAVAILABLE, cancelAuthorizationTime=2023-05-18T16:08:31+08:00, authorizationSuccessTime=2022-10-19T18:59:37+08:00)
// ow_bf4pkyYlKbQUJfy8DddJa0IrE 验证签约结果为:PayScorePermitQueryResult(appId=wx99bdea96b81e039d, mchId=1607014288, serviceId=00004000000000161536318681131017, openId=ow_bf4pkyYlKbQUJfy8DddJa0IrE, authorizationCode=20220826122959006796, authorizationState=AVAILABLE, cancelAuthorizationTime=null, authorizationSuccessTime=2022-08-26T12:30:05+08:00)
// authorizationState=AVAILABLE 说明签约成功
// authorizationState=UNAVAILABLE 说明没签约
// 验证用户是否签约支付分
@Test
public void signCheck() {
PayScorePermitQueryResult papPayContractQueryResult = wxPayConfigHandler.wxPayConfig(0L).getPayScoreService().permitQuery("ow_bf4pMuDRUWEBt9U7BKbBFAxXU");
log.info("验证签约结果为:" + papPayContractQueryResult);
}
// 用户没有签约支付分 则查询支付分参数返回给前端调用微信接口进行签约
@Test
public void signInfo() {
// 获取用户登录购买小程序时的信息
User user = userService.getByOpenId("ow_bf4pMuDRUWEBt9U7BKbBFAxXU");
// 唯一
String authCode = DateUtils.format(new Date(), "yyyyMMddHHmmss") + String.format("%06d", redisService.getLoopId(RedisIDKeyEnum.USER));
PayScorePermitCreateResult payScorePermitCreateResult = wxPayConfigHandler.wxPayConfig(0L).getPayScoreService().permitCreate(
PayScorePermitCreateRequest.builder()
.authorizationCode(authCode)
.notifyUrl(appProperties.getDomain() + "/user/sign/" + user.getId() + "/" + 0 + "/wx_notify/v1")
.build()
);
log.info("微信签约用户:" + user.getId() + "------" + JSON.toJSONString(payScorePermitCreateResult));
Map<String, String> rtnMap = new HashMap<>();
if (payScorePermitCreateResult != null && payScorePermitCreateResult.getCode().equals("SUCCESS")) {
rtnMap.put("sign_token", payScorePermitCreateResult.getApplyPermissionsToken());
rtnMap.put("apply_permissions_token", payScorePermitCreateResult.getApplyPermissionsToken());
}
// 注意:这里的如果前端不授权确认调用微信接口,则授权支付分失败。只有前端根据token调用微信接口成功后回调我们接口进行逻辑处理
log.info("前端根据tokne调用微信接口授权支付分:" + rtnMap);
}
// 创建微信支付分订单
@Test
public void createOrder() {
// 订单id
String orderId = "1234567894";
// 公司商户id
String mctId = "21090911402000008";
// 微信支付分创建订单
PayScoreOrderCreateResult payScoreOrderCreateResult = wxPayConfigHandler.wxPayConfig(0L).getPayScoreService().orderCreate(
PayScoreOrderCreateRequest.builder()
// 订单号
.outOrderNo(orderId)
.serviceIntroduction("智慧零售")
.location(
PayScoreOrderCreateRequest.Location.builder()
.startLocation("魏凯的商户测试")
.endLocation("魏凯的商户测试")
.build()
)
.timeRange(
PayScoreOrderCreateRequest.TimeRange.builder()
.startTime(DateUtils.format(new Date(), "yyyyMMdd"))
.build()
)
.riskFund(
PayScoreOrderCreateRequest.RiskFund.builder()
.name("ESTIMATE_ORDER_COST")
.amount(500)
.build()
)
.attach(mctId)
.notifyUrl(appProperties.getPaymentApi() + "/pay_score/notify/pay/" + mctId + "/" + orderId)
// 微信用户在商户对应appid下的唯一标识。
.openId("ow_bf4pMuDRUWEBt9U7BKbBFAxXU")
.needUserConfirm(false)
.build()
);
log.info("订单创建成功:" + payScoreOrderCreateResult);
}
// 取消订单
@Test
public void closeOrder() {
PayScoreOrderCancelResult payScoreOrderCancelResult = myWxPayService.getPayScoreService().orderCancel("1234567891", "取消支付分订单");
log.info("取消支付分订单:" + payScoreOrderCancelResult);
}
// state CREATED:商户已创建服务订单;DOING:服务订单进行中;DONE:服务订单完成;REVOKED:商户取消服务订单;
// 查询订单
@Test
public void queryOrder() {
PayScoreOrderQueryResult payScoreOrderQueryResult = myWxPayService.getPayScoreService().orderQuery("1234567892");
log.info("当前订单状态:" + payScoreOrderQueryResult);
}
// 订单完结(付款)
@Test
public void payOrder() {
List<PayScoreOrderCompleteRequest.PostPayment> postPayments = new ArrayList<>();
postPayments.add(
PayScoreOrderCompleteRequest.PostPayment.builder()
.name("用户购物")
// 1分钱
.amount(1)
.build()
);
PayScoreOrderCompleteResult payScoreOrderCompleteResult = myWxPayService.getPayScoreService().orderComplete(
"1234567894",
PayScoreOrderCompleteRequest.builder()
.postPayments(postPayments)
// 1分钱
.totalAmount(1)
.timeRange(
PayScoreOrderCompleteRequest.TimeRange.builder()
.endTime(DateUtils.format(new Date(), "yyyyMMdd"))
.build()
)
.build()
);
log.info("支付分订单完结:" + JSON.toJSONString(payScoreOrderCompleteResult));
}
// 订单退款
@Test
public void refundOrder() {
// 这个参数是订单支付成功后,回调所得到的。每个订单号支付成功对应一个微信支付成功单号
String wxOrderId = "4200001866202305188849577870";
String refundId = DateUtils.format(new Date(), "yyMMddHHmmss") + "0" + String.format("%05d", redisService.getLoopId(RedisIDKeyEnum.TRANSACTION));
WxPayOrderRefundResult payScorePermitCreateResult = myWxPayService.orderRefund(
WxPayOrderRefundRequest.builder()
// 原支付交易对应的微信订单号 不是我们的orderId
.transactionId(wxOrderId)
// 商户系统内部的退款单号
.outRefundNo(refundId)
.notifyUrl(appProperties.getPaymentApi() + "/pay_score/notify/refund/" + wxOrderId + "/" + refundId)
.amount(
WxPayOrderRefundRequest.Amount.builder()
// 退款金额
.refund(1)
// 原订单金额
.total(1)
.currency("CNY")
.build()
)
.build()
);
log.info("订单退款:" + payScorePermitCreateResult);
}
}
启动时,注入类介绍:
通过前端直接请求微信用户授权接口返回的jsCode调用后端接口解析出当前微信用户的openId:
@Test
public void wxUserlogin(String jsCode) throws WxErrorException {
WxMaJscode2SessionResult wxMaJscode2SessionResult = wxMaService.getUserService().getSessionInfo(jsCode);
log.info("解析得到微信用户标识信息为:" + wxMaJscode2SessionResult);
}
根据用户授权得到的openId验证当前用户是否签约微信支付分:
@Test
public void signCheck() {
PayScorePermitQueryResult papPayContractQueryResult = myWxPayService.getPayScoreService().permitQuery("ow_bf4pMuDRUWEBt9U7BKbBFAxXU");
log.info("验证签约结果为:" + papPayContractQueryResult);
}
验证签约结果为:PayScorePermitQueryResult(serviceId=00004000000000161536318681131017, openId=ow_bf4pMuDRUWEBt9U7BKbBFAxXU, authorizationCode=20221019185927000016, authorizationState=AVAILABLE, cancelAuthorizationTime=null, authorizationSuccessTime=2022-10-19T18:59:37+08:00)
authorizationState=AVAILABLE 说明已成功,authorizationState=UNAVAILABLE 说明没签约
查询支付分参数返回给前端调用微信接口进行签约:
@Test
public void signInfo() {
// 获取用户登录购买小程序时的信息 openId
User user = userService.getByOpenId("ow_bf4pMuDRUWEBt9U7BKbBFAxXU");
// 用户每次签约支付分的唯一标识
String authCode = DateUtils.format(new Date(), "yyyyMMddHHmmss") + String.format("%06d", redisService.getLoopId(RedisIDKeyEnum.USER));
PayScorePermitCreateResult payScorePermitCreateResult = myWxPayService.getPayScoreService().permitCreate(
PayScorePermitCreateRequest.builder()
// 唯一标识
.authorizationCode(authCode)
// 前端通过sign_token调用微信签约接口成功时,回调地址
.notifyUrl(appProperties.getDomain() + "/user/sign/" + user.getId() + "/" + 0 + "/wx_notify/v1")
.build()
);
log.info("微信签约用户:" + user.getId() + "------" + JSON.toJSONString(payScorePermitCreateResult));
Map<String, String> rtnMap = new HashMap<>();
if (payScorePermitCreateResult != null && payScorePermitCreateResult.getCode().equals("SUCCESS")) {
rtnMap.put("sign_token", payScorePermitCreateResult.getApplyPermissionsToken());
rtnMap.put("apply_permissions_token", payScorePermitCreateResult.getApplyPermissionsToken());
}
// 注意:这里的如果前端不授权确认调用微信接口,则授权支付分失败。只有前端根据token调用微信接口成功后回调我们接口进行逻辑处理
log.info("前端根据tokne调用微信接口授权支付分:" + rtnMap);
}
创建微信支付分订单:
// 创建微信支付分订单
@Test
public void createOrder() {
// 订单id 随便填一个
String orderId = "1234567896";
// 微信支付分创建订单
PayScoreOrderCreateResult payScoreOrderCreateResult = myWxPayService.getPayScoreService().orderCreate(
PayScoreOrderCreateRequest.builder()
// 订单号
.outOrderNo(orderId)
.serviceIntroduction("智慧零售")
.location(
PayScoreOrderCreateRequest.Location.builder()
.startLocation("魏凯的商户测试")
.endLocation("魏凯的商户测试")
.build()
)
.timeRange(
PayScoreOrderCreateRequest.TimeRange.builder()
.startTime(DateUtils.format(new Date(), "yyyyMMdd"))
.build()
)
.riskFund(
PayScoreOrderCreateRequest.RiskFund.builder()
.name("ESTIMATE_ORDER_COST")
.amount(500)
.build()
)
.notifyUrl(appProperties.getPaymentApi() + "/pay_score/notify/pay/" + orderId)
// 微信用户在商户对应appid下的唯一标识。
.openId("ow_bf4pMuDRUWEBt9U7BKbBFAxXU")
.needUserConfirm(false)
.build()
);
log.info("订单创建成功:" + payScoreOrderCreateResult);
}
取消订单:
@Test
public void closeOrder() {
PayScoreOrderCancelResult payScoreOrderCancelResult = myWxPayService.getPayScoreService().orderCancel("1234567896", "取消支付分订单");
log.info("取消支付分订单:" + payScoreOrderCancelResult);
}
查询订单状态:
// 查询订单
@Test
public void queryOrder() {
PayScoreOrderQueryResult payScoreOrderQueryResult = myWxPayService.getPayScoreService().orderQuery("1234567896");
log.info("当前订单状态:" + payScoreOrderQueryResult);
}
完结订单(付款):
@Test
public void payOrder() {
List<PayScoreOrderCompleteRequest.PostPayment> postPayments = new ArrayList<>();
postPayments.add(
PayScoreOrderCompleteRequest.PostPayment.builder()
.name("用户购物")
// 1分钱
.amount(1)
.build()
);
PayScoreOrderCompleteResult payScoreOrderCompleteResult = myWxPayService.getPayScoreService().orderComplete(
"1234567896",
PayScoreOrderCompleteRequest.builder()
.postPayments(postPayments)
// 1分钱
.totalAmount(1)
.timeRange(
PayScoreOrderCompleteRequest.TimeRange.builder()
.endTime(DateUtils.format(new Date(), "yyyyMMdd"))
.build()
)
.build()
);
log.info("支付分订单完结:" + JSON.toJSONString(payScoreOrderCompleteResult));
}
这里支付成功后,会回调接口,获取接口中的transactionId,退款需要用到这个id 4200001885202305196566109027
订单退款:
@Test
public void refundOrder() {
// 这个参数是订单支付成功后,回调所得到的。每个订单号支付成功对应一个微信支付成功单号
String wxOrderId = "4200001885202305196566109027";
String refundId = DateUtils.format(new Date(), "yyMMddHHmmss") + "0" + String.format("%05d", redisService.getLoopId(RedisIDKeyEnum.TRANSACTION));
WxPayOrderRefundResult payScorePermitCreateResult = myWxPayService.orderRefund(
WxPayOrderRefundRequest.builder()
// 原支付交易对应的微信订单号 不是我们的orderId
.transactionId(wxOrderId)
// 商户系统内部的退款单号
.outRefundNo(refundId)
.notifyUrl(appProperties.getPaymentApi() + "/pay_score/notify/refund/" + wxOrderId + "/" + refundId)
.amount(
WxPayOrderRefundRequest.Amount.builder()
// 退款金额
.refund(1)
// 原订单金额
.total(1)
.currency("CNY")
.build()
)
.build()
);
log.info("订单退款:" + payScorePermitCreateResult);
}
2.3 微信支付分官方文档
网站地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_14.shtml
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/234914.html