Files
wordpress-theme-aksrt/src/AKSRT/Payment/ShippingPart2.php
T
kate522 aaf458af1c refactor(autoload): migrate theme classes to Composer PSR-4
Move 288 types from global AKSRT_* + inc/classes manual requires into
namespace AKSRT\{Domain} under src/AKSRT/, wire composer.json psr-4,
and slim bootstrap to helpers/modules/hooks only. Split multi-class
widget/gateway files, update admin contract audit paths, and document
the layout in ADR/README.
2026-07-17 13:29:22 +08:00

153 lines
6.6 KiB
PHP

<?php
/**
* @package AKSRT
*/
namespace AKSRT\Payment;
defined('ABSPATH') || exit;
trait ShippingPart2 {
public function build_express_timeline(int $shipping_id): array {
$record = $this->get($shipping_id);
if (!$record) return [];
$cached = $this->get_express_cache($shipping_id);
$timeline = [];
$timeline[] = [
'time' => (string) ($record['created_at'] ?? ''),
'label' => sprintf(__('商家已发货:%s %s', 'aksrt'), $record['carrier_label'] ?? '', $record['tracking_no'] ?? ''),
'type' => 'shipped',
];
if (!empty($cached['traces'])) {
foreach ($cached['traces'] as $trace) {
$timeline[] = [
'time' => (string) ($trace['time'] ?? ''),
'label' => (string) ($trace['context'] ?? ''),
'type' => 'trace',
];
}
}
if (!empty($cached['signed'])) {
$timeline[] = [
'time' => (string) ($record['delivered_at'] ?? ($cached['query_time'] ?? '')),
'label' => __('快递已签收', 'aksrt'),
'type' => 'signed',
];
}
usort($timeline, static fn($a, $b) => strcmp($a['time'] ?? '', $b['time'] ?? ''));
return $timeline;
}
/* ============================================================
* Shipping Fee Resolution (§6.6 运费模板)
*
* 3 types: free / fixed / amount (满额包邮)
* Inheritance: product → category → theme defaults
* ============================================================ */
public function resolve_shipping_fee(int $product_id, float $order_amount = 0, array $address = []): array {
$config = $this->get_product_shipping_config($product_id);
$fee_type = (string) ($config['fee_type'] ?? 'fixed');
$fee_amount = (float) ($config['fee_amount'] ?? 0);
$free_threshold = (float) ($config['free_threshold'] ?? 0);
if ($fee_type === 'free') {
return ['fee' => 0.0, 'type' => 'free', 'label' => __('包邮', 'aksrt')];
}
if ($fee_type === 'amount' && $free_threshold > 0 && $order_amount >= $free_threshold) {
return ['fee' => 0.0, 'type' => 'free_threshold', 'label' => sprintf(__('满%.0f包邮', 'aksrt'), $free_threshold)];
}
$region_fee = $this->resolve_region_fee($config, $address);
if ($region_fee !== null) {
return ['fee' => $region_fee, 'type' => 'region', 'label' => __('地区运费', 'aksrt')];
}
return ['fee' => $fee_amount, 'type' => 'fixed', 'label' => sprintf(__('运费 ¥%.2f', 'aksrt'), $fee_amount)];
}
private function get_product_shipping_config(int $product_id): array {
$meta = get_post_meta($product_id, '_aksrt_shipping_config', true);
if (is_array($meta) && !empty($meta['fee_type'])) {
return $meta;
}
if (class_exists('\AKSRT\Shop\TermMeta')) {
$cat_config = \AKSRT\Shop\TermMeta::resolve_inheritance($product_id, 'shipping_fee');
if (is_array($cat_config) && !empty($cat_config['fee_type'])) {
return $cat_config;
}
}
if (class_exists('\AKSRT\Settings\Settings')) {
$shop = \AKSRT\Settings\Settings::get_shop_settings();
return [
'fee_type' => sanitize_key((string) ($shop['defaults']['shipping_fee_type'] ?? 'fixed')),
'fee_amount' => (float) ($shop['defaults']['shipping_fee_amount'] ?? 12),
'free_threshold' => (float) ($shop['defaults']['shipping_free_threshold'] ?? 0),
'region_fees' => (array) ($shop['defaults']['region_fees'] ?? []),
];
}
return ['fee_type' => 'fixed', 'fee_amount' => 12, 'free_threshold' => 0, 'region_fees' => []];
}
private function resolve_region_fee(array $config, array $address): ?float {
$region_fees = (array) ($config['region_fees'] ?? []);
if (empty($region_fees) || empty($address['province'])) {
return null;
}
$province = (string) $address['province'];
foreach ($region_fees as $region) {
$provinces = (array) ($region['provinces'] ?? []);
if (in_array($province, $provinces, true)) {
return (float) ($region['fee'] ?? 0);
}
}
return null;
}
public static function get_china_regions(): array {
$file = get_template_directory() . '/assets/data/china-regions.json';
if (!file_exists($file)) {
return self::get_builtin_provinces();
}
$data = json_decode((string) file_get_contents($file), true);
return is_array($data) ? $data : self::get_builtin_provinces();
}
private static function get_builtin_provinces(): array {
return [
['code' => '11', 'name' => '北京市'], ['code' => '12', 'name' => '天津市'],
['code' => '13', 'name' => '河北省'], ['code' => '14', 'name' => '山西省'],
['code' => '15', 'name' => '内蒙古自治区'], ['code' => '21', 'name' => '辽宁省'],
['code' => '22', 'name' => '吉林省'], ['code' => '23', 'name' => '黑龙江省'],
['code' => '31', 'name' => '上海市'], ['code' => '32', 'name' => '江苏省'],
['code' => '33', 'name' => '浙江省'], ['code' => '34', 'name' => '安徽省'],
['code' => '35', 'name' => '福建省'], ['code' => '36', 'name' => '江西省'],
['code' => '37', 'name' => '山东省'], ['code' => '41', 'name' => '河南省'],
['code' => '42', 'name' => '湖北省'], ['code' => '43', 'name' => '湖南省'],
['code' => '44', 'name' => '广东省'], ['code' => '45', 'name' => '广西壮族自治区'],
['code' => '46', 'name' => '海南省'], ['code' => '50', 'name' => '重庆市'],
['code' => '51', 'name' => '四川省'], ['code' => '52', 'name' => '贵州省'],
['code' => '53', 'name' => '云南省'], ['code' => '54', 'name' => '西藏自治区'],
['code' => '61', 'name' => '陕西省'], ['code' => '62', 'name' => '甘肃省'],
['code' => '63', 'name' => '青海省'], ['code' => '64', 'name' => '宁夏回族自治区'],
['code' => '65', 'name' => '新疆维吾尔自治区'],
['code' => '71', 'name' => '台湾省'],
['code' => '81', 'name' => '香港特别行政区'],
['code' => '82', 'name' => '澳门特别行政区'],
];
}
}