diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index fe669da5b9..ac4ba8b02e 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -40,6 +40,7 @@ from decimal import Decimal, InvalidOperation from datetime import datetime, timedelta +from rest_framework.pagination import LimitOffsetPagination from rest_framework.serializers import ValidationError from rest_framework.views import APIView from rest_framework.response import Response @@ -337,6 +338,8 @@ class StockList(generics.ListCreateAPIView): serializer_class = StockItemSerializer queryset = StockItem.objects.all() + pagination_class = LimitOffsetPagination + def create(self, request, *args, **kwargs): """ Create a new StockItem object via the API. @@ -381,7 +384,13 @@ class StockList(generics.ListCreateAPIView): queryset = self.filter_queryset(self.get_queryset()) - serializer = self.get_serializer(queryset, many=True) + page = self.paginate_queryset(queryset) + + if page is not None: + + serializer = self.get_serializer(page, many=True) + else: + serializer = self.get_serializer(queryset, many=True) data = serializer.data @@ -465,6 +474,8 @@ class StockList(generics.ListCreateAPIView): Note: b) is about 100x quicker than a), because the DRF framework adds a lot of cruft """ + if page is not None: + return self.get_paginated_response(data) if request.is_ajax(): return JsonResponse(data, safe=False) else: @@ -806,19 +817,6 @@ class StockList(generics.ListCreateAPIView): print("After error:", str(updated_after)) pass - # Limit number of results - limit = params.get('limit', None) - - if limit is not None: - try: - limit = int(limit) - - if limit > 0: - queryset = queryset[:limit] - - except (ValueError): - pass - # Also ensure that we pre-fecth all the related items queryset = queryset.prefetch_related( 'part', @@ -839,9 +837,12 @@ class StockList(generics.ListCreateAPIView): ordering_fields = [ 'part__name', + 'part__IPN', 'updated', 'stocktake_date', 'expiry_date', + 'quantity', + 'status', ] ordering = ['part__name'] @@ -851,7 +852,8 @@ class StockList(generics.ListCreateAPIView): 'batch', 'part__name', 'part__IPN', - 'part__description' + 'part__description', + 'location__name', ] diff --git a/InvenTree/templates/js/stock.js b/InvenTree/templates/js/stock.js index b115b8171c..660a09e5af 100644 --- a/InvenTree/templates/js/stock.js +++ b/InvenTree/templates/js/stock.js @@ -325,6 +325,12 @@ function loadStockTable(table, options) { grouping = options.grouping; } + // Explicitly disable part grouping functionality + // Might be able to add this in later on, + // but there is a bug which makes this crash if paginating on the server side. + // Ref: https://github.com/wenzhixin/bootstrap-table/issues/3250 + grouping = false; + table.inventreeTable({ method: 'get', formatNoMatches: function() { @@ -332,7 +338,7 @@ function loadStockTable(table, options) { }, url: options.url || "{% url 'api-stock-list' %}", queryParams: filters, - customSort: customGroupSorter, + sidePagination: 'server', name: 'stock', original: original, showColumns: true, @@ -516,6 +522,7 @@ function loadStockTable(table, options) { { field: 'part_detail.full_name', title: '{% trans "Part" %}', + sortName: 'part__name', sortable: true, switchable: false, formatter: function(value, row, index, field) { @@ -534,6 +541,7 @@ function loadStockTable(table, options) { { field: 'part_detail.IPN', title: 'IPN', + sortName: 'part__IPN', sortable: true, formatter: function(value, row, index, field) { return row.part_detail.IPN; @@ -542,7 +550,6 @@ function loadStockTable(table, options) { { field: 'part_detail.description', title: '{% trans "Description" %}', - sortable: true, formatter: function(value, row, index, field) { return row.part_detail.description; } @@ -654,8 +661,6 @@ function loadStockTable(table, options) { { field: 'packaging', title: '{% trans "Packaging" %}', - sortable: true, - searchable: true, }, { field: 'notes', diff --git a/InvenTree/templates/js/table_filters.js b/InvenTree/templates/js/table_filters.js index 39224c4ffe..fb76d2731b 100644 --- a/InvenTree/templates/js/table_filters.js +++ b/InvenTree/templates/js/table_filters.js @@ -1,5 +1,6 @@ {% load i18n %} {% load status_codes %} +{% load inventree_extras %} {% include "status_codes.html" with label='stock' options=StockStatus.list %} {% include "status_codes.html" with label='build' options=BuildStatus.list %} @@ -110,6 +111,8 @@ function getAvailableTableFilters(tableKey) { title: '{% trans "Depleted" %}', description: '{% trans "Show stock items which are depleted" %}', }, + {% settings_value "STOCK_ENABLE_EXPIRY" as expiry %} + {% if expiry %} expired: { type: 'bool', title: '{% trans "Expired" %}', @@ -120,6 +123,7 @@ function getAvailableTableFilters(tableKey) { title: '{% trans "Stale" %}', description: '{% trans "Show stock which is close to expiring" %}', }, + {% endif %} in_stock: { type: 'bool', title: '{% trans "In Stock" %}', diff --git a/InvenTree/templates/js/tables.js b/InvenTree/templates/js/tables.js index ceb38690a8..f09c683bff 100644 --- a/InvenTree/templates/js/tables.js +++ b/InvenTree/templates/js/tables.js @@ -93,7 +93,14 @@ function reloadTable(table, filters) { } } - options.queryParams = params; + options.queryParams = function(tableParams) { + + for (key in params) { + tableParams[key] = params[key]; + } + + return tableParams; + } table.bootstrapTable('refreshOptions', options); table.bootstrapTable('refresh'); @@ -126,9 +133,45 @@ $.fn.inventreeTable = function(options) { var varName = tableName + '-pagesize'; + // Pagingation options (can be server-side or client-side as specified by the caller) options.pagination = true; + options.paginationVAlign = 'both'; options.pageSize = inventreeLoad(varName, 25); options.pageList = [25, 50, 100, 250, 'all']; + options.totalField = 'count'; + options.dataField = 'results'; + + // Extract query params + var filters = options.queryParams || options.filters || {}; + + options.queryParams = function(params) { + for (var key in filters) { + params[key] = filters[key]; + } + + // Override the way that we ask the server to sort results + // It seems bootstrap-table does not offer a "native" way to do this... + if ('sort' in params) { + var order = params['order']; + + var ordering = params['sort'] || null; + + if (ordering) { + + if (order == 'desc') { + ordering = `-${ordering}`; + } + + params['ordering'] = ordering; + } + + delete params['sort']; + delete params['order']; + + } + + return params; + } options.rememberOrder = true;