commit bf3c045bda15e0e2725595786a0c39b0d63cccac Author: marsalva Date: Tue Jan 6 21:28:15 2026 +0000 Añadir worker-multi-estado.js diff --git a/worker-multi-estado.js b/worker-multi-estado.js new file mode 100644 index 0000000..7187eb8 --- /dev/null +++ b/worker-multi-estado.js @@ -0,0 +1,231 @@ +// worker-multi-estado.js +'use strict'; + +const { chromium } = require('playwright'); +const admin = require('firebase-admin'); + +// --- CONFIGURACIÓN --- +const CONFIG = { + QUEUE_COLLECTION: 'multiasistencia_cambios_estado', + RESULT_COLLECTION: 'multiasistencia_cambios_estado_log', + + // URLs base + MULTI_LOGIN: "https://web.multiasistencia.com/w3multi/acceso.php", + // La URL base para construir la dirección del servicio + MULTI_ACTION_BASE: "https://web.multiasistencia.com/w3multi/fechaccion.php", + + NAV_TIMEOUT: 60000, + RESCAN_SECONDS: 60 +}; + +// --- UTILS --- +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +function toServerTimestamp() { return admin.firestore.FieldValue.serverTimestamp(); } + +// Conversor de Hora (HH:MM) a Segundos desde media noche (formato interno Multi) +// Ej: "08:00" -> 28800 +function timeToMultiValue(timeStr) { + if (!timeStr) return ""; + const [h, m] = timeStr.split(':').map(Number); + return String((h * 3600) + (m * 60)); +} + +// --- FIREBASE INIT --- +function initFirebase() { + if (!process.env.FIREBASE_PRIVATE_KEY) throw new Error('Missing 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'), + }), + }); + } + return admin.firestore(); +} + +// --- LOGIN (Reutilizado de tu robot_cobros) --- +async function loginMulti(page, db) { + let user = "", pass = ""; + + // Buscamos credenciales en Firestore + const doc = await db.collection("providerCredentials").doc("multiasistencia").get(); + if (doc.exists) { + user = doc.data().user; + pass = doc.data().pass; + } + + if (!user) throw new Error("Faltan credenciales en providerCredentials/multiasistencia"); + + console.log('🔐 Login en Multiasistencia...'); + await page.goto(CONFIG.MULTI_LOGIN, { timeout: 60000, waitUntil: 'domcontentloaded' }); + + // Lógica de llenado robusta + const userFilled = await page.evaluate((u) => { + const el = document.querySelector('input[name="usuario"]') || document.querySelector('input[type="text"]'); + if (el) { el.value = u; el.dispatchEvent(new Event('input', { bubbles: true })); return true; } + return false; + }, user); + + if (!userFilled) await page.fill('input[name="usuario"]', user); + await page.fill('input[type="password"]', pass); + + await page.click('input[type="submit"]'); + await page.waitForTimeout(4000); +} + +// --- PLAYWRIGHT HELPERS --- +async function withBrowser(fn) { + const browser = await chromium.launch({ headless: true, args: ['--no-sandbox'] }); + const context = await browser.newContext(); + const page = await context.newPage(); + try { return await fn(page); } finally { await browser.close().catch(() => {}); } +} + +// --- LÓGICA PRINCIPAL DE CAMBIO DE ESTADO --- +async function processChangeState(page, db, jobData) { + const { serviceNumber, reasonValue, comment, dateStr, timeStr } = jobData; + + // 1. LOGIN + await loginMulti(page, db); + + // 2. IR A LA URL DEL SERVICIO + // Construimos la URL exacta que pediste con el navid incluido + const targetUrl = `${CONFIG.MULTI_ACTION_BASE}?reparacion=${serviceNumber}&modo=0&navid=%2Fw3multi%2Ffrepasos_new.php%FDGET%FDrefresh%3D1%FC`; + + console.log(`📂 Abriendo servicio ${serviceNumber}...`); + await page.goto(targetUrl, { waitUntil: 'domcontentloaded', timeout: 60000 }); + + // Esperar a que cargue el formulario (Angular puede tardar) + // Buscamos el selector del motivo para saber que cargó + await page.waitForSelector('select.answer-select', { timeout: 20000 }); + + console.log('📝 Rellenando formulario...'); + + // 3. SELECCIONAR MOTIVO (Reason) + // El HTML muestra