Sprint 0.1 — Etapa K. Documento de diseño. No se implementa en este sprint. Define qué entidad es fuente de verdad de cada dato y las relaciones entre ellas. Sirve como contrato para Sprint 0.2 (modelo de datos) y Sprint 2 (motor de sesiones).
= estado operativo del servicio de juego
Representa el uso de una estación por un cliente durante un período de tiempo.
| Dato | Fuente de verdad | Notas |
|---|---|---|
estado (activa/finalizada/cancelada) |
sesiones.estado |
Único indicador. Eliminar finalizada como fuente separada (ver §Brechas). |
fecha_inicio |
sesiones.fecha_inicio |
Set al abrir. |
fecha_fin |
sesiones.fecha_fin |
Set al finalizar/anular. |
tiempo_contratado |
sesiones.tiempo_contratado |
Inmutable tras abrir. |
tiempo_adicional |
sesiones.tiempo_adicional |
Acumulado por agregarTiempo. |
tarifa_base |
sesiones.tarifa_base |
Precio del tiempo base. |
costo_adicional |
sesiones.costo_adicional |
Suma de tiempos extra. |
productos (JSONB) |
sesiones.productos |
Snapshot de productos consumidos durante la sesión. |
cliente_id |
sesiones.cliente_id |
FK al CRM. |
sala_id, estacion |
sesiones |
Ubicación física. |
usuario_id |
sesiones.usuario_id |
Quién abrió la sesión. |
No es fuente de verdad de: totales financieros finales (eso es ventas), pagos (eso es pagos), stock (eso es productos).
= documento financiero
Es el recibo. Se genera al finalizar o anular una sesión, o al hacer una venta directa en el POS.
| Dato | Fuente de verdad | Notas |
|---|---|---|
total |
ventas.total |
Fuente oficial del total cobrado. |
subtotal_tiempo |
ventas.subtotal_tiempo |
|
subtotal_productos |
ventas.subtotal_productos |
|
descuento |
ventas.descuento |
|
metodo_pago |
ventas.metodo_pago |
Fuente oficial del método de pago. |
estado (cerrada/anulada) |
ventas.estado |
|
sesion_id |
ventas.sesion_id (UNIQUE) |
Una sesión → una venta (o ninguna si se anula sin venta). |
fecha_cierre |
ventas.fecha_cierre |
Momento financiero. |
Relación: ventas.sesion_id → sesiones.id (1:1). Una venta directa del POS tiene sesion_id = NULL.
= detalle comercial
Cada línea de una venta: tiempo o producto.
| Dato | Fuente de verdad | Notas |
|---|---|---|
tipo (‘tiempo’/’producto’) |
venta_items.tipo |
|
producto_id |
venta_items.producto_id |
FK a productos (nullable si es tiempo). |
cantidad |
venta_items.cantidad |
|
precio_unitario |
venta_items.precio_unitario |
Precio al momento de la venta. |
subtotal |
venta_items.subtotal |
cantidad * precio_unitario. |
Relación: venta_items.venta_id → ventas.id (N:1).
= movimiento financiero
BRECHA: No existe tabla
pagoshoy. Los pagos divididos se guardan como columnasmonto_efectivo/transferencia/tarjeta/digitalenventasysesiones. Sprint 0.2 debe decidir: ¿crear tablapagoso mantener columnas?
Si se crea pagos:
| Dato | Fuente de verdad | Notas |
|——|——————|——-|
| venta_id | pagos.venta_id | FK a ventas. |
| metodo | pagos.metodo | efectivo/tarjeta/transferencia/digital. |
| monto | pagos.monto | |
| medio_pago_id | pagos.medio_pago_id | FK a medios_pago (qué cuenta recibió). |
| fecha | pagos.fecha | |
Relación: pagos.venta_id → ventas.id (N:1). Una venta con pago dividido → N pagos.
= existencia física
| Dato | Fuente de verdad | Notas |
|---|---|---|
stock |
productos.stock |
Único valor autoritativo. |
stock_minimo |
productos.stock_minimo |
Umbral de alerta. |
Invariante: productos.stock = stock inicial + sum(entradas) - sum(salidas). Se mantiene mediante movimientos_stock.
= trazabilidad de cambios de stock
| Dato | Fuente de verdad | Notas |
|---|---|---|
tipo |
movimientos_stock.tipo |
entrada/salida/ajuste/venta/devolucion/merma. |
cantidad |
movimientos_stock.cantidad |
Siempre positiva; el signo lo da tipo. |
stock_anterior |
movimientos_stock.stock_anterior |
Snapshot para auditoría. |
stock_nuevo |
movimientos_stock.stock_nuevo |
Snapshot para auditoría. |
referencia |
movimientos_stock.referencia |
sesión_id o factura. |
Invariante de integridad: todo cambio a productos.stock DEBE tener un movimientos_stock correspondiente. Hoy no se valida con trigger.
= consolidación monetaria por turno
| Dato | Fuente de verdad | Notas |
|---|---|---|
efectivo_esperado |
cierres_turno.efectivo_esperado |
Calculado desde ventas del turno. |
efectivo_contado |
cierres_turno.efectivo_contado |
Ingresado por el operador (arqueo ciego). |
efectivo_descuadre |
cierres_turno.efectivo_descuadre |
contado - esperado (CHECK constraint). |
total_descuadre |
cierres_turno.total_descuadre |
Incluye inventario. |
Relación: cierre_turno_items.cierre_turno_id → cierres_turno.id (N:1).
SESIÓN (consumo operativo)
│
│ 1:1 (sesion_id UNIQUE)
▼
VENTA (documento financiero)
│
│ 1:N
├──→ VENTA_ITEM (detalle comercial)
│ │
│ │ N:1 (producto_id)
│ ▼
│ PRODUCTOS (stock)
│ │
│ │ 1:N (cada cambio de stock)
│ ▼
│ MOVIMIENTO_STOCK (trazabilidad)
│
│ 1:N (si se crea tabla pagos)
▼
PAGO (movimiento financiero)
│
│ N:1 (medio_pago_id)
▼
MEDIOS_PAGO (cuentas)
CIERRES_TURNO (consolidación por turno)
│
│ 1:N
▼
CIERRE_TURNO_ITEMS (arqueo de inventario)
sesiones vs ventassesiones.total_general y ventas.total pueden divergir. Reportes leen de ambos.ventas.total es la fuente oficial. sesiones.total_general es un snapshot de conveniencia.sesiones.total_* se elimina o se mantiene como cache con trigger de sincronización.estado vs finalizadasesiones.estado='finalizada' AND sesiones.finalizada=true son dos indicadores de lo mismo.estado es la única fuente. finalizada se elimina o se deriva.finalizada (requiere update de todo el código que la lee).pagosventas/sesiones.pagos separada.monto_* a filas de pagos.sesiones.productos (JSONB) duplica venta_itemssesiones.productos (JSONB) Y luego se insertan en venta_items al finalizar.venta_items es la fuente. sesiones.productos es un carrito temporal.sesiones.productos como carrito en vivo, pero al finalizar, venta_items es el registro oficial.productos.stock tenga su movimientos_stock.AFTER UPDATE ON productos que verifique movimiento correspondiente.pagos → no hay relación con medios_pagogastos no tiene medio_pago_id. ventas no tiene medio_pago_id.medios_pago recibió el dinero.pagos con medio_pago_id.auditoria existe pero no se puebla automáticamente.AFTER INSERT/UPDATE/DELETE en sesiones, ventas, productos, gastos.sesiones (estado=finalizada, totales)ventas (cabecera)venta_items (detalle)productos (stock) + INSERT movimientos_stocksesiones (estado=cancelada, totales=0)ventas (estado=anulada) si existeproductos (devolver stock) + INSERT movimientos_stock (tipo=devolucion)ventas + INSERT venta_itemsproductos (stock) + INSERT movimientos_stockUPDATE productos SET stock = stock - $1 WHERE id = $2 AND stock >= $1 RETURNING stockImplementación: RPC PostgreSQL (stored procedure SECURITY DEFINER) o edge function con cliente service-role que ejecute las operaciones en una transacción SQL.