feat(payment): finish Zibll key contract and wire checkout gateways

Drop dual-read payment runtime fallbacks, align PHP schema to Vue keys,
read gateway credentials only from aksrt_settings with enable toggles,
expose configured adapters at checkout, fix credits pay signatures, and
apply order expiry settings. Wire orphan order/card-pass/withdrawal
schema pages; delete unused Payment* wrappers.
This commit is contained in:
2026-07-11 17:42:35 +08:00
parent 12c31ad82b
commit c93b303453
16 changed files with 298 additions and 228 deletions
@@ -1,15 +1,22 @@
<?php
/**
* Payment settings runtime — Zibll-aligned option keys.
* Payment settings runtime — Zibll-aligned + intentional AKSRT keys.
*
* Canonical keys (aligned with Zibll option IDs where applicable):
* - Order/display: pay_no_logged_in, pay_cookie_day, pay_no_logged_remind,
* Zibll-aligned (pay_*):
* - Display/order guest: pay_no_logged_in, pay_cookie_day, pay_no_logged_remind,
* pay_box_position, pay_mark, pay_show_user, pay_show_paycount,
* pay_free_logged_show, pay_wait_float_s
* - Balance: pay_balance_s, pay_auto_to_balance, pay_balance_transfer_*
* - VIP: pay_user_vip_1_s / pay_user_vip_2_s (+ names, download limits)
* pay_free_logged_show, pay_wait_float_s, pay_service
* - Balance: pay_balance_s, pay_auto_to_balance, pay_balance_product*,
* pay_balance_transfer_*, pay_balance_pass_charge_*, pay_balance_exchange_*
* - VIP: pay_user_vip_1/2_*, pay_download_limit*, pay_download_speed*,
* pay_vip_pass_charge_*
* - Income/rebate: pay_income_*, pay_rebate_*
*
* Stored in aksrt_settings. No dual-read of legacy payment_* keys.
* Intentional AKSRT-native (payment_* / card_pass_* / withdraw_*):
* - Paid/download ops, gateway toggles+credentials, order prefix/expiry/status texts
* - payment_vip_packages (line format), payment_revenue_*, payment_affiliate_* extras
*
* Stored in aksrt_settings only. No dual-read of dropped keys.
*
* @package AKSRT
*/
@@ -72,25 +79,24 @@ class AKSRT_Settings_Payment_Runtime {
public static function get_payment_recharge_settings(): array {
$settings = AKSRT_Settings::get_all();
$packages = (string) ($settings['pay_balance_product'] ?? $settings['payment_recharge_packages'] ?? "30|30|入门包\n98|108|推荐包");
$packages = (string) ($settings['pay_balance_product'] ?? "30|30|入门包\n98|108|推荐包");
if (is_array($settings['pay_balance_product'] ?? null)) {
$packages = self::format_product_lines((array) $settings['pay_balance_product']);
}
$help_text = trim((string) ($settings['pay_balance_desc'] ?? $settings['payment_recharge_help'] ?? ''));
$desc = sanitize_textarea_field((string) ($settings['pay_balance_desc'] ?? ''));
return [
'enabled' => !empty($settings['pay_balance_s']),
'mode' => 'manual_review',
'desc' => sanitize_textarea_field((string) ($settings['pay_balance_desc'] ?? '')),
'desc' => $desc,
'auto_to_balance' => !isset($settings['pay_auto_to_balance']) || !empty($settings['pay_auto_to_balance']),
'packages_raw' => $packages,
'package_count' => self::count_structured_lines($packages),
'help_text' => $help_text !== '' ? $help_text : __('当前支持人工确认与测试联调;接入真实网关时复用同一组字段。', 'aksrt'),
'help_text' => $desc !== '' ? $desc : __('当前支持人工确认与测试联调;接入真实网关时复用同一组字段。', 'aksrt'),
'product' => [
'name' => '',
'price' => 0,
'tag' => '元',
'tag_class' => '',
'name' => sanitize_text_field((string) ($settings['pay_balance_product_name'] ?? '')),
'price' => max(0, (float) ($settings['pay_balance_price'] ?? 0)),
'tag' => sanitize_text_field((string) ($settings['pay_balance_tag'] ?? '元')),
'tag_class' => sanitize_text_field((string) ($settings['pay_balance_tag_class'] ?? '')),
'custom_s' => !isset($settings['pay_balance_product_custom_s']) || !empty($settings['pay_balance_product_custom_s']),
'custom_limit' => max(1, min(99999, (int) ($settings['pay_balance_product_custom_limit'] ?? 9999))),
],
@@ -105,9 +111,9 @@ class AKSRT_Settings_Payment_Runtime {
'only_password' => !empty($settings['pay_balance_pass_charge_only_password']),
],
'exchange' => [
'enabled' => false,
'rate' => 100,
'desc' => '',
'enabled' => !empty($settings['pay_balance_exchange_s']),
'rate' => max(1, min(10000, (int) ($settings['pay_balance_exchange_rate'] ?? 100))),
'desc' => sanitize_textarea_field((string) ($settings['pay_balance_exchange_desc'] ?? '')),
],
];
}
@@ -141,22 +147,22 @@ class AKSRT_Settings_Payment_Runtime {
}
$packages = (string) ($settings['payment_vip_packages'] ?? "30|30|月卡\n365|365|年卡");
$help_text = trim((string) ($settings['pay_user_vip_desc'] ?? $settings['payment_vip_help'] ?? ''));
$desc = sanitize_textarea_field((string) ($settings['pay_user_vip_desc'] ?? ''));
return [
'enabled' => $enabled,
'name' => $vip1_enabled ? $name1 : $badge,
'badge_text' => $badge,
'desc' => sanitize_textarea_field((string) ($settings['pay_user_vip_desc'] ?? '')),
'desc' => $desc,
'packages_raw' => $packages,
'package_count' => self::count_structured_lines($packages),
'help_text' => $help_text !== '' ? $help_text : __('会员权益以免扣下载和身份展示为主,开通后立即生效。', 'aksrt'),
'help_text' => $desc !== '' ? $desc : __('会员权益以免扣下载和身份展示为主,开通后立即生效。', 'aksrt'),
'levels' => [
1 => [
'enabled' => $vip1_enabled,
'name' => $name1,
'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit_vip_1'] ?? $settings['pay_download_limit'] ?? 0))),
'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed_vip_1'] ?? $settings['pay_download_speed'] ?? 0))),
'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit_vip_1'] ?? 0))),
'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed_vip_1'] ?? 0))),
],
2 => [
'enabled' => $vip2_enabled,
@@ -168,7 +174,6 @@ class AKSRT_Settings_Payment_Runtime {
'benefit' => [
'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit'] ?? 0))),
'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed'] ?? 0))),
'discount' => 100,
'pass_charge' => !empty($settings['pay_vip_pass_charge_s']),
'pass_charge_desc' => sanitize_textarea_field((string) ($settings['pay_vip_pass_charge_desc'] ?? '')),
],
@@ -184,14 +189,6 @@ class AKSRT_Settings_Payment_Runtime {
'desc' => sanitize_textarea_field((string) ($settings['vip_upgrade_desc'] ?? '')),
'product' => sanitize_text_field((string) ($settings['vip_upgrade_product'] ?? '')),
],
'price' => [
'month' => 0,
'year' => 0,
'permanent' => 0,
'unit' => 0,
'unit_tag' => '元',
'jump' => 0,
],
];
}
@@ -200,13 +197,13 @@ class AKSRT_Settings_Payment_Runtime {
*/
public static function get_payment_revenue_settings(): array {
$settings = AKSRT_Settings::get_all();
$note = trim((string) ($settings['pay_income_desc_details'] ?? $settings['payment_revenue_note'] ?? ''));
$note = trim((string) ($settings['payment_revenue_note'] ?? ''));
return [
'enabled' => !empty($settings['pay_income_s']),
'share_ratio' => max(0, min(100, (int) ($settings['payment_revenue_share_ratio'] ?? 70))),
'ratio_vip1' => max(0, min(100, (int) ($settings['ratio_vip_1'] ?? $settings['payment_revenue_ratio_vip1'] ?? 0))),
'ratio_vip2' => max(0, min(100, (int) ($settings['ratio_vip_2'] ?? $settings['payment_revenue_ratio_vip2'] ?? 0))),
'ratio_vip1' => max(0, min(100, (int) ($settings['ratio_vip_1'] ?? 0))),
'ratio_vip2' => max(0, min(100, (int) ($settings['ratio_vip_2'] ?? 0))),
'settlement_threshold' => max(0, (int) ($settings['payment_revenue_settlement_threshold'] ?? 100)),
'cycle_days' => max(1, min(365, (int) ($settings['payment_revenue_cycle_days'] ?? 30))),
'points_rule' => sanitize_textarea_field((string) ($settings['payment_revenue_points_rule'] ?? '')),
@@ -223,18 +220,18 @@ class AKSRT_Settings_Payment_Runtime {
*/
public static function get_payment_affiliate_settings(): array {
$settings = AKSRT_Settings::get_all();
$note = trim((string) ($settings['pay_rebate_text_desc'] ?? $settings['payment_affiliate_note'] ?? ''));
$note = trim((string) ($settings['pay_rebate_text_desc'] ?? ''));
return [
'enabled' => !empty($settings['pay_rebate_s']),
'ratio' => max(0, min(100, (int) ($settings['pay_rebate_ratio'] ?? $settings['payment_affiliate_ratio'] ?? 10))),
'ratio' => max(0, min(100, (int) ($settings['pay_rebate_ratio'] ?? 10))),
'window_days' => max(1, min(365, (int) ($settings['payment_affiliate_window_days'] ?? 30))),
'require_paid_order' => true,
'require_paid_order' => !isset($settings['payment_affiliate_require_paid_order']) || !empty($settings['payment_affiliate_require_paid_order']),
'self_s' => !isset($settings['pay_rebate_self_s']) || !empty($settings['pay_rebate_self_s']),
'show_users' => !isset($settings['pay_rebate_show_users']) || !empty($settings['pay_rebate_show_users']),
'note' => $note !== '' ? $note : __('返佣链路复用邀请体系,订单归因和结算自动衔接当前策略字段。', 'aksrt'),
'user_ratio' => [
'user' => max(0, min(100, (int) ($settings['pay_rebate_ratio'] ?? 10))),
'user' => max(0, min(100, (int) ($settings['payment_affiliate_user_ratio'] ?? $settings['pay_rebate_ratio'] ?? 10))),
'vip1' => max(0, min(100, (int) ($settings['pay_rebate_ratio_vip_1'] ?? 0))),
'vip2' => max(0, min(100, (int) ($settings['pay_rebate_ratio_vip_2'] ?? 0))),
],
@@ -303,7 +300,7 @@ class AKSRT_Settings_Payment_Runtime {
}
/**
* Order display / checkout policy (Zibll pay_* contract).
* Order display / checkout policy (Zibll pay_* + AKSRT order ops).
*
* @return array<string,mixed>
*/
@@ -347,11 +344,11 @@ class AKSRT_Settings_Payment_Runtime {
'show_pay_time' => !isset($s['payment_show_pay_time']) || !empty($s['payment_show_pay_time']),
'status_texts' => $status_texts,
'service' => [
'text' => sanitize_textarea_field((string) ($s['pay_service'] ?? $s['payment_service'] ?? '')),
'icon' => sanitize_text_field((string) ($s['payment_service_icon'] ?? '')),
'value' => sanitize_text_field((string) ($s['payment_service_value'] ?? '')),
'qq' => sanitize_text_field((string) ($s['payment_service_qq'] ?? '')),
'wechat' => esc_url_raw((string) ($s['payment_service_wechat'] ?? '')),
'text' => sanitize_textarea_field((string) ($s['pay_service'] ?? '')),
'icon' => sanitize_text_field((string) ($s['pay_service_icon'] ?? '')),
'value' => sanitize_text_field((string) ($s['pay_service_value'] ?? '')),
'qq' => sanitize_text_field((string) ($s['pay_service_qq'] ?? '')),
'wechat' => esc_url_raw((string) ($s['pay_service_wechat'] ?? '')),
],
];
}
@@ -401,6 +398,36 @@ class AKSRT_Settings_Payment_Runtime {
];
}
/**
* Whether a registered adapter is admin-enabled.
* Maps gateway ids (wechatpay) to schema toggles (payment_wechat_enabled).
*/
public static function is_gateway_enabled(string $gateway_id): bool {
$settings = AKSRT_Settings::get_all();
$map = [
'alipay' => 'payment_alipay_enabled',
'wechatpay' => 'payment_wechat_enabled',
'paypal' => 'payment_paypal_enabled',
'stripe' => 'payment_stripe_enabled',
'balance' => 'payment_balance_enabled',
'card_pass' => 'payment_card_pass_enabled',
'xunhupay' => 'payment_xunhupay_enabled',
'xhpay' => 'payment_xhpay_enabled',
'payjs' => 'payment_payjs_enabled',
'epay' => 'payment_epay_enabled',
'vmq' => 'payment_vmq_enabled',
'codepay' => 'payment_codepay_enabled',
];
$key = $map[$gateway_id] ?? '';
if ($key === '') {
return false;
}
if ($gateway_id === 'balance') {
return !empty($settings['payment_balance_enabled']) && !empty($settings['pay_balance_s']);
}
return !empty($settings[$key]);
}
/**
* @param string[] $fallback
* @return string[]