Files
whatsapp/api/lab/save_tomas_config.php
T
Lizandro GuarnizoandClaude Sonnet 4.6 86ec692028 refactor: mejorar flujo de tomas prolongadas (A+B+C+D)
A) Fix bug: grupos fuera de _tomas_config contaminaban $_mpMap y bloqueaban
   firmas configuradas. Ahora se vacían y sus secciones se agregan a
   $_mpSkippedSepIds para que PHP no las renderice.

B) Quitar campo Resultado del esquema (14 campos eliminados del form 15 en
   BD). save_tomas_config.php ya no genera campo Resultado en exámenes nuevos.
   Patrón queda: separador → hora → observaciones → firma_profesional.

C) Condicionamiento implícito: con el fix de A, solo aparecen las secciones
   del grupo configurado en _tomas_config, sin cambios en el esquema DB.

D) UX: reemplaza popup automático por badges bajo el campo _c8j2g16.
   Cada examen seleccionado muestra badge con estado (pendiente/configurado)
   y botón "Configurar tiempos" que abre el panel solo al hacer clic.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-16 11:20:15 -05:00

140 lines
5.8 KiB
PHP

<?php
/**
* POST /api/lab/save_tomas_config.php
* Gestiona los tipos de examen del formulario de Tomas Prolongadas (lab_formularios.id=15).
*
* Body JSON:
* action string 'add_exam' | 'delete_exam'
* exam_name string Nombre del nuevo tipo de examen
* tomas array [{label, tipo:'minutos'|'hora_fija', valor}] (solo add_exam)
*/
require_once __DIR__ . '/_helpers.php';
requireAdmin();
requireMethod('POST');
$body = inputJson();
$action = trim($body['action'] ?? '');
if (!in_array($action, ['add_exam', 'delete_exam'], true)) jsonError('action inválida.');
$db = Database::getInstance();
$row = $db->fetch("SELECT id, esquema FROM lab_formularios WHERE id = 15 LIMIT 1");
if (!$row) jsonError('Formulario de tomas no encontrado.', 404);
$esquema = json_decode($row['esquema'], true);
if (!is_array($esquema)) jsonError('Esquema del formulario no válido.', 500);
// ── Localizar el campo selector de tipo de examen ────────────
$idxSelector = null;
foreach ($esquema as $i => $c) {
if (($c['id'] ?? '') === '_c8j2g16') { $idxSelector = $i; break; }
}
if ($idxSelector === null) jsonError('Campo selector de examen (_c8j2g16) no encontrado.', 500);
// ── ADD EXAM ─────────────────────────────────────────────────
if ($action === 'add_exam') {
$examName = trim($body['exam_name'] ?? '');
$tomas = $body['tomas'] ?? [];
if (!$examName) jsonError('exam_name requerido.');
if (strlen($examName) > 80) jsonError('exam_name demasiado largo (máx 80 chars).');
if (!is_array($tomas) || empty($tomas)) jsonError('tomas requeridas.');
if (count($tomas) > 20) jsonError('Máximo 20 tomas por examen.');
// Verificar que el examen no exista ya
$currentOptions = $esquema[$idxSelector]['options'] ?? [];
if (in_array($examName, $currentOptions, true)) {
jsonError("El tipo de examen '$examName' ya existe.");
}
// Validar tomas
foreach ($tomas as $i => $t) {
$tipo = $t['tipo'] ?? '';
$valor = $t['valor'] ?? '';
$label = trim($t['label'] ?? '');
if (!in_array($tipo, ['minutos', 'hora_fija'], true)) jsonError("Toma $i: tipo inválido.");
if (!$label) jsonError("Toma $i: label requerido.");
if ($tipo === 'minutos' && (!is_numeric($valor) || (int)$valor < 0))
jsonError("Toma $i: valor de minutos inválido.");
if ($tipo === 'hora_fija' && !preg_match('/^\d{1,2}:\d{2}$/', $valor))
jsonError("Toma $i: hora_fija debe ser HH:MM.");
}
// Prefijo corto para IDs (basado en nombre del examen, sanitizado)
$prefix = '_' . substr(preg_replace('/[^a-z0-9]/i', '', strtolower($examName)), 0, 8) . '_';
$uid = substr(md5($examName . microtime()), 0, 4);
// 1. Agregar opción al campo selector
$esquema[$idxSelector]['options'][] = $examName;
// 2. Agregar campos al final del esquema
$condCampoId = '_c8j2g16';
foreach ($tomas as $idx => $t) {
$label = trim($t['label']);
$tipo = $t['tipo'];
$valor = $t['valor'];
// Construir label del separador
if ($tipo === 'minutos') {
$sepLabel = "$examName · Minuto $valor";
} else {
// hora_fija: convertir HH:MM a "H:MM a.m./p.m."
[$hh, $mm] = explode(':', $valor);
$h = (int)$hh; $ampm = $h >= 12 ? 'p.m.' : 'a.m.';
$h12 = $h > 12 ? $h - 12 : ($h === 0 ? 12 : $h);
$sepLabel = "$examName · {$h12}:{$mm} {$ampm}";
}
$sepId = $prefix . 's' . $idx . $uid;
$horaId = $prefix . 'h' . $idx . $uid;
$obsId = $prefix . 'o' . $idx . $uid;
$firmaId = $prefix . 'f' . $idx . $uid;
$esquema[] = [
'id' => $sepId,
'tipo' => 'separador',
'label' => $sepLabel,
'condicion'=> ['campo_id' => $condCampoId, 'valores' => [$examName]],
];
$esquema[] = ['id' => $horaId, 'tipo' => 'hora', 'label' => 'Hora de toma'];
$esquema[] = ['id' => $obsId, 'tipo' => 'texto', 'label' => 'Observaciones', 'placeholder' => '', 'required' => false];
$esquema[] = ['id' => $firmaId, 'tipo' => 'firma_profesional', 'label' => 'Firma del profesional'];
}
$db->getConnection()->prepare(
"UPDATE lab_formularios SET esquema = ? WHERE id = 15"
)->execute([json_encode($esquema, JSON_UNESCAPED_UNICODE)]);
jsonOk([
'exam_name' => $examName,
'tomas_count' => count($tomas),
'options_count'=> count($esquema[$idxSelector]['options']),
], "Examen '$examName' agregado con " . count($tomas) . " tomas.");
}
// ── DELETE EXAM ──────────────────────────────────────────────
if ($action === 'delete_exam') {
$examName = trim($body['exam_name'] ?? '');
if (!$examName) jsonError('exam_name requerido.');
$options = $esquema[$idxSelector]['options'] ?? [];
if (!in_array($examName, $options, true)) jsonError("El examen '$examName' no existe.");
// Eliminar opción del selector
$esquema[$idxSelector]['options'] = array_values(array_filter($options, fn($o) => $o !== $examName));
// Eliminar separadores condicionados únicamente a este examen
$esquema = array_values(array_filter($esquema, function($c) use ($examName) {
$cond = $c['condicion'] ?? null;
if (!$cond) return true;
$vals = $cond['valores'] ?? [];
return !(count($vals) === 1 && $vals[0] === $examName);
}));
$db->getConnection()->prepare(
"UPDATE lab_formularios SET esquema = ? WHERE id = 15"
)->execute([json_encode($esquema, JSON_UNESCAPED_UNICODE)]);
jsonOk(['exam_name' => $examName], "Examen '$examName' eliminado.");
}