Files
Verde-Web/database/seeders/SanPascualTenantSeeder.php

142 lines
5.1 KiB
PHP

<?php
namespace Database\Seeders;
use App\Models\Barangay;
use App\Models\CityMunicipality;
use App\Models\Province;
use App\Models\Region;
use App\Models\Tenant;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use MatanYadaev\EloquentSpatial\Objects\LineString;
use MatanYadaev\EloquentSpatial\Objects\Point;
use MatanYadaev\EloquentSpatial\Objects\Polygon;
/**
* Seeds San Pascual, Batangas as the pilot tenant. Idempotent.
*
* Creates the PSGC chain (Region IV-A → Batangas → San Pascual mun →
* sample barangay) if missing, then the Tenant row pointing at the
* municipality, then **backfills** every existing tenant-aware row to
* this tenant so the dev database keeps working.
*/
class SanPascualTenantSeeder extends Seeder
{
public function run(): void
{
// Region IV-A CALABARZON — likely already seeded by SamplePsgc.
$region = Region::firstOrCreate(
['psgc_code' => '040000000'],
['code' => 'R4A', 'name' => 'CALABARZON', 'island_group' => 'Luzon'],
);
$province = Province::firstOrCreate(
['psgc_code' => '041000000'],
['code' => 'BTG', 'name' => 'Batangas', 'region_id' => $region->id],
);
$municipality = CityMunicipality::firstOrCreate(
['psgc_code' => '041025000'],
[
'code' => 'SAN-PASCUAL-BAT',
'name' => 'San Pascual',
'province_id' => $province->id,
'type' => 'municipality',
'is_capital' => false,
],
);
// San Pascual centroid: ~13.8 N, 121.05 E (along the coast of Batangas Bay)
$center = ['lat' => 13.8, 'lng' => 121.05];
// Sample barangay (Poblacion equivalent). Boundary is a small box
// around the centroid; replace with PSA polygons later.
$barangay = Barangay::firstOrCreate(
['psgc_code' => '041025001'],
[
'code' => 'SP-POB',
'name' => 'Poblacion',
'city_municipality_id' => $municipality->id,
'urban_rural' => Barangay::URBAN,
'boundary' => $this->boxAround($center['lat'], $center['lng'], 0.01),
'centroid' => new Point($center['lat'], $center['lng'], 4326),
],
);
$tenant = Tenant::firstOrCreate(
['code' => 'SAN-PASCUAL-BAT'],
[
'name' => 'San Pascual, Batangas',
'short_name' => 'San Pascual',
'city_municipality_id' => $municipality->id,
'boundary_polygon' => $this->boxAround($center['lat'], $center['lng'], 0.05),
'timezone' => 'Asia/Manila',
'theme_color' => '#15803d',
'contact_email' => 'mayor@sanpascual.gov.ph',
'status' => Tenant::STATUS_ACTIVE,
],
);
$this->command->info("Tenant seeded: {$tenant->name} (code: {$tenant->code})");
$this->backfillExistingRows($tenant->id);
}
/**
* Backfill every tenant-aware table that has rows but no tenant_id.
* Safe to re-run; only updates NULL values.
*/
private function backfillExistingRows(int $tenantId): void
{
// Tables with their own tenant_id column (HasTenant applied).
$tables = [
'users', 'households', 'drop_off_points', 'dumpsites', 'partner_stores',
'service_areas', 'routes', 'collection_teams', 'trucks', 'trips',
'qr_code_batches', 'qr_codes', 'collection_logs', 'dumpsite_releases',
'payments',
'daily_collection_stats', 'weekly_route_performance', 'monthly_store_sales',
];
$totals = [];
foreach ($tables as $table) {
if (! Schema::hasColumn($table, 'tenant_id')) {
continue;
}
// Don't backfill super_admins — they have no tenant.
if ($table === 'users') {
$count = DB::table('users')
->whereNull('tenant_id')
->where('role', '!=', 'super_admin')
->update(['tenant_id' => $tenantId]);
} else {
$count = DB::table($table)
->whereNull('tenant_id')
->update(['tenant_id' => $tenantId]);
}
$totals[$table] = $count;
}
foreach ($totals as $table => $count) {
if ($count > 0) {
$this->command->info(" Backfilled {$count} {$table}");
}
}
}
private function boxAround(float $lat, float $lng, float $halfDeg): Polygon
{
return new Polygon([
new LineString([
new Point($lat - $halfDeg, $lng - $halfDeg, 4326),
new Point($lat - $halfDeg, $lng + $halfDeg, 4326),
new Point($lat + $halfDeg, $lng + $halfDeg, 4326),
new Point($lat + $halfDeg, $lng - $halfDeg, 4326),
new Point($lat - $halfDeg, $lng - $halfDeg, 4326),
]),
], 4326);
}
}