This commit is contained in:
Lizandro Guarnizo
2026-03-16 20:46:54 -05:00
parent 3b834bc24b
commit 79bcc5e4bf
4 changed files with 151 additions and 3 deletions
+2 -1
View File
@@ -55,6 +55,7 @@ class Formulario {
'esquema' => $datos['esquema'] ?? '[]',
'permite_firma' => !empty($datos['permite_firma']) ? 1 : 0,
'requiere_firma' => !empty($datos['requiere_firma']) ? 1 : 0,
'firma_modos' => $datos['firma_modos'] ?? 'canvas,foto',
'doc_encabezado' => $datos['doc_encabezado'] ?? null,
'doc_subtitulo' => $datos['doc_subtitulo'] ?? null,
'doc_logo_base64' => $datos['doc_logo_base64'] ?? null,
@@ -69,7 +70,7 @@ class Formulario {
public function actualizar(int $id, array $datos, int $adminId): bool {
$permitidos = [
'nombre','descripcion','categoria','esquema',
'permite_firma','requiere_firma','is_active',
'permite_firma','requiere_firma','firma_modos','is_active',
'doc_encabezado','doc_subtitulo','doc_logo_base64','doc_color','doc_pie_pagina',
];
$campos = array_intersect_key($datos, array_flip($permitidos));
+134
View File
@@ -0,0 +1,134 @@
<?php
/**
* fix_form_modos.php — Migración + corrección de modos de firma
* 1. Aplica la columna firma_modos si no existe
* 2. Muestra y permite corregir los modos por formulario
* ELIMINAR después de usar.
*/
require_once 'config/config.php';
if (!isUserLoggedIn()) { die('No autorizado'); }
$db = Database::getInstance();
$pdo = $db->getConnection();
// ── 1. Migración automática ──────────────────────────────────────────────────
$migMsg = '';
try {
$pdo->exec("ALTER TABLE lab_formularios
ADD COLUMN IF NOT EXISTS firma_modos VARCHAR(50) NOT NULL DEFAULT 'canvas,foto'
COMMENT 'Modos habilitados: canvas, foto o ambos (CSV)'
AFTER requiere_firma");
$migMsg = '✅ Columna <code>firma_modos</code> lista.';
} catch (PDOException $e) {
$migMsg = '⚠️ ' . htmlspecialchars($e->getMessage());
}
// ── 2. Guardar corrección manual ─────────────────────────────────────────────
$saveMsg = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['form_id'])) {
$fid = (int)$_POST['form_id'];
$canvas = !empty($_POST['canvas']);
$foto = !empty($_POST['foto']);
$modos = [];
if ($canvas) $modos[] = 'canvas';
if ($foto) $modos[] = 'foto';
if (!$modos) $modos = ['canvas']; // al menos canvas
$modosStr = implode(',', $modos);
// Actualiza columna firma_modos
$upd = $pdo->prepare('UPDATE lab_formularios SET firma_modos = ? WHERE id = ?');
$upd->execute([$modosStr, $fid]);
// También actualiza el campo tipo:'firma' dentro del esquema si existe
$row = $pdo->prepare('SELECT esquema FROM lab_formularios WHERE id = ?');
$row->execute([$fid]);
$f = $row->fetch(PDO::FETCH_ASSOC);
if ($f) {
$esquema = json_decode($f['esquema'], true) ?? [];
$changed = false;
$esquema = array_map(function($c) use ($modos, &$changed) {
if ($c['tipo'] === 'firma') { $c['modos'] = $modos; $changed = true; }
return $c;
}, $esquema);
if ($changed) {
$upd2 = $pdo->prepare('UPDATE lab_formularios SET esquema = ? WHERE id = ?');
$upd2->execute([json_encode($esquema, JSON_UNESCAPED_UNICODE), $fid]);
}
}
$saveMsg = "✅ Formulario #$fid actualizado → modos: <strong>" . htmlspecialchars($modosStr) . '</strong>';
}
// ── 3. Leer formularios ──────────────────────────────────────────────────────
$stmt = $pdo->query('SELECT id, nombre, esquema, firma_modos FROM lab_formularios WHERE is_active = 1 ORDER BY id');
$formularios = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Fix Modos Firma</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="p-4">
<h4 class="mb-3">🔧 Migración y corrección de modos de firma</h4>
<div class="alert alert-info"><?= $migMsg ?></div>
<?php if ($saveMsg): ?><div class="alert alert-success"><?= $saveMsg ?></div><?php endif; ?>
<div class="table-responsive">
<table class="table table-bordered table-sm">
<thead class="table-dark">
<tr><th>#</th><th>Nombre</th><th>firma_modos (DB col)</th><th>modos en esquema JSON</th><th>Corregir</th></tr>
</thead>
<tbody>
<?php foreach ($formularios as $f): ?>
<?php
$esquema = json_decode($f['esquema'], true) ?? [];
$firmaCampo = null;
foreach ($esquema as $c) { if ($c['tipo'] === 'firma') { $firmaCampo = $c; break; } }
$modsCol = $f['firma_modos'] ?? 'canvas,foto';
$modsArr = array_filter(explode(',', $modsCol));
$modsJson = $firmaCampo['modos'] ?? null;
$hayFotoCol = in_array('foto', $modsArr);
$hayCanvasCol = in_array('canvas', $modsArr);
?>
<tr>
<td><?= $f['id'] ?></td>
<td><?= htmlspecialchars($f['nombre']) ?></td>
<td>
<code><?= htmlspecialchars($modsCol) ?></code>
<?php if ($hayFotoCol): ?>
<span class="badge bg-warning text-dark ms-1">📷 foto ACTIVA</span>
<?php else: ?>
<span class="badge bg-success ms-1">✅ foto off</span>
<?php endif; ?>
</td>
<td>
<?php if ($modsJson !== null): ?>
<code><?= htmlspecialchars(implode(', ', $modsJson)) ?></code>
<?php else: ?>
<span class="text-muted">sin campo firma en esquema</span>
<?php endif; ?>
</td>
<td>
<form method="POST" class="d-flex gap-2 align-items-center">
<input type="hidden" name="form_id" value="<?= $f['id'] ?>">
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="canvas" id="c<?= $f['id'] ?>" <?= $hayCanvasCol ? 'checked' : '' ?>>
<label class="form-check-label" for="c<?= $f['id'] ?>">✍️ Dibujar</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="foto" id="f<?= $f['id'] ?>" <?= $hayFotoCol ? 'checked' : '' ?>>
<label class="form-check-label" for="f<?= $f['id'] ?>">📷 Foto</label>
</div>
<button type="submit" class="btn btn-sm btn-primary">Guardar</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="alert alert-warning mt-3">⚠️ Elimina este archivo del servidor después de usarlo.</div>
</body>
</html>
+7 -2
View File
@@ -937,8 +937,12 @@ async function cargarFormulario(id) {
$('tb-firma').checked = !!f.permite_firma;
$('tb-firma-req').checked = !!f.requiere_firma;
_campos = f.esquema_decoded || [];
// Leer modos: primero columna dedicada, luego campo tipo:'firma' en esquema, nunca defaultear a foto
const _firmaCampo = _campos.find(c => c.tipo === 'firma');
const _fModos = _firmaCampo?.modos || ['canvas','foto'];
const _fModosStr = f.firma_modos || ''; // columna DB: 'canvas', 'foto', 'canvas,foto' o ''
const _fModos = _fModosStr
? _fModosStr.split(',').map(m => m.trim()).filter(Boolean)
: (_firmaCampo?.modos ?? ['canvas','foto']);
$('tb-firma-canvas').checked = _fModos.includes('canvas');
$('tb-firma-foto').checked = _fModos.includes('foto');
@@ -984,7 +988,7 @@ async function guardar() {
const usarGlobal = $('tb-usar-global').checked;
// Sincronizar modos ANTES de serializar el esquema
const _modos = []; if($('tb-firma-canvas').checked)_modos.push('canvas'); if($('tb-firma-foto').checked)_modos.push('foto');
_campos = _campos.map(c => c.tipo === 'firma' ? { ...c, modos: _modos.length ? _modos : ['canvas','foto'] } : c);
_campos = _campos.map(c => c.tipo === 'firma' ? { ...c, modos: _modos.length ? _modos : ['canvas'] } : c);
const datos = {
nombre,
descripcion: $('tb-descripcion').value.trim() || null,
@@ -992,6 +996,7 @@ async function guardar() {
esquema: JSON.stringify(_campos),
permite_firma: $('tb-firma').checked ? 1 : 0,
requiere_firma: $('tb-firma-req').checked ? 1 : 0,
firma_modos: _modos.length ? _modos.join(',') : 'canvas',
doc_encabezado: usarGlobal ? null : ($('tb-doc-encabezado').value.trim() || null),
doc_subtitulo: usarGlobal ? null : ($('tb-doc-subtitulo').value.trim() || null),
doc_color: usarGlobal ? null : ($('tb-doc-color').value || null),
@@ -0,0 +1,8 @@
-- Agrega columna firma_modos a lab_formularios
-- Almacena qué modos de captura están activos: 'canvas', 'foto', o ambos separados por coma.
-- Valor por defecto: 'canvas,foto' (compatibilidad con registros anteriores)
ALTER TABLE lab_formularios
ADD COLUMN IF NOT EXISTS firma_modos VARCHAR(50) NOT NULL DEFAULT 'canvas,foto'
COMMENT 'Modos de firma habilitados: canvas, foto o ambos (CSV)'
AFTER requiere_firma;