Risk assessment form now validates power training status where required

This commit is contained in:
2022-01-12 19:09:20 +00:00
parent 9c8d8f077d
commit b4c5493705
7 changed files with 53 additions and 61 deletions

23
Pipfile.lock generated
View File

@@ -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": [

View File

@@ -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():

View File

@@ -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 <em>must</em> be a Power Technician or Power Supervisor)")
outside = models.BooleanField(help_text="Is the event outdoors?")

View File

@@ -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

View File

@@ -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

View File

@@ -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 = "<span class='fas fa-{}'></span>".format(self.icon)
icon = f"<span class='fas fa-{self.icon}'></span>"
else:
icon = "".join([w[0] for w in str(self).split()])
return mark_safe("<span class='badge badge-{} badge-pill' data-toggle='tooltip' title='{}'>{}</span>".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"]

View File

@@ -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):