Merge pull request 'feat(pay): VIP upgrade jump/unit/permanent billing like zibll' (#128) from worktree-hero-banner-chain into main
Reviewed-on: CYL/wordpress-theme-aksrt#128
This commit is contained in:
@@ -84,7 +84,14 @@ export const vipSchema = {
|
||||
fields: [
|
||||
{ key: 'vip_upgrade', label: '允许升级', type: 'switch', default: true },
|
||||
{ key: 'vip_upgrade_desc', label: '升级说明', type: 'textarea', default: '', dependsOn: { key: 'vip_upgrade', value: true } },
|
||||
{ key: 'vip_upgrade_product', label: '升级产品', type: 'input', default: '', dependsOn: { key: 'vip_upgrade', value: true } },
|
||||
{
|
||||
key: 'vip_upgrade_product',
|
||||
label: '升级产品',
|
||||
type: 'textarea',
|
||||
default: '',
|
||||
dependsOn: { key: 'vip_upgrade', value: true },
|
||||
help: '每行一条。永久VIP1升级:permanent|价格|标题;按剩余天:unit|每日单价|标题;限时跳转永久:jump|价格|标题;兼容旧格式:价格|天数|标题',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -143,7 +143,7 @@ class AKSRT_Admin_Schema_Payment {
|
||||
['key' => 'upgrade', 'title' => '升级设置', 'fields' => [
|
||||
['key' => 'vip_upgrade', 'label' => '允许升级', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'vip_upgrade_desc', 'label' => '升级说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'vip_upgrade', 'value' => true]],
|
||||
['key' => 'vip_upgrade_product', 'label' => '升级产品', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'vip_upgrade', 'value' => true], 'help' => '固定价:价格|天数|标题;按剩余天数:unit|每日单价|标题'],
|
||||
['key' => 'vip_upgrade_product', 'label' => '升级产品', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'vip_upgrade', 'value' => true], 'help' => '每行一条。永久VIP1:permanent|价格|标题;剩余天:unit|每日单价|标题;跳转永久:jump|价格|标题;兼容:价格|天数|标题'],
|
||||
]],
|
||||
],
|
||||
],
|
||||
|
||||
@@ -317,8 +317,10 @@ class AKSRT_Vip_Service {
|
||||
$action = 'upgrade';
|
||||
}
|
||||
|
||||
// Dedicated upgrade product (index 901 fixed, 902 unit remaining days).
|
||||
if ($index === 901 || $index === 902) {
|
||||
// Dedicated upgrade product:
|
||||
// 901 permanent/fixed, 902 unit remaining days, 903 jump permanent.
|
||||
$upgrade_mode = '';
|
||||
if (in_array($index, [901, 902, 903], true)) {
|
||||
$upgrade_items = $this->build_upgrade_items($user_id, $expires, $is_permanent, (string) ($upgrade['product'] ?? ''));
|
||||
$match = null;
|
||||
foreach ($upgrade_items as $ui) {
|
||||
@@ -339,6 +341,7 @@ class AKSRT_Vip_Service {
|
||||
$days = (int) $match['days'];
|
||||
$base_price = (float) ($match['base_price'] ?? $amount);
|
||||
$discount_tag = (string) ($match['discount_tag'] ?? __('升级专享', 'aksrt'));
|
||||
$upgrade_mode = sanitize_key((string) ($match['upgrade_mode'] ?? ''));
|
||||
$action = 'upgrade';
|
||||
} else {
|
||||
$packages = $this->parse_packages((string) ($vip['packages_raw'] ?? ''));
|
||||
@@ -377,6 +380,7 @@ class AKSRT_Vip_Service {
|
||||
'package_title' => (string) ($pkg['title'] ?? ''),
|
||||
'package_id' => $package_id,
|
||||
'action' => $action,
|
||||
'upgrade_mode' => $upgrade_mode,
|
||||
'base_price' => $base_price,
|
||||
'discount_tag' => $discount_tag,
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
@@ -512,6 +516,7 @@ class AKSRT_Vip_Service {
|
||||
|
||||
$level = (int) ($meta['level'] ?? 0);
|
||||
$days = (int) ($meta['days'] ?? 0);
|
||||
$upgrade_mode = sanitize_key((string) ($meta['upgrade_mode'] ?? ''));
|
||||
if ($level <= 0) {
|
||||
$decoded = $this->decode_package_id((int) ($paid_order['product_id'] ?? 0));
|
||||
if ($decoded) {
|
||||
@@ -525,13 +530,21 @@ class AKSRT_Vip_Service {
|
||||
$level = 2;
|
||||
}
|
||||
|
||||
$this->activate_vip($user_id, $level, $days);
|
||||
// unit upgrade: raise level only, keep current expiry (zibll).
|
||||
if ($upgrade_mode === 'unit') {
|
||||
$this->activate_vip($user_id, $level, 0, true);
|
||||
} else {
|
||||
$this->activate_vip($user_id, $level, $days, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply membership meta.
|
||||
*
|
||||
* @param bool $keep_expiry When true (unit upgrade), only raise level and do not change expiry.
|
||||
* When days<=0 and keep_expiry=false, set permanent (expires=0).
|
||||
*/
|
||||
public function activate_vip(int $user_id, int $level, int $days = 0): void {
|
||||
public function activate_vip(int $user_id, int $level, int $days = 0, bool $keep_expiry = false): void {
|
||||
if ($user_id <= 0) {
|
||||
return;
|
||||
}
|
||||
@@ -540,6 +553,11 @@ class AKSRT_Vip_Service {
|
||||
$new_level = max($current_level, $level);
|
||||
update_user_meta($user_id, 'aksrt_vip_level', $new_level);
|
||||
|
||||
// Unit upgrade (zibll): keep vip_exp_date, only raise level.
|
||||
if ($keep_expiry) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($days <= 0) {
|
||||
// Permanent.
|
||||
update_user_meta($user_id, 'aksrt_vip_expires', 0);
|
||||
@@ -723,11 +741,19 @@ class AKSRT_Vip_Service {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build upgrade package items (fixed and/or remaining-days unit).
|
||||
* Build upgrade package items (zibll vip_upgrade_product parity).
|
||||
*
|
||||
* upgrade.product formats:
|
||||
* - fixed: price|days|title
|
||||
* - unit: unit|daily_price|title (price = remaining_days * daily_price, days = remaining)
|
||||
* upgrade.product multi-line formats:
|
||||
* - permanent VIP1: permanent|price|title[|show_price]
|
||||
* - fixed (alias): price|days|title
|
||||
* - timed unit: unit|daily_price|title
|
||||
* - timed jump permanent: jump|price|title[|show_price]
|
||||
*
|
||||
* Rules:
|
||||
* - permanent user: only permanent/fixed (days=0 preferred)
|
||||
* - timed user: unit (keep expiry) + optional jump (to permanent)
|
||||
*
|
||||
* package index: 901 permanent/fixed, 902 unit, 903 jump
|
||||
*
|
||||
* @return array<int, array<string,mixed>>
|
||||
*/
|
||||
@@ -738,7 +764,10 @@ class AKSRT_Vip_Service {
|
||||
}
|
||||
$items = [];
|
||||
$lines = preg_split('/\r\n|\r|\n/', $raw) ?: [];
|
||||
$fixed_i = 0;
|
||||
$has_permanent = false;
|
||||
$has_unit = false;
|
||||
$has_jump = false;
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$line = trim((string) $line);
|
||||
if ($line === '') {
|
||||
@@ -747,8 +776,9 @@ class AKSRT_Vip_Service {
|
||||
$parts = array_map('trim', explode('|', $line));
|
||||
$mode = strtolower((string) ($parts[0] ?? ''));
|
||||
|
||||
// unit|daily|title — timed VIP1 only.
|
||||
if ($mode === 'unit') {
|
||||
if ($is_permanent || $expires <= time()) {
|
||||
if ($is_permanent || $expires <= time() || $has_unit) {
|
||||
continue;
|
||||
}
|
||||
$daily = isset($parts[1]) ? (float) $parts[1] : 0.0;
|
||||
@@ -779,16 +809,89 @@ class AKSRT_Vip_Service {
|
||||
'is_upgrade_product' => true,
|
||||
'upgrade_mode' => 'unit',
|
||||
];
|
||||
$has_unit = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$parsed = $this->parse_packages($line);
|
||||
if (empty($parsed[0])) {
|
||||
// jump|price|title[|show_price] — timed VIP1 only → permanent VIP2.
|
||||
if ($mode === 'jump') {
|
||||
if ($is_permanent || $has_jump) {
|
||||
continue;
|
||||
}
|
||||
$price = isset($parts[1]) ? (float) $parts[1] : 0.0;
|
||||
if ($price <= 0) {
|
||||
continue;
|
||||
}
|
||||
$title = sanitize_text_field((string) ($parts[2] ?? ''));
|
||||
if ($title === '') {
|
||||
$title = __('升级为永久会员', 'aksrt');
|
||||
}
|
||||
$show = isset($parts[3]) ? (float) $parts[3] : 0.0;
|
||||
$items[] = [
|
||||
'package_id' => $this->encode_package_id(2, 903),
|
||||
'level' => 2,
|
||||
'index' => 903,
|
||||
'action' => 'upgrade',
|
||||
'price' => round($price, 2),
|
||||
'base_price' => round($price, 2),
|
||||
'show_price' => max(0.0, $show),
|
||||
'discount_tag' => __('永久升级', 'aksrt'),
|
||||
'days' => 0,
|
||||
'title' => $title,
|
||||
'price_label' => $this->format_cash_label($price),
|
||||
'show_price_label' => $show > 0 ? $this->format_cash_label($show) : '',
|
||||
'days_label' => __('永久', 'aksrt'),
|
||||
'cta_label' => __('立即升级', 'aksrt'),
|
||||
'is_upgrade_product' => true,
|
||||
'upgrade_mode' => 'jump',
|
||||
];
|
||||
$has_jump = true;
|
||||
continue;
|
||||
}
|
||||
$fixed_i++;
|
||||
// Only one fixed upgrade product id 901.
|
||||
if ($fixed_i > 1) {
|
||||
|
||||
// permanent|price|title[|show_price]
|
||||
if ($mode === 'permanent') {
|
||||
if ($has_permanent) {
|
||||
continue;
|
||||
}
|
||||
$price = isset($parts[1]) ? (float) $parts[1] : 0.0;
|
||||
if ($price <= 0) {
|
||||
continue;
|
||||
}
|
||||
$title = sanitize_text_field((string) ($parts[2] ?? ''));
|
||||
if ($title === '') {
|
||||
$title = __('永久会员升级', 'aksrt');
|
||||
}
|
||||
$show = isset($parts[3]) ? (float) $parts[3] : 0.0;
|
||||
$items[] = [
|
||||
'package_id' => $this->encode_package_id(2, 901),
|
||||
'level' => 2,
|
||||
'index' => 901,
|
||||
'action' => 'upgrade',
|
||||
'price' => round($price, 2),
|
||||
'base_price' => round($price, 2),
|
||||
'show_price' => max(0.0, $show),
|
||||
'discount_tag' => __('升级专享', 'aksrt'),
|
||||
'days' => 0,
|
||||
'title' => $title,
|
||||
'price_label' => $this->format_cash_label($price),
|
||||
'show_price_label' => $show > 0 ? $this->format_cash_label($show) : '',
|
||||
'days_label' => __('永久', 'aksrt'),
|
||||
'cta_label' => __('立即升级', 'aksrt'),
|
||||
'is_upgrade_product' => true,
|
||||
'upgrade_mode' => 'permanent',
|
||||
];
|
||||
$has_permanent = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// fixed: price|days|title
|
||||
$parsed = $this->parse_packages($line);
|
||||
if (empty($parsed[0]) || $has_permanent) {
|
||||
continue;
|
||||
}
|
||||
// For permanent VIP1, only accept days=0 fixed lines as permanent upgrade.
|
||||
if ($is_permanent && (int) $parsed[0]['days'] > 0) {
|
||||
continue;
|
||||
}
|
||||
$pkg = $parsed[0];
|
||||
@@ -810,9 +913,19 @@ class AKSRT_Vip_Service {
|
||||
: sprintf(__('%d 天', 'aksrt'), (int) $pkg['days']),
|
||||
'cta_label' => __('立即升级', 'aksrt'),
|
||||
'is_upgrade_product' => true,
|
||||
'upgrade_mode' => 'fixed',
|
||||
'upgrade_mode' => ((int) $pkg['days'] <= 0) ? 'permanent' : 'fixed',
|
||||
];
|
||||
$has_permanent = true;
|
||||
}
|
||||
|
||||
// Permanent VIP1 should not see unit/jump.
|
||||
if ($is_permanent) {
|
||||
$items = array_values(array_filter($items, static function ($it) {
|
||||
$m = (string) ($it['upgrade_mode'] ?? '');
|
||||
return in_array($m, ['permanent', 'fixed'], true);
|
||||
}));
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user