diff --git a/worker-multi-estado.js b/worker-multi-estado.js index badded7..6defecd 100644 --- a/worker-multi-estado.js +++ b/worker-multi-estado.js @@ -22,6 +22,7 @@ function toServerTimestamp() { return admin.firestore.FieldValue.serverTimestamp function timeToMultiValue(timeStr) { if (!timeStr) return ""; const [h, m] = timeStr.split(':').map(Number); + // Formato interno de Multi: segundos desde medianoche return String((h * 3600) + (m * 60)); } @@ -40,19 +41,6 @@ function initFirebase() { return admin.firestore(); } -// --- HELPERS AVANZADOS --- -// Esta función es la clave: obliga a la web a reconocer el cambio -async function triggerEvents(page, selector) { - await page.evaluate((sel) => { - const el = document.querySelector(sel); - if (el) { - el.dispatchEvent(new Event('input', { bubbles: true })); - el.dispatchEvent(new Event('change', { bubbles: true })); - el.dispatchEvent(new Event('blur', { bubbles: true })); - } - }, selector); -} - // --- LOGIN --- async function loginMulti(page, db) { let user = "", pass = ""; @@ -84,6 +72,17 @@ async function withBrowser(fn) { try { return await fn(page); } finally { await browser.close().catch(() => {}); } } +// --- HELPERS DE EVENTOS --- +async function forceUpdate(elementHandle) { + if (elementHandle) { + await elementHandle.evaluate(el => { + el.dispatchEvent(new Event('input', { bubbles: true })); + el.dispatchEvent(new Event('change', { bubbles: true })); + el.dispatchEvent(new Event('blur', { bubbles: true })); + }); + } +} + // --- LÓGICA PRINCIPAL --- async function processChangeState(page, db, jobData) { const { serviceNumber, reasonValue, comment, dateStr, timeStr } = jobData; @@ -93,76 +92,76 @@ async function processChangeState(page, db, jobData) { // 2. IR AL SERVICIO const targetUrl = `${CONFIG.MULTI_ACTION_BASE}?reparacion=${serviceNumber}&modo=0&navid=%2Fw3multi%2Ffrepasos_new.php%FDGET%FDrefresh%3D1%FC`; - console.log(`📂 Abriendo servicio ${serviceNumber}...`); + console.log(`📂 Abriendo servicio 27867185...`); // Log limpio para depurar await page.goto(targetUrl, { waitUntil: 'domcontentloaded', timeout: 60000 }); // Esperar formulario await page.waitForSelector('select.answer-select', { timeout: 20000 }); - await page.waitForTimeout(2000); // Esperar a que Angular "se asiente" + await page.waitForTimeout(1500); - console.log('📝 Rellenando formulario (Modo Fuerza Bruta)...'); + console.log('📝 Rellenando formulario (Modo Preciso)...'); - // 3. MOTIVO (SELECT) - // Seleccionamos y forzamos el evento 'change' - const reasonSel = 'select.answer-select'; - await page.selectOption(reasonSel, String(reasonValue)); - await triggerEvents(page, reasonSel); - await page.waitForTimeout(500); + // 3. MOTIVO (Primer select de la página suele ser el motivo) + const reasonSel = page.locator('select.answer-select').first(); + await reasonSel.selectOption(String(reasonValue)); + await forceUpdate(await reasonSel.elementHandle()); // 4. COMENTARIO if (comment) { - const commentSel = 'textarea[formcontrolname="comment"]'; - await page.fill(commentSel, comment); - await triggerEvents(page, commentSel); + const commentBox = page.locator('textarea[formcontrolname="comment"]'); + await commentBox.fill(comment); + await forceUpdate(await commentBox.elementHandle()); } // 5. FECHA if (dateStr) { - const dateSel = 'input[type="date"]'; - await page.fill(dateSel, dateStr); - await triggerEvents(page, dateSel); - // Truco: hacer click fuera para validar + const dateInput = page.locator('input[type="date"]'); + await dateInput.fill(dateStr); + await forceUpdate(await dateInput.elementHandle()); + // Click fuera para asegurar validación de fecha await page.click('body'); } - // 6. HORA + // 6. HORA (El punto crítico) if (timeStr) { - const secondsValue = timeToMultiValue(timeStr); - // Buscamos el select de hora. Puede ser el segundo select de la página. - // Usamos una estrategia de búsqueda por valor para ser precisos. - const foundTime = await page.evaluate((val) => { - const selects = Array.from(document.querySelectorAll('select')); - for (const s of selects) { - // Si tiene la opción con ese valor (ej: 28800) - if (s.querySelector(`option[value="${val}"]`)) { - s.value = val; - s.dispatchEvent(new Event('change', { bubbles: true })); - s.dispatchEvent(new Event('blur', { bubbles: true })); - return true; - } - } - return false; - }, secondsValue); - - if (!foundTime) console.log(`⚠️ Advertencia: No encontré donde poner la hora ${timeStr}`); + const secondsValue = timeToMultiValue(timeStr); // ej: "28800" para 08:00 + console.log(`🕒 Intentando poner hora: ${timeStr} (Valor interno: ${secondsValue})`); + + // ESTRATEGIA INFALIBLE: Buscar el select que contiene esa opción específica usando XPath + // "Búscame un