refactored webhook realted to coupon

This commit is contained in:
rizwanisready
2024-08-05 18:40:34 +05:30
parent 85767e7b96
commit 73ca0ea974
9 changed files with 536 additions and 411 deletions

View File

@@ -1,353 +0,0 @@
import datetime
from django.conf import settings
from django.db import transaction
from django.shortcuts import get_object_or_404
from datetime import timedelta
from django.utils import timezone
from onesignal_sdk.client import Client as OneSignalClient
from accounts.models import IAmPrincipal
from manage_coupons.models import Coupon
from manage_notifications.models import (
IAmPrincipalNotificationSettings,
InAppNotification,
NotificationCategoryChoices,
)
from manage_referrals.models import (
ReferralRecord,
ReferralRecordReward,
ReferralTracking,
)
from django.core.exceptions import ObjectDoesNotExist
from manage_subscriptions.models import PrincipalSubscription, Subscription
from manage_wallets.models import (
TransactionStatus,
TransactionType,
Transaction,
)
import logging
logger = logging.getLogger(__name__)
class NotificationService:
def __init__(self):
self.client = OneSignalClient(
app_id=settings.ONE_SIGNAL_APP_ID, rest_api_key=settings.ONE_SIGNAL_API_KEY
)
def send_notification(self, title, message, player_id):
if player_id is None:
print("Player ID is None, skipping notification")
return
notification_payload = {
"headings": {"en": title},
"contents": {"en": message},
"include_player_ids": [player_id],
}
response = self.client.send_notification(notification_payload)
return response
def save_notification(self, principal, title, message, notification_category):
InAppNotification.objects.create(
principal=principal,
title=title,
message=message,
notification_category=notification_category,
)
def payment_success_notification(
self, principal, subscription, principal_subscription, amount
):
print("payment_success_notification: ", principal.player_id)
title = "Payment Successful"
end_date = principal_subscription.end_date
message = f"Your payment for {subscription} of ${amount} was successfully processed. Your subscription is valid till {end_date}"
self.send_notification(title, message, principal.player_id)
self.save_notification(
principal, title, message, NotificationCategoryChoices.TRANSACTION
)
def referral_received_notification(self, principal, amount, email):
print("referral_received_notification: ", principal.player_id)
title = "Congratulations! You got a referral G-Token."
message = f"Your referral {email} has subscribed to GoodTimesApp. You have received {amount} (£)"
self.save_notification(
principal, title, message, NotificationCategoryChoices.REFERRAL
)
if not self.should_send_referral_notification(principal):
print("Referral notifications are disabled for this user")
return
self.send_notification(title, message, principal.player_id)
def payment_failed_notification(self, principal, subscription, amount):
print("payment_failed_notification: ", principal.player_id)
title = "Payment Failed!"
message = f"Your payment for {subscription} of ${amount} was failed."
self.send_notification(title, message, principal.player_id)
self.save_notification(
principal, title, message, NotificationCategoryChoices.TRANSACTION
)
def should_send_referral_notification(self, principal):
notification_settings = get_object_or_404(
IAmPrincipalNotificationSettings,
principal=principal,
notification_category=NotificationCategoryChoices.REFERRAL,
)
return notification_settings.is_enabled
class WebhookService:
def __init__(self, webhook_data):
self.webhook_data = webhook_data
self.event_type = webhook_data["type"]
self.charge_data = webhook_data["data"]["object"]
def get_event_type(self):
return self.event_type
def get_principal(self):
principal_id = self.charge_data["metadata"]["principal"]
try:
return IAmPrincipal.objects.get(id=int(principal_id))
except (ObjectDoesNotExist, ValueError):
logger.error(f"Invalid principal ID: {principal_id}")
raise ValueError(f"Invalid principal ID: {principal_id}")
def get_transaction(self):
transaction_id = self.charge_data["metadata"]["transaction_id"]
try:
return Transaction.objects.get(id=int(transaction_id))
except (ObjectDoesNotExist, ValueError):
logger.error(f"Invalid transaction ID: {transaction_id}")
raise ValueError(f"Invalid transaction ID: {transaction_id}")
def get_subscription(self):
subscription_id = self.charge_data["metadata"]["subscription_id"]
try:
return Subscription.objects.get(id=int(subscription_id))
except (ObjectDoesNotExist, ValueError):
logger.error(f"Invalid subscription ID: {subscription_id}")
raise ValueError(f"Invalid subscription ID: {subscription_id}")
def get_order_id(self):
return self.charge_data["metadata"]["order_id"]
def get_coupon(self):
coupon_code = self.charge_data["metadata"].get("couponCode")
print("get_coupon:coupon_code: ", coupon_code)
if coupon_code:
try:
return Coupon.objects.get(coupon_code=coupon_code)
except Coupon.DoesNotExist:
logger.error(f"Invalid coupon code: {coupon_code}")
raise ValueError(f"Invalid coupon code: {coupon_code}")
return None
class ReferralRewardService:
def __init__(self, principal, principal_subscription, subscription):
self.notification_service = NotificationService()
self.principal = principal
self.principal_subscription = principal_subscription
self.subscription = subscription
def _fetch_referral_record(self):
return ReferralRecord.objects.filter(
referred_principal=self.principal,
is_completed=True,
active=True, # Assuming 'active' is a field determining if the record is currently relevant
deleted=False, # Assuming logical deletion is handled by a 'deleted' field
).first()
def _check_active_subscription(self, referrer_principal):
today = timezone.now().date()
return (
PrincipalSubscription.objects.filter(
principal=referrer_principal,
is_paid=True,
end_date__gte=today,
cancelled=False,
deleted=False,
)
.order_by("-end_date")
.first()
)
def _credit_reward(self, referral_record, subscription):
amount = subscription.referral_percentage * subscription.amount / 100
ReferralRecordReward.objects.create(
referral_record=referral_record,
subscription=subscription,
coins=1, # This value could be dynamically calculated or configured elsewhere
value=amount,
)
self._credit_transaction(referral_record.referrer_principal, amount)
self.notification_service.referral_received_notification(
referral_record.referrer_principal, amount, self.principal.email
)
def _credit_transaction(self, referrer_principal, amount):
print("_credit_transaction: ", referrer_principal)
Transaction.objects.create(
principal=referrer_principal,
transaction_type=TransactionType.CREDIT,
payment_method="",
transaction_status=TransactionStatus.SUCCESS,
amount=amount,
coins=1,
comment="Referral reward",
# Populate other fields as necessary, such as `order_id`, `product_id`, or `reference_id` if applicable
)
def _update_reward_status(self, referral_record, active_subscription):
# Check if the referrer has an active subscription and get its ID if it exists
referrer_subscription_id = (
active_subscription.id if active_subscription else None
)
# Create a new subscription for the referred principal
referred_subscription_id = self.principal_subscription.id
is_referrer_subscribed = bool(active_subscription)
ReferralTracking.objects.create(
referral_record=referral_record,
referrer_subscription_id=referrer_subscription_id,
referred_subscription_id=referred_subscription_id,
is_referrer_subscribed=is_referrer_subscribed,
)
def credit_referral_reward_if_applicable(self):
referral_record = self._fetch_referral_record()
if referral_record:
active_subscription = self._check_active_subscription(
referral_record.referrer_principal
)
if active_subscription:
print("active_subscription: ", active_subscription)
if self.subscription:
print("self.subscription: ", self.subscription)
self._credit_reward(referral_record, self.subscription)
self._update_reward_status(referral_record, active_subscription)
class SubscriptionService:
def __init__(self):
self.principal_subscription = None
def create_principal_subscription(
self,
principal,
subscription,
stripe_subscription,
order_id,
current_period_start,
current_period_end,
coupon=None,
):
subscription_days = subscription.plan.days
today = timezone.now().date()
start_date = (
datetime.datetime.fromtimestamp(current_period_start).date()
if current_period_start
else today
)
end_date = (
datetime.datetime.fromtimestamp(current_period_end).date()
if current_period_end
else (today + timedelta(days=subscription_days))
)
principal_subscription = PrincipalSubscription.objects.create(
principal=principal,
subscription=subscription,
stripe_subscription_id=stripe_subscription if stripe_subscription else "Non Recurring",
is_paid=True,
is_stripe_subscription=True if stripe_subscription else False,
order_id=order_id,
start_date=start_date,
end_date=end_date,
grace_period_end_date=end_date + timedelta(days=15),
coupon_code=coupon.coupon_code if coupon else None,
)
if coupon:
coupon.no_of_redeems += 1
coupon.save()
print("Coupon Saved Successfully!!!")
self.principal_subscription = principal_subscription
return principal_subscription
def update_transaction_success(self, principal_transaction, principal_subscription):
principal_transaction.transaction_status = TransactionStatus.SUCCESS
principal_transaction.principal_subscription = principal_subscription
principal_transaction.save()
def update_transaction_failure(self, principal_transaction):
principal_transaction.transaction_status = TransactionStatus.FAIL
principal_transaction.save()
class PaymentProcessingService:
def __init__(self, webhook_data, stripe_subscription, current_period_start, current_period_end):
self.webhook_service = WebhookService(webhook_data)
self.notification_service = NotificationService()
self.current_period_start = current_period_start
self.current_period_end = current_period_end
# Retrieve objects
self.principal = self.webhook_service.get_principal()
self.transaction = self.webhook_service.get_transaction()
self.subscription = self.webhook_service.get_subscription()
self.stripe_subscription = stripe_subscription
self.order_id = self.webhook_service.get_order_id()
self.coupon = self.webhook_service.get_coupon()
self.subscription_service = SubscriptionService()
self.principal_subscription = None
def process_event(self):
if self.webhook_service.get_event_type() == "checkout.session.completed":
self.handle_success()
else:
self.handle_failure()
def handle_success(self):
with transaction.atomic():
# Create or update the principal subscription
self.principal_subscription = (
self.subscription_service.create_principal_subscription(
principal=self.principal,
subscription=self.subscription,
stripe_subscription=self.stripe_subscription,
order_id=self.order_id,
current_period_start=self.current_period_start,
current_period_end=self.current_period_end,
coupon=self.coupon,
)
)
print("First Part Done....!!!!!")
# Update transaction status to success
self.subscription_service.update_transaction_success(
self.transaction, self.principal_subscription
)
print("Second Part Done....!!!!!")
# Now handle referral rewards, if applicable
referral_service = ReferralRewardService(
self.principal, self.principal_subscription, self.subscription
)
print("Third Part Done...!!!!!!!!!!!")
referral_service.credit_referral_reward_if_applicable()
print("Fourth Part Done....!!!!!")
self.notification_service.payment_success_notification(
self.principal,
self.subscription,
self.principal_subscription,
self.transaction.amount,
)
def handle_failure(self):
self.subscription_service.update_transaction_failure(self.transaction)
# self.notification_service.payment_failed_notification(
# self.principal, self.subscription, self.transaction.amount
# )

