mirror of
https://github.com/woodchen-ink/czlexpress-for-woocommerce.git
synced 2025-07-18 14:01:58 +08:00
505 lines
18 KiB
PHP
505 lines
18 KiB
PHP
<?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;
|
||
}
|
||
}
|
||
}
|