From 0a9f82e4803cd89549633b0cdac874427a9ff446 Mon Sep 17 00:00:00 2001 From: Arona Jones Date: Wed, 7 Jul 2021 17:34:19 +0100 Subject: [PATCH] Fettling with level granting logic Untested as all of my forms broke I guess --- RIGS/templatetags/filters.py | 4 +++ gulpfile.js | 2 +- templates/index.html | 3 +- training/models.py | 30 +++++++++++++--- training/templates/edit_training_level.html | 4 +-- training/templates/trainee_detail.html | 15 +++++--- training/templates/trainee_list.html | 38 +++++++++++++++++++++ training/urls.py | 1 + training/views.py | 11 ++++++ 9 files changed, 96 insertions(+), 12 deletions(-) create mode 100644 training/templates/trainee_list.html diff --git a/RIGS/templatetags/filters.py b/RIGS/templatetags/filters.py index 078ea459..60f31088 100644 --- a/RIGS/templatetags/filters.py +++ b/RIGS/templatetags/filters.py @@ -198,6 +198,10 @@ def user_has_qualification(user, item, depth): else: return mark_safe("") +@register.simple_tag +def user_level_if_present(user, level): + return tmodels.TrainingLevelQualification.objects.filter(trainee=user, level=level).first() + @register.simple_tag def percentage_complete(level, user): return level.percentage_complete(user) diff --git a/gulpfile.js b/gulpfile.js index 73200aaa..253673d8 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -83,7 +83,7 @@ function browserSync(done) { notify: false, open: false, port: 8001, - proxy: 'localhost:8000' + proxy: '127.0.0.1:8000' }); done(); } diff --git a/templates/index.html b/templates/index.html index f99eac8a..95217373 100644 --- a/templates/index.html +++ b/templates/index.html @@ -43,7 +43,8 @@

Training Database

- My Training Record + My Training Record + View Training Records View Training Items Log Training Session
diff --git a/training/models.py b/training/models.py index a63cab16..3f792f97 100644 --- a/training/models.py +++ b/training/models.py @@ -8,9 +8,19 @@ class Trainee(Profile): class Meta: proxy = True + @property + def is_supervisor(self): + for level_qualification in self.levels.all(): + if confirmed_on is not None and level_qualification.level.level >= TrainingLevel.SUPERVISOR: + return True + def get_records_of_depth(self, depth): return self.qualifications_obtained.filter(depth=depth) + def is_user_qualified_in(self, item, required_depth): + qual = self.qualifications_obtained.get(item=item) + return qual is not None and qual.depth >= required_depth + # Items class TrainingCategory(models.Model): reference_number = models.CharField(max_length=3) @@ -27,9 +37,10 @@ class TrainingItem(models.Model): def __str__(self): return "{}.{} {}".format(self.category.reference_number, self.reference_number, self.name) - def user_has_qualification(self, user, depth): + @staticmethod + def user_has_qualification(item, user, depth): for q in user.qualifications_obtained.all(): - if q.item == self and q.depth > depth: + if q.item == item and q.depth > depth: return True @@ -49,10 +60,17 @@ class TrainingItemQualification(models.Model): # TODO Remember that some training is external. Support for making an organisation the trainer? supervisor = models.ForeignKey('Trainee', related_name='qualifications_granted', on_delete=models.RESTRICT) notes = models.TextField(blank=True) + # TODO Maximum depth - some things stop at Complete and you can't be passed out in them def __str__(self): return "{} in {} on {}".format(self.depth, self.item, self.date) + def save(self, *args, **kwargs): + super().save() + for level in TrainingLevel.models.all(): # Mm yes efficiency + if level.user_has_requirements(self.trainee): + level_qualification = models.TrainingLevelQualification.create(trainee=self.trainee, level=level) + # Levels class TrainingLevel(models.Model, RevisionMixin): @@ -99,6 +117,10 @@ class TrainingLevel(models.Model, RevisionMixin): else: return 0 + def user_has_requirements(self, user): + return all(TrainingItem.user_has_qualification(req.item, user, req.depth) for req in self.requirements.all()) + + def __str__(self): if self.department is None: # 2TA return self.get_level_display() @@ -118,5 +140,5 @@ class TrainingLevelRequirement(models.Model): class TrainingLevelQualification(models.Model): trainee = models.ForeignKey('Trainee', related_name='levels', on_delete=models.RESTRICT) level = models.ForeignKey('TrainingLevel', on_delete=models.RESTRICT) - confirmed_on = models.DateTimeField() - confirmed_by = models.ForeignKey('Trainee', related_name='confirmer', on_delete=models.RESTRICT) + confirmed_on = models.DateTimeField(null=True) + confirmed_by = models.ForeignKey('Trainee', related_name='confirmer', on_delete=models.RESTRICT, null=True) diff --git a/training/templates/edit_training_level.html b/training/templates/edit_training_level.html index 4f529493..c2094d52 100644 --- a/training/templates/edit_training_level.html +++ b/training/templates/edit_training_level.html @@ -24,7 +24,7 @@ {% include 'form_errors.html' %} {% endif %}
{% csrf_token %} - {% render_field form.level|attr:'hidden' value=form.trainee.initial %} + {% render_field form.level|attr:'hidden' value=form.level.initial %}
diff --git a/training/templates/trainee_detail.html b/training/templates/trainee_detail.html index 5dee7551..ac7117dd 100644 --- a/training/templates/trainee_detail.html +++ b/training/templates/trainee_detail.html @@ -2,6 +2,7 @@ {% load user_has_qualification from filters %} {% load percentage_complete from filters %} +{% load user_level_if_present from filters %} {% block content %}
@@ -11,6 +12,7 @@

