Merge assetforms -> main assets branch

This commit is contained in:
2019-10-14 14:16:24 +01:00
committed by GitHub
26 changed files with 832 additions and 441 deletions

View File

@@ -39,6 +39,7 @@ class EmbeddedAuthenticationForm(AuthenticationForm):
super().__init__(*args, **kwargs)
self.fields['username'].widget.attrs.pop('autofocus', None)
class PasswordReset(PasswordResetForm):
captcha = ReCaptchaField(label='Captcha')

View File

@@ -121,8 +121,19 @@ class Command(BaseCommand):
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"]
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"]
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",
"asset_finance", "change_asset"]
for permId in keyholderPerms:
self.keyholder_group.permissions.add(Permission.objects.get(codename=permId))

View File

@@ -0,0 +1,18 @@
# Generated by Django 2.0.13 on 2019-10-08 20:48
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'),
),
]

View File

@@ -83,6 +83,7 @@ class EventEmbed(EventDetail):
class EventRA(generic.base.RedirectView):
permanent = False
def get_redirect_url(self, *args, **kwargs):
event = get_object_or_404(models.Event, pk=kwargs['pk'])
@@ -406,6 +407,7 @@ 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"]

View File

@@ -32,11 +32,6 @@ class ConnectorAdmin(admin.ModelAdmin):
list_display = ['id', '__str__', 'current_rating', 'voltage_rating', 'num_pins']
@admin.register(assets.Cable)
class CableAdmin(admin.ModelAdmin):
pass
admin.AdminSite.site_header = 'PyAssets - TEC\'s Asset System'
admin.AdminSite.site_title = 'PyAssets Admin'
admin.AdminSite.index_title = 'System Administration'

View File

@@ -1,4 +1,5 @@
from django import forms
from django.core.exceptions import ValidationError
from assets import models
@@ -9,7 +10,7 @@ class AssetForm(forms.ModelForm):
fields = '__all__'
class SupplierForm(forms.ModelForm):
class SupplierForm(forms.Form):
class Meta:
model = models.Supplier
fields = '__all__'

View File

@@ -21,6 +21,7 @@ class Command(BaseCommand):
self.create_statuses()
self.create_suppliers()
self.create_assets()
self.create_connectors()
def create_categories(self):
categories = ['Case', 'Video', 'General', 'Sound', 'Lighting', 'Rigging']
@@ -35,7 +36,8 @@ class Command(BaseCommand):
models.AssetStatus.objects.create(name=stat)
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","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"]
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",
"Input, Inc.", "Mainway Toys", "Videlectrix", "Zevo Toys", "Ajax", "Axis Chemical Co.", "Barrytron", "Carrys Candles", "Cogswell Cogs", "Spacely Sprockets", "General Forge and Foundry", "Duff Brewing Company", "Dunder Mifflin", "General Services Corporation", "Monarch Playing Card Co.", "Krustyco", "Initech", "Roboto Industries", "Primatech", "Sonky Rubber Goods", "St. Anky Beer", "Stay Puft Corporation", "Vandelay Industries", "Wernham Hogg", "Gadgetron", "Burleigh and Stronginthearm", "BLAND Corporation", "Nordyne Defense Dynamics", "Petrox Oil Company", "Roxxon", "McMahon and Tate", "Sixty Second Avenue", "Charles Townsend Agency", "Spade and Archer", "Megadodo Publications", "Rouster and Sideways", "C.H. Lavatory and Sons", "Globo Gym American Corp", "The New Firm", "SpringShield", "Compuglobalhypermeganet", "Data Systems", "Gizmonic Institute", "Initrode", "Taggart Transcontinental", "Atlantic Northern", "Niagular", "Plow King", "Big Kahuna Burger", "Big T Burgers and Fries", "Chez Quis", "Chotchkies", "The Frying Dutchman", "Klimpys", "The Krusty Krab", "Monks Diner", "Milliways", "Minuteman Cafe", "Taco Grande", "Tip Top Cafe", "Moes Tavern", "Central Perk", "Chasers"]
for supplier in suppliers:
models.Supplier.objects.create(name=supplier)
@@ -60,3 +62,14 @@ class Command(BaseCommand):
asset.purchased_from = random.choice(suppliers)
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()

