mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-01-17 05:22:16 +00:00
WIP: Basic work on audit
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<div class="modal fade" id="itemModal" role="dialog" aria-labelledby="itemModal" aria-hidded="true">
|
||||
<div class="modal fade" id="itemModal" role="dialog" aria-labelledby="itemModal" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
@@ -71,4 +71,4 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@ class AssetForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = models.Asset
|
||||
fields = '__all__'
|
||||
exclude = ['asset_id_prefix', 'asset_id_number']
|
||||
exclude = ['asset_id_prefix', 'asset_id_number', 'last_audited_at', 'last_audited_by']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
26
assets/migrations/0011_auto_20200208_2304.py
Normal file
26
assets/migrations/0011_auto_20200208_2304.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# Generated by Django 2.0.13 on 2020-02-08 23:04
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('assets', '0010_auto_20200207_1737'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='last_audited_at',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='asset',
|
||||
name='last_audited_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='audited_by', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
@@ -9,7 +9,7 @@ from django.dispatch.dispatcher import receiver
|
||||
from reversion import revisions as reversion
|
||||
from reversion.models import Version
|
||||
|
||||
from RIGS.models import RevisionMixin
|
||||
from RIGS.models import RevisionMixin, Profile
|
||||
|
||||
|
||||
class AssetCategory(models.Model):
|
||||
@@ -88,8 +88,13 @@ class Asset(models.Model, RevisionMixin):
|
||||
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)
|
||||
# TODO Remove
|
||||
next_sched_maint = models.DateField(blank=True, null=True)
|
||||
|
||||
# Audit
|
||||
last_audited_at = models.DateTimeField(blank=True, null=True)
|
||||
last_audited_by = models.ForeignKey(Profile, on_delete=models.SET_NULL, related_name='audited_by', blank=True, null=True)
|
||||
|
||||
# Cable assets
|
||||
is_cable = models.BooleanField(default=False)
|
||||
plug = models.ForeignKey(Connector, on_delete=models.SET_NULL,
|
||||
|
||||
82
assets/templates/asset_audit.html
Normal file
82
assets/templates/asset_audit.html
Normal file
@@ -0,0 +1,82 @@
|
||||
{% extends 'base_assets.html' %}
|
||||
{% load widget_tweaks %}
|
||||
{% block title %}Audit Asset {{ object.asset_id }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1>
|
||||
Audit Asset: {{ object.asset_id }}
|
||||
</h1>
|
||||
</div>
|
||||
<form class="form-horizontal" method="post" id="asset_update_form" action="{% url 'asset_audit' pk=object.asset_id%}">
|
||||
{% include 'form_errors.html' %}
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="id" value="{{ object.id|default:0 }}" hidden=true>
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="{{ form.asset_id.id_for_label }}" class="col-sm-2 control-label">Asset ID</label>
|
||||
<div class="col-sm-10">
|
||||
{% render_field form.asset_id|add_class:'form-control' value=object.asset_id %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.description.id_for_label }}" class="col-sm-2 control-label">Description</label>
|
||||
<div class="col-sm-10">
|
||||
{% render_field form.description|add_class:'form-control' value=object.description %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.category.id_for_label }}" class="col-sm-2 control-label">Category</label>
|
||||
<div class="col-sm-10">
|
||||
{% render_field form.category|add_class:'form-control'%}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.status.id_for_label }}" class="col-sm-2 control-label">Status</label>
|
||||
<div class="col-sm-10">
|
||||
{% render_field form.status|add_class:'form-control'%}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.serial_number.id_for_label }}" class="col-sm-2 control-label">Serial Number</label>
|
||||
<div class="col-sm-10">
|
||||
{% render_field form.serial_number|add_class:'form-control' value=object.serial_number %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.date_acquired.id_for_label }}" class="col-sm-2 control-label">Date Acquired</label>
|
||||
<div class="col-sm-10">
|
||||
{% render_field form.date_acquired|add_class:'form-control' value=object.date_acquired %}
|
||||
</div>
|
||||
<!--- TODO Add buttons for 'today' and 'unknown' (sets to beginning of time)--->
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.is_cable.id_for_label }}" class="col-sm-2 control-label">Cable?</label>
|
||||
<div class="col-sm-10">
|
||||
{% render_field form.is_cable|attr:'onchange=checkIfCableHidden()' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-10 pull-right">
|
||||
<button type="submit" class="btn btn-success"><i class="glyphicon glyphicon-floppy-disk"></i> Audit</button>
|
||||
<br>
|
||||
<button type="reset" class="btn btn-link" onclick="history.back()">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% 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 %}
|
||||
@@ -9,26 +9,7 @@
|
||||
<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 id="category-group" 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 id="status-group" 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 id="filter-submit" type="submit" class="btn btn-default">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
{% include 'partials/asset_search.html' %}
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
|
||||
@@ -35,6 +35,11 @@
|
||||
<div class="col-md-4">
|
||||
{% include 'partials/parent_form.html' %}
|
||||
</div>
|
||||
{% if not edit %}
|
||||
<div class="col-md-4">
|
||||
{% include 'partials/audit_details.html' %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
||||
28
assets/templates/partials/asset_search.html
Normal file
28
assets/templates/partials/asset_search.html
Normal file
@@ -0,0 +1,28 @@
|
||||
{% extends request.is_ajax|yesno:'base_ajax.html,base_assets.html' %}
|
||||
|
||||
{% load widget_tweaks %}
|
||||
|
||||
{% block title %}Asset Search{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<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 id="category-group" 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 id="status-group" 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 id="filter-submit" type="submit" class="btn btn-default">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
8
assets/templates/partials/audit_details.html
Normal file
8
assets/templates/partials/audit_details.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<div class="panel {% if object.last_audited_at is not None %} panel-success {% else %} panel-default {% endif %}">
|
||||
<div class="panel-heading">
|
||||
Audit Details
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>Audited at <span class="label label-default">{{ object.last_audited_at|default_if_none:'-' }}</span> by <span class="label label-info">{{ object.last_audited_by|default_if_none:'-' }}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -31,6 +31,9 @@ urlpatterns = [
|
||||
views.AssetOembed.as_view(),
|
||||
name='asset_oembed'),
|
||||
|
||||
path('asset/audit/', permission_required_with_403('assets.view_asset')(views.AssetAuditList.as_view()), name='asset_audit_list'),
|
||||
path('asset/id/<str:pk>/audit/', permission_required_with_403('assets.view_asset')(views.AssetAudit.as_view()), name='asset_audit'),
|
||||
|
||||
path('supplier/list', views.SupplierList.as_view(), name='supplier_list'),
|
||||
path('supplier/<int:pk>', views.SupplierDetail.as_view(), name='supplier_detail'),
|
||||
path('supplier/create', permission_required_with_403('assets.add_supplier')
|
||||
|
||||
@@ -11,6 +11,7 @@ from assets import models, forms
|
||||
from RIGS import versioning
|
||||
|
||||
import simplejson
|
||||
import datetime
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name='dispatch')
|
||||
@@ -173,6 +174,34 @@ class AssetEmbed(AssetDetail):
|
||||
template_name = 'asset_embed.html'
|
||||
|
||||
|
||||
class AssetAuditList(LoginRequiredMixin, generic.ListView):
|
||||
model = models.Asset
|
||||
template_name = 'asset_list.html'
|
||||
paginate_by = 40
|
||||
ordering = ['-pk']
|
||||
|
||||
|
||||
class AssetAudit(LoginRequiredMixin, AssetIDUrlMixin, generic.UpdateView):
|
||||
template_name = 'asset_audit.html'
|
||||
model = models.Asset
|
||||
form_class = forms.AssetForm
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['edit'] = True
|
||||
context['connectors'] = models.Connector.objects.all()
|
||||
|
||||
return context
|
||||
|
||||
def get_success_url(self):
|
||||
# TODO For some reason this doesn't stick when done in form_valid??
|
||||
asset = self.get_object()
|
||||
asset.last_audited_by = self.request.user
|
||||
asset.last_audited_at = datetime.datetime.now()
|
||||
asset.save()
|
||||
return reverse("asset_audit_list")
|
||||
|
||||
|
||||
class SupplierList(generic.ListView):
|
||||
model = models.Supplier
|
||||
template_name = 'supplier_list.html'
|
||||
|
||||
@@ -35,5 +35,6 @@
|
||||
{# % endif % #}
|
||||
{% if perms.assets.view_asset %}
|
||||
<li><a href="{% url 'asset_activity_table' %}">Recent Changes</a></li>
|
||||
<li><a href="{% url 'asset_audit_list' %}">Audit</a></li>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user