feat(user-center): redesign sidebar and wallet tips
This commit is contained in:
1 parent
82e71d1bf9
commit
a7f3caec59
24 files changed
+895
-528
No files matched your search
@@ -244,6 +244,105 @@ class Balance {
|
||||
return !empty(\AKSRT\Settings\Settings::get_all()['pay_balance_s']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomically transfer cash balance between two users.
|
||||
*
|
||||
* @param array<string,mixed> $ref
|
||||
* @return array{sender_balance:float,recipient_balance:float}|\WP_Error
|
||||
*/
|
||||
public static function transfer(int $sender_id, int $recipient_id, float $amount, string $reason_out = 'tip_sent', string $reason_in = 'tip_received', array $ref = [], string $remark = '') {
|
||||
global $wpdb;
|
||||
|
||||
$amount = round($amount, 2);
|
||||
if ($sender_id <= 0 || $recipient_id <= 0 || $sender_id === $recipient_id) {
|
||||
return new \WP_Error('aksrt_balance_transfer_user', __('转账用户无效', 'aksrt'));
|
||||
}
|
||||
if ($amount <= 0) {
|
||||
return new \WP_Error('aksrt_balance_transfer_amount', __('转账金额必须大于零', 'aksrt'));
|
||||
}
|
||||
if (!class_exists('\AKSRT\Core\DBMigrator')) {
|
||||
return new \WP_Error('aksrt_balance_transfer_unavailable', __('余额服务不可用', 'aksrt'));
|
||||
}
|
||||
|
||||
foreach ([$sender_id, $recipient_id] as $user_id) {
|
||||
if (!metadata_exists('user', $user_id, self::META_KEY)) {
|
||||
add_user_meta($user_id, self::META_KEY, '0', true);
|
||||
}
|
||||
}
|
||||
|
||||
$meta_table = $wpdb->usermeta;
|
||||
$log_table = \AKSRT\Core\DBMigrator::table('balance_log');
|
||||
$locked_ids = [$sender_id, $recipient_id];
|
||||
sort($locked_ids, SORT_NUMERIC);
|
||||
|
||||
$wpdb->query('START TRANSACTION');
|
||||
try {
|
||||
foreach ($locked_ids as $user_id) {
|
||||
$wpdb->get_var($wpdb->prepare(
|
||||
"SELECT umeta_id FROM {$meta_table} WHERE user_id = %d AND meta_key = %s FOR UPDATE",
|
||||
$user_id,
|
||||
self::META_KEY
|
||||
));
|
||||
}
|
||||
|
||||
$sender_before = (float) $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT meta_value FROM {$meta_table} WHERE user_id = %d AND meta_key = %s LIMIT 1",
|
||||
$sender_id,
|
||||
self::META_KEY
|
||||
));
|
||||
if ($sender_before < $amount) {
|
||||
$wpdb->query('ROLLBACK');
|
||||
return new \WP_Error('aksrt_balance_insufficient', __('余额不足', 'aksrt'));
|
||||
}
|
||||
|
||||
$sender_after = round($sender_before - $amount, 2);
|
||||
$recipient_before = (float) $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT meta_value FROM {$meta_table} WHERE user_id = %d AND meta_key = %s LIMIT 1",
|
||||
$recipient_id,
|
||||
self::META_KEY
|
||||
));
|
||||
$recipient_after = round($recipient_before + $amount, 2);
|
||||
|
||||
$sender_updated = $wpdb->update($meta_table, ['meta_value' => (string) $sender_after], ['user_id' => $sender_id, 'meta_key' => self::META_KEY], ['%s'], ['%d', '%s']);
|
||||
$recipient_updated = $wpdb->update($meta_table, ['meta_value' => (string) $recipient_after], ['user_id' => $recipient_id, 'meta_key' => self::META_KEY], ['%s'], ['%d', '%s']);
|
||||
if ($sender_updated !== 1 || $recipient_updated !== 1) {
|
||||
throw new \RuntimeException('balance_update_failed');
|
||||
}
|
||||
|
||||
$ref_type = isset($ref['type']) ? sanitize_key((string) $ref['type']) : 'tip';
|
||||
$ref_id = isset($ref['id']) ? (int) $ref['id'] : null;
|
||||
$created_at = current_time('mysql', true);
|
||||
$log_rows = [
|
||||
[$sender_id, -$amount, $sender_after, $reason_out],
|
||||
[$recipient_id, $amount, $recipient_after, $reason_in],
|
||||
];
|
||||
foreach ($log_rows as [$user_id, $delta, $balance_after, $reason]) {
|
||||
$inserted = $wpdb->insert($log_table, [
|
||||
'user_id' => $user_id,
|
||||
'delta' => $delta,
|
||||
'balance_after' => $balance_after,
|
||||
'reason' => sanitize_key($reason),
|
||||
'remark' => $remark !== '' ? sanitize_text_field(substr($remark, 0, 255)) : null,
|
||||
'ref_type' => $ref_type,
|
||||
'ref_id' => $ref_id,
|
||||
'created_at' => $created_at,
|
||||
], ['%d', '%f', '%f', '%s', '%s', '%s', '%d', '%s']);
|
||||
if ($inserted !== 1) {
|
||||
throw new \RuntimeException('balance_log_failed');
|
||||
}
|
||||
}
|
||||
|
||||
$wpdb->query('COMMIT');
|
||||
wp_cache_delete($sender_id, 'user_meta');
|
||||
wp_cache_delete($recipient_id, 'user_meta');
|
||||
do_action('aksrt_balance_transferred', $sender_id, $recipient_id, $amount, $ref);
|
||||
return ['sender_balance' => $sender_after, 'recipient_balance' => $recipient_after];
|
||||
} catch (\Throwable $e) {
|
||||
$wpdb->query('ROLLBACK');
|
||||
return new \WP_Error('aksrt_balance_transfer_failed', __('打赏入账失败,请稍后重试', 'aksrt'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format yuan for display.
|
||||
*/
|
||||
@@ -262,6 +361,8 @@ class Balance {
|
||||
'recharge' => __('余额充值', 'aksrt'),
|
||||
'transfer_in' => __('转入', 'aksrt'),
|
||||
'transfer_out' => __('转出', 'aksrt'),
|
||||
'tip_sent' => __('打赏支出', 'aksrt'),
|
||||
'tip_received' => __('收到打赏', 'aksrt'),
|
||||
'admin' => __('管理员调整', 'aksrt'),
|
||||
'exchange_from_credits' => __('积分兑换', 'aksrt'),
|
||||
'withdraw_hold' => __('提现冻结', 'aksrt'),
|
||||
|
||||
Reference in new issue
Block a user