View File

View File

@@ -0,0 +1,80 @@
from onesignal_sdk.client import Client as OneSignalClient
import logging
from manage_notifications.models import (
IAmPrincipalNotificationSettings,
InAppNotification,
NotificationCategoryChoices,
)
from django.shortcuts import get_object_or_404
from django.conf import settings
logger = logging.getLogger(__name__)
class NotificationService:
def __init__(self):
self.client = OneSignalClient(
app_id=settings.ONE_SIGNAL_APP_ID, rest_api_key=settings.ONE_SIGNAL_API_KEY
)
def send_notification(self, title, message, player_id):
if player_id is None:
print("Player ID is None, skipping notification")
return
notification_payload = {
"headings": {"en": title},
"contents": {"en": message},
"include_player_ids": [player_id],
}
response = self.client.send_notification(notification_payload)
return response
def save_notification(self, principal, title, message, notification_category):
InAppNotification.objects.create(
principal=principal,
title=title,
message=message,
notification_category=notification_category,
)
def payment_success_notification(
self, principal, subscription, principal_subscription, amount
):
print("payment_success_notification: ", principal.player_id)
title = "Payment Successful"
end_date = principal_subscription.end_date
message = f"Your payment for {subscription} of ${amount} was successfully processed. Your subscription is valid till {end_date}"
self.send_notification(title, message, principal.player_id)
self.save_notification(
principal, title, message, NotificationCategoryChoices.TRANSACTION
)
def referral_received_notification(self, principal, amount, email):
print("referral_received_notification: ", principal.player_id)
title = "Congratulations! You got a referral G-Token."
message = f"Your referral {email} has subscribed to GoodTimesApp. You have received {amount} (£)"
self.save_notification(
principal, title, message, NotificationCategoryChoices.REFERRAL
)
if not self.should_send_referral_notification(principal):
print("Referral notifications are disabled for this user")
return
self.send_notification(title, message, principal.player_id)
def payment_failed_notification(self, principal, subscription, amount):
print("payment_failed_notification: ", principal.player_id)
title = "Payment Failed!"
message = f"Your payment for {subscription} of ${amount} was failed."
self.send_notification(title, message, principal.player_id)
self.save_notification(
principal, title, message, NotificationCategoryChoices.TRANSACTION
)
def should_send_referral_notification(self, principal):
notification_settings = get_object_or_404(
IAmPrincipalNotificationSettings,
principal=principal,
notification_category=NotificationCategoryChoices.REFERRAL,
)
return notification_settings.is_enabled

