beginTransaction(); try { // Verificar que el turno existe y está en recepción $stmt = $pdo->prepare( "SELECT id, estado FROM turnero_turnos WHERE id = ? FOR UPDATE" ); $stmt->execute([$turnoId]); $turno = $stmt->fetch(PDO::FETCH_ASSOC); if (!$turno) { $pdo->rollBack(); jsonError('Turno no encontrado.', 404); } if (!in_array($turno['estado'], ['en_recepcion', 'espera'], true)) { $pdo->rollBack(); jsonError("El turno está en estado '{$turno['estado']}' y no se puede editar su solicitud.", 422); } // Verificar que el lugar existe $stmt = $pdo->prepare("SELECT id FROM turnero_lugares WHERE id = ? AND activo = 1"); $stmt->execute([$lugarId]); if (!$stmt->fetch()) { $pdo->rollBack(); jsonError('Lugar destino no encontrado o inactivo.', 404); } // Verificar que todos los exam_tipo_ids existen $in = implode(',', array_fill(0, count($examIds), '?')); $stmt = $pdo->prepare("SELECT COUNT(*) FROM exam_tipos WHERE id IN ({$in}) AND activo = 1"); $stmt->execute($examIds); if ((int)$stmt->fetchColumn() !== count($examIds)) { $pdo->rollBack(); jsonError('Uno o más exámenes no existen o están inactivos.', 422); } // ── Insertar o reemplazar solicitud (DELETE + INSERT para poder re-guardar) ── $stmt = $pdo->prepare("SELECT id FROM turnero_solicitudes WHERE turno_id = ?"); $stmt->execute([$turnoId]); $solAnterior = $stmt->fetch(PDO::FETCH_ASSOC); if ($solAnterior) { // Eliminar ítemes anteriores (CASCADE borrará los turnero_examen_items) $pdo->prepare("DELETE FROM turnero_solicitudes WHERE turno_id = ?")->execute([$turnoId]); } $stmt = $pdo->prepare( "INSERT INTO turnero_solicitudes (turno_id, paciente_id, lugar_id, total_cobrado, metodo_pago, observaciones, creado_por) VALUES (?, ?, ?, ?, ?, ?, ?)" ); $stmt->execute([ $turnoId, $pacienteId, $lugarId, $total, $metodoPago ?: null, $obs ?: null, adminId(), ]); $solicitudId = (int) $pdo->lastInsertId(); // ── Insertar ítemes de examen ────────────────────────────── $stmtItem = $pdo->prepare( "INSERT INTO turnero_examen_items (solicitud_id, exam_tipo_id) VALUES (?, ?)" ); foreach ($examIds as $examId) { $stmtItem->execute([$solicitudId, $examId]); } // ── Consentimientos: solo los configurados para este lugar ── $stmt = $pdo->prepare( "SELECT f.id AS formulario_id, f.nombre AS formulario_nombre FROM lab_formularios f INNER JOIN turnero_lugar_consentimientos tlc ON tlc.formulario_id = f.id WHERE tlc.lugar_id = ? AND f.is_active = 1 ORDER BY f.nombre ASC" ); $stmt->execute([$lugarId]); $consentimientosRequeridos = $stmt->fetchAll(PDO::FETCH_ASSOC); // Crear o recuperar estado de cada consentimiento requerido $stmtCreateConsent = $pdo->prepare( "INSERT IGNORE INTO turnero_consentimientos (turno_id, formulario_id, token, estado) VALUES (?, ?, UUID(), 'pendiente')" ); foreach ($consentimientosRequeridos as &$c) { $stmtCreateConsent->execute([$turnoId, $c['formulario_id']]); $stC = $pdo->prepare( "SELECT id, token, estado, enviado_at, firmado_at FROM turnero_consentimientos WHERE turno_id = ? AND formulario_id = ?" ); $stC->execute([$turnoId, $c['formulario_id']]); $row = $stC->fetch(PDO::FETCH_ASSOC); $c['id'] = $row['id'] ?? null; $c['token'] = $row['token'] ?? null; $c['estado'] = $row['estado'] ?? 'pendiente'; $c['turno_id'] = $turnoId; } unset($c); $pdo->commit(); notificarSSE(obtenerOCrearSesionHoy()); // Recuperar solicitud completa $stmt = $pdo->prepare( "SELECT s.id, s.turno_id, s.paciente_id, s.lugar_id, s.total_cobrado, s.metodo_pago, s.observaciones, s.creado_at, p.nombre_completo AS paciente_nombre, p.numero_documento AS paciente_documento, l.nombre AS lugar_nombre FROM turnero_solicitudes s LEFT JOIN lab_pacientes p ON p.id = s.paciente_id LEFT JOIN turnero_lugares l ON l.id = s.lugar_id WHERE s.id = ?" ); $stmt->execute([$solicitudId]); $solicitud = $stmt->fetch(PDO::FETCH_ASSOC); jsonOk([ 'solicitud' => $solicitud, 'consentimientos_requeridos' => $consentimientosRequeridos, ], 'Solicitud guardada correctamente'); } catch (\Throwable $e) { if ($pdo->inTransaction()) $pdo->rollBack(); jsonError('Error al crear solicitud: ' . $e->getMessage(), 500); }