Fix: puntos duplicados en ranking J8 y acumulado de Libertadores - #3
Merged
Merged
Conversation
Dos bugs de integridad de datos causaban que un usuario apareciera con más puntos de los que realmente ganó en Jornada 8 (octavos VUELTA): 1. calcularPuntosLibertadores.js: al recalcular puntos SIN filtrar por jornada (botón 'Calcular Puntos' sobre 'todas las jornadas'), el borrado previo de libertadores_puntos_clasificacion solo corría si se pasaba un jornadaNumero específico (8/9/10). Como el INSERT no usaba ON CONFLICT, cada recálculo global sin filtro iba acumulando filas duplicadas del bonus por 'equipo que avanza', inflando el ranking acumulado. Ahora el borrado también corre para 8/9/10 al recalcular todas las jornadas, y el INSERT tiene ON CONFLICT ... DO UPDATE como defensa adicional. 2. rankingsLibertadores.js / ganadoresJornadaLibertadores.js: las sumas de puntos de partidos (SUM(lp.puntos)) no verificaban que el partido referenciado siguiera existiendo. Un pronóstico 'huérfano' que quedó apuntando a un partido_id borrado (p.ej. al regenerar el fixture de octavos) seguía sumando puntos en el ranking aunque ya no apareciera en ningún lado visible para el usuario. Se agregó INNER JOIN a libertadores_partidos en todas esas subconsultas para descartar pronósticos huérfanos, igual que ya hacía el endpoint de pronósticos por partido. Tras este fix, recomendado volver a presionar 'Calcular Puntos' para la Jornada 8 (y revisar 9/10 si ya se tocaron) para forzar un recálculo limpio con las nuevas reglas.
✅ Deploy Preview for pollafutbol canceled.
|
1 similar comment
✅ Deploy Preview for pollafutbol canceled.
|
There was a problem hiding this comment.
Pull request overview
Corrige puntos duplicados en el ranking de Libertadores y excluye pronósticos asociados a partidos eliminados.
Changes:
- Limpia bonuses de clasificación al recalcular jornadas y añade
ON CONFLICT. - Filtra pronósticos huérfanos en rankings, ganadores y PDFs.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Final review status |
|---|---|
server/routes/rankingsLibertadores.js |
Requiere filtrar también ultimaJornada en /actual; el pronóstico huérfano aún puede alterar la jornada mostrada. Moderate, 4 votes. |
server/routes/ganadoresJornadaLibertadores.js |
Falta aplicar el JOIN en POST /acumulado, por lo que los pronósticos huérfanos aún pueden afectar al ganador. Critical, 3 votes. |
server/routes/calcularPuntosLibertadores.js |
ON CONFLICT requiere una restricción única existente; debe añadirse una migración que limpie duplicados y cree/verifique dicha restricción. Critical, 4 votes. |
Suppressed comments (2)
server/routes/calcularPuntosLibertadores.js:75
- Cuando se recalculan todas las jornadas, estos
DELETEeliminan J8, J9 y J10 antes de iniciar el bucle de recalculo, pero la ruta no usa una transacción. Un error, timeout o reinicio durante las muchas consultas posteriores puede dejar las tres jornadas sin ningún bonus de clasificación y los rankings perderán puntos hasta una ejecución manual exitosa. Ejecuten el borrado y la reconstrucción en una transacción (o reconstruyan en una tabla temporal y hagan un reemplazo atómico).
for (const jn of jornadasClasifACalcular) {
if (jn >= 8 && jn <= 10) {
await pool.query(
`DELETE FROM libertadores_puntos_clasificacion
WHERE jornada_numero = $1`,
[jn]
);
server/routes/calcularPuntosLibertadores.js:64
- Este comentario quedó desactualizado respecto al SQL: el
INSERTsí usaON CONFLICTen las líneas 388-392. Conviene explicar que elDELETEprevio sigue siendo necesario para limpiar filas obsoletas antes de reconstruir los bonus, en lugar de documentar una condición que ya no existe.
// (jornadaNumero no viene en el body), porque el INSERT de más abajo no usa
// ON CONFLICT: si no se borra primero, cada vez que un admin presiona "Calcular
// Puntos" sin filtrar jornada se van acumulando filas duplicadas de bonus de
// clasificación (equipo que avanza) para el mismo usuario/partido, inflando el
// ranking acumulado.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+388
to
+392
| ON CONFLICT (usuario_id, partido_id, jornada_numero) | ||
| DO UPDATE SET | ||
| equipo_clasificado = EXCLUDED.equipo_clasificado, | ||
| fase_clasificado = EXCLUDED.fase_clasificado, | ||
| puntos = EXCLUDED.puntos |
| SELECT COALESCE(SUM(lp.puntos), 0) as puntos_partidos | ||
| FROM libertadores_pronosticos lp | ||
| INNER JOIN libertadores_jornadas lj ON lp.jornada_id = lj.id | ||
| INNER JOIN libertadores_partidos p ON p.id = lp.partido_id |
Comment on lines
+212
to
+213
| -- INNER JOIN a partidos: descarta pronósticos huérfanos de partidos borrados | ||
| INNER JOIN libertadores_partidos p ON p.id = lp.partido_id |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problema
Daniel Guzmán Sagredo (y potencialmente otros usuarios) aparecía en el Ranking Jornada 8 con más puntos de los que realmente ganó (2 en vez de 1, según su propio desglose de partidos), y en el Ranking Acumulado saltó de 170 a 178 pts entre J7 y J8 (+8), cuando la suma real de partidos (1) + bonus de clasificación (2) debía dar +3.
Causas encontradas (por lectura de código; no tuve acceso a la base de datos productiva desde este entorno para confirmar con datos en vivo — el puerto 5432 está bloqueado)
calcularPuntosLibertadores.js: el borrado delibertadores_puntos_clasificacionantes de recalcular el bonus de "equipo que avanza" solo se ejecutaba cuando se recalculaba una jornada específica (8/9/10). Si un admin recalculaba todas las jornadas (sin filtrar), ese borrado se saltaba por completo, y como elINSERTno teníaON CONFLICT, cada recálculo global repetido iba acumulando filas duplicadas del bonus de clasificación para el mismo usuario/partido — inflando el acumulado. Matemáticamente esto explica el excedente observado (8 en vez de 3): con el bonus de Flamengo (2 pts) duplicado ~3 veces, el acumulado sube ~6 en vez de 2.rankingsLibertadores.js/ganadoresJornadaLibertadores.js: las sumas de puntos de partidos (SUM(lp.puntos)) no verificaban que elpartido_idreferenciado siguiera existiendo. Un pronóstico "huérfano" que quedó apuntando a un partido borrado (p. ej. al regenerar el fixture de octavos) seguía sumando puntos en el ranking aunque ya no apareciera en ningún lado visible para el usuario (el endpoint que arma la tabla de "Partidos" sí hace eseINNER JOINy por eso no lo mostraba). Esto explica el 2 en vez de 1 en el Ranking de Jornada 8.Cambios
calcularPuntosLibertadores.js: el borrado de clasificación para J8/J9/J10 ahora también corre al recalcular todas las jornadas; se agregóON CONFLICT (usuario_id, partido_id, jornada_numero) DO UPDATEcomo defensa adicional.rankingsLibertadores.js(/jornada/:numero,/acumulado/:numero,/actual) yganadoresJornadaLibertadores.js(cálculo de ganador de jornada y las consultas duplicadas del PDF): se agregóINNER JOIN libertadores_partidosen las subconsultas de puntos de partidos para descartar pronósticos huérfanos.Después de este deploy
Recomiendo volver a presionar "Calcular Puntos" para la Jornada 8 (y revisar 9/10 si ya se tocaron) para forzar un recálculo limpio con las reglas corregidas, y así limpiar cualquier fila duplicada que ya exista en
libertadores_puntos_clasificacion.🤖 Generated with Claude Code
Generated by Claude Code