From 1f6cbd74080f4af04ac38e439606f1aab37fc341 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 29 Sep 2020 23:11:37 +1000 Subject: [PATCH 01/11] Add action to uninstall a particular stock item --- .../stock/templates/stock/item_base.html | 26 +++++++++++++++++-- .../stock/templates/stock/item_installed.html | 2 +- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html index 18888e00c8..d62c3b29d2 100644 --- a/InvenTree/stock/templates/stock/item_base.html +++ b/InvenTree/stock/templates/stock/item_base.html @@ -107,6 +107,11 @@ InvenTree | {% trans "Stock Item" %} - {{ item }} {% if item.customer %}
  • {% trans "Return to stock" %}
  • {% endif %} + {% if item.belongs_to %} +
  • + {% trans "Uninstall" %} +
  • + {% endif %} @@ -165,8 +170,12 @@ InvenTree | {% trans "Stock Item" %} - {{ item }} {% if item.belongs_to %} - {% trans "Belongs To" %} - {{ item.belongs_to }} + + {% trans "Installed In" %} + + + {{ item.belongs_to }} + {% elif item.sales_order %} @@ -301,6 +310,19 @@ $("#stock-serialize").click(function() { ); }); +$('#stock-uninstall').click(function() { + + launchModalForm( + "{% url 'stock-item-uninstall' %}", + { + data: { + 'items[]': [{{ item.pk}}], + }, + reload: true, + } + ); +}); + $("#stock-test-report").click(function() { launchModalForm( "{% url 'stock-item-test-report-select' item.id %}", diff --git a/InvenTree/stock/templates/stock/item_installed.html b/InvenTree/stock/templates/stock/item_installed.html index 2d8a8142cf..cac55c9dce 100644 --- a/InvenTree/stock/templates/stock/item_installed.html +++ b/InvenTree/stock/templates/stock/item_installed.html @@ -128,7 +128,7 @@ $('#installed-table').inventreeTable({ var html = `
    `; - html += makeIconButton('fa-trash-alt icon-red', 'button-uninstall', pk, '{% trans "Uninstall item" %}'); + html += makeIconButton('fa-unlink', 'button-uninstall', pk, '{% trans "Uninstall item" %}'); html += `
    `; From 0e5f10c0200f5ac182d368d477574700f5964dc1 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 29 Sep 2020 23:41:50 +1000 Subject: [PATCH 02/11] Add some more search terms to the admin interface --- InvenTree/build/admin.py | 6 ++++++ InvenTree/company/admin.py | 12 ++++++++++++ InvenTree/order/admin.py | 12 ++++++++++++ InvenTree/stock/admin.py | 7 +++++++ 4 files changed, 37 insertions(+) diff --git a/InvenTree/build/admin.py b/InvenTree/build/admin.py index 0ef5ccb75b..b47d38e36d 100644 --- a/InvenTree/build/admin.py +++ b/InvenTree/build/admin.py @@ -20,6 +20,12 @@ class BuildAdmin(ImportExportModelAdmin): 'notes', ) + search_fields = [ + 'title', + 'part__name', + 'part__description', + ] + class BuildItemAdmin(admin.ModelAdmin): diff --git a/InvenTree/company/admin.py b/InvenTree/company/admin.py index f69bfec54f..4a802c6a41 100644 --- a/InvenTree/company/admin.py +++ b/InvenTree/company/admin.py @@ -32,6 +32,11 @@ class CompanyAdmin(ImportExportModelAdmin): list_display = ('name', 'website', 'contact') + search_fields = [ + 'name', + 'description', + ] + class SupplierPartResource(ModelResource): """ Class for managing SupplierPart data import/export """ @@ -57,6 +62,13 @@ class SupplierPartAdmin(ImportExportModelAdmin): list_display = ('part', 'supplier', 'SKU') + search_fields = [ + 'company__name', + 'part__name', + 'MPN', + 'SKU', + ] + class SupplierPriceBreakResource(ModelResource): """ Class for managing SupplierPriceBreak data import/export """ diff --git a/InvenTree/order/admin.py b/InvenTree/order/admin.py index b7ac71976c..4519f8a2a9 100644 --- a/InvenTree/order/admin.py +++ b/InvenTree/order/admin.py @@ -23,6 +23,12 @@ class PurchaseOrderAdmin(ImportExportModelAdmin): 'creation_date' ) + search_fields = [ + 'reference', + 'supplier__name', + 'description', + ] + class SalesOrderAdmin(ImportExportModelAdmin): @@ -34,6 +40,12 @@ class SalesOrderAdmin(ImportExportModelAdmin): 'creation_date', ) + search_fields = [ + 'reference', + 'customer__name', + 'description', + ] + class POLineItemResource(ModelResource): """ Class for managing import / export of POLineItem data """ diff --git a/InvenTree/stock/admin.py b/InvenTree/stock/admin.py index d3f0c31f8b..924a8de4c7 100644 --- a/InvenTree/stock/admin.py +++ b/InvenTree/stock/admin.py @@ -117,6 +117,13 @@ class StockItemAdmin(ImportExportModelAdmin): list_display = ('part', 'quantity', 'location', 'status', 'updated') + # A list of search fields which can be used for lookup on matching 'autocomplete' fields + search_fields = [ + 'part__name', + 'part__description', + 'serial', + 'batch', + ] class StockAttachmentAdmin(admin.ModelAdmin): From d1cce7df94542320a28904f2cff9fd00fc52db84 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 30 Sep 2020 00:02:10 +1000 Subject: [PATCH 03/11] Add direct admin links if the user is staff --- InvenTree/build/templates/build/build_base.html | 7 ++++++- InvenTree/company/templates/company/company_base.html | 7 ++++++- InvenTree/part/templates/part/category.html | 7 ++++++- InvenTree/part/templates/part/part_base.html | 3 +++ InvenTree/stock/templates/stock/item_base.html | 7 +++++-- InvenTree/stock/templates/stock/location.html | 7 ++++++- 6 files changed, 32 insertions(+), 6 deletions(-) diff --git a/InvenTree/build/templates/build/build_base.html b/InvenTree/build/templates/build/build_base.html index fb84b467cf..d9764d6e25 100644 --- a/InvenTree/build/templates/build/build_base.html +++ b/InvenTree/build/templates/build/build_base.html @@ -33,7 +33,12 @@ src="{% static 'img/blank_image.png' %}" {% block page_data %}

    {% trans "Build" %} {% build_status_label build.status large=True %}


    -

    {{ build.quantity }} x {{ build.part.full_name }}

    +

    + {{ build.quantity }} x {{ build.part.full_name }} + {% if user.is_staff %} + +{% endif %} +

    - {% if read_only %} - {% else %} - -
    - - +
    + + {% if read_only %} + {% else %} + + + {% endif %}
    - {% endif %}
    From 56660d52f282437de12c4007cd7b8f004dc9e9cf Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 1 Oct 2020 00:09:21 +1000 Subject: [PATCH 10/11] Add "permission denied" message on modal forms --- .../InvenTree/static/script/inventree/modals.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/InvenTree/InvenTree/static/script/inventree/modals.js b/InvenTree/InvenTree/static/script/inventree/modals.js index 1cb5346a68..80ada1596f 100644 --- a/InvenTree/InvenTree/static/script/inventree/modals.js +++ b/InvenTree/InvenTree/static/script/inventree/modals.js @@ -807,7 +807,19 @@ function launchModalForm(url, options = {}) { } }, error: function (xhr, ajaxOptions, thrownError) { + $(modal).modal('hide'); + + // Permission denied! + if (xhr.status == 403) { + showAlertDialog( + "Permission Denied", + "You do not have the required permissions to access this function" + ); + + return; + } + showAlertDialog('Error requesting form data', renderErrorMessage(xhr)); } }; From 626d0266c8c171c64fe59557ed28480607b62e7c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 1 Oct 2020 00:16:04 +1000 Subject: [PATCH 11/11] Add framework for required permissions for any ajax modal forms - Default permissions of "*" will not immediately change any modal forms - Set the permission_required attribute of any modal form for this to be implemented --- InvenTree/InvenTree/views.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/views.py b/InvenTree/InvenTree/views.py index 3f9bc5b0a9..d940229ebe 100644 --- a/InvenTree/InvenTree/views.py +++ b/InvenTree/InvenTree/views.py @@ -13,6 +13,8 @@ from django.template.loader import render_to_string from django.http import JsonResponse, HttpResponseRedirect from django.urls import reverse_lazy +from django.contrib.auth.mixins import PermissionRequiredMixin + from django.views import View from django.views.generic import UpdateView, CreateView, FormView from django.views.generic.base import TemplateView @@ -105,12 +107,32 @@ class TreeSerializer(views.APIView): return JsonResponse(response, safe=False) -class AjaxMixin(object): +class AjaxMixin(PermissionRequiredMixin): """ AjaxMixin provides basic functionality for rendering a Django form to JSON. Handles jsonResponse rendering, and adds extra data for the modal forms to process on the client side. + + Any view which inherits the AjaxMixin will need + correct permissions set using the 'permission_required' attribute + """ + # By default, allow *any* permissions + permission_required = '*' + + def has_permission(self): + """ + Override the default behaviour of has_permission from PermissionRequiredMixin. + + Basically, if permission_required attribute = '*', + no permissions are actually required! + """ + + if self.permission_required == '*': + return True + else: + return super().has_permission() + # By default, point to the modal_form template # (this can be overridden by a child class) ajax_template_name = 'modal_form.html'