// robot-homeserve/robot.js const { chromium } = require('playwright'); const admin = require('firebase-admin'); // --- CONFIGURACIÓN FIREBASE (desde ENV de Render) --- if (process.env.FIREBASE_PRIVATE_KEY) { try { admin.initializeApp({ credential: admin.credential.cert({ projectId: process.env.FIREBASE_PROJECT_ID, clientEmail: process.env.FIREBASE_CLIENT_EMAIL, privateKey: process.env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, '\n'), }), }); console.log("✅ Firebase inicializado correctamente"); } catch (err) { console.error("❌ Error inicializando Firebase:", err); process.exit(1); } } else { console.error("❌ Falta FIREBASE_PRIVATE_KEY en las variables de entorno"); process.exit(1); } const db = admin.firestore(); // --- VARIABLES DE ENTORNO --- const HOMESERVE_USER = process.env.HOMESERVE_USER; const HOMESERVE_PASS = process.env.HOMESERVE_PASS; if (!HOMESERVE_USER || !HOMESERVE_PASS) { console.error("❌ Faltan HOMESERVE_USER o HOMESERVE_PASS en ENV"); process.exit(1); } // --- FUNCIONES UTILES --- async function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function safeText(str) { return (str || '').toString().trim(); } // --- LOGICA PRINCIPAL --- async function main() { const browser = await chromium.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'], }); const context = await browser.newContext(); const page = await context.newPage(); try { console.log("🌐 Entrando a HomeServe..."); await page.goto('https://gestor.homeserve.es/', { waitUntil: 'domcontentloaded', timeout: 120000 }); // Login console.log("🔐 Login..."); await page.waitForSelector('input[type="text"]', { timeout: 60000 }); await page.fill('input[type="text"]', HOMESERVE_USER); const selectorPass = 'input[type="password"]'; await page.waitForSelector(selectorPass, { timeout: 60000 }); await page.fill(selectorPass, HOMESERVE_PASS); // Botón entrar (puede variar) const btn = await page.$('button[type="submit"]'); if (btn) { await btn.click(); } else { // fallback: enter await page.keyboard.press('Enter'); } // Espera a panel await page.waitForLoadState('networkidle', { timeout: 120000 }); console.log("✅ Logueado"); // Ir a lista de servicios / pendientes (URL/selector depende del portal) // Aquí se mantiene la lógica robusta con esperas y tolerancia. await delay(4000); // Ejemplo: navegar a "Pendientes" // (esto puede variar según HomeServe) const pendientesLink = await page.$('text=Pendientes'); if (pendientesLink) { await pendientesLink.click(); await page.waitForLoadState('networkidle', { timeout: 120000 }); await delay(2000); } // Extraer tabla/listado console.log("📥 Extrayendo servicios..."); const servicios = await page.evaluate(() => { // Intenta detectar filas en tabla const rows = Array.from(document.querySelectorAll('table tbody tr')) || Array.from(document.querySelectorAll('tbody tr')); return rows.map(r => { const cells = Array.from(r.querySelectorAll('td')).map(td => td.innerText.trim()); return { cells }; }).filter(x => x && x.cells && x.cells.length > 0); }); console.log(`🧾 Encontrados ${servicios.length} servicios (filas)`); // Guardar en Firestore const batch = db.batch(); const col = db.collection('homeserve_pendientes'); let saved = 0; for (const item of servicios) { // Aquí puedes mapear celdas a campos reales según tu tabla. // Ejemplo genérico: const ref = col.doc(); batch.set(ref, { raw: item, createdAt: admin.firestore.FieldValue.serverTimestamp(), source: 'homeserve', }); saved++; // Firestore batch max 500 ops if (saved % 450 === 0) { await batch.commit(); } } await batch.commit(); console.log(`✅ Guardados ${saved} registros en Firestore (homeserve_pendientes)`); } catch (err) { console.error("❌ Error en robot HomeServe:", err); try { await page.screenshot({ path: '/tmp/error-homeserve.png', fullPage: true }); console.log("📸 Screenshot guardada en /tmp/error-homeserve.png"); } catch (e) {} process.exitCode = 1; } finally { await browser.close(); console.log("🧹 Browser cerrado"); } } main();