Training Levels

+

Technical Assistant is conferred automatically when the item requirements are met. Technician status is also automatic, but notification of status should be made at the next general meeting, at which point 'approval' should be granted on the system. Supervisor status is not automatic and until signed off at a general meeting, does not count.Correct as of 7th July 2021, check the Training Policy.

{% for level in levels %}
@@ -37,16 +39,21 @@ -
    {% for req in level.started_requirements %}
  • {{ req.item }} {% user_has_qualification request.user req.item 0 %}
  • {% endfor %}
-
    {% for req in level.complete_requirements %}
  • {{ req.item }} {% user_has_qualification request.user req.item 1 %}
  • {% endfor %}
-
    {% for req in level.passed_out_requirements %}
  • {{ req.item }} {% user_has_qualification request.user req.item 2 %}
  • {% endfor %}
+
    {% for req in level.started_requirements %}
  • {{ req.item }} {% user_has_qualification object req.item 0 %}
  • {% endfor %}
+
    {% for req in level.complete_requirements %}
  • {{ req.item }} {% user_has_qualification object req.item 1 %}
  • {% endfor %}
+
    {% for req in level.passed_out_requirements %}
  • {{ req.item }} {% user_has_qualification object req.item 2 %}
  • {% endfor %}
{% endfor %} diff --git a/training/templates/trainee_list.html b/training/templates/trainee_list.html new file mode 100644 index 00000000..d1e67fe0 --- /dev/null +++ b/training/templates/trainee_list.html @@ -0,0 +1,38 @@ +{% extends 'base_training.html' %} + +{% load url_replace from filters %} +{% load orderby from filters %} +{% load paginator from filters %} +{% load linkornone from filters %} +{% load button from filters %} + +{% block content %} +
+
+
+ + + + + + + + + + {% for object in object_list %} + + + + + + {% empty %} + + + + {% endfor %} + +
NameSupervisor?-
{{ object.name }}No View Training Record
Nothing found
+
+
+
+{% endblock %} diff --git a/training/urls.py b/training/urls.py index 11aa55fb..500f315a 100644 --- a/training/urls.py +++ b/training/urls.py @@ -8,6 +8,7 @@ from training import views urlpatterns = [ path('items/', views.ItemList.as_view(), name='item_list'), + path('trainee/list/', views.TraineeList.as_view(), name='trainee_list'), path('trainee/', login_required(views.TraineeDetail.as_view()), name='trainee_detail'), path('trainee//', permission_required_with_403('RIGS.view_profile')(views.TraineeDetail.as_view()), diff --git a/training/views.py b/training/views.py index e0e502a4..40ff20eb 100644 --- a/training/views.py +++ b/training/views.py @@ -34,6 +34,16 @@ class TraineeDetail(views.ProfileDetail): return context +class TraineeList(generic.ListView): + model = models.Trainee + template_name = 'trainee_list.html' + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["page_title"] = "Profile List" + return context + + class SessionLog(generic.FormView): template_name = "session_log_form.html" form_class = forms.SessionLogForm @@ -109,3 +119,4 @@ class RemoveRequirement(generic.DeleteView): def get_success_url(self): return self.request.POST.get('next') +