mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Adds a DRF serializer for stock adjustments
- Currently the "StockCount" action has been transferred
This commit is contained in:
parent
8dcd2ab7ca
commit
f197d8b1da
@ -41,11 +41,7 @@ from order.serializers import POSerializer
|
|||||||
import common.settings
|
import common.settings
|
||||||
import common.models
|
import common.models
|
||||||
|
|
||||||
from .serializers import StockItemSerializer
|
import stock.serializers as StockSerializers
|
||||||
from .serializers import LocationSerializer, LocationBriefSerializer
|
|
||||||
from .serializers import StockTrackingSerializer
|
|
||||||
from .serializers import StockItemAttachmentSerializer
|
|
||||||
from .serializers import StockItemTestResultSerializer
|
|
||||||
|
|
||||||
from InvenTree.views import TreeSerializer
|
from InvenTree.views import TreeSerializer
|
||||||
from InvenTree.helpers import str2bool, isNull
|
from InvenTree.helpers import str2bool, isNull
|
||||||
@ -83,12 +79,12 @@ class StockDetail(generics.RetrieveUpdateDestroyAPIView):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
queryset = StockItem.objects.all()
|
queryset = StockItem.objects.all()
|
||||||
serializer_class = StockItemSerializer
|
serializer_class = StockSerializers.StockItemSerializer
|
||||||
|
|
||||||
def get_queryset(self, *args, **kwargs):
|
def get_queryset(self, *args, **kwargs):
|
||||||
|
|
||||||
queryset = super().get_queryset(*args, **kwargs)
|
queryset = super().get_queryset(*args, **kwargs)
|
||||||
queryset = StockItemSerializer.annotate_queryset(queryset)
|
queryset = StockSerializers.StockItemSerializer.annotate_queryset(queryset)
|
||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
@ -138,8 +134,6 @@ class StockAdjust(APIView):
|
|||||||
|
|
||||||
queryset = StockItem.objects.none()
|
queryset = StockItem.objects.none()
|
||||||
|
|
||||||
allow_missing_quantity = False
|
|
||||||
|
|
||||||
def get_items(self, request):
|
def get_items(self, request):
|
||||||
"""
|
"""
|
||||||
Return a list of items posted to the endpoint.
|
Return a list of items posted to the endpoint.
|
||||||
@ -206,23 +200,22 @@ class StockAdjust(APIView):
|
|||||||
self.notes = str(request.data.get('notes', ''))
|
self.notes = str(request.data.get('notes', ''))
|
||||||
|
|
||||||
|
|
||||||
class StockCount(StockAdjust):
|
class StockCount(generics.CreateAPIView):
|
||||||
"""
|
"""
|
||||||
Endpoint for counting stock (performing a stocktake).
|
Endpoint for counting stock (performing a stocktake).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
queryset = StockItem.objects.none()
|
||||||
|
|
||||||
self.get_items(request)
|
serializer_class = StockSerializers.StockCountSerializer
|
||||||
|
|
||||||
n = 0
|
def get_serializer_context(self):
|
||||||
|
|
||||||
for item in self.items:
|
context = super().get_serializer_context()
|
||||||
|
|
||||||
if item['item'].stocktake(item['quantity'], request.user, notes=self.notes):
|
context['request'] = self.request
|
||||||
n += 1
|
|
||||||
|
|
||||||
return Response({'success': _('Updated stock for {n} items').format(n=n)})
|
return context
|
||||||
|
|
||||||
|
|
||||||
class StockAdd(StockAdjust):
|
class StockAdd(StockAdjust):
|
||||||
@ -315,7 +308,7 @@ class StockLocationList(generics.ListCreateAPIView):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
queryset = StockLocation.objects.all()
|
queryset = StockLocation.objects.all()
|
||||||
serializer_class = LocationSerializer
|
serializer_class = StockSerializers.LocationSerializer
|
||||||
|
|
||||||
def filter_queryset(self, queryset):
|
def filter_queryset(self, queryset):
|
||||||
"""
|
"""
|
||||||
@ -517,7 +510,7 @@ class StockList(generics.ListCreateAPIView):
|
|||||||
- POST: Create a new StockItem
|
- POST: Create a new StockItem
|
||||||
"""
|
"""
|
||||||
|
|
||||||
serializer_class = StockItemSerializer
|
serializer_class = StockSerializers.StockItemSerializer
|
||||||
queryset = StockItem.objects.all()
|
queryset = StockItem.objects.all()
|
||||||
filterset_class = StockFilter
|
filterset_class = StockFilter
|
||||||
|
|
||||||
@ -639,7 +632,7 @@ class StockList(generics.ListCreateAPIView):
|
|||||||
|
|
||||||
# Serialize each StockLocation object
|
# Serialize each StockLocation object
|
||||||
for location in locations:
|
for location in locations:
|
||||||
location_map[location.pk] = LocationBriefSerializer(location).data
|
location_map[location.pk] = StockSerializers.LocationBriefSerializer(location).data
|
||||||
|
|
||||||
# Now update each StockItem with the related StockLocation data
|
# Now update each StockItem with the related StockLocation data
|
||||||
for stock_item in data:
|
for stock_item in data:
|
||||||
@ -665,7 +658,7 @@ class StockList(generics.ListCreateAPIView):
|
|||||||
|
|
||||||
queryset = super().get_queryset(*args, **kwargs)
|
queryset = super().get_queryset(*args, **kwargs)
|
||||||
|
|
||||||
queryset = StockItemSerializer.annotate_queryset(queryset)
|
queryset = StockSerializers.StockItemSerializer.annotate_queryset(queryset)
|
||||||
|
|
||||||
# Do not expose StockItem objects which are scheduled for deletion
|
# Do not expose StockItem objects which are scheduled for deletion
|
||||||
queryset = queryset.filter(scheduled_for_deletion=False)
|
queryset = queryset.filter(scheduled_for_deletion=False)
|
||||||
@ -954,7 +947,7 @@ class StockAttachmentList(generics.ListCreateAPIView, AttachmentMixin):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
queryset = StockItemAttachment.objects.all()
|
queryset = StockItemAttachment.objects.all()
|
||||||
serializer_class = StockItemAttachmentSerializer
|
serializer_class = StockSerializers.StockItemAttachmentSerializer
|
||||||
|
|
||||||
filter_backends = [
|
filter_backends = [
|
||||||
DjangoFilterBackend,
|
DjangoFilterBackend,
|
||||||
@ -973,7 +966,7 @@ class StockAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMix
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
queryset = StockItemAttachment.objects.all()
|
queryset = StockItemAttachment.objects.all()
|
||||||
serializer_class = StockItemAttachmentSerializer
|
serializer_class = StockSerializers.StockItemAttachmentSerializer
|
||||||
|
|
||||||
|
|
||||||
class StockItemTestResultDetail(generics.RetrieveUpdateDestroyAPIView):
|
class StockItemTestResultDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||||
@ -982,7 +975,7 @@ class StockItemTestResultDetail(generics.RetrieveUpdateDestroyAPIView):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
queryset = StockItemTestResult.objects.all()
|
queryset = StockItemTestResult.objects.all()
|
||||||
serializer_class = StockItemTestResultSerializer
|
serializer_class = StockSerializers.StockItemTestResultSerializer
|
||||||
|
|
||||||
|
|
||||||
class StockItemTestResultList(generics.ListCreateAPIView):
|
class StockItemTestResultList(generics.ListCreateAPIView):
|
||||||
@ -991,7 +984,7 @@ class StockItemTestResultList(generics.ListCreateAPIView):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
queryset = StockItemTestResult.objects.all()
|
queryset = StockItemTestResult.objects.all()
|
||||||
serializer_class = StockItemTestResultSerializer
|
serializer_class = StockSerializers.StockItemTestResultSerializer
|
||||||
|
|
||||||
filter_backends = [
|
filter_backends = [
|
||||||
DjangoFilterBackend,
|
DjangoFilterBackend,
|
||||||
@ -1039,7 +1032,7 @@ class StockTrackingDetail(generics.RetrieveAPIView):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
queryset = StockItemTracking.objects.all()
|
queryset = StockItemTracking.objects.all()
|
||||||
serializer_class = StockTrackingSerializer
|
serializer_class = StockSerializers.StockTrackingSerializer
|
||||||
|
|
||||||
|
|
||||||
class StockTrackingList(generics.ListAPIView):
|
class StockTrackingList(generics.ListAPIView):
|
||||||
@ -1052,7 +1045,7 @@ class StockTrackingList(generics.ListAPIView):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
queryset = StockItemTracking.objects.all()
|
queryset = StockItemTracking.objects.all()
|
||||||
serializer_class = StockTrackingSerializer
|
serializer_class = StockSerializers.StockTrackingSerializer
|
||||||
|
|
||||||
def get_serializer(self, *args, **kwargs):
|
def get_serializer(self, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
@ -1088,7 +1081,7 @@ class StockTrackingList(generics.ListAPIView):
|
|||||||
if 'location' in deltas:
|
if 'location' in deltas:
|
||||||
try:
|
try:
|
||||||
location = StockLocation.objects.get(pk=deltas['location'])
|
location = StockLocation.objects.get(pk=deltas['location'])
|
||||||
serializer = LocationSerializer(location)
|
serializer = StockSerializers.LocationSerializer(location)
|
||||||
deltas['location_detail'] = serializer.data
|
deltas['location_detail'] = serializer.data
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
@ -1097,7 +1090,7 @@ class StockTrackingList(generics.ListAPIView):
|
|||||||
if 'stockitem' in deltas:
|
if 'stockitem' in deltas:
|
||||||
try:
|
try:
|
||||||
stockitem = StockItem.objects.get(pk=deltas['stockitem'])
|
stockitem = StockItem.objects.get(pk=deltas['stockitem'])
|
||||||
serializer = StockItemSerializer(stockitem)
|
serializer = StockSerializers.StockItemSerializer(stockitem)
|
||||||
deltas['stockitem_detail'] = serializer.data
|
deltas['stockitem_detail'] = serializer.data
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
@ -1179,7 +1172,7 @@ class LocationDetail(generics.RetrieveUpdateDestroyAPIView):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
queryset = StockLocation.objects.all()
|
queryset = StockLocation.objects.all()
|
||||||
serializer_class = LocationSerializer
|
serializer_class = StockSerializers.LocationSerializer
|
||||||
|
|
||||||
|
|
||||||
stock_api_urls = [
|
stock_api_urls = [
|
||||||
|
@ -2,27 +2,29 @@
|
|||||||
JSON serializers for Stock app
|
JSON serializers for Stock app
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from rest_framework import serializers
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from decimal import Decimal
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.db.models.functions import Coalesce
|
||||||
|
from django.db.models import Case, When, Value
|
||||||
|
from django.db.models import BooleanField
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
from rest_framework import serializers
|
||||||
|
from rest_framework.serializers import ValidationError
|
||||||
|
|
||||||
|
from sql_util.utils import SubquerySum, SubqueryCount
|
||||||
|
|
||||||
from .models import StockItem, StockLocation
|
from .models import StockItem, StockLocation
|
||||||
from .models import StockItemTracking
|
from .models import StockItemTracking
|
||||||
from .models import StockItemAttachment
|
from .models import StockItemAttachment
|
||||||
from .models import StockItemTestResult
|
from .models import StockItemTestResult
|
||||||
|
|
||||||
from django.db.models.functions import Coalesce
|
|
||||||
|
|
||||||
from django.db.models import Case, When, Value
|
|
||||||
from django.db.models import BooleanField
|
|
||||||
from django.db.models import Q
|
|
||||||
|
|
||||||
from sql_util.utils import SubquerySum, SubqueryCount
|
|
||||||
|
|
||||||
from decimal import Decimal
|
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
|
|
||||||
import common.models
|
import common.models
|
||||||
from common.settings import currency_code_default, currency_code_mappings
|
from common.settings import currency_code_default, currency_code_mappings
|
||||||
|
|
||||||
@ -396,3 +398,92 @@ class StockTrackingSerializer(InvenTreeModelSerializer):
|
|||||||
'label',
|
'label',
|
||||||
'tracking_type',
|
'tracking_type',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class StockAdjustmentItemSerializer(serializers.Serializer):
|
||||||
|
"""
|
||||||
|
Serializer for a single StockItem within a stock adjument request.
|
||||||
|
|
||||||
|
Fields:
|
||||||
|
- item: StockItem object
|
||||||
|
- quantity: Numerical quantity
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
fields = [
|
||||||
|
'item',
|
||||||
|
'quantity'
|
||||||
|
]
|
||||||
|
|
||||||
|
pk = serializers.PrimaryKeyRelatedField(
|
||||||
|
queryset=StockItem.objects.all(),
|
||||||
|
many=False,
|
||||||
|
allow_null=False,
|
||||||
|
required=True,
|
||||||
|
label=_('StockItem primary key value')
|
||||||
|
)
|
||||||
|
|
||||||
|
quantity = serializers.DecimalField(
|
||||||
|
max_digits=15,
|
||||||
|
decimal_places=5,
|
||||||
|
min_value=0,
|
||||||
|
required=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class StockAdjustmentSerializer(serializers.Serializer):
|
||||||
|
"""
|
||||||
|
Base class for managing stock adjustment actions via the API
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
fields = [
|
||||||
|
'items',
|
||||||
|
'notes',
|
||||||
|
]
|
||||||
|
|
||||||
|
items = StockAdjustmentItemSerializer(many=True)
|
||||||
|
|
||||||
|
notes = serializers.CharField(
|
||||||
|
required=False,
|
||||||
|
allow_blank=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
def validate(self, data):
|
||||||
|
|
||||||
|
super().validate(data)
|
||||||
|
|
||||||
|
items = data.get('items', [])
|
||||||
|
|
||||||
|
if len(items) == 0:
|
||||||
|
raise ValidationError(_("A list of stock items must be provided"))
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
class StockCountSerializer(StockAdjustmentSerializer):
|
||||||
|
"""
|
||||||
|
Serializer for counting stock items
|
||||||
|
"""
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
"""
|
||||||
|
Perform the database transactions to count the stock
|
||||||
|
"""
|
||||||
|
request = self.context['request']
|
||||||
|
|
||||||
|
data = self.validated_data
|
||||||
|
items = data['items']
|
||||||
|
notes = data['notes']
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
|
for item in items:
|
||||||
|
|
||||||
|
stock_item = item['pk']
|
||||||
|
quantity = item['quantity']
|
||||||
|
|
||||||
|
stock_item.stocktake(
|
||||||
|
quantity,
|
||||||
|
request.user,
|
||||||
|
notes=notes
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user