diff --git a/modules/turnero/api/anexar_formulario.php b/modules/turnero/api/anexar_formulario.php
new file mode 100644
index 0000000..2a4f355
--- /dev/null
+++ b/modules/turnero/api/anexar_formulario.php
@@ -0,0 +1,43 @@
+prepare("SELECT id, sesion_id, estado FROM turnero_turnos WHERE id = ? LIMIT 1");
+$turno->execute([$turnoId]);
+$t = $turno->fetch(PDO::FETCH_ASSOC);
+if (!$t) jsonError('Turno no encontrado.', 404);
+if (!in_array($t['estado'], ['en_espera_lugar', 'en_servicio'])) jsonError('El turno no está activo.');
+
+// Verificar que el formulario existe
+$form = $pdo->prepare("SELECT id, nombre FROM lab_formularios WHERE id = ? AND is_active = 1 LIMIT 1");
+$form->execute([$formularioId]);
+if (!$form->fetch()) jsonError('Formulario no encontrado o inactivo.', 404);
+
+// Crear el consentimiento con token único
+$token = bin2hex(random_bytes(16));
+
+$ins = $pdo->prepare(
+ "INSERT INTO turnero_consentimientos (turno_id, formulario_id, token, estado, datos_respuestas)
+ VALUES (?, ?, ?, 'enviado', '{}')"
+);
+$ins->execute([$turnoId, $formularioId, $token]);
+$newId = (int)$pdo->lastInsertId();
+
+notificarSSE((int)$t['sesion_id']);
+jsonOk(['id' => $newId, 'token' => $token], 'Formulario agregado.');
diff --git a/modules/turnero/views/lugar.php b/modules/turnero/views/lugar.php
index cd5af58..fe0f631 100644
--- a/modules/turnero/views/lugar.php
+++ b/modules/turnero/views/lugar.php
@@ -92,6 +92,13 @@ foreach ($lugares as $_el) {
$especialidades[] = $_el;
}
}
+
+$formulariosList = [];
+try {
+ $formulariosList = Database::getInstance()->getConnection()
+ ->query("SELECT id, nombre FROM lab_formularios WHERE is_active = 1 ORDER BY nombre ASC")
+ ->fetchAll(PDO::FETCH_ASSOC);
+} catch (\Throwable $_) {}
?>
@@ -836,6 +843,11 @@ require_once __DIR__ . '/../../../shared/components/sidebar.php';
No se requieren consentimientos
+
+
+
@@ -1027,6 +1039,7 @@ let _tomaProgresivaActiva = false;
let hayMuestrasPendientes = false;
let _solicitudActiva = null;
let _muestrasActivas = [];
+const _formulariosList = = json_encode($formulariosList, JSON_UNESCAPED_UNICODE) ?>;
const API = '= BASE_URL ?>modules/turnero/api/';
const BASE_WA = '= BASE_URL ?>';
@@ -1667,7 +1680,7 @@ async function _olvidarConsentimiento(token, nombre) {
});
const j = await r.json();
if (!j.ok) { mostrarError(j.error || 'Error al resetear'); return; }
- cargarConsentimientos();
+ if (turnoActivo?.id) actualizarConsentimientos(turnoActivo.id);
} catch(e) { mostrarError(e.message); }
}
@@ -2061,10 +2074,45 @@ function resetFicha() {
document.getElementById('btn-regresar').classList.add('d-none');
document.getElementById('btn-rellamar').classList.add('d-none');
document.getElementById('btn-devolver').classList.add('d-none');
+ document.getElementById('btn-anexar-wrap')?.classList.add('d-none');
volverACola();
}
+// ── Anexar formulario ─────────────────────────────────────────
+function _abrirAnexarFormulario() {
+ const sel = document.getElementById('sel-anexar-form');
+ sel.innerHTML = '';
+ _formulariosList.forEach(f => {
+ const o = document.createElement('option');
+ o.value = f.id; o.textContent = f.nombre;
+ sel.appendChild(o);
+ });
+ document.getElementById('anexar-form-msg').style.display = 'none';
+ document.getElementById('btn-guardar-anexar').disabled = false;
+ document.getElementById('modal-anexar-form').style.display = 'flex';
+}
+function _cerrarAnexarFormulario() {
+ document.getElementById('modal-anexar-form').style.display = 'none';
+}
+async function _guardarAnexarFormulario() {
+ const fId = parseInt(document.getElementById('sel-anexar-form').value);
+ const msg = document.getElementById('anexar-form-msg');
+ if (!fId) { msg.textContent = 'Selecciona un formulario.'; msg.style.display=''; return; }
+ const btn = document.getElementById('btn-guardar-anexar');
+ btn.disabled = true;
+ try {
+ const r = await fetch('modules/turnero/api/anexar_formulario.php', {
+ method: 'POST', headers: {'Content-Type':'application/json'},
+ body: JSON.stringify({ turno_id: turnoActivo.id, formulario_id: fId })
+ });
+ const j = await r.json();
+ if (!j.ok) { msg.textContent = j.error || 'Error al agregar.'; msg.style.display=''; btn.disabled=false; return; }
+ _cerrarAnexarFormulario();
+ actualizarConsentimientos(turnoActivo.id);
+ } catch(e) { msg.textContent = e.message; msg.style.display=''; btn.disabled=false; }
+}
+
// ── Mobile ────────────────────────────────────────────────────
function esMobile() { return window.innerWidth <= 680; }
@@ -2099,6 +2147,7 @@ function actualizarEstadoBadge(estado) {
const btnDev = document.getElementById('btn-devolver');
const btnEsp = document.getElementById('btn-espera');
+ const btnAnexar = document.getElementById('btn-anexar-wrap');
if (estado === 'en_espera_lugar') {
btnIni.classList.remove('d-none'); btnIni.disabled = false;
btnFin.classList.add('d-none');
@@ -2106,6 +2155,7 @@ function actualizarEstadoBadge(estado) {
btnRellamar.classList.add('d-none');
btnDev.classList.remove('d-none');
if (btnEsp) btnEsp.classList.add('d-none');
+ if (btnAnexar) btnAnexar.classList.add('d-none');
} else if (estado === 'en_servicio') {
btnIni.classList.add('d-none');
btnFin.classList.remove('d-none');
@@ -2114,6 +2164,7 @@ function actualizarEstadoBadge(estado) {
btnDev.classList.remove('d-none');
// btn-espera: solo si hay toma progresiva activa (sincronizado desde renderConsentimientos)
if (btnEsp) btnEsp.classList.add('d-none');
+ if (btnAnexar) btnAnexar.classList.remove('d-none');
}
}
@@ -2864,6 +2915,26 @@ function _renderEspecialidades(grupos) {
})();
+
+
+