142 lines
5.1 KiB
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);
|
|
}
|
|
}
|