diff --git a/migrations/20260703_lugar_formulario_modo.sql b/migrations/20260703_lugar_formulario_modo.sql new file mode 100644 index 0000000..df13d46 --- /dev/null +++ b/migrations/20260703_lugar_formulario_modo.sql @@ -0,0 +1,2 @@ +ALTER TABLE turnero_lugares + ADD COLUMN IF NOT EXISTS formulario_modo ENUM('link','embebido') NOT NULL DEFAULT 'link'; diff --git a/modules/turnero/api/get_consent_token.php b/modules/turnero/api/get_consent_token.php new file mode 100644 index 0000000..0f36fff --- /dev/null +++ b/modules/turnero/api/get_consent_token.php @@ -0,0 +1,52 @@ +prepare( + "SELECT tlc.formulario_id FROM turnero_lugar_consentimientos tlc + JOIN lab_formularios f ON f.id = tlc.formulario_id AND f.is_active = 1 + WHERE tlc.lugar_id = ? + ORDER BY tlc.formulario_id ASC LIMIT 1" +); +$formRow->execute([$lugarId]); +$form = $formRow->fetch(PDO::FETCH_ASSOC); +if (!$form) jsonError('No hay formulario configurado para este lugar', 404); + +$formularioId = (int)$form['formulario_id']; + +// Buscar token existente +$existing = $pdo->prepare( + "SELECT token FROM turnero_consentimientos WHERE turno_id = ? AND formulario_id = ? LIMIT 1" +); +$existing->execute([$turnoId, $formularioId]); +$row = $existing->fetch(PDO::FETCH_ASSOC); + +if ($row) { + jsonOk(['token' => $row['token'], 'nuevo' => false]); +} + +// Crear nuevo token +$token = sprintf( + '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', + mt_rand(0,0xffff), mt_rand(0,0xffff), + mt_rand(0,0xffff), + mt_rand(0,0x0fff)|0x4000, + mt_rand(0,0x3fff)|0x8000, + mt_rand(0,0xffff), mt_rand(0,0xffff), mt_rand(0,0xffff) +); +$pdo->prepare( + "INSERT IGNORE INTO turnero_consentimientos (turno_id, formulario_id, token, estado) VALUES (?, ?, ?, 'pendiente')" +)->execute([$turnoId, $formularioId, $token]); + +jsonOk(['token' => $token, 'nuevo' => true]); diff --git a/modules/turnero/api/save_lugar.php b/modules/turnero/api/save_lugar.php index 78aac38..b8b353d 100644 --- a/modules/turnero/api/save_lugar.php +++ b/modules/turnero/api/save_lugar.php @@ -52,6 +52,8 @@ $sortOrder = (int)($input['sort_order'] ?? 99); $activo = (int)($input['activo'] ?? 1); $tipo = in_array($input['tipo'] ?? '', ['recepcion', 'muestras'], true) ? $input['tipo'] : 'muestras'; +$formModo = in_array($input['formulario_modo'] ?? '', ['link', 'embebido'], true) + ? $input['formulario_modo'] : 'link'; $formularioIds = isset($input['formulario_ids']) && is_array($input['formulario_ids']) ? array_filter(array_map('intval', $input['formulario_ids']), fn($v) => $v > 0) : []; @@ -64,15 +66,15 @@ $pdo->beginTransaction(); try { if ($id) { $stmt = $pdo->prepare( - 'UPDATE turnero_lugares SET nombre=?, tipo=?, descripcion=?, sort_order=?, activo=? WHERE id=?' + 'UPDATE turnero_lugares SET nombre=?, tipo=?, descripcion=?, sort_order=?, activo=?, formulario_modo=? WHERE id=?' ); - $stmt->execute([$nombre, $tipo, $desc ?: null, $sortOrder, $activo, $id]); + $stmt->execute([$nombre, $tipo, $desc ?: null, $sortOrder, $activo, $formModo, $id]); $lugarId = $id; } else { $stmt = $pdo->prepare( - 'INSERT INTO turnero_lugares (nombre, tipo, descripcion, sort_order, activo) VALUES (?, ?, ?, ?, ?)' + 'INSERT INTO turnero_lugares (nombre, tipo, descripcion, sort_order, activo, formulario_modo) VALUES (?, ?, ?, ?, ?, ?)' ); - $stmt->execute([$nombre, $tipo, $desc ?: null, $sortOrder, $activo]); + $stmt->execute([$nombre, $tipo, $desc ?: null, $sortOrder, $activo, $formModo]); $lugarId = (int) $pdo->lastInsertId(); } diff --git a/modules/turnero/views/configuracion.php b/modules/turnero/views/configuracion.php index 0433ba2..4e26b5e 100644 --- a/modules/turnero/views/configuracion.php +++ b/modules/turnero/views/configuracion.php @@ -207,7 +207,7 @@ $tab = $_GET['tab'] ?? 'lugares'; = $lu['activo'] ? 'Activo' : 'Inactivo' ?> - + @@ -268,7 +268,7 @@ $tab = $_GET['tab'] ?? 'lugares'; - + @@ -334,7 +334,7 @@ $tab = $_GET['tab'] ?? 'lugares'; - Consentimientos requeridos para este lugar + Formularios de consentimiento @@ -352,6 +352,23 @@ $tab = $_GET['tab'] ?? 'lugares'; No hay formularios activos configurados. + + Modo de presentación del formulario + + + + + Enviar por link / WA + + + + + + Embebido en pantalla + + + + + + + Formulario de consentimiento + + Cargando formulario... + + + + + Consentimientos informados @@ -389,9 +403,10 @@ let hayPendientes = false; let pollingColaId = null; let pollingConsentId = null; -const API = '= BASE_URL ?>modules/turnero/api/'; -const BASE_WA = '= BASE_URL ?>'; -const LUGAR_NOMBRE = document.getElementById('lbl-lugar-titulo')?.textContent || '= addslashes($lugarNombre) ?>'; +const API = '= BASE_URL ?>modules/turnero/api/'; +const BASE_WA = '= BASE_URL ?>'; +const LUGAR_NOMBRE = document.getElementById('lbl-lugar-titulo')?.textContent || '= addslashes($lugarNombre) ?>'; +const LUGAR_FORM_MODO = '= $lugarFormModo ?>'; // ── Arranque ────────────────────────────────────────────────── @@ -523,6 +538,9 @@ async function seleccionarSinLlamar(turnoId) { await cargarFichaSolicitud(t.id); clearInterval(pollingConsentId); pollingConsentId = setInterval(() => actualizarConsentimientos(turnoActivo?.id), 5000); + if (LUGAR_FORM_MODO === 'embebido' && lugarId) { + cargarFormEmbebido(t.id); + } mostrarFichaMobile(); } @@ -596,6 +614,12 @@ async function abrirFicha(turno) { // Iniciar polling de consentimientos clearInterval(pollingConsentId); pollingConsentId = setInterval(() => actualizarConsentimientos(turnoActivo?.id), 5000); + + // Formulario embebido + if (LUGAR_FORM_MODO === 'embebido' && lugarId) { + cargarFormEmbebido(turno.id); + } + mostrarFichaMobile(); } @@ -835,12 +859,41 @@ async function cambiarEstadoTurno(nuevoEstado) { } // ── Reset ───────────────────────────────────────────────────── +async function cargarFormEmbebido(turnoId) { + const sec = document.getElementById('sec-form-embebido'); + const iframe = document.getElementById('form-embebido-iframe'); + const load = document.getElementById('form-embebido-loading'); + if (!sec || !iframe) return; + sec.classList.remove('d-none'); + iframe.style.display = 'none'; + load.style.display = ''; + try { + const res = await fetch(`${API}get_consent_token.php?turno_id=${turnoId}&lugar_id=${lugarId}`); + const json = await res.json(); + if (json.ok && json.token) { + iframe.src = `${BASE_WA}ver_formulario_enviado.php?token=${encodeURIComponent(json.token)}`; + } else { + load.innerHTML = '' + (json.error || 'No hay formulario configurado') + ''; + } + } catch (e) { + load.innerHTML = 'Error al cargar formulario'; + } +} + function resetFicha() { clearInterval(pollingConsentId); turnoActivo = null; tieneConsent = false; hayPendientes = false; + // Limpiar iframe embebido + const iframe = document.getElementById('form-embebido-iframe'); + const sec = document.getElementById('sec-form-embebido'); + const load = document.getElementById('form-embebido-loading'); + if (iframe) { iframe.src = ''; iframe.style.display = 'none'; } + if (sec) { sec.classList.add('d-none'); } + if (load) { load.style.display = ''; load.innerHTML = 'Cargando formulario...'; } + document.getElementById('ficha-turno').classList.add('d-none'); document.getElementById('ficha-placeholder').classList.remove('d-none'); document.getElementById('badge-turno-activo').classList.add('d-none');