ADD: Implementa búsqueda de vehículos por tag_id y agrega configuración para API de Repuve Constancia

This commit is contained in:
Juan Felipe Zapata Moreno 2025-12-29 16:40:22 -06:00
parent ccc4449d78
commit 19e9491e04
7 changed files with 313 additions and 37 deletions

View File

@ -75,6 +75,7 @@ AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
# API REPUVE FEDERAL
REPUVE_FED_BASE_URL=
REPUVE_FED_USERNAME=
REPUVE_FED_PASSWORD=
@ -82,6 +83,14 @@ REPUVE_FED_PASSWORD=
# REPUVE ESTATAL
REPUVE_EST_URL=
# API REPUVE CONSTANCIAS
REPUVE_CONSTANCIA_BASE_URL=
REPUVE_CONSTANCIA_LOGIN_ENDPOINT=
REPUVE_CONSTANCIA_CONSULTA_ENDPOINT=
REPUVE_CONSTANCIA_EMAIL=
REPUVE_CONSTANCIA_PASSWORD=
REPUVE_CONSTANCIA_TOKEN_TTL=3600
REVERB_APP_ID=
REVERB_APP_KEY=
REVERB_APP_SECRET=

View File

@ -56,7 +56,7 @@ public function consultarVehiculo(Request $request): JsonResponse
if (!$vehiculo) {
return ApiResponse::NOT_FOUND->response([
'success' => false,
'message' => 'No se encontró el vehículo en la base de datos'
'message' => 'No se encontró el vehículo'
]);
}
@ -114,31 +114,6 @@ public function consultarVehiculo(Request $request): JsonResponse
]);
}
/**
* Guardar vehículo robado en Redis
*/
private function guardarEnRedis(string $epc, array $datosEstatal, array $datosRobo): void
{
$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' => 0,
'origen' => 'CONSULTA_MANUAL'
];
Redis::set($key, json_encode($datos));
}
/**
* Dar de baja (registrar como recuperado) un vehículo por PLACA o VIN
*/
@ -400,4 +375,32 @@ public function buscarVehiculoRobado(Request $request)
'vehiculo' => $vehiculoEncontrado['datos']
]);
}
/**
* Buscar vehículo por tag_id (tag_number)
* GET /api/vehicles/buscar
*/
public function buscarPorTag(Request $request)
{
$validated = $request->validate([
'tag_id' => 'required|string',
]);
$resultado = $this->vehicleService->consultarVehiculoPorTag(
epc: null,
tagId: $validated['tag_id']
);
if (!$resultado) {
return ApiResponse::NOT_FOUND->response([
'success' => false,
'message' => 'No se encontró el vehículo'
]);
}
return ApiResponse::OK->response([
'success' => true,
'vehiculo' => $resultado
]);
}
}

View File

