mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-01 11:10:54 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
@ -5,7 +5,6 @@ JSON API for the Stock app
|
||||
from django_filters.rest_framework import FilterSet, DjangoFilterBackend
|
||||
from django_filters import NumberFilter
|
||||
|
||||
from django.conf import settings
|
||||
from django.conf.urls import url, include
|
||||
from django.urls import reverse
|
||||
from django.db.models import Q
|
||||
@ -21,9 +20,7 @@ from .serializers import StockTrackingSerializer
|
||||
|
||||
from InvenTree.views import TreeSerializer
|
||||
from InvenTree.helpers import str2bool, isNull
|
||||
from InvenTree.status_codes import StockStatus
|
||||
|
||||
import os
|
||||
from decimal import Decimal, InvalidOperation
|
||||
|
||||
from rest_framework.serializers import ValidationError
|
||||
@ -317,13 +314,15 @@ class StockList(generics.ListCreateAPIView):
|
||||
- status: Filter by the StockItem status
|
||||
"""
|
||||
|
||||
serializer_class = StockItemSerializer
|
||||
|
||||
queryset = StockItem.objects.all()
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
|
||||
try:
|
||||
part_detail = str2bool(self.request.GET.get('part_detail', None))
|
||||
location_detail = str2bool(self.request.GET.get('location_detail', None))
|
||||
part_detail = str2bool(self.request.query_params.get('part_detail', None))
|
||||
location_detail = str2bool(self.request.query_params.get('location_detail', None))
|
||||
except AttributeError:
|
||||
part_detail = None
|
||||
location_detail = None
|
||||
@ -331,86 +330,25 @@ class StockList(generics.ListCreateAPIView):
|
||||
kwargs['part_detail'] = part_detail
|
||||
kwargs['location_detail'] = location_detail
|
||||
|
||||
# Ensure the request context is passed through
|
||||
kwargs['context'] = self.get_serializer_context()
|
||||
|
||||
return self.serializer_class(*args, **kwargs)
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
# TODO - Override the 'create' method for this view,
|
||||
# to allow the user to be recorded when a new StockItem object is created
|
||||
|
||||
queryset = self.filter_queryset(self.get_queryset())
|
||||
def get_queryset(self, *args, **kwargs):
|
||||
|
||||
# Instead of using the DRF serializer to LIST,
|
||||
# we will serialize the objects manually.
|
||||
# This is significantly faster
|
||||
queryset = super().get_queryset(*args, **kwargs)
|
||||
queryset = StockItemSerializer.prefetch_queryset(queryset)
|
||||
|
||||
data = queryset.values(
|
||||
'pk',
|
||||
'uid',
|
||||
'parent',
|
||||
'quantity',
|
||||
'serial',
|
||||
'batch',
|
||||
'status',
|
||||
'notes',
|
||||
'link',
|
||||
'location',
|
||||
'location__name',
|
||||
'location__description',
|
||||
'part',
|
||||
'part__IPN',
|
||||
'part__name',
|
||||
'part__revision',
|
||||
'part__description',
|
||||
'part__image',
|
||||
'part__category',
|
||||
'part__category__name',
|
||||
'part__category__description',
|
||||
'supplier_part',
|
||||
)
|
||||
return queryset
|
||||
|
||||
# Reduce the number of lookups we need to do for categories
|
||||
# Cache location lookups for this query
|
||||
locations = {}
|
||||
|
||||
for item in data:
|
||||
|
||||
img = item['part__image']
|
||||
|
||||
if img:
|
||||
# Use the thumbnail image instead
|
||||
fn, ext = os.path.splitext(img)
|
||||
|
||||
thumb = "{fn}.thumbnail{ext}".format(fn=fn, ext=ext)
|
||||
|
||||
thumb = os.path.join(settings.MEDIA_URL, thumb)
|
||||
else:
|
||||
thumb = ''
|
||||
|
||||
item['part__thumbnail'] = thumb
|
||||
|
||||
del item['part__image']
|
||||
|
||||
loc_id = item['location']
|
||||
|
||||
if loc_id:
|
||||
if loc_id not in locations:
|
||||
locations[loc_id] = StockLocation.objects.get(pk=loc_id).pathstring
|
||||
|
||||
item['location__path'] = locations[loc_id]
|
||||
else:
|
||||
item['location__path'] = None
|
||||
|
||||
item['status_text'] = StockStatus.label(item['status'])
|
||||
|
||||
return Response(data)
|
||||
|
||||
def get_queryset(self):
|
||||
"""
|
||||
If the query includes a particular location,
|
||||
we may wish to also request stock items from all child locations.
|
||||
"""
|
||||
def filter_queryset(self, queryset):
|
||||
|
||||
# Start with all objects
|
||||
stock_list = super(StockList, self).get_queryset()
|
||||
stock_list = super().filter_queryset(queryset)
|
||||
|
||||
# Filter out parts which are not actually "in stock"
|
||||
stock_list = stock_list.filter(customer=None, belongs_to=None)
|
||||
|
@ -8,7 +8,6 @@ from .models import StockItem, StockLocation
|
||||
from .models import StockItemTracking
|
||||
|
||||
from part.serializers import PartBriefSerializer
|
||||
from company.serializers import SupplierPartSerializer
|
||||
from InvenTree.serializers import UserSerializerBrief, InvenTreeModelSerializer
|
||||
|
||||
|
||||
@ -56,24 +55,43 @@ class StockItemSerializer(InvenTreeModelSerializer):
|
||||
- Includes serialization for the item location
|
||||
"""
|
||||
|
||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||
@staticmethod
|
||||
def prefetch_queryset(queryset):
|
||||
"""
|
||||
Prefetch related database tables,
|
||||
to reduce database hits.
|
||||
"""
|
||||
|
||||
return queryset.prefetch_related(
|
||||
'supplier_part',
|
||||
'supplier_part__supplier',
|
||||
'supplier_part__manufacturer',
|
||||
'location',
|
||||
'part',
|
||||
'tracking_info',
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def annotate_queryset(queryset):
|
||||
"""
|
||||
Add some extra annotations to the queryset,
|
||||
performing database queries as efficiently as possible.
|
||||
"""
|
||||
|
||||
# TODO
|
||||
pass
|
||||
|
||||
status_text = serializers.CharField(source='get_status_display', read_only=True)
|
||||
|
||||
part_name = serializers.CharField(source='get_part_name', read_only=True)
|
||||
|
||||
part_image = serializers.CharField(source='part__image', read_only=True)
|
||||
|
||||
tracking_items = serializers.IntegerField(source='tracking_info_count', read_only=True)
|
||||
|
||||
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
|
||||
location_detail = LocationBriefSerializer(source='location', many=False, read_only=True)
|
||||
supplier_detail = SupplierPartSerializer(source='supplier_part', many=False, read_only=True)
|
||||
|
||||
tracking_items = serializers.IntegerField(source='tracking_info_count', read_only=True)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
part_detail = kwargs.pop('part_detail', False)
|
||||
location_detail = kwargs.pop('location_detail', False)
|
||||
supplier_detail = kwargs.pop('supplier_detail', False)
|
||||
|
||||
super(StockItemSerializer, self).__init__(*args, **kwargs)
|
||||
|
||||
@ -83,9 +101,6 @@ class StockItemSerializer(InvenTreeModelSerializer):
|
||||
if location_detail is not True:
|
||||
self.fields.pop('location_detail')
|
||||
|
||||
if supplier_detail is not True:
|
||||
self.fields.pop('supplier_detail')
|
||||
|
||||
class Meta:
|
||||
model = StockItem
|
||||
fields = [
|
||||
@ -97,18 +112,14 @@ class StockItemSerializer(InvenTreeModelSerializer):
|
||||
'notes',
|
||||
'part',
|
||||
'part_detail',
|
||||
'part_name',
|
||||
'part_image',
|
||||
'pk',
|
||||
'quantity',
|
||||
'serial',
|
||||
'supplier_part',
|
||||
'supplier_detail',
|
||||
'status',
|
||||
'status_text',
|
||||
'tracking_items',
|
||||
'uid',
|
||||
'url',
|
||||
]
|
||||
|
||||
""" These fields are read-only in this context.
|
||||
|
Reference in New Issue
Block a user