Big update on report generation

This commit is contained in:
Gregory Trullemans 2022-11-19 18:51:20 +01:00
parent 402c26a00d
commit 8250139908
4 changed files with 463 additions and 352 deletions

View File

@ -161,3 +161,12 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
# https://warehouse.python.org/project/whitenoise/
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
SITE_TITLE = env("SITE_TITLE", default=None)
CLUB_NAME = env("CLUB_NAME", default=None)
ADDRESS = env("ADDRESS", default=None)
CITY = env("CITY", default=None)
ZIP = env("ZIP", default=None)
HEAD_COACH = env("HEAD_COACH", default=None)
MOBILE_PHONE = env("MOBILE_PHONE", default=None)
HEAD_COACH_EMAIL = env("HEAD_COACH_EMAIL", default=None)

View File

@ -1,7 +1,4 @@
{% load static %}
{% load menuitems %}
{% load has_group %}
{% load is_user_equal_to_gymnast %}
<!DOCTYPE html>
<html>
@ -18,364 +15,253 @@
<link rel="apple-touch-icon" sizes="76x76" href="{% static "img/apple-icon.png" %}">
<link rel="icon" type="image/png" href="{% static "img/favicon.png" %}">
<title>• Ultron - {{ gymnast.first_name }} {{ gymnast.last_name }}</title>
<title>{{ gymnast.first_name }} {{ gymnast.last_name }}</title>
<!-- Fonts and icons -->
<link href="https://fonts.googleapis.com/css?family=Poppins:200,300,400,600,700,800" rel="stylesheet" />
<!-- Font Awesome Pro -->
<link href="{% static "css/gymnast_report.css" %}" rel="stylesheet" />
<link href="{% static "css/font_awesome_all_5.15.3.css" %}" rel="stylesheet" />
<!-- Full Calendar Plugin, full documentation here: https://github.com/fullcalendar/fullcalendar -->
<link href="{% static "js/plugins/fullcalendar/main.min.css" %}" rel="stylesheet" />
<!-- JQuery UI CSS -->
<link href="{% static "js/plugins/jqueryui/jquery-ui.theme.min.css" %}" rel="stylesheet" />
<link href="{% static "js/plugins/jqueryui/jquery-ui.min.css" %}" rel="stylesheet" />
<!-- Nucleo Icons -->
<link href="{% static "css/nucleo-icons.css" %}" rel="stylesheet" />
<!-- CSS Files -->
<link href="{% static "css/black-dashboard.css" %}" rel="stylesheet" />
<!-- Maps by mapbox -->
<script src='https://api.mapbox.com/mapbox.js/v3.2.0/mapbox.js'></script>
<link href='https://api.mapbox.com/mapbox.js/v3.2.0/mapbox.css' rel='stylesheet' />
<!-- Core JS Files -->
<script src="{% static "js/core/jquery-3.6.0.min.js" %}"></script>
<script src="{% static "js/core/popper.min.js" %}"></script>
<script src="{% static "js/core/bootstrap.min.js" %}"></script>
<!-- Chart JS -->
<script src="{% static "js/plugins/moment_2.29.1.min.js" %}"></script>
<script src="{% static "js/plugins/moment_locale_en-gb.js" %}"></script>
<script src="{% static "js/plugins/chartjs_2.9.4.min.js" %}"></script>
<!-- FullCalendar CSS -->
<!-- <link href="{% static "js/plugins/fullcalendar/main.css" %}" rel="stylesheet" /> -->
<link href="{% static "css/black-dashboard_report.css" %}" rel="stylesheet" />
</head>
<body class="sidebar-mini white-content">
<div class="content">
<div class="row">
<div class="col-12 col-sm-4 col-md-4 col-lg-4">
<div class="card mb-4">
<div class="card-body">
<a href="{% url 'gymnast_report_preview' gymnast.id %}">Rapport</a>
<h4 class="title">{{ gymnast.first_name }} {{ gymnast.last_name }}</h4>
{{ gymnast.club.name }}<br />
<b>{{ gymnast.trainings_by_week }} training/week</b> for <b>{{ gymnast.hours_by_week }} hours/week</b><br />
{% if height_weight %}
<b>{{ height_weight.0.height }}cm - {{ height_weight.0.weight }}kg</b> ({{ height_weight.0.date | date:"d-m-Y" }})<br />
{% endif %}
<br />
{% if user_is_trainer and gymnast.informations %}
<p>{{ gymnast.informations }}</p>
<br />
{% endif %}
<h4>Personnal bests :</h4>
<li>
<b>10 |</b> : <b>{{ best_straightjump.0.tof }}</b> ({{ best_straightjump.0.date | date:"d-m-Y" }})
</li>
<li>
<b>R1</b> : <b>{{ best_tof_routine_1.0.tof }}</b> ({{ best_tof_routine_1.0.date | date:"d-m-Y" }})
</li>
<li>
<b>R2</b> : <b>{{ best_tof_routine_2.0.tof }}</b> ({{ best_tof_routine_2.0.date | date:"d-m-Y" }})
</li>
<li>
<b>Routine</b> : {% if best_routine %}<b>{{ best_routine.0.tof }}</b> ({{ best_routine.0.date | date:"d-m-Y" }}){% else %} (no information){% endif %}
</li>
</div>
</div>
</div>
<div class="col-12 col-sm-4 col-md-4 col-lg-4">
(doughnut)
</div>
<div class="col-12 col-sm-4 col-md-4 card mb-4">
(stat par level/rank)
</div>
</div>
<div class="row">
<div class="col-3 col-sm-1 col-md-1 col-lg-1 col-xl-1">
<ul class="nav nav-pills nav-pills-primary nav-pills-icons flex-column">
<li class="nav-item">
<a class="nav-link get-info{% if tab is None or tab == 'level' %} active{% endif %}" data-toggle="tab" href="#skill" data-ref="#skill" data-url="skill/" id="display_skill">
<i class="tim-icons icon-sound-wave"></i> <!-- Level -->
</a>
</li>
<li class="nav-item">
<a class="nav-link get-info{% if tab == 'routine' %} active{% endif %}" data-toggle="tab" href="#routine" data-ref="#routine" data-url="routine/" id="display_routines">
<i class="tim-icons icon-components"></i> <!-- Routines -->
</a>
</li>
<li class="nav-item">
<a class="nav-link get-info{% if tab == 'scores' %} active{% endif %}" data-toggle="tab" href="#scores" data-ref="#scores" data-url="scores_chrono/" id="display_scores_chrono">
<i class="fal fa-crosshairs"></i> <!-- Scores -->
</a>
</li>
{% if user_is_trainer or request.user|is_user_equal_to_gymnast:gymnast.id %}
<li class="nav-item">
<a class="nav-link get-info{% if tab == 'physiological' %} active{% endif %}" data-toggle="tab" href="#physiological" data-ref="#physiological" data-url="physiological/" id="display_physiological">
<i class="fal fa-stethoscope"></i> <!-- Physical -->
</a>
</li>
{% endif %}
<li class="nav-item">
<a class="nav-link get-info{% if tab == 'event' %} active{% endif %}" data-toggle="tab" href="#event" data-ref="#event" data-url="event/" id="display_event">
<i class="fal fa-calendar-day"></i> <!-- Events -->
</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-11 col-md-11 col-lg-11 pr-0">
<div class="tab-content">
<div class="tab-pane{% if tab is None or tab == 'skill' %} active{% endif %}" id="skill"></div>
<div class="tab-pane{% if tab == 'routine' %} active{% endif %}" id="routine"></div>
<div class="tab-pane{% if tab == 'scores' %} active{% endif %}" id="scores"></div>
{% if user_is_trainer or request.user|is_user_equal_to_gymnast:gymnast.id %}
<div class="tab-pane{% if tab == 'physiological' %} active{% endif %}" id="physiological"></div>
{% endif %}
<div class="tab-pane{% if tab == 'event' %} active{% endif %}" id="event"></div>
<!-- TODO : message d'erreur si TAB non géré. -->
</div>
</div>
</div>
</div>
<header class="white-content">
<div class="row">
<div id="header-left" class="col-7 text-12">
{{ SITE_TITLE }} - {{ CLUB_NAME }}<br />
{{ ADDRESS }} - {{ ZIP }} {{ CITY }}<br />
Season {{ season }} - week {{ week_number }}
</div>
<div id="header-right" class="col-5 text-right text-12">
Head Coach : {{ HEAD_COACH }}<br />
{{ HEAD_COACH_EMAIL }}<br />
{{ today | date:"j F Y" }}
</div>
</div>
<script src="{% static "js/plugins/perfect-scrollbar.jquery_1.4.0.min.js" %}"></script>
<!-- Plugin for Switches, full documentation here: http://www.jque.re/plugins/version3/bootstrap.switch/ -->
<script src="{% static "js/plugins/bootstrap-switch_3.3.4.js" %}"></script>
<!-- Plugin for Sweet Alert -->
<script src="{% static "js/plugins/sweetalert2.min.js" %}"></script>
<!-- Plugin for Sorting Tables -->
<script src="{% static "js/plugins/jquery.tablesorter_2.0.5b.js" %}"></script>
<!-- Forms Validations Plugin -->
<script src="{% static "js/plugins/jquery.validate_1.17.0.min.js" %}"></script>
<!-- Plugin for the Wizard, full documentation here: https://github.com/VinceG/twitter-bootstrap-wizard -->
<script src="{% static "js/plugins/jquery.bootstrap-wizard_1.4.2.js" %}"></script>
<!-- Plugin for Select, full documentation here: http://silviomoreto.github.io/bootstrap-select -->
<script src="{% static "js/plugins/bootstrap-selectpicker_1.12.4.js" %}"></script>
<!-- Plugin for the DateTimePicker, full documentation here: https://eonasdan.github.io/bootstrap-datetimepicker/ -->
<script src="{% static "js/plugins/bootstrap-datetimepicker_4.17.47.js" %}"></script>
<!-- DataTables.net Plugin, full documentation here: https://datatables.net/ -->
<script src="{% static "js/plugins/jquery.dataTables_1.10.18.min.js" %}"></script>
<!-- Plugin for Tags, full documentation here: https://github.com/bootstrap-tagsinput/bootstrap-tagsinputs -->
<script src="{% static "js/plugins/bootstrap-tagsinput_0.8.0.js" %}"></script>
<!-- Plugin for Fileupload, full documentation here: http://www.jasny.net/bootstrap/javascript/#fileinput -->
<script src="{% static "js/plugins/jasny-bootstrap_3.1.3.min.js" %}"></script>
<!-- Full Calendar Plugin, full documentation here: https://github.com/fullcalendar/fullcalendar -->
<script src="{% static "js/plugins/fullcalendar/main.js" %}"></script>
<!-- Vector Map plugin, full documentation here: http://jvectormap.com/documentation/ -->
<script src="{% static "js/plugins/jquery-jvectormap_2.0.4.js" %}"></script>
<!-- Plugin for the Sliders, full documentation here: http://refreshless.com/nouislider/ -->
<script src="{% static "js/plugins/nouislider_11.1.0.min.js" %}"></script>
<!-- Notifications Plugin -->
<script src="{% static "js/plugins/bootstrap-notify_3.1.5.js" %}"></script>
<!-- Control Center for Black Dashboard: parallax effects, scripts for the example pages etc -->
<!-- <script src="{% static "js/black-dashboard.min.js" %}"></script> -->
<script src="{% static "js/black-dashboard.js" %}"></script>
<!-- Jquery UI for autocomplete, etc. -->
<script src="{% static "js/plugins/jqueryui/jquery-ui.min.js" %}"></script>
<script type="text/javascript">
$(document).ready(function() {
$().ready(function() {
$sidebar = $('.sidebar');
$navbar = $('.navbar');
$main_panel = $('.main-panel');
$full_page = $('.full-page');
$sidebar_responsive = $('body > .navbar-collapse');
// {% if request.session.is_sidebar_minified %}sidebar_mini_active = true;
// {% else %}sidebar_mini_active = false;
// {% endif %}
// {% if request.session.template == 0 %}white_color = false;
// {% else %}white_color = true;
// {% endif %}
white_color = true;
window_width = $(window).width();
fixed_plugin_open = $('.sidebar .sidebar-wrapper .nav li.active a p').html();
// {% if request.session.sidebar == 1 %}color = 'blue';
// {% elif request.session.sidebar == 2 %}color = 'green';
// {% elif request.session.sidebar == 3 %}color = 'orange';
// {% elif request.session.sidebar == 4 %}color = 'red';
// {% else %}color = 'purple'
// {% endif %}
// $sidebar.attr('data', color);
// $main_panel.attr('data', color);
// $full_page.attr('filter-color', color);
// $sidebar_responsive.attr('data', color);
$('.fixed-plugin a').click(function(event) {
if ($(this).hasClass('switch-trigger')) {
if (event.stopPropagation) {
event.stopPropagation();
} else if (window.event) {
window.event.cancelBubble = true;
}
}
});
$('.fixed-plugin .background-color span').click(function() {
$(this).siblings().removeClass('active');
$(this).addClass('active');
var new_color = $(this).data('color');
if ($sidebar.length != 0)
$sidebar.attr('data', new_color);
if ($main_panel.length != 0)
$main_panel.attr('data', new_color);
if ($full_page.length != 0)
$full_page.attr('filter-color', new_color);
if ($sidebar_responsive.length != 0)
$sidebar_responsive.attr('data', new_color);
});
// $('.switch-sidebar-mini input').on("switchChange.bootstrapSwitch", function() {
// var $btn = $(this);
// if (sidebar_mini_active == true) {
// $('body').removeClass('sidebar-mini');
// sidebar_mini_active = false;
// blackDashboard.showSidebarMessage('Sidebar mini deactivated...');
// } else {
// $('body').addClass('sidebar-mini');
// sidebar_mini_active = true;
// blackDashboard.showSidebarMessage('Sidebar mini activated...');
// }
// // we simulate the window Resize so the charts will get updated in realtime.
// var simulateWindowResize = setInterval(function() {
// window.dispatchEvent(new Event('resize'));
// }, 180);
// // we stop the simulation of Window Resize after the animations are completed
// setTimeout(function() {
// clearInterval(simulateWindowResize);
// }, 1000);
// });
// $('.switch-change-color input').on("switchChange.bootstrapSwitch", function() {
// var $btn = $(this);
// if (white_color == true) {
// $('body').addClass('change-background');
// setTimeout(function() {
// $('body').removeClass('change-background');
// $('body').removeClass('white-content');
// }, 900);
// white_color = true; // false
// } else {
// $('body').addClass('change-background');
// setTimeout(function() {
// $('body').removeClass('change-background');
// $('body').addClass('white-content');
// }, 900);
// white_color = true;
// }
// });
// $('.light-badge').click(function() {
// $('body').addClass('white-content');
// });
// $('.dark-badge').click(function() {
// $('body').removeClass('white-content');
// });
// $('#inlineFormInputGroup').focus();
// $('#search-button').click(function(){
// alert('Clicked !');
// $('#inlineFormInputGroup').focus();
// });
});
});
</script>
<script type="text/javascript">
$(document).ready(function() {
var default_url = "{% url 'gymnast_details' gymnast.id %}";
var tab_div = '';
{% if tab is None or tab == 'skill' %}
tab_url = default_url + 'skill/';
tab_div = '#skill';
{% elif tab == 'routine' %}
tab_url = default_url + 'routine/';
tab_div = '#routine';
{% elif tab == 'scores' %}
tab_url = default_url + 'scores_chrono/';
tab_div = '#scores';
{% elif tab == 'physiological' %}
tab_url = default_url + 'physiological/';
tab_div = '#physiological'
{% elif tab == 'event' %}
tab_url = default_url + 'event/';
tab_div = '#event';
</header>
<br />
<body class="white-content">
<div class="row">
<div class="col-2">
<img src="{% static 'img/default-avatar.png' %}" class="profil_img" />
</div>
<div class="col-6 pl-0">
<h3 class="title">{{ gymnast.first_name }} {{ gymnast.last_name }}</h3>
{{ gymnast.age }} years - {{ gymnast.get_orientation_display }} twisting<br />
{% if gymnast.informations %}
{{ gymnast.to_markdown | safe }}
{% endif %}
$.ajax({
url: tab_url,
dataType: "html",
success: function(data) {
$(tab_div).replaceWith($(tab_div).html(data));
},
error: function (exception) {
console.log(exception);
}
});
$('.get-info').click(function(){
$.ajax({
url: default_url + $(this).data("url"),
dataType: "html",
context: $(this),
success: function(data) {
$($(this).data("ref")).replaceWith($($(this).data("ref")).html(data));
},
error: function (exception) {
console.log(exception);
}
});
});
});
</script>
<link href="{% static "css/ultron.css" %}" rel="stylesheet" />
</div>
<div class="col-4">
{% if last_mindstate or last_height_weigth or mindstate_analyse or height_analyse or weight_analyse %}
<h4>Physiological</h4>
<table class="table">
<tr>
<td class="pt-0 pb-0">Mind state</td>
<td class="pt-0 pb-0">{{ last_mindstate.score }}</td>
<td class="pt-0 pb-0">{{ mindstate_analyse }}</td>
</tr>
<tr>
<td class="pt-0 pb-0">Height</td>
<td class="pt-0 pb-0">{{ last_height_weigth.height }}</td>
<td class="pt-0 pb-0">{{ height_analyse }}</td>
</tr>
<tr>
<td class="pt-0 pb-0">Weight</td>
<td class="pt-0 pb-0">{{ last_height_weigth.weight }}</td>
<td class="pt-0 pb-0">{{ weight_analyse }}</td>
</tr>
</table>
{% endif %}
</div>
</div>
<br />
<div class="row">
<div class="col-8 row">
<div class="col-8">
<h4 class="mb-1">Best ToF</h4>
{% if best_tof_straightjump or best_tof_routine_1 or best_tof_routine_2 %}
<table class="table">
<thead>
<th class="pt-0 pb-0"></th>
<th class="pt-0 pb-0 text-center">Chrono</th>
<th class="pt-0 pb-0 text-center">ToF</th>
<th class="pt-0 pb-0"></th>
</thead>
{% if best_tof_straightjump %}
<tr>
<td class="pt-0 pb-0"><b>ToF |</b></td>
<td class="pt-0 pb-0 text-right">{{ best_tof_straightjump.score }}</td>
<td class="pt-0 pb-0 text-right">{{ best_tof_straightjump.tof }}</td>
<td class="pt-0 pb-0 text-right">{{ best_tof_straightjump.date|date:"j M Y" }}</td>
</tr>
{% endif %}
{% if best_tof_routine_1 %}
<tr>
<td class="pt-0 pb-0"><b>Routine 1</b></td>
<td class="pt-0 pb-0 text-right">{{ best_tof_routine_1.score }}</td>
<td class="pt-0 pb-0 text-right">{{ best_tof_routine_1.tof }}</td>
<td class="pt-0 pb-0 text-right">{{ best_tof_routine_1.date|date:"j M Y" }}</td>
</tr>
{% endif %}
{% if best_tof_routine_2 %}
<tr>
<td class="pt-0 pb-0"><b>Routine 2</b></td>
<td class="pt-0 pb-0 text-right">{{ best_tof_routine_2.score }}</td>
<td class="pt-0 pb-0 text-right">{{ best_tof_routine_2.tof }}</td>
<td class="pt-0 pb-0 text-right">{{ best_tof_routine_2.date|date:"j M Y" }}</td>
</tr>
{% endif %}
</table>
{% endif %}
</div>
<div class="col-10">
<br />
<h4 class="mb-1">Best Scores</h4>
{% if best_point_routine_1 or best_point_routine_2 %}
<table class="table">
<thead>
<th class="pt-0 pb-0"></th>
<th class="pt-0 pb-0 text-center">Exe.</th>
<th class="pt-0 pb-0 text-center">Diff.</th>
<th class="pt-0 pb-0 text-center">HD</th>
<th class="pt-0 pb-0 text-center">ToF</th>
<th class="pt-0 pb-0 text-center">Total</th>
<th class="pt-0 pb-0"></th>
</thead>
{% if best_point_routine_1 %}
<tr>
<td class="pt-0 pb-0"><b>Routine 1</b></td>
<td class="pt-0 pb-0 text-right">{{ best_point_routine_1.point_execution }}</td>
<td class="pt-0 pb-0 text-right">{{ best_point_routine_1.point_difficulty }}</td>
<td class="pt-0 pb-0 text-right">{{ best_point_routine_1.point_horizontal_displacement }}</td>
<td class="pt-0 pb-0 text-right">{{ best_point_routine_1.point_time_of_flight }}</td>
<td class="pt-0 pb-0 text-right">{{ best_point_routine_1.total }}</td>
<td class="pt-0 pb-0 text-right">{{ best_point_routine_1.event.date_begin|date:"j M Y" }}</td>
</tr>
{% endif %}
{% if best_point_routine_2 %}
<tr>
<td class="pt-0 pb-0"><b>Routine 2</b></td>
<td class="pt-0 pb-0 text-right">{{ best_point_routine_2.point_execution }}</td>
<td class="pt-0 pb-0 text-right">{{ best_point_routine_2.point_difficulty }}</td>
<td class="pt-0 pb-0 text-right">{{ best_point_routine_2.point_horizontal_displacement }}</td>
<td class="pt-0 pb-0 text-right">{{ best_point_routine_2.point_time_of_flight }}</td>
<td class="pt-0 pb-0 text-right">{{ best_point_routine_2.total }}</td>
<td class="pt-0 pb-0 text-right">{{ best_point_routine_2.event.date_begin|date:"j M Y" }}</td>
</tr>
{% endif %}
</table>
{% endif %}
</div>
</div>
<div class="col-4 row">
{% if routine_1 or routine_2 %}
<div class="col-12">
<h4 class="mb-1">Routines</h4>
</div>
<div class="col-6">
{% if routine_1 %}
<table class="table">
{% for routine_skill in routine_1.routine.skill_links.all %}
<tr>
<td class="pt-1 pb-0">{{ routine_skill.skill.notation }}</td>
<td class="pt-1 pb-0">{{ routine_skill.skill.difficulty }}</td>
</tr>
{% endfor %}
<tr>
<td class="pt-1 pb-0"></td>
<td class="pt-1 pb-0"><b>{{ routine_1.routine.difficulty }}</b></td>
</tr>
</table>
{% else %}
No compulsary routine defined.
{% endif %}
</div>
<div class="col-6">
{% if routine_2 %}
<table class="table">
{% for routine_skill in routine_2.routine.skill_links.all %}
<tr>
<td class="pt-1 pb-0">{{ routine_skill.skill.notation }}</td>
<td class="pt-1 pb-0">{{ routine_skill.skill.difficulty }}</td>
</tr>
{% endfor %}
<tr>
<td class="pt-1 pb-0"></td>
<td class="pt-1 pb-0"><b>{{ routine_2.routine.difficulty }}</b></td>
</tr>
</table>
{% else %}
No volontary routine defined.
{% endif %}
</div>
{% endif %}
</div>
</div>
<br />
<div class="row" id="learned_skill_and_plan">
<div class="col-6">
<h4 class="mb-1">Last learned skills</h4>
<table class="table">
{% for learned_skill in learned_skills %}
<tr>
<td class="pt-1 pb-0">{{ learned_skill.skill.short_label }}</td>
<td class="pt-1 pb-0">({{ learned_skill.get_learning_step_display }})</td>
<td class="pt-1 pb-0">{{ learned_skill.skill.notation }}</td>
<td class="pt-1 pb-0">{{ learned_skill.date|date:"j M Y" }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="col-5">
<h4>Next skills to learn</h4>
{% if plan_list %}
<table class="table">
{% for plan in plan_list %}
<tr>
<td class="pt-1 pb-0">{{ plan.educative.short_label }}</td>
<td class="pt-1 pb-0">()</td>
<td class="pt-1 pb-0">{{ plan.skill.notation }}</td>
<td class="pt-1 pb-0">{{ plan.date | date:"j M Y" }}</td>
</tr>
{% endfor %}
</table>
{% else %}
No objective defined.
{% endif %}
</div>
</div>
<br />
<div class="row">
<div class="col-6">
<h4 class="mb-1">Next Events</h4>
{% if next_event_list %}
<table class="table">
{% for event in next_event_list %}
<tr>
<td class="pt-1 pb-0">{{ event.date_begin | date:"j M Y" }}</td>
<td class="pt-1 pb-0">in {{ event.number_of_week_from_today }} week(s)</td>
<td class="pt-1 pb-0">{{ event.name }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
</div>
</div>
<br />
<div class="row" id="note">
<div class="col-12">
<h4 class="mb-1">Notes</h4>
{% if notes %}
{% for note in notes %}
{{ note.to_markdown | safe }}
{% endfor %}
{% else %}
No note this week.
{% endif %}
</div>
</div>
</body>
</html>

View File

@ -11,7 +11,7 @@
<h4 class=""><i class="icon-primary fal fa-laugh-wink"></i> Hi {{ user.username }} !</h4>
</div>
<div class="card-body">
Welcome to Ultron v0.71 <span class="text-muted">(last update : 13-11-2022)</span><br />
Welcome to Ultron v0.72 <span class="text-muted">(last update : 19-11-2022)</span><br />
This application is here to help coaches to manage the gymnasts (evolution, evaluation, routines, scores, …).
This tool is not perfect so feel free to make improvement proposals, bug reports, … by sending me an <a href="mailto:gregory@flyingacrobaticstrampoline.be">email</a>.<br />
<br />

View File

@ -566,3 +566,219 @@ def gymnast_display_skill(request, gymnast_id):
name="trainer"
).exists() # TODO: utiliser les {{ perms }}
return render(request, "people/gymnasts/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:
"""
res = ""
mean_value = mean(value_list)
if value > value_list[-1]:
res += "+"
elif value < value_list[-1]:
res += "-"
else:
res += "="
if value > mean_value:
res = "+" + res
elif value < mean_value:
res = "-" + res
else:
res = "=" + res
return res
@login_required
@require_http_methods(["GET"])
def generate_report(request, gymnast_id):
gymnast = get_object_or_404(Gymnast, pk=gymnast_id)
today = pendulum.now().date()
season, week_number = from_date_to_week_number(today)
# season = Season()
#
# PHYSIOLOGICAL INFORMATIONS
#
mindstate_queryset = MindState.objects.filter(gymnast=gymnast).order_by("-date")
last_mindstate = mindstate_queryset.first()
lasts_mindstate = list(mindstate_queryset.values_list("score", flat=True)[1:6])
have_physiological = False
if lasts_mindstate:
mindstate_analyse = analyse_score(last_mindstate.score, lasts_mindstate)
height_weight_queryset = HeightWeight.objects.filter(gymnast=gymnast).order_by(
"-date"
)
last_height_weigth = height_weight_queryset.first()
lasts_height = list(height_weight_queryset.values_list("height", flat=True)[1:6])
lasts_weight = list(height_weight_queryset.values_list("weight", flat=True)[1:6])
if lasts_height:
height_analyse = analyse_score(last_height_weigth.height, lasts_height)
if lasts_weight:
weight_analyse = analyse_score(last_height_weigth.weight, lasts_weight)
#
# 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()
)
#
# ROUTINES
#
routine_1 = (
gymnast.has_routine.filter(routine_type=1)
.filter(date_begin__lte=today)
.filter(Q(date_end__gte=today) | Q(date_end__isnull=True))
.first()
)
routine_2 = (
gymnast.has_routine.filter(routine_type=2)
.filter(date_begin__lte=today)
.filter(Q(date_end__gte=today) | Q(date_end__isnull=True))
.first()
)
# print(routine_2)
#
# LAST LEARNED SKILLS
#
learned_skills = (
LearnedSkill.objects.filter(gymnast=gymnast.id)
.annotate(skill_notation=F("skill__notation"))
.order_by("skill_notation", "-date")
.distinct("skill_notation")[: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=today
).order_by("date_begin")[:5]
#
# NOTES
#
begin_of_the_week = today
if today.weekday() != 0:
begin_of_the_week -= timedelta(today.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": today,
"season": season,
"last_mindstate": last_mindstate,
"mindstate_analyse": mindstate_analyse,
"last_height_weigth": last_height_weigth,
"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,
"routine_1": routine_1,
"routine_2": routine_2,
"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, "people/gymnasts/report.html", context)
response = HttpResponse(content_type="application/pdf")
response[
"Content-Disposition"
] = "inline; filename={lastname}-{firstname}-report.pdf".format(
lastname=gymnast.last_name,
firstname=gymnast.first_name,
)
html = render_to_string("people/gymnasts/report.html", context)
# font_config = FontConfiguration()
HTML(string=html).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