ADD: Implementa servicios para consulta y registro de vehículos robados

This commit is contained in:
Juan Felipe Zapata Moreno 2025-12-19 15:06:03 -06:00
parent 80bd249176
commit f648ea39eb
9 changed files with 940 additions and 3 deletions

View File

@ -0,0 +1,308 @@
<?php namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Vehicle;
use App\Services\VehicleService;
use App\Services\ConsultaEstatalService;
use App\Services\ReporteRoboService;
use Illuminate\Http\JsonResponse;
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,
private ConsultaEstatalService $consultaEstatal,
private ReporteRoboService $reporteRobo
) {}
/**
* Consultar y registrar vehículo por PLACA o VIN
*/
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 response()->json([
'success' => false,
'message' => 'Datos inválidos',
'errors' => $validator->errors()
], 422);
}
try {
$placa = $request->placa;
$vin = $request->vin;
// Consultar padrón estatal (obtener datos completos del vehículo)
Log::info('Consultando padrón estatal', ['placa' => $placa, 'vin' => $vin]);
// Si viene VIN, usar VIN, si no usar placa
$criterio = $vin ?: $placa;
$datosEstatal = $this->consultaEstatal->consultarPorEpc($criterio);
if (!$datosEstatal || (!$datosEstatal['vin'] && !$datosEstatal['placa'])) {
return response()->json([
'success' => false,
'message' => 'No se encontró información del vehículo en el padrón estatal'
], 404);
}
// Obtener VIN y Placa completos
$vinCompleto = $datosEstatal['vin'] ?: $vin;
$placaCompleta = $datosEstatal['placa'] ?: $placa;
Log::info('Datos del padrón estatal obtenidos', [
'vin' => $vinCompleto,
'placa' => $placaCompleta
]);
// Consultar REPUVE
$reporteRobo = $this->reporteRobo->consultarPorVin($vinCompleto, $placaCompleta);
$tieneReporte = $reporteRobo['tiene_reporte'] ?? false;
// Si tiene reporte de robo → Guardar en Redis
if ($tieneReporte) {
$epc = 'MANUAL_' . ($vinCompleto ?: $placaCompleta);
$this->guardarEnRedis($epc, $datosEstatal, $reporteRobo['datos']);
Log::warning('¡VEHÍCULO CON REPORTE DE ROBO REGISTRADO!', [
'vin' => $vinCompleto,
'placa' => $placaCompleta,
'autoridad' => $reporteRobo['datos']['autoridad'] ?? null
]);
return response()->json([
'success' => true,
'tiene_reporte_robo' => true,
'message' => '¡ALERTA! El vehículo tiene reporte de robo',
'vehiculo' => [
'vin' => $vinCompleto,
'placa' => $placaCompleta,
],
'reporte_robo' => $reporteRobo['datos']
]);
}
// No tiene reporte de robo
Log::info('Vehículo consultado sin reporte de robo', [
'vin' => $vinCompleto,
'placa' => $placaCompleta
]);
return response()->json([
'success' => true,
'tiene_reporte_robo' => false,
'message' => 'Vehículo sin reporte de robo',
'vehiculo' => [
'vin' => $vinCompleto,
'placa' => $placaCompleta,
]
]);
} catch (\Exception $e) {
Log::error('Error al consultar vehículo', [
'placa' => $request->placa,
'vin' => $request->vin,
'error' => $e->getMessage()
]);
return response()->json([
'success' => false,
'message' => 'Error al consultar vehículo',
'error' => $e->getMessage()
], 500);
}
}
/**
* 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
*/
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 response()->json([
'success' => false,
'message' => 'Datos inválidos',
'errors' => $validator->errors()
], 422);
}
try {
$placa = $request->placa;
$vin = $request->vin;
Log::info('Buscando vehículo robado para recuperar', ['placa' => $placa, 'vin' => $vin]);
// 1. Buscar en Redis (vehículos robados activos)
$vehiculoEncontrado = $this->buscarEnRedis($vin, $placa);
if (!$vehiculoEncontrado) {
return response()->json([
'success' => false,
'message' => 'El vehículo no se encuentra en la lista de robados activos'
], 404);
}
$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
$vehiculoRecuperado = 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_acta' => $datosRedis['fecha_acta'] ?? null,
'fecha_recuperacion' => now(),
'datos_robo_original' => $datosRedis
]);
// 3. Eliminar de Redis
Redis::del("vehiculo:robado:{$epc}");
Log::info('Vehículo registrado como recuperado', [
'id' => $vehiculoRecuperado->id,
'vin' => $vehiculoRecuperado->vin,
'placa' => $vehiculoRecuperado->placa
]);
return response()->json([
'success' => true,
'message' => 'Vehículo registrado como recuperado exitosamente',
'vehiculo' => [
'id' => $vehiculoRecuperado->id,
'epc' => $vehiculoRecuperado->epc,
'vin' => $vehiculoRecuperado->vin,
'placa' => $vehiculoRecuperado->placa,
'fecha_robo' => $vehiculoRecuperado->fecha_robo,
'fecha_recuperacion' => $vehiculoRecuperado->fecha_recuperacion,
'autoridad_robo' => $vehiculoRecuperado->autoridad_robo,
'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 response()->json([
'success' => false,
'message' => 'Error al registrar vehículo como recuperado',
'error' => $e->getMessage()
], 500);
}
}
/**
* Buscar vehículo en Redis por VIN o Placa
*/
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 EPC del key
$epc = str_replace('vehiculo:robado:', '', $key);
return [
'epc' => $epc,
'datos' => $vehiculo
];
}
}
return null;
}
/**
* Listar todos los vehículos robados activos
* GET /api/vehicles/robados
*/
public function listarRobados(): JsonResponse
{
try {
$vehiculos = $this->vehicleService->listarVehiculosRobados();
return response()->json([
'success' => true,
'total' => count($vehiculos),
'vehiculos' => $vehiculos
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'Error al listar vehículos robados',
'error' => $e->getMessage()
], 500);
}
}
}

