validate([ 'status' => ['nullable', 'in:onboarding,active,suspended'], 'q' => ['nullable', 'string', 'max:100'], 'per_page' => ['nullable', 'integer', 'min:1', 'max:100'], ]); $perPage = (int) $request->input('per_page', 25); $tenants = Tenant::query() ->with(['cityMunicipality.province.region']) ->withCount(['users', 'households', 'trucks', 'barangays']) ->when($request->filled('status'), fn ($q) => $q->where('status', $request->string('status'))) ->when($request->filled('q'), function ($q) use ($request) { $term = '%'.$request->string('q').'%'; $q->where(function ($qq) use ($term) { $qq->where('name', 'like', $term) ->orWhere('code', 'like', $term) ->orWhere('short_name', 'like', $term); }); }) ->orderBy('name') ->paginate($perPage); return $this->ok( SuperAdminTenantResource::collection($tenants), null, [ 'page' => $tenants->currentPage(), 'per_page' => $tenants->perPage(), 'total' => $tenants->total(), 'last_page' => $tenants->lastPage(), ], ); } public function store(StoreTenantRequest $request): JsonResponse { $data = $request->validated(); $tenant = DB::transaction(function () use ($data) { $boundary = $this->buildPolygon($data['boundary_polygon']); $tenant = Tenant::create([ 'name' => $data['name'], 'short_name' => $data['short_name'], 'city_municipality_id' => $data['city_municipality_id'], 'boundary_polygon' => $boundary, 'theme_color' => $data['theme_color'] ?? '#16a34a', 'logo_path' => $data['logo_path'] ?? null, 'contact_email' => $data['contact_email'], 'contact_phone' => $data['contact_phone'], 'status' => $data['status'] ?? Tenant::STATUS_ONBOARDING, 'timezone' => $data['timezone'] ?? 'Asia/Manila', ]); // Create default LGU admin account $user = User::create([ 'tenant_id' => $tenant->id, 'first_name' => 'LGU', 'last_name' => 'Admin', 'email' => $data['admin_email'], 'phone' => $data['contact_phone'], 'password' => Hash::make($data['admin_password']), 'role' => User::ROLE_ADMIN, 'status' => User::STATUS_ACTIVE, ]); $user->assignRole(User::ROLE_ADMIN); NotificationPreference::create([ 'user_id' => $user->id, 'language' => 'en', ]); return $tenant; }); return $this->created( new SuperAdminTenantResource( $tenant->load(['cityMunicipality.province.region', 'users']) ), 'LGU onboarded successfully' ); } public function show(Tenant $tenant): JsonResponse { $tenant->load(['cityMunicipality.province.region', 'users']); $tenant->loadCount(['users', 'households', 'trucks', 'barangays']); return $this->ok(new SuperAdminTenantResource($tenant)); } public function update(StoreTenantRequest $request, Tenant $tenant): JsonResponse { $data = $request->validated(); DB::transaction(function () use ($tenant, $data) { $boundary = $this->buildPolygon($data['boundary_polygon']); $tenant->update([ 'name' => $data['name'], 'short_name' => $data['short_name'], 'city_municipality_id' => $data['city_municipality_id'], 'boundary_polygon' => $boundary, 'theme_color' => $data['theme_color'] ?? $tenant->theme_color, 'logo_path' => $data['logo_path'] ?? $tenant->logo_path, 'contact_email' => $data['contact_email'], 'contact_phone' => $data['contact_phone'], 'status' => $data['status'] ?? $tenant->status, 'timezone' => $data['timezone'] ?? $tenant->timezone, ]); $admin = $tenant->users()->where('role', User::ROLE_ADMIN)->first(); if (! $admin && ! empty($data['admin_email']) && ! empty($data['admin_password'])) { $admin = User::create([ 'tenant_id' => $tenant->id, 'first_name' => 'LGU', 'last_name' => 'Admin', 'email' => $data['admin_email'], 'phone' => $data['contact_phone'], 'password' => Hash::make($data['admin_password']), 'role' => User::ROLE_ADMIN, 'status' => User::STATUS_ACTIVE, ]); $admin->assignRole(User::ROLE_ADMIN); NotificationPreference::create([ 'user_id' => $admin->id, 'language' => 'en', ]); } elseif ($admin) { if (! empty($data['admin_email'])) { // Ignore unique constraint on the same user $existing = User::where('email', $data['admin_email'])->where('id', '!=', $admin->id)->first(); if (! $existing) { $admin->email = $data['admin_email']; } } if (! empty($data['admin_password'])) { $admin->password = Hash::make($data['admin_password']); } if ($admin->isDirty('email') || $admin->isDirty('password')) { $admin->save(); } } }); $tenant->load(['cityMunicipality.province.region', 'users']); $tenant->loadCount(['users', 'households', 'trucks', 'barangays']); return $this->ok(new SuperAdminTenantResource($tenant), 'LGU updated successfully'); } public function destroy(Tenant $tenant): JsonResponse { $tenant->delete(); return $this->ok(null, 'LGU deleted successfully'); } private function buildPolygon(array $points): Polygon { $ring = array_map( fn ($p) => new Point((float) $p['lat'], (float) $p['lng'], 4326), $points, ); $first = $ring[0]; $last = $ring[count($ring) - 1]; if ($first->latitude !== $last->latitude || $first->longitude !== $last->longitude) { $ring[] = new Point($first->latitude, $first->longitude, 4326); } return new Polygon([new LineString($ring)], 4326); } }