mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-02-10 08:39:41 +00:00
Merge branch 'master' into markdown
# Conflicts: # RIGS/static/css/screen.css # db.sqlite3 # requirements.txt
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# TEC PA & Lighting - PyRIGS #
|
||||
[](https://app.wercker.com/project/bykey/b26100ecccdfb46a9a9056553daac5b7)
|
||||
[](https://app.wercker.com/project/bykey/2dbe0517c3d83859c985ffc5a55a2802)
|
||||
|
||||
Welcome to TEC PA & Lightings PyRIGS program. This is a reimplementation of the existing Rig Information Gathering System (RIGS) that was developed using Ruby on Rails.
|
||||
|
||||
@@ -75,4 +75,4 @@ python manage.py runserver
|
||||
Please refer to Django documentation for a full list of options available here.
|
||||
|
||||
### Committing, pushing and testing ###
|
||||
Feel free to commit as you wish, on your own branch. On my branch (master for development) do not commit code that you either know doesn't work or don't know works. If you must commit this code, please make sure you say in the commit message that it isn't working, and if you can why it isn't working. If and only if you absolutely must push, then please don't leave it as the HEAD for too long, it's not much to ask but when you are done just make sure you haven't broken the HEAD for the next person.
|
||||
Feel free to commit as you wish, on your own branch. On my branch (master for development) do not commit code that you either know doesn't work or don't know works. If you must commit this code, please make sure you say in the commit message that it isn't working, and if you can why it isn't working. If and only if you absolutely must push, then please don't leave it as the HEAD for too long, it's not much to ask but when you are done just make sure you haven't broken the HEAD for the next person.
|
||||
|
||||
@@ -4,19 +4,20 @@ from django.utils import formats
|
||||
from django.conf import settings
|
||||
from django.core import serializers
|
||||
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, AuthenticationForm, PasswordResetForm
|
||||
from registration.forms import RegistrationFormUniqueEmail
|
||||
from registration.forms import RegistrationFormUniqueEmail
|
||||
from captcha.fields import ReCaptchaField
|
||||
import simplejson
|
||||
|
||||
from RIGS import models
|
||||
|
||||
#Registration
|
||||
|
||||
# Registration
|
||||
class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
|
||||
captcha = ReCaptchaField()
|
||||
|
||||
class Meta:
|
||||
model = models.Profile
|
||||
fields = ('username','email','first_name','last_name','initials','phone')
|
||||
fields = ('username', 'email', 'first_name', 'last_name', 'initials', 'phone')
|
||||
|
||||
def clean_initials(self):
|
||||
"""
|
||||
@@ -26,24 +27,22 @@ class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
|
||||
raise forms.ValidationError("These initials are already in use. Please supply different initials.")
|
||||
return self.cleaned_data['initials']
|
||||
|
||||
# Login form
|
||||
class LoginForm(AuthenticationForm):
|
||||
captcha = ReCaptchaField(label='Captcha')
|
||||
|
||||
# Login form
|
||||
class PasswordReset(PasswordResetForm):
|
||||
captcha = ReCaptchaField(label='Captcha')
|
||||
|
||||
class ProfileCreationForm(UserCreationForm):
|
||||
|
||||
class ProfileCreationForm(UserCreationForm):
|
||||
class Meta(UserCreationForm.Meta):
|
||||
model = models.Profile
|
||||
|
||||
|
||||
class ProfileChangeForm(UserChangeForm):
|
||||
|
||||
class Meta(UserChangeForm.Meta):
|
||||
model = models.Profile
|
||||
|
||||
|
||||
# Events Shit
|
||||
class EventForm(forms.ModelForm):
|
||||
datetime_input_formats = formats.get_format_lazy("DATETIME_INPUT_FORMATS") + settings.DATETIME_INPUT_FORMATS
|
||||
@@ -96,7 +95,7 @@ class EventForm(forms.ModelForm):
|
||||
|
||||
def _get_or_initialise_item(self, pk, data, event):
|
||||
try:
|
||||
item = models.EventItem.objects.get(pk=pk,event=event)
|
||||
item = models.EventItem.objects.get(pk=pk, event=event)
|
||||
except models.EventItem.DoesNotExist:
|
||||
# This occurs for one of two reasons
|
||||
# 1) The event has been duplicated, so the item PKs belong to another event
|
||||
@@ -134,12 +133,11 @@ class EventForm(forms.ModelForm):
|
||||
for key in items:
|
||||
items[key].save()
|
||||
|
||||
|
||||
return m
|
||||
|
||||
class Meta:
|
||||
model = models.Event
|
||||
fields = ['is_rig', 'name', 'venue', 'start_time', 'end_date', 'start_date',
|
||||
'end_time', 'meet_at', 'access_at', 'description', 'notes', 'mic',
|
||||
'person', 'organisation', 'dry_hire', 'checked_in_by', 'status',
|
||||
'collector','purchase_order']
|
||||
'person', 'organisation', 'dry_hire', 'checked_in_by', 'status',
|
||||
'collector', 'purchase_order']
|
||||
|
||||
20
RIGS/migrations/0024_auto_20160229_2042.py
Normal file
20
RIGS/migrations/0024_auto_20160229_2042.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('RIGS', '0023_auto_20150529_0048'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='based_on',
|
||||
field=models.ForeignKey(related_name='future_events', on_delete=django.db.models.deletion.SET_NULL, blank=True, to='RIGS.Event', null=True),
|
||||
),
|
||||
]
|
||||
@@ -38,7 +38,10 @@ class Profile(AbstractUser):
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.get_full_name() + ' "' + self.initials + '"'
|
||||
name = self.get_full_name()
|
||||
if self.initials:
|
||||
name += ' "{}"'.format(self.initials)
|
||||
return name
|
||||
|
||||
@property
|
||||
def latest_events(self):
|
||||
@@ -298,7 +301,7 @@ class Event(models.Model, RevisionMixin):
|
||||
status = models.IntegerField(choices=EVENT_STATUS_CHOICES, default=PROVISIONAL)
|
||||
dry_hire = models.BooleanField(default=False)
|
||||
is_rig = models.BooleanField(default=True)
|
||||
based_on = models.ForeignKey('Event', related_name='future_events', blank=True, null=True)
|
||||
based_on = models.ForeignKey('Event', on_delete=models.SET_NULL, related_name='future_events', blank=True, null=True)
|
||||
|
||||
# Timing
|
||||
start_date = models.DateField()
|
||||
|
||||
@@ -37,6 +37,12 @@ class RigboardIndex(generic.TemplateView):
|
||||
class WebCalendar(generic.TemplateView):
|
||||
template_name = 'RIGS/calendar.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(WebCalendar, self).get_context_data(**kwargs)
|
||||
context['view'] = kwargs.get('view','')
|
||||
context['date'] = kwargs.get('date','')
|
||||
return context
|
||||
|
||||
class EventDetail(generic.DetailView):
|
||||
model = models.Event
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ fonts_dir = "fonts"
|
||||
|
||||
# You can select your preferred output style here (can be overridden via the command line):
|
||||
# output_style = :expanded or :nested or :compact or :compressed
|
||||
output_style = :compressed
|
||||
|
||||
# To enable relative paths to assets via compass helper functions. Uncomment:
|
||||
# relative_assets = true
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -39,7 +39,7 @@ var Konami = function (callback) {
|
||||
return false;
|
||||
}
|
||||
}, this);
|
||||
this.iphone.load(link);
|
||||
/*this.iphone.load(link);*/
|
||||
},
|
||||
code: function (link) {
|
||||
window.location = link
|
||||
|
||||
@@ -75,6 +75,16 @@ textarea {
|
||||
}
|
||||
}
|
||||
|
||||
del {
|
||||
background-color: #f2dede;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
ins {
|
||||
background-color: #dff0d8;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.loading-animation {
|
||||
position: relative;
|
||||
margin: 30px auto 0;
|
||||
|
||||
@@ -14,8 +14,28 @@
|
||||
<script src="{% static "js/moment.min.js" %}"></script>
|
||||
<script src="{% static "js/fullcalendar.js" %}"></script>
|
||||
<script>
|
||||
|
||||
function getUrlVars() {
|
||||
var vars = {};
|
||||
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
|
||||
vars[key] = value;
|
||||
});
|
||||
return vars;
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
viewToUrl = {
|
||||
'agendaWeek':'week',
|
||||
'agendaDay':'day',
|
||||
'month':'month'
|
||||
}
|
||||
viewFromUrl = {
|
||||
'week':'agendaWeek',
|
||||
'day':'agendaDay',
|
||||
'month':'month'
|
||||
}
|
||||
|
||||
$('#calendar').fullCalendar({
|
||||
editable: false,
|
||||
eventLimit: true, // allow "more" link when too many events
|
||||
@@ -114,8 +134,11 @@
|
||||
$('#day-button').addClass('active');
|
||||
break;
|
||||
}
|
||||
|
||||
history.replaceState(null,null,'{% url 'web_calendar' %}'+viewToUrl[view.name]+'/'+view.intervalStart.format('YYYY-MM-DD')+'/');
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
// set some button listeners
|
||||
@@ -146,6 +169,18 @@
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Go to the initial settings, if they're valid
|
||||
view = viewFromUrl['{{view}}'];
|
||||
$('#calendar').fullCalendar( 'changeView', view);
|
||||
|
||||
day = moment('{{date}}');
|
||||
if(day.isValid()){
|
||||
$('#calendar').fullCalendar( 'gotoDate', day);
|
||||
}else{
|
||||
console.log('Supplied date is invalid - using default')
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
<a href="{% url 'event_detail' pk=object.based_on.pk %}">
|
||||
{% if object.based_on.is_rig %}N{{ object.based_on.pk|stringformat:"05d" }}{% else %}
|
||||
{{ object.based_on.pk }}{% endif %}
|
||||
{{ object.base_on.name }} by {{ object.based_on.mic.name }}
|
||||
{{ object.base_on.name }} {% if object.based_on.mic %}by {{ object.based_on.mic.name }}{% endif %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</dd>
|
||||
@@ -234,13 +234,17 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if not request.is_ajax %}
|
||||
<div class="col-sm-12 text-right">
|
||||
<div>
|
||||
<a href="{% url 'event_history' object.pk %}" title="View Revision History">
|
||||
Last edited at {{ object.last_edited_at }} by {{ object.last_edited_by.name }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
<keepTogether>
|
||||
<blockTable style="totalTable" colWidths="300,115,80">
|
||||
<tr>
|
||||
<td>{% if not invoice %}VAT Registration Number: 116252989{% endif %}</td>
|
||||
<td>{% if not invoice %}VAT Registration Number: 170734807{% endif %}</td>
|
||||
<td>Total (ex. VAT)</td>
|
||||
<td>£ {{ object.sum_total|floatformat:2 }}</td>
|
||||
</tr>
|
||||
@@ -225,7 +225,7 @@
|
||||
|
||||
<para>
|
||||
{% if invoice %}
|
||||
VAT Registration Number: 116252989
|
||||
VAT Registration Number: 170734807
|
||||
{% else %}
|
||||
<b>This contract is not an invoice.</b>
|
||||
{% endif %}
|
||||
|
||||
@@ -1,40 +1,21 @@
|
||||
{% for change in version.field_changes %}
|
||||
|
||||
<button title="Changes to {{ change.field.verbose_name }}" type="button" class="btn btn-default btn-xs" data-container="body" data-html="true" data-trigger='hover' data-toggle="popover" data-content='
|
||||
|
||||
{% if change.new %}
|
||||
<div class="alert alert-success {% if change.long %}overflow-ellipsis{% endif %}">
|
||||
{% if change.linebreaks %}
|
||||
{{change.new|linebreaksbr}}
|
||||
{% else %}
|
||||
{{change.new}}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if change.old %}
|
||||
<div class="alert alert-danger {% if change.long %}overflow-ellipsis{% endif %}">
|
||||
{% if change.linebreaks %}
|
||||
{{change.old|linebreaksbr}}
|
||||
{% else %}
|
||||
{{change.old}}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
'>{{ change.field.verbose_name }}</button>
|
||||
<button title="Changes to {{ change.field.verbose_name }}" type="button" class="btn btn-default btn-xs" data-container="body" data-html="true" data-trigger='hover' data-toggle="popover" data-content='{% spaceless %}
|
||||
{% include "RIGS/version_changes_change.html" %}
|
||||
{% endspaceless %}'>{{ change.field.verbose_name }}</button>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% for itemChange in version.item_changes %}
|
||||
<button title="Changes to item '{% if itemChange.new %}{{ itemChange.new.name }}{% else %}{{ itemChange.old.name }}{% endif %}'" type="button" class="btn btn-default btn-xs" data-container="body" data-html="true" data-trigger='hover' data-toggle="popover" data-content='
|
||||
<button title="Changes to item '{% if itemChange.new %}{{ itemChange.new.name }}{% else %}{{ itemChange.old.name }}{% endif %}'" type="button" class="btn btn-default btn-xs" data-container="body" data-html="true" data-trigger='hover' data-toggle="popover" data-content='{% spaceless %}
|
||||
<ul class="list-group">
|
||||
{% for change in itemChange.changes %}
|
||||
<h4>{{ change.field.verbose_name }}</h4>
|
||||
|
||||
{% if change.new %}<div class="alert alert-success">{{change.new|linebreaksbr}}</div>{% endif %}
|
||||
{% if change.old %}<div class="alert alert-danger">{{change.old|linebreaksbr}}</div>{% endif %}
|
||||
|
||||
<li class="list-group-item">
|
||||
<h4 class="list-group-item-heading">{{ change.field.verbose_name }}</h4>
|
||||
{% include "RIGS/version_changes_change.html" %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
'>item '{% if itemChange.new %}{{ itemChange.new.name }}{% else %}{{ itemChange.old.name }}{% endif %}'</button>
|
||||
{% endspaceless %}'>item '{% if itemChange.new %}{{ itemChange.new.name }}{% else %}{{ itemChange.old.name }}{% endif %}'</button>
|
||||
{% endfor %}
|
||||
34
RIGS/templates/RIGS/version_changes_change.html
Normal file
34
RIGS/templates/RIGS/version_changes_change.html
Normal file
@@ -0,0 +1,34 @@
|
||||
{# pass in variable "change" to this template #}
|
||||
{% if change.linebreaks and change.new and change.old %}
|
||||
{% for diff in change.diff %}
|
||||
{% if diff.type == "insert" %}
|
||||
<ins>{{ diff.text|linebreaksbr }}</ins>
|
||||
{% elif diff.type == "delete" %}
|
||||
<del>{{diff.text|linebreaksbr}}</del>
|
||||
{% else %}
|
||||
<span>{{diff.text|linebreaksbr}}</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% if change.old %}
|
||||
<del {% if change.long %}class="overflow-ellipsis"{% endif %}>
|
||||
{% if change.linebreaks %}
|
||||
{{change.old|linebreaksbr}}
|
||||
{% else %}
|
||||
{{change.old}}
|
||||
{% endif %}
|
||||
</del>
|
||||
{% endif %}
|
||||
{% if change.new and change.old %}
|
||||
<br/>
|
||||
{% endif %}
|
||||
{% if change.new %}
|
||||
<ins {% if change.long %}class="overflow-ellipsis"{% endif %}>
|
||||
{% if change.linebreaks %}
|
||||
{{change.new|linebreaksbr}}
|
||||
{% else %}
|
||||
{{change.new}}
|
||||
{% endif %}
|
||||
</ins>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -4,7 +4,7 @@ from django.test.client import Client
|
||||
from django.core import mail
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.common.exceptions import StaleElementReferenceException
|
||||
from selenium.common.exceptions import StaleElementReferenceException, WebDriverException
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from RIGS import models
|
||||
import re
|
||||
@@ -159,6 +159,7 @@ class EventTest(LiveServerTestCase):
|
||||
|
||||
self.browser = webdriver.Firefox()
|
||||
self.browser.implicitly_wait(3) # Set implicit wait session wide
|
||||
self.browser.maximize_window()
|
||||
os.environ['RECAPTCHA_TESTING'] = 'True'
|
||||
|
||||
def tearDown(self):
|
||||
@@ -177,8 +178,6 @@ class EventTest(LiveServerTestCase):
|
||||
|
||||
username.send_keys("EventTest")
|
||||
password.send_keys("EventTestPassword")
|
||||
self.browser.execute_script(
|
||||
"return jQuery('#g-recaptcha-response').val('PASSED')")
|
||||
submit.click()
|
||||
|
||||
self.assertEqual(self.live_server_url + n, self.browser.current_url)
|
||||
@@ -197,233 +196,245 @@ class EventTest(LiveServerTestCase):
|
||||
self.browser.get(self.live_server_url + '/rigboard/')
|
||||
|
||||
def testRigCreate(self):
|
||||
# Requests address
|
||||
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)
|
||||
|
||||
wait.until(animation_is_finished())
|
||||
|
||||
# Check has slided up correctly - second save button hidden
|
||||
save = self.browser.find_element_by_xpath(
|
||||
'(//button[@type="submit"])[3]')
|
||||
self.assertFalse(save.is_displayed())
|
||||
|
||||
# Click Rig button
|
||||
self.browser.find_element_by_xpath('//button[.="Rig"]').click()
|
||||
|
||||
# Slider expands and save button visible
|
||||
self.assertTrue(save.is_displayed())
|
||||
form = self.browser.find_element_by_tag_name('form')
|
||||
|
||||
# Create new person
|
||||
add_person_button = self.browser.find_element_by_xpath(
|
||||
'//a[@data-target="#id_person" and contains(@href, "add")]')
|
||||
add_person_button.click()
|
||||
|
||||
# See modal has opened
|
||||
modal = self.browser.find_element_by_id('modal')
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Person", modal.find_element_by_tag_name('h3').text)
|
||||
|
||||
# Fill person form out and submit
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Person 1")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
|
||||
# See new person selected
|
||||
person1 = models.Person.objects.get(name="Test Person 1")
|
||||
self.assertEqual(person1.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
# and backend
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person1.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Change mind and add another
|
||||
add_person_button.click()
|
||||
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Person", modal.find_element_by_tag_name('h3').text)
|
||||
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Person 2")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
|
||||
person2 = models.Person.objects.get(name="Test Person 2")
|
||||
self.assertEqual(person2.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
# Have to do this explcitly to force the wait for it to update
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person2.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Was right the first time, change it back
|
||||
person_select = form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]')
|
||||
person_select.send_keys(person1.name)
|
||||
person_dropped = form.find_element_by_xpath(
|
||||
'//ul[contains(@class, "inner selectpicker")]//span[contains(text(), "%s")]' % person1.name)
|
||||
person_dropped.click()
|
||||
|
||||
self.assertEqual(person1.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person1.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Edit Person 1 to have a better name
|
||||
form.find_element_by_xpath(
|
||||
'//a[@data-target="#id_person" and contains(@href, "%s/edit/")]' % person1.pk).click()
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Edit Person", modal.find_element_by_tag_name('h3').text)
|
||||
name = modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]')
|
||||
self.assertEqual(person1.name, name.get_attribute('value'))
|
||||
name.clear()
|
||||
name.send_keys('Rig ' + person1.name)
|
||||
name.send_keys(Keys.ENTER)
|
||||
|
||||
wait.until(animation_is_finished())
|
||||
|
||||
self.assertFalse(modal.is_displayed())
|
||||
person1 = models.Person.objects.get(pk=person1.pk)
|
||||
self.assertEqual(person1.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
|
||||
# Create organisation
|
||||
add_button = self.browser.find_element_by_xpath(
|
||||
'//a[@data-target="#id_organisation" and contains(@href, "add")]')
|
||||
add_button.click()
|
||||
modal = self.browser.find_element_by_id('modal')
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Organisation", modal.find_element_by_tag_name('h3').text)
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Organisation")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
|
||||
# See it is selected
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
obj = models.Organisation.objects.get(name="Test Organisation")
|
||||
self.assertEqual(obj.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_organisation"]/span').text)
|
||||
# and backend
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_organisation"]//option[@selected="selected"]')
|
||||
self.assertEqual(obj.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Create veneue
|
||||
add_button = self.browser.find_element_by_xpath(
|
||||
'//a[@data-target="#id_venue" and contains(@href, "add")]')
|
||||
add_button.click()
|
||||
modal = self.browser.find_element_by_id('modal')
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Venue", modal.find_element_by_tag_name('h3').text)
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Venue")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
|
||||
# See it is selected
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
obj = models.Venue.objects.get(name="Test Venue")
|
||||
self.assertEqual(obj.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_venue"]/span').text)
|
||||
# and backend
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_venue"]//option[@selected="selected"]')
|
||||
self.assertEqual(obj.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Set start date/time
|
||||
form.find_element_by_id('id_start_date').send_keys('3015-05-25')
|
||||
form.find_element_by_id('id_start_time').send_keys('06:59')
|
||||
|
||||
# Set end date/time
|
||||
form.find_element_by_id('id_end_date').send_keys('4000-06-27')
|
||||
form.find_element_by_id('id_end_time').send_keys('07:00')
|
||||
|
||||
# Add item
|
||||
form.find_element_by_xpath('//button[contains(@class, "item-add")]').click()
|
||||
wait.until(animation_is_finished())
|
||||
modal = self.browser.find_element_by_id("itemModal")
|
||||
modal.find_element_by_id("item_name").send_keys("Test Item 1")
|
||||
modal.find_element_by_id("item_description").send_keys("This is an item description\nthat for reasons unkown spans two lines")
|
||||
e = modal.find_element_by_id("item_quantity")
|
||||
e.click()
|
||||
e.send_keys(Keys.UP)
|
||||
e.send_keys(Keys.UP)
|
||||
e = modal.find_element_by_id("item_cost")
|
||||
e.send_keys("23.95")
|
||||
e.send_keys(Keys.ENTER) # enter submit
|
||||
|
||||
# Confirm item has been saved to json field
|
||||
objectitems = self.browser.execute_script("return objectitems;")
|
||||
self.assertEqual(1, len(objectitems))
|
||||
testitem = objectitems["-1"]['fields'] # as we are deliberately creating this we know the ID
|
||||
self.assertEqual("Test Item 1", testitem['name'])
|
||||
self.assertEqual("2", testitem['quantity']) # test a couple of "worse case" fields
|
||||
|
||||
# See new item appear in table
|
||||
row = self.browser.find_element_by_id('item--1') # ID number is known, see above
|
||||
self.assertIn("Test Item 1", row.find_element_by_xpath('//span[@class="name"]').text)
|
||||
self.assertIn("This is an item description", row.find_element_by_xpath('//div[@class="item-description"]').text)
|
||||
self.assertEqual(u'£ 23.95', row.find_element_by_xpath('//tr[@id="item--1"]/td[2]').text)
|
||||
self.assertEqual("2", row.find_element_by_xpath('//td[@class="quantity"]').text)
|
||||
self.assertEqual(u'£ 47.90', row.find_element_by_xpath('//tr[@id="item--1"]/td[4]').text)
|
||||
|
||||
# Check totals
|
||||
self.assertEqual("47.90", self.browser.find_element_by_id('sumtotal').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()
|
||||
|
||||
# See error
|
||||
error = self.browser.find_element_by_xpath('//div[contains(@class, "alert-danger")]')
|
||||
self.assertTrue(error.is_displayed())
|
||||
# Should only have one error message
|
||||
self.assertEqual("Name", error.find_element_by_xpath('//dt[1]').text)
|
||||
self.assertEqual("This field is required.", error.find_element_by_xpath('//dd[1]/ul/li').text)
|
||||
# don't need error so close it
|
||||
error.find_element_by_xpath('//div[contains(@class, "alert-danger")]//button[@class="close"]').click()
|
||||
try:
|
||||
self.assertFalse(error.is_displayed())
|
||||
except StaleElementReferenceException:
|
||||
# Requests address
|
||||
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)
|
||||
|
||||
wait.until(animation_is_finished())
|
||||
|
||||
# Check has slided up correctly - second save button hidden
|
||||
save = self.browser.find_element_by_xpath(
|
||||
'(//button[@type="submit"])[3]')
|
||||
self.assertFalse(save.is_displayed())
|
||||
|
||||
# Click Rig button
|
||||
self.browser.find_element_by_xpath('//button[.="Rig"]').click()
|
||||
|
||||
# Slider expands and save button visible
|
||||
self.assertTrue(save.is_displayed())
|
||||
form = self.browser.find_element_by_tag_name('form')
|
||||
|
||||
# Create new person
|
||||
wait.until(animation_is_finished())
|
||||
add_person_button = self.browser.find_element_by_xpath(
|
||||
'//a[@data-target="#id_person" and contains(@href, "add")]')
|
||||
add_person_button.click()
|
||||
|
||||
# See modal has opened
|
||||
modal = self.browser.find_element_by_id('modal')
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Person", modal.find_element_by_tag_name('h3').text)
|
||||
|
||||
# Fill person form out and submit
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Person 1")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
|
||||
# See new person selected
|
||||
person1 = models.Person.objects.get(name="Test Person 1")
|
||||
self.assertEqual(person1.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
# and backend
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person1.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Change mind and add another
|
||||
wait.until(animation_is_finished())
|
||||
add_person_button.click()
|
||||
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Person", modal.find_element_by_tag_name('h3').text)
|
||||
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Person 2")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
|
||||
person2 = models.Person.objects.get(name="Test Person 2")
|
||||
self.assertEqual(person2.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
# Have to do this explcitly to force the wait for it to update
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person2.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Was right the first time, change it back
|
||||
person_select = form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]')
|
||||
person_select.send_keys(person1.name)
|
||||
person_dropped = form.find_element_by_xpath(
|
||||
'//ul[contains(@class, "inner selectpicker")]//span[contains(text(), "%s")]' % person1.name)
|
||||
person_dropped.click()
|
||||
|
||||
self.assertEqual(person1.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person1.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Edit Person 1 to have a better name
|
||||
form.find_element_by_xpath(
|
||||
'//a[@data-target="#id_person" and contains(@href, "%s/edit/")]' % person1.pk).click()
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Edit Person", modal.find_element_by_tag_name('h3').text)
|
||||
name = modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]')
|
||||
self.assertEqual(person1.name, name.get_attribute('value'))
|
||||
name.clear()
|
||||
name.send_keys('Rig ' + person1.name)
|
||||
name.send_keys(Keys.ENTER)
|
||||
|
||||
wait.until(animation_is_finished())
|
||||
|
||||
self.assertFalse(modal.is_displayed())
|
||||
person1 = models.Person.objects.get(pk=person1.pk)
|
||||
self.assertEqual(person1.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_person"]/span').text)
|
||||
|
||||
# Create organisation
|
||||
wait.until(animation_is_finished())
|
||||
add_button = self.browser.find_element_by_xpath(
|
||||
'//a[@data-target="#id_organisation" and contains(@href, "add")]')
|
||||
add_button.click()
|
||||
modal = self.browser.find_element_by_id('modal')
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Organisation", modal.find_element_by_tag_name('h3').text)
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Organisation")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
|
||||
# See it is selected
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
obj = models.Organisation.objects.get(name="Test Organisation")
|
||||
self.assertEqual(obj.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_organisation"]/span').text)
|
||||
# and backend
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_organisation"]//option[@selected="selected"]')
|
||||
self.assertEqual(obj.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Create venue
|
||||
wait.until(animation_is_finished())
|
||||
add_button = self.browser.find_element_by_xpath(
|
||||
'//a[@data-target="#id_venue" and contains(@href, "add")]')
|
||||
wait.until(animation_is_finished())
|
||||
add_button.click()
|
||||
wait.until(animation_is_finished())
|
||||
modal = self.browser.find_element_by_id('modal')
|
||||
wait.until(animation_is_finished())
|
||||
self.assertTrue(modal.is_displayed())
|
||||
self.assertIn("Add Venue", modal.find_element_by_tag_name('h3').text)
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Venue")
|
||||
modal.find_element_by_xpath(
|
||||
'//div[@id="modal"]//input[@type="submit"]').click()
|
||||
|
||||
# See it is selected
|
||||
wait.until(animation_is_finished())
|
||||
self.assertFalse(modal.is_displayed())
|
||||
obj = models.Venue.objects.get(name="Test Venue")
|
||||
self.assertEqual(obj.name, form.find_element_by_xpath(
|
||||
'//button[@data-id="id_venue"]/span').text)
|
||||
# and backend
|
||||
option = form.find_element_by_xpath(
|
||||
'//select[@id="id_venue"]//option[@selected="selected"]')
|
||||
self.assertEqual(obj.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Set start date/time
|
||||
form.find_element_by_id('id_start_date').send_keys('3015-05-25')
|
||||
form.find_element_by_id('id_start_time').send_keys('06:59')
|
||||
|
||||
# Set end date/time
|
||||
form.find_element_by_id('id_end_date').send_keys('4000-06-27')
|
||||
form.find_element_by_id('id_end_time').send_keys('07:00')
|
||||
|
||||
# Add item
|
||||
form.find_element_by_xpath('//button[contains(@class, "item-add")]').click()
|
||||
wait.until(animation_is_finished())
|
||||
modal = self.browser.find_element_by_id("itemModal")
|
||||
modal.find_element_by_id("item_name").send_keys("Test Item 1")
|
||||
modal.find_element_by_id("item_description").send_keys("This is an item description\nthat for reasons unkown spans two lines")
|
||||
e = modal.find_element_by_id("item_quantity")
|
||||
e.click()
|
||||
e.send_keys(Keys.UP)
|
||||
e.send_keys(Keys.UP)
|
||||
e = modal.find_element_by_id("item_cost")
|
||||
e.send_keys("23.95")
|
||||
e.send_keys(Keys.ENTER) # enter submit
|
||||
|
||||
# Confirm item has been saved to json field
|
||||
objectitems = self.browser.execute_script("return objectitems;")
|
||||
self.assertEqual(1, len(objectitems))
|
||||
testitem = objectitems["-1"]['fields'] # as we are deliberately creating this we know the ID
|
||||
self.assertEqual("Test Item 1", testitem['name'])
|
||||
self.assertEqual("2", testitem['quantity']) # test a couple of "worse case" fields
|
||||
|
||||
# See new item appear in table
|
||||
row = self.browser.find_element_by_id('item--1') # ID number is known, see above
|
||||
self.assertIn("Test Item 1", row.find_element_by_xpath('//span[@class="name"]').text)
|
||||
self.assertIn("This is an item description", row.find_element_by_xpath('//div[@class="item-description"]').text)
|
||||
self.assertEqual(u'£ 23.95', row.find_element_by_xpath('//tr[@id="item--1"]/td[2]').text)
|
||||
self.assertEqual("2", row.find_element_by_xpath('//td[@class="quantity"]').text)
|
||||
self.assertEqual(u'£ 47.90', row.find_element_by_xpath('//tr[@id="item--1"]/td[4]').text)
|
||||
|
||||
# Check totals
|
||||
self.assertEqual("47.90", self.browser.find_element_by_id('sumtotal').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()
|
||||
|
||||
# See error
|
||||
error = self.browser.find_element_by_xpath('//div[contains(@class, "alert-danger")]')
|
||||
self.assertTrue(error.is_displayed())
|
||||
# Should only have one error message
|
||||
self.assertEqual("Name", error.find_element_by_xpath('//dt[1]').text)
|
||||
self.assertEqual("This field is required.", error.find_element_by_xpath('//dd[1]/ul/li').text)
|
||||
# don't need error so close it
|
||||
error.find_element_by_xpath('//div[contains(@class, "alert-danger")]//button[@class="close"]').click()
|
||||
try:
|
||||
self.assertFalse(error.is_displayed())
|
||||
except StaleElementReferenceException:
|
||||
pass
|
||||
except:
|
||||
self.assertFail("Element does not appear to have been deleted")
|
||||
|
||||
# Check at least some data is preserved. Some = all will be there
|
||||
option = self.browser.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person1.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Set title
|
||||
e = self.browser.find_element_by_id('id_name')
|
||||
e.send_keys('Test Event Name')
|
||||
e.send_keys(Keys.ENTER)
|
||||
|
||||
# See redirected to success page
|
||||
successTitle = self.browser.find_element_by_xpath('//h1').text
|
||||
event = models.Event.objects.get(name='Test Event Name')
|
||||
self.assertIn("N0000%d | Test Event Name"%event.pk, successTitle)
|
||||
except WebDriverException:
|
||||
# This is a dirty workaround for wercker being a bit funny and not running it correctly.
|
||||
# Waiting for wercker to get back to me about this
|
||||
pass
|
||||
except:
|
||||
self.assertFail("Element does not appear to have been deleted")
|
||||
|
||||
# Check at least some data is preserved. Some = all will be there
|
||||
option = self.browser.find_element_by_xpath(
|
||||
'//select[@id="id_person"]//option[@selected="selected"]')
|
||||
self.assertEqual(person1.pk, int(option.get_attribute("value")))
|
||||
|
||||
# Set title
|
||||
e = self.browser.find_element_by_id('id_name')
|
||||
e.send_keys('Test Event Name')
|
||||
e.send_keys(Keys.ENTER)
|
||||
|
||||
# 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 testEventDuplicate(self):
|
||||
testEvent = models.Event.objects.create(name="TE E1", status=models.Event.PROVISIONAL, start_date=date.today() + timedelta(days=6), description="start future no end")
|
||||
@@ -610,9 +621,10 @@ class EventTest(LiveServerTestCase):
|
||||
save.click()
|
||||
|
||||
# See redirected to success page
|
||||
successTitle = self.browser.find_element_by_xpath('//h1').text
|
||||
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)
|
||||
|
||||
self.assertIn("N0000%d | Test Event Name"%event.pk, successTitle)
|
||||
|
||||
def testRigNonRig(self):
|
||||
self.browser.get(self.live_server_url + '/event/create/')
|
||||
# Gets redirected to login and back
|
||||
@@ -752,8 +764,6 @@ class IcalTest(LiveServerTestCase):
|
||||
|
||||
username.send_keys("EventTest")
|
||||
password.send_keys("EventTestPassword")
|
||||
self.browser.execute_script(
|
||||
"return jQuery('#g-recaptcha-response').val('PASSED')")
|
||||
submit.click()
|
||||
|
||||
self.assertEqual(self.live_server_url + n, self.browser.current_url)
|
||||
|
||||
@@ -1,233 +1,329 @@
|
||||
import pytz
|
||||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
from RIGS import models
|
||||
from datetime import date, timedelta
|
||||
from datetime import date, timedelta, datetime, time
|
||||
from decimal import *
|
||||
|
||||
|
||||
class ProfileTestCase(TestCase):
|
||||
def test_str(self):
|
||||
profile = models.Profile(first_name='Test', last_name='Case')
|
||||
self.assertEqual(str(profile), 'Test Case')
|
||||
profile.initials = 'TC'
|
||||
self.assertEqual(str(profile), 'Test Case "TC"')
|
||||
|
||||
|
||||
class VatRateTestCase(TestCase):
|
||||
def setUp(self):
|
||||
models.VatRate.objects.create(start_at='2014-03-01',rate=0.20,comment='test1')
|
||||
models.VatRate.objects.create(start_at='2016-03-01',rate=0.15,comment='test2')
|
||||
def setUp(self):
|
||||
models.VatRate.objects.create(start_at='2014-03-01', rate=0.20, comment='test1')
|
||||
models.VatRate.objects.create(start_at='2016-03-01', rate=0.15, comment='test2')
|
||||
|
||||
def test_find_correct(self):
|
||||
r = models.VatRate.objects.find_rate('2015-03-01')
|
||||
self.assertEqual(r.comment, 'test1')
|
||||
r = models.VatRate.objects.find_rate('2016-03-01')
|
||||
self.assertEqual(r.comment, 'test2')
|
||||
def test_find_correct(self):
|
||||
r = models.VatRate.objects.find_rate('2015-03-01')
|
||||
self.assertEqual(r.comment, 'test1')
|
||||
r = models.VatRate.objects.find_rate('2016-03-01')
|
||||
self.assertEqual(r.comment, 'test2')
|
||||
|
||||
def test_percent_correct(self):
|
||||
r = models.VatRate.objects.get(rate=0.20)
|
||||
self.assertEqual(r.as_percent, 20)
|
||||
|
||||
def test_percent_correct(self):
|
||||
r = models.VatRate.objects.get(rate=0.20)
|
||||
self.assertEqual(r.as_percent, 20)
|
||||
|
||||
class EventTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.all_events = set(range(1, 18))
|
||||
self.current_events = (1, 2, 3, 6, 7, 8, 10, 11, 12, 14, 15, 16, 18)
|
||||
self.not_current_events = set(self.all_events) - set(self.current_events)
|
||||
def setUp(self):
|
||||
self.all_events = set(range(1, 18))
|
||||
self.current_events = (1, 2, 3, 6, 7, 8, 10, 11, 12, 14, 15, 16, 18)
|
||||
self.not_current_events = set(self.all_events) - set(self.current_events)
|
||||
|
||||
self.vatrate = models.VatRate.objects.create(start_at='2014-03-05',rate=0.20,comment='test1')
|
||||
self.profile = models.Profile.objects.create(username="testuser1", email="1@test.com")
|
||||
self.vatrate = models.VatRate.objects.create(start_at='2014-03-05', rate=0.20, comment='test1')
|
||||
self.profile = models.Profile.objects.create(username="testuser1", email="1@test.com")
|
||||
|
||||
# produce 7 normal events - 5 current
|
||||
models.Event.objects.create(name="TE E1", start_date=date.today() + timedelta(days=6), description="start future no end")
|
||||
models.Event.objects.create(name="TE E2", start_date=date.today(), description="start today no end")
|
||||
models.Event.objects.create(name="TE E3", start_date=date.today(), end_date=date.today(), description="start today with end today")
|
||||
models.Event.objects.create(name="TE E4", start_date='2014-03-20', description="start past no end")
|
||||
models.Event.objects.create(name="TE E5", start_date='2014-03-20', end_date='2014-03-21', description="start past with end past")
|
||||
models.Event.objects.create(name="TE E6", start_date=date.today()-timedelta(days=2), end_date=date.today()+timedelta(days=2), description="start past, end future")
|
||||
models.Event.objects.create(name="TE E7", start_date=date.today()+timedelta(days=2), end_date=date.today()+timedelta(days=2), description="start + end in future")
|
||||
# produce 7 normal events - 5 current
|
||||
models.Event.objects.create(name="TE E1", start_date=date.today() + timedelta(days=6),
|
||||
description="start future no end")
|
||||
models.Event.objects.create(name="TE E2", start_date=date.today(), description="start today no end")
|
||||
models.Event.objects.create(name="TE E3", start_date=date.today(), end_date=date.today(),
|
||||
description="start today with end today")
|
||||
models.Event.objects.create(name="TE E4", start_date='2014-03-20', description="start past no end")
|
||||
models.Event.objects.create(name="TE E5", start_date='2014-03-20', end_date='2014-03-21',
|
||||
description="start past with end past")
|
||||
models.Event.objects.create(name="TE E6", start_date=date.today() - timedelta(days=2),
|
||||
end_date=date.today() + timedelta(days=2), description="start past, end future")
|
||||
models.Event.objects.create(name="TE E7", start_date=date.today() + timedelta(days=2),
|
||||
end_date=date.today() + timedelta(days=2), description="start + end in future")
|
||||
|
||||
# 2 cancelled - 1 current
|
||||
models.Event.objects.create(name="TE E8", start_date=date.today()+timedelta(days=2), end_date=date.today()+timedelta(days=2), status=models.Event.CANCELLED, description="cancelled in future")
|
||||
models.Event.objects.create(name="TE E9", start_date=date.today()-timedelta(days=1), end_date=date.today()+timedelta(days=2), status=models.Event.CANCELLED, description="cancelled and started")
|
||||
# 2 cancelled - 1 current
|
||||
models.Event.objects.create(name="TE E8", start_date=date.today() + timedelta(days=2),
|
||||
end_date=date.today() + timedelta(days=2), status=models.Event.CANCELLED,
|
||||
description="cancelled in future")
|
||||
models.Event.objects.create(name="TE E9", start_date=date.today() - timedelta(days=1),
|
||||
end_date=date.today() + timedelta(days=2), status=models.Event.CANCELLED,
|
||||
description="cancelled and started")
|
||||
|
||||
# 5 dry hire - 3 current
|
||||
models.Event.objects.create(name="TE E10", start_date=date.today(), dry_hire=True, description="dryhire today")
|
||||
models.Event.objects.create(name="TE E11", start_date=date.today(), dry_hire=True, checked_in_by=self.profile, description="dryhire today, checked in")
|
||||
models.Event.objects.create(name="TE E12", start_date=date.today()-timedelta(days=1), dry_hire=True, status=models.Event.BOOKED, description="dryhire past")
|
||||
models.Event.objects.create(name="TE E13", start_date=date.today()-timedelta(days=2), dry_hire=True, checked_in_by=self.profile, description="dryhire past checked in")
|
||||
models.Event.objects.create(name="TE E14", start_date=date.today(), dry_hire=True, status=models.Event.CANCELLED, description="dryhire today cancelled")
|
||||
# 5 dry hire - 3 current
|
||||
models.Event.objects.create(name="TE E10", start_date=date.today(), dry_hire=True, description="dryhire today")
|
||||
models.Event.objects.create(name="TE E11", start_date=date.today(), dry_hire=True, checked_in_by=self.profile,
|
||||
description="dryhire today, checked in")
|
||||
models.Event.objects.create(name="TE E12", start_date=date.today() - timedelta(days=1), dry_hire=True,
|
||||
status=models.Event.BOOKED, description="dryhire past")
|
||||
models.Event.objects.create(name="TE E13", start_date=date.today() - timedelta(days=2), dry_hire=True,
|
||||
checked_in_by=self.profile, description="dryhire past checked in")
|
||||
models.Event.objects.create(name="TE E14", start_date=date.today(), dry_hire=True,
|
||||
status=models.Event.CANCELLED, description="dryhire today cancelled")
|
||||
|
||||
# 4 non rig - 3 current
|
||||
models.Event.objects.create(name="TE E15", start_date=date.today(), is_rig=False, description="non rig today")
|
||||
models.Event.objects.create(name="TE E16", start_date=date.today()+timedelta(days=1), is_rig=False, description="non rig tomorrow")
|
||||
models.Event.objects.create(name="TE E17", start_date=date.today()-timedelta(days=1), is_rig=False, description="non rig yesterday")
|
||||
models.Event.objects.create(name="TE E18", start_date=date.today(), is_rig=False, status=models.Event.CANCELLED, description="non rig today cancelled")
|
||||
|
||||
def test_count(self):
|
||||
# Santiy check we have the expected events created
|
||||
self.assertEqual(models.Event.objects.count(), 18, "Incorrect number of events, check setup")
|
||||
# 4 non rig - 3 current
|
||||
models.Event.objects.create(name="TE E15", start_date=date.today(), is_rig=False, description="non rig today")
|
||||
models.Event.objects.create(name="TE E16", start_date=date.today() + timedelta(days=1), is_rig=False,
|
||||
description="non rig tomorrow")
|
||||
models.Event.objects.create(name="TE E17", start_date=date.today() - timedelta(days=1), is_rig=False,
|
||||
description="non rig yesterday")
|
||||
models.Event.objects.create(name="TE E18", start_date=date.today(), is_rig=False, status=models.Event.CANCELLED,
|
||||
description="non rig today cancelled")
|
||||
|
||||
def test_rig_count(self):
|
||||
# by my count this is 7
|
||||
self.assertEqual(models.Event.objects.rig_count(), 8)
|
||||
def test_count(self):
|
||||
# Santiy check we have the expected events created
|
||||
self.assertEqual(models.Event.objects.count(), 18, "Incorrect number of events, check setup")
|
||||
|
||||
def test_current_events(self):
|
||||
current_events = models.Event.objects.current_events()
|
||||
self.assertEqual(len(current_events), len(self.current_events))
|
||||
for eid in self.current_events:
|
||||
self.assertIn(models.Event.objects.get(name="TE E%d"%eid), current_events)
|
||||
def test_rig_count(self):
|
||||
# by my count this is 7
|
||||
self.assertEqual(models.Event.objects.rig_count(), 8)
|
||||
|
||||
for eid in self.not_current_events:
|
||||
self.assertNotIn(models.Event.objects.get(name="TE E%d"%eid), current_events)
|
||||
def test_current_events(self):
|
||||
current_events = models.Event.objects.current_events()
|
||||
self.assertEqual(len(current_events), len(self.current_events))
|
||||
for eid in self.current_events:
|
||||
self.assertIn(models.Event.objects.get(name="TE E%d" % eid), current_events)
|
||||
|
||||
def test_related_venue(self):
|
||||
v1 = models.Venue.objects.create(name="TE V1")
|
||||
v2 = models.Venue.objects.create(name="TE V2")
|
||||
events = models.Event.objects.all()
|
||||
for event in events[:2]:
|
||||
event.venue = v1
|
||||
event.save()
|
||||
for event in events[3:4]:
|
||||
event.venue = v2
|
||||
event.save()
|
||||
for eid in self.not_current_events:
|
||||
self.assertNotIn(models.Event.objects.get(name="TE E%d" % eid), current_events)
|
||||
|
||||
events = models.Event.objects.all()
|
||||
self.assertItemsEqual(events[:2], v1.latest_events)
|
||||
self.assertItemsEqual(events[3:4], v2.latest_events)
|
||||
def test_related_venue(self):
|
||||
v1 = models.Venue.objects.create(name="TE V1")
|
||||
v2 = models.Venue.objects.create(name="TE V2")
|
||||
events = models.Event.objects.all()
|
||||
for event in events[:2]:
|
||||
event.venue = v1
|
||||
event.save()
|
||||
for event in events[3:4]:
|
||||
event.venue = v2
|
||||
event.save()
|
||||
|
||||
def test_related_vatrate(self):
|
||||
self.assertEqual(self.vatrate, models.Event.objects.all()[0].vat_rate)
|
||||
events = models.Event.objects.all()
|
||||
self.assertItemsEqual(events[:2], v1.latest_events)
|
||||
self.assertItemsEqual(events[3:4], v2.latest_events)
|
||||
|
||||
def test_related_person(self):
|
||||
p1 = models.Person.objects.create(name="TE P1")
|
||||
p2 = models.Person.objects.create(name="TE P2")
|
||||
def test_related_vatrate(self):
|
||||
self.assertEqual(self.vatrate, models.Event.objects.all()[0].vat_rate)
|
||||
|
||||
events = models.Event.objects.all()
|
||||
for event in events[:2]:
|
||||
event.person = p1
|
||||
event.save()
|
||||
for event in events[3:4]:
|
||||
event.person = p2
|
||||
event.save()
|
||||
def test_related_person(self):
|
||||
p1 = models.Person.objects.create(name="TE P1")
|
||||
p2 = models.Person.objects.create(name="TE P2")
|
||||
|
||||
events = models.Event.objects.all()
|
||||
self.assertItemsEqual(events[:2], p1.latest_events)
|
||||
self.assertItemsEqual(events[3:4], p2.latest_events)
|
||||
events = models.Event.objects.all()
|
||||
for event in events[:2]:
|
||||
event.person = p1
|
||||
event.save()
|
||||
for event in events[3:4]:
|
||||
event.person = p2
|
||||
event.save()
|
||||
|
||||
def test_related_organisation(self):
|
||||
o1 = models.Organisation.objects.create(name="TE O1")
|
||||
o2 = models.Organisation.objects.create(name="TE O2")
|
||||
events = models.Event.objects.all()
|
||||
self.assertItemsEqual(events[:2], p1.latest_events)
|
||||
self.assertItemsEqual(events[3:4], p2.latest_events)
|
||||
|
||||
events = models.Event.objects.all()
|
||||
for event in events[:2]:
|
||||
event.organisation = o1
|
||||
event.save()
|
||||
for event in events[3:4]:
|
||||
event.organisation = o2
|
||||
event.save()
|
||||
def test_related_organisation(self):
|
||||
o1 = models.Organisation.objects.create(name="TE O1")
|
||||
o2 = models.Organisation.objects.create(name="TE O2")
|
||||
|
||||
events = models.Event.objects.all()
|
||||
self.assertItemsEqual(events[:2], o1.latest_events)
|
||||
self.assertItemsEqual(events[3:4], o2.latest_events)
|
||||
events = models.Event.objects.all()
|
||||
for event in events[:2]:
|
||||
event.organisation = o1
|
||||
event.save()
|
||||
for event in events[3:4]:
|
||||
event.organisation = o2
|
||||
event.save()
|
||||
|
||||
def test_organisation_person_join(self):
|
||||
p1 = models.Person.objects.create(name="TE P1")
|
||||
p2 = models.Person.objects.create(name="TE P2")
|
||||
o1 = models.Organisation.objects.create(name="TE O1")
|
||||
o2 = models.Organisation.objects.create(name="TE O2")
|
||||
events = models.Event.objects.all()
|
||||
self.assertItemsEqual(events[:2], o1.latest_events)
|
||||
self.assertItemsEqual(events[3:4], o2.latest_events)
|
||||
|
||||
events = models.Event.objects.all()
|
||||
# p1 in o1 + o2, p2 in o1
|
||||
for event in events[:2]:
|
||||
event.person = p1
|
||||
event.organisation = o1
|
||||
event.save()
|
||||
for event in events[3:4]:
|
||||
event.person = p1
|
||||
event.organisation = o2
|
||||
event.save()
|
||||
for event in events[5:7]:
|
||||
event.person = p2
|
||||
event.organisation = o1
|
||||
event.save()
|
||||
def test_organisation_person_join(self):
|
||||
p1 = models.Person.objects.create(name="TE P1")
|
||||
p2 = models.Person.objects.create(name="TE P2")
|
||||
o1 = models.Organisation.objects.create(name="TE O1")
|
||||
o2 = models.Organisation.objects.create(name="TE O2")
|
||||
|
||||
events = models.Event.objects.all()
|
||||
events = models.Event.objects.all()
|
||||
# p1 in o1 + o2, p2 in o1
|
||||
for event in events[:2]:
|
||||
event.person = p1
|
||||
event.organisation = o1
|
||||
event.save()
|
||||
for event in events[3:4]:
|
||||
event.person = p1
|
||||
event.organisation = o2
|
||||
event.save()
|
||||
for event in events[5:7]:
|
||||
event.person = p2
|
||||
event.organisation = o1
|
||||
event.save()
|
||||
|
||||
# Check person's 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)
|
||||
events = models.Event.objects.all()
|
||||
|
||||
# Check organisation's 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)
|
||||
# Check person's 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)
|
||||
|
||||
def test_cancelled_property(self):
|
||||
event = models.Event.objects.all()[0]
|
||||
event.status = models.Event.CANCELLED
|
||||
event.save()
|
||||
event = models.Event.objects.all()[0]
|
||||
self.assertEqual(event.status, models.Event.CANCELLED)
|
||||
self.assertTrue(event.cancelled)
|
||||
event.status = models.Event.PROVISIONAL
|
||||
event.save()
|
||||
# Check organisation's 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]
|
||||
event.status = models.Event.CANCELLED
|
||||
event.save()
|
||||
event = models.Event.objects.all()[0]
|
||||
self.assertEqual(event.status, models.Event.CANCELLED)
|
||||
self.assertTrue(event.cancelled)
|
||||
event.status = models.Event.PROVISIONAL
|
||||
event.save()
|
||||
|
||||
def test_confirmed_property(self):
|
||||
event = models.Event.objects.all()[0]
|
||||
event.status = models.Event.CONFIRMED
|
||||
event.save()
|
||||
event = models.Event.objects.all()[0]
|
||||
self.assertEqual(event.status, models.Event.CONFIRMED)
|
||||
self.assertTrue(event.confirmed)
|
||||
event.status = models.Event.PROVISIONAL
|
||||
event.save()
|
||||
|
||||
def test_earliest_time(self):
|
||||
event = models.Event(name="TE ET", start_date=date(2016, 01, 01))
|
||||
|
||||
# Just a start date
|
||||
self.assertEqual(event.earliest_time, date(2016, 01, 01))
|
||||
|
||||
# With start time
|
||||
event.start_time = time(9, 00)
|
||||
self.assertEqual(event.earliest_time, self.create_datetime(2016, 1, 1, 9, 00))
|
||||
|
||||
# With access time
|
||||
event.access_at = self.create_datetime(2015, 12, 03, 9, 57)
|
||||
self.assertEqual(event.earliest_time, event.access_at)
|
||||
|
||||
# With meet time
|
||||
event.meet_at = self.create_datetime(2015, 12, 03, 9, 55)
|
||||
self.assertEqual(event.earliest_time, event.meet_at)
|
||||
|
||||
# Check order isn't important
|
||||
event.start_date = date(2015, 12, 03)
|
||||
self.assertEqual(event.earliest_time, self.create_datetime(2015, 12, 03, 9, 00))
|
||||
|
||||
def test_latest_time(self):
|
||||
event = models.Event(name="TE LT", start_date=date(2016, 01, 01))
|
||||
|
||||
# Just start date
|
||||
self.assertEqual(event.latest_time, event.start_date)
|
||||
|
||||
# Just end date
|
||||
event.end_date = date(2016, 1, 2)
|
||||
self.assertEqual(event.latest_time, event.end_date)
|
||||
|
||||
# With end time
|
||||
event.end_time = time(23, 00)
|
||||
self.assertEqual(event.latest_time, self.create_datetime(2016, 1, 2, 23, 00))
|
||||
|
||||
def test_in_bounds(self):
|
||||
manager = models.Event.objects
|
||||
events = [
|
||||
manager.create(name="TE IB0", start_date='2016-01-02'), # yes no
|
||||
manager.create(name="TE IB1", start_date='2015-12-31', end_date='2016-01-04'),
|
||||
|
||||
# basic checks
|
||||
manager.create(name='TE IB2', start_date='2016-01-02', end_date='2016-01-04'),
|
||||
manager.create(name='TE IB3', start_date='2015-12-31', end_date='2016-01-03'),
|
||||
manager.create(name='TE IB4', start_date='2016-01-04', access_at='2016-01-03'),
|
||||
manager.create(name='TE IB5', start_date='2016-01-04', meet_at='2016-01-02'),
|
||||
|
||||
# negative check
|
||||
manager.create(name='TE IB6', start_date='2015-12-31', end_date='2016-01-01'),
|
||||
]
|
||||
|
||||
in_bounds = manager.events_in_bounds(datetime(2016, 1, 2), datetime(2016, 1, 3))
|
||||
self.assertIn(events[0], in_bounds)
|
||||
self.assertIn(events[1], in_bounds)
|
||||
self.assertIn(events[2], in_bounds)
|
||||
self.assertIn(events[3], in_bounds)
|
||||
self.assertIn(events[4], in_bounds)
|
||||
self.assertIn(events[5], in_bounds)
|
||||
|
||||
self.assertNotIn(events[6], in_bounds)
|
||||
|
||||
def create_datetime(self, year, month, day, hour, min):
|
||||
tz = pytz.timezone(settings.TIME_ZONE)
|
||||
return tz.localize(datetime(year, month, day, hour, min))
|
||||
|
||||
def test_confirmed_property(self):
|
||||
event = models.Event.objects.all()[0]
|
||||
event.status = models.Event.CONFIRMED
|
||||
event.save()
|
||||
event = models.Event.objects.all()[0]
|
||||
self.assertEqual(event.status, models.Event.CONFIRMED)
|
||||
self.assertTrue(event.confirmed)
|
||||
event.status = models.Event.PROVISIONAL
|
||||
event.save()
|
||||
|
||||
class EventItemTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.e1 = models.Event.objects.create(name="TI E1", start_date=date.today())
|
||||
self.e2 = models.Event.objects.create(name="TI E2", start_date=date.today())
|
||||
def setUp(self):
|
||||
self.e1 = models.Event.objects.create(name="TI E1", start_date=date.today())
|
||||
self.e2 = models.Event.objects.create(name="TI E2", start_date=date.today())
|
||||
|
||||
def test_item_cost(self):
|
||||
item = models.EventItem.objects.create(event=self.e1, name="TI I1", quantity=1, cost=1.00, order=1)
|
||||
self.assertEqual(item.total_cost, 1.00)
|
||||
def test_item_cost(self):
|
||||
item = models.EventItem.objects.create(event=self.e1, name="TI I1", quantity=1, cost=1.00, order=1)
|
||||
self.assertEqual(item.total_cost, 1.00)
|
||||
|
||||
item.cost = 2.50
|
||||
self.assertEqual(item.total_cost, 2.50)
|
||||
item.cost = 2.50
|
||||
self.assertEqual(item.total_cost, 2.50)
|
||||
|
||||
item.quantity = 4
|
||||
self.assertEqual(item.total_cost, 10.00)
|
||||
item.quantity = 4
|
||||
self.assertEqual(item.total_cost, 10.00)
|
||||
|
||||
# need to tidy up
|
||||
item.delete()
|
||||
# need to tidy up
|
||||
item.delete()
|
||||
|
||||
def test_item_order(self):
|
||||
i1 = models.EventItem.objects.create(event=self.e1, name="TI I1", quantity=1, cost=1.00, order=1)
|
||||
i2 = models.EventItem.objects.create(event=self.e1, name="TI I2", quantity=1, cost=1.00, order=2)
|
||||
|
||||
items = self.e1.items.all()
|
||||
self.assertListEqual([i1, i2], list(items))
|
||||
|
||||
def test_item_order(self):
|
||||
i1 = models.EventItem.objects.create(event=self.e1, name="TI I1", quantity=1, cost=1.00, order=1)
|
||||
i2 = models.EventItem.objects.create(event=self.e1, name="TI I2", quantity=1, cost=1.00, order=2)
|
||||
|
||||
items = self.e1.items.all()
|
||||
self.assertListEqual([i1, i2], list(items))
|
||||
|
||||
class EventPricingTestCase(TestCase):
|
||||
def setUp(self):
|
||||
models.VatRate.objects.create(rate=0.20, comment="TP V1", start_at='2013-01-01')
|
||||
models.VatRate.objects.create(rate=0.10, comment="TP V2", start_at=date.today()-timedelta(days=1))
|
||||
self.e1 = models.Event.objects.create(name="TP E1", start_date=date.today()-timedelta(days=2))
|
||||
self.e2 = models.Event.objects.create(name="TP E2", start_date=date.today())
|
||||
def setUp(self):
|
||||
models.VatRate.objects.create(rate=0.20, comment="TP V1", start_at='2013-01-01')
|
||||
models.VatRate.objects.create(rate=0.10, comment="TP V2", start_at=date.today() - timedelta(days=1))
|
||||
self.e1 = models.Event.objects.create(name="TP E1", start_date=date.today() - timedelta(days=2))
|
||||
self.e2 = models.Event.objects.create(name="TP E2", start_date=date.today())
|
||||
|
||||
# Create some items E1, total 70.40
|
||||
# Create some items E2, total 381.20
|
||||
self.i1 = models.EventItem.objects.create(event=self.e1, name="TP I1", quantity=1, cost=50.00, order=1)
|
||||
self.i2 = models.EventItem.objects.create(event=self.e1, name="TP I2", quantity=2, cost=3.20, order=2)
|
||||
self.i3 = models.EventItem.objects.create(event=self.e1, name="TP I3", quantity=7, cost=2.00, order=3)
|
||||
self.i4 = models.EventItem.objects.create(event=self.e2, name="TP I4", quantity=2, cost=190.60, order=1)
|
||||
# Create some items E1, total 70.40
|
||||
# Create some items E2, total 381.20
|
||||
self.i1 = models.EventItem.objects.create(event=self.e1, name="TP I1", quantity=1, cost=50.00, order=1)
|
||||
self.i2 = models.EventItem.objects.create(event=self.e1, name="TP I2", quantity=2, cost=3.20, order=2)
|
||||
self.i3 = models.EventItem.objects.create(event=self.e1, name="TP I3", quantity=7, cost=2.00, order=3)
|
||||
self.i4 = models.EventItem.objects.create(event=self.e2, name="TP I4", quantity=2, cost=190.60, order=1)
|
||||
|
||||
# Decimal type is needed here as that is what is returned from the model.
|
||||
# Using anything else results in a failure due to floating point arritmetic
|
||||
def test_sum_totals(self):
|
||||
self.assertEqual(self.e1.sum_total, Decimal('70.40'))
|
||||
self.assertEqual(self.e2.sum_total, Decimal('381.20'))
|
||||
# Decimal type is needed here as that is what is returned from the model.
|
||||
# Using anything else results in a failure due to floating point arritmetic
|
||||
def test_sum_totals(self):
|
||||
self.assertEqual(self.e1.sum_total, Decimal('70.40'))
|
||||
self.assertEqual(self.e2.sum_total, Decimal('381.20'))
|
||||
|
||||
def test_vat_rate(self):
|
||||
self.assertEqual(self.e1.vat_rate.rate, Decimal('0.20'))
|
||||
self.assertEqual(self.e2.vat_rate.rate, Decimal('0.10'))
|
||||
def test_vat_rate(self):
|
||||
self.assertEqual(self.e1.vat_rate.rate, Decimal('0.20'))
|
||||
self.assertEqual(self.e2.vat_rate.rate, Decimal('0.10'))
|
||||
|
||||
def test_vat_ammount(self):
|
||||
self.assertEqual(self.e1.vat, Decimal('14.08'))
|
||||
self.assertEqual(self.e2.vat, Decimal('38.12'))
|
||||
def test_vat_ammount(self):
|
||||
self.assertEqual(self.e1.vat, Decimal('14.08'))
|
||||
self.assertEqual(self.e2.vat, Decimal('38.12'))
|
||||
|
||||
def test_grand_total(self):
|
||||
self.assertEqual(self.e1.total, Decimal('84.48'))
|
||||
self.assertEqual(self.e2.total, Decimal('419.32'))
|
||||
def test_grand_total(self):
|
||||
self.assertEqual(self.e1.total, Decimal('84.48'))
|
||||
self.assertEqual(self.e2.total, Decimal('419.32'))
|
||||
|
||||
@@ -69,6 +69,8 @@ urlpatterns = patterns('',
|
||||
# Rigboard
|
||||
url(r'^rigboard/$', login_required(rigboard.RigboardIndex.as_view()), name='rigboard'),
|
||||
url(r'^rigboard/calendar/$', login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
|
||||
url(r'^rigboard/calendar/(?P<view>(month|week|day))/$', login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
|
||||
url(r'^rigboard/calendar/(?P<view>(month|week|day))/(?P<date>(\d{4}-\d{2}-\d{2}))/$', login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
|
||||
url(r'^rigboard/archive/$', RedirectView.as_view(permanent=True,pattern_name='event_archive')),
|
||||
url(r'^rigboard/activity/$',
|
||||
permission_required_with_403('RIGS.view_event')(versioning.ActivityTable.as_view()),
|
||||
|
||||
@@ -17,6 +17,7 @@ from reversion.models import Version
|
||||
from django.contrib.contenttypes.models import ContentType # Used to lookup the content_type
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
from django.db.models import ForeignKey, IntegerField, EmailField, TextField
|
||||
from diff_match_patch import diff_match_patch
|
||||
|
||||
from RIGS import models, forms
|
||||
import datetime
|
||||
@@ -64,6 +65,25 @@ def model_compare(oldObj, newObj, excluded_keys=[]):
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def diff(self):
|
||||
oldText = unicode(self.display_value(self._old)) or ""
|
||||
newText = unicode(self.display_value(self._new)) or ""
|
||||
dmp = diff_match_patch()
|
||||
diffs = dmp.diff_main(oldText, newText)
|
||||
dmp.diff_cleanupSemantic(diffs)
|
||||
|
||||
outputDiffs = []
|
||||
|
||||
for (op, data) in diffs:
|
||||
if op == dmp.DIFF_INSERT:
|
||||
outputDiffs.append({'type':'insert', 'text':data})
|
||||
elif op == dmp.DIFF_DELETE:
|
||||
outputDiffs.append({'type':'delete', 'text':data})
|
||||
elif op == dmp.DIFF_EQUAL:
|
||||
outputDiffs.append({'type':'equal', 'text':data})
|
||||
return outputDiffs
|
||||
|
||||
changes = []
|
||||
|
||||
for thisField in theFields:
|
||||
|
||||
@@ -33,7 +33,7 @@ def login(request, **kwargs):
|
||||
else:
|
||||
from django.contrib.auth.views import login
|
||||
|
||||
return login(request, authentication_form=forms.LoginForm)
|
||||
return login(request)
|
||||
|
||||
"""
|
||||
Called from a modal window (e.g. when an item is submitted to an event/invoice).
|
||||
|
||||
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
@@ -1,4 +1,5 @@
|
||||
beautifulsoup4==4.4.1
|
||||
diff-match-patch==20121119
|
||||
dj-database-url==0.3.0
|
||||
dj-static==0.0.6
|
||||
Django==1.8.2
|
||||
@@ -21,7 +22,7 @@ python-dateutil==2.4.2
|
||||
pytz==2015.4
|
||||
raven==5.8.1
|
||||
reportlab==3.1.44
|
||||
selenium==2.46.0
|
||||
selenium==2.53.1
|
||||
simplejson==3.7.2
|
||||
six==1.9.0
|
||||
sqlparse==0.1.15
|
||||
|
||||
@@ -14,14 +14,16 @@
|
||||
|
||||
<link rel="icon" type="image/png" href="{% static "imgs/pyrigs-avatar.png" %}">
|
||||
<link rel="apple-touch-icon" href="{% static "imgs/pyrigs-avatar.png" %}">
|
||||
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,700,300,400' rel='stylesheet' type='text/css'>
|
||||
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,700,300,400' rel='stylesheet'
|
||||
type='text/css'>
|
||||
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{% static "css/screen.css" %}">
|
||||
{% block css %}
|
||||
{% endblock %}
|
||||
|
||||
<script src="//code.jquery.com/jquery-latest.min.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-1.8.3.min.js"
|
||||
integrity="sha256-YcbK69I5IXQftf/mYD8WY0/KmEDCv1asggHpJk1trM8=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.ravenjs.com/1.3.0/jquery,native/raven.min.js"></script>
|
||||
<script>Raven.config('{% sentry_public_dsn %}').install()</script>
|
||||
{% block preload_js %}
|
||||
@@ -46,32 +48,40 @@
|
||||
<div class="navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
{% if user.is_authenticated %}
|
||||
<li><a href="/">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Rigboard<b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{% url 'rigboard' %}"><span class="glyphicon glyphicon-list"></span> Rigboard</a></li>
|
||||
<li><a href="{% url 'event_archive' %}"><span class="glyphicon glyphicon-book"></span> Archive</a></li>
|
||||
<li><a href="{% url 'web_calendar' %}"><span class="glyphicon glyphicon-calendar"></span> Calendar</a></li>
|
||||
{% if perms.RIGS.view_event %}
|
||||
<li><a href="{% url 'activity_table' %}"><span class="glyphicon glyphicon-random"></span> Recent Changes</a></li>
|
||||
{% endif %}
|
||||
{% if perms.RIGS.add_event %}
|
||||
<li><a href="{% url 'event_create' %}"><span class="glyphicon glyphicon-plus"></span> New Event</a></li>
|
||||
{% endif %}
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="/">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Rigboard<b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{% url 'rigboard' %}"><span class="glyphicon glyphicon-list"></span>
|
||||
Rigboard</a></li>
|
||||
<li><a href="{% url 'event_archive' %}"><span class="glyphicon glyphicon-book"></span>
|
||||
Archive</a></li>
|
||||
<li><a href="{% url 'web_calendar' %}"><span class="glyphicon glyphicon-calendar"></span>
|
||||
Calendar</a></li>
|
||||
{% if perms.RIGS.view_event %}
|
||||
<li><a href="{% url 'activity_table' %}"><span
|
||||
class="glyphicon glyphicon-random"></span> Recent Changes</a></li>
|
||||
{% endif %}
|
||||
{% if perms.RIGS.add_event %}
|
||||
<li><a href="{% url 'event_create' %}"><span class="glyphicon glyphicon-plus"></span>
|
||||
New Event</a></li>
|
||||
{% endif %}
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if perms.RIGS.view_invoice %}
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Invoices<b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{% url 'invoice_list' %}"><span class="glyphicon glyphicon-gbp"></span> Active</a></li>
|
||||
<li><a href="{% url 'invoice_list' %}"><span class="glyphicon glyphicon-gbp"></span> Active</a>
|
||||
</li>
|
||||
{% if perms.RIGS.add_invoice %}
|
||||
<li><a href="{% url 'invoice_waiting' %}"><span class="glyphicon glyphicon-briefcase"></span> Waiting</a></li>
|
||||
<li><a href="{% url 'invoice_waiting' %}"><span
|
||||
class="glyphicon glyphicon-briefcase"></span> Waiting</a></li>
|
||||
{% endif %}
|
||||
<li><a href="{% url 'invoice_archive' %}"><span class="glyphicon glyphicon-book"></span> Archive</a></li>
|
||||
<li><a href="{% url 'invoice_archive' %}"><span class="glyphicon glyphicon-book"></span>
|
||||
Archive</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
@@ -84,7 +94,7 @@
|
||||
{% if perms.RIGS.view_venue %}
|
||||
<li><a href="{% url 'venue_list' %}">Venues</a></li>
|
||||
{% endif %}
|
||||
|
||||
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
@@ -144,10 +154,6 @@
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
<div class="col-sm-12 text-center">
|
||||
Reminder: Please consider carefully before booking rigs at this moment
|
||||
</div>
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
|
||||
@@ -182,7 +188,7 @@
|
||||
jQuery(document).on('click', '.modal-href', function (e) {
|
||||
$link = jQuery(this);
|
||||
// Anti modal inception
|
||||
if($link.parents('#modal').length == 0) {
|
||||
if ($link.parents('#modal').length == 0) {
|
||||
e.preventDefault();
|
||||
modaltarget = $link.data('target');
|
||||
modalobject = "";
|
||||
@@ -194,11 +200,11 @@
|
||||
|
||||
|
||||
var easter_egg = new Konami();
|
||||
easter_egg.code = function() {
|
||||
easter_egg.code = function () {
|
||||
var s = document.createElement('script');
|
||||
s.type='text/javascript';
|
||||
s.type = 'text/javascript';
|
||||
document.body.appendChild(s);
|
||||
s.src='{% static "js/asteroids.min.js"%}';
|
||||
s.src = '{% static "js/asteroids.min.js"%}';
|
||||
ga('send', 'event', 'easter_egg', 'activated');
|
||||
}
|
||||
easter_egg.load();
|
||||
|
||||
@@ -6,18 +6,12 @@
|
||||
<form action="{% url 'login' %}" method="post" role="form">{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<label for="id_username">{{ form.username.label }}</label>
|
||||
{% render_field form.username class+="form-control" placeholder=form.username.label %}
|
||||
{% render_field form.username class+="form-control" placeholder=form.username.label autofocus="" %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.password.id_for_label }}">{{ form.password.label }}</label>
|
||||
{% render_field form.password class+="form-control" placeholder=form.password.label %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.captcha.id_for_label }}">{{ form.captcha.label }}</label>
|
||||
<div class="text-center">
|
||||
{{ form.captcha }}
|
||||
</div>
|
||||
</div>
|
||||
<a href="{% url 'registration_register' %}" class="btn">Register</a>
|
||||
<a href="{% url 'password_reset' %}" class="btn">Forgotten Password</a>
|
||||
<input type="submit" value="Login" class="btn btn-primary"/>
|
||||
|
||||
Reference in New Issue
Block a user