Update system requirements and enhance plugin functionality
- Updated system requirements in the README to reflect compatibility with WordPress 6.0+ and PHP 7.4+. - Revised usage steps for better clarity on plugin installation and configuration. - Improved order management features, including AJAX handling for shipment creation and tracking updates. - Added new custom order statuses (In Transit, Delivered) for better order tracking. - Enhanced error handling and logging during shipment creation and tracking updates. - Introduced chargeable weight calculation for shipping rates based on product dimensions and weight. These changes enhance the overall performance and usability of the CZL Express plugin.
@ -3,16 +3,45 @@ if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 获取订单列表
|
||||
// 加载必要的脚本和样式
|
||||
wp_enqueue_script('jquery');
|
||||
wp_enqueue_style('thickbox');
|
||||
wp_enqueue_script('thickbox');
|
||||
wp_enqueue_script('media-upload');
|
||||
|
||||
// 使用WooCommerce的API获取订单
|
||||
$orders_query = new WC_Order_Query(array(
|
||||
'limit' => -1,
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
'status' => array('processing', 'completed', 'shipping', 'delivered')
|
||||
'status' => array('processing', 'completed', 'on-hold', 'in_transit', 'delivered')
|
||||
));
|
||||
|
||||
$orders = $orders_query->get_orders();
|
||||
|
||||
// 获取运单信息
|
||||
global $wpdb;
|
||||
$shipments = array();
|
||||
$shipment_results = $wpdb->get_results("
|
||||
SELECT order_id, tracking_number, czl_order_id, reference_number, status as shipment_status, label_url
|
||||
FROM {$wpdb->prefix}czl_shipments
|
||||
");
|
||||
foreach ($shipment_results as $shipment) {
|
||||
$shipments[$shipment->order_id] = $shipment;
|
||||
}
|
||||
|
||||
// 添加必要的JavaScript变量
|
||||
wp_enqueue_script('jquery');
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
var czl_ajax = {
|
||||
ajax_url: '<?php echo admin_url('admin-ajax.php'); ?>',
|
||||
nonce: '<?php echo wp_create_nonce('czl_ajax_nonce'); ?>',
|
||||
creating_text: '<?php _e('正在创建运单...', 'woo-czl-express'); ?>',
|
||||
success_text: '<?php _e('运单创建成功', 'woo-czl-express'); ?>',
|
||||
error_text: '<?php _e('运单创建失败', 'woo-czl-express'); ?>'
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="wrap">
|
||||
<h1><?php _e('CZL Express 订单管理', 'woo-czl-express'); ?></h1>
|
||||
@ -37,173 +66,303 @@ $orders = $orders_query->get_orders();
|
||||
<th><?php _e('日期', 'woo-czl-express'); ?></th>
|
||||
<th><?php _e('状态', 'woo-czl-express'); ?></th>
|
||||
<th><?php _e('收件人', 'woo-czl-express'); ?></th>
|
||||
<th><?php _e('配送方式', 'woo-czl-express'); ?></th>
|
||||
<th><?php _e('运单信息', 'woo-czl-express'); ?></th>
|
||||
<th><?php _e('操作', 'woo-czl-express'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($orders as $order): ?>
|
||||
<?php
|
||||
$tracking_number = $order->get_meta('_czl_tracking_number');
|
||||
$czl_order_id = $order->get_meta('_czl_order_id');
|
||||
$reference_number = $order->get_meta('_czl_reference_number');
|
||||
|
||||
$shipping_methods = $order->get_shipping_methods();
|
||||
$shipping_method = current($shipping_methods);
|
||||
$is_czl = $shipping_method && strpos($shipping_method->get_method_id(), 'czl_express') !== false;
|
||||
if (empty($orders)) {
|
||||
echo '<tr><td colspan="8">' . __('没有找到订单', 'woo-czl-express') . '</td></tr>';
|
||||
} else {
|
||||
foreach ($orders as $order):
|
||||
$order_id = $order->get_id();
|
||||
$shipment = isset($shipments[$order_id]) ? $shipments[$order_id] : null;
|
||||
|
||||
// 获取配送方式
|
||||
$shipping_methods = $order->get_shipping_methods();
|
||||
$shipping_method = current($shipping_methods);
|
||||
$shipping_method_title = $shipping_method ? $shipping_method->get_method_title() : '';
|
||||
?>
|
||||
<tr>
|
||||
<td class="check-column">
|
||||
<input type="checkbox" name="order_ids[]" value="<?php echo esc_attr($order_id); ?>">
|
||||
</td>
|
||||
<td>
|
||||
<a href="<?php echo esc_url($order->get_edit_order_url()); ?>" target="_blank">
|
||||
#<?php echo esc_html($order->get_order_number()); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td><?php echo esc_html(wc_format_datetime($order->get_date_created())); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$status_name = wc_get_order_status_name($order->get_status());
|
||||
$status_class = sanitize_html_class('status-' . $order->get_status());
|
||||
echo "<mark class='order-status {$status_class}'><span>" . esc_html($status_name) . "</span></mark>";
|
||||
?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo esc_html($order->get_formatted_shipping_full_name()); ?><br>
|
||||
<?php echo esc_html($order->get_shipping_address_1()); ?><br>
|
||||
<?php echo esc_html($order->get_shipping_city() . ', ' . $order->get_shipping_country()); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo esc_html($shipping_method_title); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($shipment && !empty($shipment->tracking_number)): ?>
|
||||
<strong><?php _e('运单号:', 'woo-czl-express'); ?></strong>
|
||||
<a href="https://exp.czl.net/track/?query=<?php echo esc_attr($shipment->tracking_number); ?>" target="_blank">
|
||||
<?php echo esc_html($shipment->tracking_number); ?>
|
||||
</a>
|
||||
<button type="button" class="button button-small edit-tracking-btn"
|
||||
data-order-id="<?php echo $order_id; ?>"
|
||||
data-tracking-number="<?php echo esc_attr($shipment->tracking_number); ?>"
|
||||
style="margin-left: 5px;">
|
||||
<span class="dashicons dashicons-edit" style="font-size: 16px; height: 16px; width: 16px;"></span>
|
||||
</button><br>
|
||||
<strong><?php _e('CZL订单号:', 'woo-czl-express'); ?></strong>
|
||||
<?php echo esc_html($shipment->czl_order_id); ?><br>
|
||||
<strong><?php _e('参考号:', 'woo-czl-express'); ?></strong>
|
||||
<?php echo esc_html($shipment->reference_number); ?><br>
|
||||
<strong><?php _e('运单状态:', 'woo-czl-express'); ?></strong>
|
||||
<?php echo esc_html($shipment->shipment_status); ?>
|
||||
<?php else: ?>
|
||||
<?php _e('未创建运单', 'woo-czl-express'); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (!$shipment || empty($shipment->tracking_number)): ?>
|
||||
<button type="button" class="button czl-create-btn"
|
||||
data-order-id="<?php echo $order_id; ?>">
|
||||
<?php _e('创建运单', 'woo-czl-express'); ?>
|
||||
</button>
|
||||
<?php elseif (!empty($shipment->czl_order_id)): ?>
|
||||
<button type="button" class="button"
|
||||
onclick="printLabel('<?php echo $shipment->czl_order_id; ?>')">
|
||||
<?php _e('打印标签', 'woo-czl-express'); ?>
|
||||
</button>
|
||||
<button type="button" class="button update-tracking-btn"
|
||||
data-order-id="<?php echo $order_id; ?>">
|
||||
<?php _e('更新轨迹', 'woo-czl-express'); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach;
|
||||
}
|
||||
?>
|
||||
<?php if ($is_czl): ?>
|
||||
<tr>
|
||||
<th scope="row" class="check-column">
|
||||
<input type="checkbox" name="order_ids[]" value="<?php echo esc_attr($order->get_id()); ?>">
|
||||
</th>
|
||||
<td>
|
||||
<a href="<?php echo esc_url($order->get_edit_order_url()); ?>" target="_blank">
|
||||
#<?php echo esc_html($order->get_order_number()); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td><?php echo esc_html($order->get_date_created()->date_i18n('Y-m-d H:i:s')); ?></td>
|
||||
<td><?php echo esc_html(wc_get_order_status_name($order->get_status())); ?></td>
|
||||
<td>
|
||||
<?php echo esc_html($order->get_formatted_shipping_full_name()); ?><br>
|
||||
<?php echo esc_html($order->get_shipping_address_1()); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($tracking_number): ?>
|
||||
<strong><?php _e('运单号:', 'woo-czl-express'); ?></strong>
|
||||
<a href="https://exp.czl.net/track/?query=<?php echo esc_attr($tracking_number); ?>" target="_blank">
|
||||
<?php echo esc_html($tracking_number); ?>
|
||||
</a><br>
|
||||
<strong><?php _e('CZL订单号:', 'woo-czl-express'); ?></strong>
|
||||
<?php echo esc_html($czl_order_id); ?><br>
|
||||
<strong><?php _e('参考号:', 'woo-czl-express'); ?></strong>
|
||||
<?php echo esc_html($reference_number); ?>
|
||||
<?php else: ?>
|
||||
<?php _e('未创建运单', 'woo-czl-express'); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (!empty($tracking_number)): ?>
|
||||
<button type="button" class="button" onclick="printLabel(<?php echo $order->get_id(); ?>)">
|
||||
<?php _e('打印标签', 'woo-czl-express'); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if (empty($tracking_number)): ?>
|
||||
<button type="button" class="button" onclick="createShipment(<?php echo $order->get_id(); ?>)">
|
||||
<?php _e('创建运单', 'woo-czl-express'); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 添加修改跟踪单号的对话框 -->
|
||||
<div id="edit-tracking-dialog" class="hidden">
|
||||
<div style="padding:20px;">
|
||||
<div class="form-field" style="margin-bottom:15px;">
|
||||
<label for="new-tracking-number" style="display:block;margin-bottom:8px;font-weight:600;">
|
||||
<?php _e('新跟踪单号:', 'woo-czl-express'); ?>
|
||||
</label>
|
||||
<input type="text" id="new-tracking-number" style="width:100%;padding:5px;">
|
||||
<input type="hidden" id="edit-order-id" value="">
|
||||
</div>
|
||||
<div style="text-align:right;margin-top:20px;">
|
||||
<button type="button" class="button" onclick="self.parent.tb_remove();" style="margin-right:5px;">
|
||||
<?php _e('取消', 'woo-czl-express'); ?>
|
||||
</button>
|
||||
<button type="button" class="button button-primary" id="save-tracking-number">
|
||||
<?php _e('保存', 'woo-czl-express'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function($) {
|
||||
// 单个订单创建运单
|
||||
$('.create-shipment').click(function() {
|
||||
var button = $(this);
|
||||
var orderId = button.data('order-id');
|
||||
// 处理编辑按钮点击
|
||||
$('.edit-tracking-btn').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var orderId = $(this).data('order-id');
|
||||
var currentTracking = $(this).data('tracking-number');
|
||||
|
||||
button.prop('disabled', true).text('<?php _e('处理中...', 'woo-czl-express'); ?>');
|
||||
// 设置当前订单ID和跟踪单号
|
||||
$('#edit-order-id').val(orderId);
|
||||
$('#new-tracking-number').val(currentTracking || '');
|
||||
|
||||
// 打开对话框
|
||||
tb_show(
|
||||
'<?php _e('修改跟踪单号', 'woo-czl-express'); ?>',
|
||||
'#TB_inline?width=300&height=180&inlineId=edit-tracking-dialog'
|
||||
);
|
||||
|
||||
// 调整对话框样式
|
||||
$('#TB_window').css({
|
||||
'height': 'auto',
|
||||
'width': '300px',
|
||||
'margin-left': '-150px',
|
||||
'top': '50%',
|
||||
'margin-top': '-90px'
|
||||
});
|
||||
|
||||
// 聚焦输入框
|
||||
setTimeout(function() {
|
||||
$('#new-tracking-number').focus().select();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// 处理保存按钮点击
|
||||
$('#save-tracking-number').on('click', function() {
|
||||
var orderId = $('#edit-order-id').val();
|
||||
var newTrackingNumber = $('#new-tracking-number').val().trim();
|
||||
|
||||
if (!newTrackingNumber) {
|
||||
alert('请输入新的跟踪单号');
|
||||
return;
|
||||
}
|
||||
|
||||
// 发送AJAX请求更新跟踪单号
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
url: czl_ajax.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'czl_create_shipment',
|
||||
action: 'czl_update_tracking_number',
|
||||
nonce: czl_ajax.nonce,
|
||||
order_id: orderId,
|
||||
nonce: '<?php echo wp_create_nonce('czl_create_shipment'); ?>'
|
||||
tracking_number: newTrackingNumber
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
location.reload();
|
||||
alert('跟踪单号更新成功');
|
||||
self.parent.tb_remove();
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert(response.data.message);
|
||||
button.prop('disabled', false).text('<?php _e('创建运单', 'woo-czl-express'); ?>');
|
||||
alert(response.data || '更新失败');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert('<?php _e('请求失败,请重试', 'woo-czl-express'); ?>');
|
||||
button.prop('disabled', false).text('<?php _e('创建运单', 'woo-czl-express'); ?>');
|
||||
alert('请求失败,请重试');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 批量创建运单
|
||||
$('#doaction').click(function(e) {
|
||||
e.preventDefault();
|
||||
// 处理更新轨迹按钮点击
|
||||
$(document).on('click', '.update-tracking-btn', function() {
|
||||
var $button = $(this);
|
||||
var orderId = $button.data('order-id');
|
||||
|
||||
var action = $('#bulk-action-selector-top').val();
|
||||
if (action !== 'create_shipment') {
|
||||
return;
|
||||
}
|
||||
|
||||
var orderIds = [];
|
||||
$('input[name="order_ids[]"]:checked').each(function() {
|
||||
orderIds.push($(this).val());
|
||||
});
|
||||
|
||||
if (orderIds.length === 0) {
|
||||
alert('<?php _e('请选择订单', 'woo-czl-express'); ?>');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!confirm('<?php _e('确定要为选中的订单创建运单吗?', 'woo-czl-express'); ?>')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(this).prop('disabled', true).text('<?php _e('处理中...', 'woo-czl-express'); ?>');
|
||||
$button.prop('disabled', true).text('更新中...');
|
||||
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
url: czl_ajax.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'czl_bulk_create_shipment',
|
||||
order_ids: orderIds,
|
||||
nonce: '<?php echo wp_create_nonce('czl_bulk_create_shipment'); ?>'
|
||||
action: 'czl_update_tracking_info',
|
||||
nonce: czl_ajax.nonce,
|
||||
order_id: orderId
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
location.reload();
|
||||
alert('轨迹更新成功');
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert(response.data.message);
|
||||
alert(response.data || '更新失败');
|
||||
$button.prop('disabled', false).text('更新轨迹');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert('<?php _e('请求失败,请重试', 'woo-czl-express'); ?>');
|
||||
},
|
||||
complete: function() {
|
||||
$('#doaction').prop('disabled', false).text('<?php _e('应用', 'woo-czl-express'); ?>');
|
||||
alert('请求失败,请重试');
|
||||
$button.prop('disabled', false).text('更新轨迹');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 处理创建运单按钮点击
|
||||
$(document).on('click', '.czl-create-btn', function() {
|
||||
var $button = $(this);
|
||||
var orderId = $button.data('order-id');
|
||||
|
||||
// 如果按钮已经在处理中,则返回
|
||||
if ($button.hasClass('processing')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示处理中状态
|
||||
$button.addClass('processing').text(czl_ajax.creating_text);
|
||||
|
||||
// 发送AJAX请求
|
||||
$.ajax({
|
||||
url: czl_ajax.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'czl_create_shipment',
|
||||
nonce: czl_ajax.nonce,
|
||||
order_id: orderId
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
// 显示成功消息
|
||||
$button.removeClass('processing').addClass('success')
|
||||
.text(czl_ajax.success_text);
|
||||
|
||||
// 2秒后刷新页面
|
||||
setTimeout(function() {
|
||||
window.location.reload();
|
||||
}, 2000);
|
||||
} else {
|
||||
// 显示错误消息
|
||||
$button.removeClass('processing').addClass('error')
|
||||
.text(response.data);
|
||||
|
||||
// 3秒后恢复按钮状态
|
||||
setTimeout(function() {
|
||||
$button.removeClass('error')
|
||||
.text('创建运单');
|
||||
}, 3000);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
// 显示错误消息
|
||||
$button.removeClass('processing').addClass('error')
|
||||
.text(czl_ajax.error_text);
|
||||
|
||||
// 3秒后恢复按钮状态
|
||||
setTimeout(function() {
|
||||
$button.removeClass('error')
|
||||
.text('创建运单');
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 添加按钮样式
|
||||
$('<style>')
|
||||
.text(`
|
||||
.czl-create-btn {
|
||||
position: relative;
|
||||
}
|
||||
.czl-create-btn.processing {
|
||||
pointer-events: none;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.czl-create-btn.success {
|
||||
background-color: #7ad03a !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
.czl-create-btn.error {
|
||||
background-color: #dc3232 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
`)
|
||||
.appendTo('head');
|
||||
});
|
||||
|
||||
// 打印标签功能
|
||||
function printLabel(orderId) {
|
||||
jQuery.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'czl_print_label',
|
||||
order_id: orderId,
|
||||
security: '<?php echo wp_create_nonce("czl-print-label"); ?>'
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success && response.data.url) {
|
||||
// 在新窗口打开标签
|
||||
window.open(response.data.url, '_blank');
|
||||
} else {
|
||||
alert(response.data.message || '获取标签失败');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert('请求失败,请重试');
|
||||
}
|
||||
});
|
||||
// 构建标签URL
|
||||
var labelUrl = 'https://tms-label.czl.net/order/FastRpt/PDF_NEW.aspx?Format=lbl_sub一票多件161810499441.frx&PrintType=1&order_id=' + orderId;
|
||||
|
||||
// 在新窗口打开标签
|
||||
window.open(labelUrl, '_blank');
|
||||
}
|
||||
</script>
|
BIN
assets/banner-772x250.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
assets/icon-128x128.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
assets/icon-256x256.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
125
assets/js/admin.js
Normal file
@ -0,0 +1,125 @@
|
||||
jQuery(document).ready(function($) {
|
||||
// 创建运单按钮点击事件
|
||||
$('.czl-create-shipment').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var button = $(this);
|
||||
var order_id = button.data('order-id');
|
||||
|
||||
button.prop('disabled', true).text(czl_ajax.creating_text);
|
||||
|
||||
$.ajax({
|
||||
url: czl_ajax.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'czl_create_shipment',
|
||||
order_id: order_id,
|
||||
nonce: czl_ajax.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
button.text(czl_ajax.success_text);
|
||||
location.reload();
|
||||
} else {
|
||||
button.text(czl_ajax.error_text);
|
||||
alert(response.data);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
button.text(czl_ajax.error_text);
|
||||
alert('请求失败,请重试');
|
||||
},
|
||||
complete: function() {
|
||||
button.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 更新跟踪单号对话框
|
||||
var trackingDialog = $('<div id="czl-tracking-dialog" title="更新跟踪单号">' +
|
||||
'<p>请输入新的跟踪单号:</p>' +
|
||||
'<input type="text" id="czl-tracking-number" style="width: 100%;">' +
|
||||
'</div>').dialog({
|
||||
autoOpen: false,
|
||||
modal: true,
|
||||
width: 400,
|
||||
buttons: {
|
||||
"更新": function() {
|
||||
var dialog = $(this);
|
||||
var button = dialog.data('button');
|
||||
var order_id = button.data('order-id');
|
||||
var tracking_number = $('#czl-tracking-number').val();
|
||||
|
||||
if (!tracking_number) {
|
||||
alert('请输入跟踪单号');
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: czl_ajax.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'czl_update_tracking_number',
|
||||
order_id: order_id,
|
||||
tracking_number: tracking_number,
|
||||
nonce: czl_ajax.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert(response.data);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert('请求失败,请重试');
|
||||
}
|
||||
});
|
||||
},
|
||||
"取消": function() {
|
||||
$(this).dialog('close');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 更新跟踪单号按钮点击事件
|
||||
$('.czl-update-tracking').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var button = $(this);
|
||||
var currentTracking = button.data('tracking');
|
||||
|
||||
$('#czl-tracking-number').val(currentTracking || '');
|
||||
trackingDialog.data('button', button).dialog('open');
|
||||
});
|
||||
|
||||
// 更新轨迹信息按钮点击事件
|
||||
$('.czl-update-tracking-info').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
var button = $(this);
|
||||
var order_id = button.data('order-id');
|
||||
|
||||
button.prop('disabled', true).text('更新中...');
|
||||
|
||||
$.ajax({
|
||||
url: czl_ajax.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'czl_update_tracking_info',
|
||||
order_id: order_id,
|
||||
nonce: czl_ajax.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert(response.data);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert('请求失败,请重试');
|
||||
},
|
||||
complete: function() {
|
||||
button.prop('disabled', false).text('更新轨迹');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
BIN
assets/screenshot-1.png
Normal file
After Width: | Height: | Size: 199 KiB |
BIN
assets/screenshot-2.png
Normal file
After Width: | Height: | Size: 172 KiB |
BIN
assets/screenshot-3.png
Normal file
After Width: | Height: | Size: 152 KiB |
BIN
assets/screenshot-4.png
Normal file
After Width: | Height: | Size: 115 KiB |
BIN
assets/screenshot-5.png
Normal file
After Width: | Height: | Size: 144 KiB |
BIN
assets/screenshot-6.png
Normal file
After Width: | Height: | Size: 69 KiB |
@ -495,44 +495,269 @@ class CZL_API {
|
||||
}
|
||||
}
|
||||
|
||||
public function create_shipment($data) {
|
||||
/**
|
||||
* 认证方法
|
||||
*/
|
||||
public function authenticate() {
|
||||
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_error($ch));
|
||||
}
|
||||
|
||||
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('认证失败: 无效的响应数据');
|
||||
}
|
||||
|
||||
// 返回认证结果
|
||||
return array(
|
||||
'ack' => true,
|
||||
'customer_id' => $result['customer_id'],
|
||||
'customer_userid' => $result['customer_userid'],
|
||||
'message' => ''
|
||||
);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('CZL Express Error: Authentication failed - ' . $e->getMessage());
|
||||
return array(
|
||||
'ack' => false,
|
||||
'message' => $e->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function create_shipment($params) {
|
||||
try {
|
||||
error_log('CZL Express: Starting create shipment');
|
||||
|
||||
// 确保已认证
|
||||
$this->ensure_logged_in();
|
||||
// 先进行认证
|
||||
$auth_result = $this->authenticate();
|
||||
if (!$auth_result['ack']) {
|
||||
throw new Exception('认证失败: ' . $auth_result['message']);
|
||||
}
|
||||
|
||||
// 添加认证信息
|
||||
$data['customer_id'] = $this->customer_id;
|
||||
$data['customer_userid'] = $this->customer_userid;
|
||||
// 添加认证信息到参数
|
||||
$params['customer_id'] = $auth_result['customer_id'];
|
||||
$params['customer_userid'] = $auth_result['customer_userid'];
|
||||
|
||||
// 准备请求数据
|
||||
$request_data = array(
|
||||
'param' => json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
|
||||
'param' => json_encode($params)
|
||||
);
|
||||
|
||||
error_log('CZL Express: Create shipment request data - ' . print_r($request_data, true));
|
||||
|
||||
// 修改这里:使用完整的URL
|
||||
$api_url = 'https://tms.czl.net/createOrderApi.htm'; // 使用完整URL
|
||||
|
||||
// 发送请求
|
||||
$result = $this->make_request($api_url, $request_data);
|
||||
$curl = curl_init();
|
||||
curl_setopt_array($curl, array(
|
||||
CURLOPT_URL => 'https://tms.czl.net/createOrderApi.htm',
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_ENCODING => '',
|
||||
CURLOPT_MAXREDIRS => 10,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
|
||||
CURLOPT_CUSTOMREQUEST => 'POST',
|
||||
CURLOPT_POSTFIELDS => http_build_query($request_data),
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
'Accept: */*',
|
||||
'Accept-Language: zh-cn',
|
||||
'Cache-Control: no-cache',
|
||||
'Content-Type: application/x-www-form-urlencoded;charset=UTF-8'
|
||||
),
|
||||
CURLOPT_VERBOSE => true,
|
||||
CURLOPT_STDERR => fopen('php://temp', 'w+')
|
||||
));
|
||||
|
||||
// 获取详细的CURL日志
|
||||
$verbose = fopen('php://temp', 'w+');
|
||||
curl_setopt($curl, CURLOPT_STDERR, $verbose);
|
||||
|
||||
$response = curl_exec($curl);
|
||||
$err = curl_error($curl);
|
||||
|
||||
// 记录CURL详细日志
|
||||
rewind($verbose);
|
||||
$verboseLog = stream_get_contents($verbose);
|
||||
error_log('CZL Express: Curl verbose log - ' . $verboseLog);
|
||||
|
||||
if ($err) {
|
||||
throw new Exception('CURL错误: ' . $err);
|
||||
}
|
||||
|
||||
error_log('CZL Express: Raw response - ' . $response);
|
||||
|
||||
$result = json_decode($response, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new Exception('JSON解析错误: ' . json_last_error_msg());
|
||||
}
|
||||
|
||||
error_log('CZL Express: Create shipment 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);
|
||||
// 检查API错误信息
|
||||
if (isset($result['message']) && !empty($result['message'])) {
|
||||
error_log('CZL Express: API error message - ' . $result['message']);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('CZL Express Error: Create shipment failed - ' . $e->getMessage());
|
||||
error_log('CZL Express Error Stack Trace: ' . $e->getTraceAsString());
|
||||
error_log('CZL Express API Error: ' . $e->getMessage());
|
||||
throw $e;
|
||||
} finally {
|
||||
if (isset($curl)) {
|
||||
curl_close($curl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取跟踪单号
|
||||
*
|
||||
* @param string $czl_order_id CZL订单号
|
||||
* @return array 包含跟踪单号的响应数据
|
||||
* @throws Exception 如果请求失败
|
||||
*/
|
||||
public function get_tracking_number($czl_order_id) {
|
||||
$endpoint = '/api/tracking/number';
|
||||
|
||||
$params = array(
|
||||
'order_id' => $czl_order_id
|
||||
);
|
||||
|
||||
try {
|
||||
$response = $this->send_request('GET', $endpoint, $params);
|
||||
|
||||
if (empty($response['tracking_number'])) {
|
||||
throw new Exception('未找到跟踪单号');
|
||||
}
|
||||
|
||||
return array(
|
||||
'tracking_number' => $response['tracking_number'],
|
||||
'status' => isset($response['status']) ? $response['status'] : null
|
||||
);
|
||||
|
||||
} catch (Exception $e) {
|
||||
throw new Exception('获取跟踪单号失败: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取运单跟踪信息
|
||||
*/
|
||||
public function get_tracking_info($tracking_number) {
|
||||
try {
|
||||
$response = wp_remote_post('https://tms.czl.net/selectTrack.htm', array(
|
||||
'body' => array(
|
||||
'documentCode' => $tracking_number
|
||||
),
|
||||
'timeout' => 30,
|
||||
'headers' => array(
|
||||
'Accept-Encoding' => '',
|
||||
'Accept-Language' => 'zh-CN,zh;q=0.9'
|
||||
)
|
||||
));
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
throw new Exception($response->get_error_message());
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
error_log('CZL Express: Track raw response - ' . $body);
|
||||
|
||||
// 处理中文编码问题
|
||||
$body = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $body);
|
||||
$result = json_decode($body, true);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
error_log('CZL Express: JSON decode error - ' . json_last_error_msg());
|
||||
throw new Exception('JSON解析失败: ' . json_last_error_msg());
|
||||
}
|
||||
|
||||
error_log('CZL Express: Track decoded response - ' . print_r($result, true));
|
||||
|
||||
if (empty($result) || !isset($result[0])) {
|
||||
throw new Exception('无效的API响应');
|
||||
}
|
||||
|
||||
if (empty($result[0]['ack']) || $result[0]['ack'] !== 'true') {
|
||||
throw new Exception('获取跟踪信息失败: ' . ($result[0]['message'] ?? '未知错误'));
|
||||
}
|
||||
|
||||
if (empty($result[0]['data']) || !is_array($result[0]['data'])) {
|
||||
return array(
|
||||
'success' => true,
|
||||
'data' => array(
|
||||
'status' => 'pending',
|
||||
'track_content' => '暂无轨迹信息',
|
||||
'track_time' => current_time('mysql'),
|
||||
'track_location' => ''
|
||||
),
|
||||
'message' => ''
|
||||
);
|
||||
}
|
||||
|
||||
// 获取最新的轨迹状态
|
||||
$latest_track = $result[0]['data'][0];
|
||||
$track_details = $latest_track['trackDetails'] ?? array();
|
||||
$latest_detail = !empty($track_details) ? $track_details[0] : array();
|
||||
|
||||
// 根据轨迹内容判断状态
|
||||
$status = 'in_transit'; // 默认状态
|
||||
$track_content = strtolower($latest_detail['track_content'] ?? '');
|
||||
|
||||
if (strpos($track_content, 'delivered') !== false || strpos($track_content, 'signed') !== false) {
|
||||
$status = 'delivered';
|
||||
} elseif (strpos($track_content, 'pickup') !== false || strpos($track_content, 'picked up') !== false) {
|
||||
$status = 'picked_up';
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => true,
|
||||
'data' => array(
|
||||
'status' => $status,
|
||||
'track_content' => $latest_detail['track_content'] ?? '',
|
||||
'track_time' => $latest_detail['track_date'] ?? current_time('mysql'),
|
||||
'track_location' => $latest_detail['track_location'] ?? ''
|
||||
),
|
||||
'message' => ''
|
||||
);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('CZL Express API Error: ' . $e->getMessage());
|
||||
return array(
|
||||
'success' => false,
|
||||
'data' => null,
|
||||
'message' => $e->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -5,48 +5,72 @@ class CZL_Install {
|
||||
self::create_options();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建数据表
|
||||
*/
|
||||
public static function create_tables() {
|
||||
global $wpdb;
|
||||
|
||||
$charset_collate = $wpdb->get_charset_collate();
|
||||
|
||||
// 创建运单表
|
||||
$sql = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}czl_shipments (
|
||||
id bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
order_id bigint(20) NOT NULL,
|
||||
tracking_number varchar(50) NOT NULL,
|
||||
label_url varchar(255) DEFAULT NULL,
|
||||
shipping_method varchar(100) NOT NULL,
|
||||
status varchar(50) DEFAULT 'pending',
|
||||
created_at datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
tracking_number varchar(50),
|
||||
czl_order_id varchar(50),
|
||||
reference_number varchar(50),
|
||||
is_remote varchar(10),
|
||||
is_residential varchar(10),
|
||||
shipping_method varchar(50),
|
||||
status varchar(20),
|
||||
last_sync_time datetime DEFAULT NULL,
|
||||
created_at datetime NOT NULL,
|
||||
updated_at datetime NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY order_id (order_id),
|
||||
KEY tracking_number (tracking_number)
|
||||
) $charset_collate;";
|
||||
|
||||
// 创建运费规则表
|
||||
$sql .= "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}czl_shipping_rules (
|
||||
id bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
name varchar(100) NOT NULL,
|
||||
shipping_method varchar(100) NOT NULL,
|
||||
czl_product_code varchar(100) NOT NULL,
|
||||
price_adjustment varchar(255) DEFAULT NULL,
|
||||
status int(1) DEFAULT 1,
|
||||
created_at datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id)
|
||||
) $charset_collate;";
|
||||
|
||||
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
||||
dbDelta($sql);
|
||||
}
|
||||
|
||||
public static function create_options() {
|
||||
// 添加默认配置选项
|
||||
add_option('czl_api_url', '');
|
||||
add_option('czl_username', '');
|
||||
add_option('czl_password', '');
|
||||
add_option('czl_exchange_rate', '1');
|
||||
add_option('czl_product_groups', '');
|
||||
add_option('czl_express_api_url', 'https://api.czl.net');
|
||||
add_option('czl_express_api_key', '');
|
||||
add_option('czl_express_api_secret', '');
|
||||
add_option('czl_express_test_mode', 'yes');
|
||||
add_option('czl_last_tracking_sync', 0);
|
||||
add_option('czl_product_groups', array());
|
||||
}
|
||||
|
||||
public static function deactivate() {
|
||||
// 只清理定时任务
|
||||
wp_clear_scheduled_hook('czl_sync_tracking_numbers_hook');
|
||||
}
|
||||
|
||||
public static function uninstall() {
|
||||
global $wpdb;
|
||||
|
||||
// 只有在卸载时才删除数据
|
||||
if (!defined('WP_UNINSTALL_PLUGIN')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 删除数据表
|
||||
$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}czl_shipments");
|
||||
$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}czl_tracking_history");
|
||||
$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}czl_shipping_rules");
|
||||
$wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}czl_product_groups");
|
||||
|
||||
// 删除选项
|
||||
delete_option('czl_express_api_url');
|
||||
delete_option('czl_express_api_key');
|
||||
delete_option('czl_express_api_secret');
|
||||
delete_option('czl_express_test_mode');
|
||||
delete_option('czl_express_version');
|
||||
delete_option('czl_last_tracking_sync');
|
||||
delete_option('czl_express_db_version');
|
||||
delete_option('czl_product_groups');
|
||||
}
|
||||
}
|
@ -13,29 +13,32 @@ class CZL_Label {
|
||||
try {
|
||||
$order = wc_get_order($order_id);
|
||||
if (!$order) {
|
||||
throw new Exception('订单不存在');
|
||||
throw new Exception('Order not found');
|
||||
}
|
||||
|
||||
// 获取运单号
|
||||
// 获取运单号和订单号
|
||||
$tracking_number = $order->get_meta('_czl_tracking_number');
|
||||
$czl_order_id = $order->get_meta('_czl_order_id');
|
||||
|
||||
if (empty($tracking_number) && empty($czl_order_id)) {
|
||||
throw new Exception('未找到运单号或订单号');
|
||||
}
|
||||
|
||||
// 构建标签URL
|
||||
$base_url = 'https://tms.czl.net/printOrderLabel.htm';
|
||||
$params = array();
|
||||
|
||||
if (!empty($tracking_number)) {
|
||||
$params['documentCode'] = $tracking_number;
|
||||
} else {
|
||||
// 优先使用订单号
|
||||
if (!empty($czl_order_id)) {
|
||||
$params['order_id'] = $czl_order_id;
|
||||
$url = add_query_arg($params, $base_url);
|
||||
return $url;
|
||||
}
|
||||
|
||||
$url = add_query_arg($params, $base_url);
|
||||
return $url;
|
||||
// 如果没有订单号但有运单号,使用运单号
|
||||
if (!empty($tracking_number)) {
|
||||
$params['documentCode'] = $tracking_number;
|
||||
$url = add_query_arg($params, $base_url);
|
||||
return $url;
|
||||
}
|
||||
|
||||
throw new Exception('No tracking number or order ID found');
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('CZL Express Error: Failed to get label URL - ' . $e->getMessage());
|
||||
|
@ -12,143 +12,135 @@ if (!class_exists('CZL_Order')) {
|
||||
* 创建运单
|
||||
*/
|
||||
public function create_shipment($order_id) {
|
||||
global $wpdb;
|
||||
|
||||
try {
|
||||
error_log('CZL Express: Starting create shipment for order ' . $order_id);
|
||||
|
||||
// 更新订单备注以显示处理状态
|
||||
$order = wc_get_order($order_id);
|
||||
if (!$order) {
|
||||
throw new Exception('订单不存在');
|
||||
throw new Exception('订单未找到');
|
||||
}
|
||||
|
||||
// 添加处理中的状态提示
|
||||
$order->add_order_note('正在创建运单,请稍候...');
|
||||
$order->save();
|
||||
|
||||
// 检查是否已有运单
|
||||
$tracking_number = $order->get_meta('_czl_tracking_number');
|
||||
if (!empty($tracking_number)) {
|
||||
throw new Exception('订单已存在运单号');
|
||||
$existing_shipment = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT * FROM {$wpdb->prefix}czl_shipments WHERE order_id = %d",
|
||||
$order_id
|
||||
));
|
||||
|
||||
if ($existing_shipment) {
|
||||
$order->add_order_note('Shipment already exists for this order');
|
||||
throw new Exception('Shipment already exists for this order');
|
||||
}
|
||||
|
||||
// 获取运输方式信息
|
||||
$shipping_methods = $order->get_shipping_methods();
|
||||
$shipping_method = current($shipping_methods);
|
||||
|
||||
// 从配送方式元数据中获取product_id
|
||||
$product_id = $shipping_method->get_meta('product_id');
|
||||
if (empty($product_id)) {
|
||||
throw new Exception('未找到运输方式ID');
|
||||
}
|
||||
|
||||
// 在create_shipment方法中添加手机号和联系电话
|
||||
$phone = $order->get_billing_phone();
|
||||
// 清理电话号码,只保留数字
|
||||
$phone = preg_replace('/[^0-9]/', '', $phone);
|
||||
if (empty($product_id)) {
|
||||
throw new Exception('Shipping method not found');
|
||||
}
|
||||
|
||||
// 准备运单数据
|
||||
$shipment_data = array(
|
||||
'buyerid' => $order->get_id(),
|
||||
'buyerid' => strval($order->get_id()),
|
||||
'consignee_address' => $order->get_shipping_address_1() . ' ' . $order->get_shipping_address_2(),
|
||||
'consignee_city' => $order->get_shipping_city(),
|
||||
'consignee_mobile' => $order->get_billing_phone(), // 使用原始手机号
|
||||
'consignee_telephone' => $order->get_billing_phone(), // 使用原始手机号作为联系电话
|
||||
'consignee_mobile' => $order->get_billing_phone(),
|
||||
'consignee_telephone' => $order->get_billing_phone(),
|
||||
'consignee_name' => $order->get_shipping_first_name() . ' ' . $order->get_shipping_last_name(),
|
||||
'consignee_postcode' => $order->get_shipping_postcode(),
|
||||
'consignee_state' => $order->get_shipping_state(),
|
||||
'country' => $order->get_shipping_country(),
|
||||
'order_piece' => $this->get_order_items_count($order),
|
||||
'product_id' => $product_id,
|
||||
'order_piece' => strval($this->get_order_items_count($order)),
|
||||
'product_id' => strval($product_id),
|
||||
'trade_type' => 'ZYXT',
|
||||
'weight' => $this->get_order_weight($order),
|
||||
'orderInvoiceParam' => array()
|
||||
'weight' => strval($this->get_order_weight($order)),
|
||||
'length' => '10',
|
||||
'width' => '10',
|
||||
'height' => '10',
|
||||
'orderInvoiceParam' => $this->prepare_invoice_items($order)
|
||||
);
|
||||
|
||||
// 添加发票信息
|
||||
foreach ($order->get_items() as $item) {
|
||||
$product = $item->get_product();
|
||||
if (!$product) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取中文品名
|
||||
$name_cn = $product->get_meta('_czl_name_cn');
|
||||
if (empty($name_cn)) {
|
||||
throw new Exception('产品 ' . $product->get_name() . ' 缺少中文品名');
|
||||
}
|
||||
|
||||
// 获取海关编码
|
||||
$hs_code = $product->get_meta('_czl_hs_code');
|
||||
if (empty($hs_code)) {
|
||||
throw new Exception('产品 ' . $product->get_name() . ' 缺少海关编码');
|
||||
}
|
||||
|
||||
// 获取用途和材质
|
||||
$usage = $product->get_meta('_czl_usage');
|
||||
if (empty($usage)) {
|
||||
throw new Exception('产品 ' . $product->get_name() . ' 缺少用途信息');
|
||||
}
|
||||
|
||||
$material = $product->get_meta('_czl_material');
|
||||
if (empty($material)) {
|
||||
throw new Exception('产品 ' . $product->get_name() . ' 缺少材质信息');
|
||||
}
|
||||
|
||||
$shipment_data['orderInvoiceParam'][] = array(
|
||||
'invoice_amount' => $item->get_total(),
|
||||
'invoice_pcs' => $item->get_quantity(),
|
||||
'invoice_title' => $item->get_name(), // 英文品名(原商品名)
|
||||
'invoice_weight' => $product->get_weight() * $item->get_quantity(),
|
||||
'sku' => $name_cn, // 中文品名
|
||||
'hs_code' => $hs_code, // 海关编码
|
||||
'invoice_material' => $material, // 材质
|
||||
'invoice_purpose' => $usage, // 用途
|
||||
'item_id' => $product->get_id(),
|
||||
'sku_code' => $product->get_sku() // SKU作为配货信息
|
||||
);
|
||||
}
|
||||
|
||||
// 调用API创建运单
|
||||
$result = $this->api->create_shipment($shipment_data);
|
||||
error_log('CZL Express: API response - ' . print_r($result, true));
|
||||
|
||||
// 记录API响应
|
||||
error_log('CZL Express: Create shipment response - ' . print_r($result, true));
|
||||
|
||||
// 检查是否有订单号,即使API返回失败
|
||||
if (!empty($result['order_id'])) {
|
||||
// 更新订单元数据
|
||||
$order->update_meta_data('_czl_order_id', $result['order_id']);
|
||||
// 检查API响应状态
|
||||
if ($result['ack'] !== 'true') {
|
||||
$error_msg = isset($result['message']) && !empty($result['message'])
|
||||
? urldecode($result['message'])
|
||||
: '创建运单失败,请稍后重试或联系客服';
|
||||
|
||||
// 如果有跟踪号,也保存下来
|
||||
if (!empty($result['tracking_number'])) {
|
||||
$order->update_meta_data('_czl_tracking_number', $result['tracking_number']);
|
||||
}
|
||||
|
||||
// 保存偏远地区信息(如果有)
|
||||
if (isset($result['is_remote'])) {
|
||||
$order->update_meta_data('_czl_is_remote', $result['is_remote']);
|
||||
}
|
||||
if (isset($result['is_residential'])) {
|
||||
$order->update_meta_data('_czl_is_residential', $result['is_residential']);
|
||||
}
|
||||
|
||||
// 如果API返回失败但有订单号,记录错误信息
|
||||
if ($result['ack'] !== 'true') {
|
||||
$error_msg = isset($result['message']) ? urldecode($result['message']) : 'Unknown error';
|
||||
// 如果有订单号但API返回失败,记录警告并继续
|
||||
if (!empty($result['order_id']) || !empty($result['tracking_number'])) {
|
||||
$order->add_order_note(sprintf(
|
||||
__('Shipment partially created. Order ID: %s. Error: %s', 'woo-czl-express'),
|
||||
'Shipment Creation Warning: %s (Order ID: %s, Tracking Number: %s)',
|
||||
$error_msg,
|
||||
$result['order_id'],
|
||||
$error_msg
|
||||
$result['tracking_number']
|
||||
));
|
||||
$order->update_status('on-hold', __('Shipment needs manual processing', 'woo-czl-express'));
|
||||
} else {
|
||||
$order->update_status('in_transit', __('Package in transit', 'woo-czl-express'));
|
||||
// 如果没有订单号,抛出异常
|
||||
throw new Exception($error_msg);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否有订单号或跟踪号
|
||||
if (!empty($result['order_id']) || !empty($result['tracking_number'])) {
|
||||
// 保存运单信息到数据库
|
||||
$wpdb->insert(
|
||||
$wpdb->prefix . 'czl_shipments',
|
||||
array(
|
||||
'order_id' => $order_id,
|
||||
'tracking_number' => $result['tracking_number'],
|
||||
'czl_order_id' => $result['order_id'],
|
||||
'reference_number' => $result['reference_number'],
|
||||
'is_remote' => $result['is_remote'],
|
||||
'is_residential' => $result['is_residential'],
|
||||
'shipping_method' => $shipping_method->get_method_id(),
|
||||
'status' => $result['ack'] === 'true' ? 'pending' : 'warning',
|
||||
'created_at' => current_time('mysql'),
|
||||
'updated_at' => current_time('mysql')
|
||||
),
|
||||
array('%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')
|
||||
);
|
||||
|
||||
// 更新订单元数据
|
||||
$order->update_meta_data('_czl_tracking_number', $result['tracking_number']);
|
||||
$order->update_meta_data('_czl_order_id', $result['order_id']);
|
||||
$order->update_meta_data('_czl_reference_number', $result['reference_number']);
|
||||
$order->save();
|
||||
|
||||
// 即使API返回失败,只要有订单号就返回结果
|
||||
return $result;
|
||||
// 添加成功提示
|
||||
$order->add_order_note(sprintf(
|
||||
'Shipment created successfully (Order ID: %s, Tracking Number: %s)',
|
||||
$result['order_id'],
|
||||
$result['tracking_number']
|
||||
));
|
||||
|
||||
return true;
|
||||
} else {
|
||||
throw new Exception('创建运单失败:未获取到订单号');
|
||||
throw new Exception('API未返回运单号或跟踪号');
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('CZL Express Error: ' . $e->getMessage());
|
||||
throw $e;
|
||||
error_log('CZL Express Error: Create shipment failed - ' . $e->getMessage());
|
||||
error_log('CZL Express Error Stack Trace: ' . $e->getTraceAsString());
|
||||
|
||||
// 添加错误提示到订单备注
|
||||
if (isset($order)) {
|
||||
$order->add_order_note('运单创建失败: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
// 抛出异常以便上层处理
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,59 +170,135 @@ if (!class_exists('CZL_Order')) {
|
||||
$items = array();
|
||||
foreach ($order->get_items() as $item) {
|
||||
$product = $item->get_product();
|
||||
if (!$product) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取产品尺寸,确保是数字类型
|
||||
$length = floatval($product->get_length() ?: 10);
|
||||
$width = floatval($product->get_width() ?: 10);
|
||||
$height = floatval($product->get_height() ?: 10);
|
||||
|
||||
$items[] = array(
|
||||
'invoice_amount' => $item->get_total(),
|
||||
'invoice_pcs' => $item->get_quantity(),
|
||||
'invoice_amount' => strval($item->get_total()), // 转为字符串
|
||||
'invoice_pcs' => intval($item->get_quantity()), // 确保是整数
|
||||
'invoice_title' => $item->get_name(),
|
||||
'invoice_weight' => $product ? ($product->get_weight() * $item->get_quantity()) : 0.1,
|
||||
'item_id' => $product ? $product->get_id() : '',
|
||||
'sku' => $product ? $product->get_sku() : ''
|
||||
'invoice_weight' => floatval($product->get_weight() * $item->get_quantity()), // 确保是数字
|
||||
'sku' => $product->get_meta('_czl_name_cn'),
|
||||
'hs_code' => $product->get_meta('_czl_hs_code'),
|
||||
'invoice_material' => $product->get_meta('_czl_material'),
|
||||
'invoice_purpose' => $product->get_meta('_czl_usage'),
|
||||
'item_id' => strval($product->get_id()), // 转为字符串
|
||||
'sku_code' => $product->get_sku(),
|
||||
'length' => strval($length), // 转为字符串
|
||||
'width' => strval($width), // 转为字符串
|
||||
'height' => strval($height) // 转为字符串
|
||||
);
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新订单轨迹信息
|
||||
* 更新运单轨迹信息
|
||||
*/
|
||||
public function update_tracking_info($order_id) {
|
||||
try {
|
||||
$order = wc_get_order($order_id);
|
||||
if (!$order) {
|
||||
return;
|
||||
}
|
||||
global $wpdb;
|
||||
|
||||
// 获取运单信息
|
||||
$shipment = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT * FROM {$wpdb->prefix}czl_shipments WHERE order_id = %d",
|
||||
$order_id
|
||||
));
|
||||
|
||||
if (!$shipment || empty($shipment->tracking_number)) {
|
||||
throw new Exception('未找到运单信息');
|
||||
}
|
||||
|
||||
// 获取轨迹信息
|
||||
$api = new CZL_API();
|
||||
$tracking_info = $api->get_tracking_info($shipment->tracking_number);
|
||||
error_log('CZL Express: Tracking API response - ' . print_r($tracking_info, true));
|
||||
|
||||
// 处理API响应
|
||||
if (!empty($tracking_info) && isset($tracking_info['success']) && $tracking_info['success'] == 1) {
|
||||
// 检查API返回的状态
|
||||
$api_status = isset($tracking_info['data']['status']) ? strtolower(trim($tracking_info['data']['status'])) : '';
|
||||
$is_delivered = ($api_status === 'delivered');
|
||||
|
||||
$tracking_number = $order->get_meta('_czl_tracking_number');
|
||||
if (empty($tracking_number)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取轨迹信息
|
||||
$tracking_info = $this->api->get_tracking_info($tracking_number);
|
||||
if (empty($tracking_info)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存轨迹信息
|
||||
$order->update_meta_data('_czl_tracking_history', $tracking_info);
|
||||
|
||||
// 根据最新轨迹更新订单状态
|
||||
$latest_status = end($tracking_info['trackDetails']);
|
||||
if ($latest_status) {
|
||||
// 检查是否已签收
|
||||
if (strpos($latest_status['track_content'], '已签收') !== false ||
|
||||
strpos($latest_status['track_content'], 'Delivered') !== false) {
|
||||
$order->update_status('delivered', __('包裹已送达', 'woo-czl-express'));
|
||||
} else {
|
||||
$order->update_status('shipping', __('包裹运输中', 'woo-czl-express'));
|
||||
// 如果API状态不是delivered,再检查轨迹详情
|
||||
if (!$is_delivered && isset($tracking_info[0]['data'][0]['trackDetails']) && is_array($tracking_info[0]['data'][0]['trackDetails'])) {
|
||||
$latest_track = $tracking_info[0]['data'][0]['trackDetails'][0];
|
||||
$track_signdate = isset($latest_track['track_signdate']) ? trim($latest_track['track_signdate']) : '';
|
||||
$track_signperson = isset($latest_track['track_signperson']) ? trim($latest_track['track_signperson']) : '';
|
||||
|
||||
// 如果有签收时间和签收人,也认为是已签收
|
||||
if (!empty($track_signdate) && !empty($track_signperson)) {
|
||||
$is_delivered = true;
|
||||
}
|
||||
}
|
||||
|
||||
$order->save();
|
||||
// 更新运单表状态
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'czl_shipments',
|
||||
array(
|
||||
'status' => $is_delivered ? 'delivered' : 'in_transit',
|
||||
'last_sync_time' => current_time('mysql')
|
||||
),
|
||||
array('order_id' => $order_id),
|
||||
array('%s', '%s'),
|
||||
array('%d')
|
||||
);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('CZL Express Error: Failed to update tracking info - ' . $e->getMessage());
|
||||
// 获取订单对象
|
||||
$order = wc_get_order($order_id);
|
||||
if ($order) {
|
||||
// 根据签收状态更新订单状态
|
||||
if ($is_delivered && $order->get_status() !== 'completed') {
|
||||
$order->update_status('completed', sprintf('包裹已签收(%s),订单自动完成',
|
||||
$tracking_info['data']['track_content']
|
||||
));
|
||||
}
|
||||
|
||||
try {
|
||||
// 构建轨迹信息
|
||||
$note_content = array();
|
||||
$note_content[] = 'Package Status Update:';
|
||||
|
||||
if (!empty($tracking_info['data']['track_content'])) {
|
||||
$note_content[] = sprintf('Status: %s', $tracking_info['data']['track_content']);
|
||||
}
|
||||
|
||||
if (!empty($tracking_info['data']['track_location'])) {
|
||||
$note_content[] = sprintf('Location: %s', $tracking_info['data']['track_location']);
|
||||
}
|
||||
|
||||
if (!empty($tracking_info['data']['track_time'])) {
|
||||
$note_content[] = sprintf('Time: %s', $tracking_info['data']['track_time']);
|
||||
}
|
||||
|
||||
$note_content[] = sprintf('Tracking Number: %s', $shipment->tracking_number);
|
||||
$note_content[] = '';
|
||||
$note_content[] = sprintf('Track your package: https://exp.czl.net/track/?query=%s', $shipment->tracking_number);
|
||||
|
||||
// 添加新的轨迹信息
|
||||
$note = implode("\n", array_filter($note_content));
|
||||
$comment_id = $order->add_order_note($note, 1);
|
||||
|
||||
if (!$comment_id) {
|
||||
throw new Exception('Failed to add order note');
|
||||
}
|
||||
|
||||
$order->save();
|
||||
return true;
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('CZL Express: Error updating tracking info - ' . $e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -192,6 +192,35 @@ class CZL_Rate_Calculator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算单个产品的计费重
|
||||
* @param WC_Product $product 产品对象
|
||||
* @param int $quantity 数量
|
||||
* @return float 计费重
|
||||
*/
|
||||
private function calculate_chargeable_weight($product, $quantity) {
|
||||
// 获取产品尺寸和重量
|
||||
$length = (float)$product->get_length();
|
||||
$width = (float)$product->get_width();
|
||||
$height = (float)$product->get_height();
|
||||
$actual_weight = (float)$product->get_weight();
|
||||
|
||||
// 确保所有值都大于0
|
||||
$length = max($length, 1);
|
||||
$width = max($width, 1);
|
||||
$height = max($height, 1);
|
||||
$actual_weight = max($actual_weight, 0.1);
|
||||
|
||||
// 计算体积重 (长*宽*高/5000)
|
||||
$volumetric_weight = ($length * $width * $height) / 5000;
|
||||
|
||||
// 取实重和体积重中的较大值
|
||||
$chargeable_weight = max($actual_weight, $volumetric_weight);
|
||||
|
||||
// 乘以数量
|
||||
return $chargeable_weight * $quantity;
|
||||
}
|
||||
|
||||
public function calculate_shipping_rate($package) {
|
||||
try {
|
||||
error_log('CZL Express: Calculating shipping rate for package: ' . print_r($package, true));
|
||||
@ -202,44 +231,29 @@ class CZL_Rate_Calculator {
|
||||
return array();
|
||||
}
|
||||
|
||||
// 获取包裹信息
|
||||
$weight = 0;
|
||||
$length = 0;
|
||||
$width = 0;
|
||||
$height = 0;
|
||||
// 计算总计费重
|
||||
$total_chargeable_weight = 0;
|
||||
|
||||
foreach ($package['contents'] as $item) {
|
||||
$product = $item['data'];
|
||||
$quantity = $item['quantity'];
|
||||
|
||||
// 累加重量
|
||||
$item_weight = (float)$product->get_weight();
|
||||
if ($item_weight > 0) {
|
||||
$weight += $item_weight * $quantity;
|
||||
}
|
||||
|
||||
// 获取最大尺寸
|
||||
$item_length = (float)$product->get_length();
|
||||
$item_width = (float)$product->get_width();
|
||||
$item_height = (float)$product->get_height();
|
||||
|
||||
$length = max($length, $item_length);
|
||||
$width = max($width, $item_width);
|
||||
$height = max($height, $item_height);
|
||||
// 累加计费重
|
||||
$total_chargeable_weight += $this->calculate_chargeable_weight($product, $quantity);
|
||||
}
|
||||
|
||||
// 调用API获取运费
|
||||
$api_params = array(
|
||||
'weight' => $weight > 0 ? $weight : 0.1, // 默认最小重量0.1kg
|
||||
'weight' => $total_chargeable_weight, // 使用计算出的总计费重
|
||||
'country' => $package['destination']['country'],
|
||||
'postcode' => $package['destination']['postcode'],
|
||||
'length' => $length > 0 ? $length : 1,
|
||||
'width' => $width > 0 ? $width : 1,
|
||||
'height' => $height > 0 ? $height : 1,
|
||||
'cargoType' => 'P'
|
||||
'cargoType' => 'P',
|
||||
'length' => 10, // 添加固定尺寸
|
||||
'width' => 10, // 添加固定尺寸
|
||||
'height' => 10 // 添加固定尺寸
|
||||
);
|
||||
|
||||
error_log('CZL Express: API params: ' . print_r($api_params, true));
|
||||
error_log('CZL Express: API params with chargeable weight: ' . print_r($api_params, true));
|
||||
|
||||
// 调用API获取运费
|
||||
$api_rates = $this->api->get_shipping_rate($api_params);
|
||||
@ -268,6 +282,8 @@ class CZL_Rate_Calculator {
|
||||
if (strpos($product_name, $prefix) === 0) {
|
||||
$group_id = sanitize_title($group['groupName']);
|
||||
if (!isset($grouped_rates[$group_id]) ||
|
||||
!isset($grouped_rates[$group_id]['meta_data']) ||
|
||||
!isset($grouped_rates[$group_id]['meta_data']['original_amount']) ||
|
||||
$amount < $grouped_rates[$group_id]['meta_data']['original_amount']) {
|
||||
|
||||
// 构建分组运费数据
|
||||
@ -328,9 +344,7 @@ class CZL_Rate_Calculator {
|
||||
return $delivery_time;
|
||||
}
|
||||
|
||||
// 匹配各种中文时效格式并转换为英文
|
||||
|
||||
// 匹配"XX-XX个工作日"格式
|
||||
// 匹配中文时效格式
|
||||
if (preg_match('/(\d+)-(\d+)个工作日/', $delivery_time, $matches)) {
|
||||
return sprintf('%d-%d working days', $matches[1], $matches[2]);
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
<?php
|
||||
class CZL_Tracking {
|
||||
private $api;
|
||||
|
||||
public function __construct() {
|
||||
$this->api = new CZL_API();
|
||||
|
||||
// 添加定时任务钩子
|
||||
add_action('czl_update_tracking_cron', array($this, 'update_all_tracking_info'));
|
||||
|
||||
@ -11,56 +15,93 @@ class CZL_Tracking {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新所有活跃订单的轨迹信息
|
||||
* 更新所有活跃运单的轨迹信息
|
||||
*/
|
||||
public function update_all_tracking_info() {
|
||||
$orders = wc_get_orders(array(
|
||||
'limit' => -1,
|
||||
'status' => array('processing', 'shipping'),
|
||||
'meta_key' => '_czl_tracking_number',
|
||||
'meta_compare' => 'EXISTS'
|
||||
));
|
||||
global $wpdb;
|
||||
|
||||
foreach ($orders as $order) {
|
||||
$this->update_tracking_info($order->get_id());
|
||||
// 获取所有需要更新的运单
|
||||
$shipments = $wpdb->get_results(
|
||||
"SELECT * FROM {$wpdb->prefix}czl_shipments
|
||||
WHERE status NOT IN ('delivered', 'cancelled', 'failed')"
|
||||
);
|
||||
|
||||
foreach ($shipments as $shipment) {
|
||||
$this->update_tracking_info($shipment->tracking_number);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新单个订单的轨迹信息
|
||||
* 更新单个运单的轨迹信息
|
||||
*/
|
||||
public function update_tracking_info($order_id) {
|
||||
public function update_tracking_info($tracking_number) {
|
||||
global $wpdb;
|
||||
|
||||
try {
|
||||
$order = wc_get_order($order_id);
|
||||
if (!$order) {
|
||||
// 获取运单信息
|
||||
$shipment = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT * FROM {$wpdb->prefix}czl_shipments WHERE tracking_number = %s",
|
||||
$tracking_number
|
||||
));
|
||||
|
||||
if (!$shipment) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tracking_number = $order->get_meta('_czl_tracking_number');
|
||||
if (empty($tracking_number)) {
|
||||
return;
|
||||
}
|
||||
// 获取轨迹信息
|
||||
$tracking_info = $this->api->get_tracking($tracking_number);
|
||||
|
||||
$api = new CZL_API();
|
||||
$tracking_info = $api->get_tracking($tracking_number);
|
||||
|
||||
if (!empty($tracking_info)) {
|
||||
// 保存轨迹信息
|
||||
$order->update_meta_data('_czl_tracking_history', $tracking_info);
|
||||
|
||||
// 根据最新轨迹更新订单状态
|
||||
if (!empty($tracking_info['trackDetails'])) {
|
||||
$latest_status = reset($tracking_info['trackDetails']);
|
||||
if (!empty($tracking_info['trackDetails'])) {
|
||||
foreach ($tracking_info['trackDetails'] as $detail) {
|
||||
// 检查是否已存在该轨迹记录
|
||||
$exists = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT id FROM {$wpdb->prefix}czl_tracking_history
|
||||
WHERE shipment_id = %d AND track_date = %s AND track_content = %s",
|
||||
$shipment->id,
|
||||
$detail['track_date'],
|
||||
$detail['track_content']
|
||||
));
|
||||
|
||||
if (strpos($latest_status['track_content'], '已签收') !== false ||
|
||||
strpos($latest_status['track_content'], 'Delivered') !== false) {
|
||||
$order->update_status('delivered', __('Package delivered', 'woo-czl-express'));
|
||||
} elseif ($order->get_status() !== 'delivered') {
|
||||
$order->update_status('in_transit', __('Package in transit', 'woo-czl-express'));
|
||||
if (!$exists) {
|
||||
// 插入新的轨迹记录
|
||||
$wpdb->insert(
|
||||
$wpdb->prefix . 'czl_tracking_history',
|
||||
array(
|
||||
'shipment_id' => $shipment->id,
|
||||
'tracking_number' => $tracking_number,
|
||||
'track_date' => $detail['track_date'],
|
||||
'track_location' => $detail['track_location'],
|
||||
'track_content' => $detail['track_content'],
|
||||
'created_at' => current_time('mysql')
|
||||
),
|
||||
array('%d', '%s', '%s', '%s', '%s', '%s')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$order->save();
|
||||
// 更新运单状态
|
||||
$latest = reset($tracking_info['trackDetails']);
|
||||
$new_status = 'in_transit';
|
||||
|
||||
if (strpos($latest['track_content'], '已签收') !== false ||
|
||||
strpos($latest['track_content'], 'Delivered') !== false) {
|
||||
$new_status = 'delivered';
|
||||
}
|
||||
|
||||
// 更新运单状态
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'czl_shipments',
|
||||
array('status' => $new_status),
|
||||
array('id' => $shipment->id),
|
||||
array('%s'),
|
||||
array('%d')
|
||||
);
|
||||
|
||||
// 更新WooCommerce订单状态
|
||||
$order = wc_get_order($shipment->order_id);
|
||||
if ($order) {
|
||||
$order->update_status($new_status, __('Package status updated from tracking info', 'woo-czl-express'));
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
|
@ -1,22 +0,0 @@
|
||||
class WC_CZLExpress_Install {
|
||||
|
||||
public function migrate_to_hpos() {
|
||||
global $wpdb;
|
||||
|
||||
// 获取所有需要迁移的订单
|
||||
$orders = $wpdb->get_results("
|
||||
SELECT post_id, meta_key, meta_value
|
||||
FROM {$wpdb->postmeta}
|
||||
WHERE meta_key LIKE '_czlexpress_%'
|
||||
");
|
||||
|
||||
foreach ($orders as $order_data) {
|
||||
$order = wc_get_order($order_data->post_id);
|
||||
if ($order) {
|
||||
// 迁移元数据到新系统
|
||||
$order->update_meta_data($order_data->meta_key, $order_data->meta_value);
|
||||
$order->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -17,8 +17,8 @@ class WooCzlExpress {
|
||||
add_action('wp_ajax_czl_test_connection', array($this, 'handle_test_connection'));
|
||||
|
||||
// 添加自定义订单状态
|
||||
add_action('init', array($this, 'register_custom_order_statuses'));
|
||||
add_filter('wc_order_statuses', array($this, 'add_custom_order_statuses'));
|
||||
add_action('init', array($this, 'register_custom_order_statuses'), 10);
|
||||
add_filter('wc_order_statuses', array($this, 'add_custom_order_statuses'), 10);
|
||||
|
||||
// 添加订单状态自动更新
|
||||
add_action('wp_ajax_czl_update_order_status', array($this, 'update_order_status'));
|
||||
@ -35,6 +35,12 @@ class WooCzlExpress {
|
||||
if (!wp_next_scheduled('czl_update_tracking_info')) {
|
||||
wp_schedule_event(time(), 'hourly', 'czl_update_tracking_info');
|
||||
}
|
||||
|
||||
// 添加状态迁移钩子
|
||||
add_action('init', array($this, 'migrate_order_statuses'), 20);
|
||||
|
||||
// 保留批量创建功能,因为这是我们自己的订单管理页面的功能
|
||||
add_action('wp_ajax_czl_bulk_create_shipment', array($this, 'handle_bulk_create_shipment'));
|
||||
}
|
||||
|
||||
private function init() {
|
||||
@ -81,13 +87,6 @@ class WooCzlExpress {
|
||||
// 跟踪信息显示钩子
|
||||
add_action('woocommerce_order_details_after_order_table', array('CZL_Tracking', 'display_tracking_info'));
|
||||
add_action('woocommerce_admin_order_data_after_shipping_address', array('CZL_Tracking', 'display_admin_tracking_info'));
|
||||
|
||||
// 添加订单操作
|
||||
add_filter('woocommerce_order_actions', array($this, 'add_order_actions'), 10, 2);
|
||||
|
||||
// 添加AJAX处理
|
||||
add_action('wp_ajax_czl_create_shipment', array($this, 'handle_create_shipment'));
|
||||
add_action('wp_ajax_czl_bulk_create_shipment', array($this, 'handle_bulk_create_shipment'));
|
||||
}
|
||||
|
||||
public function init_shipping_method() {
|
||||
@ -364,6 +363,13 @@ class WooCzlExpress {
|
||||
* 注册自定义订单状态
|
||||
*/
|
||||
public function register_custom_order_statuses() {
|
||||
static $registered = false;
|
||||
|
||||
// 防止重复注册
|
||||
if ($registered) {
|
||||
return;
|
||||
}
|
||||
|
||||
register_post_status('wc-in_transit', array(
|
||||
'label' => _x('In Transit', 'Order status', 'woo-czl-express'),
|
||||
'public' => true,
|
||||
@ -383,18 +389,30 @@ class WooCzlExpress {
|
||||
'label_count' => _n_noop('Delivered <span class="count">(%s)</span>',
|
||||
'Delivered <span class="count">(%s)</span>', 'woo-czl-express')
|
||||
));
|
||||
|
||||
$registered = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加自定义订单状态到WooCommerce状态列表
|
||||
*/
|
||||
public function add_custom_order_statuses($order_statuses) {
|
||||
static $added = false;
|
||||
|
||||
// 防止重复添加
|
||||
if ($added) {
|
||||
return $order_statuses;
|
||||
}
|
||||
|
||||
$new_statuses = array(
|
||||
'wc-in_transit' => _x('In Transit', 'Order status', 'woo-czl-express'),
|
||||
'wc-delivered' => _x('Delivered', 'Order status', 'woo-czl-express')
|
||||
);
|
||||
|
||||
return array_merge($order_statuses, $new_statuses);
|
||||
$order_statuses = array_merge($order_statuses, $new_statuses);
|
||||
$added = true;
|
||||
|
||||
return $order_statuses;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -531,89 +549,58 @@ class WooCzlExpress {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理批量创建运单的AJAX请求
|
||||
*/
|
||||
public function handle_bulk_create_shipment() {
|
||||
check_ajax_referer('czl_bulk_create_shipment', 'nonce');
|
||||
|
||||
if (!current_user_can('manage_woocommerce')) {
|
||||
wp_send_json_error(array('message' => __('权限不足', 'woo-czl-express')));
|
||||
}
|
||||
|
||||
$order_ids = isset($_POST['order_ids']) ? array_map('intval', $_POST['order_ids']) : array();
|
||||
if (empty($order_ids)) {
|
||||
wp_send_json_error(array('message' => __('请选择订单', 'woo-czl-express')));
|
||||
}
|
||||
|
||||
$success = 0;
|
||||
$failed = 0;
|
||||
$failed_orders = array();
|
||||
$czl_order = new CZL_Order();
|
||||
|
||||
foreach ($order_ids as $order_id) {
|
||||
try {
|
||||
$order = wc_get_order($order_id);
|
||||
if (!$order) {
|
||||
throw new Exception('订单不存在');
|
||||
}
|
||||
|
||||
$result = $czl_order->create_shipment($order_id);
|
||||
|
||||
if (!empty($result)) {
|
||||
// 更新WooCommerce订单元数据
|
||||
$order->update_meta_data('_czl_tracking_number', $result['tracking_number']);
|
||||
$order->update_meta_data('_czl_order_id', $result['order_id']);
|
||||
|
||||
// 保存子单号
|
||||
if (!empty($result['childList'])) {
|
||||
$child_numbers = array_map(function($child) {
|
||||
return $child['child_number'];
|
||||
}, $result['childList']);
|
||||
$order->update_meta_data('_czl_child_numbers', $child_numbers);
|
||||
}
|
||||
|
||||
// 添加订单备注
|
||||
$order->add_order_note(
|
||||
sprintf(
|
||||
__('CZL Express运单创建成功。运单号: %s', 'woo-czl-express'),
|
||||
$result['tracking_number']
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
// 更新订单状态为运输中
|
||||
$order->update_status('shipping', __('运单已创建,包裹开始运输', 'woo-czl-express'));
|
||||
|
||||
// 保存更改
|
||||
$order->save();
|
||||
|
||||
$success++;
|
||||
} else {
|
||||
throw new Exception('运单创建失败');
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('CZL Express Error: Failed to create shipment for order ' . $order_id . ' - ' . $e->getMessage());
|
||||
if (isset($order)) {
|
||||
$order->add_order_note(
|
||||
sprintf(
|
||||
__('CZL Express运单创建失败: %s', 'woo-czl-express'),
|
||||
$e->getMessage()
|
||||
),
|
||||
true
|
||||
);
|
||||
}
|
||||
$failed++;
|
||||
$failed_orders[] = $order_id;
|
||||
try {
|
||||
// 验证nonce
|
||||
check_ajax_referer('czl_bulk_create_shipment', 'nonce');
|
||||
|
||||
if (!current_user_can('manage_woocommerce')) {
|
||||
throw new Exception(__('权限不足', 'woo-czl-express'));
|
||||
}
|
||||
|
||||
// 获取订单ID
|
||||
$order_ids = isset($_POST['order_ids']) ? array_map('intval', (array)$_POST['order_ids']) : array();
|
||||
if (empty($order_ids)) {
|
||||
throw new Exception(__('请选择订单', 'woo-czl-express'));
|
||||
}
|
||||
|
||||
$success = 0;
|
||||
$failed = 0;
|
||||
$failed_orders = array();
|
||||
$czl_order = new CZL_Order();
|
||||
|
||||
foreach ($order_ids as $order_id) {
|
||||
try {
|
||||
$result = $czl_order->create_shipment($order_id);
|
||||
if (!empty($result)) {
|
||||
$success++;
|
||||
} else {
|
||||
throw new Exception('运单创建失败');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$failed++;
|
||||
$failed_orders[] = $order_id;
|
||||
error_log('CZL Express Error: Failed to create shipment for order ' . $order_id . ' - ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
wp_send_json_success(array(
|
||||
'message' => sprintf(
|
||||
__('处理完成。成功:%d,失败:%d', 'woo-czl-express'),
|
||||
$success,
|
||||
$failed
|
||||
),
|
||||
'failed_orders' => $failed_orders
|
||||
));
|
||||
|
||||
} catch (Exception $e) {
|
||||
wp_send_json_error(array(
|
||||
'message' => $e->getMessage()
|
||||
));
|
||||
}
|
||||
|
||||
wp_send_json_success(array(
|
||||
'message' => sprintf(
|
||||
__('处理完成。成功:%d,失败:%d', 'woo-czl-express'),
|
||||
$success,
|
||||
$failed
|
||||
),
|
||||
'failed_orders' => $failed_orders
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -628,4 +615,22 @@ class WooCzlExpress {
|
||||
// 加载订单列表页面模板
|
||||
require_once WOO_CZL_EXPRESS_PATH . 'admin/views/orders.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* 迁移旧的订单状态到新的状态
|
||||
*/
|
||||
public function migrate_order_statuses() {
|
||||
global $wpdb;
|
||||
|
||||
// 从 'shipping' 迁移到 'in_transit'
|
||||
$wpdb->query("
|
||||
UPDATE {$wpdb->posts}
|
||||
SET post_status = 'wc-in_transit'
|
||||
WHERE post_status = 'wc-shipping'
|
||||
AND post_type = 'shop_order'
|
||||
");
|
||||
|
||||
// 清除订单缓存
|
||||
wc_delete_shop_order_transients();
|
||||
}
|
||||
}
|
76
languages/woo-czl-express-zh_CN.po
Normal file
@ -0,0 +1,76 @@
|
||||
# Copyright (C) 2024 CZL Express
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: CZL Express for WooCommerce 1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: https://exp.czl.net\n"
|
||||
"POT-Creation-Date: 2024-01-01 00:00:00+00:00\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"PO-Revision-Date: 2024-01-01 00:00:00+00:00\n"
|
||||
"Last-Translator: CZL Express\n"
|
||||
"Language-Team: CZL Express\n"
|
||||
"Language: zh_CN\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: woocommerce-czlexpress.php:89
|
||||
msgid "CZL Express requires WooCommerce to be installed and active"
|
||||
msgstr "CZL Express 需要安装并激活 WooCommerce"
|
||||
|
||||
#: woocommerce-czlexpress.php:98
|
||||
msgid "CZL Express requires WooCommerce 6.0.0 or higher"
|
||||
msgstr "CZL Express 需要 WooCommerce 6.0.0 或更高版本"
|
||||
|
||||
#: woocommerce-czlexpress.php:142
|
||||
msgctxt "Order status"
|
||||
msgid "In Transit"
|
||||
msgstr "运输中"
|
||||
|
||||
#: woocommerce-czlexpress.php:187
|
||||
msgid "Creating shipment..."
|
||||
msgstr "正在创建运单..."
|
||||
|
||||
#: woocommerce-czlexpress.php:188
|
||||
msgid "Shipment created successfully"
|
||||
msgstr "运单创建成功"
|
||||
|
||||
#: woocommerce-czlexpress.php:189
|
||||
msgid "Failed to create shipment"
|
||||
msgstr "运单创建失败"
|
||||
|
||||
#: woocommerce-czlexpress.php:199
|
||||
msgid "Permission denied"
|
||||
msgstr "权限不足"
|
||||
|
||||
#: woocommerce-czlexpress.php:203
|
||||
msgid "Invalid order ID"
|
||||
msgstr "无效的订单ID"
|
||||
|
||||
#: woocommerce-czlexpress.php:247
|
||||
msgid "Invalid parameters"
|
||||
msgstr "无效的参数"
|
||||
|
||||
#: woocommerce-czlexpress.php:255
|
||||
msgid "Database update failed"
|
||||
msgstr "数据库更新失败"
|
||||
|
||||
#: woocommerce-czlexpress.php:268
|
||||
msgid "Tracking number updated to: %s"
|
||||
msgstr "跟踪单号已更新为:%s"
|
||||
|
||||
#: woocommerce-czlexpress.php:289
|
||||
msgid "Insufficient permissions"
|
||||
msgstr "权限不足"
|
||||
|
||||
#: woocommerce-czlexpress.php:293
|
||||
msgid "Invalid order ID"
|
||||
msgstr "无效的订单ID"
|
||||
|
||||
#: woocommerce-czlexpress.php:297
|
||||
msgid "Update scheduled"
|
||||
msgstr "更新已计划"
|
||||
|
||||
#: woocommerce-czlexpress.php:341
|
||||
msgid "Every 30 minutes"
|
||||
msgstr "每30分钟"
|
74
languages/woo-czl-express.pot
Normal file
@ -0,0 +1,74 @@
|
||||
# Copyright (C) 2024 CZL Express
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: CZL Express for WooCommerce 1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: https://exp.czl.net\n"
|
||||
"POT-Creation-Date: 2024-01-01 00:00:00+00:00\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"PO-Revision-Date: 2024-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: CZL Express\n"
|
||||
"Language-Team: CZL Express\n"
|
||||
|
||||
#: woocommerce-czlexpress.php:89
|
||||
msgid "CZL Express requires WooCommerce to be installed and active"
|
||||
msgstr ""
|
||||
|
||||
#: woocommerce-czlexpress.php:98
|
||||
msgid "CZL Express requires WooCommerce 6.0.0 or higher"
|
||||
msgstr ""
|
||||
|
||||
#: woocommerce-czlexpress.php:142
|
||||
msgctxt "Order status"
|
||||
msgid "In Transit"
|
||||
msgstr ""
|
||||
|
||||
#: woocommerce-czlexpress.php:187
|
||||
msgid "Creating shipment..."
|
||||
msgstr ""
|
||||
|
||||
#: woocommerce-czlexpress.php:188
|
||||
msgid "Shipment created successfully"
|
||||
msgstr ""
|
||||
|
||||
#: woocommerce-czlexpress.php:189
|
||||
msgid "Failed to create shipment"
|
||||
msgstr ""
|
||||
|
||||
#: woocommerce-czlexpress.php:199
|
||||
msgid "Permission denied"
|
||||
msgstr ""
|
||||
|
||||
#: woocommerce-czlexpress.php:203
|
||||
msgid "Invalid order ID"
|
||||
msgstr ""
|
||||
|
||||
#: woocommerce-czlexpress.php:247
|
||||
msgid "Invalid parameters"
|
||||
msgstr ""
|
||||
|
||||
#: woocommerce-czlexpress.php:255
|
||||
msgid "Database update failed"
|
||||
msgstr ""
|
||||
|
||||
#: woocommerce-czlexpress.php:268
|
||||
msgid "Tracking number updated to: %s"
|
||||
msgstr ""
|
||||
|
||||
#: woocommerce-czlexpress.php:289
|
||||
msgid "Insufficient permissions"
|
||||
msgstr ""
|
||||
|
||||
#: woocommerce-czlexpress.php:293
|
||||
msgid "Invalid order ID"
|
||||
msgstr ""
|
||||
|
||||
#: woocommerce-czlexpress.php:297
|
||||
msgid "Update scheduled"
|
||||
msgstr ""
|
||||
|
||||
#: woocommerce-czlexpress.php:341
|
||||
msgid "Every 30 minutes"
|
||||
msgstr ""
|
100
readme.md
@ -10,9 +10,9 @@
|
||||
|
||||
## 系统要求
|
||||
|
||||
1. WordPress 5.0+
|
||||
1. WordPress 6.0+
|
||||
2. WooCommerce 6.0.0+
|
||||
3. PHP 7.0+
|
||||
3. PHP 7.4+
|
||||
4. MySQL 5.6+
|
||||
|
||||
## 特性
|
||||
@ -21,83 +21,35 @@
|
||||
2. 支持WooCommerce远程日志记录
|
||||
3. 支持多语言
|
||||
|
||||
## 功能
|
||||
1. 支持快捷查价, 然后映射产品和woocommerce的运输方式. 其中, 查价结果里, 有一些产品, 比如 "UPS 红单-TA价", "UPS 红单-DA55价", 这种以"UPS 红单"开头的产品. 还有比如: "FEDEX IE-DT价", "FEDEX IE-DE价", 这种以"FEDEX IE"开头的产品. 我希望在查价结果里, 把他们显示为一个类别, 比如"UPS 红单", 然后这一行只显示最便宜的一个"UPS 红单"开头的产品价格和时效. 然后这个类别可以点击展开, 下面一个列表显示所有以"UPS 红单"开头的具体产品和相关信息. 并且可以自定义类别名称和产品开头, 例如这个配置:
|
||||
productGroupConfig: {
|
||||
'UPS 蓝单': {
|
||||
prefixes: ['UPS 蓝单'],
|
||||
groupName: 'UPS 蓝单'
|
||||
},
|
||||
'UPS 红单': {
|
||||
prefixes: ['UPS 红单'],
|
||||
groupName: 'UPS 红单'
|
||||
},
|
||||
"江苏FEDEX IE": {
|
||||
prefixes: ["江苏FEDEX IE"],
|
||||
groupName: "江苏FEDEX IE"
|
||||
},
|
||||
"江苏FEDEX IP": {
|
||||
prefixes: ["江苏FEDEX IP"],
|
||||
groupName: "江苏FEDEX IP"
|
||||
},
|
||||
'FEDEX IE': {
|
||||
prefixes: ['FEDEX IE'],
|
||||
groupName: 'FEDEX IE'
|
||||
},
|
||||
'FEDEX IP': {
|
||||
prefixes: ['FEDEX IP'],
|
||||
groupName: 'FEDEX IP'
|
||||
},
|
||||
"DHL": {
|
||||
prefixes: ["DHL"],
|
||||
groupName: "DHL"
|
||||
},
|
||||
"欧美普货包税专线": {
|
||||
prefixes: ["欧美经济专线(普货)","欧美标准专线(普货)","欧洲经济专线(普货)","欧洲标准专线(普货)"],
|
||||
groupName: "欧美普货包税专线"
|
||||
},
|
||||
"欧美B类包税专线": {
|
||||
prefixes: ["欧美经济专线(B类)","欧美标准专线(B类)","欧洲经济专线(B类)","欧洲标准专线(B类)"],
|
||||
groupName: "欧美B类包税专线"
|
||||
},
|
||||
"欧美带电包税专线": {
|
||||
prefixes: ["欧美经济专线(带电)","欧美标准专线(带电)","欧洲经济专线(带电)","欧洲标准专线(带电)"],
|
||||
groupName: "欧美带电包税专线"
|
||||
},
|
||||
"迪拜DHL": {
|
||||
prefixes: ["迪拜DHL"],
|
||||
groupName: "迪拜DHL"
|
||||
},
|
||||
"迪拜UPS": {
|
||||
prefixes: ["迪拜UPS"],
|
||||
groupName: "迪拜UPS"
|
||||
},
|
||||
"迪拜FEDEX": {
|
||||
prefixes: ["迪拜FEDEX"],
|
||||
groupName: "迪拜FEDEX"
|
||||
},
|
||||
"邮政": {
|
||||
prefixes: ["E特快","EMS"],
|
||||
groupName: "邮政"
|
||||
},
|
||||
"CZL阿联酋专线": {
|
||||
prefixes: ["CZL阿联酋"],
|
||||
groupName: "CZL阿联酋专线"
|
||||
},
|
||||
}
|
||||
## 使用步骤
|
||||
|
||||
用户可以选择按产品分组映射woocommerce的运输方式. 也可以选择具体产品映射woocommerce的运输方式.
|
||||
1. 安装本插件并启用
|
||||
2. 在插件-基本设置里, 配置CZLExpress的账号密码, 以及汇率
|
||||
3. 在WooCommerce的设置里, 选择'Shipping', 配置"Shipping zones", 新建一个"Zone", 地区选择全部, Shipping method选择"CZL Express", 进行配置, 然后保存 Zone.
|
||||
4. 在"CZL Express"-"产品分组" 里, 配置产品分组, 可以删除默认分组数据, 然后添加自定义分组, 例如: "SF Line","顺丰小包".
|
||||
5. 当客户下单时, 输入地址信息后, 会自动计算运费并显示, 提供给客户选择. 下单后, 运输信息会显示在"Orders"-"Edit order"里, 信息示例:
|
||||
```
|
||||
UPS Saver (3-6 working days)
|
||||
product_id: 10381
|
||||
delivery_time: 3-6个工作日
|
||||
original_name: UPS 红单-T价
|
||||
is_group: 1
|
||||
group_name: UPS Saver
|
||||
original_amount: 747
|
||||
```
|
||||
6. 然后, 可以在"CZL Express"-"订单管理"里, 进行"创建运单", 会自动下单到CZL Express, 成功后可以"打印标签"
|
||||
7. 每半个小时会自动同步订单的跟踪单号(如果有变更). 也可以手动更改跟踪单号.
|
||||
8. 每一个小时会自动同步订单运输轨迹, 并且客户可以在订单详情页看到运输轨迹. 也支持点击"更新轨迹"进行手动更新.
|
||||
|
||||
## 功能
|
||||
1. 用户可以选择按产品分组映射woocommerce的运输方式. 然后客户下单时就会自动显示每种运输方式的运费.
|
||||
|
||||
2. 设置运输价格时, 可以设置在CZLExpress的运费上额外加上一定比例和固定金额, 支持表达式, 例如"10% + 10", 那么就是CZLExpress的运费乘以1.1, 然后加上10元.
|
||||
|
||||
3. 支持设置账号密码, 然后在woocommerce订单列表, 支持快捷下单到CZLExpress, 如果下单无误, 支持打印标签,如果下单有问题, 显示报错内容, 可以手动修改, 然后打印标签.
|
||||
3. 支持设置账号密码, 然后在woocommerce订单列表, 支持快捷下单到CZLExpress, 如果下单成功, 支持打印标签.
|
||||
|
||||
4. 在woocommerce的订单详情页, 显示CZLExpress的订单跟踪号, 并且可以点击跟踪号, 跳转到CZLExpress的订单跟踪页面.
|
||||
4. 在插件的"订单管理"里, 显示CZLExpress的订单跟踪号, 并且可以点击跟踪号, 跳转到CZLExpress的订单跟踪页面.
|
||||
|
||||
5. 在woocommerce的订单详情页, 显示CZLExpress的订单标签, 并且可以点击标签, 跳转到CZLExpress的订单标签下载页面.
|
||||
|
||||
6. 可以把订单运输轨迹, 显示在woocommerce的订单详情页.
|
||||
|
||||
7. 当用户在woocommerce下单时, 自动查询偏远和偏远费用, 然后加到运输费用里. 并且也单独显示偏远和偏远费用.
|
||||
5. 可以把订单运输轨迹, 显示在woocommerce的订单公开备注里, 客户可以看到.
|
||||
|
||||
|
||||
|
128
readme.txt
Normal file
@ -0,0 +1,128 @@
|
||||
=== CZL Express for WooCommerce ===
|
||||
Contributors: czlexpress
|
||||
Tags: woocommerce, shipping, czl express, tracking, delivery, shipping method, china shipping, international shipping
|
||||
Requires at least: 5.8
|
||||
Tested up to: 6.4.2
|
||||
Requires PHP: 7.2
|
||||
Stable tag: 1.0.0
|
||||
License: GPLv2 or later
|
||||
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
Integrate CZL Express shipping service with your WooCommerce store. Get real-time shipping rates, create shipments, and track packages.
|
||||
|
||||
== Description ==
|
||||
|
||||
CZL Express for WooCommerce provides seamless integration between your WooCommerce store and CZL Express shipping service. This plugin helps you automate your shipping process and provide better service to your customers.
|
||||
|
||||
= Key Features =
|
||||
* Real-time shipping rates calculation
|
||||
* Automatic shipment creation
|
||||
* Package tracking integration
|
||||
* Custom product grouping for shipping rates
|
||||
* Support for multiple currencies (CNY to other currencies)
|
||||
* Automatic order status updates
|
||||
* Customer-facing tracking information
|
||||
* Full HPOS (High-Performance Order Storage) support
|
||||
* WooCommerce remote logging support
|
||||
* Multi-language support
|
||||
|
||||
= Advanced Features =
|
||||
* Custom product grouping for different shipping methods
|
||||
* Flexible pricing rules with markup support (e.g., "10% + 10")
|
||||
* Quick order creation in CZL Express system
|
||||
* Label printing support
|
||||
* Automatic tracking number synchronization (every 30 minutes)
|
||||
* Automatic tracking information updates (hourly)
|
||||
* Customer-visible shipping updates
|
||||
|
||||
= Requirements =
|
||||
* WordPress 6.0 or higher
|
||||
* WooCommerce 6.0.0 or higher
|
||||
* PHP 7.4 or higher
|
||||
* MySQL 5.6 or higher
|
||||
* CZL Express account and API credentials
|
||||
|
||||
== Installation ==
|
||||
|
||||
1. Upload the plugin files to the `/wp-content/plugins/woocommerce-czlexpress` directory, or install the plugin through the WordPress plugins screen directly.
|
||||
2. Activate the plugin through the 'Plugins' screen in WordPress.
|
||||
3. Go to the plugin's settings page and configure your CZL Express API credentials and exchange rate.
|
||||
4. In WooCommerce > Settings > Shipping, configure your shipping zones:
|
||||
* Create a new zone
|
||||
* Select the desired regions
|
||||
* Add "CZL Express" as a shipping method
|
||||
* Configure the shipping method settings
|
||||
5. Go to "CZL Express" > "Product Groups" to set up your product groups:
|
||||
* Remove default groups if needed
|
||||
* Add custom groups (e.g., "SF Line", "SF Small Packet")
|
||||
6. The shipping rates will automatically calculate when customers enter their address.
|
||||
|
||||
== Frequently Asked Questions ==
|
||||
|
||||
= Do I need a CZL Express account? =
|
||||
|
||||
Yes, you need a CZL Express account and API credentials to use this plugin. Visit [https://exp.czl.net](https://exp.czl.net) to create an account.
|
||||
|
||||
= How do I get API credentials? =
|
||||
|
||||
Contact CZL Express support to obtain your API credentials.
|
||||
|
||||
= Can I test the plugin before going live? =
|
||||
|
||||
Yes, the plugin includes a test mode that allows you to test the integration without creating real shipments.
|
||||
|
||||
= How are shipping rates calculated? =
|
||||
|
||||
Shipping rates are calculated in real-time based on:
|
||||
* Package weight and dimensions
|
||||
* Destination address
|
||||
* Selected shipping method
|
||||
* Product grouping settings
|
||||
|
||||
= Can I add a markup to shipping rates? =
|
||||
|
||||
Yes, you can add both percentage and fixed amount markups. For example:
|
||||
* "10%" - Add 10% to the base rate
|
||||
* "+ 10" - Add 10 to the base rate
|
||||
* "10% + 10" - Add 10% plus 10 to the base rate
|
||||
|
||||
= How often is tracking information updated? =
|
||||
|
||||
* Tracking numbers are synced every 30 minutes
|
||||
* Tracking details are updated hourly
|
||||
* Manual updates are also available
|
||||
|
||||
= Does it support multiple currencies? =
|
||||
|
||||
Yes, rates are fetched in CNY and automatically converted to your store's currency using the configured exchange rate.
|
||||
|
||||
== Screenshots ==
|
||||
|
||||
1. Plugin settings page - Configure API credentials and general settings
|
||||
2. Shipping method configuration - Set up shipping zones and methods
|
||||
3. Product group management - Create and manage product groups
|
||||
4. Order with tracking information - View tracking details in orders
|
||||
5. Shipping rate display - How customers see shipping options
|
||||
6. Order management - Create shipments and print labels
|
||||
7. Tracking information - Customer-facing tracking updates
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 1.0.0 =
|
||||
* Initial release
|
||||
* Full WooCommerce HPOS support
|
||||
* Real-time shipping rates
|
||||
* Automatic shipment creation
|
||||
* Package tracking integration
|
||||
* Product grouping support
|
||||
* Multi-currency support
|
||||
* Automatic tracking updates
|
||||
|
||||
== Upgrade Notice ==
|
||||
|
||||
= 1.0.0 =
|
||||
Initial release of CZL Express for WooCommerce.
|
||||
|
||||
== Support ==
|
||||
|
||||
For support, please visit [https://exp.czl.net](https://exp.czl.net) or contact our support team.
|
@ -1,27 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: WooCommerce CZL Express Shipping
|
||||
* Plugin URI: https://your-domain.com/
|
||||
* Description: CZL Express shipping integration for WooCommerce
|
||||
* Plugin Name: CZL Express for WooCommerce
|
||||
* Plugin URI: https://exp.czl.net
|
||||
* Description: CZL Express shipping integration for WooCommerce. Provides real-time shipping rates, shipment creation, and package tracking for CZL Express delivery service.
|
||||
* Version: 1.0.0
|
||||
* Author: Your Name
|
||||
* Author URI: https://your-domain.com/
|
||||
* Requires at least: 5.8
|
||||
* Requires PHP: 7.2
|
||||
* Author: CZL Express
|
||||
* Author URI: https://exp.czl.net
|
||||
* License: GPL v2 or later
|
||||
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||
* Text Domain: woo-czl-express
|
||||
* Domain Path: /languages
|
||||
* Requires PHP: 7.0
|
||||
* WC requires at least: 6.0.0
|
||||
* WC tested up to: 8.0.0
|
||||
* WC tested up to: 8.3.0
|
||||
*
|
||||
* This plugin is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This plugin is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this plugin. If not, see https://www.gnu.org/licenses/gpl-2.0.html.
|
||||
*/
|
||||
|
||||
// 防止直接访问
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 防止重复加载
|
||||
if (defined('WOO_CZL_EXPRESS_VERSION')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 定义插件常量
|
||||
define('WOO_CZL_EXPRESS_VERSION', '1.0.0');
|
||||
define('WOO_CZL_EXPRESS_PATH', plugin_dir_path(__FILE__));
|
||||
define('WOO_CZL_EXPRESS_URL', plugin_dir_url(__FILE__));
|
||||
|
||||
// 在插件激活时创建数据表
|
||||
register_activation_hook(__FILE__, 'wc_czlexpress_activate');
|
||||
|
||||
function wc_czlexpress_activate() {
|
||||
// 确保加载安装类
|
||||
require_once WOO_CZL_EXPRESS_PATH . 'includes/class-czl-install.php';
|
||||
|
||||
// 创建数据表和默认选项
|
||||
CZL_Install::init();
|
||||
|
||||
// 记录版本号
|
||||
update_option('czl_express_version', WOO_CZL_EXPRESS_VERSION);
|
||||
|
||||
// 注册定时任务
|
||||
if (!wp_next_scheduled('czl_sync_tracking_numbers_hook')) {
|
||||
wp_schedule_event(time(), 'hourly', 'czl_sync_tracking_numbers_hook');
|
||||
}
|
||||
}
|
||||
|
||||
// 在插件停用时清理
|
||||
register_deactivation_hook(__FILE__, function() {
|
||||
// 清理定时任务
|
||||
wp_clear_scheduled_hook('czl_sync_tracking_numbers_hook');
|
||||
});
|
||||
|
||||
// 在插件卸载时清理数据
|
||||
register_uninstall_hook(__FILE__, array('CZL_Install', 'uninstall'));
|
||||
|
||||
// 声明支持HPOS
|
||||
add_action('before_woocommerce_init', function() {
|
||||
if (class_exists('\Automattic\WooCommerce\Utilities\FeaturesUtil')) {
|
||||
@ -55,24 +105,331 @@ function wc_czlexpress_check_environment() {
|
||||
// 初始化插件
|
||||
function woo_czl_express_init() {
|
||||
if (wc_czlexpress_check_environment()) {
|
||||
// 加载语言文件
|
||||
load_plugin_textdomain(
|
||||
'woo-czl-express',
|
||||
false,
|
||||
dirname(plugin_basename(__FILE__)) . '/languages'
|
||||
);
|
||||
|
||||
// 加载必要的类文件
|
||||
require_once WOO_CZL_EXPRESS_PATH . 'includes/class-woo-czl-express.php';
|
||||
require_once WOO_CZL_EXPRESS_PATH . 'includes/class-czl-api.php';
|
||||
require_once WOO_CZL_EXPRESS_PATH . 'includes/class-czl-order.php';
|
||||
|
||||
WooCzlExpress::instance();
|
||||
|
||||
// 添加AJAX处理
|
||||
add_action('wp_ajax_czl_create_shipment', 'czl_ajax_create_shipment');
|
||||
add_action('wp_ajax_czl_update_tracking_number', 'czl_ajax_update_tracking_number');
|
||||
add_action('wp_ajax_czl_update_tracking_info', 'czl_ajax_update_tracking_info');
|
||||
|
||||
// 添加前端脚本
|
||||
add_action('admin_enqueue_scripts', 'czl_enqueue_admin_scripts');
|
||||
|
||||
// 注册自定义订单状态
|
||||
add_action('init', 'register_czl_order_statuses');
|
||||
}
|
||||
}
|
||||
|
||||
// 注册自定义订单状态
|
||||
function register_czl_order_statuses() {
|
||||
register_post_status('wc-in_transit', array(
|
||||
'label' => _x('In Transit', 'Order status', 'woo-czl-express'),
|
||||
'public' => true,
|
||||
'show_in_admin_status_list' => true,
|
||||
'show_in_admin_all_list' => true,
|
||||
'exclude_from_search' => false,
|
||||
'label_count' => _n_noop(
|
||||
'In Transit <span class="count">(%s)</span>',
|
||||
'In Transit <span class="count">(%s)</span>',
|
||||
'woo-czl-express'
|
||||
)
|
||||
));
|
||||
|
||||
// 添加到WooCommerce订单状态列表
|
||||
add_filter('wc_order_statuses', function($order_statuses) {
|
||||
$new_statuses = array();
|
||||
|
||||
// 在processing后面插入新状态
|
||||
foreach ($order_statuses as $key => $status) {
|
||||
$new_statuses[$key] = $status;
|
||||
if ($key === 'wc-processing') {
|
||||
$new_statuses['wc-in_transit'] = _x('In Transit', 'Order status', 'woo-czl-express');
|
||||
}
|
||||
}
|
||||
|
||||
return $new_statuses;
|
||||
});
|
||||
}
|
||||
|
||||
// 注册前端脚本
|
||||
function czl_enqueue_admin_scripts($hook) {
|
||||
// 在WooCommerce订单页面和CZL Express订单页面加载脚本
|
||||
if (!in_array($hook, array('woocommerce_page_wc-orders', 'toplevel_page_czl-express-orders'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载 Thickbox
|
||||
add_thickbox();
|
||||
|
||||
// 加载自定义脚本
|
||||
wp_enqueue_script(
|
||||
'czl-admin-script',
|
||||
WOO_CZL_EXPRESS_URL . 'assets/js/admin.js',
|
||||
array('jquery'),
|
||||
WOO_CZL_EXPRESS_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script('czl-admin-script', 'czl_ajax', array(
|
||||
'ajax_url' => admin_url('admin-ajax.php'),
|
||||
'nonce' => wp_create_nonce('czl_ajax_nonce'),
|
||||
'creating_text' => 'Creating shipment...',
|
||||
'success_text' => 'Shipment created successfully',
|
||||
'error_text' => 'Failed to create shipment'
|
||||
));
|
||||
}
|
||||
|
||||
// AJAX处理函数
|
||||
function czl_ajax_create_shipment() {
|
||||
check_ajax_referer('czl_ajax_nonce', 'nonce');
|
||||
|
||||
if (!current_user_can('edit_shop_orders')) {
|
||||
wp_send_json_error('Permission denied');
|
||||
}
|
||||
|
||||
$order_id = isset($_POST['order_id']) ? intval($_POST['order_id']) : 0;
|
||||
if (!$order_id) {
|
||||
wp_send_json_error('Invalid order ID');
|
||||
}
|
||||
|
||||
try {
|
||||
$czl_order = new CZL_Order();
|
||||
$result = $czl_order->create_shipment($order_id);
|
||||
|
||||
if ($result) {
|
||||
wp_send_json_success(array(
|
||||
'message' => 'Shipment created successfully'
|
||||
));
|
||||
} else {
|
||||
wp_send_json_error('Failed to create shipment');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
wp_send_json_error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 更新跟踪单号的AJAX处理函数
|
||||
function czl_ajax_update_tracking_number() {
|
||||
check_ajax_referer('czl_ajax_nonce', 'nonce');
|
||||
|
||||
if (!current_user_can('edit_shop_orders')) {
|
||||
wp_send_json_error('Permission denied');
|
||||
}
|
||||
|
||||
$order_id = isset($_POST['order_id']) ? intval($_POST['order_id']) : 0;
|
||||
$tracking_number = isset($_POST['tracking_number']) ? sanitize_text_field($_POST['tracking_number']) : '';
|
||||
|
||||
if (!$order_id || !$tracking_number) {
|
||||
wp_send_json_error('Invalid parameters');
|
||||
}
|
||||
|
||||
try {
|
||||
global $wpdb;
|
||||
|
||||
// 更新数据库中的跟踪单号
|
||||
$updated = $wpdb->update(
|
||||
$wpdb->prefix . 'czl_shipments',
|
||||
array('tracking_number' => $tracking_number),
|
||||
array('order_id' => $order_id),
|
||||
array('%s'),
|
||||
array('%d')
|
||||
);
|
||||
|
||||
if ($updated === false) {
|
||||
throw new Exception('数据库更新失败');
|
||||
}
|
||||
|
||||
// 更新订单元数据
|
||||
$order = wc_get_order($order_id);
|
||||
if ($order) {
|
||||
$order->update_meta_data('_czl_tracking_number', $tracking_number);
|
||||
$order->save();
|
||||
|
||||
// 添加订单备注
|
||||
$order->add_order_note(sprintf(
|
||||
'Tracking number updated to: %s',
|
||||
$tracking_number
|
||||
));
|
||||
}
|
||||
|
||||
wp_send_json_success();
|
||||
|
||||
} catch (Exception $e) {
|
||||
wp_send_json_error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 更新轨迹信息的AJAX处理函数
|
||||
function czl_ajax_update_tracking_info() {
|
||||
check_ajax_referer('czl_ajax_nonce', 'nonce');
|
||||
|
||||
if (!current_user_can('edit_shop_orders')) {
|
||||
wp_send_json_error('权限不足');
|
||||
}
|
||||
|
||||
$order_id = isset($_POST['order_id']) ? intval($_POST['order_id']) : 0;
|
||||
if (!$order_id) {
|
||||
wp_send_json_error('订单ID无效');
|
||||
}
|
||||
|
||||
// 使用 wp_schedule_single_event 来异步处理更新
|
||||
wp_schedule_single_event(time(), 'czl_do_update_tracking_info', array($order_id));
|
||||
wp_send_json_success(array('message' => 'Update scheduled'));
|
||||
}
|
||||
|
||||
// 异步处理轨迹更新
|
||||
function czl_do_update_tracking_info($order_id) {
|
||||
try {
|
||||
$czl_order = new CZL_Order();
|
||||
$czl_order->update_tracking_info($order_id);
|
||||
} catch (Exception $e) {
|
||||
error_log('CZL Express: Error updating tracking info - ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
add_action('czl_do_update_tracking_info', 'czl_do_update_tracking_info');
|
||||
|
||||
add_action('plugins_loaded', 'woo_czl_express_init');
|
||||
|
||||
// 自动创建运单的钩子
|
||||
add_action('woocommerce_order_status_processing', function($order_id) {
|
||||
$czl_order = new CZL_Order();
|
||||
$czl_order->create_shipment($order_id);
|
||||
try {
|
||||
$czl_order->create_shipment($order_id);
|
||||
} catch (Exception $e) {
|
||||
error_log('CZL Express: Auto create shipment failed - ' . $e->getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
// 在插件停用时清理定时任务
|
||||
register_deactivation_hook(__FILE__, 'wc_czlexpress_deactivate');
|
||||
// 添加自定义Cron间隔
|
||||
add_filter('cron_schedules', 'czl_add_cron_interval');
|
||||
function czl_add_cron_interval($schedules) {
|
||||
// 添加每30分钟执行一次的间隔
|
||||
$schedules['czl_thirty_minutes'] = array(
|
||||
'interval' => 1800, // 30分钟 = 1800秒
|
||||
'display' => __('Every 30 minutes', 'woo-czl-express')
|
||||
);
|
||||
return $schedules;
|
||||
}
|
||||
|
||||
function wc_czlexpress_deactivate() {
|
||||
$timestamp = wp_next_scheduled('czl_update_tracking_cron');
|
||||
if ($timestamp) {
|
||||
wp_unschedule_event($timestamp, 'czl_update_tracking_cron');
|
||||
// 添加定时任务处理函数
|
||||
function czl_sync_tracking_numbers() {
|
||||
global $wpdb;
|
||||
|
||||
// 获取最后同步时间
|
||||
$last_sync = get_option('czl_last_tracking_sync', 0);
|
||||
$current_time = time();
|
||||
|
||||
// 如果距离上次同步不到25分钟,则跳过
|
||||
if (($current_time - $last_sync) < 1500) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 限制每次处理的订单数量
|
||||
$limit = 10;
|
||||
|
||||
// 获取需要同步的订单
|
||||
$shipments = $wpdb->get_results($wpdb->prepare("
|
||||
SELECT order_id, tracking_number, czl_order_id
|
||||
FROM {$wpdb->prefix}czl_shipments
|
||||
WHERE czl_order_id IS NOT NULL
|
||||
AND (last_sync_time IS NULL OR last_sync_time < DATE_SUB(NOW(), INTERVAL 25 MINUTE))
|
||||
LIMIT %d
|
||||
", $limit));
|
||||
|
||||
if (empty($shipments)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$api = new CZL_API();
|
||||
|
||||
foreach ($shipments as $shipment) {
|
||||
// 为每个订单安排单独的更新事件
|
||||
wp_schedule_single_event(
|
||||
time() + rand(1, 300), // 随机延迟1-300秒
|
||||
'czl_do_sync_single_tracking',
|
||||
array($shipment->order_id, $shipment->tracking_number, $shipment->czl_order_id)
|
||||
);
|
||||
}
|
||||
|
||||
// 更新最后同步时间
|
||||
update_option('czl_last_tracking_sync', $current_time);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log('CZL Express: Tracking number sync failed - ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 处理单个订单的同步
|
||||
function czl_do_sync_single_tracking($order_id, $current_tracking, $czl_order_id) {
|
||||
try {
|
||||
global $wpdb;
|
||||
$api = new CZL_API();
|
||||
|
||||
// 获取最新的跟踪单号
|
||||
$response = $api->get_tracking_number($czl_order_id);
|
||||
|
||||
// 更新最后同步时间
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'czl_shipments',
|
||||
array('last_sync_time' => current_time('mysql')),
|
||||
array('order_id' => $order_id),
|
||||
array('%s'),
|
||||
array('%d')
|
||||
);
|
||||
|
||||
if (!empty($response['tracking_number']) && $response['tracking_number'] !== $current_tracking) {
|
||||
// 更新跟踪单号
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'czl_shipments',
|
||||
array('tracking_number' => $response['tracking_number']),
|
||||
array('order_id' => $order_id),
|
||||
array('%s'),
|
||||
array('%d')
|
||||
);
|
||||
|
||||
// 更新订单信息
|
||||
$order = wc_get_order($order_id);
|
||||
if ($order) {
|
||||
$order->update_meta_data('_czl_tracking_number', $response['tracking_number']);
|
||||
$order->save();
|
||||
|
||||
$tracking_link = sprintf(
|
||||
'<a href="https://exp.czl.net/track/?query=%s" target="_blank">Track Your Package</a>',
|
||||
$response['tracking_number']
|
||||
);
|
||||
|
||||
$order->add_order_note(
|
||||
sprintf(
|
||||
'Tracking number updated to: %s\n%s',
|
||||
$response['tracking_number'],
|
||||
$tracking_link
|
||||
),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log(sprintf(
|
||||
'CZL Express: Failed to sync tracking number for order %d: %s',
|
||||
$order_id,
|
||||
$e->getMessage()
|
||||
));
|
||||
}
|
||||
}
|
||||
add_action('czl_do_sync_single_tracking', 'czl_do_sync_single_tracking', 10, 3);
|
||||
|
||||
// 注册定时任务钩子
|
||||
add_action('czl_sync_tracking_numbers_hook', 'czl_sync_tracking_numbers');
|