Actualizar worker-multiasistencia.js

This commit is contained in:
2026-03-11 17:00:46 +00:00
parent f89486b85b
commit 319dee87d2

View File

@@ -1,4 +1,4 @@
// worker-multiasistencia.js (Versión PostgreSQL SaaS)
// worker-multiasistencia.js (Versión PostgreSQL SaaS + Escáner de Campos Dinámicos)
import { chromium } from 'playwright';
import pg from 'pg';
@@ -114,7 +114,6 @@ async function loginMulti(page, creds) {
await page.click('input[type="submit"]');
await page.waitForTimeout(4000);
// Verificación básica de login (Si sigue estando el input de password, falló)
const isStillLogin = await page.locator('input[type="password"]').count();
if (isStillLogin > 0) throw new Error("Credenciales rechazadas por Multiasistencia.");
}
@@ -122,7 +121,7 @@ async function loginMulti(page, creds) {
// --- PROCESO PRINCIPAL ---
async function processChangeState(page, creds, jobData) {
const serviceNumber = jobData.service_number;
const reasonValue = jobData.new_status; // Asumimos que la API ya le pasa el ID numérico web
const reasonValue = jobData.new_status;
const comment = jobData.observation;
const dateStr = normalizeDate(jobData.appointment_date);
@@ -142,7 +141,7 @@ async function processChangeState(page, creds, jobData) {
await page.waitForSelector('select.answer-select', { timeout: 20000 });
await page.waitForTimeout(1000);
// SELECCIONAR MOTIVO
// 1. SELECCIONAR MOTIVO
console.log(` [3] Seleccionando estado ${reasonValue}...`);
const reasonSel = page.locator('select.answer-select').first();
const options = await reasonSel.evaluate(s => Array.from(s.options).map(o => o.value));
@@ -154,14 +153,14 @@ async function processChangeState(page, creds, jobData) {
await reasonSel.selectOption(String(reasonValue));
await forceUpdate(await reasonSel.elementHandle());
// COMENTARIO
// 2. COMENTARIO
if (comment) {
const commentBox = page.locator('textarea[formcontrolname="comment"]');
await commentBox.fill(comment);
await forceUpdate(await commentBox.elementHandle());
}
// FECHA SIGUIENTE ACCIÓN (Solo si existe fecha y es válida)
// 3. FECHA SIGUIENTE ACCIÓN (TXTFACCION) - La de la cita real
if (dateStr) {
const actionBlock = page.locator('encastrables-date-hour-field[label="TXTFACCION"]');
if (await actionBlock.count() > 0) {
@@ -173,52 +172,62 @@ async function processChangeState(page, creds, jobData) {
if (timeStr) {
const seconds = timeToMultiValue(timeStr);
const timeSel = actionBlock.locator('select.answer-select');
await timeSel.selectOption(seconds).catch(()=>{ console.log(' ⚠️ No se pudo poner la hora exacta') });
await timeSel.selectOption(seconds).catch(()=>{});
await forceUpdate(await timeSel.elementHandle());
}
} else {
// Fallback
// Fallback genérico por si cambia la etiqueta
const genDate = page.locator('input[type="date"]').first();
await genDate.fill(dateStr);
await forceUpdate(await genDate.elementHandle());
if (await genDate.count() > 0) {
await genDate.fill(dateStr);
await forceUpdate(await genDate.elementHandle());
}
}
}
// FECHA CONTACTO (AUTOMÁTICA - HOY)
const contactBlock = page.locator('encastrables-date-hour-field[label="TXTFCONTACTO"]');
if (await contactBlock.count() > 0 && await contactBlock.isVisible()) {
console.log(' [INFO] Rellenando fecha de contacto (Auto Hoy)...');
const now = getCurrentDateTime();
const cDate = contactBlock.locator('input[type="date"]');
await cDate.fill(now.dateStr);
await forceUpdate(await cDate.elementHandle());
// 4. AUTO-RELLENADOR INTELIGENTE (Detecta campos obligatorios dinámicos)
const extraDynamicFields = ['TXTFCONTACTO', 'TXTFPRIMERAV'];
for (const label of extraDynamicFields) {
const block = page.locator(`encastrables-date-hour-field[label="${label}"]`);
if (await block.count() > 0 && await block.isVisible()) {
console.log(` [INFO] Detectado campo obligatorio "${label}". Auto-rellenando...`);
const now = getCurrentDateTime();
// Rellenar Fecha
const cDate = block.locator('input[type="date"]');
await cDate.fill(now.dateStr);
await forceUpdate(await cDate.elementHandle());
const selects = contactBlock.locator('select.answer-select-time');
if (await selects.count() >= 2) {
await selects.nth(0).selectOption(now.hourStr).catch(()=>{});
await forceUpdate(await selects.nth(0).elementHandle());
await selects.nth(1).selectOption(now.minStr).catch(()=>{});
await forceUpdate(await selects.nth(1).elementHandle());
// Rellenar Hora y Minutos (Multiasistencia usa 2 selects separados para esto)
const selects = block.locator('select.answer-select-time');
if (await selects.count() >= 2) {
await selects.nth(0).selectOption(now.hourStr).catch(()=>{});
await forceUpdate(await selects.nth(0).elementHandle());
await selects.nth(1).selectOption(now.minStr).catch(()=>{});
await forceUpdate(await selects.nth(1).elementHandle());
}
}
}
await page.waitForTimeout(2000);
// GUARDAR (CON INTELIGENCIA ANTI-BLOQUEO)
// 5. GUARDAR (CON INTELIGENCIA ANTI-BLOQUEO)
const btn = page.locator('button.form-container-button-submit');
if (await btn.isDisabled()) {
console.log(' [INFO] Botón bloqueado. Forzando actualización de inputs...');
await page.locator('textarea[formcontrolname="comment"]').click();
await page.keyboard.press('Tab');
await page.waitForTimeout(1000);
if (await btn.isDisabled()) throw new Error(`El formulario está bloqueado (falta algún dato obligatorio).`);
if (await btn.isDisabled()) throw new Error(`El formulario está bloqueado. Multiasistencia pide más datos de los previstos.`);
}
console.log(' [4] Guardando cambios en Multiasistencia...');
await btn.click();
// GESTIÓN DE ALERTAS (Popups de confirmación)
// GESTIÓN DE ALERTAS (Popups de confirmación que a veces lanza la web)
await page.waitForTimeout(3000);
const confirmBtn = page.locator('button.form-container-button-submit-toast').filter({ hasText: 'Sí' });
if (await confirmBtn.count() > 0 && await confirmBtn.isVisible()) {