Again almost there...

parent 1c873f0c
......@@ -2421,6 +2421,134 @@ class Migration_031_AddWinningOutcomesFields(DatabaseMigration):
"""Remove winning_outcomes and under_over_result columns - SQLite doesn't support DROP COLUMN easily"""
logger.warning("SQLite doesn't support DROP COLUMN - winning_outcomes and under_over_result columns will remain")
return True
class Migration_032_FixExtractionAssociationDefaults(DatabaseMigration):
"""Fix incorrect defaults in extraction_associations table for KO1 and KO2"""
def __init__(self):
super().__init__("032", "Fix incorrect defaults in extraction_associations table for KO1 and KO2")
def up(self, db_manager) -> bool:
"""Update extraction associations to correct KO1 and KO2 defaults"""
try:
with db_manager.engine.connect() as conn:
# Remove incorrect associations
# Remove WIN1 and X1 from KO1
conn.execute(text("""
DELETE FROM extraction_associations
WHERE outcome_name = 'WIN1' AND extraction_result = 'KO1' AND is_default = 1
"""))
conn.execute(text("""
DELETE FROM extraction_associations
WHERE outcome_name = 'X1' AND extraction_result = 'KO1' AND is_default = 1
"""))
# Remove WIN2 and X2 from KO2
conn.execute(text("""
DELETE FROM extraction_associations
WHERE outcome_name = 'WIN2' AND extraction_result = 'KO2' AND is_default = 1
"""))
conn.execute(text("""
DELETE FROM extraction_associations
WHERE outcome_name = 'X2' AND extraction_result = 'KO2' AND is_default = 1
"""))
# Add correct associations
# Add WIN2 and X2 to KO1
conn.execute(text("""
INSERT OR IGNORE INTO extraction_associations
(outcome_name, extraction_result, is_default, created_at, updated_at)
VALUES ('WIN2', 'KO1', 1, datetime('now'), datetime('now'))
"""))
conn.execute(text("""
INSERT OR IGNORE INTO extraction_associations
(outcome_name, extraction_result, is_default, created_at, updated_at)
VALUES ('X2', 'KO1', 1, datetime('now'), datetime('now'))
"""))
# Add WIN1 and X1 to KO2
conn.execute(text("""
INSERT OR IGNORE INTO extraction_associations
(outcome_name, extraction_result, is_default, created_at, updated_at)
VALUES ('WIN1', 'KO2', 1, datetime('now'), datetime('now'))
"""))
conn.execute(text("""
INSERT OR IGNORE INTO extraction_associations
(outcome_name, extraction_result, is_default, created_at, updated_at)
VALUES ('X1', 'KO2', 1, datetime('now'), datetime('now'))
"""))
conn.commit()
logger.info("Fixed extraction association defaults for KO1 and KO2")
return True
except Exception as e:
logger.error(f"Failed to fix extraction association defaults: {e}")
return False
def down(self, db_manager) -> bool:
"""Revert the extraction association changes"""
try:
with db_manager.engine.connect() as conn:
# Remove the corrected associations
conn.execute(text("""
DELETE FROM extraction_associations
WHERE outcome_name = 'WIN2' AND extraction_result = 'KO1' AND is_default = 1
"""))
conn.execute(text("""
DELETE FROM extraction_associations
WHERE outcome_name = 'X2' AND extraction_result = 'KO1' AND is_default = 1
"""))
conn.execute(text("""
DELETE FROM extraction_associations
WHERE outcome_name = 'WIN1' AND extraction_result = 'KO2' AND is_default = 1
"""))
conn.execute(text("""
DELETE FROM extraction_associations
WHERE outcome_name = 'X1' AND extraction_result = 'KO2' AND is_default = 1
"""))
# Restore original incorrect associations
conn.execute(text("""
INSERT OR IGNORE INTO extraction_associations
(outcome_name, extraction_result, is_default, created_at, updated_at)
VALUES ('WIN1', 'KO1', 1, datetime('now'), datetime('now'))
"""))
conn.execute(text("""
INSERT OR IGNORE INTO extraction_associations
(outcome_name, extraction_result, is_default, created_at, updated_at)
VALUES ('X1', 'KO1', 1, datetime('now'), datetime('now'))
"""))
conn.execute(text("""
INSERT OR IGNORE INTO extraction_associations
(outcome_name, extraction_result, is_default, created_at, updated_at)
VALUES ('WIN2', 'KO2', 1, datetime('now'), datetime('now'))
"""))
conn.execute(text("""
INSERT OR IGNORE INTO extraction_associations
(outcome_name, extraction_result, is_default, created_at, updated_at)
VALUES ('X2', 'KO2', 1, datetime('now'), datetime('now'))
"""))
conn.commit()
logger.info("Reverted extraction association defaults for KO1 and KO2")
return True
except Exception as e:
logger.error(f"Failed to revert extraction association defaults: {e}")
return False
# Registry of all migrations in order
# Registry of all migrations in order
MIGRATIONS: List[DatabaseMigration] = [
......@@ -2455,6 +2583,7 @@ MIGRATIONS: List[DatabaseMigration] = [
Migration_029_ChangeMatchNumberToUniqueWithinFixture(),
Migration_030_AddZipValidationStatus(),
Migration_031_AddWinningOutcomesFields(),
Migration_032_FixExtractionAssociationDefaults(),
]
......
......@@ -4,6 +4,7 @@ Flask routes for web dashboard
import logging
import time
import json
from datetime import datetime, date
from flask import Blueprint, render_template, request, jsonify, redirect, url_for, flash, session, g
from flask_login import login_required, current_user, login_user, logout_user
......@@ -153,7 +154,18 @@ def bet_details(bet_id):
for detail in bet_details:
# Get match information
match = session.query(MatchModel).filter_by(id=detail.match_id).first()
# Parse winning_outcomes JSON string if it exists
winning_outcomes = []
if match and match.winning_outcomes:
try:
if isinstance(match.winning_outcomes, str):
winning_outcomes = json.loads(match.winning_outcomes)
elif isinstance(match.winning_outcomes, list):
winning_outcomes = match.winning_outcomes
except (json.JSONDecodeError, TypeError):
winning_outcomes = []
detail_dict = {
'id': detail.id,
'match_id': detail.match_id,
......@@ -165,7 +177,8 @@ def bet_details(bet_id):
'fighter1_township': match.fighter1_township if match else 'Unknown',
'fighter2_township': match.fighter2_township if match else 'Unknown',
'venue_kampala_township': match.venue_kampala_township if match else 'Unknown',
'status': match.status if match else 'Unknown'
'status': match.status if match else 'Unknown',
'winning_outcomes': winning_outcomes
} if match else None
}
......@@ -591,6 +604,17 @@ def cashier_bet_details(bet_id):
# Get match information
match = session.query(MatchModel).filter_by(id=detail.match_id).first()
# Parse winning_outcomes JSON string if it exists
winning_outcomes = []
if match and match.winning_outcomes:
try:
if isinstance(match.winning_outcomes, str):
winning_outcomes = json.loads(match.winning_outcomes)
elif isinstance(match.winning_outcomes, list):
winning_outcomes = match.winning_outcomes
except (json.JSONDecodeError, TypeError):
winning_outcomes = []
detail_dict = {
'id': detail.id,
'match_id': detail.match_id,
......@@ -602,7 +626,8 @@ def cashier_bet_details(bet_id):
'fighter1_township': match.fighter1_township if match else 'Unknown',
'fighter2_township': match.fighter2_township if match else 'Unknown',
'venue_kampala_township': match.venue_kampala_township if match else 'Unknown',
'status': match.status if match else 'Unknown'
'status': match.status if match else 'Unknown',
'winning_outcomes': winning_outcomes
} if match else None
}
......
......@@ -308,16 +308,30 @@ function showError(message) {
function formatWinningOutcomes(winningOutcomes) {
// Safely format winning outcomes, handling cases where it's not an array
let outcomesArray = [];
if (Array.isArray(winningOutcomes) && winningOutcomes.length > 0) {
return winningOutcomes.join(', ');
outcomesArray = winningOutcomes;
} else if (winningOutcomes && typeof winningOutcomes === 'string') {
return winningOutcomes;
// Try to parse JSON string
try {
const parsed = JSON.parse(winningOutcomes);
if (Array.isArray(parsed) && parsed.length > 0) {
outcomesArray = parsed;
} else {
return winningOutcomes; // Return original string if not a valid array
}
} catch (e) {
return winningOutcomes; // Return original string if parsing fails
}
} else if (winningOutcomes && typeof winningOutcomes === 'object') {
// If it's an object, try to stringify it
return JSON.stringify(winningOutcomes);
} else {
return 'Not available';
}
return outcomesArray.join(', ');
}
function renderFixtureDetails(fixture, matches) {
......
......@@ -293,16 +293,30 @@ function showError(message) {
function formatWinningOutcomes(winningOutcomes) {
// Safely format winning outcomes, handling cases where it's not an array
let outcomesArray = [];
if (Array.isArray(winningOutcomes) && winningOutcomes.length > 0) {
return winningOutcomes.join(', ');
outcomesArray = winningOutcomes;
} else if (winningOutcomes && typeof winningOutcomes === 'string') {
return winningOutcomes;
// Try to parse JSON string
try {
const parsed = JSON.parse(winningOutcomes);
if (Array.isArray(parsed) && parsed.length > 0) {
outcomesArray = parsed;
} else {
return winningOutcomes; // Return original string if not a valid array
}
} catch (e) {
return winningOutcomes; // Return original string if parsing fails
}
} else if (winningOutcomes && typeof winningOutcomes === 'object') {
// If it's an object, try to stringify it
return JSON.stringify(winningOutcomes);
} else {
return '';
}
return outcomesArray.join(', ');
}
function updateMatchDetails(match) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment