From 843d3404e9c0240bb81dbc8721a9fa0db6ff5389 Mon Sep 17 00:00:00 2001 From: "edgar.mendez" Date: Mon, 27 Oct 2025 09:25:30 -0600 Subject: [PATCH] Update Tag Model, add TagController and routes, fix InscriptionControlle --- .../Repuve/InscriptionController.php | 98 ++++++++++++------- app/Http/Controllers/TagsController.php | 52 ++++++++++ .../Requests/Repuve/VehicleStoreRequest.php | 9 +- app/Models/Tag.php | 1 + .../2025_10_18_140700_create_tags_table.php | 1 + routes/api.php | 5 + 6 files changed, 130 insertions(+), 36 deletions(-) create mode 100644 app/Http/Controllers/TagsController.php diff --git a/app/Http/Controllers/Repuve/InscriptionController.php b/app/Http/Controllers/Repuve/InscriptionController.php index a93ad4c..867a5c6 100644 --- a/app/Http/Controllers/Repuve/InscriptionController.php +++ b/app/Http/Controllers/Repuve/InscriptionController.php @@ -28,35 +28,35 @@ public function vehicleInscription(VehicleStoreRequest $request) { try { $folio = $request->input('folio'); - $tagId = $request->input('tag_id'); + $tagNumber = $request->input('tag_number'); + $vin = $request->input('vin'); // Buscar Tag y validar que NO tenga vehículo asignado - $tag = Tag::findOrFail($tagId); + $tag = Tag::where('folio', $folio)->where('tag_number', $tagNumber)->first(); + + if (!$tag) { + return ApiResponse::NOT_FOUND->response([ + 'message' => 'No se encontró el tag con el folio y tag_number proporcionados.', + 'folio' => $folio, + 'tag_number' => $tagNumber, + ]); + } if ($tag->vehicle_id) { return ApiResponse::BAD_REQUEST->response([ 'message' => 'El tag ya está asignado a un vehículo. Use actualizar en su lugar.', - 'tag_id' => $tagId, + 'tag_number' => $tagNumber, 'vehicle_id' => $tag->vehicle_id, ]); } - // Validar que el folio del tag coincida - if ($tag->folio !== $folio) { - return ApiResponse::BAD_REQUEST->response([ - 'message' => 'El folio no coincide con el tag RFID proporcionado', - 'folio_request' => $folio, - 'folio_tag' => $tag->folio, - ]); - } - // Verificar robo (API Repuve Nacional) $isStolen = $this->checkIfStolen($folio); if ($isStolen) { return ApiResponse::FORBIDDEN->response([ 'folio' => $folio, - 'tag_id' => $tagId, + 'tag_number' => $tagNumber, 'stolen' => true, 'message' => 'El vehículo reporta robo. No se puede continuar con la inscripción.', ]); @@ -85,9 +85,9 @@ public function vehicleInscription(VehicleStoreRequest $request) $vehicle = Vehicle::create([ 'anio_placa' => $vehicleData['ANIO_PLACA'], 'placa' => $vehicleData['PLACA'], - 'numero_serie' => $vehicleData['NO_SERIE'], + 'numero_serie' => $vin, 'rfc' => $vehicleData['RFC'], - 'folio' => $folio, + 'folio' => $folio, 'vigencia' => $vehicleData['VIGENCIA'], 'fecha_impresion' => $vehicleData['FECHA_IMPRESION'], 'qr_hash' => $vehicleData['QR_HASH'], @@ -155,7 +155,10 @@ public function vehicleInscription(VehicleStoreRequest $request) } // Enviar a API Repuve Nacional - $apiResponse = $this->sendToRepuveNacional($folio, $tagId, $vehicleData); + $apiResponse = $this->sendToRepuveNacional($vin); + + $apiResponse["repuve_response"]["folio_ci"] = $folio; + $apiResponse["repuve_response"]["identificador_ci"] = $tagNumber; // Procesar respuesta if (isset($apiResponse['has_error']) && $apiResponse['has_error']) { @@ -260,13 +263,13 @@ private function checkIfStolen(string $folio): bool return (bool) rand(0, 1); } - private function sendToRepuveNacional(string $folio, int $tagId, array $vehicleData): array + private function sendToRepuveNacional(string $vin): array { // Enviar datos a API Repuve Nacional // Aquí se haría la llamada real a la API de Repuve Nacional // Por ahora simulamos respuestas aleatorias usando la tabla errors - $hasError = (bool) rand(0, 1); + /* $hasError = (bool) rand(0, 1); if ($hasError) { // Obtener un error aleatorio de la tabla errors @@ -279,8 +282,7 @@ private function sendToRepuveNacional(string $folio, int $tagId, array $vehicleD 'error_code' => 'ERR_UNKNOWN', 'error_message' => 'No hay errores registrados en el catálogo', 'timestamp' => now()->toDateTimeString(), - 'folio' => $folio, - 'tag_id' => $tagId, + 'vin' => $vin, 'response_data' => null, ]; } @@ -290,25 +292,57 @@ private function sendToRepuveNacional(string $folio, int $tagId, array $vehicleD 'error_code' => $error->code, 'error_message' => $error->description, 'timestamp' => now()->toDateTimeString(), - 'folio' => $folio, - 'tag_id' => $tagId, + 'vin' => $vin, 'response_data' => null, ]; + } */ + + // Respuesta exitosa mockup REPUVE + $mockResponse = "OK:SIN INFORMACION|OTROS|SIN INFORMACION|10/07/2023|CENTRO|$vin|WSA548B|HR16777934V|2023|BLANCO|ADVANCE|TABASCO|NISSAN|MARCH|PARTICULAR|AUTOMOVIL|ACTIVO|null||null|0|null|0|10337954|E2003412012BB0C130FAD04D|Sin observaciones "; + + // Parsear la cadena a JSON + // Parsear la cadena a JSON usando los campos oficiales + $fields = [ + 'marca', + 'submarca', + 'tipo_vehiculo', + 'fecha_expedicion', + 'oficina', + 'niv', + 'placa', + 'motor', + 'modelo', + 'color', + 'version', + 'entidad', + 'marca_padron', + 'submarca_padron', + 'tipo_uso_padron', + 'tipo_vehiculo_padron', + 'estatus_registro', + 'aduana', + 'nombre_aduana', + 'patente', + 'pedimento', + 'fecha_pedimento', + 'clave_importador', + 'folio_ci', + 'identificador_ci', + 'observaciones' + ]; + $values = explode('|', str_replace('OK:', '', $mockResponse)); + $jsonResponse = []; + foreach ($fields as $i => $field) { + $jsonResponse[$field] = $values[$i] ?? null; } - // Respuesta exitosa return [ 'has_error' => false, 'error_code' => null, 'error_message' => null, 'timestamp' => now()->toDateTimeString(), - 'folio' => $folio, - 'tag_id' => $tagId, - 'response_data' => [ - 'status' => 'success', - 'repuve_id' => 'REPUVE-' . strtoupper(uniqid()), - 'validated' => true, - ], + 'vin' => $vin, + 'repuve_response' => $jsonResponse, ]; } @@ -379,7 +413,7 @@ public function searchRecord(Request $request) 'full_name' => $record->vehicle->owner->full_name, 'rfc' => $record->vehicle->owner->rfc, ], - 'tag' =>[ + 'tag' => [ 'id' => $record->vehicle->tag ? $record->vehicle->tag->id : null, 'folio' => $record->vehicle->tag ? $record->vehicle->tag->folio : null, 'status' => $record->vehicle->tag ? $record->vehicle->tag->status : null, @@ -548,7 +582,6 @@ public function listTags(Request $request) 'to' => $tags->lastItem(), ], ]); - } catch (ValidationException $e) { return ApiResponse::BAD_REQUEST->response([ 'message' => 'Error de validación', @@ -565,5 +598,4 @@ public function listTags(Request $request) ]); } } - } diff --git a/app/Http/Controllers/TagsController.php b/app/Http/Controllers/TagsController.php new file mode 100644 index 0000000..a9fa651 --- /dev/null +++ b/app/Http/Controllers/TagsController.php @@ -0,0 +1,52 @@ + + * + * @version 1.0.0 + */ +class TagsController extends Controller +{ + public function index() + { + $tags = Tag::all(); + + return ApiResponse::OK->response([ + 'data' => $tags, + ]); + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'folio' => 'required|string|max:255', + 'package_id' => 'required|integer|exists:packages,id', + 'tag_number' => 'required|string|max:255', + ]); + + $tag = Tag::create($validated); + + return ApiResponse::CREATED->response([ + 'tag' => $tag, + ]); + } + + public function show(Tag $tag) + { + return ApiResponse::OK->response([ + 'tag' => $tag, + ]); + } +} diff --git a/app/Http/Requests/Repuve/VehicleStoreRequest.php b/app/Http/Requests/Repuve/VehicleStoreRequest.php index 490be31..90246f7 100644 --- a/app/Http/Requests/Repuve/VehicleStoreRequest.php +++ b/app/Http/Requests/Repuve/VehicleStoreRequest.php @@ -14,7 +14,8 @@ public function rules(): array { return [ 'folio' => ['required', 'string', 'max:50'], - 'tag_id' => ['required', 'exists:tags,id'], + 'tag_number' => ['required', 'string', 'exists:tags,tag_number'], + 'vin' => ['required', 'string', 'max:30'], 'files' => ['nullable', 'array', 'min:1'], 'files.*' => ['file', 'mimes:jpeg,png,jpg,pdf', 'max:10240'], 'names' => ['nullable', 'array'], @@ -27,8 +28,10 @@ public function messages(): array return [ 'folio.required' => 'El folio es requerido', 'folio.string' => 'El folio debe ser una cadena de texto', - 'tag_id.required' => 'El tag_id es requerido', - 'tag_id.exists' => 'El tag_id no existe en el sistema', + 'tag_number.required' => 'El tag_number es requerido', + 'tag_number.exists' => 'El tag_number no existe en el sistema', + 'vin.required' => 'El VIN es requerido', + 'vin.string' => 'El VIN debe ser una cadena de texto', 'files.array' => 'Los archivos deben ser un array', 'files.*.file' => 'Cada elemento debe ser un archivo válido', 'files.*.mimes' => 'Los archivos deben ser de tipo: jpeg, png, jpg, pdf', diff --git a/app/Models/Tag.php b/app/Models/Tag.php index 02b5cca..7ced8ff 100644 --- a/app/Models/Tag.php +++ b/app/Models/Tag.php @@ -11,6 +11,7 @@ class Tag extends Model protected $fillable = [ 'folio', + 'tag_number', 'vehicle_id', 'package_id', ]; diff --git a/database/migrations/2025_10_18_140700_create_tags_table.php b/database/migrations/2025_10_18_140700_create_tags_table.php index 9120bf7..390b232 100644 --- a/database/migrations/2025_10_18_140700_create_tags_table.php +++ b/database/migrations/2025_10_18_140700_create_tags_table.php @@ -14,6 +14,7 @@ public function up(): void Schema::create('tags', function (Blueprint $table) { $table->id(); $table->string('folio')->unique(); + $table->string('tag_number')->unique()->nullable(); $table->foreignId('vehicle_id')->nullable()->unique()->constrained('vehicle')->nullOnDelete(); $table->foreignId('package_id')->nullable()->constrained('packages')->nullOnDelete(); $table->enum('status', ['available', 'assigned', 'cancelled', 'lost'])->default('available'); diff --git a/routes/api.php b/routes/api.php index 996062b..16ae42d 100644 --- a/routes/api.php +++ b/routes/api.php @@ -8,6 +8,7 @@ use App\Http\Controllers\Admin\RoleController; use App\Http\Controllers\Repuve\DeviceController; use App\Http\Controllers\Repuve\PackageController; +use App\Http\Controllers\TagsController; /** * Rutas del núcleo de la aplicación. @@ -63,6 +64,10 @@ Route::put('/packages-update/{id}', [PackageController::class, 'update']); Route::delete('/packages/{id}', [PackageController::class, 'destroy']); + + //Ruta CRUD Tags + Route::resource('tags', TagsController::class); + }); /** Rutas públicas */