FEAT(T): First version of the 'session log' form

This commit is contained in:
2022-02-27 21:20:34 +00:00
parent ab03ad081a
commit 5eb113156b
12 changed files with 122 additions and 45 deletions

View File

@@ -35,6 +35,13 @@ def is_ajax(request):
return request.headers.get('x-requested-with') == 'XMLHttpRequest'
def get_related(form, context): # Get some other objects to include in the form. Used when there are errors but also nice and quick.
for field, model in form.related_models.items():
value = form[field].value()
if value is not None and value != '':
context[field] = model.objects.get(pk=value)
class Index(generic.TemplateView): # Displays the current rig count along with a few other bits and pieces
template_name = 'index.html'

View File

@@ -21,7 +21,7 @@ from django.utils.decorators import method_decorator
from django.views import generic
from PyRIGS import decorators
from PyRIGS.views import OEmbedView, is_ajax, ModalURLMixin, PrintView
from PyRIGS.views import OEmbedView, is_ajax, ModalURLMixin, PrintView, get_related
from RIGS import models, forms
__author__ = 'ghost'
@@ -77,13 +77,6 @@ class EventOEmbed(OEmbedView):
url_name = 'event_embed'
def get_related(form, context): # Get some other objects to include in the form. Used when there are errors but also nice and quick.
for field, model in form.related_models.items():
value = form[field].value()
if value is not None and value != '':
context[field] = model.objects.get(pk=value)
class EventCreate(generic.CreateView):
model = models.Event
form_class = forms.EventForm

View File

@@ -6,6 +6,10 @@ from reversion.admin import VersionAdmin
admin.site.register(models.TrainingCategory, VersionAdmin)
admin.site.register(models.TrainingItem, VersionAdmin)
admin.site.register(models.TrainingLevel, VersionAdmin)
admin.site.register(models.TrainingItemQualification, VersionAdmin)
admin.site.register(models.TrainingLevelQualification, VersionAdmin)
admin.site.register(models.TrainingLevelRequirement, VersionAdmin)
@admin.register(models.TrainingItemQualification)
class TrainingItemQualificationAdmin(VersionAdmin):
list_display = ['__str__', 'trainee']

View File

@@ -1,21 +1,24 @@
import datetime
from django import forms
from training import models
from RIGS.models import Profile
def validate_user_can_train_in(supervisor, item):
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...')
class QualificationForm(forms.ModelForm):
class Meta:
model = models.TrainingItemQualification
fields = '__all__'
def __init__(self, *args, **kwargs):
pk = kwargs.pop('pk', None)
super().__init__(*args, **kwargs)
if pk:
self.fields['trainee'].initial = Profile.objects.get(pk=pk)
self.fields['date'].widget.format = '%Y-%m-%d'
def clean(self):
cleaned_data = super().clean()
item = cleaned_data.get('item')
@@ -34,13 +37,16 @@ class QualificationForm(forms.ModelForm):
item = self.cleaned_data['item']
if supervisor.pk == self.cleaned_data['trainee'].pk:
raise forms.ValidationError('One may not supervise oneself...')
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...')
validate_user_can_train_in(supervisor, item)
return supervisor
def __init__(self, *args, **kwargs):
pk = kwargs.pop('pk', None)
super().__init__(*args, **kwargs)
if pk:
self.fields['trainee'].initial = Profile.objects.get(pk=pk)
self.fields['date'].widget.format = '%Y-%m-%d'
class RequirementForm(forms.ModelForm):
depth = forms.ChoiceField(choices=models.TrainingItemQualification.CHOICES)
@@ -53,3 +59,27 @@ class RequirementForm(forms.ModelForm):
pk = kwargs.pop('pk', None)
super().__init__(*args, **kwargs)
self.fields['level'].initial = models.TrainingLevel.objects.get(pk=pk)
class SessionLogForm(forms.Form):
trainees = forms.ModelMultipleChoiceField(models.Trainee.objects.all())
items = forms.ModelMultipleChoiceField(models.TrainingItem.objects.all())
depth = forms.ChoiceField(choices=models.TrainingItemQualification.CHOICES)
supervisor = forms.ModelChoiceField(models.Trainee.objects.all())
date = forms.DateField(initial=datetime.date.today)
notes = forms.CharField(required=False, widget=forms.Textarea)
related_models = {
'supervisor': models.Trainee
}
def clean_date(self):
return QualificationForm.clean_date(self)
def clean_supervisor(self):
supervisor = self.cleaned_data['supervisor']
if supervisor in self.cleaned_data.get('trainees', []):
raise forms.ValidationError('One may not supervise oneself...')
for item in self.cleaned_data.get('items', []):
validate_user_can_train_in(supervisor, item)
return supervisor

View File

@@ -55,7 +55,7 @@ class Command(BaseCommand):
supervisor = Profile.objects.create(username="supervisor", first_name="Super", last_name="Visor",
initials="SV",
email="supervisor@example.com", is_active=True,
is_staff=True, is_approved=True)
is_staff=True, is_approved=True, is_supervisor=True)
supervisor.set_password('supervisor')
supervisor.groups.add(Group.objects.get(name="Keyholders"))
supervisor.save()

View File

@@ -1,5 +1,7 @@
import datetime
from RIGS.models import Profile, filter_by_pk
from reversion import revisions as reversion
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import Q, F, Value, CharField
from django.db.models.functions import Concat
@@ -8,6 +10,7 @@ from django.utils.safestring import mark_safe
from versioning.versioning import RevisionMixin
from queryable_properties.properties import queryable_property
from queryable_properties.managers import QueryablePropertiesManager
from django.utils.translation import gettext_lazy as _
class TraineeManager(models.Manager):
@@ -351,6 +354,9 @@ class TrainingLevelQualification(models.Model, RevisionMixin):
def activity_feed_string(self):
return str(self)
def get_absolute_url(self):
return reverse('trainee_detail', kwargs={'pk': self.trainee.pk})
class Meta:
unique_together = ["trainee", "level"]
ordering = ['-confirmed_on']