31
app/Models/Vehicle.php Normal file
View File

@ -0,0 +1,31 @@
<?php namespace App\Models;
/**
* @copyright (c) 2025 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
*/
use Illuminate\Database\Eloquent\Model;
class Vehicle extends Model
{
protected $fillable = [
'epc',
'vin',
'placa',
'fecha_robo',
'autoridad_robo',
'acta_robo',
'denunciante',
'fecha_acta',
'fecha_recuperacion',
'datos_robo_original'
];
protected $casts = [
'fecha_robo' => 'date',
'fecha_acta' => 'date',
'fecha_recuperacion' => 'datetime',
'datos_robo_original' => 'array',
];
}

View File

@ -0,0 +1,133 @@
<?php
namespace App\Services;
use Exception;
use Illuminate\Support\Facades\Log;
class ConsultaEstatalService
{
private string $soapUrl;
public function __construct()
{
$this->soapUrl = config('services.padron_estatal.url');
}
/**
* Consulta vehículo
*/
public function consultarPorEpc(string $epc): ?array
{
try {
$datos = $this->consultarPadron('niv', $epc);
return [
'placa' => $datos['placa'] ?? null,
'vin' => $datos['niv'] ?? null,
];
} catch (Exception $e) {
Log::error("Error consultando padrón por EPC: {$epc} - " . $e->getMessage());
return null;
}
}
/**
* Consulta el padrón vehicular estatal vía SOAP
*/
private function consultarPadron(string $tipo, string $valor): array
{
// Construir el Data en formato JSON
$data = json_encode([
'tipo' => $tipo,
'valor' => $valor
]);
// Construir el cuerpo SOAP
$soapBody = <<<XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://mx/tgc/ConsultaPadronVehicular.wsdl">
<soapenv:Header/>
<soapenv:Body>
<wsdl:getVehiculosRepuve>
<Data>{$data}</Data>
</wsdl:getVehiculosRepuve>
</soapenv:Body>
</soapenv:Envelope>
XML;
// Configurar cURL
$ch = curl_init($this->soapUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $soapBody);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: text/xml; charset=utf-8',
'SOAPAction: ""',
'Content-Length: ' . strlen($soapBody)
]);
try {
// Ejecutar la petición
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
if ($error) {
throw new Exception("Error en la petición: {$error}");
}
if ($httpCode !== 200) {
throw new Exception("Error HTTP {$httpCode}");
}
// Parsear la respuesta
return $this->parsearRespuesta($response);
} finally {
unset($ch);
}
}
/**
* Parsea la respuesta y extrae los datos del vehículo
*/
private function parsearRespuesta(string $soapResponse): array
{
// Extraer el contenido del tag <result>
preg_match('/<result>(.*?)<\/result>/s', $soapResponse, $matches);
if (!isset($matches[1])) {
throw new Exception("No se pudo extraer el resultado del padrón estatal");
}
$jsonContent = trim($matches[1]);
// Decodificar el JSON
$result = json_decode($jsonContent, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception("Error al decodificar JSON: " . json_last_error_msg());
}
if (!isset($result[0])) {
throw new Exception("Formato de respuesta inesperado");
}
$data = $result[0];
// Verificar si hay error
if ($data['error'] !== 0) {
throw new Exception("Error en consulta: código {$data['error']}");
}
// Verificar si hay datos
if (!isset($data['datos'][0])) {
throw new Exception("No se encontraron datos del vehículo");
}
return $data['datos'][0];
}
}

