- Changed super admin detection from role-based to `is_super_admin` flag in AdminUser model
- Added `requireDefaultAdminSiteId()` method to throw validation error when no integration site exists
- Enhanced site deletion to migrate platform role bindings to fallback site and auto-delete site-specific admin accounts
- Made agent line code optional with auto-generation fallback using `{site_code}-agent-{counter}` format
148 lines
5.6 KiB
PHP
148 lines
5.6 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\AgentNode;
|
|
use App\Services\Agent\AgentNodeService;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
/**
|
|
* 清空信用占成盘代理业务数据,并删除所有非根代理节点(保留各站点 depth=0 根节点)。
|
|
*
|
|
* 不删:期号、注单、钱包玩家、站点财务账号。
|
|
*/
|
|
final class PurgeAgentDataCommand extends Command
|
|
{
|
|
protected $signature = 'lottery:purge-agent-data
|
|
{--dry-run : 只预览,不写入}
|
|
{--force : 跳过交互确认(危险)}';
|
|
|
|
protected $description = '清空代理账期/授信流水,删除全部非根代理(保留站点根节点)';
|
|
|
|
public function handle(AgentNodeService $agentNodeService): int
|
|
{
|
|
$dryRun = (bool) $this->option('dry-run');
|
|
$force = (bool) $this->option('force');
|
|
|
|
$connection = (string) config('database.default');
|
|
$database = (string) config('database.connections.'.$connection.'.database');
|
|
$environment = (string) config('app.env');
|
|
|
|
$nonRootAgents = AgentNode::query()
|
|
->where('depth', '>', 0)
|
|
->orderByDesc('depth')
|
|
->orderByDesc('id')
|
|
->get();
|
|
|
|
$nonRootIds = $nonRootAgents->pluck('id')->map(static fn ($id): int => (int) $id)->all();
|
|
|
|
$rootBySite = DB::table('agent_nodes')
|
|
->where('depth', 0)
|
|
->get(['id', 'admin_site_id'])
|
|
->groupBy('admin_site_id')
|
|
->map(static fn ($rows) => (int) $rows->first()->id);
|
|
|
|
$playersToReassign = $nonRootIds === []
|
|
? 0
|
|
: (int) DB::table('players')->whereIn('agent_node_id', $nonRootIds)->count();
|
|
|
|
$metrics = [
|
|
['Database', $connection.' / '.$database],
|
|
['Environment', $environment],
|
|
['Non-root agents', (string) count($nonRootIds)],
|
|
['Players to reassign to root', (string) $playersToReassign],
|
|
['settlement_periods', (string) DB::table('settlement_periods')->count()],
|
|
['settlement_bills', (string) DB::table('settlement_bills')->count()],
|
|
['payment_records', (string) DB::table('payment_records')->count()],
|
|
['settlement_adjustments', (string) DB::table('settlement_adjustments')->count()],
|
|
['rebate_records', (string) DB::table('rebate_records')->count()],
|
|
['share_ledger', (string) DB::table('share_ledger')->count()],
|
|
['credit_ledger', (string) DB::table('credit_ledger')->count()],
|
|
['agent_delegation_grants', (string) DB::table('agent_delegation_grants')->count()],
|
|
];
|
|
|
|
$this->table(['Metric', 'Value'], $metrics);
|
|
|
|
if ($nonRootAgents->isNotEmpty()) {
|
|
$this->line('Non-root agents to delete:');
|
|
foreach ($nonRootAgents as $node) {
|
|
$this->line(sprintf(
|
|
' - #%d depth=%d %s (%s)',
|
|
(int) $node->id,
|
|
(int) $node->depth,
|
|
(string) $node->code,
|
|
(string) $node->name,
|
|
));
|
|
}
|
|
}
|
|
|
|
if ($dryRun) {
|
|
$this->info('Dry run only — no changes written.');
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
if (! $force && ! $this->confirm('This permanently deletes agent settlement data and non-root agents. Continue?', false)) {
|
|
$this->warn('Aborted.');
|
|
|
|
return self::FAILURE;
|
|
}
|
|
|
|
DB::transaction(function () use ($agentNodeService, $nonRootAgents, $nonRootIds, $rootBySite): void {
|
|
DB::table('settlement_adjustments')->delete();
|
|
DB::table('payment_records')->delete();
|
|
DB::table('rebate_allocations')->delete();
|
|
DB::table('rebate_records')->delete();
|
|
DB::table('share_ledger')->delete();
|
|
DB::table('settlement_bills')->delete();
|
|
DB::table('settlement_periods')->delete();
|
|
DB::table('credit_ledger')->delete();
|
|
|
|
DB::table('player_credit_accounts')->update([
|
|
'used_credit' => 0,
|
|
'frozen_credit' => 0,
|
|
'updated_at' => now(),
|
|
]);
|
|
|
|
DB::table('agent_profiles')->update([
|
|
'allocated_credit' => 0,
|
|
'used_credit' => 0,
|
|
'updated_at' => now(),
|
|
]);
|
|
|
|
if ($nonRootIds !== []) {
|
|
DB::table('agent_delegation_grants')
|
|
->whereIn('parent_agent_id', $nonRootIds)
|
|
->orWhereIn('child_agent_id', $nonRootIds)
|
|
->delete();
|
|
|
|
$players = DB::table('players')
|
|
->whereIn('agent_node_id', $nonRootIds)
|
|
->get(['id', 'agent_node_id', 'site_code']);
|
|
|
|
foreach ($players as $player) {
|
|
$agentNodeId = (int) $player->agent_node_id;
|
|
$siteId = (int) (DB::table('agent_nodes')->where('id', $agentNodeId)->value('admin_site_id') ?? 0);
|
|
$rootId = $rootBySite->get($siteId);
|
|
if ($rootId === null) {
|
|
continue;
|
|
}
|
|
|
|
DB::table('players')
|
|
->where('id', (int) $player->id)
|
|
->update(['agent_node_id' => $rootId]);
|
|
}
|
|
|
|
foreach ($nonRootAgents as $node) {
|
|
$agentNodeService->destroy($node);
|
|
}
|
|
}
|
|
});
|
|
|
|
$this->info('Agent settlement data cleared; non-root agents removed. Root nodes kept.');
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
}
|