Compare commits
4 Commits
hotfix-dis
...
feature/in
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ca55f2696 | ||
|
|
228592a0f3 | ||
|
|
1be1b1abd7 | ||
|
|
42e1931e72 |
2
.gitignore
vendored
@@ -44,7 +44,6 @@ htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.cache
|
||||
.pytest_cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
|
||||
@@ -108,4 +107,3 @@ atlassian-ide-plugin.xml
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
.vscode/
|
||||
12
Dockerfile
@@ -1,12 +0,0 @@
|
||||
FROM python:3.6
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ADD . /app
|
||||
|
||||
RUN pip install -r requirements.txt && \
|
||||
python manage.py collectstatic --noinput
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
|
||||
1
Procfile
@@ -1,2 +1 @@
|
||||
release: python manage.py migrate
|
||||
web: gunicorn PyRIGS.wsgi --log-file -
|
||||
|
||||
@@ -11,7 +11,6 @@ https://docs.djangoproject.com/en/1.7/ref/settings/
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
import os
|
||||
import raven
|
||||
import secrets
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
@@ -58,7 +57,6 @@ INSTALLED_APPS = (
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'RIGS',
|
||||
'assets',
|
||||
|
||||
'debug_toolbar',
|
||||
'registration',
|
||||
@@ -235,7 +233,3 @@ USE_GRAVATAR = True
|
||||
|
||||
TERMS_OF_HIRE_URL = "http://www.nottinghamtec.co.uk/terms.pdf"
|
||||
AUTHORISATION_NOTIFICATION_ADDRESS = 'productions@nottinghamtec.co.uk'
|
||||
RISK_ASSESSMENT_URL = os.environ.get('RISK_ASSESSMENT_URL') if os.environ.get(
|
||||
'RISK_ASSESSMENT_URL') else "http://example.com"
|
||||
RISK_ASSESSMENT_SECRET = os.environ.get('RISK_ASSESSMENT_SECRET') if os.environ.get(
|
||||
'RISK_ASSESSMENT_SECRET') else secrets.token_hex(15)
|
||||
|
||||
@@ -12,7 +12,6 @@ urlpatterns = [
|
||||
# url(r'^blog/', include('blog.urls')),
|
||||
|
||||
url(r'^', include('RIGS.urls')),
|
||||
url('^assets/', include('assets.urls')),
|
||||
url('^user/register/$', RegistrationView.as_view(form_class=RIGS.forms.ProfileRegistrationFormUniqueEmail),
|
||||
name="registration_register"),
|
||||
url('^user/', include('django.contrib.auth.urls')),
|
||||
|
||||
@@ -77,13 +77,6 @@ python manage.py runserver
|
||||
```
|
||||
Please refer to Django documentation for a full list of options available here.
|
||||
|
||||
### Development using docker
|
||||
|
||||
```
|
||||
docker build . -t pyrigs
|
||||
docker run -it --rm -p=8000:8000 -v $(pwd):/app pyrigs
|
||||
```
|
||||
|
||||
### Sample Data ###
|
||||
Sample data is available to aid local development and user acceptance testing. To load this data into your local database, first ensure the database is empty:
|
||||
```
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
from django.contrib import admin
|
||||
from RIGS import models, forms
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from reversion.admin import VersionAdmin
|
||||
|
||||
from django.contrib.admin import helpers
|
||||
from django.template.response import TemplateResponse
|
||||
from django.contrib import messages
|
||||
from django.db import transaction
|
||||
from django.contrib.admin import helpers
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db import transaction
|
||||
from django.db.models import Count
|
||||
from django.forms import ModelForm
|
||||
|
||||
from django.template.response import TemplateResponse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from reversion import revisions as reversion
|
||||
from reversion.admin import VersionAdmin
|
||||
|
||||
from RIGS import models, forms
|
||||
|
||||
# Register your models here.
|
||||
admin.site.register(models.VatRate, VersionAdmin)
|
||||
admin.site.register(models.Event, VersionAdmin)
|
||||
admin.site.register(models.EventItem, VersionAdmin)
|
||||
admin.site.register(models.Invoice)
|
||||
admin.site.register(models.Payment)
|
||||
admin.site.register(models.Invoice, VersionAdmin)
|
||||
admin.site.register(models.Payment, VersionAdmin)
|
||||
|
||||
|
||||
@admin.register(models.Profile)
|
||||
|
||||
@@ -10,8 +10,9 @@ from django.template import RequestContext
|
||||
from django.template.loader import get_template
|
||||
from django.views import generic
|
||||
from django.db.models import Q
|
||||
from django.db import transaction
|
||||
from z3c.rml import rml2pdf
|
||||
|
||||
import reversion
|
||||
from RIGS import models
|
||||
|
||||
from django import forms
|
||||
@@ -101,14 +102,14 @@ class InvoiceDelete(generic.DeleteView):
|
||||
|
||||
def get(self, request, pk):
|
||||
obj = self.get_object()
|
||||
if obj.payment_set.all().count() > 0:
|
||||
if obj.payments.all().count() > 0:
|
||||
messages.info(self.request, 'To delete an invoice, delete the payments first.')
|
||||
return HttpResponseRedirect(reverse_lazy('invoice_detail', kwargs={'pk': obj.pk}))
|
||||
return super(InvoiceDelete, self).get(pk)
|
||||
|
||||
def post(self, request, pk):
|
||||
obj = self.get_object()
|
||||
if obj.payment_set.all().count() > 0:
|
||||
if obj.payments.all().count() > 0:
|
||||
messages.info(self.request, 'To delete an invoice, delete the payments first.')
|
||||
return HttpResponseRedirect(reverse_lazy('invoice_detail', kwargs={'pk': obj.pk}))
|
||||
return super(InvoiceDelete, self).post(pk)
|
||||
@@ -159,7 +160,10 @@ class InvoiceWaiting(generic.ListView):
|
||||
|
||||
|
||||
class InvoiceEvent(generic.View):
|
||||
@transaction.atomic()
|
||||
@reversion.create_revision()
|
||||
def get(self, *args, **kwargs):
|
||||
reversion.set_user(self.request.user)
|
||||
epk = kwargs.get('pk')
|
||||
event = models.Event.objects.get(pk=epk)
|
||||
invoice, created = models.Invoice.objects.get_or_create(event=event)
|
||||
@@ -184,6 +188,13 @@ class PaymentCreate(generic.CreateView):
|
||||
initial.update({'invoice': invoice})
|
||||
return initial
|
||||
|
||||
@transaction.atomic()
|
||||
@reversion.create_revision()
|
||||
def form_valid(self, form, *args, **kwargs):
|
||||
reversion.add_to_revision(form.cleaned_data['invoice'])
|
||||
reversion.set_comment("Payment removed")
|
||||
return super().form_valid(form, *args, **kwargs)
|
||||
|
||||
def get_success_url(self):
|
||||
messages.info(self.request, "location.reload()")
|
||||
return reverse_lazy('closemodal')
|
||||
@@ -192,5 +203,12 @@ class PaymentCreate(generic.CreateView):
|
||||
class PaymentDelete(generic.DeleteView):
|
||||
model = models.Payment
|
||||
|
||||
@transaction.atomic()
|
||||
@reversion.create_revision()
|
||||
def delete(self, *args, **kwargs):
|
||||
reversion.add_to_revision(self.get_object().invoice)
|
||||
reversion.set_comment("Payment removed")
|
||||
return super().delete(*args, **kwargs)
|
||||
|
||||
def get_success_url(self):
|
||||
return self.request.POST.get('next')
|
||||
|
||||
@@ -33,13 +33,7 @@ class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
|
||||
return self.cleaned_data['initials']
|
||||
|
||||
|
||||
# Embedded Login form - remove the autofocus
|
||||
class EmbeddedAuthenticationForm(AuthenticationForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['username'].widget.attrs.pop('autofocus', None)
|
||||
|
||||
|
||||
# Login form
|
||||
class PasswordReset(PasswordResetForm):
|
||||
captcha = ReCaptchaField(label='Captcha')
|
||||
|
||||
|
||||
@@ -1,11 +1,252 @@
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.core.management import call_command
|
||||
from django.contrib.auth.models import Group, Permission
|
||||
from django.db import transaction
|
||||
from reversion import revisions as reversion
|
||||
|
||||
import datetime
|
||||
import random
|
||||
|
||||
from RIGS import models
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Adds sample data to use for testing'
|
||||
can_import_settings = True
|
||||
|
||||
people = []
|
||||
organisations = []
|
||||
venues = []
|
||||
profiles = []
|
||||
|
||||
keyholder_group = None
|
||||
finance_group = None
|
||||
|
||||
def handle(self, *args, **options):
|
||||
call_command('generateSampleRIGSData')
|
||||
call_command('generateSampleAssetsData')
|
||||
from django.conf import settings
|
||||
|
||||
if not (settings.DEBUG or settings.STAGING):
|
||||
raise CommandError('You cannot run this command in production')
|
||||
|
||||
random.seed('Some object to seed the random number generator') # otherwise it is done by time, which could lead to inconsistant tests
|
||||
|
||||
with transaction.atomic():
|
||||
models.VatRate.objects.create(start_at='2014-03-05', rate=0.20, comment='test1')
|
||||
|
||||
self.setupGenericProfiles()
|
||||
|
||||
self.setupPeople()
|
||||
self.setupOrganisations()
|
||||
self.setupVenues()
|
||||
|
||||
self.setupGroups()
|
||||
|
||||
self.setupEvents()
|
||||
|
||||
self.setupUsefulProfiles()
|
||||
|
||||
def setupPeople(self):
|
||||
names = ["Regulus Black", "Sirius Black", "Lavender Brown", "Cho Chang", "Vincent Crabbe", "Vincent Crabbe", "Bartemius Crouch", "Fleur Delacour", "Cedric Diggory", "Alberforth Dumbledore", "Albus Dumbledore", "Dudley Dursley", "Petunia Dursley", "Vernon Dursley", "Argus Filch", "Seamus Finnigan", "Nicolas Flamel", "Cornelius Fudge", "Goyle", "Gregory Goyle", "Hermione Granger", "Rubeus Hagrid", "Igor Karkaroff", "Viktor Krum", "Bellatrix Lestrange", "Alice Longbottom", "Frank Longbottom", "Neville Longbottom", "Luna Lovegood", "Xenophilius Lovegood", # noqa
|
||||
"Remus Lupin", "Draco Malfoy", "Lucius Malfoy", "Narcissa Malfoy", "Olympe Maxime", "Minerva McGonagall", "Mad-Eye Moody", "Peter Pettigrew", "Harry Potter", "James Potter", "Lily Potter", "Quirinus Quirrell", "Tom Riddle", "Mary Riddle", "Lord Voldemort", "Rita Skeeter", "Severus Snape", "Nymphadora Tonks", "Dolores Janes Umbridge", "Arthur Weasley", "Bill Weasley", "Charlie Weasley", "Fred Weasley", "George Weasley", "Ginny Weasley", "Molly Weasley", "Percy Weasley", "Ron Weasley", "Dobby", "Fluffy", "Hedwig", "Moaning Myrtle", "Aragog", "Grawp"] # noqa
|
||||
for i, name in enumerate(names):
|
||||
with reversion.create_revision():
|
||||
reversion.set_user(random.choice(self.profiles))
|
||||
|
||||
newPerson = models.Person.objects.create(name=name)
|
||||
if i % 3 == 0:
|
||||
newPerson.email = "address@person.com"
|
||||
|
||||
if i % 5 == 0:
|
||||
newPerson.notes = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"
|
||||
|
||||
if i % 7 == 0:
|
||||
newPerson.address = "1 Person Test Street \n Demoton \n United States of TEC \n RMRF 567"
|
||||
|
||||
if i % 9 == 0:
|
||||
newPerson.phone = "01234 567894"
|
||||
|
||||
newPerson.save()
|
||||
self.people.append(newPerson)
|
||||
|
||||
def setupOrganisations(self):
|
||||
names = ["Acme, inc.", "Widget Corp", "123 Warehousing", "Demo Company", "Smith and Co.", "Foo Bars", "ABC Telecom", "Fake Brothers", "QWERTY Logistics", "Demo, inc.", "Sample Company", "Sample, inc", "Acme Corp", "Allied Biscuit", "Ankh-Sto Associates", "Extensive Enterprise", "Galaxy Corp", "Globo-Chem", "Mr. Sparkle", "Globex Corporation", "LexCorp", "LuthorCorp", "North Central Positronics", "Omni Consimer Products", "Praxis Corporation", "Sombra Corporation", "Sto Plains Holdings", "Tessier-Ashpool", "Wayne Enterprises", "Wentworth Industries", "ZiffCorp", "Bluth Company", "Strickland Propane", "Thatherton Fuels", "Three Waters", "Water and Power", "Western Gas & Electric", "Mammoth Pictures", "Mooby Corp", "Gringotts", "Thrift Bank", "Flowers By Irene", "The Legitimate Businessmens Club", "Osato Chemicals", "Transworld Consortium", "Universal Export", "United Fried Chicken", "Virtucon", "Kumatsu Motors", "Keedsler Motors", "Powell Motors", "Industrial Automation", "Sirius Cybernetics Corporation", "U.S. Robotics and Mechanical Men", "Colonial Movers", "Corellian Engineering Corporation", "Incom Corporation", "General Products", "Leeding Engines Ltd.", "Blammo", # noqa
|
||||
"Input, Inc.", "Mainway Toys", "Videlectrix", "Zevo Toys", "Ajax", "Axis Chemical Co.", "Barrytron", "Carrys Candles", "Cogswell Cogs", "Spacely Sprockets", "General Forge and Foundry", "Duff Brewing Company", "Dunder Mifflin", "General Services Corporation", "Monarch Playing Card Co.", "Krustyco", "Initech", "Roboto Industries", "Primatech", "Sonky Rubber Goods", "St. Anky Beer", "Stay Puft Corporation", "Vandelay Industries", "Wernham Hogg", "Gadgetron", "Burleigh and Stronginthearm", "BLAND Corporation", "Nordyne Defense Dynamics", "Petrox Oil Company", "Roxxon", "McMahon and Tate", "Sixty Second Avenue", "Charles Townsend Agency", "Spade and Archer", "Megadodo Publications", "Rouster and Sideways", "C.H. Lavatory and Sons", "Globo Gym American Corp", "The New Firm", "SpringShield", "Compuglobalhypermeganet", "Data Systems", "Gizmonic Institute", "Initrode", "Taggart Transcontinental", "Atlantic Northern", "Niagular", "Plow King", "Big Kahuna Burger", "Big T Burgers and Fries", "Chez Quis", "Chotchkies", "The Frying Dutchman", "Klimpys", "The Krusty Krab", "Monks Diner", "Milliways", "Minuteman Cafe", "Taco Grande", "Tip Top Cafe", "Moes Tavern", "Central Perk", "Chasers"] # noqa
|
||||
for i, name in enumerate(names):
|
||||
with reversion.create_revision():
|
||||
reversion.set_user(random.choice(self.profiles))
|
||||
newOrganisation = models.Organisation.objects.create(name=name)
|
||||
if i % 2 == 0:
|
||||
newOrganisation.has_su_account = True
|
||||
|
||||
if i % 3 == 0:
|
||||
newOrganisation.email = "address@organisation.com"
|
||||
|
||||
if i % 5 == 0:
|
||||
newOrganisation.notes = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"
|
||||
|
||||
if i % 7 == 0:
|
||||
newOrganisation.address = "1 Organisation Test Street \n Demoton \n United States of TEC \n RMRF 567"
|
||||
|
||||
if i % 9 == 0:
|
||||
newOrganisation.phone = "01234 567894"
|
||||
|
||||
newOrganisation.save()
|
||||
self.organisations.append(newOrganisation)
|
||||
|
||||
def setupVenues(self):
|
||||
names = ["Bear Island", "Crossroads Inn", "Deepwood Motte", "The Dreadfort", "The Eyrie", "Greywater Watch", "The Iron Islands", "Karhold", "Moat Cailin", "Oldstones", "Raventree Hall", "Riverlands", "The Ruby Ford", "Saltpans", "Seagard", "Torrhen's Square", "The Trident", "The Twins", "The Vale of Arryn", "The Whispering Wood", "White Harbor", "Winterfell", "The Arbor", "Ashemark", "Brightwater Keep", "Casterly Rock", "Clegane's Keep", "Dragonstone", "Dorne", "God's Eye", "The Golden Tooth", # noqa
|
||||
"Harrenhal", "Highgarden", "Horn Hill", "Fingers", "King's Landing", "Lannisport", "Oldtown", "Rainswood", "Storm's End", "Summerhall", "Sunspear", "Tarth", "Castle Black", "Craster's Keep", "Fist of the First Men", "The Frostfangs", "The Gift", "The Skirling Pass", "The Wall", "Asshai", "Astapor", "Braavos", "The Dothraki Sea", "Lys", "Meereen", "Myr", "Norvos", "Pentos", "Qarth", "Qohor", "The Red Waste", "Tyrosh", "Vaes Dothrak", "Valyria", "Village of the Lhazareen", "Volantis", "Yunkai"] # noqa
|
||||
for i, name in enumerate(names):
|
||||
with reversion.create_revision():
|
||||
reversion.set_user(random.choice(self.profiles))
|
||||
newVenue = models.Venue.objects.create(name=name)
|
||||
if i % 2 == 0:
|
||||
newVenue.three_phase_available = True
|
||||
|
||||
if i % 3 == 0:
|
||||
newVenue.email = "address@venue.com"
|
||||
|
||||
if i % 5 == 0:
|
||||
newVenue.notes = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"
|
||||
|
||||
if i % 7 == 0:
|
||||
newVenue.address = "1 Venue Test Street \n Demoton \n United States of TEC \n RMRF 567"
|
||||
|
||||
if i % 9 == 0:
|
||||
newVenue.phone = "01234 567894"
|
||||
|
||||
newVenue.save()
|
||||
self.venues.append(newVenue)
|
||||
|
||||
def setupGroups(self):
|
||||
self.keyholder_group = Group.objects.create(name='Keyholders')
|
||||
self.finance_group = Group.objects.create(name='Finance')
|
||||
|
||||
keyholderPerms = ["add_event", "change_event", "view_event", "add_eventitem", "change_eventitem", "delete_eventitem", "add_organisation", "change_organisation", "view_organisation", "add_person", "change_person", "view_person", "view_profile", "add_venue", "change_venue", "view_venue"]
|
||||
financePerms = ["change_event", "view_event", "add_eventitem", "change_eventitem", "add_invoice", "change_invoice", "view_invoice", "add_organisation", "change_organisation", "view_organisation", "add_payment", "change_payment", "delete_payment", "add_person", "change_person", "view_person"]
|
||||
|
||||
for permId in keyholderPerms:
|
||||
self.keyholder_group.permissions.add(Permission.objects.get(codename=permId))
|
||||
|
||||
for permId in financePerms:
|
||||
self.finance_group.permissions.add(Permission.objects.get(codename=permId))
|
||||
|
||||
def setupGenericProfiles(self):
|
||||
names = ["Clara Oswin Oswald", "Rory Williams", "Amy Pond", "River Song", "Martha Jones", "Donna Noble", "Jack Harkness", "Mickey Smith", "Rose Tyler"]
|
||||
for i, name in enumerate(names):
|
||||
newProfile = models.Profile.objects.create(username=name.replace(" ", ""), first_name=name.split(" ")[0], last_name=name.split(" ")[-1],
|
||||
email=name.replace(" ", "") + "@example.com",
|
||||
initials="".join([j[0].upper() for j in name.split()]))
|
||||
if i % 2 == 0:
|
||||
newProfile.phone = "01234 567894"
|
||||
|
||||
newProfile.save()
|
||||
self.profiles.append(newProfile)
|
||||
|
||||
def setupUsefulProfiles(self):
|
||||
superUser = models.Profile.objects.create(username="superuser", first_name="Super", last_name="User", initials="SU",
|
||||
email="superuser@example.com", is_superuser=True, is_active=True, is_staff=True)
|
||||
superUser.set_password('superuser')
|
||||
superUser.save()
|
||||
|
||||
financeUser = models.Profile.objects.create(username="finance", first_name="Finance", last_name="User", initials="FU",
|
||||
email="financeuser@example.com", is_active=True)
|
||||
financeUser.groups.add(self.finance_group)
|
||||
financeUser.groups.add(self.keyholder_group)
|
||||
financeUser.set_password('finance')
|
||||
financeUser.save()
|
||||
|
||||
keyholderUser = models.Profile.objects.create(username="keyholder", first_name="Keyholder", last_name="User", initials="KU",
|
||||
email="keyholderuser@example.com", is_active=True)
|
||||
keyholderUser.groups.add(self.keyholder_group)
|
||||
keyholderUser.set_password('keyholder')
|
||||
keyholderUser.save()
|
||||
|
||||
basicUser = models.Profile.objects.create(username="basic", first_name="Basic", last_name="User", initials="BU",
|
||||
email="basicuser@example.com", is_active=True)
|
||||
basicUser.set_password('basic')
|
||||
basicUser.save()
|
||||
|
||||
def setupEvents(self):
|
||||
names = ["Outdoor Concert", "Hall Open Mic Night", "Festival", "Weekend Event", "Magic Show", "Society Ball", "Evening Show", "Talent Show", "Acoustic Evening", "Hire of Things", "SU Event",
|
||||
"End of Term Show", "Theatre Show", "Outdoor Fun Day", "Summer Carnival", "Open Days", "Magic Show", "Awards Ceremony", "Debating Event", "Club Night", "DJ Evening", "Building Projection", "Choir Concert"]
|
||||
descriptions = ["A brief desciption of the event", "This event is boring", "Probably wont happen", "Warning: this has lots of kit"]
|
||||
notes = ["The client came into the office at some point", "Who knows if this will happen", "Probably should check this event", "Maybe not happening", "Run away!"]
|
||||
|
||||
itemOptions = [{'name': 'Speakers', 'description': 'Some really really big speakers \n these are very loud', 'quantity': 2, 'cost': 200.00},
|
||||
{'name': 'Projector', 'description': 'Some kind of video thinamejig, probably with unnecessary processing for free', 'quantity': 1, 'cost': 500.00},
|
||||
{'name': 'Lighting Desk', 'description': 'Cannot provide guarentee that it will work', 'quantity': 1, 'cost': 200.52},
|
||||
{'name': 'Moving lights', 'description': 'Flashy lights, with the copper', 'quantity': 8, 'cost': 50.00},
|
||||
{'name': 'Microphones', 'description': 'Make loud noise \n you will want speakers with this', 'quantity': 5, 'cost': 0.50},
|
||||
{'name': 'Sound Mixer Thing', 'description': 'Might be analogue, might be digital', 'quantity': 1, 'cost': 100.00},
|
||||
{'name': 'Electricity', 'description': 'You need this', 'quantity': 1, 'cost': 200.00},
|
||||
{'name': 'Crew', 'description': 'Costs nothing, because reasons', 'quantity': 1, 'cost': 0.00},
|
||||
{'name': 'Loyalty Discount', 'description': 'Have some negative moneys', 'quantity': 1, 'cost': -50.00}]
|
||||
|
||||
dayDelta = -120 # start adding events from 4 months ago
|
||||
|
||||
for i in range(150): # Let's add 100 events
|
||||
with reversion.create_revision():
|
||||
reversion.set_user(random.choice(self.profiles))
|
||||
|
||||
name = names[i % len(names)]
|
||||
|
||||
startDate = datetime.date.today() + datetime.timedelta(days=dayDelta)
|
||||
dayDelta = dayDelta + random.randint(0, 3)
|
||||
|
||||
newEvent = models.Event.objects.create(name=name, start_date=startDate)
|
||||
|
||||
if random.randint(0, 2) > 1: # 1 in 3 have a start time
|
||||
newEvent.start_time = datetime.time(random.randint(15, 20))
|
||||
if random.randint(0, 2) > 1: # of those, 1 in 3 have an end time on the same day
|
||||
newEvent.end_time = datetime.time(random.randint(21, 23))
|
||||
elif random.randint(0, 1) > 0: # half of the others finish early the next day
|
||||
newEvent.end_date = newEvent.start_date + datetime.timedelta(days=1)
|
||||
newEvent.end_time = datetime.time(random.randint(0, 5))
|
||||
elif random.randint(0, 2) > 1: # 1 in 3 of the others finish a few days ahead
|
||||
newEvent.end_date = newEvent.start_date + datetime.timedelta(days=random.randint(1, 4))
|
||||
|
||||
if random.randint(0, 6) > 0: # 5 in 6 have MIC
|
||||
newEvent.mic = random.choice(self.profiles)
|
||||
|
||||
if random.randint(0, 6) > 0: # 5 in 6 have organisation
|
||||
newEvent.organisation = random.choice(self.organisations)
|
||||
|
||||
if random.randint(0, 6) > 0: # 5 in 6 have person
|
||||
newEvent.person = random.choice(self.people)
|
||||
|
||||
if random.randint(0, 6) > 0: # 5 in 6 have venue
|
||||
newEvent.venue = random.choice(self.venues)
|
||||
|
||||
# Could have any status, equally weighted
|
||||
newEvent.status = random.choice([models.Event.BOOKED, models.Event.CONFIRMED, models.Event.PROVISIONAL, models.Event.CANCELLED])
|
||||
|
||||
newEvent.dry_hire = (random.randint(0, 7) == 0) # 1 in 7 are dry hire
|
||||
|
||||
if random.randint(0, 1) > 0: # 1 in 2 have description
|
||||
newEvent.description = random.choice(descriptions)
|
||||
|
||||
if random.randint(0, 1) > 0: # 1 in 2 have notes
|
||||
newEvent.notes = random.choice(notes)
|
||||
|
||||
newEvent.save()
|
||||
|
||||
# Now add some items
|
||||
for j in range(random.randint(1, 5)):
|
||||
itemData = itemOptions[random.randint(0, len(itemOptions) - 1)]
|
||||
newItem = models.EventItem.objects.create(event=newEvent, order=j, **itemData)
|
||||
newItem.save()
|
||||
|
||||
while newEvent.sum_total < 0:
|
||||
itemData = itemOptions[random.randint(0, len(itemOptions) - 1)]
|
||||
newItem = models.EventItem.objects.create(event=newEvent, order=j, **itemData)
|
||||
newItem.save()
|
||||
|
||||
with reversion.create_revision():
|
||||
reversion.set_user(random.choice(self.profiles))
|
||||
if newEvent.start_date < datetime.date.today(): # think about adding an invoice
|
||||
if random.randint(0, 2) > 0: # 2 in 3 have had paperwork sent to treasury
|
||||
newInvoice = models.Invoice.objects.create(event=newEvent)
|
||||
if newEvent.status is models.Event.CANCELLED: # void cancelled events
|
||||
newInvoice.void = True
|
||||
elif random.randint(0, 2) > 1: # 1 in 3 have been paid
|
||||
models.Payment.objects.create(invoice=newInvoice, amount=newInvoice.balance, date=datetime.date.today())
|
||||
|
||||
@@ -1,260 +0,0 @@
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.contrib.auth.models import Group, Permission
|
||||
from django.db import transaction
|
||||
from reversion import revisions as reversion
|
||||
|
||||
import datetime
|
||||
import random
|
||||
|
||||
from RIGS import models
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Adds sample data to use for testing'
|
||||
can_import_settings = True
|
||||
|
||||
people = []
|
||||
organisations = []
|
||||
venues = []
|
||||
profiles = []
|
||||
|
||||
keyholder_group = None
|
||||
finance_group = None
|
||||
|
||||
def handle(self, *args, **options):
|
||||
from django.conf import settings
|
||||
|
||||
if not (settings.DEBUG or settings.STAGING):
|
||||
raise CommandError('You cannot run this command in production')
|
||||
|
||||
random.seed('Some object to seed the random number generator') # otherwise it is done by time, which could lead to inconsistant tests
|
||||
|
||||
with transaction.atomic():
|
||||
models.VatRate.objects.create(start_at='2014-03-05', rate=0.20, comment='test1')
|
||||
|
||||
self.setupGenericProfiles()
|
||||
|
||||
self.setupPeople()
|
||||
self.setupOrganisations()
|
||||
self.setupVenues()
|
||||
|
||||
self.setupGroups()
|
||||
|
||||
self.setupEvents()
|
||||
|
||||
self.setupUsefulProfiles()
|
||||
|
||||
def setupPeople(self):
|
||||
names = ["Regulus Black", "Sirius Black", "Lavender Brown", "Cho Chang", "Vincent Crabbe", "Vincent Crabbe", "Bartemius Crouch", "Fleur Delacour", "Cedric Diggory", "Alberforth Dumbledore", "Albus Dumbledore", "Dudley Dursley", "Petunia Dursley", "Vernon Dursley", "Argus Filch", "Seamus Finnigan", "Nicolas Flamel", "Cornelius Fudge", "Goyle", "Gregory Goyle", "Hermione Granger", "Rubeus Hagrid", "Igor Karkaroff", "Viktor Krum", "Bellatrix Lestrange", "Alice Longbottom", "Frank Longbottom", "Neville Longbottom", "Luna Lovegood", "Xenophilius Lovegood", # noqa
|
||||
"Remus Lupin", "Draco Malfoy", "Lucius Malfoy", "Narcissa Malfoy", "Olympe Maxime", "Minerva McGonagall", "Mad-Eye Moody", "Peter Pettigrew", "Harry Potter", "James Potter", "Lily Potter", "Quirinus Quirrell", "Tom Riddle", "Mary Riddle", "Lord Voldemort", "Rita Skeeter", "Severus Snape", "Nymphadora Tonks", "Dolores Janes Umbridge", "Arthur Weasley", "Bill Weasley", "Charlie Weasley", "Fred Weasley", "George Weasley", "Ginny Weasley", "Molly Weasley", "Percy Weasley", "Ron Weasley", "Dobby", "Fluffy", "Hedwig", "Moaning Myrtle", "Aragog", "Grawp"] # noqa
|
||||
for i, name in enumerate(names):
|
||||
with reversion.create_revision():
|
||||
reversion.set_user(random.choice(self.profiles))
|
||||
|
||||
newPerson = models.Person.objects.create(name=name)
|
||||
if i % 3 == 0:
|
||||
newPerson.email = "address@person.com"
|
||||
|
||||
if i % 5 == 0:
|
||||
newPerson.notes = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"
|
||||
|
||||
if i % 7 == 0:
|
||||
newPerson.address = "1 Person Test Street \n Demoton \n United States of TEC \n RMRF 567"
|
||||
|
||||
if i % 9 == 0:
|
||||
newPerson.phone = "01234 567894"
|
||||
|
||||
newPerson.save()
|
||||
self.people.append(newPerson)
|
||||
|
||||
def setupOrganisations(self):
|
||||
names = ["Acme, inc.", "Widget Corp", "123 Warehousing", "Demo Company", "Smith and Co.", "Foo Bars", "ABC Telecom", "Fake Brothers", "QWERTY Logistics", "Demo, inc.", "Sample Company", "Sample, inc", "Acme Corp", "Allied Biscuit", "Ankh-Sto Associates", "Extensive Enterprise", "Galaxy Corp", "Globo-Chem", "Mr. Sparkle", "Globex Corporation", "LexCorp", "LuthorCorp", "North Central Positronics", "Omni Consimer Products", "Praxis Corporation", "Sombra Corporation", "Sto Plains Holdings", "Tessier-Ashpool", "Wayne Enterprises", "Wentworth Industries", "ZiffCorp", "Bluth Company", "Strickland Propane", "Thatherton Fuels", "Three Waters", "Water and Power", "Western Gas & Electric", "Mammoth Pictures", "Mooby Corp", "Gringotts", "Thrift Bank", "Flowers By Irene", "The Legitimate Businessmens Club", "Osato Chemicals", "Transworld Consortium", "Universal Export", "United Fried Chicken", "Virtucon", "Kumatsu Motors", "Keedsler Motors", "Powell Motors", "Industrial Automation", "Sirius Cybernetics Corporation", "U.S. Robotics and Mechanical Men", "Colonial Movers", "Corellian Engineering Corporation", "Incom Corporation", "General Products", "Leeding Engines Ltd.", "Blammo", # noqa
|
||||
"Input, Inc.", "Mainway Toys", "Videlectrix", "Zevo Toys", "Ajax", "Axis Chemical Co.", "Barrytron", "Carrys Candles", "Cogswell Cogs", "Spacely Sprockets", "General Forge and Foundry", "Duff Brewing Company", "Dunder Mifflin", "General Services Corporation", "Monarch Playing Card Co.", "Krustyco", "Initech", "Roboto Industries", "Primatech", "Sonky Rubber Goods", "St. Anky Beer", "Stay Puft Corporation", "Vandelay Industries", "Wernham Hogg", "Gadgetron", "Burleigh and Stronginthearm", "BLAND Corporation", "Nordyne Defense Dynamics", "Petrox Oil Company", "Roxxon", "McMahon and Tate", "Sixty Second Avenue", "Charles Townsend Agency", "Spade and Archer", "Megadodo Publications", "Rouster and Sideways", "C.H. Lavatory and Sons", "Globo Gym American Corp", "The New Firm", "SpringShield", "Compuglobalhypermeganet", "Data Systems", "Gizmonic Institute", "Initrode", "Taggart Transcontinental", "Atlantic Northern", "Niagular", "Plow King", "Big Kahuna Burger", "Big T Burgers and Fries", "Chez Quis", "Chotchkies", "The Frying Dutchman", "Klimpys", "The Krusty Krab", "Monks Diner", "Milliways", "Minuteman Cafe", "Taco Grande", "Tip Top Cafe", "Moes Tavern", "Central Perk", "Chasers"] # noqa
|
||||
for i, name in enumerate(names):
|
||||
with reversion.create_revision():
|
||||
reversion.set_user(random.choice(self.profiles))
|
||||
newOrganisation = models.Organisation.objects.create(name=name)
|
||||
if i % 2 == 0:
|
||||
newOrganisation.has_su_account = True
|
||||
|
||||
if i % 3 == 0:
|
||||
newOrganisation.email = "address@organisation.com"
|
||||
|
||||
if i % 5 == 0:
|
||||
newOrganisation.notes = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"
|
||||
|
||||
if i % 7 == 0:
|
||||
newOrganisation.address = "1 Organisation Test Street \n Demoton \n United States of TEC \n RMRF 567"
|
||||
|
||||
if i % 9 == 0:
|
||||
newOrganisation.phone = "01234 567894"
|
||||
|
||||
newOrganisation.save()
|
||||
self.organisations.append(newOrganisation)
|
||||
|
||||
def setupVenues(self):
|
||||
names = ["Bear Island", "Crossroads Inn", "Deepwood Motte", "The Dreadfort", "The Eyrie", "Greywater Watch", "The Iron Islands", "Karhold", "Moat Cailin", "Oldstones", "Raventree Hall", "Riverlands", "The Ruby Ford", "Saltpans", "Seagard", "Torrhen's Square", "The Trident", "The Twins", "The Vale of Arryn", "The Whispering Wood", "White Harbor", "Winterfell", "The Arbor", "Ashemark", "Brightwater Keep", "Casterly Rock", "Clegane's Keep", "Dragonstone", "Dorne", "God's Eye", "The Golden Tooth", # noqa
|
||||
"Harrenhal", "Highgarden", "Horn Hill", "Fingers", "King's Landing", "Lannisport", "Oldtown", "Rainswood", "Storm's End", "Summerhall", "Sunspear", "Tarth", "Castle Black", "Craster's Keep", "Fist of the First Men", "The Frostfangs", "The Gift", "The Skirling Pass", "The Wall", "Asshai", "Astapor", "Braavos", "The Dothraki Sea", "Lys", "Meereen", "Myr", "Norvos", "Pentos", "Qarth", "Qohor", "The Red Waste", "Tyrosh", "Vaes Dothrak", "Valyria", "Village of the Lhazareen", "Volantis", "Yunkai"] # noqa
|
||||
for i, name in enumerate(names):
|
||||
with reversion.create_revision():
|
||||
reversion.set_user(random.choice(self.profiles))
|
||||
newVenue = models.Venue.objects.create(name=name)
|
||||
if i % 2 == 0:
|
||||
newVenue.three_phase_available = True
|
||||
|
||||
if i % 3 == 0:
|
||||
newVenue.email = "address@venue.com"
|
||||
|
||||
if i % 5 == 0:
|
||||
newVenue.notes = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"
|
||||
|
||||
if i % 7 == 0:
|
||||
newVenue.address = "1 Venue Test Street \n Demoton \n United States of TEC \n RMRF 567"
|
||||
|
||||
if i % 9 == 0:
|
||||
newVenue.phone = "01234 567894"
|
||||
|
||||
newVenue.save()
|
||||
self.venues.append(newVenue)
|
||||
|
||||
def setupGroups(self):
|
||||
self.keyholder_group = Group.objects.create(name='Keyholders')
|
||||
self.finance_group = Group.objects.create(name='Finance')
|
||||
|
||||
keyholderPerms = ["add_event", "change_event", "view_event",
|
||||
"add_eventitem", "change_eventitem", "delete_eventitem",
|
||||
"add_organisation", "change_organisation", "view_organisation",
|
||||
"add_person", "change_person", "view_person", "view_profile",
|
||||
"add_venue", "change_venue", "view_venue",
|
||||
"add_asset", "change_asset", "delete_asset",
|
||||
"asset_finance", "view_asset", "view_supplier", "asset_finance",
|
||||
"add_supplier"]
|
||||
financePerms = keyholderPerms + ["add_invoice", "change_invoice", "view_invoice",
|
||||
"add_payment", "change_payment", "delete_payment"]
|
||||
|
||||
for permId in keyholderPerms:
|
||||
self.keyholder_group.permissions.add(Permission.objects.get(codename=permId))
|
||||
|
||||
for permId in financePerms:
|
||||
self.finance_group.permissions.add(Permission.objects.get(codename=permId))
|
||||
|
||||
def setupGenericProfiles(self):
|
||||
names = ["Clara Oswin Oswald", "Rory Williams", "Amy Pond", "River Song", "Martha Jones", "Donna Noble", "Jack Harkness", "Mickey Smith", "Rose Tyler"]
|
||||
for i, name in enumerate(names):
|
||||
newProfile = models.Profile.objects.create(username=name.replace(" ", ""), first_name=name.split(" ")[0], last_name=name.split(" ")[-1],
|
||||
email=name.replace(" ", "") + "@example.com",
|
||||
initials="".join([j[0].upper() for j in name.split()]))
|
||||
if i % 2 == 0:
|
||||
newProfile.phone = "01234 567894"
|
||||
|
||||
newProfile.save()
|
||||
self.profiles.append(newProfile)
|
||||
|
||||
def setupUsefulProfiles(self):
|
||||
superUser = models.Profile.objects.create(username="superuser", first_name="Super", last_name="User", initials="SU",
|
||||
email="superuser@example.com", is_superuser=True, is_active=True, is_staff=True)
|
||||
superUser.set_password('superuser')
|
||||
superUser.save()
|
||||
|
||||
financeUser = models.Profile.objects.create(username="finance", first_name="Finance", last_name="User", initials="FU",
|
||||
email="financeuser@example.com", is_active=True)
|
||||
financeUser.groups.add(self.finance_group)
|
||||
financeUser.groups.add(self.keyholder_group)
|
||||
financeUser.set_password('finance')
|
||||
financeUser.save()
|
||||
|
||||
keyholderUser = models.Profile.objects.create(username="keyholder", first_name="Keyholder", last_name="User", initials="KU",
|
||||
email="keyholderuser@example.com", is_active=True)
|
||||
keyholderUser.groups.add(self.keyholder_group)
|
||||
keyholderUser.set_password('keyholder')
|
||||
keyholderUser.save()
|
||||
|
||||
basicUser = models.Profile.objects.create(username="basic", first_name="Basic", last_name="User", initials="BU",
|
||||
email="basicuser@example.com", is_active=True)
|
||||
basicUser.set_password('basic')
|
||||
basicUser.save()
|
||||
|
||||
def setupEvents(self):
|
||||
names = ["Outdoor Concert", "Hall Open Mic Night", "Festival", "Weekend Event", "Magic Show", "Society Ball", "Evening Show", "Talent Show", "Acoustic Evening", "Hire of Things", "SU Event",
|
||||
"End of Term Show", "Theatre Show", "Outdoor Fun Day", "Summer Carnival", "Open Days", "Magic Show", "Awards Ceremony", "Debating Event", "Club Night", "DJ Evening", "Building Projection", "Choir Concert"]
|
||||
descriptions = ["A brief desciption of the event", "This event is boring", "Probably wont happen", "Warning: this has lots of kit"]
|
||||
notes = ["The client came into the office at some point", "Who knows if this will happen", "Probably should check this event", "Maybe not happening", "Run away!"]
|
||||
|
||||
itemOptions = [{'name': 'Speakers', 'description': 'Some really really big speakers \n these are very loud', 'quantity': 2, 'cost': 200.00},
|
||||
{'name': 'Projector', 'description': 'Some kind of video thinamejig, probably with unnecessary processing for free', 'quantity': 1, 'cost': 500.00},
|
||||
{'name': 'Lighting Desk', 'description': 'Cannot provide guarentee that it will work', 'quantity': 1, 'cost': 200.52},
|
||||
{'name': 'Moving lights', 'description': 'Flashy lights, with the copper', 'quantity': 8, 'cost': 50.00},
|
||||
{'name': 'Microphones', 'description': 'Make loud noise \n you will want speakers with this', 'quantity': 5, 'cost': 0.50},
|
||||
{'name': 'Sound Mixer Thing', 'description': 'Might be analogue, might be digital', 'quantity': 1, 'cost': 100.00},
|
||||
{'name': 'Electricity', 'description': 'You need this', 'quantity': 1, 'cost': 200.00},
|
||||
{'name': 'Crew', 'description': 'Costs nothing, because reasons', 'quantity': 1, 'cost': 0.00},
|
||||
{'name': 'Loyalty Discount', 'description': 'Have some negative moneys', 'quantity': 1, 'cost': -50.00}]
|
||||
|
||||
dayDelta = -120 # start adding events from 4 months ago
|
||||
|
||||
for i in range(150): # Let's add 100 events
|
||||
with reversion.create_revision():
|
||||
reversion.set_user(random.choice(self.profiles))
|
||||
|
||||
name = names[i % len(names)]
|
||||
|
||||
startDate = datetime.date.today() + datetime.timedelta(days=dayDelta)
|
||||
dayDelta = dayDelta + random.randint(0, 3)
|
||||
|
||||
newEvent = models.Event.objects.create(name=name, start_date=startDate)
|
||||
|
||||
if random.randint(0, 2) > 1: # 1 in 3 have a start time
|
||||
newEvent.start_time = datetime.time(random.randint(15, 20))
|
||||
if random.randint(0, 2) > 1: # of those, 1 in 3 have an end time on the same day
|
||||
newEvent.end_time = datetime.time(random.randint(21, 23))
|
||||
elif random.randint(0, 1) > 0: # half of the others finish early the next day
|
||||
newEvent.end_date = newEvent.start_date + datetime.timedelta(days=1)
|
||||
newEvent.end_time = datetime.time(random.randint(0, 5))
|
||||
elif random.randint(0, 2) > 1: # 1 in 3 of the others finish a few days ahead
|
||||
newEvent.end_date = newEvent.start_date + datetime.timedelta(days=random.randint(1, 4))
|
||||
|
||||
if random.randint(0, 6) > 0: # 5 in 6 have MIC
|
||||
newEvent.mic = random.choice(self.profiles)
|
||||
|
||||
if random.randint(0, 6) > 0: # 5 in 6 have organisation
|
||||
newEvent.organisation = random.choice(self.organisations)
|
||||
|
||||
if random.randint(0, 6) > 0: # 5 in 6 have person
|
||||
newEvent.person = random.choice(self.people)
|
||||
|
||||
if random.randint(0, 6) > 0: # 5 in 6 have venue
|
||||
newEvent.venue = random.choice(self.venues)
|
||||
|
||||
# Could have any status, equally weighted
|
||||
newEvent.status = random.choice([models.Event.BOOKED, models.Event.CONFIRMED, models.Event.PROVISIONAL, models.Event.CANCELLED])
|
||||
|
||||
newEvent.dry_hire = (random.randint(0, 7) == 0) # 1 in 7 are dry hire
|
||||
|
||||
if random.randint(0, 1) > 0: # 1 in 2 have description
|
||||
newEvent.description = random.choice(descriptions)
|
||||
|
||||
if random.randint(0, 1) > 0: # 1 in 2 have notes
|
||||
newEvent.notes = random.choice(notes)
|
||||
|
||||
newEvent.save()
|
||||
|
||||
# Now add some items
|
||||
for j in range(random.randint(1, 5)):
|
||||
itemData = itemOptions[random.randint(0, len(itemOptions) - 1)]
|
||||
newItem = models.EventItem.objects.create(event=newEvent, order=j, **itemData)
|
||||
newItem.save()
|
||||
|
||||
while newEvent.sum_total < 0:
|
||||
itemData = itemOptions[random.randint(0, len(itemOptions) - 1)]
|
||||
newItem = models.EventItem.objects.create(event=newEvent, order=j, **itemData)
|
||||
newItem.save()
|
||||
|
||||
with reversion.create_revision():
|
||||
reversion.set_user(random.choice(self.profiles))
|
||||
if newEvent.start_date < datetime.date.today(): # think about adding an invoice
|
||||
if random.randint(0, 2) > 0: # 2 in 3 have had paperwork sent to treasury
|
||||
newInvoice = models.Invoice.objects.create(event=newEvent)
|
||||
if newEvent.status is models.Event.CANCELLED: # void cancelled events
|
||||
newInvoice.void = True
|
||||
elif random.randint(0, 2) > 1: # 1 in 3 have been paid
|
||||
models.Payment.objects.create(invoice=newInvoice, amount=newInvoice.balance, date=datetime.date.today())
|
||||
19
RIGS/migrations/0034_auto_20200122_0305.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 2.0.13 on 2020-01-22 03:05
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('RIGS', '0033_auto_20180325_0016'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='payment',
|
||||
name='invoice',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payments', to='RIGS.Invoice'),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 2.0.5 on 2019-07-28 21:28
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('RIGS', '0033_auto_20180325_0016'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='risk_assessment_edit_url',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 2.0.13 on 2019-11-24 13:19
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('RIGS', '0034_event_risk_assessment_edit_url'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='risk_assessment_edit_url',
|
||||
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='risk assessment'),
|
||||
),
|
||||
]
|
||||
@@ -1,24 +1,21 @@
|
||||
from collections import Counter
|
||||
|
||||
import datetime
|
||||
import hashlib
|
||||
import datetime
|
||||
import pytz
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
import random
|
||||
import string
|
||||
from decimal import Decimal
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils import timezone
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.functional import cached_property
|
||||
from reversion import revisions as reversion
|
||||
from reversion.models import Version
|
||||
import string
|
||||
|
||||
import random
|
||||
from collections import Counter
|
||||
from decimal import Decimal
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.urls import reverse_lazy
|
||||
|
||||
|
||||
# Create your models here.
|
||||
@@ -338,9 +335,6 @@ class Event(models.Model, RevisionMixin):
|
||||
auth_request_at = models.DateTimeField(null=True, blank=True)
|
||||
auth_request_to = models.EmailField(null=True, blank=True)
|
||||
|
||||
# Risk assessment info
|
||||
risk_assessment_edit_url = models.CharField(verbose_name="risk assessment", max_length=255, blank=True, null=True)
|
||||
|
||||
# Calculated values
|
||||
"""
|
||||
EX Vat
|
||||
@@ -533,8 +527,9 @@ class EventAuthorisation(models.Model, RevisionMixin):
|
||||
return str("N%05d" % self.event.pk + ' (requested by ' + self.sent_by.initials + ')')
|
||||
|
||||
|
||||
@reversion.register(follow=['payments'])
|
||||
@python_2_unicode_compatible
|
||||
class Invoice(models.Model):
|
||||
class Invoice(models.Model, RevisionMixin):
|
||||
event = models.OneToOneField('Event', on_delete=models.CASCADE)
|
||||
invoice_date = models.DateField(auto_now_add=True)
|
||||
void = models.BooleanField(default=False)
|
||||
@@ -549,7 +544,7 @@ class Invoice(models.Model):
|
||||
|
||||
@property
|
||||
def payment_total(self):
|
||||
total = self.payment_set.aggregate(total=models.Sum('amount'))['total']
|
||||
total = self.payments.aggregate(total=models.Sum('amount'))['total']
|
||||
if total:
|
||||
return total
|
||||
return Decimal("0.00")
|
||||
@@ -587,7 +582,7 @@ class Payment(models.Model):
|
||||
(ADJUSTMENT, 'TEC Adjustment'),
|
||||
)
|
||||
|
||||
invoice = models.ForeignKey('Invoice', on_delete=models.CASCADE)
|
||||
invoice = models.ForeignKey('Invoice', on_delete=models.CASCADE, related_name="payments")
|
||||
date = models.DateField()
|
||||
amount = models.DecimalField(max_digits=10, decimal_places=2, help_text='Please use ex. VAT')
|
||||
method = models.CharField(max_length=2, choices=METHODS, null=True, blank=True)
|
||||
|
||||
@@ -18,7 +18,6 @@ from django.core.exceptions import SuspiciousOperation
|
||||
from django.db.models import Q
|
||||
from django.contrib import messages
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from z3c.rml import rml2pdf
|
||||
from PyPDF2 import PdfFileMerger, PdfFileReader
|
||||
import simplejson
|
||||
@@ -81,25 +80,6 @@ class EventEmbed(EventDetail):
|
||||
template_name = 'RIGS/event_embed.html'
|
||||
|
||||
|
||||
class EventRA(generic.base.RedirectView):
|
||||
permanent = False
|
||||
|
||||
def get_redirect_url(self, *args, **kwargs):
|
||||
event = get_object_or_404(models.Event, pk=kwargs['pk'])
|
||||
|
||||
if event.risk_assessment_edit_url:
|
||||
return event.risk_assessment_edit_url
|
||||
|
||||
params = {
|
||||
'entry.708610078': f'N{event.pk:05}',
|
||||
'entry.905899507': event.name,
|
||||
'entry.139491562': event.venue.name if event.venue else '',
|
||||
'entry.1689826056': event.start_date.strftime('%Y-%m-%d') + ((' - ' + event.end_date.strftime('%Y-%m-%d')) if event.end_date else ''),
|
||||
'entry.902421165': event.mic.name if event.mic else ''
|
||||
}
|
||||
return settings.RISK_ASSESSMENT_URL + "?" + urllib.parse.urlencode(params)
|
||||
|
||||
|
||||
class EventCreate(generic.CreateView):
|
||||
model = models.Event
|
||||
form_class = forms.EventForm
|
||||
@@ -406,27 +386,3 @@ class EventAuthoriseRequestEmailPreview(generic.DetailView):
|
||||
})
|
||||
context['to_name'] = self.request.GET.get('to_name', None)
|
||||
return context
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name='dispatch')
|
||||
class LogRiskAssessment(generic.View):
|
||||
http_method_names = ["post"]
|
||||
|
||||
def post(self, request, **kwargs):
|
||||
data = request.POST
|
||||
shared_secret = data.get("secret")
|
||||
edit_url = data.get("editUrl")
|
||||
rig_number = data.get("rigNum")
|
||||
if shared_secret is None or edit_url is None or rig_number is None:
|
||||
return HttpResponse(status=422)
|
||||
|
||||
if shared_secret != settings.RISK_ASSESSMENT_SECRET:
|
||||
return HttpResponse(status=403)
|
||||
|
||||
rig_number = int(re.sub("[^0-9]", "", rig_number))
|
||||
|
||||
event = get_object_or_404(models.Event, pk=rig_number)
|
||||
event.risk_assessment_edit_url = edit_url
|
||||
event.save()
|
||||
|
||||
return HttpResponse(status=200)
|
||||
|
||||
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 4.8 KiB |
@@ -149,19 +149,16 @@ ins {
|
||||
}
|
||||
|
||||
html.embedded{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height:100%;
|
||||
display: table;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
justify-content: center;
|
||||
|
||||
body{
|
||||
padding:0;
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
width:100%;
|
||||
background:none;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.embed_container{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:"base_ajax_nomodal.html,base_rigs.html" %}
|
||||
{% extends request.is_ajax|yesno:"base_ajax_nomodal.html,base.html" %}
|
||||
|
||||
{% load static %}
|
||||
{% load paginator from filters %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
||||
{% load static %}
|
||||
{% load paginator from filters %}
|
||||
{% load to_class_name from filters %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% extends 'base.html' %}
|
||||
{% load paginator from filters %}
|
||||
|
||||
{% block title %}Event Archive{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
||||
{% block title %}{% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}{% endif %} | {{object.name}}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@@ -70,6 +70,39 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if event.is_rig and event.internal %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Client Authorisation</div>
|
||||
<div class="panel-body">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>Authorised</dt>
|
||||
<dd>{{ object.authorised|yesno:"Yes,No" }}</dd>
|
||||
|
||||
<dt>Authorised by</dt>
|
||||
<dd>
|
||||
{% if object.authorisation %}
|
||||
{{ object.authorisation.name }}
|
||||
(<a href="mailto:{{ object.authorisation.email }}">{{ object.authorisation.email }}</a>)
|
||||
{% endif %}
|
||||
</dd>
|
||||
|
||||
<dt>Authorised at</dt>
|
||||
<dd>{{ object.authorisation.last_edited_at }}</dd>
|
||||
|
||||
<dt>Authorised amount</dt>
|
||||
<dd>
|
||||
{% if object.authorisation %}
|
||||
£ {{ object.authorisation.amount|floatformat:"2" }}
|
||||
{% endif %}
|
||||
</dd>
|
||||
|
||||
<dt>Requested by</dt>
|
||||
<dd>{{ object.authorisation.sent_by }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col-sm-12 {% if event.is_rig %}col-md-6 col-lg-7{% endif %}">
|
||||
@@ -147,63 +180,31 @@
|
||||
<dd>{{ object.collector }}</dd>
|
||||
{% endif %}
|
||||
|
||||
{% if event.is_rig and not event.internal %}
|
||||
{% if event.is_rig %}
|
||||
<dd> </dd>
|
||||
<dt>PO</dt>
|
||||
<dd>{{ object.purchase_order }}</dd>
|
||||
|
||||
{% if object.internal %}
|
||||
<dt>Authorisation Request</dt>
|
||||
<dd>{{ object.auth_request_to|yesno:"Yes,No" }}</dd>
|
||||
|
||||
<dt>By</dt>
|
||||
<dd>{{ object.auth_request_by }}</dd>
|
||||
|
||||
<dt>At</dt>
|
||||
<dd>{{ object.auth_request_at|date:"D d M Y H:i"|default:"" }}</dd>
|
||||
|
||||
<dt>To</dt>
|
||||
<dd>{{ object.auth_request_to }}</dd>
|
||||
|
||||
{% else %}
|
||||
<dt>PO</dt>
|
||||
<dd>{{ object.purchase_order }}</dd>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if event.is_rig and event.internal %}
|
||||
<div class="col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Client Authorisation</div>
|
||||
<div class="panel-body">
|
||||
<dl class="dl-horizontal col-sm-6">
|
||||
<dt>Authorisation Request</dt>
|
||||
<dd>{{ object.auth_request_to|yesno:"Yes,No" }}</dd>
|
||||
|
||||
<dt>By</dt>
|
||||
<dd>{{ object.auth_request_by }}</dd>
|
||||
|
||||
<dt>At</dt>
|
||||
<dd>{{ object.auth_request_at|date:"D d M Y H:i"|default:"" }}</dd>
|
||||
|
||||
<dt>To</dt>
|
||||
<dd>{{ object.auth_request_to }}</dd>
|
||||
</dl>
|
||||
<dd class="visible-xs"> </dd>
|
||||
<dl class="dl-horizontal col-sm-6">
|
||||
<dt>Authorised</dt>
|
||||
<dd>{{ object.authorised|yesno:"Yes,No" }}</dd>
|
||||
|
||||
<dt>Authorised by</dt>
|
||||
<dd>
|
||||
{% if object.authorisation %}
|
||||
{{ object.authorisation.name }}
|
||||
(<a href="mailto:{{ object.authorisation.email }}">{{ object.authorisation.email }}</a>)
|
||||
{% endif %}
|
||||
</dd>
|
||||
|
||||
<dt>Authorised at</dt>
|
||||
<dd>{{ object.authorisation.last_edited_at }}</dd>
|
||||
|
||||
<dt>Authorised amount</dt>
|
||||
<dd>
|
||||
{% if object.authorisation %}
|
||||
£ {{ object.authorisation.amount|floatformat:"2" }}
|
||||
{% endif %}
|
||||
</dd>
|
||||
|
||||
<dt>Requested by</dt>
|
||||
<dd>{{ object.authorisation.sent_by }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{% endif %}
|
||||
{% if not request.is_ajax %}
|
||||
<div class="col-sm-12 text-right">
|
||||
{% include 'RIGS/event_detail_buttons.html' %}
|
||||
@@ -245,7 +246,7 @@
|
||||
<div class="row">
|
||||
<div class="col-sm-10 align-left">
|
||||
<a href="{% url 'event_history' object.pk %}" title="View Revision History">
|
||||
Last edited at {{ object.last_edited_at|default:'never' }} by {{ object.last_edited_by.name|default:'nobody' }}
|
||||
Last edited at {{ object.last_edited_at }} by {{ object.last_edited_by.name }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
|
||||
@@ -3,17 +3,6 @@
|
||||
class="glyphicon glyphicon-edit"></span> <span
|
||||
class="hidden-xs">Edit</span></a>
|
||||
{% if event.is_rig %}
|
||||
{% if not event.dry_hire %}
|
||||
<a href="{% url 'event_ra' event.pk %}" class="btn btn-default
|
||||
{% if event.risk_assessment_edit_url %}
|
||||
btn-success
|
||||
{% else %}
|
||||
btn-warning
|
||||
{% endif %}
|
||||
"><span
|
||||
class="glyphicon glyphicon-paperclip"></span> <span
|
||||
class="hidden-xs">RA</span></a>
|
||||
{% endif %}
|
||||
<a href="{% url 'event_print' event.pk %}" target="_blank" class="btn btn-default"><span
|
||||
class="glyphicon glyphicon-print"></span> <span
|
||||
class="hidden-xs">Print</span></a>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% extends 'base.html' %}
|
||||
{% load widget_tweaks %}
|
||||
{% load static %}
|
||||
{% load multiply from filters %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% extends 'base.html' %}
|
||||
{% load paginator from filters %}
|
||||
{% load static %}
|
||||
|
||||
|
||||
@@ -264,7 +264,7 @@
|
||||
</para>
|
||||
</td>
|
||||
</tr>
|
||||
{% for payment in object.invoice.payment_set.all %}
|
||||
{% for payment in object.invoice.payments.all %}
|
||||
<tr>
|
||||
<td>{{ payment.get_method_display }}</td>
|
||||
<td>{{ payment.date }}</td>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<p>
|
||||
Your event <b>N{{ object.event.pk|stringformat:"05d" }}</b> has been successfully authorised
|
||||
for <b>£{{ object.amount }}</b>
|
||||
by <b>{{ object.name }}</b> as of <b>{{ object.event.last_edited_at }}</b>.
|
||||
by <b>{{ object.name }}</b> as of <b>{{ object.last_edited_at }}</b>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Hi {{ to_name|default_if_none:"there" }},
|
||||
Hi {{ to_name|default:"there" }},
|
||||
|
||||
Your event N{{object.event.pk|stringformat:"05d"}} has been successfully authorised for £{{object.amount}} by {{object.name}} as of {{object.event.last_edited_at}}.
|
||||
Your event N{{object.event.pk|stringformat:"05d"}} has been successfully authorised for £{{object.amount}} by {{object.name}} as of {{object.last_edited_at}}.
|
||||
|
||||
{% if object.event.organisation and object.event.organisation.union_account %}{# internal #}
|
||||
Your event is now fully booked and payment will be processed by the finance department automatically.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Hi {{object.event.mic.get_full_name|default_if_none:"somebody"}},
|
||||
|
||||
Just to let you know your event N{{object.event.pk|stringformat:"05d"}} has been successfully authorised for £{{object.amount}} by {{object.name}} as of {{object.event.last_edited_at}}.
|
||||
Just to let you know your event N{{object.event.pk|stringformat:"05d"}} has been successfully authorised for £{{object.amount}} by {{object.name}} as of {{object.last_edited_at}}.
|
||||
|
||||
The TEC Rig Information Gathering System
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:'base_ajax.html,base_rigs.html' %}
|
||||
{% extends request.is_ajax|yesno:'base_ajax.html,base.html' %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}Request Authorisation{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:'base_ajax.html,base_rigs.html' %}
|
||||
{% extends request.is_ajax|yesno:'base_ajax.html,base.html' %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}NottinghamTEC Email Address Required{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% extends 'base.html' %}
|
||||
{% block title %}RIGS{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@@ -20,7 +20,6 @@
|
||||
<a class="list-group-item" href="{% url 'rigboard' %}"><span class="glyphicon glyphicon-list"></span> Rigboard</a>
|
||||
<a class="list-group-item" href="{% url 'web_calendar' %}"><span class="glyphicon glyphicon-calendar"></span> Calendar</a>
|
||||
{% if perms.RIGS.add_event %}<a class="list-group-item" href="{% url 'event_create' %}"><span class="glyphicon glyphicon-plus"></span> New Event</a>{% endif %}
|
||||
<a class="list-group-item" href="{% url 'asset_index' %}"><span class="glyphicon glyphicon-tag"></span> Asset Database </a>
|
||||
|
||||
<div class="list-group-item default"></div>
|
||||
|
||||
@@ -28,7 +27,7 @@
|
||||
<a class="list-group-item" href="//members.nottinghamtec.co.uk/wiki" target="_blank"><span class="glyphicon glyphicon-link"></span> TEC Wiki</a>
|
||||
<a class="list-group-item" href="http://members.nottinghamtec.co.uk/wiki/images/2/22/Event_Risk_Assesment.pdf" target="_blank"><span class="glyphicon glyphicon-link"></span> Pre-Event Risk Assessment</a>
|
||||
<a class="list-group-item" href="//members.nottinghamtec.co.uk/price" target="_blank"><span class="glyphicon glyphicon-link"></span> Price List</a>
|
||||
<a class="list-group-item" href="https://goo.gl/forms/jdPWov8PCNPoXtbn2" target="_blank"><span class="glyphicon glyphicon-link"></span> Subhire Insurance Form</a>
|
||||
<a class="list-group-item" href="https://form.jotformeu.com/62203600438344" target="_blank"><span class="glyphicon glyphicon-link"></span> Subhire Insurance Form</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -72,8 +71,9 @@
|
||||
</div>
|
||||
</div>
|
||||
{% if perms.RIGS.view_event %}
|
||||
<div class="col-sm-6">
|
||||
<div class="col-sm-6" >
|
||||
{% include 'RIGS/activity_feed.html' %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Delete payment on invoice {{ object.invoice.pk }}{% endblock %}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Invoice {{ object.pk }}{% endblock %}
|
||||
|
||||
@@ -6,20 +6,21 @@
|
||||
<div class="col-sm-12">
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<h2>Invoice {{ object.pk }} ({{ object.invoice_date|date:"d/m/Y"}})</h2>
|
||||
<h2>Invoice {{ object.pk }} ({{ object.invoice_date|date:"d/m/Y" }})</h2>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4 text-right">
|
||||
<div class="btn-group btn-page">
|
||||
<a href="{% url 'invoice_delete' object.pk %}" class="btn btn-default" title="Delete Invoice">
|
||||
<span class="glyphicon glyphicon-remove"></span> <span
|
||||
<a href="{% url 'invoice_delete' object.pk %}" class="btn btn-default" title="Delete Invoice">
|
||||
<span class="glyphicon glyphicon-remove"></span> <span
|
||||
class="hidden-xs">Delete</span>
|
||||
</a>
|
||||
<a href="{% url 'invoice_void' object.pk %}" class="btn btn-default" title="Void Invoice">
|
||||
<span class="glyphicon glyphicon-ban-circle"></span> <span
|
||||
</a>
|
||||
<a href="{% url 'invoice_void' object.pk %}" class="btn btn-default" title="Void Invoice">
|
||||
<span class="glyphicon glyphicon-ban-circle"></span> <span
|
||||
class="hidden-xs">Void</span>
|
||||
</a>
|
||||
<a href="{% url 'invoice_print' object.pk %}" target="_blank" title="Print Invoice" class="btn btn-default"><span
|
||||
</a>
|
||||
<a href="{% url 'invoice_print' object.pk %}" target="_blank" title="Print Invoice"
|
||||
class="btn btn-default"><span
|
||||
class="glyphicon glyphicon-print"></span> <span
|
||||
class="hidden-xs">Print</span></a>
|
||||
</div>
|
||||
@@ -83,9 +84,11 @@
|
||||
|
||||
<dt>Authorised by</dt>
|
||||
<dd>
|
||||
{% if object.event.authorised %}
|
||||
{% if object.event.authorised %}
|
||||
{{ object.event.authorisation.name }}
|
||||
(<a href="mailto:{{ object.event.authorisation.email }}">{{ object.event.authorisation.email }}</a>)
|
||||
(
|
||||
<a href="mailto:{{ object.event.authorisation.email }}">{{ object.event.authorisation.email }}</a>
|
||||
)
|
||||
{% endif %}
|
||||
</dd>
|
||||
|
||||
@@ -140,7 +143,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for payment in object.payment_set.all %}
|
||||
{% for payment in object.payments.all %}
|
||||
<tr>
|
||||
<td>{{ payment.date }}</td>
|
||||
<td>{{ payment.amount|floatformat:2 }}</td>
|
||||
@@ -172,6 +175,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 text-right">
|
||||
<div>
|
||||
<a href="{% url 'invoice_history' object.pk %}" title="View Revision History">
|
||||
Last edited at {{ object.last_edited_at }} by {{ object.last_edited_by.name }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% extends 'base.html' %}
|
||||
{% load paginator from filters %}
|
||||
|
||||
{% block title %}Invoices{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}Organisation | {{ object.name }}{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:'base_ajax.html,base_rigs.html' %}
|
||||
{% extends request.is_ajax|yesno:'base_ajax.html,base.html' %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}{% if object.pk %}Edit {{ object.name }}{% else %}Add Organisation{% endif %}{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
||||
{% load widget_tweaks %}
|
||||
{% load paginator from filters %}
|
||||
{% load url_replace from filters %}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
|
||||
{% block title %}Password Reset Disabled{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Password reset is disabled</h1>
|
||||
<p> We are very sorry for the inconvenience, but due to a security vulnerability, password reset is currently disabled until the vulnerability can be patched.</p>
|
||||
<p> If you are locked out of your account, please contact an administrator and we can manually perform a reset</p>
|
||||
{% endblock %}
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Delete payment on invoice {{ object.invoice.pk }}{% endblock %}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}Person | {{ object.name }}{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:'base_ajax.html,base_rigs.html' %}
|
||||
{% extends request.is_ajax|yesno:'base_ajax.html,base.html' %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}{% if object.pk %}Edit {{ object.name }}{% else %}Add Person{% endif %}{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
||||
{% load widget_tweaks %}
|
||||
{% load paginator from filters %}
|
||||
{% load url_replace from filters %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
||||
|
||||
{% block title %}RIGS Profile {{object.pk}}{% endblock %}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% extends 'base.html' %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}Update Profile {{object.name}}{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'base_rigs.html' %}
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}Rigboard{% endblock %}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}Venue | {{ object.name }}{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:'base_ajax.html,base_rigs.html' %}
|
||||
{% extends request.is_ajax|yesno:'base_ajax.html,base.html' %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}{{ object.pk|yesno:"Edit,Add" }} Venue{% endblock %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
||||
{% load widget_tweaks %}
|
||||
{% load paginator from filters %}
|
||||
{% load url_replace from filters %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_rigs.html" %}
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base.html" %}
|
||||
{% load to_class_name from filters %}
|
||||
{% load paginator from filters %}
|
||||
{% load static %}
|
||||
|
||||
@@ -88,7 +88,7 @@ class UserRegistrationTest(LiveServerTestCase):
|
||||
initials.send_keys('JS')
|
||||
phone.send_keys('0123456789')
|
||||
self.browser.execute_script(
|
||||
"return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()")
|
||||
"return jQuery('#g-recaptcha-response').val('PASSED')")
|
||||
|
||||
# Submit incorrect form
|
||||
submit = self.browser.find_element_by_xpath("//input[@type='submit']")
|
||||
@@ -110,9 +110,8 @@ class UserRegistrationTest(LiveServerTestCase):
|
||||
# Correct error
|
||||
password1.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}()")
|
||||
"return jQuery('#g-recaptcha-response').val('PASSED')")
|
||||
|
||||
# Submit again
|
||||
password2.send_keys(Keys.ENTER)
|
||||
@@ -151,7 +150,7 @@ class UserRegistrationTest(LiveServerTestCase):
|
||||
username.send_keys('TestUsername')
|
||||
password.send_keys('correcthorsebatterystaple')
|
||||
self.browser.execute_script(
|
||||
"return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()")
|
||||
"return jQuery('#g-recaptcha-response').val('PASSED')")
|
||||
password.send_keys(Keys.ENTER)
|
||||
|
||||
# Check we are logged in
|
||||
|
||||
@@ -414,7 +414,7 @@ class TestSampleDataGenerator(TestCase):
|
||||
@override_settings(DEBUG=True)
|
||||
def test_generate_sample_data(self):
|
||||
# Run the management command and check there are no exceptions
|
||||
call_command('generateSampleRIGSData')
|
||||
call_command('generateSampleData')
|
||||
|
||||
# Check there are lots of events
|
||||
self.assertTrue(models.Event.objects.all().count() > 100)
|
||||
@@ -422,4 +422,4 @@ class TestSampleDataGenerator(TestCase):
|
||||
def test_production_exception(self):
|
||||
from django.core.management.base import CommandError
|
||||
|
||||
self.assertRaisesRegex(CommandError, ".*production", call_command, 'generateSampleRIGSData')
|
||||
self.assertRaisesRegex(CommandError, ".*production", call_command, 'generateSampleData')
|
||||
|
||||
21
RIGS/urls.py
@@ -1,13 +1,12 @@
|
||||
from django.conf.urls import url
|
||||
from django.contrib.auth.views import password_reset
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from RIGS import models, views, rigboard, finance, ical, versioning, forms
|
||||
from django.views.generic import RedirectView
|
||||
from django.contrib.auth.views import password_reset
|
||||
from django.views.decorators.clickjacking import xframe_options_exempt
|
||||
from django.views.generic import RedirectView
|
||||
|
||||
from PyRIGS.decorators import permission_required_with_403
|
||||
from PyRIGS.decorators import api_key_required
|
||||
from PyRIGS.decorators import permission_required_with_403
|
||||
from RIGS import models, views, rigboard, finance, ical, versioning, forms
|
||||
|
||||
urlpatterns = [
|
||||
# Examples:
|
||||
@@ -19,7 +18,7 @@ urlpatterns = [
|
||||
url('^user/login/$', views.login, name='login'),
|
||||
url('^user/login/embed/$', xframe_options_exempt(views.login_embed), name='login_embed'),
|
||||
|
||||
url(r'^user/password_reset/$', views.PasswordResetDisabled.as_view()),
|
||||
url(r'^user/password_reset/$', password_reset, {'password_reset_form': forms.PasswordReset}),
|
||||
|
||||
# People
|
||||
url(r'^people/$', permission_required_with_403('RIGS.view_person')(views.PersonList.as_view()),
|
||||
@@ -101,9 +100,6 @@ urlpatterns = [
|
||||
url(r'^event/(?P<pk>\d+)/print/$',
|
||||
permission_required_with_403('RIGS.view_event')(rigboard.EventPrint.as_view()),
|
||||
name='event_print'),
|
||||
url(r'^event/(?P<pk>\d+)/ra/$',
|
||||
permission_required_with_403('RIGS.change_event')(rigboard.EventRA.as_view()),
|
||||
name='event_ra'),
|
||||
url(r'^event/create/$',
|
||||
permission_required_with_403('RIGS.add_event')(rigboard.EventCreate.as_view()),
|
||||
name='event_create'),
|
||||
@@ -147,6 +143,10 @@ urlpatterns = [
|
||||
url(r'^invoice/(?P<pk>\d+)/delete/$',
|
||||
permission_required_with_403('RIGS.change_invoice')(finance.InvoiceDelete.as_view()),
|
||||
name='invoice_delete'),
|
||||
url(r'^invoice/(?P<pk>\d+)/history/$',
|
||||
permission_required_with_403('RIGS.view_invoice')(versioning.VersionHistory.as_view()),
|
||||
name='invoice_history', kwargs={'model': models.Invoice}),
|
||||
|
||||
url(r'^payment/create/$',
|
||||
permission_required_with_403('RIGS.add_payment')(finance.PaymentCreate.as_view()),
|
||||
name='payment_create'),
|
||||
@@ -188,9 +188,6 @@ urlpatterns = [
|
||||
url(r'^api/(?P<model>\w+)/(?P<pk>\d+)/$', login_required(views.SecureAPIRequest.as_view()),
|
||||
name="api_secure"),
|
||||
|
||||
# Risk assessment API
|
||||
url(r'^log_risk_assessment/$', rigboard.LogRiskAssessment.as_view(), name='log_risk_assessment'),
|
||||
|
||||
# Legacy URL's
|
||||
url(r'^rig/show/(?P<pk>\d+)/$',
|
||||
RedirectView.as_view(permanent=True, pattern_name='event_detail')),
|
||||
|
||||
@@ -27,8 +27,6 @@ class FieldComparison(object):
|
||||
def display_value(self, value):
|
||||
if isinstance(self.field, IntegerField) and len(self.field.choices) > 0:
|
||||
return [x[1] for x in self.field.choices if x[0] == value][0]
|
||||
if self.field.name == "risk_assessment_edit_url":
|
||||
return "completed" if value else ""
|
||||
return value
|
||||
|
||||
@property
|
||||
@@ -168,7 +166,7 @@ class RIGSVersionManager(VersionQuerySet):
|
||||
for model in model_array:
|
||||
content_types.append(ContentType.objects.get_for_model(model))
|
||||
|
||||
return self.filter(content_type__in=content_types).select_related("revision").order_by("-revision__date_created")
|
||||
return self.filter(content_type__in=content_types).select_related("revision").order_by("-pk")
|
||||
|
||||
|
||||
class RIGSVersion(Version):
|
||||
@@ -206,14 +204,17 @@ class VersionHistory(generic.ListView):
|
||||
paginate_by = 25
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
return RIGSVersion.objects.get_for_object(self.get_object()).select_related("revision", "revision__user").all().order_by("-revision__date_created")
|
||||
thisModel = self.kwargs['model']
|
||||
|
||||
def get_object(self, **kwargs):
|
||||
return get_object_or_404(self.kwargs['model'], pk=self.kwargs['pk'])
|
||||
versions = RIGSVersion.objects.get_for_object_reference(thisModel, self.kwargs['pk']).select_related("revision", "revision__user").all()
|
||||
|
||||
return versions
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
thisModel = self.kwargs['model']
|
||||
context = super(VersionHistory, self).get_context_data(**kwargs)
|
||||
context['object'] = self.get_object()
|
||||
thisObject = get_object_or_404(thisModel, pk=self.kwargs['pk'])
|
||||
context['object'] = thisObject
|
||||
|
||||
return context
|
||||
|
||||
@@ -225,7 +226,7 @@ class ActivityTable(generic.ListView):
|
||||
|
||||
def get_queryset(self):
|
||||
versions = RIGSVersion.objects.get_for_multiple_models([models.Event, models.Venue, models.Person, models.Organisation, models.EventAuthorisation])
|
||||
return versions.order_by("-revision__date_created")
|
||||
return versions
|
||||
|
||||
|
||||
class ActivityFeed(generic.ListView):
|
||||
@@ -235,7 +236,7 @@ class ActivityFeed(generic.ListView):
|
||||
|
||||
def get_queryset(self):
|
||||
versions = RIGSVersion.objects.get_for_multiple_models([models.Event, models.Venue, models.Person, models.Organisation, models.EventAuthorisation])
|
||||
return versions.order_by("-revision__date_created")
|
||||
return versions
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
# Call the base implementation first to get a context
|
||||
|
||||
@@ -17,7 +17,6 @@ from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
|
||||
from RIGS import models, forms
|
||||
from assets import models as asset_models
|
||||
from functools import reduce
|
||||
|
||||
"""
|
||||
@@ -63,7 +62,7 @@ def login_embed(request, **kwargs):
|
||||
messages.warning(request, 'Cookies do not seem to be enabled. Try logging in using a new tab.')
|
||||
request.method = 'GET' # Render the page without trying to login
|
||||
|
||||
return login(request, template_name="registration/login_embed.html", authentication_form=forms.EmbeddedAuthenticationForm)
|
||||
return login(request, template_name="registration/login_embed.html")
|
||||
|
||||
|
||||
"""
|
||||
@@ -249,7 +248,6 @@ class SecureAPIRequest(generic.View):
|
||||
'organisation': models.Organisation,
|
||||
'profile': models.Profile,
|
||||
'event': models.Event,
|
||||
'supplier': asset_models.Supplier
|
||||
}
|
||||
|
||||
perms = {
|
||||
@@ -258,7 +256,6 @@ class SecureAPIRequest(generic.View):
|
||||
'organisation': 'RIGS.view_organisation',
|
||||
'profile': 'RIGS.view_profile',
|
||||
'event': None,
|
||||
'supplier': None
|
||||
}
|
||||
|
||||
'''
|
||||
@@ -392,7 +389,3 @@ class ResetApiKey(generic.RedirectView):
|
||||
self.request.user.save()
|
||||
|
||||
return reverse_lazy('profile_detail')
|
||||
|
||||
|
||||
class PasswordResetDisabled(generic.TemplateView):
|
||||
template_name = "RIGS/password_reset_disable.html"
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
from django.contrib import admin
|
||||
from assets import models as assets
|
||||
|
||||
|
||||
@admin.register(assets.AssetCategory)
|
||||
class AssetCategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'name']
|
||||
ordering = ['id']
|
||||
|
||||
|
||||
@admin.register(assets.AssetStatus)
|
||||
class AssetStatusAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'name']
|
||||
ordering = ['id']
|
||||
|
||||
|
||||
@admin.register(assets.Supplier)
|
||||
class SupplierAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'name']
|
||||
ordering = ['id']
|
||||
|
||||
|
||||
@admin.register(assets.Asset)
|
||||
class AssetAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'asset_id', 'description', 'category', 'status']
|
||||
list_filter = ['is_cable', 'category']
|
||||
search_fields = ['id', 'asset_id', 'description']
|
||||
|
||||
|
||||
@admin.register(assets.Connector)
|
||||
class ConnectorAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', '__str__', 'current_rating', 'voltage_rating', 'num_pins']
|
||||
@@ -1,5 +0,0 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AssetsConfig(AppConfig):
|
||||
name = 'assets'
|
||||
@@ -1,9 +0,0 @@
|
||||
import django_filters
|
||||
|
||||
from assets import models
|
||||
|
||||
|
||||
class AssetFilter(django_filters.FilterSet):
|
||||
class Meta:
|
||||
model = models.Asset
|
||||
fields = ['asset_id', 'description', 'serial_number', 'category', 'status']
|
||||
@@ -1,36 +0,0 @@
|
||||
from django import forms
|
||||
|
||||
from assets import models
|
||||
|
||||
|
||||
class AssetForm(forms.ModelForm):
|
||||
related_models = {
|
||||
'asset': models.Asset,
|
||||
'supplier': models.Supplier
|
||||
}
|
||||
|
||||
class Meta:
|
||||
model = models.Asset
|
||||
fields = '__all__'
|
||||
exclude = ['asset_id_prefix', 'asset_id_number']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['date_sold'].widget.format = '%Y-%m-%d'
|
||||
self.fields['date_acquired'].widget.format = '%Y-%m-%d'
|
||||
|
||||
|
||||
class AssetSearchForm(forms.Form):
|
||||
query = forms.CharField(required=False)
|
||||
category = forms.ModelMultipleChoiceField(models.AssetCategory.objects.all(), required=False)
|
||||
status = forms.ModelMultipleChoiceField(models.AssetStatus.objects.all(), required=False)
|
||||
|
||||
|
||||
class SupplierForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = models.Supplier
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class SupplierSearchForm(forms.Form):
|
||||
query = forms.CharField(required=False)
|
||||
@@ -1,23 +0,0 @@
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
|
||||
from assets import models
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Deletes testing sample data'
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
from django.conf import settings
|
||||
|
||||
if not (settings.DEBUG):
|
||||
raise CommandError('You cannot run this command in production')
|
||||
|
||||
self.delete_objects(models.AssetCategory)
|
||||
self.delete_objects(models.AssetStatus)
|
||||
self.delete_objects(models.Supplier)
|
||||
self.delete_objects(models.Connector)
|
||||
self.delete_objects(models.Asset)
|
||||
|
||||
def delete_objects(self, model):
|
||||
for object in model.objects.all():
|
||||
object.delete()
|
||||
@@ -1,120 +0,0 @@
|
||||
import random
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.utils import timezone
|
||||
from assets import models
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Creates some sample data for testing'
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
from django.conf import settings
|
||||
|
||||
if not (settings.DEBUG or settings.STAGING):
|
||||
raise CommandError('You cannot run this command in production')
|
||||
|
||||
random.seed('Some object to see the random number generator')
|
||||
|
||||
self.create_categories()
|
||||
self.create_statuses()
|
||||
self.create_suppliers()
|
||||
self.create_assets()
|
||||
self.create_connectors()
|
||||
self.create_cables()
|
||||
|
||||
def create_categories(self):
|
||||
categories = ['Case', 'Video', 'General', 'Sound', 'Lighting', 'Rigging']
|
||||
|
||||
for cat in categories:
|
||||
models.AssetCategory.objects.create(name=cat)
|
||||
|
||||
def create_statuses(self):
|
||||
statuses = [('In Service', True), ('Lost', False), ('Binned', False), ('Sold', False), ('Broken', False)]
|
||||
|
||||
for stat in statuses:
|
||||
models.AssetStatus.objects.create(name=stat[0], should_show=stat[1])
|
||||
|
||||
def create_suppliers(self):
|
||||
suppliers = ["Acme, inc.", "Widget Corp", "123 Warehousing", "Demo Company", "Smith and Co.", "Foo Bars", "ABC Telecom", "Fake Brothers", "QWERTY Logistics", "Demo, inc.", "Sample Company", "Sample, inc", "Acme Corp", "Allied Biscuit", "Ankh-Sto Associates", "Extensive Enterprise", "Galaxy Corp", "Globo-Chem", "Mr. Sparkle", "Globex Corporation", "LexCorp", "LuthorCorp", "North Central Positronics", "Omni Consimer Products", "Praxis Corporation", "Sombra Corporation", "Sto Plains Holdings", "Tessier-Ashpool", "Wayne Enterprises", "Wentworth Industries", "ZiffCorp", "Bluth Company", "Strickland Propane", "Thatherton Fuels", "Three Waters", "Water and Power", "Western Gas & Electric", "Mammoth Pictures", "Mooby Corp", "Gringotts", "Thrift Bank", "Flowers By Irene", "The Legitimate Businessmens Club", "Osato Chemicals", "Transworld Consortium", "Universal Export", "United Fried Chicken", "Virtucon", "Kumatsu Motors", "Keedsler Motors", "Powell Motors", "Industrial Automation", "Sirius Cybernetics Corporation", "U.S. Robotics and Mechanical Men", "Colonial Movers", "Corellian Engineering Corporation", "Incom Corporation", "General Products", "Leeding Engines Ltd.", "Blammo", # noqa
|
||||
"Input, Inc.", "Mainway Toys", "Videlectrix", "Zevo Toys", "Ajax", "Axis Chemical Co.", "Barrytron", "Carrys Candles", "Cogswell Cogs", "Spacely Sprockets", "General Forge and Foundry", "Duff Brewing Company", "Dunder Mifflin", "General Services Corporation", "Monarch Playing Card Co.", "Krustyco", "Initech", "Roboto Industries", "Primatech", "Sonky Rubber Goods", "St. Anky Beer", "Stay Puft Corporation", "Vandelay Industries", "Wernham Hogg", "Gadgetron", "Burleigh and Stronginthearm", "BLAND Corporation", "Nordyne Defense Dynamics", "Petrox Oil Company", "Roxxon", "McMahon and Tate", "Sixty Second Avenue", "Charles Townsend Agency", "Spade and Archer", "Megadodo Publications", "Rouster and Sideways", "C.H. Lavatory and Sons", "Globo Gym American Corp", "The New Firm", "SpringShield", "Compuglobalhypermeganet", "Data Systems", "Gizmonic Institute", "Initrode", "Taggart Transcontinental", "Atlantic Northern", "Niagular", "Plow King", "Big Kahuna Burger", "Big T Burgers and Fries", "Chez Quis", "Chotchkies", "The Frying Dutchman", "Klimpys", "The Krusty Krab", "Monks Diner", "Milliways", "Minuteman Cafe", "Taco Grande", "Tip Top Cafe", "Moes Tavern", "Central Perk", "Chasers"] # noqa
|
||||
|
||||
for supplier in suppliers:
|
||||
models.Supplier.objects.create(name=supplier)
|
||||
|
||||
def create_assets(self):
|
||||
asset_description = ['Large cable', 'Shiny thing', 'New lights', 'Really expensive microphone', 'Box of fuse flaps', 'Expensive tool we didn\'t agree to buy', 'Cable drums', 'Boring amount of tape', 'Video stuff no one knows how to use', 'More amplifiers', 'Heatshrink']
|
||||
|
||||
categories = models.AssetCategory.objects.all()
|
||||
statuses = models.AssetStatus.objects.all()
|
||||
suppliers = models.Supplier.objects.all()
|
||||
|
||||
for i in range(100):
|
||||
asset = models.Asset(
|
||||
asset_id='{}'.format(models.Asset.get_available_asset_id()),
|
||||
description=random.choice(asset_description),
|
||||
category=random.choice(categories),
|
||||
status=random.choice(statuses),
|
||||
date_acquired=timezone.now().date()
|
||||
)
|
||||
|
||||
if i % 4 == 0:
|
||||
asset.parent = models.Asset.objects.order_by('?').first()
|
||||
|
||||
if i % 3 == 0:
|
||||
asset.purchased_from = random.choice(suppliers)
|
||||
asset.clean()
|
||||
asset.save()
|
||||
|
||||
def create_cables(self):
|
||||
asset_description = ['The worm', 'Harting without a cap', 'Heavy cable', 'Extension lead', 'IEC cable that we should remember to prep']
|
||||
asset_prefixes = ["C", "C4P", "CBNC", "CDMX", "CDV", "CRCD", "CSOCA", "CXLR"]
|
||||
|
||||
csas = [0.75, 1.00, 1.25, 2.5, 4]
|
||||
lengths = [1, 2, 5, 10, 15, 20, 25, 30, 50, 100]
|
||||
cores = [3, 5]
|
||||
circuits = [1, 2, 3, 6]
|
||||
categories = models.AssetCategory.objects.all()
|
||||
statuses = models.AssetStatus.objects.all()
|
||||
suppliers = models.Supplier.objects.all()
|
||||
connectors = models.Connector.objects.all()
|
||||
|
||||
for i in range(100):
|
||||
asset = models.Asset(
|
||||
asset_id='{}'.format(models.Asset.get_available_asset_id()),
|
||||
description=random.choice(asset_description),
|
||||
category=random.choice(categories),
|
||||
status=random.choice(statuses),
|
||||
date_acquired=timezone.now().date(),
|
||||
|
||||
is_cable=True,
|
||||
plug=random.choice(connectors),
|
||||
socket=random.choice(connectors),
|
||||
csa=random.choice(csas),
|
||||
length=random.choice(lengths),
|
||||
circuits=random.choice(circuits),
|
||||
cores=random.choice(circuits)
|
||||
)
|
||||
|
||||
if i % 5 == 0:
|
||||
prefix = random.choice(asset_prefixes)
|
||||
asset.asset_id = prefix + str(models.Asset.get_available_asset_id(wanted_prefix=prefix))
|
||||
|
||||
if i % 4 == 0:
|
||||
asset.parent = models.Asset.objects.order_by('?').first()
|
||||
|
||||
if i % 3 == 0:
|
||||
asset.purchased_from = random.choice(suppliers)
|
||||
|
||||
asset.clean()
|
||||
asset.save()
|
||||
|
||||
def create_connectors(self):
|
||||
connectors = [
|
||||
{"description": "13A UK", "current_rating": 13, "voltage_rating": 230, "num_pins": 3},
|
||||
{"description": "16A", "current_rating": 16, "voltage_rating": 230, "num_pins": 3},
|
||||
{"description": "32/3", "current_rating": 32, "voltage_rating": 400, "num_pins": 5},
|
||||
{"description": "Socapex", "current_rating": 23, "voltage_rating": 600, "num_pins": 19},
|
||||
]
|
||||
for connector in connectors:
|
||||
conn = models.Connector.objects.create(** connector)
|
||||
conn.save()
|
||||
@@ -1,229 +0,0 @@
|
||||
import os
|
||||
import datetime
|
||||
import xml.etree.ElementTree as ET
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
|
||||
from assets import models
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Imports old db from XML dump'
|
||||
|
||||
epoch = datetime.date(1970, 1, 1)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
self.import_categories()
|
||||
self.import_statuses()
|
||||
self.import_suppliers()
|
||||
self.import_collections()
|
||||
self.import_assets()
|
||||
self.import_cables()
|
||||
|
||||
@staticmethod
|
||||
def xml_path(file):
|
||||
return os.path.join(settings.BASE_DIR, 'data/DB_Dump/{}'.format(file))
|
||||
|
||||
@staticmethod
|
||||
def parse_xml(file):
|
||||
tree = ET.parse(file)
|
||||
|
||||
return tree.getroot()
|
||||
|
||||
def import_categories(self):
|
||||
# 0: updated, 1: created
|
||||
tally = [0, 0]
|
||||
root = self.parse_xml(self.xml_path('TEC_Asset_Categories.xml'))
|
||||
|
||||
for child in root:
|
||||
obj, created = models.AssetCategory.objects.update_or_create(
|
||||
pk=int(child.find('AssetCategoryID').text),
|
||||
name=child.find('AssetCategory').text
|
||||
)
|
||||
|
||||
if created:
|
||||
tally[1] += 1
|
||||
else:
|
||||
tally[0] += 1
|
||||
|
||||
print('Categories - Updated: {}, Created: {}'.format(tally[0], tally[1]))
|
||||
|
||||
def import_statuses(self):
|
||||
# 0: updated, 1: created
|
||||
tally = [0, 0]
|
||||
root = self.parse_xml(self.xml_path('TEC_Asset_Status_new.xml'))
|
||||
|
||||
for child in root:
|
||||
obj, created = models.AssetStatus.objects.update_or_create(
|
||||
pk=int(child.find('StatusID').text),
|
||||
name=child.find('Status').text
|
||||
)
|
||||
|
||||
if created:
|
||||
tally[1] += 1
|
||||
else:
|
||||
tally[0] += 1
|
||||
|
||||
print('Statuses - Updated: {}, Created: {}'.format(tally[0], tally[1]))
|
||||
|
||||
def import_suppliers(self):
|
||||
# 0: updated, 1: created
|
||||
tally = [0, 0]
|
||||
root = self.parse_xml(self.xml_path('TEC_Asset_Suppliers_new.xml'))
|
||||
|
||||
for child in root:
|
||||
obj, created = models.Supplier.objects.update_or_create(
|
||||
pk=int(child.find('Supplier_x0020_Id').text),
|
||||
name=child.find('Supplier_x0020_Name').text
|
||||
)
|
||||
|
||||
if created:
|
||||
tally[1] += 1
|
||||
else:
|
||||
tally[0] += 1
|
||||
|
||||
print('Suppliers - Updated: {}, Created: {}'.format(tally[0], tally[1]))
|
||||
|
||||
def import_assets(self):
|
||||
# 0: updated, 1: created
|
||||
tally = [0, 0]
|
||||
root = self.parse_xml(self.xml_path('TEC_Assets.xml'))
|
||||
|
||||
for child in root:
|
||||
defaults = dict()
|
||||
|
||||
# defaults['pk'] = int(child.find('ID').text)
|
||||
defaults['asset_id'] = child.find('AssetID').text
|
||||
|
||||
try:
|
||||
defaults['description'] = child.find('AssetDescription').text
|
||||
except AttributeError:
|
||||
defaults['description'] = 'None'
|
||||
|
||||
defaults['category'] = models.AssetCategory.objects.get(pk=int(child.find('AssetCategoryID').text))
|
||||
defaults['status'] = models.AssetStatus.objects.get(pk=int(child.find('StatusID').text))
|
||||
|
||||
try:
|
||||
defaults['serial_number'] = child.find('SerialNumber').text
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
defaults['purchased_from'] = models.Supplier.objects.get(pk=int(child.find('Supplier_x0020_Id').text))
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
defaults['date_acquired'] = datetime.datetime.strptime(child.find('DateAcquired').text, '%d/%m/%Y').date()
|
||||
except AttributeError:
|
||||
defaults['date_acquired'] = self.epoch
|
||||
|
||||
try:
|
||||
defaults['date_sold'] = datetime.datetime.strptime(child.find('DateSold').text, '%d/%m/%Y').date()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
defaults['purchase_price'] = float(child.find('Replacement_x0020_Value').text)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
defaults['salvage_value'] = float(child.find('SalvageValue').text)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
defaults['comments'] = child.find('Comments').text
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
date = child.find('NextSchedMaint').text.split('T')[0]
|
||||
defaults['next_sched_maint'] = datetime.datetime.strptime(date, '%Y-%m-%d').date()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
print(defaults)
|
||||
|
||||
obj, created = models.Asset.objects.update_or_create(**defaults)
|
||||
|
||||
if created:
|
||||
tally[1] += 1
|
||||
else:
|
||||
tally[0] += 1
|
||||
|
||||
print('Assets - Updated: {}, Created: {}'.format(tally[0], tally[1]))
|
||||
|
||||
def import_collections(self):
|
||||
tally = [0, 0]
|
||||
root = self.parse_xml(self.xml_path('TEC_Cable_Collections.xml'))
|
||||
|
||||
for child in root:
|
||||
defaults = dict()
|
||||
|
||||
defaults['pk'] = int(child.find('ID').text)
|
||||
defaults['name'] = child.find('Cable_x0020_Trunk').text
|
||||
|
||||
obj, created = models.Collection.objects.update_or_create(**defaults)
|
||||
|
||||
if created:
|
||||
tally[1] += 1
|
||||
else:
|
||||
tally[0] += 1
|
||||
|
||||
print('Collections - Updated: {}, Created: {}'.format(tally[0], tally[1]))
|
||||
|
||||
def import_cables(self):
|
||||
tally = [0, 0]
|
||||
root = self.parse_xml(self.xml_path('TEC_Cables.xml'))
|
||||
|
||||
for child in root:
|
||||
defaults = dict()
|
||||
|
||||
defaults['asset_id'] = child.find('Asset_x0020_Number').text
|
||||
|
||||
try:
|
||||
defaults['description'] = child.find('Type_x0020_of_x0020_Cable').text
|
||||
except AttributeError:
|
||||
defaults['description'] = 'None'
|
||||
|
||||
defaults['is_cable'] = True
|
||||
defaults['category'] = models.AssetCategory.objects.get(pk=9)
|
||||
|
||||
try:
|
||||
defaults['length'] = child.find('Length_x0020__x0028_m_x0029_').text
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
defaults['status'] = models.AssetStatus.objects.get(pk=int(child.find('Status').text))
|
||||
|
||||
try:
|
||||
defaults['comments'] = child.find('Comments').text
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
collection_id = int(child.find('Collection').text)
|
||||
if collection_id != 0:
|
||||
defaults['collection'] = models.Collection.objects.get(pk=collection_id)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
defaults['purchase_price'] = float(child.find('Purchase_x0020_Price').text)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
defaults['date_acquired'] = self.epoch
|
||||
|
||||
print(defaults)
|
||||
|
||||
obj, created = models.Asset.objects.update_or_create(**defaults)
|
||||
|
||||
if created:
|
||||
tally[1] += 1
|
||||
else:
|
||||
tally[0] += 1
|
||||
|
||||
print('Collections - Updated: {}, Created: {}'.format(tally[0], tally[1]))
|
||||
@@ -1,110 +0,0 @@
|
||||
import os
|
||||
import datetime
|
||||
import xml.etree.ElementTree as ET
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Imports old db from XML dump'
|
||||
|
||||
epoch = datetime.date(1970, 1, 1)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# self.update_statuses()
|
||||
# self.update_suppliers()
|
||||
self.update_cable_statuses()
|
||||
|
||||
@staticmethod
|
||||
def xml_path(file):
|
||||
return os.path.join(settings.BASE_DIR, 'data/DB_Dump/{}'.format(file))
|
||||
|
||||
@staticmethod
|
||||
def parse_xml(file):
|
||||
tree = ET.parse(file)
|
||||
|
||||
return tree.getroot()
|
||||
|
||||
def update_statuses(self):
|
||||
file = self.xml_path('TEC_Assets.xml')
|
||||
tree = ET.parse(file)
|
||||
root = tree.getroot()
|
||||
|
||||
# map old status pk to new status pk
|
||||
status_map = {
|
||||
2: 2,
|
||||
3: 4,
|
||||
4: 3,
|
||||
5: 5,
|
||||
6: 1
|
||||
}
|
||||
|
||||
for child in root:
|
||||
status = int(child.find('StatusID').text)
|
||||
child.find('StatusID').text = str(status_map[status])
|
||||
|
||||
tree.write(file)
|
||||
|
||||
def update_suppliers(self):
|
||||
old_file = self.xml_path('TEC_Asset_Suppliers.xml')
|
||||
old_tree = ET.parse(old_file)
|
||||
old_root = old_tree.getroot()
|
||||
|
||||
new_file = self.xml_path('TEC_Asset_Suppliers_new.xml')
|
||||
new_tree = ET.parse(new_file)
|
||||
new_root = new_tree.getroot()
|
||||
|
||||
# map old supplier pk to new supplier pk
|
||||
supplier_map = dict()
|
||||
|
||||
def find_in_old(name, root):
|
||||
for child in root:
|
||||
found_id = child.find('Supplier_x0020_Id').text
|
||||
found_name = child.find('Supplier_x0020_Name').text
|
||||
|
||||
if found_name == name:
|
||||
return found_id
|
||||
|
||||
for new_child in new_root:
|
||||
new_id = new_child.find('Supplier_x0020_Id').text
|
||||
new_name = new_child.find('Supplier_x0020_Name').text
|
||||
|
||||
old_id = find_in_old(new_name, old_root)
|
||||
|
||||
supplier_map[int(old_id)] = int(new_id)
|
||||
|
||||
file = self.xml_path('TEC_Assets.xml')
|
||||
tree = ET.parse(file)
|
||||
root = tree.getroot()
|
||||
|
||||
for child in root:
|
||||
try:
|
||||
supplier = int(child.find('Supplier_x0020_Id').text)
|
||||
child.find('Supplier_x0020_Id').text = str(supplier_map[supplier])
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
tree.write(file)
|
||||
|
||||
def update_cable_statuses(self):
|
||||
file = self.xml_path('TEC_Cables.xml')
|
||||
tree = ET.parse(file)
|
||||
root = tree.getroot()
|
||||
|
||||
# map old status pk to new status pk
|
||||
status_map = {
|
||||
0: 7,
|
||||
1: 3,
|
||||
3: 2,
|
||||
4: 5,
|
||||
6: 6,
|
||||
7: 1,
|
||||
8: 4,
|
||||
9: 2,
|
||||
}
|
||||
|
||||
for child in root:
|
||||
status = int(child.find('Status').text)
|
||||
child.find('Status').text = str(status_map[status])
|
||||
|
||||
tree.write(file)
|
||||
@@ -1,86 +0,0 @@
|
||||
# Generated by Django 2.0.2 on 2018-02-28 16:06
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Asset',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('asset_id', models.IntegerField()),
|
||||
('description', models.CharField(max_length=120)),
|
||||
('serial_number', models.CharField(blank=True, max_length=150, null=True)),
|
||||
('date_acquired', models.DateField()),
|
||||
('date_sold', models.DateField(blank=True, null=True)),
|
||||
('purchase_price', models.IntegerField()),
|
||||
('salvage_value', models.IntegerField(blank=True, null=True)),
|
||||
('comments', models.TextField(blank=True, null=True)),
|
||||
('next_sched_maint', models.DateField(blank=True, null=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AssetCategory',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=80)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Asset Category',
|
||||
'verbose_name_plural': 'Asset Categories',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AssetStatus',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=80)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Asset Status',
|
||||
'verbose_name_plural': 'Asset Statuses',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Collection',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=80)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Supplier',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=80)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='category',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.AssetCategory'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='collection',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.Collection'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='purchased_from',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='assets.Supplier'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='status',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.AssetStatus'),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 2.0.2 on 2018-03-01 16:54
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='asset_id',
|
||||
field=models.IntegerField(blank=True),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 2.0.2 on 2018-03-01 17:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0002_auto_20180301_1654'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='purchase_price',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# Generated by Django 2.0.2 on 2018-03-01 17:11
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0003_auto_20180301_1700'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='collection',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='assets.Collection'),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 2.0.2 on 2018-03-01 17:25
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0004_auto_20180301_1711'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='asset_id',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,148 +0,0 @@
|
||||
# Generated by Django 2.1.5 on 2019-01-05 19:54
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
replaces = [('assets', '0006_auto_20180728_1451'), ('assets', '0007_auto_20181215_1447'), ('assets', '0008_auto_20181215_1448'), ('assets', '0009_auto_20181215_1640'), ('assets', '0010_auto_20181215_1640'), ('assets', '0011_auto_20181215_1749'), ('assets', '0012_auto_20181215_1813'), ('assets', '0013_asset_parent'), ('assets', '0014_auto_20190103_1615'), ('assets', '0015_auto_20190103_1617'), ('assets', '0016_remove_asset_collection'), ('assets', '0017_delete_collection'), ('assets', '0018_auto_20190103_1708'), ('assets', '0019_auto_20190103_1723'), ('assets', '0020_auto_20190103_1729'), ('assets', '0021_auto_20190105_1156')]
|
||||
|
||||
dependencies = [
|
||||
('assets', '0005_auto_20180301_1725'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='asset_id',
|
||||
field=models.IntegerField(blank=True, null=True, unique=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='purchase_price',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='salvage_value',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='asset_id',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='is_cable',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='length',
|
||||
field=models.DecimalField(blank=True, decimal_places=1, max_digits=10, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='asset_id',
|
||||
field=models.CharField(blank=True, max_length=10, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='asset_id',
|
||||
field=models.CharField(default='', max_length=10),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='parent',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=None, related_name='asset_parent', to='assets.Asset'),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='asset',
|
||||
name='collection',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Collection',
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Cable',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('asset_id', models.CharField(max_length=10)),
|
||||
('description', models.CharField(max_length=120)),
|
||||
('serial_number', models.CharField(blank=True, max_length=150, null=True)),
|
||||
('date_acquired', models.DateField()),
|
||||
('date_sold', models.DateField(blank=True, null=True)),
|
||||
('purchase_price', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)),
|
||||
('salvage_value', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)),
|
||||
('comments', models.TextField(blank=True, null=True)),
|
||||
('next_sched_maint', models.DateField(blank=True, null=True)),
|
||||
('is_cable', models.BooleanField(default=False)),
|
||||
('length', models.DecimalField(blank=True, decimal_places=1, help_text='m', max_digits=10, null=True)),
|
||||
('csa', models.DecimalField(blank=True, decimal_places=2, help_text='mm^2', max_digits=10, null=True)),
|
||||
('circuits', models.IntegerField(blank=True, null=True)),
|
||||
('cores', models.IntegerField(blank=True, null=True)),
|
||||
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.AssetCategory')),
|
||||
('parent', models.ForeignKey(blank=True, null=True, on_delete=None, related_name='asset_parent', to='assets.Cable')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Connector',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('description', models.CharField(max_length=80)),
|
||||
('current_rating', models.DecimalField(decimal_places=2, help_text='Amps', max_digits=10)),
|
||||
('voltage_rating', models.IntegerField(default=0, help_text='Volts')),
|
||||
('num_pins', models.IntegerField(blank=True, null=True)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cable',
|
||||
name='plug',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='plug', to='assets.Connector'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cable',
|
||||
name='purchased_from',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='assets.Supplier'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cable',
|
||||
name='socket',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='socket', to='assets.Connector'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cable',
|
||||
name='status',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.AssetStatus'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='comments',
|
||||
field=models.TextField(blank=True, default=''),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='serial_number',
|
||||
field=models.CharField(blank=True, default='', max_length=150),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cable',
|
||||
name='comments',
|
||||
field=models.TextField(blank=True, default=''),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cable',
|
||||
name='serial_number',
|
||||
field=models.CharField(blank=True, default='', max_length=150),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -1,176 +0,0 @@
|
||||
# Generated by Django 2.0.13 on 2019-12-04 17:37
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
replaces = [('assets', '0007_auto_20190108_0202'), ('assets', '0008_auto_20191002_1931'), ('assets', '0009_auto_20191008_2148'), ('assets', '0010_auto_20191013_2123'), ('assets', '0011_auto_20191013_2247'), ('assets', '0012_auto_20191014_0012'), ('assets', '0013_auto_20191016_1446'), ('assets', '0014_auto_20191017_2052')]
|
||||
|
||||
dependencies = [
|
||||
('contenttypes', '0002_remove_content_type_name'),
|
||||
('assets', '0006_auto_20180728_1451_squashed_0021_auto_20190105_1156'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='parent',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='asset_parent', to='assets.Asset'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cable',
|
||||
name='parent',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='asset_parent', to='assets.Cable'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='connector',
|
||||
name='voltage_rating',
|
||||
field=models.IntegerField(help_text='Volts'),
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='asset',
|
||||
options={'base_manager_name': 'objects'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='cable',
|
||||
options={'base_manager_name': 'objects'},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='asset',
|
||||
name='length',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='asset_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='category',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='comments',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='date_acquired',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='date_sold',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='description',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='is_cable',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='next_sched_maint',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='parent',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='purchase_price',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='purchased_from',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='salvage_value',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='serial_number',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='status',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='polymorphic_ctype',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_assets.asset_set+', to='contenttypes.ContentType'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='asset_id',
|
||||
field=models.CharField(max_length=10, unique=True),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='plug',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='socket',
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='asset',
|
||||
options={},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='asset',
|
||||
name='polymorphic_ctype',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='circuits',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='cores',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='csa',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, help_text='mm^2', max_digits=10, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='length',
|
||||
field=models.DecimalField(blank=True, decimal_places=1, help_text='m', max_digits=10, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='plug',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='plug', to='assets.Connector'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='socket',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='socket', to='assets.Connector'),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Cable',
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='asset',
|
||||
options={'ordering': ['asset_id'], 'permissions': (('asset_finance', 'Can see financial data for assets'), ('view_asset', 'Can view an asset'))},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='assetstatus',
|
||||
name='should_show',
|
||||
field=models.BooleanField(default=True, help_text='Should this be shown by default in the asset list.'),
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='supplier',
|
||||
options={'permissions': (('view_supplier', 'Can view a supplier'),)},
|
||||
),
|
||||
]
|
||||
@@ -1,51 +0,0 @@
|
||||
# Generated by Django 2.0.13 on 2019-12-06 21:24
|
||||
|
||||
from django.db import migrations, models, transaction
|
||||
import re
|
||||
|
||||
def forwards(apps, schema_editor):
|
||||
AssetModel = apps.get_model('assets', 'Asset')
|
||||
with transaction.atomic():
|
||||
for row in AssetModel.objects.all():
|
||||
|
||||
row.asset_id = row.asset_id.upper()
|
||||
asset_search = re.search("^([A-Z0-9]*?[A-Z]?)([0-9]+)$", row.asset_id)
|
||||
if asset_search is None: # If the asset_id doesn't have a number at the end
|
||||
row.asset_id += "1"
|
||||
|
||||
asset_search = re.search("^([A-Z0-9]*?[A-Z]?)([0-9]+)$", row.asset_id)
|
||||
row.asset_id_prefix = asset_search.group(1)
|
||||
row.asset_id_number = int(asset_search.group(2))
|
||||
|
||||
row.save(update_fields=['asset_id', 'asset_id_prefix', 'asset_id_number'])
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0007_auto_20190108_0202_squashed_0014_auto_20191017_2052'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='asset',
|
||||
options={'ordering': ['asset_id_prefix', 'asset_id_number'], 'permissions': (('asset_finance', 'Can see financial data for assets'), ('view_asset', 'Can view an asset'))},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='asset_id_number',
|
||||
field=models.IntegerField(default=1),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='asset_id_prefix',
|
||||
field=models.CharField(default='', max_length=8),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='asset_id',
|
||||
field=models.CharField(max_length=15, unique=True),
|
||||
),
|
||||
migrations.RunPython(
|
||||
code=forwards,
|
||||
reverse_code=migrations.operations.special.RunPython.noop,
|
||||
),
|
||||
]
|
||||
@@ -1,32 +0,0 @@
|
||||
# Generated by Django 2.0.13 on 2020-01-03 22:15
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0008_auto_20191206_2124'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='assetcategory',
|
||||
options={'ordering': ['name'], 'verbose_name': 'Asset Category', 'verbose_name_plural': 'Asset Categories'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='assetstatus',
|
||||
options={'ordering': ['name'], 'verbose_name': 'Asset Status', 'verbose_name_plural': 'Asset Statuses'},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='assetstatus',
|
||||
name='display_class',
|
||||
field=models.CharField(blank=True, help_text='HTML class to be appended to alter display of assets with this status, such as in the list.', max_length=80, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='purchased_from',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='assets', to='assets.Supplier'),
|
||||
),
|
||||
]
|
||||
179
assets/models.py
@@ -1,179 +0,0 @@
|
||||
import re
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models, connection
|
||||
from django.urls import reverse
|
||||
|
||||
from django.db.models.signals import pre_save
|
||||
from django.dispatch.dispatcher import receiver
|
||||
|
||||
from reversion import revisions as reversion
|
||||
from reversion.models import Version
|
||||
|
||||
from RIGS.models import RevisionMixin
|
||||
|
||||
|
||||
class AssetCategory(models.Model):
|
||||
class Meta:
|
||||
verbose_name = 'Asset Category'
|
||||
verbose_name_plural = 'Asset Categories'
|
||||
ordering = ['name']
|
||||
|
||||
name = models.CharField(max_length=80)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class AssetStatus(models.Model):
|
||||
class Meta:
|
||||
verbose_name = 'Asset Status'
|
||||
verbose_name_plural = 'Asset Statuses'
|
||||
ordering = ['name']
|
||||
|
||||
name = models.CharField(max_length=80)
|
||||
should_show = models.BooleanField(
|
||||
default=True, help_text="Should this be shown by default in the asset list.")
|
||||
display_class = models.CharField(max_length=80, blank=True, null=True, help_text="HTML class to be appended to alter display of assets with this status, such as in the list.")
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
@reversion.register
|
||||
class Supplier(models.Model, RevisionMixin):
|
||||
name = models.CharField(max_length=80)
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
('view_supplier', 'Can view a supplier'),
|
||||
)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('supplier_list')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Connector(models.Model):
|
||||
description = models.CharField(max_length=80)
|
||||
current_rating = models.DecimalField(decimal_places=2, max_digits=10, help_text='Amps')
|
||||
voltage_rating = models.IntegerField(help_text='Volts')
|
||||
num_pins = models.IntegerField(blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.description
|
||||
|
||||
|
||||
@reversion.register
|
||||
class Asset(models.Model, RevisionMixin):
|
||||
class Meta:
|
||||
ordering = ['asset_id_prefix', 'asset_id_number']
|
||||
permissions = (
|
||||
('asset_finance', 'Can see financial data for assets'),
|
||||
('view_asset', 'Can view an asset')
|
||||
)
|
||||
|
||||
parent = models.ForeignKey(to='self', related_name='asset_parent',
|
||||
blank=True, null=True, on_delete=models.SET_NULL)
|
||||
asset_id = models.CharField(max_length=15, unique=True)
|
||||
description = models.CharField(max_length=120)
|
||||
category = models.ForeignKey(to=AssetCategory, on_delete=models.CASCADE)
|
||||
status = models.ForeignKey(to=AssetStatus, on_delete=models.CASCADE)
|
||||
serial_number = models.CharField(max_length=150, blank=True)
|
||||
purchased_from = models.ForeignKey(to=Supplier, on_delete=models.CASCADE, blank=True, null=True, related_name="assets")
|
||||
date_acquired = models.DateField()
|
||||
date_sold = models.DateField(blank=True, null=True)
|
||||
purchase_price = models.DecimalField(blank=True, null=True, decimal_places=2, max_digits=10)
|
||||
salvage_value = models.DecimalField(blank=True, null=True, decimal_places=2, max_digits=10)
|
||||
comments = models.TextField(blank=True)
|
||||
next_sched_maint = models.DateField(blank=True, null=True)
|
||||
|
||||
# Cable assets
|
||||
is_cable = models.BooleanField(default=False)
|
||||
plug = models.ForeignKey(Connector, on_delete=models.SET_NULL,
|
||||
related_name='plug', blank=True, null=True)
|
||||
socket = models.ForeignKey(Connector, on_delete=models.SET_NULL,
|
||||
related_name='socket', blank=True, null=True)
|
||||
length = models.DecimalField(decimal_places=1, max_digits=10,
|
||||
blank=True, null=True, help_text='m')
|
||||
csa = models.DecimalField(decimal_places=2, max_digits=10,
|
||||
blank=True, null=True, help_text='mm^2')
|
||||
circuits = models.IntegerField(blank=True, null=True)
|
||||
cores = models.IntegerField(blank=True, null=True)
|
||||
|
||||
# Hidden asset_id components
|
||||
# For example, if asset_id was "C1001" then asset_id_prefix would be "C" and number "1001"
|
||||
asset_id_prefix = models.CharField(max_length=8, default="")
|
||||
asset_id_number = models.IntegerField(default=1)
|
||||
|
||||
def get_available_asset_id(wanted_prefix=""):
|
||||
sql = """
|
||||
SELECT a.asset_id_number+1
|
||||
FROM assets_asset a
|
||||
LEFT OUTER JOIN assets_asset b ON
|
||||
(a.asset_id_number + 1 = b.asset_id_number AND
|
||||
a.asset_id_prefix = b.asset_id_prefix)
|
||||
WHERE b.asset_id IS NULL AND a.asset_id_number >= %s AND a.asset_id_prefix = %s;
|
||||
"""
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(sql, [9000, wanted_prefix])
|
||||
row = cursor.fetchone()
|
||||
if row is None or row[0] is None:
|
||||
return 9000
|
||||
else:
|
||||
return row[0]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('asset_detail', kwargs={'pk': self.asset_id})
|
||||
|
||||
def __str__(self):
|
||||
out = str(self.asset_id) + ' - ' + self.description
|
||||
if self.is_cable:
|
||||
out += '{} - {}m - {}'.format(self.plug, self.length, self.socket)
|
||||
return out
|
||||
|
||||
def clean(self):
|
||||
errdict = {}
|
||||
if self.date_sold and self.date_acquired > self.date_sold:
|
||||
errdict["date_sold"] = ["Cannot sell an item before it is acquired"]
|
||||
|
||||
self.asset_id = self.asset_id.upper()
|
||||
asset_search = re.search("^([a-zA-Z0-9]*?[a-zA-Z]?)([0-9]+)$", self.asset_id)
|
||||
if asset_search is None:
|
||||
errdict["asset_id"] = [
|
||||
"An Asset ID can only consist of letters and numbers, with a final number"]
|
||||
|
||||
if self.purchase_price and self.purchase_price < 0:
|
||||
errdict["purchase_price"] = ["A price cannot be negative"]
|
||||
|
||||
if self.salvage_value and self.salvage_value < 0:
|
||||
errdict["salvage_value"] = ["A price cannot be negative"]
|
||||
|
||||
if self.is_cable:
|
||||
if not self.length or self.length <= 0:
|
||||
errdict["length"] = ["The length of a cable must be more than 0"]
|
||||
if not self.csa or self.csa <= 0:
|
||||
errdict["csa"] = ["The CSA of a cable must be more than 0"]
|
||||
if not self.circuits or self.circuits <= 0:
|
||||
errdict["circuits"] = ["There must be at least one circuit in a cable"]
|
||||
if not self.cores or self.cores <= 0:
|
||||
errdict["cores"] = ["There must be at least one core in a cable"]
|
||||
if self.socket is None:
|
||||
errdict["socket"] = ["A cable must have a socket"]
|
||||
if self.plug is None:
|
||||
errdict["plug"] = ["A cable must have a plug"]
|
||||
|
||||
if errdict != {}: # If there was an error when validation
|
||||
raise ValidationError(errdict)
|
||||
|
||||
|
||||
@receiver(pre_save, sender=Asset)
|
||||
def pre_save_asset(sender, instance, **kwargs):
|
||||
"""Automatically fills in hidden members on database access"""
|
||||
asset_search = re.search("^([a-zA-Z0-9]*?[a-zA-Z]?)([0-9]+)$", instance.asset_id)
|
||||
if asset_search is None:
|
||||
instance.asset_id += "1"
|
||||
asset_search = re.search("^([a-zA-Z0-9]*?[a-zA-Z]?)([0-9]+)$", instance.asset_id)
|
||||
instance.asset_id_prefix = asset_search.group(1)
|
||||
instance.asset_id_number = int(asset_search.group(2))
|
||||
@@ -1,23 +0,0 @@
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(xhr, settings) {
|
||||
function getCookie(name) {
|
||||
var cookieValue = null;
|
||||
if (document.cookie && document.cookie != '') {
|
||||
var cookies = document.cookie.split(';');
|
||||
for (var i = 0; i < cookies.length; i++) {
|
||||
var cookie = jQuery.trim(cookies[i]);
|
||||
// Does this cookie string begin with the name we want?
|
||||
if (cookie.substring(0, name.length + 1) == (name + '=')) {
|
||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cookieValue;
|
||||
}
|
||||
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
|
||||
// Only send the token to relative URLs i.e. locally.
|
||||
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,92 +0,0 @@
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_assets.html" %}
|
||||
{% load static %}
|
||||
{% load paginator from filters %}
|
||||
{% load to_class_name from filters %}
|
||||
|
||||
{% block title %}Asset Activity Stream{% endblock %}
|
||||
|
||||
{# TODO: Find a way to reduce code duplication...can't just include the content because of the IDs... #}
|
||||
|
||||
{% block js %}
|
||||
<script src="{% static "js/tooltip.js" %}"></script>
|
||||
<script src="{% static "js/popover.js" %}"></script>
|
||||
<script src="{% static "js/moment.min.js" %}"></script>
|
||||
<script>
|
||||
$(function () {
|
||||
$('[data-toggle="popover"]').popover().click(function(){
|
||||
if($(this).attr('href')){
|
||||
window.location.href = $(this).attr('href');
|
||||
}
|
||||
});
|
||||
|
||||
// This keeps timeago values correct, but uses an insane amount of resources
|
||||
// $(function () {
|
||||
// setInterval(function() {
|
||||
// $('.date').each(function (index, dateElem) {
|
||||
// var $dateElem = $(dateElem);
|
||||
// var formatted = moment($dateElem.attr('data-date')).fromNow();
|
||||
// $dateElem.text(formatted);
|
||||
// })
|
||||
// });
|
||||
// }, 10000);
|
||||
|
||||
|
||||
$('.date').each(function (index, dateElem) {
|
||||
var $dateElem = $(dateElem);
|
||||
var formatted = moment($dateElem.attr('data-date')).fromNow();
|
||||
$dateElem.text(formatted);
|
||||
});
|
||||
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-sm-12">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<h3>Asset Activity Stream</h3>
|
||||
</div>
|
||||
<div class="text-right col-sm-12">{% paginator %}</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Date</td>
|
||||
<td>Object</td>
|
||||
<td>Version ID</td>
|
||||
<td>User</td>
|
||||
<td>Changes</td>
|
||||
<td>Comment</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for version in object_list %}
|
||||
|
||||
<tr>
|
||||
<td>{{ version.revision.date_created }}</td>
|
||||
<td><a href="{{ version.changes.new.get_absolute_url }}">{{version.changes.new|to_class_name}} {{ version.changes.new.asset_id|default:version.changes.new.pk }}</a></td>
|
||||
<td>{{ version.pk }}|{{ version.revision.pk }}</td>
|
||||
<td>{{ version.revision.user.name }}</td>
|
||||
<td>
|
||||
{% if version.changes.old == None %}
|
||||
{{version.changes.new|to_class_name}} Created
|
||||
{% else %}
|
||||
{% include 'RIGS/version_changes.html' %}
|
||||
{% endif %} </td>
|
||||
<td>{{ version.changes.revision.comment }}</td>
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="align-right">{% paginator %}</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,61 +0,0 @@
|
||||
{% extends 'base_assets.html' %}
|
||||
{% load widget_tweaks %}
|
||||
{% load asset_templatetags %}
|
||||
{% block title %}Asset {{ object.asset_id }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="page-header">
|
||||
<h1>
|
||||
{% if duplicate %}
|
||||
Duplication of Asset: {{ previous_asset_id }}
|
||||
{% else %}
|
||||
Create Asset
|
||||
{% endif %}
|
||||
</h1>
|
||||
</div>
|
||||
{% if duplicate %}
|
||||
<form method="post" id="asset_update_form" action="{% url 'asset_duplicate' pk=previous_asset_id%}">
|
||||
{% else %}
|
||||
<form method="post" id="asset_update_form" action="{% url 'asset_create'%}">
|
||||
{% endif %}
|
||||
{% include 'form_errors.html' %}
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="id" value="{{ object.id|default:0 }}" hidden=true>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{% include 'partials/asset_form.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{% include 'partials/purchasedetails_form.html' %}
|
||||
</div>
|
||||
<div class="col-md-6" hidden="true" id="cable-table">
|
||||
{% include 'partials/cable_form.html' %}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{% include 'partials/parent_form.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{% include 'partials/asset_buttons.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js%}
|
||||
<script>
|
||||
function checkIfCableHidden() {
|
||||
if (document.getElementById("id_is_cable").checked) {
|
||||
document.getElementById("cable-table").hidden = false;
|
||||
} else {
|
||||
document.getElementById("cable-table").hidden = true;
|
||||
}
|
||||
}
|
||||
checkIfCableHidden();
|
||||
</script>
|
||||
{%endblock%}
|
||||
@@ -1,65 +0,0 @@
|
||||
{% extends 'base_assets.html' %}
|
||||
{% block title %}Asset List{% endblock %}
|
||||
{% load paginator from filters %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="page-header">
|
||||
<h1 class="text-center">Asset List</h1>
|
||||
</div>
|
||||
|
||||
<form id="asset-search-form" method="get" class="form-inline pull-right">
|
||||
<div class="input-group pull-right" style="width: auto;">
|
||||
{% render_field form.query|add_class:'form-control' placeholder='Search by Asset ID/Desc/Serial' style="width: 250px"%}
|
||||
<label for="query" class="sr-only">Asset ID/Description/Serial Number:</label>
|
||||
<span class="input-group-btn"><button type="submit" class="btn btn-default">Search</button></span>
|
||||
</div>
|
||||
<br>
|
||||
<div style="margin-top: 1em;" class="pull-right">
|
||||
<div class="form-group">
|
||||
<label for="category" class="sr-only">Category</label>
|
||||
{% render_field form.category|attr:'multiple'|add_class:'form-control selectpicker' data-none-selected-text="Categories" data-header="Categories" data-actions-box="true" %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="status" class="sr-only">Status</label>
|
||||
{% render_field form.status|attr:'multiple'|add_class:'form-control selectpicker' data-none-selected-text="Statuses" data-header="Statuses" data-actions-box="true" %}
|
||||
</div>
|
||||
<!---TODO: Auto filter whenever an option is selected, instead of using a button -->
|
||||
<button type="submit" class="btn btn-default">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Asset ID</th>
|
||||
<th>Description</th>
|
||||
<th>Category</th>
|
||||
<th>Status</th>
|
||||
<th class="hidden-xs">Quick Links</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="asset_table_body">
|
||||
{% include 'partials/asset_list_table_body.html' %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% if is_paginated %}
|
||||
<div class="text-center">
|
||||
{% paginator %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% load static %}
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static "css/bootstrap-select.min.css" %}"/>
|
||||
<link rel="stylesheet" href="{% static "css/ajax-bootstrap-select.css" %}"/>
|
||||
{% endblock %}
|
||||
|
||||
{% block preload_js %}
|
||||
<script src="{% static "js/bootstrap-select.js" %}"></script>
|
||||
<script src="{% static "js/ajax-bootstrap-select.js" %}"></script>
|
||||
{% endblock %}
|
||||
@@ -1,72 +0,0 @@
|
||||
{% extends 'base_assets.html' %}
|
||||
{% load widget_tweaks %}
|
||||
{% load asset_templatetags %}
|
||||
{% block title %}Asset {{ object.asset_id }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="page-header">
|
||||
<h1>
|
||||
{% if edit and object %}
|
||||
Edit Asset: {{ object.asset_id }}
|
||||
{% else %}
|
||||
Asset: {{ object.asset_id }}
|
||||
{% endif %}
|
||||
</h1>
|
||||
</div>
|
||||
<form method="post" id="asset_update_form" action="{% url 'asset_update' pk=object.asset_id%}">
|
||||
{% include 'form_errors.html' %}
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="id" value="{{ object.id|default:0 }}" hidden=true>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
{% include 'partials/asset_form.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
{% if perms.assets.asset_finance %}
|
||||
<div class="col-md-6">
|
||||
{% include 'partials/purchasedetails_form.html' %}
|
||||
</div>
|
||||
{%endif%}
|
||||
<div class="col-md-6"
|
||||
{% if not object.is_cable %} hidden="true" {% endif %} id="cable-table">
|
||||
{% include 'partials/cable_form.html' %}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{% include 'partials/parent_form.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{% include 'partials/asset_buttons.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% if not edit and perms.assets.view_asset %}
|
||||
<div class="col-sm-12 text-right">
|
||||
<div>
|
||||
<a href="{% url 'asset_history' object.asset_id %}" title="View Revision History">
|
||||
Last edited at {{ object.last_edited_at|default:'never' }} by {{ object.last_edited_by.name|default:'nobody' }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js%}
|
||||
{% if edit %}
|
||||
<script>
|
||||
function checkIfCableHidden() {
|
||||
if (document.getElementById("id_is_cable").checked) {
|
||||
document.getElementById("cable-table").hidden = false;
|
||||
} else {
|
||||
document.getElementById("cable-table").hidden = true;
|
||||
}
|
||||
}
|
||||
checkIfCableHidden();
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -1,16 +0,0 @@
|
||||
{% for asset in object_list %}
|
||||
<a href="javascript:void(0);" onclick="insertInParentField({{ asset.pk }}, '{{ asset }}')">
|
||||
{{ asset.asset_id }} - {{ asset.description }}
|
||||
</a>
|
||||
<br>
|
||||
{% empty %}
|
||||
No assets match given ID
|
||||
{% endfor %}
|
||||
|
||||
<script>
|
||||
function insertInParentField(pk, str) {
|
||||
$('#hidden_parent_id').val(pk);
|
||||
$('#parent_id').val(str);
|
||||
M.updateTextFields();
|
||||
}
|
||||
</script>
|
||||
@@ -1,68 +0,0 @@
|
||||
{% extends request.is_ajax|yesno:"base_ajax.html,base_assets.html" %}
|
||||
{% load to_class_name from filters %}
|
||||
{% load paginator from filters %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}{{object|to_class_name}} {{ object.asset_id }} - Revision History{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script src="{% static "js/tooltip.js" %}"></script>
|
||||
<script src="{% static "js/popover.js" %}"></script>
|
||||
<script>
|
||||
$(function () {
|
||||
$('[data-toggle="popover"]').popover().click(function(){
|
||||
if($(this).attr('href')){
|
||||
window.location.href = $(this).attr('href');
|
||||
}
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-sm-12">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<h3><a href="{{ object.get_absolute_url }}">{{object|to_class_name}} {{ object.asset_id|default:object.pk }}</a> - Revision History</h3>
|
||||
</div>
|
||||
<div class="text-right col-sm-12">{% paginator %}</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Date</td>
|
||||
<td>Version ID</td>
|
||||
<td>User</td>
|
||||
<td>Changes</td>
|
||||
<td>Comment</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for version in object_list %}
|
||||
|
||||
<tr>
|
||||
<td>{{ version.revision.date_created }}</td>
|
||||
<td>{{ version.pk }}|{{ version.revision.pk }}</td>
|
||||
<td>{{ version.revision.user.name }}</td>
|
||||
<td>
|
||||
{% if version.changes.old is None %}
|
||||
{{object|to_class_name}} Created
|
||||
{% else %}
|
||||
{% include 'RIGS/version_changes.html' %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ version.revision.comment }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="align-right">{% paginator %}</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,25 +0,0 @@
|
||||
{% if edit and object %}
|
||||
<!--edit-->
|
||||
<button type="submit" class="btn btn-success"><i class="glyphicon glyphicon-floppy-disk"></i> Save</button>
|
||||
<a class="btn btn-default" href="{% url 'asset_duplicate' object.pk %}"><i class="glyphicon glyphicon-duplicate"></i> Duplicate</a>
|
||||
{% elif duplicate %}
|
||||
<!--duplicate-->
|
||||
<button type="submit" class="btn btn-default"><i class="glyphicon glyphicon-ok-sign"></i> Create Duplicate</button>
|
||||
{% elif create %}
|
||||
<!--create-->
|
||||
<button type="submit" class="btn btn-success"><i class="glyphicon glyphicon-floppy-disk"></i> Save</button>
|
||||
{% else %}
|
||||
<!--detail view-->
|
||||
<div class="btn-group">
|
||||
<a href="{% url 'asset_update' object.asset_id %}" class="btn btn-default"><i class="glyphicon glyphicon-edit"></i> Edit</a>
|
||||
<a class="btn btn-default" href="{% url 'asset_duplicate' object.asset_id %}"><i class="glyphicon glyphicon-duplicate"></i> Duplicate</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if create or edit or duplicate %}
|
||||
<br>
|
||||
<button type="reset" class="btn btn-link" onclick="
|
||||
{%if duplicate%}
|
||||
{% url 'asset_detail' previous_asset_id %}
|
||||
{%else%}
|
||||
history.back(){%endif%}">Cancel</button>
|
||||
{% endif %}
|
||||
@@ -1,61 +0,0 @@
|
||||
{% load widget_tweaks %}
|
||||
{% load asset_templatetags %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Asset Details
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if create or edit or duplicate %}
|
||||
<div class="form-group">
|
||||
<label for="{{ form.asset_id.id_for_label }}">Asset ID</label>
|
||||
{% if duplicate %}
|
||||
{% render_field form.asset_id|add_class:'form-control' value=object.asset_id %}
|
||||
{% elif object.asset_id %}
|
||||
{% render_field form.asset_id|attr:'readonly'|add_class:'disabled_input form-control' value=object.asset_id %}
|
||||
{% else %}
|
||||
{% render_field form.asset_id|add_class:'form-control' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.description.id_for_label }}">Description</label>
|
||||
{% render_field form.description|add_class:'form-control' value=object.description %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.category.id_for_label }}" >Category</label>
|
||||
{% render_field form.category|add_class:'form-control'%}
|
||||
</div>
|
||||
{% render_field form.is_cable|attr:'onchange=checkIfCableHidden()' %} <label for="{{ form.is_cable.id_for_label }}">Cable?</label>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.status.id_for_label }}" >Status</label>
|
||||
{% render_field form.status|add_class:'form-control'%}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.serial_number.id_for_label }}">Serial Number</label>
|
||||
{% render_field form.serial_number|add_class:'form-control' value=object.serial_number %}
|
||||
</div>
|
||||
<!---TODO: Lower default number of lines in comments box-->
|
||||
<div class="form-group">
|
||||
<label for="{{ form.comments.id_for_label }}">Comments</label>
|
||||
{% render_field form.comments|add_class:'form-control' %}
|
||||
</div>
|
||||
{% else %}
|
||||
<dt>Asset ID</dt>
|
||||
<dd>{{ object.asset_id }}</dd>
|
||||
|
||||
<dt>Description</dt>
|
||||
<dd style="overflow-wrap: break-word;">{{ object.description }}</dd>
|
||||
|
||||
<dt>Category</dt>
|
||||
<dd>{{ object.category }}</dd>
|
||||
|
||||
<dt>Status</dt>
|
||||
<dd>{{ object.status }}</dd>
|
||||
|
||||
<dt>Serial Number</dt>
|
||||
<dd>{{ object.serial_number|default:'-' }}</dd>
|
||||
|
||||
<dt>Comments</dt>
|
||||
<dd style="overflow-wrap: break-word;">{{ object.comments|default:'-'|linebreaksbr }}</dd>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,18 +0,0 @@
|
||||
{% for item in object_list %}
|
||||
{# <li><a href="{% url 'asset_detail' item.pk %}">{{ item.asset_id }} - {{ item.description }}</a></li>#}
|
||||
<!---TODO: When the ability to filter the list is added, remove the colours from the filter - specifically, stop greying out sold/binned stuff if it is being searched for--> <tr class={{ item.status.display_class|default:"" }}>
|
||||
<td style="vertical-align: middle;"><a href="{% url 'asset_detail' item.asset_id %}">{{ item.asset_id }}</a></td>
|
||||
<td style="vertical-align: middle; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; max-width: 25vw">{{ item.description }}</td>
|
||||
<td style="vertical-align: middle;">{{ item.category }}</td>
|
||||
<td style="vertical-align: middle;">{{ item.status }}</td>
|
||||
<td class="hidden-xs">
|
||||
<div class="btn-group" role="group">
|
||||
<a type="button" class="btn btn-default btn-sm" href="{% url 'asset_detail' item.asset_id %}"><i class="glyphicon glyphicon-eye-open"></i> View</a>
|
||||
{% if perms.assets.change_asset %}
|
||||
<a type="button" class="btn btn-default btn-sm" href="{% url 'asset_update' item.asset_id %}"><i class="glyphicon glyphicon-edit"></i> Edit</a>
|
||||
<a type="button" class="btn btn-default btn-sm" href="{% url 'asset_duplicate' item.asset_id %}"><i class="glyphicon glyphicon-duplicate"></i> Duplicate</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
@@ -1,65 +0,0 @@
|
||||
<select name="parent" id="parent_id" class="selectpicker">
|
||||
{% if object.parent%}
|
||||
<option value="{{object.parent.pk}}" selected>{{object.parent.description}}</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
|
||||
{% load static %}
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static "css/bootstrap-select.min.css" %}"/>
|
||||
<link rel="stylesheet" href="{% static "css/ajax-bootstrap-select.css" %}"/>
|
||||
{% endblock %}
|
||||
|
||||
{% block preload_js %}
|
||||
<script src="{% static "js/bootstrap-select.js" %}"></script>
|
||||
<script src="{% static "js/ajax-bootstrap-select.js" %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
{{ js.super }}
|
||||
<script>
|
||||
$('#parent_id')
|
||||
.selectpicker({
|
||||
liveSearch: true
|
||||
})
|
||||
.ajaxSelectPicker({
|
||||
ajax: {
|
||||
url: '{% url 'asset_search_json'%}',
|
||||
type: "get",
|
||||
data: function () {
|
||||
var params = {
|
||||
{% verbatim %}query: '{{{q}}}'{% endverbatim %}
|
||||
};
|
||||
return params;
|
||||
}
|
||||
},
|
||||
locale: {
|
||||
emptyTitle: 'Search for item...'
|
||||
},
|
||||
preprocessData: function(data){
|
||||
var assets = [];
|
||||
if(data.length){
|
||||
var len = data.length;
|
||||
for(var i = 0; i < len; i++){
|
||||
var curr = data[i];
|
||||
assets.push(
|
||||
{
|
||||
'value': curr.id,
|
||||
'text': curr.label,
|
||||
'disabled': false
|
||||
}
|
||||
);
|
||||
}
|
||||
assets.push(
|
||||
{
|
||||
'value': null,
|
||||
'text': "No parent"
|
||||
});
|
||||
}
|
||||
|
||||
return assets;
|
||||
},
|
||||
preserveSelected: false
|
||||
});
|
||||
</script>
|
||||
{% endblock js %}
|
||||
@@ -1,61 +0,0 @@
|
||||
{% load widget_tweaks %}
|
||||
{% load asset_templatetags %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Cable Details
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if create or edit or duplicate %}
|
||||
<div class="form-group">
|
||||
<label for="{{ form.plug.id_for_label }}">Plug</label>
|
||||
{% render_field form.plug|add_class:'form-control'%}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.socket.id_for_label }}">Socket</label>
|
||||
{% render_field form.socket|add_class:'form-control'%}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.length.id_for_label }}">Length</label>
|
||||
<div class="input-group">
|
||||
{% render_field form.length|add_class:'form-control' %}
|
||||
<span class="input-group-addon">{{ form.length.help_text }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.csa.id_for_label }}">Cross Sectional Area</label>
|
||||
<div class="input-group">
|
||||
{% render_field form.csa|add_class:'form-control' value=object.csa %}
|
||||
<span class="input-group-addon">{{ form.csa.help_text }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.circuits.id_for_label }}">Circuits</label>
|
||||
{% render_field form.circuits|add_class:'form-control' value=object.circuits %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.cores.id_for_label }}">Cores</label>
|
||||
{% render_field form.cores|add_class:'form-control' value=object.cores %}
|
||||
</div>
|
||||
{% else %}
|
||||
<dl>
|
||||
<dt>Socket</dt>
|
||||
<dd>{{ object.socket|default_if_none:'-' }}</dd>
|
||||
|
||||
<dt>Plug</dt>
|
||||
<dd>{{ object.plug|default_if_none:'-' }}</dd>
|
||||
|
||||
<dt>Length</dt>
|
||||
<dd>{{ object.length|default_if_none:'-' }}m</dd>
|
||||
|
||||
<dt>Cross Sectional Area</dt>
|
||||
<dd>{{ object.csa|default_if_none:'-' }}m^2</dd>
|
||||
|
||||
<dt>Circuits</dt>
|
||||
<dd>{{ object.circuits|default_if_none:'-' }}</dd>
|
||||
|
||||
<dt>Cores</dt>
|
||||
<dd>{{ object.cores|default_if_none:'-' }}</dd>
|
||||
</dl>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,41 +0,0 @@
|
||||
{% load widget_tweaks %}
|
||||
{% load asset_templatetags %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Collection Details
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if create or edit or duplicate %}
|
||||
<div class="form-group">
|
||||
<label for="selectpicker">Set Parent</label>
|
||||
{% include 'partials/asset_picker.html' %}
|
||||
</div>
|
||||
{% else %}
|
||||
<dl>
|
||||
<dt>Parent</dt>
|
||||
<dd>
|
||||
{% if object.parent %}
|
||||
<a href="{% url 'asset_detail' object.parent.asset_id %}">
|
||||
{{ object.parent.asset_id }} - {{ object.parent.description }}
|
||||
</a>
|
||||
{% else %}
|
||||
<span>-</span>
|
||||
{% endif %}
|
||||
</dd>
|
||||
|
||||
<dt>Children</dt>
|
||||
{% if object.asset_parent.all %}
|
||||
{% for child in object.asset_parent.all %}
|
||||
<dd>
|
||||
<a href="{% url 'asset_detail' child.asset_id %}">
|
||||
{{ child.asset_id }} - {{ child.description }}
|
||||
</a>
|
||||
</dd>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<dd><span>-</span></dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
{% endif%}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,89 +0,0 @@
|
||||
{% load widget_tweaks %}
|
||||
{% load asset_templatetags %}
|
||||
{% load static %}
|
||||
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static "css/bootstrap-select.min.css" %}"/>
|
||||
<link rel="stylesheet" href="{% static "css/ajax-bootstrap-select.css" %}"/>
|
||||
{% endblock %}
|
||||
|
||||
{% block preload_js %}
|
||||
<script src="{% static "js/bootstrap-select.js" %}"></script>
|
||||
<script src="{% static "js/ajax-bootstrap-select.js" %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script src="{% static "js/autocompleter.js" %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Purchase Details
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if create or edit or duplicate %}
|
||||
<div class="form-group">
|
||||
<label for="{{ form.purchased_from.id_for_label }}">Supplier</label>
|
||||
<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 %}
|
||||
<option value="{{form.purchased_from.value}}" selected="selected" data-update_url="{% url 'supplier_update' form.purchased_from.value %}">{{ object.purchased_from }}</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="{{ form.purchase_price.id_for_label }}">Purchase Price</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">£</span>
|
||||
{% render_field form.purchase_price|add_class:'form-control' value=object.purchase_price %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="{{ form.salvage_value.id_for_label }}">Salvage Value</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">£</span>
|
||||
{% render_field form.salvage_value|add_class:'form-control' value=object.salvage_value %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="{{ form.date_acquired.id_for_label }}" >Date Acquired</label>
|
||||
{% if object.date_acquired%}
|
||||
{% with date_acq=object.date_acquired|date:"Y-m-d" %}
|
||||
{% render_field form.date_acquired|add_class:'form-control'|attr:'type="date"' value=date_acq %}
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
<input type="date" name="date_acquired" value="{% now "Y-m-d" %}"
|
||||
class="form-control" id="id_date_acquired">
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="{{ form.date_sold.id_for_label }}">Date Sold</label>
|
||||
{% with date_sol=object.form.date_sold|date:"Y-m-d" %}
|
||||
{% render_field form.date_sold|add_class:'form-control'|attr:'type="date"' value=date_sol %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% else %}
|
||||
<dl>
|
||||
<dt>Purchased From</dt>
|
||||
<dd>{{ object.purchased_from|default_if_none:'-' }}</dd>
|
||||
|
||||
<dt>Purchase Price</dt>
|
||||
<dd>£{{ object.purchase_price|default_if_none:'-' }}</dd>
|
||||
|
||||
<dt>Salvage Value</dt>
|
||||
<dd>£{{ object.salvage_value|default_if_none:'-' }}</dd>
|
||||
|
||||
<dt>Date Acquired</dt>
|
||||
<dd>{{ object.date_acquired|default_if_none:'-' }}</dd>
|
||||
{% if object.date_sold %}
|
||||
<dt>Date Sold</dt>
|
||||
<dd>{{ object.date_sold|default_if_none:'-' }}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||