fix(payment): refresh rebate metrics and unify withdrawal statuses

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-06 14:06:28 +08:00
co-authored by Claude Fable 5
parent 99f5c5e834
commit 50236b07fa
6 changed files with 59 additions and 22 deletions
@@ -71,7 +71,7 @@
</n-card>
<n-card class="aksrt-section-card" title="提现统计">
<n-grid :cols="4" :x-gap="12" :y-gap="12">
<n-grid :cols="6" :x-gap="12" :y-gap="12">
<n-grid-item>
<div class="aksrt-revenue__stat">
<strong>{{ withdrawalStats.total }}</strong>
@@ -81,7 +81,13 @@
<n-grid-item>
<div class="aksrt-revenue__stat">
<strong>{{ withdrawalStats.pending }}</strong>
<p>待审核</p>
<p>待处理</p>
</div>
</n-grid-item>
<n-grid-item>
<div class="aksrt-revenue__stat">
<strong>{{ withdrawalStats.processing }}</strong>
<p>处理中</p>
</div>
</n-grid-item>
<n-grid-item>
@@ -90,6 +96,12 @@
<p>已完成</p>
</div>
</n-grid-item>
<n-grid-item>
<div class="aksrt-revenue__stat">
<strong>{{ withdrawalStats.rejected }}</strong>
<p>已拒绝</p>
</div>
</n-grid-item>
<n-grid-item>
<div class="aksrt-revenue__stat">
<strong>{{ withdrawalStats.total_paid.toFixed(2) }}</strong>
@@ -108,7 +120,7 @@ import PaymentSectionPage from '@/pages/payment/PaymentSectionPage.vue'
import api from '@/api'
const revenueStats = ref({ total: 0, pending: 0, settled: 0, count: 0 })
const withdrawalStats = ref({ total: 0, pending: 0, completed: 0, total_paid: 0 })
const withdrawalStats = ref({ total: 0, pending: 0, processing: 0, completed: 0, rejected: 0, total_paid: 0 })
const timeSeries = ref([])
const granularity = ref('day')
@@ -151,7 +163,9 @@ async function loadRevenue() {
withdrawalStats.value = {
total: Number(res.data.withdrawal.total || 0),
pending: Number(res.data.withdrawal.pending || 0),
processing: Number(res.data.withdrawal.processing || 0),
completed: Number(res.data.withdrawal.completed || 0),
rejected: Number(res.data.withdrawal.rejected || 0),
total_paid: Number(res.data.withdrawal.total_paid || 0),
}
}
+5 -3
View File
@@ -168,14 +168,16 @@ class PayMenus {
if ($page !== 'aksrt_withdraw' && class_exists('\AKSRT\Payment\Withdrawal')) {
$pending = (int) \AKSRT\Payment\Withdrawal::get_instance()->get_count(['status' => \AKSRT\Payment\Withdrawal::STATUS_PENDING]);
if ($pending > 0) {
$processing = (int) \AKSRT\Payment\Withdrawal::get_instance()->get_count(['status' => \AKSRT\Payment\Withdrawal::STATUS_PROCESSING]);
$active = $pending + $processing;
if ($active > 0) {
$url = admin_url('admin.php?page=aksrt_withdraw&status=pending');
echo '<div class="notice notice-info is-dismissible">';
echo '<h3>' . esc_html__('提现申请待处理', 'aksrt') . '</h3>';
echo '<p>' . esc_html(sprintf(
/* translators: %d: pending withdrawal count */
/* translators: %d: open withdrawal count */
__('您有 %d 个提现申请待处理', 'aksrt'),
$pending
$active
)) . '</p>';
echo '<p><a class="button button-primary" href="' . esc_url($url) . '">' . esc_html__('立即处理', 'aksrt') . '</a></p>';
echo '</div>';
+3 -2
View File
@@ -46,10 +46,12 @@ class PayWithdrawals {
echo '<p>' . esc_html(sprintf(
/* translators: 1: total 2: pending 3: completed 4: paid */
__('共 %1$d 条 · 待处理 %2$d · 已完成 %3$d · 已打款 %4$s', 'aksrt'),
__('共 %1$d 条 · 待处理 %2$d · 处理中 %3$d · 已完成 %4$d · 已拒绝 %5$d · 已打款 %6$s', 'aksrt'),
(int) ($stats['total'] ?? 0),
(int) ($stats['pending'] ?? 0),
(int) ($stats['processing'] ?? 0),
(int) ($stats['completed'] ?? 0),
(int) ($stats['rejected'] ?? 0),
number_format((float) ($stats['total_paid'] ?? 0), 2)
)) . '</p>';
@@ -59,7 +61,6 @@ class PayWithdrawals {
$status_options = [
'' => __('全部状态', 'aksrt'),
'pending' => __('待处理', 'aksrt'),
'approved' => __('已通过', 'aksrt'),
'processing' => __('处理中', 'aksrt'),
'completed' => __('已完成', 'aksrt'),
'rejected' => __('已拒绝', 'aksrt'),
+2 -2
View File
@@ -150,7 +150,7 @@ class PaymentController extends ControllerBase {
$revenue_stats = \AKSRT\Payment\Revenue::get_instance()->get_stats();
}
$withdrawal_stats = ['total' => 0, 'pending' => 0, 'completed' => 0, 'total_paid' => 0];
$withdrawal_stats = ['total' => 0, 'pending' => 0, 'processing' => 0, 'completed' => 0, 'rejected' => 0, 'total_paid' => 0];
if (class_exists('\AKSRT\Payment\Withdrawal')) {
$withdrawal_stats = \AKSRT\Payment\Withdrawal::get_instance()->get_stats();
}
@@ -268,7 +268,7 @@ class PaymentController extends ControllerBase {
$new_status = sanitize_key((string) ($params['status'] ?? ''));
$note = sanitize_textarea_field((string) ($params['note'] ?? ''));
$valid_statuses = ['pending', 'approved', 'processing', 'completed', 'rejected'];
$valid_statuses = ['pending', 'processing', 'completed', 'rejected'];
if (!in_array($new_status, $valid_statuses, true)) {
return $this->error('无效的提现状态');
}
+20 -2
View File
@@ -18,6 +18,18 @@ class Rebate {
const STATUS_SETTLED = 'settled';
const STATUS_CANCELLED = 'cancelled';
private function refresh_user_metric(int $user_id): void {
if ($user_id <= 0) {
return;
}
global $wpdb;
$total = (float) $wpdb->get_var($wpdb->prepare(
"SELECT COALESCE(SUM(amount), 0) FROM {$this->table()} WHERE user_id = %d AND status IN ('pending', 'settled')",
$user_id
));
update_user_meta($user_id, 'aksrt_pay_rebate_sum', round($total, 2));
}
public static function get_instance(): self {
if (null === self::$instance) {
self::$instance = new self();
@@ -62,7 +74,7 @@ class Rebate {
'note' => $note,
]);
$id = $result ? (int) $wpdb->insert_id : 0;
$id = $result ? (int) $wpdb->insert_id : 0;
if ($id > 0) {
do_action('aksrt_pay_rebate_added', $user_id, $amount, [
'rebate_id' => $id,
@@ -123,6 +135,7 @@ class Rebate {
}
$wpdb->query('COMMIT');
$this->refresh_user_metric((int) $row['user_id']);
return true;
} catch (\Throwable $e) {
$wpdb->query('ROLLBACK');
@@ -134,9 +147,14 @@ class Rebate {
*/
public function cancel(int $id): bool {
global $wpdb;
return (bool) $wpdb->update($this->table(), [
$updated = $wpdb->update($this->table(), [
'status' => self::STATUS_CANCELLED,
], ['id' => $id, 'status' => self::STATUS_PENDING]);
if ($updated === 1) {
$row = $wpdb->get_row($wpdb->prepare("SELECT user_id FROM {$this->table()} WHERE id = %d", $id), ARRAY_A);
$this->refresh_user_metric((int) ($row['user_id'] ?? 0));
}
return $updated === 1;
}
/**
+12 -10
View File
@@ -9,11 +9,10 @@ defined('ABSPATH') || exit;
class Withdrawal {
public const STATUS_PENDING = 'pending';
public const STATUS_APPROVED = 'approved';
public const STATUS_PROCESSING = 'processing';
public const STATUS_COMPLETED = 'completed';
public const STATUS_REJECTED = 'rejected';
public const STATUS_PENDING = 'pending';
public const STATUS_PROCESSING = 'processing';
public const STATUS_COMPLETED = 'completed';
public const STATUS_REJECTED = 'rejected';
private static $instance = null;
@@ -99,7 +98,6 @@ class Withdrawal {
$new_status = sanitize_key($new_status);
$allowed = [
self::STATUS_PENDING,
self::STATUS_APPROVED,
self::STATUS_PROCESSING,
self::STATUS_COMPLETED,
self::STATUS_REJECTED,
@@ -195,7 +193,7 @@ class Withdrawal {
}
/**
* Whether user has open (pending/processing/approved) withdrawals.
* Whether user has open (pending/processing) withdrawals.
*/
public function has_open_withdrawal(int $user_id): bool {
return $this->count_open($user_id) > 0;
@@ -211,7 +209,7 @@ class Withdrawal {
}
return (int) $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$this->table()}
WHERE user_id = %d AND status IN ('pending','approved','processing')",
WHERE user_id = %d AND status IN ('pending','processing')",
$user_id
));
}
@@ -226,7 +224,7 @@ class Withdrawal {
}
$rows = $wpdb->get_results($wpdb->prepare(
"SELECT amount, account_info FROM {$this->table()}
WHERE user_id = %d AND status IN ('pending','approved','processing')",
WHERE user_id = %d AND status IN ('pending','processing')",
$user_id
), ARRAY_A);
$total = 0.0;
@@ -253,7 +251,7 @@ class Withdrawal {
$params = [$user_id];
if (!empty($args['open_only'])) {
$where[] = "status IN ('pending','approved','processing')";
$where[] = "status IN ('pending','processing')";
} else {
$status = sanitize_key((string) ($args['status'] ?? ''));
if ($status !== '') {
@@ -326,6 +324,8 @@ class Withdrawal {
"SELECT
COUNT(*) as total,
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending,
SUM(CASE WHEN status = 'processing' THEN 1 ELSE 0 END) as processing,
SUM(CASE WHEN status = 'rejected' THEN 1 ELSE 0 END) as rejected,
SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed,
COALESCE(SUM(CASE WHEN status = 'completed' THEN amount ELSE 0 END), 0) as total_paid
FROM {$this->table()}",
@@ -335,6 +335,8 @@ class Withdrawal {
return [
'total' => (int) ($row['total'] ?? 0),
'pending' => (int) ($row['pending'] ?? 0),
'processing' => (int) ($row['processing'] ?? 0),
'rejected' => (int) ($row['rejected'] ?? 0),
'completed' => (int) ($row['completed'] ?? 0),
'total_paid' => (float) ($row['total_paid'] ?? 0),
];