From 165402fc49df33d1c3d0b8344bc663fc93884a78 Mon Sep 17 00:00:00 2001 From: Joe Banks Date: Sat, 3 Oct 2026 17:03:26 +0100 Subject: [PATCH] Add dropdown showing which training items technicians can deliver training in --- training/templates/session_log_form.html | 20 ++++++++++++++++++++ training/tests/test_unit.py | 11 +++++++++++ training/views.py | 15 +++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/training/templates/session_log_form.html b/training/templates/session_log_form.html index b52a7705..e3af17a7 100644 --- a/training/templates/session_log_form.html +++ b/training/templates/session_log_form.html @@ -54,6 +54,26 @@ {% button 'submit' %} + {% if request.user.can_log_training and not request.user.is_supervisor %} +
+ +
+
+

You may deliver up to Training Complete in these items, as you are a technician who is passed out in them. Passing people out is for supervisors only.

+ {% for category, items in deliverable_items %} +
{{ category }}
+
    + {% for item in items %}
  • {{ item.display_name }}
  • {% endfor %} +
+ {% empty %} +

You can't currently deliver training in any items. An item must be marked as technician-trainable, you must be passed out in it, and you must hold any technician level its category requires.

+ {% endfor %} +
+
+
+ {% endif %} {% endblock %} diff --git a/training/tests/test_unit.py b/training/tests/test_unit.py index 6a4434f0..05f71d39 100644 --- a/training/tests/test_unit.py +++ b/training/tests/test_unit.py @@ -192,6 +192,12 @@ def test_technician_session_log(client, trainee, supervisor, admin_user): assert models.TrainingItemQualification.objects.filter( trainee=admin_user.pk, item=item, depth=models.TrainingItemQualification.COMPLETE ).exists() + # The list of deliverable items is shown, and only contains permitted items + response = client.get(url) + assertContains(response, "What training items can I deliver training in?") + assert [(c.pk, [i.pk for i in items]) for c, items in response.context["deliverable_items"]] == [ + (item.category.pk, [item.pk]) + ] # Passing out is not allowed response = client.post(url, {**data, "items_1": [], "items_2": [item.pk]}) assert response.status_code == 200 @@ -204,3 +210,8 @@ def test_technician_session_log(client, trainee, supervisor, admin_user): def test_plain_trainee_cannot_log_session(client, trainee): client.force_login(trainee) assert client.get(reverse("session_log")).status_code == 403 + + +def test_supervisor_does_not_see_deliverable_items(admin_client): + response = admin_client.get(reverse("session_log")) + assertNotContains(response, "What training items can I deliver training in?") diff --git a/training/views.py b/training/views.py index 218c69a5..b1cc6d8e 100644 --- a/training/views.py +++ b/training/views.py @@ -291,10 +291,25 @@ class SessionLog(generic.FormView): context = super().get_context_data(**kwargs) context["depths"] = models.TrainingItemQualification.CHOICES context["page_title"] = "Log Training Session" + if not self.request.user.is_supervisor: + context["deliverable_items"] = self.get_deliverable_items() get_related(context["form"], context) return context + def get_deliverable_items(self): + """Active items the current user may deliver training in, grouped by category, using the same test as form validation""" + trainee = models.Trainee.objects.get(pk=self.request.user.pk) + items = models.TrainingItem.objects.filter(active=True, technician_can_train=True).select_related( + "category", "category__training_level" + ) + grouped = {} + for item in items: + if trainee.can_deliver_training(item, models.TrainingItemQualification.COMPLETE): + grouped.setdefault(item.category, []).append(item) + return list(grouped.items()) + + class ItemQualifications(generic.ListView): template_name = "item_qualification_list.html" model = models.TrainingItemQualification