From b4c5493705beeb301bc81ca644bb555e434ae680 Mon Sep 17 00:00:00 2001 From: FreneticScribbler Date: Wed, 12 Jan 2022 19:09:20 +0000 Subject: [PATCH] Risk assessment form now validates power training status where required --- Pipfile.lock | 23 ++++++++++++----------- RIGS/forms.py | 4 ++++ RIGS/models.py | 21 ++++++++++----------- conftest.py | 4 +--- training/forms.py | 7 ------- training/models.py | 42 ++++++++++++++++++++---------------------- training/views.py | 13 ++++++------- 7 files changed, 53 insertions(+), 61 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 14ec9a11..1340ca7b 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -309,10 +309,11 @@ }, "django-hcaptcha": { "hashes": [ - "sha256:2b80197c07bb8444249bcce3758b0472d369cca309fb02d7abcd0a856431b76b" + "sha256:18804fb38a01827b6c65d111bac31265c1b96fcf52d7a54c3e2d2cb1c62ddcde", + "sha256:b2519eaf0cc97865ac72f825301122c5cf61e1e4852d6895994160222acb6c1a" ], "index": "pypi", - "version": "==0.1.0" + "version": "==0.2.0" }, "django-htmlmin": { "hashes": [ @@ -362,11 +363,11 @@ }, "django-widget-tweaks": { "hashes": [ - "sha256:19bcb66a4a9e68493ced04e7124882d753c5be517ed001556f9e35a40147f545", - "sha256:d6c64fbf92cd2df9031f597c1374982233c05a1190d295c39d1c57ce007569c7" + "sha256:01b911a1b47629de0a3a3097774798dee4eb703b94d41666929f688d5f77c723", + "sha256:07674e32031eda81077f0b8e390ce78d1d415e700cedd0396ef0ce452e95b94d" ], "index": "pypi", - "version": "==1.4.9" + "version": "==1.4.11" }, "envparse": { "hashes": [ @@ -861,11 +862,11 @@ }, "sentry-sdk": { "hashes": [ - "sha256:2a1757d6611e4bec7d672c2b7ef45afef79fed201d064f53994753303944f5a8", - "sha256:e4cb107e305b2c1b919414775fa73a9997f996447417d22b98e7610ded1e9eb5" + "sha256:2cec50166bcb67e1965f8073541b2321e3864cd6fd42a526bcde9f0c4e4cc3f8", + "sha256:7bbaa32bba806ec629962f207b597e86831c7ee2c1f287c21ba7de7fea9a9c46" ], "index": "pypi", - "version": "==1.5.1" + "version": "==1.5.2" }, "simplejson": { "hashes": [ @@ -1538,11 +1539,11 @@ }, "pytest-reverse": { "hashes": [ - "sha256:9f2a3b163378922dd332ed056a58af4cfd1ccc8ad4a76606f43ed43cfff2140b", - "sha256:d878e28c785fb20291580aa816d566a21beac508e06a2c9eb4f934d49c31ce5c" + "sha256:1695b7c9e51b28db5af13d579b33b54a80958d86b886dfabd2a246bcad3e082e", + "sha256:6acfb50acd11caf3d222366f5e1458dea2351d47b6ca5b08ab408158636250ba" ], "index": "pypi", - "version": "==1.3.0" + "version": "==1.4.0" }, "pytest-splinter": { "hashes": [ diff --git a/RIGS/forms.py b/RIGS/forms.py index 28c660ea..258928d0 100644 --- a/RIGS/forms.py +++ b/RIGS/forms.py @@ -8,6 +8,7 @@ from django.utils import timezone from reversion import revisions as reversion from RIGS import models +from training.models import TrainingLevel # Override the django form defaults to use the HTML date/time/datetime UI elements forms.DateField.widget = forms.DateInput(attrs={'type': 'date'}) @@ -164,6 +165,9 @@ class EventRiskAssessmentForm(forms.ModelForm): ], attrs={'class': 'custom-control-input', 'required': 'true'}) def clean(self): + if self.cleaned_data.get('big_power'): + if not self.cleaned_data.get('power_mic').level_qualifications.filter(level__department=TrainingLevel.POWER).exists(): + self.add_error('power_mic', forms.ValidationError("Your Power MIC must be a Power Technician.", code="power_tech_required")) # Check expected values unexpected_values = [] for field, value in models.RiskAssessment.expected_values.items(): diff --git a/RIGS/models.py b/RIGS/models.py index 90b0c3d5..16e936b1 100644 --- a/RIGS/models.py +++ b/RIGS/models.py @@ -99,7 +99,7 @@ class RevisionMixin(object): version = self.current_version if version is None: return None - return "V{0} | R{1}".format(version.pk, version.revision.pk) + return f"V{version.pk} | R{version.revision.pk}" class Person(models.Model, RevisionMixin): @@ -207,7 +207,7 @@ class VatRate(models.Model, RevisionMixin): get_latest_by = 'start_at' def __str__(self): - return self.comment + " " + str(self.start_at) + " @ " + str(self.as_percent) + "%" + return f"{self.comment} {self.start_at} @ {self.as_percent}%" class Venue(models.Model, RevisionMixin): @@ -347,10 +347,10 @@ class Event(models.Model, RevisionMixin): if self.pk: if self.is_rig: return str("N%05d" % self.pk) - else: - return self.pk - else: - return "????" + + return self.pk + + return "????" # Calculated values """ @@ -475,7 +475,7 @@ class Event(models.Model, RevisionMixin): return reverse('event_detail', kwargs={'pk': self.pk}) def __str__(self): - return "{}: {}".format(self.display_id, self.name) + return f"{self.display_id}: {self.name}" def clean(self): errdict = {} @@ -521,11 +521,11 @@ class EventItem(models.Model, RevisionMixin): ordering = ['order'] def __str__(self): - return "{}.{}: {} | {}".format(self.event_id, self.order, self.event.name, self.name) + return f"{self.event_id}.{self.order}: {self.event.name} | {self.name}" @property def activity_feed_string(self): - return str("item {}".format(self.name)) + return f"item {self.name}" @reversion.register @@ -543,7 +543,7 @@ class EventAuthorisation(models.Model, RevisionMixin): @property def activity_feed_string(self): - return "{} (requested by {})".format(self.event.display_id, self.sent_by.initials) + return f"{self.event.display_id} (requested by {self.sent_by.initials})" class InvoiceManager(models.Manager): @@ -671,7 +671,6 @@ class RiskAssessment(models.Model, RevisionMixin): # Power big_power = models.BooleanField(help_text="Does the event require larger power supplies than 13A or 16A single phase wall sockets, or draw more than 20A total current?") - # If yes to the above two, you must answer... power_mic = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='power_mic', blank=True, null=True, verbose_name="Power MIC", on_delete=models.CASCADE, help_text="Who is the Power MIC? (if yes to the above question, this person must be a Power Technician or Power Supervisor)") outside = models.BooleanField(help_text="Is the event outdoors?") diff --git a/conftest.py b/conftest.py index 3e5b278a..ac203464 100644 --- a/conftest.py +++ b/conftest.py @@ -2,9 +2,7 @@ from django.conf import settings import django import pytest from django.core.management import call_command -from RIGS.models import VatRate, Profile -import random -from django.db import connection +from RIGS.models import VatRate from PyRIGS.tests import pages import os from selenium import webdriver diff --git a/training/forms.py b/training/forms.py index 9cfcf368..9f4dbbf6 100644 --- a/training/forms.py +++ b/training/forms.py @@ -1,15 +1,8 @@ from django import forms -from datetime import date - from training import models from RIGS.models import Profile - -class SessionLogForm(forms.Form): - pass - - class QualificationForm(forms.ModelForm): class Meta: model = models.TrainingItemQualification diff --git a/training/models.py b/training/models.py index edea755a..558277fc 100644 --- a/training/models.py +++ b/training/models.py @@ -1,10 +1,8 @@ -from django.db import models - from RIGS.models import RevisionMixin, Profile from reversion import revisions as reversion +from django.db import models from django.urls import reverse - -from django.utils.safestring import SafeData, mark_safe +from django.utils.safestring import mark_safe @reversion.register(for_concrete_model=False, fields=[], follow=["qualifications_obtained", "level_qualifications"]) @@ -105,13 +103,13 @@ class TrainingItemQualification(models.Model, RevisionMixin): return str("{} in {}".format(self.get_depth_display(), self.item)) @classmethod - def get_colour_from_depth(obj, depth): + def get_colour_from_depth(cls, obj, depth): if depth == 0: return "warning" - elif depth == 1: + if depth == 1: return "success" - else: - return "info" + + return "info" def get_absolute_url(self): return reverse('trainee_item_detail', kwargs={'pk': self.trainee.pk}) @@ -157,16 +155,16 @@ class TrainingLevel(models.Model, RevisionMixin): def department_colour(self): if self.department == self.SOUND: return "info" - elif self.department == self.LIGHTING: + if self.department == self.LIGHTING: return "dark" - elif self.department == self.POWER: + if self.department == self.POWER: return "danger" - elif self.department == self.RIGGING: + if self.department == self.RIGGING: return "warning" - elif self.department == self.HAULAGE: + if self.department == self.HAULAGE: return "light" - else: - return "primary" + + return "primary" def get_requirements_of_depth(self, depth): return self.requirements.filter(depth=depth) @@ -197,8 +195,8 @@ class TrainingLevel(models.Model, RevisionMixin): if len(needed_qualifications) > 0: return int(relavant_qualifications / float(len(needed_qualifications)) * 100) - else: - return 0 + + return 0 def user_has_requirements(self, user): has_required_items = all(TrainingItem.user_has_qualification(req.item, user, req.depth) for req in self.requirements.all()) @@ -225,7 +223,7 @@ class TrainingLevel(models.Model, RevisionMixin): @property def get_icon(self): if self.icon is not None: - icon = "".format(self.icon) + icon = f"" else: icon = "".join([w[0] for w in str(self).split()]) return mark_safe("{}".format(self.department_colour, str(self), icon)) @@ -260,14 +258,14 @@ class TrainingLevelQualification(models.Model, RevisionMixin): return self.level.get_icon def clean(self): - if level.level >= TrainingLevel.SUPERVISOR and level.department != TrainingLevel.HAULAGE: - trainee.is_supervisor = True - trainee.save() + if self.level.level >= TrainingLevel.SUPERVISOR and self.level.department != TrainingLevel.HAULAGE: + self.trainee.is_supervisor = True + self.trainee.save() def __str__(self): if self.level.is_common_competencies: - return "{} is qualified in the {}".format(self.trainee, self.level) - return "{} is qualified as a {}".format(self.trainee, self.level) + return f"{self.trainee} is qualified in the {self.level}" + return f"{self.trainee} is qualified as a {self.level}" class Meta: unique_together = ["trainee", "level"] diff --git a/training/views.py b/training/views.py index 8f2f449e..dbf9cf26 100644 --- a/training/views.py +++ b/training/views.py @@ -1,14 +1,13 @@ import reversion -from django.shortcuts import render from django.urls import reverse_lazy from django.views import generic -from PyRIGS.views import OEmbedView, is_ajax, ModalURLMixin -from training import models, forms from django.utils import timezone from django.db import transaction -from django.db.models import Q, Count, OuterRef, F, Subquery, Window +from django.db.models import Q, Count +from PyRIGS.views import is_ajax, ModalURLMixin +from training import models, forms from users import views @@ -98,12 +97,12 @@ class TraineeList(generic.ListView): def get_queryset(self): q = self.request.GET.get('q', "") - filter = Q(first_name__icontains=q) | Q(last_name__icontains=q) | Q(initials__icontains=q) + fil = Q(first_name__icontains=q) | Q(last_name__icontains=q) | Q(initials__icontains=q) # try and parse an int try: val = int(q) - filter = filter | Q(pk=val) + fil = fil | Q(pk=val) except: # noqa # not an integer pass @@ -200,7 +199,7 @@ class RemoveRequirement(generic.DeleteView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - context["page_title"] = "Delete Requirement '{}' from Training Level {}?".format(self.object, self.object.level) + context["page_title"] = f"Delete Requirement '{self.object}' from Training Level {self.object.level}?" return context def get_success_url(self):