diff --git a/InvenTree/build/templates/build/detail.html b/InvenTree/build/templates/build/detail.html
index 2da2410fc8..7e6efff2af 100644
--- a/InvenTree/build/templates/build/detail.html
+++ b/InvenTree/build/templates/build/detail.html
@@ -306,9 +306,6 @@ onPanelLoad('completed', function() {
build: {{ build.id }},
is_building: false,
},
- buttons: [
- '#stock-options',
- ],
});
});
diff --git a/InvenTree/company/templates/company/detail.html b/InvenTree/company/templates/company/detail.html
index 6a653d2d0d..7d380d7c2f 100644
--- a/InvenTree/company/templates/company/detail.html
+++ b/InvenTree/company/templates/company/detail.html
@@ -319,9 +319,6 @@
supplier_part_detail: true,
location_detail: true,
},
- buttons: [
- '#stock-options',
- ],
filterKey: "companystock",
});
});
diff --git a/InvenTree/company/templates/company/supplier_part.html b/InvenTree/company/templates/company/supplier_part.html
index 9fc84ce123..5a37cbae43 100644
--- a/InvenTree/company/templates/company/supplier_part.html
+++ b/InvenTree/company/templates/company/supplier_part.html
@@ -322,7 +322,6 @@ loadStockTable($("#stock-table"), {
location_detail: true,
part_detail: false,
},
- buttons: ['#stock-options'],
});
$("#item-create").click(function() {
diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html
index d7491f753e..85065ff46f 100644
--- a/InvenTree/order/templates/order/purchase_order_detail.html
+++ b/InvenTree/order/templates/order/purchase_order_detail.html
@@ -150,9 +150,6 @@
supplier_part_detail: true,
location_detail: true,
},
- buttons: [
- '#stock-options',
- ],
filterkey: "postock"
});
diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html
index 8ecac03b6c..32bd4ac3a8 100644
--- a/InvenTree/part/templates/part/detail.html
+++ b/InvenTree/part/templates/part/detail.html
@@ -769,9 +769,6 @@
part_detail: true,
supplier_part_detail: true,
},
- buttons: [
- '#stock-options',
- ],
});
$('#item-create').click(function () {
diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py
index 3dd9480ac1..3011e2e9df 100644
--- a/InvenTree/stock/api.py
+++ b/InvenTree/stock/api.py
@@ -552,6 +552,19 @@ class StockFilter(rest_filters.FilterSet):
else:
return queryset.filter(purchase_price=None)
+ ancestor = rest_filters.ModelChoiceFilter(
+ label='Ancestor',
+ queryset=StockItem.objects.all(),
+ method='filter_ancestor'
+ )
+
+ def filter_ancestor(self, queryset, name, ancestor):
+ """Filter based on ancestor stock item"""
+
+ return queryset.filter(
+ parent__in=ancestor.get_descendants(include_self=True)
+ )
+
# Update date filters
updated_before = rest_filters.DateFilter(label='Updated before', field_name='updated', lookup_expr='lte')
updated_after = rest_filters.DateFilter(label='Updated after', field_name='updated', lookup_expr='gte')
@@ -929,19 +942,6 @@ class StockList(APIDownloadMixin, ListCreateDestroyAPIView):
except (ValueError, Part.DoesNotExist):
raise ValidationError({"part": "Invalid Part ID specified"})
- # Does the client wish to filter by the 'ancestor'?
- anc_id = params.get('ancestor', None)
-
- if anc_id:
- try:
- ancestor = StockItem.objects.get(pk=anc_id)
-
- # Only allow items which are descendants of the specified StockItem
- queryset = queryset.filter(id__in=[item.pk for item in ancestor.children.all()])
-
- except (ValueError, Part.DoesNotExist):
- raise ValidationError({"ancestor": "Invalid ancestor ID specified"})
-
# Does the client wish to filter by stock location?
loc_id = params.get('location', None)
diff --git a/InvenTree/stock/templates/stock/item.html b/InvenTree/stock/templates/stock/item.html
index 81ec9ef059..a36dd54f91 100644
--- a/InvenTree/stock/templates/stock/item.html
+++ b/InvenTree/stock/templates/stock/item.html
@@ -65,6 +65,7 @@
{% if item.child_count > 0 %}
+ {% include "filter_list.html" with id="stock-childs" %}
{% include "stock_table.html" with prefix="childs-" %}
{% else %}
@@ -300,14 +301,11 @@
{% if item.child_count > 0 %}
loadStockTable($("#childs-stock-table"), {
params: {
- location_detail: true,
- part_detail: false,
ancestor: {{ item.id }},
},
name: 'item-childs',
- buttons: [
- '#stock-options',
- ],
+ filterTarget: '#filter-list-stock-childs',
+ filterKey: 'stock',
});
{% endif %}
diff --git a/InvenTree/stock/templates/stock/location.html b/InvenTree/stock/templates/stock/location.html
index 98a8283002..60dad09d64 100644
--- a/InvenTree/stock/templates/stock/location.html
+++ b/InvenTree/stock/templates/stock/location.html
@@ -403,9 +403,6 @@
onPanelLoad('stock', function() {
loadStockTable($("#stock-table"), {
- buttons: [
- '#stock-options',
- ],
params: {
{% if location %}
location: {{ location.pk }},
diff --git a/InvenTree/templates/js/translated/stock.js b/InvenTree/templates/js/translated/stock.js
index 09351e0bc1..af07802601 100644
--- a/InvenTree/templates/js/translated/stock.js
+++ b/InvenTree/templates/js/translated/stock.js
@@ -1834,6 +1834,8 @@ function makeStockActions(table) {
*/
function loadStockTable(table, options) {
+ options.params = options.params || {};
+
// List of user-params which override the default filters
options.params['location_detail'] = true;
options.params['part_detail'] = true;
@@ -1841,8 +1843,6 @@ function loadStockTable(table, options) {
// Determine if installed items are displayed in the table
let show_installed_items = global_settings.STOCK_SHOW_INSTALLED_ITEMS;
- var params = options.params || {};
-
let filters = {};
if (!options.disableFilters) {
@@ -1850,7 +1850,7 @@ function loadStockTable(table, options) {
const filterTarget = options.filterTarget || '#filter-list-stock';
const filterKey = options.filterKey || options.name || 'stock';
- filters = loadTableFilters(filterKey, params);
+ filters = loadTableFilters(filterKey, options.params);
setupFilterList(filterKey, table, filterTarget, {
download: true,
@@ -1886,7 +1886,7 @@ function loadStockTable(table, options) {
});
}
- filters = Object.assign(filters, params);
+ filters = Object.assign(filters, options.params);
var col = null;
@@ -1909,8 +1909,8 @@ function loadStockTable(table, options) {
field: 'part',
title: '{% trans "Part" %}',
sortName: 'part__name',
- visible: params['part_detail'],
- switchable: params['part_detail'],
+ visible: options.params['part_detail'],
+ switchable: options.params['part_detail'],
formatter: function(value, row) {
let html = '';
@@ -1948,8 +1948,8 @@ function loadStockTable(table, options) {
field: 'IPN',
title: '{% trans "IPN" %}',
sortName: 'part__IPN',
- visible: params['part_detail'],
- switchable: params['part_detail'],
+ visible: options.params['part_detail'],
+ switchable: options.params['part_detail'],
formatter: function(value, row) {
var ipn = row.part_detail.IPN;
if (ipn) {
@@ -1969,8 +1969,8 @@ function loadStockTable(table, options) {
columns.push({
field: 'part_detail.description',
title: '{% trans "Description" %}',
- visible: params['part_detail'],
- switchable: params['part_detail'],
+ visible: options.params['part_detail'],
+ switchable: options.params['part_detail'],
formatter: function(value, row) {
var description = row.part_detail.description;
return withTitle(shortenString(description), description);
@@ -2168,8 +2168,8 @@ function loadStockTable(table, options) {
field: 'supplier_part',
title: '{% trans "Supplier Part" %}',
- visible: params['supplier_part_detail'] || false,
- switchable: params['supplier_part_detail'] || false,
+ visible: options.params['supplier_part_detail'] || false,
+ switchable: options.params['supplier_part_detail'] || false,
formatter: function(value, row) {
if (!value) {
return '-';
@@ -2358,7 +2358,7 @@ function loadStockTable(table, options) {
queryParams: filters,
sidePagination: 'server',
name: 'stock',
- original: params,
+ original: options.params,
showColumns: true,
showFooter: true,
columns: columns,