Compare commits
3 Commits
risk-asses
...
hotfix/for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a93f337d17 | ||
|
|
bd0832f284 | ||
|
|
567f899a39 |
29
.editorconfig
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# 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
.gitignore
vendored
@@ -53,7 +53,6 @@ coverage.xml
|
|||||||
|
|
||||||
# Django stuff:
|
# Django stuff:
|
||||||
*.log
|
*.log
|
||||||
db.sqlite3
|
|
||||||
|
|
||||||
# Sphinx documentation
|
# Sphinx documentation
|
||||||
docs/_build/
|
docs/_build/
|
||||||
|
|||||||
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>
|
||||||
23
.travis.yml
@@ -1,32 +1,21 @@
|
|||||||
language: python
|
language: python
|
||||||
python:
|
python:
|
||||||
"3.6"
|
"2.7"
|
||||||
cache: pip
|
|
||||||
|
|
||||||
addons:
|
before_install:
|
||||||
chrome: stable
|
- "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:
|
install:
|
||||||
- wget https://chromedriver.storage.googleapis.com/2.36/chromedriver_linux64.zip
|
|
||||||
- unzip chromedriver_linux64.zip
|
|
||||||
- export PATH=$PATH:$(pwd)
|
|
||||||
- chmod +x chromedriver
|
|
||||||
- pip install -r requirements.txt
|
- pip install -r requirements.txt
|
||||||
- pip install coveralls codeclimate-test-reporter pep8
|
- pip install coveralls codeclimate-test-reporter
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- export PATH=$PATH:/usr/lib/chromium-browser/
|
|
||||||
- python manage.py collectstatic --noinput
|
- python manage.py collectstatic --noinput
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- pep8 . --exclude=migrations,importer*
|
- coverage run manage.py test RIGS
|
||||||
- python manage.py check
|
|
||||||
- python manage.py makemigrations --check --dry-run
|
|
||||||
- coverage run manage.py test --verbosity=2
|
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- coveralls
|
- coveralls
|
||||||
- codeclimate-test-reporter
|
- codeclimate-test-reporter
|
||||||
|
|
||||||
notifications:
|
|
||||||
webhooks: https://fathomless-fjord-24024.herokuapp.com/notify
|
|
||||||
|
|||||||
12
Dockerfile
@@ -1,12 +0,0 @@
|
|||||||
FROM python:3.6
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
ADD . /app
|
|
||||||
|
|
||||||
RUN pip install -r requirements.txt && \
|
|
||||||
python manage.py collectstatic --noinput
|
|
||||||
|
|
||||||
EXPOSE 8000
|
|
||||||
|
|
||||||
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
|
|
||||||
@@ -1,19 +1,15 @@
|
|||||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||||
from django.shortcuts import render
|
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.urls import reverse
|
from django.shortcuts import render_to_response
|
||||||
|
from django.template import RequestContext
|
||||||
from RIGS import models
|
|
||||||
|
|
||||||
|
|
||||||
def user_passes_test_with_403(test_func, login_url=None, oembed_view=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 embed_view is set, then a JS redirect will be used, and a application/json+oembed
|
|
||||||
meta tag set with the url of oembed_view
|
|
||||||
(oembed_view will be passed the kwargs from the main function)
|
|
||||||
"""
|
"""
|
||||||
if not login_url:
|
if not login_url:
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -23,31 +19,32 @@ def user_passes_test_with_403(test_func, login_url=None, oembed_view=None):
|
|||||||
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():
|
||||||
if oembed_view is not None:
|
return HttpResponseRedirect('%s?%s=%s' % (
|
||||||
context = {}
|
login_url, REDIRECT_FIELD_NAME, request.get_full_path()))
|
||||||
context['oembed_url'] = "{0}://{1}{2}".format(request.scheme, request.META['HTTP_HOST'], reverse(oembed_view, kwargs=kwargs))
|
|
||||||
context['login_url'] = "{0}?{1}={2}".format(login_url, REDIRECT_FIELD_NAME, request.get_full_path())
|
|
||||||
resp = render(request, 'login_redirect.html', context=context)
|
|
||||||
return resp
|
|
||||||
else:
|
|
||||||
return HttpResponseRedirect('%s?%s=%s' % (login_url, REDIRECT_FIELD_NAME, request.get_full_path()))
|
|
||||||
else:
|
else:
|
||||||
resp = render(request, '403.html')
|
resp = render_to_response(
|
||||||
|
'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, oembed_view=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(lambda u: u.has_perm(perm), login_url=login_url, oembed_view=oembed_view)
|
return user_passes_test_with_403(
|
||||||
|
lambda u: u.has_perm(perm), login_url=login_url)
|
||||||
|
|
||||||
|
|
||||||
|
from RIGS import models
|
||||||
|
|
||||||
|
|
||||||
def api_key_required(function):
|
def api_key_required(function):
|
||||||
@@ -56,12 +53,14 @@ def api_key_required(function):
|
|||||||
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(request, '403.html')
|
error_resp = render_to_response(
|
||||||
|
'403.html', context_instance=RequestContext(request))
|
||||||
error_resp.status_code = 403
|
error_resp.status_code = 403
|
||||||
|
|
||||||
if key is None:
|
if key is None:
|
||||||
@@ -77,18 +76,5 @@ def api_key_required(function):
|
|||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def nottinghamtec_address_required(function):
|
|
||||||
"""
|
|
||||||
Checks that the current user has an email address ending @nottinghamtec.co.uk
|
|
||||||
"""
|
|
||||||
def wrap(request, *args, **kwargs):
|
|
||||||
# Fail if current user's email address isn't @nottinghamtec.co.uk
|
|
||||||
if not request.user.email.endswith('@nottinghamtec.co.uk'):
|
|
||||||
error_resp = render(request, 'RIGS/eventauthorisation_request_error.html')
|
|
||||||
return error_resp
|
|
||||||
|
|
||||||
return function(request, *args, **kwargs)
|
|
||||||
return wrap
|
return wrap
|
||||||
|
|||||||
@@ -1,4 +1,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')
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ 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
|
||||||
import raven
|
|
||||||
import secrets
|
|
||||||
|
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||||
|
|
||||||
@@ -25,19 +23,19 @@ SECRET_KEY = os.environ.get('SECRET_KEY') if os.environ.get(
|
|||||||
# 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
|
||||||
|
|
||||||
STAGING = bool(int(os.environ.get('STAGING'))) if os.environ.get('STAGING') else False
|
TEMPLATE_DEBUG = True
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['pyrigs.nottinghamtec.co.uk', 'rigs.nottinghamtec.co.uk', 'pyrigs.herokuapp.com']
|
ALLOWED_HOSTS = [
|
||||||
|
'pyrigs.nottinghamtec.co.uk',
|
||||||
|
'rigs.nottinghamtec.co.uk',
|
||||||
|
'pyrigs.herokuapp.com']
|
||||||
|
|
||||||
if STAGING:
|
if STAGING:
|
||||||
ALLOWED_HOSTS.append('.herokuapp.com')
|
ALLOWED_HOSTS.append('.herokuapp.com')
|
||||||
|
|
||||||
if DEBUG:
|
|
||||||
ALLOWED_HOSTS.append('localhost')
|
|
||||||
ALLOWED_HOSTS.append('example.com')
|
|
||||||
ALLOWED_HOSTS.append('127.0.0.1')
|
|
||||||
|
|
||||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||||
if not DEBUG:
|
if not DEBUG:
|
||||||
SECURE_SSL_REDIRECT = True # Redirect all http requests to https
|
SECURE_SSL_REDIRECT = True # Redirect all http requests to https
|
||||||
@@ -67,15 +65,15 @@ INSTALLED_APPS = (
|
|||||||
'raven.contrib.django.raven_compat',
|
'raven.contrib.django.raven_compat',
|
||||||
)
|
)
|
||||||
|
|
||||||
MIDDLEWARE = (
|
MIDDLEWARE_CLASSES = (
|
||||||
'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',
|
'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
|
||||||
'reversion.middleware.RevisionMiddleware',
|
'reversion.middleware.RevisionMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
)
|
)
|
||||||
@@ -146,25 +144,28 @@ LOGGING = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import raven
|
||||||
|
|
||||||
RAVEN_CONFIG = {
|
RAVEN_CONFIG = {
|
||||||
'dsn': os.environ.get('RAVEN_DSN'),
|
'dsn': os.environ.get('RAVEN_DSN'),
|
||||||
# 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
|
||||||
AUTH_USER_MODEL = 'RIGS.Profile'
|
AUTH_USER_MODEL = 'RIGS.Profile'
|
||||||
|
|
||||||
LOGIN_REDIRECT_URL = '/'
|
LOGIN_REDIRECT_URL = '/'
|
||||||
LOGIN_URL = '/user/login/'
|
LOGIN_URL = '/user/login'
|
||||||
LOGOUT_URL = '/user/logout/'
|
LOGOUT_URL = '/user/logout'
|
||||||
|
|
||||||
ACCOUNT_ACTIVATION_DAYS = 7
|
ACCOUNT_ACTIVATION_DAYS = 7
|
||||||
|
|
||||||
# reCAPTCHA settings
|
# reCAPTCHA settings
|
||||||
RECAPTCHA_PUBLIC_KEY = os.environ.get('RECAPTCHA_PUBLIC_KEY', "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI") # If not set, use development key
|
RECAPTCHA_PUBLIC_KEY = os.environ.get('RECAPTCHA_PUBLIC_KEY', None)
|
||||||
RECAPTCHA_PRIVATE_KEY = os.environ.get('RECAPTCHA_PRIVATE_KEY', "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe") # If not set, use development key
|
RECAPTCHA_PRIVATE_KEY = os.environ.get('RECAPTCHA_PRIVATE_KEY', None)
|
||||||
NOCAPTCHA = True
|
NOCAPTCHA = True
|
||||||
|
|
||||||
# Email
|
# Email
|
||||||
@@ -172,7 +173,7 @@ EMAILER_TEST = False
|
|||||||
if not DEBUG or EMAILER_TEST:
|
if not DEBUG or EMAILER_TEST:
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||||
EMAIL_HOST = os.environ.get('EMAIL_HOST')
|
EMAIL_HOST = os.environ.get('EMAIL_HOST')
|
||||||
EMAIL_PORT = int(os.environ.get('EMAIL_PORT', 25))
|
EMAIL_PORT = int(os.environ.get('EMAIL_PORT'))
|
||||||
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
|
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
|
||||||
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
|
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
|
||||||
EMAIL_USE_TLS = bool(int(os.environ.get('EMAIL_USE_TLS', 0)))
|
EMAIL_USE_TLS = bool(int(os.environ.get('EMAIL_USE_TLS', 0)))
|
||||||
@@ -198,6 +199,17 @@ 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 = (
|
||||||
|
"django.contrib.auth.context_processors.auth",
|
||||||
|
"django.core.context_processors.debug",
|
||||||
|
"django.core.context_processors.i18n",
|
||||||
|
"django.core.context_processors.media",
|
||||||
|
"django.core.context_processors.static",
|
||||||
|
"django.core.context_processors.tz",
|
||||||
|
"django.core.context_processors.request",
|
||||||
|
"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'
|
||||||
@@ -207,34 +219,10 @@ STATIC_DIRS = (
|
|||||||
os.path.join(BASE_DIR, 'static/')
|
os.path.join(BASE_DIR, 'static/')
|
||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATE_DIRS = (
|
||||||
{
|
os.path.join(BASE_DIR, 'templates'),
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
)
|
||||||
'DIRS': [
|
|
||||||
os.path.join(BASE_DIR, 'templates'),
|
|
||||||
],
|
|
||||||
'APP_DIRS': True,
|
|
||||||
'OPTIONS': {
|
|
||||||
'context_processors': [
|
|
||||||
"django.contrib.auth.context_processors.auth",
|
|
||||||
"django.template.context_processors.debug",
|
|
||||||
"django.template.context_processors.i18n",
|
|
||||||
"django.template.context_processors.media",
|
|
||||||
"django.template.context_processors.static",
|
|
||||||
"django.template.context_processors.tz",
|
|
||||||
"django.template.context_processors.request",
|
|
||||||
"django.contrib.messages.context_processors.messages",
|
|
||||||
],
|
|
||||||
'debug': DEBUG
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
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"
|
||||||
AUTHORISATION_NOTIFICATION_ADDRESS = 'productions@nottinghamtec.co.uk'
|
|
||||||
RISK_ASSESSMENT_URL = os.environ.get('RISK_ASSESSMENT_URL') if os.environ.get(
|
|
||||||
'RISK_ASSESSMENT_URL') else "http://example.com"
|
|
||||||
RISK_ASSESSMENT_SECRET = os.environ.get('RISK_ASSESSMENT_SECRET') if os.environ.get(
|
|
||||||
'RISK_ASSESSMENT_SECRET') else secrets.token_hex(15)
|
|
||||||
|
|||||||
@@ -1,29 +1,25 @@
|
|||||||
from django.conf.urls import include, url
|
from django.conf import settings
|
||||||
|
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 = [
|
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/$', RegistrationView.as_view(form_class=RIGS.forms.ProfileRegistrationFormUniqueEmail),
|
url('^user/register/$',
|
||||||
name="registration_register"),
|
RegistrationView.as_view(form_class=RIGS.forms.ProfileRegistrationFormUniqueEmail),
|
||||||
url('^user/', include('django.contrib.auth.urls')),
|
name="registration_register"),
|
||||||
url('^user/', include('registration.backends.default.urls')),
|
url('^user/', include('django.contrib.auth.urls')),
|
||||||
|
url('^user/', include('registration.backends.default.urls')),
|
||||||
|
|
||||||
url(r'^admin/', admin.site.urls),
|
url(r'^admin/', include(admin.site.urls)),
|
||||||
]
|
)
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
urlpatterns += staticfiles_urlpatterns()
|
urlpatterns += staticfiles_urlpatterns()
|
||||||
|
|
||||||
import debug_toolbar
|
|
||||||
urlpatterns = [
|
|
||||||
url(r'^__debug__/', include(debug_toolbar.urls)),
|
|
||||||
] + urlpatterns
|
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ 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 # noqa
|
from django.core.wsgi import get_wsgi_application
|
||||||
from dj_static import Cling # noqa
|
from dj_static import Cling
|
||||||
|
|
||||||
application = Cling(get_wsgi_application())
|
application = Cling(get_wsgi_application())
|
||||||
|
|||||||
23
README.md
@@ -1,8 +1,6 @@
|
|||||||
# TEC PA & Lighting - PyRIGS #
|
# TEC PA & Lighting - PyRIGS #
|
||||||
[](https://travis-ci.org/nottinghamtec/PyRIGS)
|
[](https://travis-ci.org/nottinghamtec/PyRIGS)
|
||||||
[](https://coveralls.io/github/nottinghamtec/PyRIGS?branch=develop)
|
[](https://coveralls.io/github/nottinghamtec/PyRIGS?branch=develop)
|
||||||
[](https://gemnasium.com/github.com/nottinghamtec/PyRIGS)
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
@@ -77,13 +75,6 @@ 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.
|
||||||
|
|
||||||
### Development using docker
|
|
||||||
|
|
||||||
```
|
|
||||||
docker build . -t pyrigs
|
|
||||||
docker run -it --rm -p=8000:8000 -v $(pwd):/app pyrigs
|
|
||||||
```
|
|
||||||
|
|
||||||
### Sample Data ###
|
### 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:
|
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:
|
||||||
```
|
```
|
||||||
@@ -94,7 +85,6 @@ Then load the sample data using the command:
|
|||||||
python manage.py generateSampleData
|
python manage.py generateSampleData
|
||||||
```
|
```
|
||||||
4 user accounts are created for convenience:
|
4 user accounts are created for convenience:
|
||||||
|
|
||||||
|Username |Password |
|
|Username |Password |
|
||||||
|---------|---------|
|
|---------|---------|
|
||||||
|superuser|superuser|
|
|superuser|superuser|
|
||||||
@@ -102,18 +92,5 @@ python manage.py generateSampleData
|
|||||||
|keyholder|keyholder|
|
|keyholder|keyholder|
|
||||||
|basic |basic |
|
|basic |basic |
|
||||||
|
|
||||||
### Testing ###
|
|
||||||
Tests are contained in 3 files. `RIGS/test_models.py` contains tests for logic within the data models. `RIGS/test_unit.py` contains "Live server" tests, using raw web requests. `RIGS/test_integration.py` contains user interface tests which take control of a web browser. For automated Travis tests, we use [Sauce Labs](https://saucelabs.com). When debugging locally, ensure that you have the latest version of Google Chrome installed, then install [chromedriver](https://sites.google.com/a/chromium.org/chromedriver/) and ensure it is on the `PATH`.
|
|
||||||
|
|
||||||
You can run the entire test suite, or you can run specific sections individually. For example, in order of specificity:
|
|
||||||
|
|
||||||
```
|
|
||||||
python manage.py test
|
|
||||||
python manage.py test RIGS.test_models
|
|
||||||
python manage.py test RIGS.test_models.EventTestCase
|
|
||||||
python manage.py test RIGS.test_models.EventTestCase.test_current_events
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
### 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 +0,0 @@
|
|||||||
default_app_config = 'RIGS.apps.RIGSAppConfig'
|
|
||||||
|
|||||||
@@ -1,23 +1,21 @@
|
|||||||
|
import reversion
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from RIGS import models, forms
|
|
||||||
from django.contrib.auth.admin import UserAdmin
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
from reversion.admin import VersionAdmin
|
|
||||||
|
|
||||||
from django.contrib.admin import helpers
|
|
||||||
from django.template.response import TemplateResponse
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.db import transaction
|
from django.contrib.admin import helpers
|
||||||
|
from django.contrib.auth.admin import UserAdmin
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.db import transaction
|
||||||
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 reversion import revisions as reversion
|
from RIGS import models, forms
|
||||||
|
|
||||||
# Register your models here.
|
# Register your models here.
|
||||||
admin.site.register(models.VatRate, VersionAdmin)
|
admin.site.register(models.VatRate, reversion.VersionAdmin)
|
||||||
admin.site.register(models.Event, VersionAdmin)
|
admin.site.register(models.Event, reversion.VersionAdmin)
|
||||||
admin.site.register(models.EventItem, VersionAdmin)
|
admin.site.register(models.EventItem, reversion.VersionAdmin)
|
||||||
admin.site.register(models.Invoice)
|
admin.site.register(models.Invoice)
|
||||||
admin.site.register(models.Payment)
|
admin.site.register(models.Payment)
|
||||||
|
|
||||||
@@ -43,7 +41,7 @@ class ProfileAdmin(UserAdmin):
|
|||||||
add_form = forms.ProfileCreationForm
|
add_form = forms.ProfileCreationForm
|
||||||
|
|
||||||
|
|
||||||
class AssociateAdmin(VersionAdmin):
|
class AssociateAdmin(reversion.VersionAdmin):
|
||||||
list_display = ('id', 'name', 'number_of_events')
|
list_display = ('id', 'name', 'number_of_events')
|
||||||
search_fields = ['id', 'name']
|
search_fields = ['id', 'name']
|
||||||
list_display_links = ['id', 'name']
|
list_display_links = ['id', 'name']
|
||||||
@@ -52,7 +50,8 @@ class AssociateAdmin(VersionAdmin):
|
|||||||
merge_fields = ['name']
|
merge_fields = ['name']
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
return super(AssociateAdmin, self).get_queryset(request).annotate(event_count=Count('event'))
|
return super(AssociateAdmin, self).get_queryset(
|
||||||
|
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()
|
||||||
@@ -60,12 +59,16 @@ class AssociateAdmin(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('post'): # Has the user confirmed which is the master record?
|
if request.POST.get(
|
||||||
|
'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(request, "An error occured. Did you select a 'master' record?", level=messages.ERROR)
|
self.message_user(
|
||||||
|
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():
|
||||||
@@ -81,6 +84,7 @@ class AssociateAdmin(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
|
||||||
@@ -95,7 +99,8 @@ class AssociateAdmin(VersionAdmin):
|
|||||||
'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
|
'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
|
||||||
'forms': forms
|
'forms': forms
|
||||||
}
|
}
|
||||||
return TemplateResponse(request, 'RIGS/admin_associate_merge.html', context)
|
return TemplateResponse(request, 'RIGS/admin_associate_merge.html', context,
|
||||||
|
current_app=self.admin_site.name)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(models.Person)
|
@admin.register(models.Person)
|
||||||
@@ -107,10 +112,22 @@ 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 = ['name', 'phone', 'email', 'address', 'notes', 'three_phase_available']
|
merge_fields = [
|
||||||
|
'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 = ['name', 'phone', 'email', 'address', 'notes', 'union_account']
|
merge_fields = [
|
||||||
|
'name',
|
||||||
|
'phone',
|
||||||
|
'email',
|
||||||
|
'address',
|
||||||
|
'notes',
|
||||||
|
'union_account']
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class RIGSAppConfig(AppConfig):
|
|
||||||
name = 'RIGS'
|
|
||||||
|
|
||||||
def ready(self):
|
|
||||||
import RIGS.signals
|
|
||||||
@@ -1,22 +1,20 @@
|
|||||||
|
import cStringIO as StringIO
|
||||||
import datetime
|
import datetime
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.urls import reverse_lazy
|
from django.core.urlresolvers import reverse_lazy
|
||||||
|
from django.db.models import Q
|
||||||
from django.http import Http404, HttpResponseRedirect
|
from django.http import Http404, HttpResponseRedirect
|
||||||
from django.http import HttpResponse
|
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.views import generic
|
||||||
from django.db.models import Q
|
|
||||||
from z3c.rml import rml2pdf
|
from z3c.rml import rml2pdf
|
||||||
|
|
||||||
from RIGS import models
|
from RIGS import models
|
||||||
|
|
||||||
from django import forms
|
|
||||||
forms.DateField.widget = forms.DateInput(attrs={'type': 'date'})
|
|
||||||
|
|
||||||
|
|
||||||
class InvoiceIndex(generic.ListView):
|
class InvoiceIndex(generic.ListView):
|
||||||
model = models.Invoice
|
model = models.Invoice
|
||||||
@@ -32,7 +30,8 @@ class InvoiceIndex(generic.ListView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
# Manual query is the only way I have found to do this efficiently. Not ideal but needs must
|
# Manual query is the only way I have found to do this efficiently. Not
|
||||||
|
# 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\", " \
|
||||||
@@ -57,8 +56,8 @@ class InvoicePrint(generic.View):
|
|||||||
invoice = get_object_or_404(models.Invoice, pk=pk)
|
invoice = get_object_or_404(models.Invoice, pk=pk)
|
||||||
object = invoice.event
|
object = invoice.event
|
||||||
template = get_template('RIGS/event_print.xml')
|
template = get_template('RIGS/event_print.xml')
|
||||||
|
copies = ('TEC', 'Client')
|
||||||
context = {
|
context = RequestContext(request, {
|
||||||
'object': object,
|
'object': object,
|
||||||
'fonts': {
|
'fonts': {
|
||||||
'opensans': {
|
'opensans': {
|
||||||
@@ -68,9 +67,10 @@ class InvoicePrint(generic.View):
|
|||||||
},
|
},
|
||||||
'invoice': invoice,
|
'invoice': invoice,
|
||||||
'current_user': request.user,
|
'current_user': request.user,
|
||||||
}
|
})
|
||||||
|
|
||||||
rml = template.render(context)
|
rml = template.render(context)
|
||||||
|
buffer = StringIO.StringIO()
|
||||||
|
|
||||||
buffer = rml2pdf.parseString(rml)
|
buffer = rml2pdf.parseString(rml)
|
||||||
|
|
||||||
@@ -79,7 +79,8 @@ 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['Content-Disposition'] = "filename=Invoice %05d - N%05d | %s.pdf" % (invoice.pk, invoice.event.pk, escapedEventName)
|
response[
|
||||||
|
'Content-Disposition'] = "filename=Invoice %05d | %s.pdf" % (invoice.pk, escapedEventName)
|
||||||
response.write(pdfData)
|
response.write(pdfData)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@@ -93,7 +94,8 @@ 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('invoice_detail', kwargs={'pk': object.pk}))
|
return HttpResponseRedirect(reverse_lazy(
|
||||||
|
'invoice_detail', kwargs={'pk': object.pk}))
|
||||||
|
|
||||||
|
|
||||||
class InvoiceDelete(generic.DeleteView):
|
class InvoiceDelete(generic.DeleteView):
|
||||||
@@ -102,15 +104,21 @@ class InvoiceDelete(generic.DeleteView):
|
|||||||
def get(self, request, pk):
|
def get(self, request, pk):
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
if obj.payment_set.all().count() > 0:
|
if obj.payment_set.all().count() > 0:
|
||||||
messages.info(self.request, 'To delete an invoice, delete the payments first.')
|
messages.info(
|
||||||
return HttpResponseRedirect(reverse_lazy('invoice_detail', kwargs={'pk': obj.pk}))
|
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)
|
return super(InvoiceDelete, self).get(pk)
|
||||||
|
|
||||||
def post(self, request, pk):
|
def post(self, request, pk):
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
if obj.payment_set.all().count() > 0:
|
if obj.payment_set.all().count() > 0:
|
||||||
messages.info(self.request, 'To delete an invoice, delete the payments first.')
|
messages.info(
|
||||||
return HttpResponseRedirect(reverse_lazy('invoice_detail', kwargs={'pk': obj.pk}))
|
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)
|
return super(InvoiceDelete, self).post(pk)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
@@ -125,7 +133,7 @@ class InvoiceArchive(generic.ListView):
|
|||||||
|
|
||||||
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):
|
def get_context_data(self, **kwargs):
|
||||||
@@ -144,10 +152,12 @@ class InvoiceWaiting(generic.ListView):
|
|||||||
# @todo find a way to select items
|
# @todo find a way to select items
|
||||||
events = self.model.objects.filter(
|
events = self.model.objects.filter(
|
||||||
(
|
(
|
||||||
Q(start_date__lte=datetime.date.today(), end_date__isnull=True) | # Starts before with no end
|
# Starts before with no end
|
||||||
Q(end_date__lte=datetime.date.today()) # Has end date, finishes before
|
Q(start_date__lte=datetime.date.today(), end_date__isnull=True) |
|
||||||
) & Q(invoice__isnull=True) & # Has not already been invoiced
|
# Has end date, finishes before
|
||||||
Q(is_rig=True) # Is a rig (not non-rig)
|
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') \
|
).order_by('start_date') \
|
||||||
.select_related('person',
|
.select_related('person',
|
||||||
@@ -168,7 +178,8 @@ class InvoiceEvent(generic.View):
|
|||||||
invoice.invoice_date = datetime.date.today()
|
invoice.invoice_date = datetime.date.today()
|
||||||
messages.success(self.request, 'Invoice created successfully')
|
messages.success(self.request, 'Invoice created successfully')
|
||||||
|
|
||||||
return HttpResponseRedirect(reverse_lazy('invoice_detail', kwargs={'pk': invoice.pk}))
|
return HttpResponseRedirect(reverse_lazy(
|
||||||
|
'invoice_detail', kwargs={'pk': invoice.pk}))
|
||||||
|
|
||||||
|
|
||||||
class PaymentCreate(generic.CreateView):
|
class PaymentCreate(generic.CreateView):
|
||||||
@@ -177,7 +188,9 @@ class PaymentCreate(generic.CreateView):
|
|||||||
|
|
||||||
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('invoice', self.request.POST.get('invoice', None))
|
invoicepk = self.request.GET.get(
|
||||||
|
'invoice', self.request.POST.get(
|
||||||
|
'invoice', None))
|
||||||
if invoicepk is 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)
|
||||||
|
|||||||
@@ -1,44 +1,42 @@
|
|||||||
from django import forms
|
__author__ = 'Ghost'
|
||||||
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 captcha.fields import ReCaptchaField
|
|
||||||
import simplejson
|
import simplejson
|
||||||
|
from captcha.fields import ReCaptchaField
|
||||||
|
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 registration.forms import RegistrationFormUniqueEmail
|
||||||
|
|
||||||
from RIGS import models
|
from RIGS import models
|
||||||
|
|
||||||
# Override the django form defaults to use the HTML date/time/datetime UI elements
|
|
||||||
forms.DateField.widget = forms.DateInput(attrs={'type': 'date'})
|
|
||||||
forms.TimeField.widget = forms.TextInput(attrs={'type': 'time'})
|
|
||||||
forms.DateTimeField.widget = forms.DateTimeInput(attrs={'type': 'datetime-local'})
|
|
||||||
|
|
||||||
# Registration
|
# Registration
|
||||||
|
|
||||||
|
|
||||||
class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
|
class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
|
||||||
captcha = ReCaptchaField()
|
captcha = ReCaptchaField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Profile
|
model = models.Profile
|
||||||
fields = ('username', 'email', 'first_name', 'last_name', 'initials', 'phone')
|
fields = (
|
||||||
|
'username',
|
||||||
|
'email',
|
||||||
|
'first_name',
|
||||||
|
'last_name',
|
||||||
|
'initials',
|
||||||
|
'phone')
|
||||||
|
|
||||||
def clean_initials(self):
|
def clean_initials(self):
|
||||||
"""
|
"""
|
||||||
Validate that the supplied initials are unique.
|
Validate that the supplied initials are unique.
|
||||||
"""
|
"""
|
||||||
if models.Profile.objects.filter(initials__iexact=self.cleaned_data['initials']):
|
if models.Profile.objects.filter(
|
||||||
raise forms.ValidationError("These initials are already in use. Please supply different initials.")
|
initials__iexact=self.cleaned_data['initials']):
|
||||||
|
raise forms.ValidationError(
|
||||||
|
"These initials are already in use. Please supply different initials.")
|
||||||
return self.cleaned_data['initials']
|
return self.cleaned_data['initials']
|
||||||
|
|
||||||
|
|
||||||
# Embedded Login form - remove the autofocus
|
# Login form
|
||||||
class EmbeddedAuthenticationForm(AuthenticationForm):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self.fields['username'].widget.attrs.pop('autofocus', None)
|
|
||||||
|
|
||||||
class PasswordReset(PasswordResetForm):
|
class PasswordReset(PasswordResetForm):
|
||||||
captcha = ReCaptchaField(label='Captcha')
|
captcha = ReCaptchaField(label='Captcha')
|
||||||
|
|
||||||
@@ -55,9 +53,14 @@ 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") + list(settings.DATETIME_INPUT_FORMATS)
|
datetime_input_formats = formats.get_format_lazy(
|
||||||
meet_at = forms.DateTimeField(input_formats=datetime_input_formats, required=False)
|
"DATETIME_INPUT_FORMATS") + settings.DATETIME_INPUT_FORMATS
|
||||||
access_at = forms.DateTimeField(input_formats=datetime_input_formats, required=False)
|
meet_at = forms.DateTimeField(
|
||||||
|
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()
|
||||||
|
|
||||||
@@ -99,7 +102,8 @@ 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(pk, data[key]['fields'], event)
|
items[pk] = self._get_or_initialise_item(
|
||||||
|
pk, data[key]['fields'], event)
|
||||||
|
|
||||||
return items
|
return items
|
||||||
|
|
||||||
@@ -150,32 +154,4 @@ class EventForm(forms.ModelForm):
|
|||||||
fields = ['is_rig', 'name', 'venue', 'start_time', 'end_date', 'start_date',
|
fields = ['is_rig', 'name', 'venue', 'start_time', 'end_date', 'start_date',
|
||||||
'end_time', 'meet_at', 'access_at', 'description', 'notes', 'mic',
|
'end_time', 'meet_at', 'access_at', 'description', 'notes', 'mic',
|
||||||
'person', 'organisation', 'dry_hire', 'checked_in_by', 'status',
|
'person', 'organisation', 'dry_hire', 'checked_in_by', 'status',
|
||||||
'purchase_order', 'collector']
|
'collector', 'purchase_order']
|
||||||
|
|
||||||
|
|
||||||
class BaseClientEventAuthorisationForm(forms.ModelForm):
|
|
||||||
tos = forms.BooleanField(required=True, label="Terms of hire")
|
|
||||||
name = forms.CharField(label="Your Name")
|
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
if self.cleaned_data.get('amount') != self.instance.event.total:
|
|
||||||
self.add_error('amount', 'The amount authorised must equal the total for the event (inc VAT).')
|
|
||||||
return super(BaseClientEventAuthorisationForm, self).clean()
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
abstract = True
|
|
||||||
|
|
||||||
|
|
||||||
class InternalClientEventAuthorisationForm(BaseClientEventAuthorisationForm):
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
super(InternalClientEventAuthorisationForm, self).__init__(**kwargs)
|
|
||||||
self.fields['uni_id'].required = True
|
|
||||||
self.fields['account_code'].required = True
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = models.EventAuthorisation
|
|
||||||
fields = ('tos', 'name', 'amount', 'uni_id', 'account_code')
|
|
||||||
|
|
||||||
|
|
||||||
class EventAuthorisationRequestForm(forms.Form):
|
|
||||||
email = forms.EmailField(required=True, label='Authoriser Email')
|
|
||||||
|
|||||||
57
RIGS/ical.py
@@ -1,12 +1,11 @@
|
|||||||
from RIGS import models, forms
|
|
||||||
from django_ical.views import ICalFeed
|
|
||||||
from django.db.models import Q
|
|
||||||
from django.urls import reverse_lazy, reverse, NoReverseMatch
|
|
||||||
from django.utils import timezone
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db.models import Q
|
||||||
|
from django_ical.views import ICalFeed
|
||||||
|
|
||||||
|
from RIGS import models
|
||||||
|
|
||||||
|
|
||||||
class CalendarICS(ICalFeed):
|
class CalendarICS(ICalFeed):
|
||||||
@@ -34,14 +33,17 @@ class CalendarICS(ICalFeed):
|
|||||||
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('provisional', 'true') == 'true'
|
params['provisional'] = request.GET.get(
|
||||||
|
'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 '') + ('Non-rig, ' if params['non-rig'] else '') + ('Dry Hire ' if params['dry-hire'] else '') + '\n'
|
desc = "Calendar generated by RIGS system. This includes event types: " + ('Rig, ' if params['rig'] else '') + (
|
||||||
desc = desc + "Includes events with status: " + ('Cancelled, ' if params['cancelled'] else '') + ('Provisional, ' if params['provisional'] else '') + ('Confirmed/Booked, ' if params['confirmed'] else '')
|
'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 '')
|
||||||
|
|
||||||
return desc
|
return desc
|
||||||
|
|
||||||
@@ -50,7 +52,8 @@ class CalendarICS(ICalFeed):
|
|||||||
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)
|
||||||
|
|
||||||
typeFilters = Q(pk=None) # Need something that is false for every entry
|
# 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)
|
||||||
@@ -61,18 +64,22 @@ class CalendarICS(ICalFeed):
|
|||||||
if params['rig']:
|
if params['rig']:
|
||||||
typeFilters = typeFilters | Q(is_rig=True, dry_hire=False)
|
typeFilters = typeFilters | Q(is_rig=True, dry_hire=False)
|
||||||
|
|
||||||
statusFilters = Q(pk=None) # Need something that is false for every entry
|
# 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(status=models.Event.CONFIRMED) | Q(status=models.Event.BOOKED)
|
statusFilters = statusFilters | Q(
|
||||||
|
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('-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
return models.Event.objects.filter(filter).order_by(
|
||||||
|
'-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
||||||
|
|
||||||
def item_title(self, item):
|
def item_title(self, item):
|
||||||
title = ''
|
title = ''
|
||||||
@@ -99,7 +106,8 @@ class CalendarICS(ICalFeed):
|
|||||||
return item.earliest_time
|
return item.earliest_time
|
||||||
|
|
||||||
def item_end_datetime(self, item):
|
def item_end_datetime(self, item):
|
||||||
if type(item.latest_time) == datetime.date: # Ical end_datetime is non-inclusive, so add a day
|
if isinstance(
|
||||||
|
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
|
||||||
@@ -117,19 +125,26 @@ class CalendarICS(ICalFeed):
|
|||||||
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 + ((' for ' + item.organisation.name) if item.organisation else '') + '\n'
|
desc += 'Client = ' + item.person.name + \
|
||||||
|
((' 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 = ' + (item.meet_at.astimezone(tz).strftime('%Y-%m-%d %H:%M') if item.meet_at else '---') + '\n'
|
desc += 'Crew Meet = ' + \
|
||||||
|
(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('%Y-%m-%d %H:%M') if item.access_at else '---') + '\n'
|
desc += 'Access At = ' + (item.access_at.astimezone(tz).strftime(
|
||||||
|
'%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') + ((' ' + item.start_time.strftime('%H:%M')) if item.has_start_time else '') + '\n'
|
desc += 'Event Start = ' + item.start_date.strftime('%Y-%m-%d') + (
|
||||||
|
(' ' + 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') + ((' ' + item.end_time.strftime('%H:%M')) if item.has_end_time else '') + '\n'
|
desc += 'Event End = ' + item.end_date.strftime('%Y-%m-%d') + (
|
||||||
|
(' ' + item.end_time.strftime('%H:%M')) if item.has_end_time else '') + '\n'
|
||||||
|
|
||||||
desc += '\n'
|
desc += '\n'
|
||||||
if item.description:
|
if item.description:
|
||||||
@@ -137,7 +152,7 @@ class CalendarICS(ICalFeed):
|
|||||||
# 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 = "https://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
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
from django.core.management.base import BaseCommand, CommandError
|
|
||||||
from django.contrib.auth.models import Group, Permission
|
|
||||||
from django.db import transaction
|
|
||||||
from reversion import revisions as reversion
|
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import random
|
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
|
from RIGS import models
|
||||||
|
|
||||||
|
|
||||||
@@ -27,7 +27,8 @@ class Command(BaseCommand):
|
|||||||
if not (settings.DEBUG or settings.STAGING):
|
if not (settings.DEBUG or settings.STAGING):
|
||||||
raise CommandError('You cannot run this command in production')
|
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
|
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():
|
with transaction.atomic():
|
||||||
models.VatRate.objects.create(start_at='2014-03-05', rate=0.20, comment='test1')
|
models.VatRate.objects.create(start_at='2014-03-05', rate=0.20, comment='test1')
|
||||||
@@ -45,8 +46,18 @@ class Command(BaseCommand):
|
|||||||
self.setupUsefulProfiles()
|
self.setupUsefulProfiles()
|
||||||
|
|
||||||
def setupPeople(self):
|
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", # noqa
|
names = ["Regulus Black", "Sirius Black", "Lavender Brown", "Cho Chang", "Vincent Crabbe", "Vincent Crabbe",
|
||||||
"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"] # noqa
|
"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):
|
for i, name in enumerate(names):
|
||||||
with reversion.create_revision():
|
with reversion.create_revision():
|
||||||
reversion.set_user(random.choice(self.profiles))
|
reversion.set_user(random.choice(self.profiles))
|
||||||
@@ -68,8 +79,32 @@ class Command(BaseCommand):
|
|||||||
self.people.append(newPerson)
|
self.people.append(newPerson)
|
||||||
|
|
||||||
def setupOrganisations(self):
|
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", # noqa
|
names = ["Acme, inc.", "Widget Corp", "123 Warehousing", "Demo Company", "Smith and Co.", "Foo Bars",
|
||||||
"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"] # noqa
|
"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):
|
for i, name in enumerate(names):
|
||||||
with reversion.create_revision():
|
with reversion.create_revision():
|
||||||
reversion.set_user(random.choice(self.profiles))
|
reversion.set_user(random.choice(self.profiles))
|
||||||
@@ -93,8 +128,17 @@ class Command(BaseCommand):
|
|||||||
self.organisations.append(newOrganisation)
|
self.organisations.append(newOrganisation)
|
||||||
|
|
||||||
def setupVenues(self):
|
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", # noqa
|
names = ["Bear Island", "Crossroads Inn", "Deepwood Motte", "The Dreadfort", "The Eyrie", "Greywater Watch",
|
||||||
"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"] # noqa
|
"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):
|
for i, name in enumerate(names):
|
||||||
with reversion.create_revision():
|
with reversion.create_revision():
|
||||||
reversion.set_user(random.choice(self.profiles))
|
reversion.set_user(random.choice(self.profiles))
|
||||||
@@ -121,8 +165,14 @@ class Command(BaseCommand):
|
|||||||
self.keyholder_group = Group.objects.create(name='Keyholders')
|
self.keyholder_group = Group.objects.create(name='Keyholders')
|
||||||
self.finance_group = Group.objects.create(name='Finance')
|
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"]
|
keyholderPerms = ["add_event", "change_event", "view_event", "add_eventitem", "change_eventitem",
|
||||||
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"]
|
"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:
|
for permId in keyholderPerms:
|
||||||
self.keyholder_group.permissions.add(Permission.objects.get(codename=permId))
|
self.keyholder_group.permissions.add(Permission.objects.get(codename=permId))
|
||||||
@@ -131,9 +181,11 @@ class Command(BaseCommand):
|
|||||||
self.finance_group.permissions.add(Permission.objects.get(codename=permId))
|
self.finance_group.permissions.add(Permission.objects.get(codename=permId))
|
||||||
|
|
||||||
def setupGenericProfiles(self):
|
def setupGenericProfiles(self):
|
||||||
names = ["Clara Oswin Oswald", "Rory Williams", "Amy Pond", "River Song", "Martha Jones", "Donna Noble", "Jack Harkness", "Mickey Smith", "Rose Tyler"]
|
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):
|
for i, name in enumerate(names):
|
||||||
newProfile = models.Profile.objects.create(username=name.replace(" ", ""), first_name=name.split(" ")[0], last_name=name.split(" ")[-1],
|
newProfile = models.Profile.objects.create(username=name.replace(" ", ""), first_name=name.split(" ")[0],
|
||||||
|
last_name=name.split(" ")[-1],
|
||||||
email=name.replace(" ", "") + "@example.com",
|
email=name.replace(" ", "") + "@example.com",
|
||||||
initials="".join([j[0].upper() for j in name.split()]))
|
initials="".join([j[0].upper() for j in name.split()]))
|
||||||
if i % 2 == 0:
|
if i % 2 == 0:
|
||||||
@@ -143,19 +195,23 @@ class Command(BaseCommand):
|
|||||||
self.profiles.append(newProfile)
|
self.profiles.append(newProfile)
|
||||||
|
|
||||||
def setupUsefulProfiles(self):
|
def setupUsefulProfiles(self):
|
||||||
superUser = models.Profile.objects.create(username="superuser", first_name="Super", last_name="User", initials="SU",
|
superUser = models.Profile.objects.create(username="superuser", first_name="Super", last_name="User",
|
||||||
email="superuser@example.com", is_superuser=True, is_active=True, is_staff=True)
|
initials="SU",
|
||||||
|
email="superuser@example.com", is_superuser=True, is_active=True,
|
||||||
|
is_staff=True)
|
||||||
superUser.set_password('superuser')
|
superUser.set_password('superuser')
|
||||||
superUser.save()
|
superUser.save()
|
||||||
|
|
||||||
financeUser = models.Profile.objects.create(username="finance", first_name="Finance", last_name="User", initials="FU",
|
financeUser = models.Profile.objects.create(username="finance", first_name="Finance", last_name="User",
|
||||||
|
initials="FU",
|
||||||
email="financeuser@example.com", is_active=True)
|
email="financeuser@example.com", is_active=True)
|
||||||
financeUser.groups.add(self.finance_group)
|
financeUser.groups.add(self.finance_group)
|
||||||
financeUser.groups.add(self.keyholder_group)
|
financeUser.groups.add(self.keyholder_group)
|
||||||
financeUser.set_password('finance')
|
financeUser.set_password('finance')
|
||||||
financeUser.save()
|
financeUser.save()
|
||||||
|
|
||||||
keyholderUser = models.Profile.objects.create(username="keyholder", first_name="Keyholder", last_name="User", initials="KU",
|
keyholderUser = models.Profile.objects.create(username="keyholder", first_name="Keyholder", last_name="User",
|
||||||
|
initials="KU",
|
||||||
email="keyholderuser@example.com", is_active=True)
|
email="keyholderuser@example.com", is_active=True)
|
||||||
keyholderUser.groups.add(self.keyholder_group)
|
keyholderUser.groups.add(self.keyholder_group)
|
||||||
keyholderUser.set_password('keyholder')
|
keyholderUser.set_password('keyholder')
|
||||||
@@ -167,20 +223,31 @@ class Command(BaseCommand):
|
|||||||
basicUser.save()
|
basicUser.save()
|
||||||
|
|
||||||
def setupEvents(self):
|
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",
|
names = ["Outdoor Concert", "Hall Open Mic Night", "Festival", "Weekend Event", "Magic Show", "Society Ball",
|
||||||
"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"]
|
"Evening Show", "Talent Show", "Acoustic Evening", "Hire of Things", "SU Event", "End of Term Show",
|
||||||
descriptions = ["A brief desciption of the event", "This event is boring", "Probably wont happen", "Warning: this has lots of kit"]
|
"Theatre Show", "Outdoor Fun Day", "Summer Carnival", "Open Days", "Magic Show", "Awards Ceremony",
|
||||||
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!"]
|
"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},
|
itemOptions = [
|
||||||
{'name': 'Projector', 'description': 'Some kind of video thinamejig, probably with unnecessary processing for free', 'quantity': 1, 'cost': 500.00},
|
{'name': 'Speakers', 'description': 'Some really really big speakers \n these are very loud', 'quantity': 2,
|
||||||
{'name': 'Lighting Desk', 'description': 'Cannot provide guarentee that it will work', 'quantity': 1, 'cost': 200.52},
|
'cost': 200.00},
|
||||||
{'name': 'Moving lights', 'description': 'Flashy lights, with the copper', 'quantity': 8, 'cost': 50.00},
|
{'name': 'Projector',
|
||||||
{'name': 'Microphones', 'description': 'Make loud noise \n you will want speakers with this', 'quantity': 5, 'cost': 0.50},
|
'description': 'Some kind of video thinamejig, probably with unnecessary processing for free',
|
||||||
{'name': 'Sound Mixer Thing', 'description': 'Might be analogue, might be digital', 'quantity': 1, 'cost': 100.00},
|
'quantity': 1, 'cost': 500.00},
|
||||||
{'name': 'Electricity', 'description': 'You need this', 'quantity': 1, 'cost': 200.00},
|
{'name': 'Lighting Desk', 'description': 'Cannot provide guarentee that it will work', 'quantity': 1,
|
||||||
{'name': 'Crew', 'description': 'Costs nothing, because reasons', 'quantity': 1, 'cost': 0.00},
|
'cost': 200.52},
|
||||||
{'name': 'Loyalty Discount', 'description': 'Have some negative moneys', 'quantity': 1, 'cost': -50.00}]
|
{'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
|
dayDelta = -120 # start adding events from 4 months ago
|
||||||
|
|
||||||
@@ -218,7 +285,8 @@ class Command(BaseCommand):
|
|||||||
newEvent.venue = random.choice(self.venues)
|
newEvent.venue = random.choice(self.venues)
|
||||||
|
|
||||||
# Could have any status, equally weighted
|
# Could have any status, equally weighted
|
||||||
newEvent.status = random.choice([models.Event.BOOKED, models.Event.CONFIRMED, models.Event.PROVISIONAL, models.Event.CANCELLED])
|
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
|
newEvent.dry_hire = (random.randint(0, 7) == 0) # 1 in 7 are dry hire
|
||||||
|
|
||||||
@@ -249,4 +317,5 @@ class Command(BaseCommand):
|
|||||||
if newEvent.status is models.Event.CANCELLED: # void cancelled events
|
if newEvent.status is models.Event.CANCELLED: # void cancelled events
|
||||||
newInvoice.void = True
|
newInvoice.void = True
|
||||||
elif random.randint(0, 2) > 1: # 1 in 3 have been paid
|
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())
|
models.Payment.objects.create(invoice=newInvoice, amount=newInvoice.balance,
|
||||||
|
date=datetime.date.today())
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
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'),
|
||||||
]
|
]
|
||||||
@@ -19,18 +18,32 @@ 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, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
('is_superuser', models.BooleanField(default=False,
|
||||||
('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')])),
|
help_text='Designates that this user has all permissions without explicitly assigning them.',
|
||||||
|
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, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
('is_staff', models.BooleanField(default=False,
|
||||||
('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')),
|
help_text='Designates whether the user can log into this admin site.',
|
||||||
|
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, 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')),
|
('groups', models.ManyToManyField(blank=True,
|
||||||
('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')),
|
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')),
|
||||||
|
('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,12 +1,11 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
|
||||||
from django.db import models, migrations
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0001_initial'),
|
('RIGS', '0001_initial'),
|
||||||
]
|
]
|
||||||
@@ -18,7 +17,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)),
|
||||||
('postedAt', models.DateTimeField(auto_now=True)),
|
('postedAt', models.DateTimeField(auto_now=True)),
|
||||||
('message', models.TextField()),
|
('message', models.TextField()),
|
||||||
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
|
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0002_modelcomment_person'),
|
('RIGS', '0002_modelcomment_person'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
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'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0004_organisation'),
|
('RIGS', '0004_organisation'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
import RIGS.models
|
import RIGS.models
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -33,11 +33,11 @@ class Migration(migrations.Migration):
|
|||||||
('payment_method', models.CharField(blank=True, null=True, max_length=255)),
|
('payment_method', models.CharField(blank=True, null=True, max_length=255)),
|
||||||
('payment_received', models.CharField(blank=True, null=True, max_length=255)),
|
('payment_received', models.CharField(blank=True, null=True, max_length=255)),
|
||||||
('purchase_order', models.CharField(blank=True, null=True, max_length=255)),
|
('purchase_order', models.CharField(blank=True, null=True, max_length=255)),
|
||||||
('based_on', models.ForeignKey(to='RIGS.Event', related_name='future_events', on_delete=models.CASCADE)),
|
('based_on', models.ForeignKey(to='RIGS.Event', related_name='future_events')),
|
||||||
('checked_in_by', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='event_checked_in', on_delete=models.CASCADE)),
|
('checked_in_by', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='event_checked_in')),
|
||||||
('mic', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='event_mic', on_delete=models.CASCADE)),
|
('mic', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='event_mic')),
|
||||||
('organisation', models.ForeignKey(to='RIGS.Organisation', on_delete=models.CASCADE)),
|
('organisation', models.ForeignKey(to='RIGS.Organisation')),
|
||||||
('person', models.ForeignKey(to='RIGS.Person', on_delete=models.CASCADE)),
|
('person', models.ForeignKey(to='RIGS.Person')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
},
|
},
|
||||||
@@ -52,7 +52,7 @@ class Migration(migrations.Migration):
|
|||||||
('quantity', models.IntegerField()),
|
('quantity', models.IntegerField()),
|
||||||
('cost', models.DecimalField(max_digits=10, decimal_places=2)),
|
('cost', models.DecimalField(max_digits=10, decimal_places=2)),
|
||||||
('order', models.IntegerField()),
|
('order', models.IntegerField()),
|
||||||
('event', models.ForeignKey(to='RIGS.Event', related_name='item', on_delete=models.CASCADE)),
|
('event', models.ForeignKey(to='RIGS.Event', related_name='item')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
},
|
},
|
||||||
@@ -75,7 +75,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='venue',
|
name='venue',
|
||||||
field=models.ForeignKey(to='RIGS.Venue', on_delete=models.CASCADE),
|
field=models.ForeignKey(to='RIGS.Venue'),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -14,26 +14,26 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='based_on',
|
name='based_on',
|
||||||
field=models.ForeignKey(to='RIGS.Event', related_name='future_events', blank=True, null=True, on_delete=models.CASCADE),
|
field=models.ForeignKey(to='RIGS.Event', related_name='future_events', blank=True, null=True),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='checked_in_by',
|
name='checked_in_by',
|
||||||
field=models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='event_checked_in', blank=True,
|
field=models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='event_checked_in', blank=True,
|
||||||
null=True, on_delete=models.CASCADE),
|
null=True),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='mic',
|
name='mic',
|
||||||
field=models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='event_mic', blank=True, null=True, on_delete=models.CASCADE),
|
field=models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='event_mic', blank=True, null=True),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='organisation',
|
name='organisation',
|
||||||
field=models.ForeignKey(to='RIGS.Organisation', blank=True, null=True, on_delete=models.CASCADE),
|
field=models.ForeignKey(to='RIGS.Organisation', blank=True, null=True),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -19,8 +19,8 @@ class Migration(migrations.Migration):
|
|||||||
('run', models.BooleanField(default=False)),
|
('run', models.BooleanField(default=False)),
|
||||||
('derig', models.BooleanField(default=False)),
|
('derig', models.BooleanField(default=False)),
|
||||||
('notes', models.TextField(blank=True, null=True)),
|
('notes', models.TextField(blank=True, null=True)),
|
||||||
('event', models.ForeignKey(related_name='crew', to='RIGS.Event', on_delete=models.CASCADE)),
|
('event', models.ForeignKey(related_name='crew', to='RIGS.Event')),
|
||||||
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
|
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
},
|
},
|
||||||
@@ -35,7 +35,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='eventitem',
|
model_name='eventitem',
|
||||||
name='event',
|
name='event',
|
||||||
field=models.ForeignKey(related_name='items', to='RIGS.Event', on_delete=models.CASCADE),
|
field=models.ForeignKey(related_name='items', to='RIGS.Event'),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
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'),
|
||||||
]
|
]
|
||||||
@@ -14,7 +13,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='person',
|
name='person',
|
||||||
field=models.ForeignKey(blank=True, null=True, to='RIGS.Person', on_delete=models.CASCADE),
|
field=models.ForeignKey(blank=True, null=True, to='RIGS.Person'),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
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'),
|
||||||
]
|
]
|
||||||
@@ -14,13 +13,13 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='venue',
|
name='venue',
|
||||||
field=models.ForeignKey(blank=True, to='RIGS.Venue', null=True, on_delete=models.CASCADE),
|
field=models.ForeignKey(blank=True, to='RIGS.Venue', null=True),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='eventitem',
|
model_name='eventitem',
|
||||||
name='event',
|
name='event',
|
||||||
field=models.ForeignKey(related_name='items', blank=True, to='RIGS.Event', on_delete=models.CASCADE),
|
field=models.ForeignKey(related_name='items', blank=True, to='RIGS.Event'),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
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,12 +1,11 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
|
||||||
from django.db import models, migrations
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0015_auto_20141208_0233'),
|
('RIGS', '0015_auto_20141208_0233'),
|
||||||
]
|
]
|
||||||
@@ -18,7 +17,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)),
|
||||||
('invoice_date', models.DateField(auto_now_add=True)),
|
('invoice_date', models.DateField(auto_now_add=True)),
|
||||||
('void', models.BooleanField()),
|
('void', models.BooleanField()),
|
||||||
('event', models.OneToOneField(to='RIGS.Event', on_delete=models.CASCADE)),
|
('event', models.OneToOneField(to='RIGS.Event')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
},
|
},
|
||||||
@@ -30,8 +29,10 @@ 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, choices=[(b'C', b'Cash'), (b'I', b'Internal'), (b'E', b'External'), (b'SU', b'SU Core'), (b'M', b'Members')])),
|
('method', models.CharField(max_length=2,
|
||||||
('invoice', models.ForeignKey(to='RIGS.Invoice', on_delete=models.CASCADE)),
|
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')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
},
|
},
|
||||||
@@ -40,7 +41,8 @@ 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, to=settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE),
|
field=models.ForeignKey(related_name='event_mic', verbose_name=b'MIC', blank=True,
|
||||||
|
to=settings.AUTH_USER_MODEL, null=True),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
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'),
|
||||||
]
|
]
|
||||||
@@ -14,7 +13,9 @@ 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, choices=[(b'C', b'Cash'), (b'I', b'Internal'), (b'E', b'External'), (b'SU', b'SU Core')]),
|
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')]),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
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'),
|
||||||
]
|
]
|
||||||
@@ -14,7 +13,9 @@ 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, choices=[(b'C', b'Cash'), (b'I', b'Internal'), (b'E', b'External'), (b'SU', b'SU Core'), (b'T', b'TEC Adjustment')]),
|
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')]),
|
||||||
preserve_default=True,
|
preserve_default=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
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'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models, migrations
|
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,13 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
|
||||||
from django.db import models, migrations
|
|
||||||
import django.core.validators
|
|
||||||
import django.contrib.auth.models
|
import django.contrib.auth.models
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0022_auto_20150424_2104'),
|
('RIGS', '0022_auto_20150424_2104'),
|
||||||
]
|
]
|
||||||
@@ -46,7 +45,10 @@ 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', 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'),
|
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'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='profile',
|
model_name='profile',
|
||||||
@@ -56,7 +58,12 @@ 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.'}, 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'),
|
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'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='venue',
|
model_name='venue',
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
|
||||||
from django.db import models, migrations
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0023_auto_20150529_0048'),
|
('RIGS', '0023_auto_20150529_0048'),
|
||||||
]
|
]
|
||||||
@@ -15,6 +14,7 @@ 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, blank=True, to='RIGS.Event', null=True),
|
field=models.ForeignKey(related_name='future_events', on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
blank=True, to='RIGS.Event', null=True),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.9.4 on 2016-03-31 12:02
|
|
||||||
|
|
||||||
|
|
||||||
import django.core.validators
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0024_auto_20160229_2042'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='profile',
|
|
||||||
name='username',
|
|
||||||
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=30, unique=True, validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.')], verbose_name='username'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='vatrate',
|
|
||||||
name='start_at',
|
|
||||||
field=models.DateField(),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
from django.db import models, migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0024_auto_20160229_2042'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='EventAuthorisation',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
|
||||||
('email', models.EmailField(max_length=254)),
|
|
||||||
('name', models.CharField(max_length=255)),
|
|
||||||
('uni_id', models.CharField(max_length=10, null=True, verbose_name=b'University ID', blank=True)),
|
|
||||||
('account_code', models.CharField(max_length=50, null=True, blank=True)),
|
|
||||||
('amount', models.DecimalField(verbose_name=b'authorisation amount', max_digits=10, decimal_places=2)),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('event', models.ForeignKey(related_name='authroisations', to='RIGS.Event', on_delete=models.CASCADE)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.11.1 on 2017-05-10 17:46
|
|
||||||
|
|
||||||
|
|
||||||
import django.contrib.auth.validators
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0025_auto_20160331_1302'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='profile',
|
|
||||||
name='username',
|
|
||||||
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.ASCIIUsernameValidator()], verbose_name='username'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
from django.db import models, migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0025_eventauthorisation'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='eventauthorisation',
|
|
||||||
name='created_at',
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
from django.db import models, migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0026_remove_eventauthorisation_created_at'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='eventauthorisation',
|
|
||||||
name='event',
|
|
||||||
field=models.OneToOneField(related_name='authorisation', to='RIGS.Event', on_delete=models.CASCADE),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
from django.db import models, migrations
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0027_eventauthorisation_event_singular'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='eventauthorisation',
|
|
||||||
name='sent_by',
|
|
||||||
field=models.ForeignKey(default=1, to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
from django.db import models, migrations
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0029_eventauthorisation_sent_by'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='event',
|
|
||||||
name='auth_request_at',
|
|
||||||
field=models.DateTimeField(null=True, blank=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='event',
|
|
||||||
name='auth_request_by',
|
|
||||||
field=models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='event',
|
|
||||||
name='auth_request_to',
|
|
||||||
field=models.EmailField(max_length=254, null=True, blank=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.11.1 on 2017-05-12 20:02
|
|
||||||
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0030_auth_request_sending'),
|
|
||||||
('RIGS', '0026_auto_20170510_1846'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
]
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.11.4 on 2017-09-04 22:55
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
import django.contrib.auth.validators
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('reversion', '0001_squashed_0004_auto_20160611_1202'),
|
|
||||||
('RIGS', '0031_merge_20170512_2102'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='RIGSVersion',
|
|
||||||
fields=[
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'indexes': [],
|
|
||||||
'proxy': True,
|
|
||||||
},
|
|
||||||
bases=('reversion.version',),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='event',
|
|
||||||
name='collector',
|
|
||||||
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='collected by'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='event',
|
|
||||||
name='mic',
|
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='event_mic', to=settings.AUTH_USER_MODEL, verbose_name='MIC'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='event',
|
|
||||||
name='purchase_order',
|
|
||||||
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='PO'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='eventauthorisation',
|
|
||||||
name='amount',
|
|
||||||
field=models.DecimalField(decimal_places=2, max_digits=10, verbose_name='authorisation amount'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='eventauthorisation',
|
|
||||||
name='uni_id',
|
|
||||||
field=models.CharField(blank=True, max_length=10, null=True, verbose_name='University ID'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='payment',
|
|
||||||
name='amount',
|
|
||||||
field=models.DecimalField(decimal_places=2, help_text='Please use ex. VAT', max_digits=10),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='payment',
|
|
||||||
name='method',
|
|
||||||
field=models.CharField(blank=True, choices=[('C', 'Cash'), ('I', 'Internal'), ('E', 'External'), ('SU', 'SU Core'), ('T', 'TEC Adjustment')], max_length=2, null=True),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='profile',
|
|
||||||
name='username',
|
|
||||||
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 2.0.3 on 2018-03-25 00:16
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0032_auto_20170904_2355'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='profile',
|
|
||||||
name='last_name',
|
|
||||||
field=models.CharField(blank=True, max_length=150, verbose_name='last name'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 2.0.5 on 2019-07-28 21:28
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0033_auto_20180325_0016'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='event',
|
|
||||||
name='risk_assessment_edit_url',
|
|
||||||
field=models.CharField(blank=True, max_length=255, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
252
RIGS/models.py
@@ -1,32 +1,35 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import hashlib
|
import hashlib
|
||||||
import datetime
|
|
||||||
import pytz
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from django.contrib.auth.models import AbstractUser
|
|
||||||
from django.conf import settings
|
|
||||||
from django.utils import timezone
|
|
||||||
from django.utils.functional import cached_property
|
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
|
||||||
from reversion import revisions as reversion
|
|
||||||
from reversion.models import Version
|
|
||||||
import string
|
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
import string
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
|
import pytz
|
||||||
|
import reversion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.urls import reverse_lazy
|
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
|
||||||
|
|
||||||
|
|
||||||
# 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(max_length=5, unique=True, null=True, blank=False)
|
initials = models.CharField(
|
||||||
|
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(max_length=40, blank=True, editable=False, null=True)
|
api_key = models.CharField(
|
||||||
|
max_length=40,
|
||||||
|
blank=True,
|
||||||
|
editable=False,
|
||||||
|
null=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_api_key(cls):
|
def make_api_key(cls):
|
||||||
@@ -39,7 +42,8 @@ class Profile(AbstractUser):
|
|||||||
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/" + hashlib.md5(self.email.encode('utf-8')).hexdigest() + "?d=wavatar&s=500"
|
url = "https://www.gravatar.com/avatar/" + \
|
||||||
|
hashlib.md5(self.email).hexdigest() + "?d=wavatar&s=500"
|
||||||
return url
|
return url
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -51,7 +55,8 @@ class Profile(AbstractUser):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def latest_events(self):
|
def latest_events(self):
|
||||||
return self.event_mic.order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
return self.event_mic.order_by(
|
||||||
|
'-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
@@ -63,31 +68,32 @@ class Profile(AbstractUser):
|
|||||||
|
|
||||||
|
|
||||||
class RevisionMixin(object):
|
class RevisionMixin(object):
|
||||||
@property
|
|
||||||
def current_version(self):
|
|
||||||
version = Version.objects.get_for_object(self).select_related('revision').first()
|
|
||||||
return version
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def last_edited_at(self):
|
def last_edited_at(self):
|
||||||
version = self.current_version
|
versions = reversion.get_for_object(self)
|
||||||
if version is None:
|
if versions:
|
||||||
|
version = reversion.get_for_object(self)[0]
|
||||||
|
return version.revision.date_created
|
||||||
|
else:
|
||||||
return None
|
return None
|
||||||
return version.revision.date_created
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def last_edited_by(self):
|
def last_edited_by(self):
|
||||||
version = self.current_version
|
versions = reversion.get_for_object(self)
|
||||||
if version is None:
|
if versions:
|
||||||
|
version = reversion.get_for_object(self)[0]
|
||||||
|
return version.revision.user
|
||||||
|
else:
|
||||||
return None
|
return None
|
||||||
return version.revision.user
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_version_id(self):
|
def current_version_id(self):
|
||||||
version = self.current_version
|
versions = reversion.get_for_object(self)
|
||||||
if version is None:
|
if versions:
|
||||||
|
version = reversion.get_for_object(self)[0]
|
||||||
|
return "V{0} | R{1}".format(version.pk, version.revision.pk)
|
||||||
|
else:
|
||||||
return None
|
return None
|
||||||
return "V{0} | R{1}".format(version.pk, version.revision.pk)
|
|
||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
@@ -111,7 +117,8 @@ class Person(models.Model, RevisionMixin):
|
|||||||
@property
|
@property
|
||||||
def organisations(self):
|
def organisations(self):
|
||||||
o = []
|
o = []
|
||||||
for e in Event.objects.filter(person=self).select_related('organisation'):
|
for e in Event.objects.filter(
|
||||||
|
person=self).select_related('organisation'):
|
||||||
if e.organisation:
|
if e.organisation:
|
||||||
o.append(e.organisation)
|
o.append(e.organisation)
|
||||||
|
|
||||||
@@ -122,7 +129,8 @@ class Person(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def latest_events(self):
|
def latest_events(self):
|
||||||
return self.event_set.order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
return self.event_set.order_by(
|
||||||
|
'-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})
|
||||||
@@ -155,7 +163,8 @@ class Organisation(models.Model, RevisionMixin):
|
|||||||
@property
|
@property
|
||||||
def persons(self):
|
def persons(self):
|
||||||
p = []
|
p = []
|
||||||
for e in Event.objects.filter(organisation=self).select_related('person'):
|
for e in Event.objects.filter(
|
||||||
|
organisation=self).select_related('person'):
|
||||||
if e.person:
|
if e.person:
|
||||||
p.append(e.person)
|
p.append(e.person)
|
||||||
|
|
||||||
@@ -166,7 +175,8 @@ class Organisation(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def latest_events(self):
|
def latest_events(self):
|
||||||
return self.event_set.order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
return self.event_set.order_by(
|
||||||
|
'-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})
|
||||||
@@ -179,7 +189,7 @@ class Organisation(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
class VatManager(models.Manager):
|
class VatManager(models.Manager):
|
||||||
def current_rate(self):
|
def current_rate(self):
|
||||||
return self.find_rate(timezone.now())
|
return self.find_rate(datetime.datetime.now())
|
||||||
|
|
||||||
def find_rate(self, date):
|
def find_rate(self, date):
|
||||||
# return self.filter(startAt__lte=date).latest()
|
# return self.filter(startAt__lte=date).latest()
|
||||||
@@ -194,7 +204,7 @@ class VatManager(models.Manager):
|
|||||||
@reversion.register
|
@reversion.register
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class VatRate(models.Model, RevisionMixin):
|
class VatRate(models.Model, RevisionMixin):
|
||||||
start_at = models.DateField()
|
start_at = models.DateTimeField()
|
||||||
rate = models.DecimalField(max_digits=6, decimal_places=6)
|
rate = models.DecimalField(max_digits=6, decimal_places=6)
|
||||||
comment = models.CharField(max_length=255)
|
comment = models.CharField(max_length=255)
|
||||||
|
|
||||||
@@ -209,7 +219,8 @@ class VatRate(models.Model, RevisionMixin):
|
|||||||
get_latest_by = 'start_at'
|
get_latest_by = 'start_at'
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.comment + " " + str(self.start_at) + " @ " + str(self.as_percent) + "%"
|
return self.comment + " " + \
|
||||||
|
str(self.start_at) + " @ " + str(self.as_percent) + "%"
|
||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
@@ -231,7 +242,8 @@ class Venue(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def latest_events(self):
|
def latest_events(self):
|
||||||
return self.event_set.order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
return self.event_set.order_by(
|
||||||
|
'-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})
|
||||||
@@ -245,26 +257,43 @@ 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=timezone.now().date(), end_date__isnull=True, dry_hire=False) & ~models.Q(status=Event.CANCELLED)) | # Starts after with no end
|
(models.Q(start_date__gte=datetime.date.today(), end_date__isnull=True, dry_hire=False) & ~models.Q(
|
||||||
(models.Q(end_date__gte=timezone.now().date(), dry_hire=False) & ~models.Q(status=Event.CANCELLED)) | # Ends after
|
status=Event.CANCELLED)) | # Starts after with no end
|
||||||
(models.Q(dry_hire=True, start_date__gte=timezone.now().date()) & ~models.Q(status=Event.CANCELLED)) | # Active dry hire
|
(models.Q(end_date__gte=datetime.date.today(), dry_hire=False) & ~models.Q(
|
||||||
(models.Q(dry_hire=True, checked_in_by__isnull=True) & (models.Q(status=Event.BOOKED) | models.Q(status=Event.CONFIRMED))) | # Active dry hire GT
|
status=Event.CANCELLED)) | # Ends after
|
||||||
models.Q(status=Event.CANCELLED, start_date__gte=timezone.now().date()) # Canceled but not started
|
(models.Q(dry_hire=True, start_date__gte=datetime.date.today()) & ~models.Q(
|
||||||
).order_by('start_date', 'end_date', 'start_time', 'end_time', 'meet_at').select_related('person', 'organisation', 'venue', 'mic')
|
status=Event.CANCELLED)) | # Active dry hire
|
||||||
|
(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(
|
||||||
(models.Q(start_date__gte=start.date(), start_date__lte=end.date())) | # Start date in bounds
|
# Start date in bounds
|
||||||
(models.Q(end_date__gte=start.date(), end_date__lte=end.date())) | # End date in bounds
|
(models.Q(start_date__gte=start.date(), start_date__lte=end.date())) |
|
||||||
(models.Q(access_at__gte=start, access_at__lte=end)) | # Access at in bounds
|
# End date in bounds
|
||||||
|
(models.Q(end_date__gte=start.date(), end_date__lte=end.date())) |
|
||||||
|
# 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
|
(models.Q(meet_at__gte=start, meet_at__lte=end)) | # Meet at in bounds
|
||||||
|
|
||||||
(models.Q(start_date__lte=start, end_date__gte=end)) | # Start before, end after
|
# Start before, end after
|
||||||
(models.Q(access_at__lte=start, start_date__gte=end)) | # Access before, start after
|
(models.Q(start_date__lte=start, end_date__gte=end)) |
|
||||||
(models.Q(access_at__lte=start, end_date__gte=end)) | # Access before, end after
|
# Access before, start after
|
||||||
(models.Q(meet_at__lte=start, start_date__gte=end)) | # Meet before, start after
|
(models.Q(access_at__lte=start, start_date__gte=end)) |
|
||||||
(models.Q(meet_at__lte=start, end_date__gte=end)) # Meet before, end after
|
# Access 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',
|
'organisation',
|
||||||
@@ -273,12 +302,12 @@ class EventManager(models.Manager):
|
|||||||
|
|
||||||
def rig_count(self):
|
def rig_count(self):
|
||||||
event_count = self.filter(
|
event_count = self.filter(
|
||||||
(models.Q(start_date__gte=timezone.now().date(), end_date__isnull=True, dry_hire=False,
|
(models.Q(start_date__gte=datetime.date.today(), end_date__isnull=True, dry_hire=False,
|
||||||
is_rig=True) & ~models.Q(
|
is_rig=True) & ~models.Q(
|
||||||
status=Event.CANCELLED)) | # Starts after with no end
|
status=Event.CANCELLED)) | # Starts after with no end
|
||||||
(models.Q(end_date__gte=timezone.now().date(), dry_hire=False, is_rig=True) & ~models.Q(
|
(models.Q(end_date__gte=datetime.date.today(), dry_hire=False, is_rig=True) & ~models.Q(
|
||||||
status=Event.CANCELLED)) | # Ends after
|
status=Event.CANCELLED)) | # Ends after
|
||||||
(models.Q(dry_hire=True, start_date__gte=timezone.now().date(), is_rig=True) & ~models.Q(
|
(models.Q(dry_hire=True, start_date__gte=datetime.date.today(), is_rig=True) & ~models.Q(
|
||||||
status=Event.CANCELLED)) | # Active dry hire
|
status=Event.CANCELLED)) | # Active dry hire
|
||||||
(models.Q(dry_hire=True, checked_in_by__isnull=True, is_rig=True) & (
|
(models.Q(dry_hire=True, checked_in_by__isnull=True, is_rig=True) & (
|
||||||
models.Q(status=Event.BOOKED) | models.Q(status=Event.CONFIRMED))) # Active dry hire GT
|
models.Q(status=Event.BOOKED) | models.Q(status=Event.CONFIRMED))) # Active dry hire GT
|
||||||
@@ -302,12 +331,14 @@ class Event(models.Model, RevisionMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
person = models.ForeignKey('Person', null=True, blank=True, on_delete=models.CASCADE)
|
person = models.ForeignKey('Person', null=True, blank=True)
|
||||||
organisation = models.ForeignKey('Organisation', blank=True, null=True, on_delete=models.CASCADE)
|
organisation = models.ForeignKey('Organisation', blank=True, null=True)
|
||||||
venue = models.ForeignKey('Venue', blank=True, null=True, on_delete=models.CASCADE)
|
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(choices=EVENT_STATUS_CHOICES, default=PROVISIONAL)
|
status = models.IntegerField(
|
||||||
|
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,
|
||||||
@@ -323,23 +354,27 @@ 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(settings.AUTH_USER_MODEL, related_name='event_checked_in', blank=True, null=True, on_delete=models.CASCADE)
|
checked_in_by = models.ForeignKey(
|
||||||
|
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", on_delete=models.CASCADE)
|
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(max_length=255, blank=True, null=True, verbose_name='PO')
|
purchase_order = models.CharField(
|
||||||
collector = models.CharField(max_length=255, blank=True, null=True, verbose_name='collected by')
|
max_length=255,
|
||||||
|
blank=True,
|
||||||
# Authorisation request details
|
null=True,
|
||||||
auth_request_by = models.ForeignKey('Profile', null=True, blank=True, on_delete=models.CASCADE)
|
verbose_name='PO')
|
||||||
auth_request_at = models.DateTimeField(null=True, blank=True)
|
collector = models.CharField(
|
||||||
auth_request_to = models.EmailField(null=True, blank=True)
|
max_length=255,
|
||||||
|
blank=True,
|
||||||
# Risk assessment info
|
null=True,
|
||||||
risk_assessment_edit_url = models.CharField(max_length=255, blank=True, null=True)
|
verbose_name='collected by')
|
||||||
|
|
||||||
# Calculated values
|
# Calculated values
|
||||||
"""
|
"""
|
||||||
@@ -373,7 +408,7 @@ class Event(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def vat(self):
|
def vat(self):
|
||||||
return Decimal(self.sum_total * self.vat_rate.rate).quantize(Decimal('.01'))
|
return self.sum_total * self.vat_rate.rate
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Inc VAT
|
Inc VAT
|
||||||
@@ -381,7 +416,7 @@ class Event(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def total(self):
|
def total(self):
|
||||||
return Decimal(self.sum_total + self.vat).quantize(Decimal('.01'))
|
return self.sum_total + self.vat
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cancelled(self):
|
def cancelled(self):
|
||||||
@@ -391,10 +426,6 @@ class Event(models.Model, RevisionMixin):
|
|||||||
def confirmed(self):
|
def confirmed(self):
|
||||||
return (self.status == self.BOOKED or self.status == self.CONFIRMED)
|
return (self.status == self.BOOKED or self.status == self.CONFIRMED)
|
||||||
|
|
||||||
@property
|
|
||||||
def authorised(self):
|
|
||||||
return not self.internal and self.purchase_order or self.authorisation.amount == self.total
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def has_start_time(self):
|
def has_start_time(self):
|
||||||
return self.start_time is not None
|
return self.start_time is not None
|
||||||
@@ -419,9 +450,11 @@ 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(self.start_date, self.start_time)
|
startDateTime = datetime.datetime.combine(
|
||||||
|
self.start_date, self.start_time)
|
||||||
else:
|
else:
|
||||||
startDateTime = datetime.datetime.combine(self.start_date, datetime.time(00, 00))
|
startDateTime = datetime.datetime.combine(
|
||||||
|
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
|
||||||
@@ -429,7 +462,8 @@ class Event(models.Model, RevisionMixin):
|
|||||||
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
|
||||||
|
|
||||||
earliest = min(datetime_list).astimezone(tz) # find the earliest datetime in the list
|
# 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:
|
||||||
@@ -455,26 +489,24 @@ class Event(models.Model, RevisionMixin):
|
|||||||
else:
|
else:
|
||||||
return endDate
|
return endDate
|
||||||
|
|
||||||
@property
|
|
||||||
def internal(self):
|
|
||||||
return self.organisation and self.organisation.union_account
|
|
||||||
|
|
||||||
objects = EventManager()
|
objects = EventManager()
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse_lazy('event_detail', kwargs={'pk': self.pk})
|
return reverse_lazy('event_detail', kwargs={'pk': self.pk})
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.pk) + ": " + self.name
|
return unicode(self.pk) + ": " + self.name
|
||||||
|
|
||||||
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('Unless you\'ve invented time travel, the event can\'t finish before it has started.')
|
raise ValidationError(
|
||||||
|
'Unless you\'ve invented time travel, the event can\'t finish before it has started.')
|
||||||
|
|
||||||
startEndSameDay = not self.end_date or self.end_date == self.start_date
|
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('Unless you\'ve invented time travel, the event can\'t finish before it has started.')
|
raise ValidationError(
|
||||||
|
'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."""
|
||||||
@@ -488,7 +520,7 @@ class Event(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
|
|
||||||
class EventItem(models.Model):
|
class EventItem(models.Model):
|
||||||
event = models.ForeignKey('Event', related_name='items', blank=True, on_delete=models.CASCADE)
|
event = models.ForeignKey('Event', related_name='items', blank=True)
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
description = models.TextField(blank=True, null=True)
|
description = models.TextField(blank=True, null=True)
|
||||||
quantity = models.IntegerField()
|
quantity = models.IntegerField()
|
||||||
@@ -503,39 +535,22 @@ class EventItem(models.Model):
|
|||||||
ordering = ['order']
|
ordering = ['order']
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.event.pk) + "." + str(self.order) + ": " + self.event.name + " | " + self.name
|
return str(self.event.pk) + "." + str(self.order) + \
|
||||||
|
": " + self.event.name + " | " + self.name
|
||||||
|
|
||||||
|
|
||||||
class EventCrew(models.Model):
|
class EventCrew(models.Model):
|
||||||
event = models.ForeignKey('Event', related_name='crew', on_delete=models.CASCADE)
|
event = models.ForeignKey('Event', related_name='crew')
|
||||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
user = models.ForeignKey(settings.AUTH_USER_MODEL)
|
||||||
rig = models.BooleanField(default=False)
|
rig = models.BooleanField(default=False)
|
||||||
run = models.BooleanField(default=False)
|
run = models.BooleanField(default=False)
|
||||||
derig = models.BooleanField(default=False)
|
derig = models.BooleanField(default=False)
|
||||||
notes = models.TextField(blank=True, null=True)
|
notes = models.TextField(blank=True, null=True)
|
||||||
|
|
||||||
|
|
||||||
@reversion.register
|
|
||||||
class EventAuthorisation(models.Model, RevisionMixin):
|
|
||||||
event = models.OneToOneField('Event', related_name='authorisation', on_delete=models.CASCADE)
|
|
||||||
email = models.EmailField()
|
|
||||||
name = models.CharField(max_length=255)
|
|
||||||
uni_id = models.CharField(max_length=10, blank=True, null=True, verbose_name="University ID")
|
|
||||||
account_code = models.CharField(max_length=50, blank=True, null=True)
|
|
||||||
amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="authorisation amount")
|
|
||||||
sent_by = models.ForeignKey('RIGS.Profile', on_delete=models.CASCADE)
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
|
||||||
return reverse_lazy('event_detail', kwargs={'pk': self.event.pk})
|
|
||||||
|
|
||||||
@property
|
|
||||||
def activity_feed_string(self):
|
|
||||||
return str("N%05d" % self.event.pk + ' (requested by ' + self.sent_by.initials + ')')
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class Invoice(models.Model):
|
class Invoice(models.Model):
|
||||||
event = models.OneToOneField('Event', on_delete=models.CASCADE)
|
event = models.OneToOneField('Event')
|
||||||
invoice_date = models.DateField(auto_now_add=True)
|
invoice_date = models.DateField(auto_now_add=True)
|
||||||
void = models.BooleanField(default=False)
|
void = models.BooleanField(default=False)
|
||||||
|
|
||||||
@@ -587,10 +602,17 @@ class Payment(models.Model):
|
|||||||
(ADJUSTMENT, 'TEC Adjustment'),
|
(ADJUSTMENT, 'TEC Adjustment'),
|
||||||
)
|
)
|
||||||
|
|
||||||
invoice = models.ForeignKey('Invoice', on_delete=models.CASCADE)
|
invoice = models.ForeignKey('Invoice')
|
||||||
date = models.DateField()
|
date = models.DateField()
|
||||||
amount = models.DecimalField(max_digits=10, decimal_places=2, help_text='Please use ex. VAT')
|
amount = models.DecimalField(
|
||||||
method = models.CharField(max_length=2, choices=METHODS, null=True, blank=True)
|
max_digits=10,
|
||||||
|
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,6 +1,4 @@
|
|||||||
from RIGS.models import Profile
|
|
||||||
from RIGS.forms import ProfileRegistrationFormUniqueEmail
|
from RIGS.forms import ProfileRegistrationFormUniqueEmail
|
||||||
from registration.signals import user_registered
|
|
||||||
|
|
||||||
|
|
||||||
def user_created(sender, user, request, **kwargs):
|
def user_created(sender, user, request, **kwargs):
|
||||||
@@ -12,4 +10,6 @@ def user_created(sender, user, request, **kwargs):
|
|||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
|
|
||||||
|
from registration.signals import user_registered
|
||||||
|
|
||||||
user_registered.connect(user_created)
|
user_registered.connect(user_created)
|
||||||
|
|||||||
338
RIGS/rigboard.py
@@ -1,34 +1,23 @@
|
|||||||
|
import cStringIO as StringIO
|
||||||
|
import copy
|
||||||
|
import datetime
|
||||||
|
import re
|
||||||
|
import urllib2
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import urllib.request
|
|
||||||
import urllib.error
|
|
||||||
import urllib.parse
|
|
||||||
|
|
||||||
from django.contrib.staticfiles.storage import staticfiles_storage
|
from PyPDF2 import PdfFileMerger, PdfFileReader
|
||||||
from django.core.mail import EmailMessage, EmailMultiAlternatives
|
from django.conf import settings
|
||||||
from django.views import generic
|
from django.contrib import messages
|
||||||
from django.urls 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.conf import settings
|
from django.views import generic
|
||||||
from django.urls import reverse
|
|
||||||
from django.core import signing
|
|
||||||
from django.http import HttpResponse
|
|
||||||
from django.core.exceptions import SuspiciousOperation
|
|
||||||
from django.db.models import Q
|
|
||||||
from django.contrib import messages
|
|
||||||
from django.utils.decorators import method_decorator
|
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
|
||||||
from z3c.rml import rml2pdf
|
from z3c.rml import rml2pdf
|
||||||
from PyPDF2 import PdfFileMerger, PdfFileReader
|
|
||||||
import simplejson
|
|
||||||
import premailer
|
|
||||||
|
|
||||||
from RIGS import models, forms
|
from RIGS import models, forms
|
||||||
from PyRIGS import decorators
|
|
||||||
import datetime
|
|
||||||
import re
|
|
||||||
import copy
|
|
||||||
|
|
||||||
__author__ = 'ghost'
|
__author__ = 'ghost'
|
||||||
|
|
||||||
@@ -59,46 +48,6 @@ class EventDetail(generic.DetailView):
|
|||||||
model = models.Event
|
model = models.Event
|
||||||
|
|
||||||
|
|
||||||
class EventOembed(generic.View):
|
|
||||||
model = models.Event
|
|
||||||
|
|
||||||
def get(self, request, pk=None):
|
|
||||||
embed_url = reverse('event_embed', args=[pk])
|
|
||||||
full_url = "{0}://{1}{2}".format(request.scheme, request.META['HTTP_HOST'], embed_url)
|
|
||||||
|
|
||||||
data = {
|
|
||||||
'html': '<iframe src="{0}" frameborder="0" width="100%" height="250"></iframe>'.format(full_url),
|
|
||||||
'version': '1.0',
|
|
||||||
'type': 'rich',
|
|
||||||
'height': '250'
|
|
||||||
}
|
|
||||||
|
|
||||||
json = simplejson.JSONEncoderForHTML().encode(data)
|
|
||||||
return HttpResponse(json, content_type="application/json")
|
|
||||||
|
|
||||||
|
|
||||||
class EventEmbed(EventDetail):
|
|
||||||
template_name = 'RIGS/event_embed.html'
|
|
||||||
|
|
||||||
|
|
||||||
class EventRA(generic.base.RedirectView):
|
|
||||||
permanent = False
|
|
||||||
def get_redirect_url(self, *args, **kwargs):
|
|
||||||
event = get_object_or_404(models.Event, pk=kwargs['pk'])
|
|
||||||
|
|
||||||
if event.risk_assessment_edit_url:
|
|
||||||
return event.risk_assessment_edit_url
|
|
||||||
|
|
||||||
params = {
|
|
||||||
'entry.708610078': f'N{event.pk:05}',
|
|
||||||
'entry.905899507': event.name,
|
|
||||||
'entry.139491562': event.venue.name if event.venue else '',
|
|
||||||
'entry.1689826056': event.start_date.strftime('%Y-%m-%d') + ((' - ' + event.end_date.strftime('%Y-%m-%d')) if event.end_date else ''),
|
|
||||||
'entry.902421165': event.mic.name if event.mic else ''
|
|
||||||
}
|
|
||||||
return settings.RISK_ASSESSMENT_URL + "?" + urllib.parse.urlencode(params)
|
|
||||||
|
|
||||||
|
|
||||||
class EventCreate(generic.CreateView):
|
class EventCreate(generic.CreateView):
|
||||||
model = models.Event
|
model = models.Event
|
||||||
form_class = forms.EventForm
|
form_class = forms.EventForm
|
||||||
@@ -110,10 +59,13 @@ 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(self.request, "Your item changes have been saved. Please fix the errors and save the event.")
|
messages.info(
|
||||||
|
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 errors but also nice and quick.
|
# Get some other objects to include in the form. Used when there are
|
||||||
for field, model in form.related_models.items():
|
# errors but also nice and quick.
|
||||||
|
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 != '':
|
||||||
context[field] = model.objects.get(pk=value)
|
context[field] = model.objects.get(pk=value)
|
||||||
@@ -133,19 +85,12 @@ class EventUpdate(generic.UpdateView):
|
|||||||
|
|
||||||
form = context['form']
|
form = context['form']
|
||||||
|
|
||||||
# Get some other objects to include in the form. Used when there are errors but also nice and quick.
|
# Get some other objects to include in the form. Used when there are
|
||||||
for field, model in form.related_models.items():
|
# errors but also nice and quick.
|
||||||
|
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 != '':
|
||||||
context[field] = model.objects.get(pk=value)
|
context[field] = model.objects.get(pk=value)
|
||||||
|
|
||||||
# If this event has already been emailed to a client, show a warning
|
|
||||||
if self.object.auth_request_at is not None:
|
|
||||||
messages.info(self.request, 'This event has already been sent to the client for authorisation, any changes you make will be visible to them immediately.')
|
|
||||||
|
|
||||||
if hasattr(self.object, 'authorised'):
|
|
||||||
messages.warning(self.request, 'This event has already been authorised by client, any changes to price will require reauthorisation.')
|
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
@@ -154,25 +99,18 @@ class EventUpdate(generic.UpdateView):
|
|||||||
|
|
||||||
class EventDuplicate(EventUpdate):
|
class EventDuplicate(EventUpdate):
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
old = super(EventDuplicate, self).get_object(queryset) # Get the object (the event you're duplicating)
|
# 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
|
||||||
new.purchase_order = None # Remove old PO
|
|
||||||
|
|
||||||
# Clear checked in by if it's a dry hire
|
|
||||||
if new.dry_hire is True:
|
|
||||||
new.checked_in_by = None
|
|
||||||
|
|
||||||
# Remove all the authorisation information from the new event
|
|
||||||
new.auth_request_to = None
|
|
||||||
new.auth_request_by = None
|
|
||||||
new.auth_request_at = None
|
|
||||||
|
|
||||||
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
|
||||||
else:
|
|
||||||
messages.info(self.request, 'Event data duplicated but not yet saved. Click save to complete operation.')
|
messages.info(
|
||||||
|
self.request,
|
||||||
|
'Event data duplicated but not yet saved. Click save to complete operation.')
|
||||||
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
@@ -186,29 +124,37 @@ 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)
|
||||||
template = get_template('RIGS/event_print.xml')
|
template = get_template('RIGS/event_print.xml')
|
||||||
|
copies = ('TEC', 'Client')
|
||||||
|
|
||||||
merger = PdfFileMerger()
|
merger = PdfFileMerger()
|
||||||
|
|
||||||
context = {
|
for copy in copies:
|
||||||
'object': object,
|
context = RequestContext(request, { # this should be outside the loop, but bug in 1.8.2 prevents this
|
||||||
'fonts': {
|
'object': object,
|
||||||
'opensans': {
|
'fonts': {
|
||||||
'regular': 'RIGS/static/fonts/OPENSANS-REGULAR.TTF',
|
'opensans': {
|
||||||
'bold': 'RIGS/static/fonts/OPENSANS-BOLD.TTF',
|
'regular': 'RIGS/static/fonts/OPENSANS-REGULAR.TTF',
|
||||||
}
|
'bold': 'RIGS/static/fonts/OPENSANS-BOLD.TTF',
|
||||||
},
|
}
|
||||||
'quote': True,
|
},
|
||||||
'current_user': request.user,
|
'copy': copy,
|
||||||
}
|
'current_user': request.user,
|
||||||
|
})
|
||||||
|
|
||||||
rml = template.render(context)
|
# context['copy'] = copy # this is the way to do it once we upgrade
|
||||||
|
# to Django 1.8.3
|
||||||
|
|
||||||
buffer = rml2pdf.parseString(rml)
|
rml = template.render(context)
|
||||||
merger.append(PdfFileReader(buffer))
|
buffer = StringIO.StringIO()
|
||||||
buffer.close()
|
|
||||||
|
|
||||||
terms = urllib.request.urlopen(settings.TERMS_OF_HIRE_URL)
|
buffer = rml2pdf.parseString(rml)
|
||||||
merger.append(BytesIO(terms.read()))
|
|
||||||
|
merger.append(PdfFileReader(buffer))
|
||||||
|
|
||||||
|
buffer.close()
|
||||||
|
|
||||||
|
terms = urllib2.urlopen(settings.TERMS_OF_HIRE_URL)
|
||||||
|
merger.append(StringIO.StringIO(terms.read()))
|
||||||
|
|
||||||
merged = BytesIO()
|
merged = BytesIO()
|
||||||
merger.write(merged)
|
merger.write(merged)
|
||||||
@@ -217,7 +163,8 @@ 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['Content-Disposition'] = "filename=N%05d | %s.pdf" % (object.pk, escapedEventName)
|
response[
|
||||||
|
'Content-Disposition'] = "filename=N%05d | %s.pdf" % (object.pk, escapedEventName)
|
||||||
response.write(merged.getvalue())
|
response.write(merged.getvalue())
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@@ -255,176 +202,9 @@ 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(self.request, messages.WARNING, "No events have been found matching those criteria.")
|
messages.add_message(
|
||||||
|
self.request,
|
||||||
|
messages.WARNING,
|
||||||
|
"No events have been found matching those criteria.")
|
||||||
|
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
||||||
class EventAuthorise(generic.UpdateView):
|
|
||||||
template_name = 'RIGS/eventauthorisation_form.html'
|
|
||||||
success_template = 'RIGS/eventauthorisation_success.html'
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
self.object = form.save()
|
|
||||||
|
|
||||||
self.template_name = self.success_template
|
|
||||||
messages.add_message(self.request, messages.SUCCESS,
|
|
||||||
'Success! Your event has been authorised. ' +
|
|
||||||
'You will also receive email confirmation to %s.' % (self.object.email))
|
|
||||||
return self.render_to_response(self.get_context_data())
|
|
||||||
|
|
||||||
@property
|
|
||||||
def event(self):
|
|
||||||
return models.Event.objects.select_related('organisation', 'person', 'venue').get(pk=self.kwargs['pk'])
|
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
|
||||||
return getattr(self.event, 'authorisation', None)
|
|
||||||
|
|
||||||
def get_form_class(self):
|
|
||||||
return forms.InternalClientEventAuthorisationForm
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(EventAuthorise, self).get_context_data(**kwargs)
|
|
||||||
context['event'] = self.event
|
|
||||||
|
|
||||||
context['tos_url'] = settings.TERMS_OF_HIRE_URL
|
|
||||||
return context
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
if self.get_object() is not None and self.get_object().pk is not None:
|
|
||||||
if self.event.authorised:
|
|
||||||
messages.add_message(self.request, messages.WARNING,
|
|
||||||
"This event has already been authorised. "
|
|
||||||
"Reauthorising is not necessary at this time.")
|
|
||||||
else:
|
|
||||||
messages.add_message(self.request, messages.WARNING,
|
|
||||||
"This event has already been authorised, but the amount has changed. " +
|
|
||||||
"Please check the amount and reauthorise.")
|
|
||||||
return super(EventAuthorise, self).get(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def get_form(self, **kwargs):
|
|
||||||
form = super(EventAuthorise, self).get_form(**kwargs)
|
|
||||||
form.instance.event = self.event
|
|
||||||
form.instance.email = self.request.email
|
|
||||||
form.instance.sent_by = self.request.sent_by
|
|
||||||
return form
|
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
# Verify our signature matches up and all is well with the integrity of the URL
|
|
||||||
try:
|
|
||||||
data = signing.loads(kwargs.get('hmac'))
|
|
||||||
assert int(kwargs.get('pk')) == int(data.get('pk'))
|
|
||||||
request.email = data['email']
|
|
||||||
request.sent_by = models.Profile.objects.get(pk=data['sent_by'])
|
|
||||||
except (signing.BadSignature, AssertionError, KeyError, models.Profile.DoesNotExist):
|
|
||||||
raise SuspiciousOperation(
|
|
||||||
"This URL is invalid. Please ask your TEC contact for a new URL")
|
|
||||||
return super(EventAuthorise, self).dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class EventAuthorisationRequest(generic.FormView, generic.detail.SingleObjectMixin):
|
|
||||||
model = models.Event
|
|
||||||
form_class = forms.EventAuthorisationRequestForm
|
|
||||||
template_name = 'RIGS/eventauthorisation_request.html'
|
|
||||||
|
|
||||||
@method_decorator(decorators.nottinghamtec_address_required)
|
|
||||||
def dispatch(self, *args, **kwargs):
|
|
||||||
return super(EventAuthorisationRequest, self).dispatch(*args, **kwargs)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def object(self):
|
|
||||||
return self.get_object()
|
|
||||||
|
|
||||||
def get_success_url(self):
|
|
||||||
if self.request.is_ajax():
|
|
||||||
url = reverse_lazy('closemodal')
|
|
||||||
messages.info(self.request, "location.reload()")
|
|
||||||
else:
|
|
||||||
url = reverse_lazy('event_detail', kwargs={
|
|
||||||
'pk': self.object.pk,
|
|
||||||
})
|
|
||||||
messages.add_message(self.request, messages.SUCCESS, "Authorisation request successfully sent.")
|
|
||||||
return url
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
email = form.cleaned_data['email']
|
|
||||||
event = self.object
|
|
||||||
event.auth_request_by = self.request.user
|
|
||||||
event.auth_request_at = datetime.datetime.now()
|
|
||||||
event.auth_request_to = email
|
|
||||||
event.save()
|
|
||||||
|
|
||||||
context = {
|
|
||||||
'object': self.object,
|
|
||||||
'request': self.request,
|
|
||||||
'hmac': signing.dumps({
|
|
||||||
'pk': self.object.pk,
|
|
||||||
'email': email,
|
|
||||||
'sent_by': self.request.user.pk,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
if event.person is not None and email == event.person.email:
|
|
||||||
context['to_name'] = event.person.name
|
|
||||||
elif event.organisation is not None and email == event.organisation.email:
|
|
||||||
context['to_name'] = event.organisation.name
|
|
||||||
|
|
||||||
msg = EmailMultiAlternatives(
|
|
||||||
"N%05d | %s - Event Authorisation Request" % (self.object.pk, self.object.name),
|
|
||||||
get_template("RIGS/eventauthorisation_client_request.txt").render(context),
|
|
||||||
to=[email],
|
|
||||||
reply_to=[self.request.user.email],
|
|
||||||
)
|
|
||||||
css = staticfiles_storage.path('css/email.css')
|
|
||||||
html = premailer.Premailer(get_template("RIGS/eventauthorisation_client_request.html").render(context),
|
|
||||||
external_styles=css).transform()
|
|
||||||
msg.attach_alternative(html, 'text/html')
|
|
||||||
|
|
||||||
msg.send()
|
|
||||||
|
|
||||||
return super(EventAuthorisationRequest, self).form_valid(form)
|
|
||||||
|
|
||||||
|
|
||||||
class EventAuthoriseRequestEmailPreview(generic.DetailView):
|
|
||||||
template_name = "RIGS/eventauthorisation_client_request.html"
|
|
||||||
model = models.Event
|
|
||||||
|
|
||||||
def render_to_response(self, context, **response_kwargs):
|
|
||||||
from django.contrib.staticfiles.storage import staticfiles_storage
|
|
||||||
css = staticfiles_storage.path('css/email.css')
|
|
||||||
response = super(EventAuthoriseRequestEmailPreview, self).render_to_response(context, **response_kwargs)
|
|
||||||
assert isinstance(response, HttpResponse)
|
|
||||||
response.content = premailer.Premailer(response.rendered_content, external_styles=css).transform()
|
|
||||||
return response
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
|
||||||
context = super(EventAuthoriseRequestEmailPreview, self).get_context_data(**kwargs)
|
|
||||||
context['hmac'] = signing.dumps({
|
|
||||||
'pk': self.object.pk,
|
|
||||||
'email': self.request.GET.get('email', 'hello@world.test'),
|
|
||||||
'sent_by': self.request.user.pk,
|
|
||||||
})
|
|
||||||
context['to_name'] = self.request.GET.get('to_name', None)
|
|
||||||
return context
|
|
||||||
|
|
||||||
@method_decorator(csrf_exempt, name='dispatch')
|
|
||||||
class LogRiskAssessment(generic.View):
|
|
||||||
http_method_names = ["post"]
|
|
||||||
|
|
||||||
def post(self, request, **kwargs):
|
|
||||||
data = request.POST
|
|
||||||
shared_secret = data.get("secret")
|
|
||||||
edit_url = data.get("editUrl")
|
|
||||||
rig_number = data.get("rigNum")
|
|
||||||
if shared_secret is None or edit_url is None or rig_number is None:
|
|
||||||
return HttpResponse(status=422)
|
|
||||||
|
|
||||||
if shared_secret != settings.RISK_ASSESSMENT_SECRET:
|
|
||||||
return HttpResponse(status=403)
|
|
||||||
|
|
||||||
rig_number = int(re.sub("[^0-9]", "", rig_number))
|
|
||||||
|
|
||||||
event = get_object_or_404(models.Event, pk=rig_number)
|
|
||||||
event.risk_assessment_edit_url = edit_url
|
|
||||||
event.save()
|
|
||||||
|
|
||||||
return HttpResponse(status=200)
|
|
||||||
|
|||||||
104
RIGS/signals.py
@@ -1,104 +0,0 @@
|
|||||||
import re
|
|
||||||
import urllib.request
|
|
||||||
import urllib.error
|
|
||||||
import urllib.parse
|
|
||||||
from io import BytesIO
|
|
||||||
|
|
||||||
from django.db.models.signals import post_save
|
|
||||||
from PyPDF2 import PdfFileReader, PdfFileMerger
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib.staticfiles.storage import staticfiles_storage
|
|
||||||
from django.core.mail import EmailMessage, EmailMultiAlternatives
|
|
||||||
from django.template.loader import get_template
|
|
||||||
from premailer import Premailer
|
|
||||||
from z3c.rml import rml2pdf
|
|
||||||
|
|
||||||
from RIGS import models
|
|
||||||
|
|
||||||
|
|
||||||
def send_eventauthorisation_success_email(instance):
|
|
||||||
# Generate PDF first to prevent context conflicts
|
|
||||||
context = {
|
|
||||||
'object': instance.event,
|
|
||||||
'fonts': {
|
|
||||||
'opensans': {
|
|
||||||
'regular': 'RIGS/static/fonts/OPENSANS-REGULAR.TTF',
|
|
||||||
'bold': 'RIGS/static/fonts/OPENSANS-BOLD.TTF',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'receipt': True,
|
|
||||||
'current_user': False,
|
|
||||||
}
|
|
||||||
|
|
||||||
template = get_template('RIGS/event_print.xml')
|
|
||||||
merger = PdfFileMerger()
|
|
||||||
|
|
||||||
rml = template.render(context)
|
|
||||||
|
|
||||||
buffer = rml2pdf.parseString(rml)
|
|
||||||
merger.append(PdfFileReader(buffer))
|
|
||||||
buffer.close()
|
|
||||||
|
|
||||||
terms = urllib.request.urlopen(settings.TERMS_OF_HIRE_URL)
|
|
||||||
merger.append(BytesIO(terms.read()))
|
|
||||||
|
|
||||||
merged = BytesIO()
|
|
||||||
merger.write(merged)
|
|
||||||
|
|
||||||
# Produce email content
|
|
||||||
context = {
|
|
||||||
'object': instance,
|
|
||||||
}
|
|
||||||
|
|
||||||
if instance.event.person is not None and instance.email == instance.event.person.email:
|
|
||||||
context['to_name'] = instance.event.person.name
|
|
||||||
elif instance.event.organisation is not None and instance.email == instance.event.organisation.email:
|
|
||||||
context['to_name'] = instance.event.organisation.name
|
|
||||||
|
|
||||||
subject = "N%05d | %s - Event Authorised" % (instance.event.pk, instance.event.name)
|
|
||||||
|
|
||||||
client_email = EmailMultiAlternatives(
|
|
||||||
subject,
|
|
||||||
get_template("RIGS/eventauthorisation_client_success.txt").render(context),
|
|
||||||
to=[instance.email],
|
|
||||||
reply_to=[settings.AUTHORISATION_NOTIFICATION_ADDRESS],
|
|
||||||
)
|
|
||||||
|
|
||||||
css = staticfiles_storage.path('css/email.css')
|
|
||||||
html = Premailer(get_template("RIGS/eventauthorisation_client_success.html").render(context),
|
|
||||||
external_styles=css).transform()
|
|
||||||
client_email.attach_alternative(html, 'text/html')
|
|
||||||
|
|
||||||
escapedEventName = re.sub('[^a-zA-Z0-9 \n\.]', '', instance.event.name)
|
|
||||||
|
|
||||||
client_email.attach('N%05d - %s - CONFIRMATION.pdf' % (instance.event.pk, escapedEventName),
|
|
||||||
merged.getvalue(),
|
|
||||||
'application/pdf'
|
|
||||||
)
|
|
||||||
|
|
||||||
if instance.event.mic:
|
|
||||||
mic_email_address = instance.event.mic.email
|
|
||||||
else:
|
|
||||||
mic_email_address = settings.AUTHORISATION_NOTIFICATION_ADDRESS
|
|
||||||
|
|
||||||
mic_email = EmailMessage(
|
|
||||||
subject,
|
|
||||||
get_template("RIGS/eventauthorisation_mic_success.txt").render(context),
|
|
||||||
to=[mic_email_address]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Now we have both emails successfully generated, send them out
|
|
||||||
client_email.send(fail_silently=True)
|
|
||||||
mic_email.send(fail_silently=True)
|
|
||||||
|
|
||||||
# Set event to booked now that it's authorised
|
|
||||||
instance.event.status = models.Event.BOOKED
|
|
||||||
instance.event.save()
|
|
||||||
|
|
||||||
|
|
||||||
def on_revision_commit(sender, instance, created, **kwargs):
|
|
||||||
if created:
|
|
||||||
send_eventauthorisation_success_email(instance)
|
|
||||||
|
|
||||||
|
|
||||||
post_save.connect(on_revision_commit, sender=models.EventAuthorisation)
|
|
||||||
12
RIGS/static/css/bootstrap-select.min.css
vendored
Executable file → Normal file
@@ -1 +0,0 @@
|
|||||||
body{margin:0px}.main-table{width:100%;border-collapse:collapse}.client-header{background-image:url("https://www.nottinghamtec.co.uk/imgs/wof2014-1.jpg");background-color:#222;background-repeat:no-repeat;background-position:center;width:100%;margin-bottom:28px}.client-header .logos{width:100%;max-width:640px}.client-header img{height:110px}.content-container{width:100%}.content-container .content{font-family:"Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;width:100%;max-width:600px;padding:10px;text-align:left}.content-container .content .button-container{width:100%}.content-container .content .button-container .button{padding:6px 12px;background-color:#357ebf;border-radius:4px}.content-container .content .button-container .button a{color:#fff;text-decoration:none}
|
|
||||||
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 4.8 KiB |
12
RIGS/static/js/affix.js
Executable file → Normal file
@@ -1,8 +1,8 @@
|
|||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
* Bootstrap: affix.js v3.3.7
|
* Bootstrap: affix.js v3.3.2
|
||||||
* http://getbootstrap.com/javascript/#affix
|
* http://getbootstrap.com/javascript/#affix
|
||||||
* ========================================================================
|
* ========================================================================
|
||||||
* Copyright 2011-2016 Twitter, Inc.
|
* Copyright 2011-2015 Twitter, Inc.
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
* ======================================================================== */
|
* ======================================================================== */
|
||||||
|
|
||||||
@@ -21,14 +21,14 @@
|
|||||||
.on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
|
.on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
|
||||||
|
|
||||||
this.$element = $(element)
|
this.$element = $(element)
|
||||||
this.affixed = null
|
this.affixed =
|
||||||
this.unpin = null
|
this.unpin =
|
||||||
this.pinnedOffset = null
|
this.pinnedOffset = null
|
||||||
|
|
||||||
this.checkPosition()
|
this.checkPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
Affix.VERSION = '3.3.7'
|
Affix.VERSION = '3.3.2'
|
||||||
|
|
||||||
Affix.RESET = 'affix affix-top affix-bottom'
|
Affix.RESET = 'affix affix-top affix-bottom'
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
var offset = this.options.offset
|
var offset = this.options.offset
|
||||||
var offsetTop = offset.top
|
var offsetTop = offset.top
|
||||||
var offsetBottom = offset.bottom
|
var offsetBottom = offset.bottom
|
||||||
var scrollHeight = Math.max($(document).height(), $(document.body).height())
|
var scrollHeight = $('body').height()
|
||||||
|
|
||||||
if (typeof offset != 'object') offsetBottom = offsetTop = offset
|
if (typeof offset != 'object') offsetBottom = offsetTop = offset
|
||||||
if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
|
if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
|
||||||
|
|||||||
84
RIGS/static/js/ajax-bootstrap-select.js
Normal file → Executable file
@@ -3,16 +3,16 @@
|
|||||||
*
|
*
|
||||||
* Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON.
|
* Extends existing [Bootstrap Select] implementations by adding the ability to search via AJAX requests as you type. Originally for CROSCON.
|
||||||
*
|
*
|
||||||
* @version 1.4.1
|
* @version 1.3.1
|
||||||
* @author Adam Heim - https://github.com/truckingsim
|
* @author Adam Heim - https://github.com/truckingsim
|
||||||
* @link https://github.com/truckingsim/Ajax-Bootstrap-Select
|
* @link https://github.com/truckingsim/Ajax-Bootstrap-Select
|
||||||
* @copyright 2017 Adam Heim
|
* @copyright 2015 Adam Heim
|
||||||
* @license Released under the MIT license.
|
* @license Released under the MIT license.
|
||||||
*
|
*
|
||||||
* Contributors:
|
* Contributors:
|
||||||
* Mark Carver - https://github.com/markcarver
|
* Mark Carver - https://github.com/markcarver
|
||||||
*
|
*
|
||||||
* Last build: 2017-07-21 1:08:54 PM GMT-0400
|
* Last build: 2015-01-06 8:43:11 PM EST
|
||||||
*/
|
*/
|
||||||
!(function ($, window) {
|
!(function ($, window) {
|
||||||
|
|
||||||
@@ -186,25 +186,10 @@ var AjaxBootstrapSelect = function (element, options) {
|
|||||||
if (dataKeys.length) {
|
if (dataKeys.length) {
|
||||||
// Object containing the data attribute options.
|
// Object containing the data attribute options.
|
||||||
var dataOptions = {};
|
var dataOptions = {};
|
||||||
var flattenedOptions = ['locale'];
|
|
||||||
for (i = 0, l = dataKeys.length; i < l; i++) {
|
for (i = 0, l = dataKeys.length; i < l; i++) {
|
||||||
var name = dataKeys[i].replace(/^abs([A-Z])/, matchToLowerCase).replace(/([A-Z])/g, '-$1').toLowerCase();
|
var name = dataKeys[i].replace(/^abs([A-Z])/, matchToLowerCase).replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||||
var keys = name.split('-');
|
|
||||||
|
|
||||||
// Certain options should be flattened to a single object
|
|
||||||
// and not fully expanded (such as Locale).
|
|
||||||
if (keys[0] && keys.length > 1 && flattenedOptions.indexOf(keys[0]) !== -1) {
|
|
||||||
var newKeys = [keys.shift()];
|
|
||||||
var property = '';
|
|
||||||
// Combine the remaining keys as a single property.
|
|
||||||
for (var ii = 0; ii < keys.length; ii++) {
|
|
||||||
property += (ii === 0 ? keys[ii] : keys[ii].charAt(0).toUpperCase() + keys[ii].slice(1));
|
|
||||||
}
|
|
||||||
newKeys.push(property);
|
|
||||||
keys = newKeys;
|
|
||||||
}
|
|
||||||
this.log(this.LOG_DEBUG, 'Processing data attribute "data-abs-' + name + '":', data[dataKeys[i]]);
|
this.log(this.LOG_DEBUG, 'Processing data attribute "data-abs-' + name + '":', data[dataKeys[i]]);
|
||||||
expandObject(keys, data[dataKeys[i]], dataOptions);
|
expandObject(name.split('-'), data[dataKeys[i]], dataOptions);
|
||||||
}
|
}
|
||||||
this.options = $.extend(true, {}, this.options, dataOptions);
|
this.options = $.extend(true, {}, this.options, dataOptions);
|
||||||
this.log(this.LOG_DEBUG, 'Merged in the data attribute options: ', dataOptions, this.options);
|
this.log(this.LOG_DEBUG, 'Merged in the data attribute options: ', dataOptions, this.options);
|
||||||
@@ -330,12 +315,6 @@ AjaxBootstrapSelect.prototype.init = function () {
|
|||||||
plugin.log(plugin.LOG_DEBUG, 'Key ignored.');
|
plugin.log(plugin.LOG_DEBUG, 'Key ignored.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't process if below minimum query length
|
|
||||||
if (query.length < plugin.options.minLength) {
|
|
||||||
plugin.list.setStatus(plugin.t('statusTooShort'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear out any existing timer.
|
// Clear out any existing timer.
|
||||||
clearTimeout(requestDelayTimer);
|
clearTimeout(requestDelayTimer);
|
||||||
@@ -594,25 +573,8 @@ var AjaxBootstrapSelectList = function (plugin) {
|
|||||||
this.title = null;
|
this.title = null;
|
||||||
this.selectedTextFormat = plugin.selectpicker.options.selectedTextFormat;
|
this.selectedTextFormat = plugin.selectpicker.options.selectedTextFormat;
|
||||||
|
|
||||||
// Save initial options
|
|
||||||
var initial_options = [];
|
|
||||||
plugin.$element.find('option').each(function() {
|
|
||||||
var $option = $(this);
|
|
||||||
var value = $option.attr('value');
|
|
||||||
initial_options.push({
|
|
||||||
value: value,
|
|
||||||
text: $option.text(),
|
|
||||||
'class': $option.attr('class') || '',
|
|
||||||
data: $option.data() || {},
|
|
||||||
preserved: plugin.options.preserveSelected,
|
|
||||||
selected: !!$option.attr('selected')
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.cacheSet(/*query=*/'', initial_options);
|
|
||||||
|
|
||||||
// Preserve selected options.
|
// Preserve selected options.
|
||||||
if (plugin.options.preserveSelected) {
|
if (plugin.options.preserveSelected) {
|
||||||
that.selected = initial_options;
|
|
||||||
plugin.$element.on('change.abs.preserveSelected', function (e) {
|
plugin.$element.on('change.abs.preserveSelected', function (e) {
|
||||||
var $selected = plugin.$element.find(':selected');
|
var $selected = plugin.$element.find(':selected');
|
||||||
that.selected = [];
|
that.selected = [];
|
||||||
@@ -682,7 +644,7 @@ AjaxBootstrapSelectList.prototype.build = function (data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set various properties.
|
// Set various properties.
|
||||||
$option.val(item.value).text(item.text).attr('title', item.text);
|
$option.val(item.value).text(item.text);
|
||||||
if (item['class'].length) {
|
if (item['class'].length) {
|
||||||
$option.attr('class', item['class']);
|
$option.attr('class', item['class']);
|
||||||
}
|
}
|
||||||
@@ -770,13 +732,7 @@ AjaxBootstrapSelectList.prototype.refresh = function (triggerChange) {
|
|||||||
if (!this.plugin.$element.find('option').length && emptyTitle && emptyTitle.length) {
|
if (!this.plugin.$element.find('option').length && emptyTitle && emptyTitle.length) {
|
||||||
this.setTitle(emptyTitle);
|
this.setTitle(emptyTitle);
|
||||||
}
|
}
|
||||||
else if (
|
else if (this.title) {
|
||||||
this.title ||
|
|
||||||
(
|
|
||||||
this.selectedTextFormat !== 'static' &&
|
|
||||||
this.selectedTextFormat !== this.plugin.selectpicker.options.selectedTextFormat
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
this.restoreTitle();
|
this.restoreTitle();
|
||||||
}
|
}
|
||||||
this.plugin.selectpicker.refresh();
|
this.plugin.selectpicker.refresh();
|
||||||
@@ -1268,14 +1224,6 @@ $.fn.ajaxSelectPicker.defaults = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* @member $.fn.ajaxSelectPicker.defaults
|
|
||||||
* @cfg {Number} minLength = 0
|
|
||||||
* @markdown
|
|
||||||
* Invoke a request for empty search values.
|
|
||||||
*/
|
|
||||||
minLength: 0,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @member $.fn.ajaxSelectPicker.defaults
|
* @member $.fn.ajaxSelectPicker.defaults
|
||||||
* @cfg {String} ajaxSearchUrl
|
* @cfg {String} ajaxSearchUrl
|
||||||
@@ -1348,7 +1296,8 @@ $.fn.ajaxSelectPicker.defaults = {
|
|||||||
* 39: "right",
|
* 39: "right",
|
||||||
* 38: "up",
|
* 38: "up",
|
||||||
* 40: "down",
|
* 40: "down",
|
||||||
* 91: "meta"
|
* 91: "meta",
|
||||||
|
* 229: "unknown"
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
@@ -1362,7 +1311,8 @@ $.fn.ajaxSelectPicker.defaults = {
|
|||||||
39: "right",
|
39: "right",
|
||||||
38: "up",
|
38: "up",
|
||||||
40: "down",
|
40: "down",
|
||||||
91: "meta"
|
91: "meta",
|
||||||
|
229: "unknown"
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1456,7 +1406,7 @@ $.fn.ajaxSelectPicker.defaults = {
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
preprocessData: function () { },
|
preprocessData: function(){},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @member $.fn.ajaxSelectPicker.defaults
|
* @member $.fn.ajaxSelectPicker.defaults
|
||||||
@@ -1484,7 +1434,7 @@ $.fn.ajaxSelectPicker.defaults = {
|
|||||||
* @markdown
|
* @markdown
|
||||||
* Process the data returned after this plugin, but before the list is built.
|
* Process the data returned after this plugin, but before the list is built.
|
||||||
*/
|
*/
|
||||||
processData: function () { },
|
processData: function(){},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @member $.fn.ajaxSelectPicker.defaults
|
* @member $.fn.ajaxSelectPicker.defaults
|
||||||
@@ -1597,15 +1547,7 @@ $.fn.ajaxSelectPicker.locale['en-US'] = {
|
|||||||
* @markdown
|
* @markdown
|
||||||
* The text to use in the status container when a request is being initiated.
|
* The text to use in the status container when a request is being initiated.
|
||||||
*/
|
*/
|
||||||
statusSearching: 'Searching...',
|
statusSearching: 'Searching...'
|
||||||
|
|
||||||
/**
|
|
||||||
* @member $.fn.ajaxSelectPicker.locale
|
|
||||||
* @cfg {String} statusToShort = 'Please enter more characters'
|
|
||||||
* @markdown
|
|
||||||
* The text used in the status container when the request returns no results.
|
|
||||||
*/
|
|
||||||
statusTooShort: 'Please enter more characters'
|
|
||||||
};
|
};
|
||||||
$.fn.ajaxSelectPicker.locale.en = $.fn.ajaxSelectPicker.locale['en-US'];
|
$.fn.ajaxSelectPicker.locale.en = $.fn.ajaxSelectPicker.locale['en-US'];
|
||||||
|
|
||||||
|
|||||||
8
RIGS/static/js/alert.js
Executable file → Normal file
@@ -1,8 +1,8 @@
|
|||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
* Bootstrap: alert.js v3.3.7
|
* Bootstrap: alert.js v3.3.2
|
||||||
* http://getbootstrap.com/javascript/#alerts
|
* http://getbootstrap.com/javascript/#alerts
|
||||||
* ========================================================================
|
* ========================================================================
|
||||||
* Copyright 2011-2016 Twitter, Inc.
|
* Copyright 2011-2015 Twitter, Inc.
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
* ======================================================================== */
|
* ======================================================================== */
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
$(el).on('click', dismiss, this.close)
|
$(el).on('click', dismiss, this.close)
|
||||||
}
|
}
|
||||||
|
|
||||||
Alert.VERSION = '3.3.7'
|
Alert.VERSION = '3.3.2'
|
||||||
|
|
||||||
Alert.TRANSITION_DURATION = 150
|
Alert.TRANSITION_DURATION = 150
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
|
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
|
||||||
}
|
}
|
||||||
|
|
||||||
var $parent = $(selector === '#' ? [] : selector)
|
var $parent = $(selector)
|
||||||
|
|
||||||
if (e) e.preventDefault()
|
if (e) e.preventDefault()
|
||||||
|
|
||||||
|
|||||||
@@ -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:''
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (l) {
|
var options = {
|
||||||
for(i = 0; i < l; i++){
|
ajax: {
|
||||||
array.push($.extend(true, data[i], {
|
url: $(this).data('sourceurl'),
|
||||||
text: data[i]['label'],
|
type: 'GET',
|
||||||
value: data[i]['pk'],
|
dataType: 'json',
|
||||||
data:{
|
// Use "{{{q}}}" as a placeholder and Ajax Bootstrap Select will
|
||||||
update_url: data[i]['update'],
|
// automatically replace it with the value of the search query.
|
||||||
subtext:''
|
data: {
|
||||||
}
|
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).change(function(){ //on change, update the edit button href
|
$(this).selectpicker().ajaxSelectPicker(options); //Initiaise selectPicker
|
||||||
// console.log('Selectbox Changed');
|
|
||||||
refreshUpdateHref($(this));
|
|
||||||
});
|
|
||||||
|
|
||||||
refreshUpdateHref($(this)); //Ensure href is correct at the beginning
|
$(this).change(function () { //on change, update the edit button href
|
||||||
|
// console.log('Selectbox Changed');
|
||||||
});
|
refreshUpdateHref($(this));
|
||||||
|
|
||||||
//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']);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
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']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|||||||
1457
RIGS/static/js/bootstrap-select.js
vendored
37
RIGS/static/js/button.js
Executable file → Normal file
@@ -1,8 +1,8 @@
|
|||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
* Bootstrap: button.js v3.3.7
|
* Bootstrap: button.js v3.3.2
|
||||||
* http://getbootstrap.com/javascript/#buttons
|
* http://getbootstrap.com/javascript/#buttons
|
||||||
* ========================================================================
|
* ========================================================================
|
||||||
* Copyright 2011-2016 Twitter, Inc.
|
* Copyright 2011-2015 Twitter, Inc.
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
* ======================================================================== */
|
* ======================================================================== */
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
Button.VERSION = '3.3.7'
|
Button.VERSION = '3.3.2'
|
||||||
|
|
||||||
Button.DEFAULTS = {
|
Button.DEFAULTS = {
|
||||||
loadingText: 'loading...'
|
loadingText: 'loading...'
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
var val = $el.is('input') ? 'val' : 'html'
|
var val = $el.is('input') ? 'val' : 'html'
|
||||||
var data = $el.data()
|
var data = $el.data()
|
||||||
|
|
||||||
state += 'Text'
|
state = state + 'Text'
|
||||||
|
|
||||||
if (data.resetText == null) $el.data('resetText', $el[val]())
|
if (data.resetText == null) $el.data('resetText', $el[val]())
|
||||||
|
|
||||||
@@ -41,10 +41,10 @@
|
|||||||
|
|
||||||
if (state == 'loadingText') {
|
if (state == 'loadingText') {
|
||||||
this.isLoading = true
|
this.isLoading = true
|
||||||
$el.addClass(d).attr(d, d).prop(d, true)
|
$el.addClass(d).attr(d, d)
|
||||||
} else if (this.isLoading) {
|
} else if (this.isLoading) {
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
$el.removeClass(d).removeAttr(d).prop(d, false)
|
$el.removeClass(d).removeAttr(d)
|
||||||
}
|
}
|
||||||
}, this), 0)
|
}, this), 0)
|
||||||
}
|
}
|
||||||
@@ -56,19 +56,15 @@
|
|||||||
if ($parent.length) {
|
if ($parent.length) {
|
||||||
var $input = this.$element.find('input')
|
var $input = this.$element.find('input')
|
||||||
if ($input.prop('type') == 'radio') {
|
if ($input.prop('type') == 'radio') {
|
||||||
if ($input.prop('checked')) changed = false
|
if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
|
||||||
$parent.find('.active').removeClass('active')
|
else $parent.find('.active').removeClass('active')
|
||||||
this.$element.addClass('active')
|
|
||||||
} else if ($input.prop('type') == 'checkbox') {
|
|
||||||
if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
|
|
||||||
this.$element.toggleClass('active')
|
|
||||||
}
|
}
|
||||||
$input.prop('checked', this.$element.hasClass('active'))
|
if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
|
||||||
if (changed) $input.trigger('change')
|
|
||||||
} else {
|
} else {
|
||||||
this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
|
this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
|
||||||
this.$element.toggleClass('active')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changed) this.$element.toggleClass('active')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -108,15 +104,10 @@
|
|||||||
|
|
||||||
$(document)
|
$(document)
|
||||||
.on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
|
.on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
|
||||||
var $btn = $(e.target).closest('.btn')
|
var $btn = $(e.target)
|
||||||
|
if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
|
||||||
Plugin.call($btn, 'toggle')
|
Plugin.call($btn, 'toggle')
|
||||||
if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) {
|
e.preventDefault()
|
||||||
// Prevent double click on radios, and the double selections (so cancellation) on checkboxes
|
|
||||||
e.preventDefault()
|
|
||||||
// The target component still receive the focus
|
|
||||||
if ($btn.is('input,button')) $btn.trigger('focus')
|
|
||||||
else $btn.find('input:visible,button:visible').first().trigger('focus')
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
|
.on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
|
||||||
$(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
|
$(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
|
||||||
|
|||||||
14
RIGS/static/js/carousel.js
Executable file → Normal file
@@ -1,8 +1,8 @@
|
|||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
* Bootstrap: carousel.js v3.3.7
|
* Bootstrap: carousel.js v3.3.2
|
||||||
* http://getbootstrap.com/javascript/#carousel
|
* http://getbootstrap.com/javascript/#carousel
|
||||||
* ========================================================================
|
* ========================================================================
|
||||||
* Copyright 2011-2016 Twitter, Inc.
|
* Copyright 2011-2015 Twitter, Inc.
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
* ======================================================================== */
|
* ======================================================================== */
|
||||||
|
|
||||||
@@ -17,10 +17,10 @@
|
|||||||
this.$element = $(element)
|
this.$element = $(element)
|
||||||
this.$indicators = this.$element.find('.carousel-indicators')
|
this.$indicators = this.$element.find('.carousel-indicators')
|
||||||
this.options = options
|
this.options = options
|
||||||
this.paused = null
|
this.paused =
|
||||||
this.sliding = null
|
this.sliding =
|
||||||
this.interval = null
|
this.interval =
|
||||||
this.$active = null
|
this.$active =
|
||||||
this.$items = null
|
this.$items = null
|
||||||
|
|
||||||
this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
|
this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
.on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
|
.on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
|
||||||
}
|
}
|
||||||
|
|
||||||
Carousel.VERSION = '3.3.7'
|
Carousel.VERSION = '3.3.2'
|
||||||
|
|
||||||
Carousel.TRANSITION_DURATION = 600
|
Carousel.TRANSITION_DURATION = 600
|
||||||
|
|
||||||
|
|||||||
17
RIGS/static/js/collapse.js
Executable file → Normal file
@@ -1,12 +1,11 @@
|
|||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
* Bootstrap: collapse.js v3.3.7
|
* Bootstrap: collapse.js v3.3.2
|
||||||
* http://getbootstrap.com/javascript/#collapse
|
* http://getbootstrap.com/javascript/#collapse
|
||||||
* ========================================================================
|
* ========================================================================
|
||||||
* Copyright 2011-2016 Twitter, Inc.
|
* Copyright 2011-2015 Twitter, Inc.
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
* ======================================================================== */
|
* ======================================================================== */
|
||||||
|
|
||||||
/* jshint latedef: false */
|
|
||||||
|
|
||||||
+function ($) {
|
+function ($) {
|
||||||
'use strict';
|
'use strict';
|
||||||
@@ -17,8 +16,7 @@
|
|||||||
var Collapse = function (element, options) {
|
var Collapse = function (element, options) {
|
||||||
this.$element = $(element)
|
this.$element = $(element)
|
||||||
this.options = $.extend({}, Collapse.DEFAULTS, options)
|
this.options = $.extend({}, Collapse.DEFAULTS, options)
|
||||||
this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
|
this.$trigger = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]')
|
||||||
'[data-toggle="collapse"][data-target="#' + element.id + '"]')
|
|
||||||
this.transitioning = null
|
this.transitioning = null
|
||||||
|
|
||||||
if (this.options.parent) {
|
if (this.options.parent) {
|
||||||
@@ -30,12 +28,13 @@
|
|||||||
if (this.options.toggle) this.toggle()
|
if (this.options.toggle) this.toggle()
|
||||||
}
|
}
|
||||||
|
|
||||||
Collapse.VERSION = '3.3.7'
|
Collapse.VERSION = '3.3.2'
|
||||||
|
|
||||||
Collapse.TRANSITION_DURATION = 350
|
Collapse.TRANSITION_DURATION = 350
|
||||||
|
|
||||||
Collapse.DEFAULTS = {
|
Collapse.DEFAULTS = {
|
||||||
toggle: true
|
toggle: true,
|
||||||
|
trigger: '[data-toggle="collapse"]'
|
||||||
}
|
}
|
||||||
|
|
||||||
Collapse.prototype.dimension = function () {
|
Collapse.prototype.dimension = function () {
|
||||||
@@ -173,7 +172,7 @@
|
|||||||
var data = $this.data('bs.collapse')
|
var data = $this.data('bs.collapse')
|
||||||
var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
||||||
|
|
||||||
if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
|
if (!data && options.toggle && option == 'show') options.toggle = false
|
||||||
if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
|
if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
|
||||||
if (typeof option == 'string') data[option]()
|
if (typeof option == 'string') data[option]()
|
||||||
})
|
})
|
||||||
@@ -204,7 +203,7 @@
|
|||||||
|
|
||||||
var $target = getTargetFromTrigger($this)
|
var $target = getTargetFromTrigger($this)
|
||||||
var data = $target.data('bs.collapse')
|
var data = $target.data('bs.collapse')
|
||||||
var option = data ? 'toggle' : $this.data()
|
var option = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this })
|
||||||
|
|
||||||
Plugin.call($target, option)
|
Plugin.call($target, option)
|
||||||
})
|
})
|
||||||
|
|||||||
94
RIGS/static/js/dropdown.js
Executable file → Normal file
@@ -1,8 +1,8 @@
|
|||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
* Bootstrap: dropdown.js v3.3.7
|
* Bootstrap: dropdown.js v3.3.2
|
||||||
* http://getbootstrap.com/javascript/#dropdowns
|
* http://getbootstrap.com/javascript/#dropdowns
|
||||||
* ========================================================================
|
* ========================================================================
|
||||||
* Copyright 2011-2016 Twitter, Inc.
|
* Copyright 2011-2015 Twitter, Inc.
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
* ======================================================================== */
|
* ======================================================================== */
|
||||||
|
|
||||||
@@ -19,41 +19,7 @@
|
|||||||
$(element).on('click.bs.dropdown', this.toggle)
|
$(element).on('click.bs.dropdown', this.toggle)
|
||||||
}
|
}
|
||||||
|
|
||||||
Dropdown.VERSION = '3.3.7'
|
Dropdown.VERSION = '3.3.2'
|
||||||
|
|
||||||
function getParent($this) {
|
|
||||||
var selector = $this.attr('data-target')
|
|
||||||
|
|
||||||
if (!selector) {
|
|
||||||
selector = $this.attr('href')
|
|
||||||
selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
|
|
||||||
}
|
|
||||||
|
|
||||||
var $parent = selector && $(selector)
|
|
||||||
|
|
||||||
return $parent && $parent.length ? $parent : $this.parent()
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearMenus(e) {
|
|
||||||
if (e && e.which === 3) return
|
|
||||||
$(backdrop).remove()
|
|
||||||
$(toggle).each(function () {
|
|
||||||
var $this = $(this)
|
|
||||||
var $parent = getParent($this)
|
|
||||||
var relatedTarget = { relatedTarget: this }
|
|
||||||
|
|
||||||
if (!$parent.hasClass('open')) return
|
|
||||||
|
|
||||||
if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
|
|
||||||
|
|
||||||
$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
|
|
||||||
|
|
||||||
if (e.isDefaultPrevented()) return
|
|
||||||
|
|
||||||
$this.attr('aria-expanded', 'false')
|
|
||||||
$parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
Dropdown.prototype.toggle = function (e) {
|
Dropdown.prototype.toggle = function (e) {
|
||||||
var $this = $(this)
|
var $this = $(this)
|
||||||
@@ -68,10 +34,7 @@
|
|||||||
if (!isActive) {
|
if (!isActive) {
|
||||||
if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
|
if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
|
||||||
// if mobile we use a backdrop because click events don't delegate
|
// if mobile we use a backdrop because click events don't delegate
|
||||||
$(document.createElement('div'))
|
$('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
|
||||||
.addClass('dropdown-backdrop')
|
|
||||||
.insertAfter($(this))
|
|
||||||
.on('click', clearMenus)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var relatedTarget = { relatedTarget: this }
|
var relatedTarget = { relatedTarget: this }
|
||||||
@@ -85,7 +48,7 @@
|
|||||||
|
|
||||||
$parent
|
$parent
|
||||||
.toggleClass('open')
|
.toggleClass('open')
|
||||||
.trigger($.Event('shown.bs.dropdown', relatedTarget))
|
.trigger('shown.bs.dropdown', relatedTarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
@@ -104,25 +67,57 @@
|
|||||||
var $parent = getParent($this)
|
var $parent = getParent($this)
|
||||||
var isActive = $parent.hasClass('open')
|
var isActive = $parent.hasClass('open')
|
||||||
|
|
||||||
if (!isActive && e.which != 27 || isActive && e.which == 27) {
|
if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {
|
||||||
if (e.which == 27) $parent.find(toggle).trigger('focus')
|
if (e.which == 27) $parent.find(toggle).trigger('focus')
|
||||||
return $this.trigger('click')
|
return $this.trigger('click')
|
||||||
}
|
}
|
||||||
|
|
||||||
var desc = ' li:not(.disabled):visible a'
|
var desc = ' li:not(.divider):visible a'
|
||||||
var $items = $parent.find('.dropdown-menu' + desc)
|
var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)
|
||||||
|
|
||||||
if (!$items.length) return
|
if (!$items.length) return
|
||||||
|
|
||||||
var index = $items.index(e.target)
|
var index = $items.index(e.target)
|
||||||
|
|
||||||
if (e.which == 38 && index > 0) index-- // up
|
if (e.which == 38 && index > 0) index-- // up
|
||||||
if (e.which == 40 && index < $items.length - 1) index++ // down
|
if (e.which == 40 && index < $items.length - 1) index++ // down
|
||||||
if (!~index) index = 0
|
if (!~index) index = 0
|
||||||
|
|
||||||
$items.eq(index).trigger('focus')
|
$items.eq(index).trigger('focus')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearMenus(e) {
|
||||||
|
if (e && e.which === 3) return
|
||||||
|
$(backdrop).remove()
|
||||||
|
$(toggle).each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
var $parent = getParent($this)
|
||||||
|
var relatedTarget = { relatedTarget: this }
|
||||||
|
|
||||||
|
if (!$parent.hasClass('open')) return
|
||||||
|
|
||||||
|
$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
|
||||||
|
|
||||||
|
if (e.isDefaultPrevented()) return
|
||||||
|
|
||||||
|
$this.attr('aria-expanded', 'false')
|
||||||
|
$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getParent($this) {
|
||||||
|
var selector = $this.attr('data-target')
|
||||||
|
|
||||||
|
if (!selector) {
|
||||||
|
selector = $this.attr('href')
|
||||||
|
selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
|
||||||
|
}
|
||||||
|
|
||||||
|
var $parent = selector && $(selector)
|
||||||
|
|
||||||
|
return $parent && $parent.length ? $parent : $this.parent()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// DROPDOWN PLUGIN DEFINITION
|
// DROPDOWN PLUGIN DEFINITION
|
||||||
// ==========================
|
// ==========================
|
||||||
@@ -160,6 +155,7 @@
|
|||||||
.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
|
.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
|
||||||
.on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
|
.on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
|
||||||
.on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
|
.on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
|
||||||
.on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
|
.on('keydown.bs.dropdown.data-api', '[role="menu"]', Dropdown.prototype.keydown)
|
||||||
|
.on('keydown.bs.dropdown.data-api', '[role="listbox"]', Dropdown.prototype.keydown)
|
||||||
|
|
||||||
}(jQuery);
|
}(jQuery);
|
||||||
|
|||||||
@@ -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 = new Object();
|
fields = {};
|
||||||
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);
|
|
||||||
|
|
||||||
updatePrices();
|
fields['order'] = order;
|
||||||
|
|
||||||
|
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 = new Array();
|
itemorder = [];
|
||||||
$.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;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
10
RIGS/static/js/modal.js
Executable file → Normal file
@@ -1,8 +1,8 @@
|
|||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
* Bootstrap: modal.js v3.3.7
|
* Bootstrap: modal.js v3.3.5
|
||||||
* http://getbootstrap.com/javascript/#modals
|
* http://getbootstrap.com/javascript/#modals
|
||||||
* ========================================================================
|
* ========================================================================
|
||||||
* Copyright 2011-2016 Twitter, Inc.
|
* Copyright 2011-2015 Twitter, Inc.
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
* ======================================================================== */
|
* ======================================================================== */
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Modal.VERSION = '3.3.7'
|
Modal.VERSION = '3.3.5'
|
||||||
|
|
||||||
Modal.TRANSITION_DURATION = 300
|
Modal.TRANSITION_DURATION = 300
|
||||||
Modal.BACKDROP_TRANSITION_DURATION = 150
|
Modal.BACKDROP_TRANSITION_DURATION = 150
|
||||||
@@ -140,9 +140,7 @@
|
|||||||
$(document)
|
$(document)
|
||||||
.off('focusin.bs.modal') // guard against infinite focus loop
|
.off('focusin.bs.modal') // guard against infinite focus loop
|
||||||
.on('focusin.bs.modal', $.proxy(function (e) {
|
.on('focusin.bs.modal', $.proxy(function (e) {
|
||||||
if (document !== e.target &&
|
if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
|
||||||
this.$element[0] !== e.target &&
|
|
||||||
!this.$element.has(e.target).length) {
|
|
||||||
this.$element.trigger('focus')
|
this.$element.trigger('focus')
|
||||||
}
|
}
|
||||||
}, this))
|
}, this))
|
||||||
|
|||||||
13
RIGS/static/js/popover.js
Executable file → Normal file
@@ -1,8 +1,8 @@
|
|||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
* Bootstrap: popover.js v3.3.7
|
* Bootstrap: popover.js v3.3.2
|
||||||
* http://getbootstrap.com/javascript/#popovers
|
* http://getbootstrap.com/javascript/#popovers
|
||||||
* ========================================================================
|
* ========================================================================
|
||||||
* Copyright 2011-2016 Twitter, Inc.
|
* Copyright 2011-2015 Twitter, Inc.
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
* ======================================================================== */
|
* ======================================================================== */
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
|
if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
|
||||||
|
|
||||||
Popover.VERSION = '3.3.7'
|
Popover.VERSION = '3.3.2'
|
||||||
|
|
||||||
Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
|
Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
|
||||||
placement: 'right',
|
placement: 'right',
|
||||||
@@ -75,6 +75,11 @@
|
|||||||
return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
|
return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Popover.prototype.tip = function () {
|
||||||
|
if (!this.$tip) this.$tip = $(this.options.template)
|
||||||
|
return this.$tip
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// POPOVER PLUGIN DEFINITION
|
// POPOVER PLUGIN DEFINITION
|
||||||
// =========================
|
// =========================
|
||||||
@@ -85,7 +90,7 @@
|
|||||||
var data = $this.data('bs.popover')
|
var data = $this.data('bs.popover')
|
||||||
var options = typeof option == 'object' && option
|
var options = typeof option == 'object' && option
|
||||||
|
|
||||||
if (!data && /destroy|hide/.test(option)) return
|
if (!data && option == 'destroy') return
|
||||||
if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
|
if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
|
||||||
if (typeof option == 'string') data[option]()
|
if (typeof option == 'string') data[option]()
|
||||||
})
|
})
|
||||||
|
|||||||
39
RIGS/static/js/scrollspy.js
Executable file → Normal file
@@ -1,8 +1,8 @@
|
|||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
* Bootstrap: scrollspy.js v3.3.7
|
* Bootstrap: scrollspy.js v3.3.2
|
||||||
* http://getbootstrap.com/javascript/#scrollspy
|
* http://getbootstrap.com/javascript/#scrollspy
|
||||||
* ========================================================================
|
* ========================================================================
|
||||||
* Copyright 2011-2016 Twitter, Inc.
|
* Copyright 2011-2015 Twitter, Inc.
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
* ======================================================================== */
|
* ======================================================================== */
|
||||||
|
|
||||||
@@ -14,8 +14,10 @@
|
|||||||
// ==========================
|
// ==========================
|
||||||
|
|
||||||
function ScrollSpy(element, options) {
|
function ScrollSpy(element, options) {
|
||||||
this.$body = $(document.body)
|
var process = $.proxy(this.process, this)
|
||||||
this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
|
|
||||||
|
this.$body = $('body')
|
||||||
|
this.$scrollElement = $(element).is('body') ? $(window) : $(element)
|
||||||
this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
|
this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
|
||||||
this.selector = (this.options.target || '') + ' .nav li > a'
|
this.selector = (this.options.target || '') + ' .nav li > a'
|
||||||
this.offsets = []
|
this.offsets = []
|
||||||
@@ -23,12 +25,12 @@
|
|||||||
this.activeTarget = null
|
this.activeTarget = null
|
||||||
this.scrollHeight = 0
|
this.scrollHeight = 0
|
||||||
|
|
||||||
this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
|
this.$scrollElement.on('scroll.bs.scrollspy', process)
|
||||||
this.refresh()
|
this.refresh()
|
||||||
this.process()
|
this.process()
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollSpy.VERSION = '3.3.7'
|
ScrollSpy.VERSION = '3.3.2'
|
||||||
|
|
||||||
ScrollSpy.DEFAULTS = {
|
ScrollSpy.DEFAULTS = {
|
||||||
offset: 10
|
offset: 10
|
||||||
@@ -39,19 +41,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScrollSpy.prototype.refresh = function () {
|
ScrollSpy.prototype.refresh = function () {
|
||||||
var that = this
|
var offsetMethod = 'offset'
|
||||||
var offsetMethod = 'offset'
|
var offsetBase = 0
|
||||||
var offsetBase = 0
|
|
||||||
|
|
||||||
this.offsets = []
|
|
||||||
this.targets = []
|
|
||||||
this.scrollHeight = this.getScrollHeight()
|
|
||||||
|
|
||||||
if (!$.isWindow(this.$scrollElement[0])) {
|
if (!$.isWindow(this.$scrollElement[0])) {
|
||||||
offsetMethod = 'position'
|
offsetMethod = 'position'
|
||||||
offsetBase = this.$scrollElement.scrollTop()
|
offsetBase = this.$scrollElement.scrollTop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.offsets = []
|
||||||
|
this.targets = []
|
||||||
|
this.scrollHeight = this.getScrollHeight()
|
||||||
|
|
||||||
|
var self = this
|
||||||
|
|
||||||
this.$body
|
this.$body
|
||||||
.find(this.selector)
|
.find(this.selector)
|
||||||
.map(function () {
|
.map(function () {
|
||||||
@@ -66,8 +69,8 @@
|
|||||||
})
|
})
|
||||||
.sort(function (a, b) { return a[0] - b[0] })
|
.sort(function (a, b) { return a[0] - b[0] })
|
||||||
.each(function () {
|
.each(function () {
|
||||||
that.offsets.push(this[0])
|
self.offsets.push(this[0])
|
||||||
that.targets.push(this[1])
|
self.targets.push(this[1])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +99,7 @@
|
|||||||
for (i = offsets.length; i--;) {
|
for (i = offsets.length; i--;) {
|
||||||
activeTarget != targets[i]
|
activeTarget != targets[i]
|
||||||
&& scrollTop >= offsets[i]
|
&& scrollTop >= offsets[i]
|
||||||
&& (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
|
&& (!offsets[i + 1] || scrollTop <= offsets[i + 1])
|
||||||
&& this.activate(targets[i])
|
&& this.activate(targets[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,8 +110,8 @@
|
|||||||
this.clear()
|
this.clear()
|
||||||
|
|
||||||
var selector = this.selector +
|
var selector = this.selector +
|
||||||
'[data-target="' + target + '"],' +
|
'[data-target="' + target + '"],' +
|
||||||
this.selector + '[href="' + target + '"]'
|
this.selector + '[href="' + target + '"]'
|
||||||
|
|
||||||
var active = $(selector)
|
var active = $(selector)
|
||||||
.parents('li')
|
.parents('li')
|
||||||
|
|||||||
12
RIGS/static/js/tab.js
Executable file → Normal file
@@ -1,8 +1,8 @@
|
|||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
* Bootstrap: tab.js v3.3.7
|
* Bootstrap: tab.js v3.3.2
|
||||||
* http://getbootstrap.com/javascript/#tabs
|
* http://getbootstrap.com/javascript/#tabs
|
||||||
* ========================================================================
|
* ========================================================================
|
||||||
* Copyright 2011-2016 Twitter, Inc.
|
* Copyright 2011-2015 Twitter, Inc.
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
* ======================================================================== */
|
* ======================================================================== */
|
||||||
|
|
||||||
@@ -14,12 +14,10 @@
|
|||||||
// ====================
|
// ====================
|
||||||
|
|
||||||
var Tab = function (element) {
|
var Tab = function (element) {
|
||||||
// jscs:disable requireDollarBeforejQueryAssignment
|
|
||||||
this.element = $(element)
|
this.element = $(element)
|
||||||
// jscs:enable requireDollarBeforejQueryAssignment
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Tab.VERSION = '3.3.7'
|
Tab.VERSION = '3.3.2'
|
||||||
|
|
||||||
Tab.TRANSITION_DURATION = 150
|
Tab.TRANSITION_DURATION = 150
|
||||||
|
|
||||||
@@ -67,7 +65,7 @@
|
|||||||
var $active = container.find('> .active')
|
var $active = container.find('> .active')
|
||||||
var transition = callback
|
var transition = callback
|
||||||
&& $.support.transition
|
&& $.support.transition
|
||||||
&& ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
|
&& (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)
|
||||||
|
|
||||||
function next() {
|
function next() {
|
||||||
$active
|
$active
|
||||||
@@ -90,7 +88,7 @@
|
|||||||
element.removeClass('fade')
|
element.removeClass('fade')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.parent('.dropdown-menu').length) {
|
if (element.parent('.dropdown-menu')) {
|
||||||
element
|
element
|
||||||
.closest('li.dropdown')
|
.closest('li.dropdown')
|
||||||
.addClass('active')
|
.addClass('active')
|
||||||
|
|||||||
120
RIGS/static/js/tooltip.js
Executable file → Normal file
@@ -1,9 +1,9 @@
|
|||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
* Bootstrap: tooltip.js v3.3.7
|
* Bootstrap: tooltip.js v3.3.2
|
||||||
* http://getbootstrap.com/javascript/#tooltip
|
* http://getbootstrap.com/javascript/#tooltip
|
||||||
* Inspired by the original jQuery.tipsy by Jason Frame
|
* Inspired by the original jQuery.tipsy by Jason Frame
|
||||||
* ========================================================================
|
* ========================================================================
|
||||||
* Copyright 2011-2016 Twitter, Inc.
|
* Copyright 2011-2015 Twitter, Inc.
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
* ======================================================================== */
|
* ======================================================================== */
|
||||||
|
|
||||||
@@ -15,18 +15,17 @@
|
|||||||
// ===============================
|
// ===============================
|
||||||
|
|
||||||
var Tooltip = function (element, options) {
|
var Tooltip = function (element, options) {
|
||||||
this.type = null
|
this.type =
|
||||||
this.options = null
|
this.options =
|
||||||
this.enabled = null
|
this.enabled =
|
||||||
this.timeout = null
|
this.timeout =
|
||||||
this.hoverState = null
|
this.hoverState =
|
||||||
this.$element = null
|
this.$element = null
|
||||||
this.inState = null
|
|
||||||
|
|
||||||
this.init('tooltip', element, options)
|
this.init('tooltip', element, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
Tooltip.VERSION = '3.3.7'
|
Tooltip.VERSION = '3.3.2'
|
||||||
|
|
||||||
Tooltip.TRANSITION_DURATION = 150
|
Tooltip.TRANSITION_DURATION = 150
|
||||||
|
|
||||||
@@ -51,12 +50,7 @@
|
|||||||
this.type = type
|
this.type = type
|
||||||
this.$element = $(element)
|
this.$element = $(element)
|
||||||
this.options = this.getOptions(options)
|
this.options = this.getOptions(options)
|
||||||
this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
|
this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
|
||||||
this.inState = { click: false, hover: false, focus: false }
|
|
||||||
|
|
||||||
if (this.$element[0] instanceof document.constructor && !this.options.selector) {
|
|
||||||
throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
|
|
||||||
}
|
|
||||||
|
|
||||||
var triggers = this.options.trigger.split(' ')
|
var triggers = this.options.trigger.split(' ')
|
||||||
|
|
||||||
@@ -111,20 +105,16 @@
|
|||||||
var self = obj instanceof this.constructor ?
|
var self = obj instanceof this.constructor ?
|
||||||
obj : $(obj.currentTarget).data('bs.' + this.type)
|
obj : $(obj.currentTarget).data('bs.' + this.type)
|
||||||
|
|
||||||
|
if (self && self.$tip && self.$tip.is(':visible')) {
|
||||||
|
self.hoverState = 'in'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!self) {
|
if (!self) {
|
||||||
self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
|
self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
|
||||||
$(obj.currentTarget).data('bs.' + this.type, self)
|
$(obj.currentTarget).data('bs.' + this.type, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj instanceof $.Event) {
|
|
||||||
self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.tip().hasClass('in') || self.hoverState == 'in') {
|
|
||||||
self.hoverState = 'in'
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
clearTimeout(self.timeout)
|
clearTimeout(self.timeout)
|
||||||
|
|
||||||
self.hoverState = 'in'
|
self.hoverState = 'in'
|
||||||
@@ -136,14 +126,6 @@
|
|||||||
}, self.options.delay.show)
|
}, self.options.delay.show)
|
||||||
}
|
}
|
||||||
|
|
||||||
Tooltip.prototype.isInStateTrue = function () {
|
|
||||||
for (var key in this.inState) {
|
|
||||||
if (this.inState[key]) return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
Tooltip.prototype.leave = function (obj) {
|
Tooltip.prototype.leave = function (obj) {
|
||||||
var self = obj instanceof this.constructor ?
|
var self = obj instanceof this.constructor ?
|
||||||
obj : $(obj.currentTarget).data('bs.' + this.type)
|
obj : $(obj.currentTarget).data('bs.' + this.type)
|
||||||
@@ -153,12 +135,6 @@
|
|||||||
$(obj.currentTarget).data('bs.' + this.type, self)
|
$(obj.currentTarget).data('bs.' + this.type, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj instanceof $.Event) {
|
|
||||||
self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.isInStateTrue()) return
|
|
||||||
|
|
||||||
clearTimeout(self.timeout)
|
clearTimeout(self.timeout)
|
||||||
|
|
||||||
self.hoverState = 'out'
|
self.hoverState = 'out'
|
||||||
@@ -205,7 +181,6 @@
|
|||||||
.data('bs.' + this.type, this)
|
.data('bs.' + this.type, this)
|
||||||
|
|
||||||
this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
|
this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
|
||||||
this.$element.trigger('inserted.bs.' + this.type)
|
|
||||||
|
|
||||||
var pos = this.getPosition()
|
var pos = this.getPosition()
|
||||||
var actualWidth = $tip[0].offsetWidth
|
var actualWidth = $tip[0].offsetWidth
|
||||||
@@ -213,12 +188,13 @@
|
|||||||
|
|
||||||
if (autoPlace) {
|
if (autoPlace) {
|
||||||
var orgPlacement = placement
|
var orgPlacement = placement
|
||||||
var viewportDim = this.getPosition(this.$viewport)
|
var $container = this.options.container ? $(this.options.container) : this.$element.parent()
|
||||||
|
var containerDim = this.getPosition($container)
|
||||||
|
|
||||||
placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' :
|
placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' :
|
||||||
placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' :
|
placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' :
|
||||||
placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' :
|
placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' :
|
||||||
placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' :
|
placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' :
|
||||||
placement
|
placement
|
||||||
|
|
||||||
$tip
|
$tip
|
||||||
@@ -259,8 +235,8 @@
|
|||||||
if (isNaN(marginTop)) marginTop = 0
|
if (isNaN(marginTop)) marginTop = 0
|
||||||
if (isNaN(marginLeft)) marginLeft = 0
|
if (isNaN(marginLeft)) marginLeft = 0
|
||||||
|
|
||||||
offset.top += marginTop
|
offset.top = offset.top + marginTop
|
||||||
offset.left += marginLeft
|
offset.left = offset.left + marginLeft
|
||||||
|
|
||||||
// $.fn.offset doesn't round pixel values
|
// $.fn.offset doesn't round pixel values
|
||||||
// so we use setOffset directly with our own function B-0
|
// so we use setOffset directly with our own function B-0
|
||||||
@@ -296,10 +272,10 @@
|
|||||||
this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
|
this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
|
||||||
}
|
}
|
||||||
|
|
||||||
Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
|
Tooltip.prototype.replaceArrow = function (delta, dimension, isHorizontal) {
|
||||||
this.arrow()
|
this.arrow()
|
||||||
.css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
|
.css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
|
||||||
.css(isVertical ? 'top' : 'left', '')
|
.css(isHorizontal ? 'top' : 'left', '')
|
||||||
}
|
}
|
||||||
|
|
||||||
Tooltip.prototype.setContent = function () {
|
Tooltip.prototype.setContent = function () {
|
||||||
@@ -312,16 +288,14 @@
|
|||||||
|
|
||||||
Tooltip.prototype.hide = function (callback) {
|
Tooltip.prototype.hide = function (callback) {
|
||||||
var that = this
|
var that = this
|
||||||
var $tip = $(this.$tip)
|
var $tip = this.tip()
|
||||||
var e = $.Event('hide.bs.' + this.type)
|
var e = $.Event('hide.bs.' + this.type)
|
||||||
|
|
||||||
function complete() {
|
function complete() {
|
||||||
if (that.hoverState != 'in') $tip.detach()
|
if (that.hoverState != 'in') $tip.detach()
|
||||||
if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.
|
that.$element
|
||||||
that.$element
|
.removeAttr('aria-describedby')
|
||||||
.removeAttr('aria-describedby')
|
.trigger('hidden.bs.' + that.type)
|
||||||
.trigger('hidden.bs.' + that.type)
|
|
||||||
}
|
|
||||||
callback && callback()
|
callback && callback()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,7 +305,7 @@
|
|||||||
|
|
||||||
$tip.removeClass('in')
|
$tip.removeClass('in')
|
||||||
|
|
||||||
$.support.transition && $tip.hasClass('fade') ?
|
$.support.transition && this.$tip.hasClass('fade') ?
|
||||||
$tip
|
$tip
|
||||||
.one('bsTransitionEnd', complete)
|
.one('bsTransitionEnd', complete)
|
||||||
.emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
|
.emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
|
||||||
@@ -344,7 +318,7 @@
|
|||||||
|
|
||||||
Tooltip.prototype.fixTitle = function () {
|
Tooltip.prototype.fixTitle = function () {
|
||||||
var $e = this.$element
|
var $e = this.$element
|
||||||
if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
|
if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
|
||||||
$e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
|
$e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -364,10 +338,7 @@
|
|||||||
// width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
|
// width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
|
||||||
elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
|
elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
|
||||||
}
|
}
|
||||||
var isSvg = window.SVGElement && el instanceof window.SVGElement
|
var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
|
||||||
// Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3.
|
|
||||||
// See https://github.com/twbs/bootstrap/issues/20280
|
|
||||||
var elOffset = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset())
|
|
||||||
var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
|
var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
|
||||||
var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
|
var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
|
||||||
|
|
||||||
@@ -402,7 +373,7 @@
|
|||||||
var rightEdgeOffset = pos.left + viewportPadding + actualWidth
|
var rightEdgeOffset = pos.left + viewportPadding + actualWidth
|
||||||
if (leftEdgeOffset < viewportDimensions.left) { // left overflow
|
if (leftEdgeOffset < viewportDimensions.left) { // left overflow
|
||||||
delta.left = viewportDimensions.left - leftEdgeOffset
|
delta.left = viewportDimensions.left - leftEdgeOffset
|
||||||
} else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
|
} else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
|
||||||
delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
|
delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -428,13 +399,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
Tooltip.prototype.tip = function () {
|
Tooltip.prototype.tip = function () {
|
||||||
if (!this.$tip) {
|
return (this.$tip = this.$tip || $(this.options.template))
|
||||||
this.$tip = $(this.options.template)
|
|
||||||
if (this.$tip.length != 1) {
|
|
||||||
throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.$tip
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Tooltip.prototype.arrow = function () {
|
Tooltip.prototype.arrow = function () {
|
||||||
@@ -463,13 +428,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e) {
|
self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
|
||||||
self.inState.click = !self.inState.click
|
|
||||||
if (self.isInStateTrue()) self.enter(self)
|
|
||||||
else self.leave(self)
|
|
||||||
} else {
|
|
||||||
self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Tooltip.prototype.destroy = function () {
|
Tooltip.prototype.destroy = function () {
|
||||||
@@ -477,13 +436,6 @@
|
|||||||
clearTimeout(this.timeout)
|
clearTimeout(this.timeout)
|
||||||
this.hide(function () {
|
this.hide(function () {
|
||||||
that.$element.off('.' + that.type).removeData('bs.' + that.type)
|
that.$element.off('.' + that.type).removeData('bs.' + that.type)
|
||||||
if (that.$tip) {
|
|
||||||
that.$tip.detach()
|
|
||||||
}
|
|
||||||
that.$tip = null
|
|
||||||
that.$arrow = null
|
|
||||||
that.$viewport = null
|
|
||||||
that.$element = null
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,7 +449,7 @@
|
|||||||
var data = $this.data('bs.tooltip')
|
var data = $this.data('bs.tooltip')
|
||||||
var options = typeof option == 'object' && option
|
var options = typeof option == 'object' && option
|
||||||
|
|
||||||
if (!data && /destroy|hide/.test(option)) return
|
if (!data && option == 'destroy') return
|
||||||
if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
|
if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
|
||||||
if (typeof option == 'string') data[option]()
|
if (typeof option == 'string') data[option]()
|
||||||
})
|
})
|
||||||
|
|||||||
4
RIGS/static/js/transition.js
Executable file → Normal file
@@ -1,8 +1,8 @@
|
|||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
* Bootstrap: transition.js v3.3.7
|
* Bootstrap: transition.js v3.3.2
|
||||||
* http://getbootstrap.com/javascript/#transitions
|
* http://getbootstrap.com/javascript/#transitions
|
||||||
* ========================================================================
|
* ========================================================================
|
||||||
* Copyright 2011-2016 Twitter, Inc.
|
* Copyright 2011-2015 Twitter, Inc.
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
* ======================================================================== */
|
* ======================================================================== */
|
||||||
|
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
$button_color: #357ebf;
|
|
||||||
|
|
||||||
body{
|
|
||||||
margin: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-table{
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.client-header {
|
|
||||||
background-image: url("https://www.nottinghamtec.co.uk/imgs/wof2014-1.jpg");
|
|
||||||
background-color: #222;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
margin-bottom: 28px;
|
|
||||||
|
|
||||||
.logos{
|
|
||||||
width: 100%;
|
|
||||||
max-width: 640px;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
height: 110px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-container{
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.content {
|
|
||||||
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
max-width: 600px;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
.button-container{
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.button {
|
|
||||||
padding: 6px 12px;
|
|
||||||
background-color: $button_color;
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #fff;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
@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";
|
||||||
|
|
||||||
@@ -90,105 +89,62 @@ 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);
|
||||||
};
|
}
|
||||||
}
|
;
|
||||||
}
|
|
||||||
|
|
||||||
html.embedded{
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
max-height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
body{
|
|
||||||
padding:0;
|
|
||||||
width:100%;
|
|
||||||
background:none;
|
|
||||||
overflow: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed_container{
|
|
||||||
border:5px solid #e9e9e9;
|
|
||||||
padding:12px 0px;
|
|
||||||
min-height:100%;
|
|
||||||
width:100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.source{
|
|
||||||
background: url('/static/imgs/pyrigs-avatar.png') no-repeat;
|
|
||||||
background-size: 16px 16px;
|
|
||||||
padding-left: 20px;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3{
|
|
||||||
margin-top:10px;
|
|
||||||
margin-bottom:5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p{
|
|
||||||
margin-bottom:2px;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-mic-photo{
|
|
||||||
max-width: 3em;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 () {
|
||||||
</script>
|
$("#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);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</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,50 +5,52 @@
|
|||||||
{% 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" src="{{ version.revision.user.profile_picture}}" />
|
<img class="media-object img-rounded"
|
||||||
</a>
|
src="{{ version.revision.user.profile_picture }}"/>
|
||||||
|
</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" data-date="{{version.revision.date_created|date:"c"}}"></span></small></span>
|
<span class="pull-right"><small><span class="date"
|
||||||
</h5>
|
data-date="{{ version.revision.date_created|date:"c" }}"></span></small></span>
|
||||||
|
</h5>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>
|
<p>
|
||||||
<small>
|
<small>
|
||||||
{% if version.changes.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.changes.new %}
|
|
||||||
{% if version.revision.comment %}
|
|
||||||
({{ version.revision.comment }})
|
|
||||||
{% endif %}
|
|
||||||
</small>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{% endfor %}
|
{% include 'RIGS/object_button.html' with object=version.new %}
|
||||||
</div>
|
{% if version.revision.comment %}
|
||||||
</div>
|
({{ version.revision.comment }})
|
||||||
</div>
|
{% endif %}
|
||||||
|
</small>
|
||||||
{% endblock %}
|
</p>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% 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,23 +63,25 @@
|
|||||||
</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><a href="{{ version.changes.new.get_absolute_url }}">{{version.changes.new|to_class_name}} {{ version.changes.new.pk|stringformat:"05d" }}</a></td>
|
<td>
|
||||||
<td>{{ version.pk }}|{{ version.revision.pk }}</td>
|
<a href="{{ version.new.get_absolute_url }}">{{ version.new|to_class_name }} {{ version.new.pk|stringformat:"05d" }}</a>
|
||||||
<td>{{ version.revision.user.name }}</td>
|
</td>
|
||||||
<td>
|
<td>{{ version.version.pk }}|{{ version.revision.pk }}</td>
|
||||||
{% if version.changes.old == None %}
|
<td>{{ version.revision.user.name }}</td>
|
||||||
{{version.changes.new|to_class_name}} Created
|
<td>
|
||||||
{% else %}
|
{% if version.old == None %}
|
||||||
{% include 'RIGS/version_changes.html' %}
|
{{ version.new|to_class_name }} Created
|
||||||
{% endif %} </td>
|
{% else %}
|
||||||
<td>{{ version.changes.revision.comment }}</td>
|
{% include 'RIGS/version_changes.html' %}
|
||||||
</tr>
|
{% endif %} </td>
|
||||||
|
<td>{{ version.revision.comment }}</td>
|
||||||
{% endfor %}
|
</tr>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -87,4 +89,4 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="align-right">{% paginator %}</div>
|
<div class="align-right">{% paginator %}</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -2,39 +2,40 @@
|
|||||||
{% 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 records will have associated events moved to the 'master' copy, and then will be deleted.</p>
|
<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>
|
||||||
|
|
||||||
<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 %}
|
||||||
</tr>
|
</table>
|
||||||
{% 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,18 +67,19 @@
|
|||||||
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 = {'Provisional': '#f0ad4e',
|
colours = {
|
||||||
'Confirmed': '#5cb85c' ,
|
'Provisional': '#f0ad4e',
|
||||||
'Booked': '#5cb85c' ,
|
'Confirmed': '#5cb85c',
|
||||||
'Cancelled': 'grey' ,
|
'Booked': '#5cb85c',
|
||||||
|
'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 = {
|
||||||
@@ -87,14 +88,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);
|
||||||
@@ -102,20 +103,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');
|
||||||
@@ -134,53 +135,64 @@
|
|||||||
$('#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(){ $('#calendar').fullCalendar('next') });
|
$('#next-button').click(function () {
|
||||||
$('#prev-button').click(function(){ $('#calendar').fullCalendar('prev') });
|
$('#calendar').fullCalendar('next')
|
||||||
$('#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(){ $('#calendar').fullCalendar('changeView','month') });
|
$('#month-button').click(function () {
|
||||||
$('#week-button').click(function(){ $('#calendar').fullCalendar('changeView','agendaWeek') });
|
$('#calendar').fullCalendar('changeView', 'month')
|
||||||
$('#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>
|
||||||
@@ -189,7 +201,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>
|
||||||
@@ -197,33 +209,35 @@
|
|||||||
|
|
||||||
<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 class="glyphicon glyphicon-chevron-left"></span></button>
|
<button type="button" class="btn btn-default" id="prev-button"><span
|
||||||
<button type="button" class="btn btn-default" id="next-button"><span class="glyphicon glyphicon-chevron-right"></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>
|
||||||
</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>
|
||||||
{% endblock %}
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
<div class="row">
|
|
||||||
<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 event.person %}
|
|
||||||
{{ event.person.name }}
|
|
||||||
{% endif %}
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>Email</dt>
|
|
||||||
<dd>
|
|
||||||
<span class="overflow-ellipsis">{{ event.person.email }}</span>
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>Phone Number</dt>
|
|
||||||
<dd>{{ event.person.phone }}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% if event.organisation %}
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">Organisation</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<dl class="dl-horizontal">
|
|
||||||
<dt>Organisation</dt>
|
|
||||||
<dd>
|
|
||||||
{{ event.organisation.name }}
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>Phone Number</dt>
|
|
||||||
<dd>{{ object.organisation.phone }}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-sm-12 col-md-6 col-lg-7">
|
|
||||||
<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>
|
|
||||||
{% if object.venue %}
|
|
||||||
<a href="{% url 'venue_detail' object.venue.pk %}" class="modal-href">
|
|
||||||
{{ object.venue }}
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>Status</dt>
|
|
||||||
<dd>{{ event.get_status_display }}</dd>
|
|
||||||
|
|
||||||
<dd> </dd>
|
|
||||||
|
|
||||||
<dt>Access From</dt>
|
|
||||||
<dd>{{ event.access_at|date:"D d M Y H:i"|default:"" }}</dd>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -11,14 +11,17 @@
|
|||||||
<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" class="form-control" />
|
<input type="date" name="start" id="start" value="{{ request.GET.start }}" placeholder="Start"
|
||||||
|
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" value="{% if request.GET.end %}{{ request.GET.end }}{% else %}{% now "Y-m-d" %}{% endif %}" placeholder="End" class="form-control" />
|
<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"/>
|
||||||
</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>
|
||||||
@@ -42,4 +45,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,244 +1,286 @@
|
|||||||
{% 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 %} | {{object.name}}{% endblock %}
|
{% block title %}{% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}{% endif %} |
|
||||||
|
{{ 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">
|
||||||
{% include 'RIGS/event_detail_buttons.html' %}
|
<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
|
||||||
{% endif %}
|
class="hidden-xs">Edit</span></a>
|
||||||
{% if object.is_rig %}
|
{% if event.is_rig %}
|
||||||
{# only need contact details for a rig #}
|
<a href="{% url 'event_print' event.pk %}" target="_blank" class="btn btn-default"><span
|
||||||
<div class="col-sm-12 col-md-6 col-lg-5">
|
class="glyphicon glyphicon-print"></span> <span
|
||||||
<div class="panel panel-default">
|
class="hidden-xs">Print</span></a>
|
||||||
<div class="panel-heading">Contact Details</div>
|
{% endif %}
|
||||||
<div class="panel-body">
|
<a href="{% url 'event_duplicate' event.pk %}" class="btn btn-default" title="Duplicate Rig"><span
|
||||||
<dl class="dl-horizontal">
|
class="glyphicon glyphicon-duplicate"></span> <span
|
||||||
<dt>Person</dt>
|
class="hidden-xs">Duplicate</span></a>
|
||||||
<dd>
|
{% if event.is_rig %}
|
||||||
{% if object.person %}
|
{% if perms.RIGS.add_invoice %}
|
||||||
<a href="{% url 'person_detail' object.person.pk %}" class="modal-href">
|
<a id="invoiceDropdownLabel" href="{% url 'invoice_event' event.pk %}" class="btn
|
||||||
{{ object.person }}
|
{% if event.invoice and event.invoice.is_closed %}
|
||||||
</a>
|
btn-success
|
||||||
{% endif %}
|
{% elif event.invoice %}
|
||||||
</dd>
|
btn-warning
|
||||||
|
{% else %}
|
||||||
<dt>Email</dt>
|
btn-danger
|
||||||
<dd>
|
{% endif %}
|
||||||
<a href="mailto:{{object.person.email}}" target="_blank">
|
" title="Invoice Rig"><span
|
||||||
<span class="overflow-ellipsis">{{ object.person.email }}</span>
|
class="glyphicon glyphicon-gbp"></span>
|
||||||
</a>
|
<span class="hidden-xs">Invoice</span></a>
|
||||||
</dd>
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
<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">Organisation</div>
|
<div class="panel-heading">Contact Details</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
<dt>Organisation</dt>
|
<dt>Person</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{% if object.organisation %}
|
{% if object.person %}
|
||||||
<a href="{% url 'organisation_detail' object.organisation.pk %}" class="modal-href">
|
<a href="{% url 'person_detail' object.person.pk %}" class="modal-href">
|
||||||
{{ object.organisation }}
|
{{ object.person }}
|
||||||
</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>
|
<dd><a href="tel:{{ object.person.phone }}">{{ object.person.phone }}</a></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>
|
||||||
{% endif %}
|
{% if event.organisation %}
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">Organisation</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>Organisation</dt>
|
||||||
|
<dd>
|
||||||
|
{% if object.organisation %}
|
||||||
|
<a href="{% url 'organisation_detail' object.organisation.pk %}"
|
||||||
|
class="modal-href">
|
||||||
|
{{ object.organisation }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
|
|
||||||
{% if event.is_rig and event.internal %}
|
<dt>Phone Number</dt>
|
||||||
<div class="panel panel-default">
|
<dd>
|
||||||
<div class="panel-heading">Client Authorisation</div>
|
<a href="tel:{{ object.person.phone }}">
|
||||||
<div class="panel-body">
|
{{ object.organisation.phone }}
|
||||||
<dl class="dl-horizontal">
|
</a>
|
||||||
<dt>Authorised</dt>
|
</dd>
|
||||||
<dd>{{ object.authorised|yesno:"Yes,No" }}</dd>
|
|
||||||
|
|
||||||
<dt>Authorised by</dt>
|
<dt>Has SU Account</dt>
|
||||||
<dd>
|
<dd>{{ event.organisation.union_account|yesno|capfirst }}</dd>
|
||||||
{% if object.authorisation %}
|
</dl>
|
||||||
{{ object.authorisation.name }}
|
</div>
|
||||||
(<a href="mailto:{{ object.authorisation.email }}">{{ object.authorisation.email }}</a>)
|
|
||||||
{% endif %}
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>Authorised at</dt>
|
|
||||||
<dd>{{ object.authorisation.last_edited_at }}</dd>
|
|
||||||
|
|
||||||
<dt>Authorised amount</dt>
|
|
||||||
<dd>
|
|
||||||
{% if object.authorisation %}
|
|
||||||
£ {{ object.authorisation.amount|floatformat:"2" }}
|
|
||||||
{% endif %}
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>Requested by</dt>
|
|
||||||
<dd>{{ object.authorisation.sent_by }}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% endif %}
|
||||||
{% endif %}
|
</div>
|
||||||
</div>
|
{% endif %}
|
||||||
{% endif %}
|
<div class="col-sm-12 {% if event.is_rig %}col-md-6 col-lg-7{% 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 panel-info">
|
<div class="panel-heading">Event Info</div>
|
||||||
<div class="panel-heading">Event Info</div>
|
<div class="panel-body">
|
||||||
<div class="panel-body">
|
<dl class="dl-horizontal">
|
||||||
<dl class="dl-horizontal">
|
<dt>Event Venue</dt>
|
||||||
<dt>Event Venue</dt>
|
|
||||||
<dd>
|
|
||||||
{% if object.venue %}
|
|
||||||
<a href="{% url 'venue_detail' object.venue.pk %}" class="modal-href">
|
|
||||||
{{ object.venue }}
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
{% if event.is_rig %}
|
|
||||||
<dt>Event MIC</dt>
|
|
||||||
<dd>
|
<dd>
|
||||||
{% if event.mic and perms.RIGS.view_profile %}
|
{% if object.venue %}
|
||||||
<a href="{% url 'profile_detail' event.mic.pk %}" class="modal-href">
|
<a href="{% url 'venue_detail' object.venue.pk %}" class="modal-href">
|
||||||
{{ event.mic.name }}
|
{{ object.venue }}
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
|
||||||
{{ event.mic.name }}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dd>
|
</dd>
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<dt>Status</dt>
|
{% if event.is_rig %}
|
||||||
<dd>{{ event.get_status_display }}</dd>
|
<dt>Event MIC</dt>
|
||||||
|
<dd>
|
||||||
<dd> </dd>
|
{% if event.mic and perms.RIGS.view_profile %}
|
||||||
|
<a href="{% url 'profile_detail' event.mic.pk %}" class="modal-href">
|
||||||
{% if event.is_rig %}
|
{{ event.mic.name }}
|
||||||
<dt>Crew Meet</dt>
|
</a>
|
||||||
<dd>{{ event.meet_at|date:"D d M Y H:i"|default:"" }}</dd>
|
{% else %}
|
||||||
<dd>{{ event.meet_info|default:"" }}</dd>
|
{{ event.mic.name }}
|
||||||
|
{% endif %}
|
||||||
<dt>Access From</dt>
|
</dd>
|
||||||
<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 %}
|
||||||
</dd>
|
|
||||||
|
|
||||||
{% 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 %}
|
|
||||||
<dt>Collected By</dt>
|
|
||||||
<dd>{{ object.collector }}</dd>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if event.is_rig %}
|
|
||||||
<dd> </dd>
|
<dd> </dd>
|
||||||
|
|
||||||
{% if object.internal %}
|
{% if event.is_rig %}
|
||||||
<dt>Authorisation Request</dt>
|
<dt>Crew Meet</dt>
|
||||||
<dd>{{ object.auth_request_to|yesno:"Yes,No" }}</dd>
|
<dd>{{ event.meet_at|date:"D d M Y H:i"|default:"" }}</dd>
|
||||||
|
<dd>{{ event.meet_info|default:"" }}</dd>
|
||||||
|
|
||||||
<dt>By</dt>
|
<dt>Access From</dt>
|
||||||
<dd>{{ object.auth_request_by }}</dd>
|
<dd>{{ event.access_at|date:"D d M Y H:i"|default:"" }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<dt>At</dt>
|
<dt>Event Starts</dt>
|
||||||
<dd>{{ object.auth_request_at|date:"D d M Y H:i"|default:"" }}</dd>
|
<dd>{{ event.start_date|date:"D d M Y" }} {{ event.start_time|date:"H:i" }}</dd>
|
||||||
|
|
||||||
<dt>To</dt>
|
<dt>Event Ends</dt>
|
||||||
<dd>{{ object.auth_request_to }}</dd>
|
<dd>{{ event.end_date|date:"D d M Y" }} {{ event.end_time|date:"H:i" }}</dd>
|
||||||
|
|
||||||
{% else %}
|
<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 %}
|
||||||
|
</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>
|
<dt>PO</dt>
|
||||||
<dd>{{ object.purchase_order }}</dd>
|
<dd>{{ object.purchase_order }}</dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
</dl>
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% if not request.is_ajax %}
|
|
||||||
<div class="col-sm-12 text-right">
|
|
||||||
{% include 'RIGS/event_detail_buttons.html' %}
|
|
||||||
</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">
|
||||||
{% include 'RIGS/event_detail_buttons.html' %}
|
<div class="btn-group btn-page">
|
||||||
</div>
|
<a href="{% url 'event_update' event.pk %}" class="btn btn-default"><span
|
||||||
{% endif %}
|
class="glyphicon glyphicon-edit"></span> <span
|
||||||
{% endif %}
|
class="hidden-xs">Edit</span></a>
|
||||||
{% if not request.is_ajax %}
|
{% if event.is_rig %}
|
||||||
<div class="col-sm-12 text-right">
|
<a href="{% url 'event_print' event.pk %}" target="_blank" class="btn btn-default"><span
|
||||||
<div>
|
class="glyphicon glyphicon-print"></span> <span
|
||||||
<a href="{% url 'event_history' object.pk %}" title="View Revision History">
|
class="hidden-xs">Print</span></a>
|
||||||
Last edited at {{ object.last_edited_at }} by {{ object.last_edited_by.name }}
|
{% endif %}
|
||||||
</a>
|
<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>
|
</div>
|
||||||
</div>
|
{% endif %}
|
||||||
{% endif %}
|
{% if event.is_rig %}
|
||||||
</div>
|
<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>
|
||||||
|
{% 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 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 %}
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
<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 %}
|
|
||||||
{% if not event.dry_hire %}
|
|
||||||
<a href="{% url 'event_ra' event.pk %}" class="btn btn-default
|
|
||||||
{% if event.risk_assessment_edit_url %}
|
|
||||||
btn-success
|
|
||||||
{% else %}
|
|
||||||
btn-warning
|
|
||||||
{% endif %}
|
|
||||||
"><span
|
|
||||||
class="glyphicon glyphicon-paperclip"></span> <span
|
|
||||||
class="hidden-xs">RA</span></a>
|
|
||||||
{% endif %}
|
|
||||||
<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 event.internal %}
|
|
||||||
<a class="btn btn-default item-add modal-href event-authorise-request
|
|
||||||
{% if event.authorised %}
|
|
||||||
btn-success
|
|
||||||
{% elif event.authorisation and event.authorisation.amount != event.total and event.authorisation.last_edited_at > event.auth_request_at %}
|
|
||||||
btn-warning
|
|
||||||
{% elif event.auth_request_to %}
|
|
||||||
btn-info
|
|
||||||
{% endif %}
|
|
||||||
"
|
|
||||||
href="{% url 'event_authorise_request' object.pk %}">
|
|
||||||
<span class="glyphicon glyphicon-send"></span>
|
|
||||||
<span class="hidden-xs">
|
|
||||||
{% if event.authorised %}
|
|
||||||
Authorised
|
|
||||||
{% elif event.authorisation and event.authorisation.amount != event.total and event.authorisation.last_edited_at > event.auth_request_at %}
|
|
||||||
Authorisation Issue
|
|
||||||
{% elif event.auth_request_to %}
|
|
||||||
Awaiting Authorisation
|
|
||||||
{% else %}
|
|
||||||
Request Authorisation
|
|
||||||
{% endif %}
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% 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>
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
{% extends 'base_embed.html' %}
|
|
||||||
{% load static from staticfiles %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<a href="/">
|
|
||||||
<span class="source"> R<small>ig</small> I<small>nformation</small> G<small>athering</small> S<small>ystem</small></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<span class="pull-right">
|
|
||||||
{% if object.mic %}
|
|
||||||
<div class="text-center">
|
|
||||||
<img src="{{ object.mic.profile_picture }}" class="event-mic-photo img-rounded"/>
|
|
||||||
</div>
|
|
||||||
{% elif object.is_rig %}
|
|
||||||
<span class="glyphicon glyphicon-exclamation-sign"></span>
|
|
||||||
{% endif %}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<h3>
|
|
||||||
<a {% if perms.RIGS.view_event %}href="{% url 'event_detail' object.pk %}"{% endif %}>
|
|
||||||
{% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}{% endif %}
|
|
||||||
| {{ object.name }} </a>
|
|
||||||
{% if object.venue %}
|
|
||||||
<small>at {{ object.venue }}</small>
|
|
||||||
{% endif %}
|
|
||||||
<br/><small>
|
|
||||||
{{ object.start_date|date:"D d/m/Y" }}
|
|
||||||
{% if object.has_start_time %}
|
|
||||||
{{ object.start_time|date:"H:i" }}
|
|
||||||
{% endif %}
|
|
||||||
{% if object.end_date or object.has_end_time %}
|
|
||||||
–
|
|
||||||
{% endif %}
|
|
||||||
{% if object.end_date and object.end_date != object.start_date %}
|
|
||||||
{{ object.end_date|date:"D d/m/Y" }}
|
|
||||||
{% endif %}
|
|
||||||
{% if object.has_end_time %}
|
|
||||||
{{ object.end_time|date:"H:i" }}
|
|
||||||
{% endif %}
|
|
||||||
</small>
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xs-6">
|
|
||||||
<p>
|
|
||||||
<strong>Status:</strong>
|
|
||||||
{{ object.get_status_display }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
{% if object.is_rig %}
|
|
||||||
<strong>Client:</strong> {{ object.person.name }}
|
|
||||||
{% if object.organisation %}
|
|
||||||
for {{ object.organisation.name }}
|
|
||||||
{% endif %}
|
|
||||||
{% if object.dry_hire %}(Dry Hire){% endif %}
|
|
||||||
{% else %}
|
|
||||||
<strong>Non-Rig</strong>
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>MIC:</strong>
|
|
||||||
{% if object.mic %}
|
|
||||||
{{object.mic.name}}
|
|
||||||
{% else %}
|
|
||||||
None
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-6">
|
|
||||||
|
|
||||||
{% if object.meet_at %}
|
|
||||||
<p>
|
|
||||||
<strong>Crew meet:</strong>
|
|
||||||
{{ object.meet_at|date:"H:i" }} {{ object.meet_at|date:"(Y-m-d)" }}
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
{% if object.access_at %}
|
|
||||||
<p>
|
|
||||||
<strong>Access at:</strong>
|
|
||||||
{{ object.access_at|date:"H:i" }} {{ object.access_at|date:"(Y-m-d)" }}
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
<p>
|
|
||||||
<strong>Last updated:</strong>
|
|
||||||
{{ object.last_edited_at }} by "{{ object.last_edited_by.initials }}"
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% if object.description %}
|
|
||||||
<p>
|
|
||||||
<strong>Description: </strong>
|
|
||||||
{{ object.description|linebreaksbr }}
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
@@ -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 () {
|
||||||
@@ -74,33 +74,34 @@
|
|||||||
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,
|
||||||
});
|
});
|
||||||
@@ -113,168 +114,90 @@
|
|||||||
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>
|
||||||
</div>
|
{% include 'form_errors.html' %}
|
||||||
{% include 'form_errors.html' %}
|
{% render_field form.is_rig style="display: none" %}
|
||||||
{% render_field form.is_rig style="display: none" %}
|
<input type="hidden" name="{{ form.items_json.name }}" id="{{ form.items_json.id_for_label }}"
|
||||||
<input type="hidden" name="{{ form.items_json.name }}" id="{{ form.items_json.id_for_label }}"
|
value="{{ form.items_json.value }}"/>
|
||||||
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>
|
||||||
</div>
|
{% endif %}
|
||||||
<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>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
{# Contact details #}
|
||||||
{% render_field form.description class+="form-control" %}
|
<div class="col-sm-12 col-md-6">
|
||||||
</div>
|
<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">
|
||||||
<!-- /.col-sm-12 .col-md-6 -->
|
<label for="{{ form.person.id_for_label }}"
|
||||||
|
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.venue.id_for_label }}" name="{{ form.venue.name }}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='venue' %}">
|
<select id="{{ form.person.id_for_label }}" name="{{ form.person.name }}"
|
||||||
{% if venue %}
|
class="form-control selectpicker" data-live-search="true"
|
||||||
<option value="{{form.venue.value}}" selected="selected" data-update_url="{% url 'venue_update' form.venue.value %}">{{ venue }}</option>
|
data-sourceurl="{% url 'api_secure' model='person' %}">
|
||||||
{% endif %}
|
{% if person %}
|
||||||
|
<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 'venue_create' %}" class="btn btn-default modal-href"
|
<a href="{% url 'person_create' %}" class="btn btn-default modal-href"
|
||||||
data-target="#{{ form.venue.id_for_label }}">
|
data-target="#{{ form.person.id_for_label }}">
|
||||||
<span class="glyphicon glyphicon-plus"></span>
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
</a>
|
</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 }}">
|
<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>
|
<span class="glyphicon glyphicon-pencil"></span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -282,167 +205,292 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group" data-toggle="tooltip"
|
||||||
<label for="{{ form.start_date.id_for_label }}"
|
title="The client organisation, leave blank if client is an individual">
|
||||||
class="col-sm-4 control-label">{{ form.start_date.label }}</label>
|
<label for="{{ form.organisation.id_for_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-12 col-md-7" data-toggle="tooltip" title="Start date for event, required">
|
<div class="col-sm-9 col-md-7 col-lg-8">
|
||||||
{% render_field form.start_date class+="form-control" %}
|
<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>
|
||||||
<div class="col-sm-12 col-md-5" data-toggle="tooltip" title="Start time of event, can be left blank">
|
<div class="col-sm-3 col-md-5 col-lg-4 align-right">
|
||||||
{% render_field form.start_time class+="form-control" %}
|
<div class="btn-group">
|
||||||
</div>
|
<a href="{% url 'organisation_create' %}" class="btn btn-default modal-href"
|
||||||
</div>
|
data-target="#{{ form.organisation.id_for_label }}">
|
||||||
</div>
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
</div>
|
</a>
|
||||||
<div class="form-group">
|
<a href="
|
||||||
<label for="{{ form.end_date.id_for_label }}"
|
|
||||||
class="col-sm-4 control-label">{{ form.end_date.label }}</label>
|
|
||||||
|
|
||||||
<div class="col-sm-8">
|
{% if form.organisation.value %}{% url 'organisation_update' form.organisation.value %}{% endif %}"
|
||||||
<div class="row">
|
class="btn btn-default modal-href"
|
||||||
<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">
|
id="{{ form.organisation.id_for_label }}-update"
|
||||||
{% render_field form.end_date class+="form-control" %}
|
data-target="#{{ form.organisation.id_for_label }}">
|
||||||
</div>
|
<span class="glyphicon glyphicon-pencil"></span>
|
||||||
<div class="col-sm-12 col-md-5" data-toggle="tooltip" title="End time of event, leave blank if unknown">
|
</a>
|
||||||
{% render_field form.end_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>
|
||||||
|
</div>
|
||||||
|
</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>
|
||||||
|
|
||||||
{# Rig only information #}
|
<div class="col-sm-8">
|
||||||
<div class="form-is_rig {% if object.pk and not object.is_rig %}hidden{% endif %}">
|
{% render_field form.description class+="form-control" %}
|
||||||
<div class="form-group" data-toggle="tooltip" title="The date/time at which TEC have access to the venue">
|
</div>
|
||||||
<label for="{{ form.access_at.id_for_label }}"
|
</div>
|
||||||
class="col-sm-4 control-label">{{ form.access_at.label }}</label>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- /.col-sm-12 .col-md-6 -->
|
||||||
|
|
||||||
|
{# 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">
|
<div class="col-sm-8">
|
||||||
{% render_field form.access_at class+="form-control" %}
|
{% render_field form.name class+="form-control" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group" data-toggle="tooltip" title="The date/time at which crew should meet for this event">
|
<div class="form-group" data-toggle="tooltip"
|
||||||
<label for="{{ form.meet_at.id_for_label }}"
|
title="The venue for the rig, leave blank if unknown (e.g. for a dry hire)">
|
||||||
class="col-sm-4 control-label">{{ form.meet_at.label }}</label>
|
<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">
|
||||||
{% render_field form.meet_at class+="form-control" %}
|
<div class="row">
|
||||||
</div>
|
<div class="col-sm-9 col-md-7 col-lg-8">
|
||||||
</div>
|
<select id="{{ form.venue.id_for_label }}" name="{{ form.venue.name }}"
|
||||||
<div class="form-group">
|
class="form-control selectpicker" data-live-search="true"
|
||||||
<div class="col-sm-offset-4 col-sm-8">
|
data-sourceurl="{% url 'api_secure' model='venue' %}">
|
||||||
<div class="checkbox">
|
{% if venue %}
|
||||||
<label data-toggle="tooltip" title="Mark this event as a dry-hire, so it needs to be checked in at the end">
|
<option value="{{ form.venue.value }}" selected="selected"
|
||||||
{% render_field form.dry_hire %}{{ form.dry_hire.label }}
|
data-update_url="{% url 'venue_update' form.venue.value %}">{{ venue }}</option>
|
||||||
</label>
|
{% 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>
|
||||||
</div>
|
<div class="form-group">
|
||||||
|
<label for="{{ form.start_date.id_for_label }}"
|
||||||
{# Status is needed on all events types and it looks good here in the form #}
|
class="col-sm-4 control-label">{{ form.start_date.label }}</label>
|
||||||
<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">
|
||||||
<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="row">
|
||||||
{% if mic %}
|
<div class="col-sm-12 col-md-7" data-toggle="tooltip"
|
||||||
<option value="{{form.mic.value}}" selected="selected" >{{ mic.name }}</option>
|
title="Start date for event, required">
|
||||||
{% endif %}
|
{% render_field form.start_date type="date" class+="form-control" %}
|
||||||
</select>
|
</div>
|
||||||
|
<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>
|
||||||
|
|
||||||
{% if object.dry_hire %}
|
{# Rig only information #}
|
||||||
<div class="form-group" data-toggle="tooltip" title="The person who checked-in this dry hire">
|
<div class="form-is_rig {% if object.pk and not object.is_rig %}hidden{% endif %}">
|
||||||
<label for="{{ form.checked_in_by.id_for_label }}"
|
<div class="form-group" data-toggle="tooltip"
|
||||||
class="col-sm-4 control-label">{{ form.checked_in_by.label }}</label>
|
title="The date/time at which TEC have access to the venue">
|
||||||
|
<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">
|
||||||
<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">
|
{% render_field form.access_at type="datetime-local" class+="form-control" %}
|
||||||
{% if checked_in_by %}
|
</div>
|
||||||
<option value="{{form.checked_in_by.value}}" selected="selected" >{{ checked_in_by.name }}</option>
|
</div>
|
||||||
|
<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 %}
|
|
||||||
|
|
||||||
<div class="form-group" data-toggle="tooltip" title="The student ID of the client who collected the dry-hire">
|
{% if object.dry_hire %}
|
||||||
<label for="{{ form.collector.id_for_label }}"
|
<div class="form-group" data-toggle="tooltip"
|
||||||
class="col-sm-4 control-label">{{ form.collector.label }}</label>
|
title="The person who checked-in this dry hire">
|
||||||
|
<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">
|
||||||
{% render_field form.collector 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">
|
||||||
|
{% 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>
|
<div class="form-group" data-toggle="tooltip"
|
||||||
|
title="The purchase order number (for external clients)">
|
||||||
|
<label for="{{ form.purchase_order.id_for_label }}"
|
||||||
|
class="col-sm-4 control-label">{{ form.purchase_order.label }}</label>
|
||||||
|
|
||||||
<div class="form-group" data-toggle="tooltip" title="The purchase order number (for external clients)">
|
<div class="col-sm-8">
|
||||||
<label for="{{ form.purchase_order.id_for_label }}"
|
{% render_field form.purchase_order class+="form-control" %}
|
||||||
class="col-sm-4 control-label">{{ form.purchase_order.label }}</label>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-8">
|
|
||||||
{% 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 -->
|
||||||
<!-- /.col-sm-12 .col-md-6 -->
|
<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">
|
<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>
|
||||||
class="glyphicon glyphicon-floppy-disk"></span>
|
</button>
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
{# Notes and item shit #}
|
|
||||||
<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-body">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<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">
|
|
||||||
<label for="{{ form.notes.id_for_label }}">{{ form.notes.label }}</label>
|
|
||||||
{% render_field form.notes class+="form-control" %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% include "RIGS/item_table.html" %}
|
|
||||||
</div>
|
</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 class="btn-group btn-page">
|
{# Notes and item shit #}
|
||||||
<button type="submit" class="btn btn-default" title="Save"><span
|
<div class="col-sm-12">
|
||||||
class="glyphicon glyphicon-floppy-disk"></span>
|
<div class="panel panel-default form-hws form-is_rig {% if object.pk and not object.is_rig %}hidden{% endif %}">
|
||||||
</button>
|
<div class="panel-body">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<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">
|
||||||
|
<label for="{{ form.notes.id_for_label }}">{{ form.notes.label }}</label>
|
||||||
|
{% render_field form.notes class+="form-control" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include "RIGS/item_table.html" %}
|
||||||
|
</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 class="btn-group btn-page">
|
||||||
|
<button type="submit" class="btn btn-default" title="Save"><span
|
||||||
|
class="glyphicon glyphicon-floppy-disk"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% include 'RIGS/item_modal.html' %}
|
{% include 'RIGS/item_modal.html' %}
|
||||||
|
|||||||
@@ -5,17 +5,17 @@
|
|||||||
{% block title %}Events for Invoice{% endblock %}
|
{% block title %}Events for Invoice{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
<script src="{% static "js/tooltip.js" %}"></script>
|
<script src="{% static "js/tooltip.js" %}"></script>
|
||||||
<script>
|
<script>
|
||||||
$(function () {
|
$(function () {
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% 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 ({{ count }} Events, £ {{ total|floatformat:2 }})</h2>
|
||||||
<p>These events have happened, but paperwork has not yet been sent to treasury</p>
|
<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">
|
||||||
@@ -54,22 +54,20 @@
|
|||||||
<td><a href="{% url 'event_detail' object.pk %}">N{{ object.pk|stringformat:"05d" }}</a><br>
|
<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>
|
<span class="text-muted">{{ object.get_status_display }}</span></td>
|
||||||
<td>{{ object.start_date }}</td>
|
<td>{{ object.start_date }}</td>
|
||||||
|
<td>{{ object.name }}</td>
|
||||||
<td>
|
<td>
|
||||||
{{ object.name }}
|
{% if object.organisation %}
|
||||||
{% if object.is_rig and perms.RIGS.view_event and object.authorised %}
|
{{ object.organisation.name }}
|
||||||
<span class="glyphicon glyphicon-check"></span>
|
<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 %}
|
{% endif %}
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>{{ object.sum_total|floatformat:2 }}</td>
|
||||||
{{ object.organisation.name }}
|
|
||||||
<br>
|
|
||||||
<span class="text-muted">{{ object.internal|yesno:'Internal,External' }}</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ object.sum_total|floatformat:2 }}
|
|
||||||
<br />
|
|
||||||
<span class="text-muted">{% if not object.internal %}{{ object.purchase_order }}{% endif %}</span>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
{% if object.mic %}
|
{% if object.mic %}
|
||||||
{{ object.mic.initials }}<br>
|
{{ object.mic.initials }}<br>
|
||||||
@@ -79,9 +77,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<a href="{% url 'invoice_event' object.pk %}"
|
<a href="{% url 'invoice_event' object.pk %}" class="btn btn-default" data-toggle="tooltip"
|
||||||
class="btn btn-default"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
title="'Invoice' this event - click this when paperwork has been sent to treasury">
|
title="'Invoice' this event - click this when paperwork has been sent to treasury">
|
||||||
<span class="glyphicon glyphicon-gbp"></span>
|
<span class="glyphicon glyphicon-gbp"></span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -16,29 +16,30 @@
|
|||||||
<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="page-head" alignment="center" fontName="OpenSans-Bold" fontSize="16" leading="18" spaceAfter="0"/>
|
<paraStyle name="invoice-head" alignment="center" fontName="OpenSans-Bold" fontSize="16" leading="18"
|
||||||
|
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.head_titles" fontName="OpenSans-Bold" fontSize="10" />
|
<paraStyle name="style.invoice_titles" fontName="OpenSans-Bold" fontSize="10"/>
|
||||||
<paraStyle name="style.head_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="headLayout">
|
<blockTableStyle id="invoiceLayout">
|
||||||
<blockValign value="top"/>
|
<blockValign value="top"/>
|
||||||
|
|
||||||
</blockTableStyle>
|
</blockTableStyle>
|
||||||
|
|
||||||
<blockTableStyle id="eventDetails">
|
<blockTableStyle id="eventDetails">
|
||||||
@@ -71,7 +72,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"/>
|
||||||
@@ -79,55 +80,64 @@
|
|||||||
</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" size="9"/>
|
<setFont name="OpenSans-Bold" size="22.5" leading="10"/>
|
||||||
<drawString x="137" y="760">Portland Building, University Park, Nottingham, NG7 2RD</drawString>
|
<drawString x="137" y="780">TEC PA & Lighting</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" />
|
|
||||||
<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{% if current_user %} by {{current_user.name}} |{% endif %} {% now "d/m/Y H:i" %} | {{object.current_version_id}}]
|
|
||||||
</drawCenteredString>
|
|
||||||
</pageGraphics>
|
|
||||||
|
|
||||||
<frame id="main" x1="50" y1="65" width="495" height="645"/>
|
|
||||||
</pageTemplate>
|
|
||||||
|
|
||||||
<pageTemplate id="Main">
|
<setFont name="OpenSans" size="10"/>
|
||||||
<pageGraphics>
|
{% if not invoice %}
|
||||||
<image file="RIGS/static/imgs/paperwork/corner-tr.jpg" x="395" y="642" height="200" width="200"/>
|
<drawCenteredString x="302.5" y="50">[{{ copy }} Copy]</drawCenteredString>{% endif %}
|
||||||
<image file="RIGS/static/imgs/paperwork/corner-bl.jpg" x="0" y="0" height="200" width="200"/>
|
<drawCenteredString x="302.5" y="38">[Page
|
||||||
|
<pageNumber/>
|
||||||
<setFont name="OpenSans" size="10"/>
|
of<getName id="lastPage" default="0"/>]
|
||||||
<drawCenteredString x="302.5" y="38">[Page <pageNumber/> of <getName id="lastPage" default="0" />]</drawCenteredString>
|
</drawCenteredString>
|
||||||
<setFont name="OpenSans" size="7" />
|
<setFont name="OpenSans" size="7"/>
|
||||||
<drawCenteredString x="302.5" y="26">
|
<drawCenteredString x="302.5" y="26">[Paperwork generated by {{ current_user.name }}
|
||||||
[Paperwork generated{% if current_user %} by {{current_user.name}} |{% endif %} {% now "d/m/Y H:i" %} | {{object.current_version_id}}]
|
| {% 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>
|
||||||
|
|||||||