Files
Verde-Web/app/Http/Controllers/Api/V1/Admin/AdminRouteController.php

184 lines
6.3 KiB
PHP

<?php
namespace App\Http\Controllers\Api\V1\Admin;
use App\Http\Controllers\Api\V1\ApiController;
use App\Http\Requests\Route\StoreRouteRequest;
use App\Http\Requests\Route\UpdateRouteRequest;
use App\Http\Resources\RouteResource;
use App\Models\Route;
use App\Models\RouteStop;
use App\Services\Route\RouteCalculator;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class AdminRouteController extends ApiController
{
public function __construct(private readonly RouteCalculator $calc) {}
public function index(Request $request): JsonResponse
{
$request->validate([
'status' => ['nullable', 'in:active,inactive'],
'area_id' => ['nullable', 'integer'],
'q' => ['nullable', 'string', 'max:100'],
'per_page' => ['nullable', 'integer', 'min:1', 'max:500'],
]);
$perPage = (int) $request->input('per_page', 25);
$routes = Route::query()
->with(['area', 'defaultDumpsite', 'tenant'])
->withCount('stops')
->when($request->filled('status'), fn ($q) => $q->where('status', $request->string('status')))
->when($request->filled('area_id'), fn ($q) => $q->where('area_id', $request->integer('area_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));
})
->orderBy('name')
->paginate($perPage);
return $this->ok(
RouteResource::collection($routes),
null,
[
'page' => $routes->currentPage(),
'per_page' => $routes->perPage(),
'total' => $routes->total(),
'last_page' => $routes->lastPage(),
],
);
}
public function store(StoreRouteRequest $request): JsonResponse
{
$data = $request->validated();
$route = DB::transaction(function () use ($data, $request) {
$route = Route::create([
'name' => $data['name'],
'code' => $data['code'],
'area_id' => $data['area_id'] ?? null,
'default_dumpsite_id' => $data['default_dumpsite_id'] ?? null,
'default_team_id' => $data['default_team_id'] ?? null,
'status' => $data['status'] ?? Route::STATUS_ACTIVE,
'notes' => $data['notes'] ?? null,
'created_by_admin_id' => $request->user()->id,
]);
$this->syncStops($route, $data['stops']);
return $route;
});
$this->calc->recompute($route);
return $this->created(
new RouteResource($route->fresh()->load(['area', 'defaultDumpsite', 'stops.dropOffPoint'])->loadCount('stops')),
'Route created',
);
}
public function show(Route $route): JsonResponse
{
$route->load(['area', 'defaultDumpsite', 'stops.dropOffPoint.barangay'])
->loadCount('stops');
return $this->ok(new RouteResource($route));
}
public function update(UpdateRouteRequest $request, Route $route): JsonResponse
{
$data = $request->validated();
$stopsPayload = $data['stops'] ?? null;
unset($data['stops']);
DB::transaction(function () use ($route, $data, $stopsPayload) {
$route->update($data);
if ($stopsPayload !== null) {
$this->syncStops($route, $stopsPayload);
}
});
$this->calc->recompute($route);
return $this->ok(
new RouteResource($route->fresh()->load(['area', 'defaultDumpsite', 'stops.dropOffPoint'])->loadCount('stops')),
'Route updated',
);
}
public function destroy(Route $route): JsonResponse
{
$route->delete();
return $this->ok(null, 'Route deleted');
}
public function clone(Request $request, Route $route): JsonResponse
{
$request->validate([
'name' => ['nullable', 'string', 'max:191'],
'code' => ['nullable', 'string', 'max:32'],
]);
$newCode = $request->string('code')->isEmpty()
? $route->code.'-COPY-'.strtoupper(Str::random(4))
: (string) $request->string('code');
$newName = $request->string('name')->isEmpty()
? $route->name.' (copy)'
: (string) $request->string('name');
$clone = DB::transaction(function () use ($route, $request, $newCode, $newName) {
$clone = Route::create([
'name' => $newName,
'code' => $newCode,
'area_id' => $route->area_id,
'default_dumpsite_id' => $route->default_dumpsite_id,
'default_team_id' => $route->default_team_id,
'status' => Route::STATUS_INACTIVE,
'notes' => $route->notes,
'created_by_admin_id' => $request->user()->id,
]);
$payload = $route->stops->map(fn ($s) => [
'drop_off_point_id' => $s->drop_off_point_id,
'estimated_duration_minutes' => $s->estimated_duration_at_stop_minutes,
])->all();
$this->syncStops($clone, $payload);
return $clone;
});
$this->calc->recompute($clone);
return $this->created(
new RouteResource($clone->fresh()->load(['area', 'defaultDumpsite', 'stops.dropOffPoint'])->loadCount('stops')),
'Route cloned',
);
}
/**
* Replace the route's stops with the given ordered list. Sequence is
* derived from array position (1-based) so admin can drag-reorder
* client-side and just submit the new order.
*/
private function syncStops(Route $route, array $stops): void
{
$route->stops()->delete();
foreach (array_values($stops) as $i => $stop) {
RouteStop::create([
'route_id' => $route->id,
'drop_off_point_id' => $stop['drop_off_point_id'],
'sequence' => $i + 1,
'estimated_duration_at_stop_minutes' => $stop['estimated_duration_minutes'] ?? 10,
]);
}
}
}