2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 11:36:44 +00:00

Metadata API refactor (#4545)

* Add generic metadata API endpoint

(cherry picked from commit 7bbd53fc7647e2bb18d36c8c351e3fc080037ab1)

* Refactor metadata endpoints for build models

(cherry picked from commit 722b44e1259f1c5b046c7bc4328995b8238fc342)

* Update metadata views for company models

* labels

* orders

* part

* report

* stock
This commit is contained in:
Oliver 2023-03-31 10:42:54 +11:00 committed by GitHub
parent 327ecf2156
commit 08d0084e07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 66 additions and 283 deletions

View File

@ -16,7 +16,9 @@ import users.models
from InvenTree.mixins import ListCreateAPI from InvenTree.mixins import ListCreateAPI
from InvenTree.permissions import RolePermission from InvenTree.permissions import RolePermission
from part.templatetags.inventree_extras import plugins_info from part.templatetags.inventree_extras import plugins_info
from plugin.serializers import MetadataSerializer
from .mixins import RetrieveUpdateAPI
from .status import is_worker_running from .status import is_worker_running
from .version import (inventreeApiVersion, inventreeInstanceName, from .version import (inventreeApiVersion, inventreeInstanceName,
inventreeVersion) inventreeVersion)
@ -354,3 +356,26 @@ class StatusView(APIView):
} }
return Response(data) return Response(data)
class MetadataView(RetrieveUpdateAPI):
"""Generic API endpoint for reading and editing metadata for a model"""
MODEL_REF = 'model'
def get_model_type(self):
"""Return the model type associated with this API instance"""
model = self.kwargs.get(self.MODEL_REF, None)
if model is None:
raise ValidationError(f"MetadataView called without '{self.MODEL_REF}' parameter")
return model
def get_queryset(self):
"""Return the queryset for this endpoint"""
return self.get_model_type().objects.all()
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance"""
return MetadataSerializer(self.get_model_type(), *args, **kwargs)

View File

@ -10,13 +10,11 @@ from rest_framework.exceptions import ValidationError
from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend
from django_filters import rest_framework as rest_filters from django_filters import rest_framework as rest_filters
from InvenTree.api import AttachmentMixin, APIDownloadMixin, ListCreateDestroyAPIView, StatusView from InvenTree.api import AttachmentMixin, APIDownloadMixin, ListCreateDestroyAPIView, MetadataView, StatusView
from InvenTree.helpers import str2bool, isNull, DownloadFile from InvenTree.helpers import str2bool, isNull, DownloadFile
from InvenTree.filters import InvenTreeOrderingFilter from InvenTree.filters import InvenTreeOrderingFilter
from InvenTree.status_codes import BuildStatus from InvenTree.status_codes import BuildStatus
from InvenTree.mixins import CreateAPI, RetrieveUpdateAPI, RetrieveUpdateDestroyAPI, ListCreateAPI from InvenTree.mixins import CreateAPI, RetrieveUpdateDestroyAPI, ListCreateAPI
from plugin.serializers import MetadataSerializer
import build.admin import build.admin
import build.serializers import build.serializers
@ -292,16 +290,6 @@ class BuildOrderContextMixin:
return ctx return ctx
class BuildOrderMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating BuildOrder metadata."""
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance"""
return MetadataSerializer(Build, *args, **kwargs)
queryset = Build.objects.all()
class BuildOutputCreate(BuildOrderContextMixin, CreateAPI): class BuildOutputCreate(BuildOrderContextMixin, CreateAPI):
"""API endpoint for creating new build output(s).""" """API endpoint for creating new build output(s)."""
@ -473,16 +461,6 @@ class BuildItemList(ListCreateAPI):
] ]
class BuildItemMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating BuildItem metadata."""
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance"""
return MetadataSerializer(BuildItem, *args, **kwargs)
queryset = BuildItem.objects.all()
class BuildAttachmentList(AttachmentMixin, ListCreateDestroyAPIView): class BuildAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
"""API endpoint for listing (and creating) BuildOrderAttachment objects.""" """API endpoint for listing (and creating) BuildOrderAttachment objects."""
@ -516,7 +494,7 @@ build_api_urls = [
# Build Items # Build Items
re_path(r'^item/', include([ re_path(r'^item/', include([
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
re_path(r'^metadata/', BuildItemMetadata.as_view(), name='api-build-item-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': BuildItem}, name='api-build-item-metadata'),
re_path(r'^.*$', BuildItemDetail.as_view(), name='api-build-item-detail'), re_path(r'^.*$', BuildItemDetail.as_view(), name='api-build-item-detail'),
])), ])),
re_path(r'^.*$', BuildItemList.as_view(), name='api-build-item-list'), re_path(r'^.*$', BuildItemList.as_view(), name='api-build-item-list'),
@ -532,7 +510,7 @@ build_api_urls = [
re_path(r'^finish/', BuildFinish.as_view(), name='api-build-finish'), re_path(r'^finish/', BuildFinish.as_view(), name='api-build-finish'),
re_path(r'^cancel/', BuildCancel.as_view(), name='api-build-cancel'), re_path(r'^cancel/', BuildCancel.as_view(), name='api-build-cancel'),
re_path(r'^unallocate/', BuildUnallocate.as_view(), name='api-build-unallocate'), re_path(r'^unallocate/', BuildUnallocate.as_view(), name='api-build-unallocate'),
re_path(r'^metadata/', BuildOrderMetadata.as_view(), name='api-build-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': Build}, name='api-build-metadata'),
re_path(r'^.*$', BuildDetail.as_view(), name='api-build-detail'), re_path(r'^.*$', BuildDetail.as_view(), name='api-build-detail'),
])), ])),

View File

@ -8,12 +8,11 @@ from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters from rest_framework import filters
import part.models import part.models
from InvenTree.api import AttachmentMixin, ListCreateDestroyAPIView from InvenTree.api import (AttachmentMixin, ListCreateDestroyAPIView,
MetadataView)
from InvenTree.filters import InvenTreeOrderingFilter from InvenTree.filters import InvenTreeOrderingFilter
from InvenTree.helpers import str2bool from InvenTree.helpers import str2bool
from InvenTree.mixins import (ListCreateAPI, RetrieveUpdateAPI, from InvenTree.mixins import ListCreateAPI, RetrieveUpdateDestroyAPI
RetrieveUpdateDestroyAPI)
from plugin.serializers import MetadataSerializer
from .models import (Company, CompanyAttachment, Contact, ManufacturerPart, from .models import (Company, CompanyAttachment, Contact, ManufacturerPart,
ManufacturerPartAttachment, ManufacturerPartParameter, ManufacturerPartAttachment, ManufacturerPartParameter,
@ -87,16 +86,6 @@ class CompanyDetail(RetrieveUpdateDestroyAPI):
return queryset return queryset
class CompanyMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating Company metadata."""
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance for a Company"""
return MetadataSerializer(Company, *args, **kwargs)
queryset = Company.objects.all()
class CompanyAttachmentList(AttachmentMixin, ListCreateDestroyAPIView): class CompanyAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
"""API endpoint for the CompanyAttachment model""" """API endpoint for the CompanyAttachment model"""
@ -231,16 +220,6 @@ class ManufacturerPartDetail(RetrieveUpdateDestroyAPI):
serializer_class = ManufacturerPartSerializer serializer_class = ManufacturerPartSerializer
class ManufacturerPartMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating ManufacturerPart metadata."""
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance for a Company"""
return MetadataSerializer(ManufacturerPart, *args, **kwargs)
queryset = ManufacturerPart.objects.all()
class ManufacturerPartAttachmentList(AttachmentMixin, ListCreateDestroyAPIView): class ManufacturerPartAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
"""API endpoint for listing (and creating) a ManufacturerPartAttachment (file upload).""" """API endpoint for listing (and creating) a ManufacturerPartAttachment (file upload)."""
@ -470,16 +449,6 @@ class SupplierPartDetail(RetrieveUpdateDestroyAPI):
] ]
class SupplierPartMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating SupplierPart metadata."""
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance for a Company"""
return MetadataSerializer(SupplierPart, *args, **kwargs)
queryset = SupplierPart.objects.all()
class SupplierPriceBreakFilter(rest_filters.FilterSet): class SupplierPriceBreakFilter(rest_filters.FilterSet):
"""Custom API filters for the SupplierPriceBreak list endpoint""" """Custom API filters for the SupplierPriceBreak list endpoint"""
@ -567,7 +536,7 @@ manufacturer_part_api_urls = [
])), ])),
re_path(r'^(?P<pk>\d+)/?', include([ re_path(r'^(?P<pk>\d+)/?', include([
re_path('^metadata/', ManufacturerPartMetadata.as_view(), name='api-manufacturer-part-metadata'), re_path('^metadata/', MetadataView.as_view(), {'model': ManufacturerPart}, name='api-manufacturer-part-metadata'),
re_path('^.*$', ManufacturerPartDetail.as_view(), name='api-manufacturer-part-detail'), re_path('^.*$', ManufacturerPartDetail.as_view(), name='api-manufacturer-part-detail'),
])), ])),
@ -579,7 +548,7 @@ manufacturer_part_api_urls = [
supplier_part_api_urls = [ supplier_part_api_urls = [
re_path(r'^(?P<pk>\d+)/?', include([ re_path(r'^(?P<pk>\d+)/?', include([
re_path('^metadata/', SupplierPartMetadata.as_view(), name='api-supplier-part-metadata'), re_path('^metadata/', MetadataView.as_view(), {'model': SupplierPart}, name='api-supplier-part-metadata'),
re_path('^.*$', SupplierPartDetail.as_view(), name='api-supplier-part-detail'), re_path('^.*$', SupplierPartDetail.as_view(), name='api-supplier-part-detail'),
])), ])),
@ -601,7 +570,7 @@ company_api_urls = [
])), ])),
re_path(r'^(?P<pk>\d+)/?', include([ re_path(r'^(?P<pk>\d+)/?', include([
re_path(r'^metadata/', CompanyMetadata.as_view(), name='api-company-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': Company}, name='api-company-metadata'),
re_path(r'^.*$', CompanyDetail.as_view(), name='api-company-detail'), re_path(r'^.*$', CompanyDetail.as_view(), name='api-company-detail'),
])), ])),

View File

@ -13,13 +13,12 @@ from rest_framework.exceptions import NotFound
import common.models import common.models
import InvenTree.helpers import InvenTree.helpers
from InvenTree.mixins import (ListAPI, RetrieveAPI, RetrieveUpdateAPI, from InvenTree.api import MetadataView
RetrieveUpdateDestroyAPI) from InvenTree.mixins import ListAPI, RetrieveAPI, RetrieveUpdateDestroyAPI
from InvenTree.tasks import offload_task from InvenTree.tasks import offload_task
from part.models import Part from part.models import Part
from plugin.base.label import label as plugin_label from plugin.base.label import label as plugin_label
from plugin.registry import registry from plugin.registry import registry
from plugin.serializers import MetadataSerializer
from stock.models import StockItem, StockLocation from stock.models import StockItem, StockLocation
from .models import PartLabel, StockItemLabel, StockLocationLabel from .models import PartLabel, StockItemLabel, StockLocationLabel
@ -307,16 +306,6 @@ class StockItemLabelDetail(StockItemLabelMixin, RetrieveUpdateDestroyAPI):
pass pass
class StockItemLabelMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating StockItemLabel metadata."""
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance for a Company"""
return MetadataSerializer(StockItemLabel, *args, **kwargs)
queryset = StockItemLabel.objects.all()
class StockItemLabelPrint(StockItemLabelMixin, LabelPrintMixin, RetrieveAPI): class StockItemLabelPrint(StockItemLabelMixin, LabelPrintMixin, RetrieveAPI):
"""API endpoint for printing a StockItemLabel object.""" """API endpoint for printing a StockItemLabel object."""
pass pass
@ -349,16 +338,6 @@ class StockLocationLabelDetail(StockLocationLabelMixin, RetrieveUpdateDestroyAPI
pass pass
class StockLocationLabelMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating StockLocationLabel metadata."""
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance for a Company"""
return MetadataSerializer(StockLocationLabel, *args, **kwargs)
queryset = StockLocationLabel.objects.all()
class StockLocationLabelPrint(StockLocationLabelMixin, LabelPrintMixin, RetrieveAPI): class StockLocationLabelPrint(StockLocationLabelMixin, LabelPrintMixin, RetrieveAPI):
"""API endpoint for printing a StockLocationLabel object.""" """API endpoint for printing a StockLocationLabel object."""
pass pass
@ -378,16 +357,6 @@ class PartLabelList(PartLabelMixin, LabelListView):
pass pass
class PartLabelMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating PartLabel metadata."""
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance for a Company"""
return MetadataSerializer(PartLabel, *args, **kwargs)
queryset = PartLabel.objects.all()
class PartLabelDetail(PartLabelMixin, RetrieveUpdateDestroyAPI): class PartLabelDetail(PartLabelMixin, RetrieveUpdateDestroyAPI):
"""API endpoint for a single PartLabel object.""" """API endpoint for a single PartLabel object."""
pass pass
@ -405,7 +374,7 @@ label_api_urls = [
# Detail views # Detail views
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
re_path(r'print/?', StockItemLabelPrint.as_view(), name='api-stockitem-label-print'), re_path(r'print/?', StockItemLabelPrint.as_view(), name='api-stockitem-label-print'),
re_path(r'metadata/', StockItemLabelMetadata.as_view(), name='api-stockitem-label-metadata'), re_path(r'metadata/', MetadataView.as_view(), {'model': StockItemLabel}, name='api-stockitem-label-metadata'),
re_path(r'^.*$', StockItemLabelDetail.as_view(), name='api-stockitem-label-detail'), re_path(r'^.*$', StockItemLabelDetail.as_view(), name='api-stockitem-label-detail'),
])), ])),
@ -418,7 +387,7 @@ label_api_urls = [
# Detail views # Detail views
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
re_path(r'print/?', StockLocationLabelPrint.as_view(), name='api-stocklocation-label-print'), re_path(r'print/?', StockLocationLabelPrint.as_view(), name='api-stocklocation-label-print'),
re_path(r'metadata/', StockLocationLabelMetadata.as_view(), name='api-stocklocation-label-metadata'), re_path(r'metadata/', MetadataView.as_view(), {'model': StockLocationLabel}, name='api-stocklocation-label-metadata'),
re_path(r'^.*$', StockLocationLabelDetail.as_view(), name='api-stocklocation-label-detail'), re_path(r'^.*$', StockLocationLabelDetail.as_view(), name='api-stocklocation-label-detail'),
])), ])),
@ -431,7 +400,7 @@ label_api_urls = [
# Detail views # Detail views
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
re_path(r'^print/', PartLabelPrint.as_view(), name='api-part-label-print'), re_path(r'^print/', PartLabelPrint.as_view(), name='api-part-label-print'),
re_path(r'^metadata/', PartLabelMetadata.as_view(), name='api-part-label-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': PartLabel}, name='api-part-label-metadata'),
re_path(r'^.*$', PartLabelDetail.as_view(), name='api-part-label-detail'), re_path(r'^.*$', PartLabelDetail.as_view(), name='api-part-label-detail'),
])), ])),

View File

@ -20,11 +20,11 @@ from common.models import InvenTreeSetting
from common.settings import settings from common.settings import settings
from company.models import SupplierPart from company.models import SupplierPart
from InvenTree.api import (APIDownloadMixin, AttachmentMixin, from InvenTree.api import (APIDownloadMixin, AttachmentMixin,
ListCreateDestroyAPIView, StatusView) ListCreateDestroyAPIView, MetadataView, StatusView)
from InvenTree.filters import InvenTreeOrderingFilter from InvenTree.filters import InvenTreeOrderingFilter
from InvenTree.helpers import DownloadFile, str2bool from InvenTree.helpers import DownloadFile, str2bool
from InvenTree.mixins import (CreateAPI, ListAPI, ListCreateAPI, from InvenTree.mixins import (CreateAPI, ListAPI, ListCreateAPI,
RetrieveUpdateAPI, RetrieveUpdateDestroyAPI) RetrieveUpdateDestroyAPI)
from InvenTree.status_codes import (PurchaseOrderStatus, ReturnOrderLineStatus, from InvenTree.status_codes import (PurchaseOrderStatus, ReturnOrderLineStatus,
ReturnOrderStatus, SalesOrderStatus) ReturnOrderStatus, SalesOrderStatus)
from order.admin import (PurchaseOrderExtraLineResource, from order.admin import (PurchaseOrderExtraLineResource,
@ -32,7 +32,6 @@ from order.admin import (PurchaseOrderExtraLineResource,
ReturnOrderResource, SalesOrderExtraLineResource, ReturnOrderResource, SalesOrderExtraLineResource,
SalesOrderLineItemResource, SalesOrderResource) SalesOrderLineItemResource, SalesOrderResource)
from part.models import Part from part.models import Part
from plugin.serializers import MetadataSerializer
from users.models import Owner from users.models import Owner
@ -385,16 +384,6 @@ class PurchaseOrderIssue(PurchaseOrderContextMixin, CreateAPI):
serializer_class = serializers.PurchaseOrderIssueSerializer serializer_class = serializers.PurchaseOrderIssueSerializer
class PurchaseOrderMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating PurchaseOrder metadata."""
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance for a PurchaseOrder"""
return MetadataSerializer(models.PurchaseOrder, *args, **kwargs)
queryset = models.PurchaseOrder.objects.all()
class PurchaseOrderReceive(PurchaseOrderContextMixin, CreateAPI): class PurchaseOrderReceive(PurchaseOrderContextMixin, CreateAPI):
"""API endpoint to receive stock items against a PurchaseOrder. """API endpoint to receive stock items against a PurchaseOrder.
@ -557,16 +546,6 @@ class PurchaseOrderLineItemDetail(PurchaseOrderLineItemMixin, RetrieveUpdateDest
pass pass
class PurchaseOrderLineItemMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating PurchaseOrderLineItem metadata."""
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance for a Company"""
return MetadataSerializer(models.PurchaseOrderLineItem, *args, **kwargs)
queryset = models.PurchaseOrderLineItem.objects.all()
class PurchaseOrderExtraLineList(GeneralExtraLineList, ListCreateAPI): class PurchaseOrderExtraLineList(GeneralExtraLineList, ListCreateAPI):
"""API endpoint for accessing a list of PurchaseOrderExtraLine objects.""" """API endpoint for accessing a list of PurchaseOrderExtraLine objects."""
@ -590,16 +569,6 @@ class PurchaseOrderExtraLineDetail(RetrieveUpdateDestroyAPI):
serializer_class = serializers.PurchaseOrderExtraLineSerializer serializer_class = serializers.PurchaseOrderExtraLineSerializer
class PurchaseOrderExtraLineItemMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating PurchaseOrderExtraLineItem metadata."""
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance"""
return MetadataSerializer(models.PurchaseOrderExtraLine, *args, **kwargs)
queryset = models.PurchaseOrderExtraLine.objects.all()
class SalesOrderAttachmentList(AttachmentMixin, ListCreateDestroyAPIView): class SalesOrderAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
"""API endpoint for listing (and creating) a SalesOrderAttachment (file upload)""" """API endpoint for listing (and creating) a SalesOrderAttachment (file upload)"""
@ -873,16 +842,6 @@ class SalesOrderLineItemDetail(SalesOrderLineItemMixin, RetrieveUpdateDestroyAPI
pass pass
class SalesOrderLineItemMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating SalesOrderLineItem metadata."""
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance"""
return MetadataSerializer(models.SalesOrderLineItem, *args, **kwargs)
queryset = models.SalesOrderLineItem.objects.all()
class SalesOrderExtraLineList(GeneralExtraLineList, ListCreateAPI): class SalesOrderExtraLineList(GeneralExtraLineList, ListCreateAPI):
"""API endpoint for accessing a list of SalesOrderExtraLine objects.""" """API endpoint for accessing a list of SalesOrderExtraLine objects."""
@ -906,16 +865,6 @@ class SalesOrderExtraLineDetail(RetrieveUpdateDestroyAPI):
serializer_class = serializers.SalesOrderExtraLineSerializer serializer_class = serializers.SalesOrderExtraLineSerializer
class SalesOrderExtraLineItemMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating SalesOrderExtraLineItem metadata."""
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance"""
return MetadataSerializer(models.SalesOrderExtraLine, *args, **kwargs)
queryset = models.SalesOrderExtraLine.objects.all()
class SalesOrderContextMixin: class SalesOrderContextMixin:
"""Mixin to add sales order object as serializer context variable.""" """Mixin to add sales order object as serializer context variable."""
@ -951,16 +900,6 @@ class SalesOrderComplete(SalesOrderContextMixin, CreateAPI):
serializer_class = serializers.SalesOrderCompleteSerializer serializer_class = serializers.SalesOrderCompleteSerializer
class SalesOrderMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating SalesOrder metadata."""
def get_serializer(self, *args, **kwargs):
"""Return a metadata serializer for the SalesOrder model"""
return MetadataSerializer(models.SalesOrder, *args, **kwargs)
queryset = models.SalesOrder.objects.all()
class SalesOrderAllocateSerials(SalesOrderContextMixin, CreateAPI): class SalesOrderAllocateSerials(SalesOrderContextMixin, CreateAPI):
"""API endpoint to allocation stock items against a SalesOrder, by specifying serial numbers.""" """API endpoint to allocation stock items against a SalesOrder, by specifying serial numbers."""
@ -1122,16 +1061,6 @@ class SalesOrderShipmentComplete(CreateAPI):
return ctx return ctx
class SalesOrderShipmentMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating SalesOrderShipment metadata."""
def get_serializer(self, *args, **kwargs):
"""Return MetadataSerializer instance"""
return MetadataSerializer(models.SalesOrderShipment, *args, **kwargs)
queryset = models.SalesOrderShipment.objects.all()
class PurchaseOrderAttachmentList(AttachmentMixin, ListCreateDestroyAPIView): class PurchaseOrderAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
"""API endpoint for listing (and creating) a PurchaseOrderAttachment (file upload)""" """API endpoint for listing (and creating) a PurchaseOrderAttachment (file upload)"""
@ -1604,7 +1533,7 @@ order_api_urls = [
re_path(r'^cancel/', PurchaseOrderCancel.as_view(), name='api-po-cancel'), re_path(r'^cancel/', PurchaseOrderCancel.as_view(), name='api-po-cancel'),
re_path(r'^complete/', PurchaseOrderComplete.as_view(), name='api-po-complete'), re_path(r'^complete/', PurchaseOrderComplete.as_view(), name='api-po-complete'),
re_path(r'^issue/', PurchaseOrderIssue.as_view(), name='api-po-issue'), re_path(r'^issue/', PurchaseOrderIssue.as_view(), name='api-po-issue'),
re_path(r'^metadata/', PurchaseOrderMetadata.as_view(), name='api-po-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': models.PurchaseOrder}, name='api-po-metadata'),
re_path(r'^receive/', PurchaseOrderReceive.as_view(), name='api-po-receive'), re_path(r'^receive/', PurchaseOrderReceive.as_view(), name='api-po-receive'),
# PurchaseOrder detail API endpoint # PurchaseOrder detail API endpoint
@ -1621,7 +1550,7 @@ order_api_urls = [
# API endpoints for purchase order line items # API endpoints for purchase order line items
re_path(r'^po-line/', include([ re_path(r'^po-line/', include([
path('<int:pk>/', include([ path('<int:pk>/', include([
re_path(r'^metadata/', PurchaseOrderLineItemMetadata.as_view(), name='api-po-line-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': models.PurchaseOrderLineItem}, name='api-po-line-metadata'),
re_path(r'^.*$', PurchaseOrderLineItemDetail.as_view(), name='api-po-line-detail'), re_path(r'^.*$', PurchaseOrderLineItemDetail.as_view(), name='api-po-line-detail'),
])), ])),
re_path(r'^.*$', PurchaseOrderLineItemList.as_view(), name='api-po-line-list'), re_path(r'^.*$', PurchaseOrderLineItemList.as_view(), name='api-po-line-list'),
@ -1630,7 +1559,7 @@ order_api_urls = [
# API endpoints for purchase order extra line # API endpoints for purchase order extra line
re_path(r'^po-extra-line/', include([ re_path(r'^po-extra-line/', include([
path('<int:pk>/', include([ path('<int:pk>/', include([
re_path(r'^metadata/', PurchaseOrderExtraLineItemMetadata.as_view(), name='api-po-extra-line-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': models.PurchaseOrderExtraLine}, name='api-po-extra-line-metadata'),
re_path(r'^.*$', PurchaseOrderExtraLineDetail.as_view(), name='api-po-extra-line-detail'), re_path(r'^.*$', PurchaseOrderExtraLineDetail.as_view(), name='api-po-extra-line-detail'),
])), ])),
path('', PurchaseOrderExtraLineList.as_view(), name='api-po-extra-line-list'), path('', PurchaseOrderExtraLineList.as_view(), name='api-po-extra-line-list'),
@ -1646,7 +1575,7 @@ order_api_urls = [
re_path(r'^shipment/', include([ re_path(r'^shipment/', include([
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
path('ship/', SalesOrderShipmentComplete.as_view(), name='api-so-shipment-ship'), path('ship/', SalesOrderShipmentComplete.as_view(), name='api-so-shipment-ship'),
re_path(r'^metadata/', SalesOrderShipmentMetadata.as_view(), name='api-so-shipment-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': models.SalesOrderShipment}, name='api-so-shipment-metadata'),
re_path(r'^.*$', SalesOrderShipmentDetail.as_view(), name='api-so-shipment-detail'), re_path(r'^.*$', SalesOrderShipmentDetail.as_view(), name='api-so-shipment-detail'),
])), ])),
re_path(r'^.*$', SalesOrderShipmentList.as_view(), name='api-so-shipment-list'), re_path(r'^.*$', SalesOrderShipmentList.as_view(), name='api-so-shipment-list'),
@ -1659,7 +1588,7 @@ order_api_urls = [
re_path(r'^cancel/', SalesOrderCancel.as_view(), name='api-so-cancel'), re_path(r'^cancel/', SalesOrderCancel.as_view(), name='api-so-cancel'),
re_path(r'^issue/', SalesOrderIssue.as_view(), name='api-so-issue'), re_path(r'^issue/', SalesOrderIssue.as_view(), name='api-so-issue'),
re_path(r'^complete/', SalesOrderComplete.as_view(), name='api-so-complete'), re_path(r'^complete/', SalesOrderComplete.as_view(), name='api-so-complete'),
re_path(r'^metadata/', SalesOrderMetadata.as_view(), name='api-so-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': models.SalesOrder}, name='api-so-metadata'),
# SalesOrder detail endpoint # SalesOrder detail endpoint
re_path(r'^.*$', SalesOrderDetail.as_view(), name='api-so-detail'), re_path(r'^.*$', SalesOrderDetail.as_view(), name='api-so-detail'),
@ -1675,7 +1604,7 @@ order_api_urls = [
# API endpoints for sales order line items # API endpoints for sales order line items
re_path(r'^so-line/', include([ re_path(r'^so-line/', include([
path('<int:pk>/', include([ path('<int:pk>/', include([
re_path(r'^metadata/', SalesOrderLineItemMetadata.as_view(), name='api-so-line-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': models.SalesOrderLineItem}, name='api-so-line-metadata'),
re_path(r'^.*$', SalesOrderLineItemDetail.as_view(), name='api-so-line-detail'), re_path(r'^.*$', SalesOrderLineItemDetail.as_view(), name='api-so-line-detail'),
])), ])),
path('', SalesOrderLineItemList.as_view(), name='api-so-line-list'), path('', SalesOrderLineItemList.as_view(), name='api-so-line-list'),
@ -1684,7 +1613,7 @@ order_api_urls = [
# API endpoints for sales order extra line # API endpoints for sales order extra line
re_path(r'^so-extra-line/', include([ re_path(r'^so-extra-line/', include([
path('<int:pk>/', include([ path('<int:pk>/', include([
re_path(r'^metadata/', SalesOrderExtraLineItemMetadata.as_view(), name='api-so-extra-line-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': models.SalesOrderExtraLine}, name='api-so-extra-line-metadata'),
re_path(r'^.*$', SalesOrderExtraLineDetail.as_view(), name='api-so-extra-line-detail'), re_path(r'^.*$', SalesOrderExtraLineDetail.as_view(), name='api-so-extra-line-detail'),
])), ])),
path('', SalesOrderExtraLineList.as_view(), name='api-so-extra-line-list'), path('', SalesOrderExtraLineList.as_view(), name='api-so-extra-line-list'),

View File

@ -16,7 +16,7 @@ from rest_framework.response import Response
import order.models import order.models
from build.models import Build, BuildItem from build.models import Build, BuildItem
from InvenTree.api import (APIDownloadMixin, AttachmentMixin, from InvenTree.api import (APIDownloadMixin, AttachmentMixin,
ListCreateDestroyAPIView) ListCreateDestroyAPIView, MetadataView)
from InvenTree.filters import InvenTreeOrderingFilter from InvenTree.filters import InvenTreeOrderingFilter
from InvenTree.helpers import (DownloadFile, increment_serial_number, isNull, from InvenTree.helpers import (DownloadFile, increment_serial_number, isNull,
str2bool, str2int) str2bool, str2int)
@ -28,7 +28,6 @@ from InvenTree.permissions import RolePermission
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus, from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus,
SalesOrderStatus) SalesOrderStatus)
from part.admin import PartCategoryResource, PartResource from part.admin import PartCategoryResource, PartResource
from plugin.serializers import MetadataSerializer
from . import serializers as part_serializers from . import serializers as part_serializers
from . import views from . import views
@ -230,16 +229,6 @@ class CategoryTree(ListAPI):
ordering = ['level', 'name'] ordering = ['level', 'name']
class CategoryMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating PartCategory metadata."""
def get_serializer(self, *args, **kwargs):
"""Return a MetadataSerializer pointing to the referenced PartCategory instance"""
return MetadataSerializer(PartCategory, *args, **kwargs)
queryset = PartCategory.objects.all()
class CategoryParameterList(ListCreateAPI): class CategoryParameterList(ListCreateAPI):
"""API endpoint for accessing a list of PartCategoryParameterTemplate objects. """API endpoint for accessing a list of PartCategoryParameterTemplate objects.
@ -698,16 +687,6 @@ class PartRequirements(RetrieveAPI):
return Response(data) return Response(data)
class PartMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating Part metadata."""
def get_serializer(self, *args, **kwargs):
"""Returns a MetadataSerializer instance pointing to the referenced Part"""
return MetadataSerializer(Part, *args, **kwargs)
queryset = Part.objects.all()
class PartPricingDetail(RetrieveUpdateAPI): class PartPricingDetail(RetrieveUpdateAPI):
"""API endpoint for viewing part pricing data""" """API endpoint for viewing part pricing data"""
@ -1415,16 +1394,6 @@ class PartParameterTemplateDetail(RetrieveUpdateDestroyAPI):
serializer_class = part_serializers.PartParameterTemplateSerializer serializer_class = part_serializers.PartParameterTemplateSerializer
class PartParameterTemplateMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating PartParameterTemplate metadata."""
def get_serializer(self, *args, **kwargs):
"""Return a MetadataSerializer pointing to the referenced PartParameterTemplate instance"""
return MetadataSerializer(PartParameterTemplate, *args, **kwargs)
queryset = PartParameterTemplate.objects.all()
class PartParameterList(ListCreateAPI): class PartParameterList(ListCreateAPI):
"""API endpoint for accessing a list of PartParameter objects. """API endpoint for accessing a list of PartParameter objects.
@ -1886,16 +1855,6 @@ class BomItemSubstituteDetail(RetrieveUpdateDestroyAPI):
serializer_class = part_serializers.BomItemSubstituteSerializer serializer_class = part_serializers.BomItemSubstituteSerializer
class BomItemMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating PartBOM metadata."""
def get_serializer(self, *args, **kwargs):
"""Return a MetadataSerializer pointing to the referenced PartCategory instance"""
return MetadataSerializer(BomItem, *args, **kwargs)
queryset = BomItem.objects.all()
part_api_urls = [ part_api_urls = [
# Base URL for PartCategory API endpoints # Base URL for PartCategory API endpoints
@ -1910,7 +1869,7 @@ part_api_urls = [
# Category detail endpoints # Category detail endpoints
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
re_path(r'^metadata/', CategoryMetadata.as_view(), name='api-part-category-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': PartCategory}, name='api-part-category-metadata'),
# PartCategory detail endpoint # PartCategory detail endpoint
re_path(r'^.*$', CategoryDetail.as_view(), name='api-part-category-detail'), re_path(r'^.*$', CategoryDetail.as_view(), name='api-part-category-detail'),
@ -1953,7 +1912,7 @@ part_api_urls = [
re_path(r'^parameter/', include([ re_path(r'^parameter/', include([
path('template/', include([ path('template/', include([
re_path(r'^(?P<pk>\d+)/', include([ re_path(r'^(?P<pk>\d+)/', include([
re_path(r'^metadata/?', PartParameterTemplateMetadata.as_view(), name='api-part-parameter-template-metadata'), re_path(r'^metadata/?', MetadataView.as_view(), {'model': PartParameter}, name='api-part-parameter-template-metadata'),
re_path(r'^.*$', PartParameterTemplateDetail.as_view(), name='api-part-parameter-template-detail'), re_path(r'^.*$', PartParameterTemplateDetail.as_view(), name='api-part-parameter-template-detail'),
])), ])),
re_path(r'^.*$', PartParameterTemplateList.as_view(), name='api-part-parameter-template-list'), re_path(r'^.*$', PartParameterTemplateList.as_view(), name='api-part-parameter-template-list'),
@ -2000,7 +1959,7 @@ part_api_urls = [
re_path(r'^bom-validate/', PartValidateBOM.as_view(), name='api-part-bom-validate'), re_path(r'^bom-validate/', PartValidateBOM.as_view(), name='api-part-bom-validate'),
# Part metadata # Part metadata
re_path(r'^metadata/', PartMetadata.as_view(), name='api-part-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': Part}, name='api-part-metadata'),
# Part pricing # Part pricing
re_path(r'^pricing/', PartPricingDetail.as_view(), name='api-part-pricing'), re_path(r'^pricing/', PartPricingDetail.as_view(), name='api-part-pricing'),
@ -2032,7 +1991,7 @@ bom_api_urls = [
# BOM Item Detail # BOM Item Detail
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
re_path(r'^validate/?', BomItemValidate.as_view(), name='api-bom-item-validate'), re_path(r'^validate/?', BomItemValidate.as_view(), name='api-bom-item-validate'),
re_path(r'^metadata/?', BomItemMetadata.as_view(), name='api-bom-item-metadata'), re_path(r'^metadata/?', MetadataView.as_view(), {'model': BomItem}, name='api-bom-item-metadata'),
re_path(r'^.*$', BomDetail.as_view(), name='api-bom-item-detail'), re_path(r'^.*$', BomDetail.as_view(), name='api-bom-item-detail'),
])), ])),

View File

@ -18,9 +18,8 @@ import common.models
import InvenTree.helpers import InvenTree.helpers
import order.models import order.models
import part.models import part.models
from InvenTree.mixins import (ListAPI, RetrieveAPI, RetrieveUpdateAPI, from InvenTree.api import MetadataView
RetrieveUpdateDestroyAPI) from InvenTree.mixins import ListAPI, RetrieveAPI, RetrieveUpdateDestroyAPI
from plugin.serializers import MetadataSerializer
from stock.models import StockItem, StockItemAttachment from stock.models import StockItem, StockItemAttachment
from .models import (BillOfMaterialsReport, BuildReport, PurchaseOrderReport, from .models import (BillOfMaterialsReport, BuildReport, PurchaseOrderReport,
@ -449,31 +448,6 @@ class ReturnOrderReportPrint(ReturnOrderReportMixin, ReportPrintMixin, RetrieveA
pass pass
class ReportMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating Report metadata."""
MODEL_REF = 'reportmodel'
def _get_model(self, *args, **kwargs):
"""Return model depending on which report type is requested in get_view constructor."""
reportmodel = self.kwargs.get(self.MODEL_REF, PurchaseOrderReport)
if reportmodel not in [PurchaseOrderReport, SalesOrderReport, BuildReport, BillOfMaterialsReport, TestReport]:
raise ValidationError("Invalid report model")
return reportmodel
# Return corresponding Serializer
def get_serializer(self, *args, **kwargs):
"""Return correct MetadataSerializer instance depending on which model is requested"""
# Get type of report, make sure its one of the allowed values
UseModel = self._get_model(*args, **kwargs)
return MetadataSerializer(UseModel, *args, **kwargs)
def get_queryset(self, *args, **kwargs):
"""Return correct queryset depending on which model is requested"""
UseModel = self._get_model(*args, **kwargs)
return UseModel.objects.all()
report_api_urls = [ report_api_urls = [
# Purchase order reports # Purchase order reports
@ -481,7 +455,7 @@ report_api_urls = [
# Detail views # Detail views
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
re_path(r'print/', PurchaseOrderReportPrint.as_view(), name='api-po-report-print'), re_path(r'print/', PurchaseOrderReportPrint.as_view(), name='api-po-report-print'),
re_path(r'metadata/', ReportMetadata.as_view(), {ReportMetadata.MODEL_REF: PurchaseOrderReport}, name='api-po-report-metadata'), re_path(r'metadata/', MetadataView.as_view(), {'model': PurchaseOrderReport}, name='api-po-report-metadata'),
path('', PurchaseOrderReportDetail.as_view(), name='api-po-report-detail'), path('', PurchaseOrderReportDetail.as_view(), name='api-po-report-detail'),
])), ])),
@ -494,7 +468,7 @@ report_api_urls = [
# Detail views # Detail views
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
re_path(r'print/', SalesOrderReportPrint.as_view(), name='api-so-report-print'), re_path(r'print/', SalesOrderReportPrint.as_view(), name='api-so-report-print'),
re_path(r'metadata/', ReportMetadata.as_view(), {ReportMetadata.MODEL_REF: SalesOrderReport}, name='api-so-report-metadata'), re_path(r'metadata/', MetadataView.as_view(), {'model': SalesOrderReport}, name='api-so-report-metadata'),
path('', SalesOrderReportDetail.as_view(), name='api-so-report-detail'), path('', SalesOrderReportDetail.as_view(), name='api-so-report-detail'),
])), ])),
@ -505,6 +479,7 @@ report_api_urls = [
re_path(r'ro/', include([ re_path(r'ro/', include([
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
path(r'print/', ReturnOrderReportPrint.as_view(), name='api-return-order-report-print'), path(r'print/', ReturnOrderReportPrint.as_view(), name='api-return-order-report-print'),
re_path(r'metadata/', MetadataView.as_view(), {'model': ReturnOrderReport}, name='api-so-report-metadata'),
path('', ReturnOrderReportDetail.as_view(), name='api-return-order-report-detail'), path('', ReturnOrderReportDetail.as_view(), name='api-return-order-report-detail'),
])), ])),
path('', ReturnOrderReportList.as_view(), name='api-return-order-report-list'), path('', ReturnOrderReportList.as_view(), name='api-return-order-report-list'),
@ -515,7 +490,7 @@ report_api_urls = [
# Detail views # Detail views
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
re_path(r'print/?', BuildReportPrint.as_view(), name='api-build-report-print'), re_path(r'print/?', BuildReportPrint.as_view(), name='api-build-report-print'),
re_path(r'metadata/', ReportMetadata.as_view(), {ReportMetadata.MODEL_REF: BuildReport}, name='api-build-report-metadata'), re_path(r'metadata/', MetadataView.as_view(), {'model': BuildReport}, name='api-build-report-metadata'),
re_path(r'^.$', BuildReportDetail.as_view(), name='api-build-report-detail'), re_path(r'^.$', BuildReportDetail.as_view(), name='api-build-report-detail'),
])), ])),
@ -529,7 +504,7 @@ report_api_urls = [
# Detail views # Detail views
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
re_path(r'print/?', BOMReportPrint.as_view(), name='api-bom-report-print'), re_path(r'print/?', BOMReportPrint.as_view(), name='api-bom-report-print'),
re_path(r'metadata/', ReportMetadata.as_view(), {ReportMetadata.MODEL_REF: BillOfMaterialsReport}, name='api-bom-report-metadata'), re_path(r'metadata/', MetadataView.as_view(), {'model': BillOfMaterialsReport}, name='api-bom-report-metadata'),
re_path(r'^.*$', BOMReportDetail.as_view(), name='api-bom-report-detail'), re_path(r'^.*$', BOMReportDetail.as_view(), name='api-bom-report-detail'),
])), ])),
@ -542,7 +517,7 @@ report_api_urls = [
# Detail views # Detail views
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
re_path(r'print/?', StockItemTestReportPrint.as_view(), name='api-stockitem-testreport-print'), re_path(r'print/?', StockItemTestReportPrint.as_view(), name='api-stockitem-testreport-print'),
re_path(r'metadata/', ReportMetadata.as_view(), {ReportMetadata.MODEL_REF: TestReport}, name='api-stockitem-testreport-metadata'), re_path(r'metadata/', MetadataView.as_view(), {'report': TestReport}, name='api-stockitem-testreport-metadata'),
re_path(r'^.*$', StockItemTestReportDetail.as_view(), name='api-stockitem-testreport-detail'), re_path(r'^.*$', StockItemTestReportDetail.as_view(), name='api-stockitem-testreport-detail'),
])), ])),