View File

@@ -21,7 +21,7 @@ class Command(BaseCommand):
self.delete_objects(models.AssetCategory)
self.delete_objects(models.AssetStatus)
self.delete_objects(models.Supplier)
self.delete_objects(models.Collection)
self.delete_objects(models.Connector)
self.delete_objects(models.Asset)
def delete_objects(self, model):

View File

@@ -0,0 +1,18 @@
# Generated by Django 2.0.13 on 2019-10-08 20:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('assets', '0008_auto_20191002_1931'),
]
operations = [
migrations.AlterField(
model_name='asset',
name='asset_id',
field=models.CharField(max_length=10, unique=True),
),
]

View File

@@ -0,0 +1,67 @@
# Generated by Django 2.0.13 on 2019-10-13 20:23
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('assets', '0009_auto_20191008_2148'),
]
operations = [
migrations.RemoveField(
model_name='cable',
name='asset_ptr',
),
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(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(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='socket', to='assets.Connector'),
),
migrations.DeleteModel(
name='Cable',
),
]

View File

@@ -0,0 +1,24 @@
# Generated by Django 2.0.13 on 2019-10-13 21:47
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('assets', '0010_auto_20191013_2123'),
]
operations = [
migrations.AlterField(
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.AlterField(
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'),
),
]

View File

@@ -0,0 +1,17 @@
# Generated by Django 2.0.13 on 2019-10-13 23:12
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('assets', '0011_auto_20191013_2247'),
]
operations = [
migrations.AlterModelOptions(
name='asset',
options={'permissions': (('asset_finance', 'Can see financial data for assets'),)},
),
]

View File

@@ -1,8 +1,10 @@
from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
from polymorphic.models import PolymorphicModel
import datetime
import re
class AssetCategory(models.Model):
@@ -37,10 +39,25 @@ class Supplier(models.Model):
return self.name
class Asset(PolymorphicModel):
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
class Asset(models.Model):
class Meta:
ordering = ['asset_id']
permissions = (
('asset_finance', 'Can see financial data for assets'),
)
parent = models.ForeignKey(to='self', related_name='asset_parent', blank=True, null=True, on_delete=models.SET_NULL)
asset_id = models.CharField(max_length=10)
asset_id = models.CharField(max_length=10, 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)
@@ -55,34 +72,55 @@ class Asset(PolymorphicModel):
# Cable assets
is_cable = models.BooleanField(default=False)
def get_absolute_url(self):
return reverse('asset_detail', kwargs={'pk': self.pk})
def __str__(self):
return str(self.asset_id) + ' - ' + self.description
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
class Cable(Asset):
plug = models.ForeignKey(Connector, on_delete=models.SET_NULL, related_name='plug', null=True)
socket = models.ForeignKey(Connector, on_delete=models.SET_NULL, related_name='socket', null=True)
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)
def cable_resistance(self):
rho = 0.0000000168
return (rho * self.length) / (self.csa * 1000000)
def get_absolute_url(self):
return reverse('asset_detail', kwargs={'pk': self.pk})
def __str__(self):
return '{} - {}m - {}'.format(self.plug, self.length, self.socket)
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):
if self.date_sold and self.date_acquired > self.date_sold:
raise ValidationError({"date_sold": "Cannot sell an item before it is acquired"})
self.asset_id = self.asset_id.upper()
if re.search("^[a-zA-Z0-9]+$", self.asset_id) is None:
raise ValidationError({"asset_id": "An Asset ID can only consist of letters and numbers"})
if self.purchase_price and self.purchase_price < 0:
raise ValidationError({"purchase_price": "A price cannot be negative"})
if self.salvage_value and self.salvage_value < 0:
raise ValidationError({"purchase_price": "A price cannot be negative"})
if self.is_cable:
if self.length is None:
raise ValidationError({"length": "The length of a cable must be a number"})
elif self.csa is None:
raise ValidationError({"csa": "The csa of a cable must be a number"})
elif self.circuits is None:
raise ValidationError({"circuits": "The number of circuits in a cable must be a number"})
elif self.cores is None:
raise ValidationError({"cores": "The number of cores in a cable must be a number"})
elif self.socket is None:
raise ValidationError({"plug": "A cable must have a plug"})
elif self.plug is None:
raise ValidationError({"socket": "A cable must have a socket"})
if self.length <= 0:
raise ValidationError({"length": "The length of a cable must be more than 0"})
elif self.csa <= 0:
raise ValidationError({"csa": "The CSA of a cable must be more than 0"})
elif self.circuits <= 0:
raise ValidationError({"circuits": "There must be at least one circuit in a cable"})
elif self.cores <= 0:
raise ValidationError({"cores": "There must be at least one core in a cable"})

