Start work on event checklist

This commit is contained in:
2020-08-14 16:56:17 +01:00
parent d3d7c052af
commit d3f55523da
9 changed files with 500 additions and 1 deletions

View File

@@ -169,3 +169,9 @@ class EventRiskAssessmentForm(forms.ModelForm):
model = models.RiskAssessment
fields = '__all__'
exclude = ['reviewed_at', 'reviewed_by']
class EventChecklistForm(forms.ModelForm):
class Meta:
model = models.EventChecklist
fields = '__all__'

View File

@@ -83,3 +83,55 @@ class EventRiskAssessmentReview(generic.View):
ra.reviewed_at = timezone.now()
ra.save()
return HttpResponseRedirect(reverse_lazy('ra_list'))
class EventChecklistDetail(generic.DetailView):
model = models.EventChecklist
template_name = 'event_checklist_detail.html'
class EventChecklistEdit(generic.UpdateView):
model = models.EventChecklist
template_name = 'event_checklist_form.html'
form_class = forms.EventChecklistForm
def get_context_data(self, **kwargs):
context = super(EventChecklistEdit, self).get_context_data(**kwargs)
pk = self.kwargs.get('pk')
ec = models.EventChecklist.objects.get(pk=pk)
context['event'] = ec.event
context['edit'] = True
return context
class EventChecklistCreate(generic.CreateView):
model = models.EventChecklist
template_name = 'event_checklist_form.html'
form_class = forms.EventChecklistForm
def get(self, *args, **kwargs):
epk = kwargs.get('pk')
event = models.Event.objects.get(pk=epk)
# Check if RA exists
ra = models.EventChecklist.objects.filter(event=event).first()
if ra is not None:
return HttpResponseRedirect(reverse_lazy('ec_edit', kwargs={'pk': ra.pk}))
return super(EventChecklistCreate, self).get(self)
def get_form(self, **kwargs):
form = super(EventChecklistCreate, self).get_form(**kwargs)
epk = self.kwargs.get('pk')
event = models.Event.objects.get(pk=epk)
form.instance.event = event
return form
def get_context_data(self, **kwargs):
context = super(EventChecklistCreate, self).get_context_data(**kwargs)
epk = self.kwargs.get('pk')
event = models.Event.objects.get(pk=epk)
context['event'] = event
return context
def get_success_url(self):
return reverse_lazy('ec_detail', kwargs={'pk': self.object.pk})

View File

@@ -0,0 +1,38 @@
# Generated by Django 3.0.7 on 2020-08-14 15:28
import RIGS.models
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('RIGS', '0043_auto_20200805_1606'),
]
operations = [
migrations.CreateModel(
name='EventChecklist',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('vehicles', models.TextField(help_text='List vehicles and their drivers')),
('safe_parking', models.BooleanField(help_text='Vehicles parked safely?<small>(does not obstruct venue access)</small>')),
('safe_packing', models.BooleanField(help_text='Equipment packed away safely?<small>(including flightcases)</small>')),
('exits', models.BooleanField(help_text='Emergency exits clear?')),
('trip_hazard', models.BooleanField(help_text='Appropriate barriers around kit and cabling secured?')),
('warning_signs', models.BooleanField(help_text='Warning signs in place?<small>(strobe, smoke, power etc.)</small>')),
('ear_plugs', models.BooleanField(help_text='Ear plugs issued to crew where needed?')),
('hs_location', models.TextField(help_text='Location of Safety Bag/Box')),
('extinguishers_location', models.TextField(help_text='Location of fire extinguishers')),
('rcds', models.BooleanField(help_text='RCDs installed where needed and tested?')),
('supply_test', models.BooleanField(help_text='Electrical supplies tested?<small>(using socket tester)</small>')),
('earthing', models.BooleanField(help_text='Equipment appropriately earthed?<small>(truss, stage, etc)</small>')),
('pat', models.BooleanField(help_text='All equipment in PAT period?')),
('event', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='RIGS.Event')),
('power_mic', models.ForeignKey(blank=True, help_text='Who is the Power MIC?', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='checklist', to=settings.AUTH_USER_MODEL, verbose_name='Power MIC')),
],
bases=(models.Model, RIGS.models.RevisionMixin),
),
]

View File

