48 lines
2.2 KiB
PHP
48 lines
2.2 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\Opportunity;
|
|
use App\Services\InvestmentIdentity;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Str;
|
|
|
|
class ReconcileInvestmentIdentity extends Command
|
|
{
|
|
protected $signature = 'investment:reconcile-identities {--apply : Apply direct opportunity-ID mappings after backup}';
|
|
|
|
protected $description = 'Dry-run or apply idempotent canonical mappings without changing legacy records or merging projects';
|
|
|
|
public function handle(InvestmentIdentity $identity): int
|
|
{
|
|
if (! app()->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;
|
|
}
|
|
}
|