Files
zyt/server/app/common/service/wechat/WechatWorkExternalPayService.php
T
2026-05-11 17:49:38 +08:00

125 lines
4.1 KiB
PHP
Executable File

<?php
declare(strict_types=1);
namespace app\common\service\wechat;
use think\facade\Cache;
use think\facade\Log;
/**
* 企业微信对外收款服务
* 参考 https://developer.work.weixin.qq.com/document/path/93727
*/
class WechatWorkExternalPayService
{
private string $corpId;
private string $secret;
public function __construct()
{
$config = config('pay.wechat_work', []);
$this->corpId = (string)($config['corp_id'] ?? '');
$this->secret = (string)($config['external_pay_secret'] ?? $config['secret'] ?? '');
}
/**
* 获取 access_token(对外收款应用)
*/
public function getAccessToken(): ?string
{
if (empty($this->corpId) || empty($this->secret)) {
Log::error('企业微信对外收款:corp_id 或 external_pay_secret 未配置');
return null;
}
$cacheKey = 'work_wechat_external_pay_token_' . md5($this->corpId . $this->secret);
$cached = Cache::get($cacheKey);
if ($cached) {
return $cached;
}
$url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$this->corpId}&corpsecret={$this->secret}";
$response = $this->httpGet($url);
if (!$response || ($response['errcode'] ?? -1) != 0) {
Log::error('企业微信对外收款获取access_token失败: ' . json_encode($response));
return null;
}
$accessToken = $response['access_token'];
Cache::set($cacheKey, $accessToken, ($response['expires_in'] ?? 7200) - 200);
return $accessToken;
}
/**
* 获取对外收款记录
* @param int $beginTime 开始时间戳(秒)
* @param int $endTime 结束时间戳(秒)
* @param string $payeeUserid 收款人userid,空则查全部
* @param string $cursor 分页游标
* @param int $limit 最大记录数,最大1000
* @return array
*/
public function getBillList(int $beginTime, int $endTime, string $payeeUserid = '', string $cursor = '', int $limit = 100): array
{
$accessToken = $this->getAccessToken();
if (!$accessToken) {
return ['errcode' => -1, 'errmsg' => '获取access_token失败', 'bill_list' => []];
}
$url = "https://qyapi.weixin.qq.com/cgi-bin/externalpay/get_bill_list?access_token={$accessToken}";
$data = [
'begin_time' => $beginTime,
'end_time' => $endTime,
'limit' => $limit,
];
if ($payeeUserid) {
$data['payee_userid'] = $payeeUserid;
}
if ($cursor) {
$data['cursor'] = $cursor;
}
$response = $this->httpPost($url, $data);
if (!$response) {
return ['errcode' => -1, 'errmsg' => '请求失败', 'bill_list' => []];
}
$billList = $response['bill_list'] ?? [];
return [
'errcode' => $response['errcode'] ?? 0,
'errmsg' => $response['errmsg'] ?? '',
'bill_list' => is_array($billList) ? $billList : [],
'next_cursor' => $response['next_cursor'] ?? '',
];
}
private function httpGet(string $url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$result = curl_exec($ch);
curl_close($ch);
return $result ? json_decode($result, true) : null;
}
private function httpPost(string $url, array $data)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$result = curl_exec($ch);
curl_close($ch);
return $result ? json_decode($result, true) : null;
}
}