From f3aac68a4fc05b19af57e6578d6e9022692e1d58 Mon Sep 17 00:00:00 2001 From: marsalva Date: Sun, 28 Dec 2025 20:57:03 +0000 Subject: [PATCH] Actualizar robot_cobros.js --- robot_cobros.js | 197 +++++++++++++++++++++++++----------------------- 1 file changed, 101 insertions(+), 96 deletions(-) diff --git a/robot_cobros.js b/robot_cobros.js index 5e06f74..e0a2ba9 100644 --- a/robot_cobros.js +++ b/robot_cobros.js @@ -3,7 +3,7 @@ const { chromium } = require('playwright'); const admin = require('firebase-admin'); const cors = require('cors'); -// --- 1. CONFIGURACIÓN (Solo para leer credenciales) --- +// --- CONFIGURACIÓN --- try { if (process.env.FIREBASE_PRIVATE_KEY) { if (!admin.apps.length) { @@ -15,142 +15,147 @@ try { }), }); } - console.log("✅ Firebase inicializado (Solo para leer usuario/pass)."); } -} catch (e) { console.error("❌ Error Firebase:", e.message); } +} catch (e) { console.error("Firebase Error:", e.message); } const db = admin.apps.length ? admin.firestore() : null; - const app = express(); app.use(cors({ origin: '*' })); app.use(express.json()); -// --- 2. ENDPOINT (AHORA ESPERA AL ROBOT) --- +// --- ENDPOINT --- app.post('/api/robot-cobros', async (req, res) => { - console.log("🔔 Petición recibida: Modo Simulación."); - + console.log("🔔 DIAGNÓSTICO: Iniciando..."); try { - // Esperamos a que el robot termine y nos de los datos - const resultados = await runLiquidationScanner(); - - // Se los enviamos al navegador - res.json({ - success: true, - message: "Escaneo completado", - data: resultados - }); + const reporte = await runDiagnostic(); + res.json({ success: true, message: "Diagnóstico finalizado", data: reporte }); } catch (err) { - console.error("❌ Error en robot:", err); + console.error("❌ Error Fatal:", err); res.status(500).json({ success: false, message: err.message }); } }); -app.get('/', (req, res) => res.send('🤖 Robot Scanner ONLINE (Modo Lectura)')); +app.get('/', (req, res) => res.send('🤖 Robot Sherlock ONLINE')); -// --- 3. LÓGICA DE ESCANEO (SIN GUARDAR) --- -async function runLiquidationScanner() { +// --- LÓGICA DE DETECTIVE --- +async function runDiagnostic() { let browser = null; + const logs = []; // Aquí guardaremos las pistas + + function apuntar(msg) { + console.log(msg); + logs.push({ expediente: "INFO", direccion: msg, importeLimpio: 0 }); + } + try { - console.log("🚀 Lanzando navegador..."); - - // 1. Credenciales - let user = "TU_USUARIO"; - let pass = "TU_PASS"; - + // 1. CREDENCIALES + let user = ""; let pass = ""; if (db) { const doc = await db.collection("providerCredentials").doc("homeserve").get(); - if (doc.exists) { - user = doc.data().user; - pass = doc.data().pass; - } + if (doc.exists) { user = doc.data().user; pass = doc.data().pass; } + } + if (!user) { + apuntar("❌ ERROR: No tengo usuario/pass en Firebase."); + return logs; } + apuntar("🚀 Lanzando navegador..."); browser = await chromium.launch({ headless: true, args: ['--no-sandbox'] }); const page = await browser.newPage(); - // 2. Login - console.log("🌍 Login HomeServe..."); + // 2. LOGIN + apuntar("🌍 Entrando al Login..."); await page.goto('https://www.clientes.homeserve.es/cgi-bin/fccgi.exe?w3exec=PROF_PASS', { timeout: 60000 }); - - const selUser = 'input[name="CODIGO"]'; - if (await page.isVisible(selUser)) { - await page.fill(selUser, user); + + const enLogin = await page.isVisible('input[name="CODIGO"]'); + if (enLogin) { + apuntar("🔑 Formulario detectado. Escribiendo..."); + await page.fill('input[name="CODIGO"]', user); await page.fill('input[type="password"]', pass); await page.keyboard.press('Enter'); await page.waitForTimeout(4000); + } else { + apuntar("⚠️ No vi el formulario de login. ¿Ya estaba dentro?"); } - // 3. Ir a Liquidaciones - console.log("📂 Sección Liquidaciones..."); + // 3. NAVEGAR A LIQUIDACIONES + apuntar("📂 Yendo a Consultar Liquidaciones..."); await page.goto('https://www.clientes.homeserve.es/cgi-bin/fccgi.exe?w3exec=CONSULTALIQ_WEB'); await page.waitForTimeout(2000); - // 4. Buscar enlace - console.log("🔍 Buscando última liquidación..."); - const liquidacionClicked = await page.evaluate(() => { + apuntar(`📍 URL actual: ${page.url()}`); + + // 4. INTENTAR CLICKAR FECHA + // Buscamos enlaces que parezcan una fecha YYYYMMDD o similar + const clickado = await page.evaluate(() => { const links = Array.from(document.querySelectorAll('a')); - // Busca enlace dentro de una celda que tenga texto largo (la fecha) - const target = links.find(l => l.closest('td') && l.innerText.length > 5); - if (target) { target.click(); return true; } - return false; - }); - - if (!liquidacionClicked) console.log("⚠️ No clické fecha (quizá ya estamos dentro)."); - await page.waitForTimeout(3000); - - // 5. Botón Desglose - const desgloseClicked = await page.evaluate(() => { - const inputs = Array.from(document.querySelectorAll('input[type="button"], a, button')); - const target = inputs.find(el => (el.value || el.innerText || "").toLowerCase().includes('desglose')); - if (target) { target.click(); return true; } - return false; - }); - if(desgloseClicked) await page.waitForTimeout(3000); - - // 6. LEER DATOS Y DEVOLVERLOS (NO GUARDAR) - console.log("💰 Extrayendo datos para el usuario..."); - - const extractedData = await page.evaluate(() => { - const filas = Array.from(document.querySelectorAll('tr')); - const lista = []; - - filas.forEach(tr => { - const tds = tr.querySelectorAll('td'); - // Estructura detectada en tu saldo.html: - // Col 0: Servicio, Col 1: Dirección, Col 4: Importe Autofra (Base) - if (tds.length >= 5) { - const txtServicio = tds[0].innerText.trim(); - const txtDir = tds[1].innerText.trim(); - const txtImporte = tds[4].innerText.trim(); - - if (/^\d{6,}$/.test(txtServicio)) { - lista.push({ - expediente: txtServicio, - direccion: txtDir, - importeRaw: txtImporte - }); - } - } + // Busca el primer enlace que NO sea de menú y tenga numeros + const target = links.find(l => { + const txt = l.innerText.trim(); + // Heurística: Si tiene más de 4 números seguidos, probablemente es una fecha/expediente + return /\d{4}/.test(txt) && !txt.includes('FACTURACION'); }); - return lista; + if (target) { + const texto = target.innerText; + target.click(); + return texto; + } + return null; }); - // Procesar importes (Limpieza de puntos decimales) - const finalData = extractedData.map(item => { - // "27.67" -> 27.67 (Float) - const clean = item.importeRaw.replace(/[^\d.-]/g, ''); - return { - ...item, - importeLimpio: parseFloat(clean) || 0 - }; + if (clickado) { + apuntar(`🖱️ Click realizado en enlace: "${clickado}"`); + await page.waitForTimeout(3000); + } else { + apuntar("⚠️ No encontré ningún enlace de fecha para hacer clic. ¿Está la lista vacía?"); + } + + // 5. BUSCAR DESGLOSE + const hayBotonDesglose = await page.isVisible('input[value*="Desglose" i]'); + if (hayBotonDesglose) { + apuntar("🔘 Botón 'Desglose' detectado. Pulsando..."); + await page.click('input[value*="Desglose" i]'); + await page.waitForTimeout(3000); + } + + // 6. ANÁLISIS VISUAL DE LA TABLA (EL MOMENTO DE LA VERDAD) + apuntar("👀 Analizando estructura de la página..."); + + const diagnosticoPagina = await page.evaluate(() => { + const resultado = []; + + // A) Buscar la tabla amarilla específica de saldo.html + const tablaAmarilla = document.querySelector('table[bgcolor="#F8E8A6"]'); + + if (tablaAmarilla) { + resultado.push({ expediente: "EXITO", direccion: "✅ TABLA AMARILLA ENCONTRADA", importeLimpio: 1 }); + + // Leemos las 3 primeras filas para ver qué hay dentro + const filas = Array.from(tablaAmarilla.querySelectorAll('tr')); + resultado.push({ expediente: "INFO", direccion: `La tabla tiene ${filas.length} filas.`, importeLimpio: 0 }); + + filas.slice(0, 5).forEach((tr, i) => { + resultado.push({ + expediente: `FILA ${i}`, + direccion: tr.innerText.substring(0, 50) + "...", // Primeros 50 caracteres + importeLimpio: 0 + }); + }); + } else { + // B) Si no hay tabla amarilla, ¿qué hay? + resultado.push({ expediente: "ERROR", direccion: "❌ NO VEO LA TABLA AMARILLA", importeLimpio: 0 }); + const bodyText = document.body.innerText.substring(0, 100).replace(/\n/g, ' '); + resultado.push({ expediente: "DUMP", direccion: `Texto visible: ${bodyText}`, importeLimpio: 0 }); + } + + return resultado; }); - console.log(`✅ Devolviendo ${finalData.length} registros al frontend.`); - return finalData; + return [...logs, ...diagnosticoPagina]; } catch (e) { - console.error("❌ Error:", e); - throw e; + apuntar("❌ CRASH: " + e.message); + return logs; } finally { if (browser) await browser.close(); }