add: detecciones día

This commit is contained in:
Juan Felipe Zapata Moreno 2026-01-08 12:01:54 -06:00
parent fe324af630
commit a4528a58b5
7 changed files with 351 additions and 270 deletions

View File

@ -21,7 +21,8 @@ public function __construct(
) {} ) {}
/** /**
* Consultar y registrar vehículo por PLACA o VIN (Alta de vehículo robado) * Consultar vehículo por placa/VIN y darlo de alta como robado
* POST /api/vehicles/consultar
*/ */
public function consultarVehiculo(Request $request): JsonResponse public function consultarVehiculo(Request $request): JsonResponse
{ {
@ -34,37 +35,34 @@ public function consultarVehiculo(Request $request): JsonResponse
]); ]);
if ($validator->fails()) { if ($validator->fails()) {
return ApiResponse::INTERNAL_ERROR->response([ return ApiResponse::BAD_REQUEST->response([
'success' => false, 'success' => false,
'message' => 'Datos inválidos', 'message' => 'Datos inválidos',
'errors' => $validator->errors() 'errors' => $validator->errors()
]); ]);
} }
$placa = $request->placa; $datosVehiculo = null;
$vin = $request->vin;
// Buscar vehículo en vehicle_fakes if ($request->vin) {
$vehiculo = VehicleFake::when($vin, function ($query) use ($vin) { $datosVehiculo = $this->vehicleService->consultarVehiculoPorTag($request->vin);
return $query->where('vin', $vin); }
})
->when($placa, function ($query) use ($placa) {
return $query->orWhere('placa', $placa);
})
->first();
if (!$vehiculo) { if (!$datosVehiculo && $request->placa) {
$datosVehiculo = $this->vehicleService->consultarVehiculoPorTag($request->placa);
}
if (!$datosVehiculo || !isset($datosVehiculo['tag_number'])) {
return ApiResponse::NOT_FOUND->response([ return ApiResponse::NOT_FOUND->response([
'success' => false, 'success' => false,
'message' => 'No se encontró el vehículo' 'message' => 'No se encontró el vehículo en el sistema'
]); ]);
} }
// Generar EPC $fastId = $datosVehiculo['tag_number'];
$epc = 'E280117000000' . $vehiculo->vin;
// Verificar si ya está en Redis // Verificar si ya está en Redis
$key = "vehiculo:robado:{$placa}-{$vin}"; $key = "vehiculo:robado:{$fastId}";
if (Redis::exists($key)) { if (Redis::exists($key)) {
return ApiResponse::BAD_REQUEST->response([ return ApiResponse::BAD_REQUEST->response([
'success' => false, 'success' => false,
@ -72,50 +70,35 @@ public function consultarVehiculo(Request $request): JsonResponse
]); ]);
} }
// Guardar en Redis como robado // Guardar en Redis usando la estructura del VehicleService
$datos = [ $datos = [
'epc' => $epc, 'fast_id' => $fastId,
'folio_tag' => $vehiculo->folio_tag, 'vin' => $datosVehiculo['vin'] ?? null,
'tag_number' => $vehiculo->tag_number, 'placa' => $datosVehiculo['placa'] ?? null,
'vin' => $vehiculo->vin, 'marca' => $datosVehiculo['marca'] ?? null,
'placa' => $vehiculo->placa, 'modelo' => $datosVehiculo['modelo'] ?? null,
'marca' => $vehiculo->marca, 'color' => $datosVehiculo['color'] ?? null,
'modelo' => $vehiculo->modelo, 'fecha_robo' => $request->fecha_robo,
'color' => $vehiculo->color, 'autoridad' => $request->autoridad,
'fecha_robo' => now()->format('Y-m-d'), 'acta' => $request->acta,
'acta' => 'MANUAL-' . now()->format('Ymd-His'), 'denunciante' => $request->denunciante,
'denunciante' => 'SISTEMA', 'fecha_acta' => $request->fecha_acta,
'fecha_acta' => now()->format('Y-m-d'),
'primera_deteccion' => now()->toIso8601String(), 'primera_deteccion' => now()->toIso8601String(),
'ultima_deteccion' => now()->toIso8601String(), 'ultima_deteccion' => now()->toIso8601String(),
'detecciones' => 0
]; ];
Redis::set($key, json_encode($datos)); Redis::set($key, json_encode($datos));
Log::warning('Vehículo dado de alta como robado (MANUAL)', [
'epc' => $epc,
'vin' => $vehiculo->vin,
'placa' => $vehiculo->placa
]);
return ApiResponse::OK->response([ return ApiResponse::OK->response([
'success' => true, 'success' => true,
'message' => 'Vehículo registrado como robado exitosamente', 'message' => 'Vehículo consultado y registrado como robado exitosamente',
'vehiculo' => [ 'vehiculo' => $datos
'epc' => $epc,
'folio_tag' => $vehiculo->folio_tag,
'tag_number' => $vehiculo->tag_number,
'vin' => $vehiculo->vin,
'placa' => $vehiculo->placa,
'marca' => $vehiculo->marca,
'modelo' => $vehiculo->modelo,
'color' => $vehiculo->color
]
]); ]);
} }
/** /**
* Dar de baja (registrar como recuperado) un vehículo por PLACA o VIN * Dar de baja (registrar como recuperado)
*/ */
public function recuperarVehiculo(Request $request): JsonResponse public function recuperarVehiculo(Request $request): JsonResponse
{ {
@ -139,8 +122,6 @@ public function recuperarVehiculo(Request $request): JsonResponse
$placa = $request->placa; $placa = $request->placa;
$vin = $request->vin; $vin = $request->vin;
Log::info('Buscando vehículo robado para recuperar', ['placa' => $placa, 'vin' => $vin]);
// 1. Buscar en Redis (vehículos robados activos) // 1. Buscar en Redis (vehículos robados activos)
$vehiculoEncontrado = $this->buscarEnRedis($vin, $placa); $vehiculoEncontrado = $this->buscarEnRedis($vin, $placa);
@ -152,17 +133,10 @@ public function recuperarVehiculo(Request $request): JsonResponse
} }
$datosRedis = $vehiculoEncontrado['datos']; $datosRedis = $vehiculoEncontrado['datos'];
$epc = $vehiculoEncontrado['epc'];
Log::info('Vehículo encontrado en Redis', [
'epc' => $epc,
'vin' => $datosRedis['vin'],
'placa' => $datosRedis['placa']
]);
// 2. Guardar en MySQL como recuperado // 2. Guardar en MySQL como recuperado
$vehiculoRecuperado = Vehicle::create([ $vehiculoRecuperado = Vehicle::create([
'epc' => $epc, 'fast_id' => $datosRedis['fast_id'] ?? null,
'vin' => $datosRedis['vin'] ?? null, 'vin' => $datosRedis['vin'] ?? null,
'placa' => $datosRedis['placa'] ?? null, 'placa' => $datosRedis['placa'] ?? null,
'fecha_robo' => $datosRedis['fecha_robo'] ?? null, 'fecha_robo' => $datosRedis['fecha_robo'] ?? null,
@ -174,20 +148,15 @@ public function recuperarVehiculo(Request $request): JsonResponse
]); ]);
// 3. Eliminar de Redis // 3. Eliminar de Redis
Redis::del("vehiculo:robado:{$epc}"); $fastId = $vehiculoEncontrado['fast_id'];
Redis::del("vehiculo:robado:{$fastId}");
Log::info('Vehículo registrado como recuperado', [
'id' => $vehiculoRecuperado->id,
'vin' => $vehiculoRecuperado->vin,
'placa' => $vehiculoRecuperado->placa
]);
return ApiResponse::OK->response([ return ApiResponse::OK->response([
'success' => true, 'success' => true,
'message' => 'Vehículo registrado como recuperado exitosamente', 'message' => 'Vehículo registrado como recuperado exitosamente',
'vehiculo' => [ 'vehiculo' => [
'id' => $vehiculoRecuperado->id, 'id' => $vehiculoRecuperado->id,
'epc' => $vehiculoRecuperado->epc, 'fast_id' => $vehiculoRecuperado->fast_id,
'vin' => $vehiculoRecuperado->vin, 'vin' => $vehiculoRecuperado->vin,
'placa' => $vehiculoRecuperado->placa, 'placa' => $vehiculoRecuperado->placa,
'fecha_robo' => $vehiculoRecuperado->fecha_robo, 'fecha_robo' => $vehiculoRecuperado->fecha_robo,
@ -211,7 +180,7 @@ public function recuperarVehiculo(Request $request): JsonResponse
} }
/** /**
* Buscar vehículo en Redis por VIN o Placa * Buscar vehículo en Redis
*/ */
private function buscarEnRedis(?string $vin, ?string $placa): ?array private function buscarEnRedis(?string $vin, ?string $placa): ?array
{ {
@ -227,11 +196,11 @@ private function buscarEnRedis(?string $vin, ?string $placa): ?array
// Buscar por VIN o Placa // Buscar por VIN o Placa
if (($vin && $vehiculo['vin'] === $vin) || ($placa && $vehiculo['placa'] === $placa)) { if (($vin && $vehiculo['vin'] === $vin) || ($placa && $vehiculo['placa'] === $placa)) {
// Extraer el EPC del key // Extraer el fast_id del key
$epc = str_replace('vehiculo:robado:', '', $key); $fastId = str_replace('vehiculo:robado:', '', $key);
return [ return [
'epc' => $epc, 'fast_id' => $fastId,
'datos' => $vehiculo 'datos' => $vehiculo
]; ];
} }
@ -298,6 +267,39 @@ public function listarDetecciones()
]); ]);
} }
/**
* 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) public function buscarVehiculo(Request $request)
{ {
$validated = $request->validate([ $validated = $request->validate([
@ -385,18 +387,14 @@ public function buscarPorTag(Request $request)
{ {
$validated = $request->validate([ $validated = $request->validate([
'fast_id' => 'required|string', 'fast_id' => 'required|string',
'epc' => 'nullable|string', 'antena' => 'nullable|string',
'timestamp' => 'nullable|date' 'timestamp' => 'nullable|date'
]); ]);
// Obtener el arco autenticado del middleware // Obtener el arco autenticado del middleware
$arco = $request->get('arco_autenticado'); $arco = $request->get('arco_autenticado');
// Si no se proporciona EPC, usar el FastID como identificador
$epc = $validated['epc'] ?? $validated['fast_id'];
$resultado = $this->vehicleService->procesarDeteccion( $resultado = $this->vehicleService->procesarDeteccion(
$epc,
$validated['fast_id'], $validated['fast_id'],
$arco->ip_address, $arco->ip_address,
$validated['timestamp'] ?? null $validated['timestamp'] ?? null

View File

@ -18,7 +18,7 @@ class Detection extends Model
protected $fillable = [ protected $fillable = [
'arco_id', 'arco_id',
'epc', 'fast_id',
'vin', 'vin',
'placa', 'placa',
'marca', 'marca',

View File

@ -10,7 +10,7 @@
class Vehicle extends Model class Vehicle extends Model
{ {
protected $fillable = [ protected $fillable = [
'epc', 'fast_id',
'vin', 'vin',
'placa', 'placa',
'fecha_robo', 'fecha_robo',

View File

@ -27,15 +27,15 @@ public function __construct()
} }
/** /**
* Consultar vehículo por tag_number * Consultar vehículo por tag_number, placa o VIN
* *
*/ */
public function consultarVehiculoPorTag(?string $tagNumber = null) public function consultarVehiculoPorTag(?string $criterio = null)
{ {
try { try {
// solo busca por tag_number // Validar que se proporcionó algún criterio de búsqueda
if (empty($tagNumber)) { if (empty($criterio)) {
Log::warning('ConsultaRepuveConstancia: No se proporcionó tag_number'); Log::warning('ConsultaRepuveConstancia: No se proporcionó criterio de búsqueda');
return null; return null;
} }
@ -46,19 +46,54 @@ public function consultarVehiculoPorTag(?string $tagNumber = null)
return null; return null;
} }
// Consultar vehículos con filtro tag_number // Determinar el tipo de búsqueda (intentar primero como tag_number, luego placa, luego VIN)
$url = $this->baseUrl . $this->vehiculosEndpoint; $url = $this->baseUrl . $this->vehiculosEndpoint;
Log::info('ConsultaRepuveConstancia: Consultando', [ Log::info('ConsultaRepuveConstancia: Consultando', [
'url' => $url, 'url' => $url,
'tag_number' => $tagNumber 'criterio' => $criterio
]); ]);
// Intentar buscar por tag_number primero
$response = Http::withHeaders([ $response = Http::withHeaders([
'Authorization' => 'Bearer ' . $token, 'Authorization' => 'Bearer ' . $token,
'Accept' => 'application/json', 'Accept' => 'application/json',
])->timeout(30)->get($url, [ ])->timeout(30)->get($url, [
'tag_number' => $tagNumber 'tag_number' => $criterio
]);
// Si no lo encuentra por tag_number, intentar por placa
if ($response->successful()) {
$data = $response->json();
if (isset($data['data']['records']['data']) && !empty($data['data']['records']['data'])) {
$vehiculoEncontrado = $data['data']['records']['data'][0];
return $this->transformarDatosVehiculo($vehiculoEncontrado);
}
}
// Intentar búsqueda por placa
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . $token,
'Accept' => 'application/json',
])->timeout(30)->get($url, [
'placa' => $criterio
]);
// Si no lo encuentra por placa, intentar por VIN
if ($response->successful()) {
$data = $response->json();
if (isset($data['data']['records']['data']) && !empty($data['data']['records']['data'])) {
$vehiculoEncontrado = $data['data']['records']['data'][0];
return $this->transformarDatosVehiculo($vehiculoEncontrado);
}
}
// Intentar búsqueda por VIN
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . $token,
'Accept' => 'application/json',
])->timeout(30)->get($url, [
'niv' => $criterio
]); ]);
if (!$response->successful()) { if (!$response->successful()) {
@ -84,7 +119,7 @@ public function consultarVehiculoPorTag(?string $tagNumber = null)
if (empty($vehiculos)) { if (empty($vehiculos)) {
Log::info('ConsultaRepuveConstancia: Vehículo no encontrado', [ Log::info('ConsultaRepuveConstancia: Vehículo no encontrado', [
'tag_number' => $tagNumber 'criterio' => $criterio
]); ]);
return null; return null;
} }
@ -96,7 +131,7 @@ public function consultarVehiculoPorTag(?string $tagNumber = null)
} catch (Exception $e) { } catch (Exception $e) {
Log::error('ConsultaRepuveConstancia: Error al consultar vehículo', [ Log::error('ConsultaRepuveConstancia: Error al consultar vehículo', [
'tag_number' => $tagNumber, 'criterio' => $criterio,
'error' => $e->getMessage(), 'error' => $e->getMessage(),
'trace' => $e->getTraceAsString() 'trace' => $e->getTraceAsString()
]); ]);

View File

@ -11,13 +11,15 @@
class VehicleService class VehicleService
{ {
public function __construct( public function __construct(
private ReporteRoboService $reporteRobo,
private ConsultaRepuveConstancia $consultaRepuveCons private ConsultaRepuveConstancia $consultaRepuveCons
) {} ) {}
public function procesarDeteccion(string $epc, string $fastId, string $arcoIp, ?string $timestamp = null): array /**
* Procesar detección de vehículo por fast_id
*/
public function procesarDeteccion(string $fastId, string $arcoIp): array
{ {
$key = "vehiculo:robado:{$epc}"; $key = "vehiculo:robado:{$fastId}";
// Buscar arco por IP // Buscar arco por IP
$arco = Arco::buscarPorIp($arcoIp); $arco = Arco::buscarPorIp($arcoIp);
@ -28,171 +30,53 @@ public function procesarDeteccion(string $epc, string $fastId, string $arcoIp, ?
if ($enRedis) { if ($enRedis) {
// Ya está marcado como robado, verificar si sigue así // Ya está marcado como robado, verificar si sigue así
$resultado = $this->verificarVehiculoRobado($epc, json_decode($enRedis, true)); $resultado = $this->verificarVehiculoRobado($fastId, json_decode($enRedis, true));
$this->registrarDeteccion($epc, $resultado, $arcoId); $this->registrarDeteccion($fastId, $resultado, $arcoId);
return $resultado; return $resultado;
} }
// No está en Redis, consultar servicios // No está en Redis, consultar servicios
$resultado = $this->consultarNuevoVehiculo($epc, $fastId); $resultado = $this->consultarNuevoVehiculo($fastId);
$this->registrarDeteccion($epc, $resultado, $arcoId); $this->registrarDeteccion($fastId, $resultado, $arcoId);
return $resultado; return $resultado;
} }
private function consultarNuevoVehiculo(string $epc, string $fastId): array /**
* Consultar vehículo por tag_id, placa o VIN
*/
public function consultarVehiculoPorTag(string $fastId)
{ {
// Consultar con FastID (tag_number) try {
$datosVehiculo = $this->consultaRepuveCons->consultarVehiculoPorTag($fastId); $vehiculoExterno = $this->consultaRepuveCons->consultarVehiculoPorTag($fastId);
if (!$datosVehiculo || !$datosVehiculo['vin']) { if ($vehiculoExterno) {
Log::warning('Vehículo NO encontrado.', [ Log::info('VehicleService: Vehículo encontrado', [
'epc' => $epc, 'fast_id' => $fastId,
'fast_id' => $fastId 'tag_number' => $vehiculoExterno['tag_number'] ?? null,
]); 'placa' => $vehiculoExterno['placa'] ?? null,
'vin' => $vehiculoExterno['vin'] ?? null
]);
} else {
Log::info('VehicleService: Vehículo no encontrado', [
'fast_id' => $fastId
]);
}
return [ return $vehiculoExterno;
'success' => false,
'message' => 'No se encontró información del vehículo.'
];
}
// Consultar REPUVE para verificar si está robado } catch (\Exception $e) {
$reporteRobo = $this->reporteRobo->consultarRobado( Log::error('VehicleService: Error en consulta', [
$datosVehiculo['vin'],
$datosVehiculo['placa']
);
if ($reporteRobo['tiene_reporte']) {
// Está robado → Guardar en Redis
$this->guardarEnRedis($epc, $datosVehiculo, $reporteRobo['datos']);
Log::warning('¡VEHÍCULO ROBADO DETECTADO!', [
'epc' => $epc,
'fast_id' => $fastId, 'fast_id' => $fastId,
'vin' => $datosVehiculo['vin'], 'error' => $e->getMessage(),
'placa' => $datosVehiculo['placa'] 'trace' => $e->getTraceAsString()
]); ]);
return null;
return [
'success' => true,
'tiene_reporte_robo' => true,
'estado' => 'ROBADO',
'accion' => 'GUARDADO EN BD DE ROBADOS',
'vehiculo' => array_merge($datosVehiculo, $reporteRobo['datos'])
];
} }
// No está robado - vehículo LIBRE
Log::info('Vehículo detectado - LIBRE (sin reporte de robo)', [
'epc' => $epc,
'fast_id' => $fastId,
'vin' => $datosVehiculo['vin'],
'placa' => $datosVehiculo['placa']
]);
return [
'success' => true,
'tiene_reporte_robo' => false,
'estado' => 'LIBRE',
'vehiculo' => $datosVehiculo
];
}
private function verificarVehiculoRobado(string $epc, array $datosRedis): array
{
// Consultar REPUVE para verificar estado actual
$reporteRobo = $this->reporteRobo->consultarRobado(
$datosRedis['vin'],
$datosRedis['placa']
);
if (!$reporteRobo['tiene_reporte']) {
// No tiene reporte robo - RECUPERADO
$this->registrarRecuperacion($epc, $datosRedis);
Log::info('¡VEHÍCULO RECUPERADO!', [
'epc' => $epc,
'vin' => $datosRedis['vin'],
'placa' => $datosRedis['placa']
]);
return [
'success' => true,
'tiene_reporte_robo' => false,
'estado' => 'RECUPERADO',
'accion' => 'GUARDADO EN RECUPERADOS Y ELIMINADO DE ROBADOS',
'vehiculo' => $datosRedis
];
}
// Sigue robado → Actualizar contador en Redis
$this->actualizarDeteccionRedis($epc, $datosRedis);
Log::warning('Vehículo robado detectado nuevamente', [
'epc' => $epc,
'detecciones' => $datosRedis['detecciones'] + 1
]);
return [
'success' => true,
'tiene_reporte_robo' => true,
'estado' => 'ROBADO',
'accion' => 'ACTUALIZADO_EN_REDIS',
'vehiculo' => $datosRedis
];
}
private function guardarEnRedis(string $epc, array $datosEstatal, array $datosRobo)
{
$key = "vehiculo:robado:{$epc}";
$datos = [
'epc' => $epc,
'vin' => $datosEstatal['vin'],
'placa' => $datosEstatal['placa'],
'fecha_robo' => $datosRobo['fecha_robo'] ?? null,
'autoridad' => $datosRobo['autoridad'] ?? null,
'acta' => $datosRobo['acta'] ?? null,
'denunciante' => $datosRobo['denunciante'] ?? null,
'fecha_acta' => $datosRobo['fecha_acta'] ?? null,
'primera_deteccion' => now()->toIso8601String(),
'ultima_deteccion' => now()->toIso8601String(),
'detecciones' => 1
];
Redis::set($key, json_encode($datos));
}
private function actualizarDeteccionRedis(string $epc, array $datosActuales)
{
$key = "vehiculo:robado:{$epc}";
$datosActuales['ultima_deteccion'] = now()->toIso8601String();
$datosActuales['detecciones'] = ($datosActuales['detecciones'] ?? 0) + 1;
Redis::set($key, json_encode($datosActuales));
}
private function registrarRecuperacion(string $epc, array $datosRedis)
{
// Guardar en MySQL
Vehicle::create([
'epc' => $epc,
'vin' => $datosRedis['vin'],
'placa' => $datosRedis['placa'],
'fecha_robo' => $datosRedis['fecha_robo'],
'autoridad_robo' => $datosRedis['autoridad'],
'acta_robo' => $datosRedis['acta'],
'denunciante' => $datosRedis['denunciante'],
'fecha_recuperacion' => now(),
'fecha_acta' => $datosRedis['fecha_acta'] ?? null,
'datos_robo_original' => $datosRedis
]);
// Eliminar de Redis
Redis::del("vehiculo:robado:{$epc}");
} }
/**
* Listar todos los vehículos robados activos en Redis
*/
public function listarVehiculosRobados(): array public function listarVehiculosRobados(): array
{ {
$keys = Redis::keys('vehiculo:robado:*'); $keys = Redis::keys('vehiculo:robado:*');
@ -208,7 +92,128 @@ public function listarVehiculosRobados(): array
return $vehiculos; return $vehiculos;
} }
private function registrarDeteccion(string $epc, array $resultado, ?int $arcoId = null) /**
* Listar todas las detecciones del día desde Redis
* @param string|null $fecha Fecha en formato Y-m-d (opcional, por defecto hoy)
* @return array
*/
public function listarDeteccionesDelDia(?string $fecha = null): array
{
$fecha = $fecha ?? now()->format('Y-m-d');
$pattern = "deteccion:dia:{$fecha}:*";
$keys = Redis::keys($pattern);
$detecciones = [];
foreach ($keys as $key) {
$datos = Redis::get($key);
if ($datos) {
$detecciones[] = json_decode($datos, true);
}
}
// Ordenar por fecha de detección (más reciente primero)
usort($detecciones, function($a, $b) {
return strcmp($b['fecha_deteccion'], $a['fecha_deteccion']);
});
return $detecciones;
}
/**
* Obtener estadísticas de detecciones del día
* @param string|null $fecha Fecha en formato Y-m-d (opcional, por defecto hoy)
* @return array
*/
public function obtenerEstadisticasDelDia(?string $fecha = null): array
{
$detecciones = $this->listarDeteccionesDelDia($fecha);
$total = count($detecciones);
$robados = collect($detecciones)->where('tiene_reporte_robo', true)->count();
$libres = collect($detecciones)->where('tiene_reporte_robo', false)->count();
return [
'fecha' => $fecha ?? now()->format('Y-m-d'),
'total_detecciones' => $total,
'vehiculos_robados' => $robados,
'vehiculos_libres' => $libres,
'detecciones' => $detecciones
];
}
/**
* Consultar nuevo vehículo (no está en Redis de robados)
*/
private function consultarNuevoVehiculo(string $fastId): array
{
// Consultar con FastID (tag_number)
$datosVehiculo = $this->consultaRepuveCons->consultarVehiculoPorTag($fastId);
if (!$datosVehiculo || !$datosVehiculo['vin']) {
Log::warning('Vehículo NO encontrado.', [
'fast_id' => $fastId
]);
return [
'success' => false,
'message' => 'No se encontró información del vehículo.'
];
}
Log::info('Vehículo detectado - LIBRE (no está en Redis de robados)', [
'fast_id' => $fastId,
'vin' => $datosVehiculo['vin'],
'placa' => $datosVehiculo['placa']
]);
return [
'success' => true,
'tiene_reporte_robo' => false,
'estado' => 'LIBRE',
'vehiculo' => $datosVehiculo
];
}
/**
* Verificar vehículo robado (ya está en Redis)
*/
private function verificarVehiculoRobado(string $fastId, array $datosRedis): array
{
$this->actualizarDeteccionRedis($fastId, $datosRedis);
Log::warning('Vehículo robado detectado nuevamente', [
'fast_id' => $fastId,
'vin' => $datosRedis['vin'] ?? null,
'placa' => $datosRedis['placa'] ?? null,
'detecciones' => ($datosRedis['detecciones'] ?? 0) + 1
]);
return [
'success' => true,
'tiene_reporte_robo' => true,
'estado' => 'ROBADO',
'accion' => 'ACTUALIZADO_EN_REDIS',
'vehiculo' => $datosRedis
];
}
/**
* Actualizar contador de detecciones en Redis
*/
private function actualizarDeteccionRedis(string $fastId, array $datosActuales)
{
$key = "vehiculo:robado:{$fastId}";
$datosActuales['ultima_deteccion'] = now()->toIso8601String();
$datosActuales['detecciones'] = ($datosActuales['detecciones'] ?? 0) + 1;
Redis::set($key, json_encode($datosActuales));
}
/**
* Registrar detección en MySQL y Redis (detecciones del día)
*/
private function registrarDeteccion(string $fastId, array $resultado, ?int $arcoId = null)
{ {
if (!$resultado['success'] || !isset($resultado['vehiculo'])) { if (!$resultado['success'] || !isset($resultado['vehiculo'])) {
return; return;
@ -216,9 +221,10 @@ private function registrarDeteccion(string $epc, array $resultado, ?int $arcoId
$vehiculo = $resultado['vehiculo']; $vehiculo = $resultado['vehiculo'];
// Registrar en MySQL
Detection::create([ Detection::create([
'arco_id' => $arcoId, 'arco_id' => $arcoId,
'epc' => $epc, 'fast_id' => $fastId,
'vin' => $vehiculo['vin'] ?? null, 'vin' => $vehiculo['vin'] ?? null,
'placa' => $vehiculo['placa'] ?? null, 'placa' => $vehiculo['placa'] ?? null,
'marca' => $vehiculo['marca'] ?? null, 'marca' => $vehiculo['marca'] ?? null,
@ -226,42 +232,43 @@ private function registrarDeteccion(string $epc, array $resultado, ?int $arcoId
'color' => $vehiculo['color'] ?? null, 'color' => $vehiculo['color'] ?? null,
'fecha_deteccion' => now() 'fecha_deteccion' => now()
]); ]);
// Registrar en Redis (detecciones del día)
$this->registrarDeteccionDelDia($fastId, $vehiculo, $arcoId, $resultado);
} }
/** /**
* Consultar vehículo por tag_id * Registrar detección en Redis para el día actual
* Formato de key: deteccion:dia:YYYY-MM-DD:{fastId}:{timestamp}
* Expira automáticamente a las 23:59:59 del día
*/ */
public function consultarVehiculoPorTag(?string $epc = null, ?string $tagId = null) private function registrarDeteccionDelDia(string $fastId, array $vehiculo, ?int $arcoId, array $resultado)
{ {
try { $fecha = now()->format('Y-m-d');
// Validar que se proporcionó tag_id $timestamp = now()->timestamp;
if (empty($tagId)) { $key = "deteccion:dia:{$fecha}:{$fastId}:{$timestamp}";
Log::warning('VehicleService: No se proporcionó tag_id');
return null;
}
$vehiculoExterno = $this->consultaRepuveCons->consultarVehiculoPorTag($tagId);
if ($vehiculoExterno) { $datosDeteccion = [
Log::info('VehicleService: Vehículo encontrado', [ 'fast_id' => $fastId,
'tag_id' => $vehiculoExterno['tag_id'] ?? null, 'vin' => $vehiculo['vin'] ?? null,
'tag_number' => $vehiculoExterno['tag_number'] ?? null, 'placa' => $vehiculo['placa'] ?? null,
'vin' => $vehiculoExterno['vin'] ?? null 'marca' => $vehiculo['marca'] ?? null,
]); 'modelo' => $vehiculo['modelo'] ?? null,
} else { 'color' => $vehiculo['color'] ?? null,
Log::info('VehicleService: Vehículo no encontrado', [ 'arco_id' => $arcoId,
'tag_id' => $tagId 'estado' => $resultado['estado'] ?? 'LIBRE',
]); 'tiene_reporte_robo' => $resultado['tiene_reporte_robo'] ?? false,
} 'fecha_deteccion' => now()->toIso8601String(),
];
return $vehiculoExterno; // Guardar en Redis
Redis::set($key, json_encode($datosDeteccion));
} catch (\Exception $e) { // Calcular segundos hasta el final del día (23:59:59)
Log::error('VehicleService: Error en consulta', [ $finDelDia = now()->endOfDay();
'tag_id' => $tagId, $segundosHastaFinDelDia = $finDelDia->timestamp - now()->timestamp;
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString() // Establecer expiración automática al final del día
]); Redis::expire($key, $segundosHastaFinDelDia);
return null;
}
} }
} }

View File

@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
// Renombrar columna en tabla detections
Schema::table('detections', function (Blueprint $table) {
$table->renameColumn('epc', 'fast_id');
});
// Renombrar columna en tabla vehicles
Schema::table('vehicles', function (Blueprint $table) {
$table->renameColumn('epc', 'fast_id');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// Revertir cambio en tabla detections
Schema::table('detections', function (Blueprint $table) {
$table->renameColumn('fast_id', 'epc');
});
// Revertir cambio en tabla vehicles
Schema::table('vehicles', function (Blueprint $table) {
$table->renameColumn('fast_id', 'epc');
});
}
};

View File

@ -33,6 +33,7 @@
Route::get('/vehicles/robados', [VehicleController::class, 'listarRobados']); Route::get('/vehicles/robados', [VehicleController::class, 'listarRobados']);
Route::get('/vehicles', [VehicleController::class, 'listarRecuperados']); Route::get('/vehicles', [VehicleController::class, 'listarRecuperados']);
Route::get('/vehicles/detecciones', [VehicleController::class, 'listarDetecciones']); Route::get('/vehicles/detecciones', [VehicleController::class, 'listarDetecciones']);
Route::get('/vehicles/detecciones/dia', [VehicleController::class, 'listarDeteccionesDelDia']);
Route::get('/vehicles/robado', [VehicleController::class, 'buscarVehiculoRobado']); Route::get('/vehicles/robado', [VehicleController::class, 'buscarVehiculoRobado']);
// Rutas de Arcos RFID // Rutas de Arcos RFID