支付功能设计(一)

实体设计: 

公共入参 
@ApiModelProperty("平台分配商户号")
private String merchantNo(新房分配:715938590265180167);
 
 
@ApiModelProperty("渠道")
private String channel(通联:80);
 
 
@ApiModelProperty("随机字符串")
private String randomStr;
 
 
@ApiModelProperty("签名")
private String sign;




公共返回 
sign:签名



统一返回结构体
/**
 * 错误业务码
 */
@ApiModelProperty(value = "返回码",notes = "200代表成功,其他全部是失败",example = "200")
private Integer code;
 
/**
 * 错误消息,外部使用的消息
 */
@ApiModelProperty(value = "汉字消息",example = "成功",notes = "如果异常的时候,可以直接展示在前端的消息内容")
private String msg;
 
/**
 * 返回的数据, 一般用来存储当时的数据,或一些重要信息 ,方便去查验错误
 */
@ApiModelProperty("数据")
private T data;


接口描述


1.下单

/pay/order

入参:

@ApiModelProperty("接入方支付订单ID")
private String bizOrderId;
 
@ApiModelProperty("支付渠道交易标识")
private Long amount;
 
@ApiModelProperty("收费类型")
private String receiptTypeName;
 
@ApiModelProperty("订购人姓名")
private String buyerName;
 
@ApiModelProperty("订购人地址")
private String buyerAddress;
 
@ApiModelProperty("订购人联系电话")
private String buyerPhone;
 
@ApiModelProperty("跟踪订单号")
private String businessTraceOrderNo;
 
@ApiModelProperty("证件类型")
private String identityType;
 
@ApiModelProperty("证件号")
private String identityNo;
 
@ApiModelProperty("成交金额")
private Long dealAmount;
返回:

@ApiModelProperty("接入方支付订单ID")
private String payId;
 
@ApiModelProperty("平台签名")
private String sign;




1.查询交易结果

http://域名/pay/query

入参:

@ApiModelProperty("接入方支付订单ID")
private String bizOrderId;
 
@ApiModelProperty("支付平台支付ID")
private String payId;
 
@ApiModelProperty("支付渠道交易标识")
private String channelOrderId;
返回:(payChannel->channel)

@ApiModelProperty("接入方支付订单ID")
private String bizOrderId;
 
@ApiModelProperty("支付平台支付ID")
private String payId;
 
@ApiModelProperty("支付渠道交易标识")
private String channelOrderId;
 
@ApiModelProperty("支付金额,单位分")
private String amount;
 
@ApiModelProperty("手续费,单位分")
private String fee;
 
@ApiModelProperty("支付状态")
private String status;
 
@ApiModelProperty("支付渠道")
private String channel;
 
@ApiModelProperty("支付卡号,POS刷卡返回")
private String payCardNo;
 
@ApiModelProperty("交易请求日期,格式:yyyymmdd")
private String payTime;
 
@ApiModelProperty("交易完成时间,格式:yyyymmddhhmmss")
private String finishTime;
 
@ApiModelProperty("终端号,POS刷卡返回")
private String termNo;


2.发起退款

http://域名/refund/apply

入参:

@ApiModelProperty("接入方支付订单ID")
private String bizOrderId;
 
@ApiModelProperty("支付平台支付ID")
private String payId;
 
@ApiModelProperty("退款金额,单位为分")
private String amount;
 
@ApiModelProperty("退款备注")
private String remark;
返回:

@ApiModelProperty("平台退款ID")
private String payRefundId;


3.查询退款结果

http://域名/refund/query

入参:

@ApiModelProperty("平台退款ID")
private String payRefundId;
返回:

@ApiModelProperty("支付平台定义退款ID")
private String payRefundId;
 
@ApiModelProperty("接入方支付ID(退款对应的收款业务方标识)")
private String bizOrderId;
 
@ApiModelProperty("平台支付ID(退款对应的收款支付平台支付ID)")
private String payId;
 
@ApiModelProperty("平台支付ID(退款对应的收款支付渠道交易标识)")
private String channelOrderId;
 
@ApiModelProperty("退款金额,单位分")
private String amount;
 
@ApiModelProperty("退款状态")
private String status;
 
@ApiModelProperty("退款完成时间 yyyyMMddHHmmss")
private String finishTime;


4.付款结果通知

入参:

@ApiModelProperty("接入方支付订单ID")
private String bizOrderId;
 
@ApiModelProperty("支付平台支付ID")
private String payId;
 
@ApiModelProperty("支付渠道交易标识")
private String channelOrderId;
 
@ApiModelProperty("支付金额,单位分")
private String amount;
 
@ApiModelProperty("手续费,单位分")
private String fee;
 
@ApiModelProperty("支付状态")
private String status;
 
@ApiModelProperty("支付渠道")
private String channel;
 
@ApiModelProperty("支付卡号,POS刷卡返回")
private String payCardNo;
 
@ApiModelProperty("交易请求日期,格式:yyyymmdd")
private String payTime;
 
@ApiModelProperty("交易完成时间,格式:yyyymmddhhmmss")
private String finishTime;
 
@ApiModelProperty("终端号,POS刷卡返回")
private String termNo;
返回:

字符串:success,否则会认为是通知失败



5.退款结果通知

入参:

@ApiModelProperty("支付平台定义退款ID")
private String payRefundId;
 
@ApiModelProperty("接入方支付ID(退款对应的收款业务方标识)")
private String bizOrderId;
 
@ApiModelProperty("平台支付ID(退款对应的收款支付平台支付ID)")
private String payId;
 
