feat(caja): generar lab_recepciones al confirmar solicitud en turnero

- create_solicitud.php crea lab_recepciones (es_historico=0) dentro de
  la transacción: num_factura auto-secuencial para registros nuevos,
  campos empresa/subgrupo/autorización/diagnóstico tomados de la solicitud
- Inserta lab_relaciones por cada examen con precio del snapshot JSON
- Inserta lab_pagos + lab_pagos_det si hay metodo_pago registrado
- Bloque try/catch: si migración 11 aún no corrió solo se loguea,
  no se revierte la solicitud principal
- recepcion.php muestra toast "Recepción #N generada" al guardar
- Migración 11: ALTER lab_recepciones.id → AUTO_INCREMENT,
  ADD solicitud_id, ALTER lab_pagos.numcaja_legacy → nullable

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-04 22:12:48 -05:00
co-authored by Claude Sonnet 4.6
parent a7aac706ee
commit f695b04f5b
3 changed files with 145 additions and 1 deletions
+115 -1
View File
@@ -199,6 +199,119 @@ try {
// Tabla aún no existe (migración pendiente) — continuar sin muestras
}
// ── Crear lab_recepciones + lab_relaciones + lab_pagos ───────
// Envuelto en try/catch para no romper el flujo si la migración 11
// aún no se ha ejecutado en este entorno.
$recepcionId = null;
try {
$operador = $_SESSION['admin_user']['username'] ?? ('u' . adminId());
// Subgrupo nombre (para campo subgrupo en recepcion)
$subgrupoNombre = null;
if ($subgrupoId) {
$stS = $pdo->prepare("SELECT subgrupo FROM lab_empresa_subgrupos WHERE id = ?");
$stS->execute([$subgrupoId]);
$subgrupoNombre = $stS->fetchColumn() ?: null;
}
// Tipo usuario de la empresa
$tipoUsuario = null;
if ($nitEmpresa) {
$stE = $pdo->prepare("SELECT tipo_usuario FROM lab_empresas WHERE nit = ?");
$stE->execute([$nitEmpresa]);
$tipoUsuario = $stE->fetchColumn() ?: null;
}
// Siguiente num_factura para registros nuevos (es_historico=0)
// FOR UPDATE garantiza secuencia correcta bajo concurrencia
$nextFac = (int)$pdo->query(
"SELECT COALESCE(MAX(num_factura), 0) + 1 FROM lab_recepciones WHERE es_historico = 0 FOR UPDATE"
)->fetchColumn();
// Calcular valor_desc desde el snapshot de precios
$valorTotal = $total ?? 0;
$valorDesc = 0;
if ($itemsPrecio) {
$snap = json_decode($itemsPrecio, true) ?? [];
$subtotalS = array_sum(array_column($snap, 'valor_final'));
$valorDesc = max(0, round($subtotalS - $valorTotal, 2));
}
$stR = $pdo->prepare(
"INSERT INTO lab_recepciones
(solicitud_id, paciente_id, medico_id, nit_empresa, subgrupo,
fecha_recepcion, hora_inicio, num_factura,
valor_total, valor_desc, diag_ppal, tipo_usuario, autorizacion,
usuario, es_historico)
VALUES (?, ?, ?, ?, ?, CURDATE(), CURTIME(), ?,
?, ?, ?, ?, ?, ?, 0)"
);
$stR->execute([
$solicitudId, $pacienteId, $medicoId, $nitEmpresa, $subgrupoNombre,
$nextFac,
$valorTotal, $valorDesc, $diagPpal, $tipoUsuario, $autorizacion,
$operador,
]);
$recepcionId = (int)$pdo->lastInsertId();
// lab_relaciones: un registro por examen
if (!empty($examIds)) {
$ph = implode(',', array_fill(0, count($examIds), '?'));
$stEx = $pdo->prepare("SELECT id, codigo FROM exam_tipos WHERE id IN ($ph)");
$stEx->execute($examIds);
$codigos = $stEx->fetchAll(PDO::FETCH_ASSOC);
// Mapa exam_tipo_id → precio desde el snapshot
$precioMap = [];
if ($itemsPrecio) {
foreach (json_decode($itemsPrecio, true) ?? [] as $item) {
$precioMap[(int)$item['exam_tipo_id']] = (float)($item['valor_final'] ?? 0);
}
}
$stRel = $pdo->prepare(
"INSERT INTO lab_relaciones (recepcion_id, cod_examen_legacy, exam_tipo_id, precio)
VALUES (?, ?, ?, ?)"
);
foreach ($codigos as $ex) {
$stRel->execute([
$recepcionId,
$ex['codigo'],
(int)$ex['id'],
$precioMap[(int)$ex['id']] ?? 0,
]);
}
}
// lab_pagos + lab_pagos_det si hay cobro
if ($metodoPago && ($valorTotal > 0 || $metodoPago === 'cortesia')) {
$stP = $pdo->prepare(
"INSERT INTO lab_pagos (recepcion_id, valor, fecha, usuario)
VALUES (?, ?, CURDATE(), ?)"
);
$stP->execute([$recepcionId, $valorTotal, $operador]);
$pagoId = (int)$pdo->lastInsertId();
$stD = $pdo->prepare(
"INSERT INTO lab_pagos_det (pago_id, tipo_pago, valor) VALUES (?, ?, ?)"
);
if ($metodoPago === 'combinado' && $pagosDetalle) {
foreach (json_decode($pagosDetalle, true) ?? [] as $tipo => $val) {
if ((float)$val > 0) {
$stD->execute([$pagoId, $tipo, (float)$val]);
}
}
} else {
$stD->execute([$pagoId, $metodoPago, $valorTotal]);
}
}
} catch (\Throwable $eRec) {
// Si falla (migración no aplicada, constraint, etc.) solo logueamos.
// La solicitud principal ya está lista; no la revertimos por esto.
error_log('[create_solicitud] lab_recepciones error: ' . $eRec->getMessage());
$recepcionId = null;
}
$pdo->commit();
notificarSSE(obtenerOCrearSesionHoy());
@@ -218,7 +331,8 @@ try {
$solicitud = $stmt->fetch(PDO::FETCH_ASSOC);
jsonOk([
'solicitud' => $solicitud,
'solicitud' => $solicitud,
'recepcion_id' => $recepcionId,
'consentimientos_requeridos' => $consentimientosRequeridos,
], 'Solicitud guardada correctamente');