feat(user-center): add cash wallet balance separate from credits

Introduce AKSRT_Balance (user_meta aksrt_balance + balance_log) for
Zibll-like pay_balance wallet. User center assets panel shows wallet
and points; balance gateway/card-pass/refunds credit cash when enabled.
This commit is contained in:
kate522 committed 2026-07-16 13:44:37 +08:00
1 parent f043d2c1ab
commit 8e0f9d989d
16 files changed
+637 -74

No files matched your search

+56 -13
View File
@@ -338,7 +338,7 @@ class AKSRT_Payment_Gateway {
/**
* 站内余额支付网关(内置实现)
*
* 使用积分/余额进行支付,无需第三方。
* 优先扣现金钱包(AKSRT_Balance / pay_balance);未启用时回退到积分。
*/
class AKSRT_Balance_Gateway implements AKSRT_Payment_Gateway_Interface {
@@ -351,7 +351,9 @@ class AKSRT_Balance_Gateway implements AKSRT_Payment_Gateway_Interface {
}
public function is_configured(): bool {
if (!class_exists('AKSRT_Credits')) {
$wallet_on = class_exists('AKSRT_Balance') && AKSRT_Balance::enabled();
$credits_on = class_exists('AKSRT_Credits');
if (!$wallet_on && !$credits_on) {
return false;
}
if (class_exists('AKSRT_Settings_Payment_Runtime')) {
@@ -361,17 +363,43 @@ class AKSRT_Balance_Gateway implements AKSRT_Payment_Gateway_Interface {
}
public function create_payment(array $order): array {
$user_id = (int) ($order['user_id'] ?? 0);
$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_Balance') && AKSRT_Balance::enabled()) {
if ($user_id <= 0) {
return ['success' => false, 'message' => __('请先登录', 'aksrt')];
}
$balance = AKSRT_Balance::balance($user_id);
if ($balance < $amount) {
return ['success' => false, 'message' => __('余额不足', 'aksrt')];
}
$result = AKSRT_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'),
];
}
// Fallback: legacy points-as-balance (1 元 = 100 积分).
if (!class_exists('AKSRT_Credits')) {
return ['success' => false, 'message' => __('积分系统未启用', 'aksrt')];
}
$user_id = (int) ($order['user_id'] ?? 0);
$amount = (float) ($order['amount'] ?? 0);
$credits_cost = (int) ceil($amount * 100); // 1 元 = 100 积分
$order_number = (string) ($order['order_number'] ?? '');
$credits_cost = (int) ceil($amount * 100);
$balance = AKSRT_Credits::balance($user_id);
if ($balance < $credits_cost) {
return ['success' => false, 'message' => __('余额不足', 'aksrt')];
}
@@ -416,10 +444,6 @@ class AKSRT_Balance_Gateway implements AKSRT_Payment_Gateway_Interface {
}
public function refund(string $order_number, float $amount): array {
if (!class_exists('AKSRT_Credits')) {
return ['success' => false, 'message' => __('积分系统未启用', 'aksrt')];
}
$order_repo = AKSRT_Order_Repository::get_instance();
$order = $order_repo->get($order_number);
@@ -428,8 +452,27 @@ class AKSRT_Balance_Gateway implements AKSRT_Payment_Gateway_Interface {
}
$user_id = (int) $order['user_id'];
$credits_refund = (int) ceil($amount * 100);
$amount = round((float) $amount, 2);
if (class_exists('AKSRT_Balance') && AKSRT_Balance::enabled()) {
$result = AKSRT_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')) {
return ['success' => false, 'message' => __('积分系统未启用', 'aksrt')];
}
$credits_refund = (int) ceil($amount * 100);
$result = AKSRT_Credits::add(
$user_id,
$credits_refund,