129 lines
6.0 KiB
PHP
129 lines
6.0 KiB
PHP
<?php
|
|
|
|
namespace Database\Seeders;
|
|
|
|
use Illuminate\Database\Seeder;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\File;
|
|
use RuntimeException;
|
|
|
|
class ReferenceCatalogSeeder extends Seeder
|
|
{
|
|
private const CATALOG_IDS = [
|
|
'authorities' => 'a1000000-0000-4000-8000-000000000001',
|
|
'jurisdictions' => 'a1000000-0000-4000-8000-000000000002',
|
|
'economic-activities' => 'a1000000-0000-4000-8000-000000000003',
|
|
];
|
|
|
|
/** @var array<string,string> */
|
|
private const ACTIVITY_IDS = [
|
|
'agronegocio' => 'a2000000-0000-4000-8000-000000000001',
|
|
'energia' => 'a2000000-0000-4000-8000-000000000002',
|
|
'turismo' => 'a2000000-0000-4000-8000-000000000003',
|
|
'infraestruturas' => 'a2000000-0000-4000-8000-000000000004',
|
|
'economia-azul' => 'a2000000-0000-4000-8000-000000000005',
|
|
'mercado-financeiro' => 'a2000000-0000-4000-8000-000000000006',
|
|
];
|
|
|
|
public function run(): void
|
|
{
|
|
$territory = json_decode(File::get(database_path('data/territory-locations.json')), true, 512, JSON_THROW_ON_ERROR);
|
|
if (! is_array($territory) || ! is_array($territory['records'] ?? null) || ! is_int($territory['source_version'] ?? null)) {
|
|
throw new RuntimeException('Territorial catalog source is malformed.');
|
|
}
|
|
if (! is_string($territory['records_sha256'] ?? null)
|
|
|| ! hash_equals($territory['records_sha256'], hash('sha256', json_encode($territory['records'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR)))
|
|
|| DB::table('geo_locations')->where('source_system', 'cartografia-workbook')->where('data_classification', 'public')->count() !== count($territory['records'])) {
|
|
throw new RuntimeException('Territorial catalog version does not match its verified seed records.');
|
|
}
|
|
|
|
DB::transaction(function () use ($territory): void {
|
|
DB::select('SELECT pg_advisory_xact_lock(20261001, 300100)');
|
|
|
|
$this->catalogVersion('authorities', 1, 'authority-register-pending-source', 'pending-authority-source',
|
|
'Awaiting an approved authority source; no institution or mandate is inferred.', null, null, 'draft');
|
|
$this->catalogVersion('jurisdictions', $territory['source_version'], 'cartografia-workbook', (string) $territory['source_version'],
|
|
'database/data/territory-locations.json', $territory['source_sha256'], null, 'published');
|
|
|
|
$activities = DB::table('sectors')->whereIn('slug', array_keys(self::ACTIVITY_IDS))->orderBy('slug')->get(['id', 'name', 'slug']);
|
|
if ($activities->count() !== count(self::ACTIVITY_IDS)) {
|
|
throw new RuntimeException('The curated sector source is incomplete; economic activity seed aborted.');
|
|
}
|
|
|
|
$canonical = $activities->map(fn ($row) => ['code' => $row->slug, 'label_pt_mz' => $row->name])->values()->all();
|
|
$activityChecksum = hash('sha256', json_encode($canonical, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR));
|
|
$versionId = $this->catalogVersion('economic-activities', 1, 'investmoz-curated', 'sector-seeder-v1',
|
|
'database/seeders/SectorSeeder.php; seed is a portal grouping, not an official activity classification.',
|
|
$activityChecksum, '2026-10-01', 'published');
|
|
|
|
foreach ($activities as $activity) {
|
|
$expected = [
|
|
'id' => self::ACTIVITY_IDS[$activity->slug],
|
|
'catalog_version_id' => $versionId,
|
|
'parent_id' => null,
|
|
'sector_id' => $activity->id,
|
|
'code' => $activity->slug,
|
|
'label_pt_mz' => $activity->name,
|
|
'description_pt_mz' => null,
|
|
'version_no' => 1,
|
|
'valid_from' => '2026-10-01',
|
|
'valid_to' => null,
|
|
'status' => 'published',
|
|
];
|
|
$existing = DB::table('economic_activities')->where('catalog_version_id', $versionId)->where('code', $activity->slug)->first();
|
|
if ($existing) {
|
|
foreach ($expected as $column => $value) {
|
|
if ((string) $existing->{$column} !== (string) $value) {
|
|
throw new RuntimeException('Economic activity differs from its versioned seed: '.$activity->slug);
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
DB::table('economic_activities')->insert([...$expected, 'created_at' => now(), 'updated_at' => now()]);
|
|
}
|
|
});
|
|
}
|
|
|
|
private function catalogVersion(
|
|
string $code,
|
|
int $version,
|
|
string $source,
|
|
string $sourceVersion,
|
|
string $reference,
|
|
?string $checksum,
|
|
?string $validFrom,
|
|
string $status,
|
|
): string {
|
|
$id = self::CATALOG_IDS[$code];
|
|
$expected = [
|
|
'id' => $id,
|
|
'catalog_code' => $code,
|
|
'version_no' => $version,
|
|
'locale' => 'pt-MZ',
|
|
'source_system' => $source,
|
|
'source_version' => $sourceVersion,
|
|
'source_reference' => $reference,
|
|
'source_sha256' => $checksum,
|
|
'valid_from' => $validFrom,
|
|
'valid_to' => null,
|
|
'status' => $status,
|
|
];
|
|
$existing = DB::table('reference_catalog_versions')->where('catalog_code', $code)->where('version_no', $version)->where('locale', 'pt-MZ')->first();
|
|
if ($existing) {
|
|
foreach ($expected as $column => $value) {
|
|
if ((string) $existing->{$column} !== (string) $value) {
|
|
throw new RuntimeException('Reference catalog version differs from its packaged source: '.$code);
|
|
}
|
|
}
|
|
|
|
return $id;
|
|
}
|
|
|
|
DB::table('reference_catalog_versions')->insert([...$expected, 'created_at' => now(), 'updated_at' => now()]);
|
|
|
|
return $id;
|
|
}
|
|
}
|