> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cel-eleague.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Betting operations

# Opérations de paris

Cette page documente le cycle de vie des paris et la formule de points confirmée côté Convex.

Sources principales :

* `convex/competition/betting.ts`
* `convex/competition/betting_rules.ts`
* `convex/competition/bet_settlement.ts`
* `convex/competition/betting_reasons.ts`
* `convex/competition/betting_waves.ts`
* `convex/admin/bets.ts`
* `convex/admin/cron_runners.ts`

## États de pari

`bets.status` observé :

* `PENDING`
* `WON`
* `LOST`
* `CANCELLED`

## Cycle de vie du pari

### Création / update

`createOrUpdateBet` positionne/actualise en `PENDING`.

### Settlement d’un match

`settleBetsForMatch` traite les statuts `PENDING/WON/LOST`, écrit `WON/LOST` + `settledAt`, et nettoie `cancelReason`.

### Réouverture

`reopenBetsForMatch` repasse `PENDING/WON/LOST` vers `PENDING` et remet `pointsWon = 0`.

### Annulation

* `cancelBetsForMatch` : annule `PENDING/WON/LOST`, écrit `CANCELLED`, remet `pointsWon = 0`, avec option `advanceWave`.
* `cancelPendingBetsForMatch` : annule `PENDING` seulement.

La valeur de reason utilisée par les flux de match dépend de la cause (ex. `MATCH_FORFEITED`, `MATCH_CANCELLED`, `MATCH_RESCHEDULED`, `BETTING_DISABLED`, `ADMIN_INVALIDATION`, `ADMIN_ERROR`).

## Éligibilité paris / listing

Un match listable doit être en statut paris :

* `scheduled` (minuscule) ou `SCHEDULED` (legacy),
* `bettable === true`,
* fenêtre de coupe à `BETTING_CUTOFF_MINUTES = 60`,
* pas de signal de progression de résultat (`hasMatchProgressSignal`) déjà posé.

`hasMatchProgressSignal` couvre notamment scores finalisés partiels/finaux et timestamps associés.

## Formule de scoring

`settleSingleBet` applique :

* `EXACT_SCORE` : `3` points en cas de score identique exact.
* autres types (HOME/DRAW/AWAY) : `1` point si l’issue est correcte.

## Résultat match → paris (points de couplage)

Depuis le flux Convex, les événements impactant les paris sont :

* résultat validé : settlement de la vague courante (`settleBetsForMatch`),
* contestation / réouverture (`contestResult`, `adminResetMatchResult`, `adminSetMatchResult` en retour `pending_validation`) : `reopenBetsForMatch`,
* annulations/indisponibilités match (ex. cancellation, reschedule, forfeit) : `cancel...` selon contexte.

## Forfaits club et paris

`applyClubForfeit` annule les paris via `cancelPendingBetsForMatch` avec raison `MATCH_FORFEITED` :

* seuls les paris `PENDING` de la vague courante sont affectés,
* les paris déjà gagnants/perdants ne sont pas réouverts par la réversion de forfeit.

## Admin bet bulk settlement

`requestBulkSettleBets` (admin / modérateur) crée une exécution Cron `admin-bets-bulk-settlement`.

`runBetBulkSettlement` :

* filtre et dédoublonne les IDs,
* applique patch par patch,
* écrit un audit par pari,
* envoie `notifyBetStatusChange`,
* maintient `requested/updated/skipped/failed` dans `cron_executions`.

En cas d’échec partiel, un avertissement `admin.bet_bulk_job.partial_failure_alerted` peut être déclenché.

## Limites / précautions

* Certains détails de pagination d’exports admin et de transport notification (format exact email/in-app global) sont à confirmer côté couche notification. **\[non vérifié]**
* Le format final des tables de monitoring dépend de la version du job Cron et n’est pas entièrement normalisé ici. **\[non vérifié]**
