From 4237a957ddce268c91886b1b38691b0bef4b953b Mon Sep 17 00:00:00 2001 From: Gregory Trullemans Date: Sun, 16 Oct 2022 18:23:36 +0200 Subject: [PATCH] Add in the generated PDF --- templates/followup/plan/create.html | 6 ++ templates/objectives/skills/create.html | 28 ++++++++++ templates/objectives/skills/details.html | 15 +++-- templates/people/gymnasts/tab_skill.html | 8 ++- ultron/followup/forms.py | 8 ++- .../migrations/0029_plan_informations.py | 23 ++++++++ ultron/followup/models.py | 5 +- ultron/tools/models.py | 4 ++ ultron/tools/pdf_generator.py | 55 ++++++++++++++++--- 9 files changed, 135 insertions(+), 17 deletions(-) create mode 100644 templates/objectives/skills/create.html create mode 100644 ultron/followup/migrations/0029_plan_informations.py diff --git a/templates/followup/plan/create.html b/templates/followup/plan/create.html index 9a61a7f3e6..95d2f18b30 100644 --- a/templates/followup/plan/create.html +++ b/templates/followup/plan/create.html @@ -47,6 +47,12 @@ {% if form.learning_step.errors %} {% for error in form.learning_step.errors %}{{error}}{% endfor %}{% endif %} +
+ +
+ {{ form.informations }} +
+
diff --git a/templates/objectives/skills/create.html b/templates/objectives/skills/create.html new file mode 100644 index 0000000000..4f6a171f54 --- /dev/null +++ b/templates/objectives/skills/create.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} + +{% block content %} +
+
+
+
+

{% if skill_id %}Edit{% else %}Add{% endif %} Skill informations

+
+
+
+ {% csrf_token %} +
+ +
+ {{ form.informations }} +
+
+
+ +
+
+
+
+
+
+ +{% endblock %} diff --git a/templates/objectives/skills/details.html b/templates/objectives/skills/details.html index 72dcd08097..f675c3dece 100644 --- a/templates/objectives/skills/details.html +++ b/templates/objectives/skills/details.html @@ -97,7 +97,10 @@ {% if skill.twist %} with {{ skill.twist }} half-twist {% endif %} - in a {{ skill.get_position_display }} position, landing on {{ skill.landing }}. + {% if skill.get_position_display %} + in a {{ skill.get_position_display }} position + {% endif %} + , landing on {{ skill.landing }}.


{% if skill.informations %} @@ -105,12 +108,16 @@ {% else %}

No more informations provided for this skill.

