208 lines
6.4 KiB
PHP
208 lines
6.4 KiB
PHP
<?php
|
||
/**
|
||
* @package AKSRT
|
||
*/
|
||
|
||
namespace AKSRT\Payment;
|
||
|
||
defined('ABSPATH') || exit;
|
||
|
||
class Revenue {
|
||
|
||
private static $instance = null;
|
||
|
||
public static function get_instance(): self {
|
||
if (null === self::$instance) self::$instance = new self();
|
||
return self::$instance;
|
||
}
|
||
|
||
private function table(): string {
|
||
return \AKSRT\Core\DBMigrator::table('revenue');
|
||
}
|
||
|
||
/**
|
||
* 记录收益
|
||
*/
|
||
public function add(int $user_id, float $amount, string $order_number = '', string $type = 'income'): int {
|
||
global $wpdb;
|
||
|
||
if ($user_id <= 0 || $amount <= 0) return 0;
|
||
|
||
$wpdb->insert($this->table(), [
|
||
'user_id' => $user_id,
|
||
'order_number' => sanitize_text_field($order_number),
|
||
'amount' => $amount,
|
||
'type' => sanitize_key($type),
|
||
'status' => 'pending',
|
||
'created_at' => current_time('mysql'),
|
||
], ['%d', '%s', '%f', '%s', '%s', '%s']);
|
||
|
||
$id = (int) $wpdb->insert_id;
|
||
if ($id > 0) {
|
||
do_action('aksrt_creator_income_added', $user_id, $amount, [
|
||
'order_number' => $order_number,
|
||
'type' => $type,
|
||
'revenue_id' => $id,
|
||
]);
|
||
}
|
||
return $id;
|
||
}
|
||
|
||
/**
|
||
* 结算收益
|
||
*/
|
||
public function settle(int $revenue_id): bool {
|
||
global $wpdb;
|
||
|
||
if (!class_exists('\AKSRT\Credits\Balance')) {
|
||
return false;
|
||
}
|
||
|
||
$wpdb->query('START TRANSACTION');
|
||
try {
|
||
$revenue = $wpdb->get_row($wpdb->prepare(
|
||
"SELECT id, user_id, amount, order_number FROM {$this->table()} WHERE id = %d AND status = %s FOR UPDATE",
|
||
$revenue_id,
|
||
'pending'
|
||
), ARRAY_A);
|
||
if (!is_array($revenue)) {
|
||
$wpdb->query('ROLLBACK');
|
||
return false;
|
||
}
|
||
|
||
$credited = \AKSRT\Credits\Balance::add(
|
||
(int) $revenue['user_id'],
|
||
(float) $revenue['amount'],
|
||
'creator_income',
|
||
['type' => 'revenue', 'id' => $revenue_id],
|
||
sprintf(__('创作收益结算(订单 %s)', 'aksrt'), (string) $revenue['order_number'])
|
||
);
|
||
if (is_wp_error($credited)) {
|
||
$wpdb->query('ROLLBACK');
|
||
return false;
|
||
}
|
||
|
||
$settled = $wpdb->update(
|
||
$this->table(),
|
||
['status' => 'settled', 'settled_at' => current_time('mysql')],
|
||
['id' => $revenue_id, 'status' => 'pending'],
|
||
['%s', '%s'],
|
||
['%d', '%s']
|
||
);
|
||
if ($settled !== 1) {
|
||
$wpdb->query('ROLLBACK');
|
||
return false;
|
||
}
|
||
|
||
$wpdb->query('COMMIT');
|
||
return true;
|
||
} catch (\Throwable $e) {
|
||
$wpdb->query('ROLLBACK');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取用户收益列表
|
||
*/
|
||
public function get_user_revenues(int $user_id, array $args = []): array {
|
||
global $wpdb;
|
||
|
||
$where = ['user_id = %d'];
|
||
$params = [$user_id];
|
||
|
||
$status = sanitize_key((string) ($args['status'] ?? ''));
|
||
if ($status !== '') {
|
||
$where[] = 'status = %s';
|
||
$params[] = $status;
|
||
}
|
||
|
||
$limit = max(1, min(100, (int) ($args['limit'] ?? 20)));
|
||
$offset = max(0, (int) ($args['offset'] ?? 0));
|
||
|
||
$sql = "SELECT * FROM {$this->table()} WHERE " . implode(' AND ', $where) . " ORDER BY created_at DESC LIMIT %d OFFSET %d";
|
||
$params[] = $limit;
|
||
$params[] = $offset;
|
||
|
||
return (array) $wpdb->get_results($wpdb->prepare($sql, $params), ARRAY_A);
|
||
}
|
||
|
||
/**
|
||
* Admin list (all users) with optional status / user filter.
|
||
*
|
||
* @param array{status?:string,user_id?:int,limit?:int,offset?:int} $args
|
||
* @return array{items:array<int,array>,total:int,page:int,max_pages:int}
|
||
*/
|
||
public function get_list(array $args = []): array {
|
||
global $wpdb;
|
||
|
||
$limit = max(1, min(100, (int) ($args['limit'] ?? 20)));
|
||
$offset = max(0, (int) ($args['offset'] ?? 0));
|
||
$status = sanitize_key((string) ($args['status'] ?? ''));
|
||
$user_id = (int) ($args['user_id'] ?? 0);
|
||
|
||
$where = [];
|
||
$params = [];
|
||
if ($status !== '') {
|
||
$where[] = 'status = %s';
|
||
$params[] = $status;
|
||
}
|
||
if ($user_id > 0) {
|
||
$where[] = 'user_id = %d';
|
||
$params[] = $user_id;
|
||
}
|
||
$where_sql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||
|
||
$count_sql = "SELECT COUNT(*) FROM {$this->table()} {$where_sql}";
|
||
$total = $params
|
||
? (int) $wpdb->get_var($wpdb->prepare($count_sql, $params))
|
||
: (int) $wpdb->get_var($count_sql);
|
||
|
||
$sql = "SELECT * FROM {$this->table()} {$where_sql} ORDER BY created_at DESC LIMIT %d OFFSET %d";
|
||
$params[] = $limit;
|
||
$params[] = $offset;
|
||
$items = $wpdb->get_results($wpdb->prepare($sql, $params), ARRAY_A);
|
||
|
||
return [
|
||
'items' => $items ?: [],
|
||
'total' => $total,
|
||
'page' => (int) floor($offset / $limit) + 1,
|
||
'max_pages' => (int) ceil(max(1, $total) / $limit),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 获取收益统计
|
||
*/
|
||
public function get_stats(int $user_id = 0): array {
|
||
global $wpdb;
|
||
|
||
$where = '';
|
||
$params = [];
|
||
if ($user_id > 0) {
|
||
$where = 'WHERE user_id = %d';
|
||
$params[] = $user_id;
|
||
}
|
||
|
||
$sql = "SELECT
|
||
COALESCE(SUM(amount), 0) as total,
|
||
COALESCE(SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END), 0) as pending,
|
||
COALESCE(SUM(CASE WHEN status = 'settled' THEN amount ELSE 0 END), 0) as settled,
|
||
COUNT(*) as count
|
||
FROM {$this->table()} {$where}";
|
||
|
||
if (!empty($params)) {
|
||
$row = $wpdb->get_row($wpdb->prepare($sql, $params), ARRAY_A);
|
||
} else {
|
||
$row = $wpdb->get_row($sql, ARRAY_A);
|
||
}
|
||
|
||
return [
|
||
'total' => (float) ($row['total'] ?? 0),
|
||
'pending' => (float) ($row['pending'] ?? 0),
|
||
'settled' => (float) ($row['settled'] ?? 0),
|
||
'count' => (int) ($row['count'] ?? 0),
|
||
];
|
||
}
|
||
}
|