首先吐槽一下
微信真的是越搞越垃圾,文檔和shit一樣,直接看不懂,微信的包也是,稍微一點(diǎn)沒注意,就直接蹦,一點(diǎn)面子都不給,哈哈哈哈。。。
因?yàn)槟壳绊?xiàng)目涉及到一個(gè)分銷的功能,首先就想到了微信的"企業(yè)付款到零錢功能",然后去申請,商戶后臺看到的只有"商家付款到零錢",心里想著也是一樣的,反正都是打款,應(yīng)該和以前大差不差的,結(jié)果,"商家付款到零錢"這個(gè)功能前前后后提交申請10多次,一直沒過,人工隨時(shí)排隊(duì),又解決不了問題,每次說反饋上去,然后3天后,發(fā)條短信給你,讓你"以實(shí)際審核為準(zhǔn)",麻辣隔壁,服了,好消息是:經(jīng)過長達(dá)半年的抗戰(zhàn)(2022-11 ~ 2023-05) 月,我的功能終于下來。
步入正題
首先我選擇的composer包是yansongda/pay ~3.2.0 (本來想沿用easywechant,奈何V3版本的功能需要php8.0以上,所以放棄了)
composer require yansongda/pay:~3.2.0 -vvv
創(chuàng)建一個(gè)config配置文件(生成的文件 pay.php,位于:項(xiàng)目根目錄/config/pay.php)
php artisan vendor:publish --provider="Yansongda\LaravelPay\PayServiceProvider" --tag=laravel-pay
文件大致內(nèi)容
declare(strict_types=1);
use Yansongda\Pay\Pay;
return [
// 支付寶支付相關(guān)配置
'alipay' => [
'default' => [
// 必填-支付寶分配的 app_id
'app_id' => '',
// 必填-應(yīng)用私鑰 字符串或路徑
'app_secret_cert' => '',
// 必填-應(yīng)用公鑰證書 路徑
'app_public_cert_path' => '',
// 必填-支付寶公鑰證書 路徑
'alipay_public_cert_path' => '',
// 必填-支付寶根證書 路徑
'alipay_root_cert_path' => '',
'return_url' => '',
'notify_url' => '',
// 選填-服務(wù)商模式下的服務(wù)商 id,當(dāng) mode 為 Pay::MODE_SERVICE 時(shí)使用該參數(shù)
'service_provider_id' => '',
// 選填-默認(rèn)為正常模式。可選為: MODE_NORMAL, MODE_SANDBOX, MODE_SERVICE
'mode' => Pay::MODE_NORMAL,
],
],
// 微信支付相關(guān)配置
'wechat' => [
'default' => [
// 必填-商戶號,服務(wù)商模式下為服務(wù)商商戶號
'mch_id' => '',
// 必填-商戶秘鑰
'mch_secret_key' => '',
// 必填-商戶私鑰 字符串或路徑
'mch_secret_cert' => '',
// 必填-商戶公鑰證書路徑
'mch_public_cert_path' => '',
// 必填
'notify_url' => '',
// 選填-公眾號 的 app_id
'mp_app_id' => '',
// 選填-小程序 的 app_id
'mini_app_id' => '',
// 選填-app 的 app_id
'app_id' => '',
// 選填-合單 app_id
'combine_app_id' => '',
// 選填-合單商戶號
'combine_mch_id' => '',
// 選填-服務(wù)商模式下,子公眾號 的 app_id
'sub_mp_app_id' => '',
// 選填-服務(wù)商模式下,子 app 的 app_id
'sub_app_id' => '',
// 選填-服務(wù)商模式下,子小程序 的 app_id
'sub_mini_app_id' => '',
// 選填-服務(wù)商模式下,子商戶id
'sub_mch_id' => '',
// 選填-微信公鑰證書路徑, optional,強(qiáng)烈建議 php-fpm 模式下配置此參數(shù)
'wechat_public_cert_path' => [
'45F59D4DABF31918AFCEC556D5D2C6E376675D57' => __DIR__.'/Cert/wechatPublicKey.crt',
],
// 選填-默認(rèn)為正常模式??蛇x為: MODE_NORMAL, MODE_SERVICE
'mode' => Pay::MODE_NORMAL,
],
],
// 銀聯(lián)支付相關(guān)配置
'unipay' => [
'default' => [
// 必填-商戶號
'mch_id' => '',
// 必填-商戶公私鑰
'mch_cert_path' => '',
// 必填-商戶公私鑰密碼
'mch_cert_password' => '000000',
// 必填-銀聯(lián)公鑰證書路徑
'unipay_public_cert_path' => '',
// 必填
'return_url' => '',
// 必填
'notify_url' => '',
],
],
// GuzzleHttp相關(guān)配置
'http' => [ // optional
'timeout' => 5.0, // 請求超時(shí)時(shí)間
'connect_timeout' => 5.0, // 連接超時(shí)時(shí)間
// 更多配置項(xiàng)請參考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
],
// optional,默認(rèn) warning;日志路徑為:sys_get_temp_dir().'/logs/yansongda.pay.log'
'logger' => [
'enable' => false, // 開啟日志或者關(guān)閉 true or false
'file' => null, // 日志保存路徑 默認(rèn)路徑:sys_get_temp_dir().'/logs/yansongda.pay.log'
'level' => 'debug', // 日志級別 Debug、Info、Notice、Warning、Error、Critical、Alert、Emergency
'type' => 'single', // optional, 可選 daily.
'max_file' => 30, // 留存多少天內(nèi)的日志,默認(rèn)30天,根據(jù)實(shí)際需要可以更改
],
];
具體內(nèi)容可以看官方文檔
傳送門
轉(zhuǎn)賬到零錢的一些配置和代碼
由于我只需要微信的功能,所以我精簡了一下
<?php
declare(strict_types=1);
use Yansongda\Pay\Pay;
return [
'wechat' => [
'default' => [
// 必填-商戶號,服務(wù)商模式下為服務(wù)商商戶號
'mch_id' => '',
// 必填-商戶秘鑰
'mch_secret_key' => '',
// 必填-商戶私鑰 字符串或路徑,文件名:apiclient_key.pem 的文件
'mch_secret_cert' => '',
// 必填-商戶公鑰證書路徑,文件名:apiclient_cert.pem的文件
'mch_public_cert_path' => '',
// 必填
'notify_url' => '', // 回調(diào)地址
// 選填-小程序 的 app_id
'mini_app_id' => '',
// 選填-微信公鑰證書路徑, optional,強(qiáng)烈建議 php-fpm 模式下配置此參數(shù)
// 這個(gè)參數(shù)需要去下載證書,具體下載方法在下面貼出來
'wechat_public_cert_path' => [],
// 選填-默認(rèn)為正常模式??蛇x為: MODE_NORMAL, MODE_SERVICE
'mode' => Pay::MODE_NORMAL,
],
],
'http' => [ // optional
'timeout' => 5.0,
'connect_timeout' => 5.0,
// 更多配置項(xiàng)請參考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
],
// optional,默認(rèn) warning;
'logger' => [
'enable' => true,
'file' => str_replace('\\', '/', storage_path()).'/logs/transfer/transferLog.log', // 日志我是放在laravel默認(rèn)的日志目錄下
'level' => 'warning',
'type' => 'daily', // daily 按天生成日志,生成日志格式 transferLog-2023-05-15.log
'max_file' => 180,
],
];
具體下載微信公鑰證書的方法
建議還是下載弄一下,不然每次請求都會多一次請求,默認(rèn)會去微信那邊動態(tài)獲取這個(gè)證書
傳送門

