diff --git a/corte.mjs b/corte.mjs index 4d67286..a2f4190 100644 --- a/corte.mjs +++ b/corte.mjs @@ -79,7 +79,7 @@ async function actualizarCelda(spreadsheetId, range, values) { }); await new Promise(resolve => setTimeout(resolve, 1000)); } catch (error) { - console.error('Error al actualizar celda:', error.message); + console.error('>> Error al actualizar celda:', error.message); throw error; } } @@ -90,9 +90,9 @@ async function cerrarChromeDebugging() { if (process.platform === 'win32') { exec('wmic process where "commandline like \'%--remote-debugging-port=9224%\'" call terminate', (error) => { if (error) { - console.log('⚠️ No se encontraron instancias de Chrome debugging'); + console.log('>> No se encontraron instancias de Chrome debugging'); } else { - console.log('🔒 Chrome debugging cerrado correctamente'); + console.log('>> Chrome debugging cerrado correctamente'); } resolve(); }); @@ -118,7 +118,7 @@ async function iniciarChrome(url) { + `"${url}"`, (error) => { if (error) { - console.log('⚠️ Error al iniciar Chrome:', error); + console.log('>> Error al iniciar Chrome:', error); } resolve(); } @@ -133,20 +133,20 @@ async function initBrowser(url) { await cerrarChromeDebugging(); await new Promise(resolve => setTimeout(resolve, 2000)); - console.log('🌐 Iniciando Chrome con debugging...'); + console.log('>> Iniciando Chrome con debugging...'); await iniciarChrome(url); await new Promise(resolve => setTimeout(resolve, 8000)); // Aumentado a 8 segundos - console.log('🔍 Intentando conectar con Chrome...'); + console.log('>> Intentando conectar con Chrome...'); const webSocketDebuggerUrl = await getWebSocketUrl(); - console.log('✅ Conexión establecida con Chrome'); + console.log('>> Conexión establecida con Chrome'); return await puppeteer.connect({ browserWSEndpoint: webSocketDebuggerUrl, defaultViewport: null }); } catch (error) { - console.error('❌ Error al inicializar el navegador:', error); + console.error('>> Error al inicializar el navegador:', error); throw error; } } @@ -163,7 +163,7 @@ async function getWebSocketUrl() { } throw new Error('URL de WebSocket no encontrada'); } catch (err) { - console.log(`🔄 Reintentando conexión a Chrome... (intentos restantes: ${retries})`); + console.log(`>> Reintentando conexión a Chrome... (intentos restantes: ${retries})`); await new Promise(resolve => setTimeout(resolve, 2000)); // Aumentado a 4 segundos retries--; } @@ -179,16 +179,26 @@ async function delay(ms) { // Funciones de procesamiento CORTE async function procesarCasoCorte(page, element, spreadsheetId, intentos = 1) { const MAX_INTENTOS = 3; + // Validate that case number has 9 digits + if (element.valor.length !== 9) { + console.log('>> Invalid case number - must be 9 digits'); + await actualizarCelda( + spreadsheetId, + `C${element.fila}`, + ['Invalid case number - must contain exactly 9 digits'] + ); + return true; + } try { - console.log(` ⌛ Consultando caso Corte... (Intento ${intentos}/${MAX_INTENTOS})`); + console.log(`>> Consultando caso Corte... (Intento ${intentos}/${MAX_INTENTOS})`); try { await page.goto(CONFIG.PLATFORMS.CORTE.URL, { waitUntil: 'domcontentloaded', timeout: 20000 }); } catch (navigationError) { - console.log(' ⚠️ Error de navegación o campo no encontrado, reintentando...'); + console.log('>> Error de navegación o campo no encontrado, reintentando...'); if (intentos < MAX_INTENTOS) { return await procesarCasoCorte(page, element, spreadsheetId, intentos + 1); } else { @@ -201,7 +211,7 @@ async function procesarCasoCorte(page, element, spreadsheetId, intentos = 1) { await delay(2000); await page.click('button.btn'); } catch (error) { - console.log('❌ No se pudo encontrar el botón de caso Corte.'); + console.log('>> No se pudo encontrar el botón de caso Corte.'); } try { @@ -209,7 +219,7 @@ async function procesarCasoCorte(page, element, spreadsheetId, intentos = 1) { await delay(2000); await page.type('.codeInput > input:nth-child(1)', element.valor); } catch (error) { - console.log('❌ No se pudo encontrar el campo de entrada de caso Corte.'); + console.log('>> No se pudo encontrar el campo de entrada de caso Corte.'); } await delay(2000); @@ -218,33 +228,74 @@ async function procesarCasoCorte(page, element, spreadsheetId, intentos = 1) { await page.waitForSelector('#btn_submit', { visible: true, timeout: 10000 }); await page.click('#btn_submit'); } catch (error) { - console.log('❌ No se pudo encontrar el botón de consulta Corte.'); + console.log('>> No se pudo encontrar el botón de consulta Corte.'); } - await delay(1000); + await delay(3000); try { - await delay(2000); - const noResultsElement = await page.$x("//div[contains(text(), 'No case found for this A-Number.')]"); - if (noResultsElement.length > 0) { - console.log("⚠️ No case found for this A-Number"); + await delay(3000); + // Wait for the 'No case found' message + // Check for "No case found" message + const result = await page.evaluate(() => { + const elements = document.querySelectorAll('div'); + for (const el of elements) { + if (el.textContent.includes('No case found for this A-Number.') || el.textContent.includes('Case information is unavailable.')) { + return true; + } + } + return false; + }).catch(() => false); + + if (result) { + console.log(">> No case found for this A-Number"); await actualizarCelda( spreadsheetId, `C${element.fila}`, ['No case found for this A-Number'] ); return true; + } else { + console.log('>> No error found'); + try { + const isCaptchaPresent = await page.evaluate(() => { + const captchaFrames = document.querySelectorAll('iframe[src*="hcaptcha"]'); + return Array.from(captchaFrames).some(frame => { + return frame !== null && getComputedStyle(frame).display !== 'none'; + }); + }); + + if (isCaptchaPresent) { + await delay(5000); + console.log('>> hCaptcha detected'); + await actualizarCelda( + spreadsheetId, + `C${element.fila}`, + ['Captcha detected - Please try again later'] + ); + await delay(5000); + return false; + } else { + console.log('>> No captcha detected'); + } + } catch (error) { + console.error('>> Error checking for captcha:', error); + } } } catch (error) { - console.log('ℹ️ Case found, continuing with data extraction...'); + console.error('Error during case processing:', error); + // Check for hCaptcha presence } + + + try { // Esperar a que aparezca la tarjeta de información await page.waitForSelector('.caseInfoCard', { timeout: 8000 }); - console.log(" ✅ Información encontrada"); + console.log(">> Información encontrada"); // Obtener todos los elementos de información const elements = await page.$$eval('div.caseInfoCard', nodes => @@ -253,7 +304,7 @@ async function procesarCasoCorte(page, element, spreadsheetId, intentos = 1) { // Extraer la información relevante const [box1, box2, box3, box4] = elements; - console.log(' 📋 Información obtenida:'); + console.log('>> Información obtenida:'); console.log(' Box 1:', box1); console.log(' Box 2:', box2); console.log(' Box 3:', box3); @@ -266,18 +317,18 @@ async function procesarCasoCorte(page, element, spreadsheetId, intentos = 1) { ); } catch (error) { - console.log('❌ No se pudo encontrar la información de la tarjeta.'); + console.log('>> No se pudo encontrar la información de la tarjeta.'); } return true; // Indica que el proceso fue exitoso } catch (error) { - console.error(' ❌ Error procesando caso CORTE:', error); + console.error('>> Error procesando caso CORTE:', error); if (intentos < MAX_INTENTOS) { - console.log(` 🔄 Reintentando... (${intentos}/${MAX_INTENTOS})`); + console.log(`>> Reintentando... (${intentos}/${MAX_INTENTOS})`); return await procesarCasoCorte(page, element, spreadsheetId, intentos + 1); } else { - console.log(' ⚠️ Se agotaron los intentos o error no recuperable'); + console.log('>> Se agotaron los intentos o error no recuperable'); await actualizarCelda( spreadsheetId, `C${element.fila}`, @@ -290,7 +341,7 @@ async function procesarCasoCorte(page, element, spreadsheetId, intentos = 1) { // Modificar la función procesarArchivo para manejar mejor la reconexión de Chrome async function procesarArchivo(archivo) { - console.log('\n🔍 Analizando archivo:', archivo.name); + console.log('\n>> Analizando archivo:', archivo.name); const platform_type = 'corte'; const platform = CONFIG.PLATFORMS[platform_type.toUpperCase()].URL; @@ -308,6 +359,8 @@ async function procesarArchivo(archivo) { // Separate rows into three groups based on priority const filasVaciasC = todasLasFilas.filter(row => !row.columnaC); + const filasConCaptcha = todasLasFilas.filter(row => row.columnaC && row.columnaC.includes('Captcha detected - Please try again later')); + const filasConFechaB = todasLasFilas.filter(row => { if (!row.columnaC && !row.ultimaConsulta) return false; // Already handled by filasVaciasC or filasVaciasB if (!row.ultimaConsulta) return false; // Handled by filasVaciasB @@ -346,14 +399,14 @@ async function procesarArchivo(archivo) { }); // Combine the arrays in the specified priority order - const filasOrdenadas = [...filasVaciasC, ...filasConFechaB, ...filasVaciasB]; + const filasOrdenadas = [...filasVaciasC, ...filasConCaptcha, ...filasConFechaB, ...filasVaciasB]; console.log(filasOrdenadas); - console.log(`📊 Total de filas a procesar: ${filasOrdenadas.length}`); + console.log(`>> Total de filas a procesar: ${filasOrdenadas.length}`); if (filasOrdenadas.length > 0) { - console.log('🌐 Iniciando navegador...'); + console.log('>> Iniciando navegador...'); let browser = await initBrowser(platform); let page = (await browser.pages())[0]; let fallosConsecutivos = 0; @@ -362,8 +415,8 @@ async function procesarArchivo(archivo) { let procesadas = 0; for (const element of filasOrdenadas) { procesadas++; - console.log(`\n⏳ Procesando fila ${element.fila} (${procesadas}/${filasOrdenadas.length})`); - console.log(`📝 Valor a consultar: ${element.valor}`); + console.log(`\n>> Procesando fila ${element.fila} (${procesadas}/${filasOrdenadas.length})`); + console.log(`>> Valor a consultar: ${element.valor}`); // Guardar la fecha y hora actual const fechaHoraActual = new Date().toLocaleString('es-ES', { @@ -394,7 +447,7 @@ async function procesarArchivo(archivo) { if (!resultado) { fallosConsecutivos++; if (fallosConsecutivos >= MAX_FALLOS_CONSECUTIVOS) { - console.log('🔄 Reiniciando navegador debido a fallos consecutivos...'); + console.log('>> Reiniciando navegador debido a fallos consecutivos...'); await browser.close(); await cerrarChromeDebugging(); await delay(2000); @@ -408,10 +461,10 @@ async function procesarArchivo(archivo) { } } - console.log('\n✅ Proceso completado para el archivo:', archivo.name); + console.log('\n>> Proceso completado para el archivo:', archivo.name); await browser.close(); } else { - console.log('ℹ️ No hay filas para procesar en este archivo'); + console.log('>> No hay filas para procesar en este archivo'); } } @@ -420,7 +473,7 @@ async function cerrarTodo() { if (browser) { await browser.close(); // Cerrar el navegador si está abierto } - console.log('🔄 Cerrando Chrome debugging y finalizando...'); + console.log('>> Cerrando Chrome debugging y finalizando...'); await cerrarChromeDebugging(); process.exit(); } @@ -434,19 +487,19 @@ process.on('SIGINT', async () => { // Función principal async function procesarArchivos() { try { - console.log('🚀 Iniciando proceso...'); + console.log('>> Iniciando proceso...'); const archivos = await listarArchivosEnCarpeta(CONFIG.DRIVE.FOLDER_ID); - console.log(`📁 Total de archivos encontrados: ${archivos.length}`); + console.log(`>> Total de archivos encontrados: ${archivos.length}`); let procesados = 0; for (const archivo of archivos) { procesados++; - console.log(`\n📌 Procesando archivo ${procesados}/${archivos.length}: ${archivo.name}`); + console.log(`\n>> Procesando archivo ${procesados}/${archivos.length}: ${archivo.name}`); await procesarArchivo(archivo); } - console.log('\n🎉 Proceso completado exitosamente!'); + console.log('\n>> Proceso completado exitosamente!'); } catch (error) { - console.error('❌ Error en el proceso:', error); + console.error('>> Error en el proceso:', error); } finally { await cerrarTodo(); // Asegúrate de cerrar todo al final } diff --git a/package.json b/package.json index 8604b69..b64f10e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "migracion-corte", - "version": "1.0.1", + "version": "1.0.2", "main": "corte.mjs", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", diff --git a/uscis.mjs b/uscis.mjs index fefd4a8..fa80f52 100644 --- a/uscis.mjs +++ b/uscis.mjs @@ -6,6 +6,7 @@ import { google } from 'googleapis'; import { createWriteStream } from 'fs'; import fs from 'fs'; import { app } from 'electron'; +import os from 'os'; console.log(app.getAppPath()); @@ -13,7 +14,6 @@ let url_cred = app.getAppPath().replace('app.asar', ''); url_cred = url_cred + '\\credenciales.json'; console.log(url_cred); -// Configuración const CONFIG = { PATHS: { BASE_DIR: 'C:\\Users\\Drackxus\\Documents\\NODE\\migracion', @@ -35,7 +35,6 @@ const CONFIG = { } }; -// Inicialización de Google APIs const auth = new google.auth.GoogleAuth({ keyFile: CONFIG.PATHS.CREDENTIALS, scopes: CONFIG.DRIVE.SCOPES @@ -44,25 +43,18 @@ const auth = new google.auth.GoogleAuth({ const sheets = google.sheets({ version: 'v4', auth }); const drive = google.drive({ version: 'v3', auth }); -let browser; // Variable global para el navegador - -// Funciones de Google Sheets async function listarArchivosEnCarpeta(folderId) { const res = await drive.files.list({ - q: `'${folderId}' in parents and mimeType='application/vnd.google-apps.spreadsheet' and name='base_uscis'`, + q: `'${folderId}' in parents and mimeType='application/vnd.google-apps.spreadsheet' and name='base_pruebas'`, fields: '*' }); - - console.log(`${res.data.files.length} archivo(s) encontrados con el nombre "base_uscis"`); - return res.data.files; } - async function obtenerDatosHoja(spreadsheetId) { const response = await sheets.spreadsheets.values.get({ spreadsheetId, - range: 'A:H', // Ajusta el rango según tus necesidades + range: 'A:H', }); return response.data.values; } @@ -84,346 +76,146 @@ async function actualizarCelda(spreadsheetId, range, values) { } } -// Funciones de manejo del navegador async function cerrarChromeDebugging() { return new Promise((resolve) => { if (process.platform === 'win32') { - exec('wmic process where "commandline like \'%--remote-debugging-port=9223%\'" call terminate', (error) => { - if (error) { - console.log('⚠️ No se encontraron instancias de Chrome debugging'); - } else { - console.log('🔒 Chrome debugging cerrado correctamente'); - } - resolve(); - }); + exec('wmic process where "commandline like \'%--remote-debugging-port=%\'" call terminate', () => resolve()); } else { - exec("pkill -f 'chrome.*--remote-debugging-port=9223'", () => { - resolve(); - }); + exec("pkill -f 'chrome.*--remote-debugging-port='", () => resolve()); } }); } -async function iniciarChrome(url) { +async function iniciarChromeConPuerto(url, port, userDir) { return new Promise((resolve) => { const chromeProcess = exec( - `start chrome ` - + `--remote-debugging-port=9223 ` - + `--no-sandbox ` - + `--disable-setuid-sandbox ` - + `--disable-background-timer-throttling ` - + `--disable-renderer-backgrounding ` - + `--disable-backgrounding-occluded-windows ` - + `--user-data-dir="C:\\temp\\chrome_debug_temp_uscis" ` - + `"${url}"`, - (error) => { - if (error) { - console.log('⚠️ Error al iniciar Chrome:', error); - } - resolve(); - } + `start chrome ` + + `--remote-debugging-port=${port} ` + + `--no-sandbox ` + + `--disable-setuid-sandbox ` + + `--user-data-dir="${userDir}" ` + + `"${url}"`, + () => resolve() ); }); } -async function initBrowser(url) { - try { - await cerrarChromeDebugging(); - await new Promise(resolve => setTimeout(resolve, 2000)); - - console.log('🌐 Iniciando Chrome con debugging...'); - await iniciarChrome(url); - await new Promise(resolve => setTimeout(resolve, 8000)); // Aumentado a 8 segundos - - console.log('🔍 Intentando conectar con Chrome...'); - const webSocketDebuggerUrl = await getWebSocketUrl(); - - console.log('✅ Conexión establecida con Chrome'); - return await puppeteer.connect({ - browserWSEndpoint: webSocketDebuggerUrl, - defaultViewport: null - }); - } catch (error) { - console.error('❌ Error al inicializar el navegador:', error); - throw error; - } -} - -async function getWebSocketUrl() { - let retries = 10; // Aumentado a 15 intentos - while (retries > 0) { +async function getWebSocketUrl(port) { + const maxRetries = 15; + for (let i = 0; i < maxRetries; i++) { try { - const response = await fetch('http://localhost:9223/json/version'); - if (!response.ok) throw new Error('No se pudo obtener la versión del navegador'); + const response = await fetch(`http://localhost:${port}/json/version`); const json = await response.json(); - if (json.webSocketDebuggerUrl) { - return json.webSocketDebuggerUrl; - } - throw new Error('URL de WebSocket no encontrada'); - } catch (err) { - console.log(`🔄 Reintentando conexión a Chrome... (intentos restantes: ${retries})`); - await new Promise(resolve => setTimeout(resolve, 2000)); // Aumentado a 4 segundos - retries--; - } + if (json.webSocketDebuggerUrl) return json.webSocketDebuggerUrl; + } catch {} + await new Promise(res => setTimeout(res, 2000)); } - throw new Error('No se pudo conectar a Chrome después de varios intentos'); + throw new Error(`No se pudo conectar a Chrome en el puerto ${port}`); +} + +async function initBrowserEnPuerto(url, port, userDir) { + await cerrarChromeDebugging(); + await new Promise(resolve => setTimeout(resolve, 2000)); + await iniciarChromeConPuerto(url, port, userDir); + await new Promise(resolve => setTimeout(resolve, 8000)); + const webSocketDebuggerUrl = await getWebSocketUrl(port); + return await puppeteer.connect({ + browserWSEndpoint: webSocketDebuggerUrl, + defaultViewport: null + }); } -// Funciones de utilidad async function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } -// Funciones de procesamiento USCIS async function procesarCasoUSCIS(page, element, spreadsheetId, intentos = 1) { const MAX_INTENTOS = 3; - try { - console.log(`⌛ Consultando caso USCIS... (Intento ${intentos}/${MAX_INTENTOS})`); - - try { - await page.goto(CONFIG.PLATFORMS.USCIS.URL, { - waitUntil: 'domcontentloaded', - timeout: 20000 - }); - await page.waitForSelector('#receipt_number', { timeout: 10000 }); - } catch (navigationError) { - console.log(' ⚠️ Error de navegación o campo no encontrado, reintentando...'); - if (intentos < MAX_INTENTOS) { - return await procesarCasoUSCIS(page, element, spreadsheetId, intentos + 1); - } else { - throw new Error('No se pudo acceder a la página después de varios intentos'); - } - } - - // Intentar llenar el campo y hacer clic + await page.goto(CONFIG.PLATFORMS.USCIS.URL, { waitUntil: 'domcontentloaded', timeout: 20000 }); + await page.waitForSelector('#receipt_number', { timeout: 10000 }); await page.type('#receipt_number', element.valor); await delay(1000); await page.click('::-p-text(Verifique Estatus)'); await delay(2000); - // Esperar a que se complete la acción - - // page.waitForSelector('.errorMessage', { timeout: 5000 }), - // page.waitForSelector('.conditionalLanding', { timeout: 5000 }) - - - // Verificar el resultado - const errorMessage = await page.$('.errorMessage', { timeout: 5000 }); + const errorMessage = await page.$('.errorMessage'); if (errorMessage) { - console.log(' ⚠️ Caso no válido'); - await actualizarCelda( - spreadsheetId, - `G${element.fila}`, - ['El número de recibo ingresado no es válido, intente nuevamente.'] - ); + await actualizarCelda(spreadsheetId, `G${element.fila}`, ['El número de recibo ingresado no es válido']); } else { - try { - const [titulo, descripcion] = await Promise.all([ - page.$eval('.conditionalLanding h2', el => el.innerText), - page.$eval('.conditionalLanding p', el => el.innerText) - ]); - - console.log(' ✅ Información obtenida'); - console.log(` 📌 Estado: ${titulo}`); - - await actualizarCelda( - spreadsheetId, - `G${element.fila}:H${element.fila}`, - [titulo, descripcion] - ); - } catch (dataError) { - console.error(' ❌ Error al obtener datos de la página:', dataError); - throw dataError; - } + const [titulo, descripcion] = await Promise.all([ + page.$eval('.conditionalLanding h2', el => el.innerText), + page.$eval('.conditionalLanding p', el => el.innerText) + ]); + await actualizarCelda(spreadsheetId, `G${element.fila}:H${element.fila}`, [titulo, descripcion]); } - - await delay(1000); - return true; // Indica que el proceso fue exitoso - + return true; } catch (error) { - console.error(' ❌ Error procesando caso USCIS:', error); - if (intentos < MAX_INTENTOS) { - console.log(` 🔄 Reintentando... (${intentos}/${MAX_INTENTOS})`); return await procesarCasoUSCIS(page, element, spreadsheetId, intentos + 1); } else { - console.log(' ⚠️ Se agotaron los intentos o error no recuperable'); - await actualizarCelda( - spreadsheetId, - `G${element.fila}`, - ['Error al procesar el caso. Por favor, intente más tarde.'] - ); - return false; // Indica que el proceso falló + await actualizarCelda(spreadsheetId, `G${element.fila}`, ['Error al procesar el caso']); + return false; } } } -// Modificar la función procesarArchivo para manejar mejor la reconexión de Chrome +async function procesarArchivoEnGrupo(filas, archivo, port, userDir) { + const browser = await initBrowserEnPuerto(CONFIG.PLATFORMS.USCIS.URL, port, userDir); + const page = (await browser.pages())[0]; + for (const element of filas) { + const fechaHoraActual = new Date().toLocaleString('es-ES', { + year: 'numeric', month: '2-digit', day: '2-digit', + hour: '2-digit', minute: '2-digit', second: '2-digit' + }); + await Promise.all([ + actualizarCelda(archivo.id, `F${element.fila}`, [fechaHoraActual]), + actualizarCelda(archivo.id, `G${element.fila}:H${element.fila}`, ['', '']) + ]); + await procesarCasoUSCIS(page, element, archivo.id); + } + await browser.close(); +} + async function procesarArchivo(archivo) { - console.log('\n🔍 Analizando archivo:', archivo.name); const datos = await obtenerDatosHoja(archivo.id); - const platform_type = 'uscis'; - const platform = CONFIG.PLATFORMS[platform_type.toUpperCase()].URL; + const filas = datos.slice(1).map((row, index) => ({ + valor: row[4], fila: index + 2, + ultimaConsulta: row[5], resultado: row[6] + })).filter(row => !row.resultado || !row.ultimaConsulta || ((new Date() - new Date(row.ultimaConsulta)) / 3600000 > 1)); - const todasLasFilas = datos.slice(1) - .map((row, index) => ({ - valor: row[4], // Columna 5 (Valor a consultar) - fila: index + 2, // Número de fila real - ultimaConsulta: row[5], // Columna 6 (Fecha de última consulta) - resultado: row[6] // Columna 7 (Resultado) - })); + if (!filas.length) return; - // Filter rows that need processing (either G is empty or F is older than 1 hour) - const filasAProcesar = todasLasFilas.filter(row => { - if (!row.resultado) return true; // Prioritize if column G (resultado) is empty + const numProcesos = 4; + const chunkSize = Math.ceil(filas.length / numProcesos); + const grupos = Array.from({ length: numProcesos }, (_, i) => filas.slice(i * chunkSize, (i + 1) * chunkSize)); - if (!row.ultimaConsulta) return true; // If no date in F, also process (even if G is not empty) - - const [date, time] = row.ultimaConsulta.split(', '); - const [day, month, year] = date.split('/'); - const [hours, minutes, seconds] = time.split(':'); - - const fechaUltimaConsulta = new Date(year, month - 1, day, hours, minutes, seconds); - const ahora = new Date(); - - const diferenciaHoras = (ahora - fechaUltimaConsulta) / (1000 * 60 * 60); - - if (fechaUltimaConsulta > ahora) return false; // For future dates, return false to skip processing - - return diferenciaHoras > 1; // Process only if more than 1 hour has passed - }); - - // Separate rows into three groups based on priority - const filasVaciasG = filasAProcesar.filter(row => !row.resultado); - const filasVaciasF = filasAProcesar.filter(row => row.resultado && !row.ultimaConsulta); - const filasConFechaF = filasAProcesar.filter(row => row.resultado && row.ultimaConsulta); - - // Sort rows with date in F by oldest date first - filasConFechaF.sort((a, b) => { - const [dateA, timeA] = a.ultimaConsulta.split(', '); - const [dayA, monthA, yearA] = dateA.split('/'); - const [hoursA, minutesA, secondsA] = timeA.split(':'); - const fechaA = new Date(yearA, monthA - 1, dayA, hoursA, minutesA, secondsA); - - const [dateB, timeB] = b.ultimaConsulta.split(', '); - const [dayB, monthB, yearB] = dateB.split('/'); - const [hoursB, minutesB, secondsB] = timeB.split(':'); - const fechaB = new Date(yearB, monthB - 1, dayB, hoursB, minutesB, secondsB); - - return fechaA - fechaB; // Ascending order (oldest first) - }); - - // Combine the arrays in the specified priority order - const filasOrdenadas = [...filasVaciasG, ...filasConFechaF, ...filasVaciasF]; - - console.log(filasOrdenadas); - - - console.log(`📊 Total de filas a procesar: ${filasOrdenadas.length}`); - - if (filasOrdenadas.length > 0) { - console.log('🌐 Iniciando navegador...'); - let browser = await initBrowser(platform); - let page = (await browser.pages())[0]; - let fallosConsecutivos = 0; - const MAX_FALLOS_CONSECUTIVOS = 3; - - let procesadas = 0; - for (const element of filasOrdenadas) { - procesadas++; - console.log(`\n⏳ Procesando fila ${element.fila} (${procesadas}/${filasOrdenadas.length})`); - console.log(`📝 Valor a consultar: ${element.valor}`); - - // Guardar la fecha y hora actual - const fechaHoraActual = new Date().toLocaleString('es-ES', { - year: 'numeric', - month: '2-digit', - day: '2-digit', - hour: '2-digit', - minute: '2-digit', - second: '2-digit' - }); - - // Actualizar la marca de tiempo en la columna F y limpiar las columnas G y H - await Promise.all([ - actualizarCelda( - archivo.id, - `F${element.fila}`, - [fechaHoraActual] - ), - actualizarCelda( - archivo.id, - `G${element.fila}:H${element.fila}`, - ['', ''] - ) - ]); - - const resultado = await procesarCasoUSCIS(page, element, archivo.id); - - if (!resultado) { - fallosConsecutivos++; - if (fallosConsecutivos >= MAX_FALLOS_CONSECUTIVOS) { - console.log('🔄 Reiniciando navegador debido a fallos consecutivos...'); - await browser.close(); - await cerrarChromeDebugging(); - await delay(2000); - - browser = await initBrowser(platform); - page = (await browser.pages())[0]; - fallosConsecutivos = 0; - } - } else { - fallosConsecutivos = 0; - } - } - - console.log('\n✅ Proceso completado para el archivo:', archivo.name); - await browser.close(); - } else { - console.log('ℹ️ No hay filas para procesar en este archivo'); - } + await Promise.all(grupos.map((grupo, i) => { + if (grupo.length === 0) return; + const port = 9224 + i; + const userDir = `C:/temp/chrome_debug_temp_migracion_${i}`; + return procesarArchivoEnGrupo(grupo, archivo, port, userDir); + })); } -// Función para cerrar el navegador y la aplicación async function cerrarTodo() { - if (browser) { - await browser.close(); // Cerrar el navegador si está abierto - } - console.log('🔄 Cerrando Chrome debugging y finalizando...'); await cerrarChromeDebugging(); process.exit(); - app.quit(); // Cerrar la aplicación Electron + app.quit(); } -// Manejar la señal SIGINT (Ctrl + C) process.on('SIGINT', async () => { - console.log('Recibida señal de interrupción (Ctrl + C)'); + console.log('Ctrl + C detectado'); await cerrarTodo(); }); -// Función principal async function procesarArchivos() { - try { - console.log('🚀 Iniciando proceso...'); - const archivos = await listarArchivosEnCarpeta(CONFIG.DRIVE.FOLDER_ID); - console.log(`📁 Total de archivos encontrados: ${archivos.length}`); - - let procesados = 0; - for (const archivo of archivos) { - procesados++; - console.log(`\n📌 Procesando archivo ${procesados}/${archivos.length}: ${archivo.name}`); - await procesarArchivo(archivo); - } - console.log('\n🎉 Proceso completado exitosamente!'); - } catch (error) { - console.error('❌ Error en el proceso:', error); - } finally { - await cerrarTodo(); // Asegúrate de cerrar todo al final + const archivos = await listarArchivosEnCarpeta(CONFIG.DRIVE.FOLDER_ID); + for (const archivo of archivos) { + await procesarArchivo(archivo); } + await cerrarTodo(); } -// Ejecutar el proceso app.on('ready', () => { - console.log('Aplicación Electron está lista y en ejecución sin ventana.'); procesarArchivos(); -}); +}); \ No newline at end of file