159 lines
5.3 KiB
PHP
159 lines
5.3 KiB
PHP
<?php
|
||
namespace App\Services\Platform;
|
||
|
||
use App\Models\ShopAuth;
|
||
use Illuminate\Support\Facades\Http;
|
||
use Illuminate\Support\Facades\Log;
|
||
|
||
class TaobaoClient
|
||
{
|
||
protected $shopAuth;
|
||
protected $appKey;
|
||
protected $appSecret;
|
||
|
||
public function __construct(ShopAuth $shopAuth)
|
||
{
|
||
$this->shopAuth = $shopAuth;
|
||
$this->appKey = config('platforms.taobao.app_key');
|
||
$this->appSecret = config('platforms.taobao.app_secret');
|
||
}
|
||
|
||
/**
|
||
* 拉取订单列表
|
||
*
|
||
* @param array $params
|
||
* @return array 标准化的订单数据
|
||
* @throws \Exception
|
||
*/
|
||
public function getOrders(array $params = [])
|
||
{
|
||
$this->ensureToken();
|
||
|
||
$requestParams = [
|
||
'method' => 'taobao.trades.sold.get',
|
||
'app_key' => $this->appKey,
|
||
'session' => $this->shopAuth->access_token,
|
||
'timestamp' => date('Y-m-d H:i:s'),
|
||
'v' => '2.0',
|
||
'format' => 'json',
|
||
'fields' => 'tid,type,status,payment,orders,receiver_name,receiver_phone,receiver_address,created,modified,pay_time',
|
||
'page_no' => $params['page_no'] ?? 1,
|
||
'page_size' => min($params['page_size'] ?? 40, 100),
|
||
];
|
||
|
||
if (!empty($params['start_time'])) {
|
||
$requestParams['start_created'] = $params['start_time'];
|
||
}
|
||
if (!empty($params['end_time'])) {
|
||
$requestParams['end_created'] = $params['end_time'];
|
||
}
|
||
|
||
$requestParams['sign'] = $this->generateSign($requestParams);
|
||
|
||
try {
|
||
$response = Http::timeout(30)->get('https://eco.taobao.com/router/rest', $requestParams);
|
||
$result = $response->json();
|
||
} catch (\Exception $e) {
|
||
Log::error('淘宝API请求失败', ['error' => $e->getMessage()]);
|
||
throw new \Exception('网络请求失败:' . $e->getMessage());
|
||
}
|
||
|
||
if (isset($result['error_response'])) {
|
||
$errorCode = $result['error_response']['code'];
|
||
$errorMsg = $result['error_response']['msg'];
|
||
// token 失效则刷新重试一次
|
||
if (in_array($errorCode, [26, 27])) {
|
||
$this->refreshToken();
|
||
return $this->getOrders($params);
|
||
}
|
||
throw new \Exception("淘宝API错误 [{$errorCode}]: {$errorMsg}");
|
||
}
|
||
|
||
$trades = $result['trades_sold_get_response']['trades']['trade'] ?? [];
|
||
return $this->transformOrders($trades);
|
||
}
|
||
|
||
protected function refreshToken()
|
||
{
|
||
$params = [
|
||
'method' => 'taobao.top.auth.token.refresh',
|
||
'app_key' => $this->appKey,
|
||
'session' => $this->shopAuth->refresh_token,
|
||
'timestamp' => date('Y-m-d H:i:s'),
|
||
'v' => '2.0',
|
||
'format' => 'json',
|
||
];
|
||
$params['sign'] = $this->generateSign($params);
|
||
|
||
$response = Http::get('https://eco.taobao.com/router/rest', $params);
|
||
$result = $response->json();
|
||
|
||
if (isset($result['error_response'])) {
|
||
throw new \Exception('刷新Token失败:' . $result['error_response']['msg']);
|
||
}
|
||
|
||
$tokenData = $result['top_auth_token_refresh_response'];
|
||
$this->shopAuth->access_token = $tokenData['access_token'];
|
||
$this->shopAuth->expires_at = now()->addSeconds($tokenData['expires_in']);
|
||
$this->shopAuth->refresh_token = $tokenData['refresh_token'] ?? $this->shopAuth->refresh_token;
|
||
$this->shopAuth->save();
|
||
}
|
||
|
||
protected function ensureToken()
|
||
{
|
||
if ($this->shopAuth->expires_at && $this->shopAuth->expires_at->isPast()) {
|
||
$this->refreshToken();
|
||
}
|
||
}
|
||
|
||
protected function generateSign($params)
|
||
{
|
||
ksort($params);
|
||
$str = $this->appSecret;
|
||
foreach ($params as $k => $v) {
|
||
if ($k !== 'sign') {
|
||
$str .= $k . $v;
|
||
}
|
||
}
|
||
$str .= $this->appSecret;
|
||
return strtoupper(md5($str));
|
||
}
|
||
|
||
protected function transformOrders($trades)
|
||
{
|
||
$orders = [];
|
||
foreach ($trades as $trade) {
|
||
$orders[] = [
|
||
'platform_order_sn' => (string)$trade['tid'],
|
||
'order_time' => $trade['created'],
|
||
'payment_time' => $trade['pay_time'] ?? null,
|
||
'buyer_nick' => $trade['buyer_nick'] ?? '',
|
||
'receiver_name' => $trade['receiver_name'],
|
||
'receiver_phone' => $trade['receiver_phone'],
|
||
'receiver_address' => $trade['receiver_address'],
|
||
'goods_amount' => $trade['payment'] ?? 0,
|
||
'discount_amount' => 0,
|
||
'freight' => 0,
|
||
'total_amount' => $trade['payment'] ?? 0,
|
||
'platform_status' => $trade['status'],
|
||
'items' => $this->transformItems($trade['orders']['order'] ?? []),
|
||
];
|
||
}
|
||
return $orders;
|
||
}
|
||
|
||
protected function transformItems($items)
|
||
{
|
||
$result = [];
|
||
foreach ($items as $item) {
|
||
$result[] = [
|
||
'goods_name' => $item['title'],
|
||
'platform_sku' => (string)($item['sku_id'] ?? $item['num_iid']),
|
||
'quantity' => $item['num'],
|
||
'price' => $item['price'],
|
||
'total_amount' => $item['total_fee'],
|
||
];
|
||
}
|
||
return $result;
|
||
}
|
||
} |