|
|
|
|
@ -229,7 +229,7 @@ class Tournament(BaseModel): |
|
|
|
|
return "Annulé" |
|
|
|
|
|
|
|
|
|
teams = self.teams(True) |
|
|
|
|
if self.supposedly_in_progress() or self.end_date is not None: |
|
|
|
|
if self.supposedly_in_progress() or self.end_date is not None or self.should_be_over(): |
|
|
|
|
teams = [t for t in teams if t.stage != "Attente"] |
|
|
|
|
if teams is not None and len(teams) > 0: |
|
|
|
|
word = "équipe" |
|
|
|
|
@ -337,126 +337,94 @@ class Tournament(BaseModel): |
|
|
|
|
print("else", index, self.team_count) |
|
|
|
|
return -1 |
|
|
|
|
|
|
|
|
|
def teams(self, includeWaitingList): |
|
|
|
|
# print("Starting teams method") |
|
|
|
|
bracket_teams = [] |
|
|
|
|
group_stage_teams = [] |
|
|
|
|
waiting_teams = [] |
|
|
|
|
teams = [] |
|
|
|
|
wildcard_bracket = [] |
|
|
|
|
wildcard_group_stage = [] |
|
|
|
|
complete_teams = [] |
|
|
|
|
closed_registration_date = self.closed_registration_date |
|
|
|
|
# print(f"Closed registration date: {closed_registration_date}") |
|
|
|
|
def teams(self, include_waiting_list): |
|
|
|
|
""" |
|
|
|
|
Get sorted list of teams for the tournament. |
|
|
|
|
|
|
|
|
|
for team_registration in self.team_registrations.all(): |
|
|
|
|
# print(f"Processing team registration: {team_registration}") |
|
|
|
|
is_valid = False |
|
|
|
|
if closed_registration_date is not None and team_registration.registration_date is not None and team_registration.registration_date <= closed_registration_date: |
|
|
|
|
is_valid = True |
|
|
|
|
if closed_registration_date is None: |
|
|
|
|
is_valid = True |
|
|
|
|
if team_registration.registration_date is None: |
|
|
|
|
is_valid = True |
|
|
|
|
# print(f"Is valid: {is_valid}") |
|
|
|
|
if team_registration.out_of_tournament() is False: |
|
|
|
|
team = TeamItem(team_registration) |
|
|
|
|
# print(f"Created team: {team}") |
|
|
|
|
if team_registration.group_stage_position is not None: |
|
|
|
|
team.set_stage("Poule") |
|
|
|
|
elif team_registration.bracket_position is not None: |
|
|
|
|
team.set_stage("Tableau") |
|
|
|
|
else: |
|
|
|
|
team.set_stage("Attente") |
|
|
|
|
# print(f"Team stage: {team.stage}") |
|
|
|
|
|
|
|
|
|
teams.append(team) |
|
|
|
|
if team_registration.wild_card_bracket: |
|
|
|
|
wildcard_bracket.append(team) |
|
|
|
|
elif team_registration.wild_card_group_stage: |
|
|
|
|
wildcard_group_stage.append(team) |
|
|
|
|
elif is_valid is True: |
|
|
|
|
complete_teams.append(team) |
|
|
|
|
else: |
|
|
|
|
waiting_teams.append(team) |
|
|
|
|
|
|
|
|
|
# print(f"Total teams: {len(teams)}") |
|
|
|
|
# print(f"Wildcard bracket: {len(wildcard_bracket)}") |
|
|
|
|
# print(f"Wildcard group stage: {len(wildcard_group_stage)}") |
|
|
|
|
# print(f"Complete teams: {len(complete_teams)}") |
|
|
|
|
# print(f"Waiting teams: {len(waiting_teams)}") |
|
|
|
|
|
|
|
|
|
if len(teams) < self.team_count: |
|
|
|
|
teams.sort(key=lambda s: (s.initial_weight, s.team_registration.id)) |
|
|
|
|
return teams |
|
|
|
|
|
|
|
|
|
seeds_count = min(self.team_count, len(teams)) - self.group_stage_count * self.teams_per_group_stage - len(wildcard_bracket) |
|
|
|
|
group_stage_members_count = self.group_stage_count * self.teams_per_group_stage - len(wildcard_group_stage) |
|
|
|
|
if group_stage_members_count < 0: |
|
|
|
|
group_stage_members_count = 0 |
|
|
|
|
if seeds_count < 0: |
|
|
|
|
seeds_count = 0 |
|
|
|
|
# print(f"Seeds count: {seeds_count}") |
|
|
|
|
# print(f"Group stage members count: {group_stage_members_count}") |
|
|
|
|
Args: |
|
|
|
|
include_waiting_list (bool): Whether to include teams in waiting list |
|
|
|
|
|
|
|
|
|
if self.team_sorting == TeamSortingType.INSCRIPTION_DATE: |
|
|
|
|
complete_teams.sort(key=lambda s: (s.registration_date is None, s.registration_date or datetime.min, s.initial_weight, s.team_registration.id)) |
|
|
|
|
else: |
|
|
|
|
complete_teams.sort(key=lambda s: (s.initial_weight, s.team_registration.id)) |
|
|
|
|
|
|
|
|
|
selected_teams = complete_teams[:self.team_count] |
|
|
|
|
selected_teams.sort(key=lambda s: (s.initial_weight, s.team_registration.id)) |
|
|
|
|
Returns: |
|
|
|
|
list: List of TeamItem objects sorted according to tournament rules |
|
|
|
|
""" |
|
|
|
|
# Initialize team categories |
|
|
|
|
complete_teams = [] |
|
|
|
|
wildcard_bracket = [] |
|
|
|
|
wildcard_group_stage = [] |
|
|
|
|
waiting_teams = [] |
|
|
|
|
|
|
|
|
|
if seeds_count > 0: |
|
|
|
|
bracket_teams = selected_teams[:seeds_count] + wildcard_bracket |
|
|
|
|
else: |
|
|
|
|
bracket_teams = [] |
|
|
|
|
# print(f"Bracket teams: {len(bracket_teams)}") |
|
|
|
|
# Get registration cutoff date |
|
|
|
|
closed_date = self.closed_registration_date |
|
|
|
|
|
|
|
|
|
# Process each team registration |
|
|
|
|
for team_reg in self.team_registrations.all(): |
|
|
|
|
if team_reg.out_of_tournament(): |
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
# Create team item |
|
|
|
|
team = TeamItem(team_reg) |
|
|
|
|
|
|
|
|
|
# Determine if registration is valid based on date |
|
|
|
|
is_valid = ( |
|
|
|
|
closed_date is None or |
|
|
|
|
team_reg.registration_date is None or |
|
|
|
|
(team_reg.registration_date and team_reg.registration_date <= closed_date) |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
# Categorize team |
|
|
|
|
if team_reg.wild_card_bracket: |
|
|
|
|
wildcard_bracket.append(team) |
|
|
|
|
elif team_reg.wild_card_group_stage: |
|
|
|
|
wildcard_group_stage.append(team) |
|
|
|
|
elif is_valid: |
|
|
|
|
complete_teams.append(team) |
|
|
|
|
else: |
|
|
|
|
waiting_teams.append(team) |
|
|
|
|
|
|
|
|
|
if group_stage_members_count: |
|
|
|
|
group_stage_end = seeds_count + group_stage_members_count |
|
|
|
|
group_stage_teams = selected_teams[seeds_count:group_stage_end] + wildcard_group_stage |
|
|
|
|
else: |
|
|
|
|
group_stage_teams = [] |
|
|
|
|
# print(f"Group stage teams: {len(group_stage_teams)}") |
|
|
|
|
|
|
|
|
|
waiting_list_count = len(teams) - self.team_count |
|
|
|
|
if waiting_list_count < 0: |
|
|
|
|
waiting_list_count = 0 |
|
|
|
|
# print(f"Waiting list count: {waiting_list_count}") |
|
|
|
|
|
|
|
|
|
if waiting_list_count > 0 or len(waiting_teams) > 0: |
|
|
|
|
if waiting_list_count > 0: |
|
|
|
|
waiting_teams = waiting_teams + complete_teams[-waiting_list_count:] |
|
|
|
|
if self.team_sorting == TeamSortingType.INSCRIPTION_DATE: |
|
|
|
|
waiting_teams.sort(key=lambda s: (s.registration_date is None, s.registration_date or datetime.min, s.initial_weight, s.team_registration.id)) |
|
|
|
|
# Set initial stage |
|
|
|
|
if team_reg.group_stage_position is not None: |
|
|
|
|
team.set_stage("Poule") |
|
|
|
|
elif team_reg.bracket_position is not None: |
|
|
|
|
team.set_stage("Tableau") |
|
|
|
|
else: |
|
|
|
|
waiting_teams.sort(key=lambda s: (s.initial_weight, s.team_registration.id)) |
|
|
|
|
else: |
|
|
|
|
waiting_teams = [] |
|
|
|
|
# print(f"Final waiting teams: {len(waiting_teams)}") |
|
|
|
|
team.set_stage("Attente") |
|
|
|
|
|
|
|
|
|
bracket_teams.sort(key=lambda s: (s.weight, s.team_registration.id)) |
|
|
|
|
group_stage_teams.sort(key=lambda s: (s.weight, s.team_registration.id)) |
|
|
|
|
# Sort teams based on tournament rules |
|
|
|
|
if self.team_sorting == TeamSortingType.INSCRIPTION_DATE: |
|
|
|
|
complete_teams.sort(key=lambda t: ( |
|
|
|
|
t.registration_date is None, |
|
|
|
|
t.registration_date or datetime.min, |
|
|
|
|
t.initial_weight, |
|
|
|
|
t.team_registration.id |
|
|
|
|
)) |
|
|
|
|
waiting_teams.sort(key=lambda t: ( |
|
|
|
|
t.registration_date is None, |
|
|
|
|
t.registration_date or datetime.min, |
|
|
|
|
t.initial_weight, |
|
|
|
|
t.team_registration.id |
|
|
|
|
)) |
|
|
|
|
else: |
|
|
|
|
complete_teams.sort(key=lambda t: (t.initial_weight, t.team_registration.id)) |
|
|
|
|
waiting_teams.sort(key=lambda t: (t.initial_weight, t.team_registration.id)) |
|
|
|
|
|
|
|
|
|
for team in bracket_teams: |
|
|
|
|
if team.stage == "Attente": |
|
|
|
|
team.set_stage("Tableau") |
|
|
|
|
# Determine final team list based on tournament settings |
|
|
|
|
if len(complete_teams) <= self.team_count: |
|
|
|
|
all_teams = wildcard_bracket + wildcard_group_stage + complete_teams |
|
|
|
|
if include_waiting_list: |
|
|
|
|
all_teams.extend(waiting_teams) |
|
|
|
|
return all_teams |
|
|
|
|
|
|
|
|
|
for team in group_stage_teams: |
|
|
|
|
if team.stage == "Attente": |
|
|
|
|
team.set_stage("Poule") |
|
|
|
|
# Split teams into main bracket and waiting list |
|
|
|
|
qualified_teams = complete_teams[:self.team_count] |
|
|
|
|
excess_teams = complete_teams[self.team_count:] |
|
|
|
|
|
|
|
|
|
for team in waiting_teams: |
|
|
|
|
team.set_stage("Attente") |
|
|
|
|
# Combine all waiting list teams |
|
|
|
|
waiting_list = excess_teams + waiting_teams |
|
|
|
|
|
|
|
|
|
if includeWaitingList is True: |
|
|
|
|
final_teams = bracket_teams + group_stage_teams + waiting_teams |
|
|
|
|
# print(f"Final teams with waiting list: {len(final_teams)}") |
|
|
|
|
else: |
|
|
|
|
final_teams = bracket_teams + group_stage_teams |
|
|
|
|
# print(f"Final teams without waiting list: {len(final_teams)}") |
|
|
|
|
return final_teams |
|
|
|
|
# Return final sorted list |
|
|
|
|
if include_waiting_list: |
|
|
|
|
return wildcard_bracket + wildcard_group_stage + qualified_teams + waiting_list |
|
|
|
|
return wildcard_bracket + wildcard_group_stage + qualified_teams |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def match_groups(self, broadcasted, group_stage_id, round_id): |
|
|
|
|
@ -660,7 +628,7 @@ class Tournament(BaseModel): |
|
|
|
|
matches = [] |
|
|
|
|
group_stages = [] |
|
|
|
|
|
|
|
|
|
if len(self.group_stages.all()) > 0 and self.no_bracket_match_has_started(): |
|
|
|
|
if self.group_stages.count() > 0 and self.no_bracket_match_has_started(): |
|
|
|
|
group_stages = [gs.live_group_stages() for gs in self.last_group_stage_step()] |
|
|
|
|
matches = self.broadcasted_group_stages_matches() |
|
|
|
|
first_round = self.first_round() |
|
|
|
|
@ -750,24 +718,24 @@ class Tournament(BaseModel): |
|
|
|
|
|
|
|
|
|
# all started matches have ended, possibly |
|
|
|
|
last_finished_match = self.last_finished_match() |
|
|
|
|
round = last_finished_match.round |
|
|
|
|
if round is None: # when the last finished match is in the group stage |
|
|
|
|
round = self.rounds.filter(parent__isnull=True).order_by('-index').first() |
|
|
|
|
|
|
|
|
|
if round: |
|
|
|
|
# print(f'last_finished_match = {last_finished_match.name}') |
|
|
|
|
round_root_index = round.root_round().index |
|
|
|
|
# print(f'round_index = {round_root_index}') |
|
|
|
|
if round_root_index == 0: |
|
|
|
|
return round |
|
|
|
|
else: |
|
|
|
|
round = self.round_set.filter(parent=None,index=round_root_index-1).first() |
|
|
|
|
if round: |
|
|
|
|
if last_finished_match: |
|
|
|
|
round = last_finished_match.round |
|
|
|
|
if round is None: # when the last finished match is in the group stage |
|
|
|
|
round = self.rounds.filter(parent__isnull=True).order_by('-index').first() |
|
|
|
|
|
|
|
|
|
if round: |
|
|
|
|
# print(f'last_finished_match = {last_finished_match.name}') |
|
|
|
|
round_root_index = round.root_round().index |
|
|
|
|
# print(f'round_index = {round_root_index}') |
|
|
|
|
if round_root_index == 0: |
|
|
|
|
return round |
|
|
|
|
else: |
|
|
|
|
return None |
|
|
|
|
else: |
|
|
|
|
return None |
|
|
|
|
round = self.rounds.filter(parent=None,index=round_root_index-1).first() |
|
|
|
|
if round: |
|
|
|
|
return round |
|
|
|
|
else: |
|
|
|
|
return None |
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
def last_started_match(self): |
|
|
|
|
matches = [m for m in self.all_matches(False) if m.start_date] |
|
|
|
|
@ -843,7 +811,7 @@ class Tournament(BaseModel): |
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
def has_team_registrations(self): |
|
|
|
|
return len(self.team_registrations.all()) > 0 |
|
|
|
|
return self.team_registrations.count() > 0 |
|
|
|
|
|
|
|
|
|
def display_summons(self): |
|
|
|
|
if self.end_date is not None: |
|
|
|
|
@ -938,6 +906,35 @@ class Tournament(BaseModel): |
|
|
|
|
|
|
|
|
|
return start <= now <= end |
|
|
|
|
|
|
|
|
|
def should_be_over(self): |
|
|
|
|
if self.end_date is not None: |
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
timezoned_datetime = timezone.localtime(self.start_date) |
|
|
|
|
end = timezoned_datetime + timedelta(days=self.day_duration + 1) |
|
|
|
|
now = timezone.now() |
|
|
|
|
return now >= end and self.is_build_and_not_empty() and self.nearly_over() |
|
|
|
|
|
|
|
|
|
def nearly_over(self): |
|
|
|
|
# First check group stages if they exist |
|
|
|
|
if self.group_stages.count() > 0: |
|
|
|
|
# Check if all group stages are completed |
|
|
|
|
for group_stage in self.group_stages.all(): |
|
|
|
|
if group_stage.is_completed(): |
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
# If no group stages, check semi-finals |
|
|
|
|
if self.rounds.count() > 0: |
|
|
|
|
# Get round with index 1 (semi-finals) and no parent |
|
|
|
|
semifinals = self.rounds.filter(index=1, parent=None).first() |
|
|
|
|
if semifinals: |
|
|
|
|
# Check if any match in semi-finals has started |
|
|
|
|
for match in semifinals.matches.all(): |
|
|
|
|
if match.start_date is not None and match.is_ready(): |
|
|
|
|
return True |
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
def display_points_earned(self): |
|
|
|
|
return self.federal_level_category != FederalLevelCategory.UNLISTED and self.hide_points_earned is False |
|
|
|
|
@ -946,7 +943,7 @@ class Tournament(BaseModel): |
|
|
|
|
return self.hide_teams_weight |
|
|
|
|
|
|
|
|
|
def is_build_and_not_empty(self): |
|
|
|
|
return (len(self.group_stages.all()) > 0 or len(self.rounds.all()) > 0) and len(self.team_registrations.all()) >= 4 |
|
|
|
|
return self.group_stages.count() > 0 or self.rounds.count() > 0 and self.team_registrations.count() >= 4 |
|
|
|
|
|
|
|
|
|
def day_duration_formatted(self): |
|
|
|
|
return plural_format("jour", self.day_duration) |
|
|
|
|
@ -1028,7 +1025,7 @@ class Tournament(BaseModel): |
|
|
|
|
|
|
|
|
|
# Check target team count and waiting list limit |
|
|
|
|
if self.team_count is not None: |
|
|
|
|
current_team_count = len([tr for tr in self.team_registrations.all() if tr.out_of_tournament() is False]) |
|
|
|
|
current_team_count = self.team_registrations.exclude(walk_out=True).count() |
|
|
|
|
if current_team_count >= self.team_count: |
|
|
|
|
if self.waiting_list_limit is not None: |
|
|
|
|
waiting_list_count = current_team_count - self.team_count |
|
|
|
|
@ -1058,7 +1055,7 @@ class Tournament(BaseModel): |
|
|
|
|
|
|
|
|
|
if self.team_count is not None: |
|
|
|
|
# Get all team registrations excluding walk_outs |
|
|
|
|
current_team_count = len([tr for tr in self.team_registrations.all() if tr.out_of_tournament() is False]) |
|
|
|
|
current_team_count = self.team_registrations.exclude(walk_out=True).count() |
|
|
|
|
if current_team_count >= self.team_count: |
|
|
|
|
if self.waiting_list_limit is not None: |
|
|
|
|
waiting_list_count = current_team_count - self.team_count |
|
|
|
|
@ -1093,7 +1090,7 @@ class Tournament(BaseModel): |
|
|
|
|
return -1 |
|
|
|
|
|
|
|
|
|
# Get count of active teams (not walked out) |
|
|
|
|
current_team_count = len([tr for tr in self.team_registrations.all() if tr.out_of_tournament() is False]) |
|
|
|
|
current_team_count = self.team_registrations.exclude(walk_out=True).count() |
|
|
|
|
|
|
|
|
|
# If current count is less than target count, next team is not in waiting list |
|
|
|
|
if current_team_count < self.team_count: |
|
|
|
|
|