Files
Investidor-V2/tools/prepare-fiscal-preservation-fixture.php
2026-11-02 20:31:15 +02:00

87 lines
5.9 KiB
PHP

<?php
// Synthetic metadata baseline for the historical fiscal preservation tests only.
use App\Models\SimulationFormDraft;
use App\Models\User;
use App\Support\IsolatedQaDatabase;
use Database\Seeders\ProductionReferenceSeeder;
use Database\Seeders\TerritoryReferenceSeeder;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
require dirname(__DIR__).'/vendor/autoload.php';
try {
if (PHP_SAPI !== 'cli' || ! isset($argv)) {
throw new RuntimeException('Explicit CLI arguments required.');
}
$app = require dirname(__DIR__).'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$referencesOnly = in_array('--references-only', $argv, true);
$allowed = $referencesOnly ? ['simulator_fiscal_delta_20261021_test', 'proactive_investment_20261027_test'] : ['proactive_investment_20261027_test'];
if ($app->configurationIsCached() || ! IsolatedQaDatabase::allowsSchemaChanges()
|| ! in_array(DB::connection()->getDatabaseName(), $allowed, true)) {
throw new RuntimeException('Explicit isolated proactive QA database required.');
}
$marker = 'synthetic-fiscal-preservation-20261102';
$tables = ['opportunities', 'documents', 'opportunity_documents', 'simulation_form_drafts', 'users', 'organizations', 'audit_events'];
if (! $referencesOnly) {
DB::transaction(function () use ($marker, $tables): void {
DB::select('select pg_advisory_xact_lock(261102, 1)');
$actor = User::find(1021);
if ($actor && $actor->email !== 'synthetic-fiscal-preservation@example.invalid') {
throw new RuntimeException('Existing identity 1021 differs; no account may be reset.');
}
if (DB::table('audit_events')->where('source_system', $marker)->exists()) {
// Only this tool's own synthetic baseline may be archived. A live
// draft for this actor would correctly prevent creating another.
DB::table('simulation_form_drafts')->where('owner_user_id', 1021)
->where('create_key_hash', hash('sha256', $marker.'-key'))->whereNull('deleted_at')
->update(['deleted_at' => now()]);
foreach ($tables as $table) {
if (DB::table($table)->count() === 0) {
throw new RuntimeException('An existing baseline is incomplete; inspect before repairing.');
}
}
return;
}
if (! $actor) {
$actor = User::factory()->create(['id' => 1021, 'name' => 'SYNTHETIC QA fiscal preservation',
'email' => 'synthetic-fiscal-preservation@example.invalid', 'password' => bcrypt(Str::random(64)), 'email_verified_at' => now()]);
DB::statement("select setval(pg_get_serial_sequence('users','id'), greatest((select max(id) from users), 1021))");
}
$organization = (string) Str::uuid();
DB::table('organizations')->insert(['id' => $organization, 'name' => 'SYNTHETIC QA preservation organization',
'organization_type' => 'private', 'source_system' => $marker, 'data_classification' => 'internal']);
$sector = DB::table('sectors')->insertGetId(['name' => 'SYNTHETIC QA preservation sector', 'slug' => $marker, 'is_active' => true]);
$opportunity = DB::table('opportunities')->insertGetId(['reference' => $marker, 'slug' => $marker,
'title' => 'SYNTHETIC QA preservation opportunity', 'status' => 'draft', 'sector_id' => $sector]);
$document = (string) Str::uuid();
$bytes = 'SYNTHETIC QA metadata baseline; not a scanned or downloadable document.';
DB::table('documents')->insert(['id' => $document, 'file_name' => 'SYNTHETIC-QA-METADATA.txt', 'media_type' => 'text/plain',
'storage_key' => $marker.'/'.$document, 'sha256' => hash('sha256', $bytes), 'status' => 'active', 'uploaded_by' => $actor->id,
'source_system' => $marker, 'data_classification' => 'internal']);
DB::table('opportunity_documents')->insert(['id' => (string) Str::uuid(), 'opportunity_id' => $opportunity,
'document_id' => $document, 'payload' => json_encode(['title' => 'SYNTHETIC metadata preservation only', 'visibility' => 'internal']), 'created_by' => $actor->id]);
SimulationFormDraft::create(['id' => (string) Str::uuid(), 'owner_user_id' => $actor->id, 'version_no' => 1, 'deleted_at' => now(),
'create_key_hash' => hash('sha256', $marker.'-key'), 'create_payload_hash' => hash('sha256', $marker.'-payload'),
'snapshot_sha256' => hash('sha256', $marker.'-snapshot'), 'personal_snapshot' => SimulationFormDraft::encryptSnapshot([]),
'economic_snapshot' => SimulationFormDraft::encryptSnapshot(['project_title' => 'SYNTHETIC pre-existing draft'])]);
DB::table('audit_events')->insert(['source_system' => $marker, 'entity_type' => 'qa-fixture', 'actor_user_id' => $actor->id,
'action' => 'synthetic_preservation_baseline', 'after_data' => json_encode(['synthetic' => true, 'metadata_only' => true])]);
});
}
$seeder = $referencesOnly ? ProductionReferenceSeeder::class : TerritoryReferenceSeeder::class;
if (Artisan::call('db:seed', ['--class' => $seeder, '--force' => true]) !== 0) {
throw new RuntimeException('Packaged territory reference preparation failed.');
}
echo json_encode(['database' => DB::connection()->getDatabaseName(), 'synthetic_metadata' => ! $referencesOnly, 'packaged_territories' => DB::table('geo_locations')->count(),
'counts' => array_combine($tables, array_map(fn (string $table): int => DB::table($table)->count(), $tables))], JSON_THROW_ON_ERROR).PHP_EOL;
} catch (Throwable $error) {
fwrite(STDERR, $error::class.': fixture preparation failed ('.$error->getCode().').'.PHP_EOL);
exit(1);
}