{% endif %} - - - + {% endblock %} diff --git a/templates/people/gymnasts/tab_skill.html b/templates/people/gymnasts/tab_skill.html index 2ef689f3af..ca40546174 100644 --- a/templates/people/gymnasts/tab_skill.html +++ b/templates/people/gymnasts/tab_skill.html @@ -107,8 +107,12 @@ {% endif %} {{ skill.notation }} - {{ skill.long_label }} - {{ skill.plan_date | date:"d-m-Y" }} + + {{ skill.long_label }} + + + {{ skill.plan_date | date:"d-m-Y" }} + {{ skill.difficulty }} {{ skill.level }} {{ skill.rank }} diff --git a/ultron/followup/forms.py b/ultron/followup/forms.py index 8a3909bba2..c53b2a7a5d 100644 --- a/ultron/followup/forms.py +++ b/ultron/followup/forms.py @@ -441,7 +441,7 @@ class PlanForm(forms.ModelForm): class Meta: model = Plan - fields = ("date", "gymnast", "educative", "learning_step", "is_done") + fields = ("date", "gymnast", "educative", "learning_step", "is_done", "informations") widgets = { "gymnast": forms.HiddenInput(), "educative": forms.HiddenInput(), @@ -456,6 +456,12 @@ class PlanForm(forms.ModelForm): "is_done": forms.CheckboxInput( attrs={"class": "form-control form-check-input ml-0 mt-0"} ), + "informations": forms.Textarea( + attrs={ + "class": "form-control", + "placeholder": "Informations about gymnast for this particular skill: usual mistake, fear, …", # pylint: disable=line-too-long + } + ), } gymnast_related = forms.CharField( diff --git a/ultron/followup/migrations/0029_plan_informations.py b/ultron/followup/migrations/0029_plan_informations.py new file mode 100644 index 0000000000..7e6a9f9a0e --- /dev/null +++ b/ultron/followup/migrations/0029_plan_informations.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.1 on 2022-10-16 06:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("followup", "0028_rename_cando_learnedskill_learning_step_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="plan", + name="informations", + field=models.TextField( + blank=True, + help_text="Only MarkDown is authorized", + null=True, + verbose_name="Comments", + ), + ), + ] diff --git a/ultron/followup/models.py b/ultron/followup/models.py index e40ee5e5e1..ff36d4fa36 100644 --- a/ultron/followup/models.py +++ b/ultron/followup/models.py @@ -169,7 +169,7 @@ class LearnedSkill(Seasonisable): updated_at = models.DateTimeField(auto_now=True) -class Plan(Seasonisable): +class Plan(Seasonisable, Markdownizable): """ Classe représentant les objectifs qu'un gymnaste devra savoir faire pour une date donnée. """ @@ -206,6 +206,9 @@ class Plan(Seasonisable): self.date, ) + # @property + # def is_due(self): + # return pendulum.now().date() > self.date class Point(models.Model): """ diff --git a/ultron/tools/models.py b/ultron/tools/models.py index 30e11016ff..7434fbcaab 100644 --- a/ultron/tools/models.py +++ b/ultron/tools/models.py @@ -91,6 +91,10 @@ class Seasonisable(models.Model): self.season, self.week_number = from_date_to_week_number(self.date) super().save(*args, **kwargs) + # @property + # def is_past(self): + # return pendulum.now().date() > self.date + class TemporizableQuerySet(models.QuerySet): """ diff --git a/ultron/tools/pdf_generator.py b/ultron/tools/pdf_generator.py index ef5cba93ae..cdb0f8afa4 100644 --- a/ultron/tools/pdf_generator.py +++ b/ultron/tools/pdf_generator.py @@ -44,7 +44,7 @@ environ.Env.read_env() X = 35 Y = 841.89 -INDENT = 5 +INDENT = 15 RIGHT_X = 595.27 - X TITLED_X = 125 INDENTED_X = X + INDENT @@ -85,6 +85,12 @@ class PDFDocument(object): self.mobile_phone = env("MOBILE_PHONE", default=None) self.coach_email = env("HEAD_COACH_EMAIL", default=None) + def new_page(self): + """ """ + # self.y = Y - X + self.document.showPage() + self.y = Y - X + def add_vspace(self, height=COMMON_LINE_HEIGHT): """ Passe à la ligne, la hauteur de la ligne étant passée en paramètre. @@ -190,11 +196,16 @@ class GymnastReportDocument(PDFDocument): self.add_gymnast_best_scores(gymnast) self.add_gymnast_active_routine(gymnast) # self.add_gymnast_level_information(gymnast) - self.add_gymnast_next_skills(gymnast) + planned_skill = self.add_gymnast_planned_skill(gymnast) + print(planned_skill) self.add_gymnast_last_learned_skill(gymnast) self.add_gymnast_next_events(gymnast) self.add_gymnast_week_notes(gymnast) + if planned_skill: + self.new_page() + self.add_planned_skills_details(planned_skill) + def add_gymnast_personnal_information(self, gymnast): """ Ajoute les informations personnelles du gymnast. @@ -563,7 +574,7 @@ class GymnastReportDocument(PDFDocument): ) - def add_gymnast_next_skills(self, gymnast): + def add_gymnast_planned_skill(self, gymnast): """ Ajoute les prochains skill (skill planifié) à apprendre Args: @@ -584,27 +595,29 @@ class GymnastReportDocument(PDFDocument): # le double F ne fonctionne qu'en précisant le distinct, sinon ca dédouble les résultats. # qui lui même ne fonctionne que sur un champ présent dans le `order_by` (que le premier champ ?) # - planified_skills = ( + planned_skills = ( Skill.objects.filter(plan__gymnast=gymnast.id) .filter( Q(plan__is_done=False) | Q(plan__date__gte=date.today()) ) # .annotate(plan_date=F("plan__date")) - .annotate(plan_date=F("plan__date"), learning_step=F("plan__learning_step")) - .order_by("notation", "-plan__date").distinct('notation')[:6] + .annotate(plan_date=F("plan__date"), learning_step=F("plan__learning_step"), plan_id=F("plan__id")) + .order_by("id", "-plan__date").distinct('id')[:6] ) - if planified_skills: - for planified_skill in planified_skills: + if planned_skills: + for planned_skill in planned_skills: self.add_new_line( - X, planified_skill.short_label + " " + str(LEARNING_STEP_CHOICES[planified_skill.learning_step][1]).lower() + " (" + planified_skill.notation + ") for " + planified_skill.plan_date.strftime("%d-%m-%Y") + X, planned_skill.short_label + " " + str(LEARNING_STEP_CHOICES[planned_skill.learning_step][1]).lower() + " (" + planned_skill.notation + ") for " + planned_skill.plan_date.strftime("%d-%m-%Y") ) else: self.add_new_line( X, "No next skill to learn plannified.", ) + print(planned_skills) + return planned_skills def add_gymnast_next_events(self, gymnast): """ Ajoute les évènements futurs du gymnaste """ @@ -678,3 +691,27 @@ class GymnastReportDocument(PDFDocument): X, "No note associated to this gymnast this week.", ) + + def add_planned_skills_details(self, planned_skills): + """ """ + # self.y = 20*cm + self.add_new_line( + X, + "Points of attention", + font_decoration="Bold", + ) + self.add_vspace(-0.5*cm) + + for planned_skill in planned_skills: + plan = Plan.objects.get(pk=planned_skill.plan_id) + + html_text = "" + planned_skill.short_label + " (" + planned_skill.notation + ") :" + paragraph = Paragraph(html_text, self.style) + width, height = paragraph.wrap(18*cm, 10*cm) + paragraph.drawOn(self.document, INDENTED_X, self.y - (height / 2)) + + self.add_new_line( + INDENTED_X, + plan.informations + ) + self.add_vspace(-0.4*cm)