View File

@@ -0,0 +1,117 @@
from django.db import transaction
from manage_wallets.models import (
PaymentMethod,
Transaction,
TransactionStatus,
TransactionType,
)
from .notification_service import NotificationService
from .referral_reward_service import ReferralRewardService
from .subscription_service import SubscriptionService
from .webhook_service import WebhookService
class PaymentProcessingService:
def __init__(
self,
webhook_data,
stripe_subscription,
current_period_start,
current_period_end,
):
self.webhook_service = WebhookService(webhook_data)
self.notification_service = NotificationService()
self.subscription_service = SubscriptionService()
self.stripe_subscription = stripe_subscription
self.current_period_start = current_period_start
self.current_period_end = current_period_end
self.principal_subscription = None
@property
def charge_data(self):
return self.webhook_service.charge_data
@property
def principal(self):
return self.webhook_service.get_principal()
@property
def subscription(self):
return self.webhook_service.get_subscription()
@property
def order_id(self):
return self.webhook_service.get_order_id()
@property
def coupon(self):
return self.webhook_service.get_coupon()
def create_transaction(self):
"""Create a transaction based on webhook data."""
transaction = Transaction.objects.create(
principal=self.principal,
principal_subscription=None,
transaction_type=TransactionType.PAYMENT,
payment_method=PaymentMethod.CARD,
transaction_status=TransactionStatus.INITIATE,
amount=self.subscription.amount,
order_id=self.order_id,
comment="Principal Subscription Initiated",
)
return transaction
def process_event(self, transactio):
event_type = self.webhook_service.event_type
if event_type == "checkout.session.completed":
self.handle_success(transactio)
elif event_type == "invoice.payment_succeeded":
if self.charge_data.get("billing_reason") != "subscription_create":
self.handle_success(transactio)
else:
self.handle_failure(transactio)
def handle_success(self, transactio):
with transaction.atomic():
# Create or update the principal subscription
self.principal_subscription = (
self.subscription_service.create_principal_subscription(
principal=self.principal,
subscription=self.subscription,
stripe_subscription=self.stripe_subscription,
order_id=self.order_id,
current_period_start=self.current_period_start,
current_period_end=self.current_period_end,
coupon=self.coupon,
)
)
print("First Part Done....!!!!!")
# Update transaction status to success
self.subscription_service.update_transaction_success(
transactio, self.principal_subscription
)
print("Second Part Done....!!!!!")
# Handle referral rewards
referral_service = ReferralRewardService(
self.principal, self.principal_subscription, self.subscription
)
print("Third Part Done...!!!!!!!!!!!")
referral_service.credit_referral_reward_if_applicable()
print("Fourth Part Done....!!!!!")
# Send payment success notification
self.notification_service.payment_success_notification(
self.principal,
self.subscription,
self.principal_subscription,
transactio.amount,
)
def handle_failure(self, transactio):
self.subscription_service.update_transaction_failure(transactio)
# self.notification_service.payment_failed_notification(
# self.principal, self.subscription, self.transaction.amount
# )

