From 66e1b180e43d1877548ad73f7d4494010c437aec Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 23 Feb 2021 13:42:59 +1100 Subject: [PATCH 1/6] Add option to stock table to disable grouping at run-time --- InvenTree/templates/js/stock.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/InvenTree/templates/js/stock.js b/InvenTree/templates/js/stock.js index f1794f3664..b115b8171c 100644 --- a/InvenTree/templates/js/stock.js +++ b/InvenTree/templates/js/stock.js @@ -319,6 +319,12 @@ function loadStockTable(table, options) { } } + var grouping = true; + + if ('grouping' in options) { + grouping = options.grouping; + } + table.inventreeTable({ method: 'get', formatNoMatches: function() { @@ -333,7 +339,7 @@ function loadStockTable(table, options) { {% settings_value 'STOCK_GROUP_BY_PART' as group_by_part %} {% if group_by_part %} groupByField: options.groupByField || 'part', - groupBy: true, + groupBy: grouping, groupByFormatter: function(field, id, data) { var row = data[0]; From 949a541ee0a070abd401088e847400789c043822 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 23 Feb 2021 13:43:26 +1100 Subject: [PATCH 2/6] Add more options to StockList api - Limit query results - Order by various fields --- InvenTree/part/api.py | 2 +- InvenTree/stock/api.py | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 04a37e5fff..12bfd2de1d 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -626,7 +626,7 @@ class PartList(generics.ListCreateAPIView): queryset = queryset.filter(pk__in=parts_need_stock) - # Limit choices + # Limit number of results limit = params.get('limit', None) if limit is not None: diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 4e532b90b7..75b0d9de3b 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -808,6 +808,19 @@ class StockList(generics.ListCreateAPIView): print("After error:", str(updated_after)) pass + # Limit number of results + limit = params.get('limit', None) + + if limit is not None: + try: + limit = int(limit) + + if limit > 0: + queryset = queryset[:limit] + + except (ValueError): + pass + # Also ensure that we pre-fecth all the related items queryset = queryset.prefetch_related( 'part', @@ -815,8 +828,6 @@ class StockList(generics.ListCreateAPIView): 'location' ) - queryset = queryset.order_by('part__name') - return queryset filter_backends = [ @@ -828,6 +839,15 @@ class StockList(generics.ListCreateAPIView): filter_fields = [ ] + ordering_fields = [ + 'part__name', + 'updated', + 'stocktake_date', + 'expiry_date', + ] + + ordering = ['part__name'] + search_fields = [ 'serial', 'batch', From 571a03043ecd8e202e30b556315071c3823a8ab9 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 23 Feb 2021 13:43:41 +1100 Subject: [PATCH 3/6] Show recently updated stock items on the index page --- InvenTree/templates/InvenTree/index.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/InvenTree/templates/InvenTree/index.html b/InvenTree/templates/InvenTree/index.html index 687ceaf0ee..fc7d5344b1 100644 --- a/InvenTree/templates/InvenTree/index.html +++ b/InvenTree/templates/InvenTree/index.html @@ -125,8 +125,19 @@ loadSimplePartTable("#table-bom-validation", "{% url 'api-part-list' %}", { {% if roles.stock.view %} addHeaderTitle('{% trans "Stock" %}'); +addHeaderAction('recently-updated-stock', '{% trans "Recently Updated" %}', 'fa-clock'); addHeaderAction('low-stock', '{% trans "Low Stock" %}', 'fa-shopping-cart'); addHeaderAction('stock-to-build', '{% trans "Required for Build Orders" %}', 'fa-bullhorn'); + +loadStockTable($('#table-recently-updated-stock'), { + params: { + ordering: "-updated", + limit: 10, + }, + name: 'recently-updated-stock', + grouping: false, +}); + {% settings_value "STOCK_ENABLE_EXPIRY" as expiry %} {% if expiry %} addHeaderAction('expired-stock', '{% trans "Expired Stock" %}', 'fa-calendar-times'); From 8972a51bd62449f6a0683981db3865a9d28e7856 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 23 Feb 2021 14:12:16 +1100 Subject: [PATCH 4/6] Fixes for integer validator for inventree setting --- InvenTree/common/models.py | 62 ++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 52f38bea18..0514a081d0 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -125,6 +125,13 @@ class InvenTreeSetting(models.Model): 'validator': bool }, + 'PART_RECENT_COUNT': { + 'name': _('Recent Part Count'), + 'description': _('Number of recent parts to display on index page'), + 'default': 10, + 'validator': [int, MinValueValidator(1),] + }, + 'PART_TEMPLATE': { 'name': _('Template'), 'description': _('Parts are templates by default'), @@ -521,11 +528,18 @@ class InvenTreeSetting(models.Model): validator = InvenTreeSetting.get_setting_validator(self.key) + if self.is_bool(): + self.value = InvenTree.helpers.str2bool(self.value) + + if self.is_int(): + try: + self.value = int(self.value) + except (ValueError): + raise ValidationError(_('Must be an integer value')) + if validator is not None: self.run_validator(validator) - if self.is_bool(): - self.value = InvenTree.helpers.str2bool(self.value) def run_validator(self, validator): """ @@ -535,39 +549,39 @@ class InvenTreeSetting(models.Model): if validator is None: return - # If a list of validators is supplied, iterate through each one - if type(validator) in [list, tuple]: - for v in validator: - self.run_validator(v) - - return - - if callable(validator): - # We can accept function validators with a single argument - print("Running validator function") - validator(self.value) + value = self.value # Boolean validator - if validator == bool: + if self.is_bool(): # Value must "look like" a boolean value - if InvenTree.helpers.is_bool(self.value): + if InvenTree.helpers.is_bool(value): # Coerce into either "True" or "False" - self.value = str(InvenTree.helpers.str2bool(self.value)) + value = InvenTree.helpers.str2bool(value) else: raise ValidationError({ 'value': _('Value must be a boolean value') }) - # Integer validator - if validator == int: + # Integer validator + if self.is_int(): + try: # Coerce into an integer value - self.value = str(int(self.value)) + value = int(value) except (ValueError, TypeError): raise ValidationError({ 'value': _('Value must be an integer value'), }) + # If a list of validators is supplied, iterate through each one + if type(validator) in [list, tuple]: + for v in validator: + self.run_validator(v) + + if callable(validator): + # We can accept function validators with a single argument + validator(self.value) + def validate_unique(self, exclude=None): """ Ensure that the key:value pair is unique. In addition to the base validators, this ensures that the 'key' @@ -597,7 +611,13 @@ class InvenTreeSetting(models.Model): validator = InvenTreeSetting.get_setting_validator(self.key) - return validator == bool + if validator == bool: + return True + + if type(validator) in [list, tuple]: + for v in validator: + if v == bool: + return True def as_bool(self): """ @@ -623,6 +643,8 @@ class InvenTreeSetting(models.Model): if v == int: return True + return False + def as_int(self): """ Return the value of this setting converted to a boolean value. From 8717be66fc0e776b0b0b6f7add23e09447aaa393 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 23 Feb 2021 14:15:12 +1100 Subject: [PATCH 5/6] Configure number of "recent items" shown on index page --- InvenTree/common/models.py | 7 +++++++ InvenTree/templates/InvenTree/index.html | 4 ++-- InvenTree/templates/InvenTree/settings/part.html | 1 + InvenTree/templates/InvenTree/settings/stock.html | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 0514a081d0..40fde5dcb4 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -256,6 +256,13 @@ class InvenTreeSetting(models.Model): 'validator': bool, }, + 'STOCK_RECENT_COUNT': { + 'name': _('Recent Stock Count'), + 'description': _('Number of recent stock items to display on index page'), + 'default': 10, + 'validator': [int, MinValueValidator(1),] + }, + 'BUILDORDER_REFERENCE_PREFIX': { 'name': _('Build Order Reference Prefix'), 'description': _('Prefix value for build order reference'), diff --git a/InvenTree/templates/InvenTree/index.html b/InvenTree/templates/InvenTree/index.html index fc7d5344b1..cb2cda0a30 100644 --- a/InvenTree/templates/InvenTree/index.html +++ b/InvenTree/templates/InvenTree/index.html @@ -102,7 +102,7 @@ addHeaderAction('bom-validation', '{% trans "BOM Waiting Validation" %}', 'fa-ti loadSimplePartTable("#table-latest-parts", "{% url 'api-part-list' %}", { params: { ordering: "-creation_date", - limit: 10, + limit: {% settings_value "PART_RECENT_COUNT" %}, }, name: 'latest_parts', }); @@ -132,7 +132,7 @@ addHeaderAction('stock-to-build', '{% trans "Required for Build Orders" %}', 'fa loadStockTable($('#table-recently-updated-stock'), { params: { ordering: "-updated", - limit: 10, + limit: {% settings_value "STOCK_RECENT_COUNT" %}, }, name: 'recently-updated-stock', grouping: false, diff --git a/InvenTree/templates/InvenTree/settings/part.html b/InvenTree/templates/InvenTree/settings/part.html index 9174b2f127..bef951e203 100644 --- a/InvenTree/templates/InvenTree/settings/part.html +++ b/InvenTree/templates/InvenTree/settings/part.html @@ -19,6 +19,7 @@ {% include "InvenTree/settings/setting.html" with key="PART_IPN_REGEX" %} {% include "InvenTree/settings/setting.html" with key="PART_ALLOW_DUPLICATE_IPN" %} {% include "InvenTree/settings/setting.html" with key="PART_SHOW_QUANTITY_IN_FORMS" icon="fa-hashtag" %} + {% include "InvenTree/settings/setting.html" with key="PART_RECENT_COUNT" icon="fa-clock" %} {% include "InvenTree/settings/setting.html" with key="PART_TEMPLATE" icon="fa-clone" %} {% include "InvenTree/settings/setting.html" with key="PART_ASSEMBLY" icon="fa-tools" %} diff --git a/InvenTree/templates/InvenTree/settings/stock.html b/InvenTree/templates/InvenTree/settings/stock.html index 9c82202a02..7909e11a60 100644 --- a/InvenTree/templates/InvenTree/settings/stock.html +++ b/InvenTree/templates/InvenTree/settings/stock.html @@ -16,6 +16,7 @@ {% include "InvenTree/settings/header.html" %} {% include "InvenTree/settings/setting.html" with key="STOCK_GROUP_BY_PART" icon="fa-layer-group" %} + {% include "InvenTree/settings/setting.html" with key="STOCK_RECENT_COUNT" icon="fa-clock" %} {% include "InvenTree/settings/setting.html" with key="STOCK_ENABLE_EXPIRY" icon="fa-stopwatch" %} {% include "InvenTree/settings/setting.html" with key="STOCK_STALE_DAYS" icon="fa-calendar" %} {% include "InvenTree/settings/setting.html" with key="STOCK_ALLOW_EXPIRED_SALE" icon="fa-truck" %} From 648d322f540b85b531e6889aaff8421abf6babf7 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 23 Feb 2021 14:24:09 +1100 Subject: [PATCH 6/6] Style fixes --- InvenTree/common/models.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 40fde5dcb4..06c06bde05 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -129,7 +129,7 @@ class InvenTreeSetting(models.Model): 'name': _('Recent Part Count'), 'description': _('Number of recent parts to display on index page'), 'default': 10, - 'validator': [int, MinValueValidator(1),] + 'validator': [int, MinValueValidator(1)] }, 'PART_TEMPLATE': { @@ -260,7 +260,7 @@ class InvenTreeSetting(models.Model): 'name': _('Recent Stock Count'), 'description': _('Number of recent stock items to display on index page'), 'default': 10, - 'validator': [int, MinValueValidator(1),] + 'validator': [int, MinValueValidator(1)] }, 'BUILDORDER_REFERENCE_PREFIX': { @@ -547,7 +547,6 @@ class InvenTreeSetting(models.Model): if validator is not None: self.run_validator(validator) - def run_validator(self, validator): """ Run a validator against the 'value' field for this InvenTreeSetting object. @@ -569,7 +568,7 @@ class InvenTreeSetting(models.Model): 'value': _('Value must be a boolean value') }) - # Integer validator + # Integer validator if self.is_int(): try: