System for allowing certain TrainingCategories to be trained by certain levels, regardless of supervisor status

I.e. the haulage department, ref #482. As generic as I can make it I think.
This commit is contained in:
2022-01-25 13:04:26 +00:00
parent 15ab626593
commit 33754eed60
5 changed files with 34 additions and 6 deletions

View File

@@ -23,9 +23,13 @@ class QualificationForm(forms.ModelForm):
def clean_supervisor(self):
supervisor = self.cleaned_data['supervisor']
item = self.cleaned_data['item']
if supervisor.pk == self.cleaned_data['trainee'].pk:
raise forms.ValidationError('One may not supervise oneself...')
if not supervisor.is_supervisor:
if item.category.training_level:
if not supervisor.level_qualifications.filter(level=item.category.training_level):
raise forms.ValidationError('Selected supervising person is missing requisite training level to train in this department')
elif not supervisor.is_supervisor:
raise forms.ValidationError('Selected supervisor must actually *be* a supervisor...')
return supervisor

View File

@@ -0,0 +1,19 @@
# Generated by Django 3.2.11 on 2022-01-25 12:58
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('training', '0002_alter_traininglevel_options'),
]
operations = [
migrations.AddField(
model_name='trainingcategory',
name='training_level',
field=models.ForeignKey(help_text='If this is set, any user with the selected level may pass out users within this category, regardless of other status', null=True, on_delete=django.db.models.deletion.CASCADE, to='training.traininglevel'),
),
]

View File

@@ -15,22 +15,26 @@ class Trainee(Profile, RevisionMixin):
def started_levels(self):
return [level for level in TrainingLevel.objects.all() if level.percentage_complete(self) > 0 and level.pk not in self.level_qualifications.values_list('level', flat=True)]
@property
def confirmed_levels(self):
return self.level_qualifications.exclude(confirmed_on=None).select_related('level')
@property
def is_technician(self):
return self.level_qualifications.exclude(confirmed_on=None).select_related('level') \
return self.confirmed_levels \
.filter(level__level=TrainingLevel.TECHNICIAN) \
.exclude(level__department=TrainingLevel.HAULAGE) \
.exclude(level__department__isnull=True).exists()
@property
def is_driver(self):
return self.level_qualifications.all().exclude(confirmed_on=None).select_related('level').filter(level__department=TrainingLevel.HAULAGE).exists()
return self.confirmed_levels.filter(level__department=TrainingLevel.HAULAGE).exists()
def get_records_of_depth(self, depth):
return self.qualifications_obtained.filter(depth=depth).select_related('item', 'trainee', 'supervisor')
def is_user_qualified_in(self, item, required_depth):
return self.qualifications_obtained.values('item', 'depth').filter(item=item).filter(depth__gte=required_depth).first() is not None # this is a somewhat ghetto version of get_or_none
return self.qualifications_obtained.values('item', 'depth').filter(item=item).filter(depth__gte=required_depth).exists()
def get_absolute_url(self):
return reverse('trainee_detail', kwargs={'pk': self.pk})
@@ -47,6 +51,7 @@ class Trainee(Profile, RevisionMixin):
class TrainingCategory(models.Model):
reference_number = models.IntegerField(unique=True)
name = models.CharField(max_length=50)
training_level = models.ForeignKey('TrainingLevel', on_delete=models.CASCADE, null=True, help_text="If this is set, any user with the selected level may pass out users within this category, regardless of other status")
def __str__(self):
return f"{self.reference_number}. {self.name}"

View File

@@ -42,7 +42,7 @@
</div>
<div class="form-group form-row">
<label for="supervisor" class="col-sm-2 col-form-label">Supervisor</label>
<select name="supervisor" id="supervisor_id" class="form-control selectpicker custom-select col-sm-10" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials&filters=is_supervisor" required>
<select name="supervisor" id="supervisor_id" class="form-control selectpicker custom-select col-sm-10" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials" required>
{% if object.supervisor %}
<option value="{{object.supervisor.pk}}" selected>{{object.supervisor}}</option>
{% endif %}

View File

@@ -23,7 +23,7 @@
class="form-control" id="id_search_text"/>
<span class="input-group-append">{% button 'search' id="id_search" %}</span>
</div>
<button type="submit" class="btn btn-primary mt-2 {% if request.GET.is_supervisor %}active{%endif%}" data-toggle="button" aria-pressed="false" name="is_supervisor" value="{% if request.GET.is_supervisor %}{% else %}True{% endif %}">
<button type="submit" class="btn btn-primary mt-2 {% if request.GET.is_supervisor %}active{%endif%}" data-toggle="button" aria-pressed="{% if request.GET.is_supervisor %}true{%endif%}" name="is_supervisor" value="{% if request.GET.is_supervisor %}{% else %}True{% endif %}">
Only Supervisors
</button>
</form>