image.png
具體轉(zhuǎn)賬代碼
use Yansongda\Pay\Pay;
class TestController {
public function transfer() {
$result = Pay::wechat(config('pay'))->transfer([
'appid' => wxxxxxxx, // 微信小程序的app_id
'out_batch_no' => (string)time(), // 商家批次單號
'batch_name' => '提現(xiàn)', // 該筆批量轉(zhuǎn)賬的名稱
'batch_remark' => '商家付款到零錢', // 轉(zhuǎn)賬說明
'total_amount' => 0.1 * 100, // 轉(zhuǎn)賬金額,單位:分
'total_num' => 1, // 轉(zhuǎn)賬總筆數(shù)
'transfer_detail_list' => [
[
'out_detail_no' => (string)(time() + 5), // 商家明細(xì)單號
'transfer_amount' => 0.1 * 100, // 轉(zhuǎn)賬金額
'transfer_remark' => '商家付款到零錢', // 單條轉(zhuǎn)賬備注(微信用戶會收到該備注)
'openid' => 'ozxxxxxxxxxx', // 轉(zhuǎn)賬用戶的 openid
],
],
]);
// 返回結(jié)果
return response()->json($result);
}
}
返回參數(shù):
{
"batch_id": "1318888888888888888888888888888888888888888",
"create_time": "2023-05-15T15:19:09+08:00",
"out_batch_no": "1684135149"
}
至此,商家轉(zhuǎn)賬到零錢成功
由于這個(gè)API不具備回調(diào)功能所以想知道轉(zhuǎn)賬的狀態(tài)只有2種辦法
1.微信商戶后臺直接去查詢(不建議,麻煩)
2.通過api查詢
由于yansongda V3版本并沒有直接提供一些查詢方法,但是微信所有的方法都封裝到了插件里面。
具體文檔

image.png
由于我們需要去查詢"商家付款到零錢"是否成功,所以需要找到這些類

image.png
可以去看看具體源碼的實(shí)現(xiàn),這里直接列出最終請求的地方

image.png
從上述代碼中可以看出,如果想通過商家批次單號查詢批次單QueryOutBatchNoPlugin查詢訂單,需要傳入兩個(gè)參數(shù),其他具體的可選參數(shù)可以通過"微信官網(wǎng)文檔"查看
具體代碼
class TestController {
public function queryOutBatch() {
$pay = Pay::wechat(config('pay'));
// 獲取插件
$plugins = $pay->mergeCommonPlugins([QueryOutBatchNoPlugin::class]);
// need_query_detail:【是否查詢轉(zhuǎn)賬明細(xì)單】 true-是;false-否,默認(rèn)否。商戶可選擇是否查詢指定狀態(tài)的轉(zhuǎn)賬明細(xì)單,當(dāng)轉(zhuǎn)賬批次單狀態(tài)為“FINISHED”(已完成)時(shí),才會返回滿足條件的轉(zhuǎn)賬明細(xì)單
$result = $pay->pay($plugins ,['out_batch_no' => '1684122786','need_query_detail' => false]);
return response()->json($result);
}
}
查詢返回

image.png
如果想通過其他的方法去查詢,在上述獲取插件的方法,傳入對應(yīng)的類,調(diào)用該類,并傳入對應(yīng)的值即可
如果遇到提示:此IP地址不允許調(diào)用該接口
則表示未配置白名單,去配置一下即可

image.png
去設(shè)置

image.png
添加即可,可能會有延遲。

image.png