Files
Investidor-V2/tools/portal-segmentation-date-qa.php
T
nala 287e991486
tests / ci (push) Waiting to run
oportunidades 7
2026-10-13 11:40:29 +02:00

47 lines
5.2 KiB
PHP

<?php
// Correct only metadata inferred by this QA import, retaining its first revision.
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
$workspace = dirname(__DIR__);
$private = $workspace.'/storage/app/private/investmoz-v2/portal-audit';
$directory = $private.'/segmentation-reconciliation-20261011';
$plan = json_decode(file_get_contents($private.'/portal-stability-latest.json'), true, 512, JSON_THROW_ON_ERROR);
$source = json_decode(file_get_contents($directory.'/source-provenance.json'), true, 512, JSON_THROW_ON_ERROR);
putenv('STABILITY_QA_MODE=consumers');
$app = (static fn (string $file) => require $file)($plan['source'].'/tools/portal-stability-runtime.php');
$target = DB::selectOne('select current_database() as database,inet_server_port() as port');
throw_unless($target->database === 'stability_consumers_20261011_084534_test' && (int) $target->port === 55441, RuntimeException::class, 'Exact isolated QA required.');
throw_unless(User::findOrFail(17)->can('manage-portal'), RuntimeException::class, 'Authorized QA manager required.');
$proof = DB::transaction(function () use ($source): array {
$document = DB::table('documents')->where('id', '589ed9ac-967e-439e-9dde-b0fb3996e546')->lockForUpdate()->first();
$resource = DB::table('portal_resources')->where('id', 29)->lockForUpdate()->first();
throw_unless($document?->sha256 === $source['sha256'] && $document->external_id === 'investmoz-segmentation-source-'.$source['sha256'] && $resource?->document_id === $document->id && ! $resource->published, RuntimeException::class, 'Only this private QA import is eligible.');
$changed = $document->issued_on !== null || $resource->document_date !== null;
if ($changed) {
throw_unless($resource->metadata_version === 1, RuntimeException::class, 'Concurrent metadata change; stop.');
$reference = $resource->source_reference.' Propriedades OOXML: criado '.$source['version_properties']['created'].'; alterado '.$source['version_properties']['modified'].'. Data de emissão não identificada. A alteração OOXML não equivale a emissão; primeira revisão conservada.';
$identity = hash('sha256', mb_strtolower(implode('|', array_map('trim', [(string) $document->issuer, (string) ($resource->document_number ?? ''), '', $resource->language, $resource->version_label]))));
throw_unless(! DB::table('portal_resources')->where('document_identity_key', $identity)->where('id', '!=', 29)->exists(), RuntimeException::class, 'Identity conflict; review required.');
DB::table('documents')->where('id', $document->id)->update(['issued_on' => null, 'updated_at' => now()]);
DB::table('portal_resources')->where('id', 29)->update(['document_date' => null, 'document_identity_key' => $identity, 'source_reference' => $reference, 'metadata_version' => 2, 'updated_at' => now()]);
DB::table('portal_resource_revisions')->insert(['resource_id' => 29, 'revision_no' => 2, 'change_type' => 'metadata_updated',
'snapshot' => json_encode(['resource' => DB::table('portal_resources')->where('id', 29)->first(), 'associations' => []], JSON_THROW_ON_ERROR), 'actor_user_id' => 17, 'created_at' => now()]);
DB::table('audit_events')->insert(['id' => (string) Str::uuid(), 'source_system' => 'document-batch-import', 'external_id' => $document->external_id.'-metadata-2',
'data_classification' => 'internal', 'actor_user_id' => 17, 'entity_type' => 'document', 'entity_id' => $document->id, 'action' => 'source_metadata_corrected',
'before_data' => json_encode(['document_date' => $resource->document_date, 'issued_on' => $document->issued_on, 'metadata_version' => 1], JSON_THROW_ON_ERROR),
'after_data' => json_encode(['resource_id' => 29, 'document_date' => null, 'issued_on' => null, 'metadata_version' => 2, 'sha256' => $source['sha256'], 'reason' => 'Import helper used OOXML modification date as issue date; no issue date in original. Preserve both original timestamps only as provenance.'], JSON_THROW_ON_ERROR),
'occurred_at' => now(), 'created_at' => now()]);
}
throw_unless(DB::table('documents')->where('id', $document->id)->value('issued_on') === null && DB::table('portal_resources')->where('id', 29)->value('document_date') === null, RuntimeException::class, 'Issue dates must remain unknown.');
return ['result' => 'passed', 'at' => gmdate('c'), 'resource_id' => 29, 'source_sha256' => $source['sha256'], 'correction_applied' => $changed,
'document_date' => null, 'issued_on' => null, 'OOXML_created_preserved' => $source['version_properties']['created'], 'OOXML_modified_preserved' => $source['version_properties']['modified'],
'metadata_version' => DB::table('portal_resources')->where('id', 29)->value('metadata_version'), 'historical_revisions' => DB::table('portal_resource_revisions')->where('resource_id', 29)->count(),
'original_and_first_revision_preserved' => true, 'runtime_code_changed' => false, 'active_writes' => 0];
});
$proof['target'] = $target;
file_put_contents($directory.'/source-date-correction-qa.json', json_encode($proof, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR));
echo json_encode($proof, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR).PHP_EOL;