@ApiModelProperty("平台支付ID(退款对应的收款支付渠道交易标识)")
private String channelOrderId;
 
@ApiModelProperty("退款金额,单位分")
private String amount;
 
@ApiModelProperty("退款状态")
private String status;
 
@ApiModelProperty("退款完成时间 yyyyMMddHHmmss")
private String finishTime;
返回:

字符串:success,否则会认为是通知失败

微信支付

前端开发经常涉及到支付相关的场景,下面是关于集成微信支付的一些总结。

一、支付方式

微信支付的方式有很多,目前存在的微信支付方式有:

1、付款码支付

付款码支付是用户展示微信钱包内的“刷卡条码/二维码”给商户系统扫描后直接完成支付的模式。主要应用线下面对面收银的场景。

2、Native支付

Native支付是商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式。该模式适用于PC网站支付、实体店单品或订单支付、媒体广告支付等场景。

3、JSAPI支付

JSAPI支付是用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付。应用场景有:

◆ 用户在微信公众账号内进入商家公众号,打开某个主页面,完成支付
◆ 用户的好友在朋友圈、聊天窗口等分享商家页面连接,用户点击链接打开商家页面,完成支付
◆ 将商户页面转换成二维码,用户扫描二维码后在微信浏览器中打开页面后完成支付

4、APP支付

APP支付又称移动端支付,是商户通过在移动端应用APP中集成开放SDK调起微信支付模块完成支付的模式。

5、H5支付

H5支付主要是在手机、ipad等移动设备中通过浏览器来唤起微信支付的支付产品。

6、小程序支付

小程序支付是专门被定义使用在小程序中的支付产品。目前在小程序中能且只能使用小程序支付的方式来唤起微信支付。

 

其中,前端开发涉及到的支付方式主要有JSAPI支付、H5支付和小程序支付。

二、JSAPI支付

JSAPI支付必须是在微信APP内进行,比如用户在微信里打开经纪人分享到朋友圈的旅居页面,在感兴趣的旅居路线上报名,并点击支付,就会通过JSAPI调起微信支付。

开发前,需要先在微信商户平台(pay.weixin.qq.com)设置JSAPI支付支付目录(商户平台-->产品中心-->开发配置),JSAPI支付在请求支付的时候会校验请求来源是否有在商户平台做了配置,

所以必须确保支付目录已经正确的被配置,否则将验证失败,请求支付不成功。

实现JSAPI支付,前端的逻辑一般会有下面几个步骤:

 

1. 传入openId,调用下单接口
2. 通过微信浏览器私有接口调起支付: WeixinJSBridge.invoke('getBrandWCPayRequest',{appId, paySign, ...}) // 详细参数说明参考https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
3. 支付失败回调:res => if(get_brand_wcpay_request:cancel)
4. 支付成功回调:res => if(get_brand_wcpay_request:ok) => getPayResult(轮询支付结果) => 支付成功
5. 跳到订单详情页/支付结果页

 

PS:除了可以调用微信内置的WeixinJSBridge对象的getBrandWCPayRequest方法调起支付,还可以通过加载微信jssdk,使用wx.chooseWXPay方法调起支付(https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#59)。

实际上chooseWXPay方法内部还是调用了getBrandWCPayRequest方法,而使用getBrandWCPayRequest的话就不需要引入微信jssdk。

需要注意的是,商品是否真的支付成功,结果不是实时返回的,需要自己实现getPayResult接口进行轮询。

三、H5支付

H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前述页面确认使用微信支付时,商户发起本服务呼起微信客户端进行支付。

主要用于触屏版的手机浏览器请求微信支付的场景。可以方便的从外部浏览器唤起微信支付。

提醒:H5支付不建议在APP端使用,如需要在APP中使用微信支付,请接APP支付。

实现H5支付,前端的逻辑一般会有下面几个步骤:

 

1. 传入openId,调用下单接口
2. 拼接返回的支付地址,跳转到自己的支付信息页
3. 点击确认支付
4. 重定向到微信支付地址 (https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb
5. 跳回原来的确认支付页,并查询支付状态
6. 支付成功则提示已成功支付,并跳到订单详情页/支付结果页

 

跟JSAPI支付一样,H5支付真的购买成功,结果也不是实时返回的,需要自己实现接口进行轮询。

还需要注意的是,创建订单时,后端需要记住用户的ip,并与微信后台交互时传递这个值。微信会检测用户实际支付时的ip与我们后台传递的ip是否一致,

不一致的话会提示网络环境未能通过安全验证,请稍后再试

更详细的步骤可以参考下面的时序图:

四、小程序支付

小程序中能且只能使用小程序支付的方式来唤起微信支付,而在已有小程序支付的情况下,APP可以通过跳转到微信小程序的方式,来调起微信支付。

不过,iOS 端的微信小程序不支持虚拟支付(https://developers.weixin.qq.com/community/operate/detail/1006),开发类似网商卡和微信卖房高级版等收费的线上服务的产品前,需要特别注意。

 

实现小程序支付,前端的逻辑一般会有下面几个步骤:

1. 传入openId,调用下单接口
2. 通过微信小程序支付接口调起支付:wx.requestPayment({package, paySign, ...}) // 详细参数说明参考 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5
3. 支付失败回调fail函数 =>支付失败
4. 支付成功回调success函数 => 支付成功
5. 跳到订单详情页/支付结果页

 

更详细的步骤可以参考下面的时序图:

 

五、相关参考文档

微信授权:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

微信JSAPI支付:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1

微信H5支付:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_1

微信小程序支付:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=1