feat(pay): 卡密兑换入口收敛到三个购买弹窗并对齐参考主题

- 移除余额卡片独立「卡密兑换」通用弹窗,兑换入口分布到充值/积分/会员三个弹窗的支付方式中
- 充值弹窗补齐卡密 logo 与仅卡密时的金额选择隐藏逻辑
- 积分购买弹窗 1:1 复刻参考主题 points-pay modal(商品档位/自定义/支付方式/立即支付),REST 改为 product+custom 契约
- 会员弹窗注入卡密渠道:视图模型透传 card_pass,前端渲染卡密盒并直兑 /pay/card-pass/redeem type=vip
- 后台卡密兑换拆分为余额/积分/会员三个独立开关,VIP 段旧会员卡密组清理
- REST type 改为必填(balance/vip/credits),三类型独立闸门
- 测试重写为 card-pass-modal-redeem 契约,321 项全部通过
This commit is contained in:
kate522 committed 2026-09-18 12:25:18 +08:00
1 parent 74e43aaa76
commit b88eab0bfe
18 files changed
+746 -472

No files matched your search

+4
View File
@@ -64,6 +64,9 @@ trait VipServiceModal {
}
$points_exchange = is_array($catalog['points_exchange'] ?? null) ? $catalog['points_exchange'] : [];
$methods = is_array($catalog['payment_methods'] ?? null) ? $catalog['payment_methods'] : [];
$card_pass = is_array($catalog['card_pass'] ?? null)
? array_merge(['enabled' => false, 'desc' => '', 'only_password' => false], $catalog['card_pass'])
: ['enabled' => false, 'desc' => '', 'only_password' => false];
$no_payment_method = $methods === [];
$action_reasons = [
'purchase' => $no_payment_method
@@ -124,6 +127,7 @@ trait VipServiceModal {
],
'levels' => $level_view,
'payment_methods' => $methods,
'card_pass' => $card_pass,
'allowed_actions' => [
'purchase' => $package_ids !== [] && $methods !== [],
'renew' => $has_renew && $methods !== [],
+40 -18
View File
@@ -517,30 +517,52 @@ trait VipServicePackages {
* @return array<int, array{id:string,name:string}>
*/
private function available_payment_methods(): array {
if (function_exists('aksrt_list_cash_payment_methods')) {
return aksrt_list_cash_payment_methods(true);
}
$methods = [];
if (!class_exists('\AKSRT\Payment\Gateway')) {
return $methods;
if (function_exists('aksrt_list_cash_payment_methods')) {
$methods = aksrt_list_cash_payment_methods(true);
} else {
if (!class_exists('\AKSRT\Payment\Gateway')) {
return [];
}
$gw = \AKSRT\Payment\Gateway::get_instance();
foreach (['balance', 'alipay', 'wechatpay', 'paypal', 'stripe', 'epay_alipay', 'epay_wxpay'] as $id) {
$g = $gw->get_gateway($id);
if (!$g) {
continue;
}
if (method_exists($g, 'is_configured') && !$g->is_configured()) {
continue;
}
$methods[] = [
'id' => $id,
'name' => method_exists($g, 'get_name') ? (string) $g->get_name() : $id,
];
}
}
$gw = \AKSRT\Payment\Gateway::get_instance();
foreach (['balance', 'alipay', 'wechatpay', 'paypal', 'stripe', 'epay_alipay', 'epay_wxpay'] as $id) {
$g = $gw->get_gateway($id);
if (!$g) {
continue;
}
if (method_exists($g, 'is_configured') && !$g->is_configured()) {
continue;
}
$methods[] = [
'id' => $id,
'name' => method_exists($g, 'get_name') ? (string) $g->get_name() : $id,
];
// 卡密兑换会员渠道(后台 会员购买 → 启用卡密兑换会员功能):
// 提交走 /pay/card-pass/redeem type=vip,不创建支付订单。
$card_pass = $this->vip_card_pass_context();
if (!empty($card_pass['enabled'])) {
$methods[] = ['id' => 'card_pass', 'name' => __('卡密', 'aksrt')];
}
return $methods;
}
/**
* 卡密兑换会员渠道上下文(ChargeCard vip 公开选项)。
*
* @return array{enabled:bool,desc:string,only_password:bool}
*/
private function vip_card_pass_context(): array {
$empty = ['enabled' => false, 'desc' => '', 'only_password' => false];
if (!class_exists('\AKSRT\Payment\ChargeCard')) {
return $empty;
}
$opts = \AKSRT\Payment\ChargeCard::get_instance()->get_public_options();
return is_array($opts['vip'] ?? null) ? array_merge($empty, $opts['vip']) : $empty;
}
private function format_cash_label(string $amount): string {
+5
View File
@@ -260,6 +260,7 @@ trait VipServicePurchase {
'packages' => $points_packages,
],
'payment_methods' => $methods,
'card_pass' => $this->vip_card_pass_context(),
'vip_url' => function_exists('aksrt_get_user_center_tab_url')
? aksrt_get_user_center_tab_url('credits')
: (function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url() : home_url('/')),
@@ -353,6 +354,10 @@ trait VipServicePurchase {
if ($payment_method === '') {
$payment_method = 'balance';
}
// 卡密兑换会员走 /pay/card-pass/redeem(type=vip)直兑,不创建支付订单。
if ($payment_method === 'card_pass') {
return new \WP_Error('aksrt_card_pass_redeem_required', __('卡密兑换会员请直接输入卡密提交', 'aksrt'), ['status' => 400]);
}
$note = wp_json_encode([
'vip_pay' => 1,