Merge branch 'master' into web-calendar

This commit is contained in:
Tom Price
2015-07-29 18:39:36 +01:00
29 changed files with 888 additions and 196 deletions

View File

@@ -14,6 +14,7 @@ from z3c.rml import rml2pdf
from RIGS import models
import re
class InvoiceIndex(generic.ListView):
model = models.Invoice
@@ -63,8 +64,10 @@ class InvoicePrint(generic.View):
pdfData = buffer.read()
escapedEventName = re.sub('[^a-zA-Z0-9 \n\.]', '', object.name)
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = "filename=Invoice %05d | %s.pdf" % (invoice.pk, object.name)
response['Content-Disposition'] = "filename=Invoice %05d | %s.pdf" % (invoice.pk, escapedEventName)
response.write(pdfData)
return response

View File

@@ -9,7 +9,9 @@ from django.utils.encoding import python_2_unicode_compatible
import reversion
import string
import random
from collections import Counter
from django.core.urlresolvers import reverse_lazy
from django.core.exceptions import ValidationError
from decimal import Decimal
@@ -91,9 +93,13 @@ class Person(models.Model, RevisionMixin):
def organisations(self):
o = []
for e in Event.objects.filter(person=self).select_related('organisation'):
if e.organisation and e.organisation not in o:
if e.organisation:
o.append(e.organisation)
return o
#Count up occurances and put them in descending order
c = Counter(o)
stats = c.most_common()
return stats
@property
def latest_events(self):
@@ -131,9 +137,13 @@ class Organisation(models.Model, RevisionMixin):
def persons(self):
p = []
for e in Event.objects.filter(organisation=self).select_related('person'):
if e.person and e.person not in p:
if e.person:
p.append(e.person)
return p
#Count up occurances and put them in descending order
c = Counter(p)
stats = c.most_common()
return stats
@property
def latest_events(self):
@@ -415,7 +425,21 @@ class Event(models.Model, RevisionMixin):
return reverse_lazy('event_detail', kwargs={'pk': self.pk})
def __str__(self):
return str(self.pk) + ": " + self.name
return unicode(self.pk) + ": " + self.name
def clean(self):
if self.end_date and self.start_date > self.end_date:
raise ValidationError('Unless you\'ve invented time travel, the event can\'t finish before it has started.')
startEndSameDay = not self.end_date or self.end_date == self.start_date
hasStartAndEnd = self.has_start_time and self.has_end_time
if startEndSameDay and hasStartAndEnd and self.start_time > self.end_time:
raise ValidationError('Unless you\'ve invented time travel, the event can\'t finish before it has started.')
def save(self, *args, **kwargs):
"""Call :meth:`full_clean` before saving."""
self.full_clean()
super(Event, self).save(*args, **kwargs)
class Meta:
permissions = (

View File

@@ -47,6 +47,7 @@ class EventCreate(generic.CreateView):
def get_context_data(self, **kwargs):
context = super(EventCreate, self).get_context_data(**kwargs)
context['edit'] = True
context['currentVAT'] = models.VatRate.objects.current_rate()
form = context['form']
if re.search('"-\d+"', form['items_json'].value()):
@@ -124,7 +125,10 @@ class EventPrint(generic.View):
merger.write(merged)
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = "filename=N%05d | %s.pdf" % (object.pk, object.name)
escapedEventName = re.sub('[^a-zA-Z0-9 \n\.]', '', object.name)
response['Content-Disposition'] = "filename=N%05d | %s.pdf" % (object.pk, escapedEventName)
response.write(merged.getvalue())
return response

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -11,6 +11,10 @@ function nl2br (str, is_xhtml) {
return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1'+ breakTag +'$2');
}
function escapeHtml (str) {
return $('<div/>').text(str).html();
}
function updatePrices() {
// individual rows
var sum = 0;
@@ -101,8 +105,8 @@ $('body').on('submit', '#item-form', function (e) {
}
// update the table
$row = $('#item-' + pk);
$row.find('.name').html(fields.name);
$row.find('.description').html(nl2br(fields.description));
$row.find('.name').html(escapeHtml(fields.name));
$row.find('.description').html(nl2br(escapeHtml(fields.description)));
$row.find('.cost').html(parseFloat(fields.cost).toFixed(2));
$row.find('.quantity').html(fields.quantity);

View File

@@ -1,5 +1,5 @@
/* ========================================================================
* Bootstrap: modal.js v3.3.2
* Bootstrap: modal.js v3.3.5
* http://getbootstrap.com/javascript/#modals
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
@@ -14,12 +14,15 @@
// ======================
var Modal = function (element, options) {
this.options = options
this.$body = $(document.body)
this.$element = $(element)
this.$backdrop =
this.isShown = null
this.scrollbarWidth = 0
this.options = options
this.$body = $(document.body)
this.$element = $(element)
this.$dialog = this.$element.find('.modal-dialog')
this.$backdrop = null
this.isShown = null
this.originalBodyPad = null
this.scrollbarWidth = 0
this.ignoreBackdropClick = false
if (this.options.remote) {
this.$element
@@ -30,7 +33,7 @@
}
}
Modal.VERSION = '3.3.2'
Modal.VERSION = '3.3.5'
Modal.TRANSITION_DURATION = 300
Modal.BACKDROP_TRANSITION_DURATION = 150
@@ -64,6 +67,12 @@
this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
this.$dialog.on('mousedown.dismiss.bs.modal', function () {
that.$element.one('mouseup.dismiss.bs.modal', function (e) {
if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
})
})
this.backdrop(function () {
var transition = $.support.transition && that.$element.hasClass('fade')
@@ -75,23 +84,20 @@
.show()
.scrollTop(0)
if (that.options.backdrop) that.adjustBackdrop()
that.adjustDialog()
if (transition) {
that.$element[0].offsetWidth // force reflow
}
that.$element
.addClass('in')
.attr('aria-hidden', false)
that.$element.addClass('in')
that.enforceFocus()
var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
transition ?
that.$element.find('.modal-dialog') // wait for modal to slide in
that.$dialog // wait for modal to slide in
.one('bsTransitionEnd', function () {
that.$element.trigger('focus').trigger(e)
})
@@ -118,8 +124,10 @@
this.$element
.removeClass('in')
.attr('aria-hidden', true)
.off('click.dismiss.bs.modal')
.off('mouseup.dismiss.bs.modal')
this.$dialog.off('mousedown.dismiss.bs.modal')
$.support.transition && this.$element.hasClass('fade') ?
this.$element
@@ -179,14 +187,20 @@
if (this.isShown && this.options.backdrop) {
var doAnimate = $.support.transition && animate
this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
.prependTo(this.$element)
.on('click.dismiss.bs.modal', $.proxy(function (e) {
if (e.target !== e.currentTarget) return
this.options.backdrop == 'static'
? this.$element[0].focus.call(this.$element[0])
: this.hide.call(this)
}, this))
this.$backdrop = $(document.createElement('div'))
.addClass('modal-backdrop ' + animate)
.appendTo(this.$body)
this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
if (this.ignoreBackdropClick) {
this.ignoreBackdropClick = false
return
}
if (e.target !== e.currentTarget) return
this.options.backdrop == 'static'
? this.$element[0].focus()
: this.hide()
}, this))
if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
@@ -221,16 +235,9 @@
// these following methods are used to handle overflowing modals
Modal.prototype.handleUpdate = function () {
if (this.options.backdrop) this.adjustBackdrop()
this.adjustDialog()
}
Modal.prototype.adjustBackdrop = function () {
this.$backdrop
.css('height', 0)
.css('height', this.$element[0].scrollHeight)
}
Modal.prototype.adjustDialog = function () {
var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
@@ -248,17 +255,23 @@
}
Modal.prototype.checkScrollbar = function () {
this.bodyIsOverflowing = document.body.scrollHeight > document.documentElement.clientHeight
var fullWindowWidth = window.innerWidth
if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
var documentElementRect = document.documentElement.getBoundingClientRect()
fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
}
this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
this.scrollbarWidth = this.measureScrollbar()
}
Modal.prototype.setScrollbar = function () {
var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
this.originalBodyPad = document.body.style.paddingRight || ''
if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
}
Modal.prototype.resetScrollbar = function () {
this.$body.css('padding-right', '')
this.$body.css('padding-right', this.originalBodyPad)
}
Modal.prototype.measureScrollbar = function () { // thx walsh

View File

@@ -82,7 +82,8 @@
<template > {# Note: page is 595x842 points (1 point=1/72in) #}
<pageTemplate id="Headed" >
<pageGraphics>
<image file="RIGS/static/imgs/paperwork/corner.jpg" x="395" y="642" height="200" width="200"/>
<image file="RIGS/static/imgs/paperwork/corner-tr-su.jpg" x="395" y="642" height="200" width="200"/>
<image file="RIGS/static/imgs/paperwork/corner-bl.jpg" x="0" y="0" height="200" width="200"/>
{# logo positioned 42 from left, 33 from top #}
<image file="RIGS/static/imgs/paperwork/tec-logo.jpg" x="42" y="719" height="90" width="84"/>
@@ -108,6 +109,9 @@
<pageTemplate id="Main">
<pageGraphics>
<image file="RIGS/static/imgs/paperwork/corner-tr.jpg" x="395" y="642" height="200" width="200"/>
<image file="RIGS/static/imgs/paperwork/corner-bl.jpg" x="0" y="0" height="200" width="200"/>
<setFont name="OpenSans" size="10"/>
{% if not invoice %}<drawCenteredString x="302.5" y="50">[{{ copy }} Copy]</drawCenteredString>{% endif %}
<drawCenteredString x="302.5" y="38">[Page <pageNumber/> of <getName id="lastPage" default="0" />]</drawCenteredString>

View File

@@ -14,7 +14,7 @@
<b>{{object.start_date|date:"D jS N Y"}}</b>
</para>
<keepInFrame maxHeight="30">
<keepInFrame>
<para style="style.event_description">
{{ object.description|default_if_none:""|linebreaksbr }}
</para>
@@ -268,7 +268,7 @@
<para style="blockPara">
<b>
Conditions of hire available on request or on the TEC PA &amp; Lighting website. E&amp;OE
Conditions of hire attached and available on the TEC PA &amp; Lighting website. E&amp;OE
</b>
</para>
@@ -295,7 +295,7 @@
<para style="blockPara">
<b>
Conditions of hire available on request or on the TEC PA &amp; Lighting website. E&amp;OE
Conditions of hire attached and available on the TEC PA &amp; Lighting website. E&amp;OE
</b>
</para>

View File

@@ -38,7 +38,7 @@
<small>at {{ event.venue }}</small>
{% endif %}
{% if event.dry_hire %}
<span class="badge">Dry Hire</span>
<span class="label label-default">Dry Hire</span>
{% endif %}
</h4>
{% if event.is_rig and not event.cancelled %}

View File

@@ -29,8 +29,13 @@
<td colspan="2">£ <span id="sumtotal">{{object.sum_total|default:0|floatformat:2}}</span></td>
</tr>
<tr>
<td id="vat-rate" data-rate="{{object.vat_rate.rate}}">VAT @
{{object.vat_rate.as_percent|floatformat|default:"TBD"}}%</td>
{% if not object.pk %}
<td id="vat-rate" data-rate="{{currentVAT.rate}}">VAT @
{{currentVAT.as_percent|floatformat}}% (TBC)</td>
{% else %}
<td id="vat-rate" data-rate="{{object.vat_rate.rate}}">VAT @
{{object.vat_rate.as_percent|floatformat|default:"TBD"}}%</td>
{% endif %}
<td colspan="2">£ <span id="vat">{{object.vat|default:0|floatformat:2}}</span></td>
</tr>
<tr>

View File

@@ -1,82 +1,109 @@
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
{% load widget_tweaks %}
{% block title %}{{ object.name }}{% endblock %}
{% block title %}Organisation | {{ object.name }}{% endblock %}
{% block content %}
{% if not request.is_ajax %}
<div class="row">
<div class="col-sm-8">
<h3>{{ object.name }}<br/>
<span class="small"><a href="{% url 'organisation_history' object.pk %}" title="View Revision History">
Last edited at {{ object.last_edited_at|date:"d/m/Y H:i" }} by {{ object.last_edited_by.name }}
</a></span>
</h3>
</div>
<div class="pull-right">
<a href="{% url 'organisation_update' object.pk %}" class="btn btn-primary">Edit <span
class="glyphicon glyphicon-pencil"></span></a>
</div>
<div class="col-sm-4">
</div>
</div>
{% endif %}
<div class="row">
{% if not request.is_ajax %}
<div class="col-sm-12">
<h1>Organisation | {{ object.name }}</h1>
</div>
<div class="col-sm-12 text-right">
<div class="btn-group btn-page">
<a href="{% url 'organisation_update' object.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-pencil"></span> Edit</a>
</div>
</div>
{% endif %}
<div class="col-sm-6">
<h4>Details</h4>
<dl class="dl-horizontal">
<dt>Name</dt>
<dd>{{ object.name }}</dd>
<div class="panel panel-info">
<div class="panel-heading">Organisation Details</div>
<div class="panel-body">
<dl class="dl-horizontal">
<dt>Name</dt>
<dd>{{ object.name }}</dd>
<dt>Phone</dt>
<dd><a href="tel:{{ object.phone }}">{{ object.phone }}</a></dd>
<dt>Phone</dt>
<dd><a href="tel:{{ object.phone }}">{{ object.phone }}</a></dd>
<dt>Email</dt>
<dd><a href="mailto:{{ object.email }}">{{ object.email }}</a></dd>
<dt>Email</dt>
<dd><a href="mailto:{{ object.email }}"><span class="overflow-ellipsis">{{ object.email }}</span></a></dd>
<dt>Address</dt>
<dd>{{ object.address|linebreaksbr }}</dd>
<dt>Address</dt>
<dd>{{ object.address|linebreaksbr }}</dd>
<dt>Notes</dt>
<dd>{{ object.notes|linebreaksbr }}</dd>
<dt>Notes</dt>
<dd>{{ object.notes|linebreaksbr }}</dd>
<dt>Union Account</dt>
<dd>{{ object.union_account|yesno|capfirst }}</dd>
</dl>
<dt>Union Account</dt>
<dd>{{ object.union_account|yesno|capfirst }}</dd>
</dl>
</div>
</div>
</div>
<div class="col-sm-6">
<h4>People</h4>
<ul class="list-unstyled">
{% for person in object.persons %}
<li><a href="{% url 'person_detail' person.pk %}">{{ person.name }}</a></li>
{% endfor %}
</ul>
<div class="panel panel-default">
<div class="panel-heading">Associated People</div>
<div class="panel-body">
<div class="list-group">
{% for person,count in object.persons %}
<a class="list-group-item" href="{% url 'person_detail' person.pk %}">{{ person.pk|stringformat:"05d" }} | {{ person.name }} <span class="badge" title="{{count}} events with {{person.name}} for {{object.name}}">{{count}}</span></a>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<h4>Events</h4>
{% with object.latest_events as events %}
{% include 'RIGS/event_table.html' %}
{% endwith %}
<div class="panel panel-default">
<div class="panel-heading">Associated Events</div>
<div class="panel-body">
{% with object.latest_events as events %}
{% include 'RIGS/event_table.html' %}
{% endwith %}
</div>
</div>
</div>
</div>
{% if not request.is_ajax %}
<div class="row">
<div class="col-sm-12 text-right">
<div class="btn-group btn-page">
<a href="{% url 'organisation_update' object.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-pencil"></span> Edit</a>
</div>
<div>
<a href="{% url 'organisation_history' object.pk %}" title="View Revision History">
Last edited {{ object.last_edited_at }} by {{ object.last_edited_by.name }}
</a>
</div>
</div>
</div>
{% endif %}
{% endblock %}
{% if request.is_ajax %}
{% block footer %}
<div class="row">
<div class="col-sm-10 align-left">
<a href="{% url 'organisation_history' object.pk %}" title="View Revision History">
Last edited at {{ object.last_edited_at }} by {{ object.last_edited_by.name }}
</a>
</div>
<div class="col-sm-2">
<div class="pull-right">
<a href="{% url 'organisation_update' object.pk %}" class="btn btn-primary">Edit <span
class="glyphicon glyphicon-pencil"></span></a>
<div class="col-sm-12 text-right">
<div class="btn-group btn-page">
<a href="{% url 'organisation_detail' object.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-eye-open"></span> Open Page</a>
<a href="{% url 'organisation_update' object.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-pencil"></span> Edit</a>
</div>
<div>
<a href="{% url 'organisation_history' object.pk %}" title="View Revision History">
Last edited {{ object.last_edited_at }} by {{ object.last_edited_by.name }}
</a>
</div>
</div>
</div>

View File

@@ -1,7 +1,7 @@
{% extends request.is_ajax|yesno:'base_ajax.html,base.html' %}
{% load widget_tweaks %}
{% block title %}{% if object.pk %}Edit {{ object.name }}{% else %}Add Person{% endif %}{% endblock %}
{% block title %}{% if object.pk %}Edit {{ object.name }}{% else %}Add Organisation{% endif %}{% endblock %}
{% block content %}
<div class="col-sm-offset-1 col-sm-10">

View File

@@ -1,74 +1,106 @@
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
{% load widget_tweaks %}
{% block title %}{{ object.name }}{% endblock %}
{% block title %}Person | {{ object.name }}{% endblock %}
{% block content %}
<div class="row">
<div class="col-sm-6">
<h4>Details</h4>
{% if not request.is_ajax %}
<h3>{{ object.name }}<br/>
<span class="small"><a href="{% url 'person_history' object.pk %}" title="View Revision History">
Last edited at {{ object.last_edited_at|date:"d/m/Y H:i" }} by {{ object.last_edited_by.name }}
</a></span>
</h3>
<div class="pull-right">
<a href="{% url 'person_update' object.pk %}" class="btn btn-primary">Edit <span
class="glyphicon glyphicon-pencil"></span></a>
{% if not request.is_ajax %}
<div class="col-sm-12">
<h1>Person | {{ object.name }}</h1>
</div>
<div class="col-sm-12 text-right">
<div class="btn-group btn-page">
<a href="{% url 'person_update' object.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-pencil"></span> Edit</a>
</div>
{% endif %}
<div class="">
<dl class="dl-horizontal">
<dt>Name</dt>
<dd>{{ object.name }}</dd>
</div>
{% endif %}
<div class="col-sm-6">
<div class="panel panel-info">
<div class="panel-heading">Person Details</div>
<div class="panel-body">
<dl class="dl-horizontal">
<dt>Name</dt>
<dd>{{ object.name }}</dd>
<dt>Phone</dt>
<dd><a href="tel:{{ object.phone }}">{{ object.phone }}</a></dd>
<dt>Phone</dt>
<dd><a href="tel:{{ object.phone }}">{{ object.phone }}</a></dd>
<dt>Email</dt>
<dd><a href="mailto:{{ object.email }}">{{ object.email }}</a></dd>
<dt>Email</dt>
<dd><a href="mailto:{{ object.email }}"><span class="overflow-ellipsis">{{ object.email }}</span></a></dd>
<dt>Address</dt>
<dd>{{ object.address|linebreaksbr }}</dd>
<dt>Address</dt>
<dd>{{ object.address|linebreaksbr }}</dd>
<dt>Notes</dt>
<dd>{{ object.notes|linebreaksbr }}</dd>
</dl>
<dt>Notes</dt>
<dd>{{ object.notes|linebreaksbr }}</dd>
</dl>
</div>
</div>
</div>
<div class="col-sm-6">
<h4>Organisations</h4>
<ul class="list-unstyled">
{% for organisation in object.organisations %}
<li><a href="{% url 'organisation_detail' organisation.pk %}">{{ organisation.name }}</a></li>
{% endfor %}
</ul>
<div class="panel panel-default">
<div class="panel-heading">Associated Organisations</div>
<div class="panel-body">
<div class="list-group">
{% for organisation,count in object.organisations %}
<a class="list-group-item" href="{% url 'organisation_detail' organisation.pk %}">{{ organisation.pk|stringformat:"05d" }} | {{ organisation.name }} <span class="badge" title="{{count}} events with {{object.name}} for {{organisation.name}}">{{count}}</span></a>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<h4>Events</h4>
{% with object.latest_events as events %}
{% include 'RIGS/event_table.html' %}
{% endwith %}
<div class="panel panel-default">
<div class="panel-heading">Associated Events</div>
<div class="panel-body">
{% with object.latest_events as events %}
{% include 'RIGS/event_table.html' %}
{% endwith %}
</div>
</div>
</div>
</div>
{% if not request.is_ajax %}
<div class="row">
<div class="col-sm-12 text-right">
<div class="btn-group btn-page">
<a href="{% url 'person_update' object.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-pencil"></span> Edit</a>
</div>
<div>
<a href="{% url 'person_history' object.pk %}" title="View Revision History">
Last edited {{ object.last_edited_at }} by {{ object.last_edited_by.name }}
</a>
</div>
</div>
</div>
{% endif %}
{% endblock %}
{% if request.is_ajax %}
{% block footer %}
<div class="row">
<div class="col-sm-10 align-left">
<a href="{% url 'person_history' object.pk %}" title="View Revision History">
Last edited at {{ object.last_edited_at|date:"d/m/Y H:i" }} by {{ object.last_edited_by.name }}
</a>
</div>
<div class="col-sm-2">
<div class="pull-right">
<a href="{% url 'person_update' object.pk %}" class="btn btn-primary">Edit <span
class="glyphicon glyphicon-pencil"></span></a>
<div class="col-sm-12 text-right">
<div class="btn-group btn-page">
<a href="{% url 'person_detail' object.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-eye-open"></span> Open Page</a>
<a href="{% url 'person_update' object.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-pencil"></span> Edit</a>
</div>
<div>
<a href="{% url 'person_history' object.pk %}" title="View Revision History">
Last edited {{ object.last_edited_at }} by {{ object.last_edited_by.name }}
</a>
</div>
</div>
</div>

View File

@@ -1,64 +1,96 @@
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
{% load widget_tweaks %}
{% block title %}{{ object.name }}{% endblock %}
{% block title %}Venue | {{ object.name }}{% endblock %}
{% block content %}
<div class="row">
<div class="col-sm-10 col-sm-offset-1">
{% if not request.is_ajax %}
<h3>{{ object.name }}<br/>
<span class="small"><a href="{% url 'venue_history' object.pk %}" title="View Revision History">
Last edited at {{ object.last_edited_at|date:"d/m/Y H:i" }} by {{ object.last_edited_by.name }}
</a></span>
</h3>
<div class="pull-right">
<a href="{% url 'venue_update' object.pk %}" class="btn btn-primary">Edit <span
class="glyphicon glyphicon-pencil"></span></a>
{% if not request.is_ajax %}
<div class="col-sm-12">
<h1>Venue | {{ object.name }}</h1>
</div>
<div class="col-sm-12 text-right">
<div class="btn-group btn-page">
<a href="{% url 'venue_update' object.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-pencil"></span> Edit</a>
</div>
{% endif %}
<div class="">
<dl class="dl-horizontal">
<dt>Name</dt>
<dd>{{ object.name }}</dd>
</div>
{% endif %}
<div class="col-sm-12">
<div class="panel panel-info">
<div class="panel-heading">Venue Details</div>
<div class="panel-body">
<dl class="dl-horizontal">
<dt>Name</dt>
<dd>{{ object.name }}</dd>
<dt>Phone</dt>
<dd><a href="tel:{{ object.phone }}">{{ object.phone }}</a></dd>
<dt>Phone</dt>
<dd><a href="tel:{{ object.phone }}">{{ object.phone }}</a></dd>
<dt>Email</dt>
<dd><a href="mailto:{{ object.email }}">{{ object.email }}</a></dd>
<dt>Email</dt>
<dd><a href="mailto:{{ object.email }}"><span class="overflow-ellipsis">{{ object.email }}</span></a></dd>
<dt>Address</dt>
<dd>{{ object.address|linebreaksbr }}</dd>
<dt>Address</dt>
<dd>{{ object.address|linebreaksbr }}</dd>
<dt>Notes</dt>
<dd>{{ object.notes|linebreaksbr }}</dd>
</dl>
<dt>Notes</dt>
<dd>{{ object.notes|linebreaksbr }}</dd>
<dt>Three Phase Available</dt>
<dd>{{ object.three_phase_available|yesno|capfirst }}</dd>
</dl>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
{% with object.latest_events as events %}
{% include 'RIGS/event_table.html' %}
{% endwith %}
<div class="panel panel-default">
<div class="panel-heading">Associated Events</div>
<div class="panel-body">
{% with object.latest_events as events %}
{% include 'RIGS/event_table.html' %}
{% endwith %}
</div>
</div>
</div>
</div>
{% if not request.is_ajax %}
<div class="row">
<div class="col-sm-12 text-right">
<div class="btn-group btn-page">
<a href="{% url 'venue_update' object.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-pencil"></span> Edit</a>
</div>
<div>
<a href="{% url 'venue_history' object.pk %}" title="View Revision History">
Last edited {{ object.last_edited_at }} by {{ object.last_edited_by.name }}
</a>
</div>
</div>
</div>
{% endif %}
{% endblock %}
{% if request.is_ajax %}
{% block footer %}
<div class="row">
<div class="col-sm-10 align-left">
<a href="{% url 'venue_history' object.pk %}" title="View Revision History">
Last edited at {{ object.last_edited_at|date:"d/m/Y H:i" }} by {{ object.last_edited_by.name }}
</a>
</div>
<div class="col-sm-2">
<div class="pull-right">
<a href="{% url 'venue_update' object.pk %}" class="btn btn-primary">Edit <span
class="glyphicon glyphicon-pencil"></span></a>
<div class="col-sm-12 text-right">
<div class="btn-group btn-page">
<a href="{% url 'venue_detail' object.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-eye-open"></span> Open Page</a>
<a href="{% url 'venue_update' object.pk %}" class="btn btn-default"><span
class="glyphicon glyphicon-pencil"></span> Edit</a>
</div>
<div>
<a href="{% url 'venue_history' object.pk %}" title="View Revision History">
Last edited {{ object.last_edited_at }} by {{ object.last_edited_by.name }}
</a>
</div>
</div>
</div>

View File

@@ -58,7 +58,21 @@
{% render_field form.notes class+="form-control" placeholder=form.notes.label %}
</div>
</div>
<div class="form-group">
<div class="col-sm-10 col-sm-offset-2">
<div class="checkbox">
<label>
{% render_field form.three_phase_available %} {{ form.three_phase_available.label }}
</label>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<input class="btn btn-primary pull-right" type="submit"/>

View File

@@ -145,6 +145,8 @@ class EventTest(LiveServerTestCase):
self.profile.set_password("EventTestPassword")
self.profile.save()
self.vatrate = models.VatRate.objects.create(start_at='2014-03-05',rate=0.20,comment='test1')
self.browser = webdriver.Firefox()
os.environ['RECAPTCHA_TESTING'] = 'True'
@@ -377,9 +379,9 @@ class EventTest(LiveServerTestCase):
# Check totals
self.assertEqual("47.90", self.browser.find_element_by_id('sumtotal').text)
self.assertIn("TBD%", self.browser.find_element_by_id('vat-rate').text)
self.assertEqual("0.00", self.browser.find_element_by_id('vat').text)
self.assertEqual("47.90", self.browser.find_element_by_id('total').text)
self.assertIn("(TBC)", self.browser.find_element_by_id('vat-rate').text)
self.assertEqual("9.58", self.browser.find_element_by_id('vat').text)
self.assertEqual("57.48", self.browser.find_element_by_id('total').text)
# Attempt to save - missing title
save.click()
@@ -414,6 +416,121 @@ class EventTest(LiveServerTestCase):
event = models.Event.objects.get(name='Test Event Name')
self.assertIn("N0000%d | Test Event Name"%event.pk, self.browser.find_element_by_xpath('//h1').text)
def testDateValidation(self):
self.browser.get(self.live_server_url + '/event/create/')
# Gets redirected to login and back
self.authenticate('/event/create/')
wait = WebDriverWait(self.browser, 10) #setup WebDriverWait to use later (to wait for animations)
self.browser.implicitly_wait(3) #Set session-long wait (only works for non-existant DOM objects)
wait.until(animation_is_finished())
# Click Rig button
self.browser.find_element_by_xpath('//button[.="Rig"]').click()
form = self.browser.find_element_by_tag_name('form')
save = self.browser.find_element_by_xpath('(//button[@type="submit"])[3]')
# Set title
e = self.browser.find_element_by_id('id_name')
e.send_keys('Test Event Name')
# Both dates, no times, end before start
form.find_element_by_id('id_start_date').clear()
form.find_element_by_id('id_start_date').send_keys('3015-04-24')
form.find_element_by_id('id_end_date').clear()
form.find_element_by_id('id_end_date').send_keys('3015-04-23')
# Attempt to save - should fail
save.click()
error = self.browser.find_element_by_xpath('//div[contains(@class, "alert-danger")]')
self.assertTrue(error.is_displayed())
self.assertIn("can't finish before it has started", error.find_element_by_xpath('//dd[1]/ul/li').text)
# Same date, end time before start time
form = self.browser.find_element_by_tag_name('form')
save = self.browser.find_element_by_xpath('(//button[@type="submit"])[3]')
form.find_element_by_id('id_start_date').clear()
form.find_element_by_id('id_start_date').send_keys('3015-04-24')
form.find_element_by_id('id_end_date').clear()
form.find_element_by_id('id_end_date').send_keys('3015-04-23')
form.find_element_by_id('id_start_time').clear()
form.find_element_by_id('id_start_time').send_keys('06:59')
form.find_element_by_id('id_end_time').clear()
form.find_element_by_id('id_end_time').send_keys('06:00')
# Attempt to save - should fail
save.click()
error = self.browser.find_element_by_xpath('//div[contains(@class, "alert-danger")]')
self.assertTrue(error.is_displayed())
self.assertIn("can't finish before it has started", error.find_element_by_xpath('//dd[1]/ul/li').text)
# Same date, end time before start time
form = self.browser.find_element_by_tag_name('form')
save = self.browser.find_element_by_xpath('(//button[@type="submit"])[3]')
form.find_element_by_id('id_start_date').clear()
form.find_element_by_id('id_start_date').send_keys('3015-04-24')
form.find_element_by_id('id_end_date').clear()
form.find_element_by_id('id_end_date').send_keys('3015-04-23')
form.find_element_by_id('id_start_time').clear()
form.find_element_by_id('id_start_time').send_keys('06:59')
form.find_element_by_id('id_end_time').clear()
form.find_element_by_id('id_end_time').send_keys('06:00')
# No end date, end time before start time
form = self.browser.find_element_by_tag_name('form')
save = self.browser.find_element_by_xpath('(//button[@type="submit"])[3]')
form.find_element_by_id('id_start_date').clear()
form.find_element_by_id('id_start_date').send_keys('3015-04-24')
form.find_element_by_id('id_end_date').clear()
form.find_element_by_id('id_start_time').clear()
form.find_element_by_id('id_start_time').send_keys('06:59')
form.find_element_by_id('id_end_time').clear()
form.find_element_by_id('id_end_time').send_keys('06:00')
# Attempt to save - should fail
save.click()
error = self.browser.find_element_by_xpath('//div[contains(@class, "alert-danger")]')
self.assertTrue(error.is_displayed())
self.assertIn("can't finish before it has started", error.find_element_by_xpath('//dd[1]/ul/li').text)
# 2 dates, end after start
form = self.browser.find_element_by_tag_name('form')
save = self.browser.find_element_by_xpath('(//button[@type="submit"])[3]')
form.find_element_by_id('id_start_date').clear()
form.find_element_by_id('id_start_date').send_keys('3015-04-24')
form.find_element_by_id('id_end_date').clear()
form.find_element_by_id('id_end_date').send_keys('3015-04-26')
form.find_element_by_id('id_start_time').clear()
form.find_element_by_id('id_end_time').clear()
# Attempt to save - should succeed
save.click()
# See redirected to success page
event = models.Event.objects.get(name='Test Event Name')
self.assertIn("N0000%d | Test Event Name"%event.pk, self.browser.find_element_by_xpath('//h1').text)
def testEventDetail(self):
with transaction.atomic(), reversion.create_revision():
person = models.Person(name="Event Detail Person", email="eventdetail@person.tests.rigs", phone="123 123")

View File

@@ -144,16 +144,16 @@ class EventTestCase(TestCase):
events = models.Event.objects.all()
# Check person's organisations
self.assertIn(o1, p1.organisations)
self.assertIn(o2, p1.organisations)
self.assertIn(o1, p2.organisations)
self.assertNotIn(o2, p2.organisations)
self.assertIn((o1,2), p1.organisations)
self.assertIn((o2,1), p1.organisations)
self.assertIn((o1,2), p2.organisations)
self.assertEqual(len(p2.organisations), 1)
# Check organisation's persons
self.assertIn(p1, o1.persons)
self.assertIn(p2, o1.persons)
self.assertIn(p1, o2.persons)
self.assertNotIn(p2, o2.persons)
self.assertIn((p1,2), o1.persons)
self.assertIn((p2,2), o1.persons)
self.assertIn((p1,1), o2.persons)
self.assertEqual(len(o2.persons),1)
def test_cancelled_property(self):
event = models.Event.objects.all()[0]

View File

@@ -177,7 +177,7 @@ class VenueDetail(generic.DetailView):
class VenueCreate(generic.CreateView):
model = models.Venue
fields = ['name','phone','email','address','notes']
fields = ['name','phone','email','address','notes','three_phase_available']
def get_success_url(self):
if self.request.is_ajax():
@@ -194,7 +194,7 @@ class VenueCreate(generic.CreateView):
class VenueUpdate(generic.UpdateView):
model = models.Venue
fields = ['name','phone','email','address','notes']
fields = ['name','phone','email','address','notes','three_phase_available']
def get_success_url(self):
if self.request.is_ajax():