Introduces a OneToOneField for carrier in the Refund model to support future integration and refactoring. Adds and updates TODO comments for email template usage, error handling in Stripe webhooks, and clarifies logic placement in Stripe models.
80 lines
2.6 KiB
Python
80 lines
2.6 KiB
Python
from django.views.decorators.csrf import csrf_exempt
|
|
from django.conf import settings
|
|
from django.http import HttpResponse
|
|
|
|
from rest_framework import generics
|
|
from rest_framework.response import Response
|
|
from rest_framework.views import APIView
|
|
from drf_spectacular.utils import extend_schema
|
|
import os
|
|
import logging
|
|
|
|
from .models import StripeTransaction
|
|
from commerce.models import Order, Payment
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
import stripe
|
|
stripe.api_key = os.getenv("STRIPE_SECRET_KEY")
|
|
|
|
class StripeWebhook(APIView):
|
|
@extend_schema(
|
|
tags=["stripe"],
|
|
)
|
|
def post(self, request):
|
|
payload = request.body
|
|
sig_header = request.META['HTTP_STRIPE_SIGNATURE']
|
|
|
|
try:
|
|
#build stripe event (api call)
|
|
event = stripe.Webhook.construct_event(
|
|
payload, sig_header, os.getenv("STRIPE_WEBHOOK_SECRET")
|
|
)
|
|
|
|
except ValueError as e:
|
|
# TODO: doupravit error handling, dodělat v modelu možnost pro uložení chyby a status ERROR
|
|
logger.error(f"Invalid payload: {e}")
|
|
return HttpResponse(status=400)
|
|
|
|
except stripe.error as e:
|
|
# stripe error
|
|
logger.error(f"Stripe error: {e}")
|
|
return HttpResponse(status=400)
|
|
|
|
|
|
session = event['data']['object']
|
|
|
|
|
|
# ZAPLACENO
|
|
if event['type'] == 'checkout.session.completed':
|
|
|
|
stripe_transaction = StripeTransaction.objects.get(stripe_session_id=session.id)
|
|
|
|
if stripe_transaction:
|
|
stripe_transaction.paid()
|
|
|
|
logger.info(f"Transaction {stripe_transaction.id} marked as paid.")
|
|
|
|
else:
|
|
logger.warning(f"No transaction found for session ID: {session.id}")
|
|
|
|
# EXPIRACE (zrušení objednávky) uživatel nezaplatil do 24 hodin!
|
|
elif event['type'] == 'checkout.session.expired':
|
|
order = Order.objects.get(payment=Payment.objects.get(stripe=StripeTransaction.objects.get(stripe_session_id=session.id)))
|
|
order.status = Order.STATUS_CHOICES.CANCELLED
|
|
order.save()
|
|
|
|
elif event['type'] == 'payment_intent.payment_failed':
|
|
#nothing to do for now
|
|
pass
|
|
|
|
# REFUND POTVRZEN
|
|
elif event['type'] == 'payment_intent.refunded':
|
|
session = event['data']['object']
|
|
stripe_transaction = StripeTransaction.objects.get(stripe_payment_intent=session.id)
|
|
|
|
if stripe_transaction:
|
|
stripe_transaction.refund_confirmed()
|
|
|
|
logger.info(f"Transaction {stripe_transaction.id} marked as refunded.")
|