View File

@ -0,0 +1,187 @@
<?php
namespace App\Services;
use Exception;
use Illuminate\Support\Facades\Log;
class ReporteRoboService
{
private string $baseUrl;
private string $roboEndpoint;
private string $username;
private string $password;
public function __construct()
{
$this->baseUrl = config('services.repuve_federal.base_url');
$this->roboEndpoint = config('services.repuve_federal.robo_endpoint');
$this->username = config('services.repuve_federal.username');
$this->password = config('services.repuve_federal.password');
}
public function consultarPorVin(?string $vin = null, ?string $placa = null): array
{
try {
if (empty($vin) && empty($placa)) {
Log::warning('ReporteRoboService: No se proporcionó VIN ni PLACA');
return [
'tiene_reporte' => false,
'datos' => [],
'error' => 'Debe proporcionar al menos VIN o PLACA'
];
}
$url = $this->baseUrl . $this->roboEndpoint;
// Construir arg2 según los parámetros
if (!empty($vin) && !empty($placa)) {
$arg2 = $vin . '|' . $placa . str_repeat('|', 5);
} elseif (!empty($vin)) {
$arg2 = $vin . str_repeat('|', 7);
} else {
$arg2 = '||' . $placa . str_repeat('|', 5);
}
Log::info('ReporteRoboService: Consultando REPUVE', [
'vin' => $vin,
'placa' => $placa
]);
$soapBody = <<<XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://consultaRpv.org/wsdl">
<soapenv:Header/>
<soapenv:Body>
<wsdl:doConsRepRobo>
<arg0>{$this->username}</arg0>
<arg1>{$this->password}</arg1>
<arg2>{$arg2}</arg2>
</wsdl:doConsRepRobo>
</soapenv:Body>
</soapenv:Envelope>
XML;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $soapBody);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: text/xml; charset=utf-8',
'SOAPAction: "doConsRepRobo"',
'Content-Length: ' . strlen($soapBody),
]);
try {
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
if ($error) {
Log::error('ReporteRoboService: Error de conexión', ['error' => $error]);
return [
'tiene_reporte' => false,
'datos' => [],
'error' => 'Error de conexión con REPUVE'
];
}
if ($httpCode !== 200) {
Log::error('ReporteRoboService: HTTP error', ['http_code' => $httpCode]);
return [
'tiene_reporte' => false,
'datos' => [],
'error' => "Error HTTP {$httpCode}"
];
}
return $this->parseRoboResponse($response, $vin ?? $placa);
} finally {
unset($ch);
}
} catch (Exception $e) {
Log::error('ReporteRoboService: Excepción', ['message' => $e->getMessage()]);
return [
'tiene_reporte' => false,
'datos' => [],
'error' => $e->getMessage()
];
}
}
/**
* Parsea la respuesta del servicio de robo
*/
private function parseRoboResponse(string $soapResponse, string $valor): array
{
// Extraer contenido del tag <return>
preg_match('/<return>(.*?)<\/return>/s', $soapResponse, $matches);
if (!isset($matches[1])) {
Log::error('ReporteRoboService: No se encontró tag <return>');
return [
'tiene_reporte' => false,
'datos' => [],
'error' => 'Respuesta SOAP inválida'
];
}
$contenido = trim($matches[1]);
// Verificar si hay error (ERR: o ERROR:)
if (preg_match('/(ERR|ERROR|err|error):(-?\d+)/i', $contenido, $errorMatch)) {
$errorCode = $errorMatch[2];
Log::warning('ReporteRoboService: Error del servicio', ['error_code' => $errorCode]);
return [
'tiene_reporte' => false,
'datos' => ['error_code' => $errorCode],
'error' => "Error REPUVE código {$errorCode}"
];
}
// Si empieza con OK:, parsear los datos
if (str_starts_with($contenido, 'OK:')) {
$datos = str_replace('OK:', '', $contenido);
$valores = explode('|', $datos);
// 1 = robado, 0 = no robado
$indicador = $valores[0] ?? '0';
$tieneReporte = ($indicador === '1');
$datosRobo = [
'indicador' => $indicador,
'fecha_robo' => $valores[1] ?? null,
'placa' => $valores[2] ?? null,
'vin' => $valores[3] ?? null,
'autoridad' => $valores[4] ?? null,
'acta' => $valores[5] ?? null,
'denunciante' => $valores[6] ?? null,
'fecha_acta' => $valores[7] ?? null,
];
if ($tieneReporte) {
Log::warning('ReporteRoboService: ¡VEHÍCULO ROBADO DETECTADO!', [
'vin' => $datosRobo['vin'],
'placa' => $datosRobo['placa'],
'autoridad' => $datosRobo['autoridad']
]);
}
return [
'tiene_reporte' => $tieneReporte,
'datos' => $datosRobo
];
}
Log::error('ReporteRoboService: Formato no reconocido', ['contenido' => $contenido]);
return [
'tiene_reporte' => false,
'datos' => [],
'error' => 'Formato de respuesta no reconocido'
];
}
}

