2024-12-19 20:38:24 +08:00

505 lines
18 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
class CZL_API {
private $api_url;
private $username;
private $password;
private $token;
private $token_expires;
private $country_mapping;
private $customer_id;
private $customer_userid;
public function __construct() {
$this->api_url = get_option('czl_api_url', '');
$this->username = get_option('czl_username', '');
$this->password = get_option('czl_password', '');
$this->token = get_transient('czl_api_token');
$this->token_expires = get_transient('czl_api_token_expires');
$this->init_country_mapping();
}
/**
* 初始化国家代码映射
*/
private function init_country_mapping() {
// 从API获取国家列表并缓存
$cached_mapping = get_transient('czl_country_mapping');
if ($cached_mapping !== false) {
$this->country_mapping = $cached_mapping;
return;
}
try {
$response = wp_remote_get('https://tms-api-go.czl.net/api/countries', array(
'timeout' => 30
));
if (is_wp_error($response)) {
throw new Exception($response->get_error_message());
}
$data = json_decode(wp_remote_retrieve_body($response), true);
if (!empty($data['data'])) {
$mapping = array();
foreach ($data['data'] as $country) {
$mapping[$country['ename']] = $country['code'];
}
$this->country_mapping = $mapping;
set_transient('czl_country_mapping', $mapping, DAY_IN_SECONDS);
error_log('CZL Express: Country mapping updated');
}
} catch (Exception $e) {
error_log('CZL Express Error: Failed to get country mapping - ' . $e->getMessage());
$this->country_mapping = array();
}
}
/**
* 转换国家代码
*/
private function convert_country_code($wc_country) {
error_log('CZL Express: Converting country code ' . $wc_country);
// 获取WooCommerce国家名称
$countries = WC()->countries->get_countries();
$country_name = isset($countries[$wc_country]) ? $countries[$wc_country] : '';
// 在映射中查找
foreach ($this->country_mapping as $name => $code) {
if (stripos($name, $country_name) !== false || stripos($country_name, $name) !== false) {
error_log('CZL Express: Found country mapping ' . $wc_country . ' => ' . $code);
return $code;
}
}
// 如果没找到映射,返回原始代码
error_log('CZL Express: No mapping found for ' . $wc_country . ', using original code');
return $wc_country;
}
/**
* 获取API认证Token
*/
private function get_token() {
if ($this->token && time() < $this->token_expires) {
return $this->token;
}
$response = wp_remote_post($this->api_url . '/auth/login', array(
'body' => array(
'username' => $this->username,
'password' => md5($this->password) // CZL API需要MD5加密的密码
),
'timeout' => 30
));
if (is_wp_error($response)) {
throw new Exception($response->get_error_message());
}
$body = json_decode(wp_remote_retrieve_body($response), true);
if (empty($body['success'])) {
throw new Exception(!empty($body['message']) ? $body['message'] : '认证失败');
}
$this->token = $body['data']['token'];
$this->token_expires = time() + 7200; // CZL token有效期通常是2小时
set_transient('czl_api_token', $this->token, 7200);
set_transient('czl_api_token_expires', $this->token_expires, 7200);
return $this->token;
}
/**
* 发送API请求
*/
private function request($endpoint, $method = 'GET', $data = null) {
$args = array(
'method' => $method,
'headers' => array(
'Authorization' => $this->get_token(),
'Content-Type' => 'application/json'
),
'timeout' => 30
);
if ($data !== null) {
$args['body'] = json_encode($data);
}
$response = wp_remote_request($this->api_url . $endpoint, $args);
if (is_wp_error($response)) {
throw new Exception($response->get_error_message());
}
$body = json_decode(wp_remote_retrieve_body($response), true);
if (empty($body['success'])) {
throw new Exception(!empty($body['message']) ? $body['message'] : '请求失败');
}
return $body['data'];
}
/**
* 获取运费报价
*/
public function get_shipping_rate($params) {
try {
$api_url = 'https://tms.czl.net/defaultPriceSearchJson.htm';
// 转换国家代码
$country_code = $this->convert_country_code($params['country']);
// 构建请求参数
$query = array(
'weight' => $params['weight'],
'country' => $country_code,
'cargoType' => $params['cargoType'],
'length' => $params['length'],
'width' => $params['width'],
'height' => $params['height'],
'postcode' => $params['postcode']
);
error_log('CZL Express: Shipping rate request - ' . print_r($query, true));
// 发送请求
$response = wp_remote_post($api_url . '?' . http_build_query($query), array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode($this->username . ':' . $this->password)
),
'timeout' => 30
));
if (is_wp_error($response)) {
throw new Exception($response->get_error_message());
}
$body = wp_remote_retrieve_body($response);
error_log('CZL Express: API raw response - ' . $body);
$data = json_decode($body, true);
if (empty($data)) {
throw new Exception('Empty API response');
}
// 检查响应格式
if (!is_array($data)) {
throw new Exception('Invalid API response format');
}
return $data;
} catch (Exception $e) {
error_log('CZL Express API Error: ' . $e->getMessage());
throw $e;
}
}
/**
* 格式化运费报价结果
*/
private function format_shipping_rates($rates) {
$formatted_rates = array();
foreach ($rates as $rate) {
$formatted_rates[] = array(
'method_id' => 'czl_express_' . sanitize_title($rate['product_id']),
'method_title' => $rate['product_name'],
'method_name' => $rate['product_name'],
'cost' => floatval($rate['total_amount']),
'delivery_time' => $rate['product_aging'],
'product_id' => $rate['product_id'],
'product_note' => $rate['product_note']
);
}
return $formatted_rates;
}
/**
* 创建运单
*/
public function create_order($order_data) {
try {
// 添加请求前的日志
error_log('CZL Express: Creating order with data - ' . print_r($order_data, true));
$response = wp_remote_post('https://tms.czl.net/createOrderApi.htm', array(
'body' => array(
'Param' => json_encode($order_data)
),
'timeout' => 30
));
// 添加响应日志
error_log('CZL Express: Raw API response - ' . print_r($response, true));
if (is_wp_error($response)) {
throw new Exception('API请求失败: ' . $response->get_error_message());
}
$result = json_decode(wp_remote_retrieve_body($response), true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception('JSON解析失败: ' . json_last_error_msg());
}
if (empty($result['ack']) || $result['ack'] !== 'true') {
throw new Exception(!empty($result['message']) ? urldecode($result['message']) : '未知错误');
}
return $result;
} catch (Exception $e) {
error_log('CZL Express Error: Create order failed - ' . $e->getMessage());
error_log('CZL Express Error Stack Trace: ' . $e->getTraceAsString());
throw $e;
}
}
/**
* 获取运单跟踪信息
*/
public function get_tracking($tracking_number) {
try {
$response = wp_remote_post('https://tms.czl.net/selectTrack.htm', array(
'body' => array(
'documentCode' => $tracking_number
),
'timeout' => 30
));
if (is_wp_error($response)) {
throw new Exception($response->get_error_message());
}
$result = json_decode(wp_remote_retrieve_body($response), true);
if (empty($result[0]['ack']) || $result[0]['ack'] !== 'true') {
throw new Exception('获取跟踪信息失败');
}
return $result[0]['data'][0];
} catch (Exception $e) {
error_log('CZL Express API Error: ' . $e->getMessage());
throw $e;
}
}
/**
* 获取运单标签
*/
public function get_label($order_id) {
$url = sprintf(
'https://tms-label.czl.net/order/FastRpt/PDF_NEW.aspx?Format=lbl_sub一票多件161810499441.frx&PrintType=1&order_id=%s',
$order_id
);
return $url;
}
/**
* 取消运单
*/
public function cancel_order($order_number) {
return $this->request('/shipping/cancel', 'POST', array(
'order_number' => $order_number
));
}
/**
* 测试认证
*/
public function test_auth() {
try {
$response = wp_remote_post('https://tms.czl.net/selectAuth.htm', array(
'body' => array(
'username' => $this->username,
'password' => $this->password
),
'timeout' => 30
));
if (is_wp_error($response)) {
throw new Exception($response->get_error_message());
}
$result = json_decode(wp_remote_retrieve_body($response), true);
if (empty($result['success'])) {
throw new Exception('认证失败');
}
return array(
'customer_id' => $result['customer_id'],
'customer_userid' => $result['customer_userid']
);
} catch (Exception $e) {
error_log('CZL Express API Error: ' . $e->getMessage());
throw $e;
}
}
/**
* 获取支持的国家列表
*/
public function get_countries() {
try {
$response = wp_remote_get('https://tms-api-go.czl.net/api/countries', array(
'timeout' => 30
));
if (is_wp_error($response)) {
throw new Exception($response->get_error_message());
}
$result = json_decode(wp_remote_retrieve_body($response), true);
if ($result['code'] !== 200) {
throw new Exception('获取国家列表失败');
}
return $result['data'];
} catch (Exception $e) {
error_log('CZL Express API Error: ' . $e->getMessage());
throw $e;
}
}
private function ensure_logged_in() {
try {
error_log('CZL Express: Starting authentication');
$auth_url = 'https://tms.czl.net/selectAuth.htm';
$auth_data = array(
'username' => $this->username,
'password' => $this->password
);
error_log('CZL Express: Auth request data - ' . print_r($auth_data, true));
$ch = curl_init($auth_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($auth_data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Accept-Language: zh-cn',
'Connection: Keep-Alive',
'Cache-Control: no-cache'
));
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$response = curl_exec($ch);
error_log('CZL Express: Auth raw response - ' . $response);
if (curl_errno($ch)) {
throw new Exception('认证请求失败');
}
curl_close($ch);
// 解析响应
$result = json_decode(str_replace("'", '"', $response), true);
error_log('CZL Express: Auth decoded response - ' . print_r($result, true));
if (empty($result) || !isset($result['customer_id'])) {
throw new Exception('认证失败');
}
// 保存认证信息
$this->customer_id = $result['customer_id'];
$this->customer_userid = $result['customer_userid'];
} catch (Exception $e) {
error_log('CZL Express Error: Authentication failed - ' . $e->getMessage());
throw new Exception('认证失败请联系CZL Express');
}
}
public function create_shipment($data) {
try {
error_log('CZL Express: Starting create shipment');
// 确保已登录
$this->ensure_logged_in();
// 使用类属性中的认证信息
$data['customer_id'] = $this->customer_id;
$data['customer_userid'] = $this->customer_userid;
$api_url = 'https://tms.czl.net/createOrderApi.htm';
// 构建请求数据
$request_data = array(
'param' => json_encode($data, JSON_UNESCAPED_UNICODE)
);
error_log('CZL Express: Create shipment request data - ' . print_r($request_data, true));
$ch = curl_init($api_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($request_data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Accept-Language: zh-cn',
'Connection: Keep-Alive',
'Cache-Control: no-cache',
'Content-Type: application/x-www-form-urlencoded;charset=UTF-8'
));
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
// 添加更多调试信息
curl_setopt($ch, CURLOPT_VERBOSE, true);
$verbose = fopen('php://temp', 'w+');
curl_setopt($ch, CURLOPT_STDERR, $verbose);
$response = curl_exec($ch);
// 记录详细的curl信息
if (curl_errno($ch)) {
rewind($verbose);
$verboseLog = stream_get_contents($verbose);
error_log('CZL Express: Curl verbose log - ' . $verboseLog);
error_log('CZL Express: Curl error - ' . curl_error($ch));
throw new Exception('请求失败: ' . curl_error($ch));
}
error_log('CZL Express: Create shipment raw response - ' . $response);
error_log('CZL Express: Response info - ' . print_r(curl_getinfo($ch), true));
curl_close($ch);
fclose($verbose);
// 检查响应是否为空
if (empty($response)) {
throw new Exception('服务器未返回数据');
}
// 解析响应
$result = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log('CZL Express: JSON decode error - ' . json_last_error_msg());
throw new Exception('响应数据格式错误');
}
error_log('CZL Express: Create shipment decoded response - ' . print_r($result, true));
if (!isset($result['ack']) || $result['ack'] !== 'true') {
$error_msg = isset($result['message']) ? urldecode($result['message']) : '未知错误';
error_log('CZL Express: API error message - ' . $error_msg);
throw new Exception($error_msg);
}
return $result;
} catch (Exception $e) {
error_log('CZL Express Error: Create shipment failed - ' . $e->getMessage());
error_log('CZL Express Error Stack Trace: ' . $e->getTraceAsString());
throw $e;
}
}
}