diff --git a/app/Http/Controllers/Repuve/InscriptionController.php b/app/Http/Controllers/Repuve/InscriptionController.php index c7c62c6..c529ae3 100644 --- a/app/Http/Controllers/Repuve/InscriptionController.php +++ b/app/Http/Controllers/Repuve/InscriptionController.php @@ -437,4 +437,48 @@ public function searchRecord(Request $request) 'records' => $paginatedRecords ]); } + + public function stolen(Request $request) + { + $request->validate([ + 'vin' => 'nullable|string|min:17|max:17', + 'placa' => 'nullable|string', + ], [ + 'vin.required_without' => 'Debe proporcionar al menos VIN o PLACA.', + 'placa.required_without' => 'Debe proporcionar al menos VIN o PLACA.', + ]); + + // Validar que al menos uno esté presente + if (!$request->filled('vin') && !$request->filled('placa')) { + return ApiResponse::BAD_REQUEST->response([ + 'message' => 'Debe proporcionar al menos VIN o PLACA.', + ]); + } + + try { + $vin = $request->input('vin'); + $placa = $request->input('placa'); + + // Verificar robo usando el servicio + $resultado = $this->repuveService->verificarRobo($vin, $placa); + $isStolen = $resultado['is_robado'] ?? false; + + return ApiResponse::OK->response([ + 'vin' => $vin ?: null, + 'placa' => $placa ?: null, + 'robado' => $isStolen, + 'estatus' => $isStolen ? 'REPORTADO COMO ROBADO' : 'SIN REPORTE DE ROBO', + 'message' => $isStolen + ? 'El vehículo tiene reporte de robo en REPUVE.' + : 'El vehículo no tiene reporte de robo.', + 'fecha' => now()->toDateTimeString(), + 'detalle_repuve' => $resultado, + ]); + } catch (\Exception $e) { + return ApiResponse::INTERNAL_ERROR->response([ + 'message' => 'Error al consultar el estado de robo del vehículo.', + 'error' => $e->getMessage(), + ]); + } + } } diff --git a/app/Services/RepuveService.php b/app/Services/RepuveService.php index 81f4670..ff46358 100644 --- a/app/Services/RepuveService.php +++ b/app/Services/RepuveService.php @@ -164,15 +164,12 @@ private function parseVehicleResponse(string $soapResponse, string $niv) ]; } - /** - * Verifica si un vehículo está reportado como robado - */ - public function verificarRobo(string $niv): bool + public function verificarRobo(?string $niv = null, ?string $placa = null): array { try { $url = $this->baseUrl . $this->roboEndpoint; - $arg2 = $niv . str_repeat('|', 8); + $arg2 = ($niv ?? '') . '|' . ($placa ?? '') . str_repeat('|', 7); $soapBody = << @@ -202,45 +199,61 @@ public function verificarRobo(string $niv): bool $error = curl_error($ch); curl_close($ch); - // Si hay error de conexión, asumir que NO está robado + // Si hay error de conexión, retornar error if ($error) { logger()->error('REPUVE verificarRobo: Error de conexión', [ 'error' => $error, 'niv' => $niv, + 'placa' => $placa, ]); - return false; + return [ + 'is_robado' => false, + 'has_error' => true, + 'error_message' => 'Error de conexión con el servicio REPUVE', + ]; } - // Si hay error HTTP, asumir que NO está robado + // Si hay error HTTP, retornar error if ($httpCode !== 200) { logger()->error('REPUVE verificarRobo: HTTP error', [ 'http_code' => $httpCode, 'niv' => $niv, + 'placa' => $placa, ]); - return false; + return [ + 'is_robado' => false, + 'has_error' => true, + 'error_message' => "Error HTTP {$httpCode} del servicio REPUVE", + ]; } // Parsear respuesta - $resultado = $this->parseRoboResponse($response, $niv); + $valorBuscado = $niv ?: $placa ?: 'N/A'; + $resultado = $this->parseRoboResponse($response, $valorBuscado); - // Si hubo error al parsear, asumir que NO está robado - if ($resultado['has_error'] ?? true) { + // Si hubo error al parsear, loguear pero retornar el resultado completo + if ($resultado['has_error'] ?? false) { logger()->warning('REPUVE verificarRobo: Error al parsear respuesta', [ 'niv' => $niv, + 'placa' => $placa, 'error' => $resultado['error_message'] ?? 'Desconocido', ]); - return false; } - // Retornar si está robado o no - return $resultado['is_robado'] ?? false; + // Retornar el array completo con toda la información + return $resultado; } catch (Exception $e) { logger()->error('REPUVE verificarRobo: Excepción capturada', [ 'niv' => $niv, + 'placa' => $placa, 'exception' => $e->getMessage(), ]); - return false; + return [ + 'is_robado' => false, + 'has_error' => true, + 'error_message' => 'Excepción capturada: ' . $e->getMessage(), + ]; } } diff --git a/database/migrations/2025_12_05_222705_remove_boxes_restore_packages.php b/database/migrations/2025_12_05_222705_remove_boxes_restore_packages.php index 6877220..08df458 100644 --- a/database/migrations/2025_12_05_222705_remove_boxes_restore_packages.php +++ b/database/migrations/2025_12_05_222705_remove_boxes_restore_packages.php @@ -12,7 +12,20 @@ */ public function up() { + // 1. Agregar columnas necesarias a packages (si no existen) + Schema::table('packages', function (Blueprint $table) { + if (!Schema::hasColumn('packages', 'box_number')) { + $table->integer('box_number')->after('lot'); + } + if (!Schema::hasColumn('packages', 'starting_page')) { + $table->integer('starting_page')->after('box_number'); + } + if (!Schema::hasColumn('packages', 'ending_page')) { + $table->integer('ending_page')->after('starting_page'); + } + }); + // 2. Migrar datos de boxes a packages DB::table('boxes')->orderBy('id')->chunk(100, function($boxes) { foreach ($boxes as $box) { $parentPackage = DB::table('packages')->find($box->package_id); @@ -33,7 +46,14 @@ public function up() } }); + // 3. Agregar constraint único después de migrar datos (si no existe) + if (!$this->constraintExists('packages', 'packages_lot_box_unique')) { + Schema::table('packages', function (Blueprint $table) { + $table->unique(['lot', 'box_number'], 'packages_lot_box_unique'); + }); + } + // 4. Actualizar referencias en tags Schema::table('tags', function (Blueprint $table) { $table->dropForeign(['box_id']); }); @@ -46,7 +66,7 @@ public function up() $table->foreign('package_id')->references('id')->on('packages')->onDelete('cascade'); }); - // eliminar tabla boxes + // 5. Eliminar tabla boxes Schema::dropIfExists('boxes'); // 6. Eliminar columnas de packages que ya no se usan @@ -60,11 +80,66 @@ public function up() }); } + /** + * Verificar si existe un constraint/índice + */ + private function constraintExists(string $table, string $name): bool + { + $indexes = DB::select("SHOW INDEX FROM {$table}"); + foreach ($indexes as $index) { + if ($index->Key_name === $name) { + return true; + } + } + return false; + } + /** * Reverse the migrations. */ public function down(): void { - // + // Revertir cambios en orden inverso + + // 1. Restaurar columnas de packages + Schema::table('packages', function (Blueprint $table) { + $table->integer('total_boxes')->nullable(); + $table->text('description')->nullable(); + }); + + // 2. Recrear tabla boxes + Schema::create('boxes', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('package_id'); + $table->string('box_number'); + $table->integer('starting_page'); + $table->integer('ending_page'); + $table->timestamps(); + + $table->foreign('package_id')->references('id')->on('packages')->onDelete('cascade'); + }); + + // 3. Revertir columna package_id a box_id en tags + Schema::table('tags', function (Blueprint $table) { + $table->dropForeign(['package_id']); + }); + + Schema::table('tags', function (Blueprint $table) { + $table->renameColumn('package_id', 'box_id'); + }); + + Schema::table('tags', function (Blueprint $table) { + $table->foreign('box_id')->references('id')->on('boxes')->onDelete('cascade'); + }); + + // 4. Eliminar constraint único de packages + Schema::table('packages', function (Blueprint $table) { + $table->dropUnique('packages_lot_box_unique'); + }); + + // 5. Eliminar columnas agregadas a packages + Schema::table('packages', function (Blueprint $table) { + $table->dropColumn(['box_number', 'starting_page', 'ending_page']); + }); } }; diff --git a/database/migrations/2025_12_05_224733_add_box_fields_to_packages_table.php b/database/migrations/2025_12_05_224733_add_box_fields_to_packages_table.php deleted file mode 100644 index 4523997..0000000 --- a/database/migrations/2025_12_05_224733_add_box_fields_to_packages_table.php +++ /dev/null @@ -1,32 +0,0 @@ -integer('box_number')->after('lot'); - $table->integer('starting_page')->after('box_number'); - $table->integer('ending_page')->after('starting_page'); - $table->unique(['lot', 'box_number'], 'packages_lot_box_unique'); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::table('packages', function (Blueprint $table) { - $table->dropUnique('packages_lot_box_unique'); - $table->dropColumn(['box_number', 'starting_page', 'ending_page']); - }); - } -}; diff --git a/routes/api.php b/routes/api.php index dd5c877..18891fb 100644 --- a/routes/api.php +++ b/routes/api.php @@ -34,7 +34,7 @@ // Rutas de inscripción de vehículos Route::post('inscripcion', [InscriptionController::class, 'vehicleInscription']); Route::get('consultaV', [InscriptionController::class, 'searchRecord']); - Route::post('stolen', [InscriptionController::class, 'stolen']); + Route::post('reporte-robado', [InscriptionController::class, 'stolen']); // Rutas de expedientes y documentos Route::get('expediente/{id}/pdf', [RecordController::class, 'generatePdf']);