1179 lines
38 KiB
Python
1179 lines
38 KiB
Python
|
from django.contrib.auth.decorators import login_required
|
|||
|
from django.contrib.auth.models import Group
|
|||
|
from django.contrib.auth import get_user_model
|
|||
|
|
|||
|
from django.db.models import (
|
|||
|
Q,
|
|||
|
Avg,
|
|||
|
Sum,
|
|||
|
)
|
|||
|
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
|
|||
|
from django.shortcuts import render, get_object_or_404
|
|||
|
from django.views.decorators.http import require_http_methods
|
|||
|
from django.urls import reverse
|
|||
|
from django.template.loader import render_to_string
|
|||
|
from django.conf import settings
|
|||
|
|
|||
|
from django.core.mail import send_mail
|
|||
|
|
|||
|
from weasyprint import HTML, CSS
|
|||
|
|
|||
|
# from weasyprint.fonts import FontConfiguration
|
|||
|
|
|||
|
import pendulum
|
|||
|
from datetime import date, timedelta
|
|||
|
from statistics import mean
|
|||
|
|
|||
|
from jarvis.followup.models import Event
|
|||
|
from jarvis.followup.forms import GymnastHasRoutineForm
|
|||
|
from jarvis.followup.models import (
|
|||
|
Note,
|
|||
|
Plan,
|
|||
|
Skill,
|
|||
|
Point,
|
|||
|
Chrono,
|
|||
|
Accident,
|
|||
|
MindState,
|
|||
|
Intensity,
|
|||
|
LearnedSkill,
|
|||
|
HeightWeight,
|
|||
|
SeasonInformation,
|
|||
|
NumberOfRoutineDone,
|
|||
|
)
|
|||
|
|
|||
|
from jarvis.followup.models import (
|
|||
|
CATEGORY_CHOICES,
|
|||
|
LEARNING_STEP_CHOICES,
|
|||
|
)
|
|||
|
|
|||
|
from jarvis.tools.models import Season
|
|||
|
|
|||
|
# from jarvis.tools.pdf_generator import GymnastReportDocument
|
|||
|
|
|||
|
from jarvis.tools.date_week_transition import (
|
|||
|
from_date_to_week_number,
|
|||
|
from_week_number_to_date,
|
|||
|
)
|
|||
|
|
|||
|
from .models import Gymnast
|
|||
|
from .forms import GymnastForm, UserForm
|
|||
|
|
|||
|
User = get_user_model()
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["POST"])
|
|||
|
def gymnast_lookup(request):
|
|||
|
"""
|
|||
|
Récupère la liste des gymnastes à la volée suivant des caractères de
|
|||
|
recherche entrés. (min 3 caractères)
|
|||
|
"""
|
|||
|
|
|||
|
results = []
|
|||
|
pattern = request.POST.get("pattern", None)
|
|||
|
|
|||
|
if pattern is not None and len(pattern) > 3:
|
|||
|
model_results = Gymnast.objects.filter(
|
|||
|
Q(last_name__icontains=pattern) | Q(first_name__icontains=pattern)
|
|||
|
)
|
|||
|
results = [{"ID": x.id, "Name": str(x)} for x in model_results]
|
|||
|
|
|||
|
return JsonResponse(results, safe=False)
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET"])
|
|||
|
def gymnast_listing(request):
|
|||
|
"""
|
|||
|
Si la personne connectée est un entraîneur : liste tous les gymnasts connus.
|
|||
|
Si la personne connectée est un gymnaste : renvoie sa fiche détaillée.
|
|||
|
"""
|
|||
|
season = Season()
|
|||
|
if request.user.groups.filter(name="trainer").exists():
|
|||
|
season_information_list = SeasonInformation.objects.filter(
|
|||
|
season=season.label
|
|||
|
).select_related("gymnast")
|
|||
|
context = {"season_information_list": season_information_list}
|
|||
|
return render(request, "gymnasts/list.html", context)
|
|||
|
else:
|
|||
|
gymnast = Gymnast.objects.get(user=request.user) # a mettre dans un TRY
|
|||
|
return gymnast_details(request, gymnast.id)
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET"])
|
|||
|
def gymnast_details(request, gymnast_id, tab=None):
|
|||
|
"""
|
|||
|
Récupère toutes les informations d'un gymnaste si la personne connectée est un "trainer".
|
|||
|
Si la personne connectée est un gymnaste : renvoie sa fiche détaillée.
|
|||
|
"""
|
|||
|
|
|||
|
if request.user.groups.filter(name="trainer").exists():
|
|||
|
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
|
|||
|
else:
|
|||
|
gymnast = Gymnast.objects.get(user=request.user)
|
|||
|
|
|||
|
last_season_information = gymnast.season_informations.order_by("-season").first()
|
|||
|
|
|||
|
gymnast_nb_known_skills = gymnast.known_skills.distinct(
|
|||
|
"skill"
|
|||
|
).count() # devrait disparaitre
|
|||
|
|
|||
|
nb_skill = Skill.objects.all().count()
|
|||
|
nb_known_skill = (
|
|||
|
LearnedSkill.objects.filter(gymnast=gymnast_id).distinct("skill").count()
|
|||
|
)
|
|||
|
|
|||
|
if nb_skill != 0:
|
|||
|
percentage_known_skill = (nb_known_skill / nb_skill) * 100
|
|||
|
else:
|
|||
|
percentage_known_skill = 0
|
|||
|
|
|||
|
# base_queryset = Chrono.objects.filter(gymnast=gymnast_id).order_by("-date")
|
|||
|
chronos_list = Chrono.objects.filter(gymnast=gymnast_id).order_by("-date")[:10]
|
|||
|
straightjump_score = (
|
|||
|
Chrono.objects.filter(gymnast=gymnast_id)
|
|||
|
.filter(chrono_type=0)
|
|||
|
.order_by("-date")
|
|||
|
)
|
|||
|
best_straightjump = (
|
|||
|
Chrono.objects.filter(gymnast=gymnast_id)
|
|||
|
.filter(chrono_type=0)
|
|||
|
.order_by("-score")[:1]
|
|||
|
)
|
|||
|
best_routine = (
|
|||
|
Chrono.objects.filter(gymnast=gymnast_id)
|
|||
|
.filter(chrono_type=1)
|
|||
|
.order_by("-score")[:1]
|
|||
|
)
|
|||
|
|
|||
|
context = {
|
|||
|
"gymnast": gymnast,
|
|||
|
"last_season_information": last_season_information,
|
|||
|
"gymnast_nb_known_skills": gymnast_nb_known_skills,
|
|||
|
"chronos_list": chronos_list,
|
|||
|
"straightjump_score": straightjump_score,
|
|||
|
"best_routine": best_routine,
|
|||
|
"best_straightjump": best_straightjump,
|
|||
|
"nb_skill": nb_skill,
|
|||
|
"nb_known_skill": nb_known_skill,
|
|||
|
"percentage_known_skill": percentage_known_skill,
|
|||
|
"tab": tab,
|
|||
|
}
|
|||
|
context["user_is_trainer"] = request.user.groups.filter(
|
|||
|
name="trainer"
|
|||
|
).exists() # TODO: utiliser les {{ perms }}
|
|||
|
return render(request, "gymnasts/details.html", context)
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET"])
|
|||
|
def gymnast_report_list(request, gymnast_id):
|
|||
|
""" """
|
|||
|
|
|||
|
context = {
|
|||
|
"gymnast_id": gymnast_id,
|
|||
|
}
|
|||
|
return render(request, "gymnasts/tabs/tab_documents.html", context)
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET"])
|
|||
|
def gymnast_report_evaluation(request, gymnast_id):
|
|||
|
""" """
|
|||
|
context = {
|
|||
|
"SITE_TITLE": settings.SITE_TITLE,
|
|||
|
"CLUB_NAME": settings.CLUB_NAME,
|
|||
|
"ADDRESS": settings.ADDRESS,
|
|||
|
"CITY": settings.CITY,
|
|||
|
"ZIP": settings.ZIP,
|
|||
|
"HEAD_COACH": settings.HEAD_COACH,
|
|||
|
"MOBILE_PHONE": settings.MOBILE_PHONE,
|
|||
|
"HEAD_COACH_EMAIL": settings.HEAD_COACH_EMAIL,
|
|||
|
# "week_number": week_number,
|
|||
|
# "gymnast": gymnast,
|
|||
|
# "today": date_begin,
|
|||
|
# "season": season,
|
|||
|
# "sorted_records": sorted_records,
|
|||
|
}
|
|||
|
return render(request, "gymnasts/reports/report_evaluation.html", context)
|
|||
|
# response = HttpResponse(content_type="application/pdf")
|
|||
|
# response[
|
|||
|
# "Content-Disposition"
|
|||
|
# ] = "attachment; filename={lastname}-{firstname}-report-timeline.pdf".format(
|
|||
|
# lastname=gymnast.last_name,
|
|||
|
# firstname=gymnast.first_name,
|
|||
|
# )
|
|||
|
|
|||
|
# html = render_to_string("people/gymnasts/reports/report_timeline.html", context)
|
|||
|
|
|||
|
# # font_config = FontConfiguration()
|
|||
|
# HTML(string=html, base_url=request.build_absolute_uri()).write_pdf(
|
|||
|
# response,
|
|||
|
# stylesheets=[
|
|||
|
# CSS(settings.STATICFILES_DIRS[0] + "/css/gymnast_report.css"),
|
|||
|
# CSS(settings.STATICFILES_DIRS[0] + "/css/black-dashboard_report.css"),
|
|||
|
# CSS(settings.STATICFILES_DIRS[0] + "/css/font_awesome_all_5.15.3.css"),
|
|||
|
# ],
|
|||
|
# ) # , font_config=font_config)
|
|||
|
# return response
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET"])
|
|||
|
def gymnast_display_events_and_notes(request, gymnast_id):
|
|||
|
"""
|
|||
|
Renvoie deux listes d'évènements : ceux à venir et ceux passés.
|
|||
|
"""
|
|||
|
today = pendulum.now().date()
|
|||
|
next_event_list = Event.objects.filter(gymnasts=gymnast_id, date_begin__gte=today)
|
|||
|
previous_event_list = Event.objects.filter(
|
|||
|
gymnasts=gymnast_id, date_begin__lte=today
|
|||
|
)
|
|||
|
|
|||
|
base_queryset = Note.objects.filter(gymnast=gymnast_id)
|
|||
|
if not request.user.groups.filter(name="trainer").exists():
|
|||
|
notes_list = base_queryset.filter(status=1)
|
|||
|
else:
|
|||
|
notes_list = base_queryset
|
|||
|
notes_list = notes_list.order_by("-created_at")
|
|||
|
|
|||
|
last_notes_list = notes_list[:5]
|
|||
|
latest_published_note = (
|
|||
|
base_queryset.filter(status=1).order_by("-created_at").first()
|
|||
|
)
|
|||
|
|
|||
|
context = {
|
|||
|
"next_event_list": next_event_list,
|
|||
|
"previous_event_list": previous_event_list,
|
|||
|
"last_notes_list": last_notes_list,
|
|||
|
"latest_published_note": latest_published_note,
|
|||
|
"gymnast_id": gymnast_id,
|
|||
|
}
|
|||
|
return render(request, "gymnasts/tabs/tab_events_and_notes.html", context)
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET"])
|
|||
|
def gymnast_display_accident(request, gymnast_id):
|
|||
|
"""
|
|||
|
Renvoie la liste des accidents d'un gymnaste.
|
|||
|
"""
|
|||
|
accident_list = Accident.objects.filter(gymnast=gymnast_id)
|
|||
|
context = {"accident_list": accident_list, "gymnast_id": gymnast_id}
|
|||
|
return render(request, "gymnasts/list_accident.html", context)
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET"])
|
|||
|
def gymnast_display_physiological(request, gymnast_id):
|
|||
|
"""
|
|||
|
Renvoie les listes des tailles/poids, état d'esprit et accidents.
|
|||
|
"""
|
|||
|
accident_list = Accident.objects.filter(gymnast=gymnast_id).order_by("date")
|
|||
|
mindstate_list = MindState.objects.filter(gymnast=gymnast_id).order_by("date")
|
|||
|
height_weight_list = HeightWeight.objects.filter(gymnast=gymnast_id).order_by(
|
|||
|
"date"
|
|||
|
)
|
|||
|
|
|||
|
context = {
|
|||
|
"accident_list": accident_list,
|
|||
|
"mindstate_list": mindstate_list,
|
|||
|
"height_weight_list": height_weight_list,
|
|||
|
"gymnast_id": gymnast_id,
|
|||
|
}
|
|||
|
return render(request, "gymnasts/tabs/tab_physiological.html", context)
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET"])
|
|||
|
def gymnast_display_scores_chrono(request, gymnast_id):
|
|||
|
"""
|
|||
|
Selectionne tous les scores réalisés par le gymnaste
|
|||
|
|
|||
|
Afin de ne pas avoir plusieurs valeurs pour une même date, nous faisons une
|
|||
|
moyenne par date.
|
|||
|
"""
|
|||
|
score_list = Point.objects.filter(gymnast=gymnast_id).order_by("-event__date_begin")
|
|||
|
chrono_list = Chrono.objects.filter(gymnast=gymnast_id).order_by("date")
|
|||
|
base_queryset = chrono_list.values("date").annotate(score_avg=Avg("tof"))
|
|||
|
|
|||
|
context = {
|
|||
|
"score_list": score_list,
|
|||
|
"score_routine1_list": score_list.filter(routine_type=1),
|
|||
|
"score_routine2_list": score_list.filter(routine_type=2),
|
|||
|
"score_routine3_list": score_list.filter(routine_type=3),
|
|||
|
"chrono_list": chrono_list,
|
|||
|
"chrono_10c": base_queryset.filter(chrono_type=0),
|
|||
|
"chrono_r1": base_queryset.filter(chrono_type=1),
|
|||
|
"chrono_r2": base_queryset.filter(chrono_type=2),
|
|||
|
"chrono_rf": base_queryset.filter(chrono_type=3),
|
|||
|
"gymnast_id": gymnast_id,
|
|||
|
}
|
|||
|
return render(request, "gymnasts/tabs/tab_scores_and_chronos.html", context)
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET"])
|
|||
|
def gymnast_display_mindstate(request, gymnast_id):
|
|||
|
"""
|
|||
|
Selectionne tous les scores réalisés par le gymnaste
|
|||
|
"""
|
|||
|
mindstate_list = MindState.objects.filter(gymnast=gymnast_id).order_by("-date")
|
|||
|
|
|||
|
context = {
|
|||
|
"mindstate_list": mindstate_list,
|
|||
|
"gymnast_id": gymnast_id,
|
|||
|
}
|
|||
|
return render(request, "gymnasts/list_mindstate.html", context)
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET"])
|
|||
|
def gymnast_display_routine_statistics(request, gymnast_id):
|
|||
|
"""
|
|||
|
Tag affichant les statistiques et informations de séries d'un gymnaste.
|
|||
|
"""
|
|||
|
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
|
|||
|
ghr_list = gymnast.has_routine.prefetch_related("routine").filter(
|
|||
|
Q(date_end__gte=date.today()) | Q(date_end__isnull=True)
|
|||
|
)
|
|||
|
|
|||
|
has_routine_1 = ghr_list.filter(routine_type=1)
|
|||
|
has_routine_2 = ghr_list.filter(routine_type=2)
|
|||
|
has_routine_3 = ghr_list.filter(routine_type=3)
|
|||
|
has_routine_4 = ghr_list.filter(routine_type=4)
|
|||
|
has_routine_5 = ghr_list.filter(routine_type=5)
|
|||
|
|
|||
|
routine_one_done_list = NumberOfRoutineDone.objects.filter(
|
|||
|
gymnast=gymnast_id, routine_type=1
|
|||
|
).order_by("date")
|
|||
|
routine_two_done_list = NumberOfRoutineDone.objects.filter(
|
|||
|
gymnast=gymnast_id, routine_type=2
|
|||
|
).order_by("date")
|
|||
|
intensity_list = Intensity.objects.filter(gymnast=gymnast_id).order_by("date")
|
|||
|
|
|||
|
context = {
|
|||
|
"ghr_list": ghr_list,
|
|||
|
"has_routine_1": has_routine_1,
|
|||
|
"has_routine_2": has_routine_2,
|
|||
|
"has_routine_3": has_routine_3,
|
|||
|
"has_routine_4": has_routine_4,
|
|||
|
"has_routine_5": has_routine_5,
|
|||
|
"routine_one_done_list": routine_one_done_list,
|
|||
|
"routine_two_done_list": routine_two_done_list,
|
|||
|
"intensity_list": intensity_list,
|
|||
|
"gymnast_id": gymnast_id,
|
|||
|
}
|
|||
|
return render(request, "gymnasts/tabs/tab_routines_and_routine_stats.html", context)
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET", "POST"])
|
|||
|
def link_routine_to_gymnast(request, gymnast_id=None):
|
|||
|
""" """
|
|||
|
|
|||
|
if gymnast_id:
|
|||
|
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
|
|||
|
data = {
|
|||
|
"gymnast": gymnast_id,
|
|||
|
"gymnast_related": str(gymnast),
|
|||
|
"date_end": None,
|
|||
|
}
|
|||
|
else:
|
|||
|
gymnast = None
|
|||
|
data = {"date_end": None}
|
|||
|
|
|||
|
if request.method == "POST":
|
|||
|
form = GymnastHasRoutineForm(request.POST)
|
|||
|
|
|||
|
if form.is_valid():
|
|||
|
form.save()
|
|||
|
if not gymnast:
|
|||
|
gymnast = get_object_or_404(Gymnast, pk=form.cleaned_data["gymnast"])
|
|||
|
send_mail(
|
|||
|
"Nouvelle série",
|
|||
|
"Une nouvelle série vous a été associée.",
|
|||
|
settings.EMAIL_HOST_USER,
|
|||
|
[gymnast.user.email, gymnast.email_trainer],
|
|||
|
fail_silently=False,
|
|||
|
html_message="""<p>Bonjour,</p>
|
|||
|
<p>Une nouvelle série vous a été associée.</p><br />
|
|||
|
<p>Excellente journée</p><p>Jarvis</p>""",
|
|||
|
)
|
|||
|
|
|||
|
return HttpResponseRedirect(
|
|||
|
reverse("gymnast_details_tab", args=(gymnast_id, "routine"))
|
|||
|
)
|
|||
|
|
|||
|
else:
|
|||
|
form = GymnastHasRoutineForm(instance=gymnast, initial=data)
|
|||
|
|
|||
|
context = {"form": form, "gymnast_id": gymnast_id}
|
|||
|
return render(request, "gymnasts/link_to_routine.html", context)
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET", "POST"])
|
|||
|
def gymnast_create_or_update(request, gymnast_id=None):
|
|||
|
"""
|
|||
|
Formulaire de creation et modification d'un gymnaste.
|
|||
|
"""
|
|||
|
|
|||
|
if gymnast_id:
|
|||
|
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
|
|||
|
else:
|
|||
|
gymnast = None
|
|||
|
|
|||
|
if request.method == "POST":
|
|||
|
gymnast_form = GymnastForm(request.POST, instance=gymnast)
|
|||
|
|
|||
|
if gymnast_form.is_valid():
|
|||
|
gymnast = gymnast_form.save()
|
|||
|
form_data = request.POST.dict()
|
|||
|
user_data = {}
|
|||
|
user_data["first_name"] = form_data["first_name"]
|
|||
|
user_data["last_name"] = form_data["last_name"]
|
|||
|
user_data["username"] = (
|
|||
|
form_data["first_name"].lower() + "_" + form_data["last_name"].lower()
|
|||
|
)
|
|||
|
user_data["email"] = form_data["email"].lower()
|
|||
|
user_data["is_active"] = True
|
|||
|
user_form = UserForm(user_data, instance=gymnast.user)
|
|||
|
|
|||
|
if user_form.is_valid():
|
|||
|
user = user_form.save()
|
|||
|
|
|||
|
gymnast_group, _ = Group.objects.get_or_create(name="gymnast")
|
|||
|
user.groups.add(gymnast_group)
|
|||
|
gymnast.user = user
|
|||
|
gymnast.save()
|
|||
|
|
|||
|
# if not user.has_usable_password():
|
|||
|
# user.set_password(gymnast.last_name.lower() + _ + str(gymnast.birthdate)[-2:])
|
|||
|
|
|||
|
return HttpResponseRedirect(reverse("gymnast_details", args=(gymnast.pk,)))
|
|||
|
else:
|
|||
|
return render(
|
|||
|
request, "people/gymnasts/create.html", {"form": gymnast_form}
|
|||
|
)
|
|||
|
|
|||
|
form = GymnastForm(instance=gymnast)
|
|||
|
context = {"form": form, "gymnast_id": gymnast_id}
|
|||
|
return render(request, "gymnasts/create.html", context)
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET"])
|
|||
|
def gymnast_display_skill(request, gymnast_id):
|
|||
|
"""Tag affichant les statistiques de skill d'un gymnaste
|
|||
|
|
|||
|
Le nombre de saut qu'il sait faire (total, par niveau, par rank, …), calcule la complétude, …
|
|||
|
|
|||
|
.. todo:: Générer UNE fois la liste de skill que le gymnaste ne sait pas faire (1 query)
|
|||
|
et les counts puis, dans le template on parcourt plusieurs fois cette même liste mais on
|
|||
|
affiche conditionnellement (par age, par rank, ...)
|
|||
|
|
|||
|
Il y a 4 étapes dans l'apprentissage :
|
|||
|
- skill confusion syndrom "No" - 0
|
|||
|
- avec aide (tapis, manip, …) "with help" - 1
|
|||
|
- sans aide () "without help" - 2
|
|||
|
- enchaîné (un saut avec et après) "chained" - 3
|
|||
|
- maitrisé (dans n'importe quelle condition) "masterised" - 4
|
|||
|
"""
|
|||
|
|
|||
|
context = {}
|
|||
|
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
|
|||
|
gymnast_nb_known_skills = gymnast.known_skills.distinct("skill").count()
|
|||
|
context = gymnast.get_informations_from_type("level")
|
|||
|
context.update(gymnast.get_informations_from_type("rank"))
|
|||
|
|
|||
|
planned_skill = (
|
|||
|
Plan.objects.filter(gymnast=gymnast.id, educative__in=(Skill.objects.all()))
|
|||
|
.select_related("educative", "educative__skill")
|
|||
|
.order_by("-date", "educative__long_label")
|
|||
|
)
|
|||
|
|
|||
|
context["planned_skill"] = planned_skill
|
|||
|
|
|||
|
if gymnast.gender:
|
|||
|
context["skill_by_age"] = Skill.objects.filter(
|
|||
|
age_girl_masterised__lte=gymnast.age
|
|||
|
).exclude(known_by__gymnast=gymnast.id)
|
|||
|
else:
|
|||
|
context["skill_by_age"] = Skill.objects.filter(
|
|||
|
age_boy_masterised__lte=gymnast.age
|
|||
|
).exclude(known_by__gymnast=gymnast.id)
|
|||
|
|
|||
|
learned_skills = (
|
|||
|
LearnedSkill.objects.filter(gymnast=gymnast_id)
|
|||
|
.select_related("skill")
|
|||
|
.order_by("skill_id", "-date")
|
|||
|
.distinct("skill_id")
|
|||
|
)
|
|||
|
|
|||
|
# skill_learned_by_phase = [[]] * 5
|
|||
|
# print(skill_learned_by_phase)
|
|||
|
confused_skill = list()
|
|||
|
skill_whith_help = list()
|
|||
|
skill_without_help = list()
|
|||
|
skill_chained = list()
|
|||
|
skill_masterised = list()
|
|||
|
for learned_skill in learned_skills:
|
|||
|
# print('Add skill for ' + str(learned_skill.learning_step) + ' phase')
|
|||
|
# skill_learned_by_phase[learned_skill.learning_step].append(learned_skill.skill)
|
|||
|
if learned_skill.learning_step == 0:
|
|||
|
confused_skill.append(learned_skill.skill)
|
|||
|
elif learned_skill.learning_step == 1:
|
|||
|
skill_whith_help.append(learned_skill.skill)
|
|||
|
elif learned_skill.learning_step == 2:
|
|||
|
skill_without_help.append(learned_skill.skill)
|
|||
|
elif learned_skill.learning_step == 3:
|
|||
|
skill_chained.append(learned_skill.skill)
|
|||
|
else:
|
|||
|
skill_masterised.append(learned_skill.skill)
|
|||
|
|
|||
|
# for i in range(0,4):
|
|||
|
# print(skill_learned_by_phase[i])
|
|||
|
|
|||
|
# context["confused_skill"] = skill_learned_by_phase[0]
|
|||
|
# context["skill_whith_help"] = skill_learned_by_phase[1]
|
|||
|
# context["skill_without_help"] = skill_learned_by_phase[2]
|
|||
|
# context["skill_chained"] = skill_learned_by_phase[3]
|
|||
|
# context["skill_masterised"] = skill_learned_by_phase[4]
|
|||
|
context["confused_skill"] = confused_skill
|
|||
|
context["skill_whith_help"] = skill_whith_help
|
|||
|
context["skill_without_help"] = skill_without_help
|
|||
|
context["skill_chained"] = skill_chained
|
|||
|
context["skill_masterised"] = skill_masterised
|
|||
|
|
|||
|
context["gymnast"] = gymnast
|
|||
|
context["gymnast_nb_known_skills"] = gymnast_nb_known_skills
|
|||
|
context["user_is_trainer"] = request.user.groups.filter(
|
|||
|
name="trainer"
|
|||
|
).exists() # TODO: utiliser les {{ perms }}
|
|||
|
return render(request, "gymnasts/tabs/tab_skill.html", context)
|
|||
|
|
|||
|
|
|||
|
def analyse_score(value, value_list):
|
|||
|
"""Analyse une value (value) par rapport à la moyenne de value_list et à la dernière
|
|||
|
valeur de value_list.
|
|||
|
|
|||
|
Args:
|
|||
|
value float valeur
|
|||
|
value_list array<float> liste de valeurs
|
|||
|
|
|||
|
Returns:
|
|||
|
string
|
|||
|
|
|||
|
Examples:
|
|||
|
"""
|
|||
|
result = ""
|
|||
|
mean_value = mean(value_list)
|
|||
|
|
|||
|
if value > value_list[-1]:
|
|||
|
result += "+"
|
|||
|
elif value < value_list[-1]:
|
|||
|
result += "-"
|
|||
|
else:
|
|||
|
result += "="
|
|||
|
|
|||
|
if value > mean_value:
|
|||
|
result = "+" + result
|
|||
|
elif value < mean_value:
|
|||
|
result = "-" + result
|
|||
|
else:
|
|||
|
result = "=" + result
|
|||
|
|
|||
|
return result
|
|||
|
|
|||
|
|
|||
|
def __get_distinct_followup_season_for_gymnast(gymnast_id):
|
|||
|
"""Recupère les saisons pour lesquelles le gymnastes à des followup."""
|
|||
|
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
|
|||
|
season_list = list(
|
|||
|
gymnast.chronos.values_list("season", flat=True)
|
|||
|
.distinct("season")
|
|||
|
.order_by("season")
|
|||
|
)
|
|||
|
season_list += list(
|
|||
|
gymnast.accident.values_list("season", flat=True)
|
|||
|
.distinct("season")
|
|||
|
.order_by("season")
|
|||
|
)
|
|||
|
season_list += list(
|
|||
|
gymnast.known_skills.values_list("season", flat=True)
|
|||
|
.distinct("season")
|
|||
|
.order_by("season")
|
|||
|
)
|
|||
|
season_list += list(
|
|||
|
gymnast.todo.values_list("season", flat=True)
|
|||
|
.distinct("season")
|
|||
|
.order_by("season")
|
|||
|
)
|
|||
|
season_list += list(
|
|||
|
gymnast.mindstate.values_list("season", flat=True)
|
|||
|
.distinct("season")
|
|||
|
.order_by("season")
|
|||
|
)
|
|||
|
season_list += list(
|
|||
|
gymnast.number_of_routine_done.values_list("season", flat=True)
|
|||
|
.distinct("season")
|
|||
|
.order_by("season")
|
|||
|
)
|
|||
|
season_list += list(
|
|||
|
gymnast.height_weight.values_list("season", flat=True)
|
|||
|
.distinct("season")
|
|||
|
.order_by("season")
|
|||
|
)
|
|||
|
season_list += list(
|
|||
|
gymnast.remarks.values_list("season", flat=True)
|
|||
|
.distinct("season")
|
|||
|
.order_by("season")
|
|||
|
)
|
|||
|
season_list += list(
|
|||
|
gymnast.intensities.values_list("season", flat=True)
|
|||
|
.distinct("season")
|
|||
|
.order_by("season")
|
|||
|
)
|
|||
|
return list(dict.fromkeys(season_list))
|
|||
|
|
|||
|
|
|||
|
def __get_distinct_week_number_for_season_and_gymnast(gymnast_id, season):
|
|||
|
"""Récupère les numéro de semaines pour lesquelles le gymnaste à des followup."""
|
|||
|
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
|
|||
|
weeknumber_list = list(
|
|||
|
gymnast.chronos.values_list("week_number", flat=True)
|
|||
|
.filter(season=season)
|
|||
|
.distinct("week_number")
|
|||
|
.order_by("week_number")
|
|||
|
)
|
|||
|
weeknumber_list += list(
|
|||
|
gymnast.accident.values_list("week_number", flat=True)
|
|||
|
.filter(season=season)
|
|||
|
.distinct("week_number")
|
|||
|
.order_by("week_number")
|
|||
|
)
|
|||
|
weeknumber_list += list(
|
|||
|
gymnast.known_skills.values_list("week_number", flat=True)
|
|||
|
.filter(season=season)
|
|||
|
.distinct("week_number")
|
|||
|
.order_by("week_number")
|
|||
|
)
|
|||
|
weeknumber_list += list(
|
|||
|
gymnast.todo.values_list("week_number", flat=True)
|
|||
|
.filter(season=season)
|
|||
|
.distinct("week_number")
|
|||
|
.order_by("week_number")
|
|||
|
)
|
|||
|
weeknumber_list += list(
|
|||
|
gymnast.mindstate.values_list("week_number", flat=True)
|
|||
|
.filter(season=season)
|
|||
|
.distinct("week_number")
|
|||
|
.order_by("week_number")
|
|||
|
)
|
|||
|
weeknumber_list += list(
|
|||
|
gymnast.number_of_routine_done.values_list("week_number", flat=True)
|
|||
|
.filter(season=season)
|
|||
|
.distinct("week_number")
|
|||
|
.order_by("week_number")
|
|||
|
)
|
|||
|
weeknumber_list += list(
|
|||
|
gymnast.height_weight.values_list("week_number", flat=True)
|
|||
|
.filter(season=season)
|
|||
|
.distinct("week_number")
|
|||
|
.order_by("week_number")
|
|||
|
)
|
|||
|
weeknumber_list += list(
|
|||
|
gymnast.remarks.values_list("week_number", flat=True)
|
|||
|
.filter(season=season)
|
|||
|
.distinct("week_number")
|
|||
|
.order_by("week_number")
|
|||
|
)
|
|||
|
weeknumber_list += list(
|
|||
|
gymnast.intensities.values_list("week_number", flat=True)
|
|||
|
.filter(season=season)
|
|||
|
.distinct("week_number")
|
|||
|
.order_by("week_number")
|
|||
|
)
|
|||
|
return list(dict.fromkeys(weeknumber_list))
|
|||
|
|
|||
|
|
|||
|
def get_distinct_week_number_for_season_and_gymnast(gymnast_id, season):
|
|||
|
""" """
|
|||
|
if not season:
|
|||
|
season = Season()
|
|||
|
|
|||
|
weeknumber_list = __get_distinct_week_number_for_season_and_gymnast(
|
|||
|
gymnast_id, season
|
|||
|
)
|
|||
|
return JsonResponse(weeknumber_list, safe=False)
|
|||
|
|
|||
|
|
|||
|
@require_http_methods(["GET"])
|
|||
|
def report_choice(request, gymnast_id):
|
|||
|
"""Recupère les saisons pour lesquelles le gymnastes à des followup."""
|
|||
|
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
|
|||
|
|
|||
|
today = pendulum.now().date()
|
|||
|
season, week_number = from_date_to_week_number(today)
|
|||
|
|
|||
|
season_list = __get_distinct_followup_season_for_gymnast(gymnast_id)
|
|||
|
week_number_list = sorted(
|
|||
|
__get_distinct_week_number_for_season_and_gymnast(gymnast_id, season)
|
|||
|
)
|
|||
|
context = {
|
|||
|
"gymnast": gymnast,
|
|||
|
"season": season,
|
|||
|
"season_list": season_list,
|
|||
|
"week_number": week_number,
|
|||
|
"week_number_list": week_number_list,
|
|||
|
}
|
|||
|
return render(request, "gymnasts/report_choices.html", context)
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET"])
|
|||
|
def generate_week_report(request, gymnast_id, season=None, week_number=None):
|
|||
|
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
|
|||
|
|
|||
|
if season is None:
|
|||
|
date_begin = pendulum.now().date()
|
|||
|
season, week_number = from_date_to_week_number(date_begin)
|
|||
|
else:
|
|||
|
date_begin, _ = from_week_number_to_date(season, week_number)
|
|||
|
date_begin = date_begin.date()
|
|||
|
|
|||
|
#
|
|||
|
# PHYSIOLOGICAL INFORMATIONS
|
|||
|
#
|
|||
|
# Mindstate Score
|
|||
|
mindstate_week_score = (
|
|||
|
gymnast.mindstate.filter(season=season)
|
|||
|
.filter(week_number=week_number)
|
|||
|
.aggregate(mean_mindstate_value=Avg("score"))
|
|||
|
)
|
|||
|
|
|||
|
mindstate_queryset = MindState.objects.filter(gymnast=gymnast).order_by("-date")
|
|||
|
have_physiological = False
|
|||
|
if mindstate_week_score["mean_mindstate_value"]:
|
|||
|
lasts_mindstate = list(mindstate_queryset.values_list("score", flat=True)[1:6])
|
|||
|
mindstate_analyse = analyse_score(
|
|||
|
mindstate_week_score["mean_mindstate_value"], lasts_mindstate
|
|||
|
)
|
|||
|
else:
|
|||
|
mindstate_analyse = None
|
|||
|
|
|||
|
height_weight_week_value = (
|
|||
|
gymnast.height_weight.filter(season=season)
|
|||
|
.filter(week_number=week_number)
|
|||
|
.aggregate(mean_height_value=Avg("height"), mean_weight_value=Avg("weight"))
|
|||
|
)
|
|||
|
|
|||
|
height_weight_queryset = HeightWeight.objects.filter(gymnast=gymnast).order_by(
|
|||
|
"-date"
|
|||
|
)
|
|||
|
|
|||
|
if height_weight_week_value["mean_height_value"]:
|
|||
|
lasts_height = list(
|
|||
|
height_weight_queryset.values_list("height", flat=True)[1:6]
|
|||
|
)
|
|||
|
height_analyse = analyse_score(
|
|||
|
height_weight_week_value["mean_height_value"], lasts_height
|
|||
|
)
|
|||
|
else:
|
|||
|
height_analyse = None
|
|||
|
|
|||
|
if height_weight_week_value["mean_weight_value"]:
|
|||
|
lasts_weight = list(
|
|||
|
height_weight_queryset.values_list("weight", flat=True)[1:6]
|
|||
|
)
|
|||
|
weight_analyse = analyse_score(
|
|||
|
height_weight_week_value["mean_weight_value"], lasts_weight
|
|||
|
)
|
|||
|
else:
|
|||
|
weight_analyse = None
|
|||
|
|
|||
|
intensity_week_value = (
|
|||
|
gymnast.intensities.filter(season=season)
|
|||
|
.filter(week_number=week_number)
|
|||
|
.aggregate(
|
|||
|
mean_intensity_time__value=Avg("time"),
|
|||
|
mean_intensity_difficulty_value=Avg("difficulty"),
|
|||
|
mean_quantity_of_skill_value=Avg("quantity_of_skill"),
|
|||
|
mean_number_of_passes_value=Avg("number_of_passes"),
|
|||
|
)
|
|||
|
)
|
|||
|
|
|||
|
#
|
|||
|
# BEST TOF
|
|||
|
#
|
|||
|
best_tof_straightjump = (
|
|||
|
Chrono.objects.filter(gymnast=gymnast)
|
|||
|
.filter(chrono_type=0)
|
|||
|
.order_by("-score")
|
|||
|
.first()
|
|||
|
)
|
|||
|
best_tof_routine_1 = (
|
|||
|
Chrono.objects.filter(gymnast=gymnast)
|
|||
|
.filter(chrono_type=1)
|
|||
|
.order_by("-score")
|
|||
|
.first()
|
|||
|
)
|
|||
|
best_tof_routine_2 = (
|
|||
|
Chrono.objects.filter(gymnast=gymnast)
|
|||
|
.filter(chrono_type=2)
|
|||
|
.order_by("-score")
|
|||
|
.first()
|
|||
|
)
|
|||
|
|
|||
|
#
|
|||
|
# BEST SCORES
|
|||
|
#
|
|||
|
best_point_routine_1 = (
|
|||
|
Point.objects.filter(gymnast=gymnast)
|
|||
|
.filter(routine_type=1)
|
|||
|
.order_by("-total")
|
|||
|
.first()
|
|||
|
)
|
|||
|
best_point_routine_2 = (
|
|||
|
Point.objects.filter(gymnast=gymnast)
|
|||
|
.filter(routine_type=2)
|
|||
|
.order_by("-total")
|
|||
|
.first()
|
|||
|
)
|
|||
|
best_point_routine_3 = (
|
|||
|
Point.objects.filter(gymnast=gymnast)
|
|||
|
.filter(routine_type=3)
|
|||
|
.order_by("-total")
|
|||
|
.first()
|
|||
|
)
|
|||
|
best_point_routine_4 = (
|
|||
|
Point.objects.filter(gymnast=gymnast)
|
|||
|
.filter(routine_type=4)
|
|||
|
.order_by("-total")
|
|||
|
.first()
|
|||
|
)
|
|||
|
best_point_routine_5 = (
|
|||
|
Point.objects.filter(gymnast=gymnast)
|
|||
|
.filter(routine_type=5)
|
|||
|
.order_by("-total")
|
|||
|
.first()
|
|||
|
)
|
|||
|
|
|||
|
#
|
|||
|
# ROUTINES
|
|||
|
#
|
|||
|
routine_1 = (
|
|||
|
gymnast.has_routine.filter(routine_type=1)
|
|||
|
.filter(date_begin__lte=date_begin)
|
|||
|
.filter(Q(date_end__gte=date_begin) | Q(date_end__isnull=True))
|
|||
|
.first()
|
|||
|
)
|
|||
|
routine_1_done_stat = (
|
|||
|
gymnast.number_of_routine_done.filter(routine_type=1)
|
|||
|
.filter(season=season)
|
|||
|
.filter(week_number=week_number)
|
|||
|
.aggregate(
|
|||
|
total_try=Sum("number_of_try"), total_succeeded=Sum("number_of_successes")
|
|||
|
)
|
|||
|
)
|
|||
|
|
|||
|
routine_2 = (
|
|||
|
gymnast.has_routine.filter(routine_type=2)
|
|||
|
.filter(date_begin__lte=date_begin)
|
|||
|
.filter(Q(date_end__gte=date_begin) | Q(date_end__isnull=True))
|
|||
|
.first()
|
|||
|
)
|
|||
|
routine_2_done_stat = (
|
|||
|
gymnast.number_of_routine_done.filter(routine_type=2)
|
|||
|
.filter(season=season)
|
|||
|
.filter(week_number=week_number)
|
|||
|
.aggregate(
|
|||
|
total_try=Sum("number_of_try"), total_succeeded=Sum("number_of_successes")
|
|||
|
)
|
|||
|
)
|
|||
|
|
|||
|
routine_3 = (
|
|||
|
gymnast.has_routine.filter(routine_type=3)
|
|||
|
.filter(date_begin__lte=date_begin)
|
|||
|
.filter(Q(date_end__gte=date_begin) | Q(date_end__isnull=True))
|
|||
|
.first()
|
|||
|
)
|
|||
|
routine_3_done_stat = (
|
|||
|
gymnast.number_of_routine_done.filter(routine_type=3)
|
|||
|
.filter(season=season)
|
|||
|
.filter(week_number=week_number)
|
|||
|
.aggregate(
|
|||
|
total_try=Sum("number_of_try"), total_succeeded=Sum("number_of_successes")
|
|||
|
)
|
|||
|
)
|
|||
|
|
|||
|
routine_4 = (
|
|||
|
gymnast.has_routine.filter(routine_type=4)
|
|||
|
.filter(date_begin__lte=date_begin)
|
|||
|
.filter(Q(date_end__gte=date_begin) | Q(date_end__isnull=True))
|
|||
|
.first()
|
|||
|
)
|
|||
|
routine_4_done_stat = (
|
|||
|
gymnast.number_of_routine_done.filter(routine_type=4)
|
|||
|
.filter(season=season)
|
|||
|
.filter(week_number=week_number)
|
|||
|
.aggregate(
|
|||
|
total_try=Sum("number_of_try"), total_succeeded=Sum("number_of_successes")
|
|||
|
)
|
|||
|
)
|
|||
|
|
|||
|
routine_5 = (
|
|||
|
gymnast.has_routine.filter(routine_type=5)
|
|||
|
.filter(date_begin__lte=date_begin)
|
|||
|
.filter(Q(date_end__gte=date_begin) | Q(date_end__isnull=True))
|
|||
|
.first()
|
|||
|
)
|
|||
|
routine_5_done_stat = (
|
|||
|
gymnast.number_of_routine_done.filter(routine_type=5)
|
|||
|
.filter(season=season)
|
|||
|
.filter(week_number=week_number)
|
|||
|
.aggregate(
|
|||
|
total_try=Sum("number_of_try"), total_succeeded=Sum("number_of_successes")
|
|||
|
)
|
|||
|
)
|
|||
|
|
|||
|
#
|
|||
|
# LAST LEARNED SKILLS
|
|||
|
#
|
|||
|
# TODO: il faudrait que ce soit classer d'abord par DATE et pas par skill.
|
|||
|
#
|
|||
|
# learned_skills = (
|
|||
|
# LearnedSkill.objects.filter(gymnast=gymnast.id)
|
|||
|
# .annotate(skill_notation=F("skill__notation"))
|
|||
|
# .order_by("skill_notation", "-date")
|
|||
|
# .distinct("skill_notation")[:6]
|
|||
|
# )
|
|||
|
learned_skills = LearnedSkill.objects.filter(gymnast=gymnast.id).order_by("-date")[
|
|||
|
:6
|
|||
|
]
|
|||
|
|
|||
|
#
|
|||
|
# PLANNED SKILLS
|
|||
|
#
|
|||
|
plan_list = (
|
|||
|
Plan.objects.filter(gymnast=gymnast, educative__in=(Skill.objects.all()))
|
|||
|
.filter(Q(is_done=False) | Q(date__gte=date.today()))
|
|||
|
.order_by("educative", "-date")
|
|||
|
.distinct()[:6]
|
|||
|
)
|
|||
|
|
|||
|
#
|
|||
|
# NEXT EVENTS
|
|||
|
#
|
|||
|
next_event_list = Event.objects.filter(
|
|||
|
gymnasts=gymnast.id, date_begin__gte=date_begin
|
|||
|
).order_by("date_begin")[:5]
|
|||
|
|
|||
|
#
|
|||
|
# NOTES
|
|||
|
#
|
|||
|
begin_of_the_week = date_begin
|
|||
|
if date_begin.weekday() != 0:
|
|||
|
begin_of_the_week -= timedelta(date_begin.weekday())
|
|||
|
|
|||
|
notes = (
|
|||
|
gymnast.remarks.filter(date__gte=begin_of_the_week)
|
|||
|
.filter(status=1)
|
|||
|
.order_by("date")
|
|||
|
)
|
|||
|
|
|||
|
context = {
|
|||
|
"SITE_TITLE": settings.SITE_TITLE,
|
|||
|
"CLUB_NAME": settings.CLUB_NAME,
|
|||
|
"ADDRESS": settings.ADDRESS,
|
|||
|
"CITY": settings.CITY,
|
|||
|
"ZIP": settings.ZIP,
|
|||
|
"HEAD_COACH": settings.HEAD_COACH,
|
|||
|
"MOBILE_PHONE": settings.MOBILE_PHONE,
|
|||
|
"HEAD_COACH_EMAIL": settings.HEAD_COACH_EMAIL,
|
|||
|
"week_number": week_number,
|
|||
|
"gymnast": gymnast,
|
|||
|
"today": date_begin,
|
|||
|
"season": season,
|
|||
|
"last_mindstate": mindstate_week_score["mean_mindstate_value"],
|
|||
|
"mindstate_analyse": mindstate_analyse,
|
|||
|
"last_height": height_weight_week_value["mean_height_value"],
|
|||
|
"last_weigth": height_weight_week_value["mean_weight_value"],
|
|||
|
"height_analyse": height_analyse,
|
|||
|
"weight_analyse": weight_analyse,
|
|||
|
"best_tof_straightjump": best_tof_straightjump,
|
|||
|
"best_tof_routine_1": best_tof_routine_1,
|
|||
|
"best_tof_routine_2": best_tof_routine_2,
|
|||
|
"best_point_routine_1": best_point_routine_1,
|
|||
|
"best_point_routine_2": best_point_routine_2,
|
|||
|
"best_point_routine_3": best_point_routine_3,
|
|||
|
"best_point_routine_4": best_point_routine_4,
|
|||
|
"best_point_routine_5": best_point_routine_5,
|
|||
|
"routine_1": routine_1,
|
|||
|
"routine_2": routine_2,
|
|||
|
"routine_3": routine_3,
|
|||
|
"routine_4": routine_4,
|
|||
|
"routine_5": routine_5,
|
|||
|
"routine_1_done_stat": routine_1_done_stat,
|
|||
|
"routine_2_done_stat": routine_2_done_stat,
|
|||
|
"routine_3_done_stat": routine_3_done_stat,
|
|||
|
"routine_4_done_stat": routine_4_done_stat,
|
|||
|
"routine_5_done_stat": routine_5_done_stat,
|
|||
|
"LEARNING_STEP_CHOICES": LEARNING_STEP_CHOICES,
|
|||
|
"learned_skills": learned_skills,
|
|||
|
"plan_list": plan_list,
|
|||
|
"next_event_list": next_event_list,
|
|||
|
"notes": notes,
|
|||
|
}
|
|||
|
|
|||
|
# return render(request, "gymnasts/reports/report_week.html", context)
|
|||
|
|
|||
|
response = HttpResponse(content_type="application/pdf")
|
|||
|
response[
|
|||
|
"Content-Disposition"
|
|||
|
] = "attachment; filename={lastname}-{firstname}-report.pdf".format(
|
|||
|
lastname=gymnast.last_name,
|
|||
|
firstname=gymnast.first_name,
|
|||
|
)
|
|||
|
|
|||
|
html = render_to_string("people/gymnasts/reports/report_week.html", context)
|
|||
|
|
|||
|
# font_config = FontConfiguration()
|
|||
|
HTML(string=html, base_url=request.build_absolute_uri()).write_pdf(
|
|||
|
response,
|
|||
|
stylesheets=[
|
|||
|
CSS(settings.STATICFILES_DIRS[0] + "/css/gymnast_report.css"),
|
|||
|
CSS(settings.STATICFILES_DIRS[0] + "/css/black-dashboard_report.css"),
|
|||
|
CSS(settings.STATICFILES_DIRS[0] + "/css/font_awesome_all_5.15.3.css"),
|
|||
|
],
|
|||
|
) # , font_config=font_config)
|
|||
|
return response
|
|||
|
|
|||
|
|
|||
|
@login_required
|
|||
|
@require_http_methods(["GET"])
|
|||
|
def generate_timeline_report(
|
|||
|
request, gymnast_id, season=None, week_number=None, date=None
|
|||
|
):
|
|||
|
"""Génère une timeline pour un gymnaste. On va chercher tous les
|
|||
|
- records (Chrono/ToF),
|
|||
|
- points (compétition),
|
|||
|
- nouveau apprentissage (learned skill)
|
|||
|
- accident
|
|||
|
- GymnastHasRoutine
|
|||
|
eton les trie par date.
|
|||
|
|
|||
|
"""
|
|||
|
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
|
|||
|
|
|||
|
if season is None:
|
|||
|
date_begin = pendulum.now().date()
|
|||
|
season, week_number = from_date_to_week_number(date_begin)
|
|||
|
else:
|
|||
|
date_begin, _ = from_week_number_to_date(season, week_number)
|
|||
|
date_begin = date_begin.date()
|
|||
|
|
|||
|
selected_record = []
|
|||
|
|
|||
|
list_record_straightjumps = list(
|
|||
|
gymnast.chronos.filter(chrono_type=0).order_by("date")
|
|||
|
)
|
|||
|
last_top_score = 0
|
|||
|
for record in list_record_straightjumps:
|
|||
|
if record.score > last_top_score:
|
|||
|
last_top_score = record.score
|
|||
|
selected_record.append(record)
|
|||
|
|
|||
|
list_record_first_routine = list(
|
|||
|
gymnast.chronos.filter(chrono_type=1).order_by("date")
|
|||
|
)
|
|||
|
last_top_score = 0
|
|||
|
for record in list_record_first_routine:
|
|||
|
if record.score > last_top_score:
|
|||
|
last_top_score = record.score
|
|||
|
selected_record.append(record)
|
|||
|
|
|||
|
list_record_second_routine = list(
|
|||
|
gymnast.chronos.filter(chrono_type=2).order_by("date")
|
|||
|
)
|
|||
|
last_top_score = 0
|
|||
|
for record in list_record_second_routine:
|
|||
|
if record.score > last_top_score:
|
|||
|
last_top_score = record.score
|
|||
|
selected_record.append(record)
|
|||
|
|
|||
|
list_record_third_routine = list(
|
|||
|
gymnast.chronos.filter(chrono_type=3).order_by("date")
|
|||
|
)
|
|||
|
last_top_score = 0
|
|||
|
for record in list_record_third_routine:
|
|||
|
if record.score > last_top_score:
|
|||
|
last_top_score = record.score
|
|||
|
selected_record.append(record)
|
|||
|
|
|||
|
list_record_fourth_routine = list(
|
|||
|
gymnast.chronos.filter(chrono_type=4).order_by("date")
|
|||
|
)
|
|||
|
last_top_score = 0
|
|||
|
for record in list_record_fourth_routine:
|
|||
|
if record.score > last_top_score:
|
|||
|
last_top_score = record.score
|
|||
|
selected_record.append(record)
|
|||
|
|
|||
|
list_record_fifth_routine = list(
|
|||
|
gymnast.chronos.filter(chrono_type=5).order_by("date")
|
|||
|
)
|
|||
|
last_top_score = 0
|
|||
|
for record in list_record_fifth_routine:
|
|||
|
if record.score > last_top_score:
|
|||
|
last_top_score = record.score
|
|||
|
selected_record.append(record)
|
|||
|
|
|||
|
# print(selected_record)
|
|||
|
list_record = selected_record
|
|||
|
list_record.extend(list(gymnast.accident.all().order_by("date")))
|
|||
|
# list_record.extend(list(gymnast.points.all().order_by("date")))
|
|||
|
list_record.extend(list(gymnast.known_skills.all().order_by("date")))
|
|||
|
|
|||
|
# print(list_record)
|
|||
|
sorted_records = sorted(list_record, key=lambda x: x.date)
|
|||
|
# print(sorted_records)
|
|||
|
context = {
|
|||
|
"SITE_TITLE": settings.SITE_TITLE,
|
|||
|
"CLUB_NAME": settings.CLUB_NAME,
|
|||
|
"ADDRESS": settings.ADDRESS,
|
|||
|
"CITY": settings.CITY,
|
|||
|
"ZIP": settings.ZIP,
|
|||
|
"HEAD_COACH": settings.HEAD_COACH,
|
|||
|
"MOBILE_PHONE": settings.MOBILE_PHONE,
|
|||
|
"HEAD_COACH_EMAIL": settings.HEAD_COACH_EMAIL,
|
|||
|
"week_number": week_number,
|
|||
|
"gymnast": gymnast,
|
|||
|
"today": date_begin,
|
|||
|
"season": season,
|
|||
|
"sorted_records": sorted_records,
|
|||
|
}
|
|||
|
# return render(request, "gymnasts/reports/report_timeline.html", context)
|
|||
|
response = HttpResponse(content_type="application/pdf")
|
|||
|
response[
|
|||
|
"Content-Disposition"
|
|||
|
] = "attachment; filename={lastname}-{firstname}-report-timeline.pdf".format(
|
|||
|
lastname=gymnast.last_name,
|
|||
|
firstname=gymnast.first_name,
|
|||
|
)
|
|||
|
|
|||
|
html = render_to_string("gymnasts/reports/report_timeline.html", context)
|
|||
|
|
|||
|
# font_config = FontConfiguration()
|
|||
|
HTML(string=html, base_url=request.build_absolute_uri()).write_pdf(
|
|||
|
response,
|
|||
|
stylesheets=[
|
|||
|
CSS(settings.STATICFILES_DIRS[0] + "/css/gymnast_report.css"),
|
|||
|
CSS(settings.STATICFILES_DIRS[0] + "/css/black-dashboard_report.css"),
|
|||
|
CSS(settings.STATICFILES_DIRS[0] + "/css/font_awesome_all_5.15.3.css"),
|
|||
|
],
|
|||
|
) # , font_config=font_config)
|
|||
|
return response
|