mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
* use shims for API view inheritation * Add mixin for input sanitation * fix clean operation to fix all string values * Also clean up dicts this is to future-proof this function * Update docstirng * proof custom methods against XSS through authenticated users
This commit is contained in:
parent
f8a2760955
commit
e83995b4f5
@ -6,10 +6,12 @@ from django.http import JsonResponse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import filters, generics, permissions
|
||||
from rest_framework import filters, permissions
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import ValidationError
|
||||
|
||||
from InvenTree.mixins import ListCreateAPI
|
||||
|
||||
from .status import is_worker_running
|
||||
from .version import (inventreeApiVersion, inventreeInstanceName,
|
||||
inventreeVersion)
|
||||
@ -134,7 +136,7 @@ class BulkDeleteMixin:
|
||||
)
|
||||
|
||||
|
||||
class ListCreateDestroyAPIView(BulkDeleteMixin, generics.ListCreateAPIView):
|
||||
class ListCreateDestroyAPIView(BulkDeleteMixin, ListCreateAPI):
|
||||
"""Custom API endpoint which provides BulkDelete functionality in addition to List and Create"""
|
||||
...
|
||||
|
||||
|
90
InvenTree/InvenTree/mixins.py
Normal file
90
InvenTree/InvenTree/mixins.py
Normal file
@ -0,0 +1,90 @@
|
||||
"""Mixins for (API) views in the whole project."""
|
||||
|
||||
from bleach import clean
|
||||
from rest_framework import generics, status
|
||||
from rest_framework.response import Response
|
||||
|
||||
|
||||
class CleanMixin():
|
||||
"""Model mixin class which cleans inputs."""
|
||||
|
||||
# Define a map of fields avaialble for import
|
||||
SAFE_FIELDS = {}
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""Override to clean data before processing it."""
|
||||
serializer = self.get_serializer(data=self.clean_data(request.data))
|
||||
serializer.is_valid(raise_exception=True)
|
||||
self.perform_create(serializer)
|
||||
headers = self.get_success_headers(serializer.data)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
"""Override to clean data before processing it."""
|
||||
partial = kwargs.pop('partial', False)
|
||||
instance = self.get_object()
|
||||
serializer = self.get_serializer(instance, data=self.clean_data(request.data), partial=partial)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
self.perform_update(serializer)
|
||||
|
||||
if getattr(instance, '_prefetched_objects_cache', None):
|
||||
# If 'prefetch_related' has been applied to a queryset, we need to
|
||||
# forcibly invalidate the prefetch cache on the instance.
|
||||
instance._prefetched_objects_cache = {}
|
||||
|
||||
return Response(serializer.data)
|
||||
|
||||
def clean_data(self, data: dict) -> dict:
|
||||
"""Clean / snatize data.
|
||||
|
||||
This uses mozillas bleach under the hood to disable certain html tags by
|
||||
encoding them - this leads to script tags etc. to not work.
|
||||
The results can be longer then the input; might make some character combinations
|
||||
`ugly`. Prevents XSS on the server-level.
|
||||
|
||||
Args:
|
||||
data (dict): Data that should be sanatized.
|
||||
|
||||
Returns:
|
||||
dict: Profided data sanatized; still in the same order.
|
||||
"""
|
||||
clean_data = {}
|
||||
for k, v in data.items():
|
||||
if isinstance(v, str):
|
||||
ret = clean(v)
|
||||
elif isinstance(v, dict):
|
||||
ret = self.clean_data(v)
|
||||
else:
|
||||
ret = v
|
||||
clean_data[k] = ret
|
||||
return clean_data
|
||||
|
||||
|
||||
class ListAPI(generics.ListAPIView):
|
||||
"""View for list API."""
|
||||
|
||||
|
||||
class ListCreateAPI(CleanMixin, generics.ListCreateAPIView):
|
||||
"""View for list and create API."""
|
||||
|
||||
|
||||
class CreateAPI(CleanMixin, generics.CreateAPIView):
|
||||
"""View for create API."""
|
||||
|
||||
|
||||
class RetrieveAPI(generics.RetrieveAPIView):
|
||||
"""View for retreive API."""
|
||||
pass
|
||||
|
||||
|
||||
class RetrieveUpdateAPI(CleanMixin, generics.RetrieveUpdateAPIView):
|
||||
"""View for retrieve and update API."""
|
||||
pass
|
||||
|
||||
|
||||
class RetrieveUpdateDestroyAPI(CleanMixin, generics.RetrieveUpdateDestroyAPIView):
|
||||
"""View for retrieve, update and destroy API."""
|
||||
|
||||
|
||||
class UpdateAPI(CleanMixin, generics.UpdateAPIView):
|
||||
"""View for update API."""
|
@ -3,7 +3,7 @@
|
||||
from django.urls import include, re_path
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from rest_framework import filters, generics
|
||||
from rest_framework import filters
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
@ -13,6 +13,7 @@ from InvenTree.api import AttachmentMixin, APIDownloadMixin, ListCreateDestroyAP
|
||||
from InvenTree.helpers import str2bool, isNull, DownloadFile
|
||||
from InvenTree.filters import InvenTreeOrderingFilter
|
||||
from InvenTree.status_codes import BuildStatus
|
||||
from InvenTree.mixins import CreateAPI, RetrieveUpdateDestroyAPI, ListCreateAPI
|
||||
|
||||
import build.admin
|
||||
import build.serializers
|
||||
@ -65,7 +66,7 @@ class BuildFilter(rest_filters.FilterSet):
|
||||
return queryset
|
||||
|
||||
|
||||
class BuildList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
class BuildList(APIDownloadMixin, ListCreateAPI):
|
||||
"""API endpoint for accessing a list of Build objects.
|
||||
|
||||
- GET: Return list of objects (with filters)
|
||||
@ -200,7 +201,7 @@ class BuildList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
return self.serializer_class(*args, **kwargs)
|
||||
|
||||
|
||||
class BuildDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class BuildDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of a Build object."""
|
||||
|
||||
queryset = Build.objects.all()
|
||||
@ -219,7 +220,7 @@ class BuildDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
return super().destroy(request, *args, **kwargs)
|
||||
|
||||
|
||||
class BuildUnallocate(generics.CreateAPIView):
|
||||
class BuildUnallocate(CreateAPI):
|
||||
"""API endpoint for unallocating stock items from a build order.
|
||||
|
||||
- The BuildOrder object is specified by the URL
|
||||
@ -263,7 +264,7 @@ class BuildOrderContextMixin:
|
||||
return ctx
|
||||
|
||||
|
||||
class BuildOutputCreate(BuildOrderContextMixin, generics.CreateAPIView):
|
||||
class BuildOutputCreate(BuildOrderContextMixin, CreateAPI):
|
||||
"""API endpoint for creating new build output(s)."""
|
||||
|
||||
queryset = Build.objects.none()
|
||||
@ -271,7 +272,7 @@ class BuildOutputCreate(BuildOrderContextMixin, generics.CreateAPIView):
|
||||
serializer_class = build.serializers.BuildOutputCreateSerializer
|
||||
|
||||
|
||||
class BuildOutputComplete(BuildOrderContextMixin, generics.CreateAPIView):
|
||||
class BuildOutputComplete(BuildOrderContextMixin, CreateAPI):
|
||||
"""API endpoint for completing build outputs."""
|
||||
|
||||
queryset = Build.objects.none()
|
||||
@ -279,7 +280,7 @@ class BuildOutputComplete(BuildOrderContextMixin, generics.CreateAPIView):
|
||||
serializer_class = build.serializers.BuildOutputCompleteSerializer
|
||||
|
||||
|
||||
class BuildOutputDelete(BuildOrderContextMixin, generics.CreateAPIView):
|
||||
class BuildOutputDelete(BuildOrderContextMixin, CreateAPI):
|
||||
"""API endpoint for deleting multiple build outputs."""
|
||||
|
||||
def get_serializer_context(self):
|
||||
@ -295,7 +296,7 @@ class BuildOutputDelete(BuildOrderContextMixin, generics.CreateAPIView):
|
||||
serializer_class = build.serializers.BuildOutputDeleteSerializer
|
||||
|
||||
|
||||
class BuildFinish(BuildOrderContextMixin, generics.CreateAPIView):
|
||||
class BuildFinish(BuildOrderContextMixin, CreateAPI):
|
||||
"""API endpoint for marking a build as finished (completed)."""
|
||||
|
||||
queryset = Build.objects.none()
|
||||
@ -303,7 +304,7 @@ class BuildFinish(BuildOrderContextMixin, generics.CreateAPIView):
|
||||
serializer_class = build.serializers.BuildCompleteSerializer
|
||||
|
||||
|
||||
class BuildAutoAllocate(BuildOrderContextMixin, generics.CreateAPIView):
|
||||
class BuildAutoAllocate(BuildOrderContextMixin, CreateAPI):
|
||||
"""API endpoint for 'automatically' allocating stock against a build order.
|
||||
|
||||
- Only looks at 'untracked' parts
|
||||
@ -317,7 +318,7 @@ class BuildAutoAllocate(BuildOrderContextMixin, generics.CreateAPIView):
|
||||
serializer_class = build.serializers.BuildAutoAllocationSerializer
|
||||
|
||||
|
||||
class BuildAllocate(BuildOrderContextMixin, generics.CreateAPIView):
|
||||
class BuildAllocate(BuildOrderContextMixin, CreateAPI):
|
||||
"""API endpoint to allocate stock items to a build order.
|
||||
|
||||
- The BuildOrder object is specified by the URL
|
||||
@ -333,21 +334,21 @@ class BuildAllocate(BuildOrderContextMixin, generics.CreateAPIView):
|
||||
serializer_class = build.serializers.BuildAllocationSerializer
|
||||
|
||||
|
||||
class BuildCancel(BuildOrderContextMixin, generics.CreateAPIView):
|
||||
class BuildCancel(BuildOrderContextMixin, CreateAPI):
|
||||
"""API endpoint for cancelling a BuildOrder."""
|
||||
|
||||
queryset = Build.objects.all()
|
||||
serializer_class = build.serializers.BuildCancelSerializer
|
||||
|
||||
|
||||
class BuildItemDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class BuildItemDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of a BuildItem object."""
|
||||
|
||||
queryset = BuildItem.objects.all()
|
||||
serializer_class = build.serializers.BuildItemSerializer
|
||||
|
||||
|
||||
class BuildItemList(generics.ListCreateAPIView):
|
||||
class BuildItemList(ListCreateAPI):
|
||||
"""API endpoint for accessing a list of BuildItem objects.
|
||||
|
||||
- GET: Return list of objects
|
||||
@ -442,7 +443,7 @@ class BuildAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||
]
|
||||
|
||||
|
||||
class BuildAttachmentDetail(AttachmentMixin, generics.RetrieveUpdateDestroyAPIView):
|
||||
class BuildAttachmentDetail(AttachmentMixin, RetrieveUpdateDestroyAPI):
|
||||
"""Detail endpoint for a BuildOrderAttachment object."""
|
||||
|
||||
queryset = BuildOrderAttachment.objects.all()
|
||||
|
@ -9,7 +9,7 @@ from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from django_q.tasks import async_task
|
||||
from rest_framework import filters, generics, permissions, serializers
|
||||
from rest_framework import filters, permissions, serializers
|
||||
from rest_framework.exceptions import NotAcceptable, NotFound
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
@ -18,6 +18,8 @@ import common.models
|
||||
import common.serializers
|
||||
from InvenTree.api import BulkDeleteMixin
|
||||
from InvenTree.helpers import inheritors
|
||||
from InvenTree.mixins import (CreateAPI, ListAPI, RetrieveAPI,
|
||||
RetrieveUpdateAPI, RetrieveUpdateDestroyAPI)
|
||||
from plugin.models import NotificationUserSetting
|
||||
from plugin.serializers import NotificationUserSettingSerializer
|
||||
|
||||
@ -97,7 +99,7 @@ class WebhookView(CsrfExemptMixin, APIView):
|
||||
raise NotFound()
|
||||
|
||||
|
||||
class SettingsList(generics.ListAPIView):
|
||||
class SettingsList(ListAPI):
|
||||
"""Generic ListView for settings.
|
||||
|
||||
This is inheritted by all list views for settings.
|
||||
@ -145,7 +147,7 @@ class GlobalSettingsPermissions(permissions.BasePermission):
|
||||
return False
|
||||
|
||||
|
||||
class GlobalSettingsDetail(generics.RetrieveUpdateAPIView):
|
||||
class GlobalSettingsDetail(RetrieveUpdateAPI):
|
||||
"""Detail view for an individual "global setting" object.
|
||||
|
||||
- User must have 'staff' status to view / edit
|
||||
@ -203,7 +205,7 @@ class UserSettingsPermissions(permissions.BasePermission):
|
||||
return user == obj.user
|
||||
|
||||
|
||||
class UserSettingsDetail(generics.RetrieveUpdateAPIView):
|
||||
class UserSettingsDetail(RetrieveUpdateAPI):
|
||||
"""Detail view for an individual "user setting" object.
|
||||
|
||||
- User can only view / edit settings their own settings objects
|
||||
@ -245,7 +247,7 @@ class NotificationUserSettingsList(SettingsList):
|
||||
return queryset
|
||||
|
||||
|
||||
class NotificationUserSettingsDetail(generics.RetrieveUpdateAPIView):
|
||||
class NotificationUserSettingsDetail(RetrieveUpdateAPI):
|
||||
"""Detail view for an individual "notification user setting" object.
|
||||
|
||||
- User can only view / edit settings their own settings objects
|
||||
@ -259,7 +261,7 @@ class NotificationUserSettingsDetail(generics.RetrieveUpdateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class NotificationList(BulkDeleteMixin, generics.ListAPIView):
|
||||
class NotificationList(BulkDeleteMixin, ListAPI):
|
||||
"""List view for all notifications of the current user."""
|
||||
|
||||
queryset = common.models.NotificationMessage.objects.all()
|
||||
@ -310,7 +312,7 @@ class NotificationList(BulkDeleteMixin, generics.ListAPIView):
|
||||
return queryset
|
||||
|
||||
|
||||
class NotificationDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class NotificationDetail(RetrieveUpdateDestroyAPI):
|
||||
"""Detail view for an individual notification object.
|
||||
|
||||
- User can only view / delete their own notification objects
|
||||
@ -323,7 +325,7 @@ class NotificationDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
]
|
||||
|
||||
|
||||
class NotificationReadEdit(generics.CreateAPIView):
|
||||
class NotificationReadEdit(CreateAPI):
|
||||
"""General API endpoint to manipulate read state of a notification."""
|
||||
|
||||
queryset = common.models.NotificationMessage.objects.all()
|
||||
@ -360,7 +362,7 @@ class NotificationUnread(NotificationReadEdit):
|
||||
target = False
|
||||
|
||||
|
||||
class NotificationReadAll(generics.RetrieveAPIView):
|
||||
class NotificationReadAll(RetrieveAPI):
|
||||
"""API endpoint to mark all notifications as read."""
|
||||
|
||||
queryset = common.models.NotificationMessage.objects.all()
|
||||
|
@ -5,10 +5,11 @@ from django.urls import include, re_path
|
||||
|
||||
from django_filters import rest_framework as rest_filters
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import filters, generics
|
||||
from rest_framework import filters
|
||||
|
||||
from InvenTree.api import AttachmentMixin, ListCreateDestroyAPIView
|
||||
from InvenTree.helpers import str2bool
|
||||
from InvenTree.mixins import ListCreateAPI, RetrieveUpdateDestroyAPI
|
||||
|
||||
from .models import (Company, ManufacturerPart, ManufacturerPartAttachment,
|
||||
ManufacturerPartParameter, SupplierPart,
|
||||
@ -20,7 +21,7 @@ from .serializers import (CompanySerializer,
|
||||
SupplierPriceBreakSerializer)
|
||||
|
||||
|
||||
class CompanyList(generics.ListCreateAPIView):
|
||||
class CompanyList(ListCreateAPI):
|
||||
"""API endpoint for accessing a list of Company objects.
|
||||
|
||||
Provides two methods:
|
||||
@ -67,7 +68,7 @@ class CompanyList(generics.ListCreateAPIView):
|
||||
ordering = 'name'
|
||||
|
||||
|
||||
class CompanyDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class CompanyDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail of a single Company object."""
|
||||
|
||||
queryset = Company.objects.all()
|
||||
@ -146,7 +147,7 @@ class ManufacturerPartList(ListCreateDestroyAPIView):
|
||||
]
|
||||
|
||||
|
||||
class ManufacturerPartDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class ManufacturerPartDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of ManufacturerPart object.
|
||||
|
||||
- GET: Retrieve detail view
|
||||
@ -173,7 +174,7 @@ class ManufacturerPartAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||
]
|
||||
|
||||
|
||||
class ManufacturerPartAttachmentDetail(AttachmentMixin, generics.RetrieveUpdateDestroyAPIView):
|
||||
class ManufacturerPartAttachmentDetail(AttachmentMixin, RetrieveUpdateDestroyAPI):
|
||||
"""Detail endpooint for ManufacturerPartAttachment model."""
|
||||
|
||||
queryset = ManufacturerPartAttachment.objects.all()
|
||||
@ -246,7 +247,7 @@ class ManufacturerPartParameterList(ListCreateDestroyAPIView):
|
||||
]
|
||||
|
||||
|
||||
class ManufacturerPartParameterDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class ManufacturerPartParameterDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of ManufacturerPartParameter model."""
|
||||
|
||||
queryset = ManufacturerPartParameter.objects.all()
|
||||
@ -347,7 +348,7 @@ class SupplierPartList(ListCreateDestroyAPIView):
|
||||
]
|
||||
|
||||
|
||||
class SupplierPartDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class SupplierPartDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of SupplierPart object.
|
||||
|
||||
- GET: Retrieve detail view
|
||||
@ -362,7 +363,7 @@ class SupplierPartDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
]
|
||||
|
||||
|
||||
class SupplierPriceBreakList(generics.ListCreateAPIView):
|
||||
class SupplierPriceBreakList(ListCreateAPI):
|
||||
"""API endpoint for list view of SupplierPriceBreak object.
|
||||
|
||||
- GET: Retrieve list of SupplierPriceBreak objects
|
||||
@ -381,7 +382,7 @@ class SupplierPriceBreakList(generics.ListCreateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class SupplierPriceBreakDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class SupplierPriceBreakDetail(RetrieveUpdateDestroyAPI):
|
||||
"""Detail endpoint for SupplierPriceBreak object."""
|
||||
|
||||
queryset = SupplierPriceBreak.objects.all()
|
||||
|
@ -6,11 +6,12 @@ from django.http import HttpResponse, JsonResponse
|
||||
from django.urls import include, re_path
|
||||
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import filters, generics
|
||||
from rest_framework import filters
|
||||
from rest_framework.exceptions import NotFound
|
||||
|
||||
import common.models
|
||||
import InvenTree.helpers
|
||||
from InvenTree.mixins import ListAPI, RetrieveAPI, RetrieveUpdateDestroyAPI
|
||||
from InvenTree.tasks import offload_task
|
||||
from part.models import Part
|
||||
from plugin.base.label import label as plugin_label
|
||||
@ -22,7 +23,7 @@ from .serializers import (PartLabelSerializer, StockItemLabelSerializer,
|
||||
StockLocationLabelSerializer)
|
||||
|
||||
|
||||
class LabelListView(generics.ListAPIView):
|
||||
class LabelListView(ListAPI):
|
||||
"""Generic API class for label templates."""
|
||||
|
||||
filter_backends = [
|
||||
@ -275,14 +276,14 @@ class StockItemLabelList(LabelListView, StockItemLabelMixin):
|
||||
return queryset
|
||||
|
||||
|
||||
class StockItemLabelDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class StockItemLabelDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for a single StockItemLabel object."""
|
||||
|
||||
queryset = StockItemLabel.objects.all()
|
||||
serializer_class = StockItemLabelSerializer
|
||||
|
||||
|
||||
class StockItemLabelPrint(generics.RetrieveAPIView, StockItemLabelMixin, LabelPrintMixin):
|
||||
class StockItemLabelPrint(RetrieveAPI, StockItemLabelMixin, LabelPrintMixin):
|
||||
"""API endpoint for printing a StockItemLabel object."""
|
||||
|
||||
queryset = StockItemLabel.objects.all()
|
||||
@ -391,14 +392,14 @@ class StockLocationLabelList(LabelListView, StockLocationLabelMixin):
|
||||
return queryset
|
||||
|
||||
|
||||
class StockLocationLabelDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class StockLocationLabelDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for a single StockLocationLabel object."""
|
||||
|
||||
queryset = StockLocationLabel.objects.all()
|
||||
serializer_class = StockLocationLabelSerializer
|
||||
|
||||
|
||||
class StockLocationLabelPrint(generics.RetrieveAPIView, StockLocationLabelMixin, LabelPrintMixin):
|
||||
class StockLocationLabelPrint(RetrieveAPI, StockLocationLabelMixin, LabelPrintMixin):
|
||||
"""API endpoint for printing a StockLocationLabel object."""
|
||||
|
||||
queryset = StockLocationLabel.objects.all()
|
||||
@ -483,14 +484,14 @@ class PartLabelList(LabelListView, PartLabelMixin):
|
||||
return queryset
|
||||
|
||||
|
||||
class PartLabelDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class PartLabelDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for a single PartLabel object."""
|
||||
|
||||
queryset = PartLabel.objects.all()
|
||||
serializer_class = PartLabelSerializer
|
||||
|
||||
|
||||
class PartLabelPrint(generics.RetrieveAPIView, PartLabelMixin, LabelPrintMixin):
|
||||
class PartLabelPrint(RetrieveAPI, PartLabelMixin, LabelPrintMixin):
|
||||
"""API endpoint for printing a PartLabel object."""
|
||||
|
||||
queryset = PartLabel.objects.all()
|
||||
|
@ -4,7 +4,7 @@ from django.db.models import F, Q
|
||||
from django.urls import include, path, re_path
|
||||
|
||||
from django_filters import rest_framework as rest_filters
|
||||
from rest_framework import filters, generics, status
|
||||
from rest_framework import filters, status
|
||||
from rest_framework.response import Response
|
||||
|
||||
import order.models as models
|
||||
@ -14,6 +14,8 @@ from InvenTree.api import (APIDownloadMixin, AttachmentMixin,
|
||||
ListCreateDestroyAPIView)
|
||||
from InvenTree.filters import InvenTreeOrderingFilter
|
||||
from InvenTree.helpers import DownloadFile, str2bool
|
||||
from InvenTree.mixins import (CreateAPI, ListAPI, ListCreateAPI,
|
||||
RetrieveUpdateAPI, RetrieveUpdateDestroyAPI)
|
||||
from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus
|
||||
from order.admin import (PurchaseOrderLineItemResource, PurchaseOrderResource,
|
||||
SalesOrderResource)
|
||||
@ -101,7 +103,7 @@ class PurchaseOrderFilter(rest_filters.FilterSet):
|
||||
]
|
||||
|
||||
|
||||
class PurchaseOrderList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
class PurchaseOrderList(APIDownloadMixin, ListCreateAPI):
|
||||
"""API endpoint for accessing a list of PurchaseOrder objects.
|
||||
|
||||
- GET: Return list of PurchaseOrder objects (with filters)
|
||||
@ -114,7 +116,7 @@ class PurchaseOrderList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""Save user information on create."""
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer = self.get_serializer(data=self.clean_data(request.data))
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
item = serializer.save()
|
||||
@ -254,7 +256,7 @@ class PurchaseOrderList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
ordering = '-creation_date'
|
||||
|
||||
|
||||
class PurchaseOrderDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class PurchaseOrderDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of a PurchaseOrder object."""
|
||||
|
||||
queryset = models.PurchaseOrder.objects.all()
|
||||
@ -304,7 +306,7 @@ class PurchaseOrderContextMixin:
|
||||
return context
|
||||
|
||||
|
||||
class PurchaseOrderCancel(PurchaseOrderContextMixin, generics.CreateAPIView):
|
||||
class PurchaseOrderCancel(PurchaseOrderContextMixin, CreateAPI):
|
||||
"""API endpoint to 'cancel' a purchase order.
|
||||
|
||||
The purchase order must be in a state which can be cancelled
|
||||
@ -315,7 +317,7 @@ class PurchaseOrderCancel(PurchaseOrderContextMixin, generics.CreateAPIView):
|
||||
serializer_class = serializers.PurchaseOrderCancelSerializer
|
||||
|
||||
|
||||
class PurchaseOrderComplete(PurchaseOrderContextMixin, generics.CreateAPIView):
|
||||
class PurchaseOrderComplete(PurchaseOrderContextMixin, CreateAPI):
|
||||
"""API endpoint to 'complete' a purchase order."""
|
||||
|
||||
queryset = models.PurchaseOrder.objects.all()
|
||||
@ -323,7 +325,7 @@ class PurchaseOrderComplete(PurchaseOrderContextMixin, generics.CreateAPIView):
|
||||
serializer_class = serializers.PurchaseOrderCompleteSerializer
|
||||
|
||||
|
||||
class PurchaseOrderIssue(PurchaseOrderContextMixin, generics.CreateAPIView):
|
||||
class PurchaseOrderIssue(PurchaseOrderContextMixin, CreateAPI):
|
||||
"""API endpoint to 'complete' a purchase order."""
|
||||
|
||||
queryset = models.PurchaseOrder.objects.all()
|
||||
@ -331,7 +333,7 @@ class PurchaseOrderIssue(PurchaseOrderContextMixin, generics.CreateAPIView):
|
||||
serializer_class = serializers.PurchaseOrderIssueSerializer
|
||||
|
||||
|
||||
class PurchaseOrderMetadata(generics.RetrieveUpdateAPIView):
|
||||
class PurchaseOrderMetadata(RetrieveUpdateAPI):
|
||||
"""API endpoint for viewing / updating PurchaseOrder metadata."""
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
@ -341,7 +343,7 @@ class PurchaseOrderMetadata(generics.RetrieveUpdateAPIView):
|
||||
queryset = models.PurchaseOrder.objects.all()
|
||||
|
||||
|
||||
class PurchaseOrderReceive(PurchaseOrderContextMixin, generics.CreateAPIView):
|
||||
class PurchaseOrderReceive(PurchaseOrderContextMixin, CreateAPI):
|
||||
"""API endpoint to receive stock items against a purchase order.
|
||||
|
||||
- The purchase order is specified in the URL.
|
||||
@ -405,7 +407,7 @@ class PurchaseOrderLineItemFilter(rest_filters.FilterSet):
|
||||
return queryset
|
||||
|
||||
|
||||
class PurchaseOrderLineItemList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
class PurchaseOrderLineItemList(APIDownloadMixin, ListCreateAPI):
|
||||
"""API endpoint for accessing a list of PurchaseOrderLineItem objects.
|
||||
|
||||
- GET: Return a list of PurchaseOrder Line Item objects
|
||||
@ -499,7 +501,7 @@ class PurchaseOrderLineItemList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class PurchaseOrderLineItemDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class PurchaseOrderLineItemDetail(RetrieveUpdateDestroyAPI):
|
||||
"""Detail API endpoint for PurchaseOrderLineItem object."""
|
||||
|
||||
queryset = models.PurchaseOrderLineItem.objects.all()
|
||||
@ -514,14 +516,14 @@ class PurchaseOrderLineItemDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
return queryset
|
||||
|
||||
|
||||
class PurchaseOrderExtraLineList(GeneralExtraLineList, generics.ListCreateAPIView):
|
||||
class PurchaseOrderExtraLineList(GeneralExtraLineList, ListCreateAPI):
|
||||
"""API endpoint for accessing a list of PurchaseOrderExtraLine objects."""
|
||||
|
||||
queryset = models.PurchaseOrderExtraLine.objects.all()
|
||||
serializer_class = serializers.PurchaseOrderExtraLineSerializer
|
||||
|
||||
|
||||
class PurchaseOrderExtraLineDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class PurchaseOrderExtraLineDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of a PurchaseOrderExtraLine object."""
|
||||
|
||||
queryset = models.PurchaseOrderExtraLine.objects.all()
|
||||
@ -543,14 +545,14 @@ class SalesOrderAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||
]
|
||||
|
||||
|
||||
class SalesOrderAttachmentDetail(AttachmentMixin, generics.RetrieveUpdateDestroyAPIView):
|
||||
class SalesOrderAttachmentDetail(AttachmentMixin, RetrieveUpdateDestroyAPI):
|
||||
"""Detail endpoint for SalesOrderAttachment."""
|
||||
|
||||
queryset = models.SalesOrderAttachment.objects.all()
|
||||
serializer_class = serializers.SalesOrderAttachmentSerializer
|
||||
|
||||
|
||||
class SalesOrderList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
class SalesOrderList(APIDownloadMixin, ListCreateAPI):
|
||||
"""API endpoint for accessing a list of SalesOrder objects.
|
||||
|
||||
- GET: Return list of SalesOrder objects (with filters)
|
||||
@ -562,7 +564,7 @@ class SalesOrderList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""Save user information on create."""
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer = self.get_serializer(data=self.clean_data(request.data))
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
item = serializer.save()
|
||||
@ -695,7 +697,7 @@ class SalesOrderList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
ordering = '-creation_date'
|
||||
|
||||
|
||||
class SalesOrderDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class SalesOrderDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of a SalesOrder object."""
|
||||
|
||||
queryset = models.SalesOrder.objects.all()
|
||||
@ -754,7 +756,7 @@ class SalesOrderLineItemFilter(rest_filters.FilterSet):
|
||||
return queryset
|
||||
|
||||
|
||||
class SalesOrderLineItemList(generics.ListCreateAPIView):
|
||||
class SalesOrderLineItemList(ListCreateAPI):
|
||||
"""API endpoint for accessing a list of SalesOrderLineItem objects."""
|
||||
|
||||
queryset = models.SalesOrderLineItem.objects.all()
|
||||
@ -818,21 +820,21 @@ class SalesOrderLineItemList(generics.ListCreateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class SalesOrderExtraLineList(GeneralExtraLineList, generics.ListCreateAPIView):
|
||||
class SalesOrderExtraLineList(GeneralExtraLineList, ListCreateAPI):
|
||||
"""API endpoint for accessing a list of SalesOrderExtraLine objects."""
|
||||
|
||||
queryset = models.SalesOrderExtraLine.objects.all()
|
||||
serializer_class = serializers.SalesOrderExtraLineSerializer
|
||||
|
||||
|
||||
class SalesOrderExtraLineDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class SalesOrderExtraLineDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of a SalesOrderExtraLine object."""
|
||||
|
||||
queryset = models.SalesOrderExtraLine.objects.all()
|
||||
serializer_class = serializers.SalesOrderExtraLineSerializer
|
||||
|
||||
|
||||
class SalesOrderLineItemDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class SalesOrderLineItemDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of a SalesOrderLineItem object."""
|
||||
|
||||
queryset = models.SalesOrderLineItem.objects.all()
|
||||
@ -864,21 +866,21 @@ class SalesOrderContextMixin:
|
||||
return ctx
|
||||
|
||||
|
||||
class SalesOrderCancel(SalesOrderContextMixin, generics.CreateAPIView):
|
||||
class SalesOrderCancel(SalesOrderContextMixin, CreateAPI):
|
||||
"""API endpoint to cancel a SalesOrder"""
|
||||
|
||||
queryset = models.SalesOrder.objects.all()
|
||||
serializer_class = serializers.SalesOrderCancelSerializer
|
||||
|
||||
|
||||
class SalesOrderComplete(SalesOrderContextMixin, generics.CreateAPIView):
|
||||
class SalesOrderComplete(SalesOrderContextMixin, CreateAPI):
|
||||
"""API endpoint for manually marking a SalesOrder as "complete"."""
|
||||
|
||||
queryset = models.SalesOrder.objects.all()
|
||||
serializer_class = serializers.SalesOrderCompleteSerializer
|
||||
|
||||
|
||||
class SalesOrderMetadata(generics.RetrieveUpdateAPIView):
|
||||
class SalesOrderMetadata(RetrieveUpdateAPI):
|
||||
"""API endpoint for viewing / updating SalesOrder metadata."""
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
@ -888,14 +890,14 @@ class SalesOrderMetadata(generics.RetrieveUpdateAPIView):
|
||||
queryset = models.SalesOrder.objects.all()
|
||||
|
||||
|
||||
class SalesOrderAllocateSerials(SalesOrderContextMixin, generics.CreateAPIView):
|
||||
class SalesOrderAllocateSerials(SalesOrderContextMixin, CreateAPI):
|
||||
"""API endpoint to allocation stock items against a SalesOrder, by specifying serial numbers."""
|
||||
|
||||
queryset = models.SalesOrder.objects.none()
|
||||
serializer_class = serializers.SalesOrderSerialAllocationSerializer
|
||||
|
||||
|
||||
class SalesOrderAllocate(SalesOrderContextMixin, generics.CreateAPIView):
|
||||
class SalesOrderAllocate(SalesOrderContextMixin, CreateAPI):
|
||||
"""API endpoint to allocate stock items against a SalesOrder.
|
||||
|
||||
- The SalesOrder is specified in the URL
|
||||
@ -906,14 +908,14 @@ class SalesOrderAllocate(SalesOrderContextMixin, generics.CreateAPIView):
|
||||
serializer_class = serializers.SalesOrderShipmentAllocationSerializer
|
||||
|
||||
|
||||
class SalesOrderAllocationDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class SalesOrderAllocationDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detali view of a SalesOrderAllocation object."""
|
||||
|
||||
queryset = models.SalesOrderAllocation.objects.all()
|
||||
serializer_class = serializers.SalesOrderAllocationSerializer
|
||||
|
||||
|
||||
class SalesOrderAllocationList(generics.ListAPIView):
|
||||
class SalesOrderAllocationList(ListAPI):
|
||||
"""API endpoint for listing SalesOrderAllocation objects."""
|
||||
|
||||
queryset = models.SalesOrderAllocation.objects.all()
|
||||
@ -1017,7 +1019,7 @@ class SalesOrderShipmentFilter(rest_filters.FilterSet):
|
||||
]
|
||||
|
||||
|
||||
class SalesOrderShipmentList(generics.ListCreateAPIView):
|
||||
class SalesOrderShipmentList(ListCreateAPI):
|
||||
"""API list endpoint for SalesOrderShipment model."""
|
||||
|
||||
queryset = models.SalesOrderShipment.objects.all()
|
||||
@ -1029,14 +1031,14 @@ class SalesOrderShipmentList(generics.ListCreateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class SalesOrderShipmentDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class SalesOrderShipmentDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API detail endpooint for SalesOrderShipment model."""
|
||||
|
||||
queryset = models.SalesOrderShipment.objects.all()
|
||||
serializer_class = serializers.SalesOrderShipmentSerializer
|
||||
|
||||
|
||||
class SalesOrderShipmentComplete(generics.CreateAPIView):
|
||||
class SalesOrderShipmentComplete(CreateAPI):
|
||||
"""API endpoint for completing (shipping) a SalesOrderShipment."""
|
||||
|
||||
queryset = models.SalesOrderShipment.objects.all()
|
||||
@ -1072,7 +1074,7 @@ class PurchaseOrderAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||
]
|
||||
|
||||
|
||||
class PurchaseOrderAttachmentDetail(AttachmentMixin, generics.RetrieveUpdateDestroyAPIView):
|
||||
class PurchaseOrderAttachmentDetail(AttachmentMixin, RetrieveUpdateDestroyAPI):
|
||||
"""Detail endpoint for a PurchaseOrderAttachment."""
|
||||
|
||||
queryset = models.PurchaseOrderAttachment.objects.all()
|
||||
|
@ -14,7 +14,7 @@ from django_filters.rest_framework import DjangoFilterBackend
|
||||
from djmoney.contrib.exchange.exceptions import MissingRate
|
||||
from djmoney.contrib.exchange.models import convert_money
|
||||
from djmoney.money import Money
|
||||
from rest_framework import filters, generics, serializers, status
|
||||
from rest_framework import filters, serializers, status
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.response import Response
|
||||
|
||||
@ -25,6 +25,9 @@ from company.models import Company, ManufacturerPart, SupplierPart
|
||||
from InvenTree.api import (APIDownloadMixin, AttachmentMixin,
|
||||
ListCreateDestroyAPIView)
|
||||
from InvenTree.helpers import DownloadFile, increment, isNull, str2bool
|
||||
from InvenTree.mixins import (CreateAPI, ListAPI, ListCreateAPI, RetrieveAPI,
|
||||
RetrieveUpdateAPI, RetrieveUpdateDestroyAPI,
|
||||
UpdateAPI)
|
||||
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus,
|
||||
SalesOrderStatus)
|
||||
from part.admin import PartResource
|
||||
@ -39,7 +42,7 @@ from .models import (BomItem, BomItemSubstitute, Part, PartAttachment,
|
||||
PartTestTemplate)
|
||||
|
||||
|
||||
class CategoryList(generics.ListCreateAPIView):
|
||||
class CategoryList(ListCreateAPI):
|
||||
"""API endpoint for accessing a list of PartCategory objects.
|
||||
|
||||
- GET: Return a list of PartCategory objects
|
||||
@ -155,7 +158,7 @@ class CategoryList(generics.ListCreateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class CategoryDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of a single PartCategory object."""
|
||||
|
||||
serializer_class = part_serializers.CategorySerializer
|
||||
@ -175,8 +178,11 @@ class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
|
||||
def update(self, request, *args, **kwargs):
|
||||
"""Perform 'update' function and mark this part as 'starred' (or not)"""
|
||||
if 'starred' in request.data:
|
||||
starred = str2bool(request.data.get('starred', False))
|
||||
# Clean up input data
|
||||
data = self.clean_data(request.data)
|
||||
|
||||
if 'starred' in data:
|
||||
starred = str2bool(data.get('starred', False))
|
||||
|
||||
self.get_object().set_starred(request.user, starred)
|
||||
|
||||
@ -185,7 +191,7 @@ class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
return response
|
||||
|
||||
|
||||
class CategoryMetadata(generics.RetrieveUpdateAPIView):
|
||||
class CategoryMetadata(RetrieveUpdateAPI):
|
||||
"""API endpoint for viewing / updating PartCategory metadata."""
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
@ -195,7 +201,7 @@ class CategoryMetadata(generics.RetrieveUpdateAPIView):
|
||||
queryset = PartCategory.objects.all()
|
||||
|
||||
|
||||
class CategoryParameterList(generics.ListCreateAPIView):
|
||||
class CategoryParameterList(ListCreateAPI):
|
||||
"""API endpoint for accessing a list of PartCategoryParameterTemplate objects.
|
||||
|
||||
- GET: Return a list of PartCategoryParameterTemplate objects
|
||||
@ -236,14 +242,14 @@ class CategoryParameterList(generics.ListCreateAPIView):
|
||||
return queryset
|
||||
|
||||
|
||||
class CategoryParameterDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class CategoryParameterDetail(RetrieveUpdateDestroyAPI):
|
||||
"""Detail endpoint fro the PartCategoryParameterTemplate model"""
|
||||
|
||||
queryset = PartCategoryParameterTemplate.objects.all()
|
||||
serializer_class = part_serializers.CategoryParameterTemplateSerializer
|
||||
|
||||
|
||||
class CategoryTree(generics.ListAPIView):
|
||||
class CategoryTree(ListAPI):
|
||||
"""API endpoint for accessing a list of PartCategory objects ready for rendering a tree."""
|
||||
|
||||
queryset = PartCategory.objects.all()
|
||||
@ -258,14 +264,14 @@ class CategoryTree(generics.ListAPIView):
|
||||
ordering = ['level', 'name']
|
||||
|
||||
|
||||
class PartSalePriceDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class PartSalePriceDetail(RetrieveUpdateDestroyAPI):
|
||||
"""Detail endpoint for PartSellPriceBreak model."""
|
||||
|
||||
queryset = PartSellPriceBreak.objects.all()
|
||||
serializer_class = part_serializers.PartSalePriceSerializer
|
||||
|
||||
|
||||
class PartSalePriceList(generics.ListCreateAPIView):
|
||||
class PartSalePriceList(ListCreateAPI):
|
||||
"""API endpoint for list view of PartSalePriceBreak model."""
|
||||
|
||||
queryset = PartSellPriceBreak.objects.all()
|
||||
@ -280,14 +286,14 @@ class PartSalePriceList(generics.ListCreateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class PartInternalPriceDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class PartInternalPriceDetail(RetrieveUpdateDestroyAPI):
|
||||
"""Detail endpoint for PartInternalPriceBreak model."""
|
||||
|
||||
queryset = PartInternalPriceBreak.objects.all()
|
||||
serializer_class = part_serializers.PartInternalPriceSerializer
|
||||
|
||||
|
||||
class PartInternalPriceList(generics.ListCreateAPIView):
|
||||
class PartInternalPriceList(ListCreateAPI):
|
||||
"""API endpoint for list view of PartInternalPriceBreak model."""
|
||||
|
||||
queryset = PartInternalPriceBreak.objects.all()
|
||||
@ -318,21 +324,21 @@ class PartAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||
]
|
||||
|
||||
|
||||
class PartAttachmentDetail(AttachmentMixin, generics.RetrieveUpdateDestroyAPIView):
|
||||
class PartAttachmentDetail(AttachmentMixin, RetrieveUpdateDestroyAPI):
|
||||
"""Detail endpoint for PartAttachment model."""
|
||||
|
||||
queryset = PartAttachment.objects.all()
|
||||
serializer_class = part_serializers.PartAttachmentSerializer
|
||||
|
||||
|
||||
class PartTestTemplateDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class PartTestTemplateDetail(RetrieveUpdateDestroyAPI):
|
||||
"""Detail endpoint for PartTestTemplate model."""
|
||||
|
||||
queryset = PartTestTemplate.objects.all()
|
||||
serializer_class = part_serializers.PartTestTemplateSerializer
|
||||
|
||||
|
||||
class PartTestTemplateList(generics.ListCreateAPIView):
|
||||
class PartTestTemplateList(ListCreateAPI):
|
||||
"""API endpoint for listing (and creating) a PartTestTemplate."""
|
||||
|
||||
queryset = PartTestTemplate.objects.all()
|
||||
@ -372,7 +378,7 @@ class PartTestTemplateList(generics.ListCreateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class PartThumbs(generics.ListAPIView):
|
||||
class PartThumbs(ListAPI):
|
||||
"""API endpoint for retrieving information on available Part thumbnails."""
|
||||
|
||||
queryset = Part.objects.all()
|
||||
@ -415,7 +421,7 @@ class PartThumbs(generics.ListAPIView):
|
||||
]
|
||||
|
||||
|
||||
class PartThumbsUpdate(generics.RetrieveUpdateAPIView):
|
||||
class PartThumbsUpdate(RetrieveUpdateAPI):
|
||||
"""API endpoint for updating Part thumbnails."""
|
||||
|
||||
queryset = Part.objects.all()
|
||||
@ -426,7 +432,7 @@ class PartThumbsUpdate(generics.RetrieveUpdateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class PartScheduling(generics.RetrieveAPIView):
|
||||
class PartScheduling(RetrieveAPI):
|
||||
"""API endpoint for delivering "scheduling" information about a given part via the API.
|
||||
|
||||
Returns a chronologically ordered list about future "scheduled" events,
|
||||
@ -560,7 +566,7 @@ class PartScheduling(generics.RetrieveAPIView):
|
||||
return Response(schedule)
|
||||
|
||||
|
||||
class PartMetadata(generics.RetrieveUpdateAPIView):
|
||||
class PartMetadata(RetrieveUpdateAPI):
|
||||
"""API endpoint for viewing / updating Part metadata."""
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
@ -570,7 +576,7 @@ class PartMetadata(generics.RetrieveUpdateAPIView):
|
||||
queryset = Part.objects.all()
|
||||
|
||||
|
||||
class PartSerialNumberDetail(generics.RetrieveAPIView):
|
||||
class PartSerialNumberDetail(RetrieveAPI):
|
||||
"""API endpoint for returning extra serial number information about a particular part."""
|
||||
|
||||
queryset = Part.objects.all()
|
||||
@ -595,7 +601,7 @@ class PartSerialNumberDetail(generics.RetrieveAPIView):
|
||||
return Response(data)
|
||||
|
||||
|
||||
class PartCopyBOM(generics.CreateAPIView):
|
||||
class PartCopyBOM(CreateAPI):
|
||||
"""API endpoint for duplicating a BOM."""
|
||||
|
||||
queryset = Part.objects.all()
|
||||
@ -613,7 +619,7 @@ class PartCopyBOM(generics.CreateAPIView):
|
||||
return ctx
|
||||
|
||||
|
||||
class PartValidateBOM(generics.RetrieveUpdateAPIView):
|
||||
class PartValidateBOM(RetrieveUpdateAPI):
|
||||
"""API endpoint for 'validating' the BOM for a given Part."""
|
||||
|
||||
class BOMValidateSerializer(serializers.ModelSerializer):
|
||||
@ -654,7 +660,10 @@ class PartValidateBOM(generics.RetrieveUpdateAPIView):
|
||||
|
||||
partial = kwargs.pop('partial', False)
|
||||
|
||||
serializer = self.get_serializer(part, data=request.data, partial=partial)
|
||||
# Clean up input data before using it
|
||||
data = self.clean_data(request.data)
|
||||
|
||||
serializer = self.get_serializer(part, data=data, partial=partial)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
part.validate_bom(request.user)
|
||||
@ -664,7 +673,7 @@ class PartValidateBOM(generics.RetrieveUpdateAPIView):
|
||||
})
|
||||
|
||||
|
||||
class PartDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class PartDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of a single Part object."""
|
||||
|
||||
queryset = Part.objects.all()
|
||||
@ -721,8 +730,11 @@ class PartDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
|
||||
- If the 'starred' field is provided, update the 'starred' status against current user
|
||||
"""
|
||||
if 'starred' in request.data:
|
||||
starred = str2bool(request.data.get('starred', False))
|
||||
# Clean input data
|
||||
data = self.clean_data(request.data)
|
||||
|
||||
if 'starred' in data:
|
||||
starred = str2bool(data.get('starred', False))
|
||||
|
||||
self.get_object().set_starred(request.user, starred)
|
||||
|
||||
@ -874,7 +886,7 @@ class PartFilter(rest_filters.FilterSet):
|
||||
virtual = rest_filters.BooleanFilter()
|
||||
|
||||
|
||||
class PartList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
class PartList(APIDownloadMixin, ListCreateAPI):
|
||||
"""API endpoint for accessing a list of Part objects.
|
||||
|
||||
- GET: Return list of objects
|
||||
@ -1003,7 +1015,10 @@ class PartList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
"""
|
||||
# TODO: Unit tests for this function!
|
||||
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
# Clean up input data
|
||||
data = self.clean_data(request.data)
|
||||
|
||||
serializer = self.get_serializer(data=data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
part = serializer.save()
|
||||
@ -1011,23 +1026,23 @@ class PartList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
|
||||
# Optionally copy templates from category or parent category
|
||||
copy_templates = {
|
||||
'main': str2bool(request.data.get('copy_category_templates', False)),
|
||||
'parent': str2bool(request.data.get('copy_parent_templates', False))
|
||||
'main': str2bool(data.get('copy_category_templates', False)),
|
||||
'parent': str2bool(data.get('copy_parent_templates', False))
|
||||
}
|
||||
|
||||
part.save(**{'add_category_templates': copy_templates})
|
||||
|
||||
# Optionally copy data from another part (e.g. when duplicating)
|
||||
copy_from = request.data.get('copy_from', None)
|
||||
copy_from = data.get('copy_from', None)
|
||||
|
||||
if copy_from is not None:
|
||||
|
||||
try:
|
||||
original = Part.objects.get(pk=copy_from)
|
||||
|
||||
copy_bom = str2bool(request.data.get('copy_bom', False))
|
||||
copy_parameters = str2bool(request.data.get('copy_parameters', False))
|
||||
copy_image = str2bool(request.data.get('copy_image', True))
|
||||
copy_bom = str2bool(data.get('copy_bom', False))
|
||||
copy_parameters = str2bool(data.get('copy_parameters', False))
|
||||
copy_image = str2bool(data.get('copy_image', True))
|
||||
|
||||
# Copy image?
|
||||
if copy_image:
|
||||
@ -1046,12 +1061,12 @@ class PartList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
pass
|
||||
|
||||
# Optionally create initial stock item
|
||||
initial_stock = str2bool(request.data.get('initial_stock', False))
|
||||
initial_stock = str2bool(data.get('initial_stock', False))
|
||||
|
||||
if initial_stock:
|
||||
try:
|
||||
|
||||
initial_stock_quantity = Decimal(request.data.get('initial_stock_quantity', ''))
|
||||
initial_stock_quantity = Decimal(data.get('initial_stock_quantity', ''))
|
||||
|
||||
if initial_stock_quantity <= 0:
|
||||
raise ValidationError({
|
||||
@ -1062,7 +1077,7 @@ class PartList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
'initial_stock_quantity': [_('Must be a valid quantity')],
|
||||
})
|
||||
|
||||
initial_stock_location = request.data.get('initial_stock_location', None)
|
||||
initial_stock_location = data.get('initial_stock_location', None)
|
||||
|
||||
try:
|
||||
initial_stock_location = StockLocation.objects.get(pk=initial_stock_location)
|
||||
@ -1086,20 +1101,20 @@ class PartList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
stock_item.save(user=request.user)
|
||||
|
||||
# Optionally add manufacturer / supplier data to the part
|
||||
if part.purchaseable and str2bool(request.data.get('add_supplier_info', False)):
|
||||
if part.purchaseable and str2bool(data.get('add_supplier_info', False)):
|
||||
|
||||
try:
|
||||
manufacturer = Company.objects.get(pk=request.data.get('manufacturer', None))
|
||||
manufacturer = Company.objects.get(pk=data.get('manufacturer', None))
|
||||
except Exception:
|
||||
manufacturer = None
|
||||
|
||||
try:
|
||||
supplier = Company.objects.get(pk=request.data.get('supplier', None))
|
||||
supplier = Company.objects.get(pk=data.get('supplier', None))
|
||||
except Exception:
|
||||
supplier = None
|
||||
|
||||
mpn = str(request.data.get('MPN', '')).strip()
|
||||
sku = str(request.data.get('SKU', '')).strip()
|
||||
mpn = str(data.get('MPN', '')).strip()
|
||||
sku = str(data.get('SKU', '')).strip()
|
||||
|
||||
# Construct a manufacturer part
|
||||
if manufacturer or mpn:
|
||||
@ -1347,7 +1362,7 @@ class PartList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class PartRelatedList(generics.ListCreateAPIView):
|
||||
class PartRelatedList(ListCreateAPI):
|
||||
"""API endpoint for accessing a list of PartRelated objects."""
|
||||
|
||||
queryset = PartRelated.objects.all()
|
||||
@ -1374,14 +1389,14 @@ class PartRelatedList(generics.ListCreateAPIView):
|
||||
return queryset
|
||||
|
||||
|
||||
class PartRelatedDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class PartRelatedDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for accessing detail view of a PartRelated object."""
|
||||
|
||||
queryset = PartRelated.objects.all()
|
||||
serializer_class = part_serializers.PartRelationSerializer
|
||||
|
||||
|
||||
class PartParameterTemplateList(generics.ListCreateAPIView):
|
||||
class PartParameterTemplateList(ListCreateAPI):
|
||||
"""API endpoint for accessing a list of PartParameterTemplate objects.
|
||||
|
||||
- GET: Return list of PartParameterTemplate objects
|
||||
@ -1441,14 +1456,14 @@ class PartParameterTemplateList(generics.ListCreateAPIView):
|
||||
return queryset
|
||||
|
||||
|
||||
class PartParameterTemplateDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class PartParameterTemplateDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for accessing the detail view for a PartParameterTemplate object"""
|
||||
|
||||
queryset = PartParameterTemplate.objects.all()
|
||||
serializer_class = part_serializers.PartParameterTemplateSerializer
|
||||
|
||||
|
||||
class PartParameterList(generics.ListCreateAPIView):
|
||||
class PartParameterList(ListCreateAPI):
|
||||
"""API endpoint for accessing a list of PartParameter objects.
|
||||
|
||||
- GET: Return list of PartParameter objects
|
||||
@ -1468,7 +1483,7 @@ class PartParameterList(generics.ListCreateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class PartParameterDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class PartParameterDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of a single PartParameter object."""
|
||||
|
||||
queryset = PartParameter.objects.all()
|
||||
@ -1747,7 +1762,7 @@ class BomList(ListCreateDestroyAPIView):
|
||||
]
|
||||
|
||||
|
||||
class BomImportUpload(generics.CreateAPIView):
|
||||
class BomImportUpload(CreateAPI):
|
||||
"""API endpoint for uploading a complete Bill of Materials.
|
||||
|
||||
It is assumed that the BOM has been extracted from a file using the BomExtract endpoint.
|
||||
@ -1758,7 +1773,10 @@ class BomImportUpload(generics.CreateAPIView):
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""Custom create function to return the extracted data."""
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
# Clean up input data
|
||||
data = self.clean_data(request.data)
|
||||
|
||||
serializer = self.get_serializer(data=data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
self.perform_create(serializer)
|
||||
headers = self.get_success_headers(serializer.data)
|
||||
@ -1768,21 +1786,21 @@ class BomImportUpload(generics.CreateAPIView):
|
||||
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
|
||||
|
||||
|
||||
class BomImportExtract(generics.CreateAPIView):
|
||||
class BomImportExtract(CreateAPI):
|
||||
"""API endpoint for extracting BOM data from a BOM file."""
|
||||
|
||||
queryset = Part.objects.none()
|
||||
serializer_class = part_serializers.BomImportExtractSerializer
|
||||
|
||||
|
||||
class BomImportSubmit(generics.CreateAPIView):
|
||||
class BomImportSubmit(CreateAPI):
|
||||
"""API endpoint for submitting BOM data from a BOM file."""
|
||||
|
||||
queryset = BomItem.objects.none()
|
||||
serializer_class = part_serializers.BomImportSubmitSerializer
|
||||
|
||||
|
||||
class BomDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class BomDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of a single BomItem object."""
|
||||
|
||||
queryset = BomItem.objects.all()
|
||||
@ -1798,7 +1816,7 @@ class BomDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
return queryset
|
||||
|
||||
|
||||
class BomItemValidate(generics.UpdateAPIView):
|
||||
class BomItemValidate(UpdateAPI):
|
||||
"""API endpoint for validating a BomItem."""
|
||||
|
||||
class BomItemValidationSerializer(serializers.Serializer):
|
||||
@ -1812,11 +1830,13 @@ class BomItemValidate(generics.UpdateAPIView):
|
||||
"""Perform update request."""
|
||||
partial = kwargs.pop('partial', False)
|
||||
|
||||
valid = request.data.get('valid', False)
|
||||
# Clean up input data
|
||||
data = self.clean_data(request.data)
|
||||
valid = data.get('valid', False)
|
||||
|
||||
instance = self.get_object()
|
||||
|
||||
serializer = self.get_serializer(instance, data=request.data, partial=partial)
|
||||
serializer = self.get_serializer(instance, data=data, partial=partial)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
if type(instance) == BomItem:
|
||||
@ -1825,7 +1845,7 @@ class BomItemValidate(generics.UpdateAPIView):
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
class BomItemSubstituteList(generics.ListCreateAPIView):
|
||||
class BomItemSubstituteList(ListCreateAPI):
|
||||
"""API endpoint for accessing a list of BomItemSubstitute objects."""
|
||||
|
||||
serializer_class = part_serializers.BomItemSubstituteSerializer
|
||||
@ -1843,7 +1863,7 @@ class BomItemSubstituteList(generics.ListCreateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class BomItemSubstituteDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class BomItemSubstituteDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of a single BomItemSubstitute object."""
|
||||
|
||||
queryset = BomItemSubstitute.objects.all()
|
||||
|
@ -4,12 +4,14 @@ from django.conf import settings
|
||||
from django.urls import include, re_path
|
||||
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import filters, generics, permissions, status
|
||||
from rest_framework import filters, permissions, status
|
||||
from rest_framework.exceptions import NotFound
|
||||
from rest_framework.response import Response
|
||||
|
||||
import plugin.serializers as PluginSerializers
|
||||
from common.api import GlobalSettingsPermissions
|
||||
from InvenTree.mixins import (CreateAPI, ListAPI, RetrieveUpdateAPI,
|
||||
RetrieveUpdateDestroyAPI)
|
||||
from plugin.base.action.api import ActionPluginView
|
||||
from plugin.base.barcodes.api import barcode_api_urls
|
||||
from plugin.base.locate.api import LocatePluginView
|
||||
@ -17,7 +19,7 @@ from plugin.models import PluginConfig, PluginSetting
|
||||
from plugin.registry import registry
|
||||
|
||||
|
||||
class PluginList(generics.ListAPIView):
|
||||
class PluginList(ListAPI):
|
||||
"""API endpoint for list of PluginConfig objects.
|
||||
|
||||
- GET: Return a list of all PluginConfig objects
|
||||
@ -80,7 +82,7 @@ class PluginList(generics.ListAPIView):
|
||||
]
|
||||
|
||||
|
||||
class PluginDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class PluginDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API detail endpoint for PluginConfig object.
|
||||
|
||||
get:
|
||||
@ -97,7 +99,7 @@ class PluginDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
serializer_class = PluginSerializers.PluginConfigSerializer
|
||||
|
||||
|
||||
class PluginInstall(generics.CreateAPIView):
|
||||
class PluginInstall(CreateAPI):
|
||||
"""Endpoint for installing a new plugin."""
|
||||
|
||||
queryset = PluginConfig.objects.none()
|
||||
@ -105,7 +107,10 @@ class PluginInstall(generics.CreateAPIView):
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""Install a plugin via the API"""
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
# Clean up input data
|
||||
data = self.clean_data(request.data)
|
||||
|
||||
serializer = self.get_serializer(data=data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
result = self.perform_create(serializer)
|
||||
result['input'] = serializer.data
|
||||
@ -117,7 +122,7 @@ class PluginInstall(generics.CreateAPIView):
|
||||
return serializer.save()
|
||||
|
||||
|
||||
class PluginSettingList(generics.ListAPIView):
|
||||
class PluginSettingList(ListAPI):
|
||||
"""List endpoint for all plugin related settings.
|
||||
|
||||
- read only
|
||||
@ -141,7 +146,7 @@ class PluginSettingList(generics.ListAPIView):
|
||||
]
|
||||
|
||||
|
||||
class PluginSettingDetail(generics.RetrieveUpdateAPIView):
|
||||
class PluginSettingDetail(RetrieveUpdateAPI):
|
||||
"""Detail endpoint for a plugin-specific setting.
|
||||
|
||||
Note that these cannot be created or deleted via the API
|
||||
|
@ -8,7 +8,7 @@ from django.urls import include, path, re_path
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import filters, generics
|
||||
from rest_framework import filters
|
||||
from rest_framework.response import Response
|
||||
|
||||
import build.models
|
||||
@ -16,6 +16,7 @@ import common.models
|
||||
import InvenTree.helpers
|
||||
import order.models
|
||||
import part.models
|
||||
from InvenTree.mixins import ListAPI, RetrieveAPI, RetrieveUpdateDestroyAPI
|
||||
from stock.models import StockItem, StockItemAttachment
|
||||
|
||||
from .models import (BillOfMaterialsReport, BuildReport, PurchaseOrderReport,
|
||||
@ -25,7 +26,7 @@ from .serializers import (BOMReportSerializer, BuildReportSerializer,
|
||||
SalesOrderReportSerializer, TestReportSerializer)
|
||||
|
||||
|
||||
class ReportListView(generics.ListAPIView):
|
||||
class ReportListView(ListAPI):
|
||||
"""Generic API class for report templates."""
|
||||
|
||||
filter_backends = [
|
||||
@ -330,14 +331,14 @@ class StockItemTestReportList(ReportListView, StockItemReportMixin):
|
||||
return queryset
|
||||
|
||||
|
||||
class StockItemTestReportDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class StockItemTestReportDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for a single TestReport object."""
|
||||
|
||||
queryset = TestReport.objects.all()
|
||||
serializer_class = TestReportSerializer
|
||||
|
||||
|
||||
class StockItemTestReportPrint(generics.RetrieveAPIView, StockItemReportMixin, ReportPrintMixin):
|
||||
class StockItemTestReportPrint(RetrieveAPI, StockItemReportMixin, ReportPrintMixin):
|
||||
"""API endpoint for printing a TestReport object."""
|
||||
|
||||
queryset = TestReport.objects.all()
|
||||
@ -427,14 +428,14 @@ class BOMReportList(ReportListView, PartReportMixin):
|
||||
return queryset
|
||||
|
||||
|
||||
class BOMReportDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class BOMReportDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for a single BillOfMaterialReport object."""
|
||||
|
||||
queryset = BillOfMaterialsReport.objects.all()
|
||||
serializer_class = BOMReportSerializer
|
||||
|
||||
|
||||
class BOMReportPrint(generics.RetrieveAPIView, PartReportMixin, ReportPrintMixin):
|
||||
class BOMReportPrint(RetrieveAPI, PartReportMixin, ReportPrintMixin):
|
||||
"""API endpoint for printing a BillOfMaterialReport object."""
|
||||
|
||||
queryset = BillOfMaterialsReport.objects.all()
|
||||
@ -509,14 +510,14 @@ class BuildReportList(ReportListView, BuildReportMixin):
|
||||
return queryset
|
||||
|
||||
|
||||
class BuildReportDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class BuildReportDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for a single BuildReport object."""
|
||||
|
||||
queryset = BuildReport.objects.all()
|
||||
serializer_class = BuildReportSerializer
|
||||
|
||||
|
||||
class BuildReportPrint(generics.RetrieveAPIView, BuildReportMixin, ReportPrintMixin):
|
||||
class BuildReportPrint(RetrieveAPI, BuildReportMixin, ReportPrintMixin):
|
||||
"""API endpoint for printing a BuildReport."""
|
||||
|
||||
queryset = BuildReport.objects.all()
|
||||
@ -586,14 +587,14 @@ class PurchaseOrderReportList(ReportListView, OrderReportMixin):
|
||||
return queryset
|
||||
|
||||
|
||||
class PurchaseOrderReportDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class PurchaseOrderReportDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for a single PurchaseOrderReport object."""
|
||||
|
||||
queryset = PurchaseOrderReport.objects.all()
|
||||
serializer_class = PurchaseOrderReportSerializer
|
||||
|
||||
|
||||
class PurchaseOrderReportPrint(generics.RetrieveAPIView, OrderReportMixin, ReportPrintMixin):
|
||||
class PurchaseOrderReportPrint(RetrieveAPI, OrderReportMixin, ReportPrintMixin):
|
||||
"""API endpoint for printing a PurchaseOrderReport object."""
|
||||
|
||||
OrderModel = order.models.PurchaseOrder
|
||||
@ -665,14 +666,14 @@ class SalesOrderReportList(ReportListView, OrderReportMixin):
|
||||
return queryset
|
||||
|
||||
|
||||
class SalesOrderReportDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class SalesOrderReportDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for a single SalesOrderReport object."""
|
||||
|
||||
queryset = SalesOrderReport.objects.all()
|
||||
serializer_class = SalesOrderReportSerializer
|
||||
|
||||
|
||||
class SalesOrderReportPrint(generics.RetrieveAPIView, OrderReportMixin, ReportPrintMixin):
|
||||
class SalesOrderReportPrint(RetrieveAPI, OrderReportMixin, ReportPrintMixin):
|
||||
"""API endpoint for printing a PurchaseOrderReport object."""
|
||||
|
||||
OrderModel = order.models.SalesOrder
|
||||
|
@ -12,7 +12,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from django_filters import rest_framework as rest_filters
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import filters, generics, status
|
||||
from rest_framework import filters, status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import ValidationError
|
||||
|
||||
@ -27,6 +27,8 @@ from InvenTree.api import (APIDownloadMixin, AttachmentMixin,
|
||||
from InvenTree.filters import InvenTreeOrderingFilter
|
||||
from InvenTree.helpers import (DownloadFile, extract_serial_numbers, isNull,
|
||||
str2bool)
|
||||
from InvenTree.mixins import (CreateAPI, ListAPI, ListCreateAPI, RetrieveAPI,
|
||||
RetrieveUpdateAPI, RetrieveUpdateDestroyAPI)
|
||||
from order.models import PurchaseOrder, SalesOrder, SalesOrderAllocation
|
||||
from order.serializers import PurchaseOrderSerializer
|
||||
from part.models import BomItem, Part, PartCategory
|
||||
@ -37,7 +39,7 @@ from stock.models import (StockItem, StockItemAttachment, StockItemTestResult,
|
||||
StockItemTracking, StockLocation)
|
||||
|
||||
|
||||
class StockDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class StockDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API detail endpoint for Stock object.
|
||||
|
||||
get:
|
||||
@ -78,7 +80,7 @@ class StockDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
return self.serializer_class(*args, **kwargs)
|
||||
|
||||
|
||||
class StockMetadata(generics.RetrieveUpdateAPIView):
|
||||
class StockMetadata(RetrieveUpdateAPI):
|
||||
"""API endpoint for viewing / updating StockItem metadata."""
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
@ -106,13 +108,13 @@ class StockItemContextMixin:
|
||||
return context
|
||||
|
||||
|
||||
class StockItemSerialize(StockItemContextMixin, generics.CreateAPIView):
|
||||
class StockItemSerialize(StockItemContextMixin, CreateAPI):
|
||||
"""API endpoint for serializing a stock item."""
|
||||
|
||||
serializer_class = StockSerializers.SerializeStockItemSerializer
|
||||
|
||||
|
||||
class StockItemInstall(StockItemContextMixin, generics.CreateAPIView):
|
||||
class StockItemInstall(StockItemContextMixin, CreateAPI):
|
||||
"""API endpoint for installing a particular stock item into this stock item.
|
||||
|
||||
- stock_item.part must be in the BOM for this part
|
||||
@ -123,25 +125,25 @@ class StockItemInstall(StockItemContextMixin, generics.CreateAPIView):
|
||||
serializer_class = StockSerializers.InstallStockItemSerializer
|
||||
|
||||
|
||||
class StockItemUninstall(StockItemContextMixin, generics.CreateAPIView):
|
||||
class StockItemUninstall(StockItemContextMixin, CreateAPI):
|
||||
"""API endpoint for removing (uninstalling) items from this item."""
|
||||
|
||||
serializer_class = StockSerializers.UninstallStockItemSerializer
|
||||
|
||||
|
||||
class StockItemConvert(StockItemContextMixin, generics.CreateAPIView):
|
||||
class StockItemConvert(StockItemContextMixin, CreateAPI):
|
||||
"""API endpoint for converting a stock item to a variant part"""
|
||||
|
||||
serializer_class = StockSerializers.ConvertStockItemSerializer
|
||||
|
||||
|
||||
class StockItemReturn(StockItemContextMixin, generics.CreateAPIView):
|
||||
class StockItemReturn(StockItemContextMixin, CreateAPI):
|
||||
"""API endpoint for returning a stock item from a customer"""
|
||||
|
||||
serializer_class = StockSerializers.ReturnStockItemSerializer
|
||||
|
||||
|
||||
class StockAdjustView(generics.CreateAPIView):
|
||||
class StockAdjustView(CreateAPI):
|
||||
"""A generic class for handling stocktake actions.
|
||||
|
||||
Subclasses exist for:
|
||||
@ -186,7 +188,7 @@ class StockTransfer(StockAdjustView):
|
||||
serializer_class = StockSerializers.StockTransferSerializer
|
||||
|
||||
|
||||
class StockAssign(generics.CreateAPIView):
|
||||
class StockAssign(CreateAPI):
|
||||
"""API endpoint for assigning stock to a particular customer."""
|
||||
|
||||
queryset = StockItem.objects.all()
|
||||
@ -200,7 +202,7 @@ class StockAssign(generics.CreateAPIView):
|
||||
return ctx
|
||||
|
||||
|
||||
class StockMerge(generics.CreateAPIView):
|
||||
class StockMerge(CreateAPI):
|
||||
"""API endpoint for merging multiple stock items."""
|
||||
|
||||
queryset = StockItem.objects.none()
|
||||
@ -213,7 +215,7 @@ class StockMerge(generics.CreateAPIView):
|
||||
return ctx
|
||||
|
||||
|
||||
class StockLocationList(generics.ListCreateAPIView):
|
||||
class StockLocationList(ListCreateAPI):
|
||||
"""API endpoint for list view of StockLocation objects.
|
||||
|
||||
- GET: Return list of StockLocation objects
|
||||
@ -305,7 +307,7 @@ class StockLocationList(generics.ListCreateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class StockLocationTree(generics.ListAPIView):
|
||||
class StockLocationTree(ListAPI):
|
||||
"""API endpoint for accessing a list of StockLocation objects, ready for rendering as a tree."""
|
||||
|
||||
queryset = StockLocation.objects.all()
|
||||
@ -502,7 +504,8 @@ class StockList(APIDownloadMixin, ListCreateDestroyAPIView):
|
||||
|
||||
# Copy the request data, to side-step "mutability" issues
|
||||
data = OrderedDict()
|
||||
data.update(request.data)
|
||||
# Update with cleaned input data
|
||||
data.update(self.clean_data(request.data))
|
||||
|
||||
quantity = data.get('quantity', None)
|
||||
|
||||
@ -1067,14 +1070,14 @@ class StockAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||
]
|
||||
|
||||
|
||||
class StockAttachmentDetail(AttachmentMixin, generics.RetrieveUpdateDestroyAPIView):
|
||||
class StockAttachmentDetail(AttachmentMixin, RetrieveUpdateDestroyAPI):
|
||||
"""Detail endpoint for StockItemAttachment."""
|
||||
|
||||
queryset = StockItemAttachment.objects.all()
|
||||
serializer_class = StockSerializers.StockItemAttachmentSerializer
|
||||
|
||||
|
||||
class StockItemTestResultDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class StockItemTestResultDetail(RetrieveUpdateDestroyAPI):
|
||||
"""Detail endpoint for StockItemTestResult."""
|
||||
|
||||
queryset = StockItemTestResult.objects.all()
|
||||
@ -1170,14 +1173,14 @@ class StockItemTestResultList(ListCreateDestroyAPIView):
|
||||
test_result.save()
|
||||
|
||||
|
||||
class StockTrackingDetail(generics.RetrieveAPIView):
|
||||
class StockTrackingDetail(RetrieveAPI):
|
||||
"""Detail API endpoint for StockItemTracking model."""
|
||||
|
||||
queryset = StockItemTracking.objects.all()
|
||||
serializer_class = StockSerializers.StockTrackingSerializer
|
||||
|
||||
|
||||
class StockTrackingList(generics.ListAPIView):
|
||||
class StockTrackingList(ListAPI):
|
||||
"""API endpoint for list view of StockItemTracking objects.
|
||||
|
||||
StockItemTracking objects are read-only
|
||||
@ -1276,7 +1279,10 @@ class StockTrackingList(generics.ListAPIView):
|
||||
Here we override the default 'create' implementation,
|
||||
to save the user information associated with the request object.
|
||||
"""
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
# Clean up input data
|
||||
data = self.clean_data(request.data)
|
||||
|
||||
serializer = self.get_serializer(data=data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
# Record the user who created this Part object
|
||||
@ -1314,7 +1320,7 @@ class StockTrackingList(generics.ListAPIView):
|
||||
]
|
||||
|
||||
|
||||
class LocationMetadata(generics.RetrieveUpdateAPIView):
|
||||
class LocationMetadata(RetrieveUpdateAPI):
|
||||
"""API endpoint for viewing / updating StockLocation metadata."""
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
@ -1324,7 +1330,7 @@ class LocationMetadata(generics.RetrieveUpdateAPIView):
|
||||
queryset = StockLocation.objects.all()
|
||||
|
||||
|
||||
class LocationDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
class LocationDetail(RetrieveUpdateDestroyAPI):
|
||||
"""API endpoint for detail view of StockLocation object.
|
||||
|
||||
- GET: Return a single StockLocation object
|
||||
|
@ -5,17 +5,18 @@ from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.urls import include, path, re_path
|
||||
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import filters, generics, permissions, status
|
||||
from rest_framework import filters, permissions, status
|
||||
from rest_framework.authtoken.models import Token
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from InvenTree.mixins import ListAPI, RetrieveAPI
|
||||
from InvenTree.serializers import UserSerializer
|
||||
from users.models import Owner, RuleSet, check_user_role
|
||||
from users.serializers import OwnerSerializer
|
||||
|
||||
|
||||
class OwnerList(generics.ListAPIView):
|
||||
class OwnerList(ListAPI):
|
||||
"""List API endpoint for Owner model.
|
||||
|
||||
Cannot create.
|
||||
@ -54,7 +55,7 @@ class OwnerList(generics.ListAPIView):
|
||||
return results
|
||||
|
||||
|
||||
class OwnerDetail(generics.RetrieveAPIView):
|
||||
class OwnerDetail(RetrieveAPI):
|
||||
"""Detail API endpoint for Owner model.
|
||||
|
||||
Cannot edit or delete
|
||||
@ -107,7 +108,7 @@ class RoleDetails(APIView):
|
||||
return Response(data)
|
||||
|
||||
|
||||
class UserDetail(generics.RetrieveAPIView):
|
||||
class UserDetail(RetrieveAPI):
|
||||
"""Detail endpoint for a single user."""
|
||||
|
||||
queryset = User.objects.all()
|
||||
@ -115,7 +116,7 @@ class UserDetail(generics.RetrieveAPIView):
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
|
||||
|
||||
class UserList(generics.ListAPIView):
|
||||
class UserList(ListAPI):
|
||||
"""List endpoint for detail on all users."""
|
||||
|
||||
queryset = User.objects.all()
|
||||
|
Loading…
Reference in New Issue
Block a user