mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-02-20 13:29:41 +00:00
Compare commits
66 Commits
optimisati
...
898c5f03e8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
898c5f03e8 | ||
|
c4fec483ae
|
|||
|
3028fb92d9
|
|||
| 215697ba64 | |||
|
d966bddfd7
|
|||
|
0d5e48b89c
|
|||
|
bd2c94d3e3
|
|||
|
21d09d951d
|
|||
|
014b00bc30
|
|||
|
3f8fc82260
|
|||
| 41c1c44754 | |||
|
8a2b107516
|
|||
|
f8c52803a5
|
|||
|
85d1850f08
|
|||
|
e146d9314a
|
|||
|
2c3dff79ba
|
|||
|
9ee8cd0f8b
|
|||
|
d3391d9e3e
|
|||
|
|
0086461d6c | ||
|
8bafeabe5f
|
|||
|
f214f9a835
|
|||
|
b31d53a3c5
|
|||
|
62a891c6ec
|
|||
|
8c0c0941c2
|
|||
|
abb0e35690
|
|||
|
bec0d4aee5
|
|||
|
f1e43b707e
|
|||
| 796f5b44b0 | |||
| 6458f016f0 | |||
| 9ca953423f | |||
|
|
4c5d958c6d | ||
| 85ca7b0880 | |||
|
44f9509eda
|
|||
|
a2be4cbe5e
|
|||
|
|
bb2f369ab5 | ||
|
2fdb2f260f
|
|||
|
6de3cb5d8c
|
|||
|
7c38af66f6
|
|||
|
f1a624ec8f
|
|||
|
ab01beb2cd
|
|||
|
11636809ca
|
|||
|
d7458f6366
|
|||
| febf9cf3ed | |||
| 3322a5ddf8 | |||
|
|
673bee4215 | ||
|
|
bab31107f7 | ||
|
|
2d8473b698 | ||
| d81ecd9015 | |||
| b42c583897 | |||
| 57e966826e | |||
|
6a5de4a9d6
|
|||
| 56bbf4c17c | |||
|
|
698f0be281 | ||
|
|
483f06e96f | ||
|
|
22193f3c39 | ||
|
|
59b63fe7aa | ||
| 5976ce9ea2 | |||
|
780d05e27c
|
|||
| 8cfa4bd79d | |||
|
36f83ee59b
|
|||
|
6d768832f4
|
|||
|
38da8642fa
|
|||
|
f75e1d5bfc
|
|||
|
3f959f8d56
|
|||
|
b63a01120b
|
|||
| 911336ceec |
5
.github/workflows/django.yml
vendored
5
.github/workflows/django.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
|||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.9
|
python-version: 3.9.1
|
||||||
- uses: actions/cache@v2
|
- uses: actions/cache@v2
|
||||||
id: pcache
|
id: pcache
|
||||||
with:
|
with:
|
||||||
@@ -27,8 +27,7 @@ jobs:
|
|||||||
${{ runner.os }}-pipenv-
|
${{ runner.os }}-pipenv-
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip pipenv
|
||||||
pip install pipenv
|
|
||||||
pipenv install -d
|
pipenv install -d
|
||||||
# if: steps.pcache.outputs.cache-hit != 'true'
|
# if: steps.pcache.outputs.cache-hit != 'true'
|
||||||
- name: Cache Static Files
|
- name: Cache Static Files
|
||||||
|
|||||||
13
Pipfile
13
Pipfile
@@ -19,11 +19,10 @@ cssselect = "~=1.1.0"
|
|||||||
cssutils = "~=1.0.2"
|
cssutils = "~=1.0.2"
|
||||||
dj-database-url = "~=0.5.0"
|
dj-database-url = "~=0.5.0"
|
||||||
dj-static = "~=0.0.6"
|
dj-static = "~=0.0.6"
|
||||||
Django = "~=3.1.5"
|
Django = "~=3.1.12"
|
||||||
django-debug-toolbar = "~=3.2"
|
django-debug-toolbar = "~=3.2"
|
||||||
django-filter = "~=2.4.0"
|
django-filter = "~=2.4.0"
|
||||||
django-ical = "~=1.7.1"
|
django-ical = "~=1.7.1"
|
||||||
django-recaptcha = "~=2.0.6"
|
|
||||||
django-recurrence = "~=1.10.3"
|
django-recurrence = "~=1.10.3"
|
||||||
django-registration-redux = "~=2.9"
|
django-registration-redux = "~=2.9"
|
||||||
django-reversion = "~=3.0.9"
|
django-reversion = "~=3.0.9"
|
||||||
@@ -35,11 +34,11 @@ gunicorn = "~=20.0.4"
|
|||||||
icalendar = "~=4.0.7"
|
icalendar = "~=4.0.7"
|
||||||
idna = "~=2.10"
|
idna = "~=2.10"
|
||||||
importlib-metadata = "~=3.4.0"
|
importlib-metadata = "~=3.4.0"
|
||||||
lxml = "~=4.6.2"
|
lxml = "~=4.6.5"
|
||||||
Markdown = "~=3.3.3"
|
Markdown = "~=3.3.3"
|
||||||
msgpack = "~=1.0.2"
|
msgpack = "~=1.0.2"
|
||||||
pep517 = "~=0.9.1"
|
pep517 = "~=0.9.1"
|
||||||
Pillow = "~=8.1.0"
|
Pillow = "~=8.3.2"
|
||||||
premailer = "~=3.7.0"
|
premailer = "~=3.7.0"
|
||||||
progress = "~=1.5"
|
progress = "~=1.5"
|
||||||
psutil = "~=5.8.0"
|
psutil = "~=5.8.0"
|
||||||
@@ -57,12 +56,12 @@ retrying = "~=1.3.3"
|
|||||||
simplejson = "~=3.17.2"
|
simplejson = "~=3.17.2"
|
||||||
six = "~=1.15.0"
|
six = "~=1.15.0"
|
||||||
soupsieve = "~=2.1"
|
soupsieve = "~=2.1"
|
||||||
sqlparse = "~=0.4.1"
|
sqlparse = "~=0.4.2"
|
||||||
static3 = "~=0.7.0"
|
static3 = "~=0.7.0"
|
||||||
svg2rlg = "~=0.3"
|
svg2rlg = "~=0.3"
|
||||||
tini = "~=3.0.1"
|
tini = "~=3.0.1"
|
||||||
tornado = "~=6.1"
|
tornado = "~=6.1"
|
||||||
urllib3 = "~=1.26.2"
|
urllib3 = "~=1.26.5"
|
||||||
whitenoise = "~=5.2.0"
|
whitenoise = "~=5.2.0"
|
||||||
yolk = "~=0.4.3"
|
yolk = "~=0.4.3"
|
||||||
"z3c.rml" = "~=4.1.2"
|
"z3c.rml" = "~=4.1.2"
|
||||||
@@ -77,6 +76,8 @@ zipp = "~=3.4.0"
|
|||||||
"zope.schema" = "~=6.0.1"
|
"zope.schema" = "~=6.0.1"
|
||||||
sentry-sdk = "*"
|
sentry-sdk = "*"
|
||||||
diff-match-patch = "*"
|
diff-match-patch = "*"
|
||||||
|
python-barcode = "*"
|
||||||
|
django-hCaptcha = "*"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
selenium = "~=3.141.0"
|
selenium = "~=3.141.0"
|
||||||
|
|||||||
1010
Pipfile.lock
generated
1010
Pipfile.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -65,8 +65,8 @@ INSTALLED_APPS = (
|
|||||||
'debug_toolbar',
|
'debug_toolbar',
|
||||||
'registration',
|
'registration',
|
||||||
'reversion',
|
'reversion',
|
||||||
'captcha',
|
|
||||||
'widget_tweaks',
|
'widget_tweaks',
|
||||||
|
'hcaptcha',
|
||||||
)
|
)
|
||||||
|
|
||||||
MIDDLEWARE = (
|
MIDDLEWARE = (
|
||||||
@@ -186,12 +186,13 @@ LOGOUT_URL = '/user/logout/'
|
|||||||
|
|
||||||
ACCOUNT_ACTIVATION_DAYS = 7
|
ACCOUNT_ACTIVATION_DAYS = 7
|
||||||
|
|
||||||
# reCAPTCHA settings
|
# CAPTCHA settings
|
||||||
RECAPTCHA_PUBLIC_KEY = env('RECAPTCHA_PUBLIC_KEY', default="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI") # If not set, use development key
|
if DEBUG or CI:
|
||||||
RECAPTCHA_PRIVATE_KEY = env('RECAPTCHA_PUBLIC_KEY', default="6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe") # If not set, use development key
|
HCAPTCHA_SITEKEY = '10000000-ffff-ffff-ffff-000000000001'
|
||||||
NOCAPTCHA = True
|
HCAPTCHA_SECRET = '0x0000000000000000000000000000000000000000'
|
||||||
|
else:
|
||||||
SILENCED_SYSTEM_CHECKS = ['captcha.recaptcha_test_key_error']
|
HCAPTCHA_SITEKEY = env('HCAPTCHA_SITEKEY')
|
||||||
|
HCAPTCHA_SECRET = env('HCAPTCHA_SECRET')
|
||||||
|
|
||||||
# Email
|
# Email
|
||||||
EMAILER_TEST = False
|
EMAILER_TEST = False
|
||||||
|
|||||||
@@ -33,20 +33,7 @@ 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
|
return self.model.objects.outstanding_invoices()
|
||||||
sql = "SELECT * FROM " \
|
|
||||||
"(SELECT " \
|
|
||||||
"(SELECT COUNT(p.amount) FROM \"RIGS_payment\" AS p WHERE p.invoice_id=\"RIGS_invoice\".id) AS \"payment_count\", " \
|
|
||||||
"(SELECT SUM(ei.cost * ei.quantity) FROM \"RIGS_eventitem\" AS ei WHERE ei.event_id=\"RIGS_invoice\".event_id) AS \"cost\", " \
|
|
||||||
"(SELECT SUM(p.amount) FROM \"RIGS_payment\" AS p WHERE p.invoice_id=\"RIGS_invoice\".id) AS \"payments\", " \
|
|
||||||
"\"RIGS_invoice\".\"id\", \"RIGS_invoice\".\"event_id\", \"RIGS_invoice\".\"invoice_date\", \"RIGS_invoice\".\"void\" FROM \"RIGS_invoice\") " \
|
|
||||||
"AS sub " \
|
|
||||||
"WHERE (((cost > 0.0) AND (payment_count=0)) OR (cost - payments) <> 0.0) AND void = '0'" \
|
|
||||||
"ORDER BY invoice_date"
|
|
||||||
|
|
||||||
query = self.model.objects.raw(sql)
|
|
||||||
|
|
||||||
return query
|
|
||||||
|
|
||||||
|
|
||||||
class InvoiceDetail(generic.DetailView):
|
class InvoiceDetail(generic.DetailView):
|
||||||
@@ -56,6 +43,12 @@ class InvoiceDetail(generic.DetailView):
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(InvoiceDetail, self).get_context_data(**kwargs)
|
context = super(InvoiceDetail, self).get_context_data(**kwargs)
|
||||||
context['page_title'] = "Invoice {} ({}) ".format(self.object.display_id, self.object.invoice_date.strftime("%d/%m/%Y"))
|
context['page_title'] = "Invoice {} ({}) ".format(self.object.display_id, self.object.invoice_date.strftime("%d/%m/%Y"))
|
||||||
|
if self.object.void:
|
||||||
|
context['page_title'] += "<span class='badge badge-warning float-right'>VOID</span>"
|
||||||
|
elif self.object.is_closed:
|
||||||
|
context['page_title'] += "<span class='badge badge-success float-right'>PAID</span>"
|
||||||
|
else:
|
||||||
|
context['page_title'] += "<span class='badge badge-info float-right'>OUTSTANDING</span>"
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@@ -173,24 +166,7 @@ class InvoiceWaiting(generic.ListView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return self.get_objects()
|
return self.model.objects.waiting_invoices()
|
||||||
|
|
||||||
def get_objects(self):
|
|
||||||
# TODO find a way to select items
|
|
||||||
events = self.model.objects.filter(
|
|
||||||
(
|
|
||||||
Q(start_date__lte=datetime.date.today(), end_date__isnull=True) | # Starts before with no end
|
|
||||||
Q(end_date__lte=datetime.date.today()) # Has end date, finishes before
|
|
||||||
) & Q(invoice__isnull=True) & # Has not already been invoiced
|
|
||||||
Q(is_rig=True) # Is a rig (not non-rig)
|
|
||||||
|
|
||||||
).order_by('start_date') \
|
|
||||||
.select_related('person',
|
|
||||||
'organisation',
|
|
||||||
'venue', 'mic') \
|
|
||||||
.prefetch_related('items')
|
|
||||||
|
|
||||||
return events
|
|
||||||
|
|
||||||
|
|
||||||
class InvoiceEvent(generic.View):
|
class InvoiceEvent(generic.View):
|
||||||
|
|||||||
14
RIGS/hs.py
14
RIGS/hs.py
@@ -70,6 +70,11 @@ class EventRiskAssessmentDetail(generic.DetailView):
|
|||||||
model = models.RiskAssessment
|
model = models.RiskAssessment
|
||||||
template_name = 'risk_assessment_detail.html'
|
template_name = 'risk_assessment_detail.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(EventRiskAssessmentDetail, self).get_context_data(**kwargs)
|
||||||
|
context['page_title'] = "Risk Assessment for Event <a href='{}'>{} {}</a>".format(self.object.event.get_absolute_url(), self.object.event.display_id, self.object.event.name)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
class EventRiskAssessmentList(generic.ListView):
|
class EventRiskAssessmentList(generic.ListView):
|
||||||
paginate_by = 20
|
paginate_by = 20
|
||||||
@@ -77,7 +82,7 @@ class EventRiskAssessmentList(generic.ListView):
|
|||||||
template_name = 'hs_object_list.html'
|
template_name = 'hs_object_list.html'
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return self.model.objects.order_by('reviewed_at').select_related('event')
|
return self.model.objects.exclude(event__status=models.Event.CANCELLED).order_by('reviewed_at').select_related('event')
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(EventRiskAssessmentList, self).get_context_data(**kwargs)
|
context = super(EventRiskAssessmentList, self).get_context_data(**kwargs)
|
||||||
@@ -107,7 +112,7 @@ class EventChecklistDetail(generic.DetailView):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(EventChecklistDetail, self).get_context_data(**kwargs)
|
context = super(EventChecklistDetail, self).get_context_data(**kwargs)
|
||||||
context['page_title'] = "Event Checklist for Event {} {}".format(self.object.event.display_id, self.object.event.name)
|
context['page_title'] = "Event Checklist for Event <a href='{}'>{} {}</a>".format(self.object.event.get_absolute_url(), self.object.event.display_id, self.object.event.name)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@@ -182,6 +187,9 @@ class EventChecklistList(generic.ListView):
|
|||||||
model = models.EventChecklist
|
model = models.EventChecklist
|
||||||
template_name = 'hs_object_list.html'
|
template_name = 'hs_object_list.html'
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return self.model.objects.exclude(event__status=models.Event.CANCELLED).order_by('reviewed_at').select_related('event')
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(EventChecklistList, self).get_context_data(**kwargs)
|
context = super(EventChecklistList, self).get_context_data(**kwargs)
|
||||||
context['title'] = 'Event Checklist'
|
context['title'] = 'Event Checklist'
|
||||||
@@ -210,7 +218,7 @@ class HSList(generic.ListView):
|
|||||||
template_name = 'hs_list.html'
|
template_name = 'hs_list.html'
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return models.Event.objects.all().order_by('-start_date').select_related('riskassessment').prefetch_related('checklists')
|
return models.Event.objects.all().exclude(status=models.Event.CANCELLED).order_by('-start_date').select_related('riskassessment').prefetch_related('checklists')
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(HSList, self).get_context_data(**kwargs)
|
context = super(HSList, self).get_context_data(**kwargs)
|
||||||
|
|||||||
67
RIGS/migrations/0040_auto_20210302_1148.py
Normal file
67
RIGS/migrations/0040_auto_20210302_1148.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# Generated by Django 3.1.7 on 2021-03-02 11:48
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def postgres_migration_prep(apps, schema_editor):
|
||||||
|
model = apps.get_model("RIGS", "Event")
|
||||||
|
for field in ["auth_request_to", "collector", "description", "notes", "purchase_order"]:
|
||||||
|
filter_param = {"{}__isnull".format(field): True}
|
||||||
|
update_param = {field: ""}
|
||||||
|
model.objects.filter(**filter_param).update(**update_param)
|
||||||
|
model = apps.get_model("RIGS", "EventAuthorisation")
|
||||||
|
for field in ["account_code", "uni_id"]:
|
||||||
|
filter_param = {"{}__isnull".format(field): True}
|
||||||
|
update_param = {field: ""}
|
||||||
|
model.objects.filter(**filter_param).update(**update_param)
|
||||||
|
model = apps.get_model("RIGS", "EventChecklist")
|
||||||
|
for field in ["extinguishers_location", "hs_location", "w1_description", "w2_description", "w3_description"]:
|
||||||
|
filter_param = {"{}__isnull".format(field): True}
|
||||||
|
update_param = {field: ""}
|
||||||
|
model.objects.filter(**filter_param).update(**update_param)
|
||||||
|
model = apps.get_model("RIGS", "EventItem")
|
||||||
|
for field in ["description"]:
|
||||||
|
filter_param = {"{}__isnull".format(field): True}
|
||||||
|
update_param = {field: ""}
|
||||||
|
model.objects.filter(**filter_param).update(**update_param)
|
||||||
|
model = apps.get_model("RIGS", "Organisation")
|
||||||
|
for field in ["address", "email", "notes", "phone"]:
|
||||||
|
filter_param = {"{}__isnull".format(field): True}
|
||||||
|
update_param = {field: ""}
|
||||||
|
model.objects.filter(**filter_param).update(**update_param)
|
||||||
|
model = apps.get_model("RIGS", "Payment")
|
||||||
|
for field in ["method"]:
|
||||||
|
filter_param = {"{}__isnull".format(field): True}
|
||||||
|
update_param = {field: ""}
|
||||||
|
model.objects.filter(**filter_param).update(**update_param)
|
||||||
|
model = apps.get_model("RIGS", "Person")
|
||||||
|
for field in ["address", "email", "notes", "phone"]:
|
||||||
|
filter_param = {"{}__isnull".format(field): True}
|
||||||
|
update_param = {field: ""}
|
||||||
|
model.objects.filter(**filter_param).update(**update_param)
|
||||||
|
model = apps.get_model("RIGS", "Profile")
|
||||||
|
for field in ["phone"]:
|
||||||
|
filter_param = {"{}__isnull".format(field): True}
|
||||||
|
update_param = {field: ""}
|
||||||
|
model.objects.filter(**filter_param).update(**update_param)
|
||||||
|
model = apps.get_model("RIGS", "RiskAssessment")
|
||||||
|
for field in ["general_notes", "persons_responsible_structures", "power_notes", "rigging_plan", "sound_notes"]:
|
||||||
|
filter_param = {"{}__isnull".format(field): True}
|
||||||
|
update_param = {field: ""}
|
||||||
|
model.objects.filter(**filter_param).update(**update_param)
|
||||||
|
model = apps.get_model("RIGS", "Venue")
|
||||||
|
for field in ["address", "email", "notes", "phone"]:
|
||||||
|
filter_param = {"{}__isnull".format(field): True}
|
||||||
|
update_param = {field: ""}
|
||||||
|
model.objects.filter(**filter_param).update(**update_param)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('RIGS', '0039_auto_20210123_1910'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(postgres_migration_prep, migrations.RunPython.noop)
|
||||||
|
]
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 3.1.5 on 2021-02-06 10:43
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0039_auto_20210123_1910'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='profile',
|
|
||||||
name='dark_theme',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 3.1.5 on 2021-02-08 16:03
|
# Generated by Django 3.1.7 on 2021-03-02 12:04
|
||||||
|
|
||||||
import RIGS.models
|
import RIGS.models
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
@@ -7,10 +7,27 @@ from django.db import migrations, models
|
|||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('RIGS', '0040_profile_dark_theme'),
|
('RIGS', '0040_auto_20210302_1148'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='event',
|
||||||
|
name='meet_info',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='event',
|
||||||
|
name='payment_method',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='event',
|
||||||
|
name='payment_received',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='profile',
|
||||||
|
name='dark_theme',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='auth_request_to',
|
name='auth_request_to',
|
||||||
@@ -26,26 +43,11 @@ class Migration(migrations.Migration):
|
|||||||
name='description',
|
name='description',
|
||||||
field=models.TextField(blank=True, default=''),
|
field=models.TextField(blank=True, default=''),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
|
||||||
model_name='event',
|
|
||||||
name='meet_info',
|
|
||||||
field=models.CharField(blank=True, default='', max_length=255),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='notes',
|
name='notes',
|
||||||
field=models.TextField(blank=True, default=''),
|
field=models.TextField(blank=True, default=''),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
|
||||||
model_name='event',
|
|
||||||
name='payment_method',
|
|
||||||
field=models.CharField(blank=True, default='', max_length=255),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='event',
|
|
||||||
name='payment_received',
|
|
||||||
field=models.CharField(blank=True, default='', max_length=255),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name='event',
|
||||||
name='purchase_order',
|
name='purchase_order',
|
||||||
@@ -144,7 +146,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='profile',
|
model_name='profile',
|
||||||
name='phone',
|
name='phone',
|
||||||
field=models.CharField(default='', max_length=13, null=True),
|
field=models.CharField(blank=True, default='', max_length=13),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='riskassessment',
|
model_name='riskassessment',
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 3.1.7 on 2021-03-02 11:21
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0041_auto_20210208_1603'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='profile',
|
|
||||||
name='phone',
|
|
||||||
field=models.CharField(blank=True, default='', max_length=13),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
34
RIGS/migrations/0042_auto_20211007_2338.py
Normal file
34
RIGS/migrations/0042_auto_20211007_2338.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Generated by Django 3.1.13 on 2021-10-07 22:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('RIGS', '0041_auto_20210302_1204'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='eventchecklist',
|
||||||
|
name='fd_earth_fault',
|
||||||
|
field=models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (Z<small>S</small>)', max_digits=5, null=True, verbose_name='Earth Fault Loop Impedance'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='eventchecklist',
|
||||||
|
name='w1_earth_fault',
|
||||||
|
field=models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (Z<small>S</small>)', max_digits=5, null=True, verbose_name='Earth Fault Loop Impedance'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='eventchecklist',
|
||||||
|
name='w2_earth_fault',
|
||||||
|
field=models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (Z<small>S</small>)', max_digits=5, null=True, verbose_name='Earth Fault Loop Impedance'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='eventchecklist',
|
||||||
|
name='w3_earth_fault',
|
||||||
|
field=models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (Z<small>S</small>)', max_digits=5, null=True, verbose_name='Earth Fault Loop Impedance'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
@@ -278,6 +278,19 @@ class EventManager(models.Manager):
|
|||||||
).count()
|
).count()
|
||||||
return event_count
|
return event_count
|
||||||
|
|
||||||
|
def waiting_invoices(self):
|
||||||
|
events = self.filter(
|
||||||
|
(
|
||||||
|
models.Q(start_date__lte=datetime.date.today(), end_date__isnull=True) | # Starts before with no end
|
||||||
|
models.Q(end_date__lte=datetime.date.today()) # Or has end date, finishes before
|
||||||
|
) & models.Q(invoice__isnull=True) & # Has not already been invoiced
|
||||||
|
models.Q(is_rig=True) # Is a rig (not non-rig)
|
||||||
|
).order_by('start_date') \
|
||||||
|
.select_related('person', 'organisation', 'venue', 'mic') \
|
||||||
|
.prefetch_related('items')
|
||||||
|
|
||||||
|
return events
|
||||||
|
|
||||||
|
|
||||||
@reversion.register(follow=['items'])
|
@reversion.register(follow=['items'])
|
||||||
class Event(models.Model, RevisionMixin):
|
class Event(models.Model, RevisionMixin):
|
||||||
@@ -312,7 +325,6 @@ class Event(models.Model, RevisionMixin):
|
|||||||
end_time = models.TimeField(blank=True, null=True)
|
end_time = models.TimeField(blank=True, null=True)
|
||||||
access_at = models.DateTimeField(blank=True, null=True)
|
access_at = models.DateTimeField(blank=True, null=True)
|
||||||
meet_at = models.DateTimeField(blank=True, null=True)
|
meet_at = models.DateTimeField(blank=True, null=True)
|
||||||
meet_info = models.CharField(max_length=255, blank=True, default='')
|
|
||||||
|
|
||||||
# Crew management
|
# Crew management
|
||||||
checked_in_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='event_checked_in', blank=True, null=True,
|
checked_in_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='event_checked_in', blank=True, null=True,
|
||||||
@@ -321,8 +333,6 @@ class Event(models.Model, RevisionMixin):
|
|||||||
verbose_name="MIC", on_delete=models.CASCADE)
|
verbose_name="MIC", on_delete=models.CASCADE)
|
||||||
|
|
||||||
# Monies
|
# Monies
|
||||||
payment_method = models.CharField(max_length=255, blank=True, default='')
|
|
||||||
payment_received = models.CharField(max_length=255, blank=True, default='')
|
|
||||||
purchase_order = models.CharField(max_length=255, blank=True, default='', verbose_name='PO')
|
purchase_order = models.CharField(max_length=255, blank=True, default='', verbose_name='PO')
|
||||||
collector = models.CharField(max_length=255, blank=True, default='', verbose_name='collected by')
|
collector = models.CharField(max_length=255, blank=True, default='', verbose_name='collected by')
|
||||||
|
|
||||||
@@ -333,10 +343,13 @@ class Event(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def display_id(self):
|
def display_id(self):
|
||||||
|
if self.pk:
|
||||||
if self.is_rig:
|
if self.is_rig:
|
||||||
return str("N%05d" % self.pk)
|
return str("N%05d" % self.pk)
|
||||||
else:
|
else:
|
||||||
return self.pk
|
return self.pk
|
||||||
|
else:
|
||||||
|
return "????"
|
||||||
|
|
||||||
# Calculated values
|
# Calculated values
|
||||||
"""
|
"""
|
||||||
@@ -359,6 +372,9 @@ class Event(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def vat(self):
|
def vat(self):
|
||||||
|
# No VAT is owed on internal transfers
|
||||||
|
if self.internal:
|
||||||
|
return 0
|
||||||
return Decimal(self.sum_total * self.vat_rate.rate).quantize(Decimal('.01'))
|
return Decimal(self.sum_total * self.vat_rate.rate).quantize(Decimal('.01'))
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -529,6 +545,23 @@ class EventAuthorisation(models.Model, RevisionMixin):
|
|||||||
return "{} (requested by {})".format(self.event.display_id, self.sent_by.initials)
|
return "{} (requested by {})".format(self.event.display_id, self.sent_by.initials)
|
||||||
|
|
||||||
|
|
||||||
|
class InvoiceManager(models.Manager):
|
||||||
|
def outstanding_invoices(self):
|
||||||
|
# Manual query is the only way I have found to do this efficiently. Not ideal but needs must
|
||||||
|
sql = "SELECT * FROM " \
|
||||||
|
"(SELECT " \
|
||||||
|
"(SELECT COUNT(p.amount) FROM \"RIGS_payment\" AS p WHERE p.invoice_id=\"RIGS_invoice\".id) AS \"payment_count\", " \
|
||||||
|
"(SELECT SUM(ei.cost * ei.quantity) FROM \"RIGS_eventitem\" AS ei WHERE ei.event_id=\"RIGS_invoice\".event_id) AS \"cost\", " \
|
||||||
|
"(SELECT SUM(p.amount) FROM \"RIGS_payment\" AS p WHERE p.invoice_id=\"RIGS_invoice\".id) AS \"payments\", " \
|
||||||
|
"\"RIGS_invoice\".\"id\", \"RIGS_invoice\".\"event_id\", \"RIGS_invoice\".\"invoice_date\", \"RIGS_invoice\".\"void\" FROM \"RIGS_invoice\") " \
|
||||||
|
"AS sub " \
|
||||||
|
"WHERE (((cost > 0.0) AND (payment_count=0)) OR (cost - payments) <> 0.0) AND void = '0'" \
|
||||||
|
"ORDER BY invoice_date"
|
||||||
|
|
||||||
|
query = self.raw(sql)
|
||||||
|
return query
|
||||||
|
|
||||||
|
|
||||||
@reversion.register(follow=['payment_set'])
|
@reversion.register(follow=['payment_set'])
|
||||||
class Invoice(models.Model, RevisionMixin):
|
class Invoice(models.Model, RevisionMixin):
|
||||||
event = models.OneToOneField('Event', on_delete=models.CASCADE)
|
event = models.OneToOneField('Event', on_delete=models.CASCADE)
|
||||||
@@ -537,6 +570,8 @@ class Invoice(models.Model, RevisionMixin):
|
|||||||
|
|
||||||
reversion_perm = 'RIGS.view_invoice'
|
reversion_perm = 'RIGS.view_invoice'
|
||||||
|
|
||||||
|
objects = InvoiceManager()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sum_total(self):
|
def sum_total(self):
|
||||||
return self.event.sum_total
|
return self.event.sum_total
|
||||||
@@ -767,21 +802,21 @@ class EventChecklist(models.Model, RevisionMixin):
|
|||||||
fd_voltage_l2 = models.IntegerField(blank=True, null=True, verbose_name="First Distro Voltage L2-N", help_text="L2 - N")
|
fd_voltage_l2 = models.IntegerField(blank=True, null=True, verbose_name="First Distro Voltage L2-N", help_text="L2 - N")
|
||||||
fd_voltage_l3 = models.IntegerField(blank=True, null=True, verbose_name="First Distro Voltage L3-N", help_text="L3 - N")
|
fd_voltage_l3 = models.IntegerField(blank=True, null=True, verbose_name="First Distro Voltage L3-N", help_text="L3 - N")
|
||||||
fd_phase_rotation = models.BooleanField(blank=True, null=True, verbose_name="Phase Rotation", help_text="Phase Rotation<br><small>(if required)</small>")
|
fd_phase_rotation = models.BooleanField(blank=True, null=True, verbose_name="Phase Rotation", help_text="Phase Rotation<br><small>(if required)</small>")
|
||||||
fd_earth_fault = models.IntegerField(blank=True, null=True, verbose_name="Earth Fault Loop Impedance", help_text="Earth Fault Loop Impedance (Z<small>S</small>)")
|
fd_earth_fault = models.DecimalField(blank=True, null=True, max_digits=5, decimal_places=2, verbose_name="Earth Fault Loop Impedance", help_text="Earth Fault Loop Impedance (Z<small>S</small>)")
|
||||||
fd_pssc = models.IntegerField(blank=True, null=True, verbose_name="PSCC", help_text="Prospective Short Circuit Current")
|
fd_pssc = models.IntegerField(blank=True, null=True, verbose_name="PSCC", help_text="Prospective Short Circuit Current")
|
||||||
# Worst case points
|
# Worst case points
|
||||||
w1_description = models.CharField(blank=True, default='', max_length=255, help_text="Description")
|
w1_description = models.CharField(blank=True, default='', max_length=255, help_text="Description")
|
||||||
w1_polarity = models.BooleanField(blank=True, null=True, help_text="Polarity Checked?")
|
w1_polarity = models.BooleanField(blank=True, null=True, help_text="Polarity Checked?")
|
||||||
w1_voltage = models.IntegerField(blank=True, null=True, help_text="Voltage")
|
w1_voltage = models.IntegerField(blank=True, null=True, help_text="Voltage")
|
||||||
w1_earth_fault = models.IntegerField(blank=True, null=True, help_text="Earth Fault Loop Impedance (Z<small>S</small>)")
|
w1_earth_fault = models.DecimalField(blank=True, null=True, max_digits=5, decimal_places=2, verbose_name="Earth Fault Loop Impedance", help_text="Earth Fault Loop Impedance (Z<small>S</small>)")
|
||||||
w2_description = models.CharField(blank=True, default='', max_length=255, help_text="Description")
|
w2_description = models.CharField(blank=True, default='', max_length=255, help_text="Description")
|
||||||
w2_polarity = models.BooleanField(blank=True, null=True, help_text="Polarity Checked?")
|
w2_polarity = models.BooleanField(blank=True, null=True, help_text="Polarity Checked?")
|
||||||
w2_voltage = models.IntegerField(blank=True, null=True, help_text="Voltage")
|
w2_voltage = models.IntegerField(blank=True, null=True, help_text="Voltage")
|
||||||
w2_earth_fault = models.IntegerField(blank=True, null=True, help_text="Earth Fault Loop Impedance (Z<small>S</small>)")
|
w2_earth_fault = models.DecimalField(blank=True, null=True, max_digits=5, decimal_places=2, verbose_name="Earth Fault Loop Impedance", help_text="Earth Fault Loop Impedance (Z<small>S</small>)")
|
||||||
w3_description = models.CharField(blank=True, default='', max_length=255, help_text="Description")
|
w3_description = models.CharField(blank=True, default='', max_length=255, help_text="Description")
|
||||||
w3_polarity = models.BooleanField(blank=True, null=True, help_text="Polarity Checked?")
|
w3_polarity = models.BooleanField(blank=True, null=True, help_text="Polarity Checked?")
|
||||||
w3_voltage = models.IntegerField(blank=True, null=True, help_text="Voltage")
|
w3_voltage = models.IntegerField(blank=True, null=True, help_text="Voltage")
|
||||||
w3_earth_fault = models.IntegerField(blank=True, null=True, help_text="Earth Fault Loop Impedance (Z<small>S</small>)")
|
w3_earth_fault = models.DecimalField(blank=True, null=True, max_digits=5, decimal_places=2, verbose_name="Earth Fault Loop Impedance", help_text="Earth Fault Loop Impedance (Z<small>S</small>)")
|
||||||
|
|
||||||
all_rcds_tested = models.BooleanField(blank=True, null=True, help_text="All circuit RCDs tested?<br><small>(using test button)</small>")
|
all_rcds_tested = models.BooleanField(blank=True, null=True, help_text="All circuit RCDs tested?<br><small>(using test button)</small>")
|
||||||
public_sockets_tested = models.BooleanField(blank=True, null=True, help_text="Public/Performer accessible circuits tested?<br><small>(using socket tester)</small>")
|
public_sockets_tested = models.BooleanField(blank=True, null=True, help_text="Public/Performer accessible circuits tested?<br><small>(using socket tester)</small>")
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ class EventDuplicate(EventUpdate):
|
|||||||
# Clear checked in by if it's a dry hire
|
# Clear checked in by if it's a dry hire
|
||||||
if new.dry_hire is True:
|
if new.dry_hire is True:
|
||||||
new.checked_in_by = None
|
new.checked_in_by = None
|
||||||
|
new.collector = None
|
||||||
|
|
||||||
# Remove all the authorisation information from the new event
|
# Remove all the authorisation information from the new event
|
||||||
new.auth_request_to = ''
|
new.auth_request_to = ''
|
||||||
|
|||||||
BIN
RIGS/static/imgs/square_logo.png
Normal file
BIN
RIGS/static/imgs/square_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
RIGS/static/imgs/wof2014-1-small.jpg
Normal file
BIN
RIGS/static/imgs/wof2014-1-small.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 164 KiB |
@@ -1,9 +1,12 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
{% load invoices_waiting from filters %}
|
||||||
|
{% load invoices_outstanding from filters %}
|
||||||
|
{% load total_invoices_todo from filters %}
|
||||||
|
|
||||||
{% block titleheader %}
|
{% block titleheader %}
|
||||||
<a class="navbar-brand" href="/">RIGS</a>
|
<a class="navbar-brand" style="margin-left: auto; margin-right: auto;" href="/">RIGS</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block titleelements %}
|
{% block titleelements %}
|
||||||
@@ -44,14 +47,17 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% if perms.RIGS.view_invoice %}
|
{% if perms.RIGS.view_invoice %}
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
|
{% total_invoices_todo as todo %}
|
||||||
|
{% invoices_waiting as waiting %}
|
||||||
|
{% invoices_outstanding as outstanding %}
|
||||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownInvoices" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownInvoices" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
Invoices
|
Invoices <span class="badge {% if todo == 0 %}badge-success{% else %}badge-danger{% endif %} badge-pill">{{ todo }}</span>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-menu" aria-labelledby="navbarDropdownInvoices">
|
<div class="dropdown-menu" aria-labelledby="navbarDropdownInvoices">
|
||||||
{% if perms.RIGS.add_invoice %}
|
{% if perms.RIGS.add_invoice %}
|
||||||
<a class="dropdown-item" href="{% url 'invoice_waiting' %}"><span class="fas fa-briefcase text-danger"></span> Waiting</a>
|
<a class="dropdown-item text-nowrap" href="{% url 'invoice_waiting' %}"><span class="fas fa-briefcase text-danger"></span> Waiting <span class="badge {% if waiting == 0 %}badge-success{% else %}badge-danger{% endif %} badge-pill">{{ waiting }}</span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a class="dropdown-item" href="{% url 'invoice_list' %}"><span class="fas fa-pound-sign text-warning"></span> Outstanding</a>
|
<a class="dropdown-item" href="{% url 'invoice_list' %}"><span class="fas fa-pound-sign text-warning"></span> Outstanding <span class="badge {% if outstanding == 0 %}badge-success{% else %}badge-danger{% endif %} badge-pill">{{ outstanding }}</span></a>
|
||||||
<a class="dropdown-item" href="{% url 'invoice_archive' %}"><span class="fas fa-book"></span> Archive</a>
|
<a class="dropdown-item" href="{% url 'invoice_archive' %}"><span class="fas fa-book"></span> Archive</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 text-right my-3">
|
<div class="col-12 text-right my-3">
|
||||||
{% button 'edit' url='ec_edit' pk=object.pk %}
|
{% button 'edit' url='ec_edit' pk=object.pk %}
|
||||||
{% button 'view' url='event_detail' pk=object.pk text="Event" %}
|
{% button 'view' url='event_detail' pk=object.event.pk text="Event" %}
|
||||||
{% include 'partials/review_status.html' with perm=perms.RIGS.review_eventchecklist review='ec_review' %}
|
{% include 'partials/review_status.html' with perm=perms.RIGS.review_eventchecklist review='ec_review' %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -32,7 +32,11 @@
|
|||||||
</dd>
|
</dd>
|
||||||
<dt class="col-6">{{ object|help_text:'power_mic' }}</dt>
|
<dt class="col-6">{{ object|help_text:'power_mic' }}</dt>
|
||||||
<dd class="col-6">
|
<dd class="col-6">
|
||||||
|
{% if object.power_mic %}
|
||||||
<a href="{% url 'profile_detail' object.power_mic.pk %}">{{ object.power_mic.name }}</a>
|
<a href="{% url 'profile_detail' object.power_mic.pk %}">{{ object.power_mic.name }}</a>
|
||||||
|
{% else %}
|
||||||
|
None
|
||||||
|
{% endif %}
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<p>List vehicles and their drivers</p>
|
<p>List vehicles and their drivers</p>
|
||||||
@@ -98,6 +102,10 @@
|
|||||||
<td>{{crew.role}}</td>
|
<td>{{crew.role}}</td>
|
||||||
<td>{{crew.end}}</td>
|
<td>{{crew.end}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" class="text-center bg-warning">Apparently this event happened by magic...</td>
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -105,9 +113,27 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card mb-3">
|
<div class="card mb-3">
|
||||||
<div class="card-header">Power {% include 'partials/event_size.html' with object=object.event.riskassessment %}</div>
|
<div class="card-header">Power {% include 'partials/event_size.html' with object=object.event.riskassessment %}</div>
|
||||||
{% if object.event.riskassessment.event_size != 2 %}
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
{% if object.event.riskassessment.event_size == 1 %}
|
{% if object.event.riskassessment.event_size == 0 %}
|
||||||
|
<dl class="row">
|
||||||
|
<dt class="col-10">{{ object|help_text:'rcds'|safe }}</dt>
|
||||||
|
<dd class="col-2">
|
||||||
|
{{ object.rcds|yesnoi }}
|
||||||
|
</dd>
|
||||||
|
<dt class="col-10">{{ object|help_text:'supply_test'|safe }}</dt>
|
||||||
|
<dd class="col-2">
|
||||||
|
{{ object.supply_test|yesnoi }}
|
||||||
|
</dd>
|
||||||
|
<dt class="col-10">{{ object|help_text:'earthing'|safe }}</dt>
|
||||||
|
<dd class="col-2">
|
||||||
|
{{ object.earthing|yesnoi }}
|
||||||
|
</dd>
|
||||||
|
<dt class="col-10">{{ object|help_text:'pat'|safe }}</dt>
|
||||||
|
<dd class="col-2">
|
||||||
|
{{ object.pat|yesnoi }}
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
{% else %}
|
||||||
<dl class="row">
|
<dl class="row">
|
||||||
<dt class="col-10">{{ object|help_text:'source_rcd'|safe }}</dt>
|
<dt class="col-10">{{ object|help_text:'source_rcd'|safe }}</dt>
|
||||||
<dd class="col-2">
|
<dd class="col-2">
|
||||||
@@ -212,28 +238,8 @@
|
|||||||
</dl>
|
</dl>
|
||||||
<hr>
|
<hr>
|
||||||
{% include 'partials/ec_power_info.html' %}
|
{% include 'partials/ec_power_info.html' %}
|
||||||
{% else %}
|
|
||||||
<dl class="row">
|
|
||||||
<dt class="col-10">{{ object|help_text:'rcds'|safe }}</dt>
|
|
||||||
<dd class="col-2">
|
|
||||||
{{ object.rcds|yesnoi }}
|
|
||||||
</dd>
|
|
||||||
<dt class="col-10">{{ object|help_text:'supply_test'|safe }}</dt>
|
|
||||||
<dd class="col-2">
|
|
||||||
{{ object.supply_test|yesnoi }}
|
|
||||||
</dd>
|
|
||||||
<dt class="col-10">{{ object|help_text:'earthing'|safe }}</dt>
|
|
||||||
<dd class="col-2">
|
|
||||||
{{ object.earthing|yesnoi }}
|
|
||||||
</dd>
|
|
||||||
<dt class="col-10">{{ object|help_text:'pat'|safe }}</dt>
|
|
||||||
<dd class="col-2">
|
|
||||||
{{ object.pat|yesnoi }}
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 text-right">
|
<div class="col-12 text-right">
|
||||||
{% button 'edit' url='ec_edit' pk=object.pk %}
|
{% button 'edit' url='ec_edit' pk=object.pk %}
|
||||||
|
|||||||
@@ -244,12 +244,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% elif event.riskassessment.event_size == 1 %}
|
{% else %}
|
||||||
<div class="row my-3" id="size-1">
|
<div class="row my-3" id="size-1">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
|
{% if event.riskassessment.event_size == 1 %}
|
||||||
<div class="card border-warning">
|
<div class="card border-warning">
|
||||||
<div class="card-header">Electrical Checks <small>for ‘Medium’ TEC Events </small></div>
|
<div class="card-header">Electrical Checks <small>for ‘Medium’ TEC Events </small></div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
{% else %}
|
||||||
|
<div class="card border-danger">
|
||||||
|
<div class="card-header">Electrical Checks <small>for ‘Large’ TEC Events</small></div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="alert alert-danger"><strong>Here be dragons. Ensure you have appeased the Power Gods before continuing... (If you didn't check with a Supervisor, <em>you cannot continue your event!</em>)</strong></div>
|
||||||
|
{% endif %}
|
||||||
{% include 'partials/checklist_checkbox.html' with formitem=form.source_rcd %}
|
{% include 'partials/checklist_checkbox.html' with formitem=form.source_rcd %}
|
||||||
{% include 'partials/checklist_checkbox.html' with formitem=form.labelling %}
|
{% include 'partials/checklist_checkbox.html' with formitem=form.labelling %}
|
||||||
{% include 'partials/checklist_checkbox.html' with formitem=form.earthing %}
|
{% include 'partials/checklist_checkbox.html' with formitem=form.earthing %}
|
||||||
@@ -339,17 +346,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
|
||||||
<div class="row my-3" id="size-2">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="card border-danger">
|
|
||||||
<div class="card-header">Electrical Checks <small>for ‘Large’ TEC Events</small></div>
|
|
||||||
<div class="card-body">
|
|
||||||
<p>Outside the scope of this assessment. <strong>I really hope you checked with a supervisor...</strong></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="row mt-3">
|
<div class="row mt-3">
|
||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
||||||
{% load linkornone from filters %}
|
|
||||||
{% load namewithnotes from filters %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row my-3 py-3">
|
<div class="row my-3 py-3">
|
||||||
@@ -14,50 +12,7 @@
|
|||||||
{% if object.is_rig and perms.RIGS.view_event %}
|
{% if object.is_rig and perms.RIGS.view_event %}
|
||||||
{# only need contact details for a rig #}
|
{# only need contact details for a rig #}
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
{% if event.person %}
|
{% include 'partials/contact_details.html' %}
|
||||||
<div class="card card-default mb-3">
|
|
||||||
<div class="card-header">Contact Details</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<dl class="row">
|
|
||||||
<dt class="col-sm-6">Person</dt>
|
|
||||||
<dd class="col-sm-6">
|
|
||||||
{% if object.person %}
|
|
||||||
<a href="{% url 'person_detail' object.person.pk %}" class="modal-href">
|
|
||||||
{{ object.person|namewithnotes:'person_detail' }}
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</dd>
|
|
||||||
<dt class="col-sm-6">Email</dt>
|
|
||||||
<dd class="col-sm-6">{{ object.person.email|linkornone:'mailto' }}</dd>
|
|
||||||
<dt class="col-sm-6">Phone Number</dt>
|
|
||||||
<dd class="col-sm-6">{{ object.person.phone|linkornone:'tel' }}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if event.organisation %}
|
|
||||||
<div class="card card-default">
|
|
||||||
<div class="card-header">Organisation</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<dl class="row">
|
|
||||||
<dt class="col-sm-6">Organisation</dt>
|
|
||||||
<dd class="col-sm-6">
|
|
||||||
{% if object.organisation %}
|
|
||||||
<a href="{% url 'organisation_detail' object.organisation.pk %}" class="modal-href">
|
|
||||||
{{ object.organisation|namewithnotes:'organisation_detail' }}
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</dd>
|
|
||||||
<dt class="col-sm-6">Email</dt>
|
|
||||||
<dd class="col-sm-6">{{ object.organisation.email|linkornone:'mailto' }}</dd>
|
|
||||||
<dt class="col-sm-6">Phone Number</dt>
|
|
||||||
<dd class="col-sm-6">{{ object.organisation.phone|linkornone:'tel' }}</dd>
|
|
||||||
<dt class="col-sm-6">Has SU Account</dt>
|
|
||||||
<dd class="col-sm-6">{{ event.organisation.union_account|yesno|capfirst }}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
@@ -91,7 +46,7 @@
|
|||||||
<p class="dont-break-out">{{ event.notes|linebreaksbr }}</p>
|
<p class="dont-break-out">{{ event.notes|linebreaksbr }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<br>
|
<br>
|
||||||
{% include 'item_table.html' %}
|
{% include 'partials/item_table.html' %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -27,18 +27,26 @@
|
|||||||
const matches = window.matchMedia("(prefers-reduced-motion: reduce)").matches || window.matchMedia("(update: slow)").matches;
|
const matches = window.matchMedia("(prefers-reduced-motion: reduce)").matches || window.matchMedia("(update: slow)").matches;
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
dur = matches ? 0 : 500;
|
dur = matches ? 0 : 500;
|
||||||
{% if not object.pk and not form.errors %}
|
{% if object.pk %}
|
||||||
$('.form-hws').slideUp(dur, function () {
|
// Editing
|
||||||
$('.form-is_rig').slideUp(dur);
|
{% if not object.is_rig %}
|
||||||
});
|
$('.form-is_rig').hide();
|
||||||
{% elif not object.pk and form.errors %}
|
{% endif %}
|
||||||
|
//Creation
|
||||||
|
{% else %}
|
||||||
|
// If there were errors, apply the previous Rig/not-Rig selection
|
||||||
|
{% if form.errors %}
|
||||||
|
$('.form-hws').show();
|
||||||
if ($('#{{form.is_rig.auto_id}}').attr('checked') !== 'checked') {
|
if ($('#{{form.is_rig.auto_id}}').attr('checked') !== 'checked') {
|
||||||
$('.form-is_rig').hide();
|
$('.form-is_rig').hide();
|
||||||
}
|
}
|
||||||
|
{% else %}
|
||||||
|
//Initial hide
|
||||||
|
$('.form-hws').slideUp(dur);
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not object.pk %}
|
//Button handling
|
||||||
$('#is_rig-selector button').on('click', function () {
|
$('#is_rig-selector button').on('click', function () {
|
||||||
$('.form-non_rig').slideDown(dur);
|
$('.form-non_rig').slideDown(dur); //Non rig stuff also needed for rig, so always slide down
|
||||||
if ($(this).data('is_rig') === 1) {
|
if ($(this).data('is_rig') === 1) {
|
||||||
$('#{{form.is_rig.auto_id}}').prop('checked', true);
|
$('#{{form.is_rig.auto_id}}').prop('checked', true);
|
||||||
if ($('.form-non_rig').is(':hidden')) {
|
if ($('.form-non_rig').is(':hidden')) {
|
||||||
@@ -48,7 +56,6 @@
|
|||||||
}
|
}
|
||||||
$('.form-hws, .form-hws .form-is_rig').css('overflow', 'visible');
|
$('.form-hws, .form-hws .form-is_rig').css('overflow', 'visible');
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
$('#{{form.is_rig.auto_id}}').prop('checked', false);
|
$('#{{form.is_rig.auto_id}}').prop('checked', false);
|
||||||
$('.form-is_rig').slideUp(dur);
|
$('.form-is_rig').slideUp(dur);
|
||||||
}
|
}
|
||||||
@@ -62,13 +69,6 @@
|
|||||||
$('[data-toggle="tooltip"]').tooltip();
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<noscript>
|
|
||||||
<style>
|
|
||||||
.form-hws {
|
|
||||||
display: inherit !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</noscript>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@@ -348,7 +348,7 @@
|
|||||||
{% render_field form.notes class+="form-control" %}
|
{% render_field form.notes class+="form-control" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% include 'item_table.html' %}
|
{% include 'partials/item_table.html' %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -198,11 +198,13 @@
|
|||||||
</blockTable>
|
</blockTable>
|
||||||
<keepTogether>
|
<keepTogether>
|
||||||
<blockTable style="totalTable" colWidths="300,115,80">
|
<blockTable style="totalTable" colWidths="300,115,80">
|
||||||
|
{% if object.vat > 0 %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% if quote %}VAT Registration Number: 170734807{% endif %}</td>
|
<td>{% if quote %}VAT Registration Number: 170734807</td>
|
||||||
<td>Total (ex. VAT)</td>
|
<td>Total (ex. VAT){% endif %}</td>
|
||||||
<td>£ {{ object.sum_total|floatformat:2 }}</td>
|
<td>£ {{ object.sum_total|floatformat:2 }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endif %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
{% if quote %}
|
{% if quote %}
|
||||||
@@ -211,8 +213,10 @@
|
|||||||
</para>
|
</para>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
{% if object.vat > 0 %}
|
||||||
<td>VAT @ {{ object.vat_rate.as_percent|floatformat:2 }}%</td>
|
<td>VAT @ {{ object.vat_rate.as_percent|floatformat:2 }}%</td>
|
||||||
<td>£{{ object.vat|floatformat:2 }}</td>
|
<td>£{{ object.vat|floatformat:2 }}</td>
|
||||||
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
@@ -281,7 +285,7 @@
|
|||||||
<td></td>
|
<td></td>
|
||||||
<td>
|
<td>
|
||||||
<para>
|
<para>
|
||||||
<b>Balance</b> (ex. VAT)
|
<b>Balance</b> {% if object.vat > 0 %}(ex. VAT){% endif %}
|
||||||
</para>
|
</para>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -316,7 +320,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>General Enquires and 24 Hour Emergency Contact: 0115 84 68720</td>
|
<td>General Enquires and 24 Hour Emergency Contact: 0115 84 68720</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% else %}
|
{% elif object.vat > 0 %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<para>VAT Registration Number: 170734807</para>
|
<para>VAT Registration Number: 170734807</para>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
{% with object=event auth=True %}
|
{% with object=event auth=True %}
|
||||||
{% include 'item_table.html' %}
|
{% include 'partials/item_table.html' %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,15 +5,13 @@
|
|||||||
<p>Hi {{ to_name|default:"there" }},</p>
|
<p>Hi {{ to_name|default:"there" }},</p>
|
||||||
|
|
||||||
<p><b>{{ request.user.get_full_name }}</b> has requested that you authorise <b>{{ object.display_id }}
|
<p><b>{{ request.user.get_full_name }}</b> has requested that you authorise <b>{{ object.display_id }}
|
||||||
| {{ object.name }}</b>{% if not to_name %} on behalf of <b>{{ object.person.name }}</b>{% endif %}.</p>
|
| {{ object.name }}</b>{% if not to_name %} on behalf of <b>{% if object.person %}{{ object.person.name }}{% else %}{{ object.organisation.name }}{% endif %}</b>{% endif %}.</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Please find the link below to complete the event booking process.
|
Please find the link below to complete the event booking process.
|
||||||
{% if object.event.organisation and object.event.organisation.union_account %}{# internal #}
|
|
||||||
Remember that only Presidents or Treasurers are allowed to sign off payments. You may need to forward
|
Remember that only Presidents or Treasurers are allowed to sign off payments. You may need to forward
|
||||||
this
|
this
|
||||||
email on.
|
email on.
|
||||||
{% endif %}
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Hi {{ to_name|default:"there" }},
|
Hi {{ to_name|default:"there" }},
|
||||||
|
|
||||||
{{ request.user.get_full_name }} has requested that you authorise N{{ object.pk|stringformat:"05d" }}| {{ object.name }}{% if not to_name %} on behalf of {{ object.person.name }}{% endif %}.
|
{{ request.user.get_full_name }} has requested that you authorise N{{ object.pk|stringformat:"05d" }}| {{ object.name }}{% if not to_name %} on behalf of {% if object.person %}{{ object.person.name }}{% else %}{{ object.organisation.name }}{% endif %}{% endif %}.
|
||||||
|
|
||||||
Please find the link below to complete the event booking process.
|
Please find the link below to complete the event booking process.
|
||||||
{% if object.event.organisation and object.event.organisation.union_account %}{# internal #}
|
{% if object.event.organisation and object.event.organisation.union_account %}{# internal #}
|
||||||
|
|||||||
@@ -1,24 +1,48 @@
|
|||||||
{% extends request.is_ajax|yesno:'base_ajax.html,base_rigs.html' %}
|
{% extends request.is_ajax|yesno:'base_ajax.html,base_rigs.html' %}
|
||||||
{% load widget_tweaks %}
|
{% load widget_tweaks %}
|
||||||
|
{% load static %}
|
||||||
|
{% load button from filters %}
|
||||||
|
|
||||||
{% block title %}Request Authorisation{% endblock %}
|
{% block title %}Request Authorisation{% endblock %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
<script src="{% static 'js/tooltip.js' %}"></script>
|
||||||
|
<script src="{% static 'js/popover.js' %}"></script>
|
||||||
|
<script src="{% static 'js/clipboard.min.js' %}"></script>
|
||||||
|
<script>
|
||||||
|
var clipboard = new ClipboardJS('.btn');
|
||||||
|
|
||||||
|
clipboard.on('success', function(e) {
|
||||||
|
$(e.trigger).popover('show');
|
||||||
|
window.setTimeout(function () {$(e.trigger).popover('hide')}, 3000);
|
||||||
|
e.clearSelection();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning pb-0">
|
||||||
<h1>Send authorisation request email.</h1>
|
<h1>Send authorisation request email.</h1>
|
||||||
<p>Pressing send will email the address provided. Please triple check everything before continuing.</p>
|
<p>Pressing send will email the address provided. <strong>Please triple check everything before continuing.</strong></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info pb-0">
|
||||||
|
{% if object.person.email or object.organisation.email %}
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
|
{% if object.person.email %}
|
||||||
<dt>Person Email</dt>
|
<dt>Person Email</dt>
|
||||||
<dd>{{ object.person.email }}</dd>
|
<dd><span id="person-email">{{ object.person.email }}</span>{% button 'copy' id='#person-email' %}</dd>
|
||||||
|
{% endif %}
|
||||||
|
{% if object.organisation.email %}
|
||||||
<dt>Organisation Email</dt>
|
<dt>Organisation Email</dt>
|
||||||
<dd>{{ object.organisation.email }}</dd>
|
<dd><span id="org-email">{{ object.organisation.email }}</span>{% button 'copy' id='#org-email' %}</dd>
|
||||||
|
{% endif %}
|
||||||
</dl>
|
</dl>
|
||||||
|
{% else %}
|
||||||
|
<p>No email addresses saved to the client ಠ_ಠ</p>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<form action="{{ form.action|default:request.path }}" method="POST" id="auth-request-form">
|
<form action="{{ form.action|default:request.path }}" method="POST" id="auth-request-form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|||||||
@@ -4,10 +4,11 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table mb-0">
|
<table class="table mb-0 table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">Event</th>
|
<th scope="col">Event</th>
|
||||||
|
<th scope="col">MIC</th>
|
||||||
<th scope="col">Dates</th>
|
<th scope="col">Dates</th>
|
||||||
<th scope="col">RA</th>
|
<th scope="col">RA</th>
|
||||||
<th scope="col">Checklists</th>
|
<th scope="col">Checklists</th>
|
||||||
@@ -16,7 +17,8 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for event in object_list %}
|
{% for event in object_list %}
|
||||||
<tr id="event_row">
|
<tr id="event_row">
|
||||||
<th scope="row" id="event_number"><a href="{% url 'event_detail' event.pk %}">{{ event }}</a></th>
|
<th scope="row" id="event_number"><a href="{% url 'event_detail' event.pk %}">{{ event }}</a><br><small>{{ event.get_status_display }}</small></th>
|
||||||
|
<td>{% if event.mic is not None %}<a href="{% url 'profile_detail' event.mic.pk %}">{% else %}<span class="text-danger">{% endif %}{{ event.mic }}{% if event.mic is not None %}</a>{% else %}</span>{%endif%}</td>
|
||||||
<!--Dates-->
|
<!--Dates-->
|
||||||
<td id="event_dates">
|
<td id="event_dates">
|
||||||
<span><strong>{{ event.start_date|date:"D d/m/Y" }}</strong></span>
|
<span><strong>{{ event.start_date|date:"D d/m/Y" }}</strong></span>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table mb-0">
|
<table class="table mb-0 table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">Event</th>
|
<th scope="col">Event</th>
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
{% for object in object_list %}
|
{% for object in object_list %}
|
||||||
<tr class="{% if object.reviewed_by %}table-success{%endif%}">
|
<tr class="{% if object.reviewed_by %}table-success{%endif%}">
|
||||||
{# General #}
|
{# General #}
|
||||||
<th scope="row"><a href="{% url 'event_detail' object.event.pk %}">{{ object.event }}</a></th>
|
<th scope="row"><a href="{% url 'event_detail' object.event.pk %}">{{ object.event }}</a><br><small>{{ object.event.get_status_display }}</small></th>
|
||||||
{% for field in object_list.0.fieldz %}
|
{% for field in object_list.0.fieldz %}
|
||||||
<td>{{ object|get_field:field }}</td>
|
<td>{{ object|get_field:field }}</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
{% load button from filters %}
|
{% load button from filters %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-sm-12">
|
<div class="row py-4">
|
||||||
<div class="row justify-content-end py-3">
|
<div class="col-sm-12 text-right px-0">
|
||||||
<div class="col-sm-4 text-right">
|
<div class="btn-group">
|
||||||
<div class="btn-group btn-page">
|
<a href="{% url 'event_detail' object.event.pk %}" class="btn btn-primary">Open Event Page <span class="fas fa-eye"></span></a>
|
||||||
<a href="{% url 'invoice_delete' object.pk %}" class="btn btn-danger" title="Delete Invoice">
|
<a href="{% url 'invoice_delete' object.pk %}" class="btn btn-danger" title="Delete Invoice">
|
||||||
<span class="fas fa-times"></span> <span
|
<span class="fas fa-times"></span> <span
|
||||||
class="d-none d-sm-inline">Delete</span>
|
class="d-none d-sm-inline">Delete</span>
|
||||||
@@ -17,24 +17,11 @@
|
|||||||
{% button 'print' url='invoice_print' pk=object.pk %}
|
{% button 'print' url='invoice_print' pk=object.pk %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div>
|
||||||
|
<div class="row py-4">
|
||||||
<div class="row">
|
{% with object.event as object %}
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<div class="card card-default">
|
{% include 'partials/contact_details.html' %}
|
||||||
<div class="card-header">Invoice Details<span class="float-right">
|
|
||||||
{% if object.void %}(VOID){% elif object.is_closed %}(PAID){% else %}(OUTSTANDING){% endif %}
|
|
||||||
</span></div>
|
|
||||||
<div class="card-body">
|
|
||||||
{% if object.event.organisation %}
|
|
||||||
{{ object.event.organisation.name }}<br/>
|
|
||||||
{{ object.event.organisation.address|linebreaksbr }}
|
|
||||||
{% else %}
|
|
||||||
{{ object.event.person.name }}<br/>
|
|
||||||
{{ object.event.person.address|linebreaksbr }}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
{% include 'partials/event_details.html' %}
|
{% include 'partials/event_details.html' %}
|
||||||
@@ -44,8 +31,8 @@
|
|||||||
{% include 'partials/auth_details.html' %}
|
{% include 'partials/auth_details.html' %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row py-4">
|
<div class="row py-4">
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<div class="card card-default">
|
<div class="card card-default">
|
||||||
@@ -91,7 +78,7 @@
|
|||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
{% with object.event as object %}
|
{% with object.event as object %}
|
||||||
{% include 'item_table.html' %}
|
{% include 'partials/item_table.html' %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -99,5 +86,4 @@
|
|||||||
<div class="col-12 text-right">
|
<div class="col-12 text-right">
|
||||||
{% include 'partials/last_edited.html' with target="invoice_history" %}
|
{% include 'partials/last_edited.html' with target="invoice_history" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
{% if perms.RIGS.view_event %}
|
{% if perms.RIGS.view_event %}
|
||||||
<td>£ <span class="cost">{{item.cost|floatformat:2}}</span></td>
|
<td>£<span class="cost">{{item.cost|floatformat:2}}</span></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<td class="quantity">{{item.quantity}}</td>
|
<td class="quantity">{{item.quantity}}</td>
|
||||||
{% if perms.RIGS.view_event %}
|
{% if perms.RIGS.view_event %}
|
||||||
<td>£ <span class="sub-total" data-subtotal="{{item.total_cost}}">{{item.total_cost|floatformat:2}}</span></td>
|
<td>£<span class="sub-total" data-subtotal="{{item.total_cost}}">{{item.total_cost|floatformat:2}}</span></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if edit %}
|
{% if edit %}
|
||||||
<td class="vert-align text-right">
|
<td class="vert-align text-right">
|
||||||
|
|||||||
@@ -27,12 +27,13 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
{% if auth or perms.RIGS.view_event %}
|
{% if auth or perms.RIGS.view_event %}
|
||||||
<tfoot>
|
<tfoot style="font-weight: bold">
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="3" colspan="2"></td>
|
<td rowspan="3" colspan="2"></td>
|
||||||
<td>Total (ex. VAT)</td>
|
<td>Total {% if object.vat > 0 or not object.pk %}(ex. VAT){% endif %}</td>
|
||||||
<td colspan="2">£<span id="sumtotal">{{object.sum_total|default:0|floatformat:2}}</span></td>
|
<td colspan="2">£<span id="sumtotal">{{object.sum_total|default:0|floatformat:2}}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% if object.vat > 0 or not object.pk %}
|
||||||
<tr>
|
<tr>
|
||||||
{% if not object.pk %}
|
{% if not object.pk %}
|
||||||
<td id="vat-rate" data-rate="{{currentVAT.rate}}">VAT @
|
<td id="vat-rate" data-rate="{{currentVAT.rate}}">VAT @
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
<td>Total</td>
|
<td>Total</td>
|
||||||
<td colspan="2">£<span id="total">{{object.total|default:0|floatformat:2}}</span></td>
|
<td colspan="2">£<span id="total">{{object.total|default:0|floatformat:2}}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endif %}
|
||||||
</tfoot>
|
</tfoot>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</table>
|
</table>
|
||||||
@@ -59,9 +61,9 @@
|
|||||||
<em class="description"></em>
|
<em class="description"></em>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>£ <span class="cost"></span></td>
|
<td>£<span class="cost"></span></td>
|
||||||
<td class="quantity"></td>
|
<td class="quantity"></td>
|
||||||
<td>£ <span class="sub-total"></span></td>
|
<td>£<span class="sub-total"></span></td>
|
||||||
{% if edit %}
|
{% if edit %}
|
||||||
<td class="vert-align text-right">
|
<td class="vert-align text-right">
|
||||||
<div class="btn-group" role="group" aria-label="Action buttons">
|
<div class="btn-group" role="group" aria-label="Action buttons">
|
||||||
|
|||||||
@@ -1,27 +1,29 @@
|
|||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
|
{% if event.person %}
|
||||||
<div class="card mb-3">
|
<div class="card mb-3">
|
||||||
<div class="card-header">Contact Details</div>
|
<div class="card-header">Contact Details</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<dl class="row">
|
<dl class="row">
|
||||||
<dt class="col-sm-5">Person</dt>
|
<dt class="col-sm-5">Person</dt>
|
||||||
<dd class="col-sm-7">
|
<dd class="col-sm-7">
|
||||||
{% if event.person %}
|
|
||||||
{{ event.person.name }}
|
{{ event.person.name }}
|
||||||
{% endif %}
|
|
||||||
</dd>
|
</dd>
|
||||||
|
{% if event.person.email %}
|
||||||
<dt class="col-sm-5">Email</dt>
|
<dt class="col-sm-5">Email</dt>
|
||||||
<dd class="col-sm-7">
|
<dd class="col-sm-7">
|
||||||
<span class="overflow-ellipsis">{{ event.person.email }}</span>
|
<span class="overflow-ellipsis">{{ event.person.email }}</span>
|
||||||
</dd>
|
</dd>
|
||||||
|
{% endif %}
|
||||||
|
{% if event.person.phone %}
|
||||||
<dt class="col-sm-5">Phone Number</dt>
|
<dt class="col-sm-5">Phone Number</dt>
|
||||||
<dd class="col-sm-7">{{ event.person.phone }}</dd>
|
<dd class="col-sm-7">{{ event.person.phone }}</dd>
|
||||||
|
{% endif %}
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% if event.organisation %}
|
{% if event.organisation %}
|
||||||
<div class="card mt-3">
|
<div class="card">
|
||||||
<div class="card-header">Organisation Details</div>
|
<div class="card-header">Organisation Details</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<dl class="row">
|
<dl class="row">
|
||||||
@@ -29,9 +31,10 @@
|
|||||||
<dd class="col-sm-7">
|
<dd class="col-sm-7">
|
||||||
{{ event.organisation.name }}
|
{{ event.organisation.name }}
|
||||||
</dd>
|
</dd>
|
||||||
|
{% if event.organisation.phone %}
|
||||||
<dt class="col-sm-5">Phone Number</dt>
|
<dt class="col-sm-5">Phone Number</dt>
|
||||||
<dd class="col-sm-7">{{ object.organisation.phone }}</dd>
|
<dd class="col-sm-7">{{ event.organisation.phone }}</dd>
|
||||||
|
{% endif %}
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -43,15 +46,12 @@
|
|||||||
<div class="card-header">Event Info</div>
|
<div class="card-header">Event Info</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<dl class="row">
|
<dl class="row">
|
||||||
|
{% if event.venue %}
|
||||||
<dt class="col-sm-5">Event Venue</dt>
|
<dt class="col-sm-5">Event Venue</dt>
|
||||||
<dd class="col-sm-7">
|
<dd class="col-sm-7">
|
||||||
{% if object.venue %}
|
{{ event.venue }}
|
||||||
<a href="{% url 'venue_detail' object.venue.pk %}" class="modal-href">
|
|
||||||
{{ object.venue }}
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</dd>
|
</dd>
|
||||||
|
{% endif %}
|
||||||
<dt class="col-sm-5">Status</dt>
|
<dt class="col-sm-5">Status</dt>
|
||||||
<dd class="col-sm-7">{{ event.get_status_display }}</dd>
|
<dd class="col-sm-7">{{ event.get_status_display }}</dd>
|
||||||
|
|
||||||
|
|||||||
47
RIGS/templates/partials/contact_details.html
Normal file
47
RIGS/templates/partials/contact_details.html
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{% load linkornone from filters %}
|
||||||
|
{% load namewithnotes from filters %}
|
||||||
|
|
||||||
|
{% if object.person %}
|
||||||
|
<div class="card card-default mb-3">
|
||||||
|
<div class="card-header">Person Details</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<dl class="row">
|
||||||
|
<dt class="col-sm-6">Person</dt>
|
||||||
|
<dd class="col-sm-6">
|
||||||
|
{% if object.person %}
|
||||||
|
<a href="{% url 'person_detail' object.person.pk %}" class="modal-href">
|
||||||
|
{{ object.person|namewithnotes:'person_detail' }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
|
<dt class="col-sm-6">Email</dt>
|
||||||
|
<dd class="col-sm-6">{{ object.person.email|linkornone:'mailto' }}</dd>
|
||||||
|
<dt class="col-sm-6">Phone Number</dt>
|
||||||
|
<dd class="col-sm-6">{{ object.person.phone|linkornone:'tel' }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if object.organisation %}
|
||||||
|
<div class="card card-default">
|
||||||
|
<div class="card-header">Organisation Details</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<dl class="row">
|
||||||
|
<dt class="col-sm-6">Organisation</dt>
|
||||||
|
<dd class="col-sm-6">
|
||||||
|
{% if object.organisation %}
|
||||||
|
<a href="{% url 'organisation_detail' object.organisation.pk %}" class="modal-href">
|
||||||
|
{{ object.organisation|namewithnotes:'organisation_detail' }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
|
<dt class="col-sm-6">Email</dt>
|
||||||
|
<dd class="col-sm-6">{{ object.organisation.email|linkornone:'mailto' }}</dd>
|
||||||
|
<dt class="col-sm-6">Phone Number</dt>
|
||||||
|
<dd class="col-sm-6">{{ object.organisation.phone|linkornone:'tel' }}</dd>
|
||||||
|
<dt class="col-sm-6">Has SU Account</dt>
|
||||||
|
<dd class="col-sm-6">{{ event.organisation.union_account|yesno|capfirst }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
@@ -47,5 +47,7 @@
|
|||||||
class="fas fa-pound-sign"></span>
|
class="fas fa-pound-sign"></span>
|
||||||
<span class="d-none d-sm-inline">Invoice</span></a>
|
<span class="d-none d-sm-inline">Invoice</span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<a href="https://docs.google.com/forms/d/e/1FAIpQLSf-TBOuJZCTYc2L8DWdAaC3_Werq0ulsUs8-6G85I6pA9WVsg/viewform" class="btn btn-danger"><span class="fas fa-file-invoice-dollar"></span> <span class="d-none d-sm-inline">Subhire Insurance Form</span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
<span class="badge badge-success">PO: {{ event.purchase_order }}</span>
|
<span class="badge badge-success">PO: {{ event.purchase_order }}</span>
|
||||||
{% elif event.authorised %}
|
{% elif event.authorised %}
|
||||||
<span class="badge badge-success">Authorisation: Complete <span class="fas fa-check"></span></span>
|
<span class="badge badge-success">Authorisation: Complete <span class="fas fa-check"></span></span>
|
||||||
|
{% elif event.authorisation and event.authorisation.amount != event.total and event.authorisation.last_edited_at > event.auth_request_at %}
|
||||||
|
<span class="badge badge-warning"> Authorisation: Issue <span class="fas fa-exclamation-circle"></span></span>
|
||||||
|
{% elif event.auth_request_to %}
|
||||||
|
<span class="badge badge-info"> Authorisation: Sent <span class="fas fa-paper-plane"></span></span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="badge badge-danger">Authorisation: <span class="fas fa-times"></span></span>
|
<span class="badge badge-danger">Authorisation: <span class="fas fa-times"></span></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -30,25 +30,25 @@
|
|||||||
<th scope="row" id="event_number">{{ event.display_id }}</th>
|
<th scope="row" id="event_number">{{ event.display_id }}</th>
|
||||||
<!--Dates & Times-->
|
<!--Dates & Times-->
|
||||||
<td id="event_dates">
|
<td id="event_dates">
|
||||||
<span class="text-nowrap">Start: <strong>{{ event.start_date|date:"D d/m/Y" }}</strong>
|
<span class="text-nowrap">Start: <strong>{{ event.start_date|date:"D d/m/Y" }}
|
||||||
{% if event.has_start_time %}
|
{% if event.has_start_time %}
|
||||||
{{ event.start_time|date:"H:i" }}
|
{{ event.start_time|date:"H:i" }}
|
||||||
{% endif %}
|
{% endif %}</strong>
|
||||||
</span>
|
</span>
|
||||||
{% if event.end_date %}
|
{% if event.end_date %}
|
||||||
<br>
|
<br>
|
||||||
<span class="text-nowrap">End: {% if event.end_date != event.start_date %}<strong>{{ event.end_date|date:"D d/m/Y" }}</strong>{% endif %}
|
<span class="text-nowrap">End: {% if event.end_date != event.start_date %}<strong>{{ event.end_date|date:"D d/m/Y" }}{% endif %}
|
||||||
{% if event.has_end_time %}
|
{% if event.has_end_time %}
|
||||||
{{ event.end_time|date:"H:i" }}
|
{{ event.end_time|date:"H:i" }}
|
||||||
{% endif %}
|
{% endif %}</strong>
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not event.cancelled %}
|
{% if not event.cancelled %}
|
||||||
{% if event.meet_at %}
|
{% if event.meet_at %}
|
||||||
<br><span>Crew meet: <strong>{{ event.meet_at|date:"H:i" }}</strong> {{ event.meet_at|date:"(d/m/Y)" }}</span>
|
<br><span class="text-nowrap">Meet: <strong>{{ event.meet_at|date:"D d/m/Y H:i" }}</strong></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if event.access_at %}
|
{% if event.access_at %}
|
||||||
<br><span>Access at: <strong>{{ event.access_at|date:"H:i" }}</strong> {{ event.access_at|date:"(d/m/Y)" }}</span>
|
<br><span class="text-nowrap">Access: <strong>{{ event.access_at|date:" D d/m/Y H:i" }}</strong></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
@@ -67,9 +67,9 @@
|
|||||||
</h4>
|
</h4>
|
||||||
{% if event.is_rig and not event.cancelled %}
|
{% if event.is_rig and not event.cancelled %}
|
||||||
<h5>
|
<h5>
|
||||||
{{ event.person.name }}
|
<a href="{{ event.person.get_absolute_url }}">{{ event.person.name }}</a>
|
||||||
{% if event.organisation %}
|
{% if event.organisation %}
|
||||||
for {{ event.organisation.name }}
|
for <a href="{{ event.organisation.get_absolute_url }}">{{ event.organisation.name }}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h5>
|
</h5>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elif event.is_rig %}
|
{% elif event.is_rig %}
|
||||||
<span class="fas fa-exclamation"></span>
|
<span class="fas fa-user-slash"></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
||||||
{% block title %}Risk Assessment for Event N{{ object.event.pk|stringformat:"05d" }} {{ object.event.name }}{% endblock %}
|
|
||||||
{% load help_text from filters %}
|
{% load help_text from filters %}
|
||||||
{% load yesnoi from filters %}
|
{% load yesnoi from filters %}
|
||||||
{% load linkornone from filters %}
|
{% load linkornone from filters %}
|
||||||
@@ -7,7 +6,6 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row py-3">
|
<div class="row py-3">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<h3>Risk Assessment for Event N{{ object.event.pk|stringformat:"05d" }} {{ object.event.name }}</h3>
|
|
||||||
<div class="card card-default mb-3">
|
<div class="card card-default mb-3">
|
||||||
<div class="card-header">General</div>
|
<div class="card-header">General</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@@ -51,11 +49,11 @@
|
|||||||
<dd class="col-sm-6">
|
<dd class="col-sm-6">
|
||||||
{{ object.power_mic.name|default:'None' }}
|
{{ object.power_mic.name|default:'None' }}
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="col-sm-6">{{ object|help_text:'generators' }}</dt>
|
<dt class="col-sm-6">{{ object|help_text:'outside' }}</dt>
|
||||||
<dd class="col-sm-6">
|
<dd class="col-sm-6">
|
||||||
{{ object.outside|yesnoi:'invert' }}
|
{{ object.outside|yesnoi:'invert' }}
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="col-sm-6">{{ object|help_text:'outside' }}</dt>
|
<dt class="col-sm-6">{{ object|help_text:'generators' }}</dt>
|
||||||
<dd class="col-sm-6">
|
<dd class="col-sm-6">
|
||||||
{{ object.generators|yesnoi:'invert' }}
|
{{ object.generators|yesnoi:'invert' }}
|
||||||
</dd>
|
</dd>
|
||||||
@@ -97,61 +95,67 @@
|
|||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-6 col-12">
|
||||||
<div class="card card-default mb-3">
|
<div class="card card-default mb-3">
|
||||||
<div class="card-header">Site Details</div>
|
<div class="card-header">Site Details</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<dl class="row">
|
<dl class="row">
|
||||||
<dt class="col-sm-6">{{ object|help_text:'known_venue' }}</dt>
|
<dt class="col-10">{{ object|help_text:'known_venue' }}</dt>
|
||||||
<dd class="col-sm-6">
|
<dd class="col-2">
|
||||||
{{ object.known_venue|yesnoi:'invert' }}
|
{{ object.known_venue|yesnoi:'invert' }}
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="col-sm-6">{{ object|help_text:'safe_loading'|safe }}</dt>
|
<dt class="col-10">{{ object|help_text:'safe_loading'|safe }}</dt>
|
||||||
<dd class="col-sm-6">
|
<dd class="col-2">
|
||||||
{{ object.safe_loading|yesnoi:'invert' }}
|
{{ object.safe_loading|yesnoi:'invert' }}
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="col-sm-6">{{ object|help_text:'safe_storage' }}</dt>
|
<dt class="col-10">{{ object|help_text:'safe_storage' }}</dt>
|
||||||
<dd class="col-sm-6">
|
<dd class="col-2">
|
||||||
{{ object.safe_storage|yesnoi:'invert' }}
|
{{ object.safe_storage|yesnoi:'invert' }}
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="col-sm-6">{{ object|help_text:'area_outside_of_control' }}</dt>
|
<dt class="col-10">{{ object|help_text:'area_outside_of_control' }}</dt>
|
||||||
<dd class="col-sm-6">
|
<dd class="col-2">
|
||||||
{{ object.area_outside_of_control|yesnoi:'invert' }}
|
{{ object.area_outside_of_control|yesnoi:'invert' }}
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="col-sm-6">{{ object|help_text:'barrier_required' }}</dt>
|
<dt class="col-10">{{ object|help_text:'barrier_required' }}</dt>
|
||||||
<dd class="col-sm-6">
|
<dd class="col-2">
|
||||||
{{ object.barrier_required|yesnoi:'invert' }}
|
{{ object.barrier_required|yesnoi:'invert' }}
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="col-sm-6">{{ object|help_text:'nonstandard_emergency_procedure' }}</dt>
|
<dt class="col-10">{{ object|help_text:'nonstandard_emergency_procedure' }}</dt>
|
||||||
<dd class="col-sm-6">
|
<dd class="col-2">
|
||||||
{{ object.nonstandard_emergency_procedure|yesnoi:'invert' }}
|
{{ object.nonstandard_emergency_procedure|yesnoi:'invert' }}
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-6 col-12">
|
||||||
<div class="card card-default mb-3">
|
<div class="card card-default mb-3">
|
||||||
<div class="card-header">Structures</div>
|
<div class="card-header">Structures</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<dl class="row">
|
<dl class="row">
|
||||||
<dt class="col-sm-6">{{ object|help_text:'special_structures' }}</dt>
|
<dt class="col-10">{{ object|help_text:'special_structures' }}</dt>
|
||||||
<dd class="col-sm-6">
|
<dd class="col-2">
|
||||||
{{ object.special_structures|yesnoi:'invert' }}
|
{{ object.special_structures|yesnoi:'invert' }}
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="col-sm-6">{{ object|help_text:'suspended_structures' }}</dt>
|
<dt class="col-10">{{ object|help_text:'suspended_structures' }}</dt>
|
||||||
<dd class="col-sm-6">
|
<dd class="col-2">
|
||||||
{{ object.suspended_structures|yesnoi:'invert' }}
|
{{ object.suspended_structures|yesnoi:'invert' }}
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="col-sm-6">{{ object|help_text:'persons_responsible_structures' }}</dt>
|
<dt class="col-12">{{ object|help_text:'persons_responsible_structures' }}</dt>
|
||||||
<dd class="col-sm-6">
|
<dd class="col-12">
|
||||||
{{ object.persons_responsible_structures.name|default:'N/A'|linebreaks }}
|
{{ object.persons_responsible_structures.name|default:'N/A'|linebreaks }}
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="col-6">{{ object|help_text:'rigging_plan'|safe }}</dt>
|
<dt class="col-12">{{ object|help_text:'rigging_plan'|safe }}</dt>
|
||||||
<dd class="col-6">
|
<dd class="col-12">
|
||||||
{{ object.rigging_plan|linkornone }}
|
{{ object.rigging_plan|linkornone|default:'N/A' }}
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="col-12 text-right">
|
<div class="col-12 text-right">
|
||||||
<a href="{% url 'ra_edit' object.pk %}" class="btn btn-warning my-3"><span class="fas fa-edit"></span> <span
|
<a href="{% url 'ra_edit' object.pk %}" class="btn btn-warning my-3"><span class="fas fa-edit"></span> <span
|
||||||
class="d-none d-sm-inline">Edit</span></a>
|
class="d-none d-sm-inline">Edit</span></a>
|
||||||
|
|||||||
@@ -11,13 +11,12 @@
|
|||||||
|
|
||||||
{% block preload_js %}
|
{% block preload_js %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<script src="{% static 'js/selects.js' %}" async></script>
|
<script src="{% static 'js/selects.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<script src="{% static 'js/autocompleter.js' %}"></script>
|
<script src="{% static 'js/autocompleter.js' %}"></script>
|
||||||
<script src="{% static 'js/tooltip.js' %}"></script>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function parseBool(str) {
|
function parseBool(str) {
|
||||||
|
|||||||
@@ -212,8 +212,25 @@ def button(type, url=None, pk=None, clazz="", icon=None, text="", id=None, style
|
|||||||
clazz += " btn-primary "
|
clazz += " btn-primary "
|
||||||
icon = "fa-plus"
|
icon = "fa-plus"
|
||||||
text = "New"
|
text = "New"
|
||||||
|
elif type == 'copy':
|
||||||
|
return {'copy': True, 'id': id, 'style': style}
|
||||||
elif type == 'search':
|
elif type == 'search':
|
||||||
return {'submit': True, 'class': 'btn-info', 'icon': 'fa-search', 'text': 'Search', 'id': id, 'style': style}
|
return {'submit': True, 'class': 'btn-info', 'icon': 'fa-search', 'text': 'Search', 'id': id, 'style': style}
|
||||||
elif type == 'submit':
|
elif type == 'submit':
|
||||||
return {'submit': True, 'class': 'btn-primary', 'icon': 'fa-save', 'text': 'Save', 'id': id, 'style': style}
|
return {'submit': True, 'class': 'btn-primary', 'icon': 'fa-save', 'text': 'Save', 'id': id, 'style': style}
|
||||||
return {'target': url, 'pk': pk, 'class': clazz, 'icon': icon, 'text': text, 'id': id, 'style': style}
|
return {'target': url, 'pk': pk, 'class': clazz, 'icon': icon, 'text': text, 'id': id, 'style': style}
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def invoices_waiting():
|
||||||
|
return len(models.Event.objects.waiting_invoices())
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def invoices_outstanding():
|
||||||
|
return len(models.Invoice.objects.outstanding_invoices())
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def total_invoices_todo():
|
||||||
|
return len(models.Event.objects.waiting_invoices()) + len(models.Invoice.objects.outstanding_invoices())
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class EventDetail(BasePage):
|
|||||||
|
|
||||||
# TODO Refactor into regions to match template fragmentation
|
# TODO Refactor into regions to match template fragmentation
|
||||||
_event_name_selector = (By.XPATH, '//h2')
|
_event_name_selector = (By.XPATH, '//h2')
|
||||||
_person_panel_selector = (By.XPATH, '//div[contains(text(), "Contact Details")]/..')
|
_person_panel_selector = (By.XPATH, '//div[contains(text(), "Person Details")]/..')
|
||||||
_name_selector = (By.XPATH, '//dt[text()="Person"]/following-sibling::dd[1]')
|
_name_selector = (By.XPATH, '//dt[text()="Person"]/following-sibling::dd[1]')
|
||||||
_email_selector = (By.XPATH, '//dt[text()="Email"]/following-sibling::dd[1]')
|
_email_selector = (By.XPATH, '//dt[text()="Email"]/following-sibling::dd[1]')
|
||||||
_phone_selector = (By.XPATH, '//dt[text()="Phone Number"]/following-sibling::dd[1]')
|
_phone_selector = (By.XPATH, '//dt[text()="Phone Number"]/following-sibling::dd[1]')
|
||||||
|
|||||||
@@ -721,12 +721,12 @@ def test_ec_create_medium(logged_in_browser, live_server, admin_user, medium_ra)
|
|||||||
page.fd_voltage_l2 = 235
|
page.fd_voltage_l2 = 235
|
||||||
page.fd_voltage_l3 = 0
|
page.fd_voltage_l3 = 0
|
||||||
page.fd_phase_rotation = True
|
page.fd_phase_rotation = True
|
||||||
page.fd_earth_fault = 666
|
page.fd_earth_fault = "1.21"
|
||||||
page.fd_pssc = 1984
|
page.fd_pssc = 1984
|
||||||
page.w1_description = "In the carpark, by the bins"
|
page.w1_description = "In the carpark, by the bins"
|
||||||
page.w1_polarity = True
|
page.w1_polarity = True
|
||||||
page.w1_voltage = 240
|
page.w1_voltage = 240
|
||||||
page.w1_earth_fault = 333
|
page.w1_earth_fault = "0.42"
|
||||||
|
|
||||||
page.submit()
|
page.submit()
|
||||||
assert page.success
|
assert page.success
|
||||||
|
|||||||
8
assets/converters.py
Normal file
8
assets/converters.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
class AssetIDConverter: # Forces lowercase to uppercase
|
||||||
|
regex = '[^/]+'
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
return str(value).upper()
|
||||||
|
|
||||||
|
def to_url(self, value):
|
||||||
|
return str(value).upper()
|
||||||
@@ -8,9 +8,9 @@ def add_default(apps, schema_editor):
|
|||||||
Connector = apps.get_model('assets', 'Connector')
|
Connector = apps.get_model('assets', 'Connector')
|
||||||
for cable_type in CableType.objects.all():
|
for cable_type in CableType.objects.all():
|
||||||
if cable_type.plug is None:
|
if cable_type.plug is None:
|
||||||
cable_type.plug = Connector.first()
|
cable_type.plug = Connector.objects.first()
|
||||||
if cable_type.socket is None:
|
if cable_type.socket is None:
|
||||||
cable_type.socket = Connector.first()
|
cable_type.socket = Connector.objects.first()
|
||||||
cable_type.save()
|
cable_type.save()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
23
assets/migrations/0020_auto_20210302_1201.py
Normal file
23
assets/migrations/0020_auto_20210302_1201.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 3.1.7 on 2021-03-02 12:01
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def postgres_migration_prep(apps, schema_editor):
|
||||||
|
model = apps.get_model("assets", "Supplier")
|
||||||
|
fields = ["address", "email", "notes", "phone"]
|
||||||
|
for field in fields:
|
||||||
|
filter_param = {"{}__isnull".format(field): True}
|
||||||
|
update_param = {field: ""}
|
||||||
|
model.objects.filter(**filter_param).update(**update_param)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assets', '0019_fix_cabletype'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(postgres_migration_prep, migrations.RunPython.noop)
|
||||||
|
]
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 3.1.5 on 2021-02-08 16:03
|
# Generated by Django 3.1.7 on 2021-03-02 12:04
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
@@ -7,7 +7,7 @@ import django.db.models.deletion
|
|||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('assets', '0019_fix_cabletype'),
|
('assets', '0020_auto_20210302_1201'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
@@ -49,7 +49,7 @@ class Supplier(models.Model, RevisionMixin):
|
|||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('supplier_list')
|
return reverse('supplier_detail', kwargs={'pk': self.pk})
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
@@ -82,6 +82,9 @@ class CableType(models.Model):
|
|||||||
else:
|
else:
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse('cable_type_detail', kwargs={'pk': self.pk})
|
||||||
|
|
||||||
|
|
||||||
def get_available_asset_id(wanted_prefix=""):
|
def get_available_asset_id(wanted_prefix=""):
|
||||||
sql = """
|
sql = """
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
{% load widget_tweaks %}
|
{% load widget_tweaks %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<div class="row justify-content-end">
|
||||||
|
{% include 'partials/asset_buttons.html' %}
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
{% include 'partials/asset_detail_form.html' %}
|
{% include 'partials/asset_detail_form.html' %}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
})
|
})
|
||||||
.ajaxSelectPicker({
|
.ajaxSelectPicker({
|
||||||
ajax: {
|
ajax: {
|
||||||
url: '{% url 'asset_search_json' %}',
|
url: "{% url 'asset_search_json' %}",
|
||||||
type: "GET",
|
type: "GET",
|
||||||
data: function () {
|
data: function () {
|
||||||
let params = {
|
let params = {
|
||||||
|
|||||||
@@ -11,7 +11,10 @@
|
|||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
{% button 'edit' url='asset_update' pk=object.asset_id %}
|
{% button 'edit' url='asset_update' pk=object.asset_id %}
|
||||||
{% button 'duplicate' url='asset_duplicate' pk=object.asset_id %}
|
{% button 'duplicate' url='asset_duplicate' pk=object.asset_id %}
|
||||||
<a type="button" class="btn btn-info" href="{% url 'asset_audit' object.asset_id %}"><i class="fas fa-certificate"></i> Audit</a>
|
<a type="button" class="btn btn-info" href="{% url 'asset_audit' object.asset_id %}"><span class="fas fa-certificate"></span> Audit</a>
|
||||||
|
{% if object.is_cable %}
|
||||||
|
<a type="button" class="btn btn-primary" href="{% url 'generate_label' object.asset_id %}"><span class="fas fa-barcode"></span> Generate Label</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if create or edit or duplicate %}
|
{% if create or edit or duplicate %}
|
||||||
|
|||||||
@@ -17,11 +17,9 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Cable Type</dt>
|
<dt>Cable Type</dt>
|
||||||
<dd>{{ object.cable_type|default_if_none:'-' }}</dd>
|
<dd>{% if object.cable_type %}<a href="{{object.cable_type.get_absolute_url}}">{{ object.cable_type }}</a>{%else%}-{%endif%}</dd>
|
||||||
|
|
||||||
<dt>Length</dt>
|
<dt>Length</dt>
|
||||||
<dd>{{ object.length|default_if_none:'-' }}m</dd>
|
<dd>{{ object.length|default_if_none:'-' }}m</dd>
|
||||||
|
|
||||||
<dt>Cross Sectional Area</dt>
|
<dt>Cross Sectional Area</dt>
|
||||||
<dd>{{ object.csa|default_if_none:'-' }}mm²</dd>
|
<dd>{{ object.csa|default_if_none:'-' }}mm²</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|||||||
@@ -28,13 +28,13 @@
|
|||||||
|
|
||||||
<dt>Children</dt>
|
<dt>Children</dt>
|
||||||
{% if object.asset_parent.all %}
|
{% if object.asset_parent.all %}
|
||||||
|
<div style="max-height: 200px; overflow-y: auto; -webkit-overflow-scrolling: touch; ">
|
||||||
{% for child in object.asset_parent.all %}
|
{% for child in object.asset_parent.all %}
|
||||||
<dd>
|
<dd>
|
||||||
<a href="{% url 'asset_detail' child.asset_id %}">
|
<a href="{% url 'asset_detail' child.asset_id %}">{{ child }}</a>
|
||||||
{{ child.asset_id }} - {{ child.description }}
|
|
||||||
</a>
|
|
||||||
</dd>
|
</dd>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<dd><span>-</span></dd>
|
<dd><span>-</span></dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{% load widget_tweaks %}
|
{% load widget_tweaks %}
|
||||||
|
{% load linkornone from filters %}
|
||||||
<div class="card mb-2">
|
<div class="card mb-2">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
Purchase Details
|
Purchase Details
|
||||||
@@ -7,12 +8,27 @@
|
|||||||
{% if create or edit or duplicate %}
|
{% if create or edit or duplicate %}
|
||||||
<div class="form-group" id="purchased-from-group">
|
<div class="form-group" id="purchased-from-group">
|
||||||
<label for="{{ form.purchased_from.id_for_label }}">Supplier</label>
|
<label for="{{ form.purchased_from.id_for_label }}">Supplier</label>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
<select id="{{ form.purchased_from.id_for_label }}" name="{{ form.purchased_from.name }}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='supplier' %}">
|
<select id="{{ form.purchased_from.id_for_label }}" name="{{ form.purchased_from.name }}" class="form-control selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='supplier' %}">
|
||||||
{% if object.purchased_from %}
|
{% if object.purchased_from %}
|
||||||
<option value="{{form.purchased_from.value}}" selected="selected" data-update_url="{% url 'supplier_update' form.purchased_from.value %}">{{ object.purchased_from }}</option>
|
<option value="{{form.purchased_from.value}}" selected="selected" data-update_url="{% url 'supplier_update' form.purchased_from.value %}">{{ object.purchased_from }}</option>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col align-right">
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="{% url 'supplier_create' %}" class="btn btn-success modal-href"
|
||||||
|
data-target="#{{ form.purchased_from.id_for_label }}">
|
||||||
|
<span class="fas fa-plus"></span>
|
||||||
|
</a>
|
||||||
|
<a {% if form.supplier.value %}href="{% url 'supplier_update' form.purchased_from.value %}"{% endif %} class="btn btn-warning modal-href" id="{{ form.purchased_from.id_for_label }}-update" data-target="#{{ form.purchased_from.id_for_label }}">
|
||||||
|
<span class="fas fa-edit"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="{{ form.purchase_price.id_for_label }}">Purchase Price</label>
|
<label for="{{ form.purchase_price.id_for_label }}">Purchase Price</label>
|
||||||
@@ -51,14 +67,11 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Purchased From</dt>
|
<dt>Purchased From</dt>
|
||||||
<dd>{{ object.purchased_from|default_if_none:'-' }}</dd>
|
<dd>{% if object.purchased_from %}<a href="{{object.purchased_from.get_absolute_url}}">{{ object.purchased_from }}</a>{%else%}-{%endif%}</dd>
|
||||||
|
|
||||||
<dt>Purchase Price</dt>
|
<dt>Purchase Price</dt>
|
||||||
<dd>£{{ object.purchase_price|default_if_none:'-' }}</dd>
|
<dd>£{{ object.purchase_price|default_if_none:'-' }}</dd>
|
||||||
|
|
||||||
<dt>Salvage Value</dt>
|
<dt>Salvage Value</dt>
|
||||||
<dd>£{{ object.salvage_value|default_if_none:'-' }}</dd>
|
<dd>£{{ object.salvage_value|default_if_none:'-' }}</dd>
|
||||||
|
|
||||||
<dt>Date Acquired</dt>
|
<dt>Date Acquired</dt>
|
||||||
<dd>{{ object.date_acquired|default_if_none:'-' }}</dd>
|
<dd>{{ object.date_acquired|default_if_none:'-' }}</dd>
|
||||||
{% if object.date_sold %}
|
{% if object.date_sold %}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class AssetList(BasePage):
|
|||||||
|
|
||||||
|
|
||||||
class AssetForm(FormPage):
|
class AssetForm(FormPage):
|
||||||
_purchased_from_select_locator = (By.CSS_SELECTOR, 'div#purchased-from-group>div.bootstrap-select')
|
_purchased_from_select_locator = (By.XPATH, '//div[@id="purchased-from-group"]/div/div/div')
|
||||||
_parent_select_locator = (By.CSS_SELECTOR, 'div#parent-group>div.bootstrap-select')
|
_parent_select_locator = (By.CSS_SELECTOR, 'div#parent-group>div.bootstrap-select')
|
||||||
form_items = {
|
form_items = {
|
||||||
'asset_id': (regions.TextBox, (By.ID, 'id_asset_id')),
|
'asset_id': (regions.TextBox, (By.ID, 'id_asset_id')),
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.urls import path
|
from django.urls import path, register_converter
|
||||||
from django.views.decorators.clickjacking import xframe_options_exempt
|
from django.views.decorators.clickjacking import xframe_options_exempt
|
||||||
|
|
||||||
from PyRIGS.decorators import has_oembed, permission_required_with_403
|
from PyRIGS.decorators import has_oembed, permission_required_with_403
|
||||||
from PyRIGS.views import OEmbedView
|
from PyRIGS.views import OEmbedView
|
||||||
from assets import views
|
from . import views, converters
|
||||||
|
|
||||||
|
register_converter(converters.AssetIDConverter, 'asset')
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', login_required(views.AssetList.as_view()), name='asset_index'),
|
path('', login_required(views.AssetList.as_view()), name='asset_index'),
|
||||||
path('asset/list/', login_required(views.AssetList.as_view()), name='asset_list'),
|
path('asset/list/', login_required(views.AssetList.as_view()), name='asset_list'),
|
||||||
path('asset/id/<str:pk>/', has_oembed(oembed_view="asset_oembed")(views.AssetDetail.as_view()), name='asset_detail'),
|
path('asset/id/<asset:pk>/', has_oembed(oembed_view="asset_oembed")(views.AssetDetail.as_view()), name='asset_detail'),
|
||||||
path('asset/create/', permission_required_with_403('assets.add_asset')
|
path('asset/create/', permission_required_with_403('assets.add_asset')
|
||||||
(views.AssetCreate.as_view()), name='asset_create'),
|
(views.AssetCreate.as_view()), name='asset_create'),
|
||||||
path('asset/id/<str:pk>/edit/', permission_required_with_403('assets.change_asset')
|
path('asset/id/<asset:pk>/edit/', permission_required_with_403('assets.change_asset')
|
||||||
(views.AssetEdit.as_view()), name='asset_update'),
|
(views.AssetEdit.as_view()), name='asset_update'),
|
||||||
path('asset/id/<str:pk>/duplicate/', permission_required_with_403('assets.add_asset')
|
path('asset/id/<asset:pk>/duplicate/', permission_required_with_403('assets.add_asset')
|
||||||
(views.AssetDuplicate.as_view()), name='asset_duplicate'),
|
(views.AssetDuplicate.as_view()), name='asset_duplicate'),
|
||||||
|
path('asset/id/<asset:pk>/label', login_required(views.GenerateLabel.as_view()), name='generate_label'),
|
||||||
|
|
||||||
path('cabletype/list/', login_required(views.CableTypeList.as_view()), name='cable_type_list'),
|
path('cabletype/list/', login_required(views.CableTypeList.as_view()), name='cable_type_list'),
|
||||||
path('cabletype/create/', permission_required_with_403('assets.add_cable_type')(views.CableTypeCreate.as_view()), name='cable_type_create'),
|
path('cabletype/create/', permission_required_with_403('assets.add_cable_type')(views.CableTypeCreate.as_view()), name='cable_type_create'),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import simplejson
|
import simplejson
|
||||||
|
import random
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.core import serializers
|
from django.core import serializers
|
||||||
@@ -9,6 +10,11 @@ from django.utils import timezone
|
|||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
from barcode import Code39
|
||||||
|
from barcode.writer import ImageWriter
|
||||||
|
|
||||||
from PyRIGS.views import GenericListView, GenericDetailView, GenericUpdateView, GenericCreateView, ModalURLMixin, \
|
from PyRIGS.views import GenericListView, GenericDetailView, GenericUpdateView, GenericCreateView, ModalURLMixin, \
|
||||||
is_ajax, OEmbedView
|
is_ajax, OEmbedView
|
||||||
@@ -42,9 +48,9 @@ class AssetList(LoginRequiredMixin, generic.ListView):
|
|||||||
queryset = self.model.objects.all()
|
queryset = self.model.objects.all()
|
||||||
elif len(query_string) >= 3:
|
elif len(query_string) >= 3:
|
||||||
queryset = self.model.objects.filter(
|
queryset = self.model.objects.filter(
|
||||||
Q(asset_id__exact=query_string) | Q(description__icontains=query_string) | Q(serial_number__exact=query_string))
|
Q(asset_id__exact=query_string.upper()) | Q(description__icontains=query_string) | Q(serial_number__exact=query_string))
|
||||||
else:
|
else:
|
||||||
queryset = self.model.objects.filter(Q(asset_id__exact=query_string))
|
queryset = self.model.objects.filter(Q(asset_id__exact=query_string.upper()))
|
||||||
|
|
||||||
if form.cleaned_data['category']:
|
if form.cleaned_data['category']:
|
||||||
queryset = queryset.filter(category__in=form.cleaned_data['category'])
|
queryset = queryset.filter(category__in=form.cleaned_data['category'])
|
||||||
@@ -338,3 +344,37 @@ class CableTypeUpdate(generic.UpdateView):
|
|||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse("cable_type_detail", kwargs={"pk": self.object.pk})
|
return reverse("cable_type_detail", kwargs={"pk": self.object.pk})
|
||||||
|
|
||||||
|
|
||||||
|
class GenerateLabel(generic.View):
|
||||||
|
def get(self, request, pk):
|
||||||
|
black = (0, 0, 0)
|
||||||
|
white = (255, 255, 255)
|
||||||
|
size = (700, 200)
|
||||||
|
font = ImageFont.truetype("static/fonts/OpenSans-Regular.tff", 20)
|
||||||
|
obj = get_object_or_404(models.Asset, asset_id=pk)
|
||||||
|
|
||||||
|
asset_id = "Asset: {}".format(obj.asset_id)
|
||||||
|
length = "Length: {}m".format(obj.length)
|
||||||
|
csa = "CSA: {}mm²".format(obj.csa)
|
||||||
|
|
||||||
|
image = Image.new("RGB", size, white)
|
||||||
|
logo = Image.open("static/imgs/square_logo.png")
|
||||||
|
draw = ImageDraw.Draw(image)
|
||||||
|
|
||||||
|
draw.text((210, 140), asset_id, fill=black, font=font)
|
||||||
|
draw.text((210, 170), length, fill=black, font=font)
|
||||||
|
draw.text((350, 170), csa, fill=black, font=font)
|
||||||
|
draw.multiline_text((500, 140), "TEC PA & Lighting\n(0115) 84 68720", fill=black, font=font)
|
||||||
|
|
||||||
|
barcode = Code39(str(obj.asset_id), writer=ImageWriter())
|
||||||
|
|
||||||
|
logo_size = (200, 200)
|
||||||
|
image.paste(logo.resize(logo_size, Image.ANTIALIAS))
|
||||||
|
barcode_image = barcode.render(writer_options={"quiet_zone": 0, "write_text": False})
|
||||||
|
width, height = barcode_image.size
|
||||||
|
image.paste(barcode_image.crop((0, 0, width, 135)), (int(((size[0] + logo_size[0]) - width) / 2), 0))
|
||||||
|
|
||||||
|
response = HttpResponse(content_type="image/png")
|
||||||
|
image.save(response, "PNG")
|
||||||
|
return response
|
||||||
|
|||||||
@@ -119,4 +119,18 @@
|
|||||||
background: #222;
|
background: #222;
|
||||||
color: $gray-100;
|
color: $gray-100;
|
||||||
}
|
}
|
||||||
|
input:-webkit-autofill,
|
||||||
|
input:-webkit-autofill:hover,
|
||||||
|
input:-webkit-autofill:focus,
|
||||||
|
textarea:-webkit-autofill,
|
||||||
|
textarea:-webkit-autofill:hover,
|
||||||
|
textarea:-webkit-autofill:focus,
|
||||||
|
select:-webkit-autofill,
|
||||||
|
select:-webkit-autofill:hover,
|
||||||
|
select:-webkit-autofill:focus {
|
||||||
|
border: 1px solid $info;
|
||||||
|
-webkit-text-fill-color: white;
|
||||||
|
-webkit-box-shadow: 0 0 0px 1000px rgba($info, .3) inset;
|
||||||
|
transition: background-color 5000s ease-in-out 0s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,6 +177,11 @@ svg {
|
|||||||
white-space: no-wrap;
|
white-space: no-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.fas {
|
||||||
|
padding-left: 0.1em !important;
|
||||||
|
padding-right: 0.1em !important;
|
||||||
|
}
|
||||||
|
|
||||||
html.embedded {
|
html.embedded {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
<link rel="icon" type="image/png" href="{% static 'imgs/pyrigs-avatar.png' %}">
|
<link rel="icon" type="image/png" href="{% static 'imgs/pyrigs-avatar.png' %}">
|
||||||
<link rel="apple-touch-icon" href="{% static 'imgs/pyrigs-avatar.png' %}">
|
<link rel="apple-touch-icon" href="{% static 'imgs/pyrigs-avatar.png' %}">
|
||||||
<link rel="preload" href="{% static 'fonts/fa-solid-900.woff2' %}" as="font" type="font/woff2" crossorigin>
|
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="{% static 'css/screen.css' %}">
|
<link rel="stylesheet" type="text/css" href="{% static 'css/screen.css' %}">
|
||||||
{% block css %}
|
{% block css %}
|
||||||
@@ -32,22 +31,22 @@
|
|||||||
<a class="skip-link" href='#main'>Skip to content</a>
|
<a class="skip-link" href='#main'>Skip to content</a>
|
||||||
{% include "analytics.html" %}
|
{% include "analytics.html" %}
|
||||||
{% block navbar %}
|
{% block navbar %}
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark flex-nowrap" role="navigation">
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark" role="navigation">
|
||||||
<a class="navbar-brand" href="{% if request.user.is_authenticated %}https://members.nottinghamtec.co.uk{%else%}https://nottinghamtec.co.uk{%endif%}">
|
|
||||||
<img src="{% static 'imgs/logo.webp' %}" width="40" height="40" alt="TEC's Logo: Serif 'TEC' vertically next to a blue box with the words 'PA and Lighting', surrounded by graduated rings">
|
|
||||||
</a>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<a class="navbar-brand" style="position: absolute; left:0.5em; top: 2px;" href="{% if request.user.is_authenticated %}https://rigs.nottinghamtec.co.uk{%else%}https://nottinghamtec.co.uk{%endif%}">
|
||||||
|
<img src="{% static 'imgs/logo.webp' %}" width="40" height="40" alt="TEC's Logo: Serif 'TEC' vertically next to a blue box with the words 'PA and Lighting', surrounded by graduated rings" id="logo">
|
||||||
|
</a>
|
||||||
{% block titleheader %}
|
{% block titleheader %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
<button class="navbar-toggler ml-auto" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation" onclick="document.getElementById('logo').classList.toggle('d-none');">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
</button>
|
</button>
|
||||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
<div class="collapse navbar-collapse justify-content-between" id="navbarSupportedContent">
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
{% block titleelements %}
|
{% block titleelements %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="navbar-nav ml-auto">
|
<ul class="navbar-nav align-self-end">
|
||||||
{% block titleelements_right %}
|
{% block titleelements_right %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h4 class="modal-title">{{page_title}}{% block title %}{% endblock %}</h4>
|
<h4 class="modal-title">{{page_title|safe}}{% block title %}{% endblock %}</h4>
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
<button type="submit" class="btn {{ class }}" title="{{ text }}" {% if id %}id="{{id}}"{%endif%} {% if style %}style="{{style}}"{%endif%}><span class="fas {{ icon }} align-middle"></span> <span class="d-none d-sm-inline align-middle">{{ text }}</span></button>
|
<button type="submit" class="btn {{ class }}" title="{{ text }}" {% if id %}id="{{id}}"{%endif%} {% if style %}style="{{style}}"{%endif%}><span class="fas {{ icon }} align-middle"></span> <span class="d-none d-sm-inline align-middle">{{ text }}</span></button>
|
||||||
{% elif pk %}
|
{% elif pk %}
|
||||||
<a href="{% url target pk %}" class="btn {{ class }}" {% if id %}id="{{id}}"{%endif%} {% if style %}style="{{style}}"{%endif%} {% if text == 'Print' %}target="_blank"{%endif%}><span class="fas {{ icon }} align-middle"></span> <span class="d-none d-sm-inline align-middle">{{ text }}</span></a>
|
<a href="{% url target pk %}" class="btn {{ class }}" {% if id %}id="{{id}}"{%endif%} {% if style %}style="{{style}}"{%endif%} {% if text == 'Print' %}target="_blank"{%endif%}><span class="fas {{ icon }} align-middle"></span> <span class="d-none d-sm-inline align-middle">{{ text }}</span></a>
|
||||||
|
{% elif copy %}
|
||||||
|
<button class="btn btn-secondary btn-sm mr-1" data-clipboard-target="{{id}}" data-content="Copied to clipboard!"><span class="fas fa-copy"></span></button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url target %}" class="btn {{ class }}" {% if id %}id="{{id}}"{%endif%} {% if style %}style="{{style}}"{%endif%}><span class="fas {{ icon }} align-middle"></span> <span class="d-none d-sm-inline align-middle">{{ text }}</span></a>
|
<a href="{% url target %}" class="btn {{ class }}" {% if id %}id="{{id}}"{%endif%} {% if style %}style="{{style}}"{%endif%}><span class="fas {{ icon }} align-middle"></span> <span class="d-none d-sm-inline align-middle">{{ text }}</span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<form id="searchForm" class="form-inline flex-nowrap mx-md-3 px-2 border border-light rounded" role="form" method="GET" action="{% url 'event_archive' %}">
|
<form id="searchForm" class="form-inline flex-nowrap mx-md-3 px-2 border border-light rounded w-75" role="form" method="GET" action="{% url 'event_archive' %}">
|
||||||
<div class="input-group input-group-sm flex-nowrap">
|
<div class="input-group input-group-sm flex-nowrap">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<input id="id_search_input" type="search" name="q" class="form-control form-control-sm" placeholder="Search..." value="{{ request.GET.q }}" />
|
<input id="id_search_input" type="search" name="q" class="form-control form-control-sm" placeholder="Search..." value="{{ request.GET.q }}" />
|
||||||
</div>
|
</div>
|
||||||
<select id="search-options" class="custom-select form-control" style="border-top-right-radius: 0px; border-bottom-right-radius: 0px; width: 20ch;">
|
<select id="search-options" class="custom-select form-control" style="border-top-right-radius: 0px; border-bottom-right-radius: 0px; width: 15ch;">
|
||||||
<option selected data-action="{% url 'event_archive' %}" href="#">Events</option>
|
<option selected data-action="{% url 'event_archive' %}" href="#">Events</option>
|
||||||
<option data-action="{% url 'person_list' %}" href="#">People</option>
|
<option data-action="{% url 'person_list' %}" href="#">People</option>
|
||||||
<option data-action="{% url 'organisation_list' %}" href="#">Organisations</option>
|
<option data-action="{% url 'organisation_list' %}" href="#">Organisations</option>
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-info form-control form-control-sm btn-sm w-25" style="border-top-left-radius: 0px;border-bottom-left-radius: 0px;"><span class="fas fa-search"></span><span class="sr-only"> Search</span></button>
|
<button class="btn btn-info form-control form-control-sm btn-sm w-25" style="border-top-left-radius: 0px;border-bottom-left-radius: 0px;"><span class="fas fa-search"></span><span class="sr-only"> Search</span></button>
|
||||||
<a href="{% url 'search_help' %}" class="nav-link modal-href ml-2"><span class="fas fa-question-circle"></span></a>
|
<a href="{% url 'search_help' %}" class="nav-link modal-href ml-1"><span class="fas fa-question-circle"></span></a>
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
{% extends 'base_rigs.html' %}
|
{% extends 'base_rigs.html' %}
|
||||||
{% load widget_tweaks %}
|
{% load widget_tweaks %}
|
||||||
|
{% load static %}
|
||||||
{% block title %}Registration{% endblock %}
|
{% block title %}Registration{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-sm-10 col-sm-offset-1">
|
<div style="background-image: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)), url({% static 'imgs/wof2014-1-small.jpg' %}); background-repeat: no-repeat; background-size: cover; width: 100vw; height: 100vh; position: relative; left: 50%; right: 50%; margin-left: -50vw; margin-right: -50vw; margin-top: -24px; padding-top: 24px;">
|
||||||
<h3>New User Registration</h3>
|
<div class="container">
|
||||||
|
<div class="card">
|
||||||
|
<h3 class="card-header">New User Registration</h3>
|
||||||
|
<div class="card-body">
|
||||||
{% if form.errors or supplement_form.errors %}
|
{% if form.errors or supplement_form.errors %}
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger">
|
||||||
{{form.errors}}
|
{{form.errors}}
|
||||||
{{supplement_form.errors}}
|
{{supplement_form.errors}}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="col-sm-8 col-sm-offset-2">
|
<div class="col-sm-8 col-sm-offset-2">
|
||||||
<form action="" method="post" class="" role="form">{% csrf_token %}
|
<form method="post" role="form">{% csrf_token %}
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
<div class="form-group">
|
<div class="form-group form-row">
|
||||||
<label for="{{ field.id_for_label }}" class="col-form-label col-sm-4">{{ field.label }}</label>
|
<label for="{{ field.id_for_label }}" class="col-form-label col-sm-4">{{ field.label }}</label>
|
||||||
<div class="controls col-sm-8">
|
<div class="controls col-sm-8">
|
||||||
{% render_field field class+="form-control" placeholder=field.label %}
|
{% render_field field class+="form-control" placeholder=field.label %}
|
||||||
@@ -26,4 +29,8 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,15 +1,24 @@
|
|||||||
from captcha.fields import ReCaptchaField
|
from hcaptcha.fields import hCaptchaField
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth.forms import (AuthenticationForm, PasswordResetForm,
|
from django.contrib.auth.forms import (AuthenticationForm, PasswordResetForm,
|
||||||
UserChangeForm, UserCreationForm)
|
UserChangeForm, UserCreationForm)
|
||||||
|
from django.conf import settings
|
||||||
from registration.forms import RegistrationFormUniqueEmail
|
from registration.forms import RegistrationFormUniqueEmail
|
||||||
|
|
||||||
from RIGS import models
|
from RIGS import models
|
||||||
|
|
||||||
|
|
||||||
|
class CaptchaField(hCaptchaField):
|
||||||
|
def validate(self, value):
|
||||||
|
# Skip validation if we're testing FIXME: Arona, y u so lazy
|
||||||
|
if settings.HCAPTCHA_SITEKEY != '10000000-ffff-ffff-ffff-000000000001':
|
||||||
|
super().validate(value)
|
||||||
|
|
||||||
# Registration
|
# Registration
|
||||||
|
|
||||||
|
|
||||||
class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
|
class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
|
||||||
captcha = ReCaptchaField()
|
hcaptcha = CaptchaField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Profile
|
model = models.Profile
|
||||||
@@ -41,7 +50,7 @@ class EmbeddedAuthenticationForm(CheckApprovedForm):
|
|||||||
|
|
||||||
|
|
||||||
class PasswordReset(PasswordResetForm):
|
class PasswordReset(PasswordResetForm):
|
||||||
captcha = ReCaptchaField(label='Captcha')
|
hcaptcha = CaptchaField()
|
||||||
|
|
||||||
|
|
||||||
class ProfileCreationForm(UserCreationForm):
|
class ProfileCreationForm(UserCreationForm):
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<li class="nav-item dropdown" id="user">
|
<li class="nav-item dropdown align-self-end" id="user">
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<a class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
Hi {{ user.first_name }}
|
Hi {{ user.first_name }}
|
||||||
|
|||||||
@@ -101,11 +101,11 @@
|
|||||||
<dd class="col-8">
|
<dd class="col-8">
|
||||||
{% if user.api_key %}
|
{% if user.api_key %}
|
||||||
<code id="api-key">{{user.api_key}}</code>
|
<code id="api-key">{{user.api_key}}</code>
|
||||||
<button class="btn btn-secondary align-middle" data-clipboard-target="#api-key" data-content="Copied to clipboard!"><span class="fas fa-clipboard"></span></button>
|
<button class="btn btn-secondary align-middle pr-1 btn-sm" data-clipboard-target="#api-key" data-content="Copied to clipboard!"><span class="fas fa-clipboard"></span></button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<span id="api-key">No API Key Generated</span>
|
<span id="api-key">No API Key Generated</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'reset_api_key' %}" class="btn btn-secondary align-middle">
|
<a href="{% url 'reset_api_key' %}" class="btn btn-secondary align-middle pr-1">
|
||||||
{% if user.api_key %}Reset API Key{% else %}Generate API Key{% endif %}
|
{% if user.api_key %}Reset API Key{% else %}Generate API Key{% endif %}
|
||||||
<span class="fas fa-redo"></span>
|
<span class="fas fa-redo"></span>
|
||||||
</a>
|
</a>
|
||||||
@@ -139,7 +139,7 @@
|
|||||||
<dd class="col-8">
|
<dd class="col-8">
|
||||||
{% if user.api_key %}
|
{% if user.api_key %}
|
||||||
<code id="cal-url" data-url="http{{ request.is_secure|yesno:"s,"}}://{{ request.get_host }}{% url 'ics_calendar' api_pk=user.pk api_key=user.api_key %}"></code>
|
<code id="cal-url" data-url="http{{ request.is_secure|yesno:"s,"}}://{{ request.get_host }}{% url 'ics_calendar' api_pk=user.pk api_key=user.api_key %}"></code>
|
||||||
<button class="btn btn-secondary align-middle" data-clipboard-target="#cal-url" data-content="Copied to clipboard!"><span class="fas fa-clipboard"></span></button>
|
<button class="btn btn-secondary align-middle btn-sm pr-1" data-clipboard-target="#cal-url" data-content="Copied to clipboard!"><span class="fas fa-clipboard"></span></button>
|
||||||
<br>
|
<br>
|
||||||
<small><a id="gcal-link" data-url="https://support.google.com/calendar/answer/37100" href="">Click here</a> for instructions on adding to google calendar.<br/>
|
<small><a id="gcal-link" data-url="https://support.google.com/calendar/answer/37100" href="">Click here</a> for instructions on adding to google calendar.<br/>
|
||||||
To sync from Google Calendar to mobile device, visit <a href="https://www.google.com/calendar/syncselect" target="_blank">this page</a> on your device and tick "RIGS Calendar".</small>
|
To sync from Google Calendar to mobile device, visit <a href="https://www.google.com/calendar/syncselect" target="_blank">this page</a> on your device and tick "RIGS Calendar".</small>
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
from django.test import LiveServerTestCase
|
from django.test import LiveServerTestCase
|
||||||
|
from django.test.utils import override_settings
|
||||||
from selenium.webdriver.common.keys import Keys
|
from selenium.webdriver.common.keys import Keys
|
||||||
|
|
||||||
from PyRIGS.tests.base import create_browser
|
from PyRIGS.tests.base import create_browser
|
||||||
@@ -13,14 +15,12 @@ from RIGS import models
|
|||||||
class UserRegistrationTest(LiveServerTestCase):
|
class UserRegistrationTest(LiveServerTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.browser = create_browser()
|
self.browser = create_browser()
|
||||||
|
self.browser.implicitly_wait(5) # Set implicit wait session wide
|
||||||
self.browser.implicitly_wait(3) # Set implicit wait session wide
|
|
||||||
os.environ['RECAPTCHA_TESTING'] = 'True'
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.browser.quit()
|
self.browser.quit()
|
||||||
os.environ['RECAPTCHA_TESTING'] = 'False'
|
|
||||||
|
|
||||||
|
@override_settings(DEBUG=True)
|
||||||
def test_registration(self):
|
def test_registration(self):
|
||||||
# Navigate to the registration page
|
# Navigate to the registration page
|
||||||
self.browser.get(self.live_server_url + '/user/register/')
|
self.browser.get(self.live_server_url + '/user/register/')
|
||||||
@@ -61,9 +61,11 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
last_name.send_keys('Smith')
|
last_name.send_keys('Smith')
|
||||||
initials.send_keys('JS')
|
initials.send_keys('JS')
|
||||||
# phone.send_keys('0123456789')
|
# phone.send_keys('0123456789')
|
||||||
self.browser.execute_script(
|
time.sleep(1)
|
||||||
"return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()")
|
self.browser.switch_to.frame(self.browser.find_element_by_tag_name("iframe"))
|
||||||
|
self.browser.find_element_by_id('anchor').click()
|
||||||
|
self.browser.switch_to.default_content()
|
||||||
|
time.sleep(3)
|
||||||
# Submit incorrect form
|
# Submit incorrect form
|
||||||
submit = self.browser.find_element_by_xpath("//input[@type='submit']")
|
submit = self.browser.find_element_by_xpath("//input[@type='submit']")
|
||||||
submit.click()
|
submit.click()
|
||||||
@@ -85,9 +87,6 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
# Correct error
|
# Correct error
|
||||||
password1.send_keys('correcthorsebatterystaple')
|
password1.send_keys('correcthorsebatterystaple')
|
||||||
password2.send_keys('correcthorsebatterystaple')
|
password2.send_keys('correcthorsebatterystaple')
|
||||||
self.browser.execute_script("console.log('Hello, world!')")
|
|
||||||
self.browser.execute_script(
|
|
||||||
"return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()")
|
|
||||||
|
|
||||||
# Submit again
|
# Submit again
|
||||||
password2.send_keys(Keys.ENTER)
|
password2.send_keys(Keys.ENTER)
|
||||||
@@ -126,8 +125,6 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
# Expected to fail as not approved
|
# Expected to fail as not approved
|
||||||
username.send_keys('TestUsername')
|
username.send_keys('TestUsername')
|
||||||
password.send_keys('correcthorsebatterystaple')
|
password.send_keys('correcthorsebatterystaple')
|
||||||
self.browser.execute_script(
|
|
||||||
"return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()")
|
|
||||||
password.send_keys(Keys.ENTER)
|
password.send_keys(Keys.ENTER)
|
||||||
|
|
||||||
# Test approval
|
# Test approval
|
||||||
@@ -149,8 +146,6 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
username.send_keys('TestUsername')
|
username.send_keys('TestUsername')
|
||||||
password = self.browser.find_element_by_id('id_password')
|
password = self.browser.find_element_by_id('id_password')
|
||||||
password.send_keys('correcthorsebatterystaple')
|
password.send_keys('correcthorsebatterystaple')
|
||||||
self.browser.execute_script(
|
|
||||||
"return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()")
|
|
||||||
password.send_keys(Keys.ENTER)
|
password.send_keys(Keys.ENTER)
|
||||||
|
|
||||||
# Check we are logged in
|
# Check we are logged in
|
||||||
|
|||||||
Reference in New Issue
Block a user