diff --git a/RIGS/admin.py b/RIGS/admin.py index a46a0eee..d7dbd72b 100644 --- a/RIGS/admin.py +++ b/RIGS/admin.py @@ -206,3 +206,8 @@ class RiskAssessmentAdmin(VersionAdmin): @admin.register(models.EventChecklist) class EventChecklistAdmin(VersionAdmin): list_display = ('id', 'event', 'reviewed_at', 'reviewed_by') + + +@admin.register(models.PowerTestRecord) +class EventChecklistAdmin(VersionAdmin): + list_display = ('id', 'event', 'reviewed_at', 'reviewed_by') diff --git a/RIGS/forms.py b/RIGS/forms.py index 0664875d..78128678 100644 --- a/RIGS/forms.py +++ b/RIGS/forms.py @@ -283,3 +283,17 @@ class EventChecklistForm(forms.ModelForm): model = models.EventChecklist fields = '__all__' exclude = ['reviewed_at', 'reviewed_by'] + + +class PowerTestRecordForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + for name, field in self.fields.items(): + if field.__class__ == forms.NullBooleanField: + # Only display yes/no to user, the 'none' is only ever set in the background + field.widget = forms.CheckboxInput() + + class Meta: + model = models.PowerTestRecord + fields = '__all__' + exclude = ['reviewed_at', 'reviewed_by'] diff --git a/RIGS/migrations/0046_create_powertests.py b/RIGS/migrations/0046_create_powertests.py new file mode 100644 index 00000000..95f1c8e4 --- /dev/null +++ b/RIGS/migrations/0046_create_powertests.py @@ -0,0 +1,71 @@ +# Generated by Django 3.2.16 on 2023-05-08 15:58 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import versioning.versioning + +def migrate_old_data(apps, schema_editor): + EventChecklist = apps.get_model('RIGS', 'EventChecklist') + PowerTestRecord = apps.get_model('RIGS', 'PowerTestRecord') + for ec in EventChecklist.objects.all(): + # New highscore for the most pythonic BS I've ever written. + PowerTestRecord.objects.create(event=ec.event, **{i.name:getattr(ec, i.attname) for i in PowerTestRecord._meta.get_fields() if not (i.is_relation or i.auto_created)}) + + +def revert(apps, schema_editor): + apps.get_model('RIGS', 'PowerTestRecord').objects.all().delete() + + +class Migration(migrations.Migration): + + dependencies = [ + ('RIGS', '0045_alter_profile_is_approved'), + ] + + operations = [ + migrations.CreateModel( + name='PowerTestRecord', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='power_tests', to='RIGS.event')), + ('notes', models.TextField(blank=True, default='')), + ('venue', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='RIGS.venue')), + ('reviewed_at', models.DateTimeField(null=True)), + ('rcds', models.BooleanField(blank=True, help_text='RCDs installed where needed and tested?', null=True)), + ('supply_test', models.BooleanField(blank=True, help_text='Electrical supplies tested?
(using socket tester)', null=True)), + ('earthing', models.BooleanField(blank=True, help_text='Equipment appropriately earthed?
(truss, stage, generators etc)', null=True)), + ('pat', models.BooleanField(blank=True, help_text='All equipment in PAT period?', null=True)), + ('source_rcd', models.BooleanField(blank=True, help_text='Source RCD protected?
(if cable is more than 3m long) ', null=True)), + ('labelling', models.BooleanField(blank=True, help_text='Appropriate and clear labelling on distribution and cabling?', null=True)), + ('fd_voltage_l1', models.IntegerField(blank=True, help_text='L1 - N', null=True, verbose_name='First Distro Voltage L1-N')), + ('fd_voltage_l2', models.IntegerField(blank=True, help_text='L2 - N', null=True, verbose_name='First Distro Voltage L2-N')), + ('fd_voltage_l3', models.IntegerField(blank=True, help_text='L3 - N', null=True, verbose_name='First Distro Voltage L3-N')), + ('fd_phase_rotation', models.BooleanField(blank=True, help_text='Phase Rotation
(if required)', null=True, verbose_name='Phase Rotation')), + ('fd_earth_fault', models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (ZS)', max_digits=5, null=True, verbose_name='Earth Fault Loop Impedance')), + ('fd_pssc', models.IntegerField(blank=True, help_text='Prospective Short Circuit Current', null=True, verbose_name='PSCC')), + ('w1_description', models.CharField(blank=True, default='', help_text='Description', max_length=255)), + ('w1_polarity', models.BooleanField(blank=True, help_text='Polarity Checked?', null=True)), + ('w1_voltage', models.IntegerField(blank=True, help_text='Voltage', null=True)), + ('w1_earth_fault', models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (ZS)', max_digits=5, null=True, verbose_name='Earth Fault Loop Impedance')), + ('w2_description', models.CharField(blank=True, default='', help_text='Description', max_length=255)), + ('w2_polarity', models.BooleanField(blank=True, help_text='Polarity Checked?', null=True)), + ('w2_voltage', models.IntegerField(blank=True, help_text='Voltage', null=True)), + ('w2_earth_fault', models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (ZS)', max_digits=5, null=True, verbose_name='Earth Fault Loop Impedance')), + ('w3_description', models.CharField(blank=True, default='', help_text='Description', max_length=255)), + ('w3_polarity', models.BooleanField(blank=True, help_text='Polarity Checked?', null=True)), + ('w3_voltage', models.IntegerField(blank=True, help_text='Voltage', null=True)), + ('w3_earth_fault', models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (ZS)', max_digits=5, null=True, verbose_name='Earth Fault Loop Impedance')), + ('all_rcds_tested', models.BooleanField(blank=True, help_text='All circuit RCDs tested?
(using test button)', null=True)), + ('public_sockets_tested', models.BooleanField(blank=True, help_text='Public/Performer accessible circuits tested?
(using socket tester)', null=True)), + ('reviewed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Reviewer')), + ], + options={ + 'abstract': False, + 'ordering': ['event'], + 'permissions': [('review_power', 'Can review Power Test Records')], + }, + bases=(models.Model, versioning.versioning.RevisionMixin), + ), + migrations.RunPython(migrate_old_data, reverse_code=revert), + ] diff --git a/RIGS/migrations/0047_auto_20230508_1946.py b/RIGS/migrations/0047_auto_20230508_1946.py new file mode 100644 index 00000000..555798be --- /dev/null +++ b/RIGS/migrations/0047_auto_20230508_1946.py @@ -0,0 +1,117 @@ +# Generated by Django 3.2.16 on 2023-05-08 18:46 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('RIGS', '0046_create_powertests'), + ] + + operations = [ + migrations.RemoveField( + model_name='eventchecklist', + name='all_rcds_tested', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='earthing', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='fd_earth_fault', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='fd_phase_rotation', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='fd_pssc', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='fd_voltage_l1', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='fd_voltage_l2', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='fd_voltage_l3', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='labelling', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='pat', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='public_sockets_tested', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='rcds', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='source_rcd', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='supply_test', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='w1_description', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='w1_earth_fault', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='w1_polarity', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='w1_voltage', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='w2_description', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='w2_earth_fault', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='w2_polarity', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='w2_voltage', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='w3_description', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='w3_earth_fault', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='w3_polarity', + ), + migrations.RemoveField( + model_name='eventchecklist', + name='w3_voltage', + ), + ] diff --git a/RIGS/models.py b/RIGS/models.py index 30fdecd8..0b7720ea 100644 --- a/RIGS/models.py +++ b/RIGS/models.py @@ -689,8 +689,21 @@ def validate_url(value): raise ValidationError('URL must point to a location on the TEC Sharepoint') +class ReviewableModel(models.Model): + reviewed_at = models.DateTimeField(null=True) + reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, + verbose_name="Reviewer", on_delete=models.CASCADE) + + @cached_property + def fieldz(self): + return [n.name for n in list(self._meta.get_fields()) if n.name != 'reviewed_at' and n.name != 'reviewed_by' and not n.is_relation and not n.auto_created] + + class Meta: + abstract = True + + @reversion.register -class RiskAssessment(models.Model, RevisionMixin): +class RiskAssessment(ReviewableModel, RevisionMixin): SMALL = (0, 'Small') MEDIUM = (1, 'Medium') LARGE = (2, 'Large') @@ -738,10 +751,6 @@ class RiskAssessment(models.Model, RevisionMixin): # Blimey that was a lot of options - reviewed_at = models.DateTimeField(null=True) - reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, - verbose_name="Reviewer", on_delete=models.CASCADE) - supervisor_consulted = models.BooleanField(null=True) expected_values = { @@ -778,10 +787,6 @@ class RiskAssessment(models.Model, RevisionMixin): ('review_riskassessment', 'Can review Risk Assessments') ] - @cached_property - def fieldz(self): - return [n.name for n in list(self._meta.get_fields()) if n.name != 'reviewed_at' and n.name != 'reviewed_by' and not n.is_relation and not n.auto_created] - @property def event_size(self): # Confirm event size. Check all except generators, since generators entails outside @@ -811,7 +816,7 @@ class RiskAssessment(models.Model, RevisionMixin): @reversion.register(follow=['vehicles', 'crew']) -class EventChecklist(models.Model, RevisionMixin): +class EventChecklist(ReviewableModel, RevisionMixin): event = models.ForeignKey('Event', related_name='checklists', on_delete=models.CASCADE) # General @@ -830,6 +835,30 @@ class EventChecklist(models.Model, RevisionMixin): hs_location = models.CharField(blank=True, default='', max_length=255, help_text="Location of Safety Bag/Box") extinguishers_location = models.CharField(blank=True, default='', max_length=255, help_text="Location of fire extinguishers") + inverted_fields = [] + + class Meta: + ordering = ['event'] + permissions = [ + ('review_eventchecklist', 'Can review Event Checklists') + ] + + @property + def activity_feed_string(self): + return str(self.event) + + def get_absolute_url(self): + return reverse('ec_detail', kwargs={'pk': self.pk}) + + def __str__(self): + return f"{self.pk} - {self.event}" + + +@reversion.register +class PowerTestRecord(ReviewableModel, RevisionMixin): + event = models.ForeignKey('Event', related_name='power_tests', on_delete=models.CASCADE) + venue = models.ForeignKey('Venue', on_delete=models.CASCADE) + notes = models.TextField(blank=True, default='') # Small Electrical Checks rcds = models.BooleanField(blank=True, null=True, help_text="RCDs installed where needed and tested?") supply_test = models.BooleanField(blank=True, null=True, help_text="Electrical supplies tested?
(using socket tester)") @@ -865,32 +894,15 @@ class EventChecklist(models.Model, RevisionMixin): all_rcds_tested = models.BooleanField(blank=True, null=True, help_text="All circuit RCDs tested?
(using test button)") public_sockets_tested = models.BooleanField(blank=True, null=True, help_text="Public/Performer accessible circuits tested?
(using socket tester)") - reviewed_at = models.DateTimeField(null=True) - reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, - verbose_name="Reviewer", on_delete=models.CASCADE) - - inverted_fields = [] + def __str__(self): + return f"{self.pk} - {self.event}" class Meta: ordering = ['event'] permissions = [ - ('review_eventchecklist', 'Can review Event Checklists') + ('review_power', 'Can review Power Test Records') ] - @cached_property - def fieldz(self): - return [n.name for n in list(self._meta.get_fields()) if n.name != 'reviewed_at' and n.name != 'reviewed_by' and not n.is_relation and not n.auto_created] - - @property - def activity_feed_string(self): - return str(self.event) - - def get_absolute_url(self): - return reverse('ec_detail', kwargs={'pk': self.pk}) - - def __str__(self): - return f"{self.pk} - {self.event}" - @reversion.register class EventChecklistVehicle(models.Model, RevisionMixin): diff --git a/RIGS/templates/hs/event_checklist_form.html b/RIGS/templates/hs/event_checklist_form.html index 6db9f398..2db2899a 100644 --- a/RIGS/templates/hs/event_checklist_form.html +++ b/RIGS/templates/hs/event_checklist_form.html @@ -228,123 +228,6 @@ - {% if event.riskassessment.event_size == 0 %} -
-
-
-
Electrical Checks for ‘Small’ TEC Events <6kVA (approx. 26A)
-
- {% 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 %} -
-
-
-
- {% else %} -
-
- {% if event.riskassessment.event_size == 1 %} -
-
Electrical Checks for ‘Medium’ TEC Events
-
- {% else %} -
-
Electrical Checks for ‘Large’ TEC Events
-
-
Here be dragons. Ensure you have appeased the Power Gods before continuing... (If you didn't check with a Supervisor, you cannot continue your event!)
- {% endif %} - {% include 'partials/checklist_checkbox.html' with formitem=form.source_rcd %} - {% include 'partials/checklist_checkbox.html' with formitem=form.labelling %} - {% include 'partials/checklist_checkbox.html' with formitem=form.earthing %} - {% include 'partials/checklist_checkbox.html' with formitem=form.pat %} -
-

Tests at first distro

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TestValue
Voltage
(cube meter)
{{ form.fd_voltage_l1.help_text }}{{ form.fd_voltage_l2.help_text }}{{ form.fd_voltage_l3.help_text }}
{% render_field form.fd_voltage_l1 class+="form-control" style="min-width: 5rem;" %}{% render_field form.fd_voltage_l2 class+="form-control" style="min-width: 5rem;" %}{% render_field form.fd_voltage_l3 class+="form-control" style="min-width: 5rem;" %}
{{form.fd_phase_rotation.help_text|safe}}{% include 'partials/checklist_checkbox.html' with formitem=form.fd_phase_rotation %}
{{form.fd_earth_fault.help_text|safe}}{% render_field form.fd_earth_fault class+="form-control" %}
{{form.fd_pssc.help_text|safe}}{% render_field form.fd_pssc class+="form-control" %}
-
-
-

Tests at 'Worst Case' points (at least 1 point required)

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TestPoint 1Point 2Point 3
{{form.w1_description.help_text|safe}}{% render_field form.w1_description class+="form-control" style="min-width: 5rem;" %}{% render_field form.w2_description class+="form-control" style="min-width: 5rem;" %}{% render_field form.w3_description class+="form-control" style="min-width: 5rem;" %}
{{form.w1_polarity.help_text|safe}}{% render_field form.w1_polarity %}{% render_field form.w2_polarity %}{% render_field form.w3_polarity %}
{{form.w1_voltage.help_text|safe}}{% render_field form.w1_voltage class+="form-control" %}{% render_field form.w2_voltage class+="form-control" %}{% render_field form.w3_voltage class+="form-control" %}
{{form.w1_earth_fault.help_text|safe}}{% render_field form.w1_earth_fault class+="form-control" %}{% render_field form.w2_earth_fault class+="form-control" %}{% render_field form.w3_earth_fault class+="form-control" %}
-
-
- {% include 'partials/checklist_checkbox.html' with formitem=form.all_rcds_tested %} - {% include 'partials/checklist_checkbox.html' with formitem=form.public_sockets_tested %} - {% include 'partials/ec_power_info.html' %} -
-
-
-
- {% endif %}
{% button 'submit' %} diff --git a/RIGS/templates/hs/power_detail.html b/RIGS/templates/hs/power_detail.html new file mode 100644 index 00000000..8ad27d17 --- /dev/null +++ b/RIGS/templates/hs/power_detail.html @@ -0,0 +1,167 @@ +{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %} +{% load help_text from filters %} +{% load profile_by_index from filters %} +{% load yesnoi from filters %} +{% load button from filters %} + +{% block content %} +
+
+ {% button 'edit' url='pt_edit' pk=object.pk %} + {% button 'view' url='event_detail' pk=object.event.pk text="Event" %} + {% include 'partials/review_status.html' with perm=perms.RIGS.review_power review='pt_review' %} +
+
+
+
{% include 'partials/event_size.html' with object=object.event.riskassessment %}
+
+
+
Venue
+
+ {% if object.venue %} + + {{ object.venue }} + + {% endif %} +
+
Notes
+
+ {{ object.notes }} +
+
+ {% if object.event.riskassessment.event_size == 0 %} +
+
{{ object|help_text:'rcds'|safe }}
+
+ {{ object.rcds|yesnoi }} +
+
{{ object|help_text:'supply_test'|safe }}
+
+ {{ object.supply_test|yesnoi }} +
+
{{ object|help_text:'earthing'|safe }}
+
+ {{ object.earthing|yesnoi }} +
+
{{ object|help_text:'pat'|safe }}
+
+ {{ object.pat|yesnoi }} +
+
+ {% else %} +
+
{{ object|help_text:'source_rcd'|safe }}
+
+ {{ object.source_rcd|yesnoi }} +
+
{{ object|help_text:'labelling'|safe }}
+
+ {{ object.labelling|yesnoi }} +
+
{{ object|help_text:'earthing'|safe }}
+
+ {{ object.earthing|yesnoi }} +
+
{{ object|help_text:'pat'|safe }}
+
+ {{ object.pat|yesnoi }} +
+
+
+

Tests at first distro

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestValue
Voltage
(cube meter)
{{ object|help_text:'fd_voltage_l1' }}{{ object|help_text:'fd_voltage_l2' }}{{ object|help_text:'fd_voltage_l3' }}
{{ object.fd_voltage_l1 }}{{ object.fd_voltage_l2 }}{{ object.fd_voltage_l3 }}
{{ object|help_text:'fd_phase_rotation'|safe }}{{ object.fd_phase_rotation|yesnoi }}
{{ object|help_text:'fd_earth_fault'|safe}}{{ object.fd_earth_fault }}
{{ object|help_text:'fd_pssc'}}{{ object.fd_pssc }}
+
+

Tests at 'Worst Case' points (at least 1 point required)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestPoint 1Point 2Point 3
{{ object|help_text:'w1_description'|safe}}{{ object.w1_description }}{{ object.w2_description|default:'' }}{{ object.w3_description|default:'' }}
{{ object|help_text:'w1_polarity'|safe}}{{ object.w1_polarity|yesnoi }}{{ object.w2_polarity|default:''|yesnoi }}{{ object.w3_polarity|default:''|yesnoi }}
{{ object|help_text:'w1_voltage'|safe}}{{ object.w1_voltage }}{{ object.w2_voltage|default:'' }}{{ object.w3_voltage|default:'' }}
{{ object|help_text:'w1_earth_fault'|safe}}{{ object.w1_earth_fault }}{{ object.w2_earth_fault|default:'' }}{{ object.w3_earth_fault|default:'' }}
+
+
+
{{ object|help_text:'all_rcds_tested'|safe }}
+
+ {{ object.all_rcds_tested|yesnoi }} +
+
{{ object|help_text:'public_sockets_tested'|safe }}
+
+ {{ object.public_sockets_tested|yesnoi }} +
+
+
+ {% include 'partials/ec_power_info.html' %} + {% endif %} +
+
+
+{% button 'edit' url='ec_edit' pk=object.pk %} +{% button 'view' url='event_detail' pk=object.pk text="Event" %} +{% include 'partials/review_status.html' with perm=perms.RIGS.review_eventchecklist review='ec_review' %} +
+
+{% include 'partials/last_edited.html' with target="eventchecklist_history" %} +
+{% endblock %} diff --git a/RIGS/templates/hs/power_form.html b/RIGS/templates/hs/power_form.html new file mode 100644 index 00000000..ddd81309 --- /dev/null +++ b/RIGS/templates/hs/power_form.html @@ -0,0 +1,191 @@ +{% extends request.is_ajax|yesno:'base_ajax.html,base_rigs.html' %} +{% load widget_tweaks %} +{% load static %} +{% load help_text from filters %} +{% load profile_by_index from filters %} +{% load button from filters %} + +{% block css %} + {{ block.super }} + +{% endblock %} + +{% block preload_js %} + {{ block.super }} + +{% endblock %} + +{% block js %} + {{ block.super }} + + +{% endblock %} + +{% block content %} +
+ {% include 'form_errors.html' %} + {% if edit %} +
+ {% else %} + + {% endif %} + + {% csrf_token %} +
+
+
+
Event Information
+
+
+
Event Date
+
{{ event.start_date}}{%if event.end_date %}-{{ event.end_date}}{%endif%}
+
Event Name
+
{{ event.name }}
+
Client
+
{{ event.person }}
+
Event Size
+
{% include 'partials/event_size.html' with object=event.riskassessment %}
+
+
+ + +
+ + {% render_field form.notes class+="form-control" %} +
+
+
+
+ {% if event.riskassessment.event_size == 0 %} +
+
+
+
Electrical Checks for ‘Small’ TEC Events <6kVA (approx. 26A)
+
+ {% 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 %} +
+
+
+
+ {% else %} +
+
+ {% if event.riskassessment.event_size == 1 %} +
+
Electrical Checks for ‘Medium’ TEC Events
+
+ {% else %} +
+
Electrical Checks for ‘Large’ TEC Events
+
+
Here be dragons. Ensure you have appeased the Power Gods before continuing... (If you didn't check with a Supervisor, you cannot continue your event!)
+ {% endif %} + {% include 'partials/checklist_checkbox.html' with formitem=form.source_rcd %} + {% include 'partials/checklist_checkbox.html' with formitem=form.labelling %} + {% include 'partials/checklist_checkbox.html' with formitem=form.earthing %} + {% include 'partials/checklist_checkbox.html' with formitem=form.pat %} +
+

Tests at first distro

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestValue
Voltage
(cube meter)
{{ form.fd_voltage_l1.help_text }}{{ form.fd_voltage_l2.help_text }}{{ form.fd_voltage_l3.help_text }}
{% render_field form.fd_voltage_l1 class+="form-control" style="min-width: 5rem;" %}{% render_field form.fd_voltage_l2 class+="form-control" style="min-width: 5rem;" %}{% render_field form.fd_voltage_l3 class+="form-control" style="min-width: 5rem;" %}
{{form.fd_phase_rotation.help_text|safe}}{% include 'partials/checklist_checkbox.html' with formitem=form.fd_phase_rotation %}
{{form.fd_earth_fault.help_text|safe}}{% render_field form.fd_earth_fault class+="form-control" %}
{{form.fd_pssc.help_text|safe}}{% render_field form.fd_pssc class+="form-control" %}
+
+
+

Tests at 'Worst Case' points (at least 1 point required)

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TestPoint 1Point 2Point 3
{{form.w1_description.help_text|safe}}{% render_field form.w1_description class+="form-control" style="min-width: 5rem;" %}{% render_field form.w2_description class+="form-control" style="min-width: 5rem;" %}{% render_field form.w3_description class+="form-control" style="min-width: 5rem;" %}
{{form.w1_polarity.help_text|safe}}{% render_field form.w1_polarity %}{% render_field form.w2_polarity %}{% render_field form.w3_polarity %}
{{form.w1_voltage.help_text|safe}}{% render_field form.w1_voltage class+="form-control" %}{% render_field form.w2_voltage class+="form-control" %}{% render_field form.w3_voltage class+="form-control" %}
{{form.w1_earth_fault.help_text|safe}}{% render_field form.w1_earth_fault class+="form-control" %}{% render_field form.w2_earth_fault class+="form-control" %}{% render_field form.w3_earth_fault class+="form-control" %}
+
+
+ {% include 'partials/checklist_checkbox.html' with formitem=form.all_rcds_tested %} + {% include 'partials/checklist_checkbox.html' with formitem=form.public_sockets_tested %} + {% include 'partials/ec_power_info.html' %} +
+
+
+
+ {% endif %} +
+
+ {% button 'submit' %} +
+
+ +
+{% endblock %} diff --git a/RIGS/templates/partials/ec_power_info.html b/RIGS/templates/partials/ec_power_info.html index 8dd1f92d..8273f625 100644 --- a/RIGS/templates/partials/ec_power_info.html +++ b/RIGS/templates/partials/ec_power_info.html @@ -47,6 +47,6 @@ -

Voltage Drop on Circuit: 5% (approx. 12v)

+

Voltage Drop on Circuit: ≤5% (approx. 12v)

diff --git a/RIGS/templates/partials/hs_details.html b/RIGS/templates/partials/hs_details.html index 0decf382..edafa608 100644 --- a/RIGS/templates/partials/hs_details.html +++ b/RIGS/templates/partials/hs_details.html @@ -10,10 +10,18 @@
Event Checklists:
{% for checklist in event.checklists.all %} - {% include 'partials/hs_status.html' with event=event object=checklist view='ec_detail' edit='ec_edit' create='event_ec' review='ec_review' perm=perms.RIGS.review_eventchecklist %} -
- {% endfor %} - + {% include 'partials/hs_status.html' with event=event object=checklist view='ec_detail' edit='ec_edit' create='event_ec' review='ec_review' perm=perms.RIGS.review_eventchecklist %} +
+ {% endfor %} + +
+
Power Test Records:
+ {% for record in event.power_tests.all %} + {% include 'partials/hs_status.html' with event=event object=record view='pt_detail' edit='pt_edit' create='event_pt' review='pt_review' perm=perms.RIGS.review_power %} +
+ {% endfor %} +
diff --git a/RIGS/urls.py b/RIGS/urls.py index 4f4577da..b614f750 100644 --- a/RIGS/urls.py +++ b/RIGS/urls.py @@ -81,8 +81,8 @@ urlpatterns = [ name='ra_edit'), path('event/ra/list', permission_required_with_403('RIGS.view_riskassessment')(views.EventRiskAssessmentList.as_view()), name='ra_list'), - path('event/ra//review/', permission_required_with_403('RIGS.review_riskassessment')(views.EventRiskAssessmentReview.as_view()), - name='ra_review'), + path('event/ra//review/', permission_required_with_403('RIGS.review_riskassessment')(views.MarkReviewed.as_view()), + name='ra_review', kwargs={'model': 'RiskAssessment'}), path('event/ra//print/', permission_required_with_403('RIGS.view_riskassessment')(views.RAPrint.as_view()), name='ra_print'), path('event//checklist/', permission_required_with_403('RIGS.add_eventchecklist')(views.EventChecklistCreate.as_view()), @@ -93,8 +93,17 @@ urlpatterns = [ name='ec_edit'), path('event/checklist/list', permission_required_with_403('RIGS.view_eventchecklist')(views.EventChecklistList.as_view()), name='ec_list'), - path('event/checklist//review/', permission_required_with_403('RIGS.review_eventchecklist')(views.EventChecklistReview.as_view()), - name='ec_review'), + path('event/checklist//review/', permission_required_with_403('RIGS.review_eventchecklist')(views.MarkReviewed.as_view()), + name='ec_review', kwargs={'model': 'EventChecklist'}), + + path('event//power/', permission_required_with_403('RIGS.add_powertestrecord')(views.PowerTestCreate.as_view()), + name='event_pt'), + path('event/power//', login_required(views.PowerTestDetail.as_view()), + name='pt_detail'), + path('event/power//edit/', permission_required_with_403('RIGS.change_powertestrecord')(views.PowerTestEdit.as_view()), + name='pt_edit'), + path('event/power//review/', permission_required_with_403('RIGS.review_power')(views.MarkReviewed.as_view()), + name='pt_review', kwargs={'model': 'PowerTestRecord'}), # Finance path('invoice/', permission_required_with_403('RIGS.view_invoice')(views.InvoiceIndex.as_view()), diff --git a/RIGS/views/hs.py b/RIGS/views/hs.py index cc9dffa2..6a095091 100644 --- a/RIGS/views/hs.py +++ b/RIGS/views/hs.py @@ -1,3 +1,4 @@ +from django.apps import apps from django.contrib import messages from django.http import HttpResponseRedirect from django.urls import reverse_lazy @@ -10,7 +11,35 @@ from RIGS.views.rigboard import get_related from PyRIGS.views import PrintView -class EventRiskAssessmentCreate(generic.CreateView): +class HSCreateView(generic.CreateView): + def get_form(self, **kwargs): + form = super().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().get_context_data(**kwargs) + epk = self.kwargs.get('pk') + event = models.Event.objects.get(pk=epk) + context['event'] = event + context['page_title'] = f'Create {self} for Event {event.display_id}' + return context + + +class MarkReviewed(generic.View): + def get(self, *args, **kwargs): + obj = apps.get_model('RIGS', kwargs.get('model')).objects.get(pk=kwargs.get('pk')) + with reversion.create_revision(): + reversion.set_user(self.request.user) + obj.reviewed_by = self.request.user + obj.reviewed_at = timezone.now() + obj.save() + return HttpResponseRedirect(reverse_lazy('hs_list')) + + +class EventRiskAssessmentCreate(HSCreateView): model = models.RiskAssessment template_name = 'hs/risk_assessment_form.html' form_class = forms.EventRiskAssessmentForm @@ -27,22 +56,6 @@ class EventRiskAssessmentCreate(generic.CreateView): return super(EventRiskAssessmentCreate, self).get(self) - def get_form(self, **kwargs): - form = super(EventRiskAssessmentCreate, 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(EventRiskAssessmentCreate, self).get_context_data(**kwargs) - epk = self.kwargs.get('pk') - event = models.Event.objects.get(pk=epk) - context['event'] = event - context['page_title'] = f'Create Risk Assessment for Event {event.display_id}' - get_related(context['form'], context) - return context - def get_success_url(self): return reverse_lazy('ra_detail', kwargs={'pk': self.object.pk}) @@ -98,18 +111,6 @@ class EventRiskAssessmentList(generic.ListView): return context -class EventRiskAssessmentReview(generic.View): - def get(self, *args, **kwargs): - rpk = kwargs.get('pk') - ra = models.RiskAssessment.objects.get(pk=rpk) - with reversion.create_revision(): - reversion.set_user(self.request.user) - ra.reviewed_by = self.request.user - ra.reviewed_at = timezone.now() - ra.save() - return HttpResponseRedirect(reverse_lazy('ra_list')) - - class EventChecklistDetail(generic.DetailView): model = models.EventChecklist template_name = 'hs/event_checklist_detail.html' @@ -143,7 +144,7 @@ class EventChecklistEdit(generic.UpdateView): return context -class EventChecklistCreate(generic.CreateView): +class EventChecklistCreate(HSCreateView): model = models.EventChecklist template_name = 'hs/event_checklist_form.html' form_class = forms.EventChecklistForm @@ -162,21 +163,6 @@ class EventChecklistCreate(generic.CreateView): 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 - context['page_title'] = f'Create Event Checklist for Event {event.display_id}' - return context - def get_success_url(self): return reverse_lazy('ec_detail', kwargs={'pk': self.object.pk}) @@ -199,16 +185,59 @@ class EventChecklistList(generic.ListView): return context -class EventChecklistReview(generic.View): +class PowerTestDetail(generic.DetailView): + model = models.PowerTestRecord + template_name = 'hs/power_detail.html' + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['page_title'] = f"Power Test Record for Event {self.object.event.display_id} {self.object.event.name}" + return context + + +class PowerTestEdit(generic.UpdateView): + model = models.PowerTestRecord + template_name = 'hs/power_form.html' + form_class = forms.PowerTestRecordForm + + def get_success_url(self): + ec = self.get_object() + ec.reviewed_by = None + ec.reviewed_at = None + ec.save() + return reverse_lazy('ec_detail', kwargs={'pk': self.object.pk}) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + pk = self.kwargs.get('pk') + ec = models.PowerTestRecord.objects.get(pk=pk) + context['event'] = ec.event + context['edit'] = True + context['page_title'] = f'Edit Power Test Record for Event {ec.event.display_id}' + # get_related(context['form'], context) + return context + + +class PowerTestCreate(HSCreateView): + model = models.PowerTestRecord + template_name = 'hs/power_form.html' + form_class = forms.PowerTestRecordForm + def get(self, *args, **kwargs): - rpk = kwargs.get('pk') - ec = models.EventChecklist.objects.get(pk=rpk) - with reversion.create_revision(): - reversion.set_user(self.request.user) - ec.reviewed_by = self.request.user - ec.reviewed_at = timezone.now() - ec.save() - return HttpResponseRedirect(reverse_lazy('ec_list')) + epk = kwargs.get('pk') + event = models.Event.objects.get(pk=epk) + + # Check if RA exists + ra = models.RiskAssessment.objects.filter(event=event).first() + + if ra is None: + messages.error(self.request, f'A Risk Assessment must exist prior to creating any Power Test Records for {event}! Please create one now.') + return HttpResponseRedirect(reverse_lazy('event_ra', kwargs={'pk': epk})) + + return super().get(self) + + def get_success_url(self): + return reverse_lazy('pt_detail', kwargs={'pk': self.object.pk}) class HSList(generic.ListView):