From a4a062095e1bcb1d0a3cf2bea185f48971cb93f8 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:35:12 -0500 Subject: [PATCH] up --- ...20260616_turnero_consentimientos_datos.sql | 4 + run_migration_consentimientos_datos.php | 52 +++++++ ver_formulario_enviado.php | 137 +++++++++++++++++- 3 files changed, 186 insertions(+), 7 deletions(-) create mode 100644 migrations/20260616_turnero_consentimientos_datos.sql create mode 100644 run_migration_consentimientos_datos.php diff --git a/migrations/20260616_turnero_consentimientos_datos.sql b/migrations/20260616_turnero_consentimientos_datos.sql new file mode 100644 index 0000000..8ecaaec --- /dev/null +++ b/migrations/20260616_turnero_consentimientos_datos.sql @@ -0,0 +1,4 @@ +-- Agrega columna para guardar respuestas de campos al firmar presencialmente +ALTER TABLE turnero_consentimientos + ADD COLUMN IF NOT EXISTS datos_respuestas MEDIUMTEXT DEFAULT NULL + COMMENT 'Respuestas del formulario en JSON (campos llenados al firmar presencialmente)'; diff --git a/run_migration_consentimientos_datos.php b/run_migration_consentimientos_datos.php new file mode 100644 index 0000000..7abe2cd --- /dev/null +++ b/run_migration_consentimientos_datos.php @@ -0,0 +1,52 @@ +getConnection(); + $sql = file_get_contents($sqlFile); + + $statements = array_filter(array_map('trim', explode(';', $sql))); + + echo "
πŸš€ Ejecutando migraciΓ³n: 20260616_turnero_consentimientos_datos\n\n";
+
+    foreach ($statements as $stmt) {
+        $clean = preg_replace('/--[^\n]*/', '', $stmt);
+        $clean = trim($clean);
+        if (empty($clean)) continue;
+
+        try {
+            $pdo->exec($clean);
+            $preview = substr(preg_replace('/\s+/', ' ', $clean), 0, 120);
+            echo "βœ“ {$preview}\n";
+        } catch (PDOException $e) {
+            $msg = $e->getMessage();
+            if (str_contains($msg, 'Duplicate column') || str_contains($msg, 'errno: 1060')) {
+                echo "ℹ️  (columna ya existe, omitida)\n";
+            } else {
+                throw $e;
+            }
+        }
+    }
+
+    echo "\nβœ… MigraciΓ³n completada.\n";
+    echo "   Columna agregada a turnero_consentimientos:\n";
+    echo "   β€’ datos_respuestas (MEDIUMTEXT, JSON con campos llenados al firmar presencialmente)\n
"; + + $cols = $pdo->query("SHOW COLUMNS FROM turnero_consentimientos")->fetchAll(PDO::FETCH_COLUMN); + echo "
πŸ“‹ Columnas actuales: " . implode(', ', $cols) . "
"; + +} catch (Throwable $e) { + echo "
❌ Error: " . htmlspecialchars($e->getMessage()) . "\n
"; +} diff --git a/ver_formulario_enviado.php b/ver_formulario_enviado.php index 14adb76..8477f02 100644 --- a/ver_formulario_enviado.php +++ b/ver_formulario_enviado.php @@ -30,7 +30,7 @@ if ($modoTurnero) { $tcRow = $db->fetch( "SELECT tc.id, tc.turno_id, tc.formulario_id, tc.token, tc.estado, tc.enviado_at, tc.firmado_at, tc.ip_firma, tc.ua_firma, tc.firma_svg, - tc.firma_profesional_svg, tc.firmado_profesional_at, + tc.firma_profesional_svg, tc.firmado_profesional_at, tc.datos_respuestas, f.nombre AS form_nombre, f.categoria, f.descripcion AS form_descripcion, f.esquema, f.doc_encabezado, f.doc_subtitulo, f.doc_logo_base64, f.doc_color, f.doc_pie_pagina, p.nombre_completo AS paciente_nombre, @@ -58,6 +58,9 @@ if ($modoTurnero) { if (strlen($firmaSvg) < 100) { echo json_encode(['ok' => false, 'error' => 'Firma requerida']); exit; } + $datosRespuestas = isset($input['datos_respuestas']) && is_array($input['datos_respuestas']) + ? json_encode($input['datos_respuestas'], JSON_UNESCAPED_UNICODE) + : null; $ip = filter_var( $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '', FILTER_VALIDATE_IP @@ -67,10 +70,10 @@ if ($modoTurnero) { $stmt = $pdo->prepare( "UPDATE turnero_consentimientos SET estado='firmado', firmado_at=NOW(), firma_svg=?, - ip_firma=?, ua_firma=?, version_formulario=? + ip_firma=?, ua_firma=?, version_formulario=?, datos_respuestas=? WHERE token=?" ); - $stmt->execute([$firmaSvg, $ip, $ua, (int)$tcRow['formulario_id'], $tokenTurnero]); + $stmt->execute([$firmaSvg, $ip, $ua, (int)$tcRow['formulario_id'], $datosRespuestas, $tokenTurnero]); require_once __DIR__ . '/modules/turnero/api/_helpers.php'; notificarSSE((int)$tcRow['sesion_id']); echo json_encode(['ok' => true, 'message' => 'Consentimiento firmado correctamente']); exit; @@ -99,7 +102,7 @@ if ($modoTurnero) { 'enviado_por_nombre'=> $_SESSION['admin_user']['full_name'] ?? $_SESSION['admin_user']['username'] ?? 'Turnero', 'enviado_por_email' => $_SESSION['admin_user']['email'] ?? null, 'firma_profesional_svg' => $tcRow['firma_profesional_svg'] ?? null, - 'datos_cliente' => '{}', + 'datos_cliente' => $tcRow['datos_respuestas'] ?: '{}', 'datos_prefilled' => json_encode(['__paciente' => [ 'nombre_completo' => $tcRow['paciente_nombre'] ?? '', 'numero_documento' => $tcRow['numero_documento'] ?? '', @@ -184,6 +187,7 @@ $esquema = json_decode($envio['esquema'], true) ?? []; $datosCliente = json_decode($envio['datos_cliente'] ?? '{}', true) ?? []; $datosPrefilled = json_decode($envio['datos_prefilled'] ?? '{}', true) ?? []; $todos = array_merge($datosPrefilled, $datosCliente); +$modoEditar = $modoTurnero && $envio['estado'] !== 'firmado'; // Mapa id β†’ label $labelMap = []; @@ -299,6 +303,23 @@ function esc2(mixed $v): string { .fpw-canvas { border: 2px solid #198754; border-radius: 8px; background: #f8fff9; cursor: crosshair; display: block; max-width: 100%; touch-action: none; } + /* ── Campos interactivos (modo turnero editar) ──── */ + .campo-edit { margin-bottom: 14px; } + .campo-edit label { display: block; font-size: 12px; color: #6c757d; + font-weight: 600; margin-bottom: 4px; } + .campo-edit .form-control, + .campo-edit .form-select { font-size: 13px; border-color: #c3d3f7; + background: #f8faff; } + .campo-edit .form-control:focus, + .campo-edit .form-select:focus { border-color: #1565c0; + box-shadow: 0 0 0 3px rgba(21,101,192,.12); } + .campo-edit .form-check-label { font-size: 13px; } + .campo-linked { display: flex; gap: 16px; padding: 6px 0; + border-bottom: 1px solid #f0f0f0; } + .campo-linked-label { flex: 0 0 38%; font-size: 12px; color: #6c757d; } + .campo-linked-valor { flex: 1; font-size: 13px; font-weight: 600; + color: #1565c0; } + /* ═══════ ESTILOS DE IMPRESIΓ“N ═══════════════════ */ @media print { body { background: #fff !important; font-size: 12px; } @@ -419,7 +440,10 @@ function esc2(mixed $v): string { -
Respuestas del formulario
+
+ + +
+
+
+
+
+ +
+ + +
+ +
+ + +
+ > + +
+ +
+ +
+ + +
+ > + +
+ +
+ +
+ + +
+ 'number', 'fecha' => 'date', 'hora' => 'time', default => 'text' + }; + ?> +
+ + > +
+ Guardando...'; msgEl.textContent = ''; + // Recopilar respuestas de campos interactivos + var campos = {}; + document.querySelectorAll('[name]').forEach(function(el) { + var rawName = el.name; + var isArr = rawName.slice(-2) === '[]'; + var name = isArr ? rawName.slice(0, -2) : rawName; + if (el.type === 'checkbox') { + if (el.checked) { + if (!Array.isArray(campos[name])) campos[name] = []; + campos[name].push(el.value); + } + } else if (el.type === 'radio') { + if (el.checked) campos[name] = el.value; + } else if (el.value !== '') { + campos[name] = el.value; + } + }); + fetch(window.location.href, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ firma_svg: png }) + body: JSON.stringify({ firma_svg: png, datos_respuestas: campos }) }) .then(function(r) { return r.json(); }) .then(function(data) {