diff --git a/robot_cobros.js b/robot_cobros.js index 48287d3..fe1b808 100644 --- a/robot_cobros.js +++ b/robot_cobros.js @@ -3,229 +3,111 @@ 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'), - }), - }); +// --- 1. CONFIGURACIÓN FIREBASE --- +// Si falla al iniciar, simplemente avisa pero no tira el servidor, +// para que al menos responda al ping del HTML. +try { + if (process.env.FIREBASE_PRIVATE_KEY) { + if (!admin.apps.length) { + 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."); + } else { + console.warn("⚠️ NO HAY CLAVES DE FIREBASE. El robot funcionará pero no guardará datos."); } - } 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)"); +} catch (e) { + console.error("❌ Error Firebase:", e.message); } -const db = admin.firestore(); -const APPOINTMENTS_COL = "appointments"; -const PROVIDER_DOC = "homeserve"; +const db = admin.apps.length ? admin.firestore() : null; +const COLLECTION_NAME = "homeserve_pendientes"; // O la que uses para guardar cobros // --- 2. SERVIDOR EXPRESS --- const app = express(); -app.use(cors()); // Permite peticiones desde tu HTML + +// IMPORTANTE: CORS para permitir que tu HTML hable con este servidor +app.use(cors({ origin: '*' })); 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(); +// Ruta de prueba para ver si el servidor está vivo desde el navegador +app.get('/', (req, res) => { + res.send('🤖 El Robot de Cobros está ONLINE y esperando órdenes.'); }); -// --- 5. LÓGICA PRINCIPAL DEL ROBOT --- -async function runCobrosRobot() { +// --- 3. ENDPOINT QUE LLAMA EL HTML --- +app.post('/api/robot-cobros', async (req, res) => { + console.log("🔔 Petición recibida desde la web."); + + // Respondemos INMEDIATAMENTE para que el HTML sepa que hemos oído + res.json({ success: true, message: "Orden recibida. Iniciando motor..." }); + + // Ejecutamos la lógica pesada sin bloquear + runRobotLogic().catch(err => console.error("❌ Error fatal en robot:", err)); +}); + +// --- 4. LÓGICA DEL ROBOT (Playwright) --- +async function runRobotLogic() { + console.log("🚀 Lanzando navegador..."); let browser = null; + try { - console.log('🤖 Iniciando Robot de Cobros...'); + // 1. Obtener credenciales (o usar simuladas si falla la DB) + let user = "USUARIO_DEFECTO"; + let pass = "PASS_DEFECTO"; - // 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."); + if (db) { + const doc = await db.collection("providerCredentials").doc("homeserve").get(); + if (doc.exists) { + user = doc.data().user; + pass = doc.data().pass; + } } - // 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