- Campo N.° Orden editable en la ficha, antes de seleccionar paciente - Se carga automáticamente al abrir un turno (YYYYMMDD-001, 002…) - Botón para regenerar el siguiente consecutivo - Columna numero_orden en turnero_solicitudes (VARCHAR 20) - Nuevo endpoint get_consecutivo.php calcula el siguiente del día - create_solicitud.php guarda el numero_orden junto con la solicitud Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
171 lines
6.9 KiB
PHP
171 lines
6.9 KiB
PHP
<?php
|
|
/**
|
|
* POST /modules/turnero/api/create_solicitud.php
|
|
* Crea la solicitud interna de un turno: vincula paciente, lugar y exámenes.
|
|
* Además devuelve qué consentimientos serán necesarios (sin enviarlos aún).
|
|
* Requiere login + módulo turnero.
|
|
*
|
|
* Body JSON:
|
|
* turno_id int requerido
|
|
* paciente_id int requerido
|
|
* lugar_id int requerido
|
|
* exam_tipo_ids int[] requerido (al menos 1)
|
|
* total_cobrado float opcional
|
|
* metodo_pago string opcional
|
|
* observaciones string opcional
|
|
*/
|
|
|
|
require_once __DIR__ . '/_helpers.php';
|
|
requireMethod('POST');
|
|
requireTurnero();
|
|
|
|
$datos = inputJson();
|
|
$turnoId = isset($datos['turno_id']) ? (int) $datos['turno_id'] : 0;
|
|
$pacienteId = isset($datos['paciente_id']) ? (int) $datos['paciente_id'] : 0;
|
|
$lugarId = isset($datos['lugar_id']) ? (int) $datos['lugar_id'] : 0;
|
|
$examIds = isset($datos['exam_tipo_ids']) && is_array($datos['exam_tipo_ids'])
|
|
? array_filter(array_map('intval', $datos['exam_tipo_ids'])) : [];
|
|
$total = isset($datos['total_cobrado']) && $datos['total_cobrado'] !== null
|
|
? (float) $datos['total_cobrado'] : null;
|
|
$metodoPago = isset($datos['metodo_pago']) ? trim((string) $datos['metodo_pago']) : null;
|
|
$obs = isset($datos['observaciones']) ? trim((string) $datos['observaciones']) : null;
|
|
$numOrden = isset($datos['numero_orden']) ? trim((string) $datos['numero_orden']) : null;
|
|
if ($numOrden === '') $numOrden = null;
|
|
|
|
// ── Validaciones ──────────────────────────────────────────────
|
|
if ($turnoId <= 0) jsonError('turno_id inválido.');
|
|
if ($pacienteId <= 0) jsonError('paciente_id inválido.');
|
|
if ($lugarId <= 0) jsonError('lugar_id inválido.');
|
|
if (empty($examIds)) jsonError('Debe seleccionar al menos un examen.');
|
|
|
|
$metodosValidos = ['efectivo', 'transferencia', 'tarjeta', 'eps', 'cortesia', ''];
|
|
if ($metodoPago && !in_array($metodoPago, $metodosValidos, true)) {
|
|
jsonError('metodo_pago inválido.');
|
|
}
|
|
|
|
$pdo = db();
|
|
$pdo->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, numero_orden, total_cobrado, metodo_pago, observaciones, creado_por)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
|
|
);
|
|
$stmt->execute([
|
|
$turnoId, $pacienteId, $lugarId, $numOrden,
|
|
$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);
|
|
}
|