View File

@@ -30,6 +30,9 @@
<a class="dropdown-item" href="{% url 'item_list' %}"><span class="fas fa-sitemap"></span> Item List</a>
</div>
</li>
{% if perms.training.add_trainingitemqualification or request.user.is_supervisor %}
<li class="nav-item"><a class="nav-link" href="{% url 'session_log' %}"><span class="fas fa-users"></span> Log Session</a></li>
{% endif %}
<li class="nav-item"><a class="nav-link" href="{% url 'training_activity_table' %}"><span class="fas fa-random"></span> Recent Changes</a></li>
{% endif %}
{% endblock %}

View File

@@ -41,12 +41,7 @@
{% render_field form.depth|add_class:'form-control custom-select col-sm-8' %}
</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="selectpicker px-0 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 %}
</select>
{% include 'partials/supervisor_field.html' %}
</div>
<div class="form-group form-row">
<label for="date" class="col-sm-2 col-form-label">Training Date</label>

View File

@@ -0,0 +1,6 @@
<label for="supervisor" class="col-sm-2 col-form-label">Supervisor</label>
<select name="supervisor" id="supervisor_id" class="selectpicker col-sm-10" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials" required>
{% if supervisor %}
<option value="{{form.supervisor.value}}" selected="selected">{{ supervisor }}</option>
{% endif %}
</select>

View File

@@ -1,4 +1,4 @@
{% extends 'base_rigs.html' %}
{% extends 'base_training.html' %}
{% load static %}
{% load button from filters %}
@@ -23,27 +23,34 @@
{% block content %}
<div class="row">
<div class="col">
<form class="form">
<form class="form" method="POST" id="session_form" action="{% url 'session_log' %}">
{% include 'form_errors.html' %}
{% csrf_token %}
<h3>People</h3>
<div class="form-group">
<label for="selectpicker">Select Supervisor</label>
<select name="supervisor" id="supervisor_id" class="form-control selectpicker custom-select" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
</select>
<div class="form-group row">
{% include 'partials/supervisor_field.html' %}
</div>
<div class="form-group">
<label for="selectpicker">Select Attendees</label>
<select multiple name="attendees" id="attendees_id" class="form-control selectpicker custom-select" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
<div class="form-group row">
<label for="trainees_id" class="col-sm-2">Select Attendees</label>
<select multiple name="trainees" id="trainees_id" class="selectpicker col-sm-10" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
</select>
</div>
<h3>Training Items</h3>
<div class="row">
{% for depth in depths %}
<div class="col">
<h4>{{ depth.1 }}</h4>
<select multiple name="{{ depth.0 }}" id="{{ depth.0 }}_id" class="form-control selectpicker custom-select" data-live-search="true" data-sourceurl="{% url 'api_secure' model='training_item' %}">
</select>
<div class="row px-3">
<div class="form-group">
<label for="selectpicker">Training Items</label>
<select multiple name="items" id="items_id" class="selectpicker col-12 px-0" data-live-search="true" data-sourceurl="{% url 'api_secure' model='training_item' %}?fields=description,reference_number&filters=active">
</select>
</div>
{% endfor %}
<div class="form-group pl-3">
{% include 'partials/form_field.html' with field=form.depth %}
</div>
<div class="form-group pl-3">
{% include 'partials/form_field.html' with field=form.date %}
</div>
</div>
<div class="form-group">
{% include 'partials/form_field.html' with field=form.notes %}
</div>
<div class="col-sm-12 text-right my-3">
{% button 'submit' %}

View File

@@ -26,4 +26,6 @@ urlpatterns = [
path('trainee/<int:pk>/level/<int:level_pk>/confirm', login_required(views.ConfirmLevel.as_view()), name='confirm_level'),
path('trainee/<int:pk>/item_record', login_required(views.TraineeItemDetail.as_view()), name='trainee_item_detail'),
path('session_log', has_perm_or_supervisor('training.add_trainingitemqualification')(views.SessionLog.as_view()), name='session_log'),
]

View File

@@ -5,8 +5,9 @@ from django.views import generic
from django.utils import timezone
from django.db import transaction
from django.db.models import Q, Count
from django.db.utils import IntegrityError
from PyRIGS.views import is_ajax, ModalURLMixin
from PyRIGS.views import is_ajax, ModalURLMixin, get_related
from training import models, forms
from users import views
from reversion.views import RevisionMixin
@@ -207,3 +208,26 @@ class ConfirmLevel(generic.RedirectView):
reversion.add_to_revision(trainee)
return reverse_lazy('trainee_detail', kwargs={'pk': kwargs['pk']})
class SessionLog(generic.FormView):
template_name = 'session_log_form.html'
form_class = forms.SessionLogForm
success_url = reverse_lazy('trainee_list')
def form_valid(self, form, *args, **kwargs):
for trainee in form.cleaned_data.get('trainees'):
for item in form.cleaned_data.get('items'):
try:
with transaction.atomic():
models.TrainingItemQualification.objects.create(trainee=trainee, item=item, supervisor=form.cleaned_data.get('supervisor'), depth=form.cleaned_data.get('depth'), notes=form.cleaned_data.get('notes'), date=form.cleaned_data.get('date'))
reversion.add_to_revision(trainee)
except IntegrityError:
pass # There was an attempt to create a duplicate qualification, ignore it
return super().form_valid(form, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["page_title"] = "Log Training Session"
get_related(context['form'], context)
return context