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() {
+
+
+
+
+ Historial del paciente
+
+
+ Duplicar
+
+
+
+
+
+
+
@@ -468,22 +491,6 @@ document.addEventListener('DOMContentLoaded', function() {
-
-
-
-
-
- Historial del paciente
-
-
-
-
@@ -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');