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; } }