fix error in gitignore
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
from django.db.models import Q
|
||||
from django.utils import timezone
|
||||
from rest_framework import decorators, mixins, response, status, viewsets
|
||||
|
||||
from apps.core.errors import error_response
|
||||
from apps.payments.gateways import get_gateway
|
||||
from apps.payments.models import Payment
|
||||
from apps.payments.serializers import PaymentSerializer
|
||||
from apps.rbac.permissions import ActionPermission
|
||||
|
||||
|
||||
class PaymentViewSet(
|
||||
mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet
|
||||
):
|
||||
serializer_class = PaymentSerializer
|
||||
permission_classes = [ActionPermission]
|
||||
code_map = {
|
||||
"list": "invoice.view",
|
||||
"retrieve": "invoice.view",
|
||||
"create": "reservation.create",
|
||||
"verify": "invoice.create",
|
||||
}
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
qs = Payment.objects.select_related("order", "reservation").all()
|
||||
if user.is_superuser:
|
||||
return qs
|
||||
return qs.filter(Q(order__customer__user=user) | Q(reservation__customer__user=user))
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
order = serializer.validated_data.get("order")
|
||||
reservation = serializer.validated_data.get("reservation")
|
||||
if not order and not reservation:
|
||||
return response.Response(
|
||||
error_response("PAYMENT_TARGET_REQUIRED", "An order or reservation is required."),
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
amount = serializer.validated_data["amount"]
|
||||
currency = order.currency if order else getattr(settings, "BASE_CURRENCY", "IRR")
|
||||
reference = order.order_number if order else f"RES-{str(reservation.id)[:8]}"
|
||||
|
||||
gateway = get_gateway()
|
||||
callback_url = request.build_absolute_uri("/api/v1/payments/callback/")
|
||||
result = gateway.request_payment(str(amount), currency, reference, callback_url)
|
||||
payment = Payment.objects.create(
|
||||
order=order,
|
||||
reservation=reservation,
|
||||
amount=amount,
|
||||
currency=currency,
|
||||
gateway=settings.PAYMENT_GATEWAY_PROVIDER or "mock",
|
||||
authority=result["authority"],
|
||||
status=Payment.Status.PENDING,
|
||||
request_time=timezone.now(),
|
||||
)
|
||||
return response.Response(
|
||||
{"id": str(payment.id), "authority": result["authority"], "redirect_url": result["redirect_url"]},
|
||||
status=status.HTTP_201_CREATED,
|
||||
)
|
||||
|
||||
@decorators.action(detail=True, methods=["post"])
|
||||
@transaction.atomic
|
||||
def verify(self, request, pk=None):
|
||||
payment = Payment.objects.select_for_update().get(pk=pk)
|
||||
# Idempotent: a duplicate callback must not create a duplicate success.
|
||||
if payment.status == Payment.Status.SUCCESS:
|
||||
return response.Response(PaymentSerializer(payment).data)
|
||||
gateway = get_gateway()
|
||||
result = gateway.verify(payment.authority, str(payment.amount))
|
||||
payment.verification_time = timezone.now()
|
||||
if result.get("status") == "success":
|
||||
payment.status = Payment.Status.SUCCESS
|
||||
payment.transaction_id = result["transaction_id"]
|
||||
else:
|
||||
payment.status = Payment.Status.FAILED
|
||||
payment.error = result.get("error", "")
|
||||
payment.save()
|
||||
return response.Response(PaymentSerializer(payment).data)
|
||||
Reference in New Issue
Block a user