Integrate Deutsche Post shipping API and models
Added Deutsche Post as a shipping carrier, including new models, admin, serializers, and API client integration. Updated Carrier and SiteConfiguration models to support Deutsche Post, including shipping price and API credentials. Added requirements for the Deutsche Post API client and dependencies.
This commit is contained in:
300
backend/thirdparty/deutschepost/views.py
vendored
Normal file
300
backend/thirdparty/deutschepost/views.py
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
from rest_framework import viewsets, mixins, status
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
|
||||
from drf_spectacular.utils import (
|
||||
extend_schema, extend_schema_view, OpenApiResponse,
|
||||
OpenApiParameter, OpenApiTypes
|
||||
)
|
||||
|
||||
from .models import DeutschePostOrder, DeutschePostBulkOrder
|
||||
from .serializers import (
|
||||
DeutschePostOrderSerializer,
|
||||
DeutschePostBulkOrderSerializer,
|
||||
DeutschePostTrackingSerializer,
|
||||
)
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
list=extend_schema(
|
||||
tags=["deutschepost"],
|
||||
summary="List Deutsche Post Orders",
|
||||
description="Returns a paginated list of Deutsche Post shipping orders. Orders are created internally through Carrier model. Admin only access.",
|
||||
responses=DeutschePostOrderSerializer(many=True),
|
||||
),
|
||||
retrieve=extend_schema(
|
||||
tags=["deutschepost"],
|
||||
summary="Get Deutsche Post Order Detail",
|
||||
description="Returns detailed information for a single Deutsche Post order including tracking data. Orders are managed through Carrier model.",
|
||||
responses=DeutschePostOrderSerializer,
|
||||
),
|
||||
)
|
||||
class DeutschePostOrderViewSet(
|
||||
mixins.ListModelMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
viewsets.GenericViewSet
|
||||
):
|
||||
queryset = DeutschePostOrder.objects.all().order_by("-created_at")
|
||||
serializer_class = DeutschePostOrderSerializer
|
||||
permission_classes = [IsAdminUser]
|
||||
|
||||
@extend_schema(
|
||||
tags=["deutschepost"],
|
||||
summary="Refresh Tracking Information",
|
||||
description="""
|
||||
Refresh tracking information from Deutsche Post API. This will:
|
||||
- Fetch latest order status from Deutsche Post
|
||||
- Update AWB number, barcode, and tracking URL
|
||||
- Update order state based on shipment status
|
||||
- Store raw tracking data in metadata
|
||||
|
||||
Note: Orders are created and managed through the Carrier model in commerce app.
|
||||
""",
|
||||
request=None,
|
||||
responses={
|
||||
200: DeutschePostTrackingSerializer,
|
||||
400: OpenApiResponse(description="Order not created remotely"),
|
||||
500: OpenApiResponse(description="Deutsche Post API error")
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=['post'])
|
||||
def refresh_tracking(self, request, pk=None):
|
||||
"""Refresh tracking information from Deutsche Post API."""
|
||||
order = self.get_object()
|
||||
|
||||
try:
|
||||
order.refresh_tracking()
|
||||
|
||||
# Return tracking information
|
||||
tracking_data = {
|
||||
'order_id': order.order_id,
|
||||
'awb_number': order.awb_number,
|
||||
'barcode': order.barcode,
|
||||
'tracking_url': order.tracking_url,
|
||||
'state': order.state,
|
||||
'last_updated': order.created_at, # Use created_at as proxy
|
||||
'tracking_events': order.metadata.get('tracking_events', [])
|
||||
}
|
||||
|
||||
serializer = DeutschePostTrackingSerializer(tracking_data)
|
||||
return Response(serializer.data)
|
||||
except Exception as e:
|
||||
return Response(
|
||||
{'error': str(e)},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
tags=["deutschepost"],
|
||||
summary="Cancel Deutsche Post Order",
|
||||
description="""
|
||||
Cancel the order in Deutsche Post API system. This will:
|
||||
- Call Deutsche Post API to cancel the order
|
||||
- Update the order state to CANCELLED
|
||||
- Cannot be undone once cancelled
|
||||
- Only works for orders that are not yet shipped or delivered
|
||||
|
||||
Note: Orders are created and managed through the Carrier model in commerce app.
|
||||
""",
|
||||
request=None,
|
||||
responses={
|
||||
200: DeutschePostOrderSerializer,
|
||||
400: OpenApiResponse(description="Order cannot be cancelled or API error"),
|
||||
500: OpenApiResponse(description="Deutsche Post API error")
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=['post'])
|
||||
def cancel_order(self, request, pk=None):
|
||||
"""Cancel order in Deutsche Post API."""
|
||||
order = self.get_object()
|
||||
|
||||
try:
|
||||
order.cancel_order()
|
||||
serializer = self.get_serializer(order)
|
||||
return Response(serializer.data)
|
||||
except Exception as e:
|
||||
return Response(
|
||||
{'error': str(e)},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
tags=["deutschepost"],
|
||||
summary="Get Tracking URL",
|
||||
description="""
|
||||
Get the public tracking URL for the order that customers can use to track their shipment.
|
||||
Returns the URL if available, or null if tracking is not yet available.
|
||||
""",
|
||||
request=None,
|
||||
responses={
|
||||
200: OpenApiResponse(description="Tracking URL response", examples={
|
||||
"application/json": {
|
||||
"tracking_url": "https://www.deutschepost.de/de/s/sendungsverfolgung.html?piececode=ABC123"
|
||||
}
|
||||
}),
|
||||
404: OpenApiResponse(description="Tracking URL not available")
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=['get'])
|
||||
def get_tracking_url(self, request, pk=None):
|
||||
"""Get public tracking URL for the order."""
|
||||
order = self.get_object()
|
||||
tracking_url = order.get_tracking_url()
|
||||
|
||||
if tracking_url:
|
||||
return Response({'tracking_url': tracking_url})
|
||||
else:
|
||||
return Response(
|
||||
{'error': 'Tracking URL not available yet'},
|
||||
status=status.HTTP_404_NOT_FOUND
|
||||
)
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
list=extend_schema(
|
||||
tags=["deutschepost"],
|
||||
summary="List Deutsche Post Bulk Orders",
|
||||
description="Returns a paginated list of Deutsche Post bulk shipping orders. Admin only access.",
|
||||
responses=DeutschePostBulkOrderSerializer(many=True),
|
||||
),
|
||||
retrieve=extend_schema(
|
||||
tags=["deutschepost"],
|
||||
summary="Get Deutsche Post Bulk Order Detail",
|
||||
description="Returns detailed information for a single Deutsche Post bulk order including all constituent orders.",
|
||||
responses=DeutschePostBulkOrderSerializer,
|
||||
),
|
||||
create=extend_schema(
|
||||
tags=["deutschepost"],
|
||||
summary="Create Deutsche Post Bulk Order",
|
||||
description="""
|
||||
Create a new Deutsche Post bulk order from multiple individual orders.
|
||||
|
||||
Requirements:
|
||||
- All orders must be created remotely (have order_id)
|
||||
- All linked commerce orders must use Deutsche Post delivery
|
||||
- All linked commerce orders must be completed
|
||||
- Orders cannot already be part of another bulk order
|
||||
""",
|
||||
request=DeutschePostBulkOrderSerializer,
|
||||
responses={
|
||||
201: DeutschePostBulkOrderSerializer,
|
||||
400: OpenApiResponse(description="Validation error - orders not eligible for bulk processing")
|
||||
},
|
||||
),
|
||||
)
|
||||
class DeutschePostBulkOrderViewSet(
|
||||
mixins.ListModelMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.CreateModelMixin,
|
||||
viewsets.GenericViewSet
|
||||
):
|
||||
queryset = DeutschePostBulkOrder.objects.all().order_by("-created_at")
|
||||
serializer_class = DeutschePostBulkOrderSerializer
|
||||
permission_classes = [IsAdminUser]
|
||||
|
||||
@extend_schema(
|
||||
tags=["deutschepost"],
|
||||
summary="Create Remote Bulk Order",
|
||||
description="""
|
||||
Create the bulk order in Deutsche Post API system. This will:
|
||||
- Validate all constituent orders are eligible
|
||||
- Call Deutsche Post API to create the bulk order
|
||||
- Store the returned bulk_order_id
|
||||
- Update the bulk order status to PROCESSING
|
||||
- Handle API errors and validation
|
||||
""",
|
||||
request=None,
|
||||
responses={
|
||||
200: DeutschePostBulkOrderSerializer,
|
||||
400: OpenApiResponse(description="Bulk order already created or validation error"),
|
||||
500: OpenApiResponse(description="Deutsche Post API error")
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=['post'])
|
||||
def create_remote(self, request, pk=None):
|
||||
"""Create bulk order in Deutsche Post API."""
|
||||
bulk_order = self.get_object()
|
||||
|
||||
try:
|
||||
bulk_order.create_remote_bulk_order()
|
||||
serializer = self.get_serializer(bulk_order)
|
||||
return Response(serializer.data)
|
||||
except Exception as e:
|
||||
return Response(
|
||||
{'error': str(e)},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
tags=["deutschepost"],
|
||||
summary="Cancel Remote Bulk Order",
|
||||
description="""
|
||||
Cancel the bulk order in Deutsche Post API system. This will:
|
||||
- Call Deutsche Post API to cancel the bulk order
|
||||
- Update the bulk order status to ERROR (cancelled state)
|
||||
- Cannot be undone once cancelled
|
||||
- Only works for bulk orders that are not yet completed
|
||||
""",
|
||||
request=None,
|
||||
responses={
|
||||
200: DeutschePostBulkOrderSerializer,
|
||||
400: OpenApiResponse(description="Bulk order cannot be cancelled or validation error"),
|
||||
500: OpenApiResponse(description="Deutsche Post API error")
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=['post'])
|
||||
def cancel_bulk_order(self, request, pk=None):
|
||||
"""Cancel bulk order in Deutsche Post API."""
|
||||
bulk_order = self.get_object()
|
||||
|
||||
try:
|
||||
bulk_order.cancel_bulk_order()
|
||||
serializer = self.get_serializer(bulk_order)
|
||||
return Response(serializer.data)
|
||||
except Exception as e:
|
||||
return Response(
|
||||
{'error': str(e)},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
tags=["deutschepost"],
|
||||
summary="Get Bulk Order URLs",
|
||||
description="""
|
||||
Get tracking and status URLs for the bulk order. Returns:
|
||||
- tracking_url: Public URL for tracking bulk shipment progress
|
||||
- status_url: URL for monitoring bulk order processing status
|
||||
""",
|
||||
request=None,
|
||||
responses={
|
||||
200: OpenApiResponse(description="Bulk order URLs", examples={
|
||||
"application/json": {
|
||||
"tracking_url": "https://www.deutschepost.de/de/b/bulk-tracking.html?bulk_id=BULK123",
|
||||
"status_url": "https://www.deutschepost.de/de/b/bulk-status.html?bulk_id=BULK123"
|
||||
}
|
||||
}),
|
||||
404: OpenApiResponse(description="Bulk order not created remotely yet")
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=['get'])
|
||||
def get_urls(self, request, pk=None):
|
||||
"""Get tracking and status URLs for bulk order."""
|
||||
bulk_order = self.get_object()
|
||||
|
||||
tracking_url = bulk_order.get_tracking_url()
|
||||
status_url = bulk_order.get_bulk_status_url()
|
||||
|
||||
if tracking_url or status_url:
|
||||
return Response({
|
||||
'tracking_url': tracking_url,
|
||||
'status_url': status_url,
|
||||
'bulk_order_id': bulk_order.bulk_order_id
|
||||
})
|
||||
else:
|
||||
return Response(
|
||||
{'error': 'Bulk order not created remotely yet'},
|
||||
status=status.HTTP_404_NOT_FOUND
|
||||
)
|
||||
Reference in New Issue
Block a user