@ -0,0 +1,217 @@
<?php
namespace App\Services;
use Exception;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
class ConsultaRepuveConstancia
{
private string $baseUrl;
private string $loginEndpoint;
private string $vehiculosEndpoint;
private string $email;
private string $password;
private int $tokenTtl;
public function __construct()
{
$this->baseUrl = config('services.vehiculos_externos.base_url');
$this->loginEndpoint = config('services.vehiculos_externos.login_endpoint');
$this->vehiculosEndpoint = config('services.vehiculos_externos.vehiculos_endpoint');
$this->email = config('services.vehiculos_externos.email');
$this->password = config('services.vehiculos_externos.password');
$this->tokenTtl = config('services.vehiculos_externos.token_ttl', 3600);
}
/**
* Consultar vehículo por tag_number
*
*/
public function consultarVehiculoPorTag(?string $tagNumber = null)
{
try {
// solo busca por tag_number
if (empty($tagNumber)) {
Log::warning('ConsultaRepuveConstancia: No se proporcionó tag_number');
return null;
}
// Obtener token de autenticación
$token = $this->obtenerToken();
if (!$token) {
Log::error('ConsultaRepuveConstancia: No se pudo obtener token de autenticación');
return null;
}
// Consultar vehículos con filtro tag_number
$url = $this->baseUrl . $this->vehiculosEndpoint;
Log::info('ConsultaRepuveConstancia: Consultando', [
'url' => $url,
'tag_number' => $tagNumber
]);
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . $token,
'Accept' => 'application/json',
])->timeout(30)->get($url, [
'tag_number' => $tagNumber
]);
if (!$response->successful()) {
Log::error('ConsultaRepuveConstancia: Error en petición HTTP', [
'status' => $response->status(),
'body' => $response->body()
]);
return null;
}
$data = $response->json();
// Validar estructura de respuesta
if (!isset($data['status']) || $data['status'] !== 'success' || !isset($data['data']['records']['data'])) {
Log::warning('ConsultaRepuveConstancia: Respuesta con estructura inválida', [
'response' => $data
]);
return null;
}
// recibir solo el vehículo buscado (o vacío)
$vehiculos = $data['data']['records']['data'];
if (empty($vehiculos)) {
Log::info('ConsultaRepuveConstancia: Vehículo no encontrado', [
'tag_number' => $tagNumber
]);
return null;
}
$vehiculoEncontrado = $vehiculos[0];
// Transformar datos al formato esperado
return $this->transformarDatosVehiculo($vehiculoEncontrado);
} catch (Exception $e) {
Log::error('ConsultaRepuveConstancia: Error al consultar vehículo', [
'tag_number' => $tagNumber,
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return null;
}
}
/**
* Obtener token JWT
*/
private function obtenerToken()
{
$cacheKey = 'vehiculos_externos_jwt_token';
// Intentar obtener token de caché
$token = Cache::get($cacheKey);
if ($token) {
Log::debug('ConsultaRepuveConstancia: Token obtenido de caché');
return $token;
}
// Si no está en caché, autenticar
try {
$url = $this->baseUrl . $this->loginEndpoint;
Log::info('ConsultaRepuveConstancia: Autenticando', [
'url' => $url,
'email' => $this->email
]);
$response = Http::timeout(30)->post($url, [
'email' => $this->email,
'password' => $this->password,
]);
if (!$response->successful()) {
Log::error('ConsultaRepuveConstancia: Error al autenticar', [
'status' => $response->status(),
'body' => $response->body()
]);
return null;
}
$data = $response->json();
// Validar estructura de respuesta
if (!isset($data['status']) || $data['status'] !== 'success' || !isset($data['data']['token'])) {
Log::error('ConsultaRepuveConstancia: Respuesta de login inválida', [
'response' => $data
]);
return null;
}
$token = $data['data']['token'];
// Guardar en caché (hora por defecto)
Cache::put($cacheKey, $token, $this->tokenTtl);
Log::info('ConsultaRepuveConstancia: Token obtenido y guardado en caché');
return $token;
} catch (Exception $e) {
Log::error('ConsultaRepuveConstancia: Excepción al obtener token', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return null;
}
}
/**
* Transformar datos del vehículo al formato esperado
*/
private function transformarDatosVehiculo(array $record)
{
$vehiculo = $record['vehicle'];
$tag = $vehiculo['tag'] ?? [];
$owner = $vehiculo['owner'] ?? [];
return [
'tag_number' => $tag['tag_number'] ?? null,
'folio_tag' => $tag['folio'] ?? null,
'vin' => $vehiculo['niv'] ?? null,
'placa' => $vehiculo['placa'] ?? null,
'marca' => $vehiculo['marca'] ?? null,
'modelo' => $vehiculo['modelo'] ?? null,
'linea' => $vehiculo['linea'] ?? null,
'sublinea' => $vehiculo['sublinea'] ?? null,
'color' => $vehiculo['color'] ?? null,
'numero_motor' => $vehiculo['numero_motor'] ?? null,
'clase_veh' => $vehiculo['clase_veh'] ?? null,
'tipo_servicio' => $vehiculo['tipo_servicio'] ?? null,
'rfv' => $vehiculo['rfv'] ?? null,
'nrpv' => $vehiculo['nrpv'] ?? null,
'reporte_robo' => $vehiculo['reporte_robo'] ?? false,
'propietario' => [
'id' => $owner['id'] ?? null,
'nombre_completo' => $owner['full_name'] ?? null,
'rfc' => $owner['rfc'] ?? null,
'curp' => $owner['curp'] ?? null,
'telefono' => $owner['telefono'] ?? null,
'direccion' => $owner['address'] ?? null,
],
'tag_status' => $tag['status']['name'] ?? null,
];
}
/**
* Limpiar token de caché (útil para forzar re-autenticación)
*/
public function limpiarToken()
{
Cache::forget('vehiculos_externos_jwt_token');
Log::info('ConsultaRepuveConstancia: Token eliminado de caché');
}
}

View File

@ -20,7 +20,7 @@ public function __construct()
$this->password = config('services.repuve_federal.password');
}
public function consultarPorVin(?string $vin = null, ?string $placa = null): array
public function consultarPorVin(?string $vin = null, ?string $placa = null)
{
try {
if (empty($vin) && empty($placa)) {
@ -115,13 +115,13 @@ public function consultarPorVin(?string $vin = null, ?string $placa = null): arr
/**
* Parsea la respuesta del servicio de robo
*/
private function parseRoboResponse(string $soapResponse, string $valor): array
private function parseRoboResponse(string $soapResponse, string $valor)
{
// Extraer contenido del tag <return>
// Extraer contenido
preg_match('/<return>(.*?)<\/return>/s', $soapResponse, $matches);
if (!isset($matches[1])) {
Log::error('ReporteRoboService: No se encontró tag <return>');
Log::error('ReporteRoboService:');
return [
'tiene_reporte' => false,
'datos' => [],
@ -177,7 +177,7 @@ private function parseRoboResponse(string $soapResponse, string $valor): array
];
}
Log::error('ReporteRoboService: Formato no reconocido', ['contenido' => $contenido]);
Log::error('ReporteRoboService:', ['contenido' => $contenido]);
return [
'tiene_reporte' => false,
'datos' => [],

View File

@ -11,7 +11,8 @@ class VehicleService
{
public function __construct(
private ConsultaEstatalService $consultaEstatal,
private ReporteRoboService $reporteRobo
private ReporteRoboService $reporteRobo,
private ConsultaRepuveConstancia $consultaRepuveCons
) {}
public function procesarDeteccion(string $epc, ?int $arcoId = null): array
@ -124,7 +125,7 @@ private function verificarVehiculoRobado(string $epc, ?int $arcoId, array $datos
];
}
private function guardarEnRedis(string $epc, array $datosEstatal, array $datosRobo): void
private function guardarEnRedis(string $epc, array $datosEstatal, array $datosRobo)
{
$key = "vehiculo:robado:{$epc}";
@ -145,7 +146,7 @@ private function guardarEnRedis(string $epc, array $datosEstatal, array $datosRo
Redis::set($key, json_encode($datos));
}
private function actualizarDeteccionRedis(string $epc, array $datosActuales): void
private function actualizarDeteccionRedis(string $epc, array $datosActuales)
{
$key = "vehiculo:robado:{$epc}";
@ -155,7 +156,7 @@ private function actualizarDeteccionRedis(string $epc, array $datosActuales): vo
Redis::set($key, json_encode($datosActuales));
}
private function registrarRecuperacion(string $epc, ?int $arcoId, array $datosRedis): void
private function registrarRecuperacion(string $epc, ?int $arcoId, array $datosRedis)
{
// Guardar en MySQL
Vehicle::create([
@ -190,7 +191,7 @@ public function listarVehiculosRobados(): array
return $vehiculos;
}
private function registrarDeteccion(string $epc, array $resultado): void
private function registrarDeteccion(string $epc, array $resultado)
{
if (!$resultado['success'] || !isset($resultado['vehiculo'])) {
return;
@ -208,4 +209,41 @@ private function registrarDeteccion(string $epc, array $resultado): void
'fecha_deteccion' => now()
]);
}
/**
* Consultar vehículo por tag_id
*/
public function consultarVehiculoPorTag(?string $epc = null, ?string $tagId = null)
{
try {
// Validar que se proporcionó tag_id
if (empty($tagId)) {
Log::warning('VehicleService: No se proporcionó tag_id');
return null;
}
$vehiculoExterno = $this->consultaRepuveCons->consultarVehiculoPorTag($tagId);
if ($vehiculoExterno) {
Log::info('VehicleService: Vehículo encontrado', [
'tag_id' => $vehiculoExterno['tag_id'] ?? null,
'tag_number' => $vehiculoExterno['tag_number'] ?? null,
'vin' => $vehiculoExterno['vin'] ?? null
]);
} else {
Log::info('VehicleService: Vehículo no encontrado', [
'tag_id' => $tagId
]);
}
return $vehiculoExterno;
} catch (\Exception $e) {
Log::error('VehicleService: Error en consulta', [
'tag_id' => $tagId,
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return null;
}
}
}

View File

@ -47,4 +47,13 @@
'url' => env('REPUVE_EST_URL'),
],
'vehiculos_externos' => [
'base_url' => env('REPUVE_CONSTANCIA_BASE_URL'),
'login_endpoint' => env('REPUVE_CONSTANCIA_LOGIN_ENDPOINT'),
'vehiculos_endpoint' => env('REPUVE_CONSTANCIA_CONSULTA_ENDPOINT'),
'email' => env('REPUVE_CONSTANCIA_EMAIL'),
'password' => env('REPUVE_CONSTANCIA_PASSWORD'),
'token_ttl' => env('REPUVE_CONSTANCIA_TOKEN_TTL'),
],
];

View File

@ -27,7 +27,7 @@
Route::get('/vehicles', [VehicleController::class, 'listarRecuperados']);
Route::get('/vehicles/detecciones', [VehicleController::class, 'listarDetecciones']);
Route::get('/vehicles/robado', [VehicleController::class, 'buscarVehiculoRobado']);
Route::get('/vehicles/buscar', [VehicleController::class, 'buscarPorTag']);
});
/** Rutas públicas */