Implement Moyasar payments flow with webhooks
This commit is contained in:
@@ -2,7 +2,7 @@ from rest_framework import serializers
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from apps.bookings.models import Booking
|
||||
from apps.payments.models import Payment, PaymentProvider, PaymentStatus
|
||||
from apps.payments.models import Payment, PaymentProvider
|
||||
|
||||
|
||||
class PaymentSerializer(serializers.ModelSerializer):
|
||||
@@ -18,7 +18,16 @@ class PaymentSerializer(serializers.ModelSerializer):
|
||||
"amount",
|
||||
"currency",
|
||||
"external_id",
|
||||
"idempotency_key",
|
||||
"metadata",
|
||||
"authorized_at",
|
||||
"captured_at",
|
||||
"paid_at",
|
||||
"failed_at",
|
||||
"refunded_at",
|
||||
"voided_at",
|
||||
"verified_at",
|
||||
"status_updated_at",
|
||||
"created_at",
|
||||
]
|
||||
read_only_fields = fields
|
||||
@@ -27,23 +36,33 @@ class PaymentSerializer(serializers.ModelSerializer):
|
||||
class PaymentCreateSerializer(serializers.ModelSerializer):
|
||||
booking_id = serializers.IntegerField(write_only=True)
|
||||
provider = serializers.ChoiceField(choices=PaymentProvider.choices)
|
||||
idempotency_key = serializers.UUIDField(write_only=True)
|
||||
source = serializers.JSONField(write_only=True, required=False)
|
||||
callback_url = serializers.URLField(write_only=True, required=False)
|
||||
|
||||
class Meta:
|
||||
model = Payment
|
||||
fields = ["booking_id", "provider"]
|
||||
fields = ["booking_id", "provider", "idempotency_key", "source", "callback_url"]
|
||||
|
||||
def validate_booking_id(self, value):
|
||||
if not Booking.objects.filter(id=value).exists():
|
||||
raise serializers.ValidationError(_("Booking not found"))
|
||||
return value
|
||||
|
||||
def create(self, validated_data):
|
||||
booking = Booking.objects.get(id=validated_data["booking_id"])
|
||||
return Payment.objects.create(
|
||||
booking=booking,
|
||||
provider=validated_data["provider"],
|
||||
status=PaymentStatus.CREATED,
|
||||
amount=booking.price_amount,
|
||||
currency=booking.currency,
|
||||
metadata={},
|
||||
)
|
||||
def validate(self, attrs):
|
||||
provider = attrs.get("provider")
|
||||
source = attrs.get("source")
|
||||
if provider != PaymentProvider.MOYASAR:
|
||||
raise serializers.ValidationError({"provider": _("Provider integration not implemented")})
|
||||
if source is None:
|
||||
raise serializers.ValidationError({"source": _("Payment source is required")})
|
||||
source_type = source.get("type")
|
||||
if not source_type:
|
||||
raise serializers.ValidationError({"source": _("Payment source type is required")})
|
||||
if source_type == "creditcard":
|
||||
raise serializers.ValidationError(
|
||||
{"source": _("Card data must not be sent to the backend; use frontend tokenization")}
|
||||
)
|
||||
if source_type == "token" and not attrs.get("callback_url"):
|
||||
raise serializers.ValidationError({"callback_url": _("Callback URL is required for token payments")})
|
||||
return attrs
|
||||
|
||||
Reference in New Issue
Block a user