Allow API filtering by "cascading" stock locations

This commit is contained in:
Oliver Walters 2021-04-20 20:00:15 +10:00
parent 6986709fb8
commit 412b05d76c
4 changed files with 64 additions and 12 deletions

View File

@ -289,20 +289,35 @@ class StockLocationList(generics.ListCreateAPIView):
queryset = super().get_queryset() queryset = super().get_queryset()
loc_id = self.request.query_params.get('parent', None) params = self.request.query_params
if loc_id is not None: cascade = str2bool(params.get('cascade', False))
# Look for top-level locations loc_id = params.get('parent', None)
if isNull(loc_id):
# Look for top-level locations
if isNull(loc_id):
# If we allow "cascade" at the top-level, this essentially means *all* locations
if not cascade:
queryset = queryset.filter(parent=None) queryset = queryset.filter(parent=None)
else: else:
try:
loc_id = int(loc_id) try:
queryset = queryset.filter(parent=loc_id) location = StockLocation.objects.get(pk=loc_id)
except ValueError:
pass # All sub-locations to be returned too?
if cascade:
parents = location.get_descendants(include_self=True)
parent_ids = [p.id for p in parents]
queryset = queryset.filter(parent__in=parent_ids)
else:
queryset = queryset.filter(parent=location)
except (ValueError, StockLocation.DoesNotExist):
pass
return queryset return queryset

View File

@ -15,7 +15,16 @@
<div class='panel-heading'> <div class='panel-heading'>
<h4>{% trans "Sublocations" %}</h4> <h4>{% trans "Sublocations" %}</h4>
</div> </div>
<table class='table table-striped table-condensed' id='sublocation-table'></table>
<div id='button-toolbar'>
<div class='button-toolbar container-fluid' style='float: right;'>
</div>
<div class='filter-list' id='filter-list-location'>
<!-- An empty div in which the filter list will be constructed -->
</div>
</div>
<table class='table table-striped table-condensed' data-toolbar='#button-toolbar' id='sublocation-table'></table>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -957,6 +957,12 @@ function loadStockLocationTable(table, options) {
switchable: true, switchable: true,
sortable: false, sortable: false,
}, },
{
field: 'pathstring',
title: '{% trans "Path" %}',
switchable: true,
sortable: false,
},
{ {
field: 'items', field: 'items',
title: '{% trans "Stock Items" %}', title: '{% trans "Stock Items" %}',

View File

@ -62,6 +62,28 @@ function getAvailableTableFilters(tableKey) {
}; };
} }
// Filters for "stock location" table
if (tableKey == "location") {
return {
cascade: {
type: 'bool',
title: '{% trans "Include sublocations" %}',
description: '{% trans "Include locations" %}',
}
};
}
// Filters for "part category" table
if (tableKey == "category") {
return {
cascade: {
type: 'bool',
title: '{% trans "Include subcategories" %}',
description: '{% trans "Include subcategories" %}',
}
};
}
// Filters for the "customer stock" table (really a subset of "stock") // Filters for the "customer stock" table (really a subset of "stock")
if (tableKey == "customerstock") { if (tableKey == "customerstock") {
return { return {