View File

@ -0,0 +1,187 @@
<?php
namespace App\Services;
use App\Models\Vehicle;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Log;
class VehicleService
{
public function __construct(
private ConsultaEstatalService $consultaEstatal,
private ReporteRoboService $reporteRobo
) {}
public function procesarDeteccion(string $epc, ?int $arcoId = null): array
{
$key = "vehiculo:robado:{$epc}";
// Verificar si está en Redis
$enRedis = Redis::get($key);
if ($enRedis) {
// Ya está marcado como robado, verificar si sigue así
return $this->verificarVehiculoRobado($epc, $arcoId, json_decode($enRedis, true));
}
// No está en Redis, consultar servicios
return $this->consultarNuevoVehiculo($epc, $arcoId);
}
private function consultarNuevoVehiculo(string $epc, ?int $arcoId): array
{
// Consultar padrón estatal
$datosEstatal = $this->consultaEstatal->consultarPorEpc($epc);
if (!$datosEstatal || !$datosEstatal['vin']) {
return [
'success' => false,
'message' => 'No se encontró información del vehículo'
];
}
// Consultar REPUVE
$reporteRobo = $this->reporteRobo->consultarPorVin(
$datosEstatal['vin'],
$datosEstatal['placa']
);
if ($reporteRobo['tiene_reporte']) {
// Está robado → Guardar en Redis
$this->guardarEnRedis($epc, $datosEstatal, $reporteRobo['datos']);
Log::warning('¡VEHÍCULO ROBADO DETECTADO!', [
'epc' => $epc,
'vin' => $datosEstatal['vin'],
'placa' => $datosEstatal['placa']
]);
return [
'success' => true,
'tiene_reporte_robo' => true,
'estado' => 'ROBADO',
'accion' => 'GUARDADO_EN_REDIS',
'vehiculo' => array_merge($datosEstatal, $reporteRobo['datos'])
];
}
// No está robado, no hacer nada
return [
'success' => true,
'tiene_reporte_robo' => false,
'estado' => 'LIBRE',
'vehiculo' => $datosEstatal
];
}
private function verificarVehiculoRobado(string $epc, ?int $arcoId, array $datosRedis): array
{
// Consultar REPUVE para verificar estado actual
$reporteRobo = $this->reporteRobo->consultarPorVin(
$datosRedis['vin'],
$datosRedis['placa']
);
if (!$reporteRobo['tiene_reporte']) {
// No tiene reporte robo
$this->registrarRecuperacion($epc, $arcoId, $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_MYSQL_Y_ELIMINADO_DE_REDIS',
'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): 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' => 1
];
Redis::set($key, json_encode($datos));
}
private function actualizarDeteccionRedis(string $epc, array $datosActuales): void
{
$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, ?int $arcoId, array $datosRedis): void
{
// 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}");
}
public function listarVehiculosRobados(): array
{
$keys = Redis::keys('vehiculo:robado:*');
$vehiculos = [];
foreach ($keys as $key) {
$datos = Redis::get($key);
if ($datos) {
$vehiculos[] = json_decode($datos, true);
}
}
return $vehiculos;
}
}

View File

@ -35,4 +35,16 @@
], ],
], ],
'repuve_federal' => [
'base_url' => env('REPUVE_FED_BASE_URL'),
'robo_endpoint' => '/jaxws-consultarpv/ConsultaRpv',
'inscripcion_endpoint' => '/jaxrpc-inscripcion/Inscripcion?WSDLs=',
'username' => env('REPUVE_FED_USERNAME'),
'password' => env('REPUVE_FED_PASSWORD'),
],
'padron_estatal' => [
'url' => env('REPUVE_EST_URL'),
],
]; ];

