feat(vip): Batch 1 per-level packages and admin schema
This commit is contained in:
@@ -17,12 +17,11 @@ trait VipServicePurchase {
|
||||
public function get_catalog(int $user_id = 0): array {
|
||||
$vip = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_payment_vip_settings()
|
||||
: ['enabled' => false, 'packages_raw' => '', 'levels' => [], 'renew' => [], 'upgrade' => [], 'points_exchange' => []];
|
||||
: ['enabled' => false, 'levels' => [], 'renew' => [], 'upgrade' => [], 'points_exchange' => []];
|
||||
|
||||
$level = function_exists('aksrt_get_user_vip_level') ? aksrt_get_user_vip_level($user_id) : 0;
|
||||
$expires = $user_id > 0 ? (int) get_user_meta($user_id, 'aksrt_vip_expires', true) : 0;
|
||||
$is_permanent = ($level > 0 && $expires <= 0);
|
||||
$packages = $this->parse_packages((string) ($vip['packages_raw'] ?? ''));
|
||||
$levels = is_array($vip['levels'] ?? null) ? $vip['levels'] : [];
|
||||
$renew = is_array($vip['renew'] ?? null) ? $vip['renew'] : [];
|
||||
$upgrade = is_array($vip['upgrade'] ?? null) ? $vip['upgrade'] : [];
|
||||
@@ -37,6 +36,8 @@ trait VipServicePurchase {
|
||||
if (empty($levels[$lv]['enabled'])) {
|
||||
continue;
|
||||
}
|
||||
// Cash products can be disabled per level.
|
||||
$product_s = !isset($levels[$lv]['product_s']) || !empty($levels[$lv]['product_s']);
|
||||
if ($is_permanent && $lv <= $level) {
|
||||
continue;
|
||||
}
|
||||
@@ -49,6 +50,9 @@ trait VipServicePurchase {
|
||||
|
||||
$name = (string) ($levels[$lv]['name'] ?? ('VIP' . $lv));
|
||||
$items = [];
|
||||
$packages = $product_s
|
||||
? $this->parse_level_products((string) ($levels[$lv]['products_raw'] ?? ''))
|
||||
: [];
|
||||
foreach ($packages as $idx => $pkg) {
|
||||
$base_price = (float) $pkg['price'];
|
||||
$days = (int) $pkg['days'];
|
||||
@@ -64,6 +68,22 @@ trait VipServicePurchase {
|
||||
continue;
|
||||
}
|
||||
|
||||
$show_price = (float) ($priced['show_price'] ?? 0);
|
||||
if ($show_price <= 0 && !empty($pkg['show_price']) && $action === 'pay') {
|
||||
$show_price = (float) $pkg['show_price'];
|
||||
}
|
||||
$discount_tag = (string) ($priced['tag'] ?? '');
|
||||
if ($discount_tag === '' && $action === 'pay' && !empty($pkg['tag'])) {
|
||||
$discount_tag = (string) $pkg['tag'];
|
||||
}
|
||||
|
||||
$days_label = __('永久', 'aksrt');
|
||||
if ((int) $pkg['time'] > 0) {
|
||||
$days_label = ((string) ($pkg['unit'] ?? 'day') === 'month')
|
||||
? sprintf(__('%d 个月', 'aksrt'), (int) $pkg['time'])
|
||||
: sprintf(__('%d 天', 'aksrt'), (int) $pkg['time']);
|
||||
}
|
||||
|
||||
$items[] = [
|
||||
'package_id' => $this->encode_package_id($lv, $idx + 1),
|
||||
'level' => $lv,
|
||||
@@ -71,17 +91,17 @@ trait VipServicePurchase {
|
||||
'action' => $action,
|
||||
'price' => (float) $priced['price'],
|
||||
'base_price' => $base_price,
|
||||
'show_price' => (float) ($priced['show_price'] ?? 0),
|
||||
'discount_tag' => (string) ($priced['tag'] ?? ''),
|
||||
'show_price' => $show_price,
|
||||
'discount_tag' => $discount_tag,
|
||||
'days' => $days,
|
||||
'time' => (int) ($pkg['time'] ?? 0),
|
||||
'unit' => (string) ($pkg['unit'] ?? 'day'),
|
||||
'title' => (string) $pkg['title'],
|
||||
'price_label' => $this->format_cash_label((float) $priced['price']),
|
||||
'show_price_label' => !empty($priced['show_price'])
|
||||
? $this->format_cash_label((float) $priced['show_price'])
|
||||
'show_price_label' => $show_price > 0
|
||||
? $this->format_cash_label($show_price)
|
||||
: '',
|
||||
'days_label' => ($days <= 0)
|
||||
? __('永久', 'aksrt')
|
||||
: sprintf(__('%d 天', 'aksrt'), $days),
|
||||
'days_label' => $days_label,
|
||||
'cta_label' => $action === 'renew'
|
||||
? __('立即续费', 'aksrt')
|
||||
: ($action === 'upgrade' ? __('立即升级', 'aksrt') : __('立即开通', 'aksrt')),
|
||||
@@ -163,7 +183,7 @@ trait VipServicePurchase {
|
||||
|
||||
$vip = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_payment_vip_settings()
|
||||
: ['enabled' => false, 'packages_raw' => '', 'levels' => [], 'renew' => [], 'upgrade' => []];
|
||||
: ['enabled' => false, 'levels' => [], 'renew' => [], 'upgrade' => []];
|
||||
if (empty($vip['enabled'])) {
|
||||
return new \WP_Error('aksrt_vip_disabled', __('会员功能未启用', 'aksrt'), ['status' => 400]);
|
||||
}
|
||||
@@ -203,6 +223,8 @@ trait VipServicePurchase {
|
||||
// Dedicated upgrade product:
|
||||
// 901 permanent/fixed, 902 unit remaining days, 903 jump permanent.
|
||||
$upgrade_mode = '';
|
||||
$pkg_time = 0;
|
||||
$pkg_unit = 'day';
|
||||
if (in_array($index, [901, 902, 903], true)) {
|
||||
$upgrade_items = $this->build_upgrade_items($user_id, $expires, $is_permanent, (string) ($upgrade['product'] ?? ''));
|
||||
$match = null;
|
||||
@@ -222,18 +244,30 @@ trait VipServicePurchase {
|
||||
];
|
||||
$amount = round((float) $match['price'], 2);
|
||||
$days = (int) $match['days'];
|
||||
$pkg_time = $days; // unit upgrade keeps days as remaining; jump/permanent use 0
|
||||
$pkg_unit = 'day';
|
||||
$base_price = (float) ($match['base_price'] ?? $amount);
|
||||
$discount_tag = (string) ($match['discount_tag'] ?? __('升级专享', 'aksrt'));
|
||||
$upgrade_mode = sanitize_key((string) ($match['upgrade_mode'] ?? ''));
|
||||
$action = 'upgrade';
|
||||
if ($upgrade_mode === 'jump' || $upgrade_mode === 'permanent') {
|
||||
$pkg_time = 0;
|
||||
$days = 0;
|
||||
}
|
||||
} else {
|
||||
$packages = $this->parse_packages((string) ($vip['packages_raw'] ?? ''));
|
||||
$level_cfg = is_array($levels[$level] ?? null) ? $levels[$level] : [];
|
||||
if (isset($level_cfg['product_s']) && empty($level_cfg['product_s'])) {
|
||||
return new \WP_Error('aksrt_vip_product_disabled', __('该等级暂不支持购买', 'aksrt'), ['status' => 400]);
|
||||
}
|
||||
$packages = $this->parse_level_products((string) ($level_cfg['products_raw'] ?? ''));
|
||||
$pkg = $packages[$index - 1] ?? null;
|
||||
if (!$pkg) {
|
||||
return new \WP_Error('aksrt_invalid_package', __('套餐不存在', 'aksrt'), ['status' => 400]);
|
||||
}
|
||||
$base_price = (float) $pkg['price'];
|
||||
$days = (int) $pkg['days'];
|
||||
$pkg_time = (int) ($pkg['time'] ?? 0);
|
||||
$pkg_unit = (string) ($pkg['unit'] ?? 'day');
|
||||
$priced = $this->apply_action_price($base_price, $action, $renew, $upgrade, $level, $user_level, $expires, $is_permanent, $days);
|
||||
if ($priced === null) {
|
||||
return new \WP_Error('aksrt_invalid_package', __('当前无法购买该套餐', 'aksrt'), ['status' => 400]);
|
||||
@@ -259,6 +293,8 @@ trait VipServicePurchase {
|
||||
'vip_pay' => 1,
|
||||
'level' => $level,
|
||||
'days' => $days,
|
||||
'time' => $pkg_time,
|
||||
'unit' => $pkg_unit,
|
||||
'package_index' => $index,
|
||||
'package_title' => (string) ($pkg['title'] ?? ''),
|
||||
'package_id' => $package_id,
|
||||
@@ -401,6 +437,11 @@ trait VipServicePurchase {
|
||||
|
||||
$level = (int) ($meta['level'] ?? 0);
|
||||
$days = (int) ($meta['days'] ?? 0);
|
||||
$time = (int) ($meta['time'] ?? 0);
|
||||
$unit = sanitize_key((string) ($meta['unit'] ?? 'day'));
|
||||
if (!in_array($unit, ['day', 'month'], true)) {
|
||||
$unit = 'day';
|
||||
}
|
||||
$upgrade_mode = sanitize_key((string) ($meta['upgrade_mode'] ?? ''));
|
||||
if ($level <= 0) {
|
||||
$decoded = $this->decode_package_id((int) ($paid_order['product_id'] ?? 0));
|
||||
@@ -418,6 +459,9 @@ trait VipServicePurchase {
|
||||
// unit upgrade: raise level only, keep current expiry (zibll).
|
||||
if ($upgrade_mode === 'unit') {
|
||||
$this->activate_vip($user_id, $level, 0, true);
|
||||
} elseif ($time > 0 || (isset($meta['time']) && (int) $meta['time'] === 0 && $days === 0)) {
|
||||
// Prefer calendar time+unit when present (including permanent time=0).
|
||||
$this->activate_vip_duration($user_id, $level, $time, $unit);
|
||||
} else {
|
||||
$this->activate_vip($user_id, $level, $days, false);
|
||||
}
|
||||
@@ -439,6 +483,8 @@ trait VipServicePurchase {
|
||||
$current_level = (int) get_user_meta($user_id, 'aksrt_vip_level', true);
|
||||
$new_level = max($current_level, $level);
|
||||
update_user_meta($user_id, 'aksrt_vip_level', $new_level);
|
||||
// Clear expired memory when re-granting.
|
||||
delete_user_meta($user_id, 'aksrt_vip_level_expired');
|
||||
|
||||
// Unit upgrade (zibll): keep vip_exp_date, only raise level.
|
||||
if ($keep_expiry) {
|
||||
@@ -460,6 +506,41 @@ trait VipServicePurchase {
|
||||
update_user_meta($user_id, 'aksrt_vip_expires', $base + ($days * DAY_IN_SECONDS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate VIP using calendar duration (zibll month/day).
|
||||
* time=0 → permanent. Extends from max(now, current_exp).
|
||||
*/
|
||||
public function activate_vip_duration(int $user_id, int $level, int $time, string $unit = 'day'): void {
|
||||
if ($user_id <= 0) {
|
||||
return;
|
||||
}
|
||||
$level = max(1, min(2, $level));
|
||||
$unit = $unit === 'month' ? 'month' : 'day';
|
||||
$current_level = (int) get_user_meta($user_id, 'aksrt_vip_level', true);
|
||||
$new_level = max($current_level, $level);
|
||||
update_user_meta($user_id, 'aksrt_vip_level', $new_level);
|
||||
delete_user_meta($user_id, 'aksrt_vip_level_expired');
|
||||
|
||||
if ($time <= 0) {
|
||||
update_user_meta($user_id, 'aksrt_vip_expires', 0);
|
||||
return;
|
||||
}
|
||||
|
||||
$current_exp = (int) get_user_meta($user_id, 'aksrt_vip_expires', true);
|
||||
if ($current_exp === 0 && $current_level > 0) {
|
||||
return; // keep permanent
|
||||
}
|
||||
$base = max($current_exp, time());
|
||||
$modifier = $unit === 'month'
|
||||
? ('+' . $time . ' months')
|
||||
: ('+' . $time . ' days');
|
||||
$new_exp = strtotime($modifier, $base);
|
||||
if ($new_exp === false) {
|
||||
$new_exp = $base + ($this->duration_to_days($time, $unit) * DAY_IN_SECONDS);
|
||||
}
|
||||
update_user_meta($user_id, 'aksrt_vip_expires', (int) $new_exp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user