const express = require('express'); const { chromium } = require('playwright'); const admin = require('firebase-admin'); const cors = require('cors'); // --- 1. CONFIGURACIÓN FIREBASE (IGUAL QUE TU ROBOT ORIGINAL) --- if (process.env.FIREBASE_PRIVATE_KEY) { try { if (!admin.apps.length) { // Evita error si ya está inicializado 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'), }), }); } } catch (err) { console.error("❌ Error inicializando Firebase:", err.message); process.exit(1); } } else { // Para pruebas locales sin variables de entorno, puedes descomentar esto: // var serviceAccount = require("./serviceAccountKey.json"); // admin.initializeApp({ credential: admin.credential.cert(serviceAccount) }); console.error("⚠️ FALTAN LAS CLAVES DE FIREBASE (ENV)"); } const db = admin.firestore(); const APPOINTMENTS_COL = "appointments"; const PROVIDER_DOC = "homeserve"; // --- 2. SERVIDOR EXPRESS --- const app = express(); app.use(cors()); // Permite peticiones desde tu HTML app.use(express.json()); // --- 3. FUNCIONES AUXILIARES --- async function getProviderCredentials(providerDocId) { const snap = await db.collection("providerCredentials").doc(providerDocId).get(); if (!snap.exists) throw new Error(`No existe providerCredentials/${providerDocId}`); const data = snap.data() || {}; return { user: String(data.user || "").trim(), pass: String(data.pass || "").trim() }; } function normalizeServiceNumber(raw) { // Extrae solo dígitos. Homeserve suele usar números largos. return String(raw || "").trim().replace(/\D/g, ""); } function parseMoney(str) { // Convierte "1.200,50 €" -> 1200.50 if (!str) return 0; let clean = str.replace(/[€\s]/g, ''); // Quitar símbolo y espacios clean = clean.replace(/\./g, ''); // Quitar separador miles (punto) clean = clean.replace(',', '.'); // Cambiar coma decimal por punto return parseFloat(clean) || 0; } // --- 4. ENDPOINT DEL ROBOT --- app.post('/api/robot-cobros', async (req, res) => { console.log("🚀 Recibida orden de rescate de cobros..."); // Respondemos rápido al cliente para que no se quede cargando infinitamente res.json({ success: true, message: "Robot iniciado. Revisa la consola." }); // Ejecutamos la lógica en segundo plano await runCobrosRobot(); }); // --- 5. LÓGICA PRINCIPAL DEL ROBOT --- async function runCobrosRobot() { let browser = null; try { console.log('🤖 Iniciando Robot de Cobros...'); // 1. OBTENER CREDENCIALES const creds = await getProviderCredentials(PROVIDER_DOC); console.log(`🔐 Credenciales cargadas para ${creds.user}`); // 2. LANZAR NAVEGADOR browser = await chromium.launch({ headless: true, // Pon false si quieres ver lo que hace en el servidor local args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const context = await browser.newContext(); const page = await context.newPage(); // 3. LOGIN (Misma lógica que tu robot de servicios) console.log('🌍 Entrando a HomeServe...'); await page.goto('https://www.clientes.homeserve.es/cgi-bin/fccgi.exe?w3exec=PROF_PASS', { timeout: 60000 }); const selectorUsuario = 'input[name="CODIGO"]'; const selectorPass = 'input[type="password"]'; if (await page.isVisible(selectorUsuario)) { console.log('🔑 Logueándose...'); await page.fill(selectorUsuario, ""); await page.fill(selectorPass, ""); await page.type(selectorUsuario, creds.user, { delay: 80 }); await page.type(selectorPass, creds.pass, { delay: 80 }); await page.keyboard.press('Enter'); await page.waitForTimeout(5000); } else { console.log("⚠️ Ya estaba logueado o no veo el login."); } // 4. IR A LIQUIDACIONES console.log('📂 Navegando a Liquidaciones...'); await page.goto('https://www.clientes.homeserve.es/cgi-bin/fccgi.exe?w3exec=CONSULTALIQ_WEB'); await page.waitForTimeout(2000); // 5. SELECCIONAR LA ÚLTIMA LIQUIDACIÓN // Buscamos el primer enlace dentro de la tabla de resultados. // Normalmente las webs viejas usan tablas. Buscamos el primer dentro de un