View File

@@ -0,0 +1,111 @@
from .notification_service import NotificationService
from manage_referrals.models import (
ReferralRecord,
ReferralRecordReward,
ReferralTracking,
)
from manage_wallets.models import Transaction, TransactionType, TransactionStatus
from django.utils import timezone
from manage_subscriptions.models import PrincipalSubscription
class ReferralRewardService:
def __init__(self, principal, principal_subscription, subscription):
self._notification_service = NotificationService()
self._principal = principal
self._principal_subscription = principal_subscription
self._subscription = subscription
@property
def principal(self):
return self._principal
@property
def principal_subscription(self):
return self._principal_subscription
@property
def subscription(self):
return self._subscription
@staticmethod
def _fetch_referral_record(principal):
"""Fetch the referral record for the given principal."""
return ReferralRecord.objects.filter(
referred_principal=principal,
is_completed=True,
active=True,
deleted=False,
).first()
@staticmethod
def _check_active_subscription(referrer_principal):
"""Check if the referrer principal has an active subscription."""
today = timezone.now().date()
return (
PrincipalSubscription.objects.filter(
principal=referrer_principal,
is_paid=True,
end_date__gte=today,
cancelled=False,
deleted=False,
)
.order_by("-end_date")
.first()
)
def _credit_reward(self, referral_record, subscription):
amount = subscription.referral_percentage * subscription.amount / 100
ReferralRecordReward.objects.create(
referral_record=referral_record,
subscription=subscription,
coins=1, # This value could be dynamically calculated or configured elsewhere
value=amount,
)
self._credit_transaction(referral_record.referrer_principal, amount)
self._notification_service.referral_received_notification(
referral_record.referrer_principal, amount, self.principal.email
)
def _credit_transaction(self, referrer_principal, amount):
"""Create a transaction record for the referral reward."""
print("referrer_principal: ", referrer_principal)
Transaction.objects.create(
principal=referrer_principal,
transaction_type=TransactionType.CREDIT,
payment_method="",
transaction_status=TransactionStatus.SUCCESS,
amount=amount,
coins=1,
comment="Referral reward",
)
def _update_reward_status(self, referral_record, active_subscription):
"""Update the status of the referral reward."""
referrer_subscription_id = (
active_subscription.id if active_subscription else None
)
# Create a new subscription for the referred principal
referred_subscription_id = self.principal_subscription.id
is_referrer_subscribed = bool(active_subscription)
ReferralTracking.objects.create(
referral_record=referral_record,
referrer_subscription_id=referrer_subscription_id,
referred_subscription_id=referred_subscription_id,
is_referrer_subscribed=is_referrer_subscribed,
)
def credit_referral_reward_if_applicable(self):
"""Credit referral reward if applicable based on the referral record."""
referral_record = self._fetch_referral_record(self.principal)
if referral_record:
active_subscription = self._check_active_subscription(
referral_record.referrer_principal
)
if active_subscription and self.subscription:
self._credit_reward(referral_record, self.subscription)
self._update_reward_status(referral_record, active_subscription)