View File

@ -23,13 +23,13 @@ from build.models import Build
from company.models import Company, SupplierPart from company.models import Company, SupplierPart
from company.serializers import CompanySerializer, SupplierPartSerializer from company.serializers import CompanySerializer, SupplierPartSerializer
from InvenTree.api import (APIDownloadMixin, AttachmentMixin, from InvenTree.api import (APIDownloadMixin, AttachmentMixin,
ListCreateDestroyAPIView, StatusView) ListCreateDestroyAPIView, MetadataView, StatusView)
from InvenTree.filters import InvenTreeOrderingFilter from InvenTree.filters import InvenTreeOrderingFilter
from InvenTree.helpers import (DownloadFile, extract_serial_numbers, isNull, from InvenTree.helpers import (DownloadFile, extract_serial_numbers, isNull,
str2bool, str2int) str2bool, str2int)
from InvenTree.mixins import (CreateAPI, CustomRetrieveUpdateDestroyAPI, from InvenTree.mixins import (CreateAPI, CustomRetrieveUpdateDestroyAPI,
ListAPI, ListCreateAPI, RetrieveAPI, ListAPI, ListCreateAPI, RetrieveAPI,
RetrieveUpdateAPI, RetrieveUpdateDestroyAPI) RetrieveUpdateDestroyAPI)
from InvenTree.status_codes import StockHistoryCode, StockStatus from InvenTree.status_codes import StockHistoryCode, StockStatus
from order.models import (PurchaseOrder, ReturnOrder, SalesOrder, from order.models import (PurchaseOrder, ReturnOrder, SalesOrder,
SalesOrderAllocation) SalesOrderAllocation)
@ -37,7 +37,6 @@ from order.serializers import (PurchaseOrderSerializer, ReturnOrderSerializer,
SalesOrderSerializer) SalesOrderSerializer)
from part.models import BomItem, Part, PartCategory from part.models import BomItem, Part, PartCategory
from part.serializers import PartBriefSerializer from part.serializers import PartBriefSerializer
from plugin.serializers import MetadataSerializer
from stock.admin import LocationResource, StockItemResource from stock.admin import LocationResource, StockItemResource
from stock.models import (StockItem, StockItemAttachment, StockItemTestResult, from stock.models import (StockItem, StockItemAttachment, StockItemTestResult,
StockItemTracking, StockLocation) StockItemTracking, StockLocation)
@ -83,16 +82,6 @@ class StockDetail(RetrieveUpdateDestroyAPI):
return self.serializer_class(*args, **kwargs) return self.serializer_class(*args, **kwargs)
class StockMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating StockItem metadata."""
def get_serializer(self, *args, **kwargs):
"""Return serializer."""
return MetadataSerializer(StockItem, *args, **kwargs)
queryset = StockItem.objects.all()
class StockItemContextMixin: class StockItemContextMixin:
"""Mixin class for adding StockItem object to serializer context.""" """Mixin class for adding StockItem object to serializer context."""
@ -1344,16 +1333,6 @@ class StockTrackingList(ListAPI):
] ]
class LocationMetadata(RetrieveUpdateAPI):
"""API endpoint for viewing / updating StockLocation metadata."""
def get_serializer(self, *args, **kwargs):
"""Return serializer."""
return MetadataSerializer(StockLocation, *args, **kwargs)
queryset = StockLocation.objects.all()
class LocationDetail(CustomRetrieveUpdateDestroyAPI): class LocationDetail(CustomRetrieveUpdateDestroyAPI):
"""API endpoint for detail view of StockLocation object. """API endpoint for detail view of StockLocation object.
@ -1391,7 +1370,7 @@ stock_api_urls = [
# Stock location detail endpoints # Stock location detail endpoints
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
re_path(r'^metadata/', LocationMetadata.as_view(), name='api-location-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': StockLocation}, name='api-location-metadata'),
re_path(r'^.*$', LocationDetail.as_view(), name='api-location-detail'), re_path(r'^.*$', LocationDetail.as_view(), name='api-location-detail'),
])), ])),
@ -1433,7 +1412,7 @@ stock_api_urls = [
path(r'<int:pk>/', include([ path(r'<int:pk>/', include([
re_path(r'^convert/', StockItemConvert.as_view(), name='api-stock-item-convert'), re_path(r'^convert/', StockItemConvert.as_view(), name='api-stock-item-convert'),
re_path(r'^install/', StockItemInstall.as_view(), name='api-stock-item-install'), re_path(r'^install/', StockItemInstall.as_view(), name='api-stock-item-install'),
re_path(r'^metadata/', StockMetadata.as_view(), name='api-stock-item-metadata'), re_path(r'^metadata/', MetadataView.as_view(), {'model': StockItem}, name='api-stock-item-metadata'),
re_path(r'^return/', StockItemReturn.as_view(), name='api-stock-item-return'), re_path(r'^return/', StockItemReturn.as_view(), name='api-stock-item-return'),
re_path(r'^serialize/', StockItemSerialize.as_view(), name='api-stock-item-serialize'), re_path(r'^serialize/', StockItemSerialize.as_view(), name='api-stock-item-serialize'),
re_path(r'^uninstall/', StockItemUninstall.as_view(), name='api-stock-item-uninstall'), re_path(r'^uninstall/', StockItemUninstall.as_view(), name='api-stock-item-uninstall'),