Refactore accident -> injury

This commit is contained in:
Gregory Trullemans 2023-07-06 23:37:07 +02:00
parent ebc51e15d2
commit e610725345
22 changed files with 499 additions and 152 deletions

View File

@ -93,7 +93,7 @@
</li>
{% menuitem 'event_list' 'fal fa-calendar-alt' 'Events' %}
{% if request.user|has_group:"trainer" %}
{% menuitem 'accident_list' 'fal fa-comment-alt-medical' 'Accidents' %}
{% menuitem 'injuries_list' 'fal fa-comment-alt-medical' 'Injuries' %}
{% endif %}
{% menuitem 'place_list' 'fal fa-map-marked-alt' 'Places' %}
{% if request.user|has_group:"trainer" %}

View File

@ -116,7 +116,7 @@ def home(request):
Gymnast.objects.filter(chronos__created_at__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(accident__created_at__gt=request.user.last_login)
Gymnast.objects.filter(injuries__created_at__gt=request.user.last_login)
)
last_updated_gymnasts.update(
Gymnast.objects.filter(known_skills__created_at__gt=request.user.last_login)
@ -128,7 +128,7 @@ def home(request):
| Q(wellbeings__created_at__gte=limit_date)
| Q(points__created_at__gte=limit_date)
| Q(chronos__created_at__gte=limit_date)
| Q(accident__created_at__gte=limit_date)
| Q(injuries__created_at__gte=limit_date)
| Q(known_skills__created_at__gte=limit_date)
).distinct()

View File

@ -11,12 +11,13 @@ from .models import (
Note,
Point,
Chrono,
Accident,
Injury,
WellBeing,
Intensity,
HeightWeight,
LearnedSkill,
ChronoDetails,
InjuryLocation,
GymnastHasRoutine,
SeasonInformation,
NumberOfRoutineDone,
@ -91,13 +92,35 @@ class PointAdmin(admin.ModelAdmin):
autocomplete_fields = ("gymnast", "event")
class AccidentAdmin(admin.ModelAdmin):
model = Accident
class InjuryLocationAdmin(admin.ModelAdmin):
model = InjuryLocation
fields = ("date", "gymnast", "skill", "informations") # educative
list_display = ("label",)
fields = ("label",)
search_fields = ("label",)
class InjuryAdmin(admin.ModelAdmin):
model = Injury
fields = (
"date",
"gymnast",
"skill",
"location",
"body_side",
"mechanism",
"nb_week_off",
"informations",
) # educative
readonly_fields = ("season", "week_number", "created_at", "updated_at")
list_display = ("date", "gymnast", "skill") # educative
list_filter = ("date",)
list_filter = (
("gymnast", RelatedDropdownFilter),
("location", RelatedDropdownFilter),
("body_side", DropdownFilter),
("mechanism", DropdownFilter),
)
date_hierarchy = "date"
search_fields = ("date", "gymnast") # educative
autocomplete_fields = ("gymnast", "skill")
@ -274,12 +297,13 @@ admin.site.register(Plan, PlanAdmin)
admin.site.register(Note, NoteAdmin)
admin.site.register(Point, PointAdmin)
admin.site.register(Chrono, ChronoAdmin)
admin.site.register(Accident, AccidentAdmin)
admin.site.register(Injury, InjuryAdmin)
admin.site.register(WellBeing, WellBeingAdmin)
admin.site.register(Intensity, IntensityAdmin)
admin.site.register(LearnedSkill, LearnedSkillAdmin)
admin.site.register(HeightWeight, HeightWeightAdmin)
admin.site.register(ChronoDetails, ChronoDetailsAdmin)
admin.site.register(InjuryLocation, InjuryLocationAdmin)
admin.site.register(SeasonInformation, SeasonInformationAdmin)
admin.site.register(GymnastHasRoutine, GymnastHasRoutineAdmin)
admin.site.register(NumberOfRoutineDone, NumberOfRoutineDoneAdmin)

View File

@ -7,7 +7,7 @@ from .models import (
Note,
Point,
Chrono,
Accident,
Injury,
WellBeing,
Intensity,
HeightWeight,
@ -181,10 +181,18 @@ class ScoreForm(forms.ModelForm):
)
class AccidentForm(forms.ModelForm):
class InjuryForm(forms.ModelForm):
class Meta:
model = Accident
fields = ("gymnast", "date", "nb_week_off", "informations")
model = Injury
fields = (
"gymnast",
"date",
"mechanism",
"location",
"body_side",
"nb_week_off",
"informations",
)
widgets = {
"date": forms.DateInput(
attrs={
@ -195,13 +203,16 @@ class AccidentForm(forms.ModelForm):
),
"gymnast": forms.HiddenInput(),
"skill": forms.HiddenInput(),
"mechanism": forms.Select(attrs={"class": "form-control selectpicker"}),
"location": forms.Select(attrs={"class": "form-control selectpicker"}),
"body_side": forms.Select(attrs={"class": "form-control selectpicker"}),
"nb_week_off": forms.NumberInput(
attrs={"class": "form-control", "placeholder": "xx"}
),
"informations": forms.Textarea(
attrs={
"class": "form-control",
"placeholder": "Informations about accident: context (why, where, …), consequencies, re-education exercices, …", # pylint: disable=line-too-long
"placeholder": "Informations about injury: context (why, where, …), consequencies, re-education exercices, …", # pylint: disable=line-too-long
}
),
}

View File

@ -0,0 +1,66 @@
# Generated by Django 4.2 on 2023-07-05 21:03
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("objective", "0016_routine_is_routine"),
("people", "0008_alter_gymnast_orientation"),
("followup", "0047_rename_mindstate_wellbeing"),
]
operations = [
migrations.RenameModel(
old_name="Accident",
new_name="Injury",
),
migrations.AlterModelOptions(
name="injury",
options={"verbose_name": "Injury", "verbose_name_plural": "Injuries"},
),
migrations.AlterField(
model_name="wellbeing",
name="fatigue",
field=models.PositiveSmallIntegerField(
blank=True,
default=None,
null=True,
validators=[
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(10),
],
verbose_name="Fatigue",
),
),
migrations.AlterField(
model_name="wellbeing",
name="muscle_soreness",
field=models.PositiveSmallIntegerField(
blank=True,
default=None,
null=True,
validators=[
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(10),
],
verbose_name="Muscle Soreness",
),
),
migrations.AlterField(
model_name="wellbeing",
name="sleep",
field=models.PositiveSmallIntegerField(
blank=True,
default=None,
null=True,
validators=[
django.core.validators.MinValueValidator(1),
django.core.validators.MaxValueValidator(10),
],
verbose_name="Sleep",
),
),
]

View File

@ -0,0 +1,35 @@
# Generated by Django 4.2 on 2023-07-06 10:09
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("people", "0008_alter_gymnast_orientation"),
("followup", "0048_rename_accident_injury_alter_injury_options_and_more"),
]
operations = [
migrations.AddField(
model_name="injury",
name="mechanism",
field=models.PositiveSmallIntegerField(
choices=[(0, "Overuse"), (1, "Trauma")],
default=1,
verbose_name="Injury mechanism",
),
preserve_default=False,
),
migrations.AlterField(
model_name="injury",
name="gymnast",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="injuries",
to="people.gymnast",
verbose_name="Gymnast",
),
),
]

