mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge pull request #739 from SchrodingersGat/api-consolidation
Api consolidation
This commit is contained in:
commit
85e20041c7
@ -104,21 +104,23 @@ function removePurchaseOrderLineItem(e) {
|
|||||||
function loadPurchaseOrderTable(table, options) {
|
function loadPurchaseOrderTable(table, options) {
|
||||||
/* Create a purchase-order table */
|
/* Create a purchase-order table */
|
||||||
|
|
||||||
var params = options.params || {};
|
options.params = options.params || {};
|
||||||
|
|
||||||
|
options.params['supplier_detail'] = true;
|
||||||
|
|
||||||
var filters = loadTableFilters("order");
|
var filters = loadTableFilters("order");
|
||||||
|
|
||||||
for (var key in params) {
|
for (var key in options.params) {
|
||||||
filters[key] = params[key];
|
filters[key] = options.params[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
setupFilterList("order", table);
|
setupFilterList("order", $(table));
|
||||||
|
|
||||||
$(table).inventreeTable({
|
$(table).inventreeTable({
|
||||||
url: options.url,
|
url: options.url,
|
||||||
queryParams: filters,
|
queryParams: filters,
|
||||||
groupBy: false,
|
groupBy: false,
|
||||||
original: params,
|
original: options.params,
|
||||||
formatNoMatches: function() { return "No purchase orders found"; },
|
formatNoMatches: function() { return "No purchase orders found"; },
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
@ -131,15 +133,15 @@ function loadPurchaseOrderTable(table, options) {
|
|||||||
field: 'reference',
|
field: 'reference',
|
||||||
title: 'Purchase Order',
|
title: 'Purchase Order',
|
||||||
formatter: function(value, row, index, field) {
|
formatter: function(value, row, index, field) {
|
||||||
return renderLink(value, "/order/purchase-order/" + row.pk + "/");
|
return renderLink(value, `/order/purchase-order/${row.pk}/`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
sortable: true,
|
sortable: true,
|
||||||
field: 'supplier',
|
field: 'supplier_detail',
|
||||||
title: 'Supplier',
|
title: 'Supplier',
|
||||||
formatter: function(value, row, index, field) {
|
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,
|
sortable: true,
|
||||||
field: 'lines',
|
field: 'line_items',
|
||||||
title: 'Items'
|
title: 'Items'
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -8,14 +8,10 @@ from __future__ import unicode_literals
|
|||||||
from django_filters.rest_framework import DjangoFilterBackend
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from rest_framework import generics, permissions
|
from rest_framework import generics, permissions
|
||||||
from rest_framework import filters
|
from rest_framework import filters
|
||||||
from rest_framework.response import Response
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
|
||||||
from InvenTree.status_codes import OrderStatus
|
from InvenTree.helpers import str2bool
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from part.models import Part
|
from part.models import Part
|
||||||
from company.models import SupplierPart
|
from company.models import SupplierPart
|
||||||
@ -34,66 +30,66 @@ class POList(generics.ListCreateAPIView):
|
|||||||
queryset = PurchaseOrder.objects.all()
|
queryset = PurchaseOrder.objects.all()
|
||||||
serializer_class = POSerializer
|
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
|
# Special filtering for 'status' field
|
||||||
if 'status' in request.GET:
|
status = params.get('status', None)
|
||||||
status = request.GET['status']
|
|
||||||
|
|
||||||
|
if status is not None:
|
||||||
# First attempt to filter by integer value
|
# First attempt to filter by integer value
|
||||||
try:
|
queryset = queryset.filter(status=status)
|
||||||
status = int(status)
|
|
||||||
queryset = queryset.filter(status=status)
|
|
||||||
except ValueError:
|
|
||||||
try:
|
|
||||||
value = OrderStatus.value(status)
|
|
||||||
queryset = queryset.filter(status=value)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Attempt to filter by part
|
# Attempt to filter by part
|
||||||
if 'part' in request.GET:
|
part = params.get('part', None)
|
||||||
|
|
||||||
|
if part is not None:
|
||||||
try:
|
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()])
|
queryset = queryset.filter(id__in=[p.id for p in part.purchase_orders()])
|
||||||
except (Part.DoesNotExist, ValueError):
|
except (Part.DoesNotExist, ValueError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Attempt to filter by supplier part
|
# 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:
|
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()])
|
queryset = queryset.filter(id__in=[p.id for p in supplier_part.purchase_orders()])
|
||||||
except (ValueError, SupplierPart.DoesNotExist):
|
except (ValueError, SupplierPart.DoesNotExist):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
data = queryset.values(
|
return queryset
|
||||||
'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)
|
|
||||||
|
|
||||||
permission_classes = [
|
permission_classes = [
|
||||||
permissions.IsAuthenticated,
|
permissions.IsAuthenticated,
|
||||||
@ -123,6 +119,31 @@ class PODetail(generics.RetrieveUpdateAPIView):
|
|||||||
queryset = PurchaseOrder.objects.all()
|
queryset = PurchaseOrder.objects.all()
|
||||||
serializer_class = POSerializer
|
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 = [
|
permission_classes = [
|
||||||
permissions.IsAuthenticated
|
permissions.IsAuthenticated
|
||||||
]
|
]
|
||||||
|
@ -5,7 +5,12 @@ JSON serializers for the Order API
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from django.db.models import Count
|
||||||
|
|
||||||
from InvenTree.serializers import InvenTreeModelSerializer
|
from InvenTree.serializers import InvenTreeModelSerializer
|
||||||
|
from company.serializers import CompanyBriefSerializer
|
||||||
|
|
||||||
from .models import PurchaseOrder, PurchaseOrderLineItem
|
from .models import PurchaseOrder, PurchaseOrderLineItem
|
||||||
|
|
||||||
@ -13,17 +18,48 @@ from .models import PurchaseOrder, PurchaseOrderLineItem
|
|||||||
class POSerializer(InvenTreeModelSerializer):
|
class POSerializer(InvenTreeModelSerializer):
|
||||||
""" Serializes an Order object """
|
""" 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:
|
class Meta:
|
||||||
model = PurchaseOrder
|
model = PurchaseOrder
|
||||||
|
|
||||||
fields = [
|
fields = [
|
||||||
'pk',
|
'pk',
|
||||||
'supplier',
|
'issue_date',
|
||||||
'supplier_reference',
|
'complete_date',
|
||||||
'reference',
|
'creation_date',
|
||||||
'description',
|
'description',
|
||||||
|
'line_items',
|
||||||
'link',
|
'link',
|
||||||
|
'reference',
|
||||||
|
'supplier',
|
||||||
|
'supplier_detail',
|
||||||
|
'supplier_reference',
|
||||||
'status',
|
'status',
|
||||||
|
'status_text',
|
||||||
'notes',
|
'notes',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -134,11 +134,41 @@ class PartDetail(generics.RetrieveUpdateAPIView):
|
|||||||
|
|
||||||
queryset = Part.objects.all()
|
queryset = Part.objects.all()
|
||||||
serializer_class = part_serializers.PartSerializer
|
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 = [
|
permission_classes = [
|
||||||
permissions.IsAuthenticated,
|
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):
|
class PartList(generics.ListCreateAPIView):
|
||||||
""" API endpoint for accessing a list of Part objects
|
""" API endpoint for accessing a list of Part objects
|
||||||
|
@ -58,20 +58,28 @@ class StockDetail(generics.RetrieveUpdateDestroyAPIView):
|
|||||||
serializer_class = StockItemSerializer
|
serializer_class = StockItemSerializer
|
||||||
permission_classes = (permissions.IsAuthenticated,)
|
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):
|
def get_serializer(self, *args, **kwargs):
|
||||||
|
|
||||||
try:
|
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:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
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:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
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:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -321,14 +329,19 @@ class StockList(generics.ListCreateAPIView):
|
|||||||
def get_serializer(self, *args, **kwargs):
|
def get_serializer(self, *args, **kwargs):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
part_detail = str2bool(self.request.query_params.get('part_detail', None))
|
kwargs['part_detail'] = str2bool(self.request.query_params.get('part_detail', None))
|
||||||
location_detail = str2bool(self.request.query_params.get('location_detail', None))
|
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
part_detail = None
|
pass
|
||||||
location_detail = None
|
|
||||||
|
|
||||||
kwargs['part_detail'] = part_detail
|
try:
|
||||||
kwargs['location_detail'] = location_detail
|
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
|
# Ensure the request context is passed through
|
||||||
kwargs['context'] = self.get_serializer_context()
|
kwargs['context'] = self.get_serializer_context()
|
||||||
|
@ -7,6 +7,7 @@ from rest_framework import serializers
|
|||||||
from .models import StockItem, StockLocation
|
from .models import StockItem, StockLocation
|
||||||
from .models import StockItemTracking
|
from .models import StockItemTracking
|
||||||
|
|
||||||
|
from company.serializers import SupplierPartSerializer
|
||||||
from part.serializers import PartBriefSerializer
|
from part.serializers import PartBriefSerializer
|
||||||
from InvenTree.serializers import UserSerializerBrief, InvenTreeModelSerializer
|
from InvenTree.serializers import UserSerializerBrief, InvenTreeModelSerializer
|
||||||
|
|
||||||
@ -78,13 +79,14 @@ class StockItemSerializer(InvenTreeModelSerializer):
|
|||||||
performing database queries as efficiently as possible.
|
performing database queries as efficiently as possible.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# TODO
|
# TODO - Add custom annotated fields
|
||||||
pass
|
return queryset
|
||||||
|
|
||||||
status_text = serializers.CharField(source='get_status_display', read_only=True)
|
status_text = serializers.CharField(source='get_status_display', read_only=True)
|
||||||
|
|
||||||
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
|
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
|
||||||
location_detail = LocationBriefSerializer(source='location', 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)
|
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)
|
part_detail = kwargs.pop('part_detail', False)
|
||||||
location_detail = kwargs.pop('location_detail', False)
|
location_detail = kwargs.pop('location_detail', False)
|
||||||
|
supplier_part_detail = kwargs.pop('supplier_part_detail', False)
|
||||||
|
|
||||||
super(StockItemSerializer, self).__init__(*args, **kwargs)
|
super(StockItemSerializer, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
@ -101,6 +104,9 @@ class StockItemSerializer(InvenTreeModelSerializer):
|
|||||||
if location_detail is not True:
|
if location_detail is not True:
|
||||||
self.fields.pop('location_detail')
|
self.fields.pop('location_detail')
|
||||||
|
|
||||||
|
if supplier_part_detail is not True:
|
||||||
|
self.fields.pop('supplier_part_detail')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = StockItem
|
model = StockItem
|
||||||
fields = [
|
fields = [
|
||||||
@ -116,6 +122,7 @@ class StockItemSerializer(InvenTreeModelSerializer):
|
|||||||
'quantity',
|
'quantity',
|
||||||
'serial',
|
'serial',
|
||||||
'supplier_part',
|
'supplier_part',
|
||||||
|
'supplier_part_detail',
|
||||||
'status',
|
'status',
|
||||||
'status_text',
|
'status_text',
|
||||||
'tracking_items',
|
'tracking_items',
|
||||||
|
Loading…
Reference in New Issue
Block a user