201 lines
7.5 KiB
PHP
201 lines
7.5 KiB
PHP
<?php
|
|
/**
|
|
* POST /modules/turnero/api/create_turno.php
|
|
* Genera un nuevo turno desde el kiosko o recepción.
|
|
* No requiere login (kiosko es público).
|
|
*
|
|
* Body JSON:
|
|
* prioridad_codigo string requerido "A"|"B"|"C"|"D"|"E"|"F"
|
|
* paciente_nombre string opcional
|
|
* paciente_cel string opcional
|
|
*/
|
|
|
|
require_once __DIR__ . '/_helpers.php';
|
|
requireMethod('POST');
|
|
|
|
// Este endpoint es público (kiosko no requiere login)
|
|
// Solo validamos CSRF básico: debe ser POST con JSON
|
|
|
|
$datos = inputJson();
|
|
|
|
// ── Validación ────────────────────────────────────────────────
|
|
$prioCodigo = strtoupper(trim($datos['prioridad_codigo'] ?? ''));
|
|
if (!in_array($prioCodigo, ['A', 'B', 'C', 'D', 'E', 'F'], true)) {
|
|
jsonError('prioridad_codigo inválido. Use A, B, C, D, E o F.');
|
|
}
|
|
|
|
$pacienteDoc = substr(trim($datos['paciente_nombre'] ?? ''), 0, 150);
|
|
$pacienteCel = preg_replace('/[^0-9+\- ]/', '', $datos['paciente_cel'] ?? '');
|
|
$pacienteCel = substr($pacienteCel, 0, 20);
|
|
|
|
// ── Lógica principal (dentro de transacción para evitar race conditions) ──
|
|
$pdo = db();
|
|
$pdo->beginTransaction();
|
|
|
|
try {
|
|
$sesionId = obtenerOCrearSesionHoy();
|
|
|
|
// Buscar prioridad_id
|
|
$stmt = $pdo->prepare(
|
|
'SELECT id FROM turnero_prioridades WHERE codigo = ? AND activo = 1 LIMIT 1'
|
|
);
|
|
$stmt->execute([$prioCodigo]);
|
|
$prioridad = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$prioridad) {
|
|
$pdo->rollBack();
|
|
jsonError("La prioridad '$prioCodigo' no existe o no está activa.", 422);
|
|
}
|
|
|
|
$prioridadId = (int) $prioridad['id'];
|
|
|
|
// Buscar paciente por número de documento en lab_pacientes
|
|
$pacienteNombre = $pacienteDoc;
|
|
$pacienteId = null;
|
|
$pacienteTel = $pacienteCel; // fallback: celular del kiosko
|
|
if ($pacienteDoc) {
|
|
try {
|
|
$stmtP = $pdo->prepare(
|
|
'SELECT id, nombre_completo, telefono FROM lab_pacientes WHERE numero_documento = ? AND is_active = 1 LIMIT 1'
|
|
);
|
|
$stmtP->execute([$pacienteDoc]);
|
|
$pacRow = $stmtP->fetch(PDO::FETCH_ASSOC);
|
|
if ($pacRow) {
|
|
$pacienteNombre = $pacRow['nombre_completo'];
|
|
$pacienteId = (int) $pacRow['id'];
|
|
$pacienteTel = $pacRow['telefono'] ?: $pacienteCel;
|
|
}
|
|
} catch (\Throwable $e) {
|
|
$pacienteNombre = $pacienteDoc;
|
|
}
|
|
}
|
|
|
|
// Correlativo independiente por prioridad (A-001, A-002... B-001, B-002... etc.)
|
|
$numero = siguienteNumeroPorPrioridad($sesionId, $prioridadId);
|
|
|
|
// Código visual: "A001", "B001", "E001", etc.
|
|
$codigo = $prioCodigo . str_pad($numero, 3, '0', STR_PAD_LEFT);
|
|
|
|
$stmt = $pdo->prepare(
|
|
'INSERT INTO turnero_turnos
|
|
(sesion_id, numero, codigo, prioridad_id, paciente_nombre, paciente_cel, paciente_id,
|
|
estado, creado_at)
|
|
VALUES
|
|
(?, ?, ?, ?, ?, ?, ?, "espera", NOW())'
|
|
);
|
|
$stmt->execute([
|
|
$sesionId,
|
|
$numero,
|
|
$codigo,
|
|
$prioridadId,
|
|
$pacienteNombre ?: null,
|
|
$pacienteCel ?: null,
|
|
$pacienteId,
|
|
]);
|
|
|
|
$turnoId = (int) $pdo->lastInsertId();
|
|
$pdo->commit();
|
|
|
|
notificarSSE($sesionId);
|
|
|
|
// ── Auto-crear consentimiento principal + enviar WhatsApp ──
|
|
try {
|
|
$stmtPc = $pdo->prepare(
|
|
"SELECT id, nombre FROM lab_formularios WHERE is_principal = 1 AND tipo = 'consentimiento' AND is_active = 1 LIMIT 1"
|
|
);
|
|
$stmtPc->execute();
|
|
$principalForm = $stmtPc->fetch(PDO::FETCH_ASSOC);
|
|
if ($principalForm) {
|
|
$tokenPrincipal = 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)
|
|
);
|
|
$stmtIns = $pdo->prepare(
|
|
"INSERT IGNORE INTO turnero_consentimientos (turno_id, formulario_id, token, estado)
|
|
VALUES (?, ?, ?, 'pendiente')"
|
|
);
|
|
$stmtIns->execute([$turnoId, (int)$principalForm['id'], $tokenPrincipal]);
|
|
|
|
// Enviar WhatsApp si tenemos celular
|
|
if ($pacienteTel) {
|
|
$cel = preg_replace('/[\s\-\.]/', '', $pacienteTel);
|
|
if (!str_starts_with($cel, '+')) {
|
|
$cel = '+57' . ltrim($cel, '0');
|
|
}
|
|
$enlaceFirma = (defined('BASE_URL') ? rtrim(BASE_URL, '/') : '')
|
|
. '/ver_formulario_enviado.php?token=' . urlencode($tokenPrincipal);
|
|
$nombrePacWA = $pacienteNombre ?: 'Paciente';
|
|
require_once __DIR__ . '/../../../services/WhatsAppService.php';
|
|
try {
|
|
$wa = new WhatsAppService();
|
|
$wa->sendTemplateMessage(
|
|
$cel,
|
|
'consentimiento_turno',
|
|
'es',
|
|
[
|
|
htmlspecialchars($nombrePacWA, ENT_QUOTES),
|
|
htmlspecialchars($principalForm['nombre'], ENT_QUOTES),
|
|
$codigo,
|
|
],
|
|
[$enlaceFirma]
|
|
);
|
|
} catch (\Throwable $eTmpl) {
|
|
try {
|
|
$mensajeTexto = "Hola {$nombrePacWA}, le informamos que para su turno *{$codigo}* "
|
|
. "debe firmar el siguiente consentimiento informado:\n\n"
|
|
. "*{$principalForm['nombre']}*\n\n"
|
|
. "Puede firmarlo en el siguiente enlace:\n{$enlaceFirma}\n\n"
|
|
. "Si ya firmó este documento presencial, ignore este mensaje.";
|
|
$wa->sendTextMessage($cel, $mensajeTexto);
|
|
} catch (\Throwable $eTxt) {
|
|
// Silenciar error de WhatsApp, el turno ya se creó
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (\Throwable $e) {
|
|
// Silenciar error — el turno ya se creó exitosamente
|
|
}
|
|
|
|
// Contar posición en la cola
|
|
$stmt = $pdo->prepare(
|
|
'
|
|
SELECT COUNT(*) AS posicion
|
|
FROM turnero_turnos t
|
|
JOIN turnero_prioridades p ON p.id = t.prioridad_id
|
|
WHERE t.estado = "espera"
|
|
AND t.sesion_id = ?
|
|
AND (
|
|
p.orden_peso < (SELECT orden_peso FROM turnero_prioridades WHERE id = ?)
|
|
OR (
|
|
p.orden_peso = (SELECT orden_peso FROM turnero_prioridades WHERE id = ?)
|
|
AND t.creado_at < (SELECT creado_at FROM turnero_turnos WHERE id = ?)
|
|
)
|
|
)
|
|
'
|
|
);
|
|
$stmt->execute([$sesionId, $prioridadId, $prioridadId, $turnoId]);
|
|
$posicion = (int) $stmt->fetchColumn() + 1;
|
|
|
|
jsonOk([
|
|
'turno' => [
|
|
'id' => $turnoId,
|
|
'codigo' => $codigo,
|
|
'numero' => $numero,
|
|
'prioridad_codigo' => $prioCodigo,
|
|
'posicion_cola' => $posicion,
|
|
'sesion_id' => $sesionId,
|
|
],
|
|
], "Turno $codigo asignado correctamente");
|
|
|
|
} catch (\Throwable $e) {
|
|
if ($pdo->inTransaction()) {
|
|
$pdo->rollBack();
|
|
}
|
|
jsonError('Error al crear el turno: ' . $e->getMessage(), 500);
|
|
}
|