Sesiones de Caja y Control de Turnos
Sesiones de Caja y Control de Turnos
Sección titulada «Sesiones de Caja y Control de Turnos»El módulo de caja administra la apertura de turnos, el registro de movimientos manuales (sangrías), los arqueos provisionales (Corte X), el cierre formal de turno (Corte Z) y la generación de reportes vectoriales PDF de Corte X y Corte Z en el cliente (@react-pdf/renderer).
Modelo de Datos
Sección titulada «Modelo de Datos»Las tablas principales que conforman la arquitectura del módulo en @uunit9/db son:
cash_sessions: Representa una sesión de caja o turno. Almacena marcas de tiempo (openedAt,closedAt), responsable de apertura/cierre (openedByUserId,closedByUserId), estado (status:'open'|'closed'), fondo inicial (openingAmount), montos esperados y contados (closingAmount,expectedAmount,difference), acumulados de sangrías (totalCashIn,totalCashOut) y métricas de auditoría (uncollectedOrdersCount,uncollectedAmount,totalTipsAmount,totalDiscountsAmount,totalVoidsAmount).cash_transactions: Registra los movimientos manuales de dinero en efectivo (sangrías) ocurridos durante la sesión. Cada registro indica su tipo (type:'in'|'out'), monto (amount), motivo (reason), usuario creador (createdByUserId) y timestamp.cash_session_counts: Guarda el arqueo detallado por método de pago realizado al momento del Corte Z (cashSessionId,paymentMethodId,expectedAmount,countedAmount,difference).orders: Cada comanda registra su sesión de caja de apertura (opened_cash_session_id) y su sesión de cierre/cobro (closed_cash_session_id).payments: Vincula las transacciones de cobro individuales con la sesión de caja activa (cashSessionId).print_jobs: Cola de impresión asíncrona utilizada para comandas de cocina (KDS) y tickets de compra. (Nota: los reportes de sesión de caja se generan en cliente mediante@react-pdf/renderer).
Ecuación Contable de Efectivo Esperado
Sección titulada «Ecuación Contable de Efectivo Esperado»El cálculo de efectivo esperado en caja durante la sesión o al momento del cierre se rige por la siguiente fórmula matemática:
$$\text{Esperado Efectivo} = \text{openingAmount} + \text{cashSalesTotal} + \text{totalCashIn} - \text{totalCashOut}$$
Donde:
- $\text{openingAmount}$: Fondo inicial de caja al abrir el turno.
- $\text{cashSalesTotal}$: Suma total de los pagos en efectivo registrados sin reembolsar durante la sesión.
- $\text{totalCashIn}$: Suma de todas las entradas manuales de dinero en efectivo (Cash In).
- $\text{totalCashOut}$: Suma de todos los retiros y sangrías manuales de dinero (Cash Out).
Para los métodos de pago electrónicos (Tarjetas, Transferencias, etc.), el saldo esperado corresponde al total de ventas procesadas mediante ese medio de pago específico:
$$\text{Esperado Medio Electronico} = \text{salesByMethod}[\text{type}]$$
Endpoints de la API (apps/api/src/routes/cash-sessions.ts)
Sección titulada «Endpoints de la API (apps/api/src/routes/cash-sessions.ts)»Todas las rutas requieren rol de sucursal caja o superior.
1. Consulta de Sesión Activa
Sección titulada «1. Consulta de Sesión Activa»GET /api/cash-sessions/current- Retorna la sesión de caja abierta en la sucursal activa (
status = 'open') junto con sus métricas acumuladas en tiempo real, onullsi no hay turno abierto.
- Retorna la sesión de caja abierta en la sucursal activa (
2. Listado Histórico
Sección titulada «2. Listado Histórico»GET /api/cash-sessions- Devuelve el listado de sesiones de caja de la sucursal con filtros por rango de fecha y paginación.
3. Apertura de Caja
Sección titulada «3. Apertura de Caja»POST /api/cash-sessions/open- Body:
{ openingAmount: number } - Restricción: Solo se permite una sesión abierta simultáneamente por sucursal. Si ya existe un turno abierto, responde con HTTP
409 Conflict(session_already_open).
- Body:
4. Registro de Sangrías y Movimientos Manuales
Sección titulada «4. Registro de Sangrías y Movimientos Manuales»POST /api/cash-sessions/:id/transactions- Body:
{ type: "in" | "out", amount: number, reason: string } - Inserta un registro en
cash_transactionsy valida que la sesión de caja permanezca abierta. Si la sesión ya está cerrada, devuelve409 session_already_closed.
- Body:
5. Reporte de Corte X (En Vivo)
Sección titulada «5. Reporte de Corte X (En Vivo)»GET /api/cash-sessions/:id/corte-x- Genera un arqueo parcial de la sesión activa en tiempo real sin modificar el estado del turno.
- Retorna marca de agua (
watermark: "CORTE X — ARQUEO PARCIAL"), métricas acumuladas, desglose por forma de pago, comandas pendientes y total de auditoría.
6. Cierre de Caja y Corte Z
Sección titulada «6. Cierre de Caja y Corte Z»POST /api/cash-sessions/:id/close- Body:
{"closingAmount": 1500.00,"closingByMethod": [{ "paymentMethodId": "pm_cash", "amount": 1500.00 },{ "paymentMethodId": "pm_card", "amount": 3200.00 }],"allowOpenOrders": true,"notes": "Cierre de turno nocturno"}
- Manejo de Conflicto de Comandas Abiertas: Si existen comandas abiertas sin cobrar (
uncollectedOrdersCount > 0) y no se envíaallowOpenOrders: true, la API rechaza el cierre respondiendo HTTP409 Conflict:{"error": "open_orders_exist","uncollectedOrdersCount": 3,"uncollectedAmount": 450.50} - Al autorizarse el cierre, actualiza el estado a
closed, registraclosedAt, congela las métricas de auditoría, guarda los conteos por método encash_session_countsy calcula la diferencia final (difference = closingAmount - expectedAmount).
- Body:
7. Generación de Reportes Vectoriales PDF (Cliente)
Sección titulada «7. Generación de Reportes Vectoriales PDF (Cliente)»En la capa de frontend (apps/platform), los reportes de Corte X y Corte Z son construidos dinámicamente con @react-pdf/renderer a partir de los datos retornados por los endpoints GET /api/cash-sessions/:id/corte-x y GET /api/cash-sessions/:id. Los usuarios pueden previsualizar, imprimir nativamente o descargar los archivos PDF vectoriales en formato A4 con los componentes PDFDownloadLink y BlobProvider.