Handle pending matches in today's fixture during initialization

- Add _process_today_pending_matches() to process pending matches in today's fixture
- Add _resolve_match_bets() to resolve bets for matches being finalized
- Add _get_outcome_coefficient_for_bet() to get coefficients for bet resolution
- For pending matches with no results: change status to 'bet' to play first
- For pending matches with results: finalize as 'done' and resolve associated bets
- Add Step 5 in initialize() to process today's pending matches
parent c56054b0
......@@ -462,6 +462,186 @@ class GamesThread(ThreadedComponent):
logger.error(f"Failed to get yesterday's incomplete matches: {e}")
return []
def _process_today_pending_matches(self) -> List[MatchModel]:
"""Process pending matches in today's fixture.
For each pending match:
- If no result is set: Change status to 'bet' so it can be played first
- If result is already set: Finalize as 'done' and resolve associated bets
Returns list of matches that should be played (status changed to 'bet').
"""
try:
session = self.db_manager.get_session()
try:
# Get today's date in venue timezone
today = self._get_today_venue_date()
# Convert venue date range to UTC for database query
from ..utils.timezone_utils import venue_to_utc_datetime
venue_start = datetime.combine(today, datetime.min.time())
venue_end = datetime.combine(today, datetime.max.time())
utc_start = venue_to_utc_datetime(venue_start, self.db_manager)
utc_end = venue_to_utc_datetime(venue_end, self.db_manager)
# Find pending matches in today's fixture
# Strategy 1: Matches with start_time in today's range
today_pending_with_start_time = session.query(MatchModel).filter(
MatchModel.start_time.isnot(None),
MatchModel.start_time >= utc_start,
MatchModel.start_time < utc_end,
MatchModel.status == 'pending',
MatchModel.active_status == True
).all()
# Strategy 2: Matches with NULL start_time but created_at in today's range
today_pending_without_start_time = session.query(MatchModel).filter(
MatchModel.start_time.is_(None),
MatchModel.created_at >= utc_start,
MatchModel.created_at < utc_end,
MatchModel.status == 'pending',
MatchModel.active_status == True
).all()
# Combine both sets
today_pending_matches = today_pending_with_start_time + today_pending_without_start_time
logger.info(f"🔍 Today pending check: utc_start = {utc_start}, utc_end = {utc_end}")
logger.info(f"🔍 Found {len(today_pending_with_start_time)} pending matches with start_time in today's range")
logger.info(f"🔍 Found {len(today_pending_without_start_time)} pending matches with NULL start_time but created_at in today's range")
matches_to_play = []
for match in today_pending_matches:
logger.info(f"🔍 Processing pending match {match.match_number} (fixture: {match.fixture_id})")
logger.info(f" - result: {match.result}, under_over_result: {match.under_over_result}")
# Check if match has results already set
has_result = match.result is not None or match.under_over_result is not None
if has_result:
# Match has results - finalize it as done
logger.info(f"✅ Match {match.match_number} has results - finalizing as 'done'")
match.status = 'done'
# Resolve associated bets
self._resolve_match_bets(match, session)
else:
# Match has no results - change status to 'bet' to play first
logger.info(f"🎯 Match {match.match_number} has no results - changing status to 'bet'")
match.status = 'bet'
matches_to_play.append(match)
if today_pending_matches:
session.commit()
logger.info(f"✅ Processed {len(today_pending_matches)} pending matches: {len(matches_to_play)} set to 'bet', {len(today_pending_matches) - len(matches_to_play)} finalized as 'done'")
return matches_to_play
finally:
session.close()
except Exception as e:
logger.error(f"Failed to process today's pending matches: {e}")
import traceback
logger.error(f"Traceback: {traceback.format_exc()}")
return []
def _resolve_match_bets(self, match: MatchModel, session):
"""Resolve bets for a match that is being finalized.
Args:
match: The match being finalized
session: Database session
"""
try:
# Get all pending bets for this match
pending_bets = session.query(BetDetailModel).filter(
BetDetailModel.match_id == match.id,
BetDetailModel.result == 'pending'
).all()
if not pending_bets:
logger.debug(f"No pending bets to resolve for match {match.id}")
return
logger.info(f"🔍 Resolving {len(pending_bets)} pending bets for match {match.id}")
# Determine winning outcomes
winning_outcomes = []
if match.winning_outcomes:
try:
winning_outcomes = json.loads(match.winning_outcomes)
except (json.JSONDecodeError, TypeError):
pass
# Add under_over_result if set
if match.under_over_result:
winning_outcomes.append(match.under_over_result)
# Add main result if set
if match.result:
winning_outcomes.append(match.result)
logger.info(f"🔍 Winning outcomes for match {match.id}: {winning_outcomes}")
resolved_win = 0
resolved_lost = 0
for bet in pending_bets:
if bet.outcome in winning_outcomes:
# Winner
try:
coefficient = self._get_outcome_coefficient_for_bet(match.id, bet.outcome, session)
bet.result = 'win'
bet.win_amount = bet.amount * coefficient
resolved_win += 1
logger.info(f"✅ Bet {bet.id} ({bet.outcome}) resolved as WIN with amount {bet.win_amount:.2f}")
except Exception as coeff_e:
logger.error(f"Failed to get coefficient for {bet.outcome}: {coeff_e}")
bet.result = 'win'
bet.win_amount = bet.amount # Fallback to 1x coefficient
resolved_win += 1
else:
# Loser
bet.result = 'lost'
resolved_lost += 1
logger.info(f"❌ Bet {bet.id} ({bet.outcome}) resolved as LOST")
logger.info(f"✅ Resolved {len(pending_bets)} bets for match {match.id}: {resolved_win} wins, {resolved_lost} losses")
except Exception as e:
logger.error(f"Failed to resolve bets for match {match.id}: {e}")
import traceback
logger.error(f"Traceback: {traceback.format_exc()}")
def _get_outcome_coefficient_for_bet(self, match_id: int, outcome: str, session) -> float:
"""Get coefficient for a specific outcome from match outcomes.
Args:
match_id: The match ID
outcome: The outcome name (e.g., 'UNDER', 'OVER', 'WIN1')
session: Database session
Returns:
Coefficient value, defaults to 1.0 if not found
"""
try:
match_outcome = session.query(MatchOutcomeModel).filter(
MatchOutcomeModel.match_id == match_id,
MatchOutcomeModel.column_name == outcome
).first()
if match_outcome:
return match_outcome.float_value
logger.warning(f"No coefficient found for outcome {outcome} in match {match_id}, using 1.0")
return 1.0
except Exception as e:
logger.error(f"Failed to get coefficient for outcome {outcome}: {e}")
return 1.0
def _get_or_create_today_fixture(self) -> Optional[str]:
"""Get existing today's fixture or create a new one.
......@@ -723,6 +903,15 @@ class GamesThread(ThreadedComponent):
else:
self.yesterday_fixture_id = None
# STEP 5: Process pending matches in today's fixture
logger.info("🧹 Step 5: Processing pending matches in today's fixture...")
matches_to_play = self._process_today_pending_matches()
if matches_to_play:
logger.info(f"🎯 Found {len(matches_to_play)} pending matches set to 'bet' status - will play these first")
# Store the fixture ID for these matches
if not self.pending_today_fixture_id:
self.pending_today_fixture_id = matches_to_play[0].fixture_id
# Register with message bus first
self.message_queue = self.message_bus.register_component(self.name)
......
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