View File

@@ -0,0 +1,94 @@
from datetime import timedelta
from django.utils import timezone
import datetime
from manage_subscriptions.models import PrincipalSubscription
from manage_wallets.models import TransactionStatus
class SubscriptionService:
def __init__(self):
self._principal_subscription = None
@property
def principal_subscription(self):
return self._principal_subscription
@principal_subscription.setter
def principal_subscription(self, value):
self._principal_subscription = value
def create_principal_subscription(
self,
principal,
subscription,
stripe_subscription,
order_id,
current_period_start,
current_period_end,
coupon=None,
):
"""Create a principal subscription and return it."""
start_date, end_date = self._calculate_dates(
current_period_start, current_period_end, subscription.plan.days
)
principal_subscription = PrincipalSubscription.objects.create(
principal=principal,
subscription=subscription,
stripe_subscription_id=stripe_subscription or "Non Recurring",
is_paid=True,
is_stripe_subscription=bool(stripe_subscription),
order_id=order_id,
start_date=start_date,
end_date=end_date,
grace_period_end_date=end_date + timedelta(days=15),
coupon_code=coupon.coupon_code if coupon else None,
)
if coupon:
self._update_coupon(coupon)
self.principal_subscription = principal_subscription
return principal_subscription
def update_transaction_success(self, principal_transaction, principal_subscription):
"""Update transaction status to success and associate with a subscription."""
self._update_transaction_status(
principal_transaction, TransactionStatus.SUCCESS, principal_subscription
)
def update_transaction_failure(self, principal_transaction):
"""Update transaction status to failure."""
self._update_transaction_status(principal_transaction, TransactionStatus.FAIL)
def _calculate_dates(
self, current_period_start, current_period_end, subscription_days
):
"""Calculate subscription start and end dates."""
today = timezone.now().date()
start_date = (
datetime.datetime.fromtimestamp(current_period_start).date()
if current_period_start
else today
)
end_date = (
datetime.datetime.fromtimestamp(current_period_end).date()
if current_period_end
else (today + timedelta(days=subscription_days))
)
return start_date, end_date
def _update_coupon(self, coupon):
"""Update coupon usage count."""
coupon.no_of_redeems += 1
coupon.save()
print("Coupon Saved Successfully!!!")
def _update_transaction_status(
self, transaction, status, principal_subscription=None
):
"""Update the transaction status and associate with a subscription if provided."""
transaction.transaction_status = status
if principal_subscription:
transaction.principal_subscription = principal_subscription
transaction.save()

