From 85bce24e307c33a6930a96e8e0ca26736735c616 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Jan 2021 12:32:27 +1100 Subject: [PATCH 1/5] Limit matches to the 5 "most matchy" ones --- InvenTree/part/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 26cf93e56d..6367921fbf 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -655,7 +655,9 @@ class PartCreate(AjaxCreateView): matches = match_part_names(name) if len(matches) > 0: - context['matches'] = matches + + # Limit to the top 5 matches (to prevent clutter) + context['matches'] = matches[:5] # Enforce display of the checkbox form.fields['confirm_creation'].widget = CheckboxInput() From ef3ac43c4acca3081e12f45fc9d3a6fcf2d54950 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Jan 2021 15:27:40 +1100 Subject: [PATCH 2/5] Add "last updated" date to stock table --- InvenTree/stock/serializers.py | 1 + InvenTree/templates/js/stock.js | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index 6048d5e248..b8e71ff58c 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -213,6 +213,7 @@ class StockItemSerializer(InvenTreeModelSerializer): 'supplier_part_detail', 'tracking_items', 'uid', + 'updated', ] """ These fields are read-only in this context. diff --git a/InvenTree/templates/js/stock.js b/InvenTree/templates/js/stock.js index 836fa0e242..276be131f0 100644 --- a/InvenTree/templates/js/stock.js +++ b/InvenTree/templates/js/stock.js @@ -613,6 +613,11 @@ function loadStockTable(table, options) { sortable: true, }, {% endif %} + { + field: 'updated', + title: '{% trans "Last Updated" %}', + sortable: true, + }, { field: 'notes', title: '{% trans "Notes" %}', From fc32d99327904a62d18de6bddb437d5ea0185cc7 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Jan 2021 16:39:50 +1100 Subject: [PATCH 3/5] Add "updated_before" and "updated_after" filter for stock API --- InvenTree/stock/api.py | 53 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 9f0a4278f5..c8211aaeca 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -644,7 +644,7 @@ class StockList(generics.ListCreateAPIView): queryset = queryset.filter(Q(sales_order_allocations__isnull=True) & Q(allocations__isnull=True)) # Do we wish to filter by "active parts" - active = self.request.query_params.get('active', None) + active = params.get('active', None) if active is not None: active = str2bool(active) @@ -683,7 +683,7 @@ class StockList(generics.ListCreateAPIView): raise ValidationError({"part": "Invalid Part ID specified"}) # Does the client wish to filter by the 'ancestor'? - anc_id = self.request.query_params.get('ancestor', None) + anc_id = params.get('ancestor', None) if anc_id: try: @@ -696,9 +696,9 @@ class StockList(generics.ListCreateAPIView): raise ValidationError({"ancestor": "Invalid ancestor ID specified"}) # Does the client wish to filter by stock location? - loc_id = self.request.query_params.get('location', None) + loc_id = params.get('location', None) - cascade = str2bool(self.request.query_params.get('cascade', True)) + cascade = str2bool(params.get('cascade', True)) if loc_id is not None: @@ -718,7 +718,7 @@ class StockList(generics.ListCreateAPIView): pass # Does the client wish to filter by part category? - cat_id = self.request.query_params.get('category', None) + cat_id = params.get('category', None) if cat_id: try: @@ -729,35 +729,68 @@ class StockList(generics.ListCreateAPIView): raise ValidationError({"category": "Invalid category id specified"}) # Filter by StockItem status - status = self.request.query_params.get('status', None) + status = params.get('status', None) if status: queryset = queryset.filter(status=status) # Filter by supplier_part ID - supplier_part_id = self.request.query_params.get('supplier_part', None) + supplier_part_id = params.get('supplier_part', None) if supplier_part_id: queryset = queryset.filter(supplier_part=supplier_part_id) # Filter by company (either manufacturer or supplier) - company = self.request.query_params.get('company', None) + company = params.get('company', None) if company is not None: queryset = queryset.filter(Q(supplier_part__supplier=company) | Q(supplier_part__manufacturer=company)) # Filter by supplier - supplier = self.request.query_params.get('supplier', None) + supplier = params.get('supplier', None) if supplier is not None: queryset = queryset.filter(supplier_part__supplier=supplier) # Filter by manufacturer - manufacturer = self.request.query_params.get('manufacturer', None) + manufacturer = params.get('manufacturer', None) if manufacturer is not None: queryset = queryset.filter(supplier_part__manufacturer=manufacturer) + """ + Filter by the 'last updated' date of the stock item(s): + + - updated_before=? : Filter stock items which were last updated *before* the provided date + - updated_after=? : Filter stock items which were last updated *after* the provided date + """ + + date_fmt = '%Y-%m-%d' # ISO format date string + + updated_before = params.get('updated_before', None) + updated_after = params.get('updated_after', None) + + if updated_before: + try: + updated_before = datetime.strptime(str(updated_before), date_fmt).date() + queryset = queryset.filter(updated__lte=updated_before) + + print("Before:", updated_before.isoformat()) + except (ValueError, TypeError): + # Account for improperly formatted date string + print("After before:", str(updated_before)) + pass + + if updated_after: + try: + updated_after = datetime.strptime(str(updated_after), date_fmt).date() + queryset = queryset.filter(updated__gte=updated_after) + print("After:", updated_after.isoformat()) + except (ValueError, TypeError): + # Account for improperly formatted date string + print("After error:", str(updated_after)) + pass + # Also ensure that we pre-fecth all the related items queryset = queryset.prefetch_related( 'part', From 4952c95c33fb2d7412d92cad2e20b3a1175a5666 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Jan 2021 16:51:34 +1100 Subject: [PATCH 4/5] Extra check to prevent JS crash --- InvenTree/InvenTree/static/script/inventree/tables.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/static/script/inventree/tables.js b/InvenTree/InvenTree/static/script/inventree/tables.js index 4d868f94b4..ef17d91015 100644 --- a/InvenTree/InvenTree/static/script/inventree/tables.js +++ b/InvenTree/InvenTree/static/script/inventree/tables.js @@ -154,7 +154,7 @@ $.fn.inventreeTable = function(options) { // Which columns are currently visible? var visible = table.bootstrapTable('getVisibleColumns'); - if (visible) { + if (visible && isArray(visible)) { visible.forEach(function(column) { // Visible field should *not* be visible! (hide it!) From 0dee4df8fb8ec5b2ebca6e007eaab12d616c7e9f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 15 Jan 2021 17:11:46 +1100 Subject: [PATCH 5/5] Bug fix --- InvenTree/InvenTree/static/script/inventree/tables.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/static/script/inventree/tables.js b/InvenTree/InvenTree/static/script/inventree/tables.js index ef17d91015..a40eb37285 100644 --- a/InvenTree/InvenTree/static/script/inventree/tables.js +++ b/InvenTree/InvenTree/static/script/inventree/tables.js @@ -154,7 +154,7 @@ $.fn.inventreeTable = function(options) { // Which columns are currently visible? var visible = table.bootstrapTable('getVisibleColumns'); - if (visible && isArray(visible)) { + if (visible && Array.isArray(visible)) { visible.forEach(function(column) { // Visible field should *not* be visible! (hide it!)