mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-03-06 03:58:23 +00:00
Compare commits
3 Commits
hotfix/for
...
assets_leg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b2aaa0c0e | ||
|
|
b1952b96f7 | ||
|
|
5cdc75ce5c |
@@ -1,32 +0,0 @@
|
|||||||
---
|
|
||||||
engines:
|
|
||||||
csslint:
|
|
||||||
enabled: true
|
|
||||||
duplication:
|
|
||||||
enabled: true
|
|
||||||
config:
|
|
||||||
languages:
|
|
||||||
- ruby
|
|
||||||
- javascript
|
|
||||||
- python
|
|
||||||
- php
|
|
||||||
eslint:
|
|
||||||
enabled: true
|
|
||||||
fixme:
|
|
||||||
enabled: true
|
|
||||||
radon:
|
|
||||||
enabled: true
|
|
||||||
rubocop:
|
|
||||||
enabled: true
|
|
||||||
ratings:
|
|
||||||
paths:
|
|
||||||
- "**.css"
|
|
||||||
- "**.inc"
|
|
||||||
- "**.js"
|
|
||||||
- "**.jsx"
|
|
||||||
- "**.module"
|
|
||||||
- "**.php"
|
|
||||||
- "**.py"
|
|
||||||
- "**.rb"
|
|
||||||
exclude_paths:
|
|
||||||
- config/
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
[run]
|
|
||||||
source =
|
|
||||||
./
|
|
||||||
|
|
||||||
omit =
|
|
||||||
*/migrations/*
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
--exclude-exts=.min.css
|
|
||||||
--ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# EditorConfig helps developers define and maintain consistent
|
|
||||||
# coding styles between different editors and IDEs
|
|
||||||
# editorconfig.org
|
|
||||||
|
|
||||||
root = true
|
|
||||||
|
|
||||||
|
|
||||||
[*]
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.hbs]
|
|
||||||
insert_final_newline = false
|
|
||||||
|
|
||||||
[*.{diff,md}]
|
|
||||||
trim_trailing_whitespace = false
|
|
||||||
|
|
||||||
# Python: PEP8 defines 4 spaces for indentation
|
|
||||||
[*.py]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 4
|
|
||||||
# Salt state files, YAML format, 2 spaces
|
|
||||||
[*.sls, *.yaml, *.yml]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
**/*{.,-}min.js
|
|
||||||
213
.eslintrc
213
.eslintrc
@@ -1,213 +0,0 @@
|
|||||||
ecmaFeatures:
|
|
||||||
modules: true
|
|
||||||
jsx: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
amd: true
|
|
||||||
browser: true
|
|
||||||
es6: true
|
|
||||||
jquery: true
|
|
||||||
node: true
|
|
||||||
|
|
||||||
# http://eslint.org/docs/rules/
|
|
||||||
rules:
|
|
||||||
# Possible Errors
|
|
||||||
comma-dangle: [2, never]
|
|
||||||
no-cond-assign: 2
|
|
||||||
no-console: 0
|
|
||||||
no-constant-condition: 2
|
|
||||||
no-control-regex: 2
|
|
||||||
no-debugger: 2
|
|
||||||
no-dupe-args: 2
|
|
||||||
no-dupe-keys: 2
|
|
||||||
no-duplicate-case: 2
|
|
||||||
no-empty: 2
|
|
||||||
no-empty-character-class: 2
|
|
||||||
no-ex-assign: 2
|
|
||||||
no-extra-boolean-cast: 2
|
|
||||||
no-extra-parens: 0
|
|
||||||
no-extra-semi: 2
|
|
||||||
no-func-assign: 2
|
|
||||||
no-inner-declarations: [2, functions]
|
|
||||||
no-invalid-regexp: 2
|
|
||||||
no-irregular-whitespace: 2
|
|
||||||
no-negated-in-lhs: 2
|
|
||||||
no-obj-calls: 2
|
|
||||||
no-regex-spaces: 2
|
|
||||||
no-sparse-arrays: 2
|
|
||||||
no-unexpected-multiline: 2
|
|
||||||
no-unreachable: 2
|
|
||||||
use-isnan: 2
|
|
||||||
valid-jsdoc: 0
|
|
||||||
valid-typeof: 2
|
|
||||||
|
|
||||||
# Best Practices
|
|
||||||
accessor-pairs: 2
|
|
||||||
block-scoped-var: 0
|
|
||||||
complexity: [2, 6]
|
|
||||||
consistent-return: 0
|
|
||||||
curly: 0
|
|
||||||
default-case: 0
|
|
||||||
dot-location: 0
|
|
||||||
dot-notation: 0
|
|
||||||
eqeqeq: 2
|
|
||||||
guard-for-in: 2
|
|
||||||
no-alert: 2
|
|
||||||
no-caller: 2
|
|
||||||
no-case-declarations: 2
|
|
||||||
no-div-regex: 2
|
|
||||||
no-else-return: 0
|
|
||||||
no-empty-label: 2
|
|
||||||
no-empty-pattern: 2
|
|
||||||
no-eq-null: 2
|
|
||||||
no-eval: 2
|
|
||||||
no-extend-native: 2
|
|
||||||
no-extra-bind: 2
|
|
||||||
no-fallthrough: 2
|
|
||||||
no-floating-decimal: 0
|
|
||||||
no-implicit-coercion: 0
|
|
||||||
no-implied-eval: 2
|
|
||||||
no-invalid-this: 0
|
|
||||||
no-iterator: 2
|
|
||||||
no-labels: 0
|
|
||||||
no-lone-blocks: 2
|
|
||||||
no-loop-func: 2
|
|
||||||
no-magic-number: 0
|
|
||||||
no-multi-spaces: 0
|
|
||||||
no-multi-str: 0
|
|
||||||
no-native-reassign: 2
|
|
||||||
no-new-func: 2
|
|
||||||
no-new-wrappers: 2
|
|
||||||
no-new: 2
|
|
||||||
no-octal-escape: 2
|
|
||||||
no-octal: 2
|
|
||||||
no-proto: 2
|
|
||||||
no-redeclare: 2
|
|
||||||
no-return-assign: 2
|
|
||||||
no-script-url: 2
|
|
||||||
no-self-compare: 2
|
|
||||||
no-sequences: 0
|
|
||||||
no-throw-literal: 0
|
|
||||||
no-unused-expressions: 2
|
|
||||||
no-useless-call: 2
|
|
||||||
no-useless-concat: 2
|
|
||||||
no-void: 2
|
|
||||||
no-warning-comments: 0
|
|
||||||
no-with: 2
|
|
||||||
radix: 2
|
|
||||||
vars-on-top: 0
|
|
||||||
wrap-iife: 2
|
|
||||||
yoda: 0
|
|
||||||
|
|
||||||
# Strict
|
|
||||||
strict: 0
|
|
||||||
|
|
||||||
# Variables
|
|
||||||
init-declarations: 0
|
|
||||||
no-catch-shadow: 2
|
|
||||||
no-delete-var: 2
|
|
||||||
no-label-var: 2
|
|
||||||
no-shadow-restricted-names: 2
|
|
||||||
no-shadow: 0
|
|
||||||
no-undef-init: 2
|
|
||||||
no-undef: 0
|
|
||||||
no-undefined: 0
|
|
||||||
no-unused-vars: 0
|
|
||||||
no-use-before-define: 0
|
|
||||||
|
|
||||||
# Node.js and CommonJS
|
|
||||||
callback-return: 2
|
|
||||||
global-require: 2
|
|
||||||
handle-callback-err: 2
|
|
||||||
no-mixed-requires: 0
|
|
||||||
no-new-require: 0
|
|
||||||
no-path-concat: 2
|
|
||||||
no-process-exit: 2
|
|
||||||
no-restricted-modules: 0
|
|
||||||
no-sync: 0
|
|
||||||
|
|
||||||
# Stylistic Issues
|
|
||||||
array-bracket-spacing: 0
|
|
||||||
block-spacing: 0
|
|
||||||
brace-style: 0
|
|
||||||
camelcase: 0
|
|
||||||
comma-spacing: 0
|
|
||||||
comma-style: 0
|
|
||||||
computed-property-spacing: 0
|
|
||||||
consistent-this: 0
|
|
||||||
eol-last: 0
|
|
||||||
func-names: 0
|
|
||||||
func-style: 0
|
|
||||||
id-length: 0
|
|
||||||
id-match: 0
|
|
||||||
indent: 0
|
|
||||||
jsx-quotes: 0
|
|
||||||
key-spacing: 0
|
|
||||||
linebreak-style: 0
|
|
||||||
lines-around-comment: 0
|
|
||||||
max-depth: 0
|
|
||||||
max-len: 0
|
|
||||||
max-nested-callbacks: 0
|
|
||||||
max-params: 0
|
|
||||||
max-statements: [2, 30]
|
|
||||||
new-cap: 0
|
|
||||||
new-parens: 0
|
|
||||||
newline-after-var: 0
|
|
||||||
no-array-constructor: 0
|
|
||||||
no-bitwise: 0
|
|
||||||
no-continue: 0
|
|
||||||
no-inline-comments: 0
|
|
||||||
no-lonely-if: 0
|
|
||||||
no-mixed-spaces-and-tabs: 0
|
|
||||||
no-multiple-empty-lines: 0
|
|
||||||
no-negated-condition: 0
|
|
||||||
no-nested-ternary: 0
|
|
||||||
no-new-object: 0
|
|
||||||
no-plusplus: 0
|
|
||||||
no-restricted-syntax: 0
|
|
||||||
no-spaced-func: 0
|
|
||||||
no-ternary: 0
|
|
||||||
no-trailing-spaces: 0
|
|
||||||
no-underscore-dangle: 0
|
|
||||||
no-unneeded-ternary: 0
|
|
||||||
object-curly-spacing: 0
|
|
||||||
one-var: 0
|
|
||||||
operator-assignment: 0
|
|
||||||
operator-linebreak: 0
|
|
||||||
padded-blocks: 0
|
|
||||||
quote-props: 0
|
|
||||||
quotes: 0
|
|
||||||
require-jsdoc: 0
|
|
||||||
semi-spacing: 0
|
|
||||||
semi: 0
|
|
||||||
sort-vars: 0
|
|
||||||
space-after-keywords: 0
|
|
||||||
space-before-blocks: 0
|
|
||||||
space-before-function-paren: 0
|
|
||||||
space-before-keywords: 0
|
|
||||||
space-in-parens: 0
|
|
||||||
space-infix-ops: 0
|
|
||||||
space-return-throw-case: 0
|
|
||||||
space-unary-ops: 0
|
|
||||||
spaced-comment: 0
|
|
||||||
wrap-regex: 0
|
|
||||||
|
|
||||||
# ECMAScript 6
|
|
||||||
arrow-body-style: 0
|
|
||||||
arrow-parens: 0
|
|
||||||
arrow-spacing: 0
|
|
||||||
constructor-super: 0
|
|
||||||
generator-star-spacing: 0
|
|
||||||
no-arrow-condition: 0
|
|
||||||
no-class-assign: 0
|
|
||||||
no-const-assign: 0
|
|
||||||
no-dupe-class-members: 0
|
|
||||||
no-this-before-super: 0
|
|
||||||
no-var: 0
|
|
||||||
object-shorthand: 0
|
|
||||||
prefer-arrow-callback: 0
|
|
||||||
prefer-const: 0
|
|
||||||
prefer-reflect: 0
|
|
||||||
prefer-spread: 0
|
|
||||||
prefer-template: 0
|
|
||||||
require-yield: 0
|
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,6 +1,3 @@
|
|||||||
tmp/
|
|
||||||
db.sqlite3
|
|
||||||
|
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
@@ -28,6 +25,9 @@ var/
|
|||||||
|
|
||||||
# Continer extras
|
# Continer extras
|
||||||
.vagrant
|
.vagrant
|
||||||
|
_builds
|
||||||
|
_steps
|
||||||
|
_projects
|
||||||
|
|
||||||
# PyInstaller
|
# PyInstaller
|
||||||
# Usually these files are written by a python script from a template
|
# Usually these files are written by a python script from a template
|
||||||
|
|||||||
2
.idea/modules.xml
generated
2
.idea/modules.xml
generated
@@ -2,7 +2,7 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/PyRIGS.iml" filepath="$PROJECT_DIR$/.idea/PyRIGS.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/pyrigs.iml" filepath="$PROJECT_DIR$/.idea/pyrigs.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
1156
.rubocop.yml
1156
.rubocop.yml
File diff suppressed because it is too large
Load Diff
21
.travis.yml
21
.travis.yml
@@ -1,21 +0,0 @@
|
|||||||
language: python
|
|
||||||
python:
|
|
||||||
"2.7"
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- "export DISPLAY=:99.0"
|
|
||||||
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16"
|
|
||||||
|
|
||||||
install:
|
|
||||||
- pip install -r requirements.txt
|
|
||||||
- pip install coveralls codeclimate-test-reporter
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- python manage.py collectstatic --noinput
|
|
||||||
|
|
||||||
script:
|
|
||||||
- coverage run manage.py test RIGS
|
|
||||||
|
|
||||||
after_success:
|
|
||||||
- coveralls
|
|
||||||
- codeclimate-test-reporter
|
|
||||||
@@ -1,66 +1,54 @@
|
|||||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||||
from django.http import HttpResponseRedirect
|
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
|
||||||
def user_passes_test_with_403(test_func, login_url=None):
|
def user_passes_test_with_403(test_func, login_url=None):
|
||||||
"""
|
"""
|
||||||
Decorator for views that checks that the user passes the given test.
|
Decorator for views that checks that the user passes the given test.
|
||||||
|
|
||||||
Anonymous users will be redirected to login_url, while users that fail
|
Anonymous users will be redirected to login_url, while users that fail
|
||||||
the test will be given a 403 error.
|
the test will be given a 403 error.
|
||||||
"""
|
"""
|
||||||
if not login_url:
|
if not login_url:
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
login_url = settings.LOGIN_URL
|
login_url = settings.LOGIN_URL
|
||||||
|
|
||||||
def _dec(view_func):
|
def _dec(view_func):
|
||||||
def _checklogin(request, *args, **kwargs):
|
def _checklogin(request, *args, **kwargs):
|
||||||
if test_func(request.user):
|
if test_func(request.user):
|
||||||
return view_func(request, *args, **kwargs)
|
return view_func(request, *args, **kwargs)
|
||||||
elif not request.user.is_authenticated():
|
elif not request.user.is_authenticated():
|
||||||
return HttpResponseRedirect('%s?%s=%s' % (
|
return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, request.get_full_path()))
|
||||||
login_url, REDIRECT_FIELD_NAME, request.get_full_path()))
|
|
||||||
else:
|
else:
|
||||||
resp = render_to_response(
|
resp = render_to_response('403.html', context_instance=RequestContext(request))
|
||||||
'403.html', context_instance=RequestContext(request))
|
|
||||||
resp.status_code = 403
|
resp.status_code = 403
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
_checklogin.__doc__ = view_func.__doc__
|
_checklogin.__doc__ = view_func.__doc__
|
||||||
_checklogin.__dict__ = view_func.__dict__
|
_checklogin.__dict__ = view_func.__dict__
|
||||||
return _checklogin
|
return _checklogin
|
||||||
|
|
||||||
return _dec
|
return _dec
|
||||||
|
|
||||||
|
|
||||||
def permission_required_with_403(perm, login_url=None):
|
def permission_required_with_403(perm, login_url=None):
|
||||||
"""
|
"""
|
||||||
Decorator for views that checks whether a user has a particular permission
|
Decorator for views that checks whether a user has a particular permission
|
||||||
enabled, redirecting to the log-in page or rendering a 403 as necessary.
|
enabled, redirecting to the log-in page or rendering a 403 as necessary.
|
||||||
"""
|
"""
|
||||||
return user_passes_test_with_403(
|
return user_passes_test_with_403(lambda u: u.has_perm(perm), login_url=login_url)
|
||||||
lambda u: u.has_perm(perm), login_url=login_url)
|
|
||||||
|
|
||||||
|
|
||||||
from RIGS import models
|
from RIGS import models
|
||||||
|
|
||||||
|
|
||||||
def api_key_required(function):
|
def api_key_required(function):
|
||||||
"""
|
"""
|
||||||
Decorator for views that checks api_pk and api_key.
|
Decorator for views that checks api_pk and api_key.
|
||||||
Failed users will be given a 403 error.
|
Failed users will be given a 403 error.
|
||||||
Should only be used for urls which include <api_pk> and <api_key> kwargs
|
Should only be used for urls which include <api_pk> and <api_key> kwargs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def wrap(request, *args, **kwargs):
|
def wrap(request, *args, **kwargs):
|
||||||
|
|
||||||
userid = kwargs.get('api_pk')
|
userid = kwargs.get('api_pk')
|
||||||
key = kwargs.get('api_key')
|
key = kwargs.get('api_key')
|
||||||
|
|
||||||
error_resp = render_to_response(
|
error_resp = render_to_response('403.html', context_instance=RequestContext(request))
|
||||||
'403.html', context_instance=RequestContext(request))
|
|
||||||
error_resp.status_code = 403
|
error_resp.status_code = 403
|
||||||
|
|
||||||
if key is None:
|
if key is None:
|
||||||
@@ -70,11 +58,10 @@ def api_key_required(function):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
user_object = models.Profile.objects.get(pk=userid)
|
user_object = models.Profile.objects.get(pk=userid)
|
||||||
except models.Profile.DoesNotExist:
|
except Profile.DoesNotExist:
|
||||||
return error_resp
|
return error_resp
|
||||||
|
|
||||||
if user_object.api_key != key:
|
if user_object.api_key != key:
|
||||||
return error_resp
|
return error_resp
|
||||||
return function(request, *args, **kwargs)
|
return function(request, *args, **kwargs)
|
||||||
|
return wrap
|
||||||
return wrap
|
|
||||||
@@ -2,4 +2,4 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
DATETIME_FORMAT = ('d/m/Y H:i')
|
DATETIME_FORMAT = ('d/m/Y H:i')
|
||||||
DATE_FORMAT = ('d/m/Y')
|
DATE_FORMAT = ('d/m/Y')
|
||||||
TIME_FORMAT = ('H:i')
|
TIME_FORMAT = ('H:i')
|
||||||
@@ -10,35 +10,22 @@ https://docs.djangoproject.com/en/1.7/ref/settings/
|
|||||||
|
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
import os
|
import os
|
||||||
|
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = os.environ.get('SECRET_KEY') if os.environ.get(
|
SECRET_KEY = os.environ.get('SECRET_KEY') if os.environ.get('SECRET_KEY') else 'gxhy(a#5mhp289_=6xx$7jh=eh$ymxg^ymc+di*0c*geiu3p_e'
|
||||||
'SECRET_KEY') else 'gxhy(a#5mhp289_=6xx$7jh=eh$ymxg^ymc+di*0c*geiu3p_e'
|
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = bool(int(os.environ.get('DEBUG'))) if os.environ.get('DEBUG') else True
|
DEBUG = bool(int(os.environ.get('DEBUG'))) if os.environ.get('DEBUG') else True
|
||||||
|
|
||||||
STAGING = bool(int(os.environ.get('STAGING'))
|
|
||||||
) if os.environ.get('STAGING') else False
|
|
||||||
|
|
||||||
TEMPLATE_DEBUG = True
|
TEMPLATE_DEBUG = True
|
||||||
|
|
||||||
ALLOWED_HOSTS = [
|
ALLOWED_HOSTS = ['pyrigs.nottinghamtec.co.uk', 'rigs.nottinghamtec.co.uk', 'pyrigs.herokuapp.com']
|
||||||
'pyrigs.nottinghamtec.co.uk',
|
|
||||||
'rigs.nottinghamtec.co.uk',
|
|
||||||
'pyrigs.herokuapp.com']
|
|
||||||
|
|
||||||
if STAGING:
|
|
||||||
ALLOWED_HOSTS.append('.herokuapp.com')
|
|
||||||
|
|
||||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
|
||||||
if not DEBUG:
|
|
||||||
SECURE_SSL_REDIRECT = True # Redirect all http requests to https
|
|
||||||
|
|
||||||
INTERNAL_IPS = ['127.0.0.1']
|
INTERNAL_IPS = ['127.0.0.1']
|
||||||
|
|
||||||
@@ -46,6 +33,7 @@ ADMINS = (
|
|||||||
('Tom Price', 'tomtom5152@gmail.com')
|
('Tom Price', 'tomtom5152@gmail.com')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = (
|
INSTALLED_APPS = (
|
||||||
@@ -67,7 +55,6 @@ INSTALLED_APPS = (
|
|||||||
|
|
||||||
MIDDLEWARE_CLASSES = (
|
MIDDLEWARE_CLASSES = (
|
||||||
'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',
|
'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',
|
||||||
'django.middleware.security.SecurityMiddleware',
|
|
||||||
'reversion.middleware.RevisionMiddleware',
|
'reversion.middleware.RevisionMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
@@ -82,6 +69,7 @@ ROOT_URLCONF = 'PyRIGS.urls'
|
|||||||
|
|
||||||
WSGI_APPLICATION = 'PyRIGS.wsgi.application'
|
WSGI_APPLICATION = 'PyRIGS.wsgi.application'
|
||||||
|
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
|
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
@@ -93,10 +81,9 @@ DATABASES = {
|
|||||||
|
|
||||||
if not DEBUG:
|
if not DEBUG:
|
||||||
import dj_database_url
|
import dj_database_url
|
||||||
|
|
||||||
DATABASES['default'] = dj_database_url.config()
|
DATABASES['default'] = dj_database_url.config()
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
'version': 1,
|
'version': 1,
|
||||||
'disable_existing_loggers': False,
|
'disable_existing_loggers': False,
|
||||||
@@ -124,12 +111,12 @@ LOGGING = {
|
|||||||
'mail_admins': {
|
'mail_admins': {
|
||||||
'class': 'django.utils.log.AdminEmailHandler',
|
'class': 'django.utils.log.AdminEmailHandler',
|
||||||
'level': 'ERROR',
|
'level': 'ERROR',
|
||||||
# But the emails are plain text by default - HTML is nicer
|
# But the emails are plain text by default - HTML is nicer
|
||||||
'include_html': True,
|
'include_html': True,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'loggers': {
|
'loggers': {
|
||||||
# Again, default Django configuration to email unhandled exceptions
|
# Again, default Django configuration to email unhandled exceptions
|
||||||
'django.request': {
|
'django.request': {
|
||||||
'handlers': ['mail_admins'],
|
'handlers': ['mail_admins'],
|
||||||
'level': 'ERROR',
|
'level': 'ERROR',
|
||||||
@@ -151,7 +138,6 @@ RAVEN_CONFIG = {
|
|||||||
# If you are using git, you can also automatically configure the
|
# If you are using git, you can also automatically configure the
|
||||||
# release based on the git info.
|
# release based on the git info.
|
||||||
# 'release': raven.fetch_git_sha(os.path.dirname(os.path.dirname(__file__))),
|
# 'release': raven.fetch_git_sha(os.path.dirname(os.path.dirname(__file__))),
|
||||||
'debug': DEBUG,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# User system
|
# User system
|
||||||
@@ -197,7 +183,7 @@ USE_L10N = True
|
|||||||
|
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
|
|
||||||
DATETIME_INPUT_FORMATS = ('%Y-%m-%dT%H:%M', '%Y-%m-%dT%H:%M:%S')
|
DATETIME_INPUT_FORMATS = ('%Y-%m-%dT%H:%M','%Y-%m-%dT%H:%M:%S')
|
||||||
|
|
||||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||||
"django.contrib.auth.context_processors.auth",
|
"django.contrib.auth.context_processors.auth",
|
||||||
@@ -210,6 +196,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
|
|||||||
"django.contrib.messages.context_processors.messages",
|
"django.contrib.messages.context_processors.messages",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/1.7/howto/static-files/
|
# https://docs.djangoproject.com/en/1.7/howto/static-files/
|
||||||
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
|
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
|
||||||
@@ -220,9 +207,9 @@ STATIC_DIRS = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATE_DIRS = (
|
TEMPLATE_DIRS = (
|
||||||
os.path.join(BASE_DIR, 'templates'),
|
os.path.join(BASE_DIR, 'templates'),
|
||||||
)
|
)
|
||||||
|
|
||||||
USE_GRAVATAR = True
|
USE_GRAVATAR=True
|
||||||
|
|
||||||
TERMS_OF_HIRE_URL = "http://www.nottinghamtec.co.uk/terms.pdf"
|
TERMS_OF_HIRE_URL = "http://www.nottinghamtec.co.uk/terms.pdf"
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
from django.conf import settings
|
|
||||||
from django.conf.urls import patterns, include, url
|
from django.conf.urls import patterns, include, url
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||||
|
from django.conf import settings
|
||||||
from registration.backends.default.views import RegistrationView
|
from registration.backends.default.views import RegistrationView
|
||||||
|
|
||||||
import RIGS
|
import RIGS
|
||||||
|
from RIGS import regbackend
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
# Examples:
|
# Examples:
|
||||||
# url(r'^$', 'PyRIGS.views.home', name='home'),
|
# url(r'^$', 'PyRIGS.views.home', name='home'),
|
||||||
# url(r'^blog/', include('blog.urls')),
|
# url(r'^blog/', include('blog.urls')),
|
||||||
|
|
||||||
url(r'^', include('RIGS.urls')),
|
url(r'^', include('RIGS.urls')),
|
||||||
url('^user/register/$',
|
url('^user/register/$', RegistrationView.as_view(form_class=RIGS.forms.ProfileRegistrationFormUniqueEmail),
|
||||||
RegistrationView.as_view(form_class=RIGS.forms.ProfileRegistrationFormUniqueEmail),
|
name="registration_register"),
|
||||||
name="registration_register"),
|
url('^user/', include('django.contrib.auth.urls')),
|
||||||
url('^user/', include('django.contrib.auth.urls')),
|
url('^user/', include('registration.backends.default.urls')),
|
||||||
url('^user/', include('registration.backends.default.urls')),
|
|
||||||
|
|
||||||
url(r'^admin/', include(admin.site.urls)),
|
url(r'^admin/', include(admin.site.urls)),
|
||||||
)
|
)
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
urlpatterns += staticfiles_urlpatterns()
|
urlpatterns += staticfiles_urlpatterns()
|
||||||
@@ -7,7 +7,6 @@ For more information on this file, see
|
|||||||
https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
|
https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "PyRIGS.settings")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "PyRIGS.settings")
|
||||||
|
|
||||||
from django.core.wsgi import get_wsgi_application
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|||||||
20
README.md
20
README.md
@@ -1,6 +1,5 @@
|
|||||||
# TEC PA & Lighting - PyRIGS #
|
# TEC PA & Lighting - PyRIGS #
|
||||||
[](https://travis-ci.org/nottinghamtec/PyRIGS)
|
[](https://app.wercker.com/project/bykey/2dbe0517c3d83859c985ffc5a55a2802)
|
||||||
[](https://coveralls.io/github/nottinghamtec/PyRIGS?branch=develop)
|
|
||||||
|
|
||||||
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.
|
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,22 +74,5 @@ python manage.py runserver
|
|||||||
```
|
```
|
||||||
Please refer to Django documentation for a full list of options available here.
|
Please refer to Django documentation for a full list of options available here.
|
||||||
|
|
||||||
### Sample Data ###
|
|
||||||
Sample data is available to aid local development and user acceptance testing. To load this data into your local database, first ensure the database is empty:
|
|
||||||
```
|
|
||||||
python manage.py flush
|
|
||||||
```
|
|
||||||
Then load the sample data using the command:
|
|
||||||
```
|
|
||||||
python manage.py generateSampleData
|
|
||||||
```
|
|
||||||
4 user accounts are created for convenience:
|
|
||||||
|Username |Password |
|
|
||||||
|---------|---------|
|
|
||||||
|superuser|superuser|
|
|
||||||
|finance |finance |
|
|
||||||
|keyholder|keyholder|
|
|
||||||
|basic |basic |
|
|
||||||
|
|
||||||
### Committing, pushing and testing ###
|
### 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.
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import reversion
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib import messages
|
from RIGS import models, forms
|
||||||
from django.contrib.admin import helpers
|
|
||||||
from django.contrib.auth.admin import UserAdmin
|
from django.contrib.auth.admin import UserAdmin
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
import reversion
|
||||||
|
|
||||||
|
from django.contrib.admin import helpers
|
||||||
|
from django.template.response import TemplateResponse
|
||||||
|
from django.contrib import messages
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.forms import ModelForm
|
from django.forms import ModelForm
|
||||||
from django.template.response import TemplateResponse
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
from RIGS import models, forms
|
|
||||||
|
|
||||||
# Register your models here.
|
# Register your models here.
|
||||||
admin.site.register(models.VatRate, reversion.VersionAdmin)
|
admin.site.register(models.VatRate, reversion.VersionAdmin)
|
||||||
@@ -50,8 +50,7 @@ class AssociateAdmin(reversion.VersionAdmin):
|
|||||||
merge_fields = ['name']
|
merge_fields = ['name']
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
return super(AssociateAdmin, self).get_queryset(
|
return super(AssociateAdmin, self).get_queryset(request).annotate(event_count=Count('event'))
|
||||||
request).annotate(event_count=Count('event'))
|
|
||||||
|
|
||||||
def number_of_events(self, obj):
|
def number_of_events(self, obj):
|
||||||
return obj.latest_events.count()
|
return obj.latest_events.count()
|
||||||
@@ -59,16 +58,12 @@ class AssociateAdmin(reversion.VersionAdmin):
|
|||||||
number_of_events.admin_order_field = 'event_count'
|
number_of_events.admin_order_field = 'event_count'
|
||||||
|
|
||||||
def merge(self, request, queryset):
|
def merge(self, request, queryset):
|
||||||
if request.POST.get(
|
if request.POST.get('post'): # Has the user confirmed which is the master record?
|
||||||
'post'): # Has the user confirmed which is the master record?
|
|
||||||
try:
|
try:
|
||||||
masterObjectPk = request.POST.get('master')
|
masterObjectPk = request.POST.get('master')
|
||||||
masterObject = queryset.get(pk=masterObjectPk)
|
masterObject = queryset.get(pk=masterObjectPk)
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
self.message_user(
|
self.message_user(request, "An error occured. Did you select a 'master' record?", level=messages.ERROR)
|
||||||
request,
|
|
||||||
"An error occured. Did you select a 'master' record?",
|
|
||||||
level=messages.ERROR)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
@@ -84,7 +79,6 @@ class AssociateAdmin(reversion.VersionAdmin):
|
|||||||
else: # Present the confirmation screen
|
else: # Present the confirmation screen
|
||||||
|
|
||||||
class TempForm(ModelForm):
|
class TempForm(ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = queryset.model
|
model = queryset.model
|
||||||
fields = self.merge_fields
|
fields = self.merge_fields
|
||||||
@@ -112,22 +106,10 @@ class PersonAdmin(AssociateAdmin):
|
|||||||
@admin.register(models.Venue)
|
@admin.register(models.Venue)
|
||||||
class VenueAdmin(AssociateAdmin):
|
class VenueAdmin(AssociateAdmin):
|
||||||
list_display = ('id', 'name', 'phone', 'email', 'number_of_events')
|
list_display = ('id', 'name', 'phone', 'email', 'number_of_events')
|
||||||
merge_fields = [
|
merge_fields = ['name', 'phone', 'email', 'address', 'notes', 'three_phase_available']
|
||||||
'name',
|
|
||||||
'phone',
|
|
||||||
'email',
|
|
||||||
'address',
|
|
||||||
'notes',
|
|
||||||
'three_phase_available']
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(models.Organisation)
|
@admin.register(models.Organisation)
|
||||||
class OrganisationAdmin(AssociateAdmin):
|
class OrganisationAdmin(AssociateAdmin):
|
||||||
list_display = ('id', 'name', 'phone', 'email', 'number_of_events')
|
list_display = ('id', 'name', 'phone', 'email', 'number_of_events')
|
||||||
merge_fields = [
|
merge_fields = ['name', 'phone', 'email', 'address', 'notes', 'union_account']
|
||||||
'name',
|
|
||||||
'phone',
|
|
||||||
'email',
|
|
||||||
'address',
|
|
||||||
'notes',
|
|
||||||
'union_account']
|
|
||||||
|
|||||||
117
RIGS/finance.py
117
RIGS/finance.py
@@ -1,42 +1,32 @@
|
|||||||
import cStringIO as StringIO
|
import cStringIO as StringIO
|
||||||
import datetime
|
|
||||||
import re
|
|
||||||
|
|
||||||
from django.contrib import messages
|
|
||||||
from django.core.urlresolvers import reverse_lazy
|
from django.core.urlresolvers import reverse_lazy
|
||||||
from django.db.models import Q
|
from django.db import connection
|
||||||
from django.http import Http404, HttpResponseRedirect
|
from django.http import Http404, HttpResponseRedirect
|
||||||
from django.http import HttpResponse
|
from django.views import generic
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.views import generic
|
from django.http import HttpResponse
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.contrib import messages
|
||||||
|
import datetime
|
||||||
from z3c.rml import rml2pdf
|
from z3c.rml import rml2pdf
|
||||||
|
|
||||||
from RIGS import models
|
from RIGS import models
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
class InvoiceIndex(generic.ListView):
|
class InvoiceIndex(generic.ListView):
|
||||||
model = models.Invoice
|
model = models.Invoice
|
||||||
template_name = 'RIGS/invoice_list_active.html'
|
template_name = 'RIGS/invoice_list.html'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(InvoiceIndex, self).get_context_data(**kwargs)
|
|
||||||
total = 0
|
|
||||||
for i in context['object_list']:
|
|
||||||
total += i.balance
|
|
||||||
context['total'] = total
|
|
||||||
context['count'] = len(list(context['object_list']))
|
|
||||||
return context
|
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
# Manual query is the only way I have found to do this efficiently. Not
|
# Manual query is the only way I have found to do this efficiently. Not ideal but needs must
|
||||||
# ideal but needs must
|
|
||||||
sql = "SELECT * FROM " \
|
sql = "SELECT * FROM " \
|
||||||
"(SELECT " \
|
"(SELECT " \
|
||||||
"(SELECT COUNT(p.amount) FROM \"RIGS_payment\" AS p WHERE p.invoice_id=\"RIGS_invoice\".id) AS \"payment_count\", " \
|
"(SELECT COUNT(p.amount) FROM \"RIGS_payment\" as p WHERE p.invoice_id=\"RIGS_invoice\".id) AS \"payment_count\", " \
|
||||||
"(SELECT SUM(ei.cost * ei.quantity) FROM \"RIGS_eventitem\" AS ei WHERE ei.event_id=\"RIGS_invoice\".event_id) AS \"cost\", " \
|
"(SELECT SUM(ei.cost * ei.quantity) FROM \"RIGS_eventitem\" AS ei WHERE ei.event_id=\"RIGS_invoice\".event_id) AS \"cost\", " \
|
||||||
"(SELECT SUM(p.amount) FROM \"RIGS_payment\" AS p WHERE p.invoice_id=\"RIGS_invoice\".id) AS \"payments\", " \
|
"(SELECT SUM(p.amount) FROM \"RIGS_payment\" as p WHERE p.invoice_id=\"RIGS_invoice\".id) AS \"payments\", " \
|
||||||
"\"RIGS_invoice\".\"id\", \"RIGS_invoice\".\"event_id\", \"RIGS_invoice\".\"invoice_date\", \"RIGS_invoice\".\"void\" FROM \"RIGS_invoice\") " \
|
"\"RIGS_invoice\".\"id\", \"RIGS_invoice\".\"event_id\", \"RIGS_invoice\".\"invoice_date\", \"RIGS_invoice\".\"void\" FROM \"RIGS_invoice\") " \
|
||||||
"AS sub " \
|
"AS sub " \
|
||||||
"WHERE (((cost > 0.0) AND (payment_count=0)) OR (cost - payments) <> 0.0) AND void = '0'" \
|
"WHERE (((cost > 0.0) AND (payment_count=0)) OR (cost - payments) <> 0.0) AND void = '0'" \
|
||||||
@@ -50,7 +40,6 @@ class InvoiceIndex(generic.ListView):
|
|||||||
class InvoiceDetail(generic.DetailView):
|
class InvoiceDetail(generic.DetailView):
|
||||||
model = models.Invoice
|
model = models.Invoice
|
||||||
|
|
||||||
|
|
||||||
class InvoicePrint(generic.View):
|
class InvoicePrint(generic.View):
|
||||||
def get(self, request, pk):
|
def get(self, request, pk):
|
||||||
invoice = get_object_or_404(models.Invoice, pk=pk)
|
invoice = get_object_or_404(models.Invoice, pk=pk)
|
||||||
@@ -65,8 +54,8 @@ class InvoicePrint(generic.View):
|
|||||||
'bold': 'RIGS/static/fonts/OPENSANS-BOLD.TTF',
|
'bold': 'RIGS/static/fonts/OPENSANS-BOLD.TTF',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'invoice': invoice,
|
'invoice':invoice,
|
||||||
'current_user': request.user,
|
'current_user':request.user,
|
||||||
})
|
})
|
||||||
|
|
||||||
rml = template.render(context)
|
rml = template.render(context)
|
||||||
@@ -79,12 +68,10 @@ class InvoicePrint(generic.View):
|
|||||||
escapedEventName = re.sub('[^a-zA-Z0-9 \n\.]', '', object.name)
|
escapedEventName = re.sub('[^a-zA-Z0-9 \n\.]', '', object.name)
|
||||||
|
|
||||||
response = HttpResponse(content_type='application/pdf')
|
response = HttpResponse(content_type='application/pdf')
|
||||||
response[
|
response['Content-Disposition'] = "filename=Invoice %05d | %s.pdf" % (invoice.pk, escapedEventName)
|
||||||
'Content-Disposition'] = "filename=Invoice %05d | %s.pdf" % (invoice.pk, escapedEventName)
|
|
||||||
response.write(pdfData)
|
response.write(pdfData)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
class InvoiceVoid(generic.View):
|
class InvoiceVoid(generic.View):
|
||||||
def get(self, *args, **kwargs):
|
def get(self, *args, **kwargs):
|
||||||
pk = kwargs.get('pk')
|
pk = kwargs.get('pk')
|
||||||
@@ -94,77 +81,27 @@ class InvoiceVoid(generic.View):
|
|||||||
|
|
||||||
if object.void:
|
if object.void:
|
||||||
return HttpResponseRedirect(reverse_lazy('invoice_list'))
|
return HttpResponseRedirect(reverse_lazy('invoice_list'))
|
||||||
return HttpResponseRedirect(reverse_lazy(
|
return HttpResponseRedirect(reverse_lazy('invoice_detail', kwargs={'pk': object.pk}))
|
||||||
'invoice_detail', kwargs={'pk': object.pk}))
|
|
||||||
|
|
||||||
|
|
||||||
class InvoiceDelete(generic.DeleteView):
|
|
||||||
model = models.Invoice
|
|
||||||
|
|
||||||
def get(self, request, pk):
|
|
||||||
obj = self.get_object()
|
|
||||||
if obj.payment_set.all().count() > 0:
|
|
||||||
messages.info(
|
|
||||||
self.request,
|
|
||||||
'To delete an invoice, delete the payments first.')
|
|
||||||
return HttpResponseRedirect(reverse_lazy(
|
|
||||||
'invoice_detail', kwargs={'pk': obj.pk}))
|
|
||||||
return super(InvoiceDelete, self).get(pk)
|
|
||||||
|
|
||||||
def post(self, request, pk):
|
|
||||||
obj = self.get_object()
|
|
||||||
if obj.payment_set.all().count() > 0:
|
|
||||||
messages.info(
|
|
||||||
self.request,
|
|
||||||
'To delete an invoice, delete the payments first.')
|
|
||||||
return HttpResponseRedirect(reverse_lazy(
|
|
||||||
'invoice_detail', kwargs={'pk': obj.pk}))
|
|
||||||
return super(InvoiceDelete, self).post(pk)
|
|
||||||
|
|
||||||
def get_success_url(self):
|
|
||||||
return self.request.POST.get('next')
|
|
||||||
|
|
||||||
|
|
||||||
class InvoiceArchive(generic.ListView):
|
class InvoiceArchive(generic.ListView):
|
||||||
model = models.Invoice
|
model = models.Invoice
|
||||||
template_name = 'RIGS/invoice_list_archive.html'
|
|
||||||
paginate_by = 25
|
paginate_by = 25
|
||||||
|
|
||||||
|
|
||||||
class InvoiceWaiting(generic.ListView):
|
class InvoiceWaiting(generic.ListView):
|
||||||
model = models.Event
|
model = models.Event
|
||||||
# paginate_by = 25
|
paginate_by = 25
|
||||||
template_name = 'RIGS/event_invoice.html'
|
template_name = 'RIGS/event_invoice.html'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(InvoiceWaiting, self).get_context_data(**kwargs)
|
|
||||||
total = 0
|
|
||||||
for obj in self.get_objects():
|
|
||||||
total += obj.sum_total
|
|
||||||
context['total'] = total
|
|
||||||
context['count'] = len(self.get_objects())
|
|
||||||
return context
|
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return self.get_objects()
|
|
||||||
|
|
||||||
def get_objects(self):
|
|
||||||
# @todo find a way to select items
|
# @todo find a way to select items
|
||||||
events = self.model.objects.filter(
|
events = self.model.objects.filter(is_rig=True, end_date__lt=datetime.date.today(),
|
||||||
(
|
invoice__isnull=True) \
|
||||||
# Starts before with no end
|
.order_by('start_date') \
|
||||||
Q(start_date__lte=datetime.date.today(), end_date__isnull=True) |
|
|
||||||
# Has end date, finishes before
|
|
||||||
Q(end_date__lte=datetime.date.today())
|
|
||||||
) & Q(invoice__isnull=True) # Has not already been invoiced
|
|
||||||
& Q(is_rig=True) # Is a rig (not non-rig)
|
|
||||||
|
|
||||||
).order_by('start_date') \
|
|
||||||
.select_related('person',
|
.select_related('person',
|
||||||
'organisation',
|
'organisation',
|
||||||
'venue', 'mic') \
|
'venue', 'mic')
|
||||||
.prefetch_related('items')
|
|
||||||
|
|
||||||
return events
|
return events
|
||||||
|
|
||||||
|
|
||||||
@@ -176,22 +113,18 @@ class InvoiceEvent(generic.View):
|
|||||||
|
|
||||||
if created:
|
if created:
|
||||||
invoice.invoice_date = datetime.date.today()
|
invoice.invoice_date = datetime.date.today()
|
||||||
messages.success(self.request, 'Invoice created successfully')
|
|
||||||
|
|
||||||
return HttpResponseRedirect(reverse_lazy(
|
return HttpResponseRedirect(reverse_lazy('invoice_detail', kwargs={'pk': invoice.pk}))
|
||||||
'invoice_detail', kwargs={'pk': invoice.pk}))
|
|
||||||
|
|
||||||
|
|
||||||
class PaymentCreate(generic.CreateView):
|
class PaymentCreate(generic.CreateView):
|
||||||
model = models.Payment
|
model = models.Payment
|
||||||
fields = ['invoice', 'date', 'amount', 'method']
|
fields = ['invoice','date','amount','method']
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
initial = super(generic.CreateView, self).get_initial()
|
initial = super(generic.CreateView, self).get_initial()
|
||||||
invoicepk = self.request.GET.get(
|
invoicepk = self.request.GET.get('invoice', self.request.POST.get('invoice', None))
|
||||||
'invoice', self.request.POST.get(
|
if invoicepk == None:
|
||||||
'invoice', None))
|
|
||||||
if invoicepk is None:
|
|
||||||
raise Http404()
|
raise Http404()
|
||||||
invoice = get_object_or_404(models.Invoice, pk=invoicepk)
|
invoice = get_object_or_404(models.Invoice, pk=invoicepk)
|
||||||
initial.update({'invoice': invoice})
|
initial.update({'invoice': invoice})
|
||||||
@@ -206,4 +139,4 @@ class PaymentDelete(generic.DeleteView):
|
|||||||
model = models.Payment
|
model = models.Payment
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return self.request.POST.get('next')
|
return self.request.POST.get('next')
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
__author__ = 'Ghost'
|
__author__ = 'Ghost'
|
||||||
import simplejson
|
|
||||||
from captcha.fields import ReCaptchaField
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, PasswordResetForm
|
|
||||||
from django.core import serializers
|
|
||||||
from django.utils import formats
|
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
|
from RIGS import models
|
||||||
|
|
||||||
@@ -17,22 +17,14 @@ class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Profile
|
model = models.Profile
|
||||||
fields = (
|
fields = ('username', 'email', 'first_name', 'last_name', 'initials', 'phone')
|
||||||
'username',
|
|
||||||
'email',
|
|
||||||
'first_name',
|
|
||||||
'last_name',
|
|
||||||
'initials',
|
|
||||||
'phone')
|
|
||||||
|
|
||||||
def clean_initials(self):
|
def clean_initials(self):
|
||||||
"""
|
"""
|
||||||
Validate that the supplied initials are unique.
|
Validate that the supplied initials are unique.
|
||||||
"""
|
"""
|
||||||
if models.Profile.objects.filter(
|
if models.Profile.objects.filter(initials__iexact=self.cleaned_data['initials']):
|
||||||
initials__iexact=self.cleaned_data['initials']):
|
raise forms.ValidationError("These initials are already in use. Please supply different initials.")
|
||||||
raise forms.ValidationError(
|
|
||||||
"These initials are already in use. Please supply different initials.")
|
|
||||||
return self.cleaned_data['initials']
|
return self.cleaned_data['initials']
|
||||||
|
|
||||||
|
|
||||||
@@ -53,14 +45,9 @@ class ProfileChangeForm(UserChangeForm):
|
|||||||
|
|
||||||
# Events Shit
|
# Events Shit
|
||||||
class EventForm(forms.ModelForm):
|
class EventForm(forms.ModelForm):
|
||||||
datetime_input_formats = formats.get_format_lazy(
|
datetime_input_formats = formats.get_format_lazy("DATETIME_INPUT_FORMATS") + settings.DATETIME_INPUT_FORMATS
|
||||||
"DATETIME_INPUT_FORMATS") + settings.DATETIME_INPUT_FORMATS
|
meet_at = forms.DateTimeField(input_formats=datetime_input_formats, required=False)
|
||||||
meet_at = forms.DateTimeField(
|
access_at = forms.DateTimeField(input_formats=datetime_input_formats, required=False)
|
||||||
input_formats=datetime_input_formats,
|
|
||||||
required=False)
|
|
||||||
access_at = forms.DateTimeField(
|
|
||||||
input_formats=datetime_input_formats,
|
|
||||||
required=False)
|
|
||||||
|
|
||||||
items_json = forms.CharField()
|
items_json = forms.CharField()
|
||||||
|
|
||||||
@@ -102,8 +89,7 @@ class EventForm(forms.ModelForm):
|
|||||||
items = {}
|
items = {}
|
||||||
for key in data:
|
for key in data:
|
||||||
pk = int(key)
|
pk = int(key)
|
||||||
items[pk] = self._get_or_initialise_item(
|
items[pk] = self._get_or_initialise_item(pk, data[key]['fields'], event)
|
||||||
pk, data[key]['fields'], event)
|
|
||||||
|
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
|||||||
100
RIGS/ical.py
100
RIGS/ical.py
@@ -1,18 +1,17 @@
|
|||||||
import datetime
|
from RIGS import models, forms
|
||||||
|
|
||||||
import pytz
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db.models import Q
|
|
||||||
from django_ical.views import ICalFeed
|
from django_ical.views import ICalFeed
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.core.urlresolvers import reverse_lazy, reverse, NoReverseMatch
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
from RIGS import models
|
import datetime, pytz
|
||||||
|
|
||||||
|
|
||||||
class CalendarICS(ICalFeed):
|
class CalendarICS(ICalFeed):
|
||||||
"""
|
"""
|
||||||
A simple event calender
|
A simple event calender
|
||||||
"""
|
"""
|
||||||
# Metadata which is passed on to clients
|
#Metadata which is passed on to clients
|
||||||
product_id = 'RIGS'
|
product_id = 'RIGS'
|
||||||
title = 'RIGS Calendar'
|
title = 'RIGS Calendar'
|
||||||
timezone = settings.TIME_ZONE
|
timezone = settings.TIME_ZONE
|
||||||
@@ -28,58 +27,50 @@ class CalendarICS(ICalFeed):
|
|||||||
def get_object(self, request, *args, **kwargs):
|
def get_object(self, request, *args, **kwargs):
|
||||||
params = {}
|
params = {}
|
||||||
|
|
||||||
params['dry-hire'] = request.GET.get('dry-hire', 'true') == 'true'
|
params['dry-hire'] = request.GET.get('dry-hire','true') == 'true'
|
||||||
params['non-rig'] = request.GET.get('non-rig', 'true') == 'true'
|
params['non-rig'] = request.GET.get('non-rig','true') == 'true'
|
||||||
params['rig'] = request.GET.get('rig', 'true') == 'true'
|
params['rig'] = request.GET.get('rig','true') == 'true'
|
||||||
|
|
||||||
params['cancelled'] = request.GET.get('cancelled', 'false') == 'true'
|
params['cancelled'] = request.GET.get('cancelled','false') == 'true'
|
||||||
params['provisional'] = request.GET.get(
|
params['provisional'] = request.GET.get('provisional','true') == 'true'
|
||||||
'provisional', 'true') == 'true'
|
params['confirmed'] = request.GET.get('confirmed','true') == 'true'
|
||||||
params['confirmed'] = request.GET.get('confirmed', 'true') == 'true'
|
|
||||||
|
|
||||||
return params
|
return params
|
||||||
|
|
||||||
def description(self, params):
|
def description(self,params):
|
||||||
desc = "Calendar generated by RIGS system. This includes event types: " + ('Rig, ' if params['rig'] else '') + (
|
desc = "Calendar generated by RIGS system. This includes event types: " + ('Rig, ' if params['rig'] else '') + ('Non-rig, ' if params['non-rig'] else '') + ('Dry Hire ' if params['dry-hire'] else '') + '\n'
|
||||||
'Non-rig, ' if params['non-rig'] else '') + ('Dry Hire ' if params['dry-hire'] else '') + '\n'
|
desc = desc + "Includes events with status: " + ('Cancelled, ' if params['cancelled'] else '') + ('Provisional, ' if params['provisional'] else '') + ('Confirmed/Booked, ' if params['confirmed'] else '')
|
||||||
desc = desc + "Includes events with status: " + ('Cancelled, ' if params['cancelled'] else '') + (
|
|
||||||
'Provisional, ' if params['provisional'] else '') + ('Confirmed/Booked, ' if params['confirmed'] else '')
|
|
||||||
|
|
||||||
return desc
|
return desc
|
||||||
|
|
||||||
def items(self, params):
|
def items(self, params):
|
||||||
# include events from up to 1 year ago
|
#include events from up to 1 year ago
|
||||||
start = datetime.datetime.now() - datetime.timedelta(days=365)
|
start = datetime.datetime.now() - datetime.timedelta(days=365)
|
||||||
filter = Q(start_date__gte=start)
|
filter = Q(start_date__gte=start)
|
||||||
|
|
||||||
# Need something that is false for every entry
|
typeFilters = Q(pk=None) #Need something that is false for every entry
|
||||||
typeFilters = Q(pk=None)
|
|
||||||
|
|
||||||
if params['dry-hire']:
|
if params['dry-hire']:
|
||||||
typeFilters = typeFilters | Q(dry_hire=True, is_rig=True)
|
typeFilters = typeFilters | Q(dry_hire=True, is_rig=True)
|
||||||
|
|
||||||
if params['non-rig']:
|
if params['non-rig']:
|
||||||
typeFilters = typeFilters | Q(is_rig=False)
|
typeFilters = typeFilters | Q(is_rig=False)
|
||||||
|
|
||||||
if params['rig']:
|
if params['rig']:
|
||||||
typeFilters = typeFilters | Q(is_rig=True, dry_hire=False)
|
typeFilters = typeFilters | Q(is_rig=True, dry_hire=False)
|
||||||
|
|
||||||
# Need something that is false for every entry
|
statusFilters = Q(pk=None) #Need something that is false for every entry
|
||||||
statusFilters = Q(pk=None)
|
|
||||||
|
|
||||||
if params['cancelled']:
|
if params['cancelled']:
|
||||||
statusFilters = statusFilters | Q(status=models.Event.CANCELLED)
|
statusFilters = statusFilters | Q(status=models.Event.CANCELLED)
|
||||||
if params['provisional']:
|
if params['provisional']:
|
||||||
statusFilters = statusFilters | Q(status=models.Event.PROVISIONAL)
|
statusFilters = statusFilters | Q(status=models.Event.PROVISIONAL)
|
||||||
if params['confirmed']:
|
if params['confirmed']:
|
||||||
statusFilters = statusFilters | Q(
|
statusFilters = statusFilters | Q(status=models.Event.CONFIRMED) | Q(status=models.Event.BOOKED)
|
||||||
status=models.Event.CONFIRMED) | Q(
|
|
||||||
status=models.Event.BOOKED)
|
|
||||||
|
|
||||||
filter = filter & typeFilters & statusFilters
|
filter = filter & typeFilters & statusFilters
|
||||||
|
|
||||||
return models.Event.objects.filter(filter).order_by(
|
return models.Event.objects.filter(filter).order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
||||||
'-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
|
||||||
|
|
||||||
def item_title(self, item):
|
def item_title(self, item):
|
||||||
title = ''
|
title = ''
|
||||||
@@ -96,9 +87,9 @@ class CalendarICS(ICalFeed):
|
|||||||
|
|
||||||
# Add the rig name
|
# Add the rig name
|
||||||
title += item.name
|
title += item.name
|
||||||
|
|
||||||
# Add the status
|
# Add the status
|
||||||
title += ' (' + str(item.get_status_display()) + ')'
|
title += ' ('+str(item.get_status_display())+')'
|
||||||
|
|
||||||
return title
|
return title
|
||||||
|
|
||||||
@@ -106,13 +97,12 @@ class CalendarICS(ICalFeed):
|
|||||||
return item.earliest_time
|
return item.earliest_time
|
||||||
|
|
||||||
def item_end_datetime(self, item):
|
def item_end_datetime(self, item):
|
||||||
if isinstance(
|
if type(item.latest_time) is datetime.date: # Ical end_datetime is non-inclusive, so add a day
|
||||||
item.latest_time, datetime.date): # Ical end_datetime is non-inclusive, so add a day
|
|
||||||
return item.latest_time + datetime.timedelta(days=1)
|
return item.latest_time + datetime.timedelta(days=1)
|
||||||
|
|
||||||
return item.latest_time
|
return item.latest_time
|
||||||
|
|
||||||
def item_location(self, item):
|
def item_location(self,item):
|
||||||
return item.venue
|
return item.venue
|
||||||
|
|
||||||
def item_description(self, item):
|
def item_description(self, item):
|
||||||
@@ -121,40 +111,34 @@ class CalendarICS(ICalFeed):
|
|||||||
|
|
||||||
tz = pytz.timezone(self.timezone)
|
tz = pytz.timezone(self.timezone)
|
||||||
|
|
||||||
desc = 'Rig ID = ' + str(item.pk) + '\n'
|
desc = 'Rig ID = '+str(item.pk)+'\n'
|
||||||
desc += 'Event = ' + item.name + '\n'
|
desc += 'Event = ' + item.name + '\n'
|
||||||
desc += 'Venue = ' + (item.venue.name if item.venue else '---') + '\n'
|
desc += 'Venue = ' + (item.venue.name if item.venue else '---') + '\n'
|
||||||
if item.is_rig and item.person:
|
if item.is_rig and item.person:
|
||||||
desc += 'Client = ' + item.person.name + \
|
desc += 'Client = ' + item.person.name + ( (' for '+item.organisation.name) if item.organisation else '') + '\n'
|
||||||
((' for ' + item.organisation.name)
|
|
||||||
if item.organisation else '') + '\n'
|
|
||||||
desc += 'Status = ' + str(item.get_status_display()) + '\n'
|
desc += 'Status = ' + str(item.get_status_display()) + '\n'
|
||||||
desc += 'MIC = ' + (item.mic.name if item.mic else '---') + '\n'
|
desc += 'MIC = ' + (item.mic.name if item.mic else '---') + '\n'
|
||||||
|
|
||||||
|
|
||||||
desc += '\n'
|
desc += '\n'
|
||||||
if item.meet_at:
|
if item.meet_at:
|
||||||
desc += 'Crew Meet = ' + \
|
desc += 'Crew Meet = ' + (item.meet_at.astimezone(tz).strftime('%Y-%m-%d %H:%M') if item.meet_at else '---') + '\n'
|
||||||
(item.meet_at.astimezone(tz).strftime(
|
|
||||||
'%Y-%m-%d %H:%M') if item.meet_at else '---') + '\n'
|
|
||||||
if item.access_at:
|
if item.access_at:
|
||||||
desc += 'Access At = ' + (item.access_at.astimezone(tz).strftime(
|
desc += 'Access At = ' + (item.access_at.astimezone(tz).strftime('%Y-%m-%d %H:%M') if item.access_at else '---') + '\n'
|
||||||
'%Y-%m-%d %H:%M') if item.access_at else '---') + '\n'
|
|
||||||
if item.start_date:
|
if item.start_date:
|
||||||
desc += 'Event Start = ' + item.start_date.strftime('%Y-%m-%d') + (
|
desc += 'Event Start = ' + item.start_date.strftime('%Y-%m-%d') + ((' '+item.start_time.strftime('%H:%M')) if item.has_start_time else '') + '\n'
|
||||||
(' ' + item.start_time.strftime('%H:%M')) if item.has_start_time else '') + '\n'
|
|
||||||
if item.end_date:
|
if item.end_date:
|
||||||
desc += 'Event End = ' + item.end_date.strftime('%Y-%m-%d') + (
|
desc += 'Event End = ' + item.end_date.strftime('%Y-%m-%d') + ((' '+item.end_time.strftime('%H:%M')) if item.has_end_time else '') + '\n'
|
||||||
(' ' + item.end_time.strftime('%H:%M')) if item.has_end_time else '') + '\n'
|
|
||||||
|
|
||||||
desc += '\n'
|
desc += '\n'
|
||||||
if item.description:
|
if item.description:
|
||||||
desc += 'Event Description:\n' + item.description + '\n\n'
|
desc += 'Event Description:\n'+item.description+'\n\n'
|
||||||
# if item.notes: // Need to add proper keyholder checks before this gets put back
|
# if item.notes: // Need to add proper keyholder checks before this gets put back
|
||||||
# desc += 'Notes:\n'+item.notes+'\n\n'
|
# desc += 'Notes:\n'+item.notes+'\n\n'
|
||||||
|
|
||||||
base_url = "http://rigs.nottinghamtec.co.uk"
|
base_url = "http://rigs.nottinghamtec.co.uk"
|
||||||
desc += 'URL = ' + base_url + str(item.get_absolute_url())
|
desc += 'URL = '+base_url+str(item.get_absolute_url())
|
||||||
|
|
||||||
return desc
|
return desc
|
||||||
|
|
||||||
def item_link(self, item):
|
def item_link(self, item):
|
||||||
@@ -165,8 +149,8 @@ class CalendarICS(ICalFeed):
|
|||||||
# def item_created(self, item): #TODO - Implement created date-time (using django-reversion?) - not really necessary though
|
# def item_created(self, item): #TODO - Implement created date-time (using django-reversion?) - not really necessary though
|
||||||
# return ''
|
# return ''
|
||||||
|
|
||||||
def item_updated(self, item): # some ical clients will display this
|
def item_updated(self, item): # some ical clients will display this
|
||||||
return item.last_edited_at
|
return item.last_edited_at
|
||||||
|
|
||||||
def item_guid(self, item): # use the rig-id as the ical unique event identifier
|
def item_guid(self, item): # use the rig-id as the ical unique event identifier
|
||||||
return item.pk
|
return item.pk
|
||||||
@@ -1,321 +0,0 @@
|
|||||||
import datetime
|
|
||||||
import random
|
|
||||||
|
|
||||||
import reversion
|
|
||||||
from django.contrib.auth.models import Group, Permission
|
|
||||||
from django.core.management.base import BaseCommand, CommandError
|
|
||||||
from django.db import transaction
|
|
||||||
|
|
||||||
from RIGS import models
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
help = 'Adds sample data to use for testing'
|
|
||||||
can_import_settings = True
|
|
||||||
|
|
||||||
people = []
|
|
||||||
organisations = []
|
|
||||||
venues = []
|
|
||||||
profiles = []
|
|
||||||
|
|
||||||
keyholder_group = None
|
|
||||||
finance_group = None
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
if not (settings.DEBUG or settings.STAGING):
|
|
||||||
raise CommandError('You cannot run this command in production')
|
|
||||||
|
|
||||||
random.seed(
|
|
||||||
'Some object to seed the random number generator') # otherwise it is done by time, which could lead to inconsistant tests
|
|
||||||
|
|
||||||
with transaction.atomic():
|
|
||||||
models.VatRate.objects.create(start_at='2014-03-05', rate=0.20, comment='test1')
|
|
||||||
|
|
||||||
self.setupGenericProfiles()
|
|
||||||
|
|
||||||
self.setupPeople()
|
|
||||||
self.setupOrganisations()
|
|
||||||
self.setupVenues()
|
|
||||||
|
|
||||||
self.setupGroups()
|
|
||||||
|
|
||||||
self.setupEvents()
|
|
||||||
|
|
||||||
self.setupUsefulProfiles()
|
|
||||||
|
|
||||||
def setupPeople(self):
|
|
||||||
names = ["Regulus Black", "Sirius Black", "Lavender Brown", "Cho Chang", "Vincent Crabbe", "Vincent Crabbe",
|
|
||||||
"Bartemius Crouch", "Fleur Delacour", "Cedric Diggory", "Alberforth Dumbledore", "Albus Dumbledore",
|
|
||||||
"Dudley Dursley", "Petunia Dursley", "Vernon Dursley", "Argus Filch", "Seamus Finnigan",
|
|
||||||
"Nicolas Flamel", "Cornelius Fudge", "Goyle", "Gregory Goyle", "Hermione Granger", "Rubeus Hagrid",
|
|
||||||
"Igor Karkaroff", "Viktor Krum", "Bellatrix Lestrange", "Alice Longbottom", "Frank Longbottom",
|
|
||||||
"Neville Longbottom", "Luna Lovegood", "Xenophilius Lovegood", "Remus Lupin", "Draco Malfoy",
|
|
||||||
"Lucius Malfoy", "Narcissa Malfoy", "Olympe Maxime", "Minerva McGonagall", "Mad-Eye Moody",
|
|
||||||
"Peter Pettigrew", "Harry Potter", "James Potter", "Lily Potter", "Quirinus Quirrell", "Tom Riddle",
|
|
||||||
"Mary Riddle", "Lord Voldemort", "Rita Skeeter", "Severus Snape", "Nymphadora Tonks",
|
|
||||||
"Dolores Janes Umbridge", "Arthur Weasley", "Bill Weasley", "Charlie Weasley", "Fred Weasley",
|
|
||||||
"George Weasley", "Ginny Weasley", "Molly Weasley", "Percy Weasley", "Ron Weasley", "Dobby", "Fluffy",
|
|
||||||
"Hedwig", "Moaning Myrtle", "Aragog", "Grawp"]
|
|
||||||
for i, name in enumerate(names):
|
|
||||||
with reversion.create_revision():
|
|
||||||
reversion.set_user(random.choice(self.profiles))
|
|
||||||
|
|
||||||
newPerson = models.Person.objects.create(name=name)
|
|
||||||
if i % 3 == 0:
|
|
||||||
newPerson.email = "address@person.com"
|
|
||||||
|
|
||||||
if i % 5 == 0:
|
|
||||||
newPerson.notes = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"
|
|
||||||
|
|
||||||
if i % 7 == 0:
|
|
||||||
newPerson.address = "1 Person Test Street \n Demoton \n United States of TEC \n RMRF 567"
|
|
||||||
|
|
||||||
if i % 9 == 0:
|
|
||||||
newPerson.phone = "01234 567894"
|
|
||||||
|
|
||||||
newPerson.save()
|
|
||||||
self.people.append(newPerson)
|
|
||||||
|
|
||||||
def setupOrganisations(self):
|
|
||||||
names = ["Acme, inc.", "Widget Corp", "123 Warehousing", "Demo Company", "Smith and Co.", "Foo Bars",
|
|
||||||
"ABC Telecom", "Fake Brothers", "QWERTY Logistics", "Demo, inc.", "Sample Company", "Sample, inc",
|
|
||||||
"Acme Corp", "Allied Biscuit", "Ankh-Sto Associates", "Extensive Enterprise", "Galaxy Corp",
|
|
||||||
"Globo-Chem", "Mr. Sparkle", "Globex Corporation", "LexCorp", "LuthorCorp",
|
|
||||||
"North Central Positronics", "Omni Consimer Products", "Praxis Corporation", "Sombra Corporation",
|
|
||||||
"Sto Plains Holdings", "Tessier-Ashpool", "Wayne Enterprises", "Wentworth Industries", "ZiffCorp",
|
|
||||||
"Bluth Company", "Strickland Propane", "Thatherton Fuels", "Three Waters", "Water and Power",
|
|
||||||
"Western Gas & Electric", "Mammoth Pictures", "Mooby Corp", "Gringotts", "Thrift Bank",
|
|
||||||
"Flowers By Irene", "The Legitimate Businessmens Club", "Osato Chemicals", "Transworld Consortium",
|
|
||||||
"Universal Export", "United Fried Chicken", "Virtucon", "Kumatsu Motors", "Keedsler Motors",
|
|
||||||
"Powell Motors", "Industrial Automation", "Sirius Cybernetics Corporation",
|
|
||||||
"U.S. Robotics and Mechanical Men", "Colonial Movers", "Corellian Engineering Corporation",
|
|
||||||
"Incom Corporation", "General Products", "Leeding Engines Ltd.", "Blammo", "Input, Inc.",
|
|
||||||
"Mainway Toys", "Videlectrix", "Zevo Toys", "Ajax", "Axis Chemical Co.", "Barrytron", "Carrys Candles",
|
|
||||||
"Cogswell Cogs", "Spacely Sprockets", "General Forge and Foundry", "Duff Brewing Company",
|
|
||||||
"Dunder Mifflin", "General Services Corporation", "Monarch Playing Card Co.", "Krustyco", "Initech",
|
|
||||||
"Roboto Industries", "Primatech", "Sonky Rubber Goods", "St. Anky Beer", "Stay Puft Corporation",
|
|
||||||
"Vandelay Industries", "Wernham Hogg", "Gadgetron", "Burleigh and Stronginthearm", "BLAND Corporation",
|
|
||||||
"Nordyne Defense Dynamics", "Petrox Oil Company", "Roxxon", "McMahon and Tate", "Sixty Second Avenue",
|
|
||||||
"Charles Townsend Agency", "Spade and Archer", "Megadodo Publications", "Rouster and Sideways",
|
|
||||||
"C.H. Lavatory and Sons", "Globo Gym American Corp", "The New Firm", "SpringShield",
|
|
||||||
"Compuglobalhypermeganet", "Data Systems", "Gizmonic Institute", "Initrode",
|
|
||||||
"Taggart Transcontinental", "Atlantic Northern", "Niagular", "Plow King", "Big Kahuna Burger",
|
|
||||||
"Big T Burgers and Fries", "Chez Quis", "Chotchkies", "The Frying Dutchman", "Klimpys",
|
|
||||||
"The Krusty Krab", "Monks Diner", "Milliways", "Minuteman Cafe", "Taco Grande", "Tip Top Cafe",
|
|
||||||
"Moes Tavern", "Central Perk", "Chasers"]
|
|
||||||
for i, name in enumerate(names):
|
|
||||||
with reversion.create_revision():
|
|
||||||
reversion.set_user(random.choice(self.profiles))
|
|
||||||
newOrganisation = models.Organisation.objects.create(name=name)
|
|
||||||
if i % 2 == 0:
|
|
||||||
newOrganisation.has_su_account = True
|
|
||||||
|
|
||||||
if i % 3 == 0:
|
|
||||||
newOrganisation.email = "address@organisation.com"
|
|
||||||
|
|
||||||
if i % 5 == 0:
|
|
||||||
newOrganisation.notes = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"
|
|
||||||
|
|
||||||
if i % 7 == 0:
|
|
||||||
newOrganisation.address = "1 Organisation Test Street \n Demoton \n United States of TEC \n RMRF 567"
|
|
||||||
|
|
||||||
if i % 9 == 0:
|
|
||||||
newOrganisation.phone = "01234 567894"
|
|
||||||
|
|
||||||
newOrganisation.save()
|
|
||||||
self.organisations.append(newOrganisation)
|
|
||||||
|
|
||||||
def setupVenues(self):
|
|
||||||
names = ["Bear Island", "Crossroads Inn", "Deepwood Motte", "The Dreadfort", "The Eyrie", "Greywater Watch",
|
|
||||||
"The Iron Islands", "Karhold", "Moat Cailin", "Oldstones", "Raventree Hall", "Riverlands",
|
|
||||||
"The Ruby Ford", "Saltpans", "Seagard", "Torrhen's Square", "The Trident", "The Twins",
|
|
||||||
"The Vale of Arryn", "The Whispering Wood", "White Harbor", "Winterfell", "The Arbor", "Ashemark",
|
|
||||||
"Brightwater Keep", "Casterly Rock", "Clegane's Keep", "Dragonstone", "Dorne", "God's Eye",
|
|
||||||
"The Golden Tooth", "Harrenhal", "Highgarden", "Horn Hill", "Fingers", "King's Landing", "Lannisport",
|
|
||||||
"Oldtown", "Rainswood", "Storm's End", "Summerhall", "Sunspear", "Tarth", "Castle Black",
|
|
||||||
"Craster's Keep", "Fist of the First Men", "The Frostfangs", "The Gift", "The Skirling Pass",
|
|
||||||
"The Wall", "Asshai", "Astapor", "Braavos", "The Dothraki Sea", "Lys", "Meereen", "Myr", "Norvos",
|
|
||||||
"Pentos", "Qarth", "Qohor", "The Red Waste", "Tyrosh", "Vaes Dothrak", "Valyria",
|
|
||||||
"Village of the Lhazareen", "Volantis", "Yunkai"]
|
|
||||||
for i, name in enumerate(names):
|
|
||||||
with reversion.create_revision():
|
|
||||||
reversion.set_user(random.choice(self.profiles))
|
|
||||||
newVenue = models.Venue.objects.create(name=name)
|
|
||||||
if i % 2 == 0:
|
|
||||||
newVenue.three_phase_available = True
|
|
||||||
|
|
||||||
if i % 3 == 0:
|
|
||||||
newVenue.email = "address@venue.com"
|
|
||||||
|
|
||||||
if i % 5 == 0:
|
|
||||||
newVenue.notes = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"
|
|
||||||
|
|
||||||
if i % 7 == 0:
|
|
||||||
newVenue.address = "1 Venue Test Street \n Demoton \n United States of TEC \n RMRF 567"
|
|
||||||
|
|
||||||
if i % 9 == 0:
|
|
||||||
newVenue.phone = "01234 567894"
|
|
||||||
|
|
||||||
newVenue.save()
|
|
||||||
self.venues.append(newVenue)
|
|
||||||
|
|
||||||
def setupGroups(self):
|
|
||||||
self.keyholder_group = Group.objects.create(name='Keyholders')
|
|
||||||
self.finance_group = Group.objects.create(name='Finance')
|
|
||||||
|
|
||||||
keyholderPerms = ["add_event", "change_event", "view_event", "add_eventitem", "change_eventitem",
|
|
||||||
"delete_eventitem", "add_organisation", "change_organisation", "view_organisation",
|
|
||||||
"add_person", "change_person", "view_person", "view_profile", "add_venue", "change_venue",
|
|
||||||
"view_venue"]
|
|
||||||
financePerms = ["change_event", "view_event", "add_eventitem", "change_eventitem", "add_invoice",
|
|
||||||
"change_invoice", "view_invoice", "add_organisation", "change_organisation",
|
|
||||||
"view_organisation", "add_payment", "change_payment", "delete_payment", "add_person",
|
|
||||||
"change_person", "view_person"]
|
|
||||||
|
|
||||||
for permId in keyholderPerms:
|
|
||||||
self.keyholder_group.permissions.add(Permission.objects.get(codename=permId))
|
|
||||||
|
|
||||||
for permId in financePerms:
|
|
||||||
self.finance_group.permissions.add(Permission.objects.get(codename=permId))
|
|
||||||
|
|
||||||
def setupGenericProfiles(self):
|
|
||||||
names = ["Clara Oswin Oswald", "Rory Williams", "Amy Pond", "River Song", "Martha Jones", "Donna Noble",
|
|
||||||
"Jack Harkness", "Mickey Smith", "Rose Tyler"]
|
|
||||||
for i, name in enumerate(names):
|
|
||||||
newProfile = models.Profile.objects.create(username=name.replace(" ", ""), first_name=name.split(" ")[0],
|
|
||||||
last_name=name.split(" ")[-1],
|
|
||||||
email=name.replace(" ", "") + "@example.com",
|
|
||||||
initials="".join([j[0].upper() for j in name.split()]))
|
|
||||||
if i % 2 == 0:
|
|
||||||
newProfile.phone = "01234 567894"
|
|
||||||
|
|
||||||
newProfile.save()
|
|
||||||
self.profiles.append(newProfile)
|
|
||||||
|
|
||||||
def setupUsefulProfiles(self):
|
|
||||||
superUser = models.Profile.objects.create(username="superuser", first_name="Super", last_name="User",
|
|
||||||
initials="SU",
|
|
||||||
email="superuser@example.com", is_superuser=True, is_active=True,
|
|
||||||
is_staff=True)
|
|
||||||
superUser.set_password('superuser')
|
|
||||||
superUser.save()
|
|
||||||
|
|
||||||
financeUser = models.Profile.objects.create(username="finance", first_name="Finance", last_name="User",
|
|
||||||
initials="FU",
|
|
||||||
email="financeuser@example.com", is_active=True)
|
|
||||||
financeUser.groups.add(self.finance_group)
|
|
||||||
financeUser.groups.add(self.keyholder_group)
|
|
||||||
financeUser.set_password('finance')
|
|
||||||
financeUser.save()
|
|
||||||
|
|
||||||
keyholderUser = models.Profile.objects.create(username="keyholder", first_name="Keyholder", last_name="User",
|
|
||||||
initials="KU",
|
|
||||||
email="keyholderuser@example.com", is_active=True)
|
|
||||||
keyholderUser.groups.add(self.keyholder_group)
|
|
||||||
keyholderUser.set_password('keyholder')
|
|
||||||
keyholderUser.save()
|
|
||||||
|
|
||||||
basicUser = models.Profile.objects.create(username="basic", first_name="Basic", last_name="User", initials="BU",
|
|
||||||
email="basicuser@example.com", is_active=True)
|
|
||||||
basicUser.set_password('basic')
|
|
||||||
basicUser.save()
|
|
||||||
|
|
||||||
def setupEvents(self):
|
|
||||||
names = ["Outdoor Concert", "Hall Open Mic Night", "Festival", "Weekend Event", "Magic Show", "Society Ball",
|
|
||||||
"Evening Show", "Talent Show", "Acoustic Evening", "Hire of Things", "SU Event", "End of Term Show",
|
|
||||||
"Theatre Show", "Outdoor Fun Day", "Summer Carnival", "Open Days", "Magic Show", "Awards Ceremony",
|
|
||||||
"Debating Event", "Club Night", "DJ Evening", "Building Projection", "Choir Concert"]
|
|
||||||
descriptions = ["A brief desciption of the event", "This event is boring", "Probably wont happen",
|
|
||||||
"Warning: this has lots of kit"]
|
|
||||||
notes = ["The client came into the office at some point", "Who knows if this will happen",
|
|
||||||
"Probably should check this event", "Maybe not happening", "Run away!"]
|
|
||||||
|
|
||||||
itemOptions = [
|
|
||||||
{'name': 'Speakers', 'description': 'Some really really big speakers \n these are very loud', 'quantity': 2,
|
|
||||||
'cost': 200.00},
|
|
||||||
{'name': 'Projector',
|
|
||||||
'description': 'Some kind of video thinamejig, probably with unnecessary processing for free',
|
|
||||||
'quantity': 1, 'cost': 500.00},
|
|
||||||
{'name': 'Lighting Desk', 'description': 'Cannot provide guarentee that it will work', 'quantity': 1,
|
|
||||||
'cost': 200.52},
|
|
||||||
{'name': 'Moving lights', 'description': 'Flashy lights, with the copper', 'quantity': 8, 'cost': 50.00},
|
|
||||||
{'name': 'Microphones', 'description': 'Make loud noise \n you will want speakers with this', 'quantity': 5,
|
|
||||||
'cost': 0.50},
|
|
||||||
{'name': 'Sound Mixer Thing', 'description': 'Might be analogue, might be digital', 'quantity': 1,
|
|
||||||
'cost': 100.00},
|
|
||||||
{'name': 'Electricity', 'description': 'You need this', 'quantity': 1, 'cost': 200.00},
|
|
||||||
{'name': 'Crew', 'description': 'Costs nothing, because reasons', 'quantity': 1, 'cost': 0.00},
|
|
||||||
{'name': 'Loyalty Discount', 'description': 'Have some negative moneys', 'quantity': 1, 'cost': -50.00}]
|
|
||||||
|
|
||||||
dayDelta = -120 # start adding events from 4 months ago
|
|
||||||
|
|
||||||
for i in range(150): # Let's add 100 events
|
|
||||||
with reversion.create_revision():
|
|
||||||
reversion.set_user(random.choice(self.profiles))
|
|
||||||
|
|
||||||
name = names[i % len(names)]
|
|
||||||
|
|
||||||
startDate = datetime.date.today() + datetime.timedelta(days=dayDelta)
|
|
||||||
dayDelta = dayDelta + random.randint(0, 3)
|
|
||||||
|
|
||||||
newEvent = models.Event.objects.create(name=name, start_date=startDate)
|
|
||||||
|
|
||||||
if random.randint(0, 2) > 1: # 1 in 3 have a start time
|
|
||||||
newEvent.start_time = datetime.time(random.randint(15, 20))
|
|
||||||
if random.randint(0, 2) > 1: # of those, 1 in 3 have an end time on the same day
|
|
||||||
newEvent.end_time = datetime.time(random.randint(21, 23))
|
|
||||||
elif random.randint(0, 1) > 0: # half of the others finish early the next day
|
|
||||||
newEvent.end_date = newEvent.start_date + datetime.timedelta(days=1)
|
|
||||||
newEvent.end_time = datetime.time(random.randint(0, 5))
|
|
||||||
elif random.randint(0, 2) > 1: # 1 in 3 of the others finish a few days ahead
|
|
||||||
newEvent.end_date = newEvent.start_date + datetime.timedelta(days=random.randint(1, 4))
|
|
||||||
|
|
||||||
if random.randint(0, 6) > 0: # 5 in 6 have MIC
|
|
||||||
newEvent.mic = random.choice(self.profiles)
|
|
||||||
|
|
||||||
if random.randint(0, 6) > 0: # 5 in 6 have organisation
|
|
||||||
newEvent.organisation = random.choice(self.organisations)
|
|
||||||
|
|
||||||
if random.randint(0, 6) > 0: # 5 in 6 have person
|
|
||||||
newEvent.person = random.choice(self.people)
|
|
||||||
|
|
||||||
if random.randint(0, 6) > 0: # 5 in 6 have venue
|
|
||||||
newEvent.venue = random.choice(self.venues)
|
|
||||||
|
|
||||||
# Could have any status, equally weighted
|
|
||||||
newEvent.status = random.choice(
|
|
||||||
[models.Event.BOOKED, models.Event.CONFIRMED, models.Event.PROVISIONAL, models.Event.CANCELLED])
|
|
||||||
|
|
||||||
newEvent.dry_hire = (random.randint(0, 7) == 0) # 1 in 7 are dry hire
|
|
||||||
|
|
||||||
if random.randint(0, 1) > 0: # 1 in 2 have description
|
|
||||||
newEvent.description = random.choice(descriptions)
|
|
||||||
|
|
||||||
if random.randint(0, 1) > 0: # 1 in 2 have notes
|
|
||||||
newEvent.notes = random.choice(notes)
|
|
||||||
|
|
||||||
newEvent.save()
|
|
||||||
|
|
||||||
# Now add some items
|
|
||||||
for j in range(random.randint(1, 5)):
|
|
||||||
itemData = itemOptions[random.randint(0, len(itemOptions) - 1)]
|
|
||||||
newItem = models.EventItem.objects.create(event=newEvent, order=j, **itemData)
|
|
||||||
newItem.save()
|
|
||||||
|
|
||||||
while newEvent.sum_total < 0:
|
|
||||||
itemData = itemOptions[random.randint(0, len(itemOptions) - 1)]
|
|
||||||
newItem = models.EventItem.objects.create(event=newEvent, order=j, **itemData)
|
|
||||||
newItem.save()
|
|
||||||
|
|
||||||
with reversion.create_revision():
|
|
||||||
reversion.set_user(random.choice(self.profiles))
|
|
||||||
if newEvent.start_date < datetime.date.today(): # think about adding an invoice
|
|
||||||
if random.randint(0, 2) > 0: # 2 in 3 have had paperwork sent to treasury
|
|
||||||
newInvoice = models.Invoice.objects.create(event=newEvent)
|
|
||||||
if newEvent.status is models.Event.CANCELLED: # void cancelled events
|
|
||||||
newInvoice.void = True
|
|
||||||
elif random.randint(0, 2) > 1: # 1 in 3 have been paid
|
|
||||||
models.Payment.objects.create(invoice=newInvoice, amount=newInvoice.balance,
|
|
||||||
date=datetime.date.today())
|
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
import django.core.validators
|
import django.core.validators
|
||||||
import django.utils.timezone
|
import django.utils.timezone
|
||||||
from django.db import models, migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('auth', '0001_initial'),
|
('auth', '0001_initial'),
|
||||||
]
|
]
|
||||||
@@ -18,32 +19,18 @@ class Migration(migrations.Migration):
|
|||||||
('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)),
|
('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)),
|
||||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||||
('last_login', models.DateTimeField(default=django.utils.timezone.now, verbose_name='last login')),
|
('last_login', models.DateTimeField(default=django.utils.timezone.now, verbose_name='last login')),
|
||||||
('is_superuser', models.BooleanField(default=False,
|
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||||
help_text='Designates that this user has all permissions without explicitly assigning them.',
|
('username', models.CharField(max_length=30, unique=True, help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', verbose_name='username', validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username.', 'invalid')])),
|
||||||
verbose_name='superuser status')),
|
|
||||||
('username', models.CharField(max_length=30, unique=True,
|
|
||||||
help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.',
|
|
||||||
verbose_name='username', validators=[
|
|
||||||
django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username.', 'invalid')])),
|
|
||||||
('first_name', models.CharField(max_length=30, blank=True, verbose_name='first name')),
|
('first_name', models.CharField(max_length=30, blank=True, verbose_name='first name')),
|
||||||
('last_name', models.CharField(max_length=30, blank=True, verbose_name='last name')),
|
('last_name', models.CharField(max_length=30, blank=True, verbose_name='last name')),
|
||||||
('email', models.EmailField(max_length=75, blank=True, verbose_name='email address')),
|
('email', models.EmailField(max_length=75, blank=True, verbose_name='email address')),
|
||||||
('is_staff', models.BooleanField(default=False,
|
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||||
help_text='Designates whether the user can log into this admin site.',
|
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||||
verbose_name='staff status')),
|
|
||||||
('is_active', models.BooleanField(default=True,
|
|
||||||
help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.',
|
|
||||||
verbose_name='active')),
|
|
||||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||||
('initials', models.CharField(max_length=5, unique=True)),
|
('initials', models.CharField(max_length=5, unique=True)),
|
||||||
('phone', models.CharField(max_length=13, blank=True, null=True)),
|
('phone', models.CharField(max_length=13, blank=True, null=True)),
|
||||||
('groups', models.ManyToManyField(blank=True,
|
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of his/her group.', verbose_name='groups', related_name='user_set', related_query_name='user', to='auth.Group')),
|
||||||
help_text='The groups this user belongs to. A user will get all permissions granted to each of his/her group.',
|
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', verbose_name='user permissions', related_name='user_set', related_query_name='user', to='auth.Permission')),
|
||||||
verbose_name='groups', related_name='user_set',
|
|
||||||
related_query_name='user', to='auth.Group')),
|
|
||||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.',
|
|
||||||
verbose_name='user permissions', related_name='user_set',
|
|
||||||
related_query_name='user', to='auth.Permission')),
|
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name_plural': 'users',
|
'verbose_name_plural': 'users',
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0001_initial'),
|
('RIGS', '0001_initial'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from django.db import models, migrations
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0002_modelcomment_person'),
|
('RIGS', '0002_modelcomment_person'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
|
|
||||||
import RIGS.models
|
import RIGS.models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0003_auto_20141031_0219'),
|
('RIGS', '0003_auto_20141031_0219'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from django.db import models, migrations
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0004_organisation'),
|
('RIGS', '0004_organisation'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from django.db import models, migrations
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0012_auto_20141106_0253'),
|
('RIGS', '0012_auto_20141106_0253'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from django.db import models, migrations
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0013_auto_20141202_0041'),
|
('RIGS', '0013_auto_20141202_0041'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0014_auto_20141208_0220'),
|
('RIGS', '0014_auto_20141208_0220'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0015_auto_20141208_0233'),
|
('RIGS', '0015_auto_20141208_0233'),
|
||||||
]
|
]
|
||||||
@@ -29,9 +30,7 @@ class Migration(migrations.Migration):
|
|||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
('date', models.DateField()),
|
('date', models.DateField()),
|
||||||
('amount', models.DecimalField(help_text=b'Please use ex. VAT', max_digits=10, decimal_places=2)),
|
('amount', models.DecimalField(help_text=b'Please use ex. VAT', max_digits=10, decimal_places=2)),
|
||||||
('method', models.CharField(max_length=2,
|
('method', models.CharField(max_length=2, choices=[(b'C', b'Cash'), (b'I', b'Internal'), (b'E', b'External'), (b'SU', b'SU Core'), (b'M', b'Members')])),
|
||||||
choices=[(b'C', b'Cash'), (b'I', b'Internal'), (b'E', b'External'),
|
|
||||||
(b'SU', b'SU Core'), (b'M', b'Members')])),
|
|
||||||
('invoice', models.ForeignKey(to='RIGS.Invoice')),
|
('invoice', models.ForeignKey(to='RIGS.Invoice')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
@@ -41,8 +40,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='mic',
|
name='mic',
|
||||||
field=models.ForeignKey(related_name='event_mic', verbose_name=b'MIC', blank=True,
|
field=models.ForeignKey(related_name='event_mic', verbose_name=b'MIC', blank=True, to=settings.AUTH_USER_MODEL, null=True),
|
||||||
to=settings.AUTH_USER_MODEL, null=True),
|
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from django.db import models, migrations
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0018_auto_20150130_0016'),
|
('RIGS', '0018_auto_20150130_0016'),
|
||||||
]
|
]
|
||||||
@@ -13,9 +14,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='payment',
|
model_name='payment',
|
||||||
name='method',
|
name='method',
|
||||||
field=models.CharField(blank=True, max_length=2, null=True,
|
field=models.CharField(blank=True, max_length=2, null=True, choices=[(b'C', b'Cash'), (b'I', b'Internal'), (b'E', b'External'), (b'SU', b'SU Core')]),
|
||||||
choices=[(b'C', b'Cash'), (b'I', b'Internal'), (b'E', b'External'),
|
|
||||||
(b'SU', b'SU Core')]),
|
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from django.db import models, migrations
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0019_auto_20150131_1919'),
|
('RIGS', '0019_auto_20150131_1919'),
|
||||||
]
|
]
|
||||||
@@ -13,9 +14,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='payment',
|
model_name='payment',
|
||||||
name='method',
|
name='method',
|
||||||
field=models.CharField(blank=True, max_length=2, null=True,
|
field=models.CharField(blank=True, max_length=2, null=True, choices=[(b'C', b'Cash'), (b'I', b'Internal'), (b'E', b'External'), (b'SU', b'SU Core'), (b'T', b'TEC Adjustment')]),
|
||||||
choices=[(b'C', b'Cash'), (b'I', b'Internal'), (b'E', b'External'),
|
|
||||||
(b'SU', b'SU Core'), (b'T', b'TEC Adjustment')]),
|
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from django.db import models, migrations
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0020_auto_20150303_0243'),
|
('RIGS', '0020_auto_20150303_0243'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from django.db import models, migrations
|
|||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0021_auto_20150420_1155'),
|
('RIGS', '0021_auto_20150420_1155'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import django.contrib.auth.models
|
|
||||||
import django.core.validators
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
|
import django.core.validators
|
||||||
|
import django.contrib.auth.models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0022_auto_20150424_2104'),
|
('RIGS', '0022_auto_20150424_2104'),
|
||||||
]
|
]
|
||||||
@@ -45,10 +46,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='profile',
|
model_name='profile',
|
||||||
name='groups',
|
name='groups',
|
||||||
field=models.ManyToManyField(related_query_name='user', related_name='user_set', to='auth.Group',
|
field=models.ManyToManyField(related_query_name='user', related_name='user_set', to='auth.Group', blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', verbose_name='groups'),
|
||||||
blank=True,
|
|
||||||
help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.',
|
|
||||||
verbose_name='groups'),
|
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='profile',
|
model_name='profile',
|
||||||
@@ -58,12 +56,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='profile',
|
model_name='profile',
|
||||||
name='username',
|
name='username',
|
||||||
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'},
|
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, max_length=30, validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.', 'invalid')], help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', unique=True, verbose_name='username'),
|
||||||
max_length=30, validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$',
|
|
||||||
'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.',
|
|
||||||
'invalid')],
|
|
||||||
help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.',
|
|
||||||
unique=True, verbose_name='username'),
|
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='venue',
|
model_name='venue',
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0023_auto_20150529_0048'),
|
('RIGS', '0023_auto_20150529_0048'),
|
||||||
]
|
]
|
||||||
@@ -14,7 +15,6 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='based_on',
|
name='based_on',
|
||||||
field=models.ForeignKey(related_name='future_events', on_delete=django.db.models.deletion.SET_NULL,
|
field=models.ForeignKey(related_name='future_events', on_delete=django.db.models.deletion.SET_NULL, blank=True, to='RIGS.Event', null=True),
|
||||||
blank=True, to='RIGS.Event', null=True),
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
225
RIGS/models.py
225
RIGS/models.py
@@ -1,49 +1,39 @@
|
|||||||
import datetime
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import random
|
import datetime, pytz
|
||||||
import string
|
|
||||||
from collections import Counter
|
|
||||||
from decimal import Decimal
|
|
||||||
|
|
||||||
import pytz
|
from django.db import models, connection
|
||||||
import reversion
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.core.exceptions import ValidationError
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse_lazy
|
|
||||||
from django.db import models
|
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
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
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class Profile(AbstractUser):
|
class Profile(AbstractUser):
|
||||||
initials = models.CharField(
|
initials = models.CharField(max_length=5, unique=True, null=True, blank=False)
|
||||||
max_length=5,
|
|
||||||
unique=True,
|
|
||||||
null=True,
|
|
||||||
blank=False)
|
|
||||||
phone = models.CharField(max_length=13, null=True, blank=True)
|
phone = models.CharField(max_length=13, null=True, blank=True)
|
||||||
api_key = models.CharField(
|
api_key = models.CharField(max_length=40,blank=True,editable=False, null=True)
|
||||||
max_length=40,
|
|
||||||
blank=True,
|
|
||||||
editable=False,
|
|
||||||
null=True)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_api_key(cls):
|
def make_api_key(cls):
|
||||||
size = 20
|
size=20
|
||||||
chars = string.ascii_letters + string.digits
|
chars=string.ascii_letters + string.digits
|
||||||
new_api_key = ''.join(random.choice(chars) for x in range(size))
|
new_api_key = ''.join(random.choice(chars) for x in range(size))
|
||||||
return new_api_key
|
return new_api_key;
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def profile_picture(self):
|
def profile_picture(self):
|
||||||
url = ""
|
url = ""
|
||||||
if settings.USE_GRAVATAR or settings.USE_GRAVATAR is None:
|
if settings.USE_GRAVATAR or settings.USE_GRAVATAR is None:
|
||||||
url = "https://www.gravatar.com/avatar/" + \
|
url = "https://www.gravatar.com/avatar/" + hashlib.md5(self.email).hexdigest() + "?d=wavatar&s=500"
|
||||||
hashlib.md5(self.email).hexdigest() + "?d=wavatar&s=500"
|
|
||||||
return url
|
return url
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -55,8 +45,7 @@ class Profile(AbstractUser):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def latest_events(self):
|
def latest_events(self):
|
||||||
return self.event_mic.order_by(
|
return self.event_mic.order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
||||||
'-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
@@ -66,7 +55,6 @@ class Profile(AbstractUser):
|
|||||||
('view_profile', 'Can view Profile'),
|
('view_profile', 'Can view Profile'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RevisionMixin(object):
|
class RevisionMixin(object):
|
||||||
@property
|
@property
|
||||||
def last_edited_at(self):
|
def last_edited_at(self):
|
||||||
@@ -91,11 +79,10 @@ class RevisionMixin(object):
|
|||||||
versions = reversion.get_for_object(self)
|
versions = reversion.get_for_object(self)
|
||||||
if versions:
|
if versions:
|
||||||
version = reversion.get_for_object(self)[0]
|
version = reversion.get_for_object(self)[0]
|
||||||
return "V{0} | R{1}".format(version.pk, version.revision.pk)
|
return "V{0} | R{1}".format(version.pk,version.revision.pk)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class Person(models.Model, RevisionMixin):
|
class Person(models.Model, RevisionMixin):
|
||||||
@@ -110,27 +97,25 @@ class Person(models.Model, RevisionMixin):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
string = self.name
|
string = self.name
|
||||||
if self.notes is not None:
|
if self.notes is not None:
|
||||||
if len(self.notes) > 0:
|
if len(self.notes) > 0:
|
||||||
string += "*"
|
string += "*"
|
||||||
return string
|
return string
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def organisations(self):
|
def organisations(self):
|
||||||
o = []
|
o = []
|
||||||
for e in Event.objects.filter(
|
for e in Event.objects.filter(person=self).select_related('organisation'):
|
||||||
person=self).select_related('organisation'):
|
|
||||||
if e.organisation:
|
if e.organisation:
|
||||||
o.append(e.organisation)
|
o.append(e.organisation)
|
||||||
|
|
||||||
# Count up occurances and put them in descending order
|
#Count up occurances and put them in descending order
|
||||||
c = Counter(o)
|
c = Counter(o)
|
||||||
stats = c.most_common()
|
stats = c.most_common()
|
||||||
return stats
|
return stats
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def latest_events(self):
|
def latest_events(self):
|
||||||
return self.event_set.order_by(
|
return self.event_set.order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
||||||
'-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse_lazy('person_detail', kwargs={'pk': self.pk})
|
return reverse_lazy('person_detail', kwargs={'pk': self.pk})
|
||||||
@@ -156,27 +141,25 @@ class Organisation(models.Model, RevisionMixin):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
string = self.name
|
string = self.name
|
||||||
if self.notes is not None:
|
if self.notes is not None:
|
||||||
if len(self.notes) > 0:
|
if len(self.notes) > 0:
|
||||||
string += "*"
|
string += "*"
|
||||||
return string
|
return string
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def persons(self):
|
def persons(self):
|
||||||
p = []
|
p = []
|
||||||
for e in Event.objects.filter(
|
for e in Event.objects.filter(organisation=self).select_related('person'):
|
||||||
organisation=self).select_related('person'):
|
|
||||||
if e.person:
|
if e.person:
|
||||||
p.append(e.person)
|
p.append(e.person)
|
||||||
|
|
||||||
# Count up occurances and put them in descending order
|
#Count up occurances and put them in descending order
|
||||||
c = Counter(p)
|
c = Counter(p)
|
||||||
stats = c.most_common()
|
stats = c.most_common()
|
||||||
return stats
|
return stats
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def latest_events(self):
|
def latest_events(self):
|
||||||
return self.event_set.order_by(
|
return self.event_set.order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
||||||
'-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse_lazy('organisation_detail', kwargs={'pk': self.pk})
|
return reverse_lazy('organisation_detail', kwargs={'pk': self.pk})
|
||||||
@@ -219,8 +202,7 @@ class VatRate(models.Model, RevisionMixin):
|
|||||||
get_latest_by = 'start_at'
|
get_latest_by = 'start_at'
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.comment + " " + \
|
return self.comment + " " + str(self.start_at) + " @ " + str(self.as_percent) + "%"
|
||||||
str(self.start_at) + " @ " + str(self.as_percent) + "%"
|
|
||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
@@ -242,8 +224,7 @@ class Venue(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def latest_events(self):
|
def latest_events(self):
|
||||||
return self.event_set.order_by(
|
return self.event_set.order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
||||||
'-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse_lazy('venue_detail', kwargs={'pk': self.pk})
|
return reverse_lazy('venue_detail', kwargs={'pk': self.pk})
|
||||||
@@ -257,47 +238,28 @@ class Venue(models.Model, RevisionMixin):
|
|||||||
class EventManager(models.Manager):
|
class EventManager(models.Manager):
|
||||||
def current_events(self):
|
def current_events(self):
|
||||||
events = self.filter(
|
events = self.filter(
|
||||||
(models.Q(start_date__gte=datetime.date.today(), end_date__isnull=True, dry_hire=False) & ~models.Q(
|
(models.Q(start_date__gte=datetime.date.today(), end_date__isnull=True, dry_hire=False) & ~models.Q(status=Event.CANCELLED)) | # Starts after with no end
|
||||||
status=Event.CANCELLED)) | # Starts after with no end
|
(models.Q(end_date__gte=datetime.date.today(), dry_hire=False) & ~models.Q(status=Event.CANCELLED)) | # Ends after
|
||||||
(models.Q(end_date__gte=datetime.date.today(), dry_hire=False) & ~models.Q(
|
(models.Q(dry_hire=True, start_date__gte=datetime.date.today()) & ~models.Q(status=Event.CANCELLED)) | # Active dry hire
|
||||||
status=Event.CANCELLED)) | # Ends after
|
(models.Q(dry_hire=True, checked_in_by__isnull=True) & (models.Q(status=Event.BOOKED) | models.Q(status=Event.CONFIRMED))) | # Active dry hire GT
|
||||||
(models.Q(dry_hire=True, start_date__gte=datetime.date.today()) & ~models.Q(
|
models.Q(status=Event.CANCELLED, start_date__gte=datetime.date.today()) # Canceled but not started
|
||||||
status=Event.CANCELLED)) | # Active dry hire
|
).order_by('start_date', 'end_date', 'start_time', 'end_time', 'meet_at').select_related('person', 'organisation', 'venue', 'mic')
|
||||||
(models.Q(dry_hire=True, checked_in_by__isnull=True) & (
|
|
||||||
models.Q(status=Event.BOOKED) | models.Q(status=Event.CONFIRMED))) | # Active dry hire GT
|
|
||||||
# Canceled but not started
|
|
||||||
models.Q(
|
|
||||||
status=Event.CANCELLED,
|
|
||||||
start_date__gte=datetime.date.today())
|
|
||||||
).order_by('start_date', 'end_date', 'start_time', 'end_time', 'meet_at').select_related('person',
|
|
||||||
'organisation',
|
|
||||||
'venue', 'mic')
|
|
||||||
return events
|
return events
|
||||||
|
|
||||||
def events_in_bounds(self, start, end):
|
def events_in_bounds(self, start, end):
|
||||||
events = self.filter(
|
events = self.filter(
|
||||||
# Start date in bounds
|
(models.Q(start_date__gte=start.date(), start_date__lte=end.date())) | # Start date in bounds
|
||||||
(models.Q(start_date__gte=start.date(), start_date__lte=end.date())) |
|
(models.Q(end_date__gte=start.date(), end_date__lte=end.date())) | # End date in bounds
|
||||||
# End date in bounds
|
(models.Q(access_at__gte=start, access_at__lte=end)) | # Access at in bounds
|
||||||
(models.Q(end_date__gte=start.date(), end_date__lte=end.date())) |
|
(models.Q(meet_at__gte=start, meet_at__lte=end)) | # Meet at in bounds
|
||||||
# Access at in bounds
|
|
||||||
(models.Q(access_at__gte=start, access_at__lte=end)) |
|
|
||||||
(models.Q(meet_at__gte=start, meet_at__lte=end)) | # Meet at in bounds
|
|
||||||
|
|
||||||
# Start before, end after
|
(models.Q(start_date__lte=start, end_date__gte=end)) | # Start before, end after
|
||||||
(models.Q(start_date__lte=start, end_date__gte=end)) |
|
(models.Q(access_at__lte=start, start_date__gte=end)) | # Access before, start after
|
||||||
# Access before, start after
|
(models.Q(access_at__lte=start, end_date__gte=end)) | # Access before, end after
|
||||||
(models.Q(access_at__lte=start, start_date__gte=end)) |
|
(models.Q(meet_at__lte=start, start_date__gte=end)) | # Meet before, start after
|
||||||
# Access before, end after
|
(models.Q(meet_at__lte=start, end_date__gte=end)) # Meet before, end after
|
||||||
(models.Q(access_at__lte=start, end_date__gte=end)) |
|
|
||||||
# Meet before, start after
|
|
||||||
(models.Q(meet_at__lte=start, start_date__gte=end)) |
|
|
||||||
# Meet before, end after
|
|
||||||
(models.Q(meet_at__lte=start, end_date__gte=end))
|
|
||||||
|
|
||||||
).order_by('start_date', 'end_date', 'start_time', 'end_time', 'meet_at').select_related('person',
|
).order_by('start_date', 'end_date', 'start_time', 'end_time', 'meet_at').select_related('person', 'organisation', 'venue', 'mic')
|
||||||
'organisation',
|
|
||||||
'venue', 'mic')
|
|
||||||
return events
|
return events
|
||||||
|
|
||||||
def rig_count(self):
|
def rig_count(self):
|
||||||
@@ -336,13 +298,10 @@ class Event(models.Model, RevisionMixin):
|
|||||||
venue = models.ForeignKey('Venue', blank=True, null=True)
|
venue = models.ForeignKey('Venue', blank=True, null=True)
|
||||||
description = models.TextField(blank=True, null=True)
|
description = models.TextField(blank=True, null=True)
|
||||||
notes = models.TextField(blank=True, null=True)
|
notes = models.TextField(blank=True, null=True)
|
||||||
status = models.IntegerField(
|
status = models.IntegerField(choices=EVENT_STATUS_CHOICES, default=PROVISIONAL)
|
||||||
choices=EVENT_STATUS_CHOICES,
|
|
||||||
default=PROVISIONAL)
|
|
||||||
dry_hire = models.BooleanField(default=False)
|
dry_hire = models.BooleanField(default=False)
|
||||||
is_rig = models.BooleanField(default=True)
|
is_rig = models.BooleanField(default=True)
|
||||||
based_on = models.ForeignKey('Event', on_delete=models.SET_NULL, related_name='future_events', blank=True,
|
based_on = models.ForeignKey('Event', on_delete=models.SET_NULL, related_name='future_events', blank=True, null=True)
|
||||||
null=True)
|
|
||||||
|
|
||||||
# Timing
|
# Timing
|
||||||
start_date = models.DateField()
|
start_date = models.DateField()
|
||||||
@@ -354,33 +313,20 @@ class Event(models.Model, RevisionMixin):
|
|||||||
meet_info = models.CharField(max_length=255, blank=True, null=True)
|
meet_info = models.CharField(max_length=255, blank=True, null=True)
|
||||||
|
|
||||||
# Crew management
|
# Crew management
|
||||||
checked_in_by = models.ForeignKey(
|
checked_in_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='event_checked_in', blank=True, null=True)
|
||||||
settings.AUTH_USER_MODEL,
|
|
||||||
related_name='event_checked_in',
|
|
||||||
blank=True,
|
|
||||||
null=True)
|
|
||||||
mic = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='event_mic', blank=True, null=True,
|
mic = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='event_mic', blank=True, null=True,
|
||||||
verbose_name="MIC")
|
verbose_name="MIC")
|
||||||
|
|
||||||
# Monies
|
# Monies
|
||||||
payment_method = models.CharField(max_length=255, blank=True, null=True)
|
payment_method = models.CharField(max_length=255, blank=True, null=True)
|
||||||
payment_received = models.CharField(max_length=255, blank=True, null=True)
|
payment_received = models.CharField(max_length=255, blank=True, null=True)
|
||||||
purchase_order = models.CharField(
|
purchase_order = models.CharField(max_length=255, blank=True, null=True, verbose_name='PO')
|
||||||
max_length=255,
|
collector = models.CharField(max_length=255, blank=True, null=True, verbose_name='collected by')
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
verbose_name='PO')
|
|
||||||
collector = models.CharField(
|
|
||||||
max_length=255,
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
verbose_name='collected by')
|
|
||||||
|
|
||||||
# Calculated values
|
# Calculated values
|
||||||
"""
|
"""
|
||||||
EX Vat
|
EX Vat
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sum_total(self):
|
def sum_total(self):
|
||||||
# Manual querying is required for efficiency whilst maintaining floating point arithmetic
|
# Manual querying is required for efficiency whilst maintaining floating point arithmetic
|
||||||
@@ -388,15 +334,14 @@ class Event(models.Model, RevisionMixin):
|
|||||||
# sql = "SELECT SUM(quantity * cost) AS sum_total FROM \"RIGS_eventitem\" WHERE event_id=%i" % self.id
|
# sql = "SELECT SUM(quantity * cost) AS sum_total FROM \"RIGS_eventitem\" WHERE event_id=%i" % self.id
|
||||||
# else:
|
# else:
|
||||||
# sql = "SELECT id, SUM(quantity * cost) AS sum_total FROM RIGS_eventitem WHERE event_id=%i" % self.id
|
# sql = "SELECT id, SUM(quantity * cost) AS sum_total FROM RIGS_eventitem WHERE event_id=%i" % self.id
|
||||||
# total = self.items.raw(sql)[0]
|
#total = self.items.raw(sql)[0]
|
||||||
# if total.sum_total:
|
#if total.sum_total:
|
||||||
# return total.sum_total
|
# return total.sum_total
|
||||||
# total = 0.0
|
#total = 0.0
|
||||||
# for item in self.items.filter(cost__gt=0).extra(select="SUM(cost * quantity) AS sum"):
|
#for item in self.items.filter(cost__gt=0).extra(select="SUM(cost * quantity) AS sum"):
|
||||||
# total += item.sum
|
# total += item.sum
|
||||||
total = EventItem.objects.filter(event=self).aggregate(
|
total = EventItem.objects.filter(event=self).aggregate(
|
||||||
sum_total=models.Sum(models.F('cost') * models.F('quantity'),
|
sum_total=models.Sum(models.F('cost')*models.F('quantity'), output_field=models.DecimalField(max_digits=10, decimal_places=2))
|
||||||
output_field=models.DecimalField(max_digits=10, decimal_places=2))
|
|
||||||
)['sum_total']
|
)['sum_total']
|
||||||
if total:
|
if total:
|
||||||
return total
|
return total
|
||||||
@@ -413,7 +358,6 @@ class Event(models.Model, RevisionMixin):
|
|||||||
"""
|
"""
|
||||||
Inc VAT
|
Inc VAT
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def total(self):
|
def total(self):
|
||||||
return self.sum_total + self.vat
|
return self.sum_total + self.vat
|
||||||
@@ -438,7 +382,7 @@ class Event(models.Model, RevisionMixin):
|
|||||||
def earliest_time(self):
|
def earliest_time(self):
|
||||||
"""Finds the earliest time defined in the event - this function could return either a tzaware datetime, or a naiive date object"""
|
"""Finds the earliest time defined in the event - this function could return either a tzaware datetime, or a naiive date object"""
|
||||||
|
|
||||||
# Put all the datetimes in a list
|
#Put all the datetimes in a list
|
||||||
datetime_list = []
|
datetime_list = []
|
||||||
|
|
||||||
if self.access_at:
|
if self.access_at:
|
||||||
@@ -450,25 +394,22 @@ class Event(models.Model, RevisionMixin):
|
|||||||
# If there is no start time defined, pretend it's midnight
|
# If there is no start time defined, pretend it's midnight
|
||||||
startTimeFaked = False
|
startTimeFaked = False
|
||||||
if self.has_start_time:
|
if self.has_start_time:
|
||||||
startDateTime = datetime.datetime.combine(
|
startDateTime = datetime.datetime.combine(self.start_date,self.start_time)
|
||||||
self.start_date, self.start_time)
|
|
||||||
else:
|
else:
|
||||||
startDateTime = datetime.datetime.combine(
|
startDateTime = datetime.datetime.combine(self.start_date,datetime.time(00,00))
|
||||||
self.start_date, datetime.time(00, 00))
|
|
||||||
startTimeFaked = True
|
startTimeFaked = True
|
||||||
|
|
||||||
# timezoneIssues - apply the default timezone to the naiive datetime
|
#timezoneIssues - apply the default timezone to the naiive datetime
|
||||||
tz = pytz.timezone(settings.TIME_ZONE)
|
tz = pytz.timezone(settings.TIME_ZONE)
|
||||||
startDateTime = tz.localize(startDateTime)
|
startDateTime = tz.localize(startDateTime)
|
||||||
datetime_list.append(startDateTime) # then add it to the list
|
datetime_list.append(startDateTime) # then add it to the list
|
||||||
|
|
||||||
# find the earliest datetime in the list
|
earliest = min(datetime_list).astimezone(tz) #find the earliest datetime in the list
|
||||||
earliest = min(datetime_list).astimezone(tz)
|
|
||||||
|
|
||||||
# if we faked it & it's the earliest, better own up
|
# if we faked it & it's the earliest, better own up
|
||||||
if startTimeFaked and earliest == startDateTime:
|
if startTimeFaked and earliest==startDateTime:
|
||||||
return self.start_date
|
return self.start_date
|
||||||
|
|
||||||
return earliest
|
return earliest
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -480,7 +421,7 @@ class Event(models.Model, RevisionMixin):
|
|||||||
endDate = self.start_date
|
endDate = self.start_date
|
||||||
|
|
||||||
if self.has_end_time:
|
if self.has_end_time:
|
||||||
endDateTime = datetime.datetime.combine(endDate, self.end_time)
|
endDateTime = datetime.datetime.combine(endDate,self.end_time)
|
||||||
tz = pytz.timezone(settings.TIME_ZONE)
|
tz = pytz.timezone(settings.TIME_ZONE)
|
||||||
endDateTime = tz.localize(endDateTime)
|
endDateTime = tz.localize(endDateTime)
|
||||||
|
|
||||||
@@ -489,6 +430,7 @@ class Event(models.Model, RevisionMixin):
|
|||||||
else:
|
else:
|
||||||
return endDate
|
return endDate
|
||||||
|
|
||||||
|
|
||||||
objects = EventManager()
|
objects = EventManager()
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
@@ -499,14 +441,12 @@ class Event(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
if self.end_date and self.start_date > self.end_date:
|
if self.end_date and self.start_date > self.end_date:
|
||||||
raise ValidationError(
|
raise ValidationError('Unless you\'ve invented time travel, the event can\'t finish before it has started.')
|
||||||
'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
|
startEndSameDay = not self.end_date or self.end_date == self.start_date
|
||||||
hasStartAndEnd = self.has_start_time and self.has_end_time
|
hasStartAndEnd = self.has_start_time and self.has_end_time
|
||||||
if startEndSameDay and hasStartAndEnd and self.start_time > self.end_time:
|
if startEndSameDay and hasStartAndEnd and self.start_time > self.end_time:
|
||||||
raise ValidationError(
|
raise ValidationError('Unless you\'ve invented time travel, the event can\'t finish before it has started.')
|
||||||
'Unless you\'ve invented time travel, the event can\'t finish before it has started.')
|
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""Call :meth:`full_clean` before saving."""
|
"""Call :meth:`full_clean` before saving."""
|
||||||
@@ -535,8 +475,7 @@ class EventItem(models.Model):
|
|||||||
ordering = ['order']
|
ordering = ['order']
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.event.pk) + "." + str(self.order) + \
|
return str(self.event.pk) + "." + str(self.order) + ": " + self.event.name + " | " + self.name
|
||||||
": " + self.event.name + " | " + self.name
|
|
||||||
|
|
||||||
|
|
||||||
class EventCrew(models.Model):
|
class EventCrew(models.Model):
|
||||||
@@ -564,6 +503,15 @@ class Invoice(models.Model):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def payment_total(self):
|
def payment_total(self):
|
||||||
|
# Manual querying is required for efficiency whilst maintaining floating point arithmetic
|
||||||
|
#if connection.vendor == 'postgresql':
|
||||||
|
# sql = "SELECT SUM(amount) AS total FROM \"RIGS_payment\" WHERE invoice_id=%i" % self.id
|
||||||
|
#else:
|
||||||
|
# sql = "SELECT id, SUM(amount) AS total FROM RIGS_payment WHERE invoice_id=%i" % self.id
|
||||||
|
#total = self.payment_set.raw(sql)[0]
|
||||||
|
#if total.total:
|
||||||
|
# return total.total
|
||||||
|
#return 0.0
|
||||||
total = self.payment_set.aggregate(total=models.Sum('amount'))['total']
|
total = self.payment_set.aggregate(total=models.Sum('amount'))['total']
|
||||||
if total:
|
if total:
|
||||||
return total
|
return total
|
||||||
@@ -573,10 +521,6 @@ class Invoice(models.Model):
|
|||||||
def balance(self):
|
def balance(self):
|
||||||
return self.sum_total - self.payment_total
|
return self.sum_total - self.payment_total
|
||||||
|
|
||||||
@property
|
|
||||||
def is_closed(self):
|
|
||||||
return self.balance == 0 or self.void
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%i: %s (%.2f)" % (self.pk, self.event, self.balance)
|
return "%i: %s (%.2f)" % (self.pk, self.event, self.balance)
|
||||||
|
|
||||||
@@ -604,15 +548,8 @@ class Payment(models.Model):
|
|||||||
|
|
||||||
invoice = models.ForeignKey('Invoice')
|
invoice = models.ForeignKey('Invoice')
|
||||||
date = models.DateField()
|
date = models.DateField()
|
||||||
amount = models.DecimalField(
|
amount = models.DecimalField(max_digits=10, decimal_places=2, help_text='Please use ex. VAT')
|
||||||
max_digits=10,
|
method = models.CharField(max_length=2, choices=METHODS, null=True, blank=True)
|
||||||
decimal_places=2,
|
|
||||||
help_text='Please use ex. VAT')
|
|
||||||
method = models.CharField(
|
|
||||||
max_length=2,
|
|
||||||
choices=METHODS,
|
|
||||||
null=True,
|
|
||||||
blank=True)
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s: %d" % (self.get_method_display(), self.amount)
|
return "%s: %d" % (self.get_method_display(), self.amount)
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
|
from RIGS.models import Profile
|
||||||
from RIGS.forms import ProfileRegistrationFormUniqueEmail
|
from RIGS.forms import ProfileRegistrationFormUniqueEmail
|
||||||
|
|
||||||
|
|
||||||
def user_created(sender, user, request, **kwargs):
|
def user_created(sender, user, request, **kwargs):
|
||||||
form = ProfileRegistrationFormUniqueEmail(request.POST)
|
form = ProfileRegistrationFormUniqueEmail(request.POST)
|
||||||
user.first_name = form.data['first_name']
|
user.first_name = form.data['first_name']
|
||||||
user.last_name = form.data['last_name']
|
user.last_name = form.data['last_name']
|
||||||
user.initials = form.data['initials']
|
user.initials = form.data['initials']
|
||||||
user.phone = form.data['phone']
|
user.phone = form.data['phone']
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
|
|
||||||
from registration.signals import user_registered
|
from registration.signals import user_registered
|
||||||
|
user_registered.connect(user_created)
|
||||||
user_registered.connect(user_created)
|
|
||||||
@@ -1,23 +1,24 @@
|
|||||||
|
import os
|
||||||
import cStringIO as StringIO
|
import cStringIO as StringIO
|
||||||
import copy
|
|
||||||
import datetime
|
|
||||||
import re
|
|
||||||
import urllib2
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
import urllib2
|
||||||
|
|
||||||
from PyPDF2 import PdfFileMerger, PdfFileReader
|
from django.views import generic
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib import messages
|
|
||||||
from django.core.urlresolvers import reverse_lazy
|
from django.core.urlresolvers import reverse_lazy
|
||||||
from django.db.models import Q
|
|
||||||
from django.http import HttpResponse
|
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.views import generic
|
from django.conf import settings
|
||||||
|
from django.http import HttpResponse
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.contrib import messages
|
||||||
from z3c.rml import rml2pdf
|
from z3c.rml import rml2pdf
|
||||||
|
from PyPDF2 import PdfFileMerger, PdfFileReader
|
||||||
|
|
||||||
from RIGS import models, forms
|
from RIGS import models, forms
|
||||||
|
import datetime
|
||||||
|
import re
|
||||||
|
import copy
|
||||||
|
|
||||||
__author__ = 'ghost'
|
__author__ = 'ghost'
|
||||||
|
|
||||||
@@ -33,17 +34,15 @@ class RigboardIndex(generic.TemplateView):
|
|||||||
context['events'] = models.Event.objects.current_events()
|
context['events'] = models.Event.objects.current_events()
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class WebCalendar(generic.TemplateView):
|
class WebCalendar(generic.TemplateView):
|
||||||
template_name = 'RIGS/calendar.html'
|
template_name = 'RIGS/calendar.html'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(WebCalendar, self).get_context_data(**kwargs)
|
context = super(WebCalendar, self).get_context_data(**kwargs)
|
||||||
context['view'] = kwargs.get('view', '')
|
context['view'] = kwargs.get('view','')
|
||||||
context['date'] = kwargs.get('date', '')
|
context['date'] = kwargs.get('date','')
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class EventDetail(generic.DetailView):
|
class EventDetail(generic.DetailView):
|
||||||
model = models.Event
|
model = models.Event
|
||||||
|
|
||||||
@@ -59,12 +58,10 @@ class EventCreate(generic.CreateView):
|
|||||||
|
|
||||||
form = context['form']
|
form = context['form']
|
||||||
if re.search('"-\d+"', form['items_json'].value()):
|
if re.search('"-\d+"', form['items_json'].value()):
|
||||||
messages.info(
|
messages.info(self.request, "Your item changes have been saved. Please fix the errors and save the event.")
|
||||||
self.request,
|
|
||||||
"Your item changes have been saved. Please fix the errors and save the event.")
|
|
||||||
|
|
||||||
# Get some other objects to include in the form. Used when there are
|
# Get some other objects to include in the form. Used when there are errors but also nice and quick.
|
||||||
# errors but also nice and quick.
|
|
||||||
for field, model in form.related_models.iteritems():
|
for field, model in form.related_models.iteritems():
|
||||||
value = form[field].value()
|
value = form[field].value()
|
||||||
if value is not None and value != '':
|
if value is not None and value != '':
|
||||||
@@ -85,8 +82,7 @@ class EventUpdate(generic.UpdateView):
|
|||||||
|
|
||||||
form = context['form']
|
form = context['form']
|
||||||
|
|
||||||
# Get some other objects to include in the form. Used when there are
|
# Get some other objects to include in the form. Used when there are errors but also nice and quick.
|
||||||
# errors but also nice and quick.
|
|
||||||
for field, model in form.related_models.iteritems():
|
for field, model in form.related_models.iteritems():
|
||||||
value = form[field].value()
|
value = form[field].value()
|
||||||
if value is not None and value != '':
|
if value is not None and value != '':
|
||||||
@@ -96,21 +92,16 @@ class EventUpdate(generic.UpdateView):
|
|||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy('event_detail', kwargs={'pk': self.object.pk})
|
return reverse_lazy('event_detail', kwargs={'pk': self.object.pk})
|
||||||
|
|
||||||
|
|
||||||
class EventDuplicate(EventUpdate):
|
class EventDuplicate(EventUpdate):
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
# Get the object (the event you're duplicating)
|
old = super(EventDuplicate, self).get_object(queryset) # Get the object (the event you're duplicating)
|
||||||
old = super(EventDuplicate, self).get_object(queryset)
|
new = copy.copy(old) # Make a copy of the object in memory
|
||||||
new = copy.copy(old) # Make a copy of the object in memory
|
new.based_on = old # Make the new event based on the old event
|
||||||
new.based_on = old # Make the new event based on the old event
|
|
||||||
|
|
||||||
if self.request.method in (
|
if self.request.method in ('POST', 'PUT'): # This only happens on save (otherwise items won't display in editor)
|
||||||
'POST', 'PUT'): # This only happens on save (otherwise items won't display in editor)
|
new.pk = None # This means a new event will be created on save, and all items will be re-created
|
||||||
new.pk = None # This means a new event will be created on save, and all items will be re-created
|
|
||||||
|
|
||||||
messages.info(
|
messages.info(self.request, 'Event data duplicated but not yet saved. Click save to complete operation.')
|
||||||
self.request,
|
|
||||||
'Event data duplicated but not yet saved. Click save to complete operation.')
|
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
@@ -119,7 +110,6 @@ class EventDuplicate(EventUpdate):
|
|||||||
context["duplicate"] = True
|
context["duplicate"] = True
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class EventPrint(generic.View):
|
class EventPrint(generic.View):
|
||||||
def get(self, request, pk):
|
def get(self, request, pk):
|
||||||
object = get_object_or_404(models.Event, pk=pk)
|
object = get_object_or_404(models.Event, pk=pk)
|
||||||
@@ -129,7 +119,8 @@ class EventPrint(generic.View):
|
|||||||
merger = PdfFileMerger()
|
merger = PdfFileMerger()
|
||||||
|
|
||||||
for copy in copies:
|
for copy in copies:
|
||||||
context = RequestContext(request, { # this should be outside the loop, but bug in 1.8.2 prevents this
|
|
||||||
|
context = RequestContext(request, { # this should be outside the loop, but bug in 1.8.2 prevents this
|
||||||
'object': object,
|
'object': object,
|
||||||
'fonts': {
|
'fonts': {
|
||||||
'opensans': {
|
'opensans': {
|
||||||
@@ -137,12 +128,11 @@ class EventPrint(generic.View):
|
|||||||
'bold': 'RIGS/static/fonts/OPENSANS-BOLD.TTF',
|
'bold': 'RIGS/static/fonts/OPENSANS-BOLD.TTF',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'copy': copy,
|
'copy':copy,
|
||||||
'current_user': request.user,
|
'current_user':request.user,
|
||||||
})
|
})
|
||||||
|
|
||||||
# context['copy'] = copy # this is the way to do it once we upgrade
|
# context['copy'] = copy # this is the way to do it once we upgrade to Django 1.8.3
|
||||||
# to Django 1.8.3
|
|
||||||
|
|
||||||
rml = template.render(context)
|
rml = template.render(context)
|
||||||
buffer = StringIO.StringIO()
|
buffer = StringIO.StringIO()
|
||||||
@@ -163,12 +153,10 @@ class EventPrint(generic.View):
|
|||||||
|
|
||||||
escapedEventName = re.sub('[^a-zA-Z0-9 \n\.]', '', object.name)
|
escapedEventName = re.sub('[^a-zA-Z0-9 \n\.]', '', object.name)
|
||||||
|
|
||||||
response[
|
response['Content-Disposition'] = "filename=N%05d | %s.pdf" % (object.pk, escapedEventName)
|
||||||
'Content-Disposition'] = "filename=N%05d | %s.pdf" % (object.pk, escapedEventName)
|
|
||||||
response.write(merged.getvalue())
|
response.write(merged.getvalue())
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
class EventArchive(generic.ArchiveIndexView):
|
class EventArchive(generic.ArchiveIndexView):
|
||||||
model = models.Event
|
model = models.Event
|
||||||
date_field = "start_date"
|
date_field = "start_date"
|
||||||
@@ -202,9 +190,6 @@ class EventArchive(generic.ArchiveIndexView):
|
|||||||
qs.select_related('person', 'organisation', 'venue', 'mic')
|
qs.select_related('person', 'organisation', 'venue', 'mic')
|
||||||
|
|
||||||
if len(qs) == 0:
|
if len(qs) == 0:
|
||||||
messages.add_message(
|
messages.add_message(self.request, messages.WARNING, "No events have been found matching those criteria.")
|
||||||
self.request,
|
|
||||||
messages.WARNING,
|
|
||||||
"No events have been found matching those criteria.")
|
|
||||||
|
|
||||||
return qs
|
return qs
|
||||||
@@ -1,104 +1,104 @@
|
|||||||
$(document).ready(function () {
|
$(document).ready(function() {
|
||||||
clearSelectionLabel = '(no selection)';
|
clearSelectionLabel = '(no selection)';
|
||||||
|
|
||||||
function changeSelectedValue(obj, pk, text, update_url) { //Pass in JQuery object and new parameters
|
function changeSelectedValue(obj,pk,text,update_url) { //Pass in JQuery object and new parameters
|
||||||
//console.log('Changing selected value');
|
//console.log('Changing selected value');
|
||||||
obj.find('option').remove(); //Remove all the available options
|
obj.find('option').remove(); //Remove all the available options
|
||||||
obj.append( //Add the new option
|
obj.append( //Add the new option
|
||||||
$("<option></option>")
|
$("<option></option>")
|
||||||
.attr("value", pk)
|
.attr("value",pk)
|
||||||
.text(text)
|
.text(text)
|
||||||
.data('update_url', update_url)
|
.data('update_url',update_url)
|
||||||
);
|
);
|
||||||
obj.selectpicker('render'); //Re-render the UI
|
obj.selectpicker('render'); //Re-render the UI
|
||||||
obj.selectpicker('refresh'); //Re-render the UI
|
obj.selectpicker('refresh'); //Re-render the UI
|
||||||
obj.selectpicker('val', pk); //Set the new value to be selected
|
obj.selectpicker('val', pk); //Set the new value to be selected
|
||||||
obj.change(); //Trigger the change function manually
|
obj.change(); //Trigger the change function manually
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshUpdateHref(obj) {
|
function refreshUpdateHref(obj) {
|
||||||
//console.log('Refreshing Update URL');
|
//console.log('Refreshing Update URL');
|
||||||
targetObject = $('#' + obj.attr('id') + '-update');
|
targetObject = $('#'+obj.attr('id')+'-update');
|
||||||
update_url = $('option:selected', obj).data('update_url');
|
update_url = $('option:selected', obj).data('update_url');
|
||||||
|
|
||||||
if (update_url == "") { //Probably "clear selection" has been chosen
|
if (update_url=="") { //Probably "clear selection" has been chosen
|
||||||
// console.log('Trying to disable');
|
// console.log('Trying to disable');
|
||||||
targetObject.attr('disabled', true);
|
targetObject.attr('disabled', true);
|
||||||
} else {
|
} else {
|
||||||
targetObject.attr('href', update_url);
|
targetObject.attr('href', update_url);
|
||||||
targetObject.attr('disabled', false);
|
targetObject.attr('disabled', false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$(".selectpicker").each(function () {
|
$(".selectpicker").each(function() {
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
ajax: {
|
||||||
|
url: $(this).data('sourceurl'),
|
||||||
|
type: 'GET',
|
||||||
|
dataType: 'json',
|
||||||
|
// Use "{{{q}}}" as a placeholder and Ajax Bootstrap Select will
|
||||||
|
// automatically replace it with the value of the search query.
|
||||||
|
data: {
|
||||||
|
term: '{{{q}}}'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
locale: {
|
||||||
|
emptyTitle: ''
|
||||||
|
},
|
||||||
|
clearOnEmpty:false,
|
||||||
|
//log: 3,
|
||||||
|
preprocessData: function (data) {
|
||||||
|
var i, l = data.length, array = [];
|
||||||
|
array.push({
|
||||||
|
text: clearSelectionLabel,
|
||||||
|
value: '',
|
||||||
|
data:{
|
||||||
|
update_url: '',
|
||||||
|
subtext:''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var options = {
|
if (l) {
|
||||||
ajax: {
|
for(i = 0; i < l; i++){
|
||||||
url: $(this).data('sourceurl'),
|
array.push($.extend(true, data[i], {
|
||||||
type: 'GET',
|
text: data[i]['label'],
|
||||||
dataType: 'json',
|
value: data[i]['pk'],
|
||||||
// Use "{{{q}}}" as a placeholder and Ajax Bootstrap Select will
|
data:{
|
||||||
// automatically replace it with the value of the search query.
|
update_url: data[i]['update'],
|
||||||
data: {
|
subtext:''
|
||||||
term: '{{{q}}}'
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
locale: {
|
|
||||||
emptyTitle: ''
|
|
||||||
},
|
|
||||||
clearOnEmpty: false,
|
|
||||||
//log: 3,
|
|
||||||
preprocessData: function (data) {
|
|
||||||
var i, l = data.length, array = [];
|
|
||||||
array.push({
|
|
||||||
text: clearSelectionLabel,
|
|
||||||
value: '',
|
|
||||||
data: {
|
|
||||||
update_url: '',
|
|
||||||
subtext: ''
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (l) {
|
|
||||||
for (i = 0; i < l; i++) {
|
|
||||||
array.push($.extend(true, data[i], {
|
|
||||||
text: data[i]['label'],
|
|
||||||
value: data[i]['pk'],
|
|
||||||
data: {
|
|
||||||
update_url: data[i]['update'],
|
|
||||||
subtext: ''
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$(this).prepend($("<option></option>")
|
$(this).prepend($("<option></option>")
|
||||||
.attr("value", '')
|
.attr("value",'')
|
||||||
.text(clearSelectionLabel)
|
.text(clearSelectionLabel)
|
||||||
.data('update_url', '')); //Add "clear selection" option
|
.data('update_url','')); //Add "clear selection" option
|
||||||
|
|
||||||
|
|
||||||
|
$(this).selectpicker().ajaxSelectPicker(options); //Initiaise selectPicker
|
||||||
|
|
||||||
$(this).selectpicker().ajaxSelectPicker(options); //Initiaise selectPicker
|
$(this).change(function(){ //on change, update the edit button href
|
||||||
|
// console.log('Selectbox Changed');
|
||||||
|
refreshUpdateHref($(this));
|
||||||
|
});
|
||||||
|
|
||||||
$(this).change(function () { //on change, update the edit button href
|
refreshUpdateHref($(this)); //Ensure href is correct at the beginning
|
||||||
// console.log('Selectbox Changed');
|
|
||||||
refreshUpdateHref($(this));
|
|
||||||
});
|
|
||||||
|
|
||||||
refreshUpdateHref($(this)); //Ensure href is correct at the beginning
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
//When update/edit modal box submitted
|
|
||||||
$('#modal').on('hide.bs.modal', function (e) {
|
|
||||||
if (modaltarget != undefined && modalobject != "") {
|
|
||||||
//Update the selector with new values
|
|
||||||
changeSelectedValue($(modaltarget), modalobject[0]['pk'], modalobject[0]['fields']['name'], modalobject[0]['update_url']);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//When update/edit modal box submitted
|
||||||
|
$('#modal').on('hide.bs.modal', function (e) {
|
||||||
|
if (modaltarget != undefined && modalobject != "") {
|
||||||
|
//Update the selector with new values
|
||||||
|
changeSelectedValue($(modaltarget),modalobject[0]['pk'],modalobject[0]['fields']['name'],modalobject[0]['update_url']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@@ -1,139 +1,139 @@
|
|||||||
function setupItemTable(items_json) {
|
function setupItemTable(items_json) {
|
||||||
objectitems = JSON.parse(items_json);
|
objectitems = JSON.parse(items_json)
|
||||||
$.each(objectitems, function (key, val) {
|
$.each(objectitems, function (key, val) {
|
||||||
objectitems[key] = JSON.parse(val);
|
objectitems[key] = JSON.parse(val);
|
||||||
});
|
})
|
||||||
newitem = -1;
|
newitem = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function nl2br(str, is_xhtml) {
|
function nl2br (str, is_xhtml) {
|
||||||
var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '<br />' : '<br>';
|
var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '<br />' : '<br>';
|
||||||
return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2');
|
return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1'+ breakTag +'$2');
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeHtml(str) {
|
function escapeHtml (str) {
|
||||||
return $('<div/>').text(str).html();
|
return $('<div/>').text(str).html();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePrices() {
|
function updatePrices() {
|
||||||
// individual rows
|
// individual rows
|
||||||
var sum = 0;
|
var sum = 0;
|
||||||
for (var pk in objectitems) {
|
for (var pk in objectitems) {
|
||||||
var fields = objectitems[pk].fields;
|
var fields = objectitems[pk].fields;
|
||||||
var sub = fields.cost * fields.quantity;
|
var sub = fields.cost * fields.quantity;
|
||||||
$('#item-' + pk + ' .sub-total').html(parseFloat(sub).toFixed(2)).data('subtotal', sub);
|
$('#item-' + pk + ' .sub-total').html(parseFloat(sub).toFixed(2)).data('subtotal', sub);
|
||||||
|
|
||||||
sum += Number(sub);
|
sum += Number(sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#sumtotal').text(parseFloat(sum).toFixed(2));
|
$('#sumtotal').text(parseFloat(sum).toFixed(2));
|
||||||
var vat = sum * Number($('#vat-rate').data('rate'));
|
var vat = sum * Number($('#vat-rate').data('rate'));
|
||||||
$('#vat').text(parseFloat(vat).toFixed(2));
|
$('#vat').text(parseFloat(vat).toFixed(2));
|
||||||
$('#total').text(parseFloat(sum + vat).toFixed(2));
|
$('#total').text(parseFloat(sum + vat).toFixed(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#item-table').on('click', '.item-delete', function () {
|
$('#item-table').on('click', '.item-delete', function () {
|
||||||
delete objectitems[$(this).data('pk')];
|
delete objectitems[$(this).data('pk')]
|
||||||
$('#item-' + $(this).data('pk')).remove();
|
$('#item-' + $(this).data('pk')).remove();
|
||||||
updatePrices();
|
updatePrices();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#item-table').on('click', '.item-add', function () {
|
$('#item-table').on('click', '.item-add', function () {
|
||||||
$('#item-form').data('pk', newitem);
|
$('#item-form').data('pk', newitem);
|
||||||
|
|
||||||
// Set the form values
|
// Set the form values
|
||||||
$('#item_name').val('');
|
$('#item_name').val('');
|
||||||
$('#item_description').val('');
|
$('#item_description').val('');
|
||||||
$('#item_quantity').val('');
|
$('#item_quantity').val('');
|
||||||
$('#item_cost').val('');
|
$('#item_cost').val('');
|
||||||
|
|
||||||
$($(this).data('target')).modal('show');
|
$($(this).data('target')).modal('show');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#item-table').on('click', '.item-edit', function () {
|
$('#item-table').on('click', '.item-edit', function () {
|
||||||
// set the pk as we will need this later
|
// set the pk as we will need this later
|
||||||
var pk = $(this).data('pk');
|
var pk = $(this).data('pk');
|
||||||
$('#item-form').data('pk', pk);
|
$('#item-form').data('pk', pk);
|
||||||
|
|
||||||
// Set the form values
|
// Set the form values
|
||||||
var fields = objectitems[pk].fields;
|
var fields = objectitems[pk].fields;
|
||||||
$('#item_name').val(fields.name);
|
$('#item_name').val(fields.name);
|
||||||
$('#item_description').val(fields.description);
|
$('#item_description').val(fields.description);
|
||||||
$('#item_quantity').val(fields.quantity);
|
$('#item_quantity').val(fields.quantity);
|
||||||
$('#item_cost').val(fields.cost);
|
$('#item_cost').val(fields.cost);
|
||||||
|
|
||||||
$($(this).data('target')).modal('show');
|
$($(this).data('target')).modal('show');
|
||||||
});
|
});
|
||||||
|
|
||||||
$('body').on('submit', '#item-form', function (e) {
|
$('body').on('submit', '#item-form', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var pk = $(this).data('pk');
|
var pk = $(this).data('pk');
|
||||||
$('#itemModal').modal('hide');
|
$('#itemModal').modal('hide');
|
||||||
|
|
||||||
var fields;
|
var fields;
|
||||||
if (pk == newitem--) {
|
if (pk == newitem--) {
|
||||||
// Create the new data structure and add it on.
|
// Create the new data structure and add it on.
|
||||||
fields = {};
|
fields = new Object();
|
||||||
fields['name'] = $('#item_name').val();
|
fields['name'] = $('#item_name').val()
|
||||||
fields['description'] = $('#item_description').val();
|
fields['description'] = $('#item_description').val();
|
||||||
fields['cost'] = $('#item_cost').val();
|
fields['cost'] = $('#item_cost').val();
|
||||||
fields['quantity'] = $('#item_quantity').val();
|
fields['quantity'] = $('#item_quantity').val();
|
||||||
|
|
||||||
|
var order = 0;
|
||||||
|
for (item in objectitems) {
|
||||||
|
order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fields['order'] = order;
|
||||||
|
|
||||||
|
objectitems[pk] = new Object();
|
||||||
|
objectitems[pk]['fields'] = fields;
|
||||||
|
|
||||||
|
// Add the new table
|
||||||
|
$('#new-item-row').clone().attr('id', 'item-' + pk).data('pk', pk).appendTo('#item-table-body');
|
||||||
|
$('#item-'+pk+' .item-delete, #item-'+pk+' .item-edit').data('pk', pk)
|
||||||
|
} else {
|
||||||
|
// Existing item
|
||||||
|
// update data structure
|
||||||
|
fields = objectitems[pk].fields;
|
||||||
|
fields.name = $('#item_name').val()
|
||||||
|
fields.description = $('#item_description').val();
|
||||||
|
fields.cost = $('#item_cost').val();
|
||||||
|
fields.quantity = $('#item_quantity').val();
|
||||||
|
objectitems[pk].fields = fields;
|
||||||
|
|
||||||
var order = 0;
|
|
||||||
for (item in objectitems) {
|
|
||||||
order++;
|
|
||||||
}
|
}
|
||||||
|
// update the table
|
||||||
|
$row = $('#item-' + pk);
|
||||||
|
$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);
|
||||||
|
|
||||||
fields['order'] = order;
|
updatePrices();
|
||||||
|
|
||||||
objectitems[pk] = {};
|
|
||||||
objectitems[pk]['fields'] = fields;
|
|
||||||
|
|
||||||
// Add the new table
|
|
||||||
$('#new-item-row').clone().attr('id', 'item-' + pk).data('pk', pk).appendTo('#item-table-body');
|
|
||||||
$('#item-' + pk + ' .item-delete, #item-' + pk + ' .item-edit').data('pk', pk)
|
|
||||||
} else {
|
|
||||||
// Existing item
|
|
||||||
// update data structure
|
|
||||||
fields = objectitems[pk].fields;
|
|
||||||
fields.name = $('#item_name').val();
|
|
||||||
fields.description = $('#item_description').val();
|
|
||||||
fields.cost = $('#item_cost').val();
|
|
||||||
fields.quantity = $('#item_quantity').val();
|
|
||||||
objectitems[pk].fields = fields;
|
|
||||||
|
|
||||||
}
|
|
||||||
// update the table
|
|
||||||
$row = $('#item-' + pk);
|
|
||||||
$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);
|
|
||||||
|
|
||||||
updatePrices();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$('body').on('submit', '.itemised_form', function (e) {
|
$('body').on('submit', '.itemised_form', function (e) {
|
||||||
$('#id_items_json').val(JSON.stringify(objectitems));
|
$('#id_items_json').val(JSON.stringify(objectitems));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Return a helper with preserved width of cells
|
// Return a helper with preserved width of cells
|
||||||
var fixHelper = function (e, ui) {
|
var fixHelper = function (e, ui) {
|
||||||
ui.children().each(function () {
|
ui.children().each(function () {
|
||||||
$(this).width($(this).width());
|
$(this).width($(this).width());
|
||||||
});
|
});
|
||||||
return ui;
|
return ui;
|
||||||
};
|
};
|
||||||
|
|
||||||
$("#item-table tbody").sortable({
|
$("#item-table tbody").sortable({
|
||||||
helper: fixHelper,
|
helper: fixHelper,
|
||||||
update: function (e, ui) {
|
update: function (e, ui) {
|
||||||
info = $(this).sortable("toArray");
|
info = $(this).sortable("toArray");
|
||||||
itemorder = [];
|
itemorder = new Array();
|
||||||
$.each(info, function (key, value) {
|
$.each(info, function (key, value) {
|
||||||
pk = $('#' + value).data('pk');
|
pk = $('#' + value).data('pk');
|
||||||
objectitems[pk].fields.order = key;
|
objectitems[pk].fields.order = key;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@
|
|||||||
@import "jq-ui-bootstrap/_autocomplete";
|
@import "jq-ui-bootstrap/_autocomplete";
|
||||||
@import "jq-ui-bootstrap/_menu";
|
@import "jq-ui-bootstrap/_menu";
|
||||||
@import "jq-ui-bootstrap/_tooltip";
|
@import "jq-ui-bootstrap/_tooltip";
|
||||||
|
|
||||||
@import "compass/css3/animation";
|
@import "compass/css3/animation";
|
||||||
@import "compass/css3/transform";
|
@import "compass/css3/transform";
|
||||||
|
|
||||||
@@ -89,62 +90,60 @@ ins {
|
|||||||
margin: 30px auto 0;
|
margin: 30px auto 0;
|
||||||
|
|
||||||
.circle {
|
.circle {
|
||||||
background-color: rgba(0, 0, 0, 0);
|
background-color: rgba(0,0,0,0);
|
||||||
border: 5px solid rgba(0, 183, 229, 0.9);
|
border: 5px solid rgba(0,183,229,0.9);
|
||||||
opacity: .9;
|
opacity: .9;
|
||||||
border-right: 5px solid rgba(0, 0, 0, 0);
|
border-right: 5px solid rgba(0,0,0,0);
|
||||||
border-left: 5px solid rgba(0, 0, 0, 0);
|
border-left: 5px solid rgba(0,0,0,0);
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
box-shadow: 0 0 35px #2187e7;
|
box-shadow: 0 0 35px #2187e7;
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
@include animation(spinPulse 1s infinite ease-in-out);
|
@include animation(spinPulse 1s infinite ease-in-out);
|
||||||
}
|
}
|
||||||
|
|
||||||
.circle1 {
|
.circle1 {
|
||||||
background-color: rgba(0, 0, 0, 0);
|
background-color: rgba(0,0,0,0);
|
||||||
border: 5px solid rgba(0, 183, 229, 0.9);
|
border: 5px solid rgba(0,183,229,0.9);
|
||||||
opacity: .9;
|
opacity: .9;
|
||||||
border-left: 5px solid rgba(0, 0, 0, 0);
|
border-left: 5px solid rgba(0,0,0,0);
|
||||||
border-right: 5px solid rgba(0, 0, 0, 0);
|
border-right: 5px solid rgba(0,0,0,0);
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
box-shadow: 0 0 15px #2187e7;
|
box-shadow: 0 0 15px #2187e7;
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -40px;
|
top: -40px;
|
||||||
@include animation(spinoffPulse 1s infinite linear);
|
@include animation(spinoffPulse 1s infinite linear);
|
||||||
}
|
}
|
||||||
|
|
||||||
@include keyframes(spinPulse) {
|
@include keyframes(spinPulse) {
|
||||||
0% {
|
0% {
|
||||||
@include rotate(160deg);
|
@include rotate(160deg);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
box-shadow: 0 0 1px #2187e7;
|
box-shadow: 0 0 1px #2187e7;
|
||||||
}
|
}
|
||||||
|
|
||||||
50% {
|
50% {
|
||||||
@include rotate(145deg);
|
@include rotate(145deg);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
@include rotate(-320deg);
|
@include rotate(-320deg);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
};
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@include keyframes(spinoffPulse) {
|
@include keyframes(spinoffPulse) {
|
||||||
0% {
|
0% {
|
||||||
@include rotate(0deg);
|
@include rotate(0deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
@include rotate(360deg);
|
@include rotate(360deg);
|
||||||
}
|
};
|
||||||
;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +1,66 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
<script src="{% static "js/tooltip.js" %}"></script>
|
<script src="{% static "js/tooltip.js" %}"></script>
|
||||||
<script src="{% static "js/popover.js" %}"></script>
|
<script src="{% static "js/popover.js" %}"></script>
|
||||||
<script src="{% static "js/moment.min.js" %}"></script>
|
<script src="{% static "js/moment.min.js" %}"></script>
|
||||||
<script src="{% static "js/moment-twitter.js" %}"></script>
|
<script src="{% static "js/moment-twitter.js" %}"></script>
|
||||||
<script>
|
<script>
|
||||||
$(function () {
|
$(function () {
|
||||||
$('[data-toggle="popover"]').popover().click(function () {
|
$('[data-toggle="popover"]').popover().click(function(){
|
||||||
if ($(this).attr('href')) {
|
if($(this).attr('href')){
|
||||||
window.location.href = $(this).attr('href');
|
window.location.href = $(this).attr('href');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// This keeps timeago values correct, but uses an insane amount of resources
|
// This keeps timeago values correct, but uses an insane amount of resources
|
||||||
// $(function () {
|
// $(function () {
|
||||||
// setInterval(function() {
|
// setInterval(function() {
|
||||||
// $('.date').each(function (index, dateElem) {
|
// $('.date').each(function (index, dateElem) {
|
||||||
// var $dateElem = $(dateElem);
|
// var $dateElem = $(dateElem);
|
||||||
// var formatted = moment($dateElem.attr('data-date')).fromNow();
|
// var formatted = moment($dateElem.attr('data-date')).fromNow();
|
||||||
// $dateElem.text(formatted);
|
// $dateElem.text(formatted);
|
||||||
// })
|
// })
|
||||||
// });
|
// });
|
||||||
// }, 10000);
|
// }, 10000);
|
||||||
moment().twitter();
|
moment().twitter();
|
||||||
|
|
||||||
|
})
|
||||||
|
$(document).ready(function() {
|
||||||
|
$(function () {
|
||||||
|
$( "#activity" ).hide();
|
||||||
|
$( "#activity" ).load( "{% url 'activity_feed' %}", function() {
|
||||||
|
$('#activity_loading').slideUp('slow',function(){
|
||||||
|
$('#activity').slideDown('slow');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#activity [data-toggle="popover"]').popover();
|
||||||
|
|
||||||
|
$('.date').each(function (index, dateElem) {
|
||||||
|
var $dateElem = $(dateElem);
|
||||||
|
var formatted = moment($dateElem.attr('data-date')).twitterLong();
|
||||||
|
$dateElem.text(formatted);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
$(document).ready(function () {
|
});
|
||||||
$(function () {
|
});
|
||||||
$("#activity").hide();
|
</script>
|
||||||
$("#activity").load("{% url 'activity_feed' %}", function () {
|
|
||||||
$('#activity_loading').slideUp('slow', function () {
|
|
||||||
$('#activity').slideDown('slow');
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#activity [data-toggle="popover"]').popover();
|
|
||||||
|
|
||||||
$('.date').each(function (index, dateElem) {
|
|
||||||
var $dateElem = $(dateElem);
|
|
||||||
var formatted = moment($dateElem.attr('data-date')).twitterLong();
|
|
||||||
$dateElem.text(formatted);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h4 class="panel-title">Recent Changes</h4>
|
<h4 class="panel-title">Recent Changes</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
<div id="activity_loading" class="list-group-item loading-animation">
|
<div id="activity_loading" class="list-group-item loading-animation">
|
||||||
<div class="circle"></div>
|
<div class="circle"></div>
|
||||||
<div class="circle1"></div>
|
<div class="circle1"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="activity">
|
<div id="activity">
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,52 +5,50 @@
|
|||||||
{% load to_class_name from filters %}
|
{% load to_class_name from filters %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="list-group-item">
|
<div class="list-group-item">
|
||||||
<div class="media">
|
<div class="media">
|
||||||
{% for version in object_list %}
|
{% for version in object_list %}
|
||||||
|
|
||||||
{% if not version.withPrevious %}
|
{% if not version.withPrevious %}
|
||||||
{% if not forloop.first %}
|
{% if not forloop.first %}
|
||||||
</div> {#/.media-body#}
|
</div> {#/.media-body#}
|
||||||
</div> {#/.media#}
|
</div> {#/.media#}
|
||||||
</div>
|
</div>
|
||||||
<div class="list-group-item">
|
<div class="list-group-item">
|
||||||
<div class="media">
|
<div class="media">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="media-left">
|
<div class="media-left">
|
||||||
{% if version.revision.user %}
|
{% if version.revision.user %}
|
||||||
<a href="{% url 'profile_detail' pk=version.revision.user.pk %}" class="modal-href">
|
<a href="{% url 'profile_detail' pk=version.revision.user.pk %}" class="modal-href">
|
||||||
<img class="media-object img-rounded"
|
<img class="media-object img-rounded" src="{{ version.revision.user.profile_picture}}" />
|
||||||
src="{{ version.revision.user.profile_picture }}"/>
|
</a>
|
||||||
</a>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="media-body">
|
<div class="media-body">
|
||||||
<h5>{{ version.revision.user.name }}
|
<h5>{{ version.revision.user.name }}
|
||||||
<span class="pull-right"><small><span class="date"
|
<span class="pull-right"><small><span class="date" data-date="{{version.revision.date_created|date:"c"}}"></span></small></span>
|
||||||
data-date="{{ version.revision.date_created|date:"c" }}"></span></small></span>
|
</h5>
|
||||||
</h5>
|
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>
|
<p>
|
||||||
<small>
|
<small>
|
||||||
{% if version.old == None %}
|
{% if version.old == None %}
|
||||||
Created
|
Created
|
||||||
{% else %}
|
{% else %}
|
||||||
Changed {% include 'RIGS/version_changes.html' %} in
|
Changed {% include 'RIGS/version_changes.html' %} in
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% include 'RIGS/object_button.html' with object=version.new %}
|
{% include 'RIGS/object_button.html' with object=version.new %}
|
||||||
{% if version.revision.comment %}
|
{% if version.revision.comment %}
|
||||||
({{ version.revision.comment }})
|
({{ version.revision.comment }})
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</small>
|
</small>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -10,39 +10,39 @@
|
|||||||
<script src="{% static "js/popover.js" %}"></script>
|
<script src="{% static "js/popover.js" %}"></script>
|
||||||
<script src="{% static "js/moment.min.js" %}"></script>
|
<script src="{% static "js/moment.min.js" %}"></script>
|
||||||
<script>
|
<script>
|
||||||
$(function () {
|
$(function () {
|
||||||
$('[data-toggle="popover"]').popover().click(function () {
|
$('[data-toggle="popover"]').popover().click(function(){
|
||||||
if ($(this).attr('href')) {
|
if($(this).attr('href')){
|
||||||
window.location.href = $(this).attr('href');
|
window.location.href = $(this).attr('href');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// This keeps timeago values correct, but uses an insane amount of resources
|
// This keeps timeago values correct, but uses an insane amount of resources
|
||||||
// $(function () {
|
// $(function () {
|
||||||
// setInterval(function() {
|
// setInterval(function() {
|
||||||
// $('.date').each(function (index, dateElem) {
|
// $('.date').each(function (index, dateElem) {
|
||||||
// var $dateElem = $(dateElem);
|
// var $dateElem = $(dateElem);
|
||||||
// var formatted = moment($dateElem.attr('data-date')).fromNow();
|
// var formatted = moment($dateElem.attr('data-date')).fromNow();
|
||||||
// $dateElem.text(formatted);
|
// $dateElem.text(formatted);
|
||||||
// })
|
// })
|
||||||
// });
|
// });
|
||||||
// }, 10000);
|
// }, 10000);
|
||||||
|
|
||||||
|
|
||||||
$('.date').each(function (index, dateElem) {
|
$('.date').each(function (index, dateElem) {
|
||||||
var $dateElem = $(dateElem);
|
var $dateElem = $(dateElem);
|
||||||
var formatted = moment($dateElem.attr('data-date')).fromNow();
|
var formatted = moment($dateElem.attr('data-date')).fromNow();
|
||||||
$dateElem.text(formatted);
|
$dateElem.text(formatted);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<h3>Rigboard Activity Stream</h3>
|
<h3>Rigboard Activity Stream</h3>
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
|
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Date</td>
|
<td>Date</td>
|
||||||
@@ -63,25 +63,23 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for version in object_list %}
|
{% for version in object_list %}
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ version.revision.date_created }}</td>
|
<td>{{ version.revision.date_created }}</td>
|
||||||
<td>
|
<td><a href="{{ version.new.get_absolute_url }}">{{version.new|to_class_name}} {{ version.new.pk|stringformat:"05d" }}</a></td>
|
||||||
<a href="{{ version.new.get_absolute_url }}">{{ version.new|to_class_name }} {{ version.new.pk|stringformat:"05d" }}</a>
|
<td>{{ version.version.pk }}|{{ version.revision.pk }}</td>
|
||||||
</td>
|
<td>{{ version.revision.user.name }}</td>
|
||||||
<td>{{ version.version.pk }}|{{ version.revision.pk }}</td>
|
<td>
|
||||||
<td>{{ version.revision.user.name }}</td>
|
{% if version.old == None %}
|
||||||
<td>
|
{{version.new|to_class_name}} Created
|
||||||
{% if version.old == None %}
|
{% else %}
|
||||||
{{ version.new|to_class_name }} Created
|
{% include 'RIGS/version_changes.html' %}
|
||||||
{% else %}
|
{% endif %} </td>
|
||||||
{% include 'RIGS/version_changes.html' %}
|
<td>{{ version.revision.comment }}</td>
|
||||||
{% endif %} </td>
|
</tr>
|
||||||
<td>{{ version.revision.comment }}</td>
|
|
||||||
</tr>
|
{% endfor %}
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -89,4 +87,4 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="align-right">{% paginator %}</div>
|
<div class="align-right">{% paginator %}</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -2,40 +2,39 @@
|
|||||||
{% load i18n l10n %}
|
{% load i18n l10n %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<form action="" method="post">{% csrf_token %}
|
<form action="" method="post">{% csrf_token %}
|
||||||
<p>The following objects will be merged. Please select the 'master' record which you would like to keep. Other
|
<p>The following objects will be merged. Please select the 'master' record which you would like to keep. Other records will have associated events moved to the 'master' copy, and then will be deleted.</p>
|
||||||
records will have associated events moved to the 'master' copy, and then will be deleted.</p>
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
{% for form in forms %}
|
{% for form in forms %}
|
||||||
{% if forloop.first %}
|
{% if forloop.first %}
|
||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th> ID</th>
|
<th> ID </th>
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
<th>{{ field.label }}</th>
|
<th>{{ field.label }}</th>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><input type="radio" name="master" value="{{ form.instance.pk|unlocalize }}"></td>
|
<td><input type="radio" name="master" value="{{form.instance.pk|unlocalize}}"></td>
|
||||||
<td>{{ form.instance.pk }}</td>
|
<td>{{form.instance.pk}}</td>
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
<td> {{ field.value }} </td>
|
<td> {{ field.value }} </td>
|
||||||
{% endfor %}
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{% for obj in queryset %}
|
{% for obj in queryset %}
|
||||||
<input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}"/>
|
<input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}" />
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<input type="hidden" name="action" value="merge"/>
|
<input type="hidden" name="action" value="merge" />
|
||||||
<input type="hidden" name="post" value="yes"/>
|
<input type="hidden" name="post" value="yes" />
|
||||||
<input type="submit" value="Merge them"/>
|
<input type="submit" value="Merge them" />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
{% block title %}Calendar{% endblock %}
|
{% block title %}Calendar{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
<link href="{% static "css/fullcalendar.css" %}" rel='stylesheet'/>
|
<link href="{% static "css/fullcalendar.css" %}" rel='stylesheet' />
|
||||||
<link href="{% static "css/fullcalendar.print.css" %}" rel='stylesheet' media='print'/>
|
<link href="{% static "css/fullcalendar.print.css" %}" rel='stylesheet' media='print' />
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
@@ -17,24 +17,24 @@
|
|||||||
|
|
||||||
function getUrlVars() {
|
function getUrlVars() {
|
||||||
var vars = {};
|
var vars = {};
|
||||||
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) {
|
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
|
||||||
vars[key] = value;
|
vars[key] = value;
|
||||||
});
|
});
|
||||||
return vars;
|
return vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function() {
|
||||||
|
|
||||||
viewToUrl = {
|
viewToUrl = {
|
||||||
'agendaWeek': 'week',
|
'agendaWeek':'week',
|
||||||
'agendaDay': 'day',
|
'agendaDay':'day',
|
||||||
'month': 'month'
|
'month':'month'
|
||||||
};
|
}
|
||||||
viewFromUrl = {
|
viewFromUrl = {
|
||||||
'week': 'agendaWeek',
|
'week':'agendaWeek',
|
||||||
'day': 'agendaDay',
|
'day':'agendaDay',
|
||||||
'month': 'month'
|
'month':'month'
|
||||||
};
|
}
|
||||||
|
|
||||||
$('#calendar').fullCalendar({
|
$('#calendar').fullCalendar({
|
||||||
editable: false,
|
editable: false,
|
||||||
@@ -50,16 +50,16 @@
|
|||||||
// options apply to agendaWeek and agendaDay views
|
// options apply to agendaWeek and agendaDay views
|
||||||
},
|
},
|
||||||
week: {
|
week: {
|
||||||
columnFormat: 'ddd D/M'
|
columnFormat:'ddd D/M'
|
||||||
},
|
},
|
||||||
day: {
|
day: {
|
||||||
// options apply to basicDay and agendaDay views
|
// options apply to basicDay and agendaDay views
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
header: false,
|
header:false,
|
||||||
|
|
||||||
events: function (start_moment, end_moment, timezone, callback) {
|
|
||||||
|
|
||||||
|
events: function(start_moment, end_moment, timezone, callback) {
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/api/event',
|
url: '/api/event',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
@@ -67,19 +67,18 @@
|
|||||||
start: moment(start_moment).format("YYYY-MM-DD[T]HH:mm:ss"),
|
start: moment(start_moment).format("YYYY-MM-DD[T]HH:mm:ss"),
|
||||||
end: moment(end_moment).format("YYYY-MM-DD[T]HH:mm:ss")
|
end: moment(end_moment).format("YYYY-MM-DD[T]HH:mm:ss")
|
||||||
},
|
},
|
||||||
success: function (doc) {
|
success: function(doc) {
|
||||||
var events = [];
|
var events = [];
|
||||||
colours = {
|
colours = {'Provisional': '#f0ad4e',
|
||||||
'Provisional': '#f0ad4e',
|
'Confirmed': '#5cb85c' ,
|
||||||
'Confirmed': '#5cb85c',
|
'Booked': '#5cb85c' ,
|
||||||
'Booked': '#5cb85c',
|
'Cancelled': 'grey' ,
|
||||||
'Cancelled': 'grey',
|
|
||||||
'non-rig': '#5bc0de'
|
'non-rig': '#5bc0de'
|
||||||
};
|
};
|
||||||
$(doc).each(function () {
|
$(doc).each(function() {
|
||||||
end = $(this).attr('latest');
|
end = $(this).attr('latest')
|
||||||
if (end.indexOf("T") < 0) { //If latest does not contain a time
|
if(end.indexOf("T") < 0){ //If latest does not contain a time
|
||||||
end = moment(end).add(1, 'days'); //End date is non-inclusive, so add a day
|
end = moment(end).add(1, 'days') //End date is non-inclusive, so add a day
|
||||||
}
|
}
|
||||||
|
|
||||||
thisEvent = {
|
thisEvent = {
|
||||||
@@ -88,14 +87,14 @@
|
|||||||
'className': 'modal-href',
|
'className': 'modal-href',
|
||||||
'title': $(this).attr('title'),
|
'title': $(this).attr('title'),
|
||||||
'url': $(this).attr('url')
|
'url': $(this).attr('url')
|
||||||
};
|
}
|
||||||
|
|
||||||
if ($(this).attr('is_rig') == true || $(this).attr('status') == "Cancelled") {
|
if($(this).attr('is_rig')==true || $(this).attr('status') == "Cancelled"){
|
||||||
thisEvent['color'] = colours[$(this).attr('status')];
|
thisEvent['color'] = colours[$(this).attr('status')];
|
||||||
} else {
|
}else{
|
||||||
thisEvent['color'] = colours['non-rig'];
|
thisEvent['color'] = colours['non-rig'];
|
||||||
}
|
}
|
||||||
|
|
||||||
events.push(thisEvent);
|
events.push(thisEvent);
|
||||||
});
|
});
|
||||||
callback(events);
|
callback(events);
|
||||||
@@ -103,20 +102,20 @@
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
viewRender: function (view, element) {
|
viewRender: function(view, element){
|
||||||
// Set the title of the view
|
// Set the title of the view
|
||||||
$('#calendar-header').text(view.title);
|
$('#calendar-header').text(view.title);
|
||||||
|
|
||||||
// Enable/Disable "Today" button as required
|
// Enable/Disable "Today" button as required
|
||||||
if (moment().isBetween(view.intervalStart, view.intervalEnd)) {
|
if(moment().isBetween(view.intervalStart, view.intervalEnd)){
|
||||||
//Today is within the current view
|
//Today is within the current view
|
||||||
$('#today-button').prop('disabled', true);
|
$('#today-button').prop('disabled', true);
|
||||||
} else {
|
}else{
|
||||||
$('#today-button').prop('disabled', false);
|
$('#today-button').prop('disabled', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set active view select button
|
// Set active view select button
|
||||||
switch (view.name) {
|
switch(view.name){
|
||||||
case 'month':
|
case 'month':
|
||||||
$('#month-button').addClass('active');
|
$('#month-button').addClass('active');
|
||||||
$('#week-button').removeClass('active');
|
$('#week-button').removeClass('active');
|
||||||
@@ -135,64 +134,53 @@
|
|||||||
$('#day-button').addClass('active');
|
$('#day-button').addClass('active');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
history.replaceState(null, null, '{% url 'web_calendar' %}' + viewToUrl[view.name] + '/' + view.intervalStart.format('YYYY-MM-DD') + '/');
|
history.replaceState(null,null,'{% url 'web_calendar' %}'+viewToUrl[view.name]+'/'+view.intervalStart.format('YYYY-MM-DD')+'/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
// set some button listeners
|
// set some button listeners
|
||||||
|
|
||||||
$('#next-button').click(function () {
|
$('#next-button').click(function(){ $('#calendar').fullCalendar('next') });
|
||||||
$('#calendar').fullCalendar('next')
|
$('#prev-button').click(function(){ $('#calendar').fullCalendar('prev') });
|
||||||
});
|
$('#today-button').click(function(){ $('#calendar').fullCalendar('today') });
|
||||||
$('#prev-button').click(function () {
|
|
||||||
$('#calendar').fullCalendar('prev')
|
|
||||||
});
|
|
||||||
$('#today-button').click(function () {
|
|
||||||
$('#calendar').fullCalendar('today')
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#month-button').click(function () {
|
$('#month-button').click(function(){ $('#calendar').fullCalendar('changeView','month') });
|
||||||
$('#calendar').fullCalendar('changeView', 'month')
|
$('#week-button').click(function(){ $('#calendar').fullCalendar('changeView','agendaWeek') });
|
||||||
});
|
$('#day-button').click(function(){ $('#calendar').fullCalendar('changeView','agendaDay') });
|
||||||
$('#week-button').click(function () {
|
|
||||||
$('#calendar').fullCalendar('changeView', 'agendaWeek')
|
|
||||||
});
|
|
||||||
$('#day-button').click(function () {
|
|
||||||
$('#calendar').fullCalendar('changeView', 'agendaDay')
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#go-to-date-input').change(function () {
|
$('#go-to-date-input').change(function(){
|
||||||
if (moment($('#go-to-date-input').val()).isValid()) {
|
if( moment($('#go-to-date-input').val()).isValid() ){
|
||||||
$('#go-to-date-button').prop('disabled', false);
|
$('#go-to-date-button').prop('disabled', false);
|
||||||
} else {
|
}else{
|
||||||
$('#go-to-date-button').prop('disabled', true);
|
$('#go-to-date-button').prop('disabled', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#go-to-date-button').click(function () {
|
$('#go-to-date-button').click(function(){
|
||||||
day = moment($('#go-to-date-input').val());
|
day = moment($('#go-to-date-input').val()) ;
|
||||||
if (day.isValid()) {
|
if(day.isValid()){
|
||||||
$('#calendar').fullCalendar('gotoDate', day);
|
$('#calendar').fullCalendar( 'gotoDate', day);
|
||||||
} else {
|
}else{
|
||||||
alert('Invalid Date');
|
alert('Invalid Date');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Go to the initial settings, if they're valid
|
// Go to the initial settings, if they're valid
|
||||||
view = viewFromUrl['{{view}}'];
|
view = viewFromUrl['{{view}}'];
|
||||||
$('#calendar').fullCalendar('changeView', view);
|
$('#calendar').fullCalendar( 'changeView', view);
|
||||||
|
|
||||||
day = moment('{{date}}');
|
day = moment('{{date}}');
|
||||||
if (day.isValid()) {
|
if(day.isValid()){
|
||||||
$('#calendar').fullCalendar('gotoDate', day);
|
$('#calendar').fullCalendar( 'gotoDate', day);
|
||||||
} else {
|
}else{
|
||||||
console.log('Supplied date is invalid - using default')
|
console.log('Supplied date is invalid - using default')
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -201,7 +189,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="pull-left">
|
<div class="pull-left">
|
||||||
<span id="calendar-header" class="h2"></span>
|
<span id="calendar-header" class="h2"></span>
|
||||||
@@ -209,35 +197,33 @@
|
|||||||
|
|
||||||
<div class="form-inline pull-right btn-page">
|
<div class="form-inline pull-right btn-page">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="date" class="form-control" id="go-to-date-input" placeholder="Go to date...">
|
<input type="date" class="form-control" id="go-to-date-input" placeholder="Go to date...">
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button class="btn btn-default" id="go-to-date-button" type="button" disabled>Go!</button>
|
<button class="btn btn-default" id="go-to-date-button" type="button" disabled>Go!</button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button type="button" class="btn btn-primary" id="today-button">Today</button>
|
<button type="button" class="btn btn-primary" id="today-button">Today</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button type="button" class="btn btn-default" id="prev-button"><span
|
<button type="button" class="btn btn-default" id="prev-button"><span class="glyphicon glyphicon-chevron-left"></span></button>
|
||||||
class="glyphicon glyphicon-chevron-left"></span></button>
|
<button type="button" class="btn btn-default" id="next-button"><span class="glyphicon glyphicon-chevron-right"></span></button>
|
||||||
<button type="button" class="btn btn-default" id="next-button"><span
|
|
||||||
class="glyphicon glyphicon-chevron-right"></span></button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button type="button" class="btn btn-default" id="month-button">Month</button>
|
<button type="button" class="btn btn-default" id="month-button">Month</button>
|
||||||
<button type="button" class="btn btn-default" id="week-button">Week</button>
|
<button type="button" class="btn btn-default" id="week-button">Week</button>
|
||||||
<button type="button" class="btn btn-default" id="day-button">Day</button>
|
<button type="button" class="btn btn-default" id="day-button">Day</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div id='calendar'>
|
<div id='calendar'>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% endblock %}
|
||||||
{% endblock %}
|
|
||||||
@@ -11,17 +11,14 @@
|
|||||||
<form class="form-inline">
|
<form class="form-inline">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="start">Start</label>
|
<label for="start">Start</label>
|
||||||
<input type="date" name="start" id="start" value="{{ request.GET.start }}" placeholder="Start"
|
<input type="date" name="start" id="start" value="{{ request.GET.start }}" placeholder="Start" class="form-control" />
|
||||||
class="form-control"/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="end">End</label>
|
<label for="end">End</label>
|
||||||
<input type="date" name="end" id="end"
|
<input type="date" name="end" id="end" value="{% if request.GET.end %}{{ request.GET.end }}{% else %}{% now "Y-m-d" %}{% endif %}" placeholder="End" class="form-control" />
|
||||||
value="{% if request.GET.end %}{{ request.GET.end }}{% else %}{% now "Y-m-d" %}{% endif %}"
|
|
||||||
placeholder="End" class="form-control"/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="submit" class="btn btn-primary"/>
|
<input type="submit" class="btn btn-primary" />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -45,4 +42,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,286 +1,251 @@
|
|||||||
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
||||||
{% block title %}{% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}{% endif %} |
|
{% block title %}{% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}{% endif %} | {{object.name}}{% endblock %}
|
||||||
{{ object.name }}{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% if not request.is_ajax %}
|
{% if not request.is_ajax %}
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<h1>
|
<h1>
|
||||||
{% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}{% endif %}
|
{% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}{% endif %}
|
||||||
| {{ object.name }} {% if event.dry_hire %}<span class="badge">Dry Hire</span>{% endif %}
|
| {{ object.name }} {% if event.dry_hire %}<span class="badge">Dry Hire</span>{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
<div class="btn-group btn-page">
|
<div class="btn-group btn-page">
|
||||||
<a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span
|
<a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-edit"></span> <span
|
class="glyphicon glyphicon-edit"></span> <span
|
||||||
class="hidden-xs">Edit</span></a>
|
class="hidden-xs">Edit</span></a>
|
||||||
{% if event.is_rig %}
|
{% if event.is_rig %}
|
||||||
<a href="{% url 'event_print' event.pk %}" target="_blank" class="btn btn-default"><span
|
<a href="{% url 'event_print' event.pk %}" target="_blank" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-print"></span> <span
|
class="glyphicon glyphicon-print"></span> <span
|
||||||
class="hidden-xs">Print</span></a>
|
class="hidden-xs">Print</span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'event_duplicate' event.pk %}" class="btn btn-default" title="Duplicate Rig"><span
|
<a href="{% url 'event_duplicate' event.pk %}" class="btn btn-default" title="Duplicate Rig"><span
|
||||||
class="glyphicon glyphicon-duplicate"></span> <span
|
class="glyphicon glyphicon-duplicate"></span> <span
|
||||||
class="hidden-xs">Duplicate</span></a>
|
class="hidden-xs">Duplicate</span></a>
|
||||||
{% if event.is_rig %}
|
{% if event.is_rig %}
|
||||||
{% if perms.RIGS.add_invoice %}
|
{% if perms.RIGS.add_invoice %}
|
||||||
<a id="invoiceDropdownLabel" href="{% url 'invoice_event' event.pk %}" class="btn
|
<a href="{% url 'invoice_event' event.pk %}" class="btn btn-default" title="Invoice Rig"><span
|
||||||
{% if event.invoice and event.invoice.is_closed %}
|
class="glyphicon glyphicon-gbp"></span> <span
|
||||||
btn-success
|
class="hidden-xs">Invoice</span></a>
|
||||||
{% elif event.invoice %}
|
|
||||||
btn-warning
|
|
||||||
{% else %}
|
|
||||||
btn-danger
|
|
||||||
{% endif %}
|
|
||||||
" title="Invoice Rig"><span
|
|
||||||
class="glyphicon glyphicon-gbp"></span>
|
|
||||||
<span class="hidden-xs">Invoice</span></a>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% if object.is_rig %}
|
||||||
|
{# only need contact details for a rig #}
|
||||||
|
<div class="col-sm-12 col-md-6 col-lg-5">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">Contact Details</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>Person</dt>
|
||||||
|
<dd>
|
||||||
|
{% if object.person %}
|
||||||
|
<a href="{% url 'person_detail' object.person.pk %}" class="modal-href">
|
||||||
|
{{ object.person }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>Email</dt>
|
||||||
|
<dd>
|
||||||
|
<a href="mailto:{{object.person.email}}" target="_blank">
|
||||||
|
<span class="overflow-ellipsis">{{ object.person.email }}</span>
|
||||||
|
</a>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>Phone Number</dt>
|
||||||
|
<dd><a href="tel:{{object.person.phone}}">{{ object.person.phone }}</a></dd>
|
||||||
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if event.organisation %}
|
||||||
{% endif %}
|
|
||||||
{% if object.is_rig %}
|
|
||||||
{# only need contact details for a rig #}
|
|
||||||
<div class="col-sm-12 col-md-6 col-lg-5">
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">Contact Details</div>
|
<div class="panel-heading">Organisation</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
<dt>Person</dt>
|
<dt>Organisation</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{% if object.person %}
|
{% if object.organisation %}
|
||||||
<a href="{% url 'person_detail' object.person.pk %}" class="modal-href">
|
<a href="{% url 'organisation_detail' object.organisation.pk %}" class="modal-href">
|
||||||
{{ object.person }}
|
{{ object.organisation }}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
<dt>Email</dt>
|
|
||||||
<dd>
|
|
||||||
<a href="mailto:{{ object.person.email }}" target="_blank">
|
|
||||||
<span class="overflow-ellipsis">{{ object.person.email }}</span>
|
|
||||||
</a>
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>Phone Number</dt>
|
<dt>Phone Number</dt>
|
||||||
<dd><a href="tel:{{ object.person.phone }}">{{ object.person.phone }}</a></dd>
|
<dd>
|
||||||
|
<a href="tel:{{object.person.phone}}">
|
||||||
|
{{ object.organisation.phone }}
|
||||||
|
</a>
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>Has SU Account</dt>
|
||||||
|
<dd>{{ event.organisation.union_account|yesno|capfirst }}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if event.organisation %}
|
{% endif %}
|
||||||
<div class="panel panel-default">
|
</div>
|
||||||
<div class="panel-heading">Organisation</div>
|
{% endif %}
|
||||||
<div class="panel-body">
|
<div class="col-sm-12 {% if event.is_rig %}col-md-6 col-lg-7{% endif %}">
|
||||||
<dl class="dl-horizontal">
|
<div class="panel panel-info">
|
||||||
<dt>Organisation</dt>
|
<div class="panel-heading">Event Info</div>
|
||||||
<dd>
|
<div class="panel-body">
|
||||||
{% if object.organisation %}
|
<dl class="dl-horizontal">
|
||||||
<a href="{% url 'organisation_detail' object.organisation.pk %}"
|
<dt>Event Venue</dt>
|
||||||
class="modal-href">
|
<dd>
|
||||||
{{ object.organisation }}
|
{% if object.venue %}
|
||||||
</a>
|
<a href="{% url 'venue_detail' object.venue.pk %}" class="modal-href">
|
||||||
{% endif %}
|
{{ object.venue }}
|
||||||
</dd>
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
|
|
||||||
<dt>Phone Number</dt>
|
{% if event.is_rig %}
|
||||||
<dd>
|
<dt>Event MIC</dt>
|
||||||
<a href="tel:{{ object.person.phone }}">
|
|
||||||
{{ object.organisation.phone }}
|
|
||||||
</a>
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>Has SU Account</dt>
|
|
||||||
<dd>{{ event.organisation.union_account|yesno|capfirst }}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div class="col-sm-12 {% if event.is_rig %}col-md-6 col-lg-7{% endif %}">
|
|
||||||
<div class="panel panel-info">
|
|
||||||
<div class="panel-heading">Event Info</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<dl class="dl-horizontal">
|
|
||||||
<dt>Event Venue</dt>
|
|
||||||
<dd>
|
<dd>
|
||||||
{% if object.venue %}
|
{% if event.mic and perms.RIGS.view_profile %}
|
||||||
<a href="{% url 'venue_detail' object.venue.pk %}" class="modal-href">
|
<a href="{% url 'profile_detail' event.mic.pk %}" class="modal-href">
|
||||||
{{ object.venue }}
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
{% if event.is_rig %}
|
|
||||||
<dt>Event MIC</dt>
|
|
||||||
<dd>
|
|
||||||
{% if event.mic and perms.RIGS.view_profile %}
|
|
||||||
<a href="{% url 'profile_detail' event.mic.pk %}" class="modal-href">
|
|
||||||
{{ event.mic.name }}
|
|
||||||
</a>
|
|
||||||
{% else %}
|
|
||||||
{{ event.mic.name }}
|
{{ event.mic.name }}
|
||||||
{% endif %}
|
|
||||||
</dd>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<dt>Status</dt>
|
|
||||||
<dd>{{ event.get_status_display }}</dd>
|
|
||||||
|
|
||||||
<dd> </dd>
|
|
||||||
|
|
||||||
{% if event.is_rig %}
|
|
||||||
<dt>Crew Meet</dt>
|
|
||||||
<dd>{{ event.meet_at|date:"D d M Y H:i"|default:"" }}</dd>
|
|
||||||
<dd>{{ event.meet_info|default:"" }}</dd>
|
|
||||||
|
|
||||||
<dt>Access From</dt>
|
|
||||||
<dd>{{ event.access_at|date:"D d M Y H:i"|default:"" }}</dd>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<dt>Event Starts</dt>
|
|
||||||
<dd>{{ event.start_date|date:"D d M Y" }} {{ event.start_time|date:"H:i" }}</dd>
|
|
||||||
|
|
||||||
<dt>Event Ends</dt>
|
|
||||||
<dd>{{ event.end_date|date:"D d M Y" }} {{ event.end_time|date:"H:i" }}</dd>
|
|
||||||
|
|
||||||
<dd> </dd>
|
|
||||||
|
|
||||||
<dt>Event Description</dt>
|
|
||||||
<dd>{{ event.description|linebreaksbr }}</dd>
|
|
||||||
|
|
||||||
<dd> </dd>
|
|
||||||
|
|
||||||
<dt>Based On</dt>
|
|
||||||
<dd>
|
|
||||||
{% if object.based_on %}
|
|
||||||
<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.based_on.name }}
|
|
||||||
|
|
||||||
{% if object.based_on.mic %}
|
|
||||||
by {{ object.based_on.mic.name }}
|
|
||||||
{% endif %}
|
|
||||||
</a>
|
</a>
|
||||||
|
{% else %}
|
||||||
|
{{ event.mic.name }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dd>
|
</dd>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if event.dry_hire %}
|
<dt>Status</dt>
|
||||||
<dt>Checked In By</dt>
|
<dd>{{ event.get_status_display }}</dd>
|
||||||
<dd>{{ object.checked_in_by.name }}</dd>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if event.is_rig %}
|
<dd> </dd>
|
||||||
<dt>Collected By</dt>
|
|
||||||
<dd>{{ object.collector }}</dd>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if event.is_rig %}
|
{% if event.is_rig %}
|
||||||
<dt>PO</dt>
|
<dt>Crew Meet</dt>
|
||||||
<dd>{{ object.purchase_order }}</dd>
|
<dd>{{ event.meet_at|date:"D d M Y H:i"|default:"" }}</dd>
|
||||||
|
<dd>{{ event.meet_info|default:"" }}</dd>
|
||||||
|
|
||||||
|
<dt>Access From</dt>
|
||||||
|
<dd>{{ event.access_at|date:"D d M Y H:i"|default:"" }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<dt>Event Starts</dt>
|
||||||
|
<dd>{{ event.start_date|date:"D d M Y" }} {{ event.start_time|date:"H:i" }}</dd>
|
||||||
|
|
||||||
|
<dt>Event Ends</dt>
|
||||||
|
<dd>{{ event.end_date|date:"D d M Y" }} {{ event.end_time|date:"H:i" }}</dd>
|
||||||
|
|
||||||
|
<dd> </dd>
|
||||||
|
|
||||||
|
<dt>Event Description</dt>
|
||||||
|
<dd>{{ event.description|linebreaksbr }}</dd>
|
||||||
|
|
||||||
|
<dd> </dd>
|
||||||
|
|
||||||
|
<dt>Based On</dt>
|
||||||
|
<dd>
|
||||||
|
{% if object.based_on %}
|
||||||
|
<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.based_on.name }} {% if object.based_on.mic %}by {{ object.based_on.mic.name }}{% endif %}
|
||||||
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dl>
|
</dd>
|
||||||
|
|
||||||
|
{% if event.dry_hire %}
|
||||||
|
<dt>Checked In By</dt>
|
||||||
|
<dd>{{ object.checked_in_by.name }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if event.is_rig %}
|
||||||
|
<dt>Collected By</dt>
|
||||||
|
<dd>{{ object.collector }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if event.is_rig %}
|
||||||
|
<dt>PO</dt>
|
||||||
|
<dd>{{ object.purchase_order }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% if not request.is_ajax %}
|
||||||
|
<div class="col-sm-12 text-right">
|
||||||
|
<div class="btn-group btn-page">
|
||||||
|
<a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span
|
||||||
|
class="glyphicon glyphicon-edit"></span> <span
|
||||||
|
class="hidden-xs">Edit</span></a>
|
||||||
|
{% if event.is_rig %}
|
||||||
|
<a href="{% url 'event_print' event.pk %}" target="_blank" class="btn btn-default"><span
|
||||||
|
class="glyphicon glyphicon-print"></span> <span
|
||||||
|
class="hidden-xs">Print</span></a>
|
||||||
|
{% endif %}
|
||||||
|
<a href="{% url 'event_duplicate' event.pk %}" class="btn btn-default" title="Duplicate Rig"><span
|
||||||
|
class="glyphicon glyphicon-duplicate"></span> <span
|
||||||
|
class="hidden-xs">Duplicate</span></a>
|
||||||
|
{% if event.is_rig %}
|
||||||
|
{% if perms.RIGS.add_invoice %}
|
||||||
|
<a href="{% url 'invoice_event' event.pk %}" class="btn btn-default" title="Invoice Rig"><span
|
||||||
|
class="glyphicon glyphicon-gbp"></span> <span
|
||||||
|
class="hidden-xs">Invoice</span></a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if event.is_rig %}
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">Event Details</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="well well-sm">
|
||||||
|
<h4>Notes</h4>
|
||||||
|
{{ event.notes|linebreaksbr }}
|
||||||
|
</div>
|
||||||
|
{% include 'RIGS/item_table.html' %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if not request.is_ajax %}
|
{% if not request.is_ajax %}
|
||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
<div class="btn-group btn-page">
|
<div class="btn-group btn-page">
|
||||||
<a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span
|
<a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-edit"></span> <span
|
class="glyphicon glyphicon-edit"></span> <span
|
||||||
class="hidden-xs">Edit</span></a>
|
class="hidden-xs">Edit</span></a>
|
||||||
{% if event.is_rig %}
|
{% if event.is_rig %}
|
||||||
<a href="{% url 'event_print' event.pk %}" target="_blank" class="btn btn-default"><span
|
<a href="{% url 'event_print' event.pk %}" target="_blank" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-print"></span> <span
|
class="glyphicon glyphicon-print"></span> <span
|
||||||
class="hidden-xs">Print</span></a>
|
class="hidden-xs">Print</span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'event_duplicate' event.pk %}" class="btn btn-default" title="Duplicate Rig"><span
|
<a href="{% url 'event_duplicate' event.pk %}" class="btn btn-default" title="Duplicate Rig"><span
|
||||||
class="glyphicon glyphicon-duplicate"></span> <span
|
class="glyphicon glyphicon-duplicate"></span> <span
|
||||||
class="hidden-xs">Duplicate</span></a>
|
class="hidden-xs">Duplicate</span></a>
|
||||||
{% if event.is_rig %}
|
{% if event.is_rig %}
|
||||||
{% if perms.RIGS.add_invoice %}
|
{% if perms.RIGS.add_invoice %}
|
||||||
<a id="invoiceDropdownLabel" href="{% url 'invoice_event' event.pk %}" class="btn
|
<a href="{% url 'invoice_event' event.pk %}" class="btn btn-default" title="Invoice Rig"><span
|
||||||
{% if event.invoice and event.invoice.is_closed %}
|
class="glyphicon glyphicon-gbp"></span> <span
|
||||||
btn-success
|
class="hidden-xs">Invoice</span></a>
|
||||||
{% elif event.invoice %}
|
|
||||||
btn-warning
|
|
||||||
{% else %}
|
|
||||||
btn-danger
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
" title="Invoice Rig"><span
|
{% endif %}
|
||||||
class="glyphicon glyphicon-gbp"></span>
|
|
||||||
<span class="hidden-xs">Invoice</span></a>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if event.is_rig %}
|
{% endif %}
|
||||||
<div class="col-sm-12">
|
{% if not request.is_ajax %}
|
||||||
<div class="panel panel-default">
|
<div class="col-sm-12 text-right">
|
||||||
<div class="panel-heading">Event Details</div>
|
<div>
|
||||||
<div class="panel-body">
|
<a href="{% url 'event_history' object.pk %}" title="View Revision History">
|
||||||
<div class="well well-sm">
|
Last edited at {{ object.last_edited_at }} by {{ object.last_edited_by.name }}
|
||||||
<h4>Notes</h4>
|
</a>
|
||||||
{{ event.notes|linebreaksbr }}
|
|
||||||
</div>
|
|
||||||
{% include 'RIGS/item_table.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% if not request.is_ajax %}
|
</div>
|
||||||
<div class="col-sm-12 text-right">
|
{% endif %}
|
||||||
<div class="btn-group btn-page">
|
</div>
|
||||||
<a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span
|
|
||||||
class="glyphicon glyphicon-edit"></span> <span
|
|
||||||
class="hidden-xs">Edit</span></a>
|
|
||||||
{% if event.is_rig %}
|
|
||||||
<a href="{% url 'event_print' event.pk %}" target="_blank" class="btn btn-default"><span
|
|
||||||
class="glyphicon glyphicon-print"></span> <span
|
|
||||||
class="hidden-xs">Print</span></a>
|
|
||||||
{% endif %}
|
|
||||||
<a href="{% url 'event_duplicate' event.pk %}" class="btn btn-default"
|
|
||||||
title="Duplicate Rig"><span
|
|
||||||
class="glyphicon glyphicon-duplicate"></span> <span
|
|
||||||
class="hidden-xs">Duplicate</span></a>
|
|
||||||
{% if event.is_rig %}
|
|
||||||
{% if perms.RIGS.add_invoice %}
|
|
||||||
<a id="invoiceDropdownLabel" href="{% url 'invoice_event' event.pk %}" class="btn
|
|
||||||
{% if event.invoice and event.invoice.is_closed %}
|
|
||||||
btn-success
|
|
||||||
{% elif event.invoice %}
|
|
||||||
btn-warning
|
|
||||||
{% else %}
|
|
||||||
btn-danger
|
|
||||||
{% endif %}
|
|
||||||
" title="Invoice Rig"><span
|
|
||||||
class="glyphicon glyphicon-gbp"></span>
|
|
||||||
<span class="hidden-xs">Invoice</span></a>
|
|
||||||
{% 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 %}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% if request.is_ajax %}
|
{% if request.is_ajax %}
|
||||||
|
|||||||
@@ -32,12 +32,12 @@
|
|||||||
var id_start = "{{ form.start_date.id_for_label }}";
|
var id_start = "{{ form.start_date.id_for_label }}";
|
||||||
var id_end_date = "{{ form.end_date.id_for_label }}";
|
var id_end_date = "{{ form.end_date.id_for_label }}";
|
||||||
var id_end_time = "{{ form.end_time.id_for_label }}";
|
var id_end_time = "{{ form.end_time.id_for_label }}";
|
||||||
if ($('#' + id_start).val() == $('#' + id_end_date).val()) {
|
if ($('#'+id_start).val() == $('#'+id_end_date).val()) {
|
||||||
var end_date = new Date($('#' + id_end_date).val());
|
var end_date = new Date($('#'+id_end_date).val());
|
||||||
end_date.setDate(end_date.getDate() + 1);
|
end_date.setDate(end_date.getDate() + 1);
|
||||||
$('#' + id_end_date).val(end_date.getISOString());
|
$('#'+id_end_date).val(end_date.getISOString());
|
||||||
}
|
}
|
||||||
$('#' + id_end_time).val('02:00');
|
$('#'+id_end_time).val('02:00');
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
} else {
|
} else {
|
||||||
$('.form-is_rig').slideDown();
|
$('.form-is_rig').slideDown();
|
||||||
}
|
}
|
||||||
$('.form-hws, .form-hws .form-is_rig').css('overflow', 'visible');
|
$('.form-hws').css('overflow', 'visible');
|
||||||
} else {
|
} else {
|
||||||
$('#{{form.is_rig.auto_id}}').prop('checked', false);
|
$('#{{form.is_rig.auto_id}}').prop('checked', false);
|
||||||
$('.form-is_rig').slideUp();
|
$('.form-is_rig').slideUp();
|
||||||
@@ -74,34 +74,33 @@
|
|||||||
function supportsDate() {
|
function supportsDate() {
|
||||||
//return false; //for development
|
//return false; //for development
|
||||||
var input = document.createElement('input');
|
var input = document.createElement('input');
|
||||||
input.setAttribute('type', 'date');
|
input.setAttribute('type','date');
|
||||||
var notADateValue = 'not-a-date';
|
var notADateValue = 'not-a-date';
|
||||||
input.setAttribute('value', notADateValue);
|
input.setAttribute('value', notADateValue);
|
||||||
return !(input.value === notADateValue);
|
return !(input.value === notADateValue);
|
||||||
}
|
}
|
||||||
|
if(supportsDate()){
|
||||||
if (supportsDate()) {
|
|
||||||
//Good, we'll use the browser implementation
|
//Good, we'll use the browser implementation
|
||||||
} else {
|
}else{
|
||||||
//Rubbish browser - do JQuery backup
|
//Rubbish browser - do JQuery backup
|
||||||
$('<link>')
|
$('<link>')
|
||||||
.appendTo('head')
|
.appendTo('head')
|
||||||
.attr({type: 'text/css', rel: 'stylesheet'})
|
.attr({type : 'text/css', rel : 'stylesheet'})
|
||||||
.attr('href', '{% static "css/bootstrap-datetimepicker.min.css" %}');
|
.attr('href', '{% static "css/bootstrap-datetimepicker.min.css" %}');
|
||||||
$.when(
|
$.when(
|
||||||
$.getScript("{% static "js/moment.min.js" %}"),
|
$.getScript( "{% static "js/moment.min.js" %}" ),
|
||||||
$.getScript("{% static "js/bootstrap-datetimepicker.min.js" %}"),
|
$.getScript( "{% static "js/bootstrap-datetimepicker.min.js" %}" ),
|
||||||
$.Deferred(function (deferred) {
|
$.Deferred(function( deferred ){
|
||||||
$(deferred.resolve);
|
$( deferred.resolve );
|
||||||
})
|
})
|
||||||
).done(function () {
|
).done(function(){
|
||||||
$('input[type=date]').attr('type', 'text').datetimepicker({
|
$('input[type=date]').attr('type','text').datetimepicker({
|
||||||
format: 'YYYY-MM-DD',
|
format: 'YYYY-MM-DD',
|
||||||
});
|
});
|
||||||
$('input[type=time]').attr('type', 'text').datetimepicker({
|
$('input[type=time]').attr('type','text').datetimepicker({
|
||||||
format: 'HH:mm',
|
format: 'HH:mm',
|
||||||
});
|
});
|
||||||
$('input[type=datetime-local]').attr('type', 'text').datetimepicker({
|
$('input[type=datetime-local]').attr('type','text').datetimepicker({
|
||||||
format: 'YYYY-MM-DD[T]HH:mm',
|
format: 'YYYY-MM-DD[T]HH:mm',
|
||||||
sideBySide: true,
|
sideBySide: true,
|
||||||
});
|
});
|
||||||
@@ -114,90 +113,168 @@
|
|||||||
setupItemTable($("#{{ form.items_json.id_for_label }}").val());
|
setupItemTable($("#{{ form.items_json.id_for_label }}").val());
|
||||||
});
|
});
|
||||||
$(function () {
|
$(function () {
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<form class="form-horizontal itemised_form" role="form" method="POST">{% csrf_token %}
|
<form class="form-horizontal itemised_form" role="form" method="POST">{% csrf_token %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<h2>
|
<h2>
|
||||||
{% if duplicate %}
|
{% if duplicate %}
|
||||||
Duplicate of Event N{{ object.pk|stringformat:"05d" }}
|
Duplicate of Event N{{ object.pk|stringformat:"05d" }}
|
||||||
{% elif object.pk %}
|
{% elif object.pk %}
|
||||||
Event N{{ object.pk|stringformat:"05d" }}
|
Event N{{ object.pk|stringformat:"05d" }}
|
||||||
{% else %}
|
{% else %}
|
||||||
New Event
|
New Event
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4 text-right">
|
<div class="col-sm-4 text-right">
|
||||||
<div class="btn-group btn-page">
|
<div class="btn-group btn-page">
|
||||||
<button type="submit" class="btn btn-default" title="Save"><span
|
<button type="submit" class="btn btn-default" title="Save"><span
|
||||||
class="glyphicon glyphicon-floppy-disk"></span></button>
|
class="glyphicon glyphicon-floppy-disk"></span></button>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% include 'form_errors.html' %}
|
</div>
|
||||||
{% render_field form.is_rig style="display: none" %}
|
{% include 'form_errors.html' %}
|
||||||
<input type="hidden" name="{{ form.items_json.name }}" id="{{ form.items_json.id_for_label }}"
|
{% render_field form.is_rig style="display: none" %}
|
||||||
value="{{ form.items_json.value }}"/>
|
<input type="hidden" name="{{ form.items_json.name }}" id="{{ form.items_json.id_for_label }}"
|
||||||
|
value="{{ form.items_json.value }}"/>
|
||||||
|
|
||||||
{# New rig buttons #}
|
{# New rig buttons #}
|
||||||
{% if not object.pk %}
|
{% if not object.pk %}
|
||||||
<div class="col-md-12 well">
|
<div class="col-md-12 well">
|
||||||
<div class="form-group" id="is_rig-selector">
|
<div class="form-group" id="is_rig-selector">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<span class="col-sm-6" data-toggle="tooltip"
|
<span class="col-sm-6" data-toggle="tooltip"
|
||||||
title="Anything that involves TEC kit, crew, or otherwise us providing a service to anyone.">
|
title="Anything that involves TEC kit, crew, or otherwise us providing a service to anyone.">
|
||||||
<button type="button" class="btn btn-primary col-xs-12" data-is_rig="1">Rig</button>
|
<button type="button" class="btn btn-primary col-xs-12" data-is_rig="1">Rig</button>
|
||||||
</span>
|
</span>
|
||||||
<span class="col-sm-6" data-toggle="tooltip"
|
<span class="col-sm-6" data-toggle="tooltip"
|
||||||
title="Things that aren't service-based, like training, meetings and site visits.">
|
title="Things that aren't service-based, like training, meetings and site visits.">
|
||||||
<button type="button" class="btn btn-info col-xs-12" data-is_rig="0">Non-Rig</button>
|
<button type="button" class="btn btn-info col-xs-12" data-is_rig="0">Non-Rig</button>
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# Contact details #}
|
||||||
|
<div class="col-sm-12 col-md-6">
|
||||||
|
<div class="panel panel-default form-hws form-is_rig {% if object.pk and not object.is_rig %}hidden{% endif %}">
|
||||||
|
<div class="panel-heading">Contact Details</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group" data-toggle="tooltip" title="The main contact for the event, can be left blank if purely an organisation">
|
||||||
|
<label for="{{ form.person.id_for_label }}"
|
||||||
|
class="col-sm-4 control-label">{{ form.person.label }}</label>
|
||||||
|
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-9 col-md-7 col-lg-8">
|
||||||
|
<select id="{{ form.person.id_for_label }}" name="{{ form.person.name }}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='person' %}">
|
||||||
|
{% if person %}
|
||||||
|
<option value="{{form.person.value}}" selected="selected" data-update_url="{% url 'person_update' form.person.value %}">{{ person }}</option>
|
||||||
|
{% endif %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-md-5 col-lg-4 align-right">
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="{% url 'person_create' %}" class="btn btn-default modal-href"
|
||||||
|
data-target="#{{ form.person.id_for_label }}">
|
||||||
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
|
</a>
|
||||||
|
<a href="{% if form.person.value %}{% url 'person_update' form.person.value %}{% endif %}" class="btn btn-default modal-href" id="{{ form.person.id_for_label }}-update" data-target="#{{ form.person.id_for_label }}">
|
||||||
|
<span class="glyphicon glyphicon-pencil"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" data-toggle="tooltip" title="The client organisation, leave blank if client is an individual">
|
||||||
|
<label for="{{ form.organisation.id_for_label }}"
|
||||||
|
class="col-sm-4 control-label">{{ form.organisation.label }}</label>
|
||||||
|
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-9 col-md-7 col-lg-8">
|
||||||
|
<select id="{{ form.organisation.id_for_label }}" name="{{ form.organisation.name }}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='organisation' %}" >
|
||||||
|
{% if organisation %}
|
||||||
|
<option value="{{form.organisation.value}}" selected="selected" data-update_url="{% url 'organisation_update' form.organisation.value %}">{{ organisation }}</option>
|
||||||
|
{% endif %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 col-md-5 col-lg-4 align-right">
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="{% url 'organisation_create' %}" class="btn btn-default modal-href"
|
||||||
|
data-target="#{{ form.organisation.id_for_label }}">
|
||||||
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
|
</a>
|
||||||
|
<a href="{% if form.organisation.value %}{% url 'organisation_update' form.organisation.value %}{% endif %}" class="btn btn-default modal-href" id="{{ form.organisation.id_for_label }}-update" data-target="#{{ form.organisation.id_for_label }}">
|
||||||
|
<span class="glyphicon glyphicon-pencil"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
</div>
|
||||||
|
<div class="panel panel-default form-hws form-non_rig">
|
||||||
|
<div class="panel-heading">Event Description</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group" data-toggle="tooltip" title="A short description of the event, shown on rigboard and on paperwork">
|
||||||
|
<label for="{{ form.description.id_for_label }}"
|
||||||
|
class="col-sm-4 control-label">{{ form.description.label }}</label>
|
||||||
|
|
||||||
{# Contact details #}
|
<div class="col-sm-8">
|
||||||
<div class="col-sm-12 col-md-6">
|
{% render_field form.description class+="form-control" %}
|
||||||
<div class="panel panel-default form-hws form-is_rig {% if object.pk and not object.is_rig %}hidden{% endif %}">
|
</div>
|
||||||
<div class="panel-heading">Contact Details</div>
|
</div>
|
||||||
<div class="panel-body">
|
</div>
|
||||||
<div class="form-group" data-toggle="tooltip"
|
</div>
|
||||||
title="The main contact for the event, can be left blank if purely an organisation">
|
</div>
|
||||||
<label for="{{ form.person.id_for_label }}"
|
<!-- /.col-sm-12 .col-md-6 -->
|
||||||
class="col-sm-4 control-label">{{ form.person.label }}</label>
|
|
||||||
|
{# Event details #}
|
||||||
|
<div class="col-sm-12 col-md-6">
|
||||||
|
<div class="panel panel-default form-hws form-non_rig">
|
||||||
|
<div class="panel-heading">Event Details</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div id="form-hws">
|
||||||
|
<div class="form-group" data-toggle="tooltip" title="Name of the event, displays on rigboard and on paperwork">
|
||||||
|
<label for="{{ form.name.id_for_label }}"
|
||||||
|
class="col-sm-4 control-label">{{ form.name.label }}</label>
|
||||||
|
|
||||||
|
<div class="col-sm-8">
|
||||||
|
{% render_field form.name class+="form-control" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" data-toggle="tooltip" title="The venue for the rig, leave blank if unknown (e.g. for a dry hire)">
|
||||||
|
<label for="{{ form.venue.id_for_label }}"
|
||||||
|
class="col-sm-4 control-label">{{ form.venue.label }}</label>
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-9 col-md-7 col-lg-8">
|
<div class="col-sm-9 col-md-7 col-lg-8">
|
||||||
<select id="{{ form.person.id_for_label }}" name="{{ form.person.name }}"
|
<select id="{{ form.venue.id_for_label }}" name="{{ form.venue.name }}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='venue' %}">
|
||||||
class="form-control selectpicker" data-live-search="true"
|
{% if venue %}
|
||||||
data-sourceurl="{% url 'api_secure' model='person' %}">
|
<option value="{{form.venue.value}}" selected="selected" data-update_url="{% url 'venue_update' form.venue.value %}">{{ venue }}</option>
|
||||||
{% if person %}
|
{% endif %}
|
||||||
<option value="{{ form.person.value }}" selected="selected"
|
|
||||||
data-update_url="{% url 'person_update' form.person.value %}">{{ person }}</option>
|
|
||||||
{% endif %}
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3 col-md-5 col-lg-4 align-right">
|
<div class="col-sm-3 col-md-5 col-lg-4 align-right">
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<a href="{% url 'person_create' %}" class="btn btn-default modal-href"
|
<a href="{% url 'venue_create' %}" class="btn btn-default modal-href"
|
||||||
data-target="#{{ form.person.id_for_label }}">
|
data-target="#{{ form.venue.id_for_label }}">
|
||||||
<span class="glyphicon glyphicon-plus"></span>
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
</a>
|
</a>
|
||||||
<a href="
|
<a href="{% if object.venue %}{% url 'venue_update' object.venue.pk %}{% endif %}" class="btn btn-default modal-href" id="{{ form.venue.id_for_label }}-update" data-target="#{{ form.venue.id_for_label }}">
|
||||||
|
|
||||||
{% if form.person.value %}{% url 'person_update' form.person.value %}{% endif %}"
|
|
||||||
class="btn btn-default modal-href" id="{{ form.person.id_for_label }}-update"
|
|
||||||
data-target="#{{ form.person.id_for_label }}">
|
|
||||||
<span class="glyphicon glyphicon-pencil"></span>
|
<span class="glyphicon glyphicon-pencil"></span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -205,293 +282,167 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group" data-toggle="tooltip"
|
<div class="form-group">
|
||||||
title="The client organisation, leave blank if client is an individual">
|
<label for="{{ form.start_date.id_for_label }}"
|
||||||
<label for="{{ form.organisation.id_for_label }}"
|
class="col-sm-4 control-label">{{ form.start_date.label }}</label>
|
||||||
class="col-sm-4 control-label">{{ form.organisation.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-9 col-md-7 col-lg-8">
|
<div class="col-sm-12 col-md-7" data-toggle="tooltip" title="Start date for event, required">
|
||||||
<select id="{{ form.organisation.id_for_label }}"
|
{% render_field form.start_date type="date" class+="form-control" %}
|
||||||
name="{{ form.organisation.name }}" class="form-control selectpicker"
|
|
||||||
data-live-search="true"
|
|
||||||
data-sourceurl="{% url 'api_secure' model='organisation' %}">
|
|
||||||
{% if organisation %}
|
|
||||||
<option value="{{ form.organisation.value }}" selected="selected"
|
|
||||||
data-update_url="{% url 'organisation_update' form.organisation.value %}">{{ organisation }}</option>
|
|
||||||
{% endif %}
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3 col-md-5 col-lg-4 align-right">
|
<div class="col-sm-12 col-md-5" data-toggle="tooltip" title="Start time of event, can be left blank">
|
||||||
<div class="btn-group">
|
{% render_field form.start_time type="time" class+="form-control" %}
|
||||||
<a href="{% url 'organisation_create' %}" class="btn btn-default modal-href"
|
|
||||||
data-target="#{{ form.organisation.id_for_label }}">
|
|
||||||
<span class="glyphicon glyphicon-plus"></span>
|
|
||||||
</a>
|
|
||||||
<a href="
|
|
||||||
|
|
||||||
{% if form.organisation.value %}{% url 'organisation_update' form.organisation.value %}{% endif %}"
|
|
||||||
class="btn btn-default modal-href"
|
|
||||||
id="{{ form.organisation.id_for_label }}-update"
|
|
||||||
data-target="#{{ form.organisation.id_for_label }}">
|
|
||||||
<span class="glyphicon glyphicon-pencil"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
</div>
|
<label for="{{ form.end_date.id_for_label }}"
|
||||||
<div class="panel panel-default form-hws form-non_rig">
|
class="col-sm-4 control-label">{{ form.end_date.label }}</label>
|
||||||
<div class="panel-heading">Event Description</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<div class="form-group" data-toggle="tooltip"
|
|
||||||
title="A short description of the event, shown on rigboard and on paperwork">
|
|
||||||
<label for="{{ form.description.id_for_label }}"
|
|
||||||
class="col-sm-4 control-label">{{ form.description.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
{% render_field form.description class+="form-control" %}
|
<div class="row">
|
||||||
|
<div class="col-sm-12 col-md-7" data-toggle="tooltip" title="End date of event, leave blank if unknown or same as start date">
|
||||||
|
{% render_field form.end_date type="date" class+="form-control" %}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 col-md-5" data-toggle="tooltip" title="End time of event, leave blank if unknown">
|
||||||
|
{% render_field form.end_time type="time" class+="form-control" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 col-md-offset-7 col-md-5">
|
||||||
|
<div class="btn-group btn-group-justified">
|
||||||
|
<btn class="btn btn-default btn-xs" onclick="setTime23Hours()">23:00</btn>
|
||||||
|
<btn class="btn btn-default btn-xs" onclick="setTime02Hours()">02:00</btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.col-sm-12 .col-md-6 -->
|
|
||||||
|
|
||||||
{# Event details #}
|
{# Rig only information #}
|
||||||
<div class="col-sm-12 col-md-6">
|
<div class="form-is_rig {% if object.pk and not object.is_rig %}hidden{% endif %}">
|
||||||
<div class="panel panel-default form-hws form-non_rig">
|
<div class="form-group" data-toggle="tooltip" title="The date/time at which TEC have access to the venue">
|
||||||
<div class="panel-heading">Event Details</div>
|
<label for="{{ form.access_at.id_for_label }}"
|
||||||
<div class="panel-body">
|
class="col-sm-4 control-label">{{ form.access_at.label }}</label>
|
||||||
<div id="form-hws">
|
|
||||||
<div class="form-group" data-toggle="tooltip"
|
|
||||||
title="Name of the event, displays on rigboard and on paperwork">
|
|
||||||
<label for="{{ form.name.id_for_label }}"
|
|
||||||
class="col-sm-4 control-label">{{ form.name.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
{% render_field form.name class+="form-control" %}
|
{% render_field form.access_at type="datetime-local" class+="form-control" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group" data-toggle="tooltip"
|
<div class="form-group" data-toggle="tooltip" title="The date/time at which crew should meet for this event">
|
||||||
title="The venue for the rig, leave blank if unknown (e.g. for a dry hire)">
|
<label for="{{ form.meet_at.id_for_label }}"
|
||||||
<label for="{{ form.venue.id_for_label }}"
|
class="col-sm-4 control-label">{{ form.meet_at.label }}</label>
|
||||||
class="col-sm-4 control-label">{{ form.venue.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<div class="row">
|
{% render_field form.meet_at type="datetime-local" class+="form-control" %}
|
||||||
<div class="col-sm-9 col-md-7 col-lg-8">
|
|
||||||
<select id="{{ form.venue.id_for_label }}" name="{{ form.venue.name }}"
|
|
||||||
class="form-control selectpicker" data-live-search="true"
|
|
||||||
data-sourceurl="{% url 'api_secure' model='venue' %}">
|
|
||||||
{% if venue %}
|
|
||||||
<option value="{{ form.venue.value }}" selected="selected"
|
|
||||||
data-update_url="{% url 'venue_update' form.venue.value %}">{{ venue }}</option>
|
|
||||||
{% endif %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-3 col-md-5 col-lg-4 align-right">
|
|
||||||
<div class="btn-group">
|
|
||||||
<a href="{% url 'venue_create' %}" class="btn btn-default modal-href"
|
|
||||||
data-target="#{{ form.venue.id_for_label }}">
|
|
||||||
<span class="glyphicon glyphicon-plus"></span>
|
|
||||||
</a>
|
|
||||||
<a href="
|
|
||||||
|
|
||||||
{% if object.venue %}{% url 'venue_update' object.venue.pk %}{% endif %}"
|
|
||||||
class="btn btn-default modal-href"
|
|
||||||
id="{{ form.venue.id_for_label }}-update"
|
|
||||||
data-target="#{{ form.venue.id_for_label }}">
|
|
||||||
<span class="glyphicon glyphicon-pencil"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="{{ form.start_date.id_for_label }}"
|
<div class="col-sm-offset-4 col-sm-8">
|
||||||
class="col-sm-4 control-label">{{ form.start_date.label }}</label>
|
<div class="checkbox">
|
||||||
|
<label data-toggle="tooltip" title="Mark this event as a dry-hire, so it needs to be checked in at the end">
|
||||||
|
{% render_field form.dry_hire %}{{ form.dry_hire.label }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{# Status is needed on all events types and it looks good here in the form #}
|
||||||
|
<div class="form-group" data-toggle="tooltip" title="The current status of the event. Only mark as booked once paperwork is received">
|
||||||
|
<label for="{{ form.status.id_for_label }}"
|
||||||
|
class="col-sm-4 control-label">{{ form.status.label }}</label>
|
||||||
|
|
||||||
|
<div class="col-sm-8">
|
||||||
|
{% render_field form.status class+="form-control" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-is_rig {% if object.pk and not object.is_rig %}hidden{% endif %}">
|
||||||
|
<div class="form-group" data-toggle="tooltip" title="The Member in Charge of this event">
|
||||||
|
<label for="{{ form.mic.id_for_label }}"
|
||||||
|
class="col-sm-4 control-label">{{ form.mic.label }}</label>
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<div class="row">
|
<select id="{{ form.mic.id_for_label }}" name="{{ form.mic.name }}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
|
||||||
<div class="col-sm-12 col-md-7" data-toggle="tooltip"
|
{% if mic %}
|
||||||
title="Start date for event, required">
|
<option value="{{form.mic.value}}" selected="selected" >{{ mic.name }}</option>
|
||||||
{% render_field form.start_date type="date" class+="form-control" %}
|
{% endif %}
|
||||||
</div>
|
</select>
|
||||||
<div class="col-sm-12 col-md-5" data-toggle="tooltip"
|
|
||||||
title="Start time of event, can be left blank">
|
|
||||||
{% render_field form.start_time type="time" class+="form-control" %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="{{ form.end_date.id_for_label }}"
|
|
||||||
class="col-sm-4 control-label">{{ form.end_date.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12 col-md-7" data-toggle="tooltip"
|
|
||||||
title="End date of event, leave blank if unknown or same as start date">
|
|
||||||
{% render_field form.end_date type="date" class+="form-control" %}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-12 col-md-5" data-toggle="tooltip"
|
|
||||||
title="End time of event, leave blank if unknown">
|
|
||||||
{% render_field form.end_time type="time" class+="form-control" %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12 col-md-offset-7 col-md-5">
|
|
||||||
<div class="btn-group btn-group-justified">
|
|
||||||
<btn class="btn btn-default btn-xs" onclick="setTime23Hours()">23:00</btn>
|
|
||||||
<btn class="btn btn-default btn-xs" onclick="setTime02Hours()">02:00</btn>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Rig only information #}
|
{% if object.dry_hire %}
|
||||||
<div class="form-is_rig {% if object.pk and not object.is_rig %}hidden{% endif %}">
|
<div class="form-group" data-toggle="tooltip" title="The person who checked-in this dry hire">
|
||||||
<div class="form-group" data-toggle="tooltip"
|
<label for="{{ form.checked_in_by.id_for_label }}"
|
||||||
title="The date/time at which TEC have access to the venue">
|
class="col-sm-4 control-label">{{ form.checked_in_by.label }}</label>
|
||||||
<label for="{{ form.access_at.id_for_label }}"
|
|
||||||
class="col-sm-4 control-label">{{ form.access_at.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
{% render_field form.access_at type="datetime-local" class+="form-control" %}
|
<select id="{{ form.checked_in_by.id_for_label }}" name="{{ form.checked_in_by.name }}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
|
||||||
</div>
|
{% if checked_in_by %}
|
||||||
</div>
|
<option value="{{form.checked_in_by.value}}" selected="selected" >{{ checked_in_by.name }}</option>
|
||||||
<div class="form-group" data-toggle="tooltip"
|
|
||||||
title="The date/time at which crew should meet for this event">
|
|
||||||
<label for="{{ form.meet_at.id_for_label }}"
|
|
||||||
class="col-sm-4 control-label">{{ form.meet_at.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
|
||||||
{% render_field form.meet_at type="datetime-local" class+="form-control" %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-sm-offset-4 col-sm-8">
|
|
||||||
<div class="checkbox">
|
|
||||||
<label data-toggle="tooltip"
|
|
||||||
title="Mark this event as a dry-hire, so it needs to be checked in at the end">
|
|
||||||
{% render_field form.dry_hire %}{{ form.dry_hire.label }}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{# Status is needed on all events types and it looks good here in the form #}
|
|
||||||
<div class="form-group" data-toggle="tooltip"
|
|
||||||
title="The current status of the event. Only mark as booked once paperwork is received">
|
|
||||||
<label for="{{ form.status.id_for_label }}"
|
|
||||||
class="col-sm-4 control-label">{{ form.status.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
|
||||||
{% render_field form.status class+="form-control" %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-is_rig {% if object.pk and not object.is_rig %}hidden{% endif %}">
|
|
||||||
<div class="form-group" data-toggle="tooltip" title="The Member in Charge of this event">
|
|
||||||
<label for="{{ form.mic.id_for_label }}"
|
|
||||||
class="col-sm-4 control-label">{{ form.mic.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
|
||||||
<select id="{{ form.mic.id_for_label }}" name="{{ form.mic.name }}"
|
|
||||||
class="form-control selectpicker" data-live-search="true"
|
|
||||||
data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
|
|
||||||
{% if mic %}
|
|
||||||
<option value="{{ form.mic.value }}"
|
|
||||||
selected="selected">{{ mic.name }}</option>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if object.dry_hire %}
|
<div class="form-group" data-toggle="tooltip" title="The student ID of the client who collected the dry-hire">
|
||||||
<div class="form-group" data-toggle="tooltip"
|
<label for="{{ form.collector.id_for_label }}"
|
||||||
title="The person who checked-in this dry hire">
|
class="col-sm-4 control-label">{{ form.collector.label }}</label>
|
||||||
<label for="{{ form.checked_in_by.id_for_label }}"
|
|
||||||
class="col-sm-4 control-label">{{ form.checked_in_by.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<select id="{{ form.checked_in_by.id_for_label }}"
|
{% render_field form.collector class+="form-control" %}
|
||||||
name="{{ form.checked_in_by.name }}" class="form-control selectpicker"
|
|
||||||
data-live-search="true"
|
|
||||||
data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials">
|
|
||||||
{% if checked_in_by %}
|
|
||||||
<option value="{{ form.checked_in_by.value }}"
|
|
||||||
selected="selected">{{ checked_in_by.name }}</option>
|
|
||||||
{% endif %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="form-group" data-toggle="tooltip"
|
|
||||||
title="The student ID of the client who collected the dry-hire">
|
|
||||||
<label for="{{ form.collector.id_for_label }}"
|
|
||||||
class="col-sm-4 control-label">{{ form.collector.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
|
||||||
{% render_field form.collector class+="form-control" %}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group" data-toggle="tooltip"
|
</div>
|
||||||
title="The purchase order number (for external clients)">
|
<div class="form-group" data-toggle="tooltip" title="The purchase order number (for external clients)">
|
||||||
<label for="{{ form.purchase_order.id_for_label }}"
|
<label for="{{ form.purchase_order.id_for_label }}"
|
||||||
class="col-sm-4 control-label">{{ form.purchase_order.label }}</label>
|
class="col-sm-4 control-label">{{ form.purchase_order.label }}</label>
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
{% render_field form.purchase_order class+="form-control" %}
|
{% render_field form.purchase_order class+="form-control" %}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.col-sm-12 .col-md-6 -->
|
</div>
|
||||||
<div class="col-sm-12 text-right">
|
<!-- /.col-sm-12 .col-md-6 -->
|
||||||
<div class="btn-group btn-page">
|
<div class="col-sm-12 text-right">
|
||||||
<button type="submit" class="btn btn-default" title="Save"><span
|
<div class="btn-group btn-page">
|
||||||
class="glyphicon glyphicon-floppy-disk"></span>
|
<button type="submit" class="btn btn-default" title="Save"><span
|
||||||
</button>
|
class="glyphicon glyphicon-floppy-disk"></span>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{# Notes and item shit #}
|
{# Notes and item shit #}
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="panel panel-default form-hws form-is_rig {% if object.pk and not object.is_rig %}hidden{% endif %}">
|
<div class="panel panel-default form-hws form-is_rig {% if object.pk and not object.is_rig %}hidden{% endif %}">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="form-group" data-toggle="tooltip"
|
<div class="form-group" data-toggle="tooltip" title="Notes on the event. This is only visible to keyholders, and is not displayed on the paperwork">
|
||||||
title="Notes on the event. This is only visible to keyholders, and is not displayed on the paperwork">
|
<label for="{{ form.notes.id_for_label }}">{{ form.notes.label }}</label>
|
||||||
<label for="{{ form.notes.id_for_label }}">{{ form.notes.label }}</label>
|
{% render_field form.notes class+="form-control" %}
|
||||||
{% render_field form.notes class+="form-control" %}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% include "RIGS/item_table.html" %}
|
|
||||||
</div>
|
</div>
|
||||||
|
{% include "RIGS/item_table.html" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-12 text-right form-hws form-is_rig {% if object.pk and not object.is_rig %}hidden{% endif %}">
|
</div>
|
||||||
<div class="btn-group btn-page">
|
<div class="col-sm-12 text-right form-hws form-is_rig {% if object.pk and not object.is_rig %}hidden{% endif %}">
|
||||||
<button type="submit" class="btn btn-default" title="Save"><span
|
<div class="btn-group btn-page">
|
||||||
class="glyphicon glyphicon-floppy-disk"></span>
|
<button type="submit" class="btn btn-default" title="Save"><span
|
||||||
</button>
|
class="glyphicon glyphicon-floppy-disk"></span>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% include 'RIGS/item_modal.html' %}
|
{% include 'RIGS/item_modal.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,96 +1,72 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load paginator from filters %}
|
{% load paginator from filters %}
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
{% block title %}Events for Invoice{% endblock %}
|
{% block title %}Events for Invoice{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
|
||||||
<script src="{% static "js/tooltip.js" %}"></script>
|
|
||||||
<script>
|
|
||||||
$(function () {
|
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<h2>Events for Invoice ({{ count }} Events, £ {{ total|floatformat:2 }})</h2>
|
<h2>Events for Invoice</h2>
|
||||||
<p>These events have happened, but paperwork has not yet been sent to treasury</p>
|
|
||||||
{% if is_paginated %}
|
{% if is_paginated %}
|
||||||
<div class="col-md-6 col-md-offset-6 col-sm-12 text-right">
|
<div class="col-md-6 col-md-offset-6 col-sm-12 text-right">
|
||||||
{% paginator %}
|
{% paginator %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="table-responsive col-sm-12">
|
<table class="table table-responsive table-hover">
|
||||||
<table class="table table-hover">
|
<thead>
|
||||||
<thead>
|
<tr>
|
||||||
<tr>
|
<th class="hiddenx-xs">#</th>
|
||||||
<th>Event #</th>
|
<th>Date</th>
|
||||||
<th>Start Date</th>
|
<th>Event</th>
|
||||||
<th>Event Name</th>
|
<th>Client</th>
|
||||||
<th>Client</th>
|
<th>Cost</th>
|
||||||
<th>Cost</th>
|
<th class="hidden-xs">MIC</th>
|
||||||
<th>MIC</th>
|
<th></th>
|
||||||
<th></th>
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for object in object_list %}
|
||||||
|
<tr class="
|
||||||
|
{% if object.cancelled %}
|
||||||
|
active text-muted
|
||||||
|
{% elif not object.is_rig %}
|
||||||
|
info
|
||||||
|
{% elif object.confirmed and object.mic %}
|
||||||
|
{# interpreated as (booked and mic) #}
|
||||||
|
success
|
||||||
|
{% elif object.mic %}
|
||||||
|
warning
|
||||||
|
{% else %}
|
||||||
|
danger
|
||||||
|
{% endif %}
|
||||||
|
">
|
||||||
|
<td class="hidden-xs"><a href="{% url 'event_detail' object.pk %}" target="_blank">N{{ object.pk|stringformat:"05d" }}</a></td>
|
||||||
|
<td>{{ object.end_date }}</td>
|
||||||
|
<td>{{ object.name }}</td>
|
||||||
|
<td>
|
||||||
|
{% if object.organisation %}
|
||||||
|
{{ object.organisation.name }}
|
||||||
|
{% else %}
|
||||||
|
{{ object.person.name }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>{{ object.sum_total|floatformat:2 }}</td>
|
||||||
|
<td class="text-center">
|
||||||
|
{{ object.mic.initials }}<br/>
|
||||||
|
<img src="{{ object.mic.profile_picture }}" class="event-mic-photo"/>
|
||||||
|
</td>
|
||||||
|
<td class="text-right">
|
||||||
|
<a href="{% url 'invoice_event' object.pk %}" target="_blank" class="btn btn-default">
|
||||||
|
<span class="glyphicon glyphicon-gbp"></span>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
{% endfor %}
|
||||||
<tbody>
|
</tbody>
|
||||||
{% for object in object_list %}
|
</table>
|
||||||
<tr class="
|
|
||||||
{% if object.cancelled %}
|
|
||||||
active text-muted
|
|
||||||
{% elif not object.is_rig %}
|
|
||||||
info
|
|
||||||
{% elif object.confirmed and object.mic %}
|
|
||||||
{# interpreated as (booked and mic) #}
|
|
||||||
success
|
|
||||||
{% elif object.mic %}
|
|
||||||
warning
|
|
||||||
{% else %}
|
|
||||||
danger
|
|
||||||
{% endif %}
|
|
||||||
">
|
|
||||||
<td><a href="{% url 'event_detail' object.pk %}">N{{ object.pk|stringformat:"05d" }}</a><br>
|
|
||||||
<span class="text-muted">{{ object.get_status_display }}</span></td>
|
|
||||||
<td>{{ object.start_date }}</td>
|
|
||||||
<td>{{ object.name }}</td>
|
|
||||||
<td>
|
|
||||||
{% if object.organisation %}
|
|
||||||
{{ object.organisation.name }}
|
|
||||||
<br>
|
|
||||||
<span class="text-muted">{{ object.organisation.union_account|yesno:'Internal,External' }}</span>
|
|
||||||
{% else %}
|
|
||||||
{{ object.person.name }}
|
|
||||||
<br>
|
|
||||||
<span class="text-muted">External</span>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</td>
|
|
||||||
<td>{{ object.sum_total|floatformat:2 }}</td>
|
|
||||||
<td class="text-center">
|
|
||||||
{% if object.mic %}
|
|
||||||
{{ object.mic.initials }}<br>
|
|
||||||
<img src="{{ object.mic.profile_picture }}" class="event-mic-photo"/>
|
|
||||||
{% else %}
|
|
||||||
<span class="glyphicon glyphicon-exclamation-sign"></span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td class="text-right">
|
|
||||||
<a href="{% url 'invoice_event' object.pk %}" class="btn btn-default" data-toggle="tooltip"
|
|
||||||
title="'Invoice' this event - click this when paperwork has been sent to treasury">
|
|
||||||
<span class="glyphicon glyphicon-gbp"></span>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% if is_paginated %}
|
{% if is_paginated %}
|
||||||
<div class="col-md-6 col-md-offset-6 col-sm-12 text-right">
|
<div class="col-md-6 col-md-offset-6 col-sm-12 text-right">
|
||||||
{% paginator %}
|
{% paginator %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -16,30 +16,29 @@
|
|||||||
<color id="DarkGray" RGB="#707070"/>
|
<color id="DarkGray" RGB="#707070"/>
|
||||||
</initialize>
|
</initialize>
|
||||||
|
|
||||||
<paraStyle name="style.para" fontName="OpenSans"/>
|
<paraStyle name="style.para" fontName="OpenSans" />
|
||||||
<paraStyle name="blockPara" spaceAfter="5" spaceBefore="5"/>
|
<paraStyle name="blockPara" spaceAfter="5" spaceBefore="5"/>
|
||||||
<paraStyle name="style.Heading1" fontName="OpenSans" fontSize="16" leading="18" spaceAfter="0"/>
|
<paraStyle name="style.Heading1" fontName="OpenSans" fontSize="16" leading="18" spaceAfter="0"/>
|
||||||
<paraStyle name="style.Heading2" fontName="OpenSans-Bold" fontSize="10" spaceAfter="2"/>
|
<paraStyle name="style.Heading2" fontName="OpenSans-Bold" fontSize="10" spaceAfter="2"/>
|
||||||
<paraStyle name="style.Heading3" fontName="OpenSans" fontSize="10" spaceAfter="0"/>
|
<paraStyle name="style.Heading3" fontName="OpenSans" fontSize="10" spaceAfter="0"/>
|
||||||
<paraStyle name="center" alignment="center"/>
|
<paraStyle name="center" alignment="center"/>
|
||||||
<paraStyle name="invoice-head" alignment="center" fontName="OpenSans-Bold" fontSize="16" leading="18"
|
<paraStyle name="invoice-head" alignment="center" fontName="OpenSans-Bold" fontSize="16" leading="18" spaceAfter="0"/>
|
||||||
spaceAfter="0"/>
|
|
||||||
|
|
||||||
<paraStyle name="style.event_description" fontName="OpenSans" textColor="DarkGray"/>
|
<paraStyle name="style.event_description" fontName="OpenSans" textColor="DarkGray" />
|
||||||
<paraStyle name="style.item_description" fontName="OpenSans" textColor="DarkGray" leftIndent="10"/>
|
<paraStyle name="style.item_description" fontName="OpenSans" textColor="DarkGray" leftIndent="10" />
|
||||||
<paraStyle name="style.specific_description" fontName="OpenSans" textColor="DarkGray" fontSize="10"/>
|
<paraStyle name="style.specific_description" fontName="OpenSans" textColor="DarkGray" fontSize="10" />
|
||||||
<paraStyle name="style.times" fontName="OpenSans" fontSize="10"/>
|
<paraStyle name="style.times" fontName="OpenSans" fontSize="10" />
|
||||||
<paraStyle name="style.invoice_titles" fontName="OpenSans-Bold" fontSize="10"/>
|
<paraStyle name="style.invoice_titles" fontName="OpenSans-Bold" fontSize="10" />
|
||||||
<paraStyle name="style.invoice_numbers" fontName="OpenSans" fontSize="10"/>
|
<paraStyle name="style.invoice_numbers" fontName="OpenSans" fontSize="10" />
|
||||||
|
|
||||||
<blockTableStyle id="eventSpecifics">
|
<blockTableStyle id="eventSpecifics">
|
||||||
<blockValign value="top"/>
|
<blockValign value="top"/>
|
||||||
<lineStyle kind="LINEAFTER" colorName="LightGrey" start="0,0" stop="1,0" thickness="1"/>
|
<lineStyle kind="LINEAFTER" colorName="LightGrey" start="0,0" stop="1,0" thickness="1"/>
|
||||||
</blockTableStyle>
|
</blockTableStyle>
|
||||||
|
|
||||||
<blockTableStyle id="invoiceLayout">
|
<blockTableStyle id="invoiceLayout">
|
||||||
<blockValign value="top"/>
|
<blockValign value="top"/>
|
||||||
|
|
||||||
</blockTableStyle>
|
</blockTableStyle>
|
||||||
|
|
||||||
<blockTableStyle id="eventDetails">
|
<blockTableStyle id="eventDetails">
|
||||||
@@ -72,7 +71,7 @@
|
|||||||
</blockTableStyle>
|
</blockTableStyle>
|
||||||
|
|
||||||
<blockTableStyle id="signatureTable">
|
<blockTableStyle id="signatureTable">
|
||||||
<blockTopPadding length="20"/>
|
<blockTopPadding length="20" />
|
||||||
<blockLeftPadding start="0,0" stop="0,-1" length="0"/>
|
<blockLeftPadding start="0,0" stop="0,-1" length="0"/>
|
||||||
<lineStyle kind="linebelow" start="1,0" stop="1,0" colorName="black"/>
|
<lineStyle kind="linebelow" start="1,0" stop="1,0" colorName="black"/>
|
||||||
<lineStyle kind="linebelow" start="3,0" stop="3,0" colorName="black"/>
|
<lineStyle kind="linebelow" start="3,0" stop="3,0" colorName="black"/>
|
||||||
@@ -80,64 +79,53 @@
|
|||||||
</blockTableStyle>
|
</blockTableStyle>
|
||||||
</stylesheet>
|
</stylesheet>
|
||||||
|
|
||||||
<template> {# Note: page is 595x842 points (1 point=1/72in) #}
|
<template > {# Note: page is 595x842 points (1 point=1/72in) #}
|
||||||
<pageTemplate id="Headed">
|
<pageTemplate id="Headed" >
|
||||||
<pageGraphics>
|
<pageGraphics>
|
||||||
<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-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"/>
|
<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 #}
|
{# 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"/>
|
<image file="RIGS/static/imgs/paperwork/tec-logo.jpg" x="42" y="719" height="90" width="84"/>
|
||||||
|
|
||||||
|
<setFont name="OpenSans-Bold" size="22.5" leading="10"/>
|
||||||
|
<drawString x="137" y="780">TEC PA & Lighting</drawString>
|
||||||
|
|
||||||
<setFont name="OpenSans-Bold" size="22.5" leading="10"/>
|
<setFont name="OpenSans" size="9"/>
|
||||||
<drawString x="137" y="780">TEC PA & Lighting</drawString>
|
<drawString x="137" y="760">Portland Building, University Park, Nottingham, NG7 2RD</drawString>
|
||||||
|
<drawString x="137" y="746">www.nottinghamtec.co.uk</drawString>
|
||||||
|
<drawString x="265" y="746">info@nottinghamtec.co.uk</drawString>
|
||||||
|
<drawString x="137" y="732">Phone: (0115) 846 8720</drawString>
|
||||||
|
|
||||||
<setFont name="OpenSans" size="9"/>
|
|
||||||
<drawString x="137" y="760">Portland Building, University Park, Nottingham, NG7 2RD</drawString>
|
|
||||||
<drawString x="137" y="746">www.nottinghamtec.co.uk</drawString>
|
|
||||||
<drawString x="265" y="746">info@nottinghamtec.co.uk</drawString>
|
|
||||||
<drawString x="137" y="732">Phone: (0115) 846 8720</drawString>
|
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<setFont name="OpenSans" size="7" />
|
||||||
|
<drawCenteredString x="302.5" y="26">[Paperwork generated by {{current_user.name}} | {% now "d/m/Y H:i" %} | {{object.current_version_id}}]</drawCenteredString>
|
||||||
|
</pageGraphics>
|
||||||
|
|
||||||
|
<frame id="main" x1="50" y1="65" width="495" height="645"/>
|
||||||
|
</pageTemplate>
|
||||||
|
|
||||||
<setFont name="OpenSans" size="10"/>
|
<pageTemplate id="Main">
|
||||||
{% if not invoice %}
|
<pageGraphics>
|
||||||
<drawCenteredString x="302.5" y="50">[{{ copy }} Copy]</drawCenteredString>{% endif %}
|
<image file="RIGS/static/imgs/paperwork/corner-tr.jpg" x="395" y="642" height="200" width="200"/>
|
||||||
<drawCenteredString x="302.5" y="38">[Page
|
<image file="RIGS/static/imgs/paperwork/corner-bl.jpg" x="0" y="0" height="200" width="200"/>
|
||||||
<pageNumber/>
|
|
||||||
of<getName id="lastPage" default="0"/>]
|
<setFont name="OpenSans" size="10"/>
|
||||||
</drawCenteredString>
|
{% if not invoice %}<drawCenteredString x="302.5" y="50">[{{ copy }} Copy]</drawCenteredString>{% endif %}
|
||||||
<setFont name="OpenSans" size="7"/>
|
<drawCenteredString x="302.5" y="38">[Page <pageNumber/> of <getName id="lastPage" default="0" />]</drawCenteredString>
|
||||||
<drawCenteredString x="302.5" y="26">[Paperwork generated by {{ current_user.name }}
|
<setFont name="OpenSans" size="7" />
|
||||||
| {% now "d/m/Y H:i" %} | {{ object.current_version_id }}]
|
<drawCenteredString x="302.5" y="26">[Paperwork generated by {{current_user.name}} | {% now "d/m/Y H:i" %} | {{object.current_version_id}}]</drawCenteredString>
|
||||||
</drawCenteredString>
|
</pageGraphics>
|
||||||
</pageGraphics>
|
<frame id="main" x1="50" y1="65" width="495" height="727"/>
|
||||||
|
</pageTemplate>
|
||||||
<frame id="main" x1="50" y1="65" width="495" height="645"/>
|
|
||||||
</pageTemplate>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
<setFont name="OpenSans" size="7"/>
|
|
||||||
<drawCenteredString x="302.5" y="26">[Paperwork generated by {{ current_user.name }}
|
|
||||||
| {% now "d/m/Y H:i" %} | {{ object.current_version_id }}]
|
|
||||||
</drawCenteredString>
|
|
||||||
</pageGraphics>
|
|
||||||
<frame id="main" x1="50" y1="65" width="495" height="727"/>
|
|
||||||
</pageTemplate>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<story firstPageTemplate="Headed">
|
<story firstPageTemplate="Headed">
|
||||||
{% include "RIGS/event_print_page.xml" %}
|
{% include "RIGS/event_print_page.xml" %}
|
||||||
</story>
|
</story>
|
||||||
|
|
||||||
</document>
|
</document>
|
||||||
@@ -3,25 +3,21 @@
|
|||||||
|
|
||||||
{% if invoice %}
|
{% if invoice %}
|
||||||
|
|
||||||
<blockTable style="invoiceLayout" colWidths="330,165">
|
<blockTable style="invoiceLayout" colWidths="330,165">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h1>
|
<h1><b>N{{ object.pk|stringformat:"05d" }}:</b> '{{ object.name }}'<small></small></h1>
|
||||||
<b>N{{ object.pk|stringformat:"05d" }}:</b>
|
|
||||||
'{{ object.name }}'
|
|
||||||
<small></small>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<para style="style.event_description">
|
<para style="style.event_description">
|
||||||
<b>{{ object.start_date|date:"D jS N Y" }}</b>
|
<b>{{object.start_date|date:"D jS N Y"}}</b>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<keepInFrame>
|
<keepInFrame>
|
||||||
<para style="style.event_description">
|
<para style="style.event_description">
|
||||||
{{ object.description|default_if_none:""|linebreaksbr }}
|
{{ object.description|default_if_none:""|linebreaksbr }}
|
||||||
</para>
|
</para>
|
||||||
</keepInFrame>
|
</keepInFrame>
|
||||||
|
|
||||||
{% if invoice %}
|
{% if invoice %}
|
||||||
@@ -32,25 +28,19 @@
|
|||||||
<spacer length="10"/>
|
<spacer length="10"/>
|
||||||
<blockTable style="eventDetails" colWidths="100,175">
|
<blockTable style="eventDetails" colWidths="100,175">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td><para style="invoice_titles">Invoice Number</para></td>
|
||||||
<para style="invoice_titles">Invoice Number</para>
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
<para style="invoice_numbers">{{ invoice.pk|stringformat:"05d" }}</para>
|
<para style="invoice_numbers">{{ invoice.pk|stringformat:"05d" }}</para>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td><para style="invoice_titles">Invoice Date</para></td>
|
||||||
<para style="invoice_titles">Invoice Date</para>
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
<para style="invoice_numbers">{{ invoice.invoice_date|date:"d/m/Y" }}</para>
|
<para style="invoice_numbers">{{ invoice.invoice_date|date:"d/m/Y" }}</para>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td><para style="invoice_titles">PO Number</para></td>
|
||||||
<para style="invoice_titles">PO Number</para>
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
<para style="invoice_numbers">{{ object.purchase_order|default_if_none:"" }}</para>
|
<para style="invoice_numbers">{{ object.purchase_order|default_if_none:"" }}</para>
|
||||||
</td>
|
</td>
|
||||||
@@ -58,100 +48,94 @@
|
|||||||
|
|
||||||
</blockTable>
|
</blockTable>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</blockTable>
|
</blockTable>
|
||||||
|
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<spacer length="15"/>
|
<spacer length="15"/>
|
||||||
<blockTable style="eventSpecifics" colWidths="165,165,165">
|
<blockTable style="eventSpecifics" colWidths="165,165,165">
|
||||||
<tr>
|
<tr>
|
||||||
<td leftPadding="0">
|
<td leftPadding="0">
|
||||||
<h2>Hirer</h2>
|
<h2>Hirer</h2>
|
||||||
<h3>{{ object.person.name }}</h3>
|
<h3>{{ object.person.name }}</h3>
|
||||||
<h3>{{ object.organisation.name|default_if_none:"" }}</h3>
|
<h3>{{ object.organisation.name|default_if_none:"" }}</h3>
|
||||||
{% if invoice %}
|
{% if invoice %}
|
||||||
|
<keepInFrame>
|
||||||
|
{% if object.organisation.address %}
|
||||||
|
<para style="specific_description">{{ object.organisation.address|default_if_none:""|linebreaksbr }}</para>
|
||||||
|
{% elif object.person.address %}
|
||||||
|
<para style="specific_description">{{ object.person.address|default_if_none:""|linebreaksbr }}</para>
|
||||||
|
{% endif %}
|
||||||
|
</keepInFrame>
|
||||||
|
{% endif %}
|
||||||
|
<keepInFrame>
|
||||||
|
{% if object.person.phone %}
|
||||||
|
<para style="specific_description">{{ object.person.phone }}</para>
|
||||||
|
{% elif object.organisation.phone %}
|
||||||
|
<para style="specific_description">{{ object.organisation.phone }}</para>
|
||||||
|
{% endif %}
|
||||||
|
</keepInFrame>
|
||||||
|
<keepInFrame>
|
||||||
|
{% if invoice %}
|
||||||
|
{% if object.organisation.email %}
|
||||||
|
<para style="specific_description">{{ object.organisation.email }}</para>
|
||||||
|
{% elif object.person.email %}
|
||||||
|
<para style="specific_description">{{ object.person.email }}</para>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% if object.person.email %}
|
||||||
|
<para style="specific_description">{{ object.person.email }}</para>
|
||||||
|
{% elif object.organisation.email %}
|
||||||
|
<para style="specific_description">{{ object.organisation.email }}</para>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</keepInFrame>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<h2>Venue</h2>
|
||||||
|
<h3>{{ object.venue.name }}</h3>
|
||||||
|
{% if not invoice %}
|
||||||
<keepInFrame>
|
<keepInFrame>
|
||||||
{% if object.organisation.address %}
|
<para style="specific_description">{{ object.venue.address|default_if_none:""|linebreaksbr }}</para>
|
||||||
<para style="specific_description">{{ object.organisation.address|default_if_none:""|linebreaksbr }}</para>
|
|
||||||
{% elif object.person.address %}
|
|
||||||
<para style="specific_description">{{ object.person.address|default_if_none:""|linebreaksbr }}</para>
|
|
||||||
{% endif %}
|
|
||||||
</keepInFrame>
|
</keepInFrame>
|
||||||
{% endif %}
|
|
||||||
<keepInFrame>
|
|
||||||
{% if object.person.phone %}
|
|
||||||
<para style="specific_description">{{ object.person.phone }}</para>
|
|
||||||
{% elif object.organisation.phone %}
|
|
||||||
<para style="specific_description">{{ object.organisation.phone }}</para>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</keepInFrame>
|
</td>
|
||||||
<keepInFrame>
|
<td rightPadding="0">
|
||||||
{% if invoice %}
|
|
||||||
{% if object.organisation.email %}
|
<h2>Timings</h2>
|
||||||
<para style="specific_description">{{ object.organisation.email }}</para>
|
<blockTable style="eventDetails" colWidths="55,75">
|
||||||
{% elif object.person.email %}
|
|
||||||
<para style="specific_description">{{ object.person.email }}</para>
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
{% if object.person.email %}
|
|
||||||
<para style="specific_description">{{ object.person.email }}</para>
|
|
||||||
{% elif object.organisation.email %}
|
|
||||||
<para style="specific_description">{{ object.organisation.email }}</para>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</keepInFrame>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<h2>Venue</h2>
|
|
||||||
<h3>{{ object.venue.name }}</h3>
|
|
||||||
{% if not invoice %}
|
|
||||||
<keepInFrame>
|
|
||||||
<para style="specific_description">{{ object.venue.address|default_if_none:""|linebreaksbr }}</para>
|
|
||||||
</keepInFrame>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td rightPadding="0">
|
|
||||||
|
|
||||||
<h2>Timings</h2>
|
|
||||||
<blockTable style="eventDetails" colWidths="55,75">
|
|
||||||
<tr>
|
|
||||||
<td leftPadding="0" topPadding="0">
|
|
||||||
<h3>Start</h3>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<para style="times">{{ object.start_time|time:"H:i" }}
|
|
||||||
{{ object.start_date|date:"d/m/Y" }}
|
|
||||||
</para>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td leftPadding="0">
|
|
||||||
<h3>End</h3>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<para style="times">{{ object.end_time|default_if_none:""|time:"H:i" }}
|
|
||||||
{{ object.end_date|date:"d/m/Y" }}
|
|
||||||
</para>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% if object.access_at and not invoice %}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td leftPadding="0">
|
<td leftPadding="0" topPadding="0"><h3>Start</h3></td>
|
||||||
<h3>Access</h3>
|
<td>
|
||||||
|
<para style="times">{{ object.start_time|time:"H:i" }}
|
||||||
|
{{ object.start_date|date:"d/m/Y" }}
|
||||||
|
</para>
|
||||||
</td>
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td leftPadding="0"><h3>End</h3></td>
|
||||||
|
<td>
|
||||||
|
<para style="times">{{ object.end_time|default_if_none:""|time:"H:i" }}
|
||||||
|
{{ object.end_date|date:"d/m/Y" }}
|
||||||
|
</para>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% if object.access_at and not invoice%}
|
||||||
|
<tr>
|
||||||
|
<td leftPadding="0"><h3>Access</h3></td>
|
||||||
<td>
|
<td>
|
||||||
<para style="times">{{ object.access_at|time:"H:i" }}
|
<para style="times">{{ object.access_at|time:"H:i" }}
|
||||||
{{ object.access_at|date:"d/m/Y" }}
|
{{ object.access_at|date:"d/m/Y" }}
|
||||||
</para>
|
</para>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</blockTable>
|
</blockTable>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</blockTable>
|
</blockTable>
|
||||||
|
|
||||||
<spacer length="15"/>
|
<spacer length="15"/>
|
||||||
@@ -190,11 +174,11 @@
|
|||||||
{% if item.description %}
|
{% if item.description %}
|
||||||
</para>
|
</para>
|
||||||
<para style="item_description">
|
<para style="item_description">
|
||||||
<em>{{ item.description|linebreaksbr }}</em>
|
<em>{{ item.description|linebreaksbr }}</em>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</para>
|
</para>
|
||||||
</td>
|
</td>
|
||||||
<td>£ {{ item.cost|floatformat:2 }}</td>
|
<td>£ {{ item.cost|floatformat:2 }}</td>
|
||||||
<td>{{ item.quantity }}</td>
|
<td>{{ item.quantity }}</td>
|
||||||
@@ -203,7 +187,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</blockTable>
|
</blockTable>
|
||||||
<keepTogether>
|
<keepTogether>
|
||||||
<blockTable style="totalTable" colWidths="300,115,80">
|
<blockTable style="totalTable" colWidths="300,115,80">
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% if not invoice %}VAT Registration Number: 170734807{% endif %}</td>
|
<td>{% if not invoice %}VAT Registration Number: 170734807{% endif %}</td>
|
||||||
<td>Total (ex. VAT)</td>
|
<td>Total (ex. VAT)</td>
|
||||||
@@ -212,9 +196,9 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
{% if not invoice %}
|
{% if not invoice %}
|
||||||
<para>
|
<para>
|
||||||
<b>The full hire fee is payable at least 10 days before the event.</b>
|
<b>The full hire fee is payable at least 10 days before the event.</b>
|
||||||
</para>
|
</para>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>VAT @ {{ object.vat_rate.as_percent|floatformat:2 }}%</td>
|
<td>VAT @ {{ object.vat_rate.as_percent|floatformat:2 }}%</td>
|
||||||
@@ -222,7 +206,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
{% if invoice %}
|
{% if invoice %}
|
||||||
VAT Registration Number: 170734807
|
VAT Registration Number: 170734807
|
||||||
@@ -230,7 +214,7 @@
|
|||||||
<b>This contract is not an invoice.</b>
|
<b>This contract is not an invoice.</b>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<para>
|
<para>
|
||||||
@@ -243,100 +227,92 @@
|
|||||||
</para>
|
</para>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</blockTable>
|
</blockTable>
|
||||||
</keepTogether>
|
</keepTogether>
|
||||||
{% if not invoice %}
|
{% if not invoice %}
|
||||||
<keepTogether>
|
<keepTogether>
|
||||||
<blockTable style="infoTable">
|
<blockTable style="infoTable">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<para>Bookings will
|
<para>Bookings will
|
||||||
<b>not</b>
|
<b>not</b>
|
||||||
be confirmed until payment is received and the contract is signed.
|
be confirmed until payment is received and the contract is signed.
|
||||||
</para>
|
</para>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>24 Hour Emergency Contacts: 07825 065681 and 07825 065678</td>
|
<td>24 Hour Emergency Contacts: 07825 065681 and 07825 065678</td>
|
||||||
</tr>
|
</tr>
|
||||||
</blockTable>
|
</blockTable>
|
||||||
</keepTogether>
|
</keepTogether>
|
||||||
<spacer length="15"/>
|
<spacer length="15"/>
|
||||||
<keepTogether>
|
<keepTogether>
|
||||||
|
|
||||||
<para style="blockPara">
|
<para style="blockPara">
|
||||||
<b>To be signed on booking:</b>
|
<b>To be signed on booking:</b>
|
||||||
</para>
|
</para>
|
||||||
{% if object.organisation.union_account %}
|
{% if object.organisation.union_account %}
|
||||||
<para style="blockPara">
|
<para style="blockPara">
|
||||||
<i>
|
<i>
|
||||||
I agree that am authorised to sign this invoice. I agree that I am the President/Treasurer of the hirer,
|
I agree that am authorised to sign this invoice. I agree that I am the President/Treasurer of the hirer, or
|
||||||
or
|
that I have provided written permission from either the President or Treasurer of the hirer stating that I can
|
||||||
that I have provided written permission from either the President or Treasurer of the hirer stating that
|
sign for this invoice.
|
||||||
I can
|
</i>
|
||||||
sign for this invoice.
|
|
||||||
</i>
|
|
||||||
</para>
|
</para>
|
||||||
<para style="blockPara">
|
<para style="blockPara">
|
||||||
<i>
|
<i>
|
||||||
I have read, understood and fully accepted the current conditions of hire. I agree to return any dry
|
I have read, understood and fully accepted the current conditions of hire. I agree to return any dry hire
|
||||||
hire
|
items to TEC PA & Lighting in the same condition at the end of the hire period.
|
||||||
items to TEC PA & Lighting in the same condition at the end of the hire period.
|
</i>
|
||||||
</i>
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para style="blockPara">
|
<para style="blockPara">
|
||||||
<b>
|
<b>
|
||||||
Conditions of hire attached and available on the TEC PA & Lighting website. E&OE
|
Conditions of hire attached and available on the TEC PA & Lighting website. E&OE
|
||||||
</b>
|
</b>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para style="blockPara">
|
<para style="blockPara">
|
||||||
Please return this form directly to TEC PA & Lighting and not the Students' Union Finance Department.
|
Please return this form directly to TEC PA & Lighting and not the Students' Union Finance Department.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<blockTable style="signatureTable" colWidths="70,100,325">
|
<blockTable style="signatureTable" colWidths="70,100,325">
|
||||||
<tr>
|
<tr>
|
||||||
<td>Account Code</td>
|
<td>Account Code</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
</blockTable>
|
</blockTable>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<para style="blockPara">
|
<para style="blockPara">
|
||||||
<i>
|
<i>
|
||||||
I, the hirer, have read, understand and fully accept the current conditions of hire. This document forms
|
I, the hirer, have read, understand and fully accept the current conditions of hire. This document forms a
|
||||||
a
|
binding contract between TEC PA & Lighting and the hirer, the aforementioned conditions of hire forming
|
||||||
binding contract between TEC PA & Lighting and the hirer, the aforementioned conditions of hire
|
an integral part of it.
|
||||||
forming
|
</i>
|
||||||
an integral part of it.
|
|
||||||
</i>
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para style="blockPara">
|
<para style="blockPara">
|
||||||
<b>
|
<b>
|
||||||
Conditions of hire attached and available on the TEC PA & Lighting website. E&OE
|
Conditions of hire attached and available on the TEC PA & Lighting website. E&OE
|
||||||
</b>
|
</b>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
{% include "RIGS/event_print_signature.xml" %}
|
{% include "RIGS/event_print_signature.xml" %}
|
||||||
<spacer length="10"/>
|
<spacer length="10"/>
|
||||||
<para style="blockPara">
|
<para style="blockPara">
|
||||||
<b>To be signed on the day of the event/hire:</b>
|
<b>To be signed on the day of the event/hire:</b>
|
||||||
</para>
|
</para>
|
||||||
<para style="blockPara">
|
<para style="blockPara">
|
||||||
<i>
|
<i>
|
||||||
I, the hirer, have received the goods/services as requested and in good order. I agree to return any dry
|
I, the hirer, have received the goods/services as requested and in good order. I agree to return any dry hire
|
||||||
hire
|
items to TEC PA & Lighting in a similar condition at the end of the hire period.
|
||||||
items to TEC PA & Lighting in a similar condition at the end of the hire period.
|
</i>
|
||||||
</i>
|
|
||||||
</para>
|
</para>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% include "RIGS/event_print_signature.xml" %}
|
{% include "RIGS/event_print_signature.xml" %}
|
||||||
</keepTogether>
|
</keepTogether>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<namedString id="lastPage">
|
<namedString id="lastPage"><pageNumber/></namedString>
|
||||||
<pageNumber/>
|
|
||||||
</namedString>
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<td>#</td>
|
<td class="hidden-xs">#</td>
|
||||||
<td>Event Date</td>
|
<td>Event Date</td>
|
||||||
<td>Event Details</td>
|
<td>Event Details</td>
|
||||||
<td>Event Timings</td>
|
<td>Event Timings</td>
|
||||||
@@ -23,11 +23,11 @@
|
|||||||
danger
|
danger
|
||||||
{% endif %}
|
{% endif %}
|
||||||
">
|
">
|
||||||
<td>{{ event.pk }}</td>
|
<td class="hidden-xs">{{ event.pk }}</td>
|
||||||
<td>
|
<td>
|
||||||
<div><strong>{{ event.start_date|date:"D d/m/Y" }}</strong></div>
|
<div><strong>{{ event.start_date|date:"D d/m/Y" }}</strong></div>
|
||||||
{% if event.end_date and event.end_date != event.start_date %}
|
{% if event.end_date and event.end_date != event.start_date %}
|
||||||
<div><strong>{{ event.end_date|date:"D d/m/Y" }}</strong></div>
|
<div><strong>{{ event.end_date|date:"D d/m/Y" }}</strong></div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<span class="text-muted">{{ event.get_status_display }}</span>
|
<span class="text-muted">{{ event.get_status_display }}</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -69,14 +69,13 @@
|
|||||||
{{ event.start_date|date:"(Y-m-d)" }}<br/>
|
{{ event.start_date|date:"(Y-m-d)" }}<br/>
|
||||||
</dd>
|
</dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if event.has_end_time %}
|
{% if event.has_end_time%}{% if event.start_date != event.end_date or event.start_time != event.end_time %}
|
||||||
{% if event.start_date != event.end_date or event.start_time != event.end_time %}
|
<dt>Event ends</dt>
|
||||||
<dt>Event ends</dt>
|
<dd>
|
||||||
<dd>
|
{{ event.end_time|date:"H:i" }}<br/>
|
||||||
{{ event.end_time|date:"H:i" }}<br/>
|
{{ event.end_date|date:"(Y-m-d)" }}
|
||||||
{{ event.end_date|date:"(Y-m-d)" }}
|
</dd>
|
||||||
</dd>
|
{% endif %}{% endif %}
|
||||||
{% endif %}{% endif %}
|
|
||||||
</dl>
|
</dl>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
@@ -100,4 +99,4 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -3,94 +3,76 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<h1>R
|
<h1>R<small>ig</small> I<small>nformation</small> G<small>athering</small> S<small>ystem</small></h1>
|
||||||
<small>ig</small>
|
|
||||||
I
|
|
||||||
<small>nformation</small>
|
|
||||||
G
|
|
||||||
<small>athering</small>
|
|
||||||
S
|
|
||||||
<small>ystem</small>
|
|
||||||
</h1>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<p><h4 class="list-group-item-heading" style="margin:0;">Welcome back {{ user.get_full_name }}, there
|
<p><h4 class="list-group-item-heading" style="margin:0;">Welcome back {{ user.get_full_name }}, there are {{ rig_count }} rigs coming up.</h4>
|
||||||
are {{ rig_count }} rigs coming up.</h4>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-{% if perms.RIGS.view_event %}6{% else %}12{% endif %}">
|
<div class="col-sm-{% if perms.RIGS.view_event %}6{% else %}12{% endif %}">
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h4 class="list-group-item-heading">Quick Links</h4>
|
<h4 class="list-group-item-heading">Quick Links</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
<a class="list-group-item" href="{% url 'rigboard' %}"><span
|
<a class="list-group-item" href="{% url 'rigboard' %}"><span class="glyphicon glyphicon-list"></span> Rigboard</a>
|
||||||
class="glyphicon glyphicon-list"></span> Rigboard</a>
|
<a class="list-group-item" href="{% url 'web_calendar' %}"><span class="glyphicon glyphicon-calendar"></span> Calendar</a>
|
||||||
<a class="list-group-item" href="{% url 'web_calendar' %}"><span
|
{% if perms.RIGS.add_event %}<a class="list-group-item" href="{% url 'event_create' %}"><span class="glyphicon glyphicon-plus"></span> New Event</a>{% endif %}
|
||||||
class="glyphicon glyphicon-calendar"></span> Calendar</a>
|
|
||||||
{% if perms.RIGS.add_event %}<a class="list-group-item" href="{% url 'event_create' %}"><span
|
|
||||||
class="glyphicon glyphicon-plus"></span> New Event</a>{% endif %}
|
|
||||||
|
|
||||||
<div class="list-group-item default"></div>
|
<div class="list-group-item default"></div>
|
||||||
|
|
||||||
<a class="list-group-item" href="//members.nottinghamtec.co.uk/forum" target="_blank"><span
|
<a class="list-group-item" href="//members.nottinghamtec.co.uk/forum" target="_blank"><span class="glyphicon glyphicon-link"></span> TEC Forum</a>
|
||||||
class="glyphicon glyphicon-link"></span> TEC Forum</a>
|
<a class="list-group-item" href="//members.nottinghamtec.co.uk/wiki" target="_blank"><span class="glyphicon glyphicon-link"></span> TEC Wiki</a>
|
||||||
<a class="list-group-item" href="//members.nottinghamtec.co.uk/wiki" target="_blank"><span
|
<a class="list-group-item" href="//members.nottinghamtec.co.uk/price" target="_blank"><span class="glyphicon glyphicon-link"></span> Price List</a>
|
||||||
class="glyphicon glyphicon-link"></span> TEC Wiki</a>
|
|
||||||
<a class="list-group-item" href="//members.nottinghamtec.co.uk/price" target="_blank"><span
|
|
||||||
class="glyphicon glyphicon-link"></span> Price List</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h4 class="panel-title">Search Rigboard</h4>
|
<h4 class="panel-title">Search Rigboard</h4>
|
||||||
|
</div>
|
||||||
|
<div class="list-group">
|
||||||
|
<div class="list-group-item">
|
||||||
|
<form class="form" role="form" action="{% url 'person_list' %}" method="GET">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="search" name="q" class="form-control" placeholder="Search People" />
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-search"></span></button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-group">
|
<div class="list-group-item">
|
||||||
<div class="list-group-item">
|
<form class="form" role="form" action="{% url 'organisation_list' %}" method="GET">
|
||||||
<form class="form" role="form" action="{% url 'person_list' %}" method="GET">
|
<div class="input-group">
|
||||||
<div class="input-group">
|
<input type="search" name="q" class="form-control" placeholder="Search Organisations" />
|
||||||
<input type="search" name="q" class="form-control" placeholder="Search People"/>
|
<span class="input-group-btn">
|
||||||
<span class="input-group-btn">
|
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-search"></span></button>
|
||||||
<button type="submit" class="btn btn-default"><span
|
|
||||||
class="glyphicon glyphicon-search"></span></button>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-group-item">
|
<div class="list-group-item">
|
||||||
<form class="form" role="form" action="{% url 'organisation_list' %}" method="GET">
|
<form class="form" role="form" action="{% url 'venue_list' %}" method="GET">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="search" name="q" class="form-control" placeholder="Search Organisations"/>
|
<input type="search" name="q" class="form-control" placeholder="Search Venues" />
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button type="submit" class="btn btn-default"><span
|
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-search"></span></button>
|
||||||
class="glyphicon glyphicon-search"></span></button>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
<div class="list-group-item">
|
|
||||||
<form class="form" role="form" action="{% url 'venue_list' %}" method="GET">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="search" name="q" class="form-control" placeholder="Search Venues"/>
|
|
||||||
<span class="input-group-btn">
|
|
||||||
<button type="submit" class="btn btn-default"><span
|
|
||||||
class="glyphicon glyphicon-search"></span></button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if perms.RIGS.view_event %}
|
|
||||||
<div class="col-sm-6">
|
|
||||||
{% include 'RIGS/activity_feed.html' %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% if perms.RIGS.view_event %}
|
||||||
|
<div class="col-sm-6" >
|
||||||
|
{% include 'RIGS/activity_feed.html' %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
{% extends 'base.html' %}
|
|
||||||
|
|
||||||
{% block title %}Delete payment on invoice {{ object.invoice.pk }}{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="col-sm-offset-2 col-sm-8">
|
|
||||||
<div class="alert alert-danger" role="alert">
|
|
||||||
<h2>Delete invoice {{ object.pk }}</h2>
|
|
||||||
|
|
||||||
<p>Are you sure you wish to delete invoice {{ object.pk }}?</p>
|
|
||||||
|
|
||||||
<p class="text-center"><strong>This action cannot be undone!</strong></p>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<form action="{{ action_link }}" method="post">{% csrf_token %}
|
|
||||||
<input type="hidden" name="next" value="{% url 'invoice_list' %}"/>
|
|
||||||
<a href="{% url 'invoice_detail' object.pk %}" class="btn btn-default col-sm-1">No</a>
|
|
||||||
<a href="{% url 'invoice_detail' object.pk %}" class="btn btn-default col-sm-1">No</a>
|
|
||||||
<a href="{% url 'invoice_detail' object.pk %}" class="btn btn-default col-sm-1">No</a>
|
|
||||||
<input type="submit" value="Yes" class="btn btn-danger col-sm-1"/>
|
|
||||||
<a href="{% url 'invoice_detail' object.pk %}" class="btn btn-default col-sm-1">No</a>
|
|
||||||
<a href="{% url 'invoice_detail' object.pk %}" class="btn btn-default col-sm-1">No</a>
|
|
||||||
<a href="{% url 'invoice_detail' object.pk %}" class="btn btn-default col-sm-1">No</a>
|
|
||||||
<a href="{% url 'invoice_detail' object.pk %}" class="btn btn-default col-sm-1">No</a>
|
|
||||||
<a href="{% url 'invoice_detail' object.pk %}" class="btn btn-default col-sm-1">No</a>
|
|
||||||
<a href="{% url 'invoice_detail' object.pk %}" class="btn btn-default col-sm-1">No</a>
|
|
||||||
<a href="{% url 'invoice_detail' object.pk %}" class="btn btn-default col-sm-1">No</a>
|
|
||||||
<a href="{% url 'invoice_detail' object.pk %}" class="btn btn-default col-sm-1">No</a>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -6,20 +6,16 @@
|
|||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<h2>Invoice {{ object.pk }} ({{ object.invoice_date|date:"d/m/Y" }})</h2>
|
<h2>Invoice {{ object.pk }} ({{ object.invoice_date|date:"d/m/Y"}})</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-4 text-right">
|
<div class="col-sm-4 text-right">
|
||||||
<div class="btn-group btn-page">
|
<div class="btn-group btn-page">
|
||||||
<a href="{% url 'invoice_delete' object.pk %}" class="btn btn-default" title="Void Invoice">
|
<a href="{% url 'invoice_void' object.pk %}" class="btn btn-default" title="Void Invoice">
|
||||||
<span class="glyphicon glyphicon-remove"></span> <span
|
<span class="glyphicon glyphicon-ban-circle"></span> <span
|
||||||
class="hidden-xs">Delete</span>
|
|
||||||
</a>
|
|
||||||
<a href="{% url 'invoice_void' object.pk %}" class="btn btn-default" title="Void Invoice">
|
|
||||||
<span class="glyphicon glyphicon-ban-circle"></span> <span
|
|
||||||
class="hidden-xs">Void</span>
|
class="hidden-xs">Void</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{% url 'invoice_print' object.pk %}" target="_blank" class="btn btn-default"><span
|
<a href="{% url 'invoice_print' object.pk %}" target="_blank" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-print"></span> <span
|
class="glyphicon glyphicon-print"></span> <span
|
||||||
class="hidden-xs">Print</span></a>
|
class="hidden-xs">Print</span></a>
|
||||||
</div>
|
</div>
|
||||||
@@ -42,11 +38,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<div class="panel panel-{% if object.is_closed %}success{% else %}warning{% endif %}">
|
<div class="panel panel-{% if object.void %}danger{% else %}info{% endif %}">
|
||||||
<div class="panel-heading">Event Details<span class="pull-right">
|
<div class="panel-heading">Event Details</div>
|
||||||
{% if object.void %}(VOID){% elif object.is_closed %}(PAID){% else %}(OUTSTANDING){% endif %}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
<dt>Event Number</dt>
|
<dt>Event Number</dt>
|
||||||
@@ -116,11 +109,6 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<tr>
|
|
||||||
<td class="text-right"><strong>Balance:</strong></td>
|
|
||||||
<td>{{ object.balance|floatformat:2 }}</td>
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -139,4 +127,4 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -5,79 +5,42 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<h2>{% block heading %}Invoices{% endblock %}</h2>
|
<h2>Invoices</h2>
|
||||||
{% block description %}{% endblock %}
|
|
||||||
{% if is_paginated %}
|
{% if is_paginated %}
|
||||||
<div class="col-md-6 col-md-offset-6 col-sm-12 text-right">
|
<div class="col-md-6 col-md-offset-6 col-sm-12 text-right">
|
||||||
{% paginator %}
|
{% paginator %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="table-responsive col-sm-12">
|
<table class="table table-responsive table-hover">
|
||||||
<table class="table table-hover">
|
<thead>
|
||||||
<thead>
|
<tr>
|
||||||
<tr>
|
<th>#</th>
|
||||||
<th>Invoice #</th>
|
<th>Event</th>
|
||||||
<th>Event</th>
|
<th>Invoice Date</th>
|
||||||
<th>Client</th>
|
<th>Balance</th>
|
||||||
<th>Event Date</th>
|
<th></th>
|
||||||
<th>Invoice Date</th>
|
</tr>
|
||||||
<th>Balance</th>
|
</thead>
|
||||||
<th></th>
|
<tbody>
|
||||||
|
{% for object in object_list %}
|
||||||
|
<tr class="{% if object.void %}danger{% elif object.balance == 0 %}success{% endif %}">
|
||||||
|
<td>{{ object.pk }}</td>
|
||||||
|
<td><a href="{% url 'event_detail' object.event.pk %}" target="_blank">N{{ object.event.pk|stringformat:"05d" }}</a>: {{ object.event.name }}</td>
|
||||||
|
<td>{{ object.invoice_date }}</td>
|
||||||
|
<td>{{ object.balance|floatformat:2 }}</td>
|
||||||
|
<td class="text-right">
|
||||||
|
<a href="{% url 'invoice_detail' object.pk %}" class="btn btn-default">
|
||||||
|
<span class="glyphicon glyphicon-pencil"></span>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
{% endfor %}
|
||||||
<tbody>
|
</tbody>
|
||||||
{% for object in object_list %}
|
</table>
|
||||||
<tr>
|
|
||||||
<td class="{% if object.is_closed %}success{% else %}warning{% endif %}">{{ object.pk }}<br>
|
|
||||||
<span class="text-muted">{% if object.void %}(VOID){% elif object.is_closed %}
|
|
||||||
(PAID){% else %}(O/S){% endif %}</span></td>
|
|
||||||
<td class="
|
|
||||||
{% if object.event.cancelled %}
|
|
||||||
active text-muted
|
|
||||||
{% elif not object.event.is_rig %}
|
|
||||||
info
|
|
||||||
{% elif object.event.confirmed and object.event.mic %}
|
|
||||||
{# interpreated as (booked and mic) #}
|
|
||||||
success
|
|
||||||
{% elif object.event.mic %}
|
|
||||||
warning
|
|
||||||
{% else %}
|
|
||||||
danger
|
|
||||||
{% endif %}
|
|
||||||
"><a
|
|
||||||
href="{% url 'event_detail' object.event.pk %}">N{{ object.event.pk|stringformat:"05d" }}</a>: {{ object.event.name }}
|
|
||||||
<br>
|
|
||||||
<span class="text-muted">{{ object.event.get_status_display }}{% if not object.event.mic %},
|
|
||||||
No MIC{% endif %}
|
|
||||||
</span></td>
|
|
||||||
</td>
|
|
||||||
<td>{% if object.event.organisation %}
|
|
||||||
{{ object.event.organisation.name }}
|
|
||||||
<br>
|
|
||||||
<span class="text-muted">{{ object.event.organisation.union_account|yesno:'Internal,External' }}</span>
|
|
||||||
{% else %}
|
|
||||||
{{ object.event.person.name }}
|
|
||||||
<br>
|
|
||||||
<span class="text-muted">External</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>{{ object.event.start_date }}</td>
|
|
||||||
<td>{{ object.invoice_date }}</td>
|
|
||||||
<td>{{ object.balance|floatformat:2 }}</td>
|
|
||||||
<td class="text-right">
|
|
||||||
<a href="{% url 'invoice_detail' object.pk %}" class="btn btn-default">
|
|
||||||
<span class="glyphicon glyphicon-pencil"></span>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% if is_paginated %}
|
{% if is_paginated %}
|
||||||
<div class="col-md-6 col-md-offset-6 col-sm-12 text-right">
|
<div class="col-md-6 col-md-offset-6 col-sm-12 text-right">
|
||||||
{% paginator %}
|
{% paginator %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{% extends 'RIGS/invoice_list.html' %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
Outstanding Invoices
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block heading %}
|
|
||||||
Outstanding Invoices ({{ count }} Events, £ {{ total|floatformat:2 }})
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block description %}
|
|
||||||
<p>Paperwork for these events has been sent to treasury, but the full balance has not yet appeared on a ledger</p>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{% extends 'RIGS/invoice_list.html' %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
Invoice Archive
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block heading %}
|
|
||||||
All Invoices
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block description %}
|
|
||||||
<p>This page displays all invoices: outstanding, paid, and void</p>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,25 +1,25 @@
|
|||||||
<tr id="item-{{ item.pk }}" data-pk="{{ item.pk }}" class="item_row">
|
|
||||||
<td>
|
<tr id="item-{{item.pk}}" data-pk="{{item.pk}}" class="item_row">
|
||||||
<span class="name">{{ item.name }}</span>
|
<td>
|
||||||
|
<span class="name">{{ item.name }}</span>
|
||||||
<div class="item-description">
|
<div class="item-description">
|
||||||
<em class="description">{{ item.description|linebreaksbr }}</em>
|
<em class="description">{{item.description|linebreaksbr}}</em>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>£ <span class="cost">{{ item.cost|floatformat:2 }}</span></td>
|
<td>£ <span class="cost">{{item.cost|floatformat:2}}</span></td>
|
||||||
<td class="quantity">{{ item.quantity }}</td>
|
<td class="quantity">{{item.quantity}}</td>
|
||||||
<td>£ <span class="sub-total" data-subtotal="{{ item.total_cost }}">{{ item.total_cost|floatformat:2 }}</span>
|
<td>£ <span class="sub-total" data-subtotal="{{item.total_cost}}">{{item.total_cost|floatformat:2}}</span></td>
|
||||||
</td>
|
{% if edit %}
|
||||||
{% if edit %}
|
<td class="vert-align text-right">
|
||||||
<td class="vert-align text-right">
|
<button type="button" class="item-edit btn btn-xs btn-default"
|
||||||
<button type="button" class="item-edit btn btn-xs btn-default"
|
data-pk="{{item.pk}}"
|
||||||
data-pk="{{ item.pk }}"
|
data-toggle="modal" data-target="#itemModal">
|
||||||
data-toggle="modal" data-target="#itemModal">
|
<span class="glyphicon glyphicon-edit"></span>
|
||||||
<span class="glyphicon glyphicon-edit"></span>
|
</button>
|
||||||
</button>
|
<button type="button" class="item-delete btn btn-xs btn-danger"
|
||||||
<button type="button" class="item-delete btn btn-xs btn-danger"
|
data-pk="{{item.pk}}">
|
||||||
data-pk="{{ item.pk }}">
|
<span class="glyphicon glyphicon-remove"></span>
|
||||||
<span class="glyphicon glyphicon-remove"></span>
|
</button>
|
||||||
</button>
|
</td>
|
||||||
</td>
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,73 +1,71 @@
|
|||||||
<div class="panel table-responsive">
|
<div class="panel table-responsive">
|
||||||
<table class="table table-hover" id="item-table" {% if edit %}data-orderurl="{#% url 'item_order' %#}"{% endif %}>
|
<table class="table table-hover" id="item-table" {% if edit %}data-orderurl="{#% url 'item_order' %#}"{% endif %}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Item</td>
|
<td>Item</td>
|
||||||
<td>Price</td>
|
<td>Price</td>
|
||||||
<td>Quantity</td>
|
<td>Quantity</td>
|
||||||
<td>Sub-total</td>
|
<td>Sub-total</td>
|
||||||
{% if edit %}
|
{% if edit %}
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<button type="button" class="btn btn-default btn-xs item-add"
|
<button type="button" class="btn btn-default btn-xs item-add"
|
||||||
data-url="{#% url eventitem_add object.pk %#}" data-toggle="modal"
|
data-url="{#% url eventitem_add object.pk %#}" data-toggle="modal"
|
||||||
data-target="#itemModal">
|
data-target="#itemModal">
|
||||||
<span class="glyphicon glyphicon-plus"></span>
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="item-table-body">
|
<tbody id="item-table-body">
|
||||||
{% for item in object.items.all %}
|
{% for item in object.items.all %}
|
||||||
{% include 'RIGS/item_row.html' %}
|
{% include 'RIGS/item_row.html' %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="3" colspan="2"></td>
|
<td rowspan="3" colspan="2"></td>
|
||||||
<td>Total (ex. VAT)</td>
|
<td>Total (ex. VAT)</td>
|
||||||
<td colspan="2">£ <span id="sumtotal">{{ object.sum_total|default:0|floatformat:2 }}</span></td>
|
<td colspan="2">£ <span id="sumtotal">{{object.sum_total|default:0|floatformat:2}}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
{% if not object.pk %}
|
{% if not object.pk %}
|
||||||
<td id="vat-rate" data-rate="{{ currentVAT.rate }}">VAT @
|
<td id="vat-rate" data-rate="{{currentVAT.rate}}">VAT @
|
||||||
{{ currentVAT.as_percent|floatformat }}% (TBC)
|
{{currentVAT.as_percent|floatformat}}% (TBC)</td>
|
||||||
</td>
|
{% else %}
|
||||||
{% else %}
|
<td id="vat-rate" data-rate="{{object.vat_rate.rate}}">VAT @
|
||||||
<td id="vat-rate" data-rate="{{ object.vat_rate.rate }}">VAT @
|
{{object.vat_rate.as_percent|floatformat|default:"TBD"}}%</td>
|
||||||
{{ object.vat_rate.as_percent|floatformat|default:"TBD" }}%
|
{% endif %}
|
||||||
</td>
|
<td colspan="2">£ <span id="vat">{{object.vat|default:0|floatformat:2}}</span></td>
|
||||||
{% endif %}
|
</tr>
|
||||||
<td colspan="2">£ <span id="vat">{{ object.vat|default:0|floatformat:2 }}</span></td>
|
<tr>
|
||||||
</tr>
|
<td>Total</td>
|
||||||
<tr>
|
<td colspan="2">£ <span id="total">{{object.total|default:0|floatformat:2}}</span></td>
|
||||||
<td>Total</td>
|
</tr>
|
||||||
<td colspan="2">£ <span id="total">{{ object.total|default:0|floatformat:2 }}</span></td>
|
</tfoot>
|
||||||
</tr>
|
</table>
|
||||||
</tfoot>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
<table class="hidden invisible">
|
<table class="hidden invisible">
|
||||||
<tr id="new-item-row" class="item_row">
|
<tr id="new-item-row" class="item_row">
|
||||||
<td>
|
<td>
|
||||||
<span class="name"></span>
|
<span class="name"></span>
|
||||||
<div class="item-description">
|
<div class="item-description">
|
||||||
<em class="description"></em>
|
<em class="description"></em>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>£ <span class="cost"></span></td>
|
<td>£ <span class="cost"></span></td>
|
||||||
<td class="quantity"></td>
|
<td class="quantity"></td>
|
||||||
<td>£ <span class="sub-total"></span></td>
|
<td>£ <span class="sub-total"></span></td>
|
||||||
{% if edit %}
|
{% if edit %}
|
||||||
<td class="vert-align text-right">
|
<td class="vert-align text-right">
|
||||||
<button type="button" class="item-edit btn btn-xs btn-default"
|
<button type="button" class="item-edit btn btn-xs btn-default"
|
||||||
data-toggle="modal" data-target="#itemModal">
|
data-toggle="modal" data-target="#itemModal">
|
||||||
<span class="glyphicon glyphicon-edit"></span>
|
<span class="glyphicon glyphicon-edit"></span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="item-delete btn btn-xs btn-danger">
|
<button type="button" class="item-delete btn btn-xs btn-danger">
|
||||||
<span class="glyphicon glyphicon-remove"></span>
|
<span class="glyphicon glyphicon-remove"></span>
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
{% load to_class_name from filters %}
|
{% load to_class_name from filters %}
|
||||||
{# pass in variable "object" to this template #}
|
{# pass in variable "object" to this template #}
|
||||||
|
|
||||||
<a title="{% if object.is_rig == False %}Non-rig{% elif object.dry_hire %}Dry Hire{% elif object.is_rig %}Rig{% else %}{{ object|to_class_name }}{% endif %} | '{{ object.name }}'"
|
<a title="{% if object.is_rig == False %}Non-rig{% elif object.dry_hire %}Dry Hire{% elif object.is_rig %}Rig{%else%}{{object|to_class_name}}{% endif %} | '{{object.name}}'" href="{{ object.get_absolute_url }}">{% if object.is_rig == False %}Non-rig{% elif object.dry_hire %}Dry Hire{% elif object.is_rig %}Rig{%else%}{{object|to_class_name}}{% endif %} | '{{object.name}}'</a>
|
||||||
href="{{ object.get_absolute_url }}">{% if object.is_rig == False %}Non-rig{% elif object.dry_hire %}Dry
|
|
||||||
Hire{% elif object.is_rig %}Rig{% else %}{{ object|to_class_name }}{% endif %} | '{{ object.name }}'</a>
|
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
<div class="btn-group btn-page">
|
<div class="btn-group btn-page">
|
||||||
<a href="{% url 'organisation_update' object.pk %}" class="btn btn-default"><span
|
<a href="{% url 'organisation_update' object.pk %}" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -29,8 +29,7 @@
|
|||||||
<dd><a href="tel:{{ object.phone }}">{{ object.phone }}</a></dd>
|
<dd><a href="tel:{{ object.phone }}">{{ object.phone }}</a></dd>
|
||||||
|
|
||||||
<dt>Email</dt>
|
<dt>Email</dt>
|
||||||
<dd><a href="mailto:{{ object.email }}"><span
|
<dd><a href="mailto:{{ object.email }}"><span class="overflow-ellipsis">{{ object.email }}</span></a></dd>
|
||||||
class="overflow-ellipsis">{{ object.email }}</span></a></dd>
|
|
||||||
|
|
||||||
<dt>Address</dt>
|
<dt>Address</dt>
|
||||||
<dd>{{ object.address|linebreaksbr }}</dd>
|
<dd>{{ object.address|linebreaksbr }}</dd>
|
||||||
@@ -40,7 +39,7 @@
|
|||||||
|
|
||||||
<dt>Union Account</dt>
|
<dt>Union Account</dt>
|
||||||
<dd>{{ object.union_account|yesno|capfirst }}</dd>
|
<dd>{{ object.union_account|yesno|capfirst }}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -51,10 +50,7 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
{% for person,count in object.persons %}
|
{% for person,count in object.persons %}
|
||||||
<a class="list-group-item"
|
<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>
|
||||||
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 %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -81,7 +77,7 @@
|
|||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
<div class="btn-group btn-page">
|
<div class="btn-group btn-page">
|
||||||
<a href="{% url 'organisation_update' object.pk %}" class="btn btn-default"><span
|
<a href="{% url 'organisation_update' object.pk %}" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="{% url 'organisation_history' object.pk %}" title="View Revision History">
|
<a href="{% url 'organisation_history' object.pk %}" title="View Revision History">
|
||||||
@@ -100,9 +96,9 @@
|
|||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
<div class="btn-group btn-page">
|
<div class="btn-group btn-page">
|
||||||
<a href="{% url 'organisation_detail' object.pk %}" class="btn btn-default"><span
|
<a href="{% url 'organisation_detail' object.pk %}" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-eye-open"></span> Open Page</a>
|
class="glyphicon glyphicon-eye-open"></span> Open Page</a>
|
||||||
<a href="{% url 'organisation_update' object.pk %}" class="btn btn-default"><span
|
<a href="{% url 'organisation_update' object.pk %}" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="{% url 'organisation_history' object.pk %}" title="View Revision History">
|
<a href="{% url 'organisation_history' object.pk %}" title="View Revision History">
|
||||||
@@ -112,4 +108,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-right col-sm-12">{% paginator %}</div>
|
<div class="text-right col-sm-12">{% paginator %}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
<td>{{ object.pk }}</td>
|
<td>{{ object.pk }}</td>
|
||||||
<td>{{ object.name }}</td>
|
<td>{{ object.name }}</td>
|
||||||
<td>{{ object.email }}</td>
|
<td>{{ object.email }}</td>
|
||||||
<td><a href="tel:{{ object.phone }}">{{ object.phone }}</a></td>
|
<td>{{ object.phone }}</td>
|
||||||
<td>{{ object.notes|yesno|capfirst }}</td>
|
<td>{{ object.notes|yesno|capfirst }}</td>
|
||||||
<td>{{ object.union_account|yesno|capfirst }}</td>
|
<td>{{ object.union_account|yesno|capfirst }}</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -67,4 +67,4 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="align-right">{% paginator %}</div>
|
<div class="align-right">{% paginator %}</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
<div class="btn-group btn-page">
|
<div class="btn-group btn-page">
|
||||||
<a href="{% url 'person_update' object.pk %}" class="btn btn-default"><span
|
<a href="{% url 'person_update' object.pk %}" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -29,15 +29,14 @@
|
|||||||
<dd><a href="tel:{{ object.phone }}">{{ object.phone }}</a></dd>
|
<dd><a href="tel:{{ object.phone }}">{{ object.phone }}</a></dd>
|
||||||
|
|
||||||
<dt>Email</dt>
|
<dt>Email</dt>
|
||||||
<dd><a href="mailto:{{ object.email }}"><span
|
<dd><a href="mailto:{{ object.email }}"><span class="overflow-ellipsis">{{ object.email }}</span></a></dd>
|
||||||
class="overflow-ellipsis">{{ object.email }}</span></a></dd>
|
|
||||||
|
|
||||||
<dt>Address</dt>
|
<dt>Address</dt>
|
||||||
<dd>{{ object.address|linebreaksbr }}</dd>
|
<dd>{{ object.address|linebreaksbr }}</dd>
|
||||||
|
|
||||||
<dt>Notes</dt>
|
<dt>Notes</dt>
|
||||||
<dd>{{ object.notes|linebreaksbr }}</dd>
|
<dd>{{ object.notes|linebreaksbr }}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -48,10 +47,7 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
{% for organisation,count in object.organisations %}
|
{% for organisation,count in object.organisations %}
|
||||||
<a class="list-group-item"
|
<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>
|
||||||
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 %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -78,7 +74,7 @@
|
|||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
<div class="btn-group btn-page">
|
<div class="btn-group btn-page">
|
||||||
<a href="{% url 'person_update' object.pk %}" class="btn btn-default"><span
|
<a href="{% url 'person_update' object.pk %}" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="{% url 'person_history' object.pk %}" title="View Revision History">
|
<a href="{% url 'person_history' object.pk %}" title="View Revision History">
|
||||||
@@ -97,9 +93,9 @@
|
|||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
<div class="btn-group btn-page">
|
<div class="btn-group btn-page">
|
||||||
<a href="{% url 'person_detail' object.pk %}" class="btn btn-default"><span
|
<a href="{% url 'person_detail' object.pk %}" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-eye-open"></span> Open Page</a>
|
class="glyphicon glyphicon-eye-open"></span> Open Page</a>
|
||||||
<a href="{% url 'person_update' object.pk %}" class="btn btn-default"><span
|
<a href="{% url 'person_update' object.pk %}" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="{% url 'person_history' object.pk %}" title="View Revision History">
|
<a href="{% url 'person_history' object.pk %}" title="View Revision History">
|
||||||
@@ -109,4 +105,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
<td>{{ person.pk }}</td>
|
<td>{{ person.pk }}</td>
|
||||||
<td>{{ person.name }}</td>
|
<td>{{ person.name }}</td>
|
||||||
<td>{{ person.email }}</td>
|
<td>{{ person.email }}</td>
|
||||||
<td><a href="tel:{{ person.phone }}">{{ person.phone }}</a></td>
|
<td>{{ person.phone }}</td>
|
||||||
<td>{{ person.notes|yesno|capfirst }}</td>
|
<td>{{ person.notes|yesno|capfirst }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'person_detail' person.pk %}" class="btn btn-default modal-href">
|
<a href="{% url 'person_detail' person.pk %}" class="btn btn-default modal-href">
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
{# pass in variable "profile" to this template #}
|
{# pass in variable "profile" to this template #}
|
||||||
|
|
||||||
<button title="{{ profile.name }}" type="button" class="btn btn-default btn-xs" data-container="body" data-html="true"
|
<button title="{{profile.name}}" type="button" class="btn btn-default btn-xs" data-container="body" data-html="true" data-trigger='hover focus' data-toggle="popover" data-content='
|
||||||
data-trigger='hover focus' data-toggle="popover" data-content='
|
<img src="{{profile.profile_picture}}" class="img-responsive img-rounded center-block" style="max-width:4em" />
|
||||||
<img src="{{ profile.profile_picture }}" class="img-responsive img-rounded center-block" style="max-width:4em" />
|
|
||||||
<dl class="dl-vertical">
|
<dl class="dl-vertical">
|
||||||
<dt>Email</dt>
|
<dt>Email</dt>
|
||||||
<dd>{{ profile.email }}</dd>
|
<dd>{{profile.email}}</dd>
|
||||||
|
|
||||||
<dt>Phone</dt>
|
<dt>Phone</dt>
|
||||||
<dd>{{ profile.phone }}</dd>
|
<dd>{{profile.phone}}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
'>{{ profile.first_name }}</button>
|
'>{{profile.first_name}}</button>
|
||||||
@@ -1,171 +1,157 @@
|
|||||||
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
||||||
|
|
||||||
{% block title %}RIGS Profile {{ object.pk }}{% endblock %}
|
{% block title %}RIGS Profile {{object.pk}}{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function() {
|
||||||
$('#urlParamForm').change(function () {
|
$('#urlParamForm').change(function(){
|
||||||
url = "?";
|
url = "?";
|
||||||
$('#urlParamForm *').filter(':input').each(function (index, value) {
|
$('#urlParamForm *').filter(':input').each(function(index, value){
|
||||||
defaultVal = $(value).data('default');
|
defaultVal = $(value).data('default');
|
||||||
param = $(value).val();
|
param = $(value).val();
|
||||||
val = $(value).prop('checked');
|
val = $(value).prop('checked');
|
||||||
|
|
||||||
if (val != defaultVal) {
|
if(val != defaultVal){
|
||||||
url = url + param + "=" + val + "&";
|
url = url+param+"="+val+"&";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ics_url = $('#cal-url').data('url') + url.substring(0, url.length - 1);
|
ics_url = $('#cal-url').data('url') + url.substring(0, url.length - 1);
|
||||||
$('#cal-url').text(ics_url);
|
$('#cal-url').text(ics_url);
|
||||||
|
|
||||||
gcal_url = $('#gcal-link').data('url') + encodeURIComponent(url.substring(0, url.length - 1));
|
gcal_url = $('#gcal-link').data('url') + encodeURIComponent(url.substring(0, url.length - 1));
|
||||||
$('#gcal-link').attr('href', gcal_url);
|
$('#gcal-link').attr('href',gcal_url);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#urlParamForm').change(); //Do the initial setting
|
$('#urlParamForm').change(); //Do the initial setting
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-10 col-md-offset-1">
|
<div class="col-md-10 col-md-offset-1">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<h3>{{object.name}}</h3>
|
||||||
|
</div>
|
||||||
|
{% if not request.is_ajax %}
|
||||||
|
{% if object.pk == user.pk %}
|
||||||
|
<div class="col-sm-6 text-right">
|
||||||
|
<div class="btn-group btn-page">
|
||||||
|
<a href="{% url 'profile_update_self' %}" class="btn btn-default">
|
||||||
|
Edit Profile <span class="glyphicon glyphicon-pencil"></span>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'password_change' %}" class="btn btn-default">
|
||||||
|
Change Password <span class="glyphicon glyphicon-lock"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
<div class="col-sm-8 ">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>First Name</dt>
|
||||||
|
<dd>{{object.first_name}}</dd>
|
||||||
|
|
||||||
<div class="col-sm-6">
|
<dt>Last Name</dt>
|
||||||
<h3>{{ object.name }}</h3>
|
<dd>{{object.last_name}}</dd>
|
||||||
</div>
|
|
||||||
{% if not request.is_ajax %}
|
|
||||||
{% if object.pk == user.pk %}
|
|
||||||
<div class="col-sm-6 text-right">
|
|
||||||
<div class="btn-group btn-page">
|
|
||||||
<a href="{% url 'profile_update_self' %}" class="btn btn-default">
|
|
||||||
Edit Profile <span class="glyphicon glyphicon-pencil"></span>
|
|
||||||
</a>
|
|
||||||
<a href="{% url 'password_change' %}" class="btn btn-default">
|
|
||||||
Change Password <span class="glyphicon glyphicon-lock"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
<div class="col-sm-8 ">
|
|
||||||
<dl class="dl-horizontal">
|
|
||||||
<dt>First Name</dt>
|
|
||||||
<dd>{{ object.first_name }}</dd>
|
|
||||||
|
|
||||||
<dt>Last Name</dt>
|
<dt>Email</dt>
|
||||||
<dd>{{ object.last_name }}</dd>
|
<dd>{{object.email}}</dd>
|
||||||
|
|
||||||
<dt>Email</dt>
|
<dt>Last Login</dt>
|
||||||
<dd>{{ object.email }}</dd>
|
<dd>{{object.last_login|date:"d/m/Y H:i"}}</dd>
|
||||||
|
|
||||||
<dt>Last Login</dt>
|
<dt>Date Joined</dt>
|
||||||
<dd>{{ object.last_login|date:"d/m/Y H:i" }}</dd>
|
<dd>{{object.date_joined|date:"d/m/Y H:i"}}</dd>
|
||||||
|
|
||||||
<dt>Date Joined</dt>
|
<dt>Initials</dt>
|
||||||
<dd>{{ object.date_joined|date:"d/m/Y H:i" }}</dd>
|
<dd>{{object.initials}}</dd>
|
||||||
|
|
||||||
<dt>Initials</dt>
|
<dt>Phone</dt>
|
||||||
<dd>{{ object.initials }}</dd>
|
<dd>{{object.phone}}</dd>
|
||||||
|
</dl>
|
||||||
|
{% if not request.is_ajax %}
|
||||||
|
{% if object.pk == user.pk %}
|
||||||
|
|
||||||
|
<div class="pull-right">
|
||||||
|
<a href="{% url 'reset_api_key' %}" class="btn btn-default">
|
||||||
|
{% if user.api_key %}Reset API Key{% else %}Generate API Key{% endif %}
|
||||||
|
<span class="glyphicon glyphicon-repeat"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4>Personal iCal Details</h4>
|
||||||
|
|
||||||
<dt>Phone</dt>
|
<dl class="dl-horizontal">
|
||||||
<dd><a href="tel:{{ object.phone }}">{{ object.phone }}</a></dd>
|
<dt>API Key</dt>
|
||||||
</dl>
|
<dd>
|
||||||
{% if not request.is_ajax %}
|
{% if user.api_key %}
|
||||||
{% if object.pk == user.pk %}
|
{{user.api_key}}
|
||||||
|
{% else %}
|
||||||
|
No API Key Generated
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
|
|
||||||
<div class="pull-right">
|
<dt>Calendar Options</dt>
|
||||||
<a href="{% url 'reset_api_key' %}" class="btn btn-default">
|
<dd>
|
||||||
{% if user.api_key %}Reset API Key{% else %}Generate API Key{% endif %}
|
<div class="well well-sm text-center">
|
||||||
<span class="glyphicon glyphicon-repeat"></span>
|
<form class="form-inline" id="urlParamForm">
|
||||||
</a>
|
<div class="form-group">
|
||||||
</div>
|
<label class="checkbox-inline">
|
||||||
|
<input type="checkbox" value="rig" data-default="true" checked> Rigs
|
||||||
|
</label>
|
||||||
|
<label class="checkbox-inline">
|
||||||
|
<input type="checkbox" value="non-rig" data-default="true" checked> Non-Rigs
|
||||||
|
</label>
|
||||||
|
<label class="checkbox-inline">
|
||||||
|
<input type="checkbox" value="dry-hire" data-default="true" checked> Dry-Hires
|
||||||
|
</label>
|
||||||
|
<label class="checkbox-inline">
|
||||||
|
<input type="checkbox" value="cancelled" data-default="false" > Cancelled
|
||||||
|
</label>
|
||||||
|
<label class="checkbox-inline">
|
||||||
|
<input type="checkbox" value="provisional" data-default="true" checked> Provisional
|
||||||
|
</label>
|
||||||
|
<label class="checkbox-inline">
|
||||||
|
<input type="checkbox" value="confirmed" data-default="true" checked> Confirmed/Booked
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</dd>
|
||||||
|
<dt>Calendar URL</dt>
|
||||||
|
<dd>
|
||||||
|
{% if user.api_key %}
|
||||||
|
<pre id="cal-url" data-url="http{{ request.is_secure|yesno:"s,"}}://{{ request.get_host }}{% url 'ics_calendar' api_pk=user.pk api_key=user.api_key %}"></pre>
|
||||||
|
<small><a id="gcal-link" data-url="http://www.google.com/calendar/render?cid=http{{ request.is_secure|yesno:"s,"}}://{{ request.get_host }}{% url 'ics_calendar' api_pk=user.pk api_key=user.api_key %}" href="">Click here</a> to add to google calendar.<br/>
|
||||||
|
To sync from google calendar to mobile device, visit <a href="https://www.google.com/calendar/syncselect" target="_blank">this page</a> on your device and tick "RIGS Calendar".</small>
|
||||||
|
{% else %}
|
||||||
|
<pre>No API Key Generated</pre>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<div class="center-block">
|
||||||
|
<img src="{{object.profile_picture}}" class="img-responsive img-rounded" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<h4>Personal iCal Details</h4>
|
</div>
|
||||||
|
|
||||||
<dl class="dl-horizontal">
|
<div class="row">
|
||||||
<dt>API Key</dt>
|
<div class="col-sm-12">
|
||||||
<dd>
|
<h4>Events</h4>
|
||||||
{% if user.api_key %}
|
{% with object.latest_events as events %}
|
||||||
{{ user.api_key }}
|
{% include 'RIGS/event_table.html' %}
|
||||||
{% else %}
|
{% endwith %}
|
||||||
No API Key Generated
|
</div>
|
||||||
{% endif %}
|
</div>
|
||||||
</dd>
|
</div>
|
||||||
|
</div>
|
||||||
<dt>Calendar Options</dt>
|
{% endblock %}
|
||||||
<dd>
|
|
||||||
<div class="well well-sm text-center">
|
|
||||||
<form class="form-inline" id="urlParamForm">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="checkbox-inline">
|
|
||||||
<input type="checkbox" value="rig" data-default="true" checked> Rigs
|
|
||||||
</label>
|
|
||||||
<label class="checkbox-inline">
|
|
||||||
<input type="checkbox" value="non-rig" data-default="true" checked>
|
|
||||||
Non-Rigs
|
|
||||||
</label>
|
|
||||||
<label class="checkbox-inline">
|
|
||||||
<input type="checkbox" value="dry-hire" data-default="true" checked>
|
|
||||||
Dry-Hires
|
|
||||||
</label>
|
|
||||||
<label class="checkbox-inline">
|
|
||||||
<input type="checkbox" value="cancelled" data-default="false"> Cancelled
|
|
||||||
</label>
|
|
||||||
<label class="checkbox-inline">
|
|
||||||
<input type="checkbox" value="provisional" data-default="true" checked>
|
|
||||||
Provisional
|
|
||||||
</label>
|
|
||||||
<label class="checkbox-inline">
|
|
||||||
<input type="checkbox" value="confirmed" data-default="true" checked>
|
|
||||||
Confirmed/Booked
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</dd>
|
|
||||||
<dt>Calendar URL</dt>
|
|
||||||
<dd>
|
|
||||||
{% if user.api_key %}
|
|
||||||
<pre id="cal-url" data-url="http{{ request.is_secure|yesno:"s," }}://
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{{ request.get_host }}{% url 'ics_calendar' api_pk=user.pk api_key=user.api_key %}"></pre>
|
|
||||||
<small><a id="gcal-link" data-url="https://support.google.com/calendar/answer/37100"
|
|
||||||
href="">Click here</a> for instructions on adding to google calendar.<br/>
|
|
||||||
To sync from google calendar to mobile device, visit <a
|
|
||||||
href="https://www.google.com/calendar/syncselect" target="_blank">this
|
|
||||||
page</a> on your device and tick "RIGS Calendar".
|
|
||||||
</small>
|
|
||||||
{% else %}
|
|
||||||
<pre>No API Key Generated</pre>
|
|
||||||
{% endif %}
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-sm-3">
|
|
||||||
<div class="center-block">
|
|
||||||
<img src="{{ object.profile_picture }}" class="img-responsive img-rounded"/>
|
|
||||||
</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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,77 +1,71 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load widget_tweaks %}
|
{% load widget_tweaks %}
|
||||||
|
|
||||||
{% block title %}Update Profile {{ object.name }}{% endblock %}
|
{% block title %}Update Profile {{object.name}}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-10 col-sm-offset-1">
|
<div class="col-sm-10 col-sm-offset-1">
|
||||||
{% include 'form_errors.html' %}
|
{% include 'form_errors.html' %}
|
||||||
<h3>Update Profile</h3>
|
<h3>Update Profile</h3>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<form action="{{ form.action|default:request.path }}" method="post"
|
<form action="{{form.action|default:request.path}}" method="post" class="form-horizontal">{% csrf_token %}
|
||||||
class="form-horizontal">{% csrf_token %}
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<label for="{{form.first_name.id_for_label}}" class="col-sm-4 control-label">{{form.first_name.label}}</label>
|
||||||
<label for="{{ form.first_name.id_for_label }}"
|
|
||||||
class="col-sm-4 control-label">{{ form.first_name.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
{% render_field form.first_name class+="form-control" placeholder=form.first_name.label %}
|
{% render_field form.first_name class+="form-control" placeholder=form.first_name.label %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="{{ form.last_name.id_for_label }}"
|
<label for="{{form.last_name.id_for_label}}" class="col-sm-4 control-label">{{form.last_name.label}}</label>
|
||||||
class="col-sm-4 control-label">{{ form.last_name.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
{% render_field form.last_name class+="form-control" placeholder=form.last_name.label %}
|
{% render_field form.last_name class+="form-control" placeholder=form.last_name.label %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="{{ form.email.id_for_label }}"
|
<label for="{{form.email.id_for_label}}" class="col-sm-4 control-label">{{form.email.label}}</label>
|
||||||
class="col-sm-4 control-label">{{ form.email.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
{% render_field form.email type="email" class+="form-control" placeholder=form.email.label %}
|
{% render_field form.email type="email" class+="form-control" placeholder=form.email.label %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="{{ form.initials.id_for_label }}"
|
<label for="{{form.initials.id_for_label}}" class="col-sm-4 control-label">{{form.initials.label}}</label>
|
||||||
class="col-sm-4 control-label">{{ form.initials.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
{% render_field form.initials class+="form-control" placeholder=form.initials.label %}
|
{% render_field form.initials class+="form-control" placeholder=form.initials.label %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="{{ form.phone.id_for_label }}"
|
<label for="{{form.phone.id_for_label}}" class="col-sm-4 control-label">{{form.phone.label}}</label>
|
||||||
class="col-sm-4 control-label">{{ form.phone.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
{% render_field form.phone type="tel" class+="form-control" placeholder=form.phone.label %}
|
{% render_field form.phone type="tel" class+="form-control" placeholder=form.phone.label %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input class="btn btn-primary pull-right" type="submit"/>
|
<input class="btn btn-primary pull-right" type="submit"/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-3 col-sm-offset-2">
|
<div class="col-sm-3 col-sm-offset-2">
|
||||||
<div class="center-block">
|
<div class="center-block">
|
||||||
<a href="https://gravatar.com/">
|
<a href="https://gravatar.com/">
|
||||||
<img src="{{ object.profile_picture }}" class="img-responsive img-rounded"/>
|
<img src="{{object.profile_picture}}" class="img-responsive img-rounded" />
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
Images hosted by Gravatar
|
Images hosted by Gravatar
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -8,14 +8,14 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<h3>Rigboard</h3>
|
<h3>Rigboard</h3>
|
||||||
</div>
|
</div>
|
||||||
{% if perms.RIGS.add_event %}
|
{% if perms.RIGS.add_event %}
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
<a href="{% url 'event_create' %}" class="btn btn-default pull-right">New <span
|
<a href="{% url 'event_create' %}" class="btn btn-default pull-right">New <span
|
||||||
class="glyphicon glyphicon-plus"></span></a>
|
class="glyphicon glyphicon-plus"></span></a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% comment %}
|
{% comment %}
|
||||||
{# Bring search back at a later date #}
|
{# Bring search back at a later date #}
|
||||||
<div class="col-sm-3 col-sm-offset-9">
|
<div class="col-sm-3 col-sm-offset-9">
|
||||||
@@ -33,4 +33,4 @@
|
|||||||
{% include 'RIGS/event_table.html' %}
|
{% include 'RIGS/event_table.html' %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
<div class="btn-group btn-page">
|
<div class="btn-group btn-page">
|
||||||
<a href="{% url 'venue_update' object.pk %}" class="btn btn-default"><span
|
<a href="{% url 'venue_update' object.pk %}" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -29,8 +29,7 @@
|
|||||||
<dd><a href="tel:{{ object.phone }}">{{ object.phone }}</a></dd>
|
<dd><a href="tel:{{ object.phone }}">{{ object.phone }}</a></dd>
|
||||||
|
|
||||||
<dt>Email</dt>
|
<dt>Email</dt>
|
||||||
<dd><a href="mailto:{{ object.email }}"><span
|
<dd><a href="mailto:{{ object.email }}"><span class="overflow-ellipsis">{{ object.email }}</span></a></dd>
|
||||||
class="overflow-ellipsis">{{ object.email }}</span></a></dd>
|
|
||||||
|
|
||||||
<dt>Address</dt>
|
<dt>Address</dt>
|
||||||
<dd>{{ object.address|linebreaksbr }}</dd>
|
<dd>{{ object.address|linebreaksbr }}</dd>
|
||||||
@@ -40,7 +39,7 @@
|
|||||||
|
|
||||||
<dt>Three Phase Available</dt>
|
<dt>Three Phase Available</dt>
|
||||||
<dd>{{ object.three_phase_available|yesno|capfirst }}</dd>
|
<dd>{{ object.three_phase_available|yesno|capfirst }}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -64,7 +63,7 @@
|
|||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
<div class="btn-group btn-page">
|
<div class="btn-group btn-page">
|
||||||
<a href="{% url 'venue_update' object.pk %}" class="btn btn-default"><span
|
<a href="{% url 'venue_update' object.pk %}" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="{% url 'venue_history' object.pk %}" title="View Revision History">
|
<a href="{% url 'venue_history' object.pk %}" title="View Revision History">
|
||||||
@@ -84,9 +83,9 @@
|
|||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
<div class="btn-group btn-page">
|
<div class="btn-group btn-page">
|
||||||
<a href="{% url 'venue_detail' object.pk %}" class="btn btn-default"><span
|
<a href="{% url 'venue_detail' object.pk %}" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-eye-open"></span> Open Page</a>
|
class="glyphicon glyphicon-eye-open"></span> Open Page</a>
|
||||||
<a href="{% url 'venue_update' object.pk %}" class="btn btn-default"><span
|
<a href="{% url 'venue_update' object.pk %}" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
class="glyphicon glyphicon-pencil"></span> Edit</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="{% url 'venue_history' object.pk %}" title="View Revision History">
|
<a href="{% url 'venue_history' object.pk %}" title="View Revision History">
|
||||||
@@ -96,4 +95,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -69,14 +69,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input class="btn btn-primary pull-right" type="submit"/>
|
<input class="btn btn-primary pull-right" type="submit"/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="text-right col-sm-12">{% paginator %}</div>
|
<div class="text-right col-sm-12">{% paginator %}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
<td>{{ object.pk }}</td>
|
<td>{{ object.pk }}</td>
|
||||||
<td>{{ object.name }}</td>
|
<td>{{ object.name }}</td>
|
||||||
<td>{{ object.email }}</td>
|
<td>{{ object.email }}</td>
|
||||||
<td><a href="tel:{{ object.phone }}">{{ object.phone }}</a></td>
|
<td>{{ object.phone }}</td>
|
||||||
<td>{{ object.notes|yesno|capfirst }}</td>
|
<td>{{ object.notes|yesno|capfirst }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'venue_detail' object.pk %}" class="btn btn-default modal-href">
|
<a href="{% url 'venue_detail' object.pk %}" class="btn btn-default modal-href">
|
||||||
@@ -66,4 +66,4 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="align-right">{% paginator %}</div>
|
<div class="align-right">{% paginator %}</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,18 +1,13 @@
|
|||||||
{% for change in version.field_changes %}
|
{% for change in version.field_changes %}
|
||||||
|
|
||||||
<button title="Changes to {{ change.field.verbose_name }}" type="button" class="btn btn-default btn-xs"
|
<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 %}
|
||||||
data-container="body" data-html="true" data-trigger='hover' data-toggle="popover"
|
|
||||||
data-content='{% spaceless %}
|
|
||||||
{% include "RIGS/version_changes_change.html" %}
|
{% include "RIGS/version_changes_change.html" %}
|
||||||
{% endspaceless %}'>{{ change.field.verbose_name }}</button>
|
{% endspaceless %}'>{{ change.field.verbose_name }}</button>
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% for itemChange in version.item_changes %}
|
{% for itemChange in version.item_changes %}
|
||||||
<button title="Changes to item '
|
<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 %}
|
||||||
{% 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">
|
<ul class="list-group">
|
||||||
{% for change in itemChange.changes %}
|
{% for change in itemChange.changes %}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
@@ -21,8 +16,6 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{% endspaceless %}'>item '{% if itemChange.new %}{{ itemChange.new.name }}{% else %}
|
{% endspaceless %}'>item '{% if itemChange.new %}{{ itemChange.new.name }}{% else %}{{ itemChange.old.name }}{% endif %}'</button>
|
||||||
{{ itemChange.old.name }}{% endif %}'
|
{% endfor %}
|
||||||
</button>
|
|
||||||
{% endfor %}
|
|
||||||
@@ -4,18 +4,18 @@
|
|||||||
{% if diff.type == "insert" %}
|
{% if diff.type == "insert" %}
|
||||||
<ins>{{ diff.text|linebreaksbr }}</ins>
|
<ins>{{ diff.text|linebreaksbr }}</ins>
|
||||||
{% elif diff.type == "delete" %}
|
{% elif diff.type == "delete" %}
|
||||||
<del>{{ diff.text|linebreaksbr }}</del>
|
<del>{{diff.text|linebreaksbr}}</del>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span>{{ diff.text|linebreaksbr }}</span>
|
<span>{{diff.text|linebreaksbr}}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if change.old %}
|
{% if change.old %}
|
||||||
<del {% if change.long %}class="overflow-ellipsis"{% endif %}>
|
<del {% if change.long %}class="overflow-ellipsis"{% endif %}>
|
||||||
{% if change.linebreaks %}
|
{% if change.linebreaks %}
|
||||||
{{ change.old|linebreaksbr }}
|
{{change.old|linebreaksbr}}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ change.old }}
|
{{change.old}}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</del>
|
</del>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -25,9 +25,9 @@
|
|||||||
{% if change.new %}
|
{% if change.new %}
|
||||||
<ins {% if change.long %}class="overflow-ellipsis"{% endif %}>
|
<ins {% if change.long %}class="overflow-ellipsis"{% endif %}>
|
||||||
{% if change.linebreaks %}
|
{% if change.linebreaks %}
|
||||||
{{ change.new|linebreaksbr }}
|
{{change.new|linebreaksbr}}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ change.new }}
|
{{change.new}}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ins>
|
</ins>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -3,34 +3,32 @@
|
|||||||
{% load paginator from filters %}
|
{% load paginator from filters %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block title %}{{ object|to_class_name }} {{ object.pk|stringformat:"05d" }} - Revision History{% endblock %}
|
{% block title %}{{object|to_class_name}} {{ object.pk|stringformat:"05d" }} - Revision History{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
<script src="{% static "js/tooltip.js" %}"></script>
|
<script src="{% static "js/tooltip.js" %}"></script>
|
||||||
<script src="{% static "js/popover.js" %}"></script>
|
<script src="{% static "js/popover.js" %}"></script>
|
||||||
<script>
|
<script>
|
||||||
$(function () {
|
$(function () {
|
||||||
$('[data-toggle="popover"]').popover().click(function () {
|
$('[data-toggle="popover"]').popover().click(function(){
|
||||||
if ($(this).attr('href')) {
|
if($(this).attr('href')){
|
||||||
window.location.href = $(this).attr('href');
|
window.location.href = $(this).attr('href');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<h3>
|
<h3><a href="{{ object.get_absolute_url }}">{{object|to_class_name}} {{ object.pk|stringformat:"05d" }}</a> - Revision History</h3>
|
||||||
<a href="{{ object.get_absolute_url }}">{{ object|to_class_name }} {{ object.pk|stringformat:"05d" }}</a>
|
|
||||||
- Revision History</h3>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="text-right col-sm-12">{% paginator %}</div>
|
<div class="text-right col-sm-12">{% paginator %}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Date</td>
|
<td>Date</td>
|
||||||
@@ -41,29 +39,29 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for version in object_list %}
|
{% for version in object_list %}
|
||||||
{% if version.item_changes or version.field_changes or version.old == None %}
|
{% if version.item_changes or version.field_changes or version.old == None %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ version.revision.date_created }}</td>
|
<td>{{ version.revision.date_created }}</td>
|
||||||
<td>{{ version.version.pk }}|{{ version.revision.pk }}</td>
|
<td>{{ version.version.pk }}|{{ version.revision.pk }}</td>
|
||||||
<td>{{ version.revision.user.name }}</td>
|
<td>{{ version.revision.user.name }}</td>
|
||||||
<td>
|
<td>
|
||||||
{% if version.old == None %}
|
{% if version.old == None %}
|
||||||
{{ object|to_class_name }} Created
|
{{object|to_class_name}} Created
|
||||||
{% else %}
|
{% else %}
|
||||||
{% include 'RIGS/version_changes.html' %}
|
{% include 'RIGS/version_changes.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ version.revision.comment }}
|
{{ version.revision.comment }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="align-right">{% paginator %}</div>
|
<div class="align-right">{% paginator %}</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,21 +1,18 @@
|
|||||||
from django import forms
|
|
||||||
from django import template
|
from django import template
|
||||||
|
from django import forms
|
||||||
from django.forms.forms import NON_FIELD_ERRORS
|
from django.forms.forms import NON_FIELD_ERRORS
|
||||||
from django.forms.utils import ErrorDict
|
from django.forms.utils import ErrorDict
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def multiply(value, arg):
|
def multiply(value, arg):
|
||||||
return value * arg
|
return value*arg
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def to_class_name(value):
|
def to_class_name(value):
|
||||||
return value.__class__.__name__
|
return value.__class__.__name__
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def nice_errors(form, non_field_msg='General form errors'):
|
def nice_errors(form, non_field_msg='General form errors'):
|
||||||
nice_errors = ErrorDict()
|
nice_errors = ErrorDict()
|
||||||
@@ -28,7 +25,6 @@ def nice_errors(form, non_field_msg='General form errors'):
|
|||||||
nice_errors[key] = errors
|
nice_errors[key] = errors
|
||||||
return nice_errors
|
return nice_errors
|
||||||
|
|
||||||
|
|
||||||
def paginator(context, adjacent_pages=3):
|
def paginator(context, adjacent_pages=3):
|
||||||
"""
|
"""
|
||||||
To be used in conjunction with the object_list generic view.
|
To be used in conjunction with the object_list generic view.
|
||||||
@@ -45,7 +41,7 @@ def paginator(context, adjacent_pages=3):
|
|||||||
endPage = page.number + adjacent_pages + 1
|
endPage = page.number + adjacent_pages + 1
|
||||||
if endPage >= paginator.num_pages - 1: endPage = paginator.num_pages + 1
|
if endPage >= paginator.num_pages - 1: endPage = paginator.num_pages + 1
|
||||||
page_numbers = [n for n in range(startPage, endPage) \
|
page_numbers = [n for n in range(startPage, endPage) \
|
||||||
if n > 0 and n <= paginator.num_pages]
|
if n > 0 and n <= paginator.num_pages]
|
||||||
|
|
||||||
dict = {
|
dict = {
|
||||||
'request': context['request'],
|
'request': context['request'],
|
||||||
@@ -61,29 +57,27 @@ def paginator(context, adjacent_pages=3):
|
|||||||
'has_next': page.has_next(),
|
'has_next': page.has_next(),
|
||||||
'has_previous': page.has_previous(),
|
'has_previous': page.has_previous(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if page.has_next():
|
if page.has_next():
|
||||||
dict['next'] = page.next_page_number()
|
dict['next'] = page.next_page_number()
|
||||||
if page.has_previous():
|
if page.has_previous():
|
||||||
dict['previous'] = page.previous_page_number()
|
dict['previous'] = page.previous_page_number()
|
||||||
|
|
||||||
return dict
|
return dict
|
||||||
|
|
||||||
|
|
||||||
register.inclusion_tag('pagination.html', takes_context=True)(paginator)
|
register.inclusion_tag('pagination.html', takes_context=True)(paginator)
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def url_replace(request, field, value):
|
def url_replace(request, field, value):
|
||||||
|
|
||||||
dict_ = request.GET.copy()
|
dict_ = request.GET.copy()
|
||||||
|
|
||||||
dict_[field] = value
|
dict_[field] = value
|
||||||
|
|
||||||
return dict_.urlencode()
|
return dict_.urlencode()
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def orderby(request, field, attr):
|
def orderby(request, field, attr):
|
||||||
|
|
||||||
dict_ = request.GET.copy()
|
dict_ = request.GET.copy()
|
||||||
|
|
||||||
if dict_.__contains__(field) and dict_[field] == attr:
|
if dict_.__contains__(field) and dict_[field] == attr:
|
||||||
@@ -94,4 +88,4 @@ def orderby(request, field, attr):
|
|||||||
else:
|
else:
|
||||||
dict_[field] = attr
|
dict_[field] = attr
|
||||||
|
|
||||||
return dict_.urlencode()
|
return dict_.urlencode()
|
||||||
@@ -1,25 +1,25 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import os
|
|
||||||
import re
|
|
||||||
from datetime import date, timedelta
|
|
||||||
|
|
||||||
import reversion
|
|
||||||
from django.core import mail
|
|
||||||
from django.db import transaction
|
|
||||||
from django.test import LiveServerTestCase
|
from django.test import LiveServerTestCase
|
||||||
from django.test.client import Client
|
from django.test.client import Client
|
||||||
|
from django.core import mail
|
||||||
from selenium import webdriver
|
from selenium import webdriver
|
||||||
from selenium.common.exceptions import StaleElementReferenceException, WebDriverException
|
|
||||||
from selenium.webdriver.common.keys import Keys
|
from selenium.webdriver.common.keys import Keys
|
||||||
|
from selenium.common.exceptions import StaleElementReferenceException, WebDriverException
|
||||||
from selenium.webdriver.support.ui import WebDriverWait
|
from selenium.webdriver.support.ui import WebDriverWait
|
||||||
|
|
||||||
from RIGS import models
|
from RIGS import models
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
from datetime import date, timedelta
|
||||||
|
from django.db import transaction
|
||||||
|
import reversion
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
class UserRegistrationTest(LiveServerTestCase):
|
class UserRegistrationTest(LiveServerTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.browser = webdriver.Firefox()
|
self.browser = webdriver.Firefox()
|
||||||
self.browser.implicitly_wait(3) # Set implicit wait session wide
|
self.browser.implicitly_wait(3) # Set implicit wait session wide
|
||||||
os.environ['RECAPTCHA_TESTING'] = 'True'
|
os.environ['RECAPTCHA_TESTING'] = 'True'
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
@@ -103,7 +103,7 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
# Check Email
|
# Check Email
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
email = mail.outbox[0]
|
email = mail.outbox[0]
|
||||||
self.assertIn('John Smith "JS" activation required', email.subject)
|
self.assertIn('activation required', email.subject)
|
||||||
urls = re.findall(
|
urls = re.findall(
|
||||||
'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', email.body)
|
'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', email.body)
|
||||||
self.assertEqual(len(urls), 1)
|
self.assertEqual(len(urls), 1)
|
||||||
@@ -148,17 +148,17 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
|
|
||||||
|
|
||||||
class EventTest(LiveServerTestCase):
|
class EventTest(LiveServerTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.profile = models.Profile(
|
self.profile = models.Profile(
|
||||||
username="EventTest", first_name="Event", last_name="Test", initials="ETU", is_superuser=True)
|
username="EventTest", first_name="Event", last_name="Test", initials="ETU", is_superuser=True)
|
||||||
self.profile.set_password("EventTestPassword")
|
self.profile.set_password("EventTestPassword")
|
||||||
self.profile.save()
|
self.profile.save()
|
||||||
|
|
||||||
self.vatrate = models.VatRate.objects.create(
|
self.vatrate = models.VatRate.objects.create(start_at='2014-03-05',rate=0.20,comment='test1')
|
||||||
start_at='2014-03-05', rate=0.20, comment='test1')
|
|
||||||
|
|
||||||
self.browser = webdriver.Firefox()
|
self.browser = webdriver.Firefox()
|
||||||
self.browser.implicitly_wait(3) # Set implicit wait session wide
|
self.browser.implicitly_wait(3) # Set implicit wait session wide
|
||||||
self.browser.maximize_window()
|
self.browser.maximize_window()
|
||||||
os.environ['RECAPTCHA_TESTING'] = 'True'
|
os.environ['RECAPTCHA_TESTING'] = 'True'
|
||||||
|
|
||||||
@@ -202,8 +202,7 @@ class EventTest(LiveServerTestCase):
|
|||||||
# Gets redirected to login and back
|
# Gets redirected to login and back
|
||||||
self.authenticate('/event/create/')
|
self.authenticate('/event/create/')
|
||||||
|
|
||||||
# setup WebDriverWait to use later (to wait for animations)
|
wait = WebDriverWait(self.browser, 10) #setup WebDriverWait to use later (to wait for animations)
|
||||||
wait = WebDriverWait(self.browser, 10)
|
|
||||||
|
|
||||||
wait.until(animation_is_finished())
|
wait.until(animation_is_finished())
|
||||||
|
|
||||||
@@ -229,9 +228,7 @@ class EventTest(LiveServerTestCase):
|
|||||||
modal = self.browser.find_element_by_id('modal')
|
modal = self.browser.find_element_by_id('modal')
|
||||||
wait.until(animation_is_finished())
|
wait.until(animation_is_finished())
|
||||||
self.assertTrue(modal.is_displayed())
|
self.assertTrue(modal.is_displayed())
|
||||||
self.assertIn(
|
self.assertIn("Add Person", modal.find_element_by_tag_name('h3').text)
|
||||||
"Add Person",
|
|
||||||
modal.find_element_by_tag_name('h3').text)
|
|
||||||
|
|
||||||
# Fill person form out and submit
|
# Fill person form out and submit
|
||||||
modal.find_element_by_xpath(
|
modal.find_element_by_xpath(
|
||||||
@@ -256,9 +253,7 @@ class EventTest(LiveServerTestCase):
|
|||||||
|
|
||||||
wait.until(animation_is_finished())
|
wait.until(animation_is_finished())
|
||||||
self.assertTrue(modal.is_displayed())
|
self.assertTrue(modal.is_displayed())
|
||||||
self.assertIn(
|
self.assertIn("Add Person", modal.find_element_by_tag_name('h3').text)
|
||||||
"Add Person",
|
|
||||||
modal.find_element_by_tag_name('h3').text)
|
|
||||||
|
|
||||||
modal.find_element_by_xpath(
|
modal.find_element_by_xpath(
|
||||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Person 2")
|
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Person 2")
|
||||||
@@ -294,9 +289,7 @@ class EventTest(LiveServerTestCase):
|
|||||||
'//a[@data-target="#id_person" and contains(@href, "%s/edit/")]' % person1.pk).click()
|
'//a[@data-target="#id_person" and contains(@href, "%s/edit/")]' % person1.pk).click()
|
||||||
wait.until(animation_is_finished())
|
wait.until(animation_is_finished())
|
||||||
self.assertTrue(modal.is_displayed())
|
self.assertTrue(modal.is_displayed())
|
||||||
self.assertIn(
|
self.assertIn("Edit Person", modal.find_element_by_tag_name('h3').text)
|
||||||
"Edit Person",
|
|
||||||
modal.find_element_by_tag_name('h3').text)
|
|
||||||
name = modal.find_element_by_xpath(
|
name = modal.find_element_by_xpath(
|
||||||
'//div[@id="modal"]//input[@id="id_name"]')
|
'//div[@id="modal"]//input[@id="id_name"]')
|
||||||
self.assertEqual(person1.name, name.get_attribute('value'))
|
self.assertEqual(person1.name, name.get_attribute('value'))
|
||||||
@@ -319,8 +312,7 @@ class EventTest(LiveServerTestCase):
|
|||||||
modal = self.browser.find_element_by_id('modal')
|
modal = self.browser.find_element_by_id('modal')
|
||||||
wait.until(animation_is_finished())
|
wait.until(animation_is_finished())
|
||||||
self.assertTrue(modal.is_displayed())
|
self.assertTrue(modal.is_displayed())
|
||||||
self.assertIn("Add Organisation",
|
self.assertIn("Add Organisation", modal.find_element_by_tag_name('h3').text)
|
||||||
modal.find_element_by_tag_name('h3').text)
|
|
||||||
modal.find_element_by_xpath(
|
modal.find_element_by_xpath(
|
||||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Organisation")
|
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Organisation")
|
||||||
modal.find_element_by_xpath(
|
modal.find_element_by_xpath(
|
||||||
@@ -347,9 +339,7 @@ class EventTest(LiveServerTestCase):
|
|||||||
modal = self.browser.find_element_by_id('modal')
|
modal = self.browser.find_element_by_id('modal')
|
||||||
wait.until(animation_is_finished())
|
wait.until(animation_is_finished())
|
||||||
self.assertTrue(modal.is_displayed())
|
self.assertTrue(modal.is_displayed())
|
||||||
self.assertIn(
|
self.assertIn("Add Venue", modal.find_element_by_tag_name('h3').text)
|
||||||
"Add Venue",
|
|
||||||
modal.find_element_by_tag_name('h3').text)
|
|
||||||
modal.find_element_by_xpath(
|
modal.find_element_by_xpath(
|
||||||
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Venue")
|
'//div[@id="modal"]//input[@id="id_name"]').send_keys("Test Venue")
|
||||||
modal.find_element_by_xpath(
|
modal.find_element_by_xpath(
|
||||||
@@ -375,72 +365,51 @@ class EventTest(LiveServerTestCase):
|
|||||||
form.find_element_by_id('id_end_time').send_keys('07:00')
|
form.find_element_by_id('id_end_time').send_keys('07:00')
|
||||||
|
|
||||||
# Add item
|
# Add item
|
||||||
form.find_element_by_xpath(
|
form.find_element_by_xpath('//button[contains(@class, "item-add")]').click()
|
||||||
'//button[contains(@class, "item-add")]').click()
|
|
||||||
wait.until(animation_is_finished())
|
wait.until(animation_is_finished())
|
||||||
modal = self.browser.find_element_by_id("itemModal")
|
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_name").send_keys("Test Item 1")
|
||||||
modal.find_element_by_id("item_description").send_keys(
|
modal.find_element_by_id("item_description").send_keys("This is an item description\nthat for reasons unkown spans two lines")
|
||||||
"This is an item description\nthat for reasons unkown spans two lines")
|
|
||||||
e = modal.find_element_by_id("item_quantity")
|
e = modal.find_element_by_id("item_quantity")
|
||||||
e.click()
|
e.click()
|
||||||
e.send_keys(Keys.UP)
|
e.send_keys(Keys.UP)
|
||||||
e.send_keys(Keys.UP)
|
e.send_keys(Keys.UP)
|
||||||
e = modal.find_element_by_id("item_cost")
|
e = modal.find_element_by_id("item_cost")
|
||||||
e.send_keys("23.95")
|
e.send_keys("23.95")
|
||||||
e.send_keys(Keys.ENTER) # enter submit
|
e.send_keys(Keys.ENTER) # enter submit
|
||||||
|
|
||||||
# Confirm item has been saved to json field
|
# Confirm item has been saved to json field
|
||||||
objectitems = self.browser.execute_script("return objectitems;")
|
objectitems = self.browser.execute_script("return objectitems;")
|
||||||
self.assertEqual(1, len(objectitems))
|
self.assertEqual(1, len(objectitems))
|
||||||
# as we are deliberately creating this we know the ID
|
testitem = objectitems["-1"]['fields'] # as we are deliberately creating this we know the ID
|
||||||
testitem = objectitems["-1"]['fields']
|
|
||||||
self.assertEqual("Test Item 1", testitem['name'])
|
self.assertEqual("Test Item 1", testitem['name'])
|
||||||
# test a couple of "worse case" fields
|
self.assertEqual("2", testitem['quantity']) # test a couple of "worse case" fields
|
||||||
self.assertEqual("2", testitem['quantity'])
|
|
||||||
|
|
||||||
# See new item appear in table
|
# See new item appear in table
|
||||||
row = self.browser.find_element_by_id(
|
row = self.browser.find_element_by_id('item--1') # ID number is known, see above
|
||||||
'item--1') # ID number is known, see above
|
self.assertIn("Test Item 1", row.find_element_by_xpath('//span[@class="name"]').text)
|
||||||
self.assertIn(
|
self.assertIn("This is an item description", row.find_element_by_xpath('//div[@class="item-description"]').text)
|
||||||
"Test Item 1",
|
self.assertEqual(u'£ 23.95', row.find_element_by_xpath('//tr[@id="item--1"]/td[2]').text)
|
||||||
row.find_element_by_xpath('//span[@class="name"]').text)
|
self.assertEqual("2", row.find_element_by_xpath('//td[@class="quantity"]').text)
|
||||||
self.assertIn(
|
self.assertEqual(u'£ 47.90', row.find_element_by_xpath('//tr[@id="item--1"]/td[4]').text)
|
||||||
"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
|
# Check totals
|
||||||
self.assertEqual(
|
self.assertEqual("47.90", self.browser.find_element_by_id('sumtotal').text)
|
||||||
"47.90", self.browser.find_element_by_id('sumtotal').text)
|
self.assertIn("(TBC)", self.browser.find_element_by_id('vat-rate').text)
|
||||||
self.assertIn(
|
self.assertEqual("9.58", self.browser.find_element_by_id('vat').text)
|
||||||
"(TBC)",
|
self.assertEqual("57.48", self.browser.find_element_by_id('total').text)
|
||||||
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
|
# Attempt to save - missing title
|
||||||
save.click()
|
save.click()
|
||||||
|
|
||||||
# See error
|
# See error
|
||||||
error = self.browser.find_element_by_xpath(
|
error = self.browser.find_element_by_xpath('//div[contains(@class, "alert-danger")]')
|
||||||
'//div[contains(@class, "alert-danger")]')
|
|
||||||
self.assertTrue(error.is_displayed())
|
self.assertTrue(error.is_displayed())
|
||||||
# Should only have one error message
|
# Should only have one error message
|
||||||
self.assertEqual(
|
self.assertEqual("Name", error.find_element_by_xpath('//dt[1]').text)
|
||||||
"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)
|
||||||
self.assertEqual("This field is required.",
|
|
||||||
error.find_element_by_xpath('//dd[1]/ul/li').text)
|
|
||||||
# don't need error so close it
|
# don't need error so close it
|
||||||
error.find_element_by_xpath(
|
error.find_element_by_xpath('//div[contains(@class, "alert-danger")]//button[@class="close"]').click()
|
||||||
'//div[contains(@class, "alert-danger")]//button[@class="close"]').click()
|
|
||||||
try:
|
try:
|
||||||
self.assertFalse(error.is_displayed())
|
self.assertFalse(error.is_displayed())
|
||||||
except StaleElementReferenceException:
|
except StaleElementReferenceException:
|
||||||
@@ -461,102 +430,84 @@ class EventTest(LiveServerTestCase):
|
|||||||
# See redirected to success page
|
# See redirected to success page
|
||||||
successTitle = self.browser.find_element_by_xpath('//h1').text
|
successTitle = self.browser.find_element_by_xpath('//h1').text
|
||||||
event = models.Event.objects.get(name='Test Event Name')
|
event = models.Event.objects.get(name='Test Event Name')
|
||||||
self.assertIn("N0000%d | Test Event Name" % event.pk, successTitle)
|
self.assertIn("N0000%d | Test Event Name"%event.pk, successTitle)
|
||||||
except WebDriverException:
|
except WebDriverException:
|
||||||
# This is a dirty workaround for wercker being a bit funny and not running it correctly.
|
# 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
|
# Waiting for wercker to get back to me about this
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def testEventDuplicate(self):
|
def testEventDuplicate(self):
|
||||||
testEvent = models.Event.objects.create(
|
testEvent = models.Event.objects.create(name="TE E1", status=models.Event.PROVISIONAL, start_date=date.today() + timedelta(days=6), description="start future no end")
|
||||||
name="TE E1",
|
|
||||||
status=models.Event.PROVISIONAL,
|
|
||||||
start_date=date.today() +
|
|
||||||
timedelta(
|
|
||||||
days=6),
|
|
||||||
description="start future no end")
|
|
||||||
|
|
||||||
item1 = models.EventItem(
|
item1 = models.EventItem(
|
||||||
event=testEvent,
|
event=testEvent,
|
||||||
name="Test Item 1",
|
name="Test Item 1",
|
||||||
cost="10.00",
|
cost="10.00",
|
||||||
quantity="1",
|
quantity="1",
|
||||||
order=1
|
order=1
|
||||||
).save()
|
).save()
|
||||||
item2 = models.EventItem(
|
item2 = models.EventItem(
|
||||||
event=testEvent,
|
event=testEvent,
|
||||||
name="Test Item 2",
|
name="Test Item 2",
|
||||||
description="Foo",
|
description="Foo",
|
||||||
cost="9.72",
|
cost="9.72",
|
||||||
quantity="3",
|
quantity="3",
|
||||||
order=2,
|
order=2,
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
self.browser.get(self.live_server_url + '/event/' +
|
self.browser.get(self.live_server_url + '/event/' + str(testEvent.pk) + '/duplicate/')
|
||||||
str(testEvent.pk) + '/duplicate/')
|
|
||||||
self.authenticate('/event/' + str(testEvent.pk) + '/duplicate/')
|
self.authenticate('/event/' + str(testEvent.pk) + '/duplicate/')
|
||||||
|
|
||||||
# setup WebDriverWait to use later (to wait for animations)
|
wait = WebDriverWait(self.browser, 10) #setup WebDriverWait to use later (to wait for animations)
|
||||||
wait = WebDriverWait(self.browser, 10)
|
|
||||||
|
|
||||||
save = self.browser.find_element_by_xpath(
|
save = self.browser.find_element_by_xpath(
|
||||||
'(//button[@type="submit"])[3]')
|
'(//button[@type="submit"])[3]')
|
||||||
form = self.browser.find_element_by_tag_name('form')
|
form = self.browser.find_element_by_tag_name('form')
|
||||||
|
|
||||||
|
|
||||||
# Check the items are visible
|
# Check the items are visible
|
||||||
table = self.browser.find_element_by_id(
|
table = self.browser.find_element_by_id('item-table') # ID number is known, see above
|
||||||
'item-table') # ID number is known, see above
|
|
||||||
self.assertIn("Test Item 1", table.text)
|
self.assertIn("Test Item 1", table.text)
|
||||||
self.assertIn("Test Item 2", table.text)
|
self.assertIn("Test Item 2", table.text)
|
||||||
|
|
||||||
# Add item
|
# Add item
|
||||||
form.find_element_by_xpath(
|
form.find_element_by_xpath('//button[contains(@class, "item-add")]').click()
|
||||||
'//button[contains(@class, "item-add")]').click()
|
|
||||||
wait.until(animation_is_finished())
|
wait.until(animation_is_finished())
|
||||||
modal = self.browser.find_element_by_id("itemModal")
|
modal = self.browser.find_element_by_id("itemModal")
|
||||||
modal.find_element_by_id("item_name").send_keys("Test Item 3")
|
modal.find_element_by_id("item_name").send_keys("Test Item 3")
|
||||||
modal.find_element_by_id("item_description").send_keys(
|
modal.find_element_by_id("item_description").send_keys("This is an item description\nthat for reasons unkown spans two lines")
|
||||||
"This is an item description\nthat for reasons unkown spans two lines")
|
|
||||||
e = modal.find_element_by_id("item_quantity")
|
e = modal.find_element_by_id("item_quantity")
|
||||||
e.click()
|
e.click()
|
||||||
e.send_keys(Keys.UP)
|
e.send_keys(Keys.UP)
|
||||||
e.send_keys(Keys.UP)
|
e.send_keys(Keys.UP)
|
||||||
e = modal.find_element_by_id("item_cost")
|
e = modal.find_element_by_id("item_cost")
|
||||||
e.send_keys("23.95")
|
e.send_keys("23.95")
|
||||||
e.send_keys(Keys.ENTER) # enter submit
|
e.send_keys(Keys.ENTER) # enter submit
|
||||||
|
|
||||||
# Attempt to save
|
# Attempt to save
|
||||||
save.click()
|
save.click()
|
||||||
|
|
||||||
self.assertNotIn(
|
self.assertNotIn("N0000%d"%testEvent.pk, self.browser.find_element_by_xpath('//h1').text)
|
||||||
"N0000%d" %
|
|
||||||
testEvent.pk,
|
|
||||||
self.browser.find_element_by_xpath('//h1').text)
|
|
||||||
|
|
||||||
# Check the new items are visible
|
# Check the new items are visible
|
||||||
table = self.browser.find_element_by_id(
|
table = self.browser.find_element_by_id('item-table') # ID number is known, see above
|
||||||
'item-table') # ID number is known, see above
|
|
||||||
self.assertIn("Test Item 1", table.text)
|
self.assertIn("Test Item 1", table.text)
|
||||||
self.assertIn("Test Item 2", table.text)
|
self.assertIn("Test Item 2", table.text)
|
||||||
self.assertIn("Test Item 3", table.text)
|
self.assertIn("Test Item 3", table.text)
|
||||||
|
|
||||||
infoPanel = self.browser.find_element_by_xpath(
|
infoPanel = self.browser.find_element_by_xpath('//div[contains(text(), "Event Info")]/..')
|
||||||
'//div[contains(text(), "Event Info")]/..')
|
self.assertIn("N0000%d"%testEvent.pk, infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
|
||||||
self.assertIn("N0000%d" % testEvent.pk, infoPanel.find_element_by_xpath(
|
|
||||||
'//dt[text()="Based On"]/following-sibling::dd[1]').text)
|
|
||||||
|
|
||||||
self.browser.get(self.live_server_url + '/event/' +
|
|
||||||
str(testEvent.pk)) # Go back to the old event
|
|
||||||
|
|
||||||
# Check that based-on hasn't crept into the old event
|
|
||||||
infoPanel = self.browser.find_element_by_xpath(
|
self.browser.get(self.live_server_url + '/event/' + str(testEvent.pk)) #Go back to the old event
|
||||||
'//div[contains(text(), "Event Info")]/..')
|
|
||||||
self.assertNotIn("N0000%d" % testEvent.pk, infoPanel.find_element_by_xpath(
|
#Check that based-on hasn't crept into the old event
|
||||||
'//dt[text()="Based On"]/following-sibling::dd[1]').text)
|
infoPanel = self.browser.find_element_by_xpath('//div[contains(text(), "Event Info")]/..')
|
||||||
|
self.assertNotIn("N0000%d"%testEvent.pk, infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
|
||||||
|
|
||||||
# Check the items are as they were
|
# Check the items are as they were
|
||||||
table = self.browser.find_element_by_id(
|
table = self.browser.find_element_by_id('item-table') # ID number is known, see above
|
||||||
'item-table') # ID number is known, see above
|
|
||||||
self.assertIn("Test Item 1", table.text)
|
self.assertIn("Test Item 1", table.text)
|
||||||
self.assertIn("Test Item 2", table.text)
|
self.assertIn("Test Item 2", table.text)
|
||||||
self.assertNotIn("Test Item 3", table.text)
|
self.assertNotIn("Test Item 3", table.text)
|
||||||
@@ -566,8 +517,7 @@ class EventTest(LiveServerTestCase):
|
|||||||
# Gets redirected to login and back
|
# Gets redirected to login and back
|
||||||
self.authenticate('/event/create/')
|
self.authenticate('/event/create/')
|
||||||
|
|
||||||
# setup WebDriverWait to use later (to wait for animations)
|
wait = WebDriverWait(self.browser, 10) #setup WebDriverWait to use later (to wait for animations)
|
||||||
wait = WebDriverWait(self.browser, 10)
|
|
||||||
|
|
||||||
wait.until(animation_is_finished())
|
wait.until(animation_is_finished())
|
||||||
|
|
||||||
@@ -575,8 +525,7 @@ class EventTest(LiveServerTestCase):
|
|||||||
self.browser.find_element_by_xpath('//button[.="Rig"]').click()
|
self.browser.find_element_by_xpath('//button[.="Rig"]').click()
|
||||||
|
|
||||||
form = self.browser.find_element_by_tag_name('form')
|
form = self.browser.find_element_by_tag_name('form')
|
||||||
save = self.browser.find_element_by_xpath(
|
save = self.browser.find_element_by_xpath('(//button[@type="submit"])[3]')
|
||||||
'(//button[@type="submit"])[3]')
|
|
||||||
|
|
||||||
# Set title
|
# Set title
|
||||||
e = self.browser.find_element_by_id('id_name')
|
e = self.browser.find_element_by_id('id_name')
|
||||||
@@ -591,16 +540,14 @@ class EventTest(LiveServerTestCase):
|
|||||||
|
|
||||||
# Attempt to save - should fail
|
# Attempt to save - should fail
|
||||||
save.click()
|
save.click()
|
||||||
error = self.browser.find_element_by_xpath(
|
error = self.browser.find_element_by_xpath('//div[contains(@class, "alert-danger")]')
|
||||||
'//div[contains(@class, "alert-danger")]')
|
|
||||||
self.assertTrue(error.is_displayed())
|
self.assertTrue(error.is_displayed())
|
||||||
self.assertIn("can't finish before it has started",
|
self.assertIn("can't finish before it has started", error.find_element_by_xpath('//dd[1]/ul/li').text)
|
||||||
error.find_element_by_xpath('//dd[1]/ul/li').text)
|
|
||||||
|
|
||||||
# Same date, end time before start time
|
# Same date, end time before start time
|
||||||
form = self.browser.find_element_by_tag_name('form')
|
form = self.browser.find_element_by_tag_name('form')
|
||||||
save = self.browser.find_element_by_xpath(
|
save = self.browser.find_element_by_xpath('(//button[@type="submit"])[3]')
|
||||||
'(//button[@type="submit"])[3]')
|
|
||||||
form.find_element_by_id('id_start_date').clear()
|
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_start_date').send_keys('3015-04-24')
|
||||||
|
|
||||||
@@ -615,16 +562,14 @@ class EventTest(LiveServerTestCase):
|
|||||||
|
|
||||||
# Attempt to save - should fail
|
# Attempt to save - should fail
|
||||||
save.click()
|
save.click()
|
||||||
error = self.browser.find_element_by_xpath(
|
error = self.browser.find_element_by_xpath('//div[contains(@class, "alert-danger")]')
|
||||||
'//div[contains(@class, "alert-danger")]')
|
|
||||||
self.assertTrue(error.is_displayed())
|
self.assertTrue(error.is_displayed())
|
||||||
self.assertIn("can't finish before it has started",
|
self.assertIn("can't finish before it has started", error.find_element_by_xpath('//dd[1]/ul/li').text)
|
||||||
error.find_element_by_xpath('//dd[1]/ul/li').text)
|
|
||||||
|
|
||||||
# Same date, end time before start time
|
# Same date, end time before start time
|
||||||
form = self.browser.find_element_by_tag_name('form')
|
form = self.browser.find_element_by_tag_name('form')
|
||||||
save = self.browser.find_element_by_xpath(
|
save = self.browser.find_element_by_xpath('(//button[@type="submit"])[3]')
|
||||||
'(//button[@type="submit"])[3]')
|
|
||||||
form.find_element_by_id('id_start_date').clear()
|
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_start_date').send_keys('3015-04-24')
|
||||||
|
|
||||||
@@ -637,10 +582,10 @@ class EventTest(LiveServerTestCase):
|
|||||||
form.find_element_by_id('id_end_time').clear()
|
form.find_element_by_id('id_end_time').clear()
|
||||||
form.find_element_by_id('id_end_time').send_keys('06:00')
|
form.find_element_by_id('id_end_time').send_keys('06:00')
|
||||||
|
|
||||||
|
|
||||||
# No end date, end time before start time
|
# No end date, end time before start time
|
||||||
form = self.browser.find_element_by_tag_name('form')
|
form = self.browser.find_element_by_tag_name('form')
|
||||||
save = self.browser.find_element_by_xpath(
|
save = self.browser.find_element_by_xpath('(//button[@type="submit"])[3]')
|
||||||
'(//button[@type="submit"])[3]')
|
|
||||||
form.find_element_by_id('id_start_date').clear()
|
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_start_date').send_keys('3015-04-24')
|
||||||
|
|
||||||
@@ -654,16 +599,14 @@ class EventTest(LiveServerTestCase):
|
|||||||
|
|
||||||
# Attempt to save - should fail
|
# Attempt to save - should fail
|
||||||
save.click()
|
save.click()
|
||||||
error = self.browser.find_element_by_xpath(
|
error = self.browser.find_element_by_xpath('//div[contains(@class, "alert-danger")]')
|
||||||
'//div[contains(@class, "alert-danger")]')
|
|
||||||
self.assertTrue(error.is_displayed())
|
self.assertTrue(error.is_displayed())
|
||||||
self.assertIn("can't finish before it has started",
|
self.assertIn("can't finish before it has started", error.find_element_by_xpath('//dd[1]/ul/li').text)
|
||||||
error.find_element_by_xpath('//dd[1]/ul/li').text)
|
|
||||||
|
|
||||||
# 2 dates, end after start
|
# 2 dates, end after start
|
||||||
form = self.browser.find_element_by_tag_name('form')
|
form = self.browser.find_element_by_tag_name('form')
|
||||||
save = self.browser.find_element_by_xpath(
|
save = self.browser.find_element_by_xpath('(//button[@type="submit"])[3]')
|
||||||
'(//button[@type="submit"])[3]')
|
|
||||||
form.find_element_by_id('id_start_date').clear()
|
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_start_date').send_keys('3015-04-24')
|
||||||
|
|
||||||
@@ -671,26 +614,24 @@ class EventTest(LiveServerTestCase):
|
|||||||
form.find_element_by_id('id_end_date').send_keys('3015-04-26')
|
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_start_time').clear()
|
||||||
|
|
||||||
form.find_element_by_id('id_end_time').clear()
|
form.find_element_by_id('id_end_time').clear()
|
||||||
|
|
||||||
# Attempt to save - should succeed
|
# Attempt to save - should succeed
|
||||||
save.click()
|
save.click()
|
||||||
|
|
||||||
# See redirected to success page
|
# See redirected to success page
|
||||||
successTitle = self.browser.find_element_by_xpath('//h1').text
|
successTitle = self.browser.find_element_by_xpath('//h1').text
|
||||||
event = models.Event.objects.get(name='Test Event Name')
|
event = models.Event.objects.get(name='Test Event Name')
|
||||||
self.assertIn("N0000%d | Test Event Name" % event.pk, successTitle)
|
self.assertIn("N0000%d | Test Event Name"%event.pk, successTitle)
|
||||||
|
|
||||||
def testRigNonRig(self):
|
def testRigNonRig(self):
|
||||||
self.browser.get(self.live_server_url + '/event/create/')
|
self.browser.get(self.live_server_url + '/event/create/')
|
||||||
# Gets redirected to login and back
|
# Gets redirected to login and back
|
||||||
self.authenticate('/event/create/')
|
self.authenticate('/event/create/')
|
||||||
|
|
||||||
# setup WebDriverWait to use later (to wait for animations)
|
wait = WebDriverWait(self.browser, 10) #setup WebDriverWait to use later (to wait for animations)
|
||||||
wait = WebDriverWait(self.browser, 10)
|
self.browser.implicitly_wait(3) #Set session-long wait (only works for non-existant DOM objects)
|
||||||
# Set session-long wait (only works for non-existant DOM objects)
|
|
||||||
self.browser.implicitly_wait(3)
|
|
||||||
|
|
||||||
wait.until(animation_is_finished())
|
wait.until(animation_is_finished())
|
||||||
|
|
||||||
@@ -701,8 +642,7 @@ class EventTest(LiveServerTestCase):
|
|||||||
self.browser.find_element_by_xpath('//button[.="Rig"]').click()
|
self.browser.find_element_by_xpath('//button[.="Rig"]').click()
|
||||||
|
|
||||||
form = self.browser.find_element_by_tag_name('form')
|
form = self.browser.find_element_by_tag_name('form')
|
||||||
save = self.browser.find_element_by_xpath(
|
save = self.browser.find_element_by_xpath('(//button[@type="submit"])[3]')
|
||||||
'(//button[@type="submit"])[3]')
|
|
||||||
|
|
||||||
# Set title
|
# Set title
|
||||||
e = self.browser.find_element_by_id('id_name')
|
e = self.browser.find_element_by_id('id_name')
|
||||||
@@ -714,23 +654,16 @@ class EventTest(LiveServerTestCase):
|
|||||||
|
|
||||||
# Save the rig
|
# Save the rig
|
||||||
save.click()
|
save.click()
|
||||||
detail_panel = self.browser.find_element_by_xpath(
|
detail_panel = self.browser.find_element_by_xpath("//div[@id='content']/div/div[6]/div/div")
|
||||||
"//div[@id='content']/div/div[6]/div/div")
|
|
||||||
self.assertTrue(detail_panel.is_displayed())
|
self.assertTrue(detail_panel.is_displayed())
|
||||||
self.assertIn("Event Detail", detail_panel.text)
|
self.assertIn("Event Detail", detail_panel.text)
|
||||||
|
|
||||||
def testEventDetail(self):
|
def testEventDetail(self):
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
person = models.Person(
|
person = models.Person(name="Event Detail Person", email="eventdetail@person.tests.rigs", phone="123 123")
|
||||||
name="Event Detail Person",
|
|
||||||
email="eventdetail@person.tests.rigs",
|
|
||||||
phone="123 123")
|
|
||||||
person.save()
|
person.save()
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
organisation = models.Organisation(
|
organisation = models.Organisation(name="Event Detail Organisation", email="eventdetail@organisation.tests.rigs", phone="123 456").save()
|
||||||
name="Event Detail Organisation",
|
|
||||||
email="eventdetail@organisation.tests.rigs",
|
|
||||||
phone="123 456").save()
|
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
venue = models.Venue(name="Event Detail Venue").save()
|
venue = models.Venue(name="Event Detail Venue").save()
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
@@ -760,182 +693,59 @@ class EventTest(LiveServerTestCase):
|
|||||||
order=2,
|
order=2,
|
||||||
).save()
|
).save()
|
||||||
|
|
||||||
self.browser.get(self.live_server_url + '/event/%d' % event.pk)
|
|
||||||
self.authenticate('/event/%d/' % event.pk)
|
|
||||||
self.assertIn("N%05d | %s" % (event.pk, event.name),
|
|
||||||
self.browser.find_element_by_xpath('//h1').text)
|
|
||||||
|
|
||||||
personPanel = self.browser.find_element_by_xpath(
|
self.browser.get(self.live_server_url + '/event/%d'%event.pk)
|
||||||
'//div[contains(text(), "Contact Details")]/..')
|
self.authenticate('/event/%d/'%event.pk)
|
||||||
self.assertEqual(person.name, personPanel.find_element_by_xpath(
|
self.assertIn("N%05d | %s"%(event.pk, event.name), self.browser.find_element_by_xpath('//h1').text)
|
||||||
'//dt[text()="Person"]/following-sibling::dd[1]').text)
|
|
||||||
self.assertEqual(person.email, personPanel.find_element_by_xpath(
|
|
||||||
'//dt[text()="Email"]/following-sibling::dd[1]').text)
|
|
||||||
self.assertEqual(person.phone, personPanel.find_element_by_xpath(
|
|
||||||
'//dt[text()="Phone Number"]/following-sibling::dd[1]').text)
|
|
||||||
|
|
||||||
organisationPanel = self.browser.find_element_by_xpath(
|
personPanel = self.browser.find_element_by_xpath('//div[contains(text(), "Contact Details")]/..')
|
||||||
'//div[contains(text(), "Contact Details")]/..')
|
self.assertEqual(person.name, personPanel.find_element_by_xpath('//dt[text()="Person"]/following-sibling::dd[1]').text)
|
||||||
|
self.assertEqual(person.email, personPanel.find_element_by_xpath('//dt[text()="Email"]/following-sibling::dd[1]').text)
|
||||||
|
self.assertEqual(person.phone, personPanel.find_element_by_xpath('//dt[text()="Phone Number"]/following-sibling::dd[1]').text)
|
||||||
|
|
||||||
|
organisationPanel = self.browser.find_element_by_xpath('//div[contains(text(), "Contact Details")]/..')
|
||||||
|
|
||||||
class IcalTest(LiveServerTestCase):
|
class IcalTest(LiveServerTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.all_events = set(range(1, 18))
|
self.all_events = set(range(1, 18))
|
||||||
self.current_events = (1, 2, 3, 6, 7, 8, 10, 11, 12, 14, 15, 16, 18)
|
self.current_events = (1, 2, 3, 6, 7, 8, 10, 11, 12, 14, 15, 16, 18)
|
||||||
self.not_current_events = set(
|
self.not_current_events = set(self.all_events) - set(self.current_events)
|
||||||
self.all_events) - set(self.current_events)
|
|
||||||
|
|
||||||
self.vatrate = models.VatRate.objects.create(
|
self.vatrate = models.VatRate.objects.create(start_at='2014-03-05',rate=0.20,comment='test1')
|
||||||
start_at='2014-03-05', rate=0.20, comment='test1')
|
|
||||||
self.profile = models.Profile(
|
self.profile = models.Profile(
|
||||||
username="EventTest", first_name="Event", last_name="Test", initials="ETU", is_superuser=True)
|
username="EventTest", first_name="Event", last_name="Test", initials="ETU", is_superuser=True)
|
||||||
self.profile.set_password("EventTestPassword")
|
self.profile.set_password("EventTestPassword")
|
||||||
self.profile.save()
|
self.profile.save()
|
||||||
|
|
||||||
# produce 7 normal events - 5 current - 1 last week - 1 two years ago -
|
# produce 7 normal events - 5 current - 1 last week - 1 two years ago - 2 provisional - 2 confirmed - 3 booked
|
||||||
# 2 provisional - 2 confirmed - 3 booked
|
models.Event.objects.create(name="TE E1", status=models.Event.PROVISIONAL, start_date=date.today() + timedelta(days=6), description="start future no end")
|
||||||
models.Event.objects.create(
|
models.Event.objects.create(name="TE E2", status=models.Event.PROVISIONAL, start_date=date.today(), description="start today no end")
|
||||||
name="TE E1",
|
models.Event.objects.create(name="TE E3", status=models.Event.CONFIRMED, start_date=date.today(), end_date=date.today(), description="start today with end today")
|
||||||
status=models.Event.PROVISIONAL,
|
models.Event.objects.create(name="TE E4", status=models.Event.CONFIRMED, start_date=date.today()-timedelta(weeks=104), description="start past 2 years no end")
|
||||||
start_date=date.today() +
|
models.Event.objects.create(name="TE E5", status=models.Event.BOOKED, start_date=date.today()-timedelta(days=7), end_date=date.today()-timedelta(days=1), description="start past 1 week with end past")
|
||||||
timedelta(
|
models.Event.objects.create(name="TE E6", status=models.Event.BOOKED, start_date=date.today()-timedelta(days=2), end_date=date.today()+timedelta(days=2), description="start past, end future")
|
||||||
days=6),
|
models.Event.objects.create(name="TE E7", status=models.Event.BOOKED, start_date=date.today()+timedelta(days=2), end_date=date.today()+timedelta(days=2), description="start + end in future")
|
||||||
description="start future no end")
|
|
||||||
models.Event.objects.create(
|
|
||||||
name="TE E2",
|
|
||||||
status=models.Event.PROVISIONAL,
|
|
||||||
start_date=date.today(),
|
|
||||||
description="start today no end")
|
|
||||||
models.Event.objects.create(
|
|
||||||
name="TE E3",
|
|
||||||
status=models.Event.CONFIRMED,
|
|
||||||
start_date=date.today(),
|
|
||||||
end_date=date.today(),
|
|
||||||
description="start today with end today")
|
|
||||||
models.Event.objects.create(
|
|
||||||
name="TE E4",
|
|
||||||
status=models.Event.CONFIRMED,
|
|
||||||
start_date=date.today() -
|
|
||||||
timedelta(
|
|
||||||
weeks=104),
|
|
||||||
description="start past 2 years no end")
|
|
||||||
models.Event.objects.create(
|
|
||||||
name="TE E5",
|
|
||||||
status=models.Event.BOOKED,
|
|
||||||
start_date=date.today() -
|
|
||||||
timedelta(
|
|
||||||
days=7),
|
|
||||||
end_date=date.today() -
|
|
||||||
timedelta(
|
|
||||||
days=1),
|
|
||||||
description="start past 1 week with end past")
|
|
||||||
models.Event.objects.create(
|
|
||||||
name="TE E6",
|
|
||||||
status=models.Event.BOOKED,
|
|
||||||
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",
|
|
||||||
status=models.Event.BOOKED,
|
|
||||||
start_date=date.today() +
|
|
||||||
timedelta(
|
|
||||||
days=2),
|
|
||||||
end_date=date.today() +
|
|
||||||
timedelta(
|
|
||||||
days=2),
|
|
||||||
description="start + end in future")
|
|
||||||
|
|
||||||
# 2 cancelled - 1 current
|
# 2 cancelled - 1 current
|
||||||
models.Event.objects.create(
|
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")
|
||||||
name="TE E8",
|
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")
|
||||||
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 - 1 cancelled
|
# 5 dry hire - 3 current - 1 cancelled
|
||||||
models.Event.objects.create(
|
models.Event.objects.create(name="TE E10", start_date=date.today(), dry_hire=True, description="dryhire today")
|
||||||
name="TE E10",
|
models.Event.objects.create(name="TE E11", start_date=date.today(), dry_hire=True, checked_in_by=self.profile, description="dryhire today, checked in")
|
||||||
start_date=date.today(),
|
models.Event.objects.create(name="TE E12", start_date=date.today()-timedelta(days=1), dry_hire=True, status=models.Event.BOOKED, description="dryhire past")
|
||||||
dry_hire=True,
|
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")
|
||||||
description="dryhire today")
|
models.Event.objects.create(name="TE E14", start_date=date.today(), dry_hire=True, status=models.Event.CANCELLED, description="dryhire today cancelled")
|
||||||
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
|
# 4 non rig - 3 current
|
||||||
models.Event.objects.create(
|
models.Event.objects.create(name="TE E15", start_date=date.today(), is_rig=False, description="non rig today")
|
||||||
name="TE E15",
|
models.Event.objects.create(name="TE E16", start_date=date.today()+timedelta(days=1), is_rig=False, description="non rig tomorrow")
|
||||||
start_date=date.today(),
|
models.Event.objects.create(name="TE E17", start_date=date.today()-timedelta(days=1), is_rig=False, description="non rig yesterday")
|
||||||
is_rig=False,
|
models.Event.objects.create(name="TE E18", start_date=date.today(), is_rig=False, status=models.Event.CANCELLED, description="non rig today cancelled")
|
||||||
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")
|
|
||||||
|
|
||||||
self.browser = webdriver.Firefox()
|
self.browser = webdriver.Firefox()
|
||||||
self.browser.implicitly_wait(3) # Set implicit wait session wide
|
self.browser.implicitly_wait(3) # Set implicit wait session wide
|
||||||
os.environ['RECAPTCHA_TESTING'] = 'True'
|
os.environ['RECAPTCHA_TESTING'] = 'True'
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
@@ -966,34 +776,24 @@ class IcalTest(LiveServerTestCase):
|
|||||||
|
|
||||||
# Completes and comes back to /user/
|
# Completes and comes back to /user/
|
||||||
# Checks that no api key is displayed
|
# Checks that no api key is displayed
|
||||||
self.assertEqual("No API Key Generated", self.browser.find_element_by_xpath(
|
self.assertEqual("No API Key Generated", self.browser.find_element_by_xpath("//div[@id='content']/div/div/div[3]/dl[2]/dd").text)
|
||||||
"//div[@id='content']/div/div/div[3]/dl[2]/dd").text)
|
self.assertEqual("No API Key Generated", self.browser.find_element_by_css_selector("pre").text)
|
||||||
self.assertEqual("No API Key Generated",
|
|
||||||
self.browser.find_element_by_css_selector("pre").text)
|
|
||||||
|
|
||||||
# Now creates an API key, and check a URL is displayed one
|
# Now creates an API key, and check a URL is displayed one
|
||||||
self.browser.find_element_by_link_text("Generate API Key").click()
|
self.browser.find_element_by_link_text("Generate API Key").click()
|
||||||
self.assertIn(
|
self.assertIn("rigs.ics", self.browser.find_element_by_id("cal-url").text)
|
||||||
"rigs.ics",
|
|
||||||
self.browser.find_element_by_id("cal-url").text)
|
|
||||||
self.assertNotIn("?", self.browser.find_element_by_id("cal-url").text)
|
self.assertNotIn("?", self.browser.find_element_by_id("cal-url").text)
|
||||||
|
|
||||||
# Lets change everything so it's not the default value
|
# Lets change everything so it's not the default value
|
||||||
self.browser.find_element_by_xpath("//input[@value='rig']").click()
|
self.browser.find_element_by_xpath("//input[@value='rig']").click()
|
||||||
self.browser.find_element_by_xpath("//input[@value='non-rig']").click()
|
self.browser.find_element_by_xpath("//input[@value='non-rig']").click()
|
||||||
self.browser.find_element_by_xpath(
|
self.browser.find_element_by_xpath("//input[@value='dry-hire']").click()
|
||||||
"//input[@value='dry-hire']").click()
|
self.browser.find_element_by_xpath("//input[@value='cancelled']").click()
|
||||||
self.browser.find_element_by_xpath(
|
self.browser.find_element_by_xpath("//input[@value='provisional']").click()
|
||||||
"//input[@value='cancelled']").click()
|
self.browser.find_element_by_xpath("//input[@value='confirmed']").click()
|
||||||
self.browser.find_element_by_xpath(
|
|
||||||
"//input[@value='provisional']").click()
|
|
||||||
self.browser.find_element_by_xpath(
|
|
||||||
"//input[@value='confirmed']").click()
|
|
||||||
|
|
||||||
# and then check the url is correct
|
# and then check the url is correct
|
||||||
self.assertIn(
|
self.assertIn("rigs.ics?rig=false&non-rig=false&dry-hire=false&cancelled=true&provisional=false&confirmed=false", self.browser.find_element_by_id("cal-url").text)
|
||||||
"rigs.ics?rig=false&non-rig=false&dry-hire=false&cancelled=true&provisional=false&confirmed=false",
|
|
||||||
self.browser.find_element_by_id("cal-url").text)
|
|
||||||
|
|
||||||
# Awesome - all seems to work
|
# Awesome - all seems to work
|
||||||
|
|
||||||
@@ -1006,24 +806,27 @@ class IcalTest(LiveServerTestCase):
|
|||||||
# Now creates an API key, and check a URL is displayed one
|
# Now creates an API key, and check a URL is displayed one
|
||||||
self.browser.find_element_by_link_text("Generate API Key").click()
|
self.browser.find_element_by_link_text("Generate API Key").click()
|
||||||
|
|
||||||
c = Client()
|
|
||||||
|
|
||||||
|
|
||||||
|
c = Client()
|
||||||
|
|
||||||
# Default settings - should have all non-cancelled events
|
# Default settings - should have all non-cancelled events
|
||||||
# Get the ical file (can't do this in selanium because reasons)
|
# Get the ical file (can't do this in selanium because reasons)
|
||||||
icalUrl = self.browser.find_element_by_id("cal-url").text
|
icalUrl = self.browser.find_element_by_id("cal-url").text
|
||||||
response = c.get(icalUrl)
|
response = c.get(icalUrl)
|
||||||
self.assertEqual(200, response.status_code)
|
self.assertEqual(200, response.status_code)
|
||||||
|
|
||||||
# Check has entire file
|
#Check has entire file
|
||||||
self.assertIn("BEGIN:VCALENDAR", response.content)
|
self.assertIn("BEGIN:VCALENDAR", response.content)
|
||||||
self.assertIn("END:VCALENDAR", response.content)
|
self.assertIn("END:VCALENDAR", response.content)
|
||||||
|
|
||||||
expectedIn = [1, 2, 3, 5, 6, 7, 10, 11, 12, 13, 15, 16, 17]
|
expectedIn= [1,2,3,5,6,7,10,11,12,13,15,16,17]
|
||||||
for test in range(1, 18):
|
for test in range(1,18):
|
||||||
if test in expectedIn:
|
if test in expectedIn:
|
||||||
self.assertIn("TE E" + str(test) + " ", response.content)
|
self.assertIn("TE E"+str(test)+" ", response.content)
|
||||||
else:
|
else:
|
||||||
self.assertNotIn("TE E" + str(test) + " ", response.content)
|
self.assertNotIn("TE E"+str(test)+" ", response.content)
|
||||||
|
|
||||||
|
|
||||||
# Only dry hires
|
# Only dry hires
|
||||||
self.browser.find_element_by_xpath("//input[@value='rig']").click()
|
self.browser.find_element_by_xpath("//input[@value='rig']").click()
|
||||||
@@ -1033,72 +836,66 @@ class IcalTest(LiveServerTestCase):
|
|||||||
response = c.get(icalUrl)
|
response = c.get(icalUrl)
|
||||||
self.assertEqual(200, response.status_code)
|
self.assertEqual(200, response.status_code)
|
||||||
|
|
||||||
expectedIn = [10, 11, 12, 13]
|
expectedIn= [10,11,12,13]
|
||||||
for test in range(1, 18):
|
for test in range(1,18):
|
||||||
if test in expectedIn:
|
if test in expectedIn:
|
||||||
self.assertIn("TE E" + str(test) + " ", response.content)
|
self.assertIn("TE E"+str(test)+" ", response.content)
|
||||||
else:
|
else:
|
||||||
self.assertNotIn("TE E" + str(test) + " ", response.content)
|
self.assertNotIn("TE E"+str(test)+" ", response.content)
|
||||||
|
|
||||||
|
|
||||||
# Only provisional rigs
|
# Only provisional rigs
|
||||||
self.browser.find_element_by_xpath("//input[@value='rig']").click()
|
self.browser.find_element_by_xpath("//input[@value='rig']").click()
|
||||||
self.browser.find_element_by_xpath(
|
self.browser.find_element_by_xpath("//input[@value='dry-hire']").click()
|
||||||
"//input[@value='dry-hire']").click()
|
self.browser.find_element_by_xpath("//input[@value='confirmed']").click()
|
||||||
self.browser.find_element_by_xpath(
|
|
||||||
"//input[@value='confirmed']").click()
|
|
||||||
|
|
||||||
icalUrl = self.browser.find_element_by_id("cal-url").text
|
icalUrl = self.browser.find_element_by_id("cal-url").text
|
||||||
response = c.get(icalUrl)
|
response = c.get(icalUrl)
|
||||||
self.assertEqual(200, response.status_code)
|
self.assertEqual(200, response.status_code)
|
||||||
|
|
||||||
expectedIn = [1, 2]
|
expectedIn= [1,2]
|
||||||
for test in range(1, 18):
|
for test in range(1,18):
|
||||||
if test in expectedIn:
|
if test in expectedIn:
|
||||||
self.assertIn("TE E" + str(test) + " ", response.content)
|
self.assertIn("TE E"+str(test)+" ", response.content)
|
||||||
else:
|
else:
|
||||||
self.assertNotIn("TE E" + str(test) + " ", response.content)
|
self.assertNotIn("TE E"+str(test)+" ", response.content)
|
||||||
|
|
||||||
# Only cancelled non-rigs
|
# Only cancelled non-rigs
|
||||||
self.browser.find_element_by_xpath("//input[@value='rig']").click()
|
self.browser.find_element_by_xpath("//input[@value='rig']").click()
|
||||||
self.browser.find_element_by_xpath("//input[@value='non-rig']").click()
|
self.browser.find_element_by_xpath("//input[@value='non-rig']").click()
|
||||||
self.browser.find_element_by_xpath(
|
self.browser.find_element_by_xpath("//input[@value='provisional']").click()
|
||||||
"//input[@value='provisional']").click()
|
self.browser.find_element_by_xpath("//input[@value='cancelled']").click()
|
||||||
self.browser.find_element_by_xpath(
|
|
||||||
"//input[@value='cancelled']").click()
|
|
||||||
|
|
||||||
icalUrl = self.browser.find_element_by_id("cal-url").text
|
icalUrl = self.browser.find_element_by_id("cal-url").text
|
||||||
response = c.get(icalUrl)
|
response = c.get(icalUrl)
|
||||||
self.assertEqual(200, response.status_code)
|
self.assertEqual(200, response.status_code)
|
||||||
|
|
||||||
expectedIn = [18]
|
expectedIn= [18]
|
||||||
for test in range(1, 18):
|
for test in range(1,18):
|
||||||
if test in expectedIn:
|
if test in expectedIn:
|
||||||
self.assertIn("TE E" + str(test) + " ", response.content)
|
self.assertIn("TE E"+str(test)+" ", response.content)
|
||||||
else:
|
else:
|
||||||
self.assertNotIn("TE E" + str(test) + " ", response.content)
|
self.assertNotIn("TE E"+str(test)+" ", response.content)
|
||||||
|
|
||||||
# Nothing selected
|
# Nothing selected
|
||||||
self.browser.find_element_by_xpath("//input[@value='non-rig']").click()
|
self.browser.find_element_by_xpath("//input[@value='non-rig']").click()
|
||||||
self.browser.find_element_by_xpath(
|
self.browser.find_element_by_xpath("//input[@value='cancelled']").click()
|
||||||
"//input[@value='cancelled']").click()
|
|
||||||
|
|
||||||
icalUrl = self.browser.find_element_by_id("cal-url").text
|
icalUrl = self.browser.find_element_by_id("cal-url").text
|
||||||
response = c.get(icalUrl)
|
response = c.get(icalUrl)
|
||||||
self.assertEqual(200, response.status_code)
|
self.assertEqual(200, response.status_code)
|
||||||
|
|
||||||
expectedIn = []
|
expectedIn= []
|
||||||
for test in range(1, 18):
|
for test in range(1,18):
|
||||||
if test in expectedIn:
|
if test in expectedIn:
|
||||||
self.assertIn("TE E" + str(test) + " ", response.content)
|
self.assertIn("TE E"+str(test)+" ", response.content)
|
||||||
else:
|
else:
|
||||||
self.assertNotIn("TE E" + str(test) + " ", response.content)
|
self.assertNotIn("TE E"+str(test)+" ", response.content)
|
||||||
|
|
||||||
# Wow - that was a lot of tests
|
# Wow - that was a lot of tests
|
||||||
|
|
||||||
|
|
||||||
class animation_is_finished(object):
|
class animation_is_finished(object):
|
||||||
""" Checks if animation is done """
|
""" Checks if animation is done """
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
from datetime import date, timedelta, datetime, time
|
|
||||||
from decimal import *
|
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from RIGS import models
|
from RIGS import models
|
||||||
|
from datetime import date, timedelta, datetime, time
|
||||||
|
from decimal import *
|
||||||
|
|
||||||
|
|
||||||
class ProfileTestCase(TestCase):
|
class ProfileTestCase(TestCase):
|
||||||
@@ -18,10 +16,8 @@ class ProfileTestCase(TestCase):
|
|||||||
|
|
||||||
class VatRateTestCase(TestCase):
|
class VatRateTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
models.VatRate.objects.create(
|
models.VatRate.objects.create(start_at='2014-03-01', rate=0.20, comment='test1')
|
||||||
start_at='2014-03-01', rate=0.20, comment='test1')
|
models.VatRate.objects.create(start_at='2016-03-01', rate=0.15, comment='test2')
|
||||||
models.VatRate.objects.create(
|
|
||||||
start_at='2016-03-01', rate=0.15, comment='test2')
|
|
||||||
|
|
||||||
def test_find_correct(self):
|
def test_find_correct(self):
|
||||||
r = models.VatRate.objects.find_rate('2015-03-01')
|
r = models.VatRate.objects.find_rate('2015-03-01')
|
||||||
@@ -38,27 +34,18 @@ class EventTestCase(TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.all_events = set(range(1, 18))
|
self.all_events = set(range(1, 18))
|
||||||
self.current_events = (1, 2, 3, 6, 7, 8, 10, 11, 12, 14, 15, 16, 18)
|
self.current_events = (1, 2, 3, 6, 7, 8, 10, 11, 12, 14, 15, 16, 18)
|
||||||
self.not_current_events = set(
|
self.not_current_events = set(self.all_events) - set(self.current_events)
|
||||||
self.all_events) - set(self.current_events)
|
|
||||||
|
|
||||||
self.vatrate = models.VatRate.objects.create(
|
self.vatrate = models.VatRate.objects.create(start_at='2014-03-05', rate=0.20, comment='test1')
|
||||||
start_at='2014-03-05', rate=0.20, comment='test1')
|
self.profile = models.Profile.objects.create(username="testuser1", email="1@test.com")
|
||||||
self.profile = models.Profile.objects.create(
|
|
||||||
username="testuser1", email="1@test.com")
|
|
||||||
|
|
||||||
# produce 7 normal events - 5 current
|
# produce 7 normal events - 5 current
|
||||||
models.Event.objects.create(name="TE E1", start_date=date.today() + timedelta(days=6),
|
models.Event.objects.create(name="TE E1", start_date=date.today() + timedelta(days=6),
|
||||||
description="start future no end")
|
description="start future no end")
|
||||||
models.Event.objects.create(
|
models.Event.objects.create(name="TE E2", start_date=date.today(), description="start today no end")
|
||||||
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(),
|
models.Event.objects.create(name="TE E3", start_date=date.today(), end_date=date.today(),
|
||||||
description="start today with end today")
|
description="start today with end today")
|
||||||
models.Event.objects.create(
|
models.Event.objects.create(name="TE E4", start_date='2014-03-20', description="start past no end")
|
||||||
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',
|
models.Event.objects.create(name="TE E5", start_date='2014-03-20', end_date='2014-03-21',
|
||||||
description="start past with end past")
|
description="start past with end past")
|
||||||
models.Event.objects.create(name="TE E6", start_date=date.today() - timedelta(days=2),
|
models.Event.objects.create(name="TE E6", start_date=date.today() - timedelta(days=2),
|
||||||
@@ -75,11 +62,7 @@ class EventTestCase(TestCase):
|
|||||||
description="cancelled and started")
|
description="cancelled and started")
|
||||||
|
|
||||||
# 5 dry hire - 3 current
|
# 5 dry hire - 3 current
|
||||||
models.Event.objects.create(
|
models.Event.objects.create(name="TE E10", start_date=date.today(), dry_hire=True, description="dryhire today")
|
||||||
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,
|
models.Event.objects.create(name="TE E11", start_date=date.today(), dry_hire=True, checked_in_by=self.profile,
|
||||||
description="dryhire today, checked in")
|
description="dryhire today, checked in")
|
||||||
models.Event.objects.create(name="TE E12", start_date=date.today() - timedelta(days=1), dry_hire=True,
|
models.Event.objects.create(name="TE E12", start_date=date.today() - timedelta(days=1), dry_hire=True,
|
||||||
@@ -90,11 +73,7 @@ class EventTestCase(TestCase):
|
|||||||
status=models.Event.CANCELLED, description="dryhire today cancelled")
|
status=models.Event.CANCELLED, description="dryhire today cancelled")
|
||||||
|
|
||||||
# 4 non rig - 3 current
|
# 4 non rig - 3 current
|
||||||
models.Event.objects.create(
|
models.Event.objects.create(name="TE E15", start_date=date.today(), is_rig=False, description="non rig today")
|
||||||
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,
|
models.Event.objects.create(name="TE E16", start_date=date.today() + timedelta(days=1), is_rig=False,
|
||||||
description="non rig tomorrow")
|
description="non rig tomorrow")
|
||||||
models.Event.objects.create(name="TE E17", start_date=date.today() - timedelta(days=1), is_rig=False,
|
models.Event.objects.create(name="TE E17", start_date=date.today() - timedelta(days=1), is_rig=False,
|
||||||
@@ -104,8 +83,7 @@ class EventTestCase(TestCase):
|
|||||||
|
|
||||||
def test_count(self):
|
def test_count(self):
|
||||||
# Santiy check we have the expected events created
|
# Santiy check we have the expected events created
|
||||||
self.assertEqual(models.Event.objects.count(), 18,
|
self.assertEqual(models.Event.objects.count(), 18, "Incorrect number of events, check setup")
|
||||||
"Incorrect number of events, check setup")
|
|
||||||
|
|
||||||
def test_rig_count(self):
|
def test_rig_count(self):
|
||||||
# by my count this is 7
|
# by my count this is 7
|
||||||
@@ -115,16 +93,10 @@ class EventTestCase(TestCase):
|
|||||||
current_events = models.Event.objects.current_events()
|
current_events = models.Event.objects.current_events()
|
||||||
self.assertEqual(len(current_events), len(self.current_events))
|
self.assertEqual(len(current_events), len(self.current_events))
|
||||||
for eid in self.current_events:
|
for eid in self.current_events:
|
||||||
self.assertIn(
|
self.assertIn(models.Event.objects.get(name="TE E%d" % eid), current_events)
|
||||||
models.Event.objects.get(
|
|
||||||
name="TE E%d" %
|
|
||||||
eid), current_events)
|
|
||||||
|
|
||||||
for eid in self.not_current_events:
|
for eid in self.not_current_events:
|
||||||
self.assertNotIn(
|
self.assertNotIn(models.Event.objects.get(name="TE E%d" % eid), current_events)
|
||||||
models.Event.objects.get(
|
|
||||||
name="TE E%d" %
|
|
||||||
eid), current_events)
|
|
||||||
|
|
||||||
def test_related_venue(self):
|
def test_related_venue(self):
|
||||||
v1 = models.Venue.objects.create(name="TE V1")
|
v1 = models.Venue.objects.create(name="TE V1")
|
||||||
@@ -232,43 +204,29 @@ class EventTestCase(TestCase):
|
|||||||
event.save()
|
event.save()
|
||||||
|
|
||||||
def test_earliest_time(self):
|
def test_earliest_time(self):
|
||||||
event = models.Event(name="TE ET", start_date=date(2016, 0o1, 0o1))
|
event = models.Event(name="TE ET", start_date=date(2016, 01, 01))
|
||||||
|
|
||||||
# Just a start date
|
# Just a start date
|
||||||
self.assertEqual(event.earliest_time, date(2016, 0o1, 0o1))
|
self.assertEqual(event.earliest_time, date(2016, 01, 01))
|
||||||
|
|
||||||
# With start time
|
# With start time
|
||||||
event.start_time = time(9, 00)
|
event.start_time = time(9, 00)
|
||||||
self.assertEqual(
|
self.assertEqual(event.earliest_time, self.create_datetime(2016, 1, 1, 9, 00))
|
||||||
event.earliest_time,
|
|
||||||
self.create_datetime(
|
|
||||||
2016,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
9,
|
|
||||||
00))
|
|
||||||
|
|
||||||
# With access time
|
# With access time
|
||||||
event.access_at = self.create_datetime(2015, 12, 0o3, 9, 57)
|
event.access_at = self.create_datetime(2015, 12, 03, 9, 57)
|
||||||
self.assertEqual(event.earliest_time, event.access_at)
|
self.assertEqual(event.earliest_time, event.access_at)
|
||||||
|
|
||||||
# With meet time
|
# With meet time
|
||||||
event.meet_at = self.create_datetime(2015, 12, 0o3, 9, 55)
|
event.meet_at = self.create_datetime(2015, 12, 03, 9, 55)
|
||||||
self.assertEqual(event.earliest_time, event.meet_at)
|
self.assertEqual(event.earliest_time, event.meet_at)
|
||||||
|
|
||||||
# Check order isn't important
|
# Check order isn't important
|
||||||
event.start_date = date(2015, 12, 0o3)
|
event.start_date = date(2015, 12, 03)
|
||||||
self.assertEqual(
|
self.assertEqual(event.earliest_time, self.create_datetime(2015, 12, 03, 9, 00))
|
||||||
event.earliest_time,
|
|
||||||
self.create_datetime(
|
|
||||||
2015,
|
|
||||||
12,
|
|
||||||
0o3,
|
|
||||||
9,
|
|
||||||
00))
|
|
||||||
|
|
||||||
def test_latest_time(self):
|
def test_latest_time(self):
|
||||||
event = models.Event(name="TE LT", start_date=date(2016, 0o1, 0o1))
|
event = models.Event(name="TE LT", start_date=date(2016, 01, 01))
|
||||||
|
|
||||||
# Just start date
|
# Just start date
|
||||||
self.assertEqual(event.latest_time, event.start_date)
|
self.assertEqual(event.latest_time, event.start_date)
|
||||||
@@ -279,48 +237,25 @@ class EventTestCase(TestCase):
|
|||||||
|
|
||||||
# With end time
|
# With end time
|
||||||
event.end_time = time(23, 00)
|
event.end_time = time(23, 00)
|
||||||
self.assertEqual(
|
self.assertEqual(event.latest_time, self.create_datetime(2016, 1, 2, 23, 00))
|
||||||
event.latest_time, self.create_datetime(
|
|
||||||
2016, 1, 2, 23, 00))
|
|
||||||
|
|
||||||
def test_in_bounds(self):
|
def test_in_bounds(self):
|
||||||
manager = models.Event.objects
|
manager = models.Event.objects
|
||||||
events = [
|
events = [
|
||||||
manager.create(name="TE IB0", start_date='2016-01-02'), # yes no
|
manager.create(name="TE IB0", start_date='2016-01-02'), # yes no
|
||||||
manager.create(
|
manager.create(name="TE IB1", start_date='2015-12-31', end_date='2016-01-04'),
|
||||||
name="TE IB1",
|
|
||||||
start_date='2015-12-31',
|
|
||||||
end_date='2016-01-04'),
|
|
||||||
|
|
||||||
# basic checks
|
# basic checks
|
||||||
manager.create(
|
manager.create(name='TE IB2', start_date='2016-01-02', end_date='2016-01-04'),
|
||||||
name='TE IB2',
|
manager.create(name='TE IB3', start_date='2015-12-31', end_date='2016-01-03'),
|
||||||
start_date='2016-01-02',
|
manager.create(name='TE IB4', start_date='2016-01-04', access_at='2016-01-03'),
|
||||||
end_date='2016-01-04'),
|
manager.create(name='TE IB5', start_date='2016-01-04', meet_at='2016-01-02'),
|
||||||
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
|
# negative check
|
||||||
manager.create(
|
manager.create(name='TE IB6', start_date='2015-12-31', end_date='2016-01-01'),
|
||||||
name='TE IB6',
|
|
||||||
start_date='2015-12-31',
|
|
||||||
end_date='2016-01-01'),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
in_bounds = manager.events_in_bounds(
|
in_bounds = manager.events_in_bounds(datetime(2016, 1, 2), datetime(2016, 1, 3))
|
||||||
datetime(
|
|
||||||
2016, 1, 2), datetime(
|
|
||||||
2016, 1, 3))
|
|
||||||
self.assertIn(events[0], in_bounds)
|
self.assertIn(events[0], in_bounds)
|
||||||
self.assertIn(events[1], in_bounds)
|
self.assertIn(events[1], in_bounds)
|
||||||
self.assertIn(events[2], in_bounds)
|
self.assertIn(events[2], in_bounds)
|
||||||
@@ -337,14 +272,11 @@ class EventTestCase(TestCase):
|
|||||||
|
|
||||||
class EventItemTestCase(TestCase):
|
class EventItemTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.e1 = models.Event.objects.create(
|
self.e1 = models.Event.objects.create(name="TI E1", start_date=date.today())
|
||||||
name="TI E1", start_date=date.today())
|
self.e2 = models.Event.objects.create(name="TI E2", start_date=date.today())
|
||||||
self.e2 = models.Event.objects.create(
|
|
||||||
name="TI E2", start_date=date.today())
|
|
||||||
|
|
||||||
def test_item_cost(self):
|
def test_item_cost(self):
|
||||||
item = models.EventItem.objects.create(
|
item = models.EventItem.objects.create(event=self.e1, name="TI I1", quantity=1, cost=1.00, order=1)
|
||||||
event=self.e1, name="TI I1", quantity=1, cost=1.00, order=1)
|
|
||||||
self.assertEqual(item.total_cost, 1.00)
|
self.assertEqual(item.total_cost, 1.00)
|
||||||
|
|
||||||
item.cost = 2.50
|
item.cost = 2.50
|
||||||
@@ -357,10 +289,8 @@ class EventItemTestCase(TestCase):
|
|||||||
item.delete()
|
item.delete()
|
||||||
|
|
||||||
def test_item_order(self):
|
def test_item_order(self):
|
||||||
i1 = models.EventItem.objects.create(
|
i1 = models.EventItem.objects.create(event=self.e1, name="TI I1", quantity=1, cost=1.00, order=1)
|
||||||
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)
|
||||||
i2 = models.EventItem.objects.create(
|
|
||||||
event=self.e1, name="TI I2", quantity=1, cost=1.00, order=2)
|
|
||||||
|
|
||||||
items = self.e1.items.all()
|
items = self.e1.items.all()
|
||||||
self.assertListEqual([i1, i2], list(items))
|
self.assertListEqual([i1, i2], list(items))
|
||||||
@@ -368,29 +298,17 @@ class EventItemTestCase(TestCase):
|
|||||||
|
|
||||||
class EventPricingTestCase(TestCase):
|
class EventPricingTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
models.VatRate.objects.create(
|
models.VatRate.objects.create(rate=0.20, comment="TP V1", start_at='2013-01-01')
|
||||||
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))
|
||||||
models.VatRate.objects.create(
|
self.e1 = models.Event.objects.create(name="TP E1", start_date=date.today() - timedelta(days=2))
|
||||||
rate=0.10,
|
self.e2 = models.Event.objects.create(name="TP E2", start_date=date.today())
|
||||||
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 E1, total 70.40
|
||||||
# Create some items E2, total 381.20
|
# Create some items E2, total 381.20
|
||||||
self.i1 = models.EventItem.objects.create(
|
self.i1 = models.EventItem.objects.create(event=self.e1, name="TP I1", quantity=1, cost=50.00, order=1)
|
||||||
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.i2 = models.EventItem.objects.create(
|
self.i3 = models.EventItem.objects.create(event=self.e1, name="TP I3", quantity=7, cost=2.00, order=3)
|
||||||
event=self.e1, name="TP I2", quantity=2, cost=3.20, order=2)
|
self.i4 = models.EventItem.objects.create(event=self.e2, name="TP I4", quantity=2, cost=190.60, order=1)
|
||||||
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.
|
# 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
|
# Using anything else results in a failure due to floating point arritmetic
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
from datetime import date
|
|
||||||
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
|
||||||
from django.core.management import call_command
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.utils import override_settings
|
from datetime import date
|
||||||
|
|
||||||
from RIGS import models
|
from RIGS import models
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
|
||||||
|
|
||||||
class TestAdminMergeObjects(TestCase):
|
class TestAdminMergeObjects(TestCase):
|
||||||
@@ -47,10 +44,7 @@ class TestAdminMergeObjects(TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.profile.set_password('testuser')
|
self.profile.set_password('testuser')
|
||||||
self.profile.save()
|
self.profile.save()
|
||||||
self.assertTrue(
|
self.assertTrue(self.client.login(username=self.profile.username, password='testuser'))
|
||||||
self.client.login(
|
|
||||||
username=self.profile.username,
|
|
||||||
password='testuser'))
|
|
||||||
|
|
||||||
def test_merge_confirmation(self):
|
def test_merge_confirmation(self):
|
||||||
change_url = reverse('admin:RIGS_venue_changelist')
|
change_url = reverse('admin:RIGS_venue_changelist')
|
||||||
@@ -92,16 +86,10 @@ class TestAdminMergeObjects(TestCase):
|
|||||||
self.assertTrue(models.Venue.objects.get(pk=self.venues[1].pk))
|
self.assertTrue(models.Venue.objects.get(pk=self.venues[1].pk))
|
||||||
|
|
||||||
# Check the un-needed venue has been disposed of
|
# Check the un-needed venue has been disposed of
|
||||||
self.assertRaises(
|
self.assertRaises(ObjectDoesNotExist, models.Venue.objects.get, pk=self.venues[2].pk)
|
||||||
ObjectDoesNotExist,
|
|
||||||
models.Venue.objects.get,
|
|
||||||
pk=self.venues[2].pk)
|
|
||||||
|
|
||||||
# Check the one we didn't delete is still there
|
# Check the one we didn't delete is still there
|
||||||
self.assertEqual(
|
self.assertEqual(models.Venue.objects.get(pk=self.venues[3].pk), self.venues[3])
|
||||||
models.Venue.objects.get(
|
|
||||||
pk=self.venues[3].pk),
|
|
||||||
self.venues[3])
|
|
||||||
|
|
||||||
# Check the events have been moved to the master venue
|
# Check the events have been moved to the master venue
|
||||||
for key, event in self.events.iteritems():
|
for key, event in self.events.iteritems():
|
||||||
@@ -127,16 +115,10 @@ class TestAdminMergeObjects(TestCase):
|
|||||||
self.assertTrue(models.Person.objects.get(pk=self.persons[1].pk))
|
self.assertTrue(models.Person.objects.get(pk=self.persons[1].pk))
|
||||||
|
|
||||||
# Check the un-needed people have been disposed of
|
# Check the un-needed people have been disposed of
|
||||||
self.assertRaises(
|
self.assertRaises(ObjectDoesNotExist, models.Person.objects.get, pk=self.persons[2].pk)
|
||||||
ObjectDoesNotExist,
|
|
||||||
models.Person.objects.get,
|
|
||||||
pk=self.persons[2].pk)
|
|
||||||
|
|
||||||
# Check the one we didn't delete is still there
|
# Check the one we didn't delete is still there
|
||||||
self.assertEqual(
|
self.assertEqual(models.Person.objects.get(pk=self.persons[3].pk), self.persons[3])
|
||||||
models.Person.objects.get(
|
|
||||||
pk=self.persons[3].pk),
|
|
||||||
self.persons[3])
|
|
||||||
|
|
||||||
# Check the events have been moved to the master person
|
# Check the events have been moved to the master person
|
||||||
for key, event in self.events.iteritems():
|
for key, event in self.events.iteritems():
|
||||||
@@ -159,118 +141,17 @@ class TestAdminMergeObjects(TestCase):
|
|||||||
self.assertContains(response, self.organisations[1].name)
|
self.assertContains(response, self.organisations[1].name)
|
||||||
|
|
||||||
# Check the master copy still exists
|
# Check the master copy still exists
|
||||||
self.assertTrue(
|
self.assertTrue(models.Organisation.objects.get(pk=self.organisations[1].pk))
|
||||||
models.Organisation.objects.get(
|
|
||||||
pk=self.organisations[1].pk))
|
|
||||||
|
|
||||||
# Check the un-needed organisations have been disposed of
|
# Check the un-needed organisations have been disposed of
|
||||||
self.assertRaises(
|
self.assertRaises(ObjectDoesNotExist, models.Organisation.objects.get, pk=self.organisations[2].pk)
|
||||||
ObjectDoesNotExist,
|
|
||||||
models.Organisation.objects.get,
|
|
||||||
pk=self.organisations[2].pk)
|
|
||||||
|
|
||||||
# Check the one we didn't delete is still there
|
# Check the one we didn't delete is still there
|
||||||
self.assertEqual(
|
self.assertEqual(models.Organisation.objects.get(pk=self.organisations[3].pk), self.organisations[3])
|
||||||
models.Organisation.objects.get(
|
|
||||||
pk=self.organisations[3].pk),
|
|
||||||
self.organisations[3])
|
|
||||||
|
|
||||||
# Check the events have been moved to the master organisation
|
# Check the events have been moved to the master organisation
|
||||||
for key, event in self.events.iteritems():
|
for key, event in self.events.iteritems():
|
||||||
updatedEvent = models.Event.objects.get(pk=event.pk)
|
updatedEvent = models.Event.objects.get(pk=event.pk)
|
||||||
if event.organisation == self.organisations[
|
if event.organisation == self.organisations[3]: # The one we left in place
|
||||||
3]: # The one we left in place
|
|
||||||
continue
|
continue
|
||||||
self.assertEqual(updatedEvent.organisation, self.organisations[1])
|
self.assertEqual(updatedEvent.organisation, self.organisations[1])
|
||||||
|
|
||||||
|
|
||||||
class TestInvoiceDelete(TestCase):
|
|
||||||
@classmethod
|
|
||||||
def setUpTestData(cls):
|
|
||||||
cls.profile = models.Profile.objects.create(
|
|
||||||
username="testuser1",
|
|
||||||
email="1@test.com",
|
|
||||||
is_superuser=True,
|
|
||||||
is_active=True,
|
|
||||||
is_staff=True)
|
|
||||||
|
|
||||||
cls.events = {
|
|
||||||
1: models.Event.objects.create(name="TE E1", start_date=date.today()),
|
|
||||||
2: models.Event.objects.create(name="TE E2", start_date=date.today())
|
|
||||||
}
|
|
||||||
|
|
||||||
cls.invoices = {
|
|
||||||
1: models.Invoice.objects.create(event=cls.events[1]),
|
|
||||||
2: models.Invoice.objects.create(event=cls.events[2])
|
|
||||||
}
|
|
||||||
|
|
||||||
cls.payments = {
|
|
||||||
1: models.Payment.objects.create(invoice=cls.invoices[1], date=date.today(), amount=12.34,
|
|
||||||
method=models.Payment.CASH)
|
|
||||||
}
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.profile.set_password('testuser')
|
|
||||||
self.profile.save()
|
|
||||||
self.assertTrue(
|
|
||||||
self.client.login(
|
|
||||||
username=self.profile.username,
|
|
||||||
password='testuser'))
|
|
||||||
|
|
||||||
def test_invoice_delete_allowed(self):
|
|
||||||
request_url = reverse(
|
|
||||||
'invoice_delete', kwargs={
|
|
||||||
'pk': self.invoices[2].pk})
|
|
||||||
|
|
||||||
response = self.client.get(request_url, follow=True)
|
|
||||||
self.assertContains(response, "Are you sure")
|
|
||||||
|
|
||||||
# Check the invoice still exists
|
|
||||||
self.assertTrue(models.Invoice.objects.get(pk=self.invoices[2].pk))
|
|
||||||
|
|
||||||
# Actually delete it
|
|
||||||
response = self.client.post(request_url, follow=True)
|
|
||||||
|
|
||||||
# Check the invoice is deleted
|
|
||||||
self.assertRaises(
|
|
||||||
ObjectDoesNotExist,
|
|
||||||
models.Invoice.objects.get,
|
|
||||||
pk=self.invoices[2].pk)
|
|
||||||
|
|
||||||
def test_invoice_delete_not_allowed(self):
|
|
||||||
request_url = reverse(
|
|
||||||
'invoice_delete', kwargs={
|
|
||||||
'pk': self.invoices[1].pk})
|
|
||||||
|
|
||||||
response = self.client.get(request_url, follow=True)
|
|
||||||
self.assertContains(
|
|
||||||
response,
|
|
||||||
"To delete an invoice, delete the payments first.")
|
|
||||||
|
|
||||||
# Check the invoice still exists
|
|
||||||
self.assertTrue(models.Invoice.objects.get(pk=self.invoices[1].pk))
|
|
||||||
|
|
||||||
# Try to actually delete it
|
|
||||||
response = self.client.post(request_url, follow=True)
|
|
||||||
|
|
||||||
# Check this didn't work
|
|
||||||
self.assertTrue(models.Invoice.objects.get(pk=self.invoices[1].pk))
|
|
||||||
|
|
||||||
|
|
||||||
class TestSampleDataGenerator(TestCase):
|
|
||||||
@override_settings(DEBUG=True)
|
|
||||||
def test_generate_sample_data(self):
|
|
||||||
# Run the management command and check there are no exceptions
|
|
||||||
call_command('generateSampleData')
|
|
||||||
|
|
||||||
# Check there are lots of events
|
|
||||||
self.assertTrue(models.Event.objects.all().count() > 100)
|
|
||||||
|
|
||||||
def test_production_exception(self):
|
|
||||||
from django.core.management.base import CommandError
|
|
||||||
|
|
||||||
self.assertRaisesRegexp(
|
|
||||||
CommandError,
|
|
||||||
".*production",
|
|
||||||
call_command,
|
|
||||||
'generateSampleData')
|
|
||||||
|
|||||||
181
RIGS/urls.py
181
RIGS/urls.py
@@ -1,225 +1,158 @@
|
|||||||
from django.conf.urls import patterns, url
|
from django.conf.urls import patterns, include, url
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from RIGS import models, views, rigboard, finance, ical, versioning, forms
|
||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
|
|
||||||
from PyRIGS.decorators import api_key_required
|
|
||||||
from PyRIGS.decorators import permission_required_with_403
|
from PyRIGS.decorators import permission_required_with_403
|
||||||
from RIGS import models, views, rigboard, finance, ical, versioning, forms
|
from PyRIGS.decorators import api_key_required
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
# Examples:
|
# Examples:
|
||||||
# url(r'^$', 'PyRIGS.views.home', name='home'),
|
# url(r'^$', 'PyRIGS.views.home', name='home'),
|
||||||
# url(r'^blog/', include('blog.urls')),
|
# url(r'^blog/', include('blog.urls')),
|
||||||
url('^$', login_required(
|
url('^$', login_required(views.Index.as_view()), name='index'),
|
||||||
views.Index.as_view()), name='index'),
|
url(r'^closemodal/$', views.CloseModal.as_view(), name='closemodal'),
|
||||||
url(r'^closemodal/$',
|
|
||||||
views.CloseModal.as_view(),
|
|
||||||
name='closemodal'),
|
|
||||||
|
|
||||||
url('^user/login/$', 'RIGS.views.login', name='login'),
|
url('^user/login/$', 'RIGS.views.login', name='login'),
|
||||||
url(r'^user/password_reset/$',
|
url(r'^user/password_reset/$', 'django.contrib.auth.views.password_reset', {'password_reset_form':forms.PasswordReset}),
|
||||||
'django.contrib.auth.views.password_reset',
|
|
||||||
{'password_reset_form': forms.PasswordReset}),
|
|
||||||
|
|
||||||
# People
|
# People
|
||||||
url(r'^people/$', permission_required_with_403('RIGS.view_person')(views.PersonList.as_view()),
|
url(r'^people/$', permission_required_with_403('RIGS.view_person')(views.PersonList.as_view()),
|
||||||
name='person_list'),
|
name='person_list'),
|
||||||
url(r'^people/add/$',
|
url(r'^people/add/$',
|
||||||
permission_required_with_403('RIGS.add_person')(
|
permission_required_with_403('RIGS.add_person')(views.PersonCreate.as_view()),
|
||||||
views.PersonCreate.as_view()),
|
|
||||||
name='person_create'),
|
name='person_create'),
|
||||||
url(r'^people/(?P<pk>\d+)/$',
|
url(r'^people/(?P<pk>\d+)/$',
|
||||||
permission_required_with_403('RIGS.view_person')(
|
permission_required_with_403('RIGS.view_person')(views.PersonDetail.as_view()),
|
||||||
views.PersonDetail.as_view()),
|
|
||||||
name='person_detail'),
|
name='person_detail'),
|
||||||
url(r'^people/(?P<pk>\d+)/history/$',
|
url(r'^people/(?P<pk>\d+)/history/$',
|
||||||
permission_required_with_403('RIGS.view_person')(
|
permission_required_with_403('RIGS.view_person')(versioning.VersionHistory.as_view()),
|
||||||
versioning.VersionHistory.as_view()),
|
|
||||||
name='person_history', kwargs={'model': models.Person}),
|
name='person_history', kwargs={'model': models.Person}),
|
||||||
url(r'^people/(?P<pk>\d+)/edit/$',
|
url(r'^people/(?P<pk>\d+)/edit/$',
|
||||||
permission_required_with_403('RIGS.change_person')(
|
permission_required_with_403('RIGS.change_person')(views.PersonUpdate.as_view()),
|
||||||
views.PersonUpdate.as_view()),
|
|
||||||
name='person_update'),
|
name='person_update'),
|
||||||
|
|
||||||
# Organisations
|
# Organisations
|
||||||
url(r'^organisations/$',
|
url(r'^organisations/$',
|
||||||
permission_required_with_403('RIGS.view_organisation')(
|
permission_required_with_403('RIGS.view_organisation')(views.OrganisationList.as_view()),
|
||||||
views.OrganisationList.as_view()),
|
|
||||||
name='organisation_list'),
|
name='organisation_list'),
|
||||||
url(r'^organisations/add/$',
|
url(r'^organisations/add/$',
|
||||||
permission_required_with_403('RIGS.add_organisation')(
|
permission_required_with_403('RIGS.add_organisation')(views.OrganisationCreate.as_view()),
|
||||||
views.OrganisationCreate.as_view()),
|
|
||||||
name='organisation_create'),
|
name='organisation_create'),
|
||||||
url(r'^organisations/(?P<pk>\d+)/$',
|
url(r'^organisations/(?P<pk>\d+)/$',
|
||||||
permission_required_with_403('RIGS.view_organisation')(
|
permission_required_with_403('RIGS.view_organisation')(views.OrganisationDetail.as_view()),
|
||||||
views.OrganisationDetail.as_view()),
|
|
||||||
name='organisation_detail'),
|
name='organisation_detail'),
|
||||||
url(r'^organisations/(?P<pk>\d+)/history/$',
|
url(r'^organisations/(?P<pk>\d+)/history/$',
|
||||||
permission_required_with_403('RIGS.view_organisation')(
|
permission_required_with_403('RIGS.view_organisation')(versioning.VersionHistory.as_view()),
|
||||||
versioning.VersionHistory.as_view()),
|
|
||||||
name='organisation_history', kwargs={'model': models.Organisation}),
|
name='organisation_history', kwargs={'model': models.Organisation}),
|
||||||
url(r'^organisations/(?P<pk>\d+)/edit/$',
|
url(r'^organisations/(?P<pk>\d+)/edit/$',
|
||||||
permission_required_with_403('RIGS.change_organisation')(
|
permission_required_with_403('RIGS.change_organisation')(views.OrganisationUpdate.as_view()),
|
||||||
views.OrganisationUpdate.as_view()),
|
|
||||||
name='organisation_update'),
|
name='organisation_update'),
|
||||||
|
|
||||||
# Venues
|
# Venues
|
||||||
url(r'^venues/$',
|
url(r'^venues/$',
|
||||||
permission_required_with_403('RIGS.view_venue')(
|
permission_required_with_403('RIGS.view_venue')(views.VenueList.as_view()),
|
||||||
views.VenueList.as_view()),
|
|
||||||
name='venue_list'),
|
name='venue_list'),
|
||||||
url(r'^venues/add/$',
|
url(r'^venues/add/$',
|
||||||
permission_required_with_403('RIGS.add_venue')(
|
permission_required_with_403('RIGS.add_venue')(views.VenueCreate.as_view()),
|
||||||
views.VenueCreate.as_view()),
|
|
||||||
name='venue_create'),
|
name='venue_create'),
|
||||||
url(r'^venues/(?P<pk>\d+)/$',
|
url(r'^venues/(?P<pk>\d+)/$',
|
||||||
permission_required_with_403('RIGS.view_venue')(
|
permission_required_with_403('RIGS.view_venue')(views.VenueDetail.as_view()),
|
||||||
views.VenueDetail.as_view()),
|
|
||||||
name='venue_detail'),
|
name='venue_detail'),
|
||||||
url(r'^venues/(?P<pk>\d+)/history/$',
|
url(r'^venues/(?P<pk>\d+)/history/$',
|
||||||
permission_required_with_403('RIGS.view_venue')(
|
permission_required_with_403('RIGS.view_venue')(versioning.VersionHistory.as_view()),
|
||||||
versioning.VersionHistory.as_view()),
|
|
||||||
name='venue_history', kwargs={'model': models.Venue}),
|
name='venue_history', kwargs={'model': models.Venue}),
|
||||||
url(r'^venues/(?P<pk>\d+)/edit/$',
|
url(r'^venues/(?P<pk>\d+)/edit/$',
|
||||||
permission_required_with_403('RIGS.change_venue')(
|
permission_required_with_403('RIGS.change_venue')(views.VenueUpdate.as_view()),
|
||||||
views.VenueUpdate.as_view()),
|
|
||||||
name='venue_update'),
|
name='venue_update'),
|
||||||
|
|
||||||
# Rigboard
|
# Rigboard
|
||||||
url(r'^rigboard/$',
|
url(r'^rigboard/$', login_required(rigboard.RigboardIndex.as_view()), name='rigboard'),
|
||||||
login_required(rigboard.RigboardIndex.as_view()),
|
url(r'^rigboard/calendar/$', login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
|
||||||
name='rigboard'),
|
url(r'^rigboard/calendar/(?P<view>(month|week|day))/$', login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
|
||||||
url(r'^rigboard/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'),
|
||||||
login_required()(rigboard.WebCalendar.as_view()),
|
url(r'^rigboard/archive/$', RedirectView.as_view(permanent=True,pattern_name='event_archive')),
|
||||||
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/$',
|
url(r'^rigboard/activity/$',
|
||||||
permission_required_with_403('RIGS.view_event')(
|
permission_required_with_403('RIGS.view_event')(versioning.ActivityTable.as_view()),
|
||||||
versioning.ActivityTable.as_view()),
|
|
||||||
name='activity_table'),
|
name='activity_table'),
|
||||||
url(r'^rigboard/activity/feed/$',
|
url(r'^rigboard/activity/feed/$',
|
||||||
permission_required_with_403('RIGS.view_event')(
|
permission_required_with_403('RIGS.view_event')(versioning.ActivityFeed.as_view()),
|
||||||
versioning.ActivityFeed.as_view()),
|
|
||||||
name='activity_feed'),
|
name='activity_feed'),
|
||||||
|
|
||||||
url(r'^event/(?P<pk>\d+)/$',
|
url(r'^event/(?P<pk>\d+)/$',
|
||||||
permission_required_with_403('RIGS.view_event')(
|
permission_required_with_403('RIGS.view_event')(rigboard.EventDetail.as_view()),
|
||||||
rigboard.EventDetail.as_view()),
|
|
||||||
name='event_detail'),
|
name='event_detail'),
|
||||||
url(r'^event/(?P<pk>\d+)/print/$',
|
url(r'^event/(?P<pk>\d+)/print/$',
|
||||||
permission_required_with_403('RIGS.view_event')(
|
permission_required_with_403('RIGS.view_event')(rigboard.EventPrint.as_view()),
|
||||||
rigboard.EventPrint.as_view()),
|
|
||||||
name='event_print'),
|
name='event_print'),
|
||||||
url(r'^event/create/$',
|
url(r'^event/create/$',
|
||||||
permission_required_with_403('RIGS.add_event')(
|
permission_required_with_403('RIGS.add_event')(rigboard.EventCreate.as_view()),
|
||||||
rigboard.EventCreate.as_view()),
|
|
||||||
name='event_create'),
|
name='event_create'),
|
||||||
url(r'^event/(?P<pk>\d+)/edit/$',
|
url(r'^event/(?P<pk>\d+)/edit/$',
|
||||||
permission_required_with_403('RIGS.change_event')(
|
permission_required_with_403('RIGS.change_event')(rigboard.EventUpdate.as_view()),
|
||||||
rigboard.EventUpdate.as_view()),
|
|
||||||
name='event_update'),
|
name='event_update'),
|
||||||
url(r'^event/(?P<pk>\d+)/duplicate/$',
|
url(r'^event/(?P<pk>\d+)/duplicate/$',
|
||||||
permission_required_with_403('RIGS.add_event')(
|
permission_required_with_403('RIGS.add_event')(rigboard.EventDuplicate.as_view()),
|
||||||
rigboard.EventDuplicate.as_view()),
|
|
||||||
name='event_duplicate'),
|
name='event_duplicate'),
|
||||||
url(r'^event/archive/$', login_required()(rigboard.EventArchive.as_view()),
|
url(r'^event/archive/$', login_required()(rigboard.EventArchive.as_view()),
|
||||||
name='event_archive'),
|
name='event_archive'),
|
||||||
|
|
||||||
url(r'^event/(?P<pk>\d+)/history/$',
|
url(r'^event/(?P<pk>\d+)/history/$',
|
||||||
permission_required_with_403('RIGS.view_event')(
|
permission_required_with_403('RIGS.view_event')(versioning.VersionHistory.as_view()),
|
||||||
versioning.VersionHistory.as_view()),
|
|
||||||
name='event_history', kwargs={'model': models.Event}),
|
name='event_history', kwargs={'model': models.Event}),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Finance
|
# Finance
|
||||||
url(r'^invoice/$',
|
url(r'^invoice/$',
|
||||||
permission_required_with_403('RIGS.view_invoice')(
|
permission_required_with_403('RIGS.view_invoice')(finance.InvoiceIndex.as_view()),
|
||||||
finance.InvoiceIndex.as_view()),
|
|
||||||
name='invoice_list'),
|
name='invoice_list'),
|
||||||
url(r'^invoice/archive/$',
|
url(r'^invoice/archive/$',
|
||||||
permission_required_with_403('RIGS.view_invoice')(
|
permission_required_with_403('RIGS.view_invoice')(finance.InvoiceArchive.as_view()),
|
||||||
finance.InvoiceArchive.as_view()),
|
|
||||||
name='invoice_archive'),
|
name='invoice_archive'),
|
||||||
url(r'^invoice/waiting/$',
|
url(r'^invoice/waiting/$',
|
||||||
permission_required_with_403('RIGS.add_invoice')(
|
permission_required_with_403('RIGS.add_invoice')(finance.InvoiceWaiting.as_view()),
|
||||||
finance.InvoiceWaiting.as_view()),
|
|
||||||
name='invoice_waiting'),
|
name='invoice_waiting'),
|
||||||
|
|
||||||
url(r'^event/(?P<pk>\d+)/invoice/$',
|
url(r'^event/(?P<pk>\d+)/invoice/$',
|
||||||
permission_required_with_403('RIGS.add_invoice')(
|
permission_required_with_403('RIGS.add_invoice')(finance.InvoiceEvent.as_view()),
|
||||||
finance.InvoiceEvent.as_view()),
|
|
||||||
name='invoice_event'),
|
name='invoice_event'),
|
||||||
|
|
||||||
url(r'^invoice/(?P<pk>\d+)/$',
|
url(r'^invoice/(?P<pk>\d+)/$',
|
||||||
permission_required_with_403('RIGS.view_invoice')(
|
permission_required_with_403('RIGS.view_invoice')(finance.InvoiceDetail.as_view()),
|
||||||
finance.InvoiceDetail.as_view()),
|
|
||||||
name='invoice_detail'),
|
name='invoice_detail'),
|
||||||
url(r'^invoice/(?P<pk>\d+)/print/$',
|
url(r'^invoice/(?P<pk>\d+)/print/$',
|
||||||
permission_required_with_403('RIGS.view_invoice')(
|
permission_required_with_403('RIGS.view_invoice')(finance.InvoicePrint.as_view()),
|
||||||
finance.InvoicePrint.as_view()),
|
|
||||||
name='invoice_print'),
|
name='invoice_print'),
|
||||||
url(r'^invoice/(?P<pk>\d+)/void/$',
|
url(r'^invoice/(?P<pk>\d+)/void/$',
|
||||||
permission_required_with_403('RIGS.change_invoice')(
|
permission_required_with_403('RIGS.change_invoice')(finance.InvoiceVoid.as_view()),
|
||||||
finance.InvoiceVoid.as_view()),
|
|
||||||
name='invoice_void'),
|
name='invoice_void'),
|
||||||
url(r'^invoice/(?P<pk>\d+)/delete/$',
|
|
||||||
permission_required_with_403('RIGS.change_invoice')(
|
|
||||||
finance.InvoiceDelete.as_view()),
|
|
||||||
name='invoice_delete'),
|
|
||||||
url(r'^payment/create/$',
|
url(r'^payment/create/$',
|
||||||
permission_required_with_403('RIGS.add_payment')(
|
permission_required_with_403('RIGS.add_payment')(finance.PaymentCreate.as_view()),
|
||||||
finance.PaymentCreate.as_view()),
|
|
||||||
name='payment_create'),
|
name='payment_create'),
|
||||||
url(r'^payment/(?P<pk>\d+)/delete/$',
|
url(r'^payment/(?P<pk>\d+)/delete/$',
|
||||||
permission_required_with_403('RIGS.add_payment')(
|
permission_required_with_403('RIGS.add_payment')(finance.PaymentDelete.as_view()),
|
||||||
finance.PaymentDelete.as_view()),
|
|
||||||
name='payment_delete'),
|
name='payment_delete'),
|
||||||
|
|
||||||
# User editing
|
# User editing
|
||||||
url(r'^user/$',
|
url(r'^user/$', login_required(views.ProfileDetail.as_view()), name='profile_detail'),
|
||||||
login_required(views.ProfileDetail.as_view()),
|
|
||||||
name='profile_detail'),
|
|
||||||
url(r'^user/(?P<pk>\d+)/$',
|
url(r'^user/(?P<pk>\d+)/$',
|
||||||
permission_required_with_403('RIGS.view_profile')(
|
permission_required_with_403('RIGS.view_profile')(views.ProfileDetail.as_view()),
|
||||||
views.ProfileDetail.as_view()),
|
name='profile_detail'),
|
||||||
name='profile_detail'),
|
|
||||||
url(r'^user/edit/$', login_required(views.ProfileUpdateSelf.as_view()),
|
url(r'^user/edit/$', login_required(views.ProfileUpdateSelf.as_view()),
|
||||||
name='profile_update_self'),
|
name='profile_update_self'),
|
||||||
url(r'^user/reset_api_key$',
|
url(r'^user/reset_api_key$', login_required(views.ResetApiKey.as_view(permanent=False)), name='reset_api_key'),
|
||||||
login_required(
|
|
||||||
views.ResetApiKey.as_view(
|
|
||||||
permanent=False)),
|
|
||||||
name='reset_api_key'),
|
|
||||||
|
|
||||||
# ICS Calendar - API key authentication
|
# ICS Calendar - API key authentication
|
||||||
url(r'^ical/(?P<api_pk>\d+)/(?P<api_key>\w+)/rigs.ics$',
|
url(r'^ical/(?P<api_pk>\d+)/(?P<api_key>\w+)/rigs.ics$', api_key_required(ical.CalendarICS()), name="ics_calendar"),
|
||||||
api_key_required(ical.CalendarICS()), name="ics_calendar"),
|
|
||||||
|
|
||||||
# API
|
# API
|
||||||
url(r'^api/(?P<model>\w+)/$',
|
url(r'^api/(?P<model>\w+)/$', login_required(views.SecureAPIRequest.as_view()), name="api_secure"),
|
||||||
login_required(views.SecureAPIRequest.as_view()),
|
url(r'^api/(?P<model>\w+)/(?P<pk>\d+)/$', login_required(views.SecureAPIRequest.as_view()), name="api_secure"),
|
||||||
name="api_secure"),
|
|
||||||
url(r'^api/(?P<model>\w+)/(?P<pk>\d+)/$',
|
|
||||||
login_required(views.SecureAPIRequest.as_view()),
|
|
||||||
name="api_secure"),
|
|
||||||
|
|
||||||
# Legacy URL's
|
# Legacy URL's
|
||||||
url(r'^rig/show/(?P<pk>\d+)/$',
|
url(r'^rig/show/(?P<pk>\d+)/$', RedirectView.as_view(permanent=True,pattern_name='event_detail')),
|
||||||
RedirectView.as_view(permanent=True,
|
url(r'^bookings/$', RedirectView.as_view(permanent=True,pattern_name='rigboard')),
|
||||||
pattern_name='event_detail')),
|
url(r'^bookings/past/$', RedirectView.as_view(permanent=True,pattern_name='event_archive')),
|
||||||
url(r'^bookings/$',
|
)
|
||||||
RedirectView.as_view(permanent=True,
|
|
||||||
pattern_name='rigboard')),
|
|
||||||
url(r'^bookings/past/$',
|
|
||||||
RedirectView.as_view(permanent=True,
|
|
||||||
pattern_name='event_archive')),
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,39 +1,37 @@
|
|||||||
import datetime
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import reversion
|
|
||||||
from diff_match_patch import diff_match_patch
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db.models import IntegerField, EmailField, TextField
|
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
|
|
||||||
|
# Versioning
|
||||||
|
import reversion
|
||||||
|
from reversion.models import Version
|
||||||
|
from django.contrib.contenttypes.models import ContentType # Used to lookup the content_type
|
||||||
|
from django.db.models import IntegerField, EmailField, TextField
|
||||||
|
from diff_match_patch import diff_match_patch
|
||||||
|
|
||||||
from RIGS import models
|
from RIGS import models
|
||||||
|
import datetime
|
||||||
|
|
||||||
logger = logging.getLogger('tec.pyrigs')
|
logger = logging.getLogger('tec.pyrigs')
|
||||||
|
|
||||||
|
|
||||||
def model_compare(oldObj, newObj, excluded_keys=[]):
|
def model_compare(oldObj, newObj, excluded_keys=[]):
|
||||||
# recieves two objects of the same model, and compares them. Returns an
|
# recieves two objects of the same model, and compares them. Returns an array of FieldCompare objects
|
||||||
# array of FieldCompare objects
|
|
||||||
try:
|
try:
|
||||||
# This becomes deprecated in Django 1.8!!!!!!!!!!!!! (but an
|
theFields = oldObj._meta.fields # This becomes deprecated in Django 1.8!!!!!!!!!!!!! (but an alternative becomes available)
|
||||||
# alternative becomes available)
|
|
||||||
theFields = oldObj._meta.fields
|
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
theFields = newObj._meta.fields
|
theFields = newObj._meta.fields
|
||||||
|
|
||||||
class FieldCompare(object):
|
class FieldCompare(object):
|
||||||
|
|
||||||
def __init__(self, field=None, old=None, new=None):
|
def __init__(self, field=None, old=None, new=None):
|
||||||
self.field = field
|
self.field = field
|
||||||
self._old = old
|
self._old = old
|
||||||
self._new = new
|
self._new = new
|
||||||
|
|
||||||
def display_value(self, value):
|
def display_value(self, value):
|
||||||
if isinstance(self.field, IntegerField) and len(
|
if isinstance(self.field, IntegerField) and len(self.field.choices) > 0:
|
||||||
self.field.choices) > 0:
|
|
||||||
return [x[1] for x in self.field.choices if x[0] == value][0]
|
return [x[1] for x in self.field.choices if x[0] == value][0]
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@@ -106,15 +104,13 @@ def model_compare(oldObj, newObj, excluded_keys=[]):
|
|||||||
|
|
||||||
|
|
||||||
def compare_event_items(old, new):
|
def compare_event_items(old, new):
|
||||||
# Recieves two event version objects and compares their items, returns an
|
# Recieves two event version objects and compares their items, returns an array of ItemCompare objects
|
||||||
# array of ItemCompare objects
|
|
||||||
|
|
||||||
item_type = ContentType.objects.get_for_model(models.EventItem)
|
item_type = ContentType.objects.get_for_model(models.EventItem)
|
||||||
old_item_versions = old.revision.version_set.filter(content_type=item_type)
|
old_item_versions = old.revision.version_set.filter(content_type=item_type)
|
||||||
new_item_versions = new.revision.version_set.filter(content_type=item_type)
|
new_item_versions = new.revision.version_set.filter(content_type=item_type)
|
||||||
|
|
||||||
class ItemCompare(object):
|
class ItemCompare(object):
|
||||||
|
|
||||||
def __init__(self, old=None, new=None, changes=None):
|
def __init__(self, old=None, new=None, changes=None):
|
||||||
self.old = old
|
self.old = old
|
||||||
self.new = new
|
self.new = new
|
||||||
@@ -130,25 +126,18 @@ def compare_event_items(old, new):
|
|||||||
for version in new_item_versions: # go through the new versions
|
for version in new_item_versions: # go through the new versions
|
||||||
if version.field_dict["event"] == new.object_id_int:
|
if version.field_dict["event"] == new.object_id_int:
|
||||||
try:
|
try:
|
||||||
# see if there's a matching old version
|
compare = item_dict[version.object_id] # see if there's a matching old version
|
||||||
compare = item_dict[version.object_id]
|
compare.new = version.object_version.object # then add the new version to the dictionary
|
||||||
# then add the new version to the dictionary
|
|
||||||
compare.new = version.object_version.object
|
|
||||||
except KeyError: # there's no matching old version, so add this item to the dictionary by itself
|
except KeyError: # there's no matching old version, so add this item to the dictionary by itself
|
||||||
compare = ItemCompare(new=version.object_version.object)
|
compare = ItemCompare(new=version.object_version.object)
|
||||||
|
|
||||||
# update the dictionary with the changes
|
item_dict[version.object_id] = compare # update the dictionary with the changes
|
||||||
item_dict[version.object_id] = compare
|
|
||||||
|
|
||||||
changes = []
|
changes = []
|
||||||
for (_, compare) in item_dict.items():
|
for (_, compare) in item_dict.items():
|
||||||
compare.changes = model_compare(
|
compare.changes = model_compare(compare.old, compare.new, ['id', 'event', 'order']) # see what's changed
|
||||||
compare.old, compare.new, [
|
|
||||||
'id', 'event', 'order']) # see what's changed
|
|
||||||
if len(compare.changes) >= 1:
|
if len(compare.changes) >= 1:
|
||||||
# transfer into a sequential array to make it easier to deal with
|
changes.append(compare) # transfer into a sequential array to make it easier to deal with later
|
||||||
# later
|
|
||||||
changes.append(compare)
|
|
||||||
|
|
||||||
return changes
|
return changes
|
||||||
|
|
||||||
@@ -169,8 +158,7 @@ def get_previous_version(version):
|
|||||||
thisId = version.object_id
|
thisId = version.object_id
|
||||||
thisVersionId = version.pk
|
thisVersionId = version.pk
|
||||||
|
|
||||||
versions = reversion.get_for_object_reference(
|
versions = reversion.get_for_object_reference(version.content_type.model_class(), thisId)
|
||||||
version.content_type.model_class(), thisId)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
previousVersions = versions.filter(revision_id__lt=version.revision_id).latest(
|
previousVersions = versions.filter(revision_id__lt=version.revision_id).latest(
|
||||||
@@ -185,7 +173,7 @@ def get_changes_for_version(newVersion, oldVersion=None):
|
|||||||
# Pass in a previous version if you already know it (for efficiancy)
|
# Pass in a previous version if you already know it (for efficiancy)
|
||||||
# if not provided then it will be looked up in the database
|
# if not provided then it will be looked up in the database
|
||||||
|
|
||||||
if oldVersion is None:
|
if oldVersion == None:
|
||||||
oldVersion = get_previous_version(newVersion)
|
oldVersion = get_previous_version(newVersion)
|
||||||
|
|
||||||
modelClass = newVersion.content_type.model_class()
|
modelClass = newVersion.content_type.model_class()
|
||||||
@@ -204,8 +192,7 @@ def get_changes_for_version(newVersion, oldVersion=None):
|
|||||||
|
|
||||||
if oldVersion:
|
if oldVersion:
|
||||||
compare['old'] = oldVersion.object_version.object
|
compare['old'] = oldVersion.object_version.object
|
||||||
compare['field_changes'] = model_compare(
|
compare['field_changes'] = model_compare(compare['old'], compare['new'])
|
||||||
compare['old'], compare['new'])
|
|
||||||
compare['item_changes'] = compare_event_items(oldVersion, newVersion)
|
compare['item_changes'] = compare_event_items(oldVersion, newVersion)
|
||||||
|
|
||||||
return compare
|
return compare
|
||||||
@@ -220,8 +207,7 @@ class VersionHistory(generic.ListView):
|
|||||||
thisModel = self.kwargs['model']
|
thisModel = self.kwargs['model']
|
||||||
|
|
||||||
# thisObject = get_object_or_404(thisModel, pk=self.kwargs['pk'])
|
# thisObject = get_object_or_404(thisModel, pk=self.kwargs['pk'])
|
||||||
versions = reversion.get_for_object_reference(
|
versions = reversion.get_for_object_reference(thisModel, self.kwargs['pk'])
|
||||||
thisModel, self.kwargs['pk'])
|
|
||||||
|
|
||||||
return versions
|
return versions
|
||||||
|
|
||||||
@@ -239,8 +225,7 @@ class VersionHistory(generic.ListView):
|
|||||||
if versionNo >= len(versions) - 1:
|
if versionNo >= len(versions) - 1:
|
||||||
thisItem = get_changes_for_version(thisVersion, None)
|
thisItem = get_changes_for_version(thisVersion, None)
|
||||||
else:
|
else:
|
||||||
thisItem = get_changes_for_version(
|
thisItem = get_changes_for_version(thisVersion, versions[versionNo + 1])
|
||||||
thisVersion, versions[versionNo + 1])
|
|
||||||
|
|
||||||
items.append(thisItem)
|
items.append(thisItem)
|
||||||
|
|
||||||
@@ -256,8 +241,7 @@ class ActivityTable(generic.ListView):
|
|||||||
paginate_by = 25
|
paginate_by = 25
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
versions = get_versions_for_model(
|
versions = get_versions_for_model([models.Event, models.Venue, models.Person, models.Organisation])
|
||||||
[models.Event, models.Venue, models.Person, models.Organisation])
|
|
||||||
return versions
|
return versions
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
@@ -281,17 +265,14 @@ class ActivityFeed(generic.ListView):
|
|||||||
paginate_by = 25
|
paginate_by = 25
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
versions = get_versions_for_model(
|
versions = get_versions_for_model([models.Event, models.Venue, models.Person, models.Organisation])
|
||||||
[models.Event, models.Venue, models.Person, models.Organisation])
|
|
||||||
return versions
|
return versions
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
maxTimeDelta = []
|
maxTimeDelta = []
|
||||||
|
|
||||||
maxTimeDelta.append({'maxAge': datetime.timedelta(
|
maxTimeDelta.append({'maxAge': datetime.timedelta(days=1), 'group': datetime.timedelta(hours=1)})
|
||||||
days=1), 'group': datetime.timedelta(hours=1)})
|
maxTimeDelta.append({'maxAge': None, 'group': datetime.timedelta(days=1)})
|
||||||
maxTimeDelta.append(
|
|
||||||
{'maxAge': None, 'group': datetime.timedelta(days=1)})
|
|
||||||
|
|
||||||
# Call the base implementation first to get a context
|
# Call the base implementation first to get a context
|
||||||
context = super(ActivityFeed, self).get_context_data(**kwargs)
|
context = super(ActivityFeed, self).get_context_data(**kwargs)
|
||||||
@@ -300,23 +281,19 @@ class ActivityFeed(generic.ListView):
|
|||||||
|
|
||||||
for thisVersion in context['object_list']:
|
for thisVersion in context['object_list']:
|
||||||
thisItem = get_changes_for_version(thisVersion, None)
|
thisItem = get_changes_for_version(thisVersion, None)
|
||||||
if thisItem['item_changes'] or thisItem[
|
if thisItem['item_changes'] or thisItem['field_changes'] or thisItem['old'] == None:
|
||||||
'field_changes'] or thisItem['old'] is None:
|
|
||||||
thisItem['withPrevious'] = False
|
thisItem['withPrevious'] = False
|
||||||
if len(items) >= 1:
|
if len(items) >= 1:
|
||||||
timeAgo = datetime.datetime.now(thisItem['revision'].date_created.tzinfo) - thisItem[
|
timeAgo = datetime.datetime.now(thisItem['revision'].date_created.tzinfo) - thisItem[
|
||||||
'revision'].date_created
|
'revision'].date_created
|
||||||
timeDiff = items[-1]['revision'].date_created - \
|
timeDiff = items[-1]['revision'].date_created - thisItem['revision'].date_created
|
||||||
thisItem['revision'].date_created
|
|
||||||
timeTogether = False
|
timeTogether = False
|
||||||
for params in maxTimeDelta:
|
for params in maxTimeDelta:
|
||||||
if params['maxAge'] is None or timeAgo <= params[
|
if params['maxAge'] is None or timeAgo <= params['maxAge']:
|
||||||
'maxAge']:
|
|
||||||
timeTogether = timeDiff < params['group']
|
timeTogether = timeDiff < params['group']
|
||||||
break
|
break
|
||||||
|
|
||||||
sameUser = thisItem[
|
sameUser = thisItem['revision'].user == items[-1]['revision'].user
|
||||||
'revision'].user == items[-1]['revision'].user
|
|
||||||
thisItem['withPrevious'] = timeTogether & sameUser
|
thisItem['withPrevious'] = timeTogether & sameUser
|
||||||
|
|
||||||
items.append(thisItem)
|
items.append(thisItem)
|
||||||
|
|||||||
196
RIGS/views.py
196
RIGS/views.py
@@ -1,25 +1,23 @@
|
|||||||
import datetime
|
from django.core.exceptions import PermissionDenied
|
||||||
import operator
|
from django.http.response import HttpResponseRedirect
|
||||||
from functools import reduce
|
from django.http import HttpResponse
|
||||||
|
from django.core.urlresolvers import reverse_lazy, reverse, NoReverseMatch
|
||||||
|
from django.views import generic
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.core import serializers
|
||||||
|
from django.conf import settings
|
||||||
import simplejson
|
import simplejson
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core import serializers
|
import datetime, pytz
|
||||||
from django.core.exceptions import PermissionDenied
|
import operator
|
||||||
from django.core.urlresolvers import reverse_lazy, reverse, NoReverseMatch
|
from registration.views import RegistrationView
|
||||||
from django.db.models import Q
|
|
||||||
from django.http import HttpResponse
|
|
||||||
from django.http.response import HttpResponseRedirect
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from django.views import generic
|
|
||||||
|
|
||||||
from RIGS import models
|
from RIGS import models, forms
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Displays the current rig count along with a few other bits and pieces
|
Displays the current rig count along with a few other bits and pieces
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Index(generic.TemplateView):
|
class Index(generic.TemplateView):
|
||||||
template_name = 'RIGS/index.html'
|
template_name = 'RIGS/index.html'
|
||||||
|
|
||||||
@@ -28,7 +26,6 @@ class Index(generic.TemplateView):
|
|||||||
context['rig_count'] = models.Event.objects.rig_count()
|
context['rig_count'] = models.Event.objects.rig_count()
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
def login(request, **kwargs):
|
def login(request, **kwargs):
|
||||||
if request.user.is_authenticated():
|
if request.user.is_authenticated():
|
||||||
next = request.REQUEST.get('next', '/')
|
next = request.REQUEST.get('next', '/')
|
||||||
@@ -38,14 +35,11 @@ def login(request, **kwargs):
|
|||||||
|
|
||||||
return login(request)
|
return login(request)
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Called from a modal window (e.g. when an item is submitted to an event/invoice).
|
Called from a modal window (e.g. when an item is submitted to an event/invoice).
|
||||||
May optionally also include some javascript in a success message to cause a load of
|
May optionally also include some javascript in a success message to cause a load of
|
||||||
the new information onto the page.
|
the new information onto the page.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class CloseModal(generic.TemplateView):
|
class CloseModal(generic.TemplateView):
|
||||||
template_name = 'closemodal.html'
|
template_name = 'closemodal.html'
|
||||||
|
|
||||||
@@ -60,8 +54,7 @@ class PersonList(generic.ListView):
|
|||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
q = self.request.GET.get('q', "")
|
q = self.request.GET.get('q', "")
|
||||||
if len(q) >= 3:
|
if len(q) >= 3:
|
||||||
object_list = self.model.objects.filter(
|
object_list = self.model.objects.filter(Q(name__icontains=q) | Q(email__icontains=q))
|
||||||
Q(name__icontains=q) | Q(email__icontains=q))
|
|
||||||
else:
|
else:
|
||||||
object_list = self.model.objects.all()
|
object_list = self.model.objects.all()
|
||||||
orderBy = self.request.GET.get('orderBy', None)
|
orderBy = self.request.GET.get('orderBy', None)
|
||||||
@@ -76,24 +69,16 @@ class PersonDetail(generic.DetailView):
|
|||||||
|
|
||||||
class PersonCreate(generic.CreateView):
|
class PersonCreate(generic.CreateView):
|
||||||
model = models.Person
|
model = models.Person
|
||||||
fields = ['name', 'phone', 'email', 'address', 'notes']
|
fields = ['name','phone','email','address','notes']
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
if self.request.is_ajax():
|
if self.request.is_ajax():
|
||||||
url = reverse_lazy('closemodal')
|
url = reverse_lazy('closemodal')
|
||||||
update_url = str(
|
update_url = str(reverse_lazy('person_update',kwargs={'pk':self.object.pk}))
|
||||||
reverse_lazy(
|
messages.info(self.request, "modalobject="+serializers.serialize("json", [self.object]))
|
||||||
'person_update', kwargs={
|
messages.info(self.request, "modalobject[0]['update_url']='"+update_url+"'")
|
||||||
'pk': self.object.pk}))
|
|
||||||
messages.info(self.request, "modalobject=" +
|
|
||||||
serializers.serialize("json", [self.object]))
|
|
||||||
messages.info(
|
|
||||||
self.request,
|
|
||||||
"modalobject[0]['update_url']='" +
|
|
||||||
update_url +
|
|
||||||
"'")
|
|
||||||
else:
|
else:
|
||||||
url = reverse_lazy('person_detail', kwargs={
|
url = reverse_lazy('person_detail', kwargs={
|
||||||
'pk': self.object.pk,
|
'pk': self.object.pk,
|
||||||
})
|
})
|
||||||
return url
|
return url
|
||||||
@@ -101,24 +86,16 @@ class PersonCreate(generic.CreateView):
|
|||||||
|
|
||||||
class PersonUpdate(generic.UpdateView):
|
class PersonUpdate(generic.UpdateView):
|
||||||
model = models.Person
|
model = models.Person
|
||||||
fields = ['name', 'phone', 'email', 'address', 'notes']
|
fields = ['name','phone','email','address','notes']
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
if self.request.is_ajax():
|
if self.request.is_ajax():
|
||||||
url = reverse_lazy('closemodal')
|
url = reverse_lazy('closemodal')
|
||||||
update_url = str(
|
update_url = str(reverse_lazy('person_update',kwargs={'pk':self.object.pk}))
|
||||||
reverse_lazy(
|
messages.info(self.request, "modalobject="+serializers.serialize("json", [self.object]))
|
||||||
'person_update', kwargs={
|
messages.info(self.request, "modalobject[0]['update_url']='"+update_url+"'")
|
||||||
'pk': self.object.pk}))
|
|
||||||
messages.info(self.request, "modalobject=" +
|
|
||||||
serializers.serialize("json", [self.object]))
|
|
||||||
messages.info(
|
|
||||||
self.request,
|
|
||||||
"modalobject[0]['update_url']='" +
|
|
||||||
update_url +
|
|
||||||
"'")
|
|
||||||
else:
|
else:
|
||||||
url = reverse_lazy('person_detail', kwargs={
|
url = reverse_lazy('person_detail', kwargs={
|
||||||
'pk': self.object.pk,
|
'pk': self.object.pk,
|
||||||
})
|
})
|
||||||
return url
|
return url
|
||||||
@@ -131,8 +108,7 @@ class OrganisationList(generic.ListView):
|
|||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
q = self.request.GET.get('q', "")
|
q = self.request.GET.get('q', "")
|
||||||
if len(q) >= 3:
|
if len(q) >= 3:
|
||||||
object_list = self.model.objects.filter(
|
object_list = self.model.objects.filter(Q(name__icontains=q) | Q(address__icontains=q))
|
||||||
Q(name__icontains=q) | Q(address__icontains=q))
|
|
||||||
else:
|
else:
|
||||||
object_list = self.model.objects.all()
|
object_list = self.model.objects.all()
|
||||||
orderBy = self.request.GET.get('orderBy', "")
|
orderBy = self.request.GET.get('orderBy', "")
|
||||||
@@ -147,25 +123,16 @@ class OrganisationDetail(generic.DetailView):
|
|||||||
|
|
||||||
class OrganisationCreate(generic.CreateView):
|
class OrganisationCreate(generic.CreateView):
|
||||||
model = models.Organisation
|
model = models.Organisation
|
||||||
fields = ['name', 'phone', 'email', 'address', 'notes', 'union_account']
|
fields = ['name','phone','email','address','notes','union_account']
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
if self.request.is_ajax():
|
if self.request.is_ajax():
|
||||||
url = reverse_lazy('closemodal')
|
url = reverse_lazy('closemodal')
|
||||||
update_url = str(
|
update_url = str(reverse_lazy('organisation_update',kwargs={'pk':self.object.pk}))
|
||||||
reverse_lazy(
|
messages.info(self.request, "modalobject="+serializers.serialize("json", [self.object]))
|
||||||
'organisation_update',
|
messages.info(self.request, "modalobject[0]['update_url']='"+update_url+"'")
|
||||||
kwargs={
|
|
||||||
'pk': self.object.pk}))
|
|
||||||
messages.info(self.request, "modalobject=" +
|
|
||||||
serializers.serialize("json", [self.object]))
|
|
||||||
messages.info(
|
|
||||||
self.request,
|
|
||||||
"modalobject[0]['update_url']='" +
|
|
||||||
update_url +
|
|
||||||
"'")
|
|
||||||
else:
|
else:
|
||||||
url = reverse_lazy('organisation_detail', kwargs={
|
url = reverse_lazy('organisation_detail', kwargs={
|
||||||
'pk': self.object.pk,
|
'pk': self.object.pk,
|
||||||
})
|
})
|
||||||
return url
|
return url
|
||||||
@@ -173,25 +140,16 @@ class OrganisationCreate(generic.CreateView):
|
|||||||
|
|
||||||
class OrganisationUpdate(generic.UpdateView):
|
class OrganisationUpdate(generic.UpdateView):
|
||||||
model = models.Organisation
|
model = models.Organisation
|
||||||
fields = ['name', 'phone', 'email', 'address', 'notes', 'union_account']
|
fields = ['name','phone','email','address','notes','union_account']
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
if self.request.is_ajax():
|
if self.request.is_ajax():
|
||||||
url = reverse_lazy('closemodal')
|
url = reverse_lazy('closemodal')
|
||||||
update_url = str(
|
update_url = str(reverse_lazy('organisation_update',kwargs={'pk':self.object.pk}))
|
||||||
reverse_lazy(
|
messages.info(self.request, "modalobject="+serializers.serialize("json", [self.object]))
|
||||||
'organisation_update',
|
messages.info(self.request, "modalobject[0]['update_url']='"+update_url+"'")
|
||||||
kwargs={
|
|
||||||
'pk': self.object.pk}))
|
|
||||||
messages.info(self.request, "modalobject=" +
|
|
||||||
serializers.serialize("json", [self.object]))
|
|
||||||
messages.info(
|
|
||||||
self.request,
|
|
||||||
"modalobject[0]['update_url']='" +
|
|
||||||
update_url +
|
|
||||||
"'")
|
|
||||||
else:
|
else:
|
||||||
url = reverse_lazy('organisation_detail', kwargs={
|
url = reverse_lazy('organisation_detail', kwargs={
|
||||||
'pk': self.object.pk,
|
'pk': self.object.pk,
|
||||||
})
|
})
|
||||||
return url
|
return url
|
||||||
@@ -204,8 +162,7 @@ class VenueList(generic.ListView):
|
|||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
q = self.request.GET.get('q', "")
|
q = self.request.GET.get('q', "")
|
||||||
if len(q) >= 3:
|
if len(q) >= 3:
|
||||||
object_list = self.model.objects.filter(
|
object_list = self.model.objects.filter(Q(name__icontains=q) | Q(address__icontains=q))
|
||||||
Q(name__icontains=q) | Q(address__icontains=q))
|
|
||||||
else:
|
else:
|
||||||
object_list = self.model.objects.all()
|
object_list = self.model.objects.all()
|
||||||
orderBy = self.request.GET.get('orderBy', "")
|
orderBy = self.request.GET.get('orderBy', "")
|
||||||
@@ -220,30 +177,16 @@ class VenueDetail(generic.DetailView):
|
|||||||
|
|
||||||
class VenueCreate(generic.CreateView):
|
class VenueCreate(generic.CreateView):
|
||||||
model = models.Venue
|
model = models.Venue
|
||||||
fields = [
|
fields = ['name','phone','email','address','notes','three_phase_available']
|
||||||
'name',
|
|
||||||
'phone',
|
|
||||||
'email',
|
|
||||||
'address',
|
|
||||||
'notes',
|
|
||||||
'three_phase_available']
|
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
if self.request.is_ajax():
|
if self.request.is_ajax():
|
||||||
url = reverse_lazy('closemodal')
|
url = reverse_lazy('closemodal')
|
||||||
update_url = str(
|
update_url = str(reverse_lazy('venue_update',kwargs={'pk':self.object.pk}))
|
||||||
reverse_lazy(
|
messages.info(self.request, "modalobject="+serializers.serialize("json", [self.object]))
|
||||||
'venue_update', kwargs={
|
messages.info(self.request, "modalobject[0]['update_url']='"+update_url+"'")
|
||||||
'pk': self.object.pk}))
|
|
||||||
messages.info(self.request, "modalobject=" +
|
|
||||||
serializers.serialize("json", [self.object]))
|
|
||||||
messages.info(
|
|
||||||
self.request,
|
|
||||||
"modalobject[0]['update_url']='" +
|
|
||||||
update_url +
|
|
||||||
"'")
|
|
||||||
else:
|
else:
|
||||||
url = reverse_lazy('venue_detail', kwargs={
|
url = reverse_lazy('venue_detail', kwargs={
|
||||||
'pk': self.object.pk,
|
'pk': self.object.pk,
|
||||||
})
|
})
|
||||||
return url
|
return url
|
||||||
@@ -251,30 +194,16 @@ class VenueCreate(generic.CreateView):
|
|||||||
|
|
||||||
class VenueUpdate(generic.UpdateView):
|
class VenueUpdate(generic.UpdateView):
|
||||||
model = models.Venue
|
model = models.Venue
|
||||||
fields = [
|
fields = ['name','phone','email','address','notes','three_phase_available']
|
||||||
'name',
|
|
||||||
'phone',
|
|
||||||
'email',
|
|
||||||
'address',
|
|
||||||
'notes',
|
|
||||||
'three_phase_available']
|
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
if self.request.is_ajax():
|
if self.request.is_ajax():
|
||||||
url = reverse_lazy('closemodal')
|
url = reverse_lazy('closemodal')
|
||||||
update_url = str(
|
update_url = str(reverse_lazy('venue_update',kwargs={'pk':self.object.pk}))
|
||||||
reverse_lazy(
|
messages.info(self.request, "modalobject="+serializers.serialize("json", [self.object]))
|
||||||
'venue_update', kwargs={
|
messages.info(self.request, "modalobject[0]['update_url']='"+update_url+"'")
|
||||||
'pk': self.object.pk}))
|
|
||||||
messages.info(self.request, "modalobject=" +
|
|
||||||
serializers.serialize("json", [self.object]))
|
|
||||||
messages.info(
|
|
||||||
self.request,
|
|
||||||
"modalobject[0]['update_url']='" +
|
|
||||||
update_url +
|
|
||||||
"'")
|
|
||||||
else:
|
else:
|
||||||
url = reverse_lazy('venue_detail', kwargs={
|
url = reverse_lazy('venue_detail', kwargs={
|
||||||
'pk': self.object.pk,
|
'pk': self.object.pk,
|
||||||
})
|
})
|
||||||
return url
|
return url
|
||||||
@@ -332,9 +261,9 @@ class SecureAPIRequest(generic.View):
|
|||||||
# Supply data for autocomplete ajax request in json form
|
# Supply data for autocomplete ajax request in json form
|
||||||
term = request.GET.get('term', None)
|
term = request.GET.get('term', None)
|
||||||
if term:
|
if term:
|
||||||
if fields is None: # Default to just name
|
if fields is None: # Default to just name
|
||||||
fields = ['name']
|
fields = ['name']
|
||||||
|
|
||||||
# Build a list of Q objects for use later
|
# Build a list of Q objects for use later
|
||||||
queries = []
|
queries = []
|
||||||
for part in term.split(" "):
|
for part in term.split(" "):
|
||||||
@@ -344,6 +273,7 @@ class SecureAPIRequest(generic.View):
|
|||||||
qs.append(q)
|
qs.append(q)
|
||||||
queries.append(reduce(operator.or_, qs))
|
queries.append(reduce(operator.or_, qs))
|
||||||
|
|
||||||
|
|
||||||
# Build the data response list
|
# Build the data response list
|
||||||
results = []
|
results = []
|
||||||
query = reduce(operator.and_, queries)
|
query = reduce(operator.and_, queries)
|
||||||
@@ -354,31 +284,25 @@ class SecureAPIRequest(generic.View):
|
|||||||
'value': o.pk,
|
'value': o.pk,
|
||||||
'label': o.name,
|
'label': o.name,
|
||||||
}
|
}
|
||||||
try: # See if there is a valid update URL
|
try: # See if there is a valid update URL
|
||||||
data['update'] = reverse(
|
data['update'] = reverse("%s_update" % model, kwargs={'pk': o.pk})
|
||||||
"%s_update" %
|
|
||||||
model, kwargs={
|
|
||||||
'pk': o.pk})
|
|
||||||
except NoReverseMatch:
|
except NoReverseMatch:
|
||||||
pass
|
pass
|
||||||
results.append(data)
|
results.append(data)
|
||||||
|
|
||||||
# return a data response
|
# return a data response
|
||||||
json = simplejson.dumps(results)
|
json = simplejson.dumps(results)
|
||||||
return HttpResponse(
|
return HttpResponse(json, content_type="application/json") # Always json
|
||||||
json, content_type="application/json") # Always json
|
|
||||||
|
|
||||||
start = request.GET.get('start', None)
|
start = request.GET.get('start', None)
|
||||||
end = request.GET.get('end', None)
|
end = request.GET.get('end', None)
|
||||||
|
|
||||||
if model == "event" and start and end:
|
if model == "event" and start and end:
|
||||||
# Probably a calendar request
|
# Probably a calendar request
|
||||||
start_datetime = datetime.datetime.strptime(
|
start_datetime = datetime.datetime.strptime( start, "%Y-%m-%dT%H:%M:%S" )
|
||||||
start, "%Y-%m-%dT%H:%M:%S")
|
end_datetime = datetime.datetime.strptime( end, "%Y-%m-%dT%H:%M:%S" )
|
||||||
end_datetime = datetime.datetime.strptime(end, "%Y-%m-%dT%H:%M:%S")
|
|
||||||
|
|
||||||
objects = self.models[model].objects.events_in_bounds(
|
objects = self.models[model].objects.events_in_bounds(start_datetime,end_datetime)
|
||||||
start_datetime, end_datetime)
|
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
for item in objects:
|
for item in objects:
|
||||||
@@ -394,12 +318,10 @@ class SecureAPIRequest(generic.View):
|
|||||||
|
|
||||||
results.append(data)
|
results.append(data)
|
||||||
json = simplejson.dumps(results)
|
json = simplejson.dumps(results)
|
||||||
return HttpResponse(
|
return HttpResponse(json, content_type="application/json") # Always json
|
||||||
json, content_type="application/json") # Always json
|
|
||||||
|
|
||||||
return HttpResponse(model)
|
return HttpResponse(model)
|
||||||
|
|
||||||
|
|
||||||
class ProfileDetail(generic.DetailView):
|
class ProfileDetail(generic.DetailView):
|
||||||
model = models.Profile
|
model = models.Profile
|
||||||
|
|
||||||
@@ -412,7 +334,6 @@ class ProfileDetail(generic.DetailView):
|
|||||||
|
|
||||||
return self.model.objects.filter(pk=pk)
|
return self.model.objects.filter(pk=pk)
|
||||||
|
|
||||||
|
|
||||||
class ProfileUpdateSelf(generic.UpdateView):
|
class ProfileUpdateSelf(generic.UpdateView):
|
||||||
model = models.Profile
|
model = models.Profile
|
||||||
fields = ['first_name', 'last_name', 'email', 'initials', 'phone']
|
fields = ['first_name', 'last_name', 'email', 'initials', 'phone']
|
||||||
@@ -424,14 +345,13 @@ class ProfileUpdateSelf(generic.UpdateView):
|
|||||||
return self.model.objects.filter(pk=pk)
|
return self.model.objects.filter(pk=pk)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
url = reverse_lazy('profile_detail')
|
url = reverse_lazy('profile_detail')
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
|
||||||
class ResetApiKey(generic.RedirectView):
|
class ResetApiKey(generic.RedirectView):
|
||||||
def get_redirect_url(self, *args, **kwargs):
|
def get_redirect_url(self, *args, **kwargs):
|
||||||
self.request.user.api_key = self.request.user.make_api_key()
|
self.request.user.api_key = self.request.user.make_api_key()
|
||||||
|
|
||||||
self.request.user.save()
|
self.request.user.save()
|
||||||
|
|
||||||
return reverse_lazy('profile_detail')
|
return reverse_lazy('profile_detail')
|
||||||
|
|||||||
53
app.json
53
app.json
@@ -1,53 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "PyRIGS",
|
|
||||||
"description": "",
|
|
||||||
"scripts": {
|
|
||||||
"postdeploy": "python manage.py migrate && python manage.py generateSampleData"
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"DEBUG": {
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"STAGING": "1",
|
|
||||||
"EMAIL_FROM": {
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"EMAIL_HOST": {
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"EMAIL_HOST_PASSWORD": {
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"EMAIL_HOST_USER": {
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"EMAIL_PORT": {
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"EMAIL_USE_SSL": {
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"RECAPTCHA_PRIVATE_KEY": {
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"RECAPTCHA_PUBLIC_KEY": {
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"SECRET_KEY": {
|
|
||||||
"generator": "secret"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"formation": {
|
|
||||||
"web": {
|
|
||||||
"quantity": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"addons": [
|
|
||||||
"heroku-postgresql"
|
|
||||||
],
|
|
||||||
"buildpacks": [
|
|
||||||
{
|
|
||||||
"url": "heroku/python"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
3
assets/admin.py
Normal file
3
assets/admin.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
71
assets/models.py
Normal file
71
assets/models.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
from django.db import models
|
||||||
|
import reversion
|
||||||
|
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
|
class Suppliers(models.Model):
|
||||||
|
name = models.CharField(max_length=100)
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractAsset(models.Model):
|
||||||
|
STATUS_LOST = 1
|
||||||
|
STATUS_ACTIVE = 2
|
||||||
|
STATUS_INACTIVE = 3
|
||||||
|
STATUS_BROKEN = 4
|
||||||
|
STATUS_SCRAPPED = 5
|
||||||
|
STATUS_NOT_BUILT = 6
|
||||||
|
STATUS_SOLD = 7
|
||||||
|
|
||||||
|
STATUS_CHOICES = (
|
||||||
|
(STATUS_LOST, 'Lost'),
|
||||||
|
(STATUS_ACTIVE, 'Active'),
|
||||||
|
(STATUS_INACTIVE, 'Inactive'),
|
||||||
|
(STATUS_BROKEN, 'Broken'),
|
||||||
|
(STATUS_SCRAPPED, 'Scrapped'),
|
||||||
|
(STATUS_NOT_BUILT, 'Not Yet Built'),
|
||||||
|
(STATUS_SOLD, 'Sold'),
|
||||||
|
)
|
||||||
|
|
||||||
|
status = models.IntegerField(choices=STATUS_CHOICES)
|
||||||
|
notes = models.TextField(blank=True, null=True)
|
||||||
|
# test_period # decide what to do with this later
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
|
||||||
|
class Asset(models.Model):
|
||||||
|
CATEGORY_GENERAL = 1
|
||||||
|
CATEGORY_CASE = 2
|
||||||
|
CATEGORY_COMMS = 3
|
||||||
|
CATEGORY_DECKING = 4
|
||||||
|
CATEGORY_OFFICE = 5
|
||||||
|
CATEGORY_SOUND = 10
|
||||||
|
CATEGORY_LIGHTING = 20
|
||||||
|
CATEGORY_VIDEO = 30
|
||||||
|
CATEGORY_RIGGING = 40
|
||||||
|
CATEGORY_TRUSS = 41
|
||||||
|
CATEGORY_LADDERS = 42
|
||||||
|
CATEGORY_POWER = 50
|
||||||
|
CATEGORY_DISTRO = 51
|
||||||
|
|
||||||
|
CATEGORY_CHOICES = (
|
||||||
|
(CATEGORY_SOUND, 'Sound'),
|
||||||
|
(CATEGORY_LIGHTING, 'Lighting'),
|
||||||
|
('Other', (
|
||||||
|
(CATEGORY_GENERAL, 'General'),
|
||||||
|
(CATEGORY_CASE, 'Case'),
|
||||||
|
(CATEGORY_COMMS, 'Comms'),
|
||||||
|
(CATEGORY_DECKING, 'Decking'),
|
||||||
|
(CATEGORY_OFFICE, 'Office'),
|
||||||
|
)),
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
serial_number = models.CharField(max_length=255)
|
||||||
|
date_acquired = models.DateField(null=True, blank=True)
|
||||||
|
date_sold = models.DateField(null=True, blank=True)
|
||||||
|
purchase_price = models.DecimalField(max_digits=10, decimal_places=2)
|
||||||
|
replacement_price = models.DecimalField(max_digits=10, decimal_places=2)
|
||||||
|
|
||||||
3
assets/tests.py
Normal file
3
assets/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
3
assets/views.py
Normal file
3
assets/views.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
31
importer.py
31
importer.py
@@ -14,11 +14,11 @@ from RIGS import models
|
|||||||
import reversion
|
import reversion
|
||||||
import datetime
|
import datetime
|
||||||
import uuid
|
import uuid
|
||||||
|
from multiprocessing import Process
|
||||||
|
|
||||||
# Slight fix for needing to restablish the connection
|
# Slight fix for needing to restablish the connection
|
||||||
connection.close()
|
connection.close()
|
||||||
|
|
||||||
|
|
||||||
def fix_email(email):
|
def fix_email(email):
|
||||||
if not (email is None or email is "") and ("@" not in email):
|
if not (email is None or email is "") and ("@" not in email):
|
||||||
email += "@nottingham.ac.uk"
|
email += "@nottingham.ac.uk"
|
||||||
@@ -110,8 +110,7 @@ def import_organisations(delete=False):
|
|||||||
notes = row[5]
|
notes = row[5]
|
||||||
|
|
||||||
object, created = models.Organisation.objects.get_or_create(pk=row[0], name=row[1], phone=row[2],
|
object, created = models.Organisation.objects.get_or_create(pk=row[0], name=row[1], phone=row[2],
|
||||||
address=row[
|
address=row[3],
|
||||||
3],
|
|
||||||
union_account=row[4], notes=notes)
|
union_account=row[4], notes=notes)
|
||||||
if created:
|
if created:
|
||||||
print("Created: " + object.__str__())
|
print("Created: " + object.__str__())
|
||||||
@@ -326,15 +325,13 @@ def import_invoices(delete=False):
|
|||||||
payment.save()
|
payment.save()
|
||||||
print(payment)
|
print(payment)
|
||||||
|
|
||||||
if invoice.invoice_date < (
|
if invoice.invoice_date < (datetime.date.today() - datetime.timedelta(days=365)) and invoice.balance:
|
||||||
datetime.date.today() - datetime.timedelta(days=365)) and invoice.balance:
|
|
||||||
p2 = models.Payment(amount=invoice.balance)
|
p2 = models.Payment(amount=invoice.balance)
|
||||||
p2.invoice = invoice
|
p2.invoice = invoice
|
||||||
p2.method = payment.ADJUSTMENT
|
p2.method = payment.ADJUSTMENT
|
||||||
p2.date = datetime.date.today()
|
p2.date = datetime.date.today()
|
||||||
p2.save()
|
p2.save()
|
||||||
|
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def main():
|
def main():
|
||||||
# processs = []
|
# processs = []
|
||||||
@@ -343,7 +340,7 @@ def main():
|
|||||||
# processs.append(Process(target=import_organisations, args=(True,)))
|
# processs.append(Process(target=import_organisations, args=(True,)))
|
||||||
# processs.append(Process(target=import_vat_rates, args=(True,)))
|
# processs.append(Process(target=import_vat_rates, args=(True,)))
|
||||||
# processs.append(Process(target=import_venues, args=(True,)))
|
# processs.append(Process(target=import_venues, args=(True,)))
|
||||||
|
|
||||||
# # Start all processs
|
# # Start all processs
|
||||||
# [x.start() for x in processs]
|
# [x.start() for x in processs]
|
||||||
# # Wait for all processs to finish
|
# # Wait for all processs to finish
|
||||||
@@ -354,34 +351,22 @@ def main():
|
|||||||
import_organisations(True)
|
import_organisations(True)
|
||||||
import_vat_rates(True)
|
import_vat_rates(True)
|
||||||
import_venues(True)
|
import_venues(True)
|
||||||
|
|
||||||
import_rigs(True)
|
import_rigs(True)
|
||||||
import_eventitem(True)
|
import_eventitem(True)
|
||||||
import_invoices(True)
|
import_invoices(True)
|
||||||
|
|
||||||
# Do this before doing non rigs else it gets ugly
|
# Do this before doing non rigs else it gets ugly
|
||||||
sql = "SELECT setval(\'\"RIGS_%s_id_seq\"\', (SELECT MAX(id) FROM \"RIGS_%s\"));" % (
|
sql = "SELECT setval(\'\"RIGS_%s_id_seq\"\', (SELECT MAX(id) FROM \"RIGS_%s\"));" % ('event', 'event')
|
||||||
'event', 'event')
|
|
||||||
cursor = connections['default'].cursor()
|
cursor = connections['default'].cursor()
|
||||||
cursor.execute(sql)
|
cursor.execute(sql)
|
||||||
import_nonrigs(False)
|
import_nonrigs(False)
|
||||||
|
|
||||||
sequences = [
|
sequences = ['profile', 'person', 'organisation', 'vatrate', 'venue', 'event', 'eventitem', 'invoice', 'payment']
|
||||||
'profile',
|
|
||||||
'person',
|
|
||||||
'organisation',
|
|
||||||
'vatrate',
|
|
||||||
'venue',
|
|
||||||
'event',
|
|
||||||
'eventitem',
|
|
||||||
'invoice',
|
|
||||||
'payment']
|
|
||||||
for seq in sequences:
|
for seq in sequences:
|
||||||
sql = "SELECT setval(\'\"RIGS_%s_id_seq\"\', (SELECT MAX(id) FROM \"RIGS_%s\"));" % (
|
sql = "SELECT setval(\'\"RIGS_%s_id_seq\"\', (SELECT MAX(id) FROM \"RIGS_%s\"));" % (seq, seq)
|
||||||
seq, seq)
|
|
||||||
cursor = connections['default'].cursor()
|
cursor = connections['default'].cursor()
|
||||||
cursor.execute(sql)
|
cursor.execute(sql)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ python-dateutil==2.4.2
|
|||||||
pytz==2015.4
|
pytz==2015.4
|
||||||
raven==5.8.1
|
raven==5.8.1
|
||||||
reportlab==3.1.44
|
reportlab==3.1.44
|
||||||
selenium==2.53.6
|
selenium==2.53.1
|
||||||
simplejson==3.7.2
|
simplejson==3.7.2
|
||||||
six==1.9.0
|
six==1.9.0
|
||||||
sqlparse==0.1.15
|
sqlparse==0.1.15
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<link rel="icon" type="image/png" href="{% static "imgs/pyrigs-avatar.png" %}">
|
<link rel="icon" type="image/png" href="{% static "imgs/pyrigs-avatar.png" %}">
|
||||||
<link rel="apple-touch-icon" href="{% static "imgs/pyrigs-avatar.png" %}">
|
<link rel="apple-touch-icon" href="{% static "imgs/pyrigs-avatar.png" %}">
|
||||||
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400italic,700,300,400' rel='stylesheet'
|
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,700,300,400' rel='stylesheet'
|
||||||
type='text/css'>
|
type='text/css'>
|
||||||
|
|
||||||
|
|
||||||
@@ -74,12 +74,12 @@
|
|||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Invoices<b class="caret"></b></a>
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Invoices<b class="caret"></b></a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
|
<li><a href="{% url 'invoice_list' %}"><span class="glyphicon glyphicon-gbp"></span> Active</a>
|
||||||
|
</li>
|
||||||
{% if perms.RIGS.add_invoice %}
|
{% if perms.RIGS.add_invoice %}
|
||||||
<li><a href="{% url 'invoice_waiting' %}"><span
|
<li><a href="{% url 'invoice_waiting' %}"><span
|
||||||
class="glyphicon glyphicon-briefcase text-danger"></span> Waiting</a></li>
|
class="glyphicon glyphicon-briefcase"></span> Waiting</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li><a href="{% url 'invoice_list' %}"><span class="glyphicon glyphicon-gbp text-warning"></span> Outstanding</a>
|
|
||||||
</li>
|
|
||||||
<li><a href="{% url 'invoice_archive' %}"><span class="glyphicon glyphicon-book"></span>
|
<li><a href="{% url 'invoice_archive' %}"><span class="glyphicon glyphicon-book"></span>
|
||||||
Archive</a></li>
|
Archive</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{{ user|safe }} activation required
|
{{ user }} activation required
|
||||||
103
wercker.yml
Normal file
103
wercker.yml
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# This references the default Python container from
|
||||||
|
# the Docker Hub with the 2.7 tag:
|
||||||
|
# https://registry.hub.docker.com/_/python/
|
||||||
|
# If you want to use a slim Python container with
|
||||||
|
# version 3.4.3 you would use: python:3.4-slim
|
||||||
|
# If you want Google's container you would reference google/python
|
||||||
|
# Read more about containers on our dev center
|
||||||
|
# http://devcenter.wercker.com/docs/containers/index.html
|
||||||
|
box: heroku/python
|
||||||
|
# You can also use services such as databases. Read more on our dev center:
|
||||||
|
# http://devcenter.wercker.com/docs/services/index.html
|
||||||
|
services:
|
||||||
|
# - id: postgres
|
||||||
|
# env:
|
||||||
|
# POSTGRES_PASSWORD: pyrigstesting
|
||||||
|
# POSTGRES_USER: pyrigs
|
||||||
|
# http://devcenter.wercker.com/docs/services/postgresql.html
|
||||||
|
|
||||||
|
# - mongodb
|
||||||
|
# http://devcenter.wercker.com/docs/services/mongodb.html
|
||||||
|
|
||||||
|
# This is the build pipeline. Pipelines are the core of wercker
|
||||||
|
# Read more about pipelines on our dev center
|
||||||
|
# http://devcenter.wercker.com/docs/pipelines/index.html
|
||||||
|
build:
|
||||||
|
# The steps that will be executed on build
|
||||||
|
# Steps make up the actions in your pipeline
|
||||||
|
# Read more about steps on our dev center:
|
||||||
|
# http://devcenter.wercker.com/docs/steps/index.html
|
||||||
|
steps:
|
||||||
|
- install-packages:
|
||||||
|
packages: firefox xvfb
|
||||||
|
|
||||||
|
- script:
|
||||||
|
name: Enable virtual display
|
||||||
|
code: |-
|
||||||
|
# Start xvfb which gives the context an virtual display
|
||||||
|
# which is required for tests that require an GUI
|
||||||
|
export DISPLAY=:99.0
|
||||||
|
start-stop-daemon --start --quiet --pidfile /tmp/xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1024x768x24 -ac +extension GLX +render -noreset
|
||||||
|
# Give xvfb time to start. 3 seconds is the default for all xvfb-run commands.
|
||||||
|
# sleep 3
|
||||||
|
|
||||||
|
- script:
|
||||||
|
name: virtualenv install
|
||||||
|
code: |
|
||||||
|
pip install virtualenv
|
||||||
|
|
||||||
|
# A step that sets up the python virtual environment
|
||||||
|
- virtualenv:
|
||||||
|
name: setup virtual environment
|
||||||
|
install_wheel: false # Enable wheel to speed up builds (experimental)
|
||||||
|
|
||||||
|
# # Use this virtualenv step for python 3.2
|
||||||
|
# - virtualenv
|
||||||
|
# name: setup virtual environment
|
||||||
|
# python_location: /usr/bin/python3.2
|
||||||
|
|
||||||
|
# # This pip-install clears the local wheel cache
|
||||||
|
# - pip-install:
|
||||||
|
# clean_wheel_dir: true
|
||||||
|
|
||||||
|
# A custom script step, name value is used in the UI
|
||||||
|
# and the code value contains the command that get executed
|
||||||
|
- script:
|
||||||
|
name: Python Version
|
||||||
|
code: |
|
||||||
|
echo "python version $(python --version) running"
|
||||||
|
echo "pip version $(pip --version) running"
|
||||||
|
|
||||||
|
# Django uses this to connect to the database
|
||||||
|
# - script:
|
||||||
|
# name: set environment
|
||||||
|
# code: |
|
||||||
|
# export DEBUG=0
|
||||||
|
# export DATABASE_URL="postgres://pyrigs:pyrigstesting@$POSTGRES_PORT_5432_TCP_ADDR:$POSTGRES_PORT_5432_TCP_PORT$POSTGRES_NAME"
|
||||||
|
|
||||||
|
# A step that executes `pip install` command.
|
||||||
|
- pip-install
|
||||||
|
|
||||||
|
# Install coverage
|
||||||
|
- script:
|
||||||
|
name: install coverage
|
||||||
|
code: |
|
||||||
|
pip install coverage
|
||||||
|
|
||||||
|
# Collect static files so the manifest storage knows where to look
|
||||||
|
- script:
|
||||||
|
name: collect static
|
||||||
|
code: |
|
||||||
|
python manage.py collectstatic --noinput
|
||||||
|
|
||||||
|
# Run python tests
|
||||||
|
- script:
|
||||||
|
name: run tests
|
||||||
|
code: |
|
||||||
|
coverage run manage.py test RIGS
|
||||||
|
|
||||||
|
- script:
|
||||||
|
name: collect coverage data
|
||||||
|
code: |
|
||||||
|
coverage report -m --include=PyRIGS/*.*,RIGS/*.* --omit=*/migrations/* | tee coverage.txt
|
||||||
|
coverage html --include=PyRIGS/*.*,RIGS/*.* --omit=*/migrations/*
|
||||||
Reference in New Issue
Block a user