feat: encuesta de satisfacción post-finalizar toma de muestras
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
4a4cbc31b8
commit
2455417bb4
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* POST /modules/turnero/api/enviar_encuesta.php
|
||||||
|
* Envía la plantilla "encuesta" al paciente del turno vía WhatsApp turnero.
|
||||||
|
* Body JSON: { turno_id: int }
|
||||||
|
*/
|
||||||
|
require_once __DIR__ . '/_helpers.php';
|
||||||
|
require_once __DIR__ . '/../../../services/WhatsAppService.php';
|
||||||
|
requireMethod('POST');
|
||||||
|
requireTurnero();
|
||||||
|
|
||||||
|
$body = inputJson();
|
||||||
|
$turnoId = (int)($body['turno_id'] ?? 0);
|
||||||
|
if (!$turnoId) jsonError('turno_id requerido.');
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Obtener user_id y teléfono del paciente vía turnero_turnos → lab_pacientes → users
|
||||||
|
$row = $pdo->prepare(
|
||||||
|
"SELECT u.id AS user_id, u.phone_number, t.paciente_cel, t.paciente_nombre
|
||||||
|
FROM turnero_turnos t
|
||||||
|
LEFT JOIN lab_pacientes lp ON lp.id = t.paciente_id
|
||||||
|
LEFT JOIN users u ON u.id = lp.user_id
|
||||||
|
WHERE t.id = ? LIMIT 1"
|
||||||
|
);
|
||||||
|
$row->execute([$turnoId]);
|
||||||
|
$pac = $row->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$pac) jsonError('Turno no encontrado.', 404);
|
||||||
|
|
||||||
|
$userId = $pac['user_id'] ? (int)$pac['user_id'] : null;
|
||||||
|
$phone = $pac['phone_number'] ?? null;
|
||||||
|
|
||||||
|
// Fallback: buscar por paciente_cel si no hay user_id
|
||||||
|
if (!$userId && !empty($pac['paciente_cel'])) {
|
||||||
|
$cel = preg_replace('/\D/', '', $pac['paciente_cel']);
|
||||||
|
$u2 = $pdo->prepare("SELECT id, phone_number FROM users WHERE REPLACE(phone_number,'+','') LIKE ? LIMIT 1");
|
||||||
|
$u2->execute(['%' . substr($cel, -10)]);
|
||||||
|
$uRow = $u2->fetch(PDO::FETCH_ASSOC);
|
||||||
|
if ($uRow) { $userId = (int)$uRow['id']; $phone = $uRow['phone_number']; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$userId || !$phone) jsonError('El paciente no tiene número de WhatsApp registrado.');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$wa = new WhatsAppService('turnero');
|
||||||
|
$meta = ['canal' => 'turnero', 'operator_id' => adminId()];
|
||||||
|
$wa->sendTemplateMessage($phone, 'encuesta', 'es_CO', [], [], null, $meta);
|
||||||
|
jsonOk(['mensaje' => 'Encuesta enviada a ' . ($pac['paciente_nombre'] ?? $phone)]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
jsonError('Error al enviar: ' . $e->getMessage());
|
||||||
|
}
|
||||||
@@ -994,6 +994,26 @@ require_once __DIR__ . '/../../../shared/components/sidebar.php';
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- ── Bar encuesta post-finalizar ─────────────────────────────── -->
|
||||||
|
<div id="bar-encuesta" style="
|
||||||
|
display:none;position:fixed;bottom:0;left:0;right:0;z-index:9100;
|
||||||
|
background:#0f4c81;color:#fff;padding:14px 20px;
|
||||||
|
display:none;align-items:center;gap:14px;flex-wrap:wrap;
|
||||||
|
box-shadow:0 -4px 20px rgba(0,0,0,.25)">
|
||||||
|
<i class="fas fa-star" style="font-size:1.2rem;color:#fbbf24;flex-shrink:0"></i>
|
||||||
|
<span id="bar-encuesta-txt" style="flex:1;font-size:.95rem;font-weight:500"></span>
|
||||||
|
<button onclick="_enviarEncuesta()" id="btn-enc-enviar"
|
||||||
|
style="background:#22c55e;color:#fff;border:none;border-radius:8px;
|
||||||
|
padding:8px 18px;font-weight:600;cursor:pointer;white-space:nowrap">
|
||||||
|
<i class="fas fa-paper-plane me-1"></i>Enviar encuesta
|
||||||
|
</button>
|
||||||
|
<button onclick="_cerrarEncuestaBar()"
|
||||||
|
style="background:rgba(255,255,255,.15);color:#fff;border:none;border-radius:8px;
|
||||||
|
padding:8px 14px;cursor:pointer;white-space:nowrap">
|
||||||
|
Omitir
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- ── Modal de consentimiento embebido (modo embebido) ────────── -->
|
<!-- ── Modal de consentimiento embebido (modo embebido) ────────── -->
|
||||||
<div id="modal-consentimiento" style="
|
<div id="modal-consentimiento" style="
|
||||||
display:none;position:fixed;inset:0;z-index:9000;
|
display:none;position:fixed;inset:0;z-index:9000;
|
||||||
@@ -1961,7 +1981,9 @@ async function finalizarAtencion() {
|
|||||||
if (hayPendientes) { mostrarError('Debe firmar todos los consentimientos antes de finalizar.'); return; }
|
if (hayPendientes) { mostrarError('Debe firmar todos los consentimientos antes de finalizar.'); return; }
|
||||||
if (hayMuestrasPendientes) { mostrarError('Debe marcar cada muestra como recibida o pendiente antes de finalizar.'); return; }
|
if (hayMuestrasPendientes) { mostrarError('Debe marcar cada muestra como recibida o pendiente antes de finalizar.'); return; }
|
||||||
if (!confirm(`¿Finalizar atención del turno ${turnoActivo.codigo}?`)) return;
|
if (!confirm(`¿Finalizar atención del turno ${turnoActivo.codigo}?`)) return;
|
||||||
await cambiarEstadoTurno('finalizado');
|
const _t = { id: turnoActivo.id, paciente_nombre: turnoActivo.paciente_nombre };
|
||||||
|
const ok = await cambiarEstadoTurno('finalizado');
|
||||||
|
if (ok) _ofrecerEncuesta(_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function marcarAusente() {
|
async function marcarAusente() {
|
||||||
@@ -2024,15 +2046,58 @@ async function cambiarEstadoTurno(nuevoEstado) {
|
|||||||
} else {
|
} else {
|
||||||
mostrarError(json.error);
|
mostrarError(json.error);
|
||||||
}
|
}
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
resetFicha();
|
resetFicha();
|
||||||
cargarCola();
|
cargarCola();
|
||||||
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
mostrarError(err.message);
|
mostrarError(err.message);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Encuesta post-finalizar ───────────────────────────────────
|
||||||
|
let _encuestaTurnoId = null, _encuestaTimer = null;
|
||||||
|
|
||||||
|
function _ofrecerEncuesta(turno) {
|
||||||
|
_encuestaTurnoId = turno.id;
|
||||||
|
const bar = document.getElementById('bar-encuesta');
|
||||||
|
document.getElementById('bar-encuesta-txt').textContent =
|
||||||
|
`¿Enviar encuesta de satisfacción a ${turno.paciente_nombre || 'el paciente'}?`;
|
||||||
|
document.getElementById('btn-enc-enviar').disabled = false;
|
||||||
|
document.getElementById('btn-enc-enviar').innerHTML = '<i class="fas fa-paper-plane me-1"></i>Enviar encuesta';
|
||||||
|
bar.style.display = 'flex';
|
||||||
|
clearTimeout(_encuestaTimer);
|
||||||
|
_encuestaTimer = setTimeout(_cerrarEncuestaBar, 12000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function _enviarEncuesta() {
|
||||||
|
if (!_encuestaTurnoId) return;
|
||||||
|
const btn = document.getElementById('btn-enc-enviar');
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Enviando…';
|
||||||
|
try {
|
||||||
|
const res = await fetch(API + 'enviar_encuesta.php', {
|
||||||
|
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ turno_id: _encuestaTurnoId }),
|
||||||
|
});
|
||||||
|
const json = await res.json();
|
||||||
|
_cerrarEncuestaBar();
|
||||||
|
if (json.ok) mostrarToast('Encuesta enviada ✓', 'success', 3000);
|
||||||
|
else mostrarToast('No se pudo enviar: ' + (json.error || 'error'), 'warning', 4000);
|
||||||
|
} catch (e) {
|
||||||
|
_cerrarEncuestaBar();
|
||||||
|
mostrarToast('Error al enviar encuesta', 'warning', 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _cerrarEncuestaBar() {
|
||||||
|
clearTimeout(_encuestaTimer);
|
||||||
|
document.getElementById('bar-encuesta').style.display = 'none';
|
||||||
|
_encuestaTurnoId = null;
|
||||||
|
}
|
||||||
|
|
||||||
// ── Reset ficha ───────────────────────────────────────────────
|
// ── Reset ficha ───────────────────────────────────────────────
|
||||||
function resetFicha() {
|
function resetFicha() {
|
||||||
clearInterval(pollingConsentId);
|
clearInterval(pollingConsentId);
|
||||||
|
|||||||
Reference in New Issue
Block a user