总结一下微信支付的企业分账功能,自己前前后后折腾了一两天,也给后来的同学一个参考
关于分账这个功能,可能应用的也比较少,网上相关的资料也比较少
关于分账功能的应用场景,可以参考微信官方文档 https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=26_1
使用PHP 进行开发(毕竟PHP是世界上最好的语言)
所使用到的环境或包或者工具
本地环境 Windows10
线上环境:
服务器 CentOS 7.3
宝塔Linux面板6.9
ThinkPHP5.1.38
PHP 7.3.4
MySQL 5.7
Nginx -Tengine2.2
Redis 5.0.4
think-queue 2.0.4 (注意:3.X是TP6使用的,目前TP5.1对应的是2.X版本)
关于TP的队列,可以参考大佬的文章 https://github.com/coolseven/notes/blob/master/thinkphp-queue/README.md
php-redis 拓展
Supervisor 进程守护
本文的微信开发使用的是EasyWechat
当前版本是4.1
官网https://www.easywechat.com/
EasyWechat的环境要求如下
安装EasyWechat
composer require overtrue/wechat:~4.0 -vvv
EasyWechat 官网的文档中没有分账功能的介绍,但是通过阅读源码发现其实这个功能是有的。那么下面会进行使用介绍
首先说一下分账的流程,官方给的图
从图里得知,要实现分账功能需要在统一下单的API参数里多加一个参数 profit_sharing = 'Y'
等用户支付了之后,订单资金会进行冻结,订单进行分账,分账完毕之后,解冻资金,就可以进行后续资金操作了。
大概步骤:微信支付后的回调(支付结果通知)=>在回调处理中将数据处理好(例如更新订单表)=>将需要分账的人或者商户号和需要分账金额的数据处理完毕=>插入到队列中=>读取队列的数据=>开始分账=>分账完毕(成功或者失败)
下列的分账任务我们将其 命名为 ProfitSharingJob
1、确认订单已经支付后(微信支付回调通知),处理好需要分账的数据
发布任务的关键代码
Queue::later(30,'app\\api\\job\\ProfitSharing',$notify_arr,'ProfitSharingJob');
参数:
30,因为微信推荐的是订单20秒后再分账,这里延后30秒执行这个任务。
'app\\api\\job\\ProfitSharing' 任务文件的完整命名空间
$notify_arr 组装好的数组
‘ProfitSharingJob’ 任务名称
对队列不熟悉的同学请参考文章开头提供的队列教程。
队列的配置文件位于项目配置 config/queue.conf
将Think-queue的默认驱动调整为Redis
'Redis',
'expire' => null, // 任务的过期时间,默认为60秒; 若要禁用,则设置为 null
'default' => 'think-queue', // 默认的队列名称
'host' => '127.0.0.1', // redis 主机ip
'port' => 6379, // redis 端口
'password' => '', // redis 密码
'select' => 1, // 使用哪一个 db,默认为 db0
'timeout' => 0, // redis连接的超时时间
'persistent' => false, // 是否是长连接
];
新建一个php文件用于接收任务,位于application/api/job,命名为ProfitSharing
写入如下代码
attempts() > 5){
$job->delete();
}else{
//调用分账
$res = $this->profitSharing($data);
if ($res){
//执行成功则删除这个任务
$job->delete();
return ;
}
else{
//重试
$job->release(30);
}
}
}
//失败了之后执行
public function failed($data){
Log::error($data);
}
//分账功能
public function profitSharing($data){
//具体分账的业务逻辑
$wx_pay = new WxPay();
return $wx_pay->profitSharing($data);
}
}
具体的业务逻辑
先添加分账人到微信服务器:
我是写在service层
先引入easywechat
use EasyWeChat\Factory;
构造函数里写好配置或者写在某个基类里。
public $config;
function __construct()
{
//CLI模式下config只能通过load方法去加载位于application下的模块配置文件
$wxPay = \think\facade\Config::load(\think\facade\Env::get('root_path').'application/api/config/wxPay.php');
$this->config = [
'app_id' => $wxPay['app_id'],
'mch_id' => $wxPay['mch_id'],
'key' => $wxPay['mch_key'],
'cert_path' => $wxPay['cert_path'],
'key_path' => $wxPay['key_path'],
'log' => [
'level' => 'debug',
'file' => Env::get('root_path').'/runtime/log/easywechat.log',
],
];
}
添加收账方代码如下:
如果是个人传入openid或者微信号
商户则传入商户号
type变量接收如下三个参数中的一个
MERCHANT_ID:商户ID
PERSONAL_WECHATID:个人微信号
PERSONAL_OPENID:个人openid
//添加分账接收方
public function addReceiver($openid,$type){
$r = Factory::payment($this->config);
$res = $r->profit_sharing->addReceiver([
//个人类型
'type' => $type,
'account' => $openid,
'relation_type' => 'DISTRIBUTOR',
]);
if ($res['return_code']=="SUCCESS" && $res["result_code"] == "SUCCESS"){
return true;
}
return false;
}
开始分账,注意分账方的信息对json对象,类似以下结构
$receiver = [
"type" => $type,
"account" => $user['openid'],
"amount" => (int)$amount,
"description" => "分享好友奖励".$user['amount'].'元',
];
接收三个参数。微信的订单号,系统内部的订单号,以及接受分账的json对象。
这里用的单次分账功能
public function share($wx_order_no,$order_no,$receiver){
$share = Factory::payment($this->config);
$res = $share->profit_sharing->share(
$wx_order_no,
$order_no,
$receiver
);
if($res['return_code']=="SUCCESS" && $res["result_code"] == "SUCCESS"){
return "SUCCESS";
}else{
Log::write($res);
}
}
到此分账功能就完结。
接着需要将ThinkPHP的队列进行进程常驻
参考命令,最后的ProfitSharingJob为任务名
php think queue:work --daemon --queue ProfitSharingJob
接着用supervisor 守护这个进程,确保在崩溃的时候能重新拉起
在宝塔安装supervisor管理器插件
分别填入项目根目录, php所在位置,以及命令(这时候不应该以 think开头,完整命令为)
think queue:work --daemon --queue ProfitSharingJob
至此,在小程序中支付之后,在supervisor管理的日志中可以看到执行情况。
到此完结。
本人的技术水平有限,写文章水平也有限。希望各位指出不足之处,感谢!