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/ # https://warehouse.python.org/project/whitenoise/
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" 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 static %}
{% load menuitems %}
{% load has_group %}
{% load is_user_equal_to_gymnast %}
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
@ -18,364 +15,253 @@
<link rel="apple-touch-icon" sizes="76x76" href="{% static "img/apple-icon.png" %}"> <link rel="apple-touch-icon" sizes="76x76" href="{% static "img/apple-icon.png" %}">
<link rel="icon" type="image/png" href="{% static "img/favicon.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 --> <!-- Fonts and icons -->
<link href="https://fonts.googleapis.com/css?family=Poppins:200,300,400,600,700,800" rel="stylesheet" /> <link href="https://fonts.googleapis.com/css?family=Poppins:200,300,400,600,700,800" rel="stylesheet" />
<!-- Font Awesome Pro --> <!-- 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" /> <link href="{% static "css/font_awesome_all_5.15.3.css" %}" rel="stylesheet" />
<link href="{% static "css/black-dashboard_report.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" /> -->
</head> </head>
<body class="sidebar-mini white-content"> <header class="white-content">
<div class="content"> <div class="row">
<div class="row"> <div id="header-left" class="col-7 text-12">
<div class="col-12 col-sm-4 col-md-4 col-lg-4"> {{ SITE_TITLE }} - {{ CLUB_NAME }}<br />
<div class="card mb-4"> {{ ADDRESS }} - {{ ZIP }} {{ CITY }}<br />
<div class="card-body"> Season {{ season }} - week {{ week_number }}
<a href="{% url 'gymnast_report_preview' gymnast.id %}">Rapport</a> </div>
<div id="header-right" class="col-5 text-right text-12">
<h4 class="title">{{ gymnast.first_name }} {{ gymnast.last_name }}</h4> Head Coach : {{ HEAD_COACH }}<br />
{{ gymnast.club.name }}<br /> {{ HEAD_COACH_EMAIL }}<br />
<b>{{ gymnast.trainings_by_week }} training/week</b> for <b>{{ gymnast.hours_by_week }} hours/week</b><br /> {{ today | date:"j F Y" }}
{% 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>
</div> </div>
</div> </div>
</header>
<script src="{% static "js/plugins/perfect-scrollbar.jquery_1.4.0.min.js" %}"></script> <br />
<body class="white-content">
<!-- Plugin for Switches, full documentation here: http://www.jque.re/plugins/version3/bootstrap.switch/ --> <div class="row">
<script src="{% static "js/plugins/bootstrap-switch_3.3.4.js" %}"></script> <div class="col-2">
<!-- Plugin for Sweet Alert --> <img src="{% static 'img/default-avatar.png' %}" class="profil_img" />
<script src="{% static "js/plugins/sweetalert2.min.js" %}"></script> </div>
<!-- Plugin for Sorting Tables --> <div class="col-6 pl-0">
<script src="{% static "js/plugins/jquery.tablesorter_2.0.5b.js" %}"></script> <h3 class="title">{{ gymnast.first_name }} {{ gymnast.last_name }}</h3>
<!-- Forms Validations Plugin --> {{ gymnast.age }} years - {{ gymnast.get_orientation_display }} twisting<br />
<script src="{% static "js/plugins/jquery.validate_1.17.0.min.js" %}"></script> {% if gymnast.informations %}
<!-- Plugin for the Wizard, full documentation here: https://github.com/VinceG/twitter-bootstrap-wizard --> {{ gymnast.to_markdown | safe }}
<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';
{% endif %} {% endif %}
</div>
$.ajax({ <div class="col-4">
url: tab_url, {% if last_mindstate or last_height_weigth or mindstate_analyse or height_analyse or weight_analyse %}
dataType: "html", <h4>Physiological</h4>
success: function(data) { <table class="table">
$(tab_div).replaceWith($(tab_div).html(data)); <tr>
}, <td class="pt-0 pb-0">Mind state</td>
error: function (exception) { <td class="pt-0 pb-0">{{ last_mindstate.score }}</td>
console.log(exception); <td class="pt-0 pb-0">{{ mindstate_analyse }}</td>
} </tr>
}); <tr>
<td class="pt-0 pb-0">Height</td>
$('.get-info').click(function(){ <td class="pt-0 pb-0">{{ last_height_weigth.height }}</td>
$.ajax({ <td class="pt-0 pb-0">{{ height_analyse }}</td>
url: default_url + $(this).data("url"), </tr>
dataType: "html", <tr>
context: $(this), <td class="pt-0 pb-0">Weight</td>
success: function(data) { <td class="pt-0 pb-0">{{ last_height_weigth.weight }}</td>
$($(this).data("ref")).replaceWith($($(this).data("ref")).html(data)); <td class="pt-0 pb-0">{{ weight_analyse }}</td>
}, </tr>
error: function (exception) { </table>
console.log(exception); {% endif %}
} </div>
}); </div>
}); <br />
}); <div class="row">
<div class="col-8 row">
</script> <div class="col-8">
<h4 class="mb-1">Best ToF</h4>
<link href="{% static "css/ultron.css" %}" rel="stylesheet" /> {% 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> </body>
</html> </html>

View File

@ -11,7 +11,7 @@
<h4 class=""><i class="icon-primary fal fa-laugh-wink"></i> Hi {{ user.username }} !</h4> <h4 class=""><i class="icon-primary fal fa-laugh-wink"></i> Hi {{ user.username }} !</h4>
</div> </div>
<div class="card-body"> <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 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 /> 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 /> <br />

View File

@ -566,3 +566,219 @@ def gymnast_display_skill(request, gymnast_id):
name="trainer" name="trainer"
).exists() # TODO: utiliser les {{ perms }} ).exists() # TODO: utiliser les {{ perms }}
return render(request, "people/gymnasts/tab_skill.html", context) 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