一、第三方第四方聚合支付平台及支付系统源码介绍
背景
如今,网购已经渗透到人们日常生活中的方方面面,做为网购的载体,互联网电商平台发展如火如荼,支付功能做为其不可或缺的一部分,实现起来,也有各种各样的方案。根据自己有限的认知,我主观上把目前行业内的支付实现方案做以下归类:(网站接入支付!就去优易个人免签支付平台)
持有支付业务许可证,又称支付牌照,自有支付品牌,比如阿里的支付宝、腾讯的微信支付(财付通)、京东的京东支付等;
自建第三方支付聚合平台,对接第三方支付(支付宝、微信支付、中国银联、各大商业银行直连等),为其自有订单提供支付功能;
一些研发资源有限的电商平台,选择市场中直接能提供全套聚合支付的支付平台,省去研发环节,能够以最短时间较低的成本为其平台提供支付功能。
我从开发者的角度,主要针对第二类,讲述怎么去构建商户自己的聚合支付平台,以及投产上线后所需要主意的事项,打造一套简单、稳定、高效的聚合支付平台。
整体设计
一个完善的聚合支付系统,拥有支付网关、主动对账、退款网关、支付/退款状态查询等功能模块。
我会以LNMP架构为基础,细分成六个章节对每一部分做尽量详细的说明。
聚合支付平台的核心,就是怎么合理的去管理接入的各种支付SDK,很多童鞋从官网下载到SDK,几乎不做任何逻辑修改,就直接放到项目的目录中使用,这样做虽然开发成本很低,但弊端颇多,首先要说的就是不易维护,各支付SDK代码结构、风格不一样,后期维护成功高;代码各自为政,没有统一的调用方法;配置分散,无法集中维护系统配置项;无法提供统一有效的日志数据等。因此,我建议首先定义一个Interface,代码如下:
- <?php
- defined('BASEPATH') OR exit('No direct script access allowed');
- /**
- * PaymentHandlerInterface
- *
- * PHP 5.4 compatibility interface
- *
- * @package CodeIgniter
- * @subpackage Libraries
- * @category Payment
- * @author Eric <think2017@gmail.com>
- * @link https://zhuanlan.zhihu.com/paycenter
- */
- interface PaymentHandlerInterface {
- public function doPay($payParams = array());
- public function doQuery($queryParams = array());
- public function doRefund($refundParams = array());
- public function doRefundQuery($refundNo);
- public function payNotifyHandler(&$input);
- public function refundNotifyHandler(&$input);
- }
然后,每次接入新的支付方式的过程,其实就是实现该Interface的过程。
通常情况下,一种支付方式有一个class[将其class备注为支付类]来实现,但面对一种支付方式提供了多种支付场景,比如微信(提供了公众号支付、APP支付、扫码支付、H5支付、小程序支付、微信免密代扣等)、中国银联(提供了PC网关支付、WAP支付、APP支付、银联云闪付等),我们该怎么办,我建议针对每种不同的支付场景,都有单独的class来实现,理由如下:
不同的支付场景,程序执行的流程也不一样,比如中国银联PC网关支付,是需要将支付报文通过客户端浏览器表单POST给银联支付网关,跳转至银联支付网页进行支付,而银联APP支付则是通过curl将支付报文提交给银联支付网关,再将其返回的tn码返回给商户APP,商户APP凭该tn码发起支付交易;
对订单系统的订单支付方式展示更加准确,分配给商户不同购物平台(PC端、H5端、APP)的支付方式id是唯一的。如果商户系统不同支付场景所申请的商户号不一样,则需要在推送至财务系统的支付方式也不能重复,否则无法对账;
支付类的代码逻辑只关注于自身的支付逻辑处理,不引入额外的判断流程。
那么,就有童鞋就会想到了,一个很头疼的问题,代码冗余。大部分第三方支付,虽然提供了不同支付场景,但基础接口都是一样的,只是部分参数不同,或支付流程上面的少许差别。这时候我们就要考虑好以第三方支付平台为单位来封装一个支付抽象类类,实现对第三方支付平台的所有api对接,不涉及到商户系统的业务流程,比如微信支付,我们创建一个Wechat_driver抽象类,代码如下图:
- <?php
- defined('BASEPATH') OR exit('No direct script access allowed');
- /**
- * Wechat_driver
- * 微信支付底层API
- * PHP 5.4 compatibility interface
- *
- * @package CodeIgniter
- * @subpackage Libraries
- * @category Payment
- * @author Eric <think2017@gmail.com>
- * @link https://zhuanlan.zhihu.com/paycenter
- */
- abstract class Wechat_driver implements PaymentHandlerInterface {
- use Payment_utils, Common_utils;
- protected $_config;
- /**
- * Class constructor
- *
- * @param array $apiConfig Configuration parameters
- * @return void
- */
- public function __construct(&$apiConfig)
- {
- $this->_config =& $apiConfig;
- }
- /**
- * 统一下单接口
- *
- * @param array $payParams
- * @return array $retval
- * code int 状态码
- * type string 支付凭证类型:prepay_id/code_url/mweb_url
- * data string 支付凭证
- */
- protected function unified_order($payParams)
- {
- }
- /**
- * 订单支付状态查询接口
- *
- * @param string $tradeNo 订单支付单号
- * @return array $retval
- * code int 状态码
- * data string 接口返回报文
- */
- public function order_query($tradeNo)
- {
- }
- /**
- * 微信支付/退款异步通知
- *
- * @param string $input 通知报文
- * @return array $retval
- * code int 状态码
- * data string 接口返回报文
- */
- public function notify(&$input)
- {
- }
- /**
- * 退款申请接口
- *
- * @param array $refundParams 退款单数据
- * trade_no string 订单支付单号
- * refund_no string 订单退款单号
- * total_fee float 订单实付金额
- * refund_fee float 退款申请金额
- * @return array $retval
- * code int 状态码
- * data string 接口返回报文
- */
- public function refund($refundParams)
- {
- }
- /**
- * 订单退款状态查询接口
- *
- * @param string $refundNo 订单退款单号
- * @return array $retval
- * code int 状态码
- * data string 接口返回报文
- */
- public function refund_query($refundNo)
- {
- }
- /**
- * 下载对账单
- * @param string $billDate 对账单日期
- * @param string $billType 对账单类型
- * @return array $retval
- * code int 状态码
- * data string 接口返回报文
- */
- protected function downloadbill($billDate, $billType)
- {
- }
- /**
- * 计算签名
- *
- * @param array $data 签名数据
- * @param string $signType 签名类型 md5/sha1
- * @return string 签名结果
- */
- private function unified_sign($data, $signType = 'md5')
- {
- }
有了上面的支付抽象类,针对每一种支付方法,都可以继承该抽象类,并拥有自己的独立的支付流程,比如:微信app支付,我们可以创建一个 Wechat_app_driver.php 支付子类,支付子类调用抽象类提供的各种底层api,来实现支付、查询、退款等功能,代码参考。
- <?php
- defined('BASEPATH') OR exit('No direct script access allowed');
- /**
- * Wechat_app_driver
- * 微信app支付中间层
- * PHP 5.4 compatibility interface
- *
- * @package CodeIgniter
- * @subpackage Libraries
- * @category Payment
- * @author Eric <think2017@gmail.com>
- * @link https://zhuanlan.zhihu.com/paycenter
- */
- class Wechat_app_driver extends Wechat_driver implements PaymentHandlerInterface {
- protected $_config;
- /**
- * Class constructor
- *
- * @param array $apiParams Configuration parameters
- * @return void
- */
- public function __construct(&$apiConfig)
- {
- $this->_config =& $apiConfig;
- }
- /**
- * 支付接口
- *
- * @param array $orderParams 支付订单参数
- * @return array response
- * code int 状态码
- * msg string 接口消息
- * data array 支付凭证类型:prepay_id
- */
- public function doPay($payParams = array())
- {
- $totalFee = (int)bcmul($payParams['total_fee'], 100);
- $aResponse = $this->unified_order([
- 'trade_type' => 'APP',
- 'total_fee' => $totalFee,
- 'trade_no' => $payParams['trade_no'],
- 'openid' => $payParams['openid'] ? $payParams['openid'] : '',
- ]);
- if ($aResponse['code'] == 200) {
- $this->response(['code' => 200, 'data' => ['prepayid' => $aResponse['data']['value']], 'msg' => 'success.']);
- } else {
- $this->response(['code' => 500, 'data' => null, 'msg' => 'unifiedorder error.']);
- }
- }
- /**
- * 订单查询接口
- *
- * @param array $queryParams 订单查询参数
- * string $trade_no 支付单号
- * @return array
- */
- public function doQuery($queryParams = array())
- {
- return $this->order_query($queryParams['trade_no']);
- }
- /**
- * 订单退款申请接口
- *
- * @param string $refundParams 退款单数据
- * @return array
- */
- public function doRefund($refundParams = array())
- {
- return $this->refund($refundParams);
- }
- /**
- * 订单退款状态查询接口
- *
- * @param string $refundNo 订单退款单号
- * @return array
- */
- public function doRefundQuery($refundNo)
- {
- return $this->refund_query($refundNo);
- }
- /**
- * 支付通知报文解析验签
- *
- * @param string $tradeNo 通知报文
- * @return array
- */
- public function payNotifyHandler(&$input)
- {
- return $this->notify($input);
- }
- /**
- * 退款通知报文解析验签
- *
- * @param string $input 通知报文
- * @return array
- */
- public function refundNotifyHandler(&$input)
- {
- return;
- }
- }
上面分别提到了 支付Interface、支付抽象类、支付子类三种支付类,它们之间的关系是怎样的,见下图
以下UML类图,只以微信、银联部分类为基础,可参考。(网站接入支付!就去U易个人免签支付平台)
对上图做简要说明,
PaymentHandlerInterface是所有支付类的接口,系统所有支付功能类都需要实现它;
Wechat_driver、Unionpay_driver为对接第三方支付接口的支付抽象类,需要实现第三方支付接口的所有API交互,为支付功能类提供功能方法;
Wechat_app_driver、Wechat_mweb_driver、Wechat_native_driver、Unionpay_app_driver、Unionpay_wap_driver为系统支付功能类,调用抽象类的各基础方法,为系统提供支付、查询、退款、退款查询等功能;
Common_utils、Payment_utils为系统工具类,Common_utils可提供诸如curl封装、日志函数、dns查询等系统可以通用的方法,Payment_utils可封装xml数据解析、各种加密解密函数等第三方支付平台所需的方法;
二、聚合二维码支付收款平台介绍
无现金支付成时代潮流,对于我们现在人来说:中国已经成为移动支付发展最快的一个国家,现在基本上都已经实现了无现金支付。大家都是使用支付宝、微信、等其他的移动支付平台来实现移动支付。
手机的快速发展,加速了移动支付行业的发展,以及加速了支付行业的兴起。比如:支付二维码代理、各种pos机业务一、
聚合收款平台介绍:
支付方式除了支付宝、微信就属要说三方支付了,比如说:付呗、翼支付,他们都属于三方支付中的一种,这些支付方式和支付宝、微信差不多。主要经营支付二维码。或者是支付二维码之类的,可以说是三方支付行业的巨头!
支付宝:
支付宝是可以说支付行业的大佬,出门消费,几乎所有的商户都支持支付宝消费,每日的成交量不可估量,在市场上占据了大半个江山。支付宝不仅作为移动平台,而且连接到生活的方方面面,使用率在不断的上升。
微信
微信不单单是一种聊天工具,也是一种。带着智能手机,走到哪就打开微信二维码,轻松一扫就能完成支付和收款,使用的范围不必支付宝的小,越来越多的移动支付平台正在潜移默化的影响着每一个的消费方式,为生活提供了便利不说,还促进了社会的进步与发展。
为什么聚合支付盛行?
现在支付不用现金,都是用手机支付,而且使用现金还需要找零。而且可大商户门店都使用这两种支付平台最常见。但是只有这两种支付方式但是又有点单一。
如果使用聚合二维码支付是不是快捷很多。
而且快捷支付=“聚合二维码”就可以使用多种支付方式,不会局限一种,可以一张码实现:支付宝、微信、云支付、银联、百度钱包等多种支付渠道!
三、免签支付平台源码介绍
最常用的免签支付平台就是微信支付和支付宝支付,QQ钱包等。
(网站接入支付!就去优易个人免签支付平台)