ThinkPHP5.1 Queue Redis 微信支付之企业分账

总结一下微信支付的企业分账功能,自己前前后后折腾了一两天,也给后来的同学一个参考

关于分账这个功能,可能应用的也比较少,网上相关的资料也比较少

关于分账功能的应用场景,可以参考微信官方文档 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

<?php

return [
    //Redis,Database,Topthink ,Sync这四种驱动
    'connector' => '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

 

写入如下代码

<?php
/**
 * Created by 九城.
 * Author: 九城
 * QQ : 940993208
 *
 * Date: 2019/10/3
 * Time: 12:43
 */

namespace app\api\job;

use app\api\service\WxPay;
use think\facade\Log;
use think\queue\Job;

class ProfitSharing
{

    public function fire(Job $job,$data){
        //如果任务重试次数大于5次则删除这个任务
        if ($job->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管理的日志中可以看到执行情况。

到此完结。

本人的技术水平有限,写文章水平也有限。希望各位指出不足之处,感谢!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章