413 lines
14 KiB
PHP
413 lines
14 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Vehicle;
|
|
use App\Models\Detection;
|
|
use App\Models\VehicleFake;
|
|
use App\Services\VehicleService;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Redis;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class VehicleController extends Controller
|
|
{
|
|
public function __construct(
|
|
private VehicleService $vehicleService
|
|
) {}
|
|
|
|
/**
|
|
* Consultar vehículo por placa/VIN y darlo de alta como robado
|
|
* POST /api/vehicles/consultar
|
|
*/
|
|
public function consultarVehiculo(Request $request): JsonResponse
|
|
{
|
|
$validator = Validator::make($request->all(), [
|
|
'placa' => 'required_without:vin|string|nullable',
|
|
'vin' => 'required_without:placa|string|nullable',
|
|
], [
|
|
'placa.required_without' => 'Debe proporcionar al menos placa o VIN',
|
|
'vin.required_without' => 'Debe proporcionar al menos placa o VIN',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return ApiResponse::BAD_REQUEST->response([
|
|
'success' => false,
|
|
'message' => 'Datos inválidos',
|
|
'errors' => $validator->errors()
|
|
]);
|
|
}
|
|
|
|
$datosVehiculo = null;
|
|
|
|
if ($request->vin) {
|
|
$datosVehiculo = $this->vehicleService->consultarVehiculoPorTag($request->vin);
|
|
}
|
|
|
|
if (!$datosVehiculo && $request->placa) {
|
|
$datosVehiculo = $this->vehicleService->consultarVehiculoPorTag($request->placa);
|
|
}
|
|
|
|
if (!$datosVehiculo || !isset($datosVehiculo['tag_number'])) {
|
|
return ApiResponse::NOT_FOUND->response([
|
|
'success' => false,
|
|
'message' => 'No se encontró el vehículo en el sistema'
|
|
]);
|
|
}
|
|
|
|
$fastId = $datosVehiculo['tag_number'];
|
|
|
|
// Verificar si ya está en Redis
|
|
$key = "vehiculo:robado:{$fastId}";
|
|
if (Redis::exists($key)) {
|
|
return ApiResponse::BAD_REQUEST->response([
|
|
'success' => false,
|
|
'message' => 'El vehículo ya está registrado como robado'
|
|
]);
|
|
}
|
|
|
|
// Guardar en Redis usando la estructura del VehicleService
|
|
$datos = [
|
|
'fast_id' => $fastId,
|
|
'vin' => $datosVehiculo['vin'] ?? null,
|
|
'placa' => $datosVehiculo['placa'] ?? null,
|
|
'marca' => $datosVehiculo['marca'] ?? null,
|
|
'modelo' => $datosVehiculo['modelo'] ?? null,
|
|
'color' => $datosVehiculo['color'] ?? null,
|
|
'fecha_robo' => $request->fecha_robo,
|
|
'autoridad' => $request->autoridad,
|
|
'acta' => $request->acta,
|
|
'denunciante' => $request->denunciante,
|
|
'fecha_acta' => $request->fecha_acta,
|
|
'primera_deteccion' => now()->toIso8601String(),
|
|
'ultima_deteccion' => now()->toIso8601String(),
|
|
'detecciones' => 0
|
|
];
|
|
|
|
Redis::set($key, json_encode($datos));
|
|
|
|
return ApiResponse::OK->response([
|
|
'success' => true,
|
|
'message' => 'Vehículo consultado y registrado como robado exitosamente',
|
|
'vehiculo' => $datos
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Dar de baja (registrar como recuperado)
|
|
*/
|
|
public function recuperarVehiculo(Request $request): JsonResponse
|
|
{
|
|
$validator = Validator::make($request->all(), [
|
|
'placa' => 'required_without:vin|string|nullable',
|
|
'vin' => 'required_without:placa|string|nullable',
|
|
], [
|
|
'placa.required_without' => 'Debe proporcionar al menos placa o VIN',
|
|
'vin.required_without' => 'Debe proporcionar al menos placa o VIN',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return ApiResponse::BAD_REQUEST->response([
|
|
'success' => false,
|
|
'message' => 'Datos inválidos',
|
|
'errors' => $validator->errors()
|
|
]);
|
|
}
|
|
|
|
try {
|
|
$placa = $request->placa;
|
|
$vin = $request->vin;
|
|
|
|
// 1. Buscar en Redis (vehículos robados activos)
|
|
$vehiculoEncontrado = $this->buscarEnRedis($vin, $placa);
|
|
|
|
if (!$vehiculoEncontrado) {
|
|
return ApiResponse::NOT_FOUND->response([
|
|
'success' => false,
|
|
'message' => 'El vehículo no se encuentra en la lista de robados activos'
|
|
]);
|
|
}
|
|
|
|
$datosRedis = $vehiculoEncontrado['datos'];
|
|
|
|
// 2. Guardar en MySQL como recuperado
|
|
$vehiculoRecuperado = Vehicle::create([
|
|
'fast_id' => $datosRedis['fast_id'] ?? null,
|
|
'vin' => $datosRedis['vin'] ?? null,
|
|
'placa' => $datosRedis['placa'] ?? null,
|
|
'fecha_robo' => $datosRedis['fecha_robo'] ?? null,
|
|
'acta_robo' => $datosRedis['acta'] ?? null,
|
|
'denunciante' => $datosRedis['denunciante'] ?? null,
|
|
'fecha_acta' => $datosRedis['fecha_acta'] ?? null,
|
|
'fecha_recuperacion' => now(),
|
|
'datos_robo_original' => $datosRedis
|
|
]);
|
|
|
|
// 3. Eliminar de Redis
|
|
$fastId = $vehiculoEncontrado['fast_id'];
|
|
Redis::del("vehiculo:robado:{$fastId}");
|
|
|
|
return ApiResponse::OK->response([
|
|
'success' => true,
|
|
'message' => 'Vehículo registrado como recuperado exitosamente',
|
|
'vehiculo' => [
|
|
'id' => $vehiculoRecuperado->id,
|
|
'fast_id' => $vehiculoRecuperado->fast_id,
|
|
'vin' => $vehiculoRecuperado->vin,
|
|
'placa' => $vehiculoRecuperado->placa,
|
|
'fecha_robo' => $vehiculoRecuperado->fecha_robo,
|
|
'fecha_recuperacion' => $vehiculoRecuperado->fecha_recuperacion,
|
|
'acta_robo' => $vehiculoRecuperado->acta_robo,
|
|
]
|
|
]);
|
|
} catch (\Exception $e) {
|
|
Log::error('Error al recuperar vehículo', [
|
|
'placa' => $request->placa,
|
|
'vin' => $request->vin,
|
|
'error' => $e->getMessage()
|
|
]);
|
|
|
|
return ApiResponse::INTERNAL_ERROR->response([
|
|
'success' => false,
|
|
'message' => 'Error al registrar vehículo como recuperado',
|
|
'error' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Buscar vehículo en Redis
|
|
*/
|
|
private function buscarEnRedis(?string $vin, ?string $placa): ?array
|
|
{
|
|
$keys = Redis::keys('vehiculo:robado:*');
|
|
|
|
foreach ($keys as $key) {
|
|
$datos = Redis::get($key);
|
|
if (!$datos) {
|
|
continue;
|
|
}
|
|
|
|
$vehiculo = json_decode($datos, true);
|
|
|
|
// Buscar por VIN o Placa
|
|
if (($vin && $vehiculo['vin'] === $vin) || ($placa && $vehiculo['placa'] === $placa)) {
|
|
// Extraer el fast_id del key
|
|
$fastId = str_replace('vehiculo:robado:', '', $key);
|
|
|
|
return [
|
|
'fast_id' => $fastId,
|
|
'datos' => $vehiculo
|
|
];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Listar todos los vehículos robados activos
|
|
* GET /api/vehicles/robados
|
|
*/
|
|
public function listarRobados(Request $request)
|
|
{
|
|
try {
|
|
$vehiculos = $this->vehicleService->listarVehiculosRobados();
|
|
|
|
$collection = collect($vehiculos);
|
|
|
|
$perPage = $request->input('per_page', config('app.pagination', 15));
|
|
$page = $request->input('page', 1);
|
|
|
|
$paginatedVehiculos = new \Illuminate\Pagination\LengthAwarePaginator(
|
|
$collection->forPage($page, $perPage),
|
|
$collection->count(),
|
|
$perPage,
|
|
$page,
|
|
['path' => $request->url(), 'query' => $request->query()]
|
|
);
|
|
|
|
return ApiResponse::OK->response([
|
|
'success' => true,
|
|
'total' => $collection->count(),
|
|
'vehiculos' => $paginatedVehiculos
|
|
]);
|
|
} catch (\Exception $e) {
|
|
return ApiResponse::BAD_REQUEST->response([
|
|
'success' => false,
|
|
'message' => 'Error al listar vehículos robados',
|
|
'error' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
public function listarRecuperados()
|
|
{
|
|
$vehiculos = Vehicle::orderBy('fecha_recuperacion', 'desc')
|
|
->paginate(config('app.pagination'));
|
|
|
|
return ApiResponse::OK->response([
|
|
'success' => true,
|
|
'vehiculos' => $vehiculos
|
|
]);
|
|
}
|
|
|
|
public function listarDetecciones()
|
|
{
|
|
$detecciones = Detection::orderBy('fecha_deteccion', 'desc')
|
|
->paginate(config('app.pagination'));
|
|
|
|
return ApiResponse::OK->response([
|
|
'success' => true,
|
|
'detecciones' => $detecciones
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Listar detecciones del día desde Redis
|
|
* GET /api/vehicles/detecciones/dia
|
|
*/
|
|
public function listarDeteccionesDelDia(Request $request)
|
|
{
|
|
$fecha = $request->input('fecha'); // Formato: Y-m-d (opcional)
|
|
|
|
if ($fecha && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $fecha)) {
|
|
return ApiResponse::BAD_REQUEST->response([
|
|
'success' => false,
|
|
'message' => 'Formato de fecha inválido. Use YYYY-MM-DD'
|
|
]);
|
|
}
|
|
|
|
try {
|
|
$detecciones = $this->vehicleService->listarDeteccionesDelDia($fecha);
|
|
|
|
return ApiResponse::OK->response([
|
|
'success' => true,
|
|
'fecha' => $fecha ?? now()->format('Y-m-d'),
|
|
'total' => count($detecciones),
|
|
'detecciones' => $detecciones
|
|
]);
|
|
} catch (\Exception $e) {
|
|
return ApiResponse::INTERNAL_ERROR->response([
|
|
'success' => false,
|
|
'message' => 'Error al obtener detecciones del día',
|
|
'error' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
public function buscarVehiculo(Request $request)
|
|
{
|
|
$validated = $request->validate([
|
|
'placa' => 'required_without:vin|string|nullable',
|
|
'vin' => 'required_without:placa|string|nullable',
|
|
]);
|
|
|
|
$placa = $validated['placa'] ?? null;
|
|
$vin = $validated['vin'] ?? null;
|
|
|
|
$vehiculo = VehicleFake::when($vin, function ($query) use ($vin) {
|
|
return $query->where('vin', $vin);
|
|
})
|
|
->when($placa, function ($query) use ($placa) {
|
|
return $query->orWhere('placa', $placa);
|
|
})
|
|
->first();
|
|
|
|
if (!$vehiculo) {
|
|
return ApiResponse::NOT_FOUND->response([
|
|
'success' => false,
|
|
'message' => 'No se encontró el vehículo en la base de datos'
|
|
]);
|
|
}
|
|
|
|
// Buscar detecciones del vehículo
|
|
$detecciones = Detection::when($vin, function ($query) use ($vin) {
|
|
return $query->where('vin', $vin);
|
|
})
|
|
->when($placa, function ($query) use ($placa) {
|
|
return $query->orWhere('placa', $placa);
|
|
})
|
|
->orderBy('fecha_deteccion', 'desc')
|
|
->paginate(config('app.pagination'));
|
|
|
|
return ApiResponse::OK->response([
|
|
'success' => true,
|
|
'vehiculo' => [
|
|
'folio_tag' => $vehiculo->folio_tag,
|
|
'tag_number' => $vehiculo->tag_number,
|
|
'placa' => $vehiculo->placa,
|
|
'vin' => $vehiculo->vin,
|
|
'marca' => $vehiculo->marca,
|
|
'modelo' => $vehiculo->modelo,
|
|
'color' => $vehiculo->color,
|
|
],
|
|
'total_detecciones' => $detecciones->total(),
|
|
'detecciones' => $detecciones
|
|
]);
|
|
}
|
|
|
|
public function buscarVehiculoRobado(Request $request)
|
|
{
|
|
$validated = $request->validate([
|
|
'placa' => 'required_without:vin|string|nullable',
|
|
'vin' => 'required_without:placa|string|nullable',
|
|
]);
|
|
|
|
$placa = $validated['placa'] ?? null;
|
|
$vin = $validated['vin'] ?? null;
|
|
|
|
// Buscar en Redis
|
|
$vehiculoEncontrado = $this->buscarEnRedis($vin, $placa);
|
|
|
|
if (!$vehiculoEncontrado) {
|
|
return ApiResponse::NOT_FOUND->response([
|
|
'success' => false,
|
|
'message' => 'El vehículo no está registrado como robado'
|
|
]);
|
|
}
|
|
|
|
return ApiResponse::OK->response([
|
|
'success' => true,
|
|
'message' => 'Vehículo encontrado en lista de robados',
|
|
'vehiculo' => $vehiculoEncontrado['datos']
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Procesar detección de tag RFID
|
|
* POST /api/vehicles/buscar
|
|
* Requiere autenticación mediante token de arco
|
|
*/
|
|
public function buscarPorTag(Request $request)
|
|
{
|
|
$validated = $request->validate([
|
|
'fast_id' => 'required|string',
|
|
'antena' => 'nullable|string',
|
|
'timestamp' => 'nullable|date'
|
|
]);
|
|
|
|
// Obtener el arco autenticado del middleware
|
|
$arco = $request->get('arco_autenticado');
|
|
|
|
$resultado = $this->vehicleService->procesarDeteccion(
|
|
$validated['fast_id'],
|
|
$arco->ip_address,
|
|
$validated['antena'] ?? null
|
|
);
|
|
|
|
if (!$resultado['success']) {
|
|
return ApiResponse::NOT_FOUND->response([
|
|
'success' => false,
|
|
'message' => $resultado['message'] ?? 'No se encontró el vehículo'
|
|
]);
|
|
}
|
|
|
|
return ApiResponse::OK->response($resultado);
|
|
}
|
|
}
|