@@ -639,3 +639,41 @@ class RiskAssessment(models.Model, RevisionMixin):
def __str__(self):
return "%i - %s" % (self.pk, self.event)
@reversion.register
class EventChecklist(models.Model, RevisionMixin):
event = models.OneToOneField('Event', on_delete=models.CASCADE)
# General
power_mic = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='checklist', blank=True, null=True,
verbose_name="Power MIC", on_delete=models.CASCADE, help_text="Who is the Power MIC?")
# TODO Tabular format
vehicles = models.TextField(help_text="List vehicles and their drivers")
# Safety Checks
safe_parking = models.BooleanField(help_text="Vehicles parked safely?<br><small>(does not obstruct venue access)</small>")
safe_packing = models.BooleanField(help_text="Equipment packed away safely?<br><small>(including flightcases)</small>")
exits = models.BooleanField(help_text="Emergency exits clear?")
trip_hazard = models.BooleanField(help_text="Appropriate barriers around kit and cabling secured?")
warning_signs = models.BooleanField(help_text="Warning signs in place?<br><small>(strobe, smoke, power etc.)</small>")
ear_plugs = models.BooleanField(help_text="Ear plugs issued to crew where needed?")
hs_location = models.CharField(max_length=255, help_text="Location of Safety Bag/Box")
extinguishers_location = models.CharField(max_length=255, help_text="Location of fire extinguishers")
# Crew Record TODO
# Small Electrical Checks
rcds = models.BooleanField(help_text="RCDs installed where needed and tested?")
supply_test = models.BooleanField(help_text="Electrical supplies tested?<br><small>(using socket tester)</small>")
earthing = models.BooleanField(help_text="Equipment appropriately earthed?<br><small>(truss, stage, etc)</small>")
pat = models.BooleanField(help_text="All equipment in PAT period?")
@property
def activity_feed_string(self):
return str(self.event)
def get_absolute_url(self):
return reverse_lazy('ec_detail', kwargs={'pk': self.pk})
def __str__(self):
return "%i - %s" % (self.pk, self.event)

View File

