This commit is contained in:
2026-11-02 20:27:11 +02:00
parent b44378b899
commit badaada043
300 changed files with 17458 additions and 1056 deletions
+10 -5
View File
@@ -25,7 +25,7 @@ final class Installation
public static function migrationHash(): string
{
return hash('sha256', file_get_contents(__DIR__.'/BudgetSchema.php').file_get_contents(__DIR__.'/budget-contract.json').file_get_contents(dirname(__DIR__).'/internal-requisitions/Schema.php'));
return hash('sha256', file_get_contents(__DIR__.'/BudgetSchema.php').file_get_contents(__DIR__.'/BudgetUiSchema.php').file_get_contents(__DIR__.'/budget-contract.json').file_get_contents(dirname(__DIR__).'/internal-requisitions/Schema.php'));
}
public static function signature(ConnectionInterface $db, array $tables): string
@@ -42,7 +42,7 @@ final class Installation
public static function tables(): array
{
return [...self::TABLES, 'permission_grants', 'ir_requests', 'ir_steps', 'ir_events', 'ir_commands', 'ir_policies', 'ir_policy_versions'];
return [...self::TABLES, ...BudgetUiSchema::TABLES, 'permission_grants', 'ir_requests', 'ir_steps', 'ir_events', 'ir_commands', 'ir_policies', 'ir_policy_versions'];
}
public static function migrate(ConnectionInterface $db, string $expectedTarget, string $backupHash, string $operator): array
@@ -56,7 +56,7 @@ final class Installation
$schema = $db->getSchemaBuilder();
if ($schema->hasTable('sgc_installations')) {
$old = $db->table('sgc_installations')->where('module', 'internal-requisitions')->first();
if (! $old || $old->revision !== 1 || ! hash_equals($old->migration_sha256, self::migrationHash()) || ! hash_equals($old->schema_signature, self::signature($db, self::tables()))) {
if (! $old || $old->revision !== 2 || ! hash_equals($old->migration_sha256, self::migrationHash()) || ! hash_equals($old->schema_signature, self::signature($db, self::tables()))) {
throw new \RuntimeException('Instalação/schema divergente; reconciliar sem sobrescrever.');
}
@@ -89,6 +89,7 @@ final class Installation
$db->statement("ALTER TABLE permission_grants ADD CONSTRAINT permission_grants_scope_check CHECK (({$parts[1]}) OR (unit_id IS NOT NULL AND permission::text IN ($literals)))");
}
RequisitionSchema::install($db);
BudgetUiSchema::create($db);
$schema->create('sgc_installations', function (Blueprint $table) {
$table->string('module')->primary();
$table->integer('revision');
@@ -99,7 +100,7 @@ final class Installation
$table->string('database_operator');
$table->timestampTz('prepared_at');
});
$db->table('sgc_installations')->insert(['module' => 'internal-requisitions', 'revision' => 1, 'schema_signature' => self::signature($db, self::tables()), 'migration_sha256' => self::migrationHash(), 'backup_sha256' => $backupHash, 'operator' => $operator, 'database_operator' => $db->selectOne('select current_user as name')->name, 'prepared_at' => now()]);
$db->table('sgc_installations')->insert(['module' => 'internal-requisitions', 'revision' => 2, 'schema_signature' => self::signature($db, self::tables()), 'migration_sha256' => self::migrationHash(), 'backup_sha256' => $backupHash, 'operator' => $operator, 'database_operator' => $db->selectOne('select current_user as name')->name, 'prepared_at' => now()]);
$db->unprepared("CREATE FUNCTION sgc_installations_immutable() RETURNS trigger LANGUAGE plpgsql AS \$\$ BEGIN RAISE EXCEPTION 'Preserve installation history'; END; \$\$; CREATE TRIGGER sgc_installations_immutable BEFORE UPDATE OR DELETE ON sgc_installations FOR EACH ROW EXECUTE FUNCTION sgc_installations_immutable();");
return ['prepared' => true, 'replayed' => false, 'activated' => false];
@@ -115,6 +116,10 @@ final class Installation
abort_unless($scope['unit_id'] !== null && in_array(implode(':', $scope), config('purchasing-operational.scopes', []), true), 403, 'Opção interna não configurada para esta unidade.');
abort_unless($db->getSchemaBuilder()->hasTable('sgc_installations'), 503, 'Schema operacional não preparado.');
$row = $db->table('sgc_installations')->where('module', 'internal-requisitions')->first();
abort_unless($row && $row->revision === 1 && hash_equals($row->migration_sha256, self::migrationHash()) && hash_equals($row->schema_signature, self::signature($db, self::tables())), 503, 'Schema operacional não preparado.');
$signatureMatches=$row && hash_equals($row->schema_signature, self::signature($db, self::tables()));
if(!$signatureMatches && class_exists(\Tempo\Purchasing\SgfSourcing\Schema::class)){
$signatureMatches=\Tempo\Purchasing\SgfSourcing\Schema::compatible($db);
}
abort_unless($row && $row->revision === 2 && hash_equals($row->migration_sha256, self::migrationHash()) && $signatureMatches, 503, 'Schema operacional não preparado.');
}
}