From 80fab4fc4cfc0ed2d6567b37bbc42448596c7427 Mon Sep 17 00:00:00 2001 From: SebasCodeDev Date: Sat, 24 Jan 2026 04:59:52 -0500 Subject: [PATCH 1/2] docs(issue-48): complete technical documentation and versioning v1.3.1 across all layers --- src/main/java/com/automatizacion/App.java | 33 +++++++-- .../automation/DoctorSimAutomation.java | 22 +++++- .../automation/DoctorSimAutomationImpl.java | 57 ++++++++++---- .../BusquedaContactosController.java | 29 +++++--- .../driver/WebDriverFactory.java | 21 +++++- .../locators/DoctorSimLocators.java | 35 ++++----- .../automatizacion/model/ConfigManager.java | 39 ++++------ .../automatizacion/model/ExcelManager.java | 74 ++++++++----------- .../model/ResultadoBusqueda.java | 35 ++++++++- .../repository/ExcelRepository.java | 25 ++++++- .../repository/ExcelRepositoryImpl.java | 19 ++++- .../automatizacion/service/RedService.java | 14 +++- .../service/RedServiceImpl.java | 19 ++++- .../com/automatizacion/view/ConsolaView.java | 38 ++++------ 14 files changed, 310 insertions(+), 150 deletions(-) diff --git a/src/main/java/com/automatizacion/App.java b/src/main/java/com/automatizacion/App.java index 3e284f2..a2d82af 100644 --- a/src/main/java/com/automatizacion/App.java +++ b/src/main/java/com/automatizacion/App.java @@ -12,22 +12,31 @@ import javax.swing.*; import java.util.Scanner; +/** + * Clase principal (Entry Point) del sistema de automatización. + * Orquesta el arranque de la infraestructura, carga de configuraciones + * y gestiona el bucle principal de interacción con el usuario. + * + * @author SebasCodeDev + * @version 1.3.1 + * @since 01/24/2026 + */ public class App { public static void main(String[] args) { - // 🔧 Configuración + // --- Fase de Configuración --- + // Recupera parámetros externos desde el archivo de propiedades String rutaExcel = ConfigManager.get("ruta.excel"); - String url = ConfigManager.get("web.url"); // Aquí obtienes la URL de la config.properties + String url = ConfigManager.get("web.url"); - // 🧱 Infraestructura + // --- Inicialización de Componentes (Infraestructura) --- ExcelManager excelManager = new ExcelManager(); ConsolaView vista = new ConsolaView(); - DoctorSimAutomation automation = new DoctorSimAutomationImpl(); RedService redService = new RedServiceImpl(); - // 🎮 Controller + // --- Inyección de Dependencias en el Controller --- BusquedaContactosController controller = new BusquedaContactosController( excelManager, @@ -40,6 +49,7 @@ public static void main(String[] args) { Scanner scanner = new Scanner(System.in); + // --- Ciclo de Vida de la Aplicación --- while (true) { vista.mostrarMensaje(""" @@ -54,11 +64,20 @@ public static void main(String[] args) { """); vista.mostrarMensaje("Ingrese opción:"); + + // Validación básica de entrada por consola + if (!scanner.hasNextInt()) { + vista.mostrarMensaje("❌ Por favor, ingresa un número válido."); + scanner.next(); // Limpiar buffer + continue; + } + int opcion = scanner.nextInt(); switch (opcion) { case 1 -> { + // Captura interactiva de fila inicial mediante ventana de diálogo String input = JOptionPane.showInputDialog( null, "¿Desde qué fila deseas iniciar la ejecución?", @@ -72,7 +91,7 @@ public static void main(String[] args) { } try { - int filaInicio = Integer.parseInt(input) - 1; // base 0 + int filaInicio = Integer.parseInt(input) - 1; // Ajuste a índice base 0 controller.ejecutar(filaInicio); } catch (NumberFormatException e) { JOptionPane.showMessageDialog( @@ -98,4 +117,4 @@ public static void main(String[] args) { } } } -} +} \ No newline at end of file diff --git a/src/main/java/com/automatizacion/automation/DoctorSimAutomation.java b/src/main/java/com/automatizacion/automation/DoctorSimAutomation.java index 5bd921d..f3f4535 100644 --- a/src/main/java/com/automatizacion/automation/DoctorSimAutomation.java +++ b/src/main/java/com/automatizacion/automation/DoctorSimAutomation.java @@ -2,15 +2,35 @@ import com.automatizacion.model.ResultadoBusqueda; +/** + * Interfaz que define el contrato para la automatización de DoctorSim. + * * @author SebasCodeDev + * @version 1.3.1 + */ public interface DoctorSimAutomation { + /** + * Inicia el navegador y carga la URL del servicio. + */ void iniciar(String url); + /** + * Ingresa el número en el formulario y ejecuta la búsqueda. + */ void ingresarNumero(String numero) throws Exception; + /** + * Extrae el resultado obtenido tras la consulta. + */ ResultadoBusqueda consultarResultado(); + /** + * Refresca la página para limpiar la sesión actual. + */ void refrescar(); + /** + * Cierra el navegador y libera recursos. + */ void cerrar(); -} +} \ No newline at end of file diff --git a/src/main/java/com/automatizacion/automation/DoctorSimAutomationImpl.java b/src/main/java/com/automatizacion/automation/DoctorSimAutomationImpl.java index 7dcee00..b7f5f27 100644 --- a/src/main/java/com/automatizacion/automation/DoctorSimAutomationImpl.java +++ b/src/main/java/com/automatizacion/automation/DoctorSimAutomationImpl.java @@ -6,71 +6,96 @@ import org.openqa.selenium.*; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; - import java.time.Duration; +/** + * Clase que implementa la lógica de interacción con el portal DoctorSim. + * Centraliza el manejo de elementos web y control de flujo de la búsqueda. + * @author SebasCodeDev + * @version 1.3.1 + */ public class DoctorSimAutomationImpl implements DoctorSimAutomation { private WebDriver driver; /** - * Inicializa el WebDriver usando la fábrica y abre la URL. + * Crea la instancia del navegador y navega a la página objetivo. */ @Override public void iniciar(String url) { + // Se utiliza el Factory para obtener un driver configurado driver = WebDriverFactory.crear(url); } + /** + * Proceso de ingreso de datos en el buscador. + */ @Override public void ingresarNumero(String numero) throws InterruptedException { + // Espera máxima de 20 segundos para que el input sea interactuable WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(20)); - WebElement input = wait.until( - ExpectedConditions.elementToBeClickable(DoctorSimLocators.INPUT_NUMERO) - ); + // Localiza el campo de texto del número + WebElement input = wait.until(ExpectedConditions.elementToBeClickable(DoctorSimLocators.INPUT_NUMERO)); + + // Limpia cualquier residuo de texto antes de escribir input.clear(); + + // Pequeñas pausas para asegurar que la página procese los eventos de teclado Thread.sleep(800); input.sendKeys(numero); + Thread.sleep(600); + // Simula la tecla Enter para disparar la consulta input.sendKeys(Keys.ENTER); } + /** + * Evalúa si la consulta fue exitosa o si aparecieron obstáculos. + */ @Override public ResultadoBusqueda consultarResultado() { try { + // Intenta localizar el texto del operador con una espera corta WebDriverWait waitRes = new WebDriverWait(driver, Duration.ofSeconds(5)); - WebElement operador = waitRes.until( - ExpectedConditions.visibilityOfElementLocated(DoctorSimLocators.OPERADOR) - ); + WebElement operador = waitRes.until(ExpectedConditions.visibilityOfElementLocated(DoctorSimLocators.OPERADOR)); - String resultado = operador.getText().trim().toUpperCase(); - return ResultadoBusqueda.ok(resultado); + // Retorna el resultado formateado en mayúsculas + return ResultadoBusqueda.ok(operador.getText().trim().toUpperCase()); } catch (TimeoutException e) { - - // Detectar modal + // Si no aparece el resultado, verifica si hay un modal de error visible if (!driver.findElements(DoctorSimLocators.MODAL_OPERADOR).isEmpty()) { try { + // Intenta cerrar el modal para no bloquear futuras ejecuciones driver.findElement(DoctorSimLocators.BOTON_OK).click(); - } catch (Exception ignored) {} - + } catch (Exception ignored) { + // Si falla el clic, se ignora para continuar con el flujo + } return ResultadoBusqueda.modal(); } - + // Si no hay modal ni resultado, se marca como no detectado return ResultadoBusqueda.noDetectado(); } } + /** + * Recarga la página actual del navegador. + */ @Override public void refrescar() { driver.navigate().refresh(); } + /** + * Finaliza la sesión del navegador de forma segura. + */ @Override public void cerrar() { if (driver != null) { driver.quit(); + // Limpia la referencia para evitar fugas de memoria driver = null; } } -} +} \ No newline at end of file diff --git a/src/main/java/com/automatizacion/controller/BusquedaContactosController.java b/src/main/java/com/automatizacion/controller/BusquedaContactosController.java index 0ea2d1b..2eda151 100644 --- a/src/main/java/com/automatizacion/controller/BusquedaContactosController.java +++ b/src/main/java/com/automatizacion/controller/BusquedaContactosController.java @@ -16,8 +16,8 @@ * NO contiene lógica de red * NO contiene lógica de infraestructura * - * @author Jhoan - * @version 3.1 + * @author SebasCodeDev + * @version 1.3.1 */ public class BusquedaContactosController { @@ -28,20 +28,23 @@ public class BusquedaContactosController { private final String rutaExcel; String url; + /** + * Constructor que recibe las dependencias y la configuración necesaria. + */ public BusquedaContactosController( ExcelManager excelManager, ConsolaView vista, DoctorSimAutomation automation, RedService redService, String rutaExcel, - String url // ✅ nuevo parámetro + String url ) { this.excelManager = excelManager; this.vista = vista; this.automation = automation; this.redService = redService; this.rutaExcel = rutaExcel; - this.url = url; // ✅ ahora sí tiene un valor + this.url = url; } /** @@ -51,6 +54,7 @@ public void ejecutar(int filaInicio) { List contactos = excelManager.leerContactos(rutaExcel); + // Validación de rango para evitar errores de índice if (filaInicio < 0 || filaInicio >= contactos.size()) { vista.mostrarError("La fila de inicio no es válida."); return; @@ -58,8 +62,8 @@ public void ejecutar(int filaInicio) { vista.mostrarMensaje("🚀 Iniciando proceso desde fila " + (filaInicio + 1)); - redService.alternarRed(); - automation.iniciar(url); // ✅ AQUÍ SE INICIALIZA EL DRIVER + // AQUÍ SE INICIALIZA EL DRIVER + automation.iniciar(url); for (int i = filaInicio; i < contactos.size(); i++) { String numero = contactos.get(i); @@ -69,9 +73,13 @@ public void ejecutar(int filaInicio) { automation.ingresarNumero(numero); ResultadoBusqueda resultado = automation.consultarResultado(); + // Lógica de recuperación si se detecta un bloqueo (modal) if (resultado.hayModal()) { vista.mostrarMensaje("🚩 Modal detectado. Cambiando red..."); - excelManager.escribirOperador(rutaExcel, i + 1, ResultadoBusqueda.noDetectado().getOperador()); // <--- esto se perdió + // Se guarda operador no detectado + excelManager.escribirOperador(rutaExcel, i + 1, ResultadoBusqueda.noDetectado().getOperador()); + + // Reinicio de sesión con cambio de IP automation.cerrar(); redService.alternarRed(); automation.iniciar(url); @@ -80,6 +88,7 @@ public void ejecutar(int filaInicio) { continue; } + // Registro del operador encontrado en el Excel excelManager.escribirOperador( rutaExcel, i + 1, @@ -109,8 +118,9 @@ public void reprocesarNoDetectados() { vista.mostrarMensaje("🔁 Reprocesando " + filas.size() + " registros..."); + // Preparación del entorno para el reintento redService.alternarRed(); - automation.iniciar(url); // ✅ AQUÍ TAMBIÉN + automation.iniciar(url); List contactos = excelManager.leerContactos(rutaExcel); @@ -125,6 +135,7 @@ public void reprocesarNoDetectados() { if (resultado.hayModal()) { vista.mostrarMensaje("🚩 Modal detectado. Cambiando red..."); excelManager.escribirOperador(rutaExcel, fila, ResultadoBusqueda.noDetectado().getOperador()); + automation.cerrar(); redService.alternarRed(); automation.iniciar(url); @@ -147,4 +158,4 @@ public void reprocesarNoDetectados() { automation.cerrar(); vista.mostrarMensaje("✅ Reprocesamiento completado"); } -} +} \ No newline at end of file diff --git a/src/main/java/com/automatizacion/driver/WebDriverFactory.java b/src/main/java/com/automatizacion/driver/WebDriverFactory.java index abd9531..740e596 100644 --- a/src/main/java/com/automatizacion/driver/WebDriverFactory.java +++ b/src/main/java/com/automatizacion/driver/WebDriverFactory.java @@ -4,14 +4,33 @@ import org.openqa.selenium.chrome.*; import io.github.bonigarcia.wdm.WebDriverManager; +/** + * Fábrica encargada de centralizar la creación y configuración + * de la instancia de WebDriver para Chrome. + * * @author SebasCodeDev + * @version 1.3.1 + */ public class WebDriverFactory { + /** + * Configura el driver, define opciones de inicio y navega a la URL base. + * @param url Dirección web que el navegador cargará al iniciar. + * @return Una instancia de WebDriver (ChromeDriver) lista para usar. + */ public static WebDriver crear(String url) { + // Configura automáticamente el binario de ChromeDriver según la versión del navegador WebDriverManager.chromedriver().setup(); + + // Configuración de parámetros de inicio para Chrome ChromeOptions options = new ChromeOptions(); options.addArguments("--start-maximized", "--remote-allow-origins=*"); + + // Inicialización del driver con las opciones definidas WebDriver driver = new ChromeDriver(options); + + // Navegación inmediata a la URL proporcionada driver.get(url); + return driver; } -} +} \ No newline at end of file diff --git a/src/main/java/com/automatizacion/locators/DoctorSimLocators.java b/src/main/java/com/automatizacion/locators/DoctorSimLocators.java index cec3991..427602b 100644 --- a/src/main/java/com/automatizacion/locators/DoctorSimLocators.java +++ b/src/main/java/com/automatizacion/locators/DoctorSimLocators.java @@ -3,39 +3,34 @@ import org.openqa.selenium.By; /** - * DESCRIPCION GENRAL DE LA CLASE: - *

- * Clase {@code DoctorSimLocators} contiene los localizadores (By) utilizados en la página de consulta - * del operador en DoctorSIM. - *

- * Estos localizadores permiten a Selenium identificar los elementos necesarios para: - * Ingresar el número telefónico. - * Iniciar la consulta. - * Leer el operador detectado. - *

- * Se recomienda mantener esta clase exclusiva para localizadores, - * evitando lógica o interacciones con la UI. + * Repositorio centralizado de selectores para el portal DoctorSim. + * Esta clase sigue el patrón de diseño Object Repository para facilitar + * el mantenimiento y la reutilización de elementos de la interfaz. * - * @author Jhoan - * @version 1.0 + * @author SebasCodeDev + * @version 1.3.1 * @since 06/11/2025 */ public class DoctorSimLocators { /** - * Campo de texto donde se ingresa el número telefónico. + * Selector para el campo de entrada del número telefónico. */ public static final By INPUT_NUMERO = By.id("phone"); /** - * Elemento donde se muestra el operador después de realizar la consulta. + * Selector del contenedor que muestra el nombre del operador tras la búsqueda. */ public static final By OPERADOR = By.xpath("//*[@id=\"showSelec\"]/div[2]/div/div/div/div/div/p"); + /** + * Selector del mensaje emergente (modal) que indica errores o avisos del sistema. + */ public static final By MODAL_OPERADOR = By.xpath("//*[@id=\"message_select\"]/div/div/div[1]/center/span"); + /** + * Botón de confirmación para cerrar los modales de advertencia. + */ + public static final By BOTON_OK = By.xpath("//*[@id=\"message_select\"]/div/div/div[3]/a"); - public static final By BOTON_OK = By.xpath("//*[@id=\"message_select\"]/div/div/div[3]/a"); - - -} +} \ No newline at end of file diff --git a/src/main/java/com/automatizacion/model/ConfigManager.java b/src/main/java/com/automatizacion/model/ConfigManager.java index f08840d..4522c2f 100644 --- a/src/main/java/com/automatizacion/model/ConfigManager.java +++ b/src/main/java/com/automatizacion/model/ConfigManager.java @@ -5,32 +5,23 @@ import java.util.Properties; /** - * La clase {@code ConfigManager} se encarga de cargar y gestionar las configuraciones - * definidas en el archivo {@code config.properties}, ubicado dentro del directorio - * {@code resources}. - *

- * Esta clase facilita el acceso a valores externos como: - * Rutas de archivos (por ejemplo, Excel) - * URLs usadas en la automatización - * Parámetros generales configurables - *

- * El archivo de configuración debe llamarse {@code config.properties} - * y estar ubicado en: - * src/main/resources/config.properties - *

- * Uso: - * String url = ConfigManager.get("web.url"); - * String excel = ConfigManager.get("excel.path"); + * Gestor de configuraciones encargado de cargar y administrar las propiedades + * externas del proyecto desde el archivo {@code config.properties}. + * * Permite centralizar valores como URLs, rutas de archivos y parámetros + * de ejecución sin necesidad de modificar el código fuente. * - * @author Jhoan - * @version 1.0 - * @since 06/11/2025 + * @author SebasCodeDev + * @version 1.3.1 + * @since 01/24/2026 */ public class ConfigManager { + /** + * Objeto contenedor de las duplas clave-valor del archivo de configuración. + */ private static final Properties properties = new Properties(); - // Carga el archivo de propiedades al iniciar la clase + // Bloque estático para asegurar que las propiedades se carguen al iniciar la aplicación static { try (InputStream input = ConfigManager.class.getClassLoader().getResourceAsStream("config.properties")) { @@ -46,12 +37,12 @@ public class ConfigManager { } /** - * Obtiene el valor de una clave definida en el archivo de configuración. + * Recupera un valor específico basado en su identificador único (key). * - * @param key clave a buscar en el archivo .properties - * @return valor asociado a la clave, o {@code null} si no existe + * @param key Identificador de la propiedad definida en el archivo .properties. + * @return El valor asociado como {@code String}, o {@code null} si la clave no existe. */ public static String get(String key) { return properties.getProperty(key); } -} +} \ No newline at end of file diff --git a/src/main/java/com/automatizacion/model/ExcelManager.java b/src/main/java/com/automatizacion/model/ExcelManager.java index f5ad11f..2524fae 100644 --- a/src/main/java/com/automatizacion/model/ExcelManager.java +++ b/src/main/java/com/automatizacion/model/ExcelManager.java @@ -9,25 +9,20 @@ import java.util.List; /** - * DESCRIPCION GENRAL DE LA CLASE: - * La clase {@code ExcelManager} sencargada de gestionar la lectura y escritura en el archivo Excel utilizado - * en el proceso de automatización. - *

- * ESTA CLASE PERMITE - * Leer una lista de números telefónicos desde una hoja específica. - * Registrar el operador correspondiente a cada número. - *

- * Configuración utilizada: - * Números se leen desde la columna C (índice 2). - * Operadores se escriben en la columna B (índice 1). + * Gestor encargado de la persistencia de datos en archivos Excel. + * Maneja la lectura de contactos y la actualización de estados de los operadores. * - * @author Jhoan Sebastoian Peña Ordoñez - * @version 1.0 - * @since 06/11/2025 + * @author SebasCodeDev + * @version 1.3.1 + * @since 01/24/2026 */ - public class ExcelManager { + /** + * Extrae la lista de números telefónicos desde la primera columna de la hoja principal. + * @param rutaExcel Ruta absoluta o relativa del archivo .xlsx + * @return Lista de strings con los números encontrados. + */ public static List leerContactos(String rutaExcel) { List contactos = new ArrayList<>(); try (FileInputStream file = new FileInputStream(rutaExcel); @@ -39,14 +34,15 @@ public static List leerContactos(String rutaExcel) { return contactos; } - for (int i = 1; i <= sheet.getLastRowNum(); i++) { // empieza en fila 1 (evita título) + // Recorre desde la segunda fila para omitir los encabezados + for (int i = 1; i <= sheet.getLastRowNum(); i++) { Row fila = sheet.getRow(i); if (fila == null) continue; - Cell celda = fila.getCell(0); // Columna C (índice 2) - if (celda == null) - continue; - // ✅ Convertir número correctamente evitando notación científica + Cell celda = fila.getCell(0); + if (celda == null) continue; + + // Normalización de datos para evitar notación científica en números largos String numero = ""; if (celda.getCellType() == CellType.NUMERIC) { numero = String.valueOf((long) celda.getNumericCellValue()); @@ -67,22 +63,23 @@ public static List leerContactos(String rutaExcel) { } /** - * Escribe en la hoja el operador detectado para un número. - * - * @param rutaExcel Ruta del archivo Excel. - * @param fila Número de fila en la cual escribir. - * @param operador Operador identificado. + * Registra el resultado del operador en la columna correspondiente del archivo Excel. + * @param rutaExcel Ruta del archivo. + * @param fila Índice de la fila a modificar. + * @param operador Texto con el nombre del operador detectado. */ - public static void escribirOperador(String rutaExcel, int fila, String operador) { try (FileInputStream file = new FileInputStream(rutaExcel); Workbook workbook = new XSSFWorkbook(file)) { Sheet sheet = workbook.getSheet("Hoja1"); Row row = sheet.getRow(fila); - Cell cell = row.createCell(1); // Columna B + + // Crea o sobrescribe la celda en la columna de resultados (Columna B) + Cell cell = row.createCell(1); cell.setCellValue(operador); + // Flujo de salida para guardar los cambios en el disco try (FileOutputStream out = new FileOutputStream(rutaExcel)) { workbook.write(out); } @@ -92,19 +89,10 @@ public static void escribirOperador(String rutaExcel, int fila, String operador) } /** - * Obtiene la lista de filas que requieren reprocesamiento por presentar - * un operador marcado como "NO DETECTADO" o "NO ENCONTRADO" dentro del archivo Excel. - *

- * El método lee la hoja "Hoja1" del archivo indicado, evalúa la columna correspondiente - * al operador (columna 12, índice basado en 0) y agrega a la lista todas las filas - * que coincidan con los valores mencionados. - *

- * - * @param rutaExcel Ruta completa del archivo Excel desde donde se obtendrá la información. - * @return Una lista con los números de fila (basados en índice 1) que deben ser reprocesadas. - * @throws RuntimeException Si ocurre un error durante la lectura del archivo Excel. + * Filtra las filas que no pudieron ser procesadas correctamente para su reintento. + * @param rutaExcel Ruta del archivo. + * @return Lista de índices de filas marcadas con error o no detectadas. */ - public static List obtenerFilasNoDetectados(String rutaExcel) { List filasReprocesar = new ArrayList<>(); @@ -117,13 +105,15 @@ public static List obtenerFilasNoDetectados(String rutaExcel) { Row fila = sheet.getRow(i); if (fila == null) continue; - Cell celdaOperador = fila.getCell(1); // Columna operador (K) + // Evaluación del estado en la columna de resultados + Cell celdaOperador = fila.getCell(1); if (celdaOperador != null) { String valor = celdaOperador.getStringCellValue().trim().toUpperCase(); + // Identificación de estados que requieren una nueva consulta if (valor.equals("NO DETECTADO") || valor.equals("NO ENCONTRADO")) { - filasReprocesar.add(i); // Guardamos el número de fila + filasReprocesar.add(i); } } } @@ -134,4 +124,4 @@ public static List obtenerFilasNoDetectados(String rutaExcel) { return filasReprocesar; } -} +} \ No newline at end of file diff --git a/src/main/java/com/automatizacion/model/ResultadoBusqueda.java b/src/main/java/com/automatizacion/model/ResultadoBusqueda.java index 34eb4fc..891d4c0 100644 --- a/src/main/java/com/automatizacion/model/ResultadoBusqueda.java +++ b/src/main/java/com/automatizacion/model/ResultadoBusqueda.java @@ -1,32 +1,65 @@ package com.automatizacion.model; +/** + * Modelo que representa el resultado de una consulta en la plataforma. + * Encapsula la información del operador obtenido y el estado de la interfaz (modales). + * * @author SebasCodeDev + * @version 1.3.1 + * @since 01/24/2026 + */ public class ResultadoBusqueda { private final String operador; private final boolean modal; + /** + * Constructor privado para forzar el uso de métodos de fábrica estáticos. + * @param operador Nombre del operador identificado. + * @param modal Indica si se detectó una interrupción por ventana emergente. + */ private ResultadoBusqueda(String operador, boolean modal) { this.operador = operador; this.modal = modal; } + /** + * Crea un resultado exitoso con el nombre del operador. + * @param operador Texto del operador detectado. + * @return Instancia de ResultadoBusqueda con éxito. + */ public static ResultadoBusqueda ok(String operador) { return new ResultadoBusqueda(operador, false); } + /** + * Crea un resultado que indica la presencia de un bloqueo por modal. + * @return Instancia de ResultadoBusqueda con estado de modal activo. + */ public static ResultadoBusqueda modal() { return new ResultadoBusqueda(null, true); } + /** + * Crea un resultado para casos donde la consulta no arrojó datos claros. + * @return Instancia de ResultadoBusqueda marcada como "NO DETECTADO". + */ public static ResultadoBusqueda noDetectado() { return new ResultadoBusqueda("NO DETECTADO", false); } + /** + * Verifica si el flujo fue interrumpido por un modal de error o aviso. + * @return true si hay un modal presente, false de lo contrario. + */ public boolean hayModal() { return modal; } + /** + * Obtiene el nombre del operador almacenado. + * @return Cadena con el nombre del operador o "NO DETECTADO". + */ public String getOperador() { return operador; } -} +} \ No newline at end of file diff --git a/src/main/java/com/automatizacion/repository/ExcelRepository.java b/src/main/java/com/automatizacion/repository/ExcelRepository.java index 3bbc898..a7c9f37 100644 --- a/src/main/java/com/automatizacion/repository/ExcelRepository.java +++ b/src/main/java/com/automatizacion/repository/ExcelRepository.java @@ -2,11 +2,34 @@ import java.util.List; +/** + * Interfaz que define el contrato para la gestión de datos en archivos Excel. + * Proporciona los métodos necesarios para la lectura de entradas y persistencia de resultados. + * * @author SebasCodeDev + * @version 1.3.1 + * @since 01/24/2026 + */ public interface ExcelRepository { + /** + * Extrae la lista de contactos (números) desde el archivo Excel especificado. + * @param rutaExcel Ruta del archivo de origen. + * @return Lista de strings con los contactos procesados. + */ List leerContactos(String rutaExcel); + /** + * Registra el nombre del operador identificado en la fila correspondiente. + * @param rutaExcel Ruta del archivo donde se guardará la información. + * @param fila Índice de la fila a actualizar. + * @param operador Nombre del operador obtenido en la consulta. + */ void escribirOperador(String rutaExcel, int fila, String operador); + /** + * Identifica y retorna los índices de las filas que no fueron procesadas con éxito. + * @param rutaExcel Ruta del archivo a analizar. + * @return Lista de enteros que representan las filas para reprocesamiento. + */ List obtenerFilasNoDetectados(String rutaExcel); -} +} \ No newline at end of file diff --git a/src/main/java/com/automatizacion/repository/ExcelRepositoryImpl.java b/src/main/java/com/automatizacion/repository/ExcelRepositoryImpl.java index c78a617..e299c7a 100644 --- a/src/main/java/com/automatizacion/repository/ExcelRepositoryImpl.java +++ b/src/main/java/com/automatizacion/repository/ExcelRepositoryImpl.java @@ -3,20 +3,37 @@ import com.automatizacion.model.ExcelManager; import java.util.List; +/** + * Implementación de la interfaz ExcelRepository. + * Actúa como un adaptador que delega las operaciones de bajo nivel + * a la utilidad especializada ExcelManager. + * * @author SebasCodeDev + * @version 1.3.1 + * @since 01/24/2026 + */ public class ExcelRepositoryImpl implements ExcelRepository { + /** + * Recupera la lista de contactos delegando la lectura al gestor de Excel. + */ @Override public List leerContactos(String rutaExcel) { return ExcelManager.leerContactos(rutaExcel); } + /** + * Registra el resultado del operador invocando el método de escritura del gestor. + */ @Override public void escribirOperador(String rutaExcel, int fila, String operador) { ExcelManager.escribirOperador(rutaExcel, fila, operador); } + /** + * Obtiene los índices de filas fallidas consultando la lógica del gestor de Excel. + */ @Override public List obtenerFilasNoDetectados(String rutaExcel) { return ExcelManager.obtenerFilasNoDetectados(rutaExcel); } -} +} \ No newline at end of file diff --git a/src/main/java/com/automatizacion/service/RedService.java b/src/main/java/com/automatizacion/service/RedService.java index 1801db9..38142ef 100644 --- a/src/main/java/com/automatizacion/service/RedService.java +++ b/src/main/java/com/automatizacion/service/RedService.java @@ -1,5 +1,17 @@ package com.automatizacion.service; +/** + * Interfaz que define las operaciones de gestión de conectividad para el bot. + * Proporciona mecanismos para mitigar bloqueos mediante la rotación de red. + * * @author SebasCodeDev + * @version 1.3.1 + * @since 01/24/2026 + */ public interface RedService { + + /** + * Ejecuta el proceso de desconexión y reconexión para obtener una nueva identidad de red. + * Este método es vital para evitar detecciones de tráfico automatizado y superar modales de error. + */ void alternarRed(); -} +} \ No newline at end of file diff --git a/src/main/java/com/automatizacion/service/RedServiceImpl.java b/src/main/java/com/automatizacion/service/RedServiceImpl.java index 3efa315..b42758e 100644 --- a/src/main/java/com/automatizacion/service/RedServiceImpl.java +++ b/src/main/java/com/automatizacion/service/RedServiceImpl.java @@ -1,11 +1,25 @@ package com.automatizacion.service; +/** + * Implementación del servicio de red mediante comandos nativos de Windows. + * Utiliza 'netsh' para alternar entre puntos de acceso Wi-Fi configurados + * con el fin de refrescar la dirección IP y evitar bloqueos. + * * @author SebasCodeDev + * @version 1.3.1 + * @since 01/24/2026 + */ public class RedServiceImpl implements RedService { + // Identificador del punto de acceso actual private String redActual = " claro "; + /** + * Alterna la conexión entre dos perfiles Wi-Fi específicos. + * Ejecuta comandos de consola (cmd) para gestionar la interfaz inalámbrica. + */ @Override public void alternarRed() { + // Lógica de alternancia (Toggle) entre redes disponibles if (redActual.equals(" claro ")) { redActual = " claro 2"; } else { @@ -15,11 +29,13 @@ public void alternarRed() { try { System.out.println("📶 [WIFI] Cambiando a: [" + redActual + "]"); + // Desconexión de la interfaz actual para forzar la liberación de IP Process p1 = Runtime.getRuntime() .exec("netsh wlan disconnect interface=\"Wi-Fi\""); p1.waitFor(); Thread.sleep(2000); + // Comando para conectar al nuevo perfil Wi-Fi especificado String[] cmdConectar = { "cmd.exe", "/c", @@ -29,6 +45,7 @@ public void alternarRed() { Process p2 = Runtime.getRuntime().exec(cmdConectar); p2.waitFor(); + // Tiempo de espera técnico para asegurar la obtención de una nueva IP dinámica System.out.println("⏳ [WIFI] Esperando 2s para estabilizar conexión..."); Thread.sleep(2000); @@ -36,4 +53,4 @@ public void alternarRed() { System.err.println("❌ Error en cambio de red: " + e.getMessage()); } } -} +} \ No newline at end of file diff --git a/src/main/java/com/automatizacion/view/ConsolaView.java b/src/main/java/com/automatizacion/view/ConsolaView.java index 6d55cf6..f49d82d 100644 --- a/src/main/java/com/automatizacion/view/ConsolaView.java +++ b/src/main/java/com/automatizacion/view/ConsolaView.java @@ -1,44 +1,32 @@ package com.automatizacion.view; /** - * La clase {@code ConsolaView} se encarga de gestionar la salida de mensajes en la consola. - *

- * Es utilizada como capa de visualización (Vista) dentro del patrón MVC, proporcionando - * métodos para mostrar mensajes informativos y mensajes de error durante la ejecución - * del proceso de automatización. - *

- * Responsabilidades: - * Mostrar mensajes estándar al usuario. - * Mostrar advertencias o errores con formato diferenciado. - *

- * Ejemplo de uso: - * ConsolaView view = new ConsolaView(); - * view.mostrarMensaje("Proceso iniciado..."); - * view.mostrarError("No se pudo cargar el archivo."); + * Clase encargada de la interfaz de usuario por consola. + * Actúa como la capa de salida (Vista) en el patrón MVC, centralizando + * la comunicación de eventos y errores durante la ejecución del bot. * - * @author Jhoan Sebastián Peña Ordoñez - * @version 1.0 - * @since 06/11/2025 + * @author SebasCodeDev + * @version 1.3.1 + * @since 01/24/2026 */ public class ConsolaView { /** - * Muestra un mensaje informativo en la consola. + * Imprime un mensaje informativo estándar en la salida del sistema. * - * @param mensaje texto que se desea mostrar al usuario + * @param mensaje Texto explicativo del paso actual del proceso. */ public void mostrarMensaje(String mensaje) { System.out.println(mensaje); } /** - * Muestra un mensaje de error en la consola, precedido de - * un ícono de advertencia para facilitar su identificación. + * Imprime una alerta de error en la salida de errores (stderr). + * Incluye un formato visual para resaltar fallos críticos o excepciones. * - * @param error descripción del error ocurrido + * @param error Descripción detallada del problema encontrado. */ public void mostrarError(String error) { - System.err.println("⚠ " + error); + System.err.println("⚠ ERROR: " + error); } - -} +} \ No newline at end of file From b32cd6701860d6ce9e46e8f09f7e72acc09857b4 Mon Sep 17 00:00:00 2001 From: SebasCodeDev Date: Sat, 24 Jan 2026 05:26:34 -0500 Subject: [PATCH 2/2] feat(issue-149: aactualizacion de version de archivo README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c0377bc..1e2cff9 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ El flujo principal es: | Campo | Detalle | |:-------------------------------:|:------------------:| -| **Versión Actual** | 1.3.0 | +| **Versión Actual** | 1.3.1 | | **Última Actualización** | 23 de Enero, 2026 | | **Lenguaje** | Java 17+ | | **Framework de Automatización** | Selenium WebDriver |