From 0441eb4c38e63c214453a801cfc3d5ca5ed74a18 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 14 Apr 2017 12:54:34 +1000 Subject: [PATCH] API improvements for Stock app --- InvenTree/stock/serializers.py | 10 +---- InvenTree/stock/urls.py | 25 +++++++----- InvenTree/stock/views.py | 70 +++++++++++++++++++++++++++++----- 3 files changed, 76 insertions(+), 29 deletions(-) diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index 0e06115d39..a542edf150 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -35,18 +35,10 @@ class LocationDetailSerializer(serializers.ModelSerializer): """ Detailed information about a stock location """ - # List of all stock items in this location - items = StockItemSerializer(many=True, read_only=True) - - # List of all child locations under this one - children = LocationBriefSerializer(many=True, read_only=True) - class Meta: model = StockLocation fields = ('pk', 'name', 'description', 'parent', - 'path', - 'children', - 'items') + 'path') diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index c7a27fe560..b3496e5768 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -1,15 +1,20 @@ -from django.conf.urls import url +from django.conf.urls import url, include from . import views -urlpatterns = [ - # List all stock quantities for a given part - url(r'^part/(?P[0-9]+)$', views.PartStockDetail.as_view()), +locpatterns = [ + url(r'^(?P[0-9]+)/?$', views.LocationDetail.as_view()), - # List all stock items in a given location - url(r'^location/(?P[0-9]+)$', views.LocationDetail.as_view()), - - # List all top-level locations - url(r'^location/$', views.LocationList.as_view()), - url(r'^$', views.LocationList.as_view()) + url(r'^\?*[^/]*/?$', views.LocationList.as_view()) +] + +urlpatterns = [ + # Stock location urls + url(r'^location/?', include(locpatterns)), + + # Detail for a single stock item + url(r'^(?P[0-9]+)$', views.StockDetail.as_view()), + + # List all stock items, with optional filters + url(r'^\?*[^/]*/?$', views.StockList.as_view()), ] diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 8100abdb92..c7d5cfe8b5 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -1,22 +1,55 @@ -from rest_framework import generics +from rest_framework import generics, permissions +import django_filters from .models import StockLocation, StockItem - from .serializers import StockItemSerializer, LocationDetailSerializer -class PartStockDetail(generics.ListCreateAPIView): - """ Return a list of all stockitems for a given part - """ +class StockDetail(generics.RetrieveUpdateDestroyAPIView): + queryset = StockItem.objects.all() serializer_class = StockItemSerializer + +class StockFilter(django_filters.rest_framework.FilterSet): + min_stock = django_filters.NumberFilter(name='quantity', lookup_expr='gte') + max_stock = django_filters.NumberFilter(name='quantity', lookup_expr='lte') + + class Meta: + model = StockItem + fields = ['quantity'] + +class StockList(generics.ListCreateAPIView): + + serializer_class = StockItemSerializer + permission_classes = (permissions.IsAuthenticatedOrReadOnly,) + filter_backends = (django_filters.rest_framework.DjangoFilterBackend,) + filter_class = StockFilter + def get_queryset(self): - part_id = self.kwargs['part'] - return StockItem.objects.filter(part=part_id) + items = StockItem.objects.all() + # Specify a particular part + part_id = self.request.query_params.get('part', None) + if part_id: + items = items.filter(part=part_id) -class LocationDetail(generics.RetrieveAPIView): + # Specify a particular location + loc_id = self.request.query_params.get('location', None) + + if loc_id: + items = items.filter(location=loc_id) + + return items + + def create(self, request, *args, **kwargs): + # If the PART parameter is passed in the URL, use that + part_id = self.request.query_params.get('part', None) + if part_id: + request.data['part'] = part_id + return super(StockList, self).create(request, *args, **kwargs) + +class LocationDetail(generics.RetrieveUpdateDestroyAPIView): """ Return information on a specific stock location """ @@ -24,10 +57,27 @@ class LocationDetail(generics.RetrieveAPIView): serializer_class = LocationDetailSerializer -class LocationList(generics.ListAPIView): +class LocationList(generics.ListCreateAPIView): """ Return a list of top-level locations Locations are considered "top-level" if they do not have a parent """ - queryset = StockLocation.objects.filter(parent=None) + def get_queryset(self): + params = self.request.query_params + + locations = StockLocation.objects.all() + + parent_id = params.get('parent', None) + + if parent_id and parent_id.lower() in ['none', 'false', 'null', 'top']: + locations = locations.filter(parent=None) + else: + try: + parent_id_num = int(parent_id) + locations = locations.filter(parent=parent_id_num) + except: + pass + + return locations + serializer_class = LocationDetailSerializer