Overview
The ticket creation system handles lottery bet registration with multi-layer validation, restriction rules enforcement, commission calculation, and transactional safety. All tickets go through a secure flow that ensures data integrity and compliance with betting limits.Ticket Lifecycle
Creating a Ticket
Select sorteo and validate status
The sorteo must be in
OPEN status. Tickets cannot be created for SCHEDULED, CLOSED, or EVALUATED sorteos.Check sales cutoff time
The system enforces a sales cutoff period before the sorteo draw time. This is resolved hierarchically:Priority chain:
RestrictionRule.salesCutoffMinutes(User → Ventana → Banca)Loteria.rulesJson.closingTimeBeforeDraw- Default: 5 minutes
System processes validations
The system automatically:
- Validates number range (00-99 for 2-digit lotteries)
- Checks
allowedBetTypesfromLoteria.rulesJson - Applies restriction rules (max per number, max per ticket)
- Resolves base multiplier using priority chain
- Calculates commissions with snapshot
- Assigns sequential ticket number
Validation Rules
Number Range Validation
Fromsrc/api/v1/controllers/ticket.controller.ts:11-20:
- Numbers must be within
rulesJson.numberRange(default: 00-99) - REVENTADO bets require
requiresMatchingNumberconfig - Bet types must be in
allowedBetTypesarray
Restriction Rules Application
Restriction rules are applied hierarchically with first match wins logic:
- User-level (priority 100)
- Ventana-level (priority 10)
- Banca-level (priority 1)
Impersonation (VENTANA/ADMIN)
VENTANA and ADMIN users can create tickets on behalf of VENDEDOR users.ticket.controller.ts:11-20:
- VENDEDOR role:
vendedorIdis ignored, uses authenticated user - VENTANA role:
vendedorIdmust belong to sameventanaId - ADMIN role: Can use any valid
vendedorIdwith VENDEDOR role - The ticket’s
ventanaIdis always from the effective vendedor
Managing Existing Tickets
List Tickets
scope:mine|all(RBAC-filtered)date:today|yesterday|week|month|rangefromDate,toDate: Fordate=range(YYYY-MM-DD)sorteoId: Filter by specific sorteoloteriaId: Filter by lotterywinnersOnly: Boolean, only winning ticketsnumber: Filter by bet numberisActive: Boolean, active/cancelled tickets
Get Ticket Details
- Jugadas (bets) with commission snapshots
- Sorteo details
- Payment history
- Evaluation results (if evaluated)
Cancel a Ticket
src/api/v1/controllers/ticket.controller.ts:155-159:
Restore a Ticket
src/api/v1/controllers/ticket.controller.ts:161-165:
Commission Snapshot
Every jugada includes an immutable commission snapshot at creation time:- User commission policy
- Ventana commission policy
- Banca commission policy
- Default: 0%
Transactional Safety
All ticket creation useswithTransactionRetry from src/core/withConnectionRetry.ts:
- Deadlock handling: Exponential backoff on P2034 errors
- Timeout protection: Explicit transaction timeout
- Atomic operations: Sequential ticket number + restriction check + creation
- Activity logging: Asynchronous audit trail
Filter Options API
Get available filter values based on actual tickets:src/api/v1/controllers/ticket.controller.ts:879-946:
Returns:
Best Practices
Always validate sorteo status before UI
Always validate sorteo status before UI
Fetch sorteo details and check
status === 'OPEN' before showing ticket creation form.Handle cutoff times gracefully
Handle cutoff times gracefully
Display remaining time to cutoff. Refresh sorteo status periodically.
Batch number lookups
Batch number lookups
Use
/tickets/numbers-summary to get aggregated bet amounts per number before creating tickets.Implement idempotency
Implement idempotency
Store
requestId client-side to prevent duplicate submissions on network retry.Related Endpoints
- Sorteo Management - Understanding sorteo lifecycle
- Restriction Rules - Setting up betting limits
- Payments - Processing winning ticket payments
- Analytics - Ticket statistics and reports