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) ); } $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) VALUES (?, ?, ?, 'pendiente')" ); $stmtActualizar = $pdo->prepare( "UPDATE turnero_consentimientos SET estado = 'enviado', enviado_at = NOW() WHERE id = ?" ); $wa = new WhatsAppService('turnero'); $waMeta = ['canal' => 'turnero']; $waTemplate = 'consentimiento_turno'; $stmtLang = $pdo->prepare("SELECT language_code FROM message_templates WHERE template_name = ? LIMIT 1"); $stmtLang->execute([$waTemplate]); $waLang = $stmtLang->fetchColumn() ?: 'es'; $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]); $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); }