Files
whatsapp/api/lab/submit_formulario.php
2026-06-16 16:55:22 -05:00

160 lines
6.7 KiB
PHP

<?php
/**
* POST /api/lab/submit_formulario.php — Guardar respuesta del cliente (público, sin auth)
* GET /api/lab/submit_formulario.php?t=TOKEN — Verificar estado del token (público)
*
* Body JSON (POST): { token, datos_cliente:{...}, firma_svg? }
*/
// No usar _helpers.php porque este endpoint es PÚBLICO (no requiere sesión)
require_once __DIR__ . '/../../config/config.php';
require_once __DIR__ . '/../../classes/lab/Formulario.php';
require_once __DIR__ . '/../../classes/Database.php';
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; }
function pubOk(array $data = [], string $msg = ''): void {
$r = ['success' => true];
if ($msg) $r['message'] = $msg;
echo json_encode(array_merge($r, $data), JSON_UNESCAPED_UNICODE);
exit;
}
function pubErr(string $msg, int $code = 400): void {
http_response_code($code);
echo json_encode(['success' => false, 'error' => $msg], JSON_UNESCAPED_UNICODE);
exit;
}
try {
$form = new Formulario();
// GET: cargar datos del formulario por token
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$token = $_GET['t'] ?? '';
if (!$token) pubErr('Token requerido');
$envio = $form->obtenerPorToken($token);
if (!$envio) pubErr('Link inválido o expirado', 404);
// Config de diseño: primero override del formulario, luego config global
$db2 = Database::getInstance();
$cfgRows = $db2->fetchAll('SELECT clave, valor FROM lab_config ORDER BY clave');
$gCfg = [];
foreach ($cfgRows as $r) { $gCfg[$r['clave']] = $r['valor']; }
$docConfig = [
'doc_color' => $envio['doc_color'] ?: ($gCfg['doc_color'] ?? '#1565c0'),
'doc_logo_base64' => $envio['doc_logo_base64'] ?: ($gCfg['doc_logo_base64'] ?? null),
'doc_encabezado' => $envio['doc_encabezado'] ?: ($gCfg['empresa_nombre'] ?? null),
'doc_subtitulo' => $envio['doc_subtitulo'] ?: ($gCfg['empresa_subtitulo'] ?? null),
'doc_pie_pagina' => $envio['doc_pie_pagina'] ?: ($gCfg['doc_pie_pagina'] ?? null),
];
// Estructura que espera form_cliente.php
pubOk([
'formulario' => [
'nombre' => $envio['form_nombre'],
'descripcion' => $envio['form_descripcion'] ?? '',
'esquema_decoded'=> $envio['esquema_decoded'],
'permite_firma' => (bool)($envio['permite_firma'] ?? false),
'requiere_firma' => (bool)($envio['requiere_firma'] ?? false),
],
'envio' => [
'id' => $envio['id'],
'estado' => $envio['estado'],
'firma_svg' => $envio['firma_svg'] ?? null,
'hash_verificacion'=> $envio['hash_verificacion'] ?? null,
'completado_en' => $envio['completado_en'] ?? null,
],
'prefilled' => $envio['prefilled_decoded'] ?? [],
'config' => $docConfig,
]);
}
// POST: guardar respuesta
$raw = file_get_contents('php://input');
$datos = json_decode($raw, true) ?? [];
$token = $datos['token'] ?? '';
if (!$token) pubErr('Token requerido');
$envio = $form->obtenerPorToken($token);
if (!$envio) pubErr('Link inválido o expirado', 404);
if (in_array($envio['estado'], ['completado', 'firmado'])) {
// El formulario ya fue guardado (posible reintento tras error de red).
// Devolvemos éxito con los datos existentes para que el cliente no quede bloqueado.
$db = Database::getInstance();
$saved = $db->fetch('SELECT id, hash_verificacion, firma_svg FROM lab_form_envios WHERE token = ?', [$token]);
pubOk([
'firmado' => !empty($saved['firma_svg']),
'hash' => $saved['hash_verificacion'] ?? null,
'envio_id' => $saved['id'] ?? null,
'ya_enviado'=> true,
], 'Formulario enviado correctamente. ¡Gracias!');
}
$datosCliente = $datos['datos_cliente'] ?? [];
$firmaSvg = $datos['firma_svg'] ?? null;
$firmaFoto = $datos['firma_foto'] ?? null;
// Guardar foto de firma dentro de datos_cliente para no requerir nueva columna
if ($firmaFoto) {
$datosCliente['__firma_foto'] = $firmaFoto;
}
// Validar que si requiere firma, venga
if ($envio['requiere_firma'] && !$firmaSvg) {
pubErr('La firma es obligatoria para este formulario');
}
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '';
$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
$ok = $form->guardarRespuesta($token, $datosCliente, $firmaSvg, $ip, $ua);
if (!$ok) pubErr('No se pudo guardar la respuesta', 500);
// Recuperar hash e id para la respuesta
$db = Database::getInstance();
$saved = $db->fetch('SELECT id, hash_verificacion, turnero_consentimiento_id FROM lab_form_envios WHERE token = ?', [$token]);
// Si este envío está vinculado a un consentimiento del turnero, marcarlo como firmado
if (!empty($saved['turnero_consentimiento_id'])) {
$pdo2 = $db->getConnection();
$tc = $pdo2->prepare(
"SELECT tc.id, t.sesion_id FROM turnero_consentimientos tc
JOIN turnero_turnos t ON t.id = tc.turno_id
WHERE tc.id = ? AND tc.estado != 'firmado'"
);
$tc->execute([(int)$saved['turnero_consentimiento_id']]);
$tcRow = $tc->fetch(PDO::FETCH_ASSOC);
if ($tcRow) {
$datosRespuestasJson = !empty($datosCliente)
? json_encode($datosCliente, JSON_UNESCAPED_UNICODE)
: null;
$pdo2->prepare(
"UPDATE turnero_consentimientos
SET estado='firmado', firmado_at=NOW(), firma_svg=?,
ip_firma=?, ua_firma=?, datos_respuestas=?
WHERE id=?"
)->execute([$firmaSvg, $ip, substr($ua, 0, 500), $datosRespuestasJson, (int)$tcRow['id']]);
// Notificar via SSE para actualizar lugar.php en tiempo real
if ($tcRow['sesion_id']) {
require_once __DIR__ . '/../../modules/turnero/api/_helpers.php';
notificarSSE((int)$tcRow['sesion_id']);
}
}
}
pubOk([
'firmado' => (bool)$firmaSvg,
'hash' => $saved['hash_verificacion'] ?? null,
'envio_id' => $saved['id'] ?? null,
], 'Formulario enviado correctamente. ¡Gracias!');
} catch (Exception $e) {
pubErr($e->getMessage(), 500);
}