Balabce globalized

parent a1afa146
This diff is collapsed.
This diff is collapsed.
......@@ -745,23 +745,25 @@ class MatchTimerComponent(ThreadedComponent):
return 'all_bets_on_start'
def _select_random_match_templates(self, count: int, session) -> List[Any]:
"""Select random match templates from the database"""
"""Select random match templates from the database that have validated ZIP files"""
try:
from ..database.models import MatchTemplateModel
from sqlalchemy.orm import joinedload
# Get all active match templates
# Get all active match templates with validated ZIP files
match_templates = session.query(MatchTemplateModel).options(joinedload(MatchTemplateModel.outcomes)).filter(
MatchTemplateModel.active_status == True
MatchTemplateModel.active_status == True,
MatchTemplateModel.zip_upload_status == 'completed',
MatchTemplateModel.zip_validation_status == 'valid'
).all()
if len(match_templates) < count:
logger.warning(f"Only {len(match_templates)} match templates found, requested {count}")
logger.warning(f"Only {len(match_templates)} validated match templates found, requested {count}")
return match_templates
# Select random templates
selected_templates = random.sample(match_templates, count)
logger.info(f"Selected {len(selected_templates)} random match templates")
logger.info(f"Selected {len(selected_templates)} random validated match templates")
return selected_templates
except Exception as e:
......
......@@ -2890,6 +2890,55 @@ class Migration_038_AddWin1Win2Associations(DatabaseMigration):
return False
class Migration_039_AddMatchNumberToBetDetails(DatabaseMigration):
"""Add match_number column to bets_details table for storing match numbers directly"""
def __init__(self):
super().__init__("039", "Add match_number column to bets_details table")
def up(self, db_manager) -> bool:
"""Add match_number column to bets_details table"""
try:
with db_manager.engine.connect() as conn:
# Check if match_number column already exists
result = conn.execute(text("PRAGMA table_info(bets_details)"))
columns = [row[1] for row in result.fetchall()]
if 'match_number' not in columns:
# Add match_number column
conn.execute(text("""
ALTER TABLE bets_details
ADD COLUMN match_number INTEGER
"""))
# Populate existing records with match numbers from matches table
conn.execute(text("""
UPDATE bets_details
SET match_number = (
SELECT m.match_number
FROM matches m
WHERE m.id = bets_details.match_id
)
WHERE match_number IS NULL
"""))
conn.commit()
logger.info("match_number column added to bets_details table")
else:
logger.info("match_number column already exists in bets_details table")
return True
except Exception as e:
logger.error(f"Failed to add match_number column to bets_details: {e}")
return False
def down(self, db_manager) -> bool:
"""Remove match_number column - SQLite doesn't support DROP COLUMN easily"""
logger.warning("SQLite doesn't support DROP COLUMN - match_number column will remain")
return True
class Migration_036_AddMatchTemplatesTables(DatabaseMigration):
"""Add matches_templates and match_outcomes_templates tables for storing match templates"""
......@@ -3047,6 +3096,7 @@ MIGRATIONS: List[DatabaseMigration] = [
Migration_036_AddMatchTemplatesTables(),
Migration_037_RenameDailyRedistributionShortfallTable(),
Migration_038_AddWin1Win2Associations(),
Migration_039_AddMatchNumberToBetDetails(),
]
......
......@@ -772,6 +772,7 @@ class BetDetailModel(BaseModel):
bet_id = Column(String(1024), ForeignKey('bets.uuid'), nullable=False, comment='Foreign key to bets table uuid field')
match_id = Column(Integer, ForeignKey('matches.id'), nullable=False, comment='Foreign key to matches table')
match_number = Column(Integer, comment='Match number for display purposes')
outcome = Column(String(255), nullable=False, comment='Bet outcome/prediction')
amount = Column(Float(precision=2), nullable=False, comment='Bet amount with 2 decimal precision')
win_amount = Column(Float(precision=2), default=0.0, nullable=False, comment='Winning amount (calculated when result is win)')
......
This diff is collapsed.
......@@ -89,9 +89,9 @@
{% for detail in bet.bet_details %}
<tr>
<td>
<strong>Match #{{ detail.match.match_number }}</strong><br>
<strong>Match #{{ detail.match_number }}</strong><br>
<small class="text-muted">
{{ detail.match.fighter1_township }} vs {{ detail.match.fighter2_township }}
{{ detail.match.fighter1_township if detail.match else 'Unknown' }} vs {{ detail.match.fighter2_township if detail.match else 'Unknown' }}
</small>
</td>
<td>
......@@ -450,7 +450,7 @@
"bet_details": [
{% for detail in bet.bet_details %}
{
"match_number": "{{ detail.match.match_number if detail.match else 'Unknown' }}",
"match_number": "{{ detail.match_number }}",
"fighter1": "{{ detail.match.fighter1_township if detail.match else 'Unknown' }}",
"fighter2": "{{ detail.match.fighter2_township if detail.match else 'Unknown' }}",
"venue": "{{ detail.match.venue_kampala_township if detail.match else 'Unknown' }}",
......
......@@ -533,7 +533,7 @@ function updateBetsTable(data, container) {
const totalAmount = parseFloat(bet.total_amount).toFixed(2);
// Collect unique match numbers
const matchNumbers = [...new Set(bet.details ? bet.details.map(detail => detail.match ? detail.match.match_number : 'Unknown').filter(n => n !== 'Unknown') : [])];
const matchNumbers = [...new Set(bet.details ? bet.details.map(detail => detail.match_number || 'Unknown').filter(n => n !== 'Unknown') : [])];
// Determine overall bet status based on details
let overallStatus = 'pending';
......@@ -719,7 +719,7 @@ function transformBetDataForReceipt(betData) {
total_amount: betData.total_amount,
bet_count: betData.details_count || betData.details.length,
bet_details: betData.details.map(detail => ({
match_number: detail.match ? detail.match.match_number : 'Unknown',
match_number: detail.match_number || 'Unknown',
fighter1: detail.match ? detail.match.fighter1_township : 'Unknown',
fighter2: detail.match ? detail.match.fighter2_township : 'Unknown',
venue: detail.match ? detail.match.venue_kampala_township : 'Unknown',
......
......@@ -477,6 +477,7 @@ function getUploadStatusBadge(fixture) {
function resetFixtures() {
const confirmMessage = 'WARNING: This will permanently delete ALL fixture data including:\n\n' +
'• All synchronized matches and outcomes\n' +
'• All match templates and template outcomes\n' +
'• All downloaded ZIP files\n' +
'• This action cannot be undone!\n\n' +
'Are you sure you want to reset all fixtures data?';
......@@ -500,7 +501,7 @@ function resetFixtures() {
.then(response => response.json())
.then(data => {
if (data.success) {
alert(`Fixtures reset successfully!\n\nRemoved:\n• ${data.removed.matches} matches\n• ${data.removed.outcomes} outcomes\n• ${data.removed.zip_files} ZIP files`);
alert(`Fixtures reset successfully!\n\nRemoved:\n• ${data.removed.matches} matches\n• ${data.removed.outcomes} outcomes\n• ${data.removed.templates} match templates\n• ${data.removed.template_outcomes} template outcomes\n• ${data.removed.zip_files} ZIP files`);
// Reload fixtures to show empty state
loadFixtures();
} else {
......
......@@ -499,6 +499,8 @@ document.addEventListener('DOMContentLoaded', function() {
// Load redistribution balance (admin only)
if (document.getElementById('redistribution-balance')) {
loadRedistributionBalance();
// Periodic update of redistribution balance
setInterval(loadRedistributionBalance, 5000); // Update every 5 seconds
}
// Quick action buttons
......
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