diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py new file mode 100644 index 0000000000..7851efd8dd --- /dev/null +++ b/InvenTree/InvenTree/api_version.py @@ -0,0 +1,149 @@ +""" +InvenTree API version information +""" + + +# InvenTree API version +INVENTREE_API_VERSION = 40 + +""" +Increment this API version number whenever there is a significant change to the API that any clients need to know about + +v40 -> 2022-04-19 + - Adds ability to filter StockItem list by "tracked" parameter + - This checks the serial number or batch code fields + +v39 -> 2022-04-18 + - Adds ability to filter StockItem list by "has_batch" parameter + +v38 -> 2022-04-14 : https://github.com/inventree/InvenTree/pull/2828 + - Adds the ability to include stock test results for "installed items" + +v37 -> 2022-04-07 : https://github.com/inventree/InvenTree/pull/2806 + - Adds extra stock availability information to the BomItem serializer + +v36 -> 2022-04-03 + - Adds ability to filter part list endpoint by unallocated_stock argument + +v35 -> 2022-04-01 : https://github.com/inventree/InvenTree/pull/2797 + - Adds stock allocation information to the Part API + - Adds calculated field for "unallocated_quantity" + +v34 -> 2022-03-25 + - Change permissions for "plugin list" API endpoint (now allows any authenticated user) + +v33 -> 2022-03-24 + - Adds "plugins_enabled" information to root API endpoint + +v32 -> 2022-03-19 + - Adds "parameters" detail to Part API endpoint (use ¶meters=true) + - Adds ability to filter PartParameterTemplate API by Part instance + - Adds ability to filter PartParameterTemplate API by PartCategory instance + +v31 -> 2022-03-14 + - Adds "updated" field to SupplierPriceBreakList and SupplierPriceBreakDetail API endpoints + +v30 -> 2022-03-09 + - Adds "exclude_location" field to BuildAutoAllocation API endpoint + - Allows BuildItem API endpoint to be filtered by BomItem relation + +v29 -> 2022-03-08 + - Adds "scheduling" endpoint for predicted stock scheduling information + +v28 -> 2022-03-04 + - Adds an API endpoint for auto allocation of stock items against a build order + - Ref: https://github.com/inventree/InvenTree/pull/2713 + +v27 -> 2022-02-28 + - Adds target_date field to individual line items for purchase orders and sales orders + +v26 -> 2022-02-17 + - Adds API endpoint for uploading a BOM file and extracting data + +v25 -> 2022-02-17 + - Adds ability to filter "part" list endpoint by "in_bom_for" argument + +v24 -> 2022-02-10 + - Adds API endpoint for deleting (cancelling) build order outputs + +v23 -> 2022-02-02 + - Adds API endpoints for managing plugin classes + - Adds API endpoints for managing plugin settings + +v22 -> 2021-12-20 + - Adds API endpoint to "merge" multiple stock items + +v21 -> 2021-12-04 + - Adds support for multiple "Shipments" against a SalesOrder + - Refactors process for stock allocation against a SalesOrder + +v20 -> 2021-12-03 + - Adds ability to filter POLineItem endpoint by "base_part" + - Adds optional "order_detail" to POLineItem list endpoint + +v19 -> 2021-12-02 + - Adds the ability to filter the StockItem API by "part_tree" + - Returns only stock items which match a particular part.tree_id field + +v18 -> 2021-11-15 + - Adds the ability to filter BomItem API by "uses" field + - This returns a list of all BomItems which "use" the specified part + - Includes inherited BomItem objects + +v17 -> 2021-11-09 + - Adds API endpoints for GLOBAL and USER settings objects + - Ref: https://github.com/inventree/InvenTree/pull/2275 + +v16 -> 2021-10-17 + - Adds API endpoint for completing build order outputs + +v15 -> 2021-10-06 + - Adds detail endpoint for SalesOrderAllocation model + - Allows use of the API forms interface for adjusting SalesOrderAllocation objects + +v14 -> 2021-10-05 + - Stock adjustment actions API is improved, using native DRF serializer support + - However adjustment actions now only support 'pk' as a lookup field + +v13 -> 2021-10-05 + - Adds API endpoint to allocate stock items against a BuildOrder + - Updates StockItem API with improved filtering against BomItem data + +v12 -> 2021-09-07 + - Adds API endpoint to receive stock items against a PurchaseOrder + +v11 -> 2021-08-26 + - Adds "units" field to PartBriefSerializer + - This allows units to be introspected from the "part_detail" field in the StockItem serializer + +v10 -> 2021-08-23 + - Adds "purchase_price_currency" to StockItem serializer + - Adds "purchase_price_string" to StockItem serializer + - Purchase price is now writable for StockItem serializer + +v9 -> 2021-08-09 + - Adds "price_string" to part pricing serializers + +v8 -> 2021-07-19 + - Refactors the API interface for SupplierPart and ManufacturerPart models + - ManufacturerPart objects can no longer be created via the SupplierPart API endpoint + +v7 -> 2021-07-03 + - Introduced the concept of "API forms" in https://github.com/inventree/InvenTree/pull/1716 + - API OPTIONS endpoints provide comprehensive field metedata + - Multiple new API endpoints added for database models + +v6 -> 2021-06-23 + - Part and Company images can now be directly uploaded via the REST API + +v5 -> 2021-06-21 + - Adds API interface for manufacturer part parameters + +v4 -> 2021-06-01 + - BOM items can now accept "variant stock" to be assigned against them + - Many slight API tweaks were needed to get this to work properly! + +v3 -> 2021-05-22: + - The updated StockItem "history tracking" now uses a different interface + +""" diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index 86242c65af..4663b6a111 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -1,4 +1,5 @@ -""" Version information for InvenTree. +""" +Version information for InvenTree. Provides information on the current InvenTree version """ @@ -8,150 +9,11 @@ import re import common.models +from InvenTree.api_version import INVENTREE_API_VERSION + # InvenTree software version INVENTREE_SW_VERSION = "0.7.0 dev" -# InvenTree API version -INVENTREE_API_VERSION = 39 - -""" -Increment this API version number whenever there is a significant change to the API that any clients need to know about - -v39 -> 2022-04-18 - - Adds ability to filter StockItem list by "has_batch" parameter - -v38 -> 2022-04-14 : https://github.com/inventree/InvenTree/pull/2828 - - Adds the ability to include stock test results for "installed items" - -v37 -> 2022-04-07 : https://github.com/inventree/InvenTree/pull/2806 - - Adds extra stock availability information to the BomItem serializer - -v36 -> 2022-04-03 - - Adds ability to filter part list endpoint by unallocated_stock argument - -v35 -> 2022-04-01 : https://github.com/inventree/InvenTree/pull/2797 - - Adds stock allocation information to the Part API - - Adds calculated field for "unallocated_quantity" - -v34 -> 2022-03-25 - - Change permissions for "plugin list" API endpoint (now allows any authenticated user) - -v33 -> 2022-03-24 - - Adds "plugins_enabled" information to root API endpoint - -v32 -> 2022-03-19 - - Adds "parameters" detail to Part API endpoint (use ¶meters=true) - - Adds ability to filter PartParameterTemplate API by Part instance - - Adds ability to filter PartParameterTemplate API by PartCategory instance - -v31 -> 2022-03-14 - - Adds "updated" field to SupplierPriceBreakList and SupplierPriceBreakDetail API endpoints - -v30 -> 2022-03-09 - - Adds "exclude_location" field to BuildAutoAllocation API endpoint - - Allows BuildItem API endpoint to be filtered by BomItem relation - -v29 -> 2022-03-08 - - Adds "scheduling" endpoint for predicted stock scheduling information - -v28 -> 2022-03-04 - - Adds an API endpoint for auto allocation of stock items against a build order - - Ref: https://github.com/inventree/InvenTree/pull/2713 - -v27 -> 2022-02-28 - - Adds target_date field to individual line items for purchase orders and sales orders - -v26 -> 2022-02-17 - - Adds API endpoint for uploading a BOM file and extracting data - -v25 -> 2022-02-17 - - Adds ability to filter "part" list endpoint by "in_bom_for" argument - -v24 -> 2022-02-10 - - Adds API endpoint for deleting (cancelling) build order outputs - -v23 -> 2022-02-02 - - Adds API endpoints for managing plugin classes - - Adds API endpoints for managing plugin settings - -v22 -> 2021-12-20 - - Adds API endpoint to "merge" multiple stock items - -v21 -> 2021-12-04 - - Adds support for multiple "Shipments" against a SalesOrder - - Refactors process for stock allocation against a SalesOrder - -v20 -> 2021-12-03 - - Adds ability to filter POLineItem endpoint by "base_part" - - Adds optional "order_detail" to POLineItem list endpoint - -v19 -> 2021-12-02 - - Adds the ability to filter the StockItem API by "part_tree" - - Returns only stock items which match a particular part.tree_id field - -v18 -> 2021-11-15 - - Adds the ability to filter BomItem API by "uses" field - - This returns a list of all BomItems which "use" the specified part - - Includes inherited BomItem objects - -v17 -> 2021-11-09 - - Adds API endpoints for GLOBAL and USER settings objects - - Ref: https://github.com/inventree/InvenTree/pull/2275 - -v16 -> 2021-10-17 - - Adds API endpoint for completing build order outputs - -v15 -> 2021-10-06 - - Adds detail endpoint for SalesOrderAllocation model - - Allows use of the API forms interface for adjusting SalesOrderAllocation objects - -v14 -> 2021-10-05 - - Stock adjustment actions API is improved, using native DRF serializer support - - However adjustment actions now only support 'pk' as a lookup field - -v13 -> 2021-10-05 - - Adds API endpoint to allocate stock items against a BuildOrder - - Updates StockItem API with improved filtering against BomItem data - -v12 -> 2021-09-07 - - Adds API endpoint to receive stock items against a PurchaseOrder - -v11 -> 2021-08-26 - - Adds "units" field to PartBriefSerializer - - This allows units to be introspected from the "part_detail" field in the StockItem serializer - -v10 -> 2021-08-23 - - Adds "purchase_price_currency" to StockItem serializer - - Adds "purchase_price_string" to StockItem serializer - - Purchase price is now writable for StockItem serializer - -v9 -> 2021-08-09 - - Adds "price_string" to part pricing serializers - -v8 -> 2021-07-19 - - Refactors the API interface for SupplierPart and ManufacturerPart models - - ManufacturerPart objects can no longer be created via the SupplierPart API endpoint - -v7 -> 2021-07-03 - - Introduced the concept of "API forms" in https://github.com/inventree/InvenTree/pull/1716 - - API OPTIONS endpoints provide comprehensive field metedata - - Multiple new API endpoints added for database models - -v6 -> 2021-06-23 - - Part and Company images can now be directly uploaded via the REST API - -v5 -> 2021-06-21 - - Adds API interface for manufacturer part parameters - -v4 -> 2021-06-01 - - BOM items can now accept "variant stock" to be assigned against them - - Many slight API tweaks were needed to get this to work properly! - -v3 -> 2021-05-22: - - The updated StockItem "history tracking" now uses a different interface - -""" - def inventreeInstanceName(): """ Returns the InstanceName settings for the current database """ diff --git a/InvenTree/part/templates/markdownx/widget.html b/InvenTree/part/templates/markdownx/widget.html deleted file mode 100644 index 61c8673748..0000000000 --- a/InvenTree/part/templates/markdownx/widget.html +++ /dev/null @@ -1,10 +0,0 @@ -{% load i18n %} - -
-
- {% include 'django/forms/widgets/textarea.html' %} -
-
-
-
-
\ No newline at end of file diff --git a/InvenTree/part/templates/part/category.html b/InvenTree/part/templates/part/category.html index 6a61ef2fbf..2f7076c850 100644 --- a/InvenTree/part/templates/part/category.html +++ b/InvenTree/part/templates/part/category.html @@ -187,6 +187,15 @@ +
+
+

