turnero_consentimientos nunca guardó quién lo generó; el pie del documento mostraba el nombre de quien tuviera sesión abierta al verlo, no de quien realmente lo atendió (por eso siempre aparecía el mismo usuario). Se agrega la columna creado_por, se llena en los 6 puntos donde se crea un registro (recepción, envío por WhatsApp, anexar formulario extra, autocreación por examen/lugar), y ver_formulario_enviado.php ahora prioriza ese dato real sobre el usuario de la sesión actual. Los documentos ya firmados antes de este cambio siguen sin ese dato y usan el fallback anterior. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
213 lines
7.9 KiB
PHP
213 lines
7.9 KiB
PHP
<?php
|
|
/**
|
|
* POST /modules/turnero/api/send_consentimiento.php
|
|
* Genera y/o reenvía consentimientos informados por WhatsApp para un turno.
|
|
*
|
|
* Lógica:
|
|
* 1. Lee los turnero_examen_items del turno.
|
|
* 2. Para cada exam_tipo_id busca en exam_tipo_consentimientos qué formulario_id requiere.
|
|
* 3. Deduplica: varios exámenes que apunten al mismo formulario → 1 solo envío.
|
|
* 4. Por cada formulario distinto:
|
|
* a. Si ya existe un turnero_consentimientos con ese (turno_id, formulario_id) → reutiliza / reenvía.
|
|
* b. Si no existe: genera token UUID, inserta con estado 'pendiente'.
|
|
* 5. Envía mensaje WhatsApp al celular del turno / paciente con enlace de firma.
|
|
* 6. Actualiza estado → 'enviado' y registra enviado_at.
|
|
*
|
|
* Body JSON:
|
|
* turno_id int requerido
|
|
*
|
|
* Requiere login + módulo turnero.
|
|
*/
|
|
|
|
require_once __DIR__ . '/_helpers.php';
|
|
requireMethod('POST');
|
|
requireTurnero();
|
|
|
|
require_once __DIR__ . '/../../../services/WhatsAppService.php';
|
|
|
|
$datos = inputJson();
|
|
$turnoId = isset($datos['turno_id']) ? (int) $datos['turno_id'] : 0;
|
|
|
|
if ($turnoId <= 0) jsonError('turno_id inválido.');
|
|
|
|
$pdo = db();
|
|
|
|
// ── 1. Cargar turno (con fallback de paciente desde kiosko) ──
|
|
$stmt = $pdo->prepare(
|
|
"SELECT t.id, t.codigo, t.paciente_nombre, t.paciente_cel, t.paciente_id,
|
|
t.estado,
|
|
COALESCE(p_sol.telefono, p_tur.telefono) AS pac_celular,
|
|
COALESCE(p_sol.nombre_completo, p_tur.nombre_completo) AS pac_nombre
|
|
FROM turnero_turnos t
|
|
LEFT JOIN turnero_solicitudes s ON s.turno_id = t.id
|
|
LEFT JOIN lab_pacientes p_sol ON p_sol.id = s.paciente_id
|
|
LEFT JOIN lab_pacientes p_tur ON p_tur.id = t.paciente_id
|
|
WHERE t.id = ?"
|
|
);
|
|
$stmt->execute([$turnoId]);
|
|
$turno = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$turno) jsonError('Turno no encontrado.', 404);
|
|
|
|
// Celular: preferencia paciente BD → kiosko
|
|
$celular = $turno['pac_celular'] ?: $turno['paciente_cel'] ?: null;
|
|
if (!$celular) {
|
|
jsonError('El paciente no tiene número de celular registrado.', 422);
|
|
}
|
|
$celular = preg_replace('/[^0-9]/', '', $celular);
|
|
|
|
// ── 2. Obtener formularios configurados para este turno ───────
|
|
$stmt = $pdo->prepare(
|
|
"SELECT tc.formulario_id, f.nombre AS formulario_nombre
|
|
FROM turnero_consentimientos tc
|
|
JOIN lab_formularios f ON f.id = tc.formulario_id
|
|
WHERE tc.turno_id = ?
|
|
ORDER BY f.nombre ASC"
|
|
);
|
|
$stmt->execute([$turnoId]);
|
|
$formulariosRequeridos = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
if (empty($formulariosRequeridos)) {
|
|
jsonOk(['consentimientos' => [], 'mensaje' => 'Este turno no tiene consentimientos requeridos.']);
|
|
}
|
|
|
|
// ── 4. Generar / recuperar tokens UUID ────────────────────────
|
|
function generarUuid(): string
|
|
{
|
|
return 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)
|
|
);
|
|
}
|
|
|
|
// ── Leer config de WhatsApp (igual que create_turno.php) ─────
|
|
$stmtCfg = $pdo->prepare(
|
|
"SELECT clave, valor FROM lab_config WHERE clave IN ('turnero_wa_template','turnero_wa_lang')"
|
|
);
|
|
$stmtCfg->execute();
|
|
$cfgWA = $stmtCfg->fetchAll(PDO::FETCH_KEY_PAIR);
|
|
$waTemplateName = $cfgWA['turnero_wa_template'] ?? 'consentimiento_turno';
|
|
$waLangFallback = $cfgWA['turnero_wa_lang'] ?? 'es';
|
|
|
|
$pdo->beginTransaction();
|
|
$consentimientosResultado = [];
|
|
$erroresEnvio = [];
|
|
|
|
try {
|
|
$stmtBuscar = $pdo->prepare(
|
|
"SELECT id, token, estado FROM turnero_consentimientos
|
|
WHERE turno_id = ? AND formulario_id = ?"
|
|
);
|
|
$stmtInsertar = $pdo->prepare(
|
|
"INSERT INTO turnero_consentimientos (turno_id, formulario_id, token, estado, creado_por)
|
|
VALUES (?, ?, ?, 'pendiente', ?)"
|
|
);
|
|
$stmtActualizar = $pdo->prepare(
|
|
"UPDATE turnero_consentimientos
|
|
SET estado = 'enviado', enviado_at = NOW()
|
|
WHERE id = ?"
|
|
);
|
|
|
|
$wa = new WhatsAppService('turnero');
|
|
$waMeta = ['canal' => 'turnero'];
|
|
$waTemplate = $waTemplateName;
|
|
$stmtLang = $pdo->prepare("SELECT language_code FROM message_templates WHERE template_name = ? LIMIT 1");
|
|
$stmtLang->execute([$waTemplate]);
|
|
$waLang = $stmtLang->fetchColumn() ?: $waLangFallback;
|
|
|
|
$baseUrl = defined('BASE_URL') ? rtrim(BASE_URL, '/') : (
|
|
(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http')
|
|
. '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost')
|
|
);
|
|
|
|
foreach ($formulariosRequeridos as $form) {
|
|
$formularioId = (int) $form['formulario_id'];
|
|
$formularioNom = $form['formulario_nombre'];
|
|
|
|
// Buscar si ya existe
|
|
$stmtBuscar->execute([$turnoId, $formularioId]);
|
|
$existente = $stmtBuscar->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($existente) {
|
|
$consentId = (int) $existente['id'];
|
|
$token = $existente['token'];
|
|
// Si ya está firmado/rechazado, no reenviar
|
|
if (in_array($existente['estado'], ['firmado', 'rechazado'], true)) {
|
|
$consentimientosResultado[] = [
|
|
'id' => $consentId,
|
|
'formulario_id' => $formularioId,
|
|
'formulario_nombre'=> $formularioNom,
|
|
'estado' => $existente['estado'],
|
|
'enviado' => false,
|
|
];
|
|
continue;
|
|
}
|
|
} else {
|
|
$token = generarUuid();
|
|
$stmtInsertar->execute([$turnoId, $formularioId, $token, adminId()]);
|
|
$consentId = (int) $pdo->lastInsertId();
|
|
}
|
|
|
|
$enlaceFirma = $baseUrl . '/ver_formulario_enviado.php?token=' . urlencode($token);
|
|
$nombrePac = $turno['pac_nombre'] ?: ($turno['paciente_nombre'] ?? 'Paciente');
|
|
|
|
// ── Enviar con template (mismo formato que create_turno.php) ──
|
|
$enviado = false;
|
|
try {
|
|
$rawComps = [
|
|
['type' => 'body', 'parameters' => [['type' => 'text', 'text' => $turno['codigo']]]],
|
|
['type' => 'button', 'sub_type' => 'url', 'index' => '0',
|
|
'parameters' => [['type' => 'text', 'text' => $token]]],
|
|
];
|
|
$wa->sendTemplateMessage($celular, $waTemplate, $waLang, [], [], $rawComps, $waMeta);
|
|
$enviado = true;
|
|
} catch (\Throwable $eTemplate) {
|
|
// Fallback texto plano
|
|
try {
|
|
$mensajeTexto = "Hola {$nombrePac}, su turno *{$turno['codigo']}* requiere firma de consentimiento:\n{$enlaceFirma}";
|
|
$wa->sendTextMessage($celular, $mensajeTexto, $waMeta);
|
|
$enviado = true;
|
|
} catch (\Throwable $eTexto) {
|
|
$erroresEnvio[] = "Formulario '{$formularioNom}': " . $eTexto->getMessage();
|
|
}
|
|
}
|
|
|
|
if ($enviado) {
|
|
$stmtActualizar->execute([$consentId]);
|
|
$estado = 'enviado';
|
|
} else {
|
|
$estado = 'pendiente';
|
|
}
|
|
|
|
$consentimientosResultado[] = [
|
|
'id' => $consentId,
|
|
'formulario_id' => $formularioId,
|
|
'formulario_nombre' => $formularioNom,
|
|
'token' => $token,
|
|
'estado' => $estado,
|
|
'enviado' => $enviado,
|
|
'enlace_firma' => $enlaceFirma,
|
|
];
|
|
}
|
|
|
|
$pdo->commit();
|
|
|
|
$msgExtra = !empty($erroresEnvio)
|
|
? ' (Advertencias: ' . implode('; ', $erroresEnvio) . ')'
|
|
: '';
|
|
|
|
jsonOk(
|
|
['consentimientos' => $consentimientosResultado],
|
|
count(array_filter($consentimientosResultado, fn($c) => $c['enviado']))
|
|
. ' consentimiento(s) enviado(s) por WhatsApp' . $msgExtra
|
|
);
|
|
|
|
} catch (\Throwable $e) {
|
|
if ($pdo->inTransaction()) $pdo->rollBack();
|
|
jsonError('Error al procesar consentimientos: ' . $e->getMessage(), 500);
|
|
}
|