diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index fe28d780c7..0a9d39225b 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -12,11 +12,14 @@ import common.models INVENTREE_SW_VERSION = "0.7.0 dev" # InvenTree API version -INVENTREE_API_VERSION = 35 +INVENTREE_API_VERSION = 36 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +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" diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 3a2bb6eeb3..f7bb81520d 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -798,6 +798,20 @@ class PartFilter(rest_filters.FilterSet): return queryset + # unallocated_stock filter + unallocated_stock = rest_filters.BooleanFilter(label='Unallocated stock', method='filter_unallocated_stock') + + def filter_unallocated_stock(self, queryset, name, value): + + value = str2bool(value) + + if value: + queryset = queryset.filter(Q(unallocated_stock__gt=0)) + else: + queryset = queryset.filter(Q(unallocated_stock__lte=0)) + + return queryset + is_template = rest_filters.BooleanFilter() assembly = rest_filters.BooleanFilter() diff --git a/InvenTree/templates/js/translated/part.js b/InvenTree/templates/js/translated/part.js index b0283a1b35..1c66c32b6e 100644 --- a/InvenTree/templates/js/translated/part.js +++ b/InvenTree/templates/js/translated/part.js @@ -494,10 +494,40 @@ function duplicateBom(part_id, options={}) { function partStockLabel(part, options={}) { if (part.in_stock) { - return `{% trans "Stock" %}: ${part.in_stock}`; + // There IS stock available for this part + + // Is stock "low" (below the 'minimum_stock' quantity)? + if (part.minimum_stock && part.minimum_stock > part.in_stock) { + return `{% trans "Low stock" %}: ${part.in_stock}${part.units}`; + } else if (part.unallocated_stock == 0) { + if (part.ordering) { + // There is no available stock, but stock is on order + return `{% trans "On Order" %}: ${part.ordering}${part.units}`; + } else if (part.building) { + // There is no available stock, but stock is being built + return `{% trans "Building" %}: ${part.building}${part.units}`; + } else { + // There is no available stock + return `{% trans "Available" %}: 0/${part.in_stock}${part.units}`; + } + } else { + return `{% trans "Available" %}: ${part.unallocated_stock}/${part.in_stock}${part.units}`; + } } else { - return `{% trans "No Stock" %}`; + // There IS NO stock available for this part + + if (part.ordering) { + // There is no stock, but stock is on order + return `{% trans "On Order" %}: ${part.ordering}${part.units}`; + } else if (part.building) { + // There is no stock, but stock is being built + return `{% trans "Building" %}: ${part.building}${part.units}`; + } else { + // There is no stock + return `{% trans "No Stock" %}`; + } } + } @@ -1160,12 +1190,14 @@ function partGridTile(part) { if (!part.in_stock) { stock = `{% trans "No Stock" %}`; + } else if (!part.unallocated_stock) { + stock = `{% trans "Not available" %}`; } rows += `{% trans "Stock" %}${stock}`; - if (part.on_order) { - rows += `{$ trans "On Order" %}${part.on_order}`; + if (part.ordering) { + rows += `{% trans "On Order" %}${part.ordering}`; } if (part.building) { @@ -1322,31 +1354,47 @@ function loadPartTable(table, url, options={}) { columns.push(col); col = { - field: 'in_stock', - title: '{% trans "Stock" %}', + field: 'unallocated_stock', + title: '{% trans "Available" %}', searchable: false, formatter: function(value, row) { var link = '?display=part-stock'; - if (value) { + if (row.in_stock) { // There IS stock available for this part // Is stock "low" (below the 'minimum_stock' quantity)? - if (row.minimum_stock && row.minimum_stock > value) { + if (row.minimum_stock && row.minimum_stock > row.in_stock) { value += `{% trans "Low stock" %}`; + } else if (value == 0) { + if (row.ordering) { + // There is no available stock, but stock is on order + value = `0{% trans "On Order" %}: ${row.ordering}`; + link = '?display=purchase-orders'; + } else if (row.building) { + // There is no available stock, but stock is being built + value = `0{% trans "Building" %}: ${row.building}`; + link = '?display=build-orders'; + } else { + // There is no available stock + value = `0{% trans "Not available" %}`; + } } - - } else if (row.on_order) { - // There is no stock available, but stock is on order - value = `0{% trans "On Order" %}: ${row.on_order}`; - link = '?display=purchase-orders'; - } else if (row.building) { - // There is no stock available, but stock is being built - value = `0{% trans "Building" %}: ${row.building}`; - link = '?display=build-orders'; } else { - // There is no stock available - value = `0{% trans "No Stock" %}`; + // There IS NO stock available for this part + + if (row.ordering) { + // There is no stock, but stock is on order + value = `0{% trans "On Order" %}: ${row.ordering}`; + link = '?display=purchase-orders'; + } else if (row.building) { + // There is no stock, but stock is being built + value = `0{% trans "Building" %}: ${row.building}`; + link = '?display=build-orders'; + } else { + // There is no stock + value = `0{% trans "No Stock" %}`; + } } return renderLink(value, `/part/${row.pk}/${link}`); diff --git a/InvenTree/templates/js/translated/table_filters.js b/InvenTree/templates/js/translated/table_filters.js index 81d43d2c3f..6212568950 100644 --- a/InvenTree/templates/js/translated/table_filters.js +++ b/InvenTree/templates/js/translated/table_filters.js @@ -427,12 +427,16 @@ function getAvailableTableFilters(tableKey) { }, has_stock: { type: 'bool', - title: '{% trans "Stock available" %}', + title: '{% trans "In stock" %}', }, low_stock: { type: 'bool', title: '{% trans "Low stock" %}', }, + unallocated_stock: { + type: 'bool', + title: '{% trans "Available stock" %}', + }, assembly: { type: 'bool', title: '{% trans "Assembly" %}',