diff --git a/robot.js b/robot.js new file mode 100644 index 0000000..75ec421 --- /dev/null +++ b/robot.js @@ -0,0 +1,148 @@ +// 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(); \ No newline at end of file