diff --git a/assets/admin/src/schema/sections/payment/gateway.js b/assets/admin/src/schema/sections/payment/gateway.js
index 050acb31..9dfd718a 100644
--- a/assets/admin/src/schema/sections/payment/gateway.js
+++ b/assets/admin/src/schema/sections/payment/gateway.js
@@ -12,7 +12,7 @@ export const gatewaySchema = {
payment_wechat_enabled: false,
payment_alipay_enabled: false,
payment_paypal_enabled: false,
- payment_balance_enabled: false,
+ payment_balance_enabled: true,
payment_card_pass_enabled: false,
payment_xunhupay_enabled: false,
payment_xhpay_enabled: false,
@@ -73,7 +73,7 @@ export const gatewaySchema = {
{ key: 'payment_alipay_enabled', label: '支付宝', type: 'switch', default: false },
{ key: 'payment_paypal_enabled', label: 'PayPal', type: 'switch', default: false },
{ key: 'payment_stripe_enabled', label: 'Stripe', type: 'switch', default: false },
- { key: 'payment_balance_enabled', label: '余额支付', type: 'switch', default: false },
+ { key: 'payment_balance_enabled', label: '余额支付', type: 'switch', default: true, help: '需同时在「余额充值」启用余额功能。关闭后用户中心仍可有钱包,但结账不可用余额支付。' },
{ key: 'payment_card_pass_enabled', label: '卡密充值', type: 'switch', default: false },
{ key: 'payment_xunhupay_enabled', label: '虎皮椒', type: 'switch', default: false },
{ key: 'payment_xhpay_enabled', label: '小火付', type: 'switch', default: false },
diff --git a/assets/admin/src/schema/sections/payment/recharge.js b/assets/admin/src/schema/sections/payment/recharge.js
index fd4a2223..d8d773bd 100644
--- a/assets/admin/src/schema/sections/payment/recharge.js
+++ b/assets/admin/src/schema/sections/payment/recharge.js
@@ -32,9 +32,9 @@ export const rechargeSchema = {
title: '充值开关',
icon: 'fas fa-wallet',
fields: [
- { key: 'pay_balance_s', label: '启用余额功能', type: 'switch', default: true },
+ { key: 'pay_balance_s', label: '启用余额功能', type: 'switch', default: true, help: '开启后用户中心显示现金钱包,并默认允许余额支付(可在收款接口单独关闭)。充值需另配支付宝/微信等外部网关。' },
{ key: 'pay_balance_desc', label: '充值说明', type: 'textarea', default: '', dependsOn: { key: 'pay_balance_s', value: true } },
- { key: 'pay_auto_to_balance', label: '自动到账到余额', type: 'switch', default: true, dependsOn: { key: 'pay_balance_s', value: true } },
+ { key: 'pay_auto_to_balance', label: '自动到账到余额', type: 'switch', default: true, dependsOn: { key: 'pay_balance_s', value: true }, help: '充值订单支付成功后自动入账钱包(卡密/管理员调整不受此开关限制)。' },
],
},
{
diff --git a/assets/js/cms-download.js b/assets/js/cms-download.js
index 19d6205b..5fea8c08 100644
--- a/assets/js/cms-download.js
+++ b/assets/js/cms-download.js
@@ -548,18 +548,35 @@
}
body += '';
}
- let methodHtml = '';
- methods.forEach(function (m, idx) {
- const id = escapeAttr(m.id || '');
- const name = escapeHtml(m.name || id);
- methodHtml += '';
- });
- if (methodHtml) {
- body += '
' + tt('pay_method', '支付方式') + '
' + methodHtml + '
';
- }
- body += '';
- body += '';
- body += '
';
+ const walletBal = typeof preview.wallet_balance === 'number'
+ ? preview.wallet_balance
+ : (typeof preview.balance === 'number' ? preview.balance : 0);
+ const hasBalanceMethod = methods.some(function (m) { return (m && m.id) === 'balance'; });
+ if (hasBalanceMethod) {
+ body += '' + tt('my_wallet', '我的余额') + '¥' + Number(walletBal).toFixed(2) + '
';
+ if (preview.balance_enough === false) {
+ body += '' + tt('wallet_short', '余额不足,请先充值或选择其他支付方式') + '
';
+ if (preview.credits_url) {
+ body += '';
+ }
+ }
+ }
+ let methodHtml = '';
+ methods.forEach(function (m, idx) {
+ const id = escapeAttr(m.id || '');
+ const name = escapeHtml(m.name || id);
+ methodHtml += '';
+ });
+ if (methodHtml) {
+ body += '' + tt('pay_method', '支付方式') + '
' + methodHtml + '
';
+ } else {
+ body += '' + tt('no_pay_method', '暂无可用支付方式,请联系站长配置收款接口') + '
';
+ }
+ body += '';
+ if (methodHtml) {
+ body += '';
+ }
+ body += '
';
}
open('' + tt('confirm_buy', '确认购买') + '
' + body, returnFocusEl);
diff --git a/inc/helpers/aksrt-pay.php b/inc/helpers/aksrt-pay.php
index ae88f9d3..e7d48b89 100644
--- a/inc/helpers/aksrt-pay.php
+++ b/inc/helpers/aksrt-pay.php
@@ -107,12 +107,8 @@ if (!function_exists('aksrt_list_cash_payment_methods')) {
];
}
- if ($methods === []) {
- $methods[] = $logged_in
- ? ['id' => 'balance', 'name' => __('站内余额', 'aksrt')]
- : ['id' => 'alipay', 'name' => __('支付宝', 'aksrt')];
- }
-
+ // Do not inject a fake balance/alipay option when nothing is configured —
+ // callers should surface “暂无可用支付方式” instead of a dead method.
return $methods;
}
}
diff --git a/src/AKSRT/Admin/Schema/SchemaPayment.php b/src/AKSRT/Admin/Schema/SchemaPayment.php
index 83176572..02324c8a 100644
--- a/src/AKSRT/Admin/Schema/SchemaPayment.php
+++ b/src/AKSRT/Admin/Schema/SchemaPayment.php
@@ -95,6 +95,10 @@ class SchemaPayment {
['key' => 'pay_balance_exchange_rate', 'label' => '兑换比例', 'type' => 'number', 'default' => 100, 'min' => 1, 'max' => 10000, 'dependsOn' => ['key' => 'pay_balance_exchange_s', 'value' => true]],
['key' => 'pay_balance_exchange_desc', 'label' => '兑换说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'pay_balance_exchange_s', 'value' => true]],
]],
+ ['key' => 'withdraw', 'title' => '余额提现', 'fields' => [
+ ['key' => 'pay_balance_withdraw_s', 'label' => '启用余额提现', 'type' => 'switch', 'default' => false, 'dependsOn' => ['key' => 'pay_balance_s', 'value' => true]],
+ ['key' => 'pay_balance_withdraw_lowest_money', 'label' => '最低提现金额', 'type' => 'number', 'default' => 50, 'min' => 1, 'max' => 99999, 'dependsOn' => ['key' => 'pay_balance_withdraw_s', 'value' => true]],
+ ]],
],
],
'vip' => [
@@ -229,7 +233,7 @@ class SchemaPayment {
['key' => 'payment_wechat_enabled', 'label' => '微信支付', 'type' => 'switch', 'default' => false],
['key' => 'payment_alipay_enabled', 'label' => '支付宝', 'type' => 'switch', 'default' => false],
['key' => 'payment_paypal_enabled', 'label' => 'PayPal', 'type' => 'switch', 'default' => false],
- ['key' => 'payment_balance_enabled', 'label' => '余额支付', 'type' => 'switch', 'default' => false],
+ ['key' => 'payment_balance_enabled', 'label' => '余额支付', 'type' => 'switch', 'default' => true],
['key' => 'payment_card_pass_enabled', 'label' => '卡密充值', 'type' => 'switch', 'default' => false],
['key' => 'payment_xunhupay_enabled', 'label' => '虎皮椒', 'type' => 'switch', 'default' => false],
['key' => 'payment_xhpay_enabled', 'label' => '小火付', 'type' => 'switch', 'default' => false],
diff --git a/src/AKSRT/Content/PayHelpers.php b/src/AKSRT/Content/PayHelpers.php
index 88943e7b..d43d73fc 100644
--- a/src/AKSRT/Content/PayHelpers.php
+++ b/src/AKSRT/Content/PayHelpers.php
@@ -120,7 +120,14 @@ trait PayHelpers {
? (class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_currency_name() : __('积分', 'aksrt'))
: '¥'));
- $balance = ($uid > 0 && class_exists('\AKSRT\Credits\Credits')) ? \AKSRT\Credits\Credits::balance($uid) : 0;
+ // Points cashier uses Credits; cash cashier uses wallet (元). Keep both for UI.
+ $points_balance = ($uid > 0 && class_exists('\AKSRT\Credits\Credits'))
+ ? (int) \AKSRT\Credits\Credits::balance($uid)
+ : 0;
+ $wallet_balance = ($uid > 0 && class_exists('\AKSRT\Credits\Balance') && \AKSRT\Credits\Balance::enabled())
+ ? (float) \AKSRT\Credits\Balance::balance($uid)
+ : 0.0;
+ $balance = $pay_modo === 'points' ? $points_balance : $wallet_balance;
$methods = $this->available_payment_methods($pay_modo, $uid > 0);
$amount_label = $this->format_amount_label($amount, $pay_modo, $currency);
@@ -140,6 +147,11 @@ trait PayHelpers {
? aksrt_get_user_free_downloaded_number($uid) : 0;
$quota_over = $free_limit > 0 && $free_used >= $free_limit;
+ $payable_amount = $pay_modo === 'points' ? (int) ceil($payable) : round($payable, 2);
+ $balance_enough = $pay_modo === 'points'
+ ? ($points_balance >= (int) ceil($amount))
+ : ($wallet_balance + 0.0001 >= (float) $payable_amount);
+
return [
'post_id' => $post_id,
'title' => get_the_title($post),
@@ -153,7 +165,7 @@ trait PayHelpers {
'base' => $pay_modo === 'points' ? (int) ceil($base) : round($base, 2),
'list_amount' => $pay_modo === 'points' ? (int) ceil($list_amount) : round($list_amount, 2),
'list_amount_label' => $list_label,
- 'payable' => $pay_modo === 'points' ? (int) ceil($payable) : round($payable, 2),
+ 'payable' => $payable_amount,
'original' => (float) ($priced['original'] ?? 0),
'vip1' => (float) ($priced['vip1'] ?? 0),
'vip2' => (float) ($priced['vip2'] ?? 0),
@@ -181,7 +193,9 @@ trait PayHelpers {
'need_purchase' => !$has_paid && !$need_vip && $amount > 0,
'logged_in' => $uid > 0,
'balance' => $balance,
- 'balance_enough' => $pay_modo !== 'points' || $balance >= (int) ceil($amount),
+ 'wallet_balance' => $wallet_balance,
+ 'points_balance' => $points_balance,
+ 'balance_enough' => $balance_enough,
'payment_methods' => $methods,
'login_url' => wp_login_url(get_permalink($post)),
'vip_url' => $vip_page,
diff --git a/src/AKSRT/Content/VipServicePackages.php b/src/AKSRT/Content/VipServicePackages.php
index d27527d4..012f9000 100644
--- a/src/AKSRT/Content/VipServicePackages.php
+++ b/src/AKSRT/Content/VipServicePackages.php
@@ -506,9 +506,12 @@ trait VipServicePackages {
* @return array
*/
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 [['id' => 'balance', 'name' => __('站内余额', 'aksrt')]];
+ return $methods;
}
$gw = \AKSRT\Payment\Gateway::get_instance();
foreach (['balance', 'alipay', 'wechatpay', 'paypal', 'stripe'] as $id) {
@@ -524,9 +527,6 @@ trait VipServicePackages {
'name' => method_exists($g, 'get_name') ? (string) $g->get_name() : $id,
];
}
- if ($methods === []) {
- $methods[] = ['id' => 'balance', 'name' => __('站内余额', 'aksrt')];
- }
return $methods;
}
diff --git a/src/AKSRT/Content/VipServicePurchase.php b/src/AKSRT/Content/VipServicePurchase.php
index f8137703..6de268ff 100644
--- a/src/AKSRT/Content/VipServicePurchase.php
+++ b/src/AKSRT/Content/VipServicePurchase.php
@@ -132,7 +132,12 @@ trait VipServicePurchase {
$points_packages = $this->get_points_exchange_packages($vip, $levels);
}
- $balance = ($user_id > 0 && class_exists('\AKSRT\Credits\Credits')) ? \AKSRT\Credits\Credits::balance($user_id) : 0;
+ $points_balance = ($user_id > 0 && class_exists('\AKSRT\Credits\Credits'))
+ ? (int) \AKSRT\Credits\Credits::balance($user_id)
+ : 0;
+ $wallet_balance = ($user_id > 0 && class_exists('\AKSRT\Credits\Balance') && \AKSRT\Credits\Balance::enabled())
+ ? (float) \AKSRT\Credits\Balance::balance($user_id)
+ : 0.0;
$methods = $this->available_payment_methods();
$currency_name = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_currency_name() : __('积分', 'aksrt');
@@ -144,7 +149,8 @@ trait VipServicePurchase {
'user_expires' => $expires,
'user_is_permanent' => $is_permanent,
'user_expires_label' => $this->format_expires_label($expires, $level),
- 'user_points' => $balance,
+ 'user_points' => $points_balance,
+ 'wallet_balance' => $wallet_balance,
'currency_name' => $currency_name,
'renew_enabled' => $renew_enabled,
'upgrade_enabled' => $upgrade_enabled,
diff --git a/src/AKSRT/Credits/BalanceServiceCharge.php b/src/AKSRT/Credits/BalanceServiceCharge.php
index ec6457f6..33d5930f 100644
--- a/src/AKSRT/Credits/BalanceServiceCharge.php
+++ b/src/AKSRT/Credits/BalanceServiceCharge.php
@@ -81,6 +81,13 @@ trait BalanceServiceCharge {
if (!class_exists('AKSRT\\Credits\\Balance')) {
return;
}
+ // Honor pay_auto_to_balance (default on). When off, leave order paid without wallet credit.
+ if (class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'get_payment_recharge_settings')) {
+ $recharge_cfg = \AKSRT\Settings\Settings::get_payment_recharge_settings();
+ if (isset($recharge_cfg['auto_to_balance']) && empty($recharge_cfg['auto_to_balance'])) {
+ return;
+ }
+ }
$note = json_decode((string) ($order['note'] ?? ''), true);
if (!is_array($note)) {
$note = [];
diff --git a/src/AKSRT/Forum/TopicPay.php b/src/AKSRT/Forum/TopicPay.php
index f1d9da09..bcc12416 100644
--- a/src/AKSRT/Forum/TopicPay.php
+++ b/src/AKSRT/Forum/TopicPay.php
@@ -189,16 +189,14 @@ class TopicPay {
}
$has_paid = $this->user_has_paid($uid, $topic_id);
- $balance = 0;
- if ($uid > 0 && class_exists('\AKSRT\Credits\Credits')) {
- $balance = (int) \AKSRT\Credits\Credits::balance($uid);
+ $wallet_balance = 0.0;
+ if ($uid > 0 && class_exists('\AKSRT\Credits\Balance') && \AKSRT\Credits\Balance::enabled()) {
+ $wallet_balance = (float) \AKSRT\Credits\Balance::balance($uid);
}
$methods = function_exists('aksrt_list_cash_payment_methods')
? aksrt_list_cash_payment_methods($uid > 0)
- : ($uid > 0
- ? [['id' => 'balance', 'name' => __('站内余额', 'aksrt')]]
- : [['id' => 'alipay', 'name' => __('支付宝', 'aksrt')]]);
+ : [];
$coupon_allowed = $this->is_coupon_allowed($topic_id);
$coupon_error = '';
@@ -259,8 +257,9 @@ class TopicPay {
'need_vip' => false,
'need_purchase' => !$has_paid && !$is_free,
'logged_in' => $uid > 0,
- 'balance' => $balance,
- 'balance_enough' => true,
+ 'balance' => $wallet_balance,
+ 'wallet_balance' => $wallet_balance,
+ 'balance_enough' => $is_free || ($wallet_balance + 0.0001 >= (float) $payable),
'payment_methods' => $methods,
'login_url' => wp_login_url(get_permalink($post)),
'vip_url' => home_url('/'),
diff --git a/src/AKSRT/Payment/BalanceGateway.php b/src/AKSRT/Payment/BalanceGateway.php
index e0ae4cc6..3630049c 100644
--- a/src/AKSRT/Payment/BalanceGateway.php
+++ b/src/AKSRT/Payment/BalanceGateway.php
@@ -10,7 +10,7 @@ defined('ABSPATH') || exit;
/**
* 站内余额支付网关(内置实现)。
*
- * 优先扣现金钱包(\AKSRT\Credits\Balance / pay_balance);未启用时回退到积分。
+ * 仅扣现金钱包(\AKSRT\Credits\Balance / pay_balance_s),不再回退到积分。
*/
class BalanceGateway implements GatewayInterface {
@@ -24,9 +24,8 @@ class BalanceGateway implements GatewayInterface {
}
public function is_configured(): bool {
- $wallet_on = class_exists('\AKSRT\Credits\Balance') && \AKSRT\Credits\Balance::enabled();
- $credits_on = class_exists('\AKSRT\Credits\Credits');
- if (!$wallet_on && !$credits_on) {
+ // Cash wallet only — do not treat points as 余额.
+ if (!class_exists('\AKSRT\Credits\Balance') || !\AKSRT\Credits\Balance::enabled()) {
return false;
}
if (class_exists('\AKSRT\Settings\PaymentRuntime')) {
@@ -40,55 +39,26 @@ class BalanceGateway implements GatewayInterface {
$amount = round((float) ($order['amount'] ?? 0), 2);
$order_number = (string) ($order['order_number'] ?? '');
- // Prefer cash wallet when pay_balance_s is on.
- if (class_exists('\AKSRT\Credits\Balance') && \AKSRT\Credits\Balance::enabled()) {
- if ($user_id <= 0) {
- return ['success' => false, 'message' => __('请先登录', 'aksrt')];
- }
- $balance = \AKSRT\Credits\Balance::balance($user_id);
- if ($balance < $amount) {
- return ['success' => false, 'message' => __('余额不足', 'aksrt')];
- }
- $result = \AKSRT\Credits\Balance::deduct(
- $user_id,
- $amount,
- 'order_payment',
- ['type' => 'order', 'id' => 0, 'order' => $order_number],
- sprintf(__('订单 %s 支付', 'aksrt'), $order_number)
- );
- if (is_wp_error($result)) {
- return ['success' => false, 'message' => $result->get_error_message() ?: __('扣款失败', 'aksrt')];
- }
- return [
- 'success' => true,
- 'transaction_id' => 'BAL_' . ($order_number !== '' ? $order_number : (string) time()),
- 'message' => __('余额支付成功', 'aksrt'),
- ];
+ if (!class_exists('\AKSRT\Credits\Balance') || !\AKSRT\Credits\Balance::enabled()) {
+ return ['success' => false, 'message' => __('余额功能未启用', 'aksrt')];
}
-
- // Fallback: legacy points-as-balance (1 元 = 100 积分).
- if (!class_exists('\AKSRT\Credits\Credits')) {
- return ['success' => false, 'message' => __('积分系统未启用', 'aksrt')];
+ if ($user_id <= 0) {
+ return ['success' => false, 'message' => __('请先登录', 'aksrt')];
}
-
- $credits_cost = (int) ceil($amount * 100);
- $balance = \AKSRT\Credits\Credits::balance($user_id);
- if ($balance < $credits_cost) {
+ $balance = \AKSRT\Credits\Balance::balance($user_id);
+ if ($balance < $amount) {
return ['success' => false, 'message' => __('余额不足', 'aksrt')];
}
-
- $result = \AKSRT\Credits\Credits::deduct(
+ $result = \AKSRT\Credits\Balance::deduct(
$user_id,
- $credits_cost,
+ $amount,
'order_payment',
- ['order' => $order_number],
+ ['type' => 'order', 'id' => 0, 'order' => $order_number],
sprintf(__('订单 %s 支付', 'aksrt'), $order_number)
);
-
if (is_wp_error($result)) {
return ['success' => false, 'message' => $result->get_error_message() ?: __('扣款失败', 'aksrt')];
}
-
return [
'success' => true,
'transaction_id' => 'BAL_' . ($order_number !== '' ? $order_number : (string) time()),
@@ -127,37 +97,20 @@ class BalanceGateway implements GatewayInterface {
$user_id = (int) $order['user_id'];
$amount = round((float) $amount, 2);
- if (class_exists('\AKSRT\Credits\Balance') && \AKSRT\Credits\Balance::enabled()) {
- $result = \AKSRT\Credits\Balance::add(
- $user_id,
- $amount,
- 'order_refund',
- ['type' => 'order', 'order' => $order_number],
- sprintf(__('订单 %s 退款', 'aksrt'), $order_number)
- );
- if (is_wp_error($result)) {
- return ['success' => false, 'message' => $result->get_error_message() ?: __('退款失败', 'aksrt')];
- }
- return ['success' => true, 'refund_id' => 'BAL_REF_' . $order_number, 'message' => __('退款成功', 'aksrt')];
+ if (!class_exists('\AKSRT\Credits\Balance') || !\AKSRT\Credits\Balance::enabled()) {
+ return ['success' => false, 'message' => __('余额功能未启用', 'aksrt')];
}
- if (!class_exists('\AKSRT\Credits\Credits')) {
- return ['success' => false, 'message' => __('积分系统未启用', 'aksrt')];
- }
-
- $credits_refund = (int) ceil($amount * 100);
- $result = \AKSRT\Credits\Credits::add(
+ $result = \AKSRT\Credits\Balance::add(
$user_id,
- $credits_refund,
+ $amount,
'order_refund',
- ['order' => $order_number],
+ ['type' => 'order', 'order' => $order_number],
sprintf(__('订单 %s 退款', 'aksrt'), $order_number)
);
-
if (is_wp_error($result)) {
return ['success' => false, 'message' => $result->get_error_message() ?: __('退款失败', 'aksrt')];
}
-
return ['success' => true, 'refund_id' => 'BAL_REF_' . $order_number, 'message' => __('退款成功', 'aksrt')];
}
}
diff --git a/src/AKSRT/Settings/PaymentRuntime.php b/src/AKSRT/Settings/PaymentRuntime.php
index 32c6dbb7..85f2a32d 100644
--- a/src/AKSRT/Settings/PaymentRuntime.php
+++ b/src/AKSRT/Settings/PaymentRuntime.php
@@ -467,7 +467,15 @@ class PaymentRuntime {
return false;
}
if ($gateway_id === 'balance') {
- return !empty($settings['payment_balance_enabled']) && !empty($settings['pay_balance_s']);
+ // Master: 余额充值 → 启用余额功能. Optional kill-switch: payment_balance_enabled=false.
+ // Missing key (legacy sites) follows pay_balance_s so "open wallet" alone enables pay.
+ if (empty($settings['pay_balance_s'])) {
+ return false;
+ }
+ if (array_key_exists('payment_balance_enabled', $settings) && empty($settings['payment_balance_enabled'])) {
+ return false;
+ }
+ return true;
}
return !empty($settings[$key]);
}