from datetime import timedelta import datetime from django.db import transaction from django.shortcuts import get_object_or_404 from django.utils import timezone from rest_framework import status from rest_framework.views import APIView from django.conf import settings import stripe from accounts.models import IAmPrincipal import json from goodtimes import constants, services from manage_subscriptions.models import ( Subscription, PrincipalSubscription, SubscriptionStatus, WebhookEvent, ) from goodtimes.utils import ApiResponse from accounts.resource_action import ( PRINCIPAL_TYPE_EVENT_USER, PRINCIPAL_TYPE_EVENT_MANAGER, PRINCIPAL_TYPE_FREE_USER, ) from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework_simplejwt.authentication import JWTAuthentication from manage_wallets.models import ( PaymentMethod, Transaction, TransactionStatus, TransactionType, ) from .serializers import PrincipalSubscriptionSerializer from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator from rest_framework.response import Response class CreatePrincipalSubscriptionApi(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] stripe.api_key = settings.STRIPE_SECRET_KEY def post(self, request): serializer = PrincipalSubscriptionSerializer(data=request.data) if serializer.is_valid(): subscription_id = serializer.validated_data.get("subscription") try: subscription = Subscription.objects.get(id=subscription_id) except Subscription.DoesNotExist: return ApiResponse.error( status=status.HTTP_404_NOT_FOUND, message="Subscription not found." ) order_id = ( "order_" + str(timezone.localtime().timestamp()) + str(request.user.email) ) print("order_id: ", order_id) # Create a Transaction object with status INITIATE transaction = Transaction.objects.create( principal=request.user, principal_subscription=None, # Since the subscription is not created yet transaction_type=TransactionType.DEPOSIT, # or PAYMENT, as applicable payment_method=PaymentMethod.CARD, # Assuming CARD for this example transaction_status=TransactionStatus.INITIATE, amount=subscription.amount, order_id=order_id, comment="Principal Subscription Initiated", ) try: customer = stripe.Customer.create( email=request.user.email, shipping={ "name": request.user.first_name, "address": { "line1": "Test Address", "city": "Test City", "postal_code": "SW1A 2AA", "country": "GB", # Adjust accordingly }, }, ) payment_intent = stripe.PaymentIntent.create( amount=int(subscription.amount * 100), currency="GBP", description="Principal Subscription", metadata={ "principal": request.user.id, "order_id": order_id, "subscription": str(subscription.id), "transaction_id": str(transaction.id), }, customer=customer.id, ) return Response( { "client_secret": payment_intent.client_secret, "message": "Payment intent created successfully", } ) except stripe.error.StripeError as e: # Handle Stripe-related errors return Response({"error": str(e)}, status=400) else: fail_response = { "status": status.HTTP_400_BAD_REQUEST, "message": "Validation Failed", "errors": serializer.errors, } return ApiResponse.error(**fail_response) # class CreatePrincipalSubscriptionApi(APIView): # authentication_classes = [JWTAuthentication] # permission_classes = [IsAuthenticated] # def post(self, request): # serializer = PrincipalSubscriptionSerializer(data=request.data) # if serializer.is_valid(): # subscription_id = serializer.validated_data.get("subscription").id # try: # subscription = Subscription.objects.get(id=subscription_id) # except Subscription.DoesNotExist: # return ApiResponse.error( # status=status.HTTP_404_NOT_FOUND, message="Subscription not found." # ) # start_date = timezone.localtime().date() # end_date = start_date + timedelta(days=subscription.plan.days) # grace_period_end_date = end_date + timedelta(days=15) # # You can directly pass the additional fields as save method arguments # instance = serializer.save( # start_date=start_date, # end_date=end_date, # grace_period_end_date=grace_period_end_date, # created_by=request.user, # Assuming your model has this field and you want to track who created the subscription # ) # success_response = { # "status": status.HTTP_201_CREATED, # Use 201 for successful resource creation # "message": "Success", # "data": serializer.data, # } # return ApiResponse.success(**success_response) # else: # fail_response = { # "status": status.HTTP_400_BAD_REQUEST, # "message": "Validation Failed", # "errors": serializer.errors, # } # return ApiResponse.error(**fail_response) @method_decorator(csrf_exempt, name="dispatch") class StripeWebhookTest(APIView): authentication_classes = [] permission_classes = [AllowAny] @transaction.atomic def post(self, request): stripe.api_key = settings.STRIPE_SECRET_KEY payload = request.body sig_header = request.META["HTTP_STRIPE_SIGNATURE"] endpoint_secret = "whsec_ccf1f87295603cdd1733995ee2d3c0d6f74c7ceaf28916ea45114a54b7ce1d0f" # Make sure to retrieve this from your settings event = None try: event = stripe.Event.construct_from(json.loads(payload), stripe.api_key) event_id = event["id"] event_type = event["type"] principal_id = event["data"]["object"]["metadata"]["principal"] webhook_event, created = WebhookEvent.objects.get_or_create( event_id=event_id, defaults={ "event_type": event_type, "event_payload": json.loads(payload), }, ) if not created and webhook_event.status == "processed": return ApiResponse.success( status=status.HTTP_208_ALREADY_REPORTED, message="Event already processed", ) # Check if there is an active principal subscription if self._has_active_principal_subscription(principal_id): return ApiResponse.success( status=status.HTTP_208_ALREADY_REPORTED, message="Active principal subscription already exists", ) payment_service = services.PaymentProcessingService(webhook_data=event) payment_service.process_event() webhook_event = WebhookEvent.objects.get(event_id=event_id) webhook_event.status = "processed" webhook_event.processed_at = timezone.now() # Make sure to import timezone webhook_event.save() return ApiResponse.success( status=status.HTTP_200_OK, message="Event processed successfully" ) except ValueError as e: # Invalid payload return ApiResponse.error( status=status.HTTP_400_BAD_REQUEST, message="Invalid payload", errors=str(e), ) except stripe.error.SignatureVerificationError as e: # Invalid signature return ApiResponse.error( status=status.HTTP_400_BAD_REQUEST, message="Invalid signature", errors=str(e), ) except Transaction.DoesNotExist: # Handle case where the transaction does not exist return ApiResponse.error( status=status.HTTP_404_NOT_FOUND, message="Transaction not found" ) except Exception as e: webhook_event.status = "failed" webhook_event.error_message = str(e) webhook_event.save() return ApiResponse.error( status=status.HTTP_500_INTERNAL_SERVER_ERROR, message="Error processing event", errors=str(e), ) def _has_active_principal_subscription(self, principal_id): return PrincipalSubscription.objects.filter( principal__id=principal_id, active=True, deleted=False, is_paid=True, end_date__gte=timezone.now().date(), ).exists() class LastActiveSubscriptionView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] def get(self, request, *args, **kwargs): today = timezone.now().date() try: last_active_subscription = PrincipalSubscription.objects.filter( principal=request.user, is_paid=True, cancelled=False, deleted=False, active=True, status=SubscriptionStatus.ACTIVE, end_date__gte=today, ).latest("end_date") serializer = PrincipalSubscriptionSerializer(last_active_subscription) return ApiResponse.success( status=status.HTTP_200_OK, message=constants.SUCCESS, data=serializer.data, ) except PrincipalSubscription.DoesNotExist: return ApiResponse.error( status=status.HTTP_404_NOT_FOUND, message="No Active Subscription Found", errors="No Active Subscription Found", )