{% trans "Stock Items" %}

+
+
+ {% include "stock_table.html" %} +
+
+

{% trans "Part Parameters" %}

@@ -223,6 +232,21 @@ {{ block.super }} {% if category %} + + onPanelLoad('stock', function() { + loadStockTable( + $('#stock-table'), + { + params: { + category: {{ category.pk }}, + part_detail: true, + location_detail: true, + supplier_part_detail: true, + } + } + ); + }); + onPanelLoad('parameters', function() { loadParametricPartTable( "#parametric-part-table", diff --git a/InvenTree/part/templates/part/category_sidebar.html b/InvenTree/part/templates/part/category_sidebar.html index 3d945d0433..5468d953ae 100644 --- a/InvenTree/part/templates/part/category_sidebar.html +++ b/InvenTree/part/templates/part/category_sidebar.html @@ -14,6 +14,8 @@ {% include "sidebar_link.html" with url=url text=text icon="fa-file-upload" %} {% endif %} {% if category %} +{% trans "Stock Items" as text %} +{% include "sidebar_item.html" with label='stock' text=text icon='fa-boxes' %} {% trans "Parameters" as text %} {% include "sidebar_item.html" with label="parameters" text=text icon="fa-tasks" %} {% endif %} \ No newline at end of file diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 3768cd8787..d4fc5c93d1 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -402,11 +402,16 @@ class StockFilter(rest_filters.FilterSet): serialized = rest_filters.BooleanFilter(label='Has serial number', method='filter_serialized') def filter_serialized(self, queryset, name, value): + """ + Filter by whether the StockItem has a serial number (or not) + """ + + q = Q(serial=None) | Q(serial='') if str2bool(value): - queryset = queryset.exclude(serial=None) + queryset = queryset.exclude(q) else: - queryset = queryset.filter(serial=None) + queryset = queryset.filter(q) return queryset @@ -417,10 +422,31 @@ class StockFilter(rest_filters.FilterSet): Filter by whether the StockItem has a batch code (or not) """ + q = Q(batch=None) | Q(batch='') + if str2bool(value): - queryset = queryset.exclude(batch=None) + queryset = queryset.exclude(q) else: - queryset = queryset.filter(batch=None) + queryset = queryset.filter(q) + + return queryset + + tracked = rest_filters.BooleanFilter(label='Tracked', method='filter_tracked') + + def filter_tracked(self, queryset, name, value): + """ + Filter by whether this stock item is *tracked*, meaning either: + - It has a serial number + - It has a batch code + """ + + q_batch = Q(batch=None) | Q(batch='') + q_serial = Q(serial=None) | Q(serial='') + + if str2bool(value): + queryset = queryset.exclude(q_batch & q_serial) + else: + queryset = queryset.filter(q_batch & q_serial) return queryset diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index dc93f61e81..43593d3283 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -453,6 +453,12 @@ class StockItem(MPTTModel): super().clean() + if self.serial is not None and type(self.serial) is str: + self.serial = self.serial.strip() + + if self.batch is not None and type(self.batch) is str: + self.batch = self.batch.strip() + try: if self.part.trackable: # Trackable parts must have integer values for quantity field! diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py index 73bee54110..7f94c6dedf 100644 --- a/InvenTree/stock/test_api.py +++ b/InvenTree/stock/test_api.py @@ -210,6 +210,46 @@ class StockItemListTest(StockAPITestCase): for item in response: self.assertIsNone(item['serial']) + def test_filter_by_has_batch(self): + """ + Test the 'has_batch' filter, which tests if the stock item has been assigned a batch code + """ + + with_batch = self.get_stock(has_batch=1) + without_batch = self.get_stock(has_batch=0) + + n_stock_items = StockItem.objects.all().count() + + # Total sum should equal the total count of stock items + self.assertEqual(n_stock_items, len(with_batch) + len(without_batch)) + + for item in with_batch: + self.assertFalse(item['batch'] in [None, '']) + + for item in without_batch: + self.assertTrue(item['batch'] in [None, '']) + + def test_filter_by_tracked(self): + """ + Test the 'tracked' filter. + This checks if the stock item has either a batch code *or* a serial number + """ + + tracked = self.get_stock(tracked=True) + untracked = self.get_stock(tracked=False) + + n_stock_items = StockItem.objects.all().count() + + self.assertEqual(n_stock_items, len(tracked) + len(untracked)) + + blank = [None, ''] + + for item in tracked: + self.assertTrue(item['batch'] not in blank or item['serial'] not in blank) + + for item in untracked: + self.assertTrue(item['batch'] in blank and item['serial'] in blank) + def test_filter_by_expired(self): """ Filter StockItem by expiry status diff --git a/InvenTree/templates/js/translated/model_renderers.js b/InvenTree/templates/js/translated/model_renderers.js index 186349b5ac..656a3f9f63 100644 --- a/InvenTree/templates/js/translated/model_renderers.js +++ b/InvenTree/templates/js/translated/model_renderers.js @@ -108,7 +108,7 @@ function renderStockItem(name, data, parameters={}, options={}) { stock_detail = `{% trans "Quantity" %}: ${data.quantity}`; } - if (data.batch != null) { + if (data.batch) { stock_detail += ` - {% trans "Batch" %}: ${data.batch}`; } } diff --git a/InvenTree/templates/js/translated/notification.js b/InvenTree/templates/js/translated/notification.js index a289dcb8f7..74079669ab 100644 --- a/InvenTree/templates/js/translated/notification.js +++ b/InvenTree/templates/js/translated/notification.js @@ -171,6 +171,9 @@ function notificationCheck(force = false) { { success: function(response) { updateNotificationIndicator(response.length); + }, + error: function(xhr) { + console.warn('Could not access server: /api/notifications'); } } ); diff --git a/InvenTree/templates/js/translated/stock.js b/InvenTree/templates/js/translated/stock.js index c13ea41f99..de42528142 100644 --- a/InvenTree/templates/js/translated/stock.js +++ b/InvenTree/templates/js/translated/stock.js @@ -241,9 +241,11 @@ function stockItemFields(options={}) { serial: { icon: 'fa-hashtag', }, + batch: { + icon: 'fa-layer-group', + }, status: {}, expiry_date: {}, - batch: {}, purchase_price: { icon: 'fa-dollar-sign', }, @@ -964,7 +966,7 @@ function adjustStock(action, items, options={}) { quantity = `#${item.serial}`; } - if (item.batch != null) { + if (item.batch) { quantity += ` - {% trans "Batch" %}: ${item.batch}`; } @@ -2657,7 +2659,8 @@ function installStockItem(stock_item_id, part_id, options={}) {
`; @@ -2683,7 +2686,7 @@ function installStockItem(stock_item_id, part_id, options={}) { filters: { part_detail: true, in_stock: true, - serialized: true, + tracked: true, }, adjustFilters: function(filters, opts) { var part = getFormFieldValue('part', {}, opts); diff --git a/InvenTree/templates/js/translated/table_filters.js b/InvenTree/templates/js/translated/table_filters.js index 303d484788..c806afd4b1 100644 --- a/InvenTree/templates/js/translated/table_filters.js +++ b/InvenTree/templates/js/translated/table_filters.js @@ -242,6 +242,11 @@ function getAvailableTableFilters(tableKey) { title: '{% trans "Batch" %}', description: '{% trans "Batch code" %}', }, + tracked: { + title: '{% trans "Tracked" %}', + description: '{% trans "Stock item is tracked by either batch code or serial number" %}', + type: 'bool', + }, has_purchase_price: { type: 'bool', title: '{% trans "Has purchase price" %}',