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:
163
backend/thirdparty/deutschepost/serializers.py
vendored
Normal file
163
backend/thirdparty/deutschepost/serializers.py
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from .models import DeutschePostOrder, DeutschePostBulkOrder
|
||||
|
||||
|
||||
class DeutschePostOrderSerializer(serializers.ModelSerializer):
|
||||
commerce_order_id = serializers.IntegerField(write_only=True, required=False)
|
||||
state_display = serializers.CharField(source='get_state_display', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = DeutschePostOrder
|
||||
fields = [
|
||||
'id', 'created_at', 'state', 'state_display', 'commerce_order', 'commerce_order_id',
|
||||
'order_id', 'customer_ekp',
|
||||
'recipient_name', 'recipient_phone', 'recipient_email',
|
||||
'address_line1', 'address_line2', 'address_line3',
|
||||
'city', 'address_state', 'postal_code', 'destination_country',
|
||||
'product_type', 'service_level', 'shipment_gross_weight',
|
||||
'shipment_amount', 'shipment_currency',
|
||||
'sender_tax_id', 'importer_tax_id', 'return_item_wanted',
|
||||
'cust_ref', 'awb_number', 'barcode', 'tracking_url',
|
||||
'metadata', 'last_error'
|
||||
]
|
||||
read_only_fields = [
|
||||
'id', 'created_at', 'order_id', 'awb_number', 'barcode',
|
||||
'tracking_url', 'metadata', 'last_error'
|
||||
]
|
||||
|
||||
def validate_commerce_order_id(self, value):
|
||||
"""Validate that commerce order exists and uses Deutsche Post delivery."""
|
||||
try:
|
||||
from commerce.models import Order
|
||||
order = Order.objects.get(id=value)
|
||||
|
||||
if not order.carrier:
|
||||
raise ValidationError("Commerce order must have a carrier assigned")
|
||||
|
||||
if order.carrier.shipping_method != "deutschepost":
|
||||
raise ValidationError("Commerce order must use Deutsche Post delivery method")
|
||||
|
||||
if order.status != Order.OrderStatus.COMPLETED:
|
||||
raise ValidationError("Commerce order must be completed before creating Deutsche Post order")
|
||||
|
||||
return value
|
||||
except Order.DoesNotExist:
|
||||
raise ValidationError("Commerce order does not exist")
|
||||
|
||||
def validate_destination_country(self, value):
|
||||
"""Validate country code format."""
|
||||
if len(value) != 2:
|
||||
raise ValidationError("Country code must be 2 characters (ISO format)")
|
||||
return value.upper()
|
||||
|
||||
def validate_shipment_gross_weight(self, value):
|
||||
"""Validate weight is reasonable."""
|
||||
if value <= 0:
|
||||
raise ValidationError("Shipment weight must be greater than 0")
|
||||
if value > 30000: # 30kg limit for most Deutsche Post products
|
||||
raise ValidationError("Shipment weight cannot exceed 30kg (30000g)")
|
||||
return value
|
||||
|
||||
def create(self, validated_data):
|
||||
commerce_order_id = validated_data.pop('commerce_order_id', None)
|
||||
|
||||
if commerce_order_id:
|
||||
from commerce.models import Order
|
||||
validated_data['commerce_order'] = Order.objects.get(id=commerce_order_id)
|
||||
|
||||
return super().create(validated_data)
|
||||
|
||||
|
||||
class DeutschePostBulkOrderSerializer(serializers.ModelSerializer):
|
||||
deutschepost_order_ids = serializers.ListField(
|
||||
child=serializers.IntegerField(),
|
||||
write_only=True,
|
||||
required=True,
|
||||
help_text="List of DeutschePostOrder IDs to include in bulk order"
|
||||
)
|
||||
status_display = serializers.CharField(source='get_status_display', read_only=True)
|
||||
orders_count = serializers.SerializerMethodField(read_only=True)
|
||||
tracking_url = serializers.SerializerMethodField(read_only=True)
|
||||
status_url = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = DeutschePostBulkOrder
|
||||
fields = [
|
||||
'id', 'created_at', 'status', 'status_display',
|
||||
'bulk_order_id', 'bulk_order_type', 'description',
|
||||
'deutschepost_orders', 'deutschepost_order_ids', 'orders_count',
|
||||
'tracking_url', 'status_url',
|
||||
'metadata', 'last_error'
|
||||
]
|
||||
read_only_fields = [
|
||||
'id', 'created_at', 'bulk_order_id', 'deutschepost_orders',
|
||||
'metadata', 'last_error'
|
||||
]
|
||||
|
||||
def get_orders_count(self, obj):
|
||||
return obj.deutschepost_orders.count()
|
||||
|
||||
def get_tracking_url(self, obj):
|
||||
return obj.get_tracking_url()
|
||||
|
||||
def get_status_url(self, obj):
|
||||
return obj.get_bulk_status_url()
|
||||
|
||||
def validate_deutschepost_order_ids(self, value):
|
||||
"""Validate that all orders exist and are eligible for bulk processing."""
|
||||
if not value:
|
||||
raise ValidationError("At least one Deutsche Post order is required")
|
||||
|
||||
errors = []
|
||||
orders = DeutschePostOrder.objects.filter(id__in=value)
|
||||
|
||||
if len(orders) != len(value):
|
||||
missing_ids = set(value) - set(orders.values_list('id', flat=True))
|
||||
errors.append(f"Orders not found: {missing_ids}")
|
||||
|
||||
for order in orders:
|
||||
# Check if order is created remotely
|
||||
if not order.order_id:
|
||||
errors.append(f"Order {order.id} not created remotely")
|
||||
|
||||
# Check if commerce order uses Deutsche Post
|
||||
if order.commerce_order:
|
||||
if not order.commerce_order.carrier:
|
||||
errors.append(f"Commerce order {order.commerce_order.id} has no carrier")
|
||||
elif order.commerce_order.carrier.shipping_method != "deutschepost":
|
||||
errors.append(f"Commerce order {order.commerce_order.id} doesn't use Deutsche Post")
|
||||
elif order.commerce_order.status != order.commerce_order.OrderStatus.COMPLETED:
|
||||
errors.append(f"Commerce order {order.commerce_order.id} is not completed")
|
||||
|
||||
# Check if order is already in another bulk order
|
||||
if order.bulk_orders.exists():
|
||||
errors.append(f"Order {order.id} already in bulk order")
|
||||
|
||||
if errors:
|
||||
raise ValidationError(errors)
|
||||
|
||||
return value
|
||||
|
||||
def create(self, validated_data):
|
||||
order_ids = validated_data.pop('deutschepost_order_ids')
|
||||
|
||||
bulk_order = super().create(validated_data)
|
||||
|
||||
# Add orders to bulk order
|
||||
orders = DeutschePostOrder.objects.filter(id__in=order_ids)
|
||||
bulk_order.deutschepost_orders.set(orders)
|
||||
|
||||
return bulk_order
|
||||
|
||||
|
||||
class DeutschePostTrackingSerializer(serializers.Serializer):
|
||||
"""Serializer for tracking information response."""
|
||||
order_id = serializers.CharField(read_only=True)
|
||||
awb_number = serializers.CharField(read_only=True)
|
||||
barcode = serializers.CharField(read_only=True)
|
||||
tracking_url = serializers.URLField(read_only=True)
|
||||
state = serializers.CharField(read_only=True)
|
||||
last_updated = serializers.DateTimeField(read_only=True)
|
||||
tracking_events = serializers.JSONField(read_only=True)
|
||||
Reference in New Issue
Block a user