@@ -0,0 +1,156 @@
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
{% block title %}Risk Assessment for Event N{{ object.event.pk|stringformat:"05d" }} {{ object.event.name }}{% endblock %}
{% load help_text from filters %}
{% block content %}
<div class="row my-3 py-3">
<div class="col-sm-12">
<h3>Event Checklist for Event N{{ object.event.pk|stringformat:"05d" }} {{ object.event.name }}</h3>
<div class="row">
<div class="col-12 text-right">
<a href="{% url 'ec_edit' object.pk %}" class="btn btn-warning my-3"><span class="fas fa-edit"></span> <span
class="hidden-xs">Edit</span></a>
</div>
</div>
<div class="card card-default mb-3">
<div class="card-header">General</div>
<div class="card-body">
<dl class="row">
<dt class="col-10">{{ object|help_text:'nonstandard_equipment' }}</dt>
<dd class="col-2">
{{ object.nonstandard_equipment|yesno|title }}
</dd>
<dt class="col-10">{{ object|help_text:'nonstandard_use'|safe }}</dt>
<dd class="col-2">
{{ object.nonstandard_use|yesno|title }}
</dd>
<dt class="col-10">{{ object|help_text:'contractors' }}</dt>
<dd class="col-2">
{{ object.contractors|yesno|title }}
</dd>
<dt class="col-10">{{ object|help_text:'other_companies' }}</dt>
<dd class="col-2">
{{ object.othercompanies|yesno|title }}
</dd>
<dt class="col-10">{{ object|help_text:'crew_fatigue' }}</dt>
<dd class="col-2">
{{ object.crewfatigue|yesno|title }}
</dd>
<dt class="col-12">{{ object|help_text:'general_notes' }}</dt>
<dd class="col-12">
{{ object.general_notes|default:'N/A'|linebreaks }}
</dd>
</dl>
</div>
</div>
<div class="card card-default mb-3">
<div class="card-header">Power</div>
<div class="card-body">
<dl class="row">
<dt class="col-sm-6">{{ object|help_text:'big_power' }}</dt>
<dd class="col-sm-6">
{{ object.big_power|yesno|title }}
</dd>
<dt class="col-sm-6">{{ object|help_text:'power_mic' }}</dt>
<dd class="col-sm-6">
{{ object.power_mic.name|default:'None' }}
</dd>
<dt class="col-sm-6">{{ object|help_text:'generators' }}</dt>
<dd class="col-sm-6">
{{ object.generators|yesno|title }}
</dd>
<dt class="col-sm-6">{{ object|help_text:'other_companies_power' }}</dt>
<dd class="col-sm-6">
{{ object.other_companies_power|yesno|title }}
</dd>
<dt class="col-sm-6">{{ object|help_text:'nonstandard_equipment_power' }}</dt>
<dd class="col-sm-6">
{{ object.nonstandard_equipment_power|yesno|title }}
</dd>
<dt class="col-sm-6">{{ object|help_text:'multiple_electrical_environments' }}</dt>
<dd class="col-sm-6">
{{ object.multiple_electrical_environments|yesno|title }}
</dd>
<dt class="col-12">{{ object|help_text:'power_notes' }}</dt>
<dd class="col-12">
{{ object.power_notes|default:'N/A'|linebreaks }}
</dd>
</dl>
</div>
</div>
<div class="card card-default mb-3">
<div class="card-header">Sound</div>
<div class="card-body">
<dl class="row">
<dt class="col-sm-6">{{ object|help_text:'noise_monitoring' }}</dt>
<dd class="col-sm-6">
{{ object.noise_monitoring|yesno|title }}
</dd>
<dt class="col-12">{{ object|help_text:'sound_notes' }}</dt>
<dd class="col-12">
{{ object.sound_notes|default:'N/A'|linebreaks }}
</dd>
</dl>
</div>
</div>
<div class="card card-default mb-3">
<div class="card-header">Site Details</div>
<div class="card-body">
<dl class="row">
<dt class="col-sm-6">{{ object|help_text:'known_venue' }}</dt>
<dd class="col-sm-6">
{{ object.known_venue|yesno|title }}
</dd>
<dt class="col-sm-6">{{ object|help_text:'safe_loading'|safe }}</dt>
<dd class="col-sm-6">
{{ object.safe_loading.name|yesno|title }}
</dd>
<dt class="col-sm-6">{{ object|help_text:'safe_storage' }}</dt>
<dd class="col-sm-6">
{{ object.safe_storage|yesno|title }}
</dd>
<dt class="col-sm-6">{{ object|help_text:'area_outside_of_control' }}</dt>
<dd class="col-sm-6">
{{ object.area_outside_of_control|yesno|title }}
</dd>
<dt class="col-sm-6">{{ object|help_text:'barrier_required' }}</dt>
<dd class="col-sm-6">
{{ object.barrier_required|yesno|title }}
</dd>
<dt class="col-sm-6">{{ object|help_text:'nonstandard_emergency_procedure' }}</dt>
<dd class="col-sm-6">
{{ object.nonstandard_emergency_procedure|yesno|title }}
</dd>
</dl>
</div>
</div>
<div class="card card-default mb-3">
<div class="card-header">Structures</div>
<div class="card-body">
<dl class="row">
<dt class="col-sm-6">{{ object|help_text:'special_structures' }}</dt>
<dd class="col-sm-6">
{{ object.special_structures|yesno|title }}
</dd>
<dt class="col-sm-6">{{ object|help_text:'persons_responsible_structures' }}</dt>
<dd class="col-sm-6">
{{ object.persons_responsible_structures.name|default:'N/A'|linebreaks }}
</dd>
<dt class="col-sm-6">{{ object|help_text:'suspended_structures' }}</dt>
<dd class="col-sm-6">
{{ object.suspended_structures|yesno|title }}
</dd>
</dl>
</div>
</div>
</div>
</div>
<div class="col-12 text-right">
<a href="{% url 'ec_edit' object.pk %}" class="btn btn-warning my-3"><span class="fas fa-edit"></span> <span
class="hidden-xs">Edit</span></a>
</div>
<div class="col-12 text-right">
{% include 'partials/last_edited.html' with target="ec_history" %}
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,187 @@
{% extends request.is_ajax|yesno:'base_ajax.html,base_rigs.html' %}
{% load widget_tweaks %}
{% load static %}
{% load help_text from filters %}
{% block title %}{% if edit %}Edit{% else %}Create{% endif %} Event Checklist for Event N{{ event.pk|stringformat:"05d" }}{% endblock %}
{% block css %}
{{ block.super }}
<link rel="stylesheet" href="{% static 'css/bootstrap-select.css' %}"/>
<link rel="stylesheet" href="{% static 'css/ajax-bootstrap-select.css' %}"/>
{% endblock %}
{% block preload_js %}
{{ block.super }}
<script src="{% static 'js/bootstrap-select.js' %}"></script>
<script src="{% static 'js/ajax-bootstrap-select.js' %}"></script>
{% endblock %}
{% block js %}
{{ block.super }}
<script src="{% static 'js/jquery-ui.js' %}"></script><!--TODO optimise--->
<script src="{% static 'js/interaction.js' %}"></script>
<script src="{% static 'js/modal.js' %}"></script>
<script src="{% static 'js/tooltip.js' %}"></script>
<script src="{% static 'js/autocompleter.js' %}"></script>
{% endblock %}
{% block content %}
<div class="col-sm-offset-1 col-sm-10">
<h3>{% if edit %}Edit{% else %}Create{% endif %} Event Checklist for Event N{{ event.pk|stringformat:"05d" }}</h3>
{% include 'form_errors.html' %}
{% if edit %}
<form role="form" method="POST" action="{% url 'ec_edit' pk=object.pk %}">
{% else %}
<form role="form" method="POST" action="{% url 'event_ec' pk=event.pk %}">
{% endif %}
<input type="hidden" name="{{ form.event.name }}" id="{{ form.event.id_for_label }}"
value="{{event.pk}}"/>
{% csrf_token %}
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">Event Information</div>
<div class="card-body">
<dl class="col-12 row">
<dt class="col-4">Event Date</dt>
<dd class="col-8">{{form.event.start_date}}</dd>
<dt class="col-4">Event Name</dt>
<dd class="col-8">{{form.event.name}}</dd>
<dt class="col-4">Client</dt>
<dd class="col-8">{{form.event.person}}</dd>
<dt class="col-4">Venue</dt>
<dd class="col-8">{{form.event.Venue}}</dd>
</dl>
<label for="{{ form.power_mic.id_for_label }}"
class="col-4 control-label">{{ form.power_mic.help_text }}</label>
<div class="col-8">
<select id="{{ form.power_mic.id_for_label }}" name="{{ form.power_mic.name }}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
{% if object.power_mic %}
<option value="{{object.power_mic.pk}}" selected="selected">{{ object.power_mic.name }}</option>
{% endif %}
</select>
</div>
<label class="col-12 pt-3" for="{{ form.vehicles.id_for_label }}">{{ form.vehicles.help_text }}</label>
<table class="table">
<thead>
<tr>
<th scope="col">Vehicle</th>
<th scope="col">Driver</th>
</tr>
</thead>
<tbody>
{% for i in '012'|make_list %}
<tr>
<td><input type="text" class="form-control"/></td>
<th scope="row">
<select id="{{ form.power_mic.id_for_label }}" name="{{ form.power_mic.name }}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
{% if object.power_mic %}
<option value="{{object.power_mic.pk}}" selected="selected">{{ object.power_mic.name }}</option>
{% endif %}
</select>
</th>
</tr>
{% endfor %}
</tbody>
</table>
<div class="text-right">
<button class="btn btn-secondary"><span class="fas fa-plus"></span> Add Vehicle</button>
</div>
</div>
</div>
</div>
</div>
<div class="row my-3">
<div class="col-12">
<div class="card">
<div class="card-header">Safety Checks</div>
<div class="card-body">
{% include 'partials/checklist_checkbox.html' with formitem=form.safe_parking %}
{% include 'partials/checklist_checkbox.html' with formitem=form.safe_packing %}
{% include 'partials/checklist_checkbox.html' with formitem=form.exits %}
{% include 'partials/checklist_checkbox.html' with formitem=form.trip_hazard %}
{% include 'partials/checklist_checkbox.html' with formitem=form.warning_signs %}
{% include 'partials/checklist_checkbox.html' with formitem=form.ear_plugs %}
<label class="col-4 pt-3" for="{{ form.hs_location.id_for_label }}">{{ form.hs_location.help_text }}</label>
{% render_field form.hs_location class+="form-control" %}
<label class="col-4 pt-3" for="{{ form.extinguishers_location.id_for_label }}">{{ form.extinguishers_location.help_text }}</label>
{% render_field form.extinguishers_location class+="form-control" %}
</div>
</div>
</div>
</div>
<div class="row my-3">
<div class="col-12">
<div class="card">
<div class="card-header">Crew Record</div>
<div class="card-body">
<table class="table">
<thead>
<tr>
<th scope="col">Crewmember</th>
<th scope="col">Start Time</th>
<th scope="col">Role</th>
<th scope="col">End Time</th>
</tr>
</thead>
<tbody>
{% for i in '012'|make_list %}
<tr>
<th scope="row">
<select id="{{ form.power_mic.id_for_label }}" name="{{ form.power_mic.name }}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
{% if object.power_mic %}
<option value="{{object.power_mic.pk}}" selected="selected">{{ object.power_mic.name }}</option>
{% endif %}
</select>
</th>
<td><input type="time" class="form-control"/></td>
<td><input type="text" class="form-control"/></td>
<td><input type="time" class="form-control"/></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="text-right">
<button class="btn btn-secondary"><span class="fas fa-plus"></span> Add Crewmember</button>
</div>
</div>
</div>
</div>
</div>
<div class="row my-3">
<div class="col-12">
<div class="card">
<div class="card-header">Electrical Checks <small>for Small TEC Events <6kVA (aprox. 26A)</small></div>
<div class="card-body">
{% include 'partials/checklist_checkbox.html' with formitem=form.rcds %}
{% include 'partials/checklist_checkbox.html' with formitem=form.supply_test %}
{% include 'partials/checklist_checkbox.html' with formitem=form.earthing %}
{% include 'partials/checklist_checkbox.html' with formitem=form.pat %}
</div>
</div>
</div>
</div>
<div class="row my-3">
<div class="col-12">
<div class="card">
<div class="card-header">Electrical Checks <small>for Medium TEC Events </small></div>
<div class="card-body">
</div>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-sm-12 text-right">
<div class="btn-group">
<button type="submit" class="btn btn-primary" title="Save"><i
class="fas fa-save"></i> Save
</button>
</div>
</div>
</div>
</form>
</div>
{% endblock %}