View File

@ -0,0 +1,28 @@
# Generated by Django 4.2 on 2023-07-06 10:36
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("objective", "0016_routine_is_routine"),
("followup", "0049_injury_mechanism_alter_injury_gymnast"),
]
operations = [
migrations.AlterField(
model_name="injury",
name="skill",
field=models.ForeignKey(
blank=True,
default=None,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="injuries",
to="objective.skill",
verbose_name="Skill",
),
),
]

View File

@ -0,0 +1,32 @@
# Generated by Django 4.2 on 2023-07-06 12:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("followup", "0050_alter_injury_skill"),
]
operations = [
migrations.CreateModel(
name="InjuryLocation",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("label", models.CharField(max_length=100)),
],
options={
"verbose_name": "Injury Location",
"verbose_name_plural": "Injury Locations",
},
),
]

View File

@ -0,0 +1,26 @@
# Generated by Django 4.2 on 2023-07-06 12:44
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("followup", "0051_injurylocation"),
]
operations = [
migrations.AddField(
model_name="injury",
name="location",
field=models.ForeignKey(
default=1,
on_delete=django.db.models.deletion.CASCADE,
related_name="injuries",
to="followup.injurylocation",
verbose_name="Location",
),
preserve_default=False,
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 4.2 on 2023-07-06 12:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("followup", "0052_injury_location"),
]
operations = [
migrations.AddField(
model_name="injury",
name="body_side",
field=models.PositiveSmallIntegerField(
choices=[(0, "Left"), (1, "Right")], default=1, verbose_name="Body side"
),
preserve_default=False,
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 4.2 on 2023-07-06 20:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("followup", "0053_injury_body_side"),
]
operations = [
migrations.AlterField(
model_name="injury",
name="body_side",
field=models.PositiveSmallIntegerField(
choices=[(0, "N/A"), (1, "Left"), (2, "Right"), (3, "Both")],
verbose_name="Body side",
),
),
]

View File

@ -11,6 +11,36 @@ from jarvis.location.models import Club
User = get_user_model()
INJURY_MECHANISM_CHOICE = (
(0, "Overuse"),
(1, "Trauma"),
)
INJURY_BODY_SIDE_CHOICE = (
(0, "N/A"),
(1, "Left"),
(2, "Right"),
(3, "Both"),
)
INJURY_LOCATION_CHOICE = (
(0, "Head / Face"),
(1, "Neck / Cervical spine"),
(2, "Sternum / Ribs / Upperback"),
(3, "Abdomen"),
(4, "Low back / Sacrum / Pelvis"),
(5, "Shoulder / Clavicula"),
(6, "Upper Arm"),
(7, "Elbow"),
(8, "Hand / Finger / Thumb"),
(9, "Hip / Groin"),
(9, "Thigh"),
(10, "Knee"),
(11, "Lower Leg / Achilles Tendon"),
(12, "Ankle"),
(13, "Foot / Toe"),
)
ROUTINE_TYPE_CHOICE = (
(0, "Other"),
(1, "Q1R1"),
@ -134,32 +164,59 @@ class ChronoDetails(models.Model):
value = models.DecimalField(max_digits=5, decimal_places=3)
class Accident(Markdownizable, Seasonisable):
class InjuryLocation(models.Model):
"""
La classe `Accident` permet d'indiquer qu'un gymnaste a eu un accident, en liaison avec un
Classe représentant les localisations de blessures
"""
class Meta:
verbose_name = "Injury Location"
verbose_name_plural = "Injury Locations"
label = models.CharField(max_length=100, null=False, blank=False)
def __str__(self):
return f"{self.label}"
class Injury(Markdownizable, Seasonisable):
"""
La classe `Injury` permet d'indiquer qu'un gymnaste a eu un blessure, en liaison avec un
skill ou non.
"""
class Meta:
verbose_name = "Accident"
verbose_name_plural = "Accidents"
verbose_name = "Injury"
verbose_name_plural = "Injuries"
# unique_together = ("gymnast", "skill", "date")
gymnast = models.ForeignKey(
Gymnast,
verbose_name="Gymnast",
related_name="accident",
related_name="injuries",
on_delete=models.CASCADE,
)
skill = models.ForeignKey(
"objective.Skill",
verbose_name="Skill",
related_name="accident",
related_name="injuries",
on_delete=models.SET_NULL,
default=None,
blank=True,
null=True,
)
location = models.ForeignKey(
InjuryLocation,
verbose_name="Location",
related_name="injuries",
on_delete=models.CASCADE,
)
body_side = models.PositiveSmallIntegerField(
choices=INJURY_BODY_SIDE_CHOICE, verbose_name="Body side"
)
mechanism = models.PositiveSmallIntegerField(
choices=INJURY_MECHANISM_CHOICE, verbose_name="Injury mechanism"
)
nb_week_off = models.SmallIntegerField(
blank=True, null=True, verbose_name="# week off"
)

View File

@ -7,14 +7,14 @@
<div class="col-12 col-sm-12 col-md-8 col-lg-8 col-xl-6">
<div class="card">
<div class="card-header">
<h4 class="">{% if accident_id %}Edit{% else %}Add{% endif %} accident</h4>
<h4 class="">{% if injury_id %}Edit{% else %}Add{% endif %} injury</h4>
</div>
<div class="card-body">
<form action="{% if accident_id %}{% url 'accident_update' accident_id %}{% else %}{% url 'accident_create' %}{% endif %}" method="post" class="form-horizontal" id="formulaire" name="formulaire">
<form action="{% if injury_id %}{% url 'injury_update' injury_id %}{% else %}{% url 'injury_create' %}{% endif %}" method="post" class="form-horizontal" id="formulaire" name="formulaire">
{% csrf_token %}
<div class="form-group row ">
<label for="id_date" class="col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Gymnast <span class="text-danger"><b>*</b></span></label>
<div class="col-sm-9 col-md-9 col-lg-6 col-lg-4 col-xl-4 {% if form.jumper.errors %}has-danger{% endif %}">
<label for="id_date" class="col-4 col-sm-3 col-form-label">Gymnast <span class="text-danger"><b>*</b></span></label>
<div class="col-sm-8 col-md-6 col-lg-6 col-xl-6 {% if form.jumper.errors %}has-danger{% endif %}">
{% if request.user|has_group:"trainer" %}
{{ form.gymnast }}
{{ form.gymnast_related }}
@ -26,14 +26,14 @@
</div>
</div>
<div class="form-group row ">
<label for="id_date" class="col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Date <span class="text-danger"><b>*</b></span></label>
<label for="id_date" class="col-4 col-sm-3 col-form-label">{{ form.date.label }} <span class="text-danger"><b>*</b></span></label>
<div class="col-sm-3 col-md-4 col-lg-4 col-xl-4 {% if form.date.errors %}has-danger{% endif %}">
{{ form.date }}
{% if form.date.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.date.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_skill" class="col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Skill</label>
<label for="id_skill" class="col-4 col-sm-3 col-form-label">Skill</label>
<div class="col-sm-8 col-md-6 col-lg-6 col-xl-6 {% if form.skill.errors %}has-danger{% endif %}">
{{ form.skill }}
{{ form.skill_related }}
@ -41,20 +41,41 @@
</div>
</div>
<div class="form-group row ">
<label for="id_nb_week_off" class="col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label"># Week off</label>
<label for="id_mechanism" class="col-4 col-sm-3 col-form-label">{{ form.mechanism.label }} <span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-3 col-md-4 col-lg-4 col-xl-4 {% if form.mechanism.errors %}has-danger{% endif %}">
{{ form.mechanism }}
{% if form.mechanism.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.mechanism.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_location" class="col-4 col-sm-3 col-form-label">{{ form.location.label }}<span class="text-danger"><b>*</b></span></label>
<div class="col-sm-8 col-md-6 col-lg-6 col-xl-6 {% if form.location.errors %}has-danger{% endif %}">
{{ form.location }}
{% if form.location.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.location.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_body_side" class="col-4 col-sm-3 col-form-label">{{ form.body_side.label }}<span class="text-danger"><b>*</b></span></label>
<div class="col-5 col-sm-3 col-md-4 col-lg-4 col-xl-4 {% if form.body_side.errors %}has-danger{% endif %}">
{{ form.body_side }}
{% if form.body_side.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.body_side.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_nb_week_off" class="col-4 col-sm-3 col-form-label"># Week off</label>
<div class="col-sm-3 col-md-4 col-lg-2 {% if form.nb_week_off.errors %}has-danger{% endif %}">
{{ form.nb_week_off }}
{% if form.nb_week_off.errors %}&nbsp;<span class="btn btn-sm btn-danger-outline">{% for error in form.nb_week_off.errors %}{{ error }}{% endfor %}</span>{% endif %}
</div>
</div>
<div class="form-group row ">
<label for="id_information" class="col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Informations</label>
<label for="id_information" class="col-4 col-sm-3 col-form-label">Informations</label>
<div class="col-sm-9 col-md-9 col-lg-9 col-xl-9 {% if form.id_informations.errors %}has-danger{% endif %}">
{{ form.informations }}
</div>
</div>
<div class="form-group text-center">
<input type="submit" value="{% if accident_id %}Save{% else %}Add{% endif %}" class="btn btn-warning" />
<input type="submit" value="{% if injury_id %}Save{% else %}Add{% endif %}" class="btn btn-warning" />
</div>
</form>
</div>

View File

@ -6,19 +6,20 @@
<div class="col-12 col-sm-8 col-md-6">
<div class="card">
<div class="card-header">
<h4 class="mb-0">Accident : {{ accident.date | date:"d-m-Y" }}</h4>
<h4 class="mb-0">Injury on {{ injury.date | date:"j N Y" }}</h4>
</div>
<div class="card-body">
<a href="{% url 'gymnast_details' accident.gymnast.id %}">{{ accident.gymnast }}</a><br />
{% if accident.nb_week_off %}
{{ accident.nb_week_off }} week(s) off.<br />
<a href="{% url 'gymnast_details' injury.gymnast.id %}">{{ injury.gymnast }}</a>{% if injury.skill %} injuried on <i>{{ injury.skill.notation }}</i>{% endif %}<br />
{{ injury.get_mechanism_display }} on {{ injury.location}} ({{ injury.get_body_side_display }})<br />
{% if injury.nb_week_off %}
Gymnast {{ injury.nb_week_off }} week(s) off.<br />
{% endif %}
<br />
{{ accident.to_markdown | safe }}
{{ injury.to_markdown | safe }}
<div class="card-footer pl-0 pb-0">
<a href="{% url 'accident_list' %}">
<a href="{% url 'injuries_list' %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="tim-icons icon-double-left"></i>
</button>

View File

@ -5,11 +5,11 @@
<div class="card-header">
<div class="row">
<div class="col-md-4">
<h4 class=""> Accidents Listing</h4>
<h4 class=""> Injuries Listing</h4>
</div>
<div class="col-1 ml-auto">
<div class="text-right">
<a href="{% url 'accident_create' %}">
<a href="{% url 'injury_create' %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>
@ -20,37 +20,43 @@
</div>
<div class="card-body">
<div class="table-responsive">
{% if accident_list %}
<table class="table tablesorter table-striped" data-sort="table" id="accident_table">
{% if injuries_list %}
<table class="table tablesorter table-striped" data-sort="table" id="injury_table">
<thead class="text-primary">
<tr>
<th style="width: 3%"></th>
<th class="header text-left" style="width: 10%">Date</th>
<th class="header text-left" style="width: 30%">Gymnast</th>
<th style="width: 30%">Skill</th>
<th style="width: 25%"># Week off</th>
<th class="header text-left" style="width: 8%">Date</th>
<th class="header text-left" style="width: 20%">Gymnast</th>
<th class="header text-left" style="width: 9%">Mechanism</th>
<th class="header text-left" style="width: 20%">Location</th>
<th class="header text-left" style="width: 8%">Side</th>
<th style="width: 20%">Skill</th>
<th style="width: 8%"># Week off</th>
</tr>
</thead>
<tbody>
{% for accident in accident_list %}
{% for injury in injuries_list %}
<tr role="row" class="{% cycle 'odd' 'even' %}">
<td>
<a href="{% url 'accident_update' accident.id %}">
<a href="{% url 'injury_update' injury.id %}">
<span class="tim-icons icon-pencil text-warning"></span>
</a>
</td>
<td class="text-left"><a href="{% url 'accident_details' accident.id %}">{{ accident.date | date:"d-m-Y" }}</a></td>
<td class="text-left"><a href="{% url 'gymnast_details_tab' accident.gymnast.id 'physiological' %}">{{ accident.gymnast }}</a></td>
<td class="text-left"><a href="{% url 'injury_details' injury.id %}">{{ injury.date | date:"d-m-Y" }}</a></td>
<td class="text-left"><a href="{% url 'gymnast_details_tab' injury.gymnast.id 'physiological' %}">{{ injury.gymnast }}</a></td>
<td class="text-left">{{ injury.get_mechanism_display }}</td>
<td class="text-left">{{ injury.location }}</td>
<td class="text-left">{{ injury.get_body_side_display }}</td>
<td class="text-left">
{% if accident.skill %}
<a href="{% url 'skill_details' accident.skill.id %}">{{ accident.skill }}</a>
{% if injury.skill %}
<a href="{% url 'skill_details' injury.skill.id %}">{{ injury.skill }}</a>
{% else %}
-
{% endif %}
</td>
<td class="text-right">
{% if accident.nb_week_off %}
{{ accident.nb_week_off }}
{% if injury.nb_week_off %}
{{ injury.nb_week_off }}
{% else %}
-
{% endif %}
@ -60,7 +66,7 @@
</tbody>
</table>
{% else %}
<p class="muted-text">There are no accident corresponding to your criterias.</p>
<p class="muted-text">There are no injury corresponding to your criterias.</p>
{% endif %}
</div>
</div>
@ -70,7 +76,7 @@
{% block footerscript %}
<script type="text/javascript">
$(document).ready(function () {
$('#accident_table').tablesorter({
$('#injury_table').tablesorter({
headers: {
0: { sorter: false }, // disable first column
},
@ -78,7 +84,7 @@
sortList: [[1, 1]]
});
$('#accident_table').DataTable({
$('#injury_table').DataTable({
scrollY: 500,
paging: false,
searching: false,

View File

@ -61,24 +61,20 @@ class URLTestCase(TestCase):
self.assertEqual(resolve("/follow-up/score/add/").view_name, "score_create")
self.assertEqual(resolve("/follow-up/score/edit/1/").view_name, "score_update")
# Accident URL
# Injury URL
self.assertEqual(
resolve("/follow-up/accident/search/").view_name, "accident_search"
resolve("/follow-up/injury/search/").view_name, "injury_search"
)
self.assertEqual(resolve("/follow-up/accident/").view_name, "accident_list")
self.assertEqual(resolve("/follow-up/injury/").view_name, "injuries_list")
self.assertEqual(resolve("/follow-up/injury/add/").view_name, "injury_create")
self.assertEqual(
resolve("/follow-up/accident/add/").view_name, "accident_create"
resolve("/follow-up/injury/add/1/").view_name,
"injury_create_for_gymnast",
)
self.assertEqual(
resolve("/follow-up/accident/add/1/").view_name,
"accident_create_for_gymnast",
)
self.assertEqual(
resolve("/follow-up/accident/edit/1/").view_name, "accident_update"
)
self.assertEqual(
resolve("/follow-up/accident/1/").view_name, "accident_details"
resolve("/follow-up/injury/edit/1/").view_name, "injury_update"
)
self.assertEqual(resolve("/follow-up/injury/1/").view_name, "injury_details")
# WellBeing URL
self.assertEqual(resolve("/follow-up/wellbeing/").view_name, "wellbeing_list")

View File

@ -153,22 +153,20 @@ urlpatterns = [
#
#
# ACCIDENT
path(r"accident/search/", views.accident_listing, name="accident_search"),
path(r"accident/", views.accident_listing, name="accident_list"),
path(r"accident/add/", views.accident_create_or_update, name="accident_create"),
path(r"injury/search/", views.injuries_listing, name="injury_search"),
path(r"injury/", views.injuries_listing, name="injuries_list"),
path(r"injury/add/", views.injury_create_or_update, name="injury_create"),
path(
r"accident/add/<int:gymnast_id>/",
views.accident_create_or_update,
name="accident_create_for_gymnast",
r"injury/add/<int:gymnast_id>/",
views.injury_create_or_update,
name="injury_create_for_gymnast",
),
path(
r"accident/edit/<int:accident_id>/",
views.accident_create_or_update,
name="accident_update",
),
path(
r"accident/<int:accident_id>/", views.accident_detail, name="accident_details"
r"injury/edit/<int:injury_id>/",
views.injury_create_or_update,
name="injury_update",
),
path(r"injury/<int:injury_id>/", views.injury_detail, name="injury_details"),
#
#
# WELLBEING

View File

@ -19,7 +19,7 @@ from .models import (
Note,
Point,
Chrono,
Accident,
Injury,
WellBeing,
Intensity,
LearnedSkill,
@ -35,7 +35,7 @@ from .forms import (
NoteForm,
ScoreForm,
ChronoForm,
AccidentForm,
InjuryForm,
WellBeingForm,
IntensityForm,
HeightWeightForm,
@ -795,10 +795,10 @@ def score_listing(request, gymnast_id=None):
@login_required
@require_http_methods(["GET"])
def accident_listing(request):
def injuries_listing(request):
"""
Récupère la liste des accidents.
Si c'est un gymnaste qui est connecté, il ne peut récupérer que la liste de ses accidents.
Récupère la liste des bessures.
Si c'est un gymnaste qui est connecté, il ne peut récupérer que la liste de ses blessures.
Si c'est un autre utilisateur (entraîneur), la liste peut répondre à un pattern si celui-ci est
définit.
"""
@ -806,94 +806,92 @@ def accident_listing(request):
if request.user.groups.filter(name="trainer").exists():
pattern = request.GET.get("pattern", None)
if pattern:
accident_list = Accident.objects.filter(
injuries_list = Injury.objects.filter(
Q(gymnast__last_name__icontains=pattern)
| Q(gymnast__first_name__icontains=pattern)
)
else:
accident_list = Accident.objects.all()
injuries_list = Injury.objects.all()
else:
accident_list = Accident.objects.filter(
injuries_list = Injury.objects.filter(
Q(gymnast__last_name=request.user.last_name)
& Q(gymnast__first_name=request.user.first_name)
)
context = {"accident_list": accident_list}
return render(request, "accidents/list.html", context)
context = {"injuries_list": injuries_list}
return render(request, "injuries/list.html", context)
@login_required
@require_http_methods(["GET", "POST"])
def accident_create_or_update(request, accident_id=None, gymnast_id=None):
def injury_create_or_update(request, injury_id=None, gymnast_id=None):
"""
Formulaire de création d'un nouvel accident.
Formulaire de création d'un nouvel blessure.
Args:
accident_id (int) identifiant d'un accident
injury_id (int) identifiant d'une blessure
gymnast_id (int) identifiant d'un gymnaste
"""
if accident_id:
accident = get_object_or_404(Accident, pk=accident_id)
if injury_id:
injury = get_object_or_404(Injury, pk=injury_id)
data = {
"gymnast_related": accident.gymnast,
"skill_related": accident.skill,
"gymnast_related": injury.gymnast,
"skill_related": injury.skill,
}
else:
accident = None
injury = None
data = None
if gymnast_id is not None:
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
data = {"gymnast": gymnast_id, "gymnast_related": str(gymnast)}
if request.method == "POST":
form = AccidentForm(request.POST, instance=accident)
form = InjuryForm(request.POST, instance=injury)
if form.is_valid():
accident = form.save()
injury = form.save()
# notification
receiver = []
gymnast = Gymnast.objects.get(pk=form.cleaned_data["gymnast"].id)
functionality = ContentType.objects.get(model="accident")
functionality = ContentType.objects.get(model="injury")
for notification in gymnast.notifications.filter(
functionality=functionality
):
receiver.append(notification.user.email)
send_mail(
f"{gymnast} : Nouvel accident enregistré",
f"Un nouvel accident enregistré pour {gymnast}",
f"{gymnast} : Nouvelle blessure enregistrée",
f"Une nouvelle blessure enregistrée pour {gymnast}",
settings.EMAIL_HOST_USER,
receiver,
fail_silently=False,
html_message=f"""<p>Bonjour,</p>
<p>Un nouvel accident enregistré pour {gymnast}.</p><br />
<p>Un nouvelle blessure enregistrée pour {gymnast}.</p><br />
<p>Excellente journée</p><p>Jarvis</p>""",
)
return HttpResponseRedirect(
reverse("accident_details", args=(accident.pk,))
)
return HttpResponseRedirect(reverse("injury_details", args=(injury.pk,)))
else:
return render(request, "accidents/create.html", {"form": form})
return render(request, "injuries/create.html", {"form": form})
form = AccidentForm(instance=accident, initial=data)
context = {"form": form, "accident_id": accident_id}
return render(request, "accidents/create.html", context)
form = InjuryForm(instance=injury, initial=data)
context = {"form": form, "injury_id": injury_id}
return render(request, "injuries/create.html", context)
@login_required
@require_http_methods(["GET"])
def accident_detail(request, accident_id):
def injury_detail(request, injury_id):
"""
Récupère toutes les informations d'un accident.
Récupère toutes les informations d'une blessure.
Args:
accident_id (int) identifiant d'un accident
injury_id (int) identifiant d'une blessure
"""
accident = get_object_or_404(Accident, pk=accident_id)
return render(request, "accidents/details.html", {"accident": accident})
injury = get_object_or_404(Injury, pk=injury_id)
return render(request, "injuries/details.html", {"injury": injury})
@login_required
@ -922,10 +920,10 @@ def wellbeing_create_or_update(
request, wellbeing_id=None, gymnast_id=None, event_id=None
):
"""
Formulaire de création d'un nouvel accident.
Formulaire de création d'une nouvelle blessure.
Args:
wellbeing_id (int) identifiant d'un accident
wellbeing_id (int) identifiant d'une blessure
gymnast_id (int) identifiant d'un gymnaste
event_id (int) identifiant d'un événement
"""

View File

@ -2,10 +2,10 @@
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h4>Accidents</h4>
<h4>Injuries</h4>
</div>
<div class="card-body pt-0 pb-0">
{% if accident_list %}
{% if injuries_list %}
<div class="card-body pl-0 pt-0 pr-0">
<table class="table table-striped table-condensed tablesorter mb-1">
<thead>
@ -16,26 +16,26 @@
</tr>
</thead>
<tbody>
{% for accident in accident_list %}
{% for injury in injuries_list %}
<tr>
<td class="text-left">
<a href="{% url 'accident_update' accident.id %}">
<a href="{% url 'injury_update' injury.id %}">
&nbsp;<span class="tim-icons icon-pencil text-warning"></span>
</a>
</td>
<td class="text-center"><a href="{% url 'accident_details' accident.id %}">{{ accident.date | date:"d-m-Y" }}</a></td>
<td class="text-left"><a href="{% url 'skill_details' accident.skill.id %}">{{ accident.skill }}</a></td>
<td class="text-center"><a href="{% url 'injury_details' injury.id %}">{{ injury.date | date:"d-m-Y" }}</a></td>
<td class="text-left"><a href="{% url 'skill_details' injury.skill.id %}">{{ injury.skill }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<p class="pl-3 text-muted">No accident known for this gymnast.</p>
<p class="pl-3 text-muted">No injury known for this gymnast.</p>
{% endif %}
</div>
<div class="card-footer text-right text-muted pt-0">
<a href="{% url 'accident_create_for_gymnast' gymnastid %}">
<a href="{% url 'injury_create_for_gymnast' gymnastid %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>

View File

@ -64,40 +64,46 @@
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h4>Accidents</h4>
<h4>Injuries</h4>
</div>
<div class="card-body pt-0 pb-0">
{% if accident_list %}
<table class="table tablesorter table-striped table-condensed" id="accident_table">
{% if injuries_list %}
<table class="table tablesorter table-striped table-condensed" id="injury_table">
<thead>
<tr>
<th style="width: 3%"></th>
<th class="header text-center" style="width: 10%">Date</th>
<th class="header text-left" style="width: 50%">Skill</th>
<th class="header text-left" style="width: 40%"># Week Off</th>
<th class="header text-left" style="width: 10%">Mechanism</th>
<th class="header text-left" style="width: 25%">Location</th>
<th class="header text-left" style="width: 10%">Side</th>
<th class="header text-left" style="width: 25%">Skill</th>
<th class="header text-center" style="width: 10%"># Week Off</th>
</tr>
</thead>
<tbody>
{% for accident in accident_list %}
{% for injury in injuries_list %}
<tr>
<td class="text-left">
<a href="{% url 'accident_update' accident.id %}">
<a href="{% url 'injury_update' injury.id %}">
&nbsp;<span class="tim-icons icon-pencil text-warning"></span>
</a>
</td>
<td class="text-center"><a href="{% url 'accident_details' accident.id %}">{{ accident.date | date:"d-m-Y" }}</a></td>
<td class="text-left">{% if accident.skill %}<a href="{% url 'skill_details' accident.skill.id %}">{{ accident.skill }}</a>{% else %}-{% endif %}</td>
<td class="text-left">{{ accident.nb_week_off }}</td>
<td class="text-center"><a href="{% url 'injury_details' injury.id %}">{{ injury.date | date:"d-m-Y" }}</a></td>
<td class="text-left">{{ injury.get_mechanism_display }}</td>
<td class="text-left">{{ injury.location }}</td>
<td class="text-left">{{ injury.get_body_side_display }}</td>
<td class="text-left">{% if injury.skill %}<a href="{% url 'skill_details' injury.skill.id %}">{{ injury.skill }}</a>{% else %}-{% endif %}</td>
<td class="text-center">{{ injury.nb_week_off }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="text-muted">No accident known for this gymnast.</p>
<p class="text-muted">No injury known for this gymnast.</p>
{% endif %}
</div>
<div class="card-footer text-right text-muted pt-0">
<a href="{% url 'accident_create_for_gymnast' gymnast_id %}">
<a href="{% url 'injury_create_for_gymnast' gymnast_id %}">
<button type="submit" value="add" class="btn btn-icon btn-warning ">
<i class="fas fa-plus"></i>
</button>

View File

@ -37,9 +37,9 @@ gymnast_urlpatterns = [
name="gymnast_display_events_and_notes",
),
path(
r"details/<int:gymnast_id>/accident/",
views.gymnast_display_accident,
name="gymnast_display_accident",
r"details/<int:gymnast_id>/injury/",
views.gymnast_display_injury,
name="gymnast_display_injury",
),
path(
r"details/<int:gymnast_id>/scores_chrono/",

View File

@ -35,7 +35,7 @@ from jarvis.followup.models import (
Skill,
Point,
Chrono,
Accident,
Injury,
WellBeing,
Intensity,
LearnedSkill,
@ -280,35 +280,35 @@ def gymnast_display_events_and_notes(request, gymnast_id):
@login_required
@require_http_methods(["GET"])
def gymnast_display_accident(request, gymnast_id):
def gymnast_display_injury(request, gymnast_id):
"""
Renvoie la liste des accidents d'un gymnaste.
Renvoie la liste des blessures d'un gymnaste.
Args:
gymnast_id (int) identifiant du gymnast
"""
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)
injuries_list = Injury.objects.filter(gymnast=gymnast_id)
context = {"injuries_list": injuries_list, "gymnast_id": gymnast_id}
return render(request, "gymnasts/list_injury.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.
Renvoie les listes des tailles/poids, état d'esprit et blessures.
Args:
gymnast_id (int) identifiant du gymnast
"""
accident_list = Accident.objects.filter(gymnast=gymnast_id).order_by("date")
injuries_list = Injury.objects.filter(gymnast=gymnast_id).order_by("date")
wellbeing_list = WellBeing.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,
"injuries_list": injuries_list,
"wellbeing_list": wellbeing_list,
"height_weight_list": height_weight_list,
"gymnast_id": gymnast_id,
@ -690,7 +690,7 @@ def __get_distinct_followup_season_for_gymnast(gymnast_id):
.order_by("season")
)
season_list += list(
gymnast.accident.values_list("season", flat=True)
gymnast.injuries.values_list("season", flat=True)
.distinct("season")
.order_by("season")
)
@ -747,7 +747,7 @@ def __get_distinct_week_number_for_season_and_gymnast(gymnast_id, season):
.order_by("week_number")
)
weeknumber_list += list(
gymnast.accident.values_list("week_number", flat=True)
gymnast.injuries.values_list("week_number", flat=True)
.filter(season=season)
.distinct("week_number")
.order_by("week_number")
@ -1373,7 +1373,7 @@ def generate_timeline_report(
- records (Chrono/ToF),
- points (compétition),
- nouveau apprentissage (learned skill)
- accident
- blessures
- GymnastHasRoutine
eton les trie par date.
@ -1450,7 +1450,7 @@ def generate_timeline_report(
# print(selected_record)
list_record = selected_record
list_record.extend(list(gymnast.accident.all().order_by("date")))
list_record.extend(list(gymnast.injuries.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")))