Il badge Sherpa dei palloni conta solo i turni confermati, non le proposte
rosa.ts calcolava Giocatore.palloni su completaTurni() (turni salvati + proposte automatiche di rotazione non ancora confermate da nessuno): un giocatore poteva avanzare nel badge senza aver mai confermato un turno, solo perché l'algoritmo lo proponeva per un evento passato. Ora passa a conteggioTurni() solo turniSalvati (i turni davvero confermati in turni_palloni); completaTurni() resta in uso solo per la UI di rotazione (TurnoPalloni.tsx, PromemoriaPalloni.tsx). Corregge anche la StatTile "quante volte hai portato i palloni" nel profilo, che leggeva lo stesso valore. Aggiornato palloni-badge.test.ts per verificare il nuovo comportamento (un evento non confermato non conta più per nessuno) invece del vecchio. docs/modules/ badge.md e palloni.md aggiornati di conseguenza, spostando la voce da "Limiti noti" a "risolto". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+27
-23
@@ -36,13 +36,12 @@ badge assegnati per voto dai compagni.
|
|||||||
- **Badge Sherpa dei palloni** (`palloni`, in `badgeDefs`): `g.palloni` non è un contatore
|
- **Badge Sherpa dei palloni** (`palloni`, in `badgeDefs`): `g.palloni` non è un contatore
|
||||||
incrementato a ogni evento, ma ricalcolato da `conteggioTurni()` (`palloni-core.ts`) su
|
incrementato a ogni evento, ma ricalcolato da `conteggioTurni()` (`palloni-core.ts`) su
|
||||||
`Giocatore.palloni` (`rosa.ts`) — meccanismo di turni/rotazione descritto per intero in
|
`Giocatore.palloni` (`rosa.ts`) — meccanismo di turni/rotazione descritto per intero in
|
||||||
[palloni.md](palloni.md), non ripetuto qui. Un punto rilevante per il badge, **non ovvio**:
|
[palloni.md](palloni.md), non ripetuto qui. `rosa.ts` passa a `conteggioTurni()` **solo i
|
||||||
il conteggio include anche le proposte automatiche di `completaTurni()` **non ancora
|
turni confermati** (`turniSalvati` da `useTurniPalloni()`), non l'output di
|
||||||
confermate** da nessuno (solo per partite/eventi, mai per allenamenti), non solo i turni
|
`completaTurni()`: le proposte automatiche di rotazione (usate altrove, per la UI di
|
||||||
salvati esplicitamente in `turni_palloni` — un giocatore può ricevere credito per un turno
|
`TurnoPalloni.tsx`) non contano per il badge, che premia solo chi ha davvero confermato di
|
||||||
che non ha mai confermato di aver fatto, semplicemente perché l'algoritmo di rotazione lo ha
|
aver portato i palloni. Conta solo per eventi già trascorsi (`e.data < oggi`, stesso
|
||||||
proposto per un evento ormai passato. Conta solo per eventi già trascorsi (`e.data < oggi`,
|
criterio delle presenze).
|
||||||
stesso criterio delle presenze).
|
|
||||||
- **Badge Pagellone** (`pagella`, in `badgeDefs`): a differenza degli altri badge da
|
- **Badge Pagellone** (`pagella`, in `badgeDefs`): a differenza degli altri badge da
|
||||||
contatore, richiede un numero minimo di voti (`VOTI_MINIMI_PAGELLA = 5`, `badges.ts`) prima
|
contatore, richiede un numero minimo di voti (`VOTI_MINIMI_PAGELLA = 5`, `badges.ts`) prima
|
||||||
che `g.mediaVoto` conti — sotto soglia `valore(g)` è forzato a `0` (badge bloccato), anche
|
che `g.mediaVoto` conti — sotto soglia `valore(g)` è forzato a `0` (badge bloccato), anche
|
||||||
@@ -91,7 +90,7 @@ soglia raggiunta o superata (soglie inclusive), oltre l'oro resta oro.
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `mvp` | MVP | partite vinte nettamente al voto MVP dei compagni (`g.mvp`, vedi pipeline sopra) | 1 / 3 / 5 |
|
| `mvp` | MVP | partite vinte nettamente al voto MVP dei compagni (`g.mvp`, vedi pipeline sopra) | 1 / 3 / 5 |
|
||||||
| `pagella` | Pagellone | media dei voti pagella ricevuti dai compagni a fine partita (`g.mediaVoto`), solo se ne ha ricevuti almeno `VOTI_MINIMI_PAGELLA` (5) | 6.5 / 7.5 / 8.5 |
|
| `pagella` | Pagellone | media dei voti pagella ricevuti dai compagni a fine partita (`g.mediaVoto`), solo se ne ha ricevuti almeno `VOTI_MINIMI_PAGELLA` (5) | 6.5 / 7.5 / 8.5 |
|
||||||
| `palloni` | Sherpa dei palloni | quante volte hai fatto (o ti è stato proposto, vedi sopra) il turno palloni (`g.palloni`) | 3 / 6 / 10 |
|
| `palloni` | Sherpa dei palloni | quante volte hai confermato il turno palloni (`g.palloni`) — le proposte automatiche non ancora confermate non contano | 3 / 6 / 10 |
|
||||||
| `presenze` | Presenza fissa | totale presenze (presente o ritardo) a eventi/partite di sempre, non solo della stagione in corso (`g.presenze`) | 5 / 15 / 30 |
|
| `presenze` | Presenza fissa | totale presenze (presente o ritardo) a eventi/partite di sempre, non solo della stagione in corso (`g.presenze`) | 5 / 15 / 30 |
|
||||||
| `serie-allenamenti` | Sempre in palestra | allenamenti consecutivi presenti (`g.serieAllenamenti`); un infortunio non spezza la serie, un'assenza sì | 3 / 6 / 10 |
|
| `serie-allenamenti` | Sempre in palestra | allenamenti consecutivi presenti (`g.serieAllenamenti`); un infortunio non spezza la serie, un'assenza sì | 3 / 6 / 10 |
|
||||||
| `serie-conferme` | Risposta lampo | conferme di presenza consecutive date entro 24h dalla convocazione (`g.serieConferme`) | 3 / 8 / 15 |
|
| `serie-conferme` | Risposta lampo | conferme di presenza consecutive date entro 24h dalla convocazione (`g.serieConferme`) | 3 / 8 / 15 |
|
||||||
@@ -205,22 +204,22 @@ dopo l'analisi che ha trovato il gap "un voto solo sblocca il badge"):
|
|||||||
tenga il badge bloccato sotto soglia, lo sblocchi al voto minimo con il grado giusto, e
|
tenga il badge bloccato sotto soglia, lo sblocchi al voto minimo con il grado giusto, e
|
||||||
applichi le soglie normali sopra soglia.
|
applichi le soglie normali sopra soglia.
|
||||||
|
|
||||||
**Badge Sherpa dei palloni — pipeline end-to-end e proposte non confermate** (analisi
|
**Badge Sherpa dei palloni — pipeline end-to-end, ora senza contare le proposte non
|
||||||
dedicata: nessun bug trovato, ma il comportamento "le proposte contano" — già in
|
confermate** (analisi dedicata: trovato e sistemato il gap "le proposte contano", che
|
||||||
`palloni.md` — non era mai stato dimostrato con dati veri):
|
gonfiava il badge di turni mai confermati da nessuno — vedi "Problemi noti da sistemare"):
|
||||||
- Unit: `badges.test.ts:93-104` — soglie 3/6/10 (confine incluso, oltre l'oro resta oro) +
|
- Unit: `badges.test.ts:93-104` — soglie 3/6/10 (confine incluso, oltre l'oro resta oro) +
|
||||||
`palloni-core.test.ts`, già completo prima di questa sessione (`completaTurni()`,
|
`palloni-core.test.ts`, già completo prima di questa sessione (`completaTurni()`,
|
||||||
`conteggioTurni()`, rotazione bilanciata su un giro completo di partite, allenamenti mai
|
`conteggioTurni()`, rotazione bilanciata su un giro completo di partite, allenamenti mai
|
||||||
proposti in automatico, turno di un giocatore non più in rosa che non rompe il conteggio).
|
proposti in automatico, turno di un giocatore non più in rosa che non rompe il conteggio).
|
||||||
- Integration (`npx supabase start` richiesto):
|
- Integration (`npx supabase start` richiesto):
|
||||||
- `scritture.test.ts` — un turno resta uno per evento (l'upsert sostituisce, non aggiunge).
|
- `scritture.test.ts` — un turno resta uno per evento (l'upsert sostituisce, non aggiunge).
|
||||||
- `palloni-badge.test.ts` (nuovo) — end-to-end reale: scrive eventi e turni **solo
|
- `palloni-badge.test.ts` — end-to-end reale: scrive eventi e turni **solo parzialmente
|
||||||
parzialmente confermati** su `eventi_app`/`turni_palloni`, rilegge via REST come fa
|
confermati** su `eventi_app`/`turni_palloni`, rilegge via REST come fa `fetchTurni()`/
|
||||||
`fetchTurni()`/`daRiga()`, passa i dati per `completaTurni()` → `conteggioTurni()` fino a
|
`daRiga()` e passa `turniSalvati` (solo confermati, mai l'output di `completaTurni()`) a
|
||||||
`statoBadge()`: dimostra che un evento passato senza turno confermato riceve comunque una
|
`conteggioTurni()` fino a `statoBadge()`: dimostra che un evento passato senza turno
|
||||||
proposta automatica che **conta per il badge di chi viene scelto**, anche se non ha mai
|
confermato **non conta per nessuno**, anche se un algoritmo di rotazione (usato altrove
|
||||||
confermato nulla; verifica anche che un evento futuro non conti, pur avendo già
|
per la UI) lo proporrebbe automaticamente; verifica anche che un evento futuro non conti,
|
||||||
un'assegnazione.
|
pur avendo già una conferma.
|
||||||
|
|
||||||
**Badge Presenza fissa — pipeline end-to-end** (analisi dedicata: nessun bug trovato; a
|
**Badge Presenza fissa — pipeline end-to-end** (analisi dedicata: nessun bug trovato; a
|
||||||
differenza di MVP/pagelle/badge social, per questo badge **non serve** l'estensione RLS di
|
differenza di MVP/pagelle/badge social, per questo badge **non serve** l'estensione RLS di
|
||||||
@@ -318,14 +317,19 @@ Trovati in audit, nessuno bloccante (nessun bug nella logica di calcolo):
|
|||||||
risposte precedenti a `m9`: su quelle righe la serie è un'approssimazione.
|
risposte precedenti a `m9`: su quelle righe la serie è un'approssimazione.
|
||||||
- Nessuno storico dei badge sbloccati: se cambiano le soglie o i dati sorgente, un badge già
|
- Nessuno storico dei badge sbloccati: se cambiano le soglie o i dati sorgente, un badge già
|
||||||
"ottenuto" può sparire o apparire retroattivamente.
|
"ottenuto" può sparire o apparire retroattivamente.
|
||||||
- **Sherpa dei palloni conta anche le proposte non confermate**: `g.palloni` include i turni
|
|
||||||
che `completaTurni()` propone in automatico per un evento passato senza assegnazione
|
|
||||||
esplicita, non solo quelli confermati in `turni_palloni` — comportamento voluto (documentato
|
|
||||||
in [palloni.md](palloni.md)), dimostrato con dati veri in `palloni-badge.test.ts`, ma non
|
|
||||||
intuitivo: un giocatore può vedere avanzare il badge senza aver mai cliccato nulla.
|
|
||||||
- Notifiche "nuovo badge" solo locali al dispositivo (localStorage), si ripetono cambiando
|
- Notifiche "nuovo badge" solo locali al dispositivo (localStorage), si ripetono cambiando
|
||||||
browser o dispositivo.
|
browser o dispositivo.
|
||||||
|
|
||||||
|
**Risolto (analisi del badge Sherpa dei palloni)**: prima `g.palloni` (`rosa.ts`) includeva
|
||||||
|
anche i turni che `completaTurni()` propone in automatico per un evento passato senza
|
||||||
|
assegnazione esplicita, non solo quelli confermati in `turni_palloni` — un giocatore poteva
|
||||||
|
vedere avanzare il badge senza aver mai confermato nulla, semplicemente perché l'algoritmo di
|
||||||
|
rotazione l'aveva proposto. Ora `rosa.ts` passa a `conteggioTurni()` solo `turniSalvati` (i
|
||||||
|
turni confermati), non l'output di `completaTurni()`: quest'ultimo resta in uso solo per la
|
||||||
|
UI di rotazione (`TurnoPalloni.tsx`, `PromemoriaPalloni.tsx`), mai per il conteggio del badge.
|
||||||
|
Dimostrato con dati veri in `palloni-badge.test.ts`. [palloni.md](palloni.md) aggiornato di
|
||||||
|
conseguenza.
|
||||||
|
|
||||||
**Risolto (M13, `20260908120000_m13_convocati_e_pagelle_chiuse.sql`)**: prima la policy di M11
|
**Risolto (M13, `20260908120000_m13_convocati_e_pagelle_chiuse.sql`)**: prima la policy di M11
|
||||||
garantiva solo che il voto fosse firmato con il proprio `votante_id`, non che il votato (né il
|
garantiva solo che il voto fosse firmato con il proprio `votante_id`, non che il votato (né il
|
||||||
votante) fossero convocati per quella partita — filtro solo applicativo, aggirabile scrivendo
|
votante) fossero convocati per quella partita — filtro solo applicativo, aggirabile scrivendo
|
||||||
|
|||||||
@@ -33,11 +33,12 @@ compaiono.
|
|||||||
- `useAssegnaTurno()` (`palloni.ts`) conferma una proposta o riassegna manualmente, con
|
- `useAssegnaTurno()` (`palloni.ts`) conferma una proposta o riassegna manualmente, con
|
||||||
upsert su `evento_id`.
|
upsert su `evento_id`.
|
||||||
- Il conteggio "quante volte hai portato i palloni" mostrato nel profilo e nei badge è
|
- Il conteggio "quante volte hai portato i palloni" mostrato nel profilo e nei badge è
|
||||||
ricalcolato a runtime da `conteggioTurni()` su turni salvati **più proposte non ancora
|
ricalcolato a runtime da `conteggioTurni()` sui **soli turni confermati** (`turniSalvati`
|
||||||
confermate** (partite/eventi) — non è uno storico in tabella dedicata. Conta solo gli
|
in `rosa.ts`) — non è uno storico in tabella dedicata, ma non include le proposte
|
||||||
eventi già passati (`e.data < oggi`, stesso criterio delle presenze): un turno assegnato
|
automatiche di `completaTurni()` (quelle restano solo per la UI di rotazione,
|
||||||
in anticipo per un allenamento futuro non è ancora "portato", quindi non sale finché quel
|
`TurnoPalloni.tsx`/`PromemoriaPalloni.tsx`). Conta solo gli eventi già passati (`e.data <
|
||||||
giorno non arriva.
|
oggi`, stesso criterio delle presenze): un turno assegnato in anticipo per un allenamento
|
||||||
|
futuro non è ancora "portato", quindi non sale finché quel giorno non arriva.
|
||||||
- `TurnoPalloni.tsx` mostra/assegna il turno sulla card di un evento; `PromemoriaPalloni.tsx`
|
- `TurnoPalloni.tsx` mostra/assegna il turno sulla card di un evento; `PromemoriaPalloni.tsx`
|
||||||
è il banner in Home per il giocatore di turno.
|
è il banner in Home per il giocatore di turno.
|
||||||
|
|
||||||
@@ -62,8 +63,6 @@ nessuna chiamata di rete. Stesso meccanismo di `apri-sondaggio` (vedi
|
|||||||
- **L'invio è manuale**: nessun cron manda il promemoria da solo, se l'admin non preme il
|
- **L'invio è manuale**: nessun cron manda il promemoria da solo, se l'admin non preme il
|
||||||
pulsante non parte niente (DD-025). `destinatariPromemoriaPalloni()` — la versione "chi è di
|
pulsante non parte niente (DD-025). `destinatariPromemoriaPalloni()` — la versione "chi è di
|
||||||
turno oggi" — resta in `palloni-core.ts` ma non la chiama più nessuno.
|
turno oggi" — resta in `palloni-core.ts` ma non la chiama più nessuno.
|
||||||
- Il conteggio dei turni include anche le proposte non confermate: badge e statistiche
|
|
||||||
possono contare turni mai effettivamente convalidati da nessuno.
|
|
||||||
- La rotazione non considera le assenze dichiarate: può proporre il turno a chi ha risposto
|
- La rotazione non considera le assenze dichiarate: può proporre il turno a chi ha risposto
|
||||||
"assente" o "infortunato" per quell'evento.
|
"assente" o "infortunato" per quell'evento.
|
||||||
|
|
||||||
|
|||||||
+17
-3
@@ -61,7 +61,7 @@ export function useRosa(): Giocatore[] {
|
|||||||
const voti = useVotiMvp();
|
const voti = useVotiMvp();
|
||||||
const { voti: pagelle } = usePagelle();
|
const { voti: pagelle } = usePagelle();
|
||||||
const { righe: cacche } = useCacche();
|
const { righe: cacche } = useCacche();
|
||||||
const { turni } = useTurniPalloni();
|
const { salvati: turniSalvati } = useTurniPalloni();
|
||||||
const { infortuni, ritardi } = useInfortuniERitardi();
|
const { infortuni, ritardi } = useInfortuniERitardi();
|
||||||
const { eventi } = useEventi();
|
const { eventi } = useEventi();
|
||||||
const { presenze: mappaPresenze, tempi } = useRispostePresenze();
|
const { presenze: mappaPresenze, tempi } = useRispostePresenze();
|
||||||
@@ -71,7 +71,10 @@ export function useRosa(): Giocatore[] {
|
|||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
const medie = mediePagelle(pagelle);
|
const medie = mediePagelle(pagelle);
|
||||||
const statCacche = statisticheCacche(cacche);
|
const statCacche = statisticheCacche(cacche);
|
||||||
const palloni = conteggioTurni(turni, eventi);
|
// Solo i turni confermati, non le proposte automatiche di completaTurni(): il badge deve
|
||||||
|
// premiare chi ha davvero portato i palloni, non chi l'algoritmo di rotazione ha
|
||||||
|
// scelto per un evento passato senza che nessuno confermasse nulla.
|
||||||
|
const palloni = conteggioTurni(turniSalvati, eventi);
|
||||||
const mvpVinti = mvpVintiPerGiocatore(votiMvp);
|
const mvpVinti = mvpVintiPerGiocatore(votiMvp);
|
||||||
|
|
||||||
return squadra
|
return squadra
|
||||||
@@ -98,7 +101,18 @@ export function useRosa(): Giocatore[] {
|
|||||||
infortuni: infortuni[g.id] ?? 0,
|
infortuni: infortuni[g.id] ?? 0,
|
||||||
ritardi: ritardi[g.id] ?? 0,
|
ritardi: ritardi[g.id] ?? 0,
|
||||||
}));
|
}));
|
||||||
}, [squadra, votiMvp, pagelle, cacche, turni, infortuni, ritardi, eventi, mappaPresenze, tempi]);
|
}, [
|
||||||
|
squadra,
|
||||||
|
votiMvp,
|
||||||
|
pagelle,
|
||||||
|
cacche,
|
||||||
|
turniSalvati,
|
||||||
|
infortuni,
|
||||||
|
ritardi,
|
||||||
|
eventi,
|
||||||
|
mappaPresenze,
|
||||||
|
tempi,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Il giocatore selezionato sul dispositivo, con le statistiche complete. */
|
/** Il giocatore selezionato sul dispositivo, con le statistiche complete. */
|
||||||
|
|||||||
@@ -3,24 +3,26 @@
|
|||||||
* `bun test/integration/palloni-badge.test.ts`.
|
* `bun test/integration/palloni-badge.test.ts`.
|
||||||
*
|
*
|
||||||
* I test unitari (`test/unit/palloni-core.test.ts`, `test/unit/badges.test.ts`) verificano
|
* I test unitari (`test/unit/palloni-core.test.ts`, `test/unit/badges.test.ts`) verificano
|
||||||
* `completaTurni()`/`conteggioTurni()` e `statoBadge()` come funzioni pure, con eventi e turni
|
* `conteggioTurni()` e `statoBadge()` come funzioni pure, con eventi e turni costruiti a mano.
|
||||||
* costruiti a mano. Qui invece si scrivono eventi e turni veri su `eventi_app`/`turni_palloni`,
|
* Qui invece si scrivono eventi e turni veri su `eventi_app`/`turni_palloni`, si rileggono via
|
||||||
* si rileggono via REST con la stessa forma di `fetchTurni()`/`daRiga()`, e si passa il
|
* REST con la stessa forma di `fetchTurni()`/`daRiga()`, e si passa il risultato attraverso
|
||||||
* risultato attraverso `completaTurni()` → `conteggioTurni()` fino a `statoBadge()` sul badge
|
* `conteggioTurni()` fino a `statoBadge()` sul badge `palloni`: se una colonna cambia nome o la
|
||||||
* `palloni`: se una colonna cambia nome o la mappatura si rompe, qui il grado del badge torna
|
* mappatura si rompe, qui il grado del badge torna sbagliato anche se i test unitari restano
|
||||||
* sbagliato anche se i test unitari restano verdi, perché quelli non toccano mai il database.
|
* verdi, perché quelli non toccano mai il database.
|
||||||
*
|
*
|
||||||
* Copre in particolare un comportamento **documentato ma non ovvio** (`docs/modules/
|
* Verifica in particolare che il badge conti **solo i turni confermati**
|
||||||
* palloni.md` § Limiti noti): il conteggio usato dal badge include anche le proposte
|
* (`Giocatore.palloni` in `rosa.ts` usa `turniSalvati`, non l'output di `completaTurni()`):
|
||||||
* automatiche non ancora confermate da nessuno, non solo i turni salvati esplicitamente. Qui
|
* un evento passato senza turno confermato non deve avanzare il badge di nessuno, anche se
|
||||||
* lo si dimostra con dati veri, non solo con l'affermazione in doc.
|
* `completaTurni()` (usato altrove, per la UI di rotazione) lo proporrebbe automaticamente a
|
||||||
|
* qualcuno. Prima di questo fix il badge includeva anche le proposte non confermate — vedi
|
||||||
|
* `docs/modules/badge.md` § Limiti noti (risolto) per il dettaglio del bug e della correzione.
|
||||||
*
|
*
|
||||||
* Gira solo sullo stack locale (`npx supabase start`) e cancella le proprie righe alla fine:
|
* Gira solo sullo stack locale (`npx supabase start`) e cancella le proprie righe alla fine:
|
||||||
* usa id con il prefisso `test-palloni-badge`, che nessun dato vero può avere.
|
* usa id con il prefisso `test-palloni-badge`, che nessun dato vero può avere.
|
||||||
*/
|
*/
|
||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
import { badgeDefs, statoBadge } from "@/lib/badges";
|
import { badgeDefs, statoBadge } from "@/lib/badges";
|
||||||
import { completaTurni, conteggioTurni, type CandidatoTurno } from "@/lib/palloni-core";
|
import { conteggioTurni } from "@/lib/palloni-core";
|
||||||
import { daRiga, type RigaEvento, type Evento } from "@/lib/eventi";
|
import { daRiga, type RigaEvento, type Evento } from "@/lib/eventi";
|
||||||
import { giocatori, type Giocatore } from "@/lib/crapp-data";
|
import { giocatori, type Giocatore } from "@/lib/crapp-data";
|
||||||
import { statoLocale } from "../helpers/locale";
|
import { statoLocale } from "../helpers/locale";
|
||||||
@@ -41,11 +43,6 @@ if (!locale) {
|
|||||||
// così restano "passati" (e quindi contati) a prescindere da quando gira il test.
|
// così restano "passati" (e quindi contati) a prescindere da quando gira il test.
|
||||||
const OGGI = "2099-01-01";
|
const OGGI = "2099-01-01";
|
||||||
|
|
||||||
const ROSA: CandidatoTurno[] = [
|
|
||||||
{ id: "pv1", nome: "Uno" },
|
|
||||||
{ id: "pv2", nome: "Due" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const rest = (percorso: string, init?: RequestInit) =>
|
const rest = (percorso: string, init?: RequestInit) =>
|
||||||
fetch(`${URL_BASE}/rest/v1/${percorso}`, {
|
fetch(`${URL_BASE}/rest/v1/${percorso}`, {
|
||||||
...init,
|
...init,
|
||||||
@@ -86,6 +83,7 @@ if (!locale) {
|
|||||||
return righe.map(daRiga);
|
return righe.map(daRiga);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Rilegge esattamente come `fetchTurni()`: solo i turni confermati, nessuna proposta. */
|
||||||
async function leggiTurniSalvati(): Promise<Record<string, string>> {
|
async function leggiTurniSalvati(): Promise<Record<string, string>> {
|
||||||
const res = await rest(
|
const res = await rest(
|
||||||
`turni_palloni?evento_id=like.${PREFISSO}*&select=evento_id,giocatore_id`,
|
`turni_palloni?evento_id=like.${PREFISSO}*&select=evento_id,giocatore_id`,
|
||||||
@@ -103,12 +101,11 @@ if (!locale) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await prova(
|
await prova(
|
||||||
"il badge palloni passa da bronzo ad argento con turni reali, incluse le proposte non confermate",
|
"il badge palloni passa da bronzo ad argento con turni reali, ignorando gli eventi mai confermati",
|
||||||
async () => {
|
async () => {
|
||||||
// m1-m3: turno confermato esplicitamente a pv1 (3 turni -> soglia bronzo).
|
// m1-m3: turno confermato esplicitamente a pv1 (3 turni -> soglia bronzo).
|
||||||
// m4: NESSUN turno salvato -> completaTurni() deve proporlo in automatico a chi ha
|
// m4: NESSUN turno confermato -> non deve contare per nessuno, anche se un algoritmo
|
||||||
// fatto meno turni (pv2, a zero) -> conta comunque per il badge di pv2, pur non
|
// di rotazione (usato altrove per la UI) proporrebbe qualcuno in automatico.
|
||||||
// essendo mai stato confermato da nessuno (comportamento documentato in palloni.md).
|
|
||||||
// m5-m7: confermati di nuovo a pv1 (6 turni totali -> soglia argento).
|
// m5-m7: confermati di nuovo a pv1 (6 turni totali -> soglia argento).
|
||||||
const eventi = [
|
const eventi = [
|
||||||
[`${PREFISSO}-m1`, "2020-01-01", "pv1"],
|
[`${PREFISSO}-m1`, "2020-01-01", "pv1"],
|
||||||
@@ -129,36 +126,28 @@ if (!locale) {
|
|||||||
const salvati = await leggiTurniSalvati();
|
const salvati = await leggiTurniSalvati();
|
||||||
assert.equal(Object.keys(salvati).length, 6, "6 turni confermati esplicitamente, m4 no");
|
assert.equal(Object.keys(salvati).length, 6, "6 turni confermati esplicitamente, m4 no");
|
||||||
|
|
||||||
const turniCompleti = completaTurni(salvati, eventiLetti, ROSA);
|
const conteggio = conteggioTurni(salvati, eventiLetti, OGGI);
|
||||||
assert.equal(
|
|
||||||
turniCompleti[`${PREFISSO}-m4`],
|
|
||||||
"pv2",
|
|
||||||
"m4 senza turno salvato: la proposta automatica sceglie pv2 (meno turni)",
|
|
||||||
);
|
|
||||||
|
|
||||||
const conteggio = conteggioTurni(turniCompleti, eventiLetti, OGGI);
|
|
||||||
assert.equal(conteggio["pv1"], 6, "6 turni confermati per pv1");
|
assert.equal(conteggio["pv1"], 6, "6 turni confermati per pv1");
|
||||||
assert.equal(
|
assert.equal(
|
||||||
conteggio["pv2"],
|
conteggio["pv2"] ?? 0,
|
||||||
1,
|
0,
|
||||||
"pv2 non ha mai confermato nulla, ma la proposta per m4 conta comunque",
|
"pv2 non ha mai confermato nulla: m4 senza conferma non conta per nessuno",
|
||||||
);
|
);
|
||||||
|
|
||||||
const badgePv1 = statoBadge(palloniDef, giocatoreAzzerato(conteggio["pv1"]!));
|
const badgePv1 = statoBadge(palloniDef, giocatoreAzzerato(conteggio["pv1"]!));
|
||||||
assert.equal(badgePv1.grado, "argento", "6 turni: soglia argento raggiunta");
|
assert.equal(badgePv1.grado, "argento", "6 turni: soglia argento raggiunta");
|
||||||
|
|
||||||
const badgePv2 = statoBadge(palloniDef, giocatoreAzzerato(conteggio["pv2"]!));
|
const badgePv2 = statoBadge(palloniDef, giocatoreAzzerato(conteggio["pv2"] ?? 0));
|
||||||
assert.equal(badgePv2.grado, null, "1 turno (solo proposto): sotto la soglia bronzo (3)");
|
assert.equal(badgePv2.grado, null, "zero turni confermati: nessun badge");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
await prova("un evento futuro non riceve conteggio, anche se già assegnato", async () => {
|
await prova("un evento futuro non riceve conteggio, anche se già confermato", async () => {
|
||||||
// Stesso scenario di sopra ma con "oggi" prima di tutti gli eventi: nessuno dei turni,
|
// Stesso scenario di sopra ma con "oggi" prima di tutti gli eventi: nessun turno
|
||||||
// confermati o proposti, deve ancora contare per il badge.
|
// confermato deve ancora contare per il badge.
|
||||||
const eventiLetti = await leggiEventi();
|
const eventiLetti = await leggiEventi();
|
||||||
const salvati = await leggiTurniSalvati();
|
const salvati = await leggiTurniSalvati();
|
||||||
const turniCompleti = completaTurni(salvati, eventiLetti, ROSA);
|
const conteggio = conteggioTurni(salvati, eventiLetti, "2019-01-01");
|
||||||
const conteggio = conteggioTurni(turniCompleti, eventiLetti, "2019-01-01");
|
|
||||||
assert.deepEqual(conteggio, {}, "tutti gli eventi sono nel futuro rispetto a 'oggi'");
|
assert.deepEqual(conteggio, {}, "tutti gli eventi sono nel futuro rispetto a 'oggi'");
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user