From 92a8b57edefb3e92cd6bb80296b83ddbd3ae11ca Mon Sep 17 00:00:00 2001 From: Jhony Lucas Date: Sun, 4 Aug 2024 16:45:24 -0300 Subject: [PATCH] fix: change stripe webhooks logic. --- backend/apps/account/models.py | 6 ++++ backend/apps/account/signals.py | 32 ++++++++++++++++++ backend/apps/account_payment/graphql.py | 4 +-- backend/apps/account_payment/webhooks.py | 43 +++++++++++++++++++++--- 4 files changed, 78 insertions(+), 7 deletions(-) diff --git a/backend/apps/account/models.py b/backend/apps/account/models.py index 40c09540..5a4b63bc 100644 --- a/backend/apps/account/models.py +++ b/backend/apps/account/models.py @@ -549,6 +549,12 @@ def stripe_subscription_created_at(self): def is_pro(self): return "bd_pro" in self.subscription.plan.product.metadata.get("code", "") + @property + def canceled_at(self): + if self.subscription: + return self.subscription.canceled_at + return None + def split_password(password: str) -> Tuple[str, str, str, str]: """Split a password into four parts: algorithm, iterations, salt, and hash""" diff --git a/backend/apps/account/signals.py b/backend/apps/account/signals.py index 79e1f775..a3d889a7 100644 --- a/backend/apps/account/signals.py +++ b/backend/apps/account/signals.py @@ -3,14 +3,17 @@ from django.conf import settings from django.core.mail import EmailMultiAlternatives +from django.db.models import Q from django.db.models.signals import post_save from django.dispatch import receiver from django.template.loader import render_to_string from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_encode +from djstripe.models import Customer as DJStripeCustomer from backend.apps.account.models import Account, Subscription from backend.apps.account.token import token_generator +from backend.apps.account_payment.webhooks import add_user from backend.custom.environment import get_frontend_url, is_prd @@ -38,6 +41,30 @@ def send_activation_email(account: Account): msg.send() +def create_subscription(user: Account): + """ + Create an internal subscription if the email has a Stripe subscription. + """ + customer = DJStripeCustomer.objects.filter(email=user.email).first() + stripe_subscription = None + + if customer: + stripe_subscription = customer.subscriptions.filter( + Q(status="active") | Q(status="trialing") + ).first() + + if stripe_subscription: + Subscription.objects.create( + admin=user, + subscription=stripe_subscription, + ) + + customer.subscriber = user + customer.save() + # Add user to Google Group + add_user(user.email) + + @receiver(post_save, sender=Account) def send_activation_email_signal(sender, instance, created, raw, **kwargs): """Send activation email to instance after registration @@ -51,6 +78,11 @@ def send_activation_email_signal(sender, instance, created, raw, **kwargs): if created and not raw and not instance.is_active and is_prd(): send_activation_email(instance) + # Check if the account has an active subscription in Stripe + # If it does, create an internal subscription + if created: + create_subscription(instance) + def send_welcome_email(account: Account): """Send welcome email to account""" diff --git a/backend/apps/account_payment/graphql.py b/backend/apps/account_payment/graphql.py index 7a496e94..4ff1db21 100644 --- a/backend/apps/account_payment/graphql.py +++ b/backend/apps/account_payment/graphql.py @@ -231,8 +231,8 @@ class Arguments: def mutate(cls, root, info, subscription_id): try: subscription = Subscription.objects.get(id=subscription_id) - subscription = subscription.subscription - subscription = subscription.cancel() + stripe_subscription = subscription.subscription + stripe_subscription.cancel(at_period_end=True) return None except Exception as e: logger.error(e) diff --git a/backend/apps/account_payment/webhooks.py b/backend/apps/account_payment/webhooks.py index 51494921..4ea7c037 100644 --- a/backend/apps/account_payment/webhooks.py +++ b/backend/apps/account_payment/webhooks.py @@ -18,9 +18,11 @@ def get_subscription(event: Event) -> Subscription: """Get internal subscription model, mirror of stripe""" logger.info(f"Procurando inscrição interna do cliente {event.customer.email}") subscription = DJStripeSubscription.objects.get(id=event.data["object"]["id"]) - if hasattr(subscription, "internal_subscription"): + internal_subscription = Subscription.objects.filter(subscription=subscription).first() + + if internal_subscription: logger.info(f"Retornando inscrição interna do cliente {event.customer.email}") - return subscription.internal_subscription + return internal_subscription else: if event.customer.subscriber: logger.info(f"Criando inscrição interna do cliente {event.customer.email}") @@ -118,12 +120,22 @@ def update_customer(event: Event, **kwargs): @webhooks.handler("customer.subscription.updated") def subscribe(event: Event, **kwargs): """Add customer to allowed google groups""" + subscription = get_subscription(event) + if event.data["object"]["status"] in ["trialing", "active"]: - if subscription := get_subscription(event): + if subscription: logger.info(f"Adicionando a inscrição do cliente {event.customer.email}") - add_user(event.customer.email) subscription.is_active = True subscription.save() + # Add user to google group if subscription exists or not + add_user(event.customer.email) + else: + if subscription: + logger.info(f"Removendo a inscrição do cliente {event.customer.email}") + subscription.is_active = False + subscription.save() + # Remove user from google group if subscription exists or not + remove_user(event.customer.email) @webhooks.handler("customer.subscription.deleted") @@ -131,9 +143,30 @@ def unsubscribe(event: Event, **kwargs): """Remove customer from allowed google groups""" if subscription := get_subscription(event): logger.info(f"Removendo a inscrição do cliente {event.customer.email}") - remove_user(event.customer.email) subscription.is_active = False subscription.save() + # Remove user from google group if subscription exists or not + remove_user(event.customer.email) + + +@webhooks.handler("customer.subscription.paused") +def pause_subscription(event: Event, **kwargs): + """Pause customer subscription""" + if subscription := get_subscription(event): + logger.info(f"Pausando a inscrição do cliente {event.customer.email}") + subscription.is_active = False + subscription.save() + remove_user(event.customer.email) + + +@webhooks.handler("customer.subscription.resumed") +def resume_subscription(event: Event, **kwargs): + """Resume customer subscription""" + if subscription := get_subscription(event): + logger.info(f"Resumindo a inscrição do cliente {event.customer.email}") + subscription.is_active = True + subscription.save() + add_user(event.customer.email) # Reference