diff --git a/InvenTree/InvenTree/static/script/inventree/inventree.js b/InvenTree/InvenTree/static/script/inventree/inventree.js index 703c49218b..90dbacbe35 100644 --- a/InvenTree/InvenTree/static/script/inventree/inventree.js +++ b/InvenTree/InvenTree/static/script/inventree/inventree.js @@ -136,4 +136,53 @@ function imageHoverIcon(url) { `; return html; +} + +function inventreeSave(name, value) { + /* + * Save a key:value pair to local storage + */ + + var key = "inventree-" + name; + localStorage.setItem(key, value); +} + +function inventreeLoad(name, defaultValue) { + /* + * Retrieve a key:value pair from local storage + */ + + var key = "inventree-" + name; + + var value = localStorage.getItem(key); + + if (value == null) { + return defaultValue; + } else { + return value; + } +} + +function inventreeLoadInt(name) { + /* + * Retrieve a value from local storage, and attempt to cast to integer + */ + + var data = inventreeLoad(name); + + return parseInt(data, 10); +} + +function inventreeLoadFloat(name) { + + var data = inventreeLoad(name); + + return parseFloat(data); +} + +function inventreeDel(name) { + + var key = 'inventree-' + name; + + localStorage.removeItem(key); } \ No newline at end of file diff --git a/InvenTree/InvenTree/static/script/inventree/part.js b/InvenTree/InvenTree/static/script/inventree/part.js index 1056a7706b..0904c22a0d 100644 --- a/InvenTree/InvenTree/static/script/inventree/part.js +++ b/InvenTree/InvenTree/static/script/inventree/part.js @@ -191,15 +191,10 @@ function loadPartTable(table, url, options={}) { } }); - $(table).bootstrapTable({ + $(table).inventreeTable({ url: url, - sortable: true, - search: true, sortName: 'name', method: 'get', - pagination: true, - pageSize: 25, - rememberOrder: true, formatNoMatches: function() { return "No parts found"; }, queryParams: function(p) { return query; diff --git a/InvenTree/InvenTree/static/script/inventree/stock.js b/InvenTree/InvenTree/static/script/inventree/stock.js index ae07be1dd3..e4582e879e 100644 --- a/InvenTree/InvenTree/static/script/inventree/stock.js +++ b/InvenTree/InvenTree/static/script/inventree/stock.js @@ -42,13 +42,10 @@ function loadStockTable(table, options) { var params = options.params || {}; - table.bootstrapTable({ - sortable: true, - search: true, + console.log('load stock table'); + + table.inventreeTable({ method: 'get', - pagination: true, - pageSize: 25, - rememberOrder: true, formatNoMatches: function() { return 'No stock items matching query'; }, @@ -386,15 +383,10 @@ function loadStockTrackingTable(table, options) { } }); - table.bootstrapTable({ - sortable: true, - search: true, + table.inventreeTable({ method: 'get', - rememberOrder: true, queryParams: options.params, columns: cols, - pagination: true, - pageSize: 50, url: options.url, }); diff --git a/InvenTree/InvenTree/static/script/inventree/tables.js b/InvenTree/InvenTree/static/script/inventree/tables.js index 59bc446d5e..3b2279e18e 100644 --- a/InvenTree/InvenTree/static/script/inventree/tables.js +++ b/InvenTree/InvenTree/static/script/inventree/tables.js @@ -44,6 +44,31 @@ function isNumeric(n) { } +/* Wrapper function for bootstrapTable. + * Sets some useful defaults, and manage persistent settings. + */ +$.fn.inventreeTable = function(options) { + + var tableName = options.name || 'table'; + + var varName = tableName + '-pagesize'; + + options.pagination = true; + options.pageSize = inventreeLoad(varName, 25); + options.pageList = [25, 50, 100, 250, 'all']; + options.rememberOrder = true; + options.sortable = true; + options.search = true; + + // Callback to save pagination data + options.onPageChange = function(number, size) { + inventreeSave(varName, size); + }; + + // Standard options for all tables + this.bootstrapTable(options); +} + function customGroupSorter(sortName, sortOrder, sortData) { console.log('got here'); diff --git a/InvenTree/build/templates/build/allocate.html b/InvenTree/build/templates/build/allocate.html index 3471b1283a..3e67c65145 100644 --- a/InvenTree/build/templates/build/allocate.html +++ b/InvenTree/build/templates/build/allocate.html @@ -62,9 +62,7 @@ InvenTree | Allocate Parts {% else %} - $("#build-list").bootstrapTable({ - search: true, - sortable: true, + $("#build-list").inventreeTable({ }); $("#btn-allocate").click(function() { diff --git a/InvenTree/build/templates/build/index.html b/InvenTree/build/templates/build/index.html index 3c9eda3544..fb75d0586a 100644 --- a/InvenTree/build/templates/build/index.html +++ b/InvenTree/build/templates/build/index.html @@ -44,9 +44,7 @@ InvenTree | Build List }); }); - $(".build-table").bootstrapTable({ - sortable: true, - search: true, + $(".build-table").inventreeTable({ formatNoMatches: function() { return 'No builds found'; }, columns: [ { diff --git a/InvenTree/company/templates/company/detail_part.html b/InvenTree/company/templates/company/detail_part.html index 2cc100390b..16d564a9db 100644 --- a/InvenTree/company/templates/company/detail_part.html +++ b/InvenTree/company/templates/company/detail_part.html @@ -45,11 +45,7 @@ }); }); - $("#part-table").bootstrapTable({ - sortable: true, - search: true, - pagination: true, - pageSize: 50, + $("#part-table").inventreeTable({ formatNoMatches: function() { return "No supplier parts found for {{ company.name }}"; }, queryParams: function(p) { return { diff --git a/InvenTree/company/templates/company/detail_purchase_orders.html b/InvenTree/company/templates/company/detail_purchase_orders.html index 077a107848..8c299cbd4e 100644 --- a/InvenTree/company/templates/company/detail_purchase_orders.html +++ b/InvenTree/company/templates/company/detail_purchase_orders.html @@ -42,9 +42,7 @@ newOrder(); }); - $("#po-table").bootstrapTable({ - search: true, - sortable: true, + $(".po-table").inventreeTable({ }); {% endblock %} diff --git a/InvenTree/company/templates/company/index.html b/InvenTree/company/templates/company/index.html index 17b737b670..711ed8eb37 100644 --- a/InvenTree/company/templates/company/index.html +++ b/InvenTree/company/templates/company/index.html @@ -32,11 +32,7 @@ InvenTree | Supplier List }); }); - $("#company-table").bootstrapTable({ - sortable: true, - search: true, - pagination: true, - pageSize: 50, + $("#company-table").inventreeTable({ formatNoMatches: function() { return "No company information found"; }, columns: [ { diff --git a/InvenTree/order/forms.py b/InvenTree/order/forms.py index c7942e3549..4844ef4344 100644 --- a/InvenTree/order/forms.py +++ b/InvenTree/order/forms.py @@ -6,6 +6,7 @@ Django Forms for interacting with Order objects from __future__ import unicode_literals from django import forms +from django.utils.translation import ugettext as _ from InvenTree.forms import HelperForm @@ -14,7 +15,7 @@ from .models import PurchaseOrder, PurchaseOrderLineItem class IssuePurchaseOrderForm(HelperForm): - confirm = forms.BooleanField(required=False, help_text='Place order') + confirm = forms.BooleanField(required=False, help_text=_('Place order')) class Meta: model = PurchaseOrder @@ -23,6 +24,17 @@ class IssuePurchaseOrderForm(HelperForm): ] +class CancelPurchaseOrderForm(HelperForm): + + confirm = forms.BooleanField(required=False, help_text=_('Cancel order')) + + class Meta: + model = PurchaseOrder + fields = [ + 'confirm', + ] + + class EditPurchaseOrderForm(HelperForm): """ Form for editing a PurchaseOrder object """ diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index 9eff4d11c3..de0ac86bad 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -98,6 +98,13 @@ class Order(models.Model): self.complete_date = datetime.now().date() self.save() + def cancel_order(self): + """ Marks the order as CANCELLED. """ + + if self.status in [OrderStatus.PLACED, OrderStatus.PENDING]: + self.status = OrderStatus.CANCELLED + self.save() + class PurchaseOrder(Order): """ A PurchaseOrder represents goods shipped inwards from an external supplier. diff --git a/InvenTree/order/templates/order/order_cancel.html b/InvenTree/order/templates/order/order_cancel.html new file mode 100644 index 0000000000..3c71028b06 --- /dev/null +++ b/InvenTree/order/templates/order/order_cancel.html @@ -0,0 +1,7 @@ +{% extends "modal_form.html" %} + +{% block pre_form_content %} + +Cancelling this order means that the order will no longer be editable. + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/po_table.html b/InvenTree/order/templates/order/po_table.html index 16fa462951..0fe41e8efa 100644 --- a/InvenTree/order/templates/order/po_table.html +++ b/InvenTree/order/templates/order/po_table.html @@ -1,4 +1,4 @@ - +
diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html index 2ddbdc3052..83bd526a96 100644 --- a/InvenTree/order/templates/order/purchase_order_detail.html +++ b/InvenTree/order/templates/order/purchase_order_detail.html @@ -43,6 +43,11 @@ InvenTree | {{ order }} {% endif %} + {% if order.status == OrderStatus.PENDING or order.status == OrderStatus.PLACED %} + + {% endif %}

@@ -176,6 +181,12 @@ $("#edit-order").click(function() { ); }); +$("#cancel-order").click(function() { + launchModalForm("{% url 'purchase-order-cancel' order.id %}", { + reload: true, + }); +}); + $("#receive-order").click(function() { launchModalForm("{% url 'purchase-order-receive' order.id %}", { reload: true, @@ -210,9 +221,7 @@ $('#new-po-line').click(function() { }); {% endif %} -$("#po-lines-table").bootstrapTable({ - search: true, - sortable: true, +$("#po-lines-table").inventreeTable({ }); diff --git a/InvenTree/order/templates/order/purchase_orders.html b/InvenTree/order/templates/order/purchase_orders.html index 0e93c6d900..6e6e45cdfd 100644 --- a/InvenTree/order/templates/order/purchase_orders.html +++ b/InvenTree/order/templates/order/purchase_orders.html @@ -32,8 +32,7 @@ $("#po-create").click(function() { ); }); -$("#po-table").bootstrapTable({ - search: true, +$("#po-table").inventreeTable({ }); {% endblock %} \ No newline at end of file diff --git a/InvenTree/order/urls.py b/InvenTree/order/urls.py index 38687342c2..994e6b054d 100644 --- a/InvenTree/order/urls.py +++ b/InvenTree/order/urls.py @@ -11,6 +11,7 @@ from . import views purchase_order_detail_urls = [ + url(r'^cancel/?', views.PurchaseOrderCancel.as_view(), name='purchase-order-cancel'), url(r'^edit/?', views.PurchaseOrderEdit.as_view(), name='purchase-order-edit'), url(r'^issue/?', views.PurchaseOrderIssue.as_view(), name='purchase-order-issue'), url(r'^receive/?', views.PurchaseOrderReceive.as_view(), name='purchase-order-receive'), diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 86a231075e..49d2ed01ed 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -112,6 +112,39 @@ class PurchaseOrderEdit(AjaxUpdateView): return form +class PurchaseOrderCancel(AjaxUpdateView): + """ View for cancelling a purchase order """ + + model = PurchaseOrder + ajax_form_title = 'Cancel Order' + ajax_template_name = 'order/order_cancel.html' + form_class = order_forms.CancelPurchaseOrderForm + + def post(self, request, *args, **kwargs): + """ Mark the PO as 'CANCELLED' """ + + order = self.get_object() + form = self.get_form() + + confirm = str2bool(request.POST.get('confirm', False)) + + valid = False + + if not confirm: + form.errors['confirm'] = [_('Confirm order cancellation')] + else: + valid = True + + data = { + 'form_valid': valid + } + + if valid: + order.cancel_order() + + return self.renderJsonResponse(request, form, data) + + class PurchaseOrderIssue(AjaxUpdateView): """ View for changing a purchase order from 'PENDING' to 'ISSUED' """ diff --git a/InvenTree/part/templates/part/allocation.html b/InvenTree/part/templates/part/allocation.html index 807251a0d1..21c3413ea0 100644 --- a/InvenTree/part/templates/part/allocation.html +++ b/InvenTree/part/templates/part/allocation.html @@ -29,9 +29,7 @@ {% block js_ready %} - $("#build-table").bootstrapTable({ - search: true, - sortable: true, + $("#build-table").inventreeTable({ columns: [ { title: 'Build', diff --git a/InvenTree/part/templates/part/attachments.html b/InvenTree/part/templates/part/attachments.html index c31db94c3e..1f35535fcd 100644 --- a/InvenTree/part/templates/part/attachments.html +++ b/InvenTree/part/templates/part/attachments.html @@ -89,9 +89,7 @@ }); }); - $("#attachment-table").bootstrapTable({ - search: true, - sortable: true, + $("#attachment-table").inventreeTable({ }); {% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/build.html b/InvenTree/part/templates/part/build.html index 958a057409..6f44aded08 100644 --- a/InvenTree/part/templates/part/build.html +++ b/InvenTree/part/templates/part/build.html @@ -31,11 +31,7 @@ }); }); - $("#build-table").bootstrapTable({ - sortable: true, - search: true, - pagination: true, - pageSize: 50, + $("#build-table").inventreeTable({ queryParams: function(p) { return { part: {{ part.id }}, diff --git a/InvenTree/part/templates/part/category.html b/InvenTree/part/templates/part/category.html index d9913482fd..f6c49b2094 100644 --- a/InvenTree/part/templates/part/category.html +++ b/InvenTree/part/templates/part/category.html @@ -8,9 +8,6 @@ {% if category %}

{{ category.name }}

{{ category.description }}

- {% if category.default_location %} -

Default Location: {{ category.default_location }}

- {% endif %} {% else %}

Part Categories

All parts

@@ -32,6 +29,39 @@

+ {% if category %} +

Category Details

+
Company
+ + + + + + + + + {% if category.default_location %} + + + + + {% endif %} + {% if category.default_keywords %} + + + + + {% endif %} + + + + + + + + +
Category Path{{ category.pathstring }}
Category Description{{ category.description }}
Default Location{{ category.default_location.pathstring }}
Keywords{{ category.default_keywords }}
Subcategories{{ category.children.count }}
Parts (Including subcategories){{ category.partcount }}
+ {% endif %} @@ -67,16 +97,16 @@ {% block js_ready %} {{ block.super }} - if (sessionStorage.getItem("inventree-show-part-categories")) { + if (inventreeLoadInt("show-part-cats") == 1) { $("#collapse-item-categories").collapse('show'); } $("#collapse-item-categories").on('shown.bs.collapse', function() { - sessionStorage.setItem('inventree-show-part-categories', 1); + inventreeSave('show-part-cats', 1); }); $("#collapse-item-categories").on('hidden.bs.collapse', function() { - sessionStorage.removeItem('inventree-show-part-categories'); + inventreeDel('show-part-cats'); }); $("#cat-create").click(function() { diff --git a/InvenTree/part/templates/part/orders.html b/InvenTree/part/templates/part/orders.html index d3488bea2d..b3f84735f3 100644 --- a/InvenTree/part/templates/part/orders.html +++ b/InvenTree/part/templates/part/orders.html @@ -26,9 +26,7 @@ {% block js_ready %} {{ block.super }} -$("#po-table").bootstrapTable({ - search: true, - sortable: true, +$("#po-table").inventreeTable({ }); $("#part-order2").click(function() { diff --git a/InvenTree/part/templates/part/params.html b/InvenTree/part/templates/part/params.html index 1ccb9d4da6..f1d575d2b7 100644 --- a/InvenTree/part/templates/part/params.html +++ b/InvenTree/part/templates/part/params.html @@ -44,9 +44,7 @@ {% block js_ready %} {{ block.super }} - $('#param-table').bootstrapTable({ - search: true, - sortable: true, + $('#param-table').inventreeTable({ }); $('#param-create').click(function() { diff --git a/InvenTree/part/templates/part/subcategories.html b/InvenTree/part/templates/part/subcategories.html index abf61d743e..c503d5504c 100644 --- a/InvenTree/part/templates/part/subcategories.html +++ b/InvenTree/part/templates/part/subcategories.html @@ -12,7 +12,9 @@ {% if child.description %} - {{ child.description }} {% endif %} - {{ child.partcount }} + {% if child.partcount > 0 %} + {{ child.partcount }} Part{% if child.partcount > 1 %}s{% endif %} + {% endif %} {% endfor %} diff --git a/InvenTree/part/templates/part/supplier.html b/InvenTree/part/templates/part/supplier.html index 35593f3fdc..8d21f6417c 100644 --- a/InvenTree/part/templates/part/supplier.html +++ b/InvenTree/part/templates/part/supplier.html @@ -50,9 +50,7 @@ }); }); - $("#supplier-table").bootstrapTable({ - sortable: true, - search: true, + $("#supplier-table").inventreeTable({ formatNoMatches: function() { return "No supplier parts available for {{ part.full_name }}"; }, queryParams: function(p) { return { diff --git a/InvenTree/part/templates/part/used_in.html b/InvenTree/part/templates/part/used_in.html index 665d7ed58f..872288723e 100644 --- a/InvenTree/part/templates/part/used_in.html +++ b/InvenTree/part/templates/part/used_in.html @@ -16,9 +16,7 @@ {% block js_ready %} {{ block.super }} - $("#used-table").bootstrapTable({ - sortable: true, - search: true, + $("#used-table").inventreeTable({ formatNoMatches: function() { return "{{ part.full_name }} is not used to make any other parts"; }, queryParams: function(p) { return { diff --git a/InvenTree/part/templates/part/variants.html b/InvenTree/part/templates/part/variants.html index fd55029ba5..725a7ba9b4 100644 --- a/InvenTree/part/templates/part/variants.html +++ b/InvenTree/part/templates/part/variants.html @@ -53,9 +53,7 @@ {{ block.super }} - $('#variant-table').bootstrapTable({ - search: true, - sortable: true, + $('#variant-table').inventreeTable({ }); $('#new-variant').click(function() { diff --git a/InvenTree/stock/templates/stock/location.html b/InvenTree/stock/templates/stock/location.html index 6a0d05cfcc..45743bbd5d 100644 --- a/InvenTree/stock/templates/stock/location.html +++ b/InvenTree/stock/templates/stock/location.html @@ -32,6 +32,27 @@

+ {% if location %} +

Location Details

+ + + + + + + + + + + + + + + + + +
Location Path{{ location.pathstring }}
Location Description{{ location.description }}
Sublocations{{ location.children.count }}
Stock Items{{ location.item_count }}
+ {% endif %}
@@ -55,16 +76,16 @@ {% block js_ready %} {{ block.super }} - if (sessionStorage.getItem("inventree-show-part-locations")) { + if (inventreeLoadInt("show-part-locs") == 1) { $("#collapse-item-locations").collapse('show'); } $("#collapse-item-locations").on('shown.bs.collapse', function() { - sessionStorage.setItem('inventree-show-part-locations', 1); + inventreeSave('show-part-locs', 1); }); $("#collapse-item-locations").on('hidden.bs.collapse', function() { - sessionStorage.removeItem('inventree-show-part-locations'); + inventreeDel('show-part-locs'); }); $("#stock-export").click(function() { diff --git a/InvenTree/stock/templates/stock/location_list.html b/InvenTree/stock/templates/stock/location_list.html index 9ce7a1814c..a6e1811f46 100644 --- a/InvenTree/stock/templates/stock/location_list.html +++ b/InvenTree/stock/templates/stock/location_list.html @@ -8,7 +8,9 @@ Sub-Locations{{ children|length }} diff --git a/InvenTree/templates/InvenTree/search.html b/InvenTree/templates/InvenTree/search.html index a31e4ed1a8..fef14b6712 100644 --- a/InvenTree/templates/InvenTree/search.html +++ b/InvenTree/templates/InvenTree/search.html @@ -83,7 +83,7 @@ InvenTree | Search Results onSearchResults('#supplier-part-results-table', '#supplier-part-result-count'); - $("#category-results-table").bootstrapTable({ + $("#category-results-table").inventreeTable({ url: "{% url 'api-part-category-list' %}", queryParams: { search: "{{ query }}", @@ -103,7 +103,7 @@ InvenTree | Search Results ], }); - $("#location-results-table").bootstrapTable({ + $("#location-results-table").inventreeTable({ url: "{% url 'api-location-list' %}", queryParams: { search: "{{ query }}", @@ -134,14 +134,11 @@ InvenTree | Search Results } ); - $("#company-results-table").bootstrapTable({ + $("#company-results-table").inventreeTable({ url: "{% url 'api-company-list' %}", queryParams: { search: "{{ query }}", }, - pagination: true, - pageSize: 25, - search: true, columns: [ { field: 'name', @@ -157,14 +154,11 @@ InvenTree | Search Results ] }); - $("#supplier-part-results-table").bootstrapTable({ + $("#supplier-part-results-table").inventreeTable({ url: "{% url 'api-part-supplier-list' %}", queryParams: { search: "{{ query }}", }, - pagination: true, - pageSize: 25, - search: true, columns: [ { field: 'supplier_name', diff --git a/InvenTree/templates/InvenTree/settings/currency.html b/InvenTree/templates/InvenTree/settings/currency.html index 712cd1700c..4eb9420f05 100644 --- a/InvenTree/templates/InvenTree/settings/currency.html +++ b/InvenTree/templates/InvenTree/settings/currency.html @@ -19,15 +19,11 @@ {% block js_ready %} {{ block.super }} - $("#currency-table").bootstrapTable({ + $("#currency-table").inventreeTable({ url: "{% url 'api-currency-list' %}", queryParams: { ordering: 'suffix' }, - sortable: true, - search: true, - pagination: true, - pageSize: 25, formatNoMatches: function() { return "No currencies found"; }, rowStyle: function(row, index) { if (row.base) { diff --git a/InvenTree/templates/InvenTree/settings/part.html b/InvenTree/templates/InvenTree/settings/part.html index 87535c7db1..2bbfaf2b03 100644 --- a/InvenTree/templates/InvenTree/settings/part.html +++ b/InvenTree/templates/InvenTree/settings/part.html @@ -19,15 +19,11 @@ {% block js_ready %} {{ block.super }} - $("#param-table").bootstrapTable({ + $("#param-table").inventreeTable({ url: "{% url 'api-part-param-template-list' %}", queryParams: { ordering: 'name', }, - sortable: true, - search: true, - pagination: true, - pageSize: 25, formatNoMatches: function() { return "No part parameter templates found"; }, columns: [ {