记录一个完善的多支付方式的支付业务流程
订单与支付,只要涉及到钱的,就会存在支付流程。
通常,可以有多种支付,比如余额,第三方支付(支付宝、微信)等
到目前为止,已经写了很多支付相关的代码,几乎倒背如流,现在总结一下过程与逻辑。
简单唯一的后端接口
后端接口,只设计一个接口,主要是为了简单,如果前端需要调用多个接口,则容易混乱。
核心方法:function pay()
该方法,有三个步骤。
- 判断是否传递了订单号 ordernum,如果没有,则自动调用 deal (下单)方法,参数为 pay 参数,并返回 deal 方法的结果。
- 已经有了订单号,那么先判断是否存在 paytype,如果没有 paytype,则根据传递的订单号返回 deal 方法相同的结果
- 如果存在 paytype ,则进行 paycheck 方法,如果paycheck通过,则调用公共方法,完成订单,并自动执行 paySuccess 方法
下单并生成订单
下单,首先要接收前端传递的参数, 根据参数识别购买的东西,并计算得到金额。
此时,要插入2条不同的数据到数据库,第一条是调用公共方法并插入到公共表(?有一个公共表 pay_log,用于记录所有的订单,用于记录 paytype(支付方式),paydate(下单时间),支付状态(paystate))
建立公共订单的作用,是为了统一支付,毕竟想要自动完成多种支付方式自动支付,至少得有一个统一的表。
第二个表,是具体业务的订单表,比如买了什么商品,商品的id是什么?商品的参数是什么,这个记录得手动插入。
两条记录插入完毕,返回订单对象给前端(比如包括了订单号,订单有效期(一般30分钟内有效),订单金额 等)。
返回订单信息
这里的返回,和上一步是一模一样的。但是有必要性。
比如第一次生成订单时,用户点击了关闭,那么用户在“我的订单”列表里,找到了未支付的订单,再点击“支付”。
此时,仅有一个参数,那就是订单号:ordernum
我们需要根据订单号,也同样还原订单对象,比如订单有效期,订单金额,xxx等,以便用户可以继续支付
支付订单
支付订单,可能需要传递的参数:订单号(ordernum),支付方式(paytype),支付密码(paypwd)
支付密码,不是必须的,比如调起了支付宝,则和当前平台无关。而如果是本平台的密码支付,则需要支付密码
首先根据订单号,支付方式,支付密码,进行校验,校验的内容可以是:支付密码是否正确,是否触发具体的商品购买限制?(比如抢购类,下单时库存还是够的,但是支付时就不够了。。。)
校验完毕,确定满足支付状态。则调用公共方法,进行反射,动态获取 paytype 已经写好的支付代码。
paytype的代码前篇一律,比如余额支付,包括了:校验订单的状态是否正常(应该是未支付状态,避免重复支付),扣除用户的余额,修改订单的状态,执行 paySuccess方法。
到此,实际已经完成支付。但是这里有一个点没说清除,就是paySuccess。
支付完成的回调
比如第三方支付,支付宝、微信等,实际是异步完成的。
我们无法控制它什么时候完成, 但我们写了回调方法,只要它完成了就会触发回调。
那么为了规范起见,即使是余额支付(无论什么支付),也调用该方法(也就是把支付完成的逻辑,全部写在该方法中,而不要重复写)。
paySuccess,就是该回调。
在回调里,比如记录订单的完成时间。记录订单的支付方式(为什么在这时候记录?因为只要真正完成了,才确定支付方式到底是什么),以及通知用户(提醒用户,订单支付成功)等
(还有一种可能,就是抢购类,为了卖得更多,但是库存在高并发下超售了,此时使用的是“付款减库存”,那么判断一下是否超售,超售则该订单无效,可以在paySuccess自动退款)
这样,整个过程就比较完善了。
总结
涉及两张表:业务订单表,公共订单表(pay_log)
生成订单号的方法(没有参数):create_ordernum()
生成订单对象的方法(有参数如ordernum,money, title):createPayForm()
支付校验的方法(支付前校验的方法,也就是得到ordernum后、支付前的校验):payCheck()
核心支付方法(前端只调这一个方法):pay()
支付完成方法(有参数如money, paytype, payreturn(支付完成给前端展示的重定向后的url),用于反射并自动完成不同支付方式逻辑的公共函数):payFinish()
支付回调方法:paySuccess()
文章作者: 朱丰华
文章链接: https://smart.52dixiaowo.com/blog/post-27.html
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。