View File

@@ -0,0 +1,6 @@
{% load widget_tweaks %}
{% load help_text from filters %}
<div class="form-check">
{% render_field formitem|attr:'required=true' class+="form-check-input" %}
<label class="form-check-label" for="{{ formitem.id_for_label }}">{{formitem.help_text|safe}}</label>
</div>

View File

@@ -16,6 +16,13 @@
{% endif%}
<hr>
<h5>Event Checklist:</h5>
Coming Soon
{% if event.eventchecklist %}
<span class="fas fa-check text-success"></span> Completed <div class="btn-group"><a href="{% url 'ec_detail' event.eventchecklist.pk %}" class="btn btn-primary"><span class="fas fa-eye"></span> <span
class="hidden-xs">View</span><a href="{% url 'ec_edit' event.eventchecklist.pk %}" class="btn btn-warning"><span class="fas fa-edit"></span> <span
class="hidden-xs">Edit</span></a></div>
{% else %}
<a href="{% url 'event_ec' event.pk %}" class="btn btn-success"><span class="fas fa-paperclip"></span> <span
class="hidden-xs">Create Risk Assessment</span></a>
{% endif%}
</div>
</div>

View File

@@ -103,6 +103,15 @@ urlpatterns = [
name='ra_list'),
path('event/ra/<int:pk>/review/', permission_required_with_403('RIGS.change_event')(hs.EventRiskAssessmentReview.as_view()), name='ra_review'),
path('event/<int:pk>/checklist/', permission_required_with_403('RIGS.change_event')(hs.EventChecklistCreate.as_view()),
name='event_ec'),
path('event/checklist/<int:pk>/', permission_required_with_403('RIGS.change_event')(hs.EventChecklistDetail.as_view()),
name='ec_detail'),
path('event/checklist/<int:pk>/edit/', permission_required_with_403('RIGS.change_event')(hs.EventChecklistEdit.as_view()),
name='ec_edit'),
path('event/checklist/<int:pk>/history/', permission_required_with_403('RIGS.change_event')(versioning.VersionHistory.as_view()),
name='ec_history', kwargs={'model': models.EventChecklist}),
# Finance
path('invoice/', permission_required_with_403('RIGS.view_invoice')(finance.InvoiceIndex.as_view()),
name='invoice_list'),