2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-29 12:06:44 +00:00

Added update endpoints for StockItem

- Stocktake
- Take-Stock
This commit is contained in:
Oliver Walters 2017-04-20 22:08:27 +10:00
parent 7efb4c21d3
commit 2c28ef6b3c
4 changed files with 118 additions and 6 deletions

View File

@ -7,6 +7,8 @@ from supplier.models import SupplierPart
from part.models import Part from part.models import Part
from InvenTree.models import InvenTreeTree from InvenTree.models import InvenTreeTree
from datetime import datetime
class StockLocation(InvenTreeTree): class StockLocation(InvenTreeTree):
""" Organization tree for StockItem objects """ Organization tree for StockItem objects
@ -26,7 +28,7 @@ class StockItem(models.Model):
updated = models.DateField(auto_now=True) updated = models.DateField(auto_now=True)
# last time the stock was checked / counted # last time the stock was checked / counted
last_checked = models.DateField(blank=True, null=True) stocktake_date = models.DateField(blank=True, null=True)
review_needed = models.BooleanField(default=False) review_needed = models.BooleanField(default=False)
@ -59,6 +61,65 @@ class StockItem(models.Model):
# If stock item is incoming, an (optional) ETA field # If stock item is incoming, an (optional) ETA field
expected_arrival = models.DateField(null=True, blank=True) expected_arrival = models.DateField(null=True, blank=True)
infinite = models.BooleanField(default=False)
def stocktake(self, count):
""" Perform item stocktake.
When the quantity of an item is counted,
record the date of stocktake
"""
count = int(count)
if count < 0 or self.infinite:
return
self.quantity = count
self.stocktake_date = datetime.now().date()
self.save()
def take_stock(self, amount):
""" Take items from stock
This function can be called by initiating a ProjectRun,
or by manually taking the items from the stock location
"""
if self.infinite:
return
amount = int(amount)
if amount < 0:
raise ValueError("Stock amount must be positive")
q = self.quantity - amount
if q < 0:
q = 0
self.quantity = q
self.save()
def add_stock(self, amount):
""" Add items to stock
This function can be called by initiating a ProjectRun,
or by manually adding the items to the stock location
"""
amount = int(amount)
if self.infinite or amount == 0:
return
amount = int(amount)
q = self.quantity + amount
if q < 0:
q = 0
self.quantity = q
self.save()
def __str__(self): def __str__(self):
return "{n} x {part} @ {loc}".format( return "{n} x {part} @ {loc}".format(
n=self.quantity, n=self.quantity,

View File

@ -17,10 +17,22 @@ class StockItemSerializer(serializers.HyperlinkedModelSerializer):
'status', 'status',
'notes', 'notes',
'updated', 'updated',
'last_checked', 'stocktake_date',
'review_needed', 'review_needed',
'expected_arrival') 'expected_arrival')
""" These fields are read-only in this context.
They can be updated by accessing the appropriate API endpoints
"""
read_only_fields = ('stocktake_date', 'quantity',)
class StockQuantitySerializer(serializers.ModelSerializer):
class Meta:
model = StockItem
fields = ('quantity',)
class LocationSerializer(serializers.HyperlinkedModelSerializer): class LocationSerializer(serializers.HyperlinkedModelSerializer):
""" Detailed information about a stock location """ Detailed information about a stock location

View File

@ -1,10 +1,18 @@
from django.conf.urls import url from django.conf.urls import url, include
from . import views from . import views
stock_endpoints = [
url(r'^$', views.StockDetail.as_view(), name='stockitem-detail'),
url(r'^stocktake/?$', views.StockStocktakeEndpoint.as_view(), name='stockitem-stocktake'),
url(r'^add-stock/?$', views.AddStockEndpoint.as_view(), name='stockitem-add-stock'),
]
stock_urls = [ stock_urls = [
# Detail for a single stock item # Detail for a single stock item
url(r'^(?P<pk>[0-9]+)/?$', views.StockDetail.as_view(), name='stockitem-detail'), url(r'^(?P<pk>[0-9]+)/', include(stock_endpoints)),
# List all stock items, with optional filters # List all stock items, with optional filters
url(r'^\?.*/?$', views.StockList.as_view()), url(r'^\?.*/?$', views.StockList.as_view()),

View File

@ -1,11 +1,12 @@
from django_filters.rest_framework import FilterSet, DjangoFilterBackend from django_filters.rest_framework import FilterSet, DjangoFilterBackend
from django_filters import NumberFilter from django_filters import NumberFilter
from rest_framework import generics, permissions from rest_framework import generics, permissions, response
# from InvenTree.models import FilterChildren # from InvenTree.models import FilterChildren
from .models import StockLocation, StockItem, StockTracking from .models import StockLocation, StockItem, StockTracking
from .serializers import StockItemSerializer, LocationSerializer, StockTrackingSerializer from .serializers import StockItemSerializer, StockQuantitySerializer
from .serializers import LocationSerializer, StockTrackingSerializer
class StockDetail(generics.RetrieveUpdateDestroyAPIView): class StockDetail(generics.RetrieveUpdateDestroyAPIView):
@ -53,6 +54,36 @@ class StockList(generics.ListCreateAPIView):
filter_class = StockFilter filter_class = StockFilter
class StockStocktakeEndpoint(generics.UpdateAPIView):
queryset = StockItem.objects.all()
serializer_class = StockQuantitySerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def update(self, request, *args, **kwargs):
object = self.get_object()
object.stocktake(request.data['quantity'])
serializer = self.get_serializer(object)
return response.Response(serializer.data)
class AddStockEndpoint(generics.UpdateAPIView):
queryset = StockItem.objects.all()
serializer_class = StockQuantitySerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def update(self, request, *args, **kwargs):
object = self.get_object()
object.add_stock(request.data['quantity'])
serializer = self.get_serializer(object)
return response.Response(serializer.data)
class LocationDetail(generics.RetrieveUpdateDestroyAPIView): class LocationDetail(generics.RetrieveUpdateDestroyAPIView):
""" """