View File

@@ -0,0 +1,77 @@
from django.conf import settings
import stripe
from django.core.exceptions import ObjectDoesNotExist
from accounts.models import IAmPrincipal
from manage_coupons.models import Coupon
from manage_subscriptions.models import Subscription
import logging
logger = logging.getLogger(__name__)
stripe.api_key = settings.STRIPE_SECRET_KEY
class WebhookService:
def __init__(self, webhook_data):
self._webhook_data = webhook_data
self._event_type = webhook_data["type"]
self._charge_data = webhook_data["data"]["object"]
self._metadata = self._fetch_metadata()
def _fetch_metadata(self):
"""Fetch metadata based on the event type."""
if self._event_type == "checkout.session.completed":
return self._charge_data.get("metadata", {})
elif self._event_type == "invoice.payment_succeeded":
subscription_id = self._charge_data.get("subscription")
if subscription_id:
subscription = stripe.Subscription.retrieve(subscription_id)
return subscription.get("metadata", {})
return {}
@property
def event_type(self):
return self._event_type
@property
def charge_data(self):
return self._charge_data
def _get_object_from_metadata(self, model, id_key):
"""Retrieve object from metadata."""
obj_id = self._metadata.get(id_key)
if obj_id:
try:
return model.objects.get(id=int(obj_id))
except (ObjectDoesNotExist, ValueError) as e:
logger.error(f"Invalid {model.__name__} ID: {obj_id}")
raise ValueError(f"Invalid {model.__name__} ID: {obj_id}") from e
return None
def get_event_type(self):
return self.event_type
def get_principal(self):
"""Retrieve principal from metadata."""
return self._get_object_from_metadata(IAmPrincipal, "principal")
def get_subscription(self):
"""Retrieve subscription from metadata."""
return self._get_object_from_metadata(Subscription, "subscription_id")
def get_order_id(self):
"""Retrieve order ID from metadata."""
return self._metadata.get("order_id")
def get_coupon(self):
"""Retrieve coupon from metadata."""
coupon_code = self._metadata.get("couponCode")
print("get_coupon:coupon_code: ", coupon_code)
if coupon_code:
try:
return Coupon.objects.get(coupon_code=coupon_code)
except Coupon.DoesNotExist:
logger.error(f"Invalid coupon code: {coupon_code}")
raise ValueError(f"Invalid coupon code: {coupon_code}")
return None

View File

