mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-01-17 05:22:16 +00:00
Initial work on new checklist handling. No more JSON!
This commit is contained in:
@@ -4,9 +4,11 @@ from django.conf import settings
|
|||||||
from django.core import serializers
|
from django.core import serializers
|
||||||
from django.core.mail import EmailMessage, EmailMultiAlternatives
|
from django.core.mail import EmailMessage, EmailMultiAlternatives
|
||||||
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, AuthenticationForm, PasswordResetForm
|
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, AuthenticationForm, PasswordResetForm
|
||||||
|
from django.db import transaction
|
||||||
from registration.forms import RegistrationFormUniqueEmail
|
from registration.forms import RegistrationFormUniqueEmail
|
||||||
from django.contrib.auth.forms import AuthenticationForm
|
from django.contrib.auth.forms import AuthenticationForm
|
||||||
from captcha.fields import ReCaptchaField
|
from captcha.fields import ReCaptchaField
|
||||||
|
from reversion import revisions as reversion
|
||||||
import simplejson
|
import simplejson
|
||||||
|
|
||||||
from RIGS import models
|
from RIGS import models
|
||||||
@@ -18,8 +20,6 @@ forms.DateTimeField.widget = forms.DateTimeInput(attrs={'type': 'datetime-local'
|
|||||||
|
|
||||||
|
|
||||||
# Events Shit
|
# Events Shit
|
||||||
|
|
||||||
|
|
||||||
class EventForm(forms.ModelForm):
|
class EventForm(forms.ModelForm):
|
||||||
datetime_input_formats = list(settings.DATETIME_INPUT_FORMATS)
|
datetime_input_formats = list(settings.DATETIME_INPUT_FORMATS)
|
||||||
meet_at = forms.DateTimeField(input_formats=datetime_input_formats, required=False)
|
meet_at = forms.DateTimeField(input_formats=datetime_input_formats, required=False)
|
||||||
@@ -172,6 +172,50 @@ class EventRiskAssessmentForm(forms.ModelForm):
|
|||||||
|
|
||||||
|
|
||||||
class EventChecklistForm(forms.ModelForm):
|
class EventChecklistForm(forms.ModelForm):
|
||||||
|
items = {}
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
vehicles = {key:val for key, val in self.data.items()
|
||||||
|
if key.startswith('vehicle')}
|
||||||
|
drivers = {key:val for key, val in self.data.items()
|
||||||
|
if key.startswith('driver')}
|
||||||
|
for key in vehicles:
|
||||||
|
pk = int(key.split('_')[1])
|
||||||
|
driver_key = 'driver_' + str(pk)
|
||||||
|
if(drivers[driver_key] == ''):
|
||||||
|
raise forms.ValidationError('Add a driver to vehicle ' + str(pk), code='vehicle_mismatch')
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
item = models.EventChecklistVehicle.objects.get(pk=pk)
|
||||||
|
except models.EventChecklistVehicle.DoesNotExist:
|
||||||
|
item = models.EventChecklistVehicle()
|
||||||
|
|
||||||
|
item.vehicle = vehicles['vehicle_' + str(pk)]
|
||||||
|
item.driver = models.Profile.objects.get(pk=drivers['driver_' + str(pk)])
|
||||||
|
|
||||||
|
# item does not have a database pk yet as it isn't saved
|
||||||
|
self.items[pk] = item
|
||||||
|
|
||||||
|
return super(EventChecklistForm, self).clean()
|
||||||
|
|
||||||
|
def save(self, commit=True):
|
||||||
|
checklist = super(EventChecklistForm, self).save(commit=False)
|
||||||
|
if (commit):
|
||||||
|
# Remove all existing, to be recreated from the form
|
||||||
|
checklist.vehicles.all().delete()
|
||||||
|
checklist.save()
|
||||||
|
|
||||||
|
for key in self.items:
|
||||||
|
item = self.items[key]
|
||||||
|
reversion.add_to_revision(item)
|
||||||
|
# finish and save new database items
|
||||||
|
item.checklist = checklist
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
self.items.clear()
|
||||||
|
|
||||||
|
return checklist
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.EventChecklist
|
model = models.EventChecklist
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|||||||
@@ -100,7 +100,6 @@ class EventChecklistEdit(generic.UpdateView):
|
|||||||
ec = models.EventChecklist.objects.get(pk=pk)
|
ec = models.EventChecklist.objects.get(pk=pk)
|
||||||
context['event'] = ec.event
|
context['event'] = ec.event
|
||||||
context['edit'] = True
|
context['edit'] = True
|
||||||
context['vehicles_length'] = range(len(self.object.vehicles))
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
class EventChecklistCreate(generic.CreateView):
|
class EventChecklistCreate(generic.CreateView):
|
||||||
@@ -132,7 +131,6 @@ class EventChecklistCreate(generic.CreateView):
|
|||||||
epk = self.kwargs.get('pk')
|
epk = self.kwargs.get('pk')
|
||||||
event = models.Event.objects.get(pk=epk)
|
event = models.Event.objects.get(pk=epk)
|
||||||
context['event'] = event
|
context['event'] = event
|
||||||
context['vehicles_length'] = range(2)
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
|
|||||||
38
RIGS/migrations/0046_auto_20200828_1246.py
Normal file
38
RIGS/migrations/0046_auto_20200828_1246.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# Generated by Django 3.1 on 2020-08-28 11:46
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('RIGS', '0045_auto_20200824_1431'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='eventchecklist',
|
||||||
|
name='vehicles',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='eventchecklist',
|
||||||
|
name='power_mic',
|
||||||
|
field=models.ForeignKey(help_text='Who is the Power MIC?', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='checklists', to=settings.AUTH_USER_MODEL, verbose_name='Power MIC'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='profile',
|
||||||
|
name='first_name',
|
||||||
|
field=models.CharField(blank=True, max_length=150, verbose_name='first name'),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='EventChecklistVehicle',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('vehicle', models.CharField(max_length=255)),
|
||||||
|
('checklist', models.ForeignKey(blank=True, on_delete=django.db.models.deletion.CASCADE, related_name='vehicles', to='RIGS.eventchecklist')),
|
||||||
|
('driver', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='drivers', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -505,7 +505,6 @@ class EventAuthorisation(models.Model, RevisionMixin):
|
|||||||
return str("N%05d" % self.event.pk + ' (requested by ' + self.sent_by.initials + ')')
|
return str("N%05d" % self.event.pk + ' (requested by ' + self.sent_by.initials + ')')
|
||||||
|
|
||||||
|
|
||||||
@reversion.register(follow=['payment_set'])
|
|
||||||
class Invoice(models.Model):
|
class Invoice(models.Model):
|
||||||
event = models.OneToOneField('Event', on_delete=models.CASCADE)
|
event = models.OneToOneField('Event', on_delete=models.CASCADE)
|
||||||
invoice_date = models.DateField(auto_now_add=True)
|
invoice_date = models.DateField(auto_now_add=True)
|
||||||
@@ -627,15 +626,14 @@ class RiskAssessment(models.Model, RevisionMixin):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%i - %s" % (self.pk, self.event)
|
return "%i - %s" % (self.pk, self.event)
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register(follow=['vehicles',])
|
||||||
class EventChecklist(models.Model, RevisionMixin):
|
class EventChecklist(models.Model, RevisionMixin):
|
||||||
|
|
||||||
event = models.OneToOneField('Event', on_delete=models.CASCADE)
|
event = models.OneToOneField('Event', on_delete=models.CASCADE)
|
||||||
|
|
||||||
# General
|
# General
|
||||||
power_mic = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='checklist',
|
power_mic = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='checklists', null=True,
|
||||||
verbose_name="Power MIC", on_delete=models.CASCADE, help_text="Who is the Power MIC?")
|
verbose_name="Power MIC", on_delete=models.CASCADE, help_text="Who is the Power MIC?")
|
||||||
vehicles = models.JSONField(help_text="List vehicles and their drivers", default=dict, null=False)
|
#vehicles = models.JSONField(help_text="List vehicles and their drivers", default=dict, null=False)
|
||||||
|
|
||||||
# Safety Checks
|
# Safety Checks
|
||||||
safe_parking = models.BooleanField(help_text="Vehicles parked safely?<br><small>(does not obstruct venue access)</small>")
|
safe_parking = models.BooleanField(help_text="Vehicles parked safely?<br><small>(does not obstruct venue access)</small>")
|
||||||
@@ -667,3 +665,13 @@ class EventChecklist(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%i - %s" % (self.pk, self.event)
|
return "%i - %s" % (self.pk, self.event)
|
||||||
|
|
||||||
|
|
||||||
|
@reversion.register
|
||||||
|
class EventChecklistVehicle(models.Model):
|
||||||
|
checklist = models.ForeignKey('EventChecklist', related_name='vehicles', blank=True, on_delete=models.CASCADE)
|
||||||
|
vehicle = models.CharField(max_length=255)
|
||||||
|
driver = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='drivers', on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{} driven by {}".format(self.vehicle, str(self.driver))
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
function changeSelectedValue(e,t,a,l){e.find("option").remove(),e.append($("<option></option>").attr("value",t).text(a).data("update_url",l)),e.selectpicker("render"),e.selectpicker("refresh"),e.selectpicker("val",t),e.change()}function refreshUpdateHref(e){targetObject=$("#"+e.attr("id")+"-update"),update_url=$("option:selected",e).data("update_url"),""==update_url?targetObject.attr("disabled",!0):(targetObject.attr("href",update_url),targetObject.attr("disabled",!1))}function initPicker(e){console.log("called!");var t={ajax:{url:e.data("sourceurl"),type:"GET",dataType:"json",data:{term:"{{{q}}}"}},locale:{emptyTitle:""},clearOnEmpty:!1,preprocessData:function(e){var t,a=e.length,l=[];if(l.push({text:clearSelectionLabel,value:"",data:{update_url:"",subtext:""}}),a)for(t=0;t<a;t++)l.push($.extend(!0,e[t],{text:e[t].label,value:e[t].pk,data:{update_url:e[t].update,subtext:""}}));return l}};e.prepend($("<option></option>").attr("value","").text(clearSelectionLabel).data("update_url","")),e.selectpicker().ajaxSelectPicker(t),e.change((function(){refreshUpdateHref(e)})),refreshUpdateHref(e)}$(document).ready((function(){clearSelectionLabel="(no selection)",$(".selectpicker").each((function(){initPicker($(this))})),$("#modal").on("hide.bs.modal",(function(e){null!=modaltarget&&""!=modalobject&&changeSelectedValue($(modaltarget),modalobject[0].pk,modalobject[0].fields.name,modalobject[0].update_url)}))}));
|
function changeSelectedValue(e,t,a,r){e.find("option").remove(),e.append($("<option></option>").attr("value",t).text(a).data("update_url",r)),e.selectpicker("render"),e.selectpicker("refresh"),e.selectpicker("val",t),e.change()}function refreshUpdateHref(e){targetObject=$("#"+e.attr("id")+"-update"),update_url=$("option:selected",e).data("update_url"),""==update_url?targetObject.attr("disabled",!0):(targetObject.attr("href",update_url),targetObject.attr("disabled",!1))}function initPicker(e){var t={ajax:{url:e.data("sourceurl"),type:"GET",dataType:"json",data:{term:"{{{q}}}"}},locale:{emptyTitle:""},clearOnEmpty:!1,preprocessData:function(e){var t,a=e.length,r=[];if(r.push({text:clearSelectionLabel,value:"",data:{update_url:"",subtext:""}}),a)for(t=0;t<a;t++)r.push($.extend(!0,e[t],{text:e[t].label,value:e[t].pk,data:{update_url:e[t].update,subtext:""}}));return r}};e.prepend($("<option></option>").attr("value","").text(clearSelectionLabel).data("update_url","")),e.selectpicker().ajaxSelectPicker(t),e.change((function(){refreshUpdateHref(e)})),refreshUpdateHref(e)}$(document).ready((function(){clearSelectionLabel="(no selection)",$(".selectpicker").each((function(){initPicker($(this))})),$("#modal").on("hide.bs.modal",(function(e){null!=modaltarget&&""!=modalobject&&changeSelectedValue($(modaltarget),modalobject[0].pk,modalobject[0].fields.name,modalobject[0].update_url)}))}));
|
||||||
@@ -28,7 +28,6 @@ function refreshUpdateHref(obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initPicker(obj) {
|
function initPicker(obj) {
|
||||||
console.log('called!');
|
|
||||||
var options = {
|
var options = {
|
||||||
ajax: {
|
ajax: {
|
||||||
url: obj.data('sourceurl'),
|
url: obj.data('sourceurl'),
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
{% 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 %}
|
{% block title %}Event Checklist for Event N{{ object.event.pk|stringformat:"05d" }} {{ object.event.name }}{% endblock %}
|
||||||
{% load help_text from filters %}
|
{% load help_text from filters %}
|
||||||
{% load get_json_element from filters %}
|
|
||||||
{% load get_item from filters %}
|
|
||||||
{% load profile_by_index from filters %}
|
{% load profile_by_index from filters %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@@ -24,11 +22,10 @@
|
|||||||
{{ object.power_mic.name }}
|
{{ object.power_mic.name }}
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<p>{{ object|help_text:'vehicles' }}</p>
|
<p>List vehicles and their drivers</p>
|
||||||
<ul>
|
<ul>
|
||||||
{% for i in object.vehicles %}
|
{% for i in object.vehicles.all %}
|
||||||
|
<li>{{i}}</li>
|
||||||
<li>Vehicle <strong>{{ object.vehicles|get_item:i|get_item:'vehicle'|default:'none' }}</strong> driven by <strong>{{ object.vehicles|get_item:i|get_item:'driver'|profile_by_index|default:'nobody'}}</strong></li>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
{% load widget_tweaks %}
|
{% load widget_tweaks %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load help_text from filters %}
|
{% load help_text from filters %}
|
||||||
{% load get_json_element from filters %}
|
|
||||||
{% load get_item from filters %}
|
|
||||||
{% load profile_by_index from filters %}
|
{% load profile_by_index from filters %}
|
||||||
|
|
||||||
{% block title %}{% if edit %}Edit{% else %}Create{% endif %} Event Checklist for Event N{{ event.pk|stringformat:"05d" }}{% endblock %}
|
{% block title %}{% if edit %}Edit{% else %}Create{% endif %} Event Checklist for Event N{{ event.pk|stringformat:"05d" }}{% endblock %}
|
||||||
@@ -55,39 +53,31 @@
|
|||||||
$('#medium-event').slideUp();
|
$('#medium-event').slideUp();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$("form").submit(function( event ) {
|
|
||||||
// Mmmm Javascript data mangling...
|
|
||||||
var raw = $('*[data-serialize]').serializeArray();
|
|
||||||
var post = raw.reduce(function (result, current) {
|
|
||||||
var index = current.name.split('_')[1];
|
|
||||||
var name = current.name.split('_')[0];
|
|
||||||
result[index] = result[index] || {};
|
|
||||||
var nested = result[index] || {};
|
|
||||||
if(current.value):
|
|
||||||
nested[name] = current.value;
|
|
||||||
result[index] = nested;
|
|
||||||
return result;
|
|
||||||
}, {});
|
|
||||||
$({{form.vehicles.id_for_label}}).val(JSON.stringify(post));
|
|
||||||
});
|
|
||||||
$('#vehicle-add').on('click', function (event) {
|
$('#vehicle-add').on('click', function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
var newID = Number($('#vehiclest').attr('data-pk'));
|
var newID = Number($('#vehiclest').attr('data-pk'));
|
||||||
$('#vehicles_new').clone().attr('style', "").attr('id', 'vehicles_' + newID).appendTo('#vehiclest');
|
$('#vehicles_new').clone().attr('style', "").attr('id', 'vehicles_' + newID).appendTo('#vehiclest');
|
||||||
$('#vehicles_' + newID).find('select,input').attr('name', function(){
|
$('#vehicles_' + newID).find('select,input').attr('name', function(){
|
||||||
return this.name.split('_')[0] + '_' + newID;
|
return this.name.split('_')[0] + '_' + newID;
|
||||||
}).attr('data-serialize', 'true');
|
//Disabled prevents the hidden row being sent to the form
|
||||||
|
}).removeAttr('disabled');
|
||||||
|
$('#vehicles_' + newID).find('button[data-action=delete]').attr('data-id', newID);
|
||||||
$('#vehicles_' + newID).find('select').addClass('selectpicker');
|
$('#vehicles_' + newID).find('select').addClass('selectpicker');
|
||||||
$('#vehicles_' + newID).find('.selectpicker').selectpicker('refresh');
|
$('#vehicles_' + newID).find('.selectpicker').selectpicker('refresh');
|
||||||
$(".selectpicker").each(function(){initPicker($(this))});
|
$(".selectpicker").each(function(){initPicker($(this))});
|
||||||
$('#vehiclest').attr('data-pk', newID + 1);
|
$('#vehiclest').attr('data-pk', newID - 1);
|
||||||
|
});
|
||||||
|
$('button[data-action=delete]').on('click', function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
console.log($(this).attr('data-id'));
|
||||||
|
$('#vehicles_' + $(this).attr('data-id')).remove();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-sm-offset-1 col-sm-10">
|
<div class="col-12">
|
||||||
<h3>{% if edit %}Edit{% else %}Create{% endif %} Event Checklist for Event N{{ event.pk|stringformat:"05d" }}</h3>
|
<h3>{% if edit %}Edit{% else %}Create{% endif %} Event Checklist for Event N{{ event.pk|stringformat:"05d" }}</h3>
|
||||||
{% include 'form_errors.html' %}
|
{% include 'form_errors.html' %}
|
||||||
{% if edit %}
|
{% if edit %}
|
||||||
@@ -122,36 +112,36 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<label class="col-12 pt-3" for="{{ form.vehicles.id_for_label }}">{{ form.vehicles.help_text }}</label>
|
<p class="pt-3">List vehicles and their drivers</p>
|
||||||
<input name="{{ form.vehicles.name }}" id="{{ form.vehicles.id_for_label }}"
|
|
||||||
value="{{ form.vehicles.value }}"/>
|
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">Vehicle</th>
|
<th scope="col">Vehicle</th>
|
||||||
<th scope="col">Driver</th>
|
<th scope="col">Driver</th>
|
||||||
|
<th scope="col"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="vehiclest" data-pk="2">
|
<tbody id="vehiclest" data-pk="-1">
|
||||||
<tr id="vehicles_new" style="display: none;">
|
<tr id="vehicles_new" style="display: none;">
|
||||||
<td><input name="vehicle_new" type="text" class="form-control"/></td>
|
<td><input type="text" class="form-control" name="vehicle_new" disabled="true"/></td>
|
||||||
<td>
|
<td>
|
||||||
<select name="driver_new" class="form-control" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
|
<select class="form-control" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials" name="driver_new" disabled="true">
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
|
<td><button class="btn btn-danger" data-action='delete'><span class="fas fa-times"></span></button</td>
|
||||||
</tr>
|
</tr>
|
||||||
{# TODO Add required to all fields on row when one is edited #}
|
{# TODO Add required to all fields on row when one is edited #}
|
||||||
{% for i in vehicles_length %}
|
{% for i in object.vehicles.all %}
|
||||||
<tr id="vehicles_{{i}}">
|
<tr id="vehicles_{{i.pk}}">
|
||||||
<td><input name="vehicle_{{i}}" type="text" class="form-control" data-serialize="true" value="{{ form.vehicles.value|get_json_element:i|get_item:'vehicle'|default:'' }}"/></td>
|
<td><input name="vehicle_{{i.pk}}" type="text" class="form-control" value="{{ i.vehicle }}"/></td>
|
||||||
<td>
|
<td>
|
||||||
<select name="driver_{{i}}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials" data-serialize="true">
|
<select name="driver_{{i.pk}}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
|
||||||
{% if form.vehicles.value|get_json_element:i|get_item:'driver' is not 0 %}
|
{% if i.driver != '' %}
|
||||||
<option value="{{ form.vehicles.value|get_json_element:i|get_item:'driver'|default:'0' }}" selected="selected">{{form.vehicles.value|get_json_element:i|get_item:'driver'|profile_by_index}}</option>
|
<option value="{{i.driver.pk}}" selected="selected">{{ i.driver.name }}</option>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
{# TODO Delete functionality <td><button class="btn btn-danger" data-id='{{i}}' data-action='delete'><span class="fas fa-times"></span></button</td>#}
|
<td><button class="btn btn-danger" data-id='{{i.pk}}' data-action='delete'><span class="fas fa-times"></span></button</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -39,8 +39,12 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'event_ec' event.pk %}" class="btn btn-success"><span class="fas fa-paperclip"></span> <span
|
{% if event.eventchecklist %}
|
||||||
class="hidden-xs">Create Event Checklist</span></a>
|
<a class="btn btn-primary" href="{% url 'ec_detail' event.eventchecklist.pk %}">View</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{% url 'event_ec' event.pk %}" class="btn btn-success"><span class="fas fa-paperclip"></span> <span
|
||||||
|
class="hidden-xs">Create Event Checklist</span></a>
|
||||||
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
|
|||||||
@@ -53,13 +53,13 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row py-4">
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<div class="card card-default">
|
<div class="card card-default">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="pull-right">
|
<div class="text-right py-3">
|
||||||
<a href="{% url 'payment_create' %}?invoice={{ object.pk }}"
|
<a href="{% url 'payment_create' %}?invoice={{ object.pk }}"
|
||||||
class="btn btn-default modal-href"
|
class="btn btn-success modal-href"
|
||||||
data-target="#{{ form.person.id_for_label }}">
|
data-target="#{{ form.person.id_for_label }}">
|
||||||
<span class="fas fa-plus"></span> Add
|
<span class="fas fa-plus"></span> Add
|
||||||
</a>
|
</a>
|
||||||
@@ -104,7 +104,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% include 'partials/last_edited.html' with target="invoice_history" %}
|
<div class="col-12 text-right">
|
||||||
|
{% include 'partials/last_edited.html' with target="invoice_history" %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -137,19 +137,6 @@ def profile_by_index(value):
|
|||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
#TODO More sensible returns
|
|
||||||
@register.filter
|
|
||||||
def get_json_element(value, element):
|
|
||||||
try:
|
|
||||||
return json.loads(value)[str(element)]
|
|
||||||
except Exception as e:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@register.filter
|
|
||||||
def get_item(dictionary, key):
|
|
||||||
if(type(dictionary) is dict):
|
|
||||||
return dictionary.get(key)
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def next(alist, current_index):
|
def next(alist, current_index):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -115,6 +115,9 @@ urlpatterns = [
|
|||||||
name='ec_history', kwargs={'model': models.EventChecklist}),
|
name='ec_history', kwargs={'model': models.EventChecklist}),
|
||||||
path('event/checklist/list', permission_required_with_403('RIGS.change_event')(hs.EventChecklistList.as_view()),
|
path('event/checklist/list', permission_required_with_403('RIGS.change_event')(hs.EventChecklistList.as_view()),
|
||||||
name='ec_list'),
|
name='ec_list'),
|
||||||
|
# TEMPORARY
|
||||||
|
path('event/vehicle/<int:pk>/history/', permission_required_with_403('RIGS.change_event')(versioning.VersionHistory.as_view()),
|
||||||
|
name='vc_history', kwargs={'model': models.EventChecklistVehicle}),
|
||||||
|
|
||||||
# Finance
|
# Finance
|
||||||
path('invoice/', permission_required_with_403('RIGS.view_invoice')(finance.InvoiceIndex.as_view()),
|
path('invoice/', permission_required_with_403('RIGS.view_invoice')(finance.InvoiceIndex.as_view()),
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
{% if version.changes.old == None %}
|
{% if version.changes.old == None %}
|
||||||
Created
|
Created
|
||||||
{% else %}
|
{% else %}
|
||||||
Changed {% include 'version_changes.html' %} in
|
Changed {% include 'partials/version_changes.html' %} in
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% include 'partials/object_button.html' with object=version.changes.new %}
|
{% include 'partials/object_button.html' with object=version.changes.new %}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{% if version.changes.item_changes or version.changes.field_changes or version.changes.old == None %}
|
{% if version.changes.anything_changed or version.changes.old == None %}
|
||||||
{% for change in version.changes.field_changes %}
|
{% for change in version.changes.field_changes %}
|
||||||
<span title="Changes to {{ change.field.verbose_name }}" class="badge badge-info p-2" data-container="body" data-html="true" data-trigger='hover' data-toggle="popover" data-content='{% spaceless %}{% include "version_changes_change.html" %}{% endspaceless %}'>{{ change.field.verbose_name }}</span>
|
<span title="Changes to {{ change.field.verbose_name }}" class="badge badge-info p-2" data-container="body" data-html="true" data-trigger='hover' data-toggle="popover" data-content='{% spaceless %}{% include "version_changes_change.html" %}{% endspaceless %}'>{{ change.field.verbose_name }}</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
{% if version.changes.old is None %}
|
{% if version.changes.old is None %}
|
||||||
{{object|to_class_name}} Created
|
{{object|to_class_name}} Created
|
||||||
{% else %}
|
{% else %}
|
||||||
{% include 'version_changes.html' %}
|
{% include 'partials/version_changes.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ class FieldComparison(object):
|
|||||||
|
|
||||||
|
|
||||||
class ModelComparison(object):
|
class ModelComparison(object):
|
||||||
|
|
||||||
def __init__(self, old=None, new=None, version=None, excluded_keys=[]):
|
def __init__(self, old=None, new=None, version=None, excluded_keys=[]):
|
||||||
# recieves two objects of the same model, and compares them. Returns an array of FieldCompare objects
|
# recieves two objects of the same model, and compares them. Returns an array of FieldCompare objects
|
||||||
try:
|
try:
|
||||||
@@ -117,29 +116,30 @@ class ModelComparison(object):
|
|||||||
@cached_property
|
@cached_property
|
||||||
def item_changes(self):
|
def item_changes(self):
|
||||||
# Recieves two event version objects and compares their items, returns an array of ItemCompare objects
|
# Recieves two event version objects and compares their items, returns an array of ItemCompare objects
|
||||||
|
|
||||||
item_type = ContentType.objects.get_for_model(models.EventItem)
|
item_type = ContentType.objects.get_for_model(models.EventItem)
|
||||||
old_item_versions = self.version.parent.revision.version_set.filter(content_type=item_type)
|
item_dict = {}
|
||||||
new_item_versions = self.version.revision.version_set.filter(content_type=item_type)
|
if hasattr(self.version, 'parent'):
|
||||||
|
old_item_versions = self.version.parent.revision.version_set.filter(content_type=item_type)
|
||||||
|
new_item_versions = self.version.revision.version_set.filter(content_type=item_type)
|
||||||
|
|
||||||
comparisonParams = {'excluded_keys': ['id', 'event', 'order']}
|
comparisonParams = {'excluded_keys': ['id', 'event', 'order']}
|
||||||
|
|
||||||
# Build some dicts of what we have
|
# Build some dicts of what we have
|
||||||
item_dict = {} # build a list of items, key is the item_pk
|
# build a list of items, key is the item_pk
|
||||||
for version in old_item_versions: # put all the old versions in a list
|
for version in old_item_versions: # put all the old versions in a list
|
||||||
if version.field_dict["event_id"] == int(self.new.pk):
|
if version.field_dict["event_id"] == int(self.new.pk):
|
||||||
compare = ModelComparison(old=version._object_version.object, **comparisonParams)
|
compare = ModelComparison(old=version._object_version.object, **comparisonParams)
|
||||||
item_dict[version.object_id] = compare
|
item_dict[version.object_id] = compare
|
||||||
|
|
||||||
for version in new_item_versions: # go through the new versions
|
for version in new_item_versions: # go through the new versions
|
||||||
if version.field_dict["event_id"] == int(self.new.pk):
|
if version.field_dict["event_id"] == int(self.new.pk):
|
||||||
try:
|
try:
|
||||||
compare = item_dict[version.object_id] # see if there's a matching old version
|
compare = item_dict[version.object_id] # see if there's a matching old version
|
||||||
compare.new = version._object_version.object # then add the new version to the dictionary
|
compare.new = version._object_version.object # then add the new version to the dictionary
|
||||||
except KeyError: # there's no matching old version, so add this item to the dictionary by itself
|
except KeyError: # there's no matching old version, so add this item to the dictionary by itself
|
||||||
compare = ModelComparison(new=version._object_version.object, **comparisonParams)
|
compare = ModelComparison(new=version._object_version.object, **comparisonParams)
|
||||||
|
|
||||||
item_dict[version.object_id] = compare # update the dictionary with the changes
|
item_dict[version.object_id] = compare # update the dictionary with the changes
|
||||||
|
|
||||||
changes = []
|
changes = []
|
||||||
for (_, compare) in list(item_dict.items()):
|
for (_, compare) in list(item_dict.items()):
|
||||||
|
|||||||
Reference in New Issue
Block a user