Merge pull request #739 from SchrodingersGat/api-consolidation

Api consolidation
This commit is contained in:
Oliver 2020-04-20 09:55:16 +10:00 committed by GitHub
commit 85e20041c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 178 additions and 69 deletions

View File

@ -104,21 +104,23 @@ function removePurchaseOrderLineItem(e) {
function loadPurchaseOrderTable(table, options) {
/* Create a purchase-order table */
var params = options.params || {};
options.params = options.params || {};
options.params['supplier_detail'] = true;
var filters = loadTableFilters("order");
for (var key in params) {
filters[key] = params[key];
for (var key in options.params) {
filters[key] = options.params[key];
}
setupFilterList("order", table);
setupFilterList("order", $(table));
$(table).inventreeTable({
url: options.url,
queryParams: filters,
groupBy: false,
original: params,
original: options.params,
formatNoMatches: function() { return "No purchase orders found"; },
columns: [
{
@ -131,15 +133,15 @@ function loadPurchaseOrderTable(table, options) {
field: 'reference',
title: 'Purchase Order',
formatter: function(value, row, index, field) {
return renderLink(value, "/order/purchase-order/" + row.pk + "/");
return renderLink(value, `/order/purchase-order/${row.pk}/`);
}
},
{
sortable: true,
field: 'supplier',
field: 'supplier_detail',
title: 'Supplier',
formatter: function(value, row, index, field) {
return imageHoverIcon(row.supplier__image) + renderLink(row.supplier__name, '/company/' + value + '/purchase-orders/');
return imageHoverIcon(row.supplier_detail.image) + renderLink(row.supplier_detail.name, `/company/${row.supplier}/purchase-orders/`);
}
},
{
@ -162,7 +164,7 @@ function loadPurchaseOrderTable(table, options) {
},
{
sortable: true,
field: 'lines',
field: 'line_items',
title: 'Items'
},
],

View File

@ -8,14 +8,10 @@ from __future__ import unicode_literals
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import generics, permissions
from rest_framework import filters
from rest_framework.response import Response
from django.conf import settings
from django.conf.urls import url
from InvenTree.status_codes import OrderStatus
import os
from InvenTree.helpers import str2bool
from part.models import Part
from company.models import SupplierPart
@ -34,66 +30,66 @@ class POList(generics.ListCreateAPIView):
queryset = PurchaseOrder.objects.all()
serializer_class = POSerializer
def list(self, request, *args, **kwargs):
def get_serializer(self, *args, **kwargs):
queryset = self.get_queryset().prefetch_related('supplier', 'lines')
try:
kwargs['supplier_detail'] = str2bool(self.request.query_params.get('supplier_detail', False))
except AttributeError:
pass
queryset = self.filter_queryset(queryset)
# Ensure the request context is passed through
kwargs['context'] = self.get_serializer_context()
return self.serializer_class(*args, **kwargs)
def get_queryset(self, *args, **kwargs):
queryset = super().get_queryset(*args, **kwargs)
queryset = queryset.prefetch_related(
'supplier',
'lines',
)
queryset = POSerializer.annotate_queryset(queryset)
return queryset
def filter_queryset(self, queryset):
# Perform basic filtering
queryset = super().filter_queryset(queryset)
params = self.request.query_params
# Special filtering for 'status' field
if 'status' in request.GET:
status = request.GET['status']
status = params.get('status', None)
if status is not None:
# First attempt to filter by integer value
try:
status = int(status)
queryset = queryset.filter(status=status)
except ValueError:
try:
value = OrderStatus.value(status)
queryset = queryset.filter(status=value)
except ValueError:
pass
queryset = queryset.filter(status=status)
# Attempt to filter by part
if 'part' in request.GET:
part = params.get('part', None)
if part is not None:
try:
part = Part.objects.get(pk=request.GET['part'])
part = Part.objects.get(pk=part)
queryset = queryset.filter(id__in=[p.id for p in part.purchase_orders()])
except (Part.DoesNotExist, ValueError):
pass
# Attempt to filter by supplier part
if 'supplier_part' in request.GET:
supplier_part = params.get('supplier_part', None)
if supplier_part is not None:
try:
supplier_part = SupplierPart.objects.get(pk=request.GET['supplier_part'])
supplier_part = SupplierPart.objects.get(pk=supplier_part)
queryset = queryset.filter(id__in=[p.id for p in supplier_part.purchase_orders()])
except (ValueError, SupplierPart.DoesNotExist):
pass
data = queryset.values(
'pk',
'supplier',
'supplier_reference',
'supplier__name',
'supplier__image',
'reference',
'description',
'link',
'status',
'notes',
'creation_date',
)
for item in data:
order = queryset.get(pk=item['pk'])
item['supplier__image'] = os.path.join(settings.MEDIA_URL, item['supplier__image'])
item['status_text'] = OrderStatus.label(item['status'])
item['lines'] = order.lines.count()
return Response(data)
return queryset
permission_classes = [
permissions.IsAuthenticated,
@ -123,6 +119,31 @@ class PODetail(generics.RetrieveUpdateAPIView):
queryset = PurchaseOrder.objects.all()
serializer_class = POSerializer
def get_serializer(self, *args, **kwargs):
try:
kwargs['supplier_detail'] = str2bool(self.request.query_params.get('supplier_detail', False))
except AttributeError:
pass
# Ensure the request context is passed through
kwargs['context'] = self.get_serializer_context()
return self.serializer_class(*args, **kwargs)
def get_queryset(self, *args, **kwargs):
queryset = super().get_queryset(*args, **kwargs)
queryset = queryset.prefetch_related(
'supplier',
'lines',
)
queryset = POSerializer.annotate_queryset(queryset)
return queryset
permission_classes = [
permissions.IsAuthenticated
]

View File

@ -5,7 +5,12 @@ JSON serializers for the Order API
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from rest_framework import serializers
from django.db.models import Count
from InvenTree.serializers import InvenTreeModelSerializer
from company.serializers import CompanyBriefSerializer
from .models import PurchaseOrder, PurchaseOrderLineItem
@ -13,17 +18,48 @@ from .models import PurchaseOrder, PurchaseOrderLineItem
class POSerializer(InvenTreeModelSerializer):
""" Serializes an Order object """
def __init__(self, *args, **kwargs):
supplier_detail = kwargs.pop('supplier_detail', False)
super().__init__(*args, **kwargs)
if supplier_detail is not True:
self.fields.pop('supplier_detail')
@staticmethod
def annotate_queryset(queryset):
"""
Add extra information to the queryset
"""
return queryset.annotate(
line_items=Count('lines'),
)
supplier_detail = CompanyBriefSerializer(source='supplier', many=False, read_only=True)
line_items = serializers.IntegerField(read_only=True)
status_text = serializers.CharField(source='get_status_display', read_only=True)
class Meta:
model = PurchaseOrder
fields = [
'pk',
'supplier',
'supplier_reference',
'reference',
'issue_date',
'complete_date',
'creation_date',
'description',
'line_items',
'link',
'reference',
'supplier',
'supplier_detail',
'supplier_reference',
'status',
'status_text',
'notes',
]

View File

@ -134,11 +134,41 @@ class PartDetail(generics.RetrieveUpdateAPIView):
queryset = Part.objects.all()
serializer_class = part_serializers.PartSerializer
starred_parts = None
def get_queryset(self, *args, **kwargs):
queryset = super().get_queryset(*args, **kwargs)
queryset = part_serializers.PartSerializer.prefetch_queryset(queryset)
queryset = part_serializers.PartSerializer.annotate_queryset(queryset)
return queryset
permission_classes = [
permissions.IsAuthenticated,
]
def get_serializer(self, *args, **kwargs):
try:
cat_detail = str2bool(self.request.query_params.get('category_detail', False))
except AttributeError:
cat_detail = None
# Ensure the request context is passed through
kwargs['context'] = self.get_serializer_context()
kwargs['category_detail'] = cat_detail
# Pass a list of "starred" parts fo the current user to the serializer
# We do this to reduce the number of database queries required!
if self.starred_parts is None and self.request is not None:
self.starred_parts = [star.part for star in self.request.user.starred_parts.all()]
kwargs['starred_parts'] = self.starred_parts
return self.serializer_class(*args, **kwargs)
class PartList(generics.ListCreateAPIView):
""" API endpoint for accessing a list of Part objects

View File

@ -58,20 +58,28 @@ class StockDetail(generics.RetrieveUpdateDestroyAPIView):
serializer_class = StockItemSerializer
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self, *args, **kwargs):
queryset = super().get_queryset(*args, **kwargs)
queryset = StockItemSerializer.prefetch_queryset(queryset)
queryset = StockItemSerializer.annotate_queryset(queryset)
return queryset
def get_serializer(self, *args, **kwargs):
try:
kwargs['part_detail'] = str2bool(self.request.GET.get('part_detail', False))
kwargs['part_detail'] = str2bool(self.request.query_params.get('part_detail', False))
except AttributeError:
pass
try:
kwargs['location_detail'] = str2bool(self.request.GET.get('location_detail', False))
kwargs['location_detail'] = str2bool(self.request.query_params.get('location_detail', False))
except AttributeError:
pass
try:
kwargs['supplier_detail'] = str2bool(self.request.GET.get('supplier_detail', False))
kwargs['supplier_part_detail'] = str2bool(self.request.query_params.get('supplier_detail', False))
except AttributeError:
pass
@ -321,14 +329,19 @@ class StockList(generics.ListCreateAPIView):
def get_serializer(self, *args, **kwargs):
try:
part_detail = str2bool(self.request.query_params.get('part_detail', None))
location_detail = str2bool(self.request.query_params.get('location_detail', None))
kwargs['part_detail'] = str2bool(self.request.query_params.get('part_detail', None))
except AttributeError:
part_detail = None
location_detail = None
pass
kwargs['part_detail'] = part_detail
kwargs['location_detail'] = location_detail
try:
kwargs['location_detail'] = str2bool(self.request.query_params.get('location_detail', None))
except AttributeError:
pass
try:
kwargs['supplier_part_detail'] = str2bool(self.request.query_params.get('supplier_part_detail', None))
except AttributeError:
pass
# Ensure the request context is passed through
kwargs['context'] = self.get_serializer_context()

View File

@ -7,6 +7,7 @@ from rest_framework import serializers
from .models import StockItem, StockLocation
from .models import StockItemTracking
from company.serializers import SupplierPartSerializer
from part.serializers import PartBriefSerializer
from InvenTree.serializers import UserSerializerBrief, InvenTreeModelSerializer
@ -78,13 +79,14 @@ class StockItemSerializer(InvenTreeModelSerializer):
performing database queries as efficiently as possible.
"""
# TODO
pass
# TODO - Add custom annotated fields
return queryset
status_text = serializers.CharField(source='get_status_display', read_only=True)
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
location_detail = LocationBriefSerializer(source='location', many=False, read_only=True)
supplier_part_detail = SupplierPartSerializer(source='supplier_part', many=False, read_only=True)
tracking_items = serializers.IntegerField(source='tracking_info_count', read_only=True)
@ -92,6 +94,7 @@ class StockItemSerializer(InvenTreeModelSerializer):
part_detail = kwargs.pop('part_detail', False)
location_detail = kwargs.pop('location_detail', False)
supplier_part_detail = kwargs.pop('supplier_part_detail', False)
super(StockItemSerializer, self).__init__(*args, **kwargs)
@ -101,6 +104,9 @@ class StockItemSerializer(InvenTreeModelSerializer):
if location_detail is not True:
self.fields.pop('location_detail')
if supplier_part_detail is not True:
self.fields.pop('supplier_part_detail')
class Meta:
model = StockItem
fields = [
@ -116,6 +122,7 @@ class StockItemSerializer(InvenTreeModelSerializer):
'quantity',
'serial',
'supplier_part',
'supplier_part_detail',
'status',
'status_text',
'tracking_items',