Billar Pro models each physical billiard table as a Mesa entity that transitions between two states —Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ierinconc/billar-pro-backend/llms.txt
Use this file to discover all available pages before exploring further.
LIBRE (free) and OCUPADA (occupied). The moment a table is marked occupied, the API records the exact start time. When it is closed, the elapsed time is used to compute the play charge, a Sesion record is persisted, and all product consumptions registered during that session are linked to it. This lifecycle is the core accounting unit of the system.
The Mesa Entity
Every active table in the hall is represented by aMesa row in the database.
| Field | Type | Description |
|---|---|---|
id | Long | Auto-generated primary key. |
numero | Integer | Human-readable table number displayed in the hall. Must be unique among active tables. |
estado | String | Current state: "LIBRE" or "OCUPADA". Set to "LIBRE" on creation. |
precioPorHora | Double | Hourly rate charged for play time. Must be greater than 0. |
horaInicio | LocalDateTime | The timestamp when the table was last opened. null while the table is free. |
activa | Boolean | Soft-delete flag. Defaults to true. Tables with existing sessions are never physically deleted; instead activa is set to false. |
Table & Session Lifecycle
Create a table
Register a new table by sending its number and hourly rate:The service validates three rules before saving:
numeromust not already exist among active tables (activa = true). A duplicate throwsRuntimeException("Ya existe una mesa activa con ese número").precioPorHoramust be present (non-null). An absent value throwsRuntimeException("El precio de la hora por mesa es obligatorio").precioPorHoramust be greater than0. A zero or negative value throwsRuntimeException("El precio del tiempo por mesa debe ser mayor a 0").
estado = "LIBRE" and activa = true.Open a session — occupy the table
When players sit down, mark the table as occupied:The service sets
estado = "OCUPADA" and captures horaInicio = LocalDateTime.now(), then persists the updated record. The response is the updated Mesa object.Register consumptions
While the table is occupied, staff can record any number of product sales against it:Each
Consumo record is saved with sesion = null, indicating it belongs to the current open session. See Products & Consumption for full details.Close the table
When play ends, close the table to generate the final bill:The service executes the following steps atomically:
- Reads
horaIniciofrom theMesarecord. - Captures
ahora = LocalDateTime.now(). - Computes elapsed time:
- Computes the table charge:
- Calls
SesionService.guardarSesion(mesa, horaInicio, ahora), which:- Fetches all
Consumorecords for this table wheresesion IS NULL. - Sums their
subtotalvalues intototalConsumos. - Persists a new
Sesionrow. - Updates every pending
Consumoto point at the new session.
- Fetches all
- Resets
mesa.estado = "LIBRE"andmesa.horaInicio = null.
CierreMesaDTO with the complete breakdown.The CierreMesaDTO Response
Closing a table returns the following payload:| Field | Type | Description |
|---|---|---|
horasJugadas | Double | Elapsed play time expressed as a decimal fraction of hours (e.g., 1.5 = 1 h 30 min). |
precioPorHora | Double | The table’s configured hourly rate at the time of closing. |
totalAPagar | Double | horasJugadas × precioPorHora — the charge for play time only. |
totalConsumos | Double | Sum of all product consumption subtotals linked to this session. |
totalGeneral | Double | totalAPagar + totalConsumos — the complete amount due. |
The Sesion Entity
Once a table is closed, aSesion record provides a permanent, immutable record of that game.
| Field | Type | Description |
|---|---|---|
id | Long | Auto-generated primary key. |
mesa | Mesa | FK reference to the table that was played on. |
horaInicio | LocalDateTime | Exact timestamp when the table was occupied. |
horaFin | LocalDateTime | Exact timestamp when the table was closed. |
horasJugadas | Double | Computed decimal hours between horaInicio and horaFin. |
totalMesa | Double | horasJugadas × precioPorHora. |
totalConsumos | Double | Sum of all product subtotals in this session. |
totalGeneral | Double | totalMesa + totalConsumos. |
fecha | LocalDate | Calendar date (LocalDate.now()) on which the session was closed. Used for all report queries. |
Editing a Table
A table’snumero and precioPorHora can be updated via:
OCUPADA — the service throws a RuntimeException to prevent modifying an in-progress session’s rate.
Soft-Delete Behavior
Deleting a table viaDELETE /api/mesas/{id}/delete follows a guarded path:
- If the table has no associated sessions, it is physically removed from the database (
deleteById). - If the table has at least one historical session, it is soft-deleted:
activais set tofalseand the record is preserved. This ensures that session history and reports referencing the table remain consistent.
GET /api/mesas (which queries findAllByActivaTrue) and from the uniqueness check on numero.
Billing is strictly time-proportional. The formula
Duration.between(horaInicio, now()).toMinutes() / 60.0 converts the elapsed minutes into a decimal hours value before multiplying by the hourly rate. A session of 45 minutes on a table priced at 8,000/hr therefore yields 6,000 — exactly 0.75 × 8,000.