webhook separate file

This commit is contained in:
rizwanisready
2024-05-04 23:22:17 +05:30
parent 4cf2a9ebc4
commit d2f2400e35
4 changed files with 272 additions and 4 deletions

View File

@@ -227,7 +227,9 @@ class PaymentProcessingService:
return None
def _get_subscription(self):
logger.debug("subscription_id: ", self.charge_data["metadata"]["subscription_id"])
logger.debug(
"subscription_id: ", self.charge_data["metadata"]["subscription_id"]
)
subscription_id = self.charge_data["metadata"]["subscription_id"]
if subscription_id:
try:
@@ -257,7 +259,9 @@ class PaymentProcessingService:
self.principal_subscription = principal_subscription
return principal_subscription
except Subscription.DoesNotExist:
logger.error("SOmething Went Wrong inside _create_principal_subscription().")
logger.error(
"SOmething Went Wrong inside _create_principal_subscription()."
)
return None

261
goodtimes/webhook.py Normal file
View File

@@ -0,0 +1,261 @@
from django.conf import settings
from django.db import transaction
import requests
from datetime import timedelta
from django.utils import timezone
from onesignal_sdk.client import Client as OneSignalClient
from accounts.models import IAmPrincipal, IAmPrincipalOtp, IAmPrincipalType
from manage_referrals.models import (
GoodTimeCoins,
ReferralRecord,
ReferralRecordReward,
ReferralTracking,
)
from django.core.exceptions import ObjectDoesNotExist
from manage_subscriptions.models import PrincipalSubscription, Subscription
from manage_wallets.models import (
TransactionStatus,
TransactionType,
Wallet,
Transaction,
)
import logging
logger = logging.getLogger(__name__)
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.select_related("type").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.select_related("principal_subscription").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"]
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):
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
ReferralTracking.objects.create(
referral_record=referral_record,
referrer_subscription_id=referrer_subscription_id,
referred_subscription_id=referred_subscription_id,
is_referrer_subscribed=active_subscription,
)
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:
if self.subscription:
self._credit_reward(referral_record, self.subscription)
self._update_reward_status(referral_record, active_subscription)
else:
self._update_reward_status(referral_record, None)
class SubscriptionService:
def __init__(self):
self.principal_subscription = None
def create_principal_subscription(self, principal, subscription, order_id):
subscription_days = subscription.plan.days
today = timezone.now().date()
last_date = today + timedelta(days=subscription_days)
principal_subscription = PrincipalSubscription.objects.create(
principal=principal,
subscription=subscription,
is_paid=True,
order_id=order_id,
start_date=today,
end_date=last_date,
grace_period_end_date=last_date + timedelta(days=15),
)
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):
self.webhook_service = WebhookService(webhook_data)
self.subscription_service = SubscriptionService()
self.notification_service = NotificationService()
# Retrieve objects
self.principal = self.webhook_service.get_principal_id()
self.transaction = self.webhook_service.get_transaction_id()
self.subscription = self.webhook_service.get_subscription_id()
self.order_id = self.webhook_service.get_order_id()
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(
self.principal, self.subscription, self.order_id
)
)
# Update transaction status to success
self.subscription_service.update_transaction_success(
self.transaction, self.principal_subscription
)
# Now handle referral rewards, if applicable
if self.principal_subscription:
referral_service = ReferralRewardService(
self.principal, self.principal_subscription, self.subscription
)
referral_service.credit_referral_reward_if_applicable()
self.notification_service.payment_success_notification(
self.principal, self.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
)
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):
notification_payload = {
"headings": {"en": title},
"contents": {"en": message},
"include_player_ids": player_id,
}
response = self.client.send_notification(notification_payload)
return response
def payment_success_notification(self, principal, subscription, amount):
title = "Payment Successful"
message = f"Your payment for {subscription} of ${amount} was successfully processed. Your subscription is valid till {subscription.end_date}"
self.send_notification(title, message, principal.player_id)
def referral_received_notification(self, principal, amount, email):
title = "Congratulations! You got a referral G-Token."
message = f"Your referral {email} has subscribed to GoodTimesApp. You have received {amount} (£)"
self.send_notification(title, message, principal.player_id)
def payment_failed_notification(self, principal, subscription, amount):
title = "Payment Failed!"
message = f"Your payment for {subscription} of ${amount} was failed."
self.send_notification(title, message, principal.player_id)

View File

@@ -3,7 +3,8 @@ import requests
from django.db.models import Q
from onesignal_sdk.client import Client as OneSignalClient
from django.conf import settings
from .models import IAmPrincipalNotificationSettings, IAmPrincipal, PrincipalType
from accounts.models import IAmPrincipal
from .models import IAmPrincipalNotificationSettings, PrincipalType
import logging
logger = logging.getLogger(__name__)

View File

@@ -35,6 +35,7 @@ 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
class CreatePrincipalSubscriptionApi(APIView):
@@ -200,7 +201,8 @@ class StripeWebhookTest(APIView):
message="Active principal subscription already exists",
)
payment_service = services.PaymentProcessingService(webhook_data=event)
# payment_service = services.PaymentProcessingService(webhook_data=event)
payment_service = PaymentProcessingService(webhook_data=event)
payment_service.process_event()
webhook_event = WebhookEvent.objects.get(event_id=event_id)
webhook_event.status = "processed"