积分与余额账务系统硬切重构

This commit is contained in:
2026-08-24 15:59:11 +08:00
parent ca12226b39
commit 5cae5b5c93
159 changed files with 7275 additions and 4718 deletions
+55 -65
View File
@@ -175,81 +175,71 @@ final class ReferralAttribution {
);
return;
}
if (!class_exists('\AKSRT\Credits\Credits')) {
return;
}
if (!empty($settings['require_verify']) && !$this->is_verified($invitee_id)) {
return;
}
$wpdb->query('START TRANSACTION');
try {
$row = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$table} WHERE invitee_id = %d AND status = 'bound' FOR UPDATE",
$invitee_id
), ARRAY_A);
if (!is_array($row) || (string) ($row['reward_status'] ?? 'pending') !== 'pending') {
$wpdb->query('ROLLBACK');
return;
$row = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$table} WHERE invitee_id = %d AND status = 'bound'",
$invitee_id
), ARRAY_A);
if (!is_array($row) || (string) ($row['reward_status'] ?? 'pending') !== 'pending') {
return;
}
$relation_id = (int) $row['id'];
$promoter_id = (int) $row['promoter_id'];
if ($promoter_id <= 0) {
$wpdb->update($table, ['reward_status' => 'skipped'], ['id' => $relation_id, 'reward_status' => 'pending'], ['%s'], ['%d', '%s']);
return;
}
$promoter_amount = max(0, (int) ($settings['promoter_amount'] ?? 0));
$referred_amount = max(0, (int) ($settings['referred_amount'] ?? 0));
$entries = [];
if ($promoter_amount > 0) {
$entries[] = ['user_id' => $promoter_id, 'asset' => \AKSRT\Ledger\AssetType::POINTS->value, 'delta_minor' => $promoter_amount, 'entry_type' => 'credit', 'counterparty_user_id' => $invitee_id, 'remark' => __('推广注册奖励', 'aksrt')];
}
if ($referred_amount > 0) {
$entries[] = ['user_id' => $invitee_id, 'asset' => \AKSRT\Ledger\AssetType::POINTS->value, 'delta_minor' => $referred_amount, 'entry_type' => 'credit', 'counterparty_user_id' => $promoter_id, 'remark' => __('推广注册新用户奖励', 'aksrt')];
}
if ($entries === []) {
$wpdb->update($table, ['reward_status' => 'rewarded', 'rewarded_at' => current_time('mysql', true)], ['id' => $relation_id, 'reward_status' => 'pending'], ['%s', '%s'], ['%d', '%s']);
return;
}
$level_points = max(0, (int) ($settings['level_points'] ?? 0));
$command = new \AKSRT\Ledger\LedgerCommand(
\AKSRT\Ledger\OperationKey::deterministic('referral-reward', [$relation_id]),
'referral',
$entries,
'referral',
(string) $relation_id,
0,
['invitee_id' => $invitee_id, 'promoter_id' => $promoter_id]
);
$guard = function () use ($wpdb, $table, $relation_id, $settings, $row) {
$locked = $wpdb->get_row($wpdb->prepare("SELECT reward_status FROM {$table} WHERE id = %d FOR UPDATE", $relation_id), ARRAY_A);
if (!is_array($locked) || (string) $locked['reward_status'] !== 'pending') {
return new \WP_Error('aksrt_referral_state', __('推广奖励状态已变化', 'aksrt'), ['status' => 409]);
}
$relation_id = (int) $row['id'];
$promoter_id = (int) $row['promoter_id'];
if ($promoter_id <= 0 || !$this->ip_daily_check($row, $settings)) {
$wpdb->update($table, ['reward_status' => 'skipped'], ['id' => $relation_id], ['%s'], ['%d']);
$wpdb->query('COMMIT');
return;
}
$claimed = $wpdb->update(
$table,
['reward_status' => 'rewarding'],
['id' => $relation_id, 'reward_status' => 'pending'],
['%s'],
['%d', '%s']
);
if ($claimed !== 1) {
$wpdb->query('ROLLBACK');
return;
}
$ref = ['type' => 'referral', 'id' => $relation_id];
$promoter_amount = max(0, (int) ($settings['promoter_amount'] ?? 0));
$referred_amount = max(0, (int) ($settings['referred_amount'] ?? 0));
if ($promoter_amount > 0) {
$result = \AKSRT\Credits\Credits::add($promoter_id, $promoter_amount, 'referral', $ref, __('推广注册奖励', 'aksrt'), false);
if (is_wp_error($result)) {
throw new \RuntimeException($result->get_error_message());
}
}
if ($referred_amount > 0) {
$result = \AKSRT\Credits\Credits::add($invitee_id, $referred_amount, 'referral_new_user', $ref, __('推广注册新用户奖励', 'aksrt'), false);
if (is_wp_error($result)) {
throw new \RuntimeException($result->get_error_message());
}
}
$level_points = max(0, (int) ($settings['level_points'] ?? 0));
return $this->ip_daily_check($row, $settings)
? true
: new \WP_Error('aksrt_referral_daily_limit', __('当前网络今日推广奖励次数已达上限', 'aksrt'), ['status' => 409]);
};
$mutation = function () use ($wpdb, $table, $relation_id, $level_points, $promoter_id) {
if ($level_points > 0 && class_exists('\AKSRT\User\Level')) {
\AKSRT\User\Level::add($promoter_id, 'referral', $level_points, true);
}
$rewarded_at = current_time('mysql', true);
$updated = $wpdb->update(
$table,
['reward_status' => 'rewarded', 'rewarded_at' => $rewarded_at],
['id' => $relation_id, 'reward_status' => 'rewarding'],
['reward_status' => 'rewarded', 'rewarded_at' => current_time('mysql', true)],
['id' => $relation_id, 'reward_status' => 'pending'],
['%s', '%s'],
['%d', '%s']
);
if ($updated !== 1) {
throw new \RuntimeException('Unable to finalize referral reward.');
}
$wpdb->query('COMMIT');
return $updated === 1 ? true : new \WP_Error('aksrt_referral_update', __('推广奖励状态更新失败', 'aksrt'), ['status' => 500]);
};
$result = \AKSRT\Ledger\LedgerService::get_instance()->post($command, $guard, $mutation);
if (!is_wp_error($result) && !$result->replayed) {
do_action('aksrt_referral_rewarded', $relation_id, $promoter_id, $invitee_id);
} catch (\Throwable $e) {
$wpdb->query('ROLLBACK');
}
}
@@ -408,7 +398,7 @@ final class ReferralAttribution {
'points_reward' => !empty($reward['enabled']),
'affiliate' => !empty($affiliate['enabled']),
],
'current_ratio' => (float) \AKSRT\Settings\Settings::affiliate_ratio_for_user($user_id),
'current_ratio' => (int) \AKSRT\Settings\Settings::affiliate_ratio_for_user($user_id),
'ratios' => (array) ($affiliate['ratios'] ?? []),
'order_types' => (array) ($affiliate['order_types'] ?? ['membership', 'content']),
'rules' => [
@@ -655,12 +645,12 @@ final class ReferralAttribution {
$today_utc = (new \DateTimeImmutable('today', wp_timezone()))
->setTimezone(new \DateTimeZone('UTC'))
->format('Y-m-d H:i:s');
$count = (int) $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$table} WHERE registration_ip = %s AND reward_status = 'rewarded' AND rewarded_at >= %s FOR UPDATE",
$ids = $wpdb->get_col($wpdb->prepare(
"SELECT id FROM {$table} WHERE registration_ip = %s AND reward_status = 'rewarded' AND rewarded_at >= %s ORDER BY id ASC FOR UPDATE",
$ip,
$today_utc
));
return $count < $cap;
return count($ids) < $cap;
}
private function client_ip(): string {