environment('local', 'testing')) { $this->error('This migration command is restricted to local/testing environments.'); return self::FAILURE; } $report = DB::transaction(function () use ($identity) { $ids = Opportunity::orderBy('id')->pluck('id'); $missing = $ids->diff(DB::table('investment_item_opportunities')->pluck('opportunity_id'))->values(); if ($this->option('apply')) { foreach ($missing as $id) { $identity->forOpportunity($id); } } return ['generated_at' => now()->toIso8601String(), 'mode' => $this->option('apply') ? 'apply' : 'dry-run', 'opportunity_count' => $ids->count(), 'missing_before' => $missing->count(), 'missing_after' => $ids->diff(DB::table('investment_item_opportunities')->pluck('opportunity_id'))->count(), 'unmapped_project_count' => DB::table('projects')->whereNull('deleted_at')->whereNotIn('id', DB::table('investment_item_projects')->select('project_id'))->count(), 'changes_to_legacy_records' => 0, 'automatic_project_merges' => 0, 'rule' => 'Map stable opportunity primary keys only. Project correspondence requires documentary reconciliation.']; }); $path = 'zone-reconciliation/'.now()->format('Ymd-His').'-'.Str::uuid().'.json'; Storage::disk('local')->put($path, json_encode($report, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); $this->line(json_encode([...$report, 'private_report' => $path], JSON_THROW_ON_ERROR)); return self::SUCCESS; } }