mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-15 19:45:46 +00:00
Adds API endpoints for ReturnOrder
- Add list endpoint - Add detail endpoint - Adds required serializer models
This commit is contained in:
@ -277,6 +277,19 @@ class SalesOrderAllocationAdmin(ImportExportModelAdmin):
|
|||||||
autocomplete_fields = ('line', 'shipment', 'item',)
|
autocomplete_fields = ('line', 'shipment', 'item',)
|
||||||
|
|
||||||
|
|
||||||
|
class ReturnOrderResource(InvenTreeResource):
|
||||||
|
"""Class for managing import / export of ReturnOrder data"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Metaclass options"""
|
||||||
|
model = models.ReturnOrder
|
||||||
|
skip_unchanged = True
|
||||||
|
clean_model_instances = True
|
||||||
|
exclude = [
|
||||||
|
'metadata',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class ReturnOrderAdmin(ImportExportModelAdmin):
|
class ReturnOrderAdmin(ImportExportModelAdmin):
|
||||||
"""Admin class for the ReturnOrder model"""
|
"""Admin class for the ReturnOrder model"""
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ from InvenTree.mixins import (CreateAPI, ListAPI, ListCreateAPI,
|
|||||||
from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus
|
from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus
|
||||||
from order.admin import (PurchaseOrderExtraLineResource,
|
from order.admin import (PurchaseOrderExtraLineResource,
|
||||||
PurchaseOrderLineItemResource, PurchaseOrderResource,
|
PurchaseOrderLineItemResource, PurchaseOrderResource,
|
||||||
SalesOrderExtraLineResource,
|
ReturnOrderResource, SalesOrderExtraLineResource,
|
||||||
SalesOrderLineItemResource, SalesOrderResource)
|
SalesOrderLineItemResource, SalesOrderResource)
|
||||||
from part.models import Part
|
from part.models import Part
|
||||||
from plugin.serializers import MetadataSerializer
|
from plugin.serializers import MetadataSerializer
|
||||||
@ -1213,6 +1213,106 @@ class PurchaseOrderAttachmentDetail(AttachmentMixin, RetrieveUpdateDestroyAPI):
|
|||||||
serializer_class = serializers.PurchaseOrderAttachmentSerializer
|
serializer_class = serializers.PurchaseOrderAttachmentSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class ReturnOrderFilter(OrderFilter):
|
||||||
|
"""Custom API filters for the ReturnOrderList endpoint"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Metaclass options"""
|
||||||
|
|
||||||
|
model = models.ReturnOrder
|
||||||
|
fields = [
|
||||||
|
'customer',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ReturnOrderList(APIDownloadMixin, ListCreateAPI):
|
||||||
|
"""API endpoint for accessing a list of ReturnOrder objects"""
|
||||||
|
|
||||||
|
queryset = models.ReturnOrder.objects.all()
|
||||||
|
serializer_class = serializers.ReturnOrderSerializer
|
||||||
|
filterset_class = ReturnOrderFilter
|
||||||
|
|
||||||
|
def get_serializer(self, *args, **kwargs):
|
||||||
|
"""Return serializer instance for this endpoint"""
|
||||||
|
try:
|
||||||
|
kwargs['customer_detail'] = str2bool(
|
||||||
|
self.request.query_params.get('customer_detail', False)
|
||||||
|
)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Ensure the context is passed through to the serializer
|
||||||
|
kwargs['context'] = self.get_serializer_context()
|
||||||
|
|
||||||
|
return self.serializer_class(*args, **kwargs)
|
||||||
|
|
||||||
|
def download_queryset(self, queryset, export_format):
|
||||||
|
"""Download this queryset as a file"""
|
||||||
|
|
||||||
|
dataset = ReturnOrderResource().export(queryset=queryset)
|
||||||
|
filedata = dataset.export(export_format)
|
||||||
|
filename = f"InvenTree_ReturnOrders.{export_format}"
|
||||||
|
|
||||||
|
return DownloadFile(filedata, filename)
|
||||||
|
|
||||||
|
def filter_queryset(self, queryset):
|
||||||
|
"""Custom queryset filtering not supported by the ReturnOrderFilter class"""
|
||||||
|
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
filter_backends = [
|
||||||
|
rest_filters.DjangoFilterBackend,
|
||||||
|
filters.SearchFilter,
|
||||||
|
InvenTreeOrderingFilter,
|
||||||
|
]
|
||||||
|
|
||||||
|
ordering_field_aliases = {
|
||||||
|
'reference': ['reference_int', 'reference'],
|
||||||
|
}
|
||||||
|
|
||||||
|
filterset_fields = [
|
||||||
|
'customer',
|
||||||
|
]
|
||||||
|
|
||||||
|
ordering_fields = [
|
||||||
|
'creation_date',
|
||||||
|
'reference',
|
||||||
|
'customer__name',
|
||||||
|
'customer_reference',
|
||||||
|
'status',
|
||||||
|
'target_date',
|
||||||
|
]
|
||||||
|
|
||||||
|
search_fields = [
|
||||||
|
'customer__name',
|
||||||
|
'reference',
|
||||||
|
'description',
|
||||||
|
'customer_reference',
|
||||||
|
]
|
||||||
|
|
||||||
|
ordering = '-reference'
|
||||||
|
|
||||||
|
|
||||||
|
class ReturnOrderDetail(RetrieveUpdateDestroyAPI):
|
||||||
|
"""API endpoint for detail view of a single ReturnOrder object"""
|
||||||
|
|
||||||
|
queryset = models.ReturnOrder.objects.all()
|
||||||
|
serializer_class = serializers.ReturnOrderSerializer
|
||||||
|
|
||||||
|
def get_serializer(self, *args, **kwargs):
|
||||||
|
"""Return the serializer instance for this endpoint"""
|
||||||
|
try:
|
||||||
|
kwargs['customer_detail'] = str2bool(
|
||||||
|
self.request.query_params.get('customer_detail', False)
|
||||||
|
)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
kwargs['context'] = self.get_serializer_context()
|
||||||
|
|
||||||
|
return self.serializer_class(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class OrderCalendarExport(ICalFeed):
|
class OrderCalendarExport(ICalFeed):
|
||||||
"""Calendar export for Purchase/Sales Orders
|
"""Calendar export for Purchase/Sales Orders
|
||||||
|
|
||||||
@ -1450,6 +1550,16 @@ order_api_urls = [
|
|||||||
re_path(r'^.*$', SalesOrderAllocationList.as_view(), name='api-so-allocation-list'),
|
re_path(r'^.*$', SalesOrderAllocationList.as_view(), name='api-so-allocation-list'),
|
||||||
])),
|
])),
|
||||||
|
|
||||||
|
# API endpoints for return orders
|
||||||
|
re_path(r'^return/', include([
|
||||||
|
|
||||||
|
# Return Order detail
|
||||||
|
path('<int:pk>/', ReturnOrderDetail.as_view(), name='api-return-order-detail'),
|
||||||
|
|
||||||
|
# Return Order list
|
||||||
|
re_path(r'^.*$', ReturnOrderList.as_view(), name='api-return-order-list'),
|
||||||
|
])),
|
||||||
|
|
||||||
# API endpoint for subscribing to ICS calendar of purchase/sales orders
|
# API endpoint for subscribing to ICS calendar of purchase/sales orders
|
||||||
re_path(r'^calendar/(?P<ordertype>purchase-order|sales-order)/calendar.ics', OrderCalendarExport(), name='api-po-so-calendar'),
|
re_path(r'^calendar/(?P<ordertype>purchase-order|sales-order)/calendar.ics', OrderCalendarExport(), name='api-po-so-calendar'),
|
||||||
]
|
]
|
||||||
|
@ -46,9 +46,13 @@ from users import models as UserModels
|
|||||||
logger = logging.getLogger('inventree')
|
logger = logging.getLogger('inventree')
|
||||||
|
|
||||||
|
|
||||||
class TotalPriceMixin:
|
class TotalPriceMixin(models.Model):
|
||||||
"""Mixin which provides 'total_price' field for an order"""
|
"""Mixin which provides 'total_price' field for an order"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Meta for MetadataMixin."""
|
||||||
|
abstract = True
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""Update the total_price field when saved"""
|
"""Update the total_price field when saved"""
|
||||||
|
|
||||||
@ -1573,7 +1577,7 @@ class ReturnOrder(Order):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def get_api_url():
|
def get_api_url():
|
||||||
"""Return the API URL associated with the ReturnOrder model"""
|
"""Return the API URL associated with the ReturnOrder model"""
|
||||||
return reverse('api-return-list')
|
return reverse('api-return-order-list')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def api_defaults(cls, request):
|
def api_defaults(cls, request):
|
||||||
@ -1645,7 +1649,7 @@ class ReturnOrderAttachment(InvenTreeAttachment):
|
|||||||
def get_api_url():
|
def get_api_url():
|
||||||
"""Return the API URL associated with the ReturnOrderAttachment class"""
|
"""Return the API URL associated with the ReturnOrderAttachment class"""
|
||||||
|
|
||||||
return reverse('api-return-attachment-list')
|
return reverse('api-return-order-attachment-list')
|
||||||
|
|
||||||
def getSubdir(self):
|
def getSubdir(self):
|
||||||
"""Return the directory path where ReturnOrderAttachment files are located"""
|
"""Return the directory path where ReturnOrderAttachment files are located"""
|
||||||
|
@ -645,7 +645,7 @@ class PurchaseOrderAttachmentSerializer(InvenTreeAttachmentSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class SalesOrderSerializer(AbstractOrderSerializer, InvenTreeModelSerializer):
|
class SalesOrderSerializer(AbstractOrderSerializer, InvenTreeModelSerializer):
|
||||||
"""Serializers for the SalesOrder object."""
|
"""Serializer for the SalesOrder model class"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Metaclass options."""
|
"""Metaclass options."""
|
||||||
@ -1398,3 +1398,78 @@ class SalesOrderAttachmentSerializer(InvenTreeAttachmentSerializer):
|
|||||||
fields = InvenTreeAttachmentSerializer.attachment_fields([
|
fields = InvenTreeAttachmentSerializer.attachment_fields([
|
||||||
'order',
|
'order',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
class ReturnOrderSerializer(InvenTreeModelSerializer):
|
||||||
|
"""Serializer for the ReturnOrder model class"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Metaclass options"""
|
||||||
|
|
||||||
|
model = order.models.ReturnOrder
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
'pk',
|
||||||
|
'creation_date',
|
||||||
|
'customer',
|
||||||
|
'customer_detail',
|
||||||
|
'customer_reference',
|
||||||
|
'description',
|
||||||
|
'link',
|
||||||
|
'notes',
|
||||||
|
'reference',
|
||||||
|
'responsible',
|
||||||
|
'responsible_detail',
|
||||||
|
'status',
|
||||||
|
'status_text',
|
||||||
|
]
|
||||||
|
|
||||||
|
read_only_fields = [
|
||||||
|
'status',
|
||||||
|
'creation_date',
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""Initialization routine for the serializer"""
|
||||||
|
|
||||||
|
customer_detail = kwargs.pop('customer_detail', False)
|
||||||
|
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
if customer_detail is not True:
|
||||||
|
self.fields.pop('customer_detail')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def annotate_queryset(queryset):
|
||||||
|
"""Custom annotation for the serializer queryset"""
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
customer_detail = CompanyBriefSerializer(source='customer', many=False, read_only=True)
|
||||||
|
|
||||||
|
status_text = serializers.CharField(source='get_status_display', read_only=True)
|
||||||
|
|
||||||
|
responsible_detail = OwnerSerializer(source='responsible', read_only=True, many=False)
|
||||||
|
|
||||||
|
reference = serializers.CharField(required=True)
|
||||||
|
|
||||||
|
def validate_reference(self, reference):
|
||||||
|
"""Custom validation for the reference field"""
|
||||||
|
|
||||||
|
order.models.ReturnOrder.validate_reference_field(reference)
|
||||||
|
|
||||||
|
return reference
|
||||||
|
|
||||||
|
|
||||||
|
class ReturnOrderAttachmentSerializer(InvenTreeAttachmentSerializer):
|
||||||
|
"""Serializer for the ReturnOrderAttachment model"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Metaclass options"""
|
||||||
|
|
||||||
|
model = order.models.ReturnOrderAttachment
|
||||||
|
|
||||||
|
fields = InvenTreeAttachmentSerializer.attachment_fields([
|
||||||
|
'order',
|
||||||
|
])
|
||||||
|
Reference in New Issue
Block a user