View File

@@ -0,0 +1,71 @@
{% 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_pk%}">
{% else %}
<form method="post" id="asset_update_form" action="{% url 'asset_create'%}">
{% endif %}
{% include 'form_errors.html' %}
<div class="row" style="padding-bottom: 1em">
<div class="col-sm-12">
<div class="pull-right">
{% include 'partials/asset_buttons.html' %}
</div>
</div>
</div>
{% 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>
{% include 'partials/confirm_delete.html' with object=object %}
{% 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%}

View File

@@ -8,41 +8,48 @@
<h1 class="text-center">Asset List</h1>
</div>
<form id="asset-search-form">
<form id="asset-search-form" method="get" class="form-inline pull-right">
{% csrf_token %}
<div class="input-group">
<input type="query" name="query" placeholder="Search by Asset ID/Description" class="form-control" value="{{searchName}}">
<div class="input-group pull-right" style="width: auto;">
<input type="query" name="query" placeholder="Search by Asset ID/Description" class="form-control" value="{{search_name}}" style="width: 250px">
<label for="asset_id" class="sr-only">Asset ID/Description:</label>
<span class="input-group-btn"><button type="submit" class="btn btn-default">Search</button></span>
</div>
</form>
<form class="form-inline" id="asset-filter-form">
{% csrf_token %}
<br>
<div style="margin-top: 1em;" class="pull-right">
<div class="form-group">
<label for="cat">Category:</label>
<label for="cat" class="sr-only">Category</label>
<select name="cat" class="form-control">
<option>None</option>
<option value="" class="text-muted">(category)</option>
{% for name in categories %}
{% if name.name == category_select %}
<option selected>
{% else %}
<option>
{% endif %}
{{ name }}
</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="status">Status:</label>
<label for="status" class="sr-only">Status</label>
<select name="status" class="form-control">
<option>None</option>
<option value="">(status)</option>
{% for name in statuses %}
{% if name.name == status_select %}
<option selected>
{% else %}
<option>
{% endif %}
{{ name }}
</option>
{% endfor %}
</select>
</div>
<!---TODO: Auto filter whenever an option is selected, instead of using a button --->
<!---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">

View File

@@ -9,304 +9,64 @@
<div class="page-header">
<h1>
{% if edit and object %}
Edit Asset: {{ object.asset_id }} - {{ object.description }}
{% elif duplicate %}
Duplication of Asset: {{ previous_asset_id }}
{% elif not object %}
Create Asset
Edit Asset: {{ object.asset_id }}
{% else %}
Asset: {{ object.asset_id }} - {{ object.description }}
Asset: {{ object.asset_id }}
{% endif %}
</h1>
</div>
<div class="row" style="padding-bottom: 1em">
<form method="post" id="asset_update_form" action="{% url 'asset_update' pk=object.pk%}">
{% include 'form_errors.html' %}
<div class="row" style="padding-bottom: 1em">
<div class="col-sm-12">
<div class="pull-right">
{% include 'partials/asset_buttons.html' %}
</div>
</div>
</div>
<form method="post" id="asset_update_form">
</div>
{% csrf_token %}
<input type="hidden" name="id" value="{{ object.id|default:0 }}" hidden=true>
<div class="row">
<div class="col-sm-12">
<div class="panel panel-default">
<div class="panel-heading">
Asset Details
</div>
<div class="panel-body">
{% if 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 disabled'|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>
<select name="{{ form.category.name }}" id="{{ form.category.id_for_label }}"
required class="form-control">
{% for id, choice in form.category.field.choices %}
<option value="{{ id }}"
{% if object.category.id == id %}selected{% endif %}>{{ choice }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="{{ form.status.id_for_label }}" >Status</label>
<select class="form-control" name="{{ form.status.name }}" id="{{ form.status.id_for_label }}" required>
{% for id, choice in form.status.field.choices %}
<option value="{{ id }}"
{% if not object.status.id and choice == "Active" or object.status.id == id %}selected{% endif %}>{{ choice }}</option>
{% endfor %}
</select>
</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>{{ 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>{{ object.comments|default:'-'|linebreaksbr }}</dd>
{% endif %}
</div>
</div>
{% include 'partials/asset_form.html' %}
</div>
</div>
<div class="row">
{% if perms.asset.asset_financial %}
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
Purchase Details
{% include 'partials/purchasedetails_form.html' %}
</div>
<div class="panel-body">
{% if edit or duplicate %}
<div class="form-group">
<label for="{{ form.purchased_from.id_for_label }}">Purchased From</label>
<select class="form-control" name="{{ form.purchased_from.name }}"
id="{{ form.purchased_from.id_for_label }}">
{% for id, choice in form.purchased_from.field.choices %}
<option value="{{ id }}"
{% if object.purchased_from.id == id %}selected{% endif %}>{{ choice }}</option>
{% endfor %}
</select>
{%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="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 class="col-md-4">
{% include 'partials/parent_form.html' %}
</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 %}
{% render_field form.date_acquired|add_class:'form-control'|attr:'type="date"' value=object.date_acquired|date %}
{% else %}
<input type="date" name="date_acquired" value="{% now "DATE_FORMAT" %}"
class="form-control" id="id_date_acquired">
{% endif %}
</div>
<div class="form-group">
<label for="{{ form.date_sold.id_for_label }}">Date Sold</label>
{% render_field form.date_sold|add_class:'form-control'|attr:'type="date"' value=object.date_sold|date %}
</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>
</div>
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
Collection Details
</div>
<div class="panel-body">
{% if edit or duplicate %}
<div class="form-group">
<label for="parent_id">Parent</label>
<input type="hidden" name="{{ form.parent.html_name }}" id="hidden_parent_id"
value="{{ object.parent.id }}">
<div class="input-group">
<input type="text" id="parent_id" value="{{ object.parent|default:'' }}"
disabled="" class="form-control">
<span class="input-group-btn"><button type="button" class="btn btn-default" onclick="clearParent()">Clear
</button></span>
</div>
</div>
<div class="form-group">
<label for="parent_search">Search for asset</label>
<div class="input-group">
<input type="text" id="parent_search" class="form-control">
<span class="input-group-btn"><button type="button" class="btn btn-default" onclick="formAssetSearch()">
<i class="glyphicon glyphicon-search"></i> Search
</button></span>
</div>
</div>
<div class="col s2">
<br>
</div>
<div class="col s12" id="formAssetSearchResult">
<!--Placeholder for search results-->
</div>
{% else %}
<dl>
<dt>Parent</dt>
<dd>
{% if object.parent %}
<a href="{% url 'asset_detail' object.parent.pk %}">
{{ 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.pk %}">
{{ child.asset_id }} - {{ child.description }}
</a>
</dd>
{% endfor %}
{% else %}
<dd><span>-</span></dd>
{% endif %}
</dl>
{% endif %}
</div>
</div>
</div>
</div>
</form>
<div class="row">
<div class="row">
<div class="col-md-12">
{% include 'partials/asset_buttons.html' %}
</div>
</div>
</div>
</form>
{% include 'partials/confirm_delete.html' with object=object %}
{% endblock %}
{% block js %}
{% block js%}
{% if edit %}
<script>
function updateAsset() {
$.ajax({
url: "{% url 'ajax_asset_update' %}", // the endpoint
type: "POST", // http method
data: {
form: $('#asset_update_form').serialize()
},
traditional: true,
headers: {
'X-CSRFToken': document.getElementById("asset_update_form").csrfmiddlewaretoken.value
},
success: function(data) {
// console.log(data);
window.location.href = data['url'];
},
error: function(xhr) {
console.log(xhr.status + ": " + xhr.responseText)
function checkIfCableHidden() {
if (document.getElementById("id_is_cable").checked) {
document.getElementById("cable-table").hidden = false;
} else {
document.getElementById("cable-table").hidden = true;
}
});
}
checkIfCableHidden();
</script>
{# <script>#}
{# $('#asset_update_form').on('submit', function(event){#}
{#console.log($('#asset_update_form').serialize());#}
{# event.preventDefault();#}
{# updateAsset();#}
{# return false;#}
{# });#}
{# </script>#}
<script>
function clearParent() {
$('#hidden_parent_id').val('');
$('#parent_id').val('');
}
</script>
<script>
$(document).ready(function() {
{
%
if edit or duplicate %
}
var comments_id = '#{{ form.comments.id_for_label }}';
$(comments_id).val('{{ object.comments|linebreaksn }}'); {
%
endif %
}
})
</script>
{% endif %}
{% endblock %}

View File

@@ -1,20 +1,27 @@
{% 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>
<a class="btn btn-danger" data-toggle="modal" data-target="#confirm_delete_modal"><i class="glyphicon glyphicon-trash"></i> Delete</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">
{% if edit and object %}
<!--edit-->
<button type="button" class="btn btn-success" onclick="updateAsset()"><i class="glyphicon glyphicon-floppy-disk"></i> Save</button>
<a class="btn btn-default" href="{% url 'asset_update' object.pk %}?duplicate=true"><i class="glyphicon glyphicon-duplicate"></i> Duplicate</a>
<a class="btn btn-danger" data-toggle="modal" data-target="#confirm_delete_modal"><i class="glyphicon glyphicon-trash"></i> Delete</a>
{% elif duplicate %}
<!--duplicate-->
<button type="button" class="btn btn-default" onclick="updateAsset()"><i class="glyphicon glyphicon-ok-sign"></i> Create Duplicate</button>
<a href="{% url 'asset_detail' previous_asset_pk %}" class="btn btn-warning"><i class="glyphicon glyphicon-remove"></i> Cancel</a>
{% elif not object %}
<!--create-->
<button type="button" class="btn btn-success" onclick="updateAsset()"><i class="glyphicon glyphicon-floppy-disk"></i> Save</button>
{% else %}
<!--detail view-->
<a href="{% url 'asset_update' object.pk %}" class="btn btn-default"><i class="glyphicon glyphicon-edit"></i> Edit</a>
<a class="btn btn-default" href="{% url 'asset_update' object.pk %}?duplicate=true"><i class="glyphicon glyphicon-duplicate"></i> Duplicate</a>
<a class="btn btn-default" href="{% url 'asset_duplicate' object.pk %}"><i class="glyphicon glyphicon-duplicate"></i> Duplicate</a>
<a class="btn btn-danger" data-toggle="modal" data-target="#confirm_delete_modal"><i class="glyphicon glyphicon-trash"></i> Delete</a>
{% endif %}
</div>
{% endif %}
{% if create or edit or duplicate %}
<br>
<button type="reset" class="btn btn-link" onclick="
{%if duplicate%}
{% url 'asset_detail' previous_asset_pk %}
{%else%}
history.back(){%endif%}">Cancel</button>
{% endif %}

View File

@@ -0,0 +1,75 @@
{% 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>
<select name="{{ form.category.name }}" id="{{ form.category.id_for_label }}" required class="form-control">
{% for id, choice in form.category.field.choices %}
<option value="{{ id }}"
{% if object.category.id == id %}
selected
{% endif %}>
{{ choice }}
</option>
{% endfor %}
</select>
</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>
<select class="form-control" name="{{ form.status.name }}" id="{{ form.status.id_for_label }}" required>
{% for id, choice in form.status.field.choices %}
<option value="{{ id }}"
{% if not object.status.id and choice == "Active" or object.status.id == id %}selected{% endif %}>{{ choice }}</option>
{% endfor %}
</select>
</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>

View File

@@ -1,7 +1,6 @@
{% 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="
<!---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="
{% if item.status.name == 'Broken' %}
danger
{% elif item.status.name == 'Lost'%}
@@ -12,15 +11,18 @@
text-muted
{% endif %}
">
<td><a href="{% url 'asset_detail' item.pk %}">{{ item.asset_id }}</a></td>
<td>{{ item.description }}</td>
<td>{{ item.category }}</td>
<td>{{ item.status }}</td>
<td style="vertical-align: middle;"><a href="{% url 'asset_detail' item.pk %}">{{ 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>
<div class="btn-group" role="group">
<a type="button" class="btn btn-default btn-sm" href="{% url 'asset_detail' item.pk %}"><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.pk %}"><i class="glyphicon glyphicon-edit"></i> Edit</a>
<a type="button" class="btn btn-default btn-sm" href="{% url 'asset_update' item.pk %}?duplicate=true"><i class="glyphicon glyphicon-duplicate"></i> Duplicate</a>
{% endif %}
</div>
</td>
</tr>

View File

@@ -0,0 +1,63 @@
<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 %}
<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 %}

View File

@@ -0,0 +1,75 @@
{% 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>
<select name="{{ form.plug.name }}" id="{{ form.plug.id_for_label }}" class="form-control">
<option value="">
{% for connector in connectors %}
<option value="{{ connector.pk }}">
{{ connector.description }}
</option>
{%endfor%}
</select>
</div>
<div class="form-group">
<label for="{{ form.socket.id_for_label }}">Socket</label>
<select name="{{ form.socket.name }}" id="{{ form.socket.id_for_label }}" class="form-control">
<option value="">
{% for connector in connectors %}
<option value="{{ connector.pk }}">
{{ connector.description }}
</option>
{%endfor%}
</select>
</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>

View File

@@ -0,0 +1,41 @@
{% 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.pk %}">
{{ 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.pk %}">
{{ child.asset_id }} - {{ child.description }}
</a>
</dd>
{% endfor %}
{% else %}
<dd><span>-</span></dd>
{% endif %}
</dl>
{% endif%}
</div>
</div>

View File

@@ -0,0 +1,76 @@
{% load widget_tweaks %}
{% load asset_templatetags %}
<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 }}">Purchased From</label>
<select class="form-control" name="{{ form.purchased_from.name }}" id="{{ form.purchased_from.id_for_label }}">
{% for id, choice in form.purchased_from.field.choices %}
<option value="{{ id }}"
{% if object.purchased_from.id == id %}
selected
{% endif %}>
{{ choice }}</option>
{% endfor %}
</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>

View File

@@ -2,24 +2,26 @@ from django.urls import path, include
from rest_framework import routers
from assets import views, api
from PyRIGS.decorators import permission_required_with_403
router = routers.DefaultRouter()
router.register(r'api/assets', api.AssetViewSet)
urlpatterns = [
# path('', views.Index.as_view(), name='index'),
path('', views.AssetList.as_view(), name='index'),
path('asset/list/', views.AssetList.as_view(), name='asset_list'),
path('asset/<int:pk>/', views.AssetDetail.as_view(), name='asset_detail'),
path('asset/create/', views.AssetEdit.as_view(), name='asset_create'),
path('asset/<int:pk>/edit/', views.AssetEdit.as_view(), name='asset_update'),
path('asset/delete/', views.asset_delete, name='ajax_asset_delete'),
path('asset/update/', views.asset_update, name='ajax_asset_update'),
path('asset/create/', permission_required_with_403('assets.create_asset')(views.AssetCreate.as_view()), name='asset_create'),
path('asset/<int:pk>/edit/', permission_required_with_403('assets.change_asset')(views.AssetEdit.as_view()), name='asset_update'),
path('asset/<int:pk>/duplicate/', permission_required_with_403('assets.create_asset')(views.AssetDuplicate.as_view()), name='asset_duplicate'),
path('asset/delete/', permission_required_with_403('assets.delete_asset')(views.asset_delete), name='ajax_asset_delete'),
path('asset/search/', views.AssetSearch.as_view(), name='asset_search_json'),
path('supplier/list', views.SupplierList.as_view(), name='supplier_list'),
path('supplier/<int:pk>', views.SupplierDetail.as_view(), name='supplier_detail'),
path('supplier/create', views.SupplierCreate.as_view(), name='supplier_create'),
path('supplier/<int:pk>/edit', views.SupplierUpdate.as_view(), name='supplier_update'),
path('supplier/create', permission_required_with_403('assets.create_supplier')(views.SupplierCreate.as_view()), name='supplier_create'),
path('supplier/<int:pk>/edit', permission_required_with_403('assets.edit_supplier')(views.SupplierUpdate.as_view()), name='supplier_update'),
path('', include(router.urls)),
]

View File

@@ -1,7 +1,7 @@
from django.shortcuts import render, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse, QueryDict
from django.http import HttpResponse, QueryDict, JsonResponse
from django.core import serializers
from django.views import generic
from django.contrib.auth import views as auth_views
@@ -13,6 +13,7 @@ from dateutil import parser
import simplejson as json
from assets import models, forms
class AssetList(LoginRequiredMixin, generic.ListView):
model = models.Asset
template_name = 'asset_list.html'
@@ -20,96 +21,101 @@ class AssetList(LoginRequiredMixin, generic.ListView):
ordering = ['-pk']
def get_queryset(self):
#TODO Feedback to user when search fails
# TODO Feedback to user when search fails
query = self.request.GET.get('query', "")
if len(query) >= 3:
return self.model.objects.filter(Q(asset_id__exact=query) | Q(description__icontains=query))
elif query != "":
return self.model.objects.filter(Q(asset_id__exact=query))
if len(query) == 0:
queryset = self.model.objects.all()
elif len(query) >= 3:
queryset = self.model.objects.filter(Q(asset_id__exact=query) | Q(description__icontains=query))
else:
queryset = self.model.objects.filter(Q(asset_id__exact=query))
cat = self.request.GET.get('cat', "")
status = self.request.GET.get('status', "")
if cat != "None":
return self.model.objects.filter(category__name__exact=cat)
elif status != "None":
return self.model.objects.filter(status__name__exact=status)
else:
return self.model.objects.all()
if cat != "":
queryset = queryset.filter(category__name__exact=cat)
if status != "":
queryset = queryset.filter(status__name__exact=status)
return queryset
def get_context_data(self, **kwargs):
context = super(AssetList, self).get_context_data(**kwargs)
context["search_name"] = self.request.GET.get('query', "")
context["categories"] = models.AssetCategory.objects.all()
context["category_select"] = self.request.GET.get('cat', "")
context["statuses"] = models.AssetStatus.objects.all()
return context;
context["status_select"] = self.request.GET.get('status', "")
return context
class AssetSearch(AssetList):
def render_to_response(self, context, **response_kwargs):
result = []
for asset in context["object_list"]:
result.append({"id": asset.pk, "label": (asset.asset_id + " | " + asset.description)})
return JsonResponse(result, safe=False)
class AssetDetail(LoginRequiredMixin, generic.DetailView):
model = models.Asset
template_name = 'asset_update.html'
# class AssetCreate(LoginRequiredMixin, generic.TemplateView):
# fields = '__all__'
# template_name = 'asset_update.html'
# # success_url = reverse_lazy('asset_list')
class AssetEdit(LoginRequiredMixin, generic.TemplateView):
class AssetEdit(LoginRequiredMixin, generic.UpdateView):
template_name = 'asset_update.html'
model = models.Asset
form_class = forms.AssetForm
def get_context_data(self, **kwargs):
context = super(AssetEdit, self).get_context_data(**kwargs)
if self.kwargs:
context['object'] = get_object_or_404(models.Asset, pk=self.kwargs['pk'])
context['form'] = forms.AssetForm
# context['asset_names'] = models.Asset.objects.values_list('asset_id', 'description').order_by('-date_acquired')[]
if self.request.GET.get('duplicate'):
context['duplicate'] = True
context['previous_asset_id'] = context['object'].asset_id
context['previous_asset_pk'] = context['object'].pk
context['object'].pk = 0
context['object'].asset_id = ''
context['object'].serial_number = ''
else:
context = super().get_context_data(**kwargs)
context['edit'] = True
context["connectors"] = models.Connector.objects.all()
return context
@login_required()
def asset_update(request):
context = dict()
def get_success_url(self):
return reverse("asset_detail", kwargs={"pk": self.object.id})
if request.method == 'POST' and request.is_ajax():
defaults = QueryDict(request.POST['form'].encode('ASCII')).dict()
defaults.pop('csrfmiddlewaretoken')
asset_pk = int(defaults.pop('id'))
class AssetCreate(LoginRequiredMixin, generic.CreateView):
template_name = 'asset_create.html'
model = models.Asset
form_class = forms.AssetForm
if defaults['date_acquired']:
defaults['date_acquired'] = parser.parse(defaults.pop('date_acquired'))
else:
defaults['date_acquired'] = None
def get_context_data(self, **kwargs):
context = super(AssetCreate, self).get_context_data(**kwargs)
if defaults['date_sold']:
defaults['date_sold'] = parser.parse(defaults.pop('date_sold'))
else:
defaults['date_sold'] = None
context["create"] = True
context["connectors"] = models.Connector.objects.all()
# if defaults['parent']:
# defaults['parent'] = models.Asset.objects.get(asset_id=defaults.pop('parent'))
return context
form = forms.AssetForm(defaults)
context['valid'] = form.is_valid()
context['errors'] = form.errors.as_json()
def get_success_url(self):
return reverse("asset_detail", kwargs={"pk": self.object.id})
if asset_pk == 0:
asset = models.Asset.objects.create(**form.cleaned_data)
else:
asset, created = models.Asset.objects.update_or_create(pk=asset_pk, defaults=form.cleaned_data)
context['url'] = reverse('asset_detail', args=[asset.pk])
class DuplicateMixin:
def get(self, request, *args, **kwargs):
self.object = self.get_object()
self.object.pk = None
return self.render_to_response(self.get_context_data())
return HttpResponse(json.dumps(context), content_type='application/json')
class AssetDuplicate(DuplicateMixin, AssetCreate):
model = models.Asset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["create"] = None
context["duplicate"] = True
context['previous_asset_id'] = self.get_object().asset_id
context["previous_asset_pk"] = self.kwargs.get(self.pk_url_kwarg)
return context
@login_required()
@@ -123,6 +129,7 @@ def asset_delete(request):
return HttpResponse(json.dumps(context), content_type='application/json')
class SupplierList(generic.ListView):
model = models.Supplier
template_name = 'supplier_list.html'