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; } }