@@ -7,9 +7,7 @@ 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 goodtimes import constants
from manage_subscriptions.models import (
Subscription,
PrincipalSubscription,
@@ -35,7 +33,11 @@ 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
from goodtimes.webhook import PaymentProcessingService
from goodtimes.webhook.payment_processing_service import PaymentProcessingService
import logging
logger = logging.getLogger(__name__)
class CreatePrincipalSubscriptionApi(APIView):
@@ -175,25 +177,32 @@ class StripeWebhookTest(APIView):
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 = stripe.Webhook.construct_event(payload, sig_header, endpoint_secret)
event_id = event["id"]
event_type = event["type"]
# principal_id = event["data"]["object"]["metadata"]["principal"]
stripe_subscription_id = event["data"]["object"].get("subscription")
if stripe_subscription_id:
stripe_subscription = stripe.Subscription.retrieve(stripe_subscription_id)
current_period_start = stripe_subscription["current_period_start"]
current_period_end = stripe_subscription["current_period_end"]
else:
current_period_start = None
current_period_end = None
stripe_subscription = (
stripe.Subscription.retrieve(stripe_subscription_id)
if stripe_subscription_id
else None
)
current_period_start = (
stripe_subscription["current_period_start"]
if stripe_subscription
else None
)
current_period_end = (
stripe_subscription["current_period_end"]
if stripe_subscription
else None
)
webhook_event, created = WebhookEvent.objects.get_or_create(
event_id=event_id,
defaults={
"event_type": event_type,
"event_payload": json.loads(payload),
"event_payload": event,
},
)
@@ -209,53 +218,59 @@ class StripeWebhookTest(APIView):
current_period_start=current_period_start,
current_period_end=current_period_end,
)
payment_service.process_event()
webhook_event = WebhookEvent.objects.get(event_id=event_id)
transaction = payment_service.create_transaction()
try:
payment_service.process_event(transaction)
transaction.transaction_status = TransactionStatus.SUCCESS
except Exception as e:
transaction.transaction_status = TransactionStatus.FAIL
transaction.error_message = str(e)
logger.error(f"Transaction Error: {str(e)}")
raise e
finally:
transaction.save()
webhook_event.status = "processed"
webhook_event.processed_at = timezone.now() # Make sure to import timezone
webhook_event.processed_at = timezone.now()
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
logger.error(f"Invalid Stripe signature: {str(e)}")
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
except ValueError as e:
logger.error(f"Invalid payload: {str(e)}")
return ApiResponse.error(
status=status.HTTP_404_NOT_FOUND, message="Transaction not found"
status=status.HTTP_400_BAD_REQUEST,
message="Invalid payload",
errors=str(e),
)
except Transaction.DoesNotExist as e:
logger.error(f"Transaction does not exist: {str(e)}")
return ApiResponse.error(
status=status.HTTP_404_NOT_FOUND,
message="Transaction not found",
errors=str(e),
)
except Exception as e:
webhook_event.status = "failed"
webhook_event.error_message = str(e)
webhook_event.save()
logger.error(f"Error processing webhook event: {str(e)}")
if "webhook_event" in locals():
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]

View File

@@ -727,8 +727,7 @@ def create_checkout_session(request):
"principal": str(request.user.id),
"order_id": order_id,
"subscription_id": str(subscription.id),
"subscription": str(subscription.id),
"transaction_id": "",
"product_id": str(subscription.stripe_product.product_id if subscription.stripe_product else None),
"couponCode": coupon_code if coupon_code else None,
},
}
@@ -745,21 +744,6 @@ def create_checkout_session(request):
except stripe.error.StripeError as e:
return JsonResponse({"error": f"Stripe error: {str(e)}"}, status=400)
# Create a Transaction object with status INITIATE
transaction = Transaction.objects.create(
principal=request.user,
principal_subscription=None, # Subscription not created yet
transaction_type=TransactionType.PAYMENT,
payment_method=PaymentMethod.CARD,
transaction_status=TransactionStatus.INITIATE,
amount=final_amount,
order_id=order_id,
comment="Principal Subscription Initiated",
)
# Updating transaction_id in session_data metadata
session_data["metadata"]["transaction_id"] = str(transaction.id)
# Creating the Stripe Checkout Session
try:
if subscription.price_id:
@@ -777,7 +761,7 @@ def create_checkout_session(request):
session_data["line_items"] = [
{
"price_data": {
"currency": "usd",
"currency": "gbp",
"product_data": {
"name": subscription.title,
"description": subscription.short_description,