115 lines
4.7 KiB
Python
115 lines
4.7 KiB
Python
from rest_framework import serializers
|
|
|
|
from adventrues.models import AdventureOffering
|
|
from equipment.models import EquipmentItem
|
|
from marketing.models import ListingClick
|
|
from marketing.services import listing_click_valid_for_booking
|
|
|
|
from .models import Booking, BookingEventLog
|
|
from .services import create_booking_request, quote_booking
|
|
|
|
|
|
class BookingEventLogSerializer(serializers.ModelSerializer):
|
|
actor_email = serializers.EmailField(source="actor.email", read_only=True)
|
|
|
|
class Meta:
|
|
model = BookingEventLog
|
|
fields = ("id", "from_status", "to_status", "note", "actor_email", "created_at")
|
|
|
|
|
|
class BookingSerializer(serializers.ModelSerializer):
|
|
customer_email = serializers.EmailField(source="customer.email", read_only=True)
|
|
vendor_slug = serializers.CharField(source="vendor.slug", read_only=True)
|
|
equipment_public_id = serializers.CharField(source="equipment_item.public_id", read_only=True)
|
|
adventure_public_id = serializers.CharField(source="adventure_offering.public_id", read_only=True)
|
|
events = BookingEventLogSerializer(many=True, read_only=True)
|
|
|
|
class Meta:
|
|
model = Booking
|
|
fields = (
|
|
"id",
|
|
"customer_email",
|
|
"vendor_slug",
|
|
"equipment_item",
|
|
"equipment_public_id",
|
|
"adventure_public_id",
|
|
"starts_at",
|
|
"ends_at",
|
|
"status",
|
|
"total_price",
|
|
"customer_notes",
|
|
"vendor_notes",
|
|
"events",
|
|
"listing_click",
|
|
"created_at",
|
|
"updated_at",
|
|
)
|
|
read_only_fields = ("status", "total_price", "created_at", "updated_at", "events", "listing_click")
|
|
|
|
|
|
class BookingCreateSerializer(serializers.Serializer):
|
|
equipment_item_id = serializers.PrimaryKeyRelatedField(
|
|
queryset=EquipmentItem.objects.filter(is_active=True),
|
|
required=False,
|
|
allow_null=True,
|
|
)
|
|
adventure_offering_id = serializers.PrimaryKeyRelatedField(
|
|
queryset=AdventureOffering.objects.filter(is_active=True),
|
|
required=False,
|
|
allow_null=True,
|
|
)
|
|
starts_at = serializers.DateTimeField()
|
|
ends_at = serializers.DateTimeField()
|
|
customer_notes = serializers.CharField(required=False, allow_blank=True)
|
|
participants_count = serializers.IntegerField(required=False, min_value=1, default=1)
|
|
marketing_click_id = serializers.IntegerField(required=False, allow_null=True)
|
|
|
|
def validate(self, attrs):
|
|
equipment_item = attrs.get("equipment_item_id")
|
|
adventure_offering = attrs.get("adventure_offering_id")
|
|
if bool(equipment_item) == bool(adventure_offering):
|
|
raise serializers.ValidationError("Provide exactly one target: equipment_item_id or adventure_offering_id.")
|
|
click_id = attrs.get("marketing_click_id")
|
|
listing_click = None
|
|
if click_id is not None:
|
|
listing_click = ListingClick.objects.filter(pk=click_id).first()
|
|
if not listing_click:
|
|
raise serializers.ValidationError({"marketing_click_id": "Invalid marketing_click_id."})
|
|
if not listing_click_valid_for_booking(
|
|
click=listing_click,
|
|
equipment_item=equipment_item,
|
|
adventure_offering=adventure_offering,
|
|
):
|
|
raise serializers.ValidationError(
|
|
{"marketing_click_id": "Click does not match this listing or is outside the attribution window."}
|
|
)
|
|
attrs["_listing_click"] = listing_click
|
|
try:
|
|
quote_booking(
|
|
equipment_item=equipment_item,
|
|
adventure_offering=adventure_offering,
|
|
starts_at=attrs["starts_at"],
|
|
ends_at=attrs["ends_at"],
|
|
participants_count=attrs.get("participants_count", 1),
|
|
)
|
|
except Exception as exc:
|
|
raise serializers.ValidationError(str(exc)) from exc
|
|
return attrs
|
|
|
|
def create(self, validated_data):
|
|
try:
|
|
booking = create_booking_request(
|
|
customer=self.context["request"].user,
|
|
starts_at=validated_data["starts_at"],
|
|
ends_at=validated_data["ends_at"],
|
|
equipment_item=validated_data.get("equipment_item_id"),
|
|
adventure_offering=validated_data.get("adventure_offering_id"),
|
|
participants_count=validated_data.get("participants_count", 1),
|
|
customer_notes=validated_data.get("customer_notes", ""),
|
|
listing_click=validated_data.get("_listing_click"),
|
|
)
|
|
except Exception as exc:
|
|
raise serializers.ValidationError({"non_field_errors": [str(exc)]}) from exc
|
|
|
|
return booking
|