arcos-backend/app/Http/Controllers/Api/VehicleController.php
2025-12-22 12:52:00 -06:00

404 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 y registrar vehículo por PLACA o VIN (Alta de vehículo robado)
*/
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::INTERNAL_ERROR->response([
'success' => false,
'message' => 'Datos inválidos',
'errors' => $validator->errors()
]);
}
$placa = $request->placa;
$vin = $request->vin;
// Buscar vehículo en vehicle_fakes
$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'
]);
}
// Generar EPC
$epc = 'E280117000000' . $vehiculo->vin;
// Verificar si ya está en Redis
$key = "vehiculo:robado:{$placa}-{$vin}";
if (Redis::exists($key)) {
return ApiResponse::BAD_REQUEST->response([
'success' => false,
'message' => 'El vehículo ya está registrado como robado'
]);
}
// Guardar en Redis como robado
$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,
'fecha_robo' => now()->format('Y-m-d'),
'acta' => 'MANUAL-' . now()->format('Ymd-His'),
'denunciante' => 'SISTEMA',
'fecha_acta' => now()->format('Y-m-d'),
'primera_deteccion' => now()->toIso8601String(),
'ultima_deteccion' => now()->toIso8601String(),
];
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([
'success' => true,
'message' => 'Vehículo registrado como robado exitosamente',
'vehiculo' => [
'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
]
]);
}
/**
* 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 ApiResponse::BAD_REQUEST->response([
'success' => false,
'message' => 'Datos inválidos',
'errors' => $validator->errors()
]);
}
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 ApiResponse::NOT_FOUND->response([
'success' => false,
'message' => 'El vehículo no se encuentra en la lista de robados activos'
]);
}
$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'] ?? 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
Redis::del("vehiculo:robado:{$epc}");
Log::info('Vehículo registrado como recuperado', [
'id' => $vehiculoRecuperado->id,
'vin' => $vehiculoRecuperado->vin,
'placa' => $vehiculoRecuperado->placa
]);
return ApiResponse::OK->response([
'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,
'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 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(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
]);
}
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']
]);
}
}