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

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Fable 5 committed 2026-08-06 14:06:28 +08:00
1 parent 99f5c5e834
commit 50236b07fa
6 files changed
+59 -22

No files matched your search

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