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.
 
 
 
 
padelclub_backend/tournaments/models.py

433 lines
17 KiB

from os import WEXITED, preadv
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.conf import settings
import uuid
import os
from django.utils import timezone
from django.utils.encoding import Promise
import tournaments
class FederalCategory(models.IntegerChoices):
MEN = 0, 'Men'
WOMEN = 1, 'Women'
MIXED = 2, 'Mixed'
class FederalLevelCategory(models.IntegerChoices):
P25 = 25, 'P25'
P100 = 100, 'P100'
P250 = 250, 'P250'
P500 = 500, 'P500'
P1000 = 1000, 'P1000'
P1500 = 1500, 'P1500'
P2000 = 2000, 'P2000'
class FederalAgeCategory(models.IntegerChoices):
A11_12 = 120, 'A11_12'
A13_14 = 140, 'A13_14'
A15_16 = 160, 'A15_16'
A17_18 = 180, 'A17_18'
SENIOR = 200, 'SENIOR'
A45 = 450, 'A45'
A55 = 550, 'A55'
class FederalMatchCategory(models.IntegerChoices):
TWO_SETS = 0, 'Two sets'
TWO_SETS_SUPER_TIE = 1, 'Two sets super tie'
TWO_SETS_FOUR_GAME = 2, 'Two sets of four games'
NINE_GAMES = 3, 'Nine games'
SUPER_TIE = 4, 'Super Tie-Break'
MEGA_TIE = 5, 'Mega Tie-Break'
TWO_SETS_DECISIVE_POINT = 6, 'Two Sets with decisive point'
TWO_SETS_DECISIVE_POINT_SUPER_TIE = 7, 'Two Sets with decisive point and super tie-break'
TWO_SETS_FOUR_GAME_DECISIVE_POINT = 8, 'Two sets of four games with decisive point'
NINE_GAMES_DECISIVE_POINT = 9, 'Nine games with decisive point'
class Club(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=50)
acronym = models.CharField(max_length=10)
phone = models.CharField(max_length=15, null=True, blank=True)
code = models.CharField(max_length=10, null=True, blank=True)
federal_club_data = models.JSONField(null=True, blank=True)
address = models.CharField(max_length=200, null=True, blank=True)
city = models.CharField(max_length=100, null=True, blank=True)
zip_code = models.CharField(max_length=10, null=True, blank=True)
latitude = models.FloatField(null=True, blank=True)
longitude = models.FloatField(null=True, blank=True)
def __str__(self):
return self.name
class CustomUser(AbstractUser):
pass
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
umpire_code = models.CharField(max_length=50, blank=True, null=True)
clubs = models.ManyToManyField(Club)
phone = models.CharField(max_length=15, null=True, blank=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
licence_id = models.CharField(max_length=10, null=True, blank=True)
def __str__(self):
return self.username
class Event(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
club = models.ForeignKey(Club, on_delete=models.CASCADE)
date = models.DateTimeField()
name = models.CharField(max_length=200, null=True, blank=True)
federal_tournament_data = models.JSONField(null=True, blank=True)
court_count = models.IntegerField(null=True, blank=True)
tenup_id = models.IntegerField(null=True, blank=True)
group_stage_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
round_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
loser_round_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
def __str__(self):
return self.name
class Tournament(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
event = models.ForeignKey(Event, blank=True, null=True, on_delete=models.CASCADE)
creator = models.ForeignKey(CustomUser, blank=True, null=True, on_delete=models.CASCADE)
name = models.CharField(max_length=200, null=True, blank=True)
start_date = models.DateTimeField()
end_date = models.DateTimeField(null=True, blank=True)
creation_date = models.DateTimeField()
is_private = models.BooleanField()
format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
group_stage_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
round_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
loser_round_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
bracket_sort_mode = models.IntegerField(default=0)
group_stage_count = models.IntegerField(default=0)
rank_source_date = models.DateTimeField(null=True, blank=True)
# custom_name = models.CharField(max_length=100, null=True, blank=True)
day_duration = models.IntegerField(default=0)
team_count = models.IntegerField(default=0)
team_sorting = models.IntegerField(default=0)
federal_category = models.IntegerField(default=FederalCategory.MEN, choices=FederalCategory.choices) # optional ?
federal_level_category = models.IntegerField(default=FederalLevelCategory.P100, choices=FederalLevelCategory.choices)
federal_age_category = models.IntegerField(default=FederalAgeCategory.SENIOR, choices=FederalAgeCategory.choices)
group_stage_court_count = models.IntegerField(null=True, blank=True)
seed_count = models.IntegerField(default=0)
closed_registration_date = models.DateTimeField(null=True, blank=True)
group_stage_additional_qualified = models.IntegerField(default=0)
court_count = models.IntegerField(null=True, blank=True)
prioritize_club_members = models.BooleanField()
qualified_per_group_stage = models.IntegerField(default=0)
teams_per_group_stage = models.IntegerField(default=0)
#estimated_end_date = models.DateTimeField(null=True, blank=True)
def __str__(self):
return self.name
def level(self):
return self.get_federal_level_category_display()
def category(self):
return self.get_federal_category_display()
def formatted_start_date(self):
return self.start_date.strftime("%d/%m/%y")
def team_calls(self):
team_calls = []
for team_registration in self.teamregistration_set.all():
call_date = team_registration.call_date
if call_date:
names = team_registration.team_names()
stage = team_registration.next_stage()
weight = team_registration.weight()
team_call = TeamCall(names, call_date, weight, stage, team_registration.logo)
team_calls.append(team_call)
return team_calls
# stage_call = StageCall(f"1/{self.index}")
# for match in self.match_set.all():
# names = map(lambda ts: ts.player_names(), match.teamstate_set.all())
# if names:
# team_call = TeamCall(names, match.formatted_start_date)
# stage_call.add_team(team_call)
# return stage_call
class Round(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
index = models.IntegerField(null=True, blank=True)
loser = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE)
format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
def __str__(self):
return f"{self.tournament.name} - {self.name()}"
# def stage_call(self):
# stage_call = StageCall(f"1/{self.index}")
# for match in self.match_set.all():
# names = map(lambda ts: ts.player_names(), match.teamstate_set.all())
# if names:
# team_call = TeamCall(names, match.formatted_start_date)
# stage_call.add_team(team_call)
# return stage_call
def name(self):
if self.index == 0:
return "Finale"
elif self.index == 1:
return "Demi-Finales"
elif self.index == 2:
return "Quarts de finale"
elif self.index == 3:
return "Huitième de finale"
elif self.index == 4:
return "Seizième de finale"
else:
return ""
class GroupStage(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
index = models.IntegerField(null=True, blank=True)
format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
def __str__(self):
return f"{self.tournament.name} - {self.name()}"
def name(self):
return f"Poule {self.index}"
# def stage_call(self):
# stage_call = StageCall(f"poule{self.index}")
# for team_registration in self.teamregistration_set.all():
# names = map(lambda pr: pr.name(), team_registration.playerregistration_set.all())
# time = self.next_match(team_registration).start_date.strftime("%H:%M") # "17h45" # which match do we take, the first unfinished?
# team_call = TeamCall(names, time)
# return stage_call
def next_match(self, player_registration):
matches = self.matches_for_registration(player_registration).filter(end_date__isnull=False).order_by('start_date')
return matches[0]
def matches_for_registration(self, player_registration):
team_states = TeamState.objects.filter(player_registrations=player_registration)
return map(lambda ts: ts.match, team_states)
class Match(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
round = models.ForeignKey(Round, null=True, blank=True, on_delete=models.CASCADE)
group_stage = models.ForeignKey(GroupStage, null=True, blank=True, on_delete=models.CASCADE)
start_date = models.DateTimeField(null=True, blank=True)
end_date = models.DateTimeField(null=True, blank=True)
index = models.IntegerField(null=True, blank=True)
format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
court = models.IntegerField(null=True, blank=True)
serving_team_id = models.UUIDField(null=True, blank=True)
winning_team_id = models.UUIDField(null=True, blank=True)
losing_team_id = models.UUIDField(null=True, blank=True)
broadcasted = models.BooleanField(default=False)
def __str__(self):
items = [f"Match {self.index}", self.formatted_start_date()]
desc = " - ".join(items)
player_names = " / ".join(self.player_names())
if self.round:
return f"{str(self.round)} > {desc} > {player_names}"
elif self.group_stage:
return f"{str(self.group_stage)} > {desc} > {player_names}"
def player_names(self):
return map(lambda ts: ts.player_names(), self.team_states.all())
def formatted_start_date(self):
if self.start_date:
return self.start_date.strftime("%H:%M")
else:
return "no date"
# return str(self.start_date) #.strftime("%H:%M")
def current_duration(self):
if self.end_date:
return (self.end_date - self.start_date).total_seconds()
else:
return (timezone.now() - self.start_date).total_seconds()
def durationPrefix(self):
if self.current_duration() > 0:
return "Temps de jeu"
else:
return "Démarrage prévu dans"
def formatted_duration(self):
_seconds = self.current_duration()
if _seconds > 0:
_hours = int(_seconds / 3600)
_minutes = int((_seconds % 3600) / 60)
return f"{_hours:02d}h{_minutes:02d}min"
else :
_seconds = _seconds * -1
_hours = int(_seconds / 3600)
_minutes = int((_seconds % 3600) / 60)
return f"{_hours:02d}h{_minutes:02d}min"
def seconds(self):
return (timezone.now() - self.date).total_seconds()
def live_match(self):
title = f"{self.index}"
date = self.formatted_start_date()
duration = self.formatted_duration()
livematch = LiveMatch(title, date, duration)
for team_state in self.team_states:
break
# def __init__(self, names, date, weight, stage, image):
# def __init__(self, title, date, teams, duration):
class TeamRegistration(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
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)
initial_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)
def __str__(self):
return self.player_names()
def team_names(self):
if self.name:
return [self.name]
else:
return map(lambda pr: pr.name(), self.playerregistration_set.all())
def player_names(self):
names = map(lambda pr: pr.name(), self.playerregistration_set.all())
str = " - ".join(names)
if len(str) > 0:
return str
else:
return "no players"
def next_stage(self):
matches = Match.objects.filter(group_stage__isnull=True, team_states__player_registrations__id=self.id).order_by('round__index')
if matches:
return matches[0].round.name()
elif self.group_stage:
return self.group_stage.name()
else:
return "--"
def weight(self):
top_two_players = self.playerregistration_set.all().order_by('rank')[:2]
weight = 0
for player in top_two_players:
rank = player.rank if player.rank is not None else 0
weight += rank
return weight
class PlayerRegistration(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
team_registration = models.ForeignKey(TeamRegistration, on_delete=models.CASCADE)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
licence_id = models.CharField(max_length=20, null=True, blank=True)
rank = models.IntegerField(null=True, blank=True)
has_paid = models.BooleanField(default=False)
unranked = models.BooleanField(default=False)
def __str__(self):
return self.name()
def name(self):
return f"{self.first_name} {self.last_name}"
class TeamState(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
match = models.ForeignKey(Match, on_delete=models.CASCADE, related_name="team_states")
player_registrations = models.ManyToManyField(PlayerRegistration, blank=True)
score = models.CharField(max_length=50, null=True, blank=True)
walk_out = models.IntegerField(null=True, blank=True) #id, int of the walked_out team
lucky_loser = models.BooleanField()
def __str__(self):
return f"{str(self.match)}: {self.player_names()}"
def player_names(self):
names = map(lambda player: player.name(), self.player_registrations.all())
return " - ".join(names)
def team_name(self):
class Team:
def __init__(self, image, names, scores, is_winner):
self.image = image
self.names = []
self.scores = []
self.is_winner = is_winner
def add_names(self, name):
self.names.append(name)
def add_set_score(self, score):
self.scores.append(score)
class LiveMatch:
def __init__(self, title, date, duration):
self.title = title
self.date = date
self.teams = []
self.duration = duration
def add_team(self, team):
self.teams.append(team)
class TeamCall:
def __init__(self, names, date, weight, stage, image):
self.names = []
self.names = names
self.date = date
self.weight = weight
self.stage = stage
self.image = image
# class Set(models.Model):
# class Game(models.Model):
# set = models.ForeignKey(Set, on_delete=models.CASCADE)
# format = models.IntegerField()
# class Point(models.Model):
# game = models.ForeignKey(Game, on_delete=models.CASCADE)
# action = models.IntegerField()
# date = models.DateTimeField()
# team_id = models.IntegerField()