The Banca Management Backend implements a flexible commission system with JSON-based policies that can be configured at three levels: User, Ventana, and Banca.
Key Features
Hierarchical Three-level priority: USER → VENTANA → BANCA
Rule-Based JSON policies with multiple matching rules
Immutable Snapshot captured at ticket creation time
Temporal Policies with effectiveFrom/effectiveTo dates
Graceful Malformed JSON defaults to 0% commission
Auditable Track which rule applied to each bet
Policy Structure
Commission policies are stored as JSON with version 1 schema:
{
"version" : 1 ,
"effectiveFrom" : "2025-01-01T00:00:00.000Z" ,
"effectiveTo" : "2025-12-31T23:59:59.999Z" ,
"defaultPercent" : 5.0 ,
"rules" : [
{
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"loteriaId" : "uuid-of-loteria" ,
"betType" : "NUMERO" ,
"multiplierRange" : { "min" : 70 , "max" : 100 },
"percent" : 8.5
},
{
"id" : "auto-generated-uuid" ,
"loteriaId" : null ,
"betType" : "REVENTADO" ,
"multiplierRange" : { "min" : 0 , "max" : 999 },
"percent" : 12.0
}
]
}
Field Descriptions
Policy schema version (currently 1)
ISO 8601 date when policy becomes active (null = no start limit)
ISO 8601 date when policy expires (null = no end limit)
Default commission percentage (0-100) if no rules match
Array of commission rules evaluated in order
Rule Structure
Unique identifier for the rule (auto-generated if not provided)
Specific loteria UUID (null = wildcard, matches any loteria)
Bet type: NUMERO, REVENTADO, or null (wildcard)
Range of multipliers: { "min": number, "max": number } (inclusive)
Commission percentage (0-100) for this rule
Resolution Priority
Commission policies are resolved hierarchically with first match wins :
Check User Policy
If the user (vendedor) has a commission policy, evaluate its rules in order.
If a rule matches, use that commission percentage.
Check Ventana Policy
If no user policy or no matching rule, check the ventana’s policy.
Check Banca Policy
If no ventana policy or no matching rule, check the banca’s policy.
Use Default or Zero
If no policies exist or no rules match, use the policy’s defaultPercent or 0%.
Matching Logic
A rule matches a jugada (bet) if ALL conditions are satisfied:
loteriaId matches (or rule has null = wildcard)
betType matches (or rule has null = wildcard)
finalMultiplierX is within [min, max] range (inclusive)
First matching rule in the array wins - order matters!
Snapshot Immutability
When a ticket is created, commission details are captured and frozen in each jugada:
interface JugadaCommission {
commissionPercent : number ; // 0-100
commissionAmount : number ; // round2(amount * percent / 100)
commissionOrigin : string ; // "USER" | "VENTANA" | "BANCA" | null
commissionRuleId : string ; // UUID of the rule that matched
}
Commission snapshots ensure consistent payouts even if policies change after ticket creation.
Example Snapshot
{
"id" : "jugada-uuid" ,
"ticketId" : "ticket-uuid" ,
"number" : "42" ,
"amount" : 100.00 ,
"betType" : "NUMERO" ,
"finalMultiplierX" : 80 ,
"commissionPercent" : 8.5 ,
"commissionAmount" : 8.50 ,
"commissionOrigin" : "USER" ,
"commissionRuleId" : "550e8400-e29b-41d4-a716-446655440000"
}
Managing Policies
Only ADMIN users can create or update commission policies via the API.
Set Banca Policy
curl -X PUT http://localhost:4000/api/v1/bancas/{bancaId}/commission-policy \
-H "Authorization: Bearer {accessToken}" \
-H "Content-Type: application/json" \
-d '{
"version": 1,
"defaultPercent": 5.0,
"effectiveFrom": null,
"effectiveTo": null,
"rules": [
{
"loteriaId": null,
"betType": null,
"multiplierRange": { "min": 0, "max": 999 },
"percent": 5.0
}
]
}'
Set Ventana Policy
curl -X PUT http://localhost:4000/api/v1/ventanas/{ventanaId}/commission-policy \
-H "Authorization: Bearer {accessToken}" \
-H "Content-Type: application/json" \
-d '{
"version": 1,
"defaultPercent": 7.0,
"rules": [
{
"loteriaId": "specific-loteria-uuid",
"betType": "NUMERO",
"multiplierRange": { "min": 70, "max": 100 },
"percent": 10.0
}
]
}'
Set User Policy
curl -X PUT http://localhost:4000/api/v1/users/{userId}/commission-policy \
-H "Authorization: Bearer {accessToken}" \
-H "Content-Type: application/json" \
-d '{
"version": 1,
"defaultPercent": 12.0,
"rules": [
{
"betType": "REVENTADO",
"multiplierRange": { "min": 0, "max": 999 },
"percent": 15.0
}
]
}'
Get Policy
# Get banca policy
curl http://localhost:4000/api/v1/bancas/{bancaId}/commission-policy \
-H "Authorization: Bearer {accessToken}"
# Get ventana policy
curl http://localhost:4000/api/v1/ventanas/{ventanaId}/commission-policy \
-H "Authorization: Bearer {accessToken}"
# Get user policy
curl http://localhost:4000/api/v1/users/{userId}/commission-policy \
-H "Authorization: Bearer {accessToken}"
Analytics Integration
Commission metrics are included in sales analytics endpoints:
Sales Summary
curl "http://localhost:4000/api/v1/ventas/summary?fromDate=2025-03-01&toDate=2025-03-31" \
-H "Authorization: Bearer {accessToken}"
Response includes:
{
"success" : true ,
"data" : {
"totalSales" : 100000.00 ,
"totalPayout" : 60000.00 ,
"commissionTotal" : 8500.00 ,
"netAfterCommission" : 91500.00 ,
"netRevenue" : 31500.00
}
}
Sales Breakdown by Dimension
curl "http://localhost:4000/api/v1/ventas/breakdown?dimension=ventana&fromDate=2025-03-01" \
-H "Authorization: Bearer {accessToken}"
Response includes commission per ventana:
{
"success" : true ,
"data" : [
{
"ventanaId" : "uuid-1" ,
"ventanaName" : "Ventana Central" ,
"totalSales" : 50000.00 ,
"commissionTotal" : 4250.00
},
{
"ventanaId" : "uuid-2" ,
"ventanaName" : "Ventana Norte" ,
"totalSales" : 50000.00 ,
"commissionTotal" : 4250.00
}
]
}
Time Series with Commission
curl "http://localhost:4000/api/v1/ventas/timeseries?granularity=day&fromDate=2025-03-01&toDate=2025-03-07" \
-H "Authorization: Bearer {accessToken}"
Response includes daily commission totals:
{
"success" : true ,
"data" : [
{
"timestamp" : "2025-03-01T00:00:00.000Z" ,
"totalSales" : 15000.00 ,
"commissionTotal" : 1275.00
},
{
"timestamp" : "2025-03-02T00:00:00.000Z" ,
"totalSales" : 18000.00 ,
"commissionTotal" : 1530.00
}
]
}
Error Handling
Graceful Degradation: If a commission policy JSON is malformed or invalid, the system logs a warning and applies 0% commission instead of blocking ticket creation.
This ensures that technical issues with policies don’t prevent sales operations.
Validation Errors
Invalid JSON structure → 0% commission + warning log
Missing required fields → 0% commission + warning log
Invalid percentage values (< 0 or > 100) → Clamped to 0-100
Invalid multiplier ranges → Rule skipped
Best Practices
Order rules from specific to general
Place more specific rules (with multiple conditions) first in the array: {
"rules" : [
// Specific: Loteria A + NUMERO + High multiplier
{ "loteriaId" : "..." , "betType" : "NUMERO" , "multiplierRange" : { "min" : 80 , "max" : 100 }, "percent" : 12 },
// Less specific: Any NUMERO
{ "betType" : "NUMERO" , "multiplierRange" : { "min" : 0 , "max" : 999 }, "percent" : 8 },
// Catch-all: Any bet
{ "loteriaId" : null , "betType" : null , "multiplierRange" : { "min" : 0 , "max" : 999 }, "percent" : 5 }
]
}
Use temporal policies for promotions
Test policies before deploying
Create test tickets to verify commission calculations match expectations. Review commission snapshots in ticket details.
Document rule IDs for audit trails
Use meaningful UUIDs or generate UUIDs and keep a mapping for later reference when analyzing commission data.
Ticket Creation How tickets capture commission snapshots
Analytics API View commission metrics in reports