You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
265 lines
9.5 KiB
265 lines
9.5 KiB
from django.db import models
|
|
from django.db.models.sql.query import Q
|
|
from . import Tournament, GroupStage, Match
|
|
import uuid
|
|
from django.utils import timezone
|
|
from django.db.models import Count
|
|
|
|
class TeamRegistration(models.Model):
|
|
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
|
|
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
|
|
group_stage = models.ForeignKey(GroupStage, null=True, blank=True, on_delete=models.SET_NULL)
|
|
registration_date = models.DateTimeField(null=True, blank=True)
|
|
call_date = models.DateTimeField(null=True, blank=True)
|
|
bracket_position = models.IntegerField(null=True, blank=True)
|
|
group_stage_position = models.IntegerField(null=True, blank=True)
|
|
comment = models.CharField(max_length=200, null=True, blank=True)
|
|
source = models.CharField(max_length=20, null=True, blank=True)
|
|
source_value = models.CharField(max_length=200, null=True, blank=True)
|
|
logo = models.CharField(max_length=200, null=True, blank=True) #models.FilePathField(path=os.path.join(settings.STATIC_ROOT, "images"), null=True, blank=True)
|
|
name = models.CharField(max_length=200, null=True, blank=True)
|
|
|
|
walk_out = models.BooleanField(default=False)
|
|
wild_card_bracket = models.BooleanField(default=False)
|
|
wild_card_group_stage = models.BooleanField(default=False)
|
|
weight = models.IntegerField(default=0)
|
|
locked_weight = models.IntegerField(null=True, blank=True)
|
|
|
|
confirmation_date = models.DateTimeField(null=True, blank=True)
|
|
qualified = models.BooleanField(default=False)
|
|
|
|
final_ranking = models.IntegerField(null=True, blank=True)
|
|
points_earned = models.IntegerField(null=True, blank=True)
|
|
|
|
def __str__(self):
|
|
if self.name:
|
|
return self.name
|
|
# return f"{self.name}: {self.player_names()}"
|
|
return self.player_names()
|
|
|
|
def player_names_as_list(self):
|
|
return [pr.name() for pr in self.playerregistration_set.all()]
|
|
|
|
|
|
def team_names(self):
|
|
if self.name:
|
|
return [self.name]
|
|
else:
|
|
return self.player_names_as_list()
|
|
|
|
def shortened_team_names(self):
|
|
if self.name:
|
|
return [self.name]
|
|
else:
|
|
players = list(self.playerregistration_set.all())
|
|
if len(players) == 1:
|
|
return [players[0].shortened_name(), '']
|
|
else:
|
|
return [pr.shortened_name() for pr in players]
|
|
|
|
@property
|
|
def players(self):
|
|
# Fetch related PlayerRegistration objects
|
|
return self.playerregistration_set.all().order_by('rank')
|
|
|
|
def player_names(self):
|
|
names = self.player_names_as_list()
|
|
str = " - ".join(names)
|
|
if len(str) > 0:
|
|
return str
|
|
else:
|
|
return "no players"
|
|
|
|
def formatted_team_names(self):
|
|
if self.name:
|
|
return self.name
|
|
names = [pr.last_name for pr in self.playerregistration_set.all()][:2] # Take max first 2
|
|
joined_names = " / ".join(names)
|
|
if joined_names:
|
|
return f"Paire {joined_names}"
|
|
return "Détail de l'équipe"
|
|
|
|
def next_match(self):
|
|
all_matches = [ts.match for ts in self.teamscore_set.all()]
|
|
now = timezone.now()
|
|
all_matches = sorted(all_matches, key=lambda m: m.start_date if m.start_date is not None else now)
|
|
matches = [m for m in all_matches if m.end_date is None]
|
|
if matches:
|
|
return matches[0]
|
|
else:
|
|
return None
|
|
|
|
def next_stage(self):
|
|
matches = map(lambda ts: ts.match, self.teamscore_set.all())
|
|
matches = [m for m in matches if m.group_stage is None]
|
|
matches = sorted(matches, key=lambda m: m.round.index)
|
|
|
|
# matches = self.teamscore_set
|
|
# matches = Match.objects.filter(group_stage__isnull=True, team_scores__player_registrations__id=self.id).order_by('round__index')
|
|
# print(f"matches = {len(matches)}")
|
|
if matches:
|
|
return matches[0].round.name()
|
|
elif self.group_stage:
|
|
return self.group_stage.name()
|
|
else:
|
|
return "--"
|
|
|
|
def set_weight(self):
|
|
self.weight = self.playerregistration_set.aggregate(total_weight=models.Sum('computed_rank'))['total_weight'] or 0
|
|
self.save() # Save the updated weight if necessary
|
|
|
|
def is_valid_for_summon(self):
|
|
return self.playerregistration_set.count() > 0 or self.name is not None
|
|
|
|
def initial_weight(self):
|
|
if self.locked_weight is None:
|
|
return self.weight
|
|
else:
|
|
return self.locked_weight
|
|
|
|
def local_call_date(self):
|
|
timezone = self.tournament.timezone()
|
|
if self.call_date:
|
|
return self.call_date.astimezone(timezone)
|
|
else:
|
|
# print("no date")
|
|
return None
|
|
|
|
def local_registration_date(self):
|
|
timezone = self.tournament.timezone()
|
|
if self.registration_date:
|
|
return self.registration_date.astimezone(timezone)
|
|
else:
|
|
# print("no date")
|
|
return None
|
|
|
|
def out_of_tournament(self):
|
|
return self.walk_out
|
|
|
|
def get_other_player(self, player):
|
|
for p in self.playerregistration_set.all():
|
|
if p != player:
|
|
return p
|
|
return None
|
|
|
|
def is_in_waiting_list(self):
|
|
return self.tournament.get_team_waiting_list_position(self)
|
|
|
|
def get_matches(self):
|
|
matches = Match.objects.filter(team_scores__team_registration=self).distinct()
|
|
print(f"All matches for team {self.id}: {matches.count()}")
|
|
for match in matches:
|
|
print(f"Match {match.id}: start_date={match.start_date}, end_date={match.end_date}")
|
|
return matches
|
|
|
|
def get_upcoming_matches(self):
|
|
matches = self.get_matches()
|
|
upcoming = matches.filter(end_date__isnull=True).order_by('start_date')
|
|
print(f"Upcoming matches count: {upcoming.count()}")
|
|
return [match.live_match() for match in upcoming]
|
|
|
|
def get_completed_matches(self):
|
|
matches = self.get_matches()
|
|
completed = matches.filter(end_date__isnull=False).order_by('-end_date')
|
|
print(f"Completed matches count: {completed.count()}")
|
|
return [match.live_match() for match in completed]
|
|
|
|
def get_statistics(self):
|
|
|
|
stats = {
|
|
'final_ranking': self.get_final_ranking(),
|
|
'weight': self.weight,
|
|
'points_earned': self.get_points_earned(),
|
|
'initial_stage': self.get_initial_stage(),
|
|
'matches_played': self.count_matches_played(),
|
|
'victory_ratio': self.calculate_victory_ratio(),
|
|
'team_rank': self.team_rank_label(),
|
|
'total_teams': self.total_teams(),
|
|
}
|
|
return stats
|
|
|
|
def team_rank(self):
|
|
teams = self.tournament.teams(False) # Get list of TeamItem objects
|
|
try:
|
|
# Find the TeamItem that corresponds to this TeamRegistration
|
|
team_index = next(i for i, team in enumerate(teams)
|
|
if team.team_registration.id == self.id)
|
|
return team_index + 1
|
|
except (StopIteration, ValueError):
|
|
return None
|
|
|
|
def team_rank_label(self):
|
|
team_rank = self.team_rank()
|
|
if team_rank is None:
|
|
return "--"
|
|
return f"{team_rank}"
|
|
|
|
def total_teams(self):
|
|
teams = self.tournament.teams(False)
|
|
return f"{len(teams)}"
|
|
|
|
def get_initial_stage(self):
|
|
matches = self.get_matches().order_by('start_date')
|
|
first_match = matches.first()
|
|
if first_match:
|
|
if first_match.group_stage:
|
|
return "Poule"
|
|
elif first_match.round:
|
|
return first_match.round.name()
|
|
return None
|
|
|
|
|
|
def get_final_ranking(self):
|
|
if self.final_ranking:
|
|
if self.final_ranking == 1:
|
|
return "1er" + self.ranking_delta()
|
|
return f"{self.final_ranking}ème" + self.ranking_delta()
|
|
return None
|
|
|
|
def ranking_delta(self):
|
|
team_rank = self.team_rank()
|
|
if team_rank is None or self.final_ranking is None:
|
|
return ""
|
|
|
|
sign = "-"
|
|
if team_rank > self.final_ranking:
|
|
sign = "+"
|
|
if team_rank == self.final_ranking:
|
|
sign = "+"
|
|
return f" ({sign}"+f"{abs(self.final_ranking - team_rank)})"
|
|
|
|
def get_points_earned(self):
|
|
return self.points_earned
|
|
|
|
def calculate_total_duration(self):
|
|
total_seconds = 0
|
|
for match in self.get_matches().filter(end_date__isnull=False):
|
|
if match.start_date and match.end_date:
|
|
duration = (match.end_date - match.start_date).total_seconds()
|
|
total_seconds += duration
|
|
|
|
if total_seconds > 0:
|
|
hours = int(total_seconds // 3600)
|
|
minutes = int((total_seconds % 3600) // 60)
|
|
if hours > 0:
|
|
return f"{hours}h{minutes:02d}"
|
|
return f"{minutes}min"
|
|
return None
|
|
|
|
def count_matches_played(self):
|
|
return self.get_matches().filter(end_date__isnull=False).count()
|
|
|
|
def calculate_victory_ratio(self):
|
|
matches = self.get_matches().filter(end_date__isnull=False)
|
|
total_matches = matches.count()
|
|
if total_matches > 0:
|
|
wins = matches.filter(winning_team_id=self.id).count()
|
|
# ratio = (wins / total_matches) * 100
|
|
return f"{wins}/{total_matches}"
|
|
return None
|
|
|
|
def has_registered_online(self):
|
|
for p in self.playerregistration_set.all():
|
|
if p.registered_online:
|
|
return True
|
|
return False
|
|
|