162 lines
6.2 KiB
PHP
162 lines
6.2 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\V1\Admin;
|
|
|
|
use App\Http\Controllers\Api\V1\ApiController;
|
|
use App\Http\Requests\DropOff\StoreCapacityLogRequest;
|
|
use App\Http\Requests\DropOff\StoreDropOffPointRequest;
|
|
use App\Http\Requests\DropOff\UpdateDropOffPointRequest;
|
|
use App\Http\Resources\DropOffCapacityLogResource;
|
|
use App\Http\Resources\DropOffPointResource;
|
|
use App\Models\DropOffCapacityLog;
|
|
use App\Models\DropOffPoint;
|
|
use App\Services\DropOff\DropOffPointFinder;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use MatanYadaev\EloquentSpatial\Objects\Point;
|
|
use MatanYadaev\EloquentSpatial\Objects\Polygon;
|
|
|
|
class AdminDropOffPointController extends ApiController
|
|
{
|
|
public function __construct(private readonly DropOffPointFinder $dopFinder) {}
|
|
|
|
public function index(Request $request): JsonResponse
|
|
{
|
|
$request->validate([
|
|
'status' => ['nullable', 'in:active,maintenance,closed'],
|
|
'barangay_id' => ['nullable', 'integer'],
|
|
'q' => ['nullable', 'string', 'max:100'],
|
|
'per_page' => ['nullable', 'integer', 'min:1', 'max:500'],
|
|
]);
|
|
|
|
$perPage = (int) $request->input('per_page', 25);
|
|
|
|
$points = DropOffPoint::query()
|
|
->with(['barangay', 'tenant'])
|
|
->when($request->filled('status'), fn ($q) => $q->where('status', $request->string('status')))
|
|
->when($request->filled('barangay_id'), fn ($q) => $q->where('barangay_id', $request->integer('barangay_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(
|
|
DropOffPointResource::collection($points),
|
|
null,
|
|
[
|
|
'page' => $points->currentPage(),
|
|
'per_page' => $points->perPage(),
|
|
'total' => $points->total(),
|
|
'last_page' => $points->lastPage(),
|
|
],
|
|
);
|
|
}
|
|
|
|
public function store(StoreDropOffPointRequest $request): JsonResponse
|
|
{
|
|
$data = $request->validated();
|
|
$point = $this->makePoint($data);
|
|
|
|
$dop = DropOffPoint::create([
|
|
'name' => $data['name'],
|
|
'code' => $data['code'],
|
|
'barangay_id' => $data['barangay_id'] ?? null,
|
|
'coordinates' => $point,
|
|
'address_line' => $data['address_line'],
|
|
'capacity_kg' => $data['capacity_kg'] ?? null,
|
|
'operating_hours' => $data['operating_hours'] ?? null,
|
|
'accepted_waste_types' => $data['accepted_waste_types'] ?? null,
|
|
'status' => $data['status'] ?? DropOffPoint::STATUS_ACTIVE,
|
|
'photo_path' => $data['photo_path'] ?? null,
|
|
'contact_person' => $data['contact_person'] ?? null,
|
|
'contact_phone' => $data['contact_phone'] ?? null,
|
|
'geofence' => ! empty($data['geofence_wkt']) ? Polygon::fromJson($data['geofence_wkt'], 4326) : null,
|
|
]);
|
|
|
|
return $this->created(new DropOffPointResource($dop->load('barangay')), 'Drop-off point created');
|
|
}
|
|
|
|
public function show(DropOffPoint $dropOffPoint): JsonResponse
|
|
{
|
|
$dropOffPoint->load('barangay.cityMunicipality');
|
|
$dropOffPoint->loadMissing(['capacityLogs' => fn ($q) => $q->latest('recorded_at')->limit(20)]);
|
|
|
|
return $this->ok([
|
|
'drop_off_point' => new DropOffPointResource($dropOffPoint),
|
|
'recent_capacity_logs' => DropOffCapacityLogResource::collection($dropOffPoint->capacityLogs),
|
|
]);
|
|
}
|
|
|
|
public function update(UpdateDropOffPointRequest $request, DropOffPoint $dropOffPoint): JsonResponse
|
|
{
|
|
$data = $request->validated();
|
|
$oldStatus = $dropOffPoint->status;
|
|
$newStatus = $data['status'] ?? $oldStatus;
|
|
|
|
if (isset($data['lat'], $data['lng'])) {
|
|
$data['coordinates'] = $this->makePoint($data);
|
|
}
|
|
unset($data['lat'], $data['lng']);
|
|
|
|
if (array_key_exists('geofence_wkt', $data)) {
|
|
$data['geofence'] = ! empty($data['geofence_wkt']) ? Polygon::fromJson($data['geofence_wkt'], 4326) : null;
|
|
unset($data['geofence_wkt']);
|
|
}
|
|
|
|
DB::transaction(function () use ($dropOffPoint, $data, $oldStatus, $newStatus) {
|
|
$dropOffPoint->update($data);
|
|
|
|
if ($newStatus !== DropOffPoint::STATUS_ACTIVE && $oldStatus === DropOffPoint::STATUS_ACTIVE) {
|
|
$households = $dropOffPoint->households;
|
|
foreach ($households as $household) {
|
|
$nearest = $this->dopFinder->nearest(
|
|
$household->coordinates->latitude,
|
|
$household->coordinates->longitude
|
|
);
|
|
$household->update(['assigned_drop_off_point_id' => $nearest?->id]);
|
|
}
|
|
}
|
|
});
|
|
|
|
return $this->ok(
|
|
new DropOffPointResource($dropOffPoint->fresh()->load('barangay')),
|
|
'Drop-off point updated',
|
|
);
|
|
}
|
|
|
|
public function destroy(DropOffPoint $dropOffPoint): JsonResponse
|
|
{
|
|
$dropOffPoint->delete();
|
|
|
|
return $this->ok(null, 'Drop-off point deleted');
|
|
}
|
|
|
|
public function logCapacity(StoreCapacityLogRequest $request, DropOffPoint $dropOffPoint): JsonResponse
|
|
{
|
|
$data = $request->validated();
|
|
|
|
$log = DropOffCapacityLog::create([
|
|
'drop_off_point_id' => $dropOffPoint->id,
|
|
'fill_percent' => $data['fill_percent'],
|
|
'recorded_at' => $data['recorded_at'] ?? now(),
|
|
'recorded_by_user_id' => $request->user()->id,
|
|
'notes' => $data['notes'] ?? null,
|
|
]);
|
|
|
|
return $this->created(
|
|
new DropOffCapacityLogResource($log->load('recordedBy')),
|
|
'Capacity reading recorded',
|
|
);
|
|
}
|
|
|
|
private function makePoint(array $data): Point
|
|
{
|
|
return new Point((float) $data['lat'], (float) $data['lng'], 4326);
|
|
}
|
|
}
|