From c511da18bd5c586598dbbd64a0a2990541fbb6b3 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Fri, 3 Jul 2026 08:13:38 -0500 Subject: [PATCH] recepcion: fix solo_muestras, reorder fields, duplicar visita, kiosko label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - create_solicitud.php: evitar SQL `IN ()` vacío cuando solo_muestras=1 sin exámenes - recepcion.php: mover embarazada+médico después del historial del paciente - recepcion.php: actualizar label kiosko con nombre real al vincular paciente - recepcion.php: botón "Duplicar" en historial para copiar exámenes y pago de última visita - recepcion.php: omitir validación de consentimientos pendientes cuando es solo_muestras - recepcion.php: agregar alias esc() = escHtml() usado en buscarMedico Co-Authored-By: Claude Sonnet 4.6 --- modules/turnero/api/create_solicitud.php | 16 ++-- modules/turnero/views/recepcion.php | 112 +++++++++++++++++------ 2 files changed, 94 insertions(+), 34 deletions(-) diff --git a/modules/turnero/api/create_solicitud.php b/modules/turnero/api/create_solicitud.php index 9cbba38..acc008d 100644 --- a/modules/turnero/api/create_solicitud.php +++ b/modules/turnero/api/create_solicitud.php @@ -94,13 +94,15 @@ try { jsonError('Lugar destino no encontrado o inactivo.', 404); } - // Verificar que todos los exam_tipo_ids existen - $in = implode(',', array_fill(0, count($examIds), '?')); - $stmt = $pdo->prepare("SELECT COUNT(*) FROM exam_tipos WHERE id IN ({$in}) AND activo = 1"); - $stmt->execute($examIds); - if ((int)$stmt->fetchColumn() !== count($examIds)) { - $pdo->rollBack(); - jsonError('Uno o más exámenes no existen o están inactivos.', 422); + // Verificar que todos los exam_tipo_ids existen (se omite si solo_muestras y sin exámenes) + if (!empty($examIds)) { + $in = implode(',', array_fill(0, count($examIds), '?')); + $stmt = $pdo->prepare("SELECT COUNT(*) FROM exam_tipos WHERE id IN ({$in}) AND activo = 1"); + $stmt->execute($examIds); + if ((int)$stmt->fetchColumn() !== count($examIds)) { + $pdo->rollBack(); + jsonError('Uno o más exámenes no existen o están inactivos.', 422); + } } // ── Insertar o reemplazar solicitud (DELETE + INSERT para poder re-guardar) ── diff --git a/modules/turnero/views/recepcion.php b/modules/turnero/views/recepcion.php index 461d6ee..84ec2e1 100644 --- a/modules/turnero/views/recepcion.php +++ b/modules/turnero/views/recepcion.php @@ -404,7 +404,7 @@ document.addEventListener('DOMContentLoaded', function() {
- Nombre del kiosko: + Kiosko:
@@ -438,6 +438,29 @@ document.addEventListener('DOMContentLoaded', function() { + +
+ +
+
+
+ Cargando… +
+
+
+
+
@@ -468,22 +491,6 @@ document.addEventListener('DOMContentLoaded', function() {
- - -
- -
-
-
- Cargando… -
-
-
-
@@ -1038,10 +1045,11 @@ function abrirFicha(turno) { document.getElementById('badge-turno-activo').classList.remove('d-none'); document.getElementById('badge-codigo').textContent = turno.codigo; - // Nombre del kiosko + // Nombre del kiosko (valor capturado en kiosko; se actualiza al vincular paciente) if (turno.paciente_nombre) { document.getElementById('bloque-nombre-kiosko').classList.remove('d-none'); document.getElementById('lbl-nombre-kiosko').textContent = turno.paciente_nombre; + document.getElementById('lbl-kiosko-label').textContent = 'Kiosko:'; document.getElementById('inp-buscar-pac').value = turno.paciente_nombre; } @@ -1154,13 +1162,19 @@ function seleccionarPaciente(pac) { } document.getElementById('bloque-pac-no-vinculado').classList.add('d-none'); document.getElementById('bloque-pac-seleccionado').classList.remove('d-none'); - document.getElementById('lbl-pac-nombre').textContent = - (pac.full_name || (pac.nombre||'') + ' ' + (pac.apellido||'')).trim(); + const pacNombre = (pac.full_name || pac.nombre_completo || (pac.nombre||'') + ' ' + (pac.apellido||'')).trim(); + document.getElementById('lbl-pac-nombre').textContent = pacNombre; document.getElementById('lbl-pac-doc').textContent = (pac.tipo_documento||'') + ' ' + (pac.documento||pac.numero_documento||''); document.getElementById('lbl-pac-cel').textContent = pac.telefono || pac.celular || ''; document.getElementById('lista-pacientes-res').innerHTML = ''; + // Actualizar etiqueta kiosko con el nombre real del paciente vinculado + const lblKiosko = document.getElementById('lbl-nombre-kiosko'); + if (lblKiosko && document.getElementById('bloque-nombre-kiosko').classList.contains('d-none') === false) { + lblKiosko.textContent = pacNombre; + document.getElementById('lbl-kiosko-label').textContent = 'Cliente:'; + } // Mostrar historial del paciente const secHist = document.getElementById('sec-historial-pac'); @@ -1168,6 +1182,7 @@ function seleccionarPaciente(pac) { // Resetear estado colapsado document.getElementById('hist-pac-body').classList.add('d-none'); document.getElementById('btn-hist-toggle').classList.remove('open'); + document.getElementById('btn-duplicar-wrap').classList.remove('d-none'); // Precargar en background (usuario decide si abre) _historialPacienteCargado = false; _historialPacienteId = pac.id; @@ -1203,6 +1218,7 @@ function desvincularPaciente() { document.getElementById('sec-historial-pac').classList.add('d-none'); document.getElementById('hist-pac-body').classList.add('d-none'); document.getElementById('btn-hist-toggle').classList.remove('open'); + document.getElementById('btn-duplicar-wrap').classList.add('d-none'); document.getElementById('lista-pacientes-res').innerHTML = ''; document.getElementById('inp-buscar-pac').value = ''; document.getElementById('chk-embarazada').checked = false; @@ -1314,14 +1330,16 @@ async function guardarSolicitud() { const lugarId = parseInt(document.getElementById('sel-lugar').value); if (!lugarId) { mostrarError('Seleccione el lugar destino.'); return; } - // ✅ VALIDACIÓN: verificar que los consentimientos del lugar estén firmados - const consentPendientes = Array.from(document.querySelectorAll('.consent-item.pendiente, .consent-item.enviado, .consent-item.visto')).length; - if (consentPendientes > 0) { - mostrarError('⚠️ El paciente debe firmar los consentimientos del lugar antes de guardar la solicitud.'); - return; - } - const soloMuestras = document.getElementById('chk-solo-muestras').checked; + + // ✅ VALIDACIÓN: verificar que los consentimientos del lugar estén firmados (omitir en solo muestras) + if (!soloMuestras) { + const consentPendientes = Array.from(document.querySelectorAll('.consent-item.pendiente, .consent-item.enviado, .consent-item.visto')).length; + if (consentPendientes > 0) { + mostrarError('⚠️ El paciente debe firmar los consentimientos del lugar antes de guardar la solicitud.'); + return; + } + } const examIds = Array.from(document.querySelectorAll('.exam-chk:checked')).map(c => parseInt(c.value)); if (!soloMuestras && !examIds.length) { mostrarError('Seleccione al menos un examen.'); return; } @@ -1739,6 +1757,45 @@ function resetMedico() { quitarMedico(); } +async function duplicarUltimaVisita() { + if (!_historialPacienteId) { mostrarError('No hay paciente seleccionado.'); return; } + mostrarToast('Buscando última visita…', 'info', 1500); + try { + // 1. Obtener el turno más reciente del paciente + const rH = await fetch(`${API}get_historial.php?paciente_id=${_historialPacienteId}&per_page=1&page=1`); + const jH = await rH.json(); + if (!jH.ok || !jH.turnos?.length) { mostrarError('Sin visitas anteriores para duplicar.'); return; } + const ultimoTurnoId = jH.turnos[0].id; + + // 2. Obtener solicitud + exámenes de esa visita + const rS = await fetch(`${API}get_consentimientos.php?turno_id=${ultimoTurnoId}&incluir_solicitud=1`); + const jS = await rS.json(); + if (!jS.ok || !jS.examenes?.length) { mostrarError('La última visita no tiene exámenes registrados.'); return; } + + // 3. Pre-marcar checkboxes con los exam_tipo_ids + const ids = new Set(jS.examenes.map(e => String(e.id))); + let marcados = 0; + document.querySelectorAll('.exam-chk').forEach(c => { + const match = ids.has(c.value); + c.checked = match; + if (match) marcados++; + }); + + // 4. Pre-llenar pago si viene + if (jS.solicitud?.metodo_pago) { + document.getElementById('sel-pago').value = jS.solicitud.metodo_pago; + togglePagoCombinado(); + } + if (jS.solicitud?.total_cobrado) { + document.getElementById('inp-total').value = jS.solicitud.total_cobrado; + } + + mostrarToast(`Duplicado: ${marcados} exámen${marcados !== 1 ? 'es' : ''} copiado${marcados !== 1 ? 's' : ''}.`, 'success', 3000); + } catch (e) { + mostrarError('Error al duplicar: ' + e.message); + } +} + function escJs(s) { return String(s||'').replace(/\\/g,'\\\\').replace(/'/g,"\\'"); } function toggleSoloMuestras() { @@ -1766,6 +1823,7 @@ function escHtml(str) { d.appendChild(document.createTextNode(String(str))); return d.innerHTML; } +const esc = escHtml; function resetPlaceholder() { const ph = document.getElementById('ficha-placeholder');