From 85b906f49dc32d417fa4a731ea40b6454cf6de0c Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 10 Nov 2021 09:48:52 +1100 Subject: [PATCH 1/8] Adds "stock" column sorting for stock table --- InvenTree/stock/api.py | 2 ++ InvenTree/templates/js/translated/stock.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index e287441382..e01ad51b55 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -876,6 +876,7 @@ class StockList(generics.ListCreateAPIView): ordering_field_aliases = { 'SKU': 'supplier_part__SKU', + 'stock': ['quantity', 'serial'], } ordering_fields = [ @@ -887,6 +888,7 @@ class StockList(generics.ListCreateAPIView): 'stocktake_date', 'expiry_date', 'quantity', + 'stock', 'status', 'SKU', ] diff --git a/InvenTree/templates/js/translated/stock.js b/InvenTree/templates/js/translated/stock.js index ec785969cd..ba4238e6f7 100644 --- a/InvenTree/templates/js/translated/stock.js +++ b/InvenTree/templates/js/translated/stock.js @@ -1128,7 +1128,9 @@ function loadStockTable(table, options) { col = { field: 'quantity', + sortName: 'stock', title: '{% trans "Stock" %}', + sortable: true, formatter: function(value, row) { var val = parseFloat(value); From 257be18d7962c64e85be903e0a0f2daea9cc0ad8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 10 Nov 2021 10:47:17 +1100 Subject: [PATCH 2/8] Add 'serial_int' field to stockitem model - Allows for integer sorting of stock items --- .../migrations/0068_stockitem_serial_int.py | 18 ++++++++++++++++++ InvenTree/stock/models.py | 2 ++ 2 files changed, 20 insertions(+) create mode 100644 InvenTree/stock/migrations/0068_stockitem_serial_int.py diff --git a/InvenTree/stock/migrations/0068_stockitem_serial_int.py b/InvenTree/stock/migrations/0068_stockitem_serial_int.py new file mode 100644 index 0000000000..874978dc61 --- /dev/null +++ b/InvenTree/stock/migrations/0068_stockitem_serial_int.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.5 on 2021-11-09 23:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('stock', '0067_alter_stockitem_part'), + ] + + operations = [ + migrations.AddField( + model_name='stockitem', + name='serial_int', + field=models.IntegerField(default=0), + ), + ] diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 320807e0c1..8601e96f36 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -504,6 +504,8 @@ class StockItem(MPTTModel): help_text=_('Serial number for this item') ) + serial_int = models.IntegerField(default=0) + link = InvenTreeURLField( verbose_name=_('External Link'), max_length=125, blank=True, From 738ba4eddfa05f7a20e78b0c011bd88095bd774f Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 10 Nov 2021 10:59:48 +1100 Subject: [PATCH 3/8] Data migration to initially update serial number fields for all stock items - Also automatically updates serial_int field when saving StockItem --- .../migrations/0069_auto_20211109_2347.py | 55 +++++++++++++++++++ InvenTree/stock/models.py | 26 +++++++++ 2 files changed, 81 insertions(+) create mode 100644 InvenTree/stock/migrations/0069_auto_20211109_2347.py diff --git a/InvenTree/stock/migrations/0069_auto_20211109_2347.py b/InvenTree/stock/migrations/0069_auto_20211109_2347.py new file mode 100644 index 0000000000..3eaa8c784d --- /dev/null +++ b/InvenTree/stock/migrations/0069_auto_20211109_2347.py @@ -0,0 +1,55 @@ +# Generated by Django 3.2.5 on 2021-11-09 23:47 + +import re + +from django.db import migrations + + +def update_serials(apps, schema_editor): + """ + Rebuild the integer serial number field for existing StockItem objects + """ + + StockItem = apps.get_model('stock', 'stockitem') + + for item in StockItem.objects.all(): + + if item.serial is None: + # Skip items without existing serial numbers + continue + + serial = 0 + + result = re.match(r"^(\d+)", item.serial or "") + + if result and len(result.groups()) == 1: + try: + serial = int(result.groups()[0]) + except: + serial = 0 + + + item.serial_int = serial + print(item, item.serial, '->', item.serial_int) + item.save() + + +def nupdate_serials(apps, schema_editor): + """ + Provided only for reverse migration compatibility + """ + pass + + +class Migration(migrations.Migration): + + dependencies = [ + ('stock', '0068_stockitem_serial_int'), + ] + + operations = [ + migrations.RunPython( + update_serials, + reverse_code=nupdate_serials, + ) + ] diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 8601e96f36..5bc56f4bc6 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -7,6 +7,7 @@ Stock database model definitions from __future__ import unicode_literals import os +import re from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError, FieldError @@ -223,6 +224,29 @@ class StockItem(MPTTModel): self.scheduled_for_deletion = True self.save() + def update_serial_number(self): + """ + Update the 'serial_int' field, to be an integer representation of the serial number. + This is used for efficient numerical sorting + """ + + serial = getattr(self, 'serial', '') + + # Default value if we cannot convert to an integer + serial_int = 0 + + # Look at the start of the string - can it be "integerized"? + result = re.match(r'^(\d+)', serial or "") + + if result and len(result.groups()) == 1: + try: + serial_int = int(result.groups()[0]) + except: + serial_int = 0 + + self.serial_int = serial_int + + def save(self, *args, **kwargs): """ Save this StockItem to the database. Performs a number of checks: @@ -234,6 +258,8 @@ class StockItem(MPTTModel): self.validate_unique() self.clean() + self.update_serial_number() + user = kwargs.pop('user', None) # If 'add_note = False' specified, then no tracking note will be added for item creation From 25ce043337a26e2d417febdd5d446ed62b31076b Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 10 Nov 2021 11:00:43 +1100 Subject: [PATCH 4/8] Adjust ordering sequence for StockItem --- InvenTree/stock/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index e01ad51b55..2ffc2e8d69 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -876,7 +876,7 @@ class StockList(generics.ListCreateAPIView): ordering_field_aliases = { 'SKU': 'supplier_part__SKU', - 'stock': ['quantity', 'serial'], + 'stock': ['quantity', 'serial_int', 'serial'], } ordering_fields = [ From 067f12d5eb19014c31a95511189301da8ce52a6d Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 10 Nov 2021 11:01:12 +1100 Subject: [PATCH 5/8] PEP fixes --- InvenTree/stock/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 5bc56f4bc6..84942b215e 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -246,7 +246,6 @@ class StockItem(MPTTModel): self.serial_int = serial_int - def save(self, *args, **kwargs): """ Save this StockItem to the database. Performs a number of checks: From ba11a73f91e73c0e97dfdfddc232d60408a3a9a8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 10 Nov 2021 11:22:58 +1100 Subject: [PATCH 6/8] Fix for saving stock item objects --- InvenTree/stock/models.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 84942b215e..8e07074a76 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -235,14 +235,18 @@ class StockItem(MPTTModel): # Default value if we cannot convert to an integer serial_int = 0 - # Look at the start of the string - can it be "integerized"? - result = re.match(r'^(\d+)', serial or "") + if serial is not None: - if result and len(result.groups()) == 1: - try: - serial_int = int(result.groups()[0]) - except: - serial_int = 0 + serial = str(serial) + + # Look at the start of the string - can it be "integerized"? + result = re.match(r'^(\d+)', serial) + + if result and len(result.groups()) == 1: + try: + serial_int = int(result.groups()[0]) + except: + serial_int = 0 self.serial_int = serial_int From 919f182c25d06cff2ac98ab2140cc2b9f1630989 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 10 Nov 2021 11:30:11 +1100 Subject: [PATCH 7/8] Remove debug messages --- InvenTree/stock/migrations/0069_auto_20211109_2347.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/InvenTree/stock/migrations/0069_auto_20211109_2347.py b/InvenTree/stock/migrations/0069_auto_20211109_2347.py index 3eaa8c784d..f4cdde7794 100644 --- a/InvenTree/stock/migrations/0069_auto_20211109_2347.py +++ b/InvenTree/stock/migrations/0069_auto_20211109_2347.py @@ -20,7 +20,7 @@ def update_serials(apps, schema_editor): serial = 0 - result = re.match(r"^(\d+)", item.serial or "") + result = re.match(r"^(\d+)", str(item.serial)) if result and len(result.groups()) == 1: try: @@ -30,7 +30,6 @@ def update_serials(apps, schema_editor): item.serial_int = serial - print(item, item.serial, '->', item.serial_int) item.save() From 986a13864ae2c38b9858749ce5cbedfa67640b46 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 10 Nov 2021 11:37:30 +1100 Subject: [PATCH 8/8] Exclude 'serial_int' when exporting stock data --- InvenTree/stock/admin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/InvenTree/stock/admin.py b/InvenTree/stock/admin.py index 5f1b134966..abd3db20cb 100644 --- a/InvenTree/stock/admin.py +++ b/InvenTree/stock/admin.py @@ -117,6 +117,8 @@ class StockItemResource(ModelResource): exclude = [ # Exclude MPTT internal model fields 'lft', 'rght', 'tree_id', 'level', + # Exclude internal fields + 'serial_int', ]