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管理的日誌中可以看到執行情況。

到此完結。

本人的技術水平有限,寫文章水平也有限。希望各位指出不足之處,感謝!

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