2019-08-02 11:44:56 +00:00
|
|
|
"""
|
|
|
|
JSON API for the Order app
|
|
|
|
"""
|
|
|
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
|
|
|
from django_filters.rest_framework import DjangoFilterBackend
|
2020-10-05 13:36:55 +00:00
|
|
|
from rest_framework import generics
|
2019-12-09 10:19:35 +00:00
|
|
|
from rest_framework import filters
|
2019-08-02 11:44:56 +00:00
|
|
|
|
2020-05-11 13:41:57 +00:00
|
|
|
from django.conf.urls import url, include
|
2019-08-02 11:44:56 +00:00
|
|
|
|
2020-04-19 23:41:21 +00:00
|
|
|
from InvenTree.helpers import str2bool
|
2020-05-12 11:40:42 +00:00
|
|
|
from InvenTree.api import AttachmentMixin
|
2020-06-05 02:08:47 +00:00
|
|
|
from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus
|
2019-12-09 10:19:35 +00:00
|
|
|
|
2019-12-09 10:55:00 +00:00
|
|
|
from part.models import Part
|
2020-02-12 01:44:52 +00:00
|
|
|
from company.models import SupplierPart
|
2019-12-09 10:55:00 +00:00
|
|
|
|
2019-08-02 11:44:56 +00:00
|
|
|
from .models import PurchaseOrder, PurchaseOrderLineItem
|
2020-05-11 13:41:57 +00:00
|
|
|
from .models import PurchaseOrderAttachment
|
|
|
|
from .serializers import POSerializer, POLineItemSerializer, POAttachmentSerializer
|
2019-08-02 11:44:56 +00:00
|
|
|
|
2020-04-22 12:24:06 +00:00
|
|
|
from .models import SalesOrder, SalesOrderLineItem
|
2020-05-11 13:41:57 +00:00
|
|
|
from .models import SalesOrderAttachment
|
|
|
|
from .serializers import SalesOrderSerializer, SOLineItemSerializer, SOAttachmentSerializer
|
2020-04-20 10:11:21 +00:00
|
|
|
|
2019-08-02 11:44:56 +00:00
|
|
|
|
|
|
|
class POList(generics.ListCreateAPIView):
|
2020-04-20 10:11:21 +00:00
|
|
|
""" API endpoint for accessing a list of PurchaseOrder objects
|
2019-08-02 11:44:56 +00:00
|
|
|
|
|
|
|
- GET: Return list of PO objects (with filters)
|
|
|
|
- POST: Create a new PurchaseOrder object
|
|
|
|
"""
|
|
|
|
|
|
|
|
queryset = PurchaseOrder.objects.all()
|
|
|
|
serializer_class = POSerializer
|
|
|
|
|
2020-04-19 23:41:21 +00:00
|
|
|
def get_serializer(self, *args, **kwargs):
|
2019-12-09 10:19:35 +00:00
|
|
|
|
2020-04-19 23:41:21 +00:00
|
|
|
try:
|
|
|
|
kwargs['supplier_detail'] = str2bool(self.request.query_params.get('supplier_detail', False))
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
2019-12-09 10:19:35 +00:00
|
|
|
|
2020-04-19 23:41:21 +00:00
|
|
|
# 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
|
2019-12-09 10:19:35 +00:00
|
|
|
|
2020-06-05 02:06:28 +00:00
|
|
|
# Filter by 'outstanding' status
|
|
|
|
outstanding = params.get('outstanding', None)
|
|
|
|
|
|
|
|
if outstanding is not None:
|
|
|
|
outstanding = str2bool(outstanding)
|
|
|
|
|
|
|
|
if outstanding:
|
|
|
|
queryset = queryset.filter(status__in=PurchaseOrderStatus.OPEN)
|
|
|
|
else:
|
|
|
|
queryset = queryset.exclude(status__in=PurchaseOrderStatus.OPEN)
|
|
|
|
|
2019-12-09 10:19:35 +00:00
|
|
|
# Special filtering for 'status' field
|
2020-04-19 23:41:21 +00:00
|
|
|
status = params.get('status', None)
|
2019-12-09 10:19:35 +00:00
|
|
|
|
2020-04-19 23:41:21 +00:00
|
|
|
if status is not None:
|
2019-12-09 10:19:35 +00:00
|
|
|
# First attempt to filter by integer value
|
2020-04-19 23:41:21 +00:00
|
|
|
queryset = queryset.filter(status=status)
|
2019-12-09 10:19:35 +00:00
|
|
|
|
2019-12-09 10:55:00 +00:00
|
|
|
# Attempt to filter by part
|
2020-04-19 23:41:21 +00:00
|
|
|
part = params.get('part', None)
|
|
|
|
|
|
|
|
if part is not None:
|
2019-12-09 10:55:00 +00:00
|
|
|
try:
|
2020-04-19 23:41:21 +00:00
|
|
|
part = Part.objects.get(pk=part)
|
2019-12-09 10:55:00 +00:00
|
|
|
queryset = queryset.filter(id__in=[p.id for p in part.purchase_orders()])
|
|
|
|
except (Part.DoesNotExist, ValueError):
|
|
|
|
pass
|
|
|
|
|
2020-02-12 01:44:52 +00:00
|
|
|
# Attempt to filter by supplier part
|
2020-04-19 23:41:21 +00:00
|
|
|
supplier_part = params.get('supplier_part', None)
|
|
|
|
|
|
|
|
if supplier_part is not None:
|
2020-02-12 01:44:52 +00:00
|
|
|
try:
|
2020-04-19 23:41:21 +00:00
|
|
|
supplier_part = SupplierPart.objects.get(pk=supplier_part)
|
2020-02-12 01:44:52 +00:00
|
|
|
queryset = queryset.filter(id__in=[p.id for p in supplier_part.purchase_orders()])
|
|
|
|
except (ValueError, SupplierPart.DoesNotExist):
|
|
|
|
pass
|
|
|
|
|
2020-04-19 23:41:21 +00:00
|
|
|
return queryset
|
2019-12-09 10:19:35 +00:00
|
|
|
|
2019-08-02 11:44:56 +00:00
|
|
|
filter_backends = [
|
|
|
|
DjangoFilterBackend,
|
2019-12-09 10:19:35 +00:00
|
|
|
filters.SearchFilter,
|
|
|
|
filters.OrderingFilter,
|
2019-08-02 11:44:56 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
filter_fields = [
|
|
|
|
'supplier',
|
|
|
|
]
|
|
|
|
|
2019-12-09 10:19:35 +00:00
|
|
|
ordering_fields = [
|
|
|
|
'creation_date',
|
|
|
|
'reference',
|
|
|
|
]
|
|
|
|
|
|
|
|
ordering = '-creation_date'
|
|
|
|
|
2019-08-02 11:44:56 +00:00
|
|
|
|
|
|
|
class PODetail(generics.RetrieveUpdateAPIView):
|
|
|
|
""" API endpoint for detail view of a PurchaseOrder object """
|
|
|
|
|
|
|
|
queryset = PurchaseOrder.objects.all()
|
|
|
|
serializer_class = POSerializer
|
|
|
|
|
2020-04-19 23:41:21 +00:00
|
|
|
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
|
|
|
|
|
2019-08-02 11:44:56 +00:00
|
|
|
|
|
|
|
class POLineItemList(generics.ListCreateAPIView):
|
2020-04-20 11:11:59 +00:00
|
|
|
""" API endpoint for accessing a list of POLineItem objects
|
2019-08-02 11:44:56 +00:00
|
|
|
|
|
|
|
- GET: Return a list of PO Line Item objects
|
|
|
|
- POST: Create a new PurchaseOrderLineItem object
|
|
|
|
"""
|
|
|
|
|
|
|
|
queryset = PurchaseOrderLineItem.objects.all()
|
|
|
|
serializer_class = POLineItemSerializer
|
|
|
|
|
2020-04-24 02:52:08 +00:00
|
|
|
def get_serializer(self, *args, **kwargs):
|
|
|
|
|
|
|
|
try:
|
|
|
|
kwargs['part_detail'] = str2bool(self.request.query_params.get('part_detail', False))
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
kwargs['context'] = self.get_serializer_context()
|
|
|
|
|
|
|
|
return self.serializer_class(*args, **kwargs)
|
|
|
|
|
2019-08-02 11:44:56 +00:00
|
|
|
filter_backends = [
|
|
|
|
DjangoFilterBackend,
|
|
|
|
]
|
|
|
|
|
|
|
|
filter_fields = [
|
|
|
|
'order',
|
|
|
|
'part'
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
class POLineItemDetail(generics.RetrieveUpdateAPIView):
|
|
|
|
""" API endpoint for detail view of a PurchaseOrderLineItem object """
|
|
|
|
|
|
|
|
queryset = PurchaseOrderLineItem
|
|
|
|
serializer_class = POLineItemSerializer
|
|
|
|
|
|
|
|
|
2020-05-12 11:40:42 +00:00
|
|
|
class SOAttachmentList(generics.ListCreateAPIView, AttachmentMixin):
|
2020-05-11 13:41:57 +00:00
|
|
|
"""
|
|
|
|
API endpoint for listing (and creating) a SalesOrderAttachment (file upload)
|
|
|
|
"""
|
|
|
|
|
|
|
|
queryset = SalesOrderAttachment.objects.all()
|
|
|
|
serializer_class = SOAttachmentSerializer
|
|
|
|
|
|
|
|
filter_fields = [
|
|
|
|
'order',
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2020-04-20 10:11:21 +00:00
|
|
|
class SOList(generics.ListCreateAPIView):
|
|
|
|
"""
|
|
|
|
API endpoint for accessing a list of SalesOrder objects.
|
|
|
|
|
|
|
|
- GET: Return list of SO objects (with filters)
|
|
|
|
- POST: Create a new SalesOrder
|
|
|
|
"""
|
|
|
|
|
|
|
|
queryset = SalesOrder.objects.all()
|
2020-04-20 22:57:13 +00:00
|
|
|
serializer_class = SalesOrderSerializer
|
2020-04-20 10:11:21 +00:00
|
|
|
|
|
|
|
def get_serializer(self, *args, **kwargs):
|
|
|
|
|
|
|
|
try:
|
|
|
|
kwargs['customer_detail'] = str2bool(self.request.query_params.get('customer_detail', False))
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
# Ensure the context is passed through to the serializer
|
|
|
|
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(
|
|
|
|
'customer',
|
|
|
|
'lines'
|
|
|
|
)
|
|
|
|
|
2020-04-20 22:57:13 +00:00
|
|
|
queryset = SalesOrderSerializer.annotate_queryset(queryset)
|
2020-04-20 10:11:21 +00:00
|
|
|
|
|
|
|
return queryset
|
|
|
|
|
|
|
|
def filter_queryset(self, queryset):
|
|
|
|
"""
|
|
|
|
Perform custom filtering operations on the SalesOrder queryset.
|
|
|
|
"""
|
|
|
|
|
|
|
|
queryset = super().filter_queryset(queryset)
|
|
|
|
|
|
|
|
params = self.request.query_params
|
|
|
|
|
2020-06-05 02:08:47 +00:00
|
|
|
# Filter by 'outstanding' status
|
|
|
|
outstanding = params.get('outstanding', None)
|
|
|
|
|
|
|
|
if outstanding is not None:
|
|
|
|
outstanding = str2bool(outstanding)
|
|
|
|
|
|
|
|
if outstanding:
|
|
|
|
queryset = queryset.filter(status__in=SalesOrderStatus.OPEN)
|
|
|
|
else:
|
|
|
|
queryset = queryset.exclude(status__in=SalesOrderStatus.OPEN)
|
|
|
|
|
2020-04-20 10:11:21 +00:00
|
|
|
status = params.get('status', None)
|
|
|
|
|
|
|
|
if status is not None:
|
|
|
|
queryset = queryset.filter(status=status)
|
|
|
|
|
2020-04-20 23:17:50 +00:00
|
|
|
# Filter by "Part"
|
|
|
|
# Only return SalesOrder which have LineItem referencing the part
|
|
|
|
part = params.get('part', None)
|
|
|
|
|
|
|
|
if part is not None:
|
|
|
|
try:
|
|
|
|
part = Part.objects.get(pk=part)
|
|
|
|
queryset = queryset.filter(id__in=[so.id for so in part.sales_orders()])
|
|
|
|
except (Part.DoesNotExist, ValueError):
|
|
|
|
pass
|
2020-04-20 10:11:21 +00:00
|
|
|
|
|
|
|
return queryset
|
|
|
|
|
|
|
|
filter_backends = [
|
|
|
|
DjangoFilterBackend,
|
|
|
|
filters.SearchFilter,
|
|
|
|
filters.OrderingFilter,
|
|
|
|
]
|
|
|
|
|
|
|
|
filter_fields = [
|
|
|
|
'customer',
|
|
|
|
]
|
|
|
|
|
|
|
|
ordering_fields = [
|
|
|
|
'creation_date',
|
|
|
|
'reference'
|
|
|
|
]
|
|
|
|
|
|
|
|
ordering = '-creation_date'
|
|
|
|
|
|
|
|
|
|
|
|
class SODetail(generics.RetrieveUpdateAPIView):
|
|
|
|
"""
|
|
|
|
API endpoint for detail view of a SalesOrder object.
|
|
|
|
"""
|
|
|
|
|
|
|
|
queryset = SalesOrder.objects.all()
|
2020-04-20 22:57:13 +00:00
|
|
|
serializer_class = SalesOrderSerializer
|
2020-04-20 10:11:21 +00:00
|
|
|
|
|
|
|
def get_serializer(self, *args, **kwargs):
|
|
|
|
|
|
|
|
try:
|
|
|
|
kwargs['customer_detail'] = str2bool(self.request.query_params.get('customer_detail', False))
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
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('customer', 'lines')
|
|
|
|
|
2020-04-20 22:57:13 +00:00
|
|
|
queryset = SalesOrderSerializer.annotate_queryset(queryset)
|
2020-04-20 10:11:21 +00:00
|
|
|
|
|
|
|
return queryset
|
|
|
|
|
2020-04-20 11:11:59 +00:00
|
|
|
|
|
|
|
class SOLineItemList(generics.ListCreateAPIView):
|
|
|
|
"""
|
|
|
|
API endpoint for accessing a list of SalesOrderLineItem objects.
|
|
|
|
"""
|
|
|
|
|
|
|
|
queryset = SalesOrderLineItem.objects.all()
|
|
|
|
serializer_class = SOLineItemSerializer
|
|
|
|
|
2020-04-20 22:57:13 +00:00
|
|
|
def get_serializer(self, *args, **kwargs):
|
|
|
|
|
|
|
|
try:
|
|
|
|
kwargs['part_detail'] = str2bool(self.request.query_params.get('part_detail', False))
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
try:
|
|
|
|
kwargs['order_detail'] = str2bool(self.request.query_params.get('order_detail', False))
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
|
|
|
|
2020-04-22 10:10:23 +00:00
|
|
|
try:
|
|
|
|
kwargs['allocations'] = str2bool(self.request.query_params.get('allocations', False))
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
|
|
|
|
2020-04-20 22:57:13 +00:00
|
|
|
kwargs['context'] = self.get_serializer_context()
|
|
|
|
|
|
|
|
return self.serializer_class(*args, **kwargs)
|
|
|
|
|
|
|
|
def get_queryset(self, *args, **kwargs):
|
|
|
|
|
|
|
|
queryset = super().get_queryset(*args, **kwargs)
|
|
|
|
|
2020-04-26 22:58:18 +00:00
|
|
|
queryset = queryset.prefetch_related(
|
2020-04-20 22:57:13 +00:00
|
|
|
'part',
|
|
|
|
'part__stock_items',
|
2020-04-22 02:12:48 +00:00
|
|
|
'allocations',
|
2020-04-22 10:26:05 +00:00
|
|
|
'allocations__item__location',
|
2020-04-20 22:57:13 +00:00
|
|
|
'order',
|
2020-04-26 22:58:18 +00:00
|
|
|
'order__stock_items',
|
2020-04-20 22:57:13 +00:00
|
|
|
)
|
|
|
|
|
2020-04-26 22:58:18 +00:00
|
|
|
return queryset
|
|
|
|
|
2020-04-20 11:11:59 +00:00
|
|
|
filter_backends = [DjangoFilterBackend]
|
|
|
|
|
|
|
|
filter_fields = [
|
|
|
|
'order',
|
2020-04-22 10:10:23 +00:00
|
|
|
'part',
|
2020-04-20 11:11:59 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
class SOLineItemDetail(generics.RetrieveUpdateAPIView):
|
|
|
|
""" API endpoint for detail view of a SalesOrderLineItem object """
|
|
|
|
|
|
|
|
queryset = SalesOrderLineItem.objects.all()
|
|
|
|
serializer_class = SOLineItemSerializer
|
|
|
|
|
2020-04-20 10:11:21 +00:00
|
|
|
|
2020-05-12 11:40:42 +00:00
|
|
|
class POAttachmentList(generics.ListCreateAPIView, AttachmentMixin):
|
2020-05-11 13:41:57 +00:00
|
|
|
"""
|
|
|
|
API endpoint for listing (and creating) a PurchaseOrderAttachment (file upload)
|
|
|
|
"""
|
|
|
|
|
|
|
|
queryset = PurchaseOrderAttachment.objects.all()
|
|
|
|
serializer_class = POAttachmentSerializer
|
|
|
|
|
|
|
|
filter_fields = [
|
|
|
|
'order',
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2020-04-20 10:11:21 +00:00
|
|
|
order_api_urls = [
|
|
|
|
# API endpoints for purchase orders
|
|
|
|
url(r'^po/(?P<pk>\d+)/$', PODetail.as_view(), name='api-po-detail'),
|
2020-05-11 13:41:57 +00:00
|
|
|
url(r'po/attachment/', include([
|
|
|
|
url(r'^.*$', POAttachmentList.as_view(), name='api-po-attachment-list'),
|
|
|
|
])),
|
|
|
|
url(r'^po/.*$', POList.as_view(), name='api-po-list'),
|
2020-04-20 10:11:21 +00:00
|
|
|
|
|
|
|
# API endpoints for purchase order line items
|
|
|
|
url(r'^po-line/(?P<pk>\d+)/$', POLineItemDetail.as_view(), name='api-po-line-detail'),
|
|
|
|
url(r'^po-line/$', POLineItemList.as_view(), name='api-po-line-list'),
|
2019-08-02 11:44:56 +00:00
|
|
|
|
2020-04-20 10:11:21 +00:00
|
|
|
# API endpoints for sales ordesr
|
|
|
|
url(r'^so/(?P<pk>\d+)/$', SODetail.as_view(), name='api-so-detail'),
|
2020-05-11 13:41:57 +00:00
|
|
|
url(r'so/attachment/', include([
|
|
|
|
url(r'^.*$', SOAttachmentList.as_view(), name='api-so-attachment-list'),
|
|
|
|
])),
|
|
|
|
|
|
|
|
url(r'^so/.*$', SOList.as_view(), name='api-so-list'),
|
2020-04-20 11:11:59 +00:00
|
|
|
|
|
|
|
# API endpoints for sales order line items
|
|
|
|
url(r'^so-line/(?P<pk>\d+)/$', SOLineItemDetail.as_view(), name='api-so-line-detail'),
|
|
|
|
url(r'^so-line/$', SOLineItemList.as_view(), name='api-so-line-list'),
|
2019-08-02 11:44:56 +00:00
|
|
|
]
|