226 lines
8.6 KiB
PHP
226 lines
8.6 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\V1\Admin;
|
|
|
|
use App\Http\Controllers\Api\V1\ApiController;
|
|
use App\Http\Requests\Dumpsite\StoreDumpsiteRequest;
|
|
use App\Http\Requests\Dumpsite\UpdateDumpsiteRequest;
|
|
use App\Http\Resources\DumpsiteResource;
|
|
use App\Models\Dumpsite;
|
|
use App\Models\CityMunicipality;
|
|
use App\Models\Trip;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use MatanYadaev\EloquentSpatial\Objects\LineString;
|
|
use MatanYadaev\EloquentSpatial\Objects\Point;
|
|
use MatanYadaev\EloquentSpatial\Objects\Polygon;
|
|
|
|
class AdminDumpsiteController extends ApiController
|
|
{
|
|
public function index(Request $request): JsonResponse
|
|
{
|
|
$request->validate([
|
|
'status' => ['nullable', 'in:active,maintenance,closed'],
|
|
'city_municipality_id' => ['nullable', 'integer'],
|
|
'q' => ['nullable', 'string', 'max:100'],
|
|
'per_page' => ['nullable', 'integer', 'min:1', 'max:500'],
|
|
]);
|
|
|
|
$perPage = (int) $request->input('per_page', 25);
|
|
|
|
$dumpsites = Dumpsite::query()
|
|
->with(['cityMunicipality', 'tenant'])
|
|
->when($request->filled('status'), fn ($q) => $q->where('status', $request->string('status')))
|
|
->when(
|
|
$request->filled('city_municipality_id'),
|
|
fn ($q) => $q->where('city_municipality_id', $request->integer('city_municipality_id')),
|
|
)
|
|
->when($request->filled('q'), function ($q) use ($request) {
|
|
$term = '%'.$request->string('q').'%';
|
|
$q->where(fn ($qq) => $qq->where('name', 'like', $term)
|
|
->orWhere('code', 'like', $term)
|
|
->orWhere('address_line', 'like', $term));
|
|
})
|
|
->orderBy('name')
|
|
->paginate($perPage);
|
|
|
|
return $this->ok(
|
|
DumpsiteResource::collection($dumpsites),
|
|
null,
|
|
[
|
|
'page' => $dumpsites->currentPage(),
|
|
'per_page' => $dumpsites->perPage(),
|
|
'total' => $dumpsites->total(),
|
|
'last_page' => $dumpsites->lastPage(),
|
|
],
|
|
);
|
|
}
|
|
|
|
public function store(StoreDumpsiteRequest $request): JsonResponse
|
|
{
|
|
$data = $request->validated();
|
|
|
|
$payload = $this->mapPayload($data);
|
|
$payload['name'] = $data['name'];
|
|
$payload['address_line'] = $data['address_line'];
|
|
$payload['city_municipality_id'] = $data['city_municipality_id'];
|
|
$payload['accepted_waste_types'] = $data['accepted_waste_types'] ?? null;
|
|
$payload['operating_hours'] = $data['operating_hours'] ?? null;
|
|
$payload['capacity_tons'] = $data['capacity_tons'] ?? null;
|
|
$payload['contact_person'] = $data['contact_person'] ?? null;
|
|
$payload['contact_phone'] = $data['contact_phone'] ?? null;
|
|
$payload['status'] = $data['status'] ?? Dumpsite::STATUS_ACTIVE;
|
|
|
|
if (empty($data['permit_number'])) {
|
|
$lgu = CityMunicipality::findOrFail($data['city_municipality_id']);
|
|
$year = now()->year;
|
|
$random = strtoupper(bin2hex(random_bytes(3)));
|
|
$payload['permit_number'] = "DENR-{$year}-" . strtoupper($lgu->code) . "-{$random}";
|
|
} else {
|
|
$payload['permit_number'] = $data['permit_number'];
|
|
}
|
|
|
|
if (empty($data['code'])) {
|
|
$lgu = CityMunicipality::findOrFail($data['city_municipality_id']);
|
|
$baseCode = 'DS-' . strtoupper($lgu->code);
|
|
$count = Dumpsite::where('city_municipality_id', $lgu->id)->count() + 1;
|
|
$code = $baseCode . '-' . str_pad($count, 2, '0', STR_PAD_LEFT);
|
|
while (Dumpsite::where('code', $code)->exists()) {
|
|
$count++;
|
|
$code = $baseCode . '-' . str_pad($count, 2, '0', STR_PAD_LEFT);
|
|
}
|
|
$payload['code'] = $code;
|
|
} else {
|
|
$payload['code'] = $data['code'];
|
|
}
|
|
|
|
$dumpsite = Dumpsite::create($payload);
|
|
|
|
return $this->created(
|
|
new DumpsiteResource($dumpsite->fresh()->load('cityMunicipality')),
|
|
'Dumpsite created',
|
|
);
|
|
}
|
|
|
|
public function show(Dumpsite $dumpsite): JsonResponse
|
|
{
|
|
$dumpsite->load('cityMunicipality.province.region');
|
|
|
|
return $this->ok(new DumpsiteResource($dumpsite));
|
|
}
|
|
|
|
public function update(UpdateDumpsiteRequest $request, Dumpsite $dumpsite): JsonResponse
|
|
{
|
|
$data = $request->validated();
|
|
$payload = $this->mapPayload($data);
|
|
|
|
// Carry through scalar/json fields that mapPayload doesn't touch.
|
|
foreach ([
|
|
'name', 'code', 'address_line', 'city_municipality_id',
|
|
'accepted_waste_types', 'operating_hours', 'capacity_tons',
|
|
'contact_person', 'contact_phone', 'permit_number', 'status',
|
|
] as $key) {
|
|
if (array_key_exists($key, $data)) {
|
|
$payload[$key] = $data[$key];
|
|
}
|
|
}
|
|
|
|
if (array_key_exists('permit_number', $payload)) {
|
|
if (empty($payload['permit_number'])) {
|
|
$lguId = $payload['city_municipality_id'] ?? $dumpsite->city_municipality_id;
|
|
if ($lguId) {
|
|
$lgu = CityMunicipality::findOrFail($lguId);
|
|
$year = now()->year;
|
|
$random = strtoupper(bin2hex(random_bytes(3)));
|
|
$payload['permit_number'] = "DENR-{$year}-" . strtoupper($lgu->code) . "-{$random}";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (array_key_exists('code', $payload)) {
|
|
if (empty($payload['code'])) {
|
|
$lguId = $payload['city_municipality_id'] ?? $dumpsite->city_municipality_id;
|
|
if ($lguId) {
|
|
$lgu = CityMunicipality::findOrFail($lguId);
|
|
$baseCode = 'DS-' . strtoupper($lgu->code);
|
|
$count = Dumpsite::where('city_municipality_id', $lguId)->count() + 1;
|
|
$code = $baseCode . '-' . str_pad($count, 2, '0', STR_PAD_LEFT);
|
|
while (Dumpsite::where('code', $code)->where('id', '!=', $dumpsite->id)->exists()) {
|
|
$count++;
|
|
$code = $baseCode . '-' . str_pad($count, 2, '0', STR_PAD_LEFT);
|
|
}
|
|
$payload['code'] = $code;
|
|
}
|
|
}
|
|
}
|
|
|
|
$oldStatus = $dumpsite->status;
|
|
$newStatus = $payload['status'] ?? $oldStatus;
|
|
|
|
DB::transaction(function () use ($dumpsite, $payload, $oldStatus, $newStatus) {
|
|
$dumpsite->update($payload);
|
|
|
|
if ($newStatus !== Dumpsite::STATUS_ACTIVE && $oldStatus === Dumpsite::STATUS_ACTIVE) {
|
|
$trips = Trip::where('dumpsite_id', $dumpsite->id)
|
|
->whereIn('status', [Trip::STATUS_SCHEDULED, Trip::STATUS_IN_PROGRESS, Trip::STATUS_AT_DUMPSITE])
|
|
->get();
|
|
|
|
foreach ($trips as $trip) {
|
|
$trip->update([
|
|
'status' => Trip::STATUS_CANCELLED,
|
|
'notes' => trim(($trip->notes ?? '')."\nSystem: Trip cancelled because the dumpsite was moved to ".$newStatus.' status.'),
|
|
]);
|
|
}
|
|
}
|
|
});
|
|
|
|
return $this->ok(
|
|
new DumpsiteResource($dumpsite->fresh()->load('cityMunicipality')),
|
|
'Dumpsite updated',
|
|
);
|
|
}
|
|
|
|
public function destroy(Dumpsite $dumpsite): JsonResponse
|
|
{
|
|
$dumpsite->delete();
|
|
|
|
return $this->ok(null, 'Dumpsite deleted');
|
|
}
|
|
|
|
/**
|
|
* Translate lat/lng + boundary_polygon[{lat,lng}, ...] inputs into
|
|
* spatial Polygon/Point objects suitable for assignment to the model.
|
|
*/
|
|
private function mapPayload(array $data): array
|
|
{
|
|
$payload = [];
|
|
|
|
if (isset($data['lat'], $data['lng'])) {
|
|
$payload['coordinates'] = new Point((float) $data['lat'], (float) $data['lng'], 4326);
|
|
}
|
|
|
|
if (array_key_exists('geofence_wkt', $data)) {
|
|
$payload['boundary_polygon'] = ! empty($data['geofence_wkt']) ? Polygon::fromJson($data['geofence_wkt'], 4326) : null;
|
|
}
|
|
|
|
return $payload;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|