View File

@ -0,0 +1,46 @@
<?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
{
Schema::create('vehicles', function (Blueprint $table) {
$table->id();
// Identificadores del vehículo
$table->string('epc')->unique();
$table->string('vin')->nullable();
$table->string('placa')->nullable();
// Datos del reporte de robo
$table->date('fecha_robo')->nullable();
$table->string('autoridad_robo')->nullable();
$table->string('acta_robo')->nullable();
$table->string('denunciante')->nullable();
$table->date('fecha_acta')->nullable();
// Datos de recuperación
$table->timestamp('fecha_recuperacion')->nullable();
// Datos completos del robo original (JSON) - Para auditoría
$table->json('datos_robo_original')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('vehicles');
}
};

View File

@ -66,11 +66,39 @@ services:
- arcos-network - arcos-network
mem_limit: 400m mem_limit: 400m
redis:
image: redis:alpine
ports:
- "${REDIS_PORT}:6379"
volumes:
- redis_data:/data
networks:
- arcos-network
mem_limit: 256m
healthcheck:
test: ["CMD", "redis-cli", "ping"]
timeout: 5s
retries: 5
redis-commander:
image: rediscommander/redis-commander:latest
environment:
- ${REDIS_HOST}:redis:6379
ports:
- "${REDIS_COMMANDER_PORT}:8081"
networks:
- arcos-network
mem_limit: 256m
depends_on:
- redis
volumes: volumes:
nginx_data: nginx_data:
driver: local driver: local
mysql_data: mysql_data:
driver: local driver: local
redis_data:
driver: local
networks: networks:
arcos-network: arcos-network:

View File

@ -1,23 +1,28 @@
<?php <?php
use App\Http\Controllers\Api\VehicleController;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
/** /**
* Rutas del núcleo de la aplicación. * Rutas del núcleo de la aplicación.
* *
* Se recomienda que no se modifiquen estas rutas a menos que sepa lo que está haciendo. * Se recomienda que no se modifiquen estas rutas a menos que sepa lo que está haciendo.
*/ */
require('core.php'); require('core.php');
/** /**
* Rutas de tu aplicación. * Rutas de tu aplicación.
* *
* Estas rutas son de la aplicación AP I que desarrollarás. Siéntete libre de agregar lo que consideres necesario. * Estas rutas son de la aplicación AP I que desarrollarás. Siéntete libre de agregar lo que consideres necesario.
* Procura revisar que no existan rutas que entren en conflicto con las rutas del núcleo. * Procura revisar que no existan rutas que entren en conflicto con las rutas del núcleo.
*/ */
/** Rutas protegidas (requieren autenticación) */ /** Rutas protegidas (requieren autenticación) */
Route::middleware('auth:api')->group(function() { Route::middleware('auth:api')->group(function() {
// Tus rutas protegidas
Route::post('/vehicles/consultar', [VehicleController::class, 'consultarVehiculo']);
Route::post('/vehicles/recuperar', [VehicleController::class, 'recuperarVehiculo']);
Route::get('/vehicles/robados', [VehicleController::class, 'listarRobados']);
}); });
/** Rutas públicas */ /** Rutas públicas */