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 @@
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 %}
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 %}
+
+
+
+
+
+
+ | Name |
+ Supervisor? |
+ - |
+
+
+
+ {% for object in object_list %}
+
+ | {{ object.name }} |
+ No |
+ View Training Record |
+
+ {% empty %}
+
+ | Nothing found |
+
+ {% endfor %}
+
+
+
+
+
+{% 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')
+