fix tz stuff and ttc stuff

timetoconfirm
Raz 7 months ago
parent 255758f02d
commit 7264f139ee
  1. 2
      shop/models.py
  2. 167
      tournaments/models/tournament.py
  3. 16
      tournaments/signals.py
  4. 2
      tournaments/tasks.py

@ -1,5 +1,6 @@
from django.db import models
from django.conf import settings
from django.utils import timezone
class OrderStatus(models.TextChoices):
PENDING = 'PENDING', 'Pending'
@ -94,7 +95,6 @@ class Coupon(models.Model):
return self.code
def is_valid(self):
from django.utils import timezone
now = timezone.now()
if not self.is_active:
return False

@ -609,7 +609,7 @@ class Tournament(BaseModel):
# if now is before the first match, we want to show the summons + group stage or first matches
# change timezone to datetime to avoid the bug RuntimeWarning: DateTimeField Tournament.start_date received a naive datetime (2024-05-16 00:00:00) while time zone support is active.
current_time = timezone.now()
current_time = timezone.localtime()
tournament_start = self.local_start_date()
one_hour_before_start = tournament_start - timedelta(hours=1)
@ -852,17 +852,17 @@ class Tournament(BaseModel):
if self.end_date is not None:
return is_build_and_not_empty
if timezone.now() >= self.local_start_date():
if self.has_started():
return is_build_and_not_empty
minimum_publish_date = self.creation_date.replace(hour=9, minute=0) + timedelta(days=1)
return timezone.now() >= timezone.localtime(minimum_publish_date)
minimum_publish_date = self.creation_date.replace(hour=7, minute=0) + timedelta(days=1)
return timezone.now() >= minimum_publish_date
def display_teams(self):
if self.end_date is not None:
return self.has_team_registrations()
if self.publish_teams:
return self.has_team_registrations()
if timezone.now() >= self.local_start_date():
if self.has_started():
return self.has_team_registrations()
return False
@ -874,7 +874,7 @@ class Tournament(BaseModel):
return False
if self.publish_summons:
return self.has_summons()
if timezone.now() >= self.local_start_date():
if self.has_started():
return self.has_summons()
return False
@ -888,7 +888,7 @@ class Tournament(BaseModel):
first_group_stage_start_date = self.group_stage_start_date()
if first_group_stage_start_date is None:
return timezone.now() >= self.local_start_date()
return self.has_started()
else:
return timezone.now() >= first_group_stage_start_date
@ -896,9 +896,7 @@ class Tournament(BaseModel):
group_stages = [gs for gs in self.group_stages.all() if gs.start_date is not None]
if len(group_stages) == 0:
return None
timezone = self.timezone()
return min(group_stages, key=lambda gs: gs.start_date).start_date.astimezone(timezone)
return min(group_stages, key=lambda gs: gs.start_date).start_date
def display_matches(self):
if self.end_date is not None:
@ -911,19 +909,22 @@ class Tournament(BaseModel):
first_match_start_date = self.first_match_start_date(bracket_matches)
if first_match_start_date is None:
return timezone.now() >= self.local_start_date()
return self.has_started()
bracket_start_date = self.getEightAm(first_match_start_date)
if bracket_start_date < self.local_start_date():
bracket_start_date = self.local_start_date()
if bracket_start_date < self.start_date:
bracket_start_date = self.start_date
group_stage_start_date = self.group_stage_start_date()
now = timezone.now()
if group_stage_start_date is not None:
if bracket_start_date < group_stage_start_date:
return timezone.now() >=first_match_start_date
return now >=first_match_start_date
if timezone.now() >= bracket_start_date:
if now >= bracket_start_date:
return True
return False
@ -939,45 +940,59 @@ class Tournament(BaseModel):
matches = [m for m in bracket_matches if m.start_date is not None]
if len(matches) == 0:
return None
return min(matches, key=lambda m: m.start_date).local_start_date()
return min(matches, key=lambda m: m.start_date)
def getEightAm(self, date):
return date.replace(hour=8, minute=0, second=0, microsecond=0, tzinfo=date.tzinfo)
def has_started(self, hour_delta=None):
timezoned_datetime = self.local_start_date()
now_utc = timezone.now()
now = now_utc.astimezone(self.timezone())
if hour_delta is not None:
timezoned_datetime -= timedelta(hours=hour_delta)
return now >= timezoned_datetime
def will_start_soon(self):
return self.has_started(hour_delta=2)
def supposedly_in_progress(self):
# end = self.start_date + timedelta(days=self.day_duration + 1)
# return self.start_date.replace(hour=0, minute=0) <= timezone.now() <= end
timezoned_datetime = self.local_start_date()
end = timezoned_datetime + timedelta(days=self.day_duration + 1)
now = timezone.now()
now_utc = timezone.now()
now = now_utc.astimezone(self.timezone())
start = timezoned_datetime.replace(hour=0, minute=0)
print(f"timezoned_datetime: {timezoned_datetime}")
print(f"tournament end date: {end}")
print(f"current time: {now}")
print(f"tournament start: {start}")
print(f"start <= now <= end: {start <= now <= end}")
# print(f"timezoned_datetime: {timezoned_datetime}")
# print(f"tournament end date: {end}")
# print(f"current time: {now}")
# print(f"tournament start: {start}")
# print(f"start <= now <= end: {start <= now <= end}")
return start <= now <= end
def starts_in_the_future(self):
# tomorrow = datetime.now().date() + timedelta(days=1)
timezoned_datetime = self.local_start_date()
start = timezoned_datetime.replace(hour=0, minute=0)
now = timezone.now()
now_utc = timezone.now()
now = now_utc.astimezone(self.timezone())
return start >= now
def has_ended(self):
return self.end_date is not None
def should_be_over(self):
if self.end_date is not None:
if self.has_ended():
return True
timezoned_datetime = self.local_start_date()
end = timezoned_datetime + timedelta(days=self.day_duration + 1)
now = timezone.now()
now_utc = timezone.now()
now = now_utc.astimezone(self.timezone())
return now >= end and self.is_build_and_not_empty() and self.nearly_over()
def nearly_over(self):
@ -1096,6 +1111,33 @@ class Tournament(BaseModel):
else:
return "La sélection se fait par date d'inscription"
def automatic_waiting_list(self):
"""
Determines if automatic waiting list processing should be applied based on the tournament's registration status.
Returns True if automatic waiting list processing should be applied, False otherwise.
"""
if self.enable_time_to_confirm is False:
return False
# Get the current registration status
status = self.get_online_registration_status()
# Define which status values should allow automatic waiting list
status_map = {
OnlineRegistrationStatus.OPEN: True,
OnlineRegistrationStatus.NOT_ENABLED: False,
OnlineRegistrationStatus.NOT_STARTED: False,
OnlineRegistrationStatus.ENDED: False,
OnlineRegistrationStatus.WAITING_LIST_POSSIBLE: False,
OnlineRegistrationStatus.WAITING_LIST_FULL: True, # Still manage in case spots open up
OnlineRegistrationStatus.IN_PROGRESS: False, # Allow for last-minute changes
OnlineRegistrationStatus.ENDED_WITH_RESULTS: False,
OnlineRegistrationStatus.CANCELED: False
}
# Return the mapped value or False as default for any unmapped status
return status_map.get(status, False)
def get_online_registration_status(self):
if self.is_canceled():
return OnlineRegistrationStatus.CANCELED
@ -1103,7 +1145,7 @@ class Tournament(BaseModel):
return OnlineRegistrationStatus.ENDED_WITH_RESULTS
if self.enable_online_registration is False:
return OnlineRegistrationStatus.NOT_ENABLED
if self.supposedly_in_progress():
if self.has_started():
return OnlineRegistrationStatus.ENDED
if self.closed_registration_date is not None:
return OnlineRegistrationStatus.WAITING_LIST_POSSIBLE
@ -1111,13 +1153,11 @@ class Tournament(BaseModel):
now = timezone.now()
if self.opening_registration_date is not None:
timezoned_datetime = timezone.localtime(self.opening_registration_date)
if now < timezoned_datetime:
if now < self.opening_registration_date:
return OnlineRegistrationStatus.NOT_STARTED
if self.registration_date_limit is not None:
timezoned_datetime = timezone.localtime(self.registration_date_limit)
if now > timezoned_datetime:
if now > self.registration_date_limit:
return OnlineRegistrationStatus.WAITING_LIST_POSSIBLE
if self.team_sorting == TeamSortingType.RANK:
@ -1163,14 +1203,15 @@ class Tournament(BaseModel):
# Check if registration is closed
if self.registration_date_limit is not None:
if timezone.now() > timezone.localtime(self.registration_date_limit):
if timezone.now() > self.registration_date_limit:
return False
# Otherwise unregistration is allowed
return True
def get_waiting_list_position(self):
current_time = timezone.now()
now_utc = timezone.now()
current_time = now_utc.astimezone(self.timezone())
local_registration_federal_limit = self.local_registration_federal_limit()
if self.team_sorting == TeamSortingType.RANK and local_registration_federal_limit is not None:
if current_time < local_registration_federal_limit:
@ -1315,7 +1356,8 @@ class Tournament(BaseModel):
return None
def waiting_list_teams(self, teams):
current_time = timezone.now()
now_utc = timezone.now()
current_time = now_utc.astimezone(self.timezone())
local_registration_federal_limit = self.local_registration_federal_limit()
if self.team_sorting == TeamSortingType.RANK and local_registration_federal_limit is not None:
if current_time < local_registration_federal_limit:
@ -1349,6 +1391,7 @@ class Tournament(BaseModel):
and m.court_index is not None
]
now = timezone.now()
# Group matches by court
matches_by_court = {}
courts = set()
@ -1362,7 +1405,7 @@ class Tournament(BaseModel):
for court in matches_by_court:
matches_by_court[court].sort(key=lambda m: (
m.start_date is None, # None dates come last
m.start_date if m.start_date else timezone.now()
m.start_date if m.start_date else now
))
# Sort courts and organize them into groups of 4
@ -1535,14 +1578,29 @@ class Tournament(BaseModel):
# 7. Check urgency overrides
apply_business_rules = True
for hours_threshold, override in URGENCY_OVERRIDE["thresholds"].items():
if hours_until_tournament <= hours_threshold:
apply_business_rules = False
# Ensure minimum response time
minutes_to_confirm = max(minutes_to_confirm,
URGENCY_OVERRIDE["minimum_response_time"] / 10 if getattr(settings, 'LIVE_TESTING', False)
else URGENCY_OVERRIDE["minimum_response_time"])
break
# Default business hours
business_start_hour = BUSINESS_RULES["hours"]["start"]
business_end_hour = BUSINESS_RULES["hours"]["end"]
# for hours_threshold, override in URGENCY_OVERRIDE["thresholds"].items():
# if hours_until_tournament <= hours_threshold:
# apply_business_rules = False
# # Ensure minimum response time
# minutes_to_confirm = max(minutes_to_confirm,
# URGENCY_OVERRIDE["minimum_response_time"] / 10 if getattr(settings, 'LIVE_TESTING', False)
# else URGENCY_OVERRIDE["minimum_response_time"])
# break
# Adjust business hours based on tournament proximity
if hours_until_tournament <= 24:
# 24 hours before tournament: 7am - 10pm
business_start_hour = 7
business_end_hour = 22
if hours_until_tournament <= 12:
# 12 hours before tournament: 6am - 1am (next day)
business_start_hour = 6
business_end_hour = 25 # 1am next day (25 in 24-hour format)
# 8. Calculate raw deadline
raw_deadline = current_time + timezone.timedelta(minutes=minutes_to_confirm)
@ -1558,23 +1616,14 @@ class Tournament(BaseModel):
# 10. Apply business hours rules if needed
if apply_business_rules and live_testing is False:
# Check if deadline falls outside business hours
is_weekend = raw_deadline.weekday() in BUSINESS_RULES["days"]["weekend"]
before_hours = raw_deadline.hour < BUSINESS_RULES["hours"]["start"]
after_hours = raw_deadline.hour >= BUSINESS_RULES["hours"]["end"]
before_hours = raw_deadline.hour < business_start_hour
after_hours = raw_deadline.hour >= business_end_hour
if is_weekend or before_hours or after_hours:
if before_hours or after_hours:
# Extend to next business day
if after_hours or is_weekend:
if after_hours:
# Move to next day
days_to_add = 1
if is_weekend:
# If Saturday, move to Monday
if raw_deadline.weekday() == 5: # Saturday
days_to_add = 2
# If Sunday, move to Monday
elif raw_deadline.weekday() == 6: # Sunday
days_to_add = 1
raw_deadline += timezone.timedelta(days=days_to_add)
# Set to business start hour
@ -1584,7 +1633,7 @@ class Tournament(BaseModel):
second=0,
microsecond=0
)
print(f"Is weekend: {is_weekend}, Before hours: {before_hours}, After hours: {after_hours}")
print(f"Before hours: {before_hours}, After hours: {after_hours}")
print(f"Live testing: {live_testing}")
print(f"Current time: {current_time}")

@ -49,18 +49,18 @@ def notify_object_creation_on_discord(created, instance):
def notify_team(team, tournament, message_type):
print(team, message_type)
if tournament.enable_online_registration is False:
print("returning because tournament.enable_online_registration false")
return
# if tournament.enable_online_registration is False:
# print("returning because tournament.enable_online_registration false")
# return
if team.has_registered_online() is False:
print("returning because team.has_registered_online false")
return
if tournament.should_be_over():
print("returning becausetournament.should_be_over")
return
if tournament.supposedly_in_progress():
print("returning because tournament.supposedly_in_progress")
if tournament.has_ended():
print("returning because tournament.has_ended")
return
# if tournament.will_start_soon():
# print("returning because tournament.supposedly_in_progress")
# return
if is_not_sqlite_backend():
print("is_not_sqlite_backend")

@ -43,7 +43,7 @@ def check_confirmation_deadlines():
processed_teams.add(team_registration.id)
tournament = team_registration.tournament
if not tournament or not tournament.enable_online_registration:
if not tournament or not tournament.automatic_waiting_list():
continue
teams = tournament.teams(True)

Loading…
Cancel
Save