From 6e5150bc851844da759db436d6293ff959308ef8 Mon Sep 17 00:00:00 2001 From: Jan Baykara Date: Tue, 4 Oct 2022 17:48:22 +0100 Subject: [PATCH 1/5] Log shopify webhook routes --- app/signals.py | 6 ++++++ app/urls.py | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/app/signals.py b/app/signals.py index b4738f17..77d92c45 100644 --- a/app/signals.py +++ b/app/signals.py @@ -61,6 +61,8 @@ def cancel_gift_recipient_subscription(event, **kwargs): def sync(*args, data: shopify.Product, **kwargs): from app.models.wagtail import BaseShopifyProductPage + print("products_updated", data) + product_id = data.get("id") print("Product", product_id, "was updated") BookPage.sync_from_shopify_product_id(product_id) @@ -70,6 +72,8 @@ def sync(*args, data: shopify.Product, **kwargs): def sync(*args, data: shopify.Product, **kwargs): from app.models.wagtail import BaseShopifyProductPage + print("products_create", data) + product_id = data.get("id") print("Product", product_id, "was created") BookPage.sync_from_shopify_product_id(product_id) @@ -79,6 +83,8 @@ def sync(*args, data: shopify.Product, **kwargs): def sync(*args, data: shopify.Product, **kwargs): from app.models.wagtail import BaseShopifyProductPage + print("products_delete", data) + product_id = data.get("id") print("Product", product_id, "was deleted") BookPage.objects.filter(shopify_product_id=product_id).delete() diff --git a/app/urls.py b/app/urls.py index 102be747..474ba073 100644 --- a/app/urls.py +++ b/app/urls.py @@ -1,9 +1,13 @@ +import logging + from django.conf import settings from django.conf.urls.static import static from django.contrib import admin from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.templatetags.static import static as get_static_path from django.urls import include, path, re_path +from django.utils.decorators import method_decorator +from django.views.decorators.csrf import csrf_exempt from django.views.generic import TemplateView from django.views.generic.base import RedirectView from shopify_webhook.views import WebhookView @@ -32,6 +36,16 @@ # from wagtail_transfer import urls as wagtailtransfer_urls +class ModifiedWebhookView(WebhookView): + @method_decorator(csrf_exempt) + def post(self, request, *args, **kwargs): + logging.debug("Shopify request", request) + logging.debug( + [request.webhook_domain, request.webhook_topic, request.webhook_data] + ) + return super().post(request, *args, **kwargs) + + urlpatterns = [ path("oauth/", include("oauth2_provider.urls", namespace="oauth2_provider")), path("django/", admin.site.urls), @@ -116,7 +130,7 @@ path("accounts/", include("allauth.urls")), path("stripe/", include("djstripe.urls", namespace="djstripe")), path("customer_portal/", StripeCustomerPortalView.as_view(), name="customerportal"), - path("shopify/webhook/", WebhookView.as_view(), name="shopify_webhook"), + path("shopify/webhook/", ModifiedWebhookView.as_view(), name="shopify_webhook"), path( ShippingCostView.url_pattern, ShippingCostView.as_view(), name="shippingcosts" ), From fabf4e1db51409d8a7100b8f54e9d8d5ffbfec61 Mon Sep 17 00:00:00 2001 From: Jan Baykara Date: Tue, 4 Oct 2022 18:04:56 +0100 Subject: [PATCH 2/5] Use unbanned URL for shopify webhooks --- app/urls.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/app/urls.py b/app/urls.py index 474ba073..4456032f 100644 --- a/app/urls.py +++ b/app/urls.py @@ -33,19 +33,6 @@ SubscriptionCheckoutView, ) -# from wagtail_transfer import urls as wagtailtransfer_urls - - -class ModifiedWebhookView(WebhookView): - @method_decorator(csrf_exempt) - def post(self, request, *args, **kwargs): - logging.debug("Shopify request", request) - logging.debug( - [request.webhook_domain, request.webhook_topic, request.webhook_data] - ) - return super().post(request, *args, **kwargs) - - urlpatterns = [ path("oauth/", include("oauth2_provider.urls", namespace="oauth2_provider")), path("django/", admin.site.urls), @@ -130,7 +117,7 @@ def post(self, request, *args, **kwargs): path("accounts/", include("allauth.urls")), path("stripe/", include("djstripe.urls", namespace="djstripe")), path("customer_portal/", StripeCustomerPortalView.as_view(), name="customerportal"), - path("shopify/webhook/", ModifiedWebhookView.as_view(), name="shopify_webhook"), + path("shopify/webhooks/", WebhookView.as_view(), name="shopify_webhook"), path( ShippingCostView.url_pattern, ShippingCostView.as_view(), name="shippingcosts" ), From 32af6a09dba18c094e962ef066f0e5d4ce0fe46f Mon Sep 17 00:00:00 2001 From: Jan Baykara Date: Tue, 4 Oct 2022 18:20:29 +0100 Subject: [PATCH 3/5] Use variable URL for shopify webhooks --- app/settings/base.py | 1 + app/urls.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/settings/base.py b/app/settings/base.py index 7d4af49b..a646e3e1 100644 --- a/app/settings/base.py +++ b/app/settings/base.py @@ -304,6 +304,7 @@ SHOPIFY_COLLECTION_ID = os.environ.get("SHOPIFY_COLLECTION_ID", "402936398057") SHOPIFY_PRIVATE_APP_PASSWORD = os.environ.get("SHOPIFY_PRIVATE_APP_PASSWORD", None) SHOPIFY_APP_API_SECRET = os.environ.get("SHOPIFY_APP_API_SECRET", "") +SHOPIFY_WEBHOOK_PATH = os.environ.get("SHOPIFY_WEBHOOK_PATH", "shopify/webhooks/") # CSP X_FRAME_OPTIONS = "SAMEORIGIN" diff --git a/app/urls.py b/app/urls.py index 4456032f..711e3e87 100644 --- a/app/urls.py +++ b/app/urls.py @@ -117,7 +117,7 @@ path("accounts/", include("allauth.urls")), path("stripe/", include("djstripe.urls", namespace="djstripe")), path("customer_portal/", StripeCustomerPortalView.as_view(), name="customerportal"), - path("shopify/webhooks/", WebhookView.as_view(), name="shopify_webhook"), + path(settings.SHOPIFY_WEBHOOK_PATH, WebhookView.as_view(), name="shopify_webhook"), path( ShippingCostView.url_pattern, ShippingCostView.as_view(), name="shippingcosts" ), From c3d12e756d18f5c2adc529cb933b503b96184db1 Mon Sep 17 00:00:00 2001 From: Jan Baykara Date: Tue, 4 Oct 2022 18:22:08 +0100 Subject: [PATCH 4/5] Default to UK timezone and display timezone of time, closes #361 --- app/templates/app/includes/event_card.html | 6 +++--- app/templates/base.html | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/templates/app/includes/event_card.html b/app/templates/app/includes/event_card.html index a22fdc7a..50df318f 100644 --- a/app/templates/app/includes/event_card.html +++ b/app/templates/app/includes/event_card.html @@ -1,4 +1,4 @@ -{% load menu_tags humanize brand groundwork_geo wagtailsettings_tags account setting django_bootstrap5 wagtailcore_tags static wagtailroutablepage_tags django_bootstrap5 setting %} +{% load tz menu_tags humanize brand groundwork_geo wagtailsettings_tags account setting django_bootstrap5 wagtailcore_tags static wagtailroutablepage_tags django_bootstrap5 setting %}
  • {{ event.name }}
    {{ event.location_type|replace:"_| " }} · - Starts at {{event.starts_at|date:"P"}} + Starts at {{event.starts_at|date:"P T"}} · {{event.starts_at|naturaltime}}
    @@ -41,4 +41,4 @@

    {{ event.name }}

    {% endif %} -
  • \ No newline at end of file + diff --git a/app/templates/base.html b/app/templates/base.html index c3a51a56..c9cf7c04 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -1,5 +1,6 @@ -{% load wagtailuserbar django_vite menu_tags setting %} +{% load wagtailuserbar django_vite menu_tags setting tz %} +{% timezone "Europe/London" %} @@ -73,3 +74,4 @@ {% block bottom_of_page %}{% endblock %} +{% endtimezone %} From fb793ce4cf28d85f77361445f7cd3265e70973a6 Mon Sep 17 00:00:00 2001 From: Jan Baykara Date: Mon, 17 Oct 2022 18:43:37 +0100 Subject: [PATCH 5/5] Revive deleted changes --- app/forms.py | 10 ++-- app/models/django.py | 21 ++++---- app/models/stripe.py | 29 ++++++++--- app/templates/account/cancel.html | 46 +++++++++++++--- app/templates/account/login.html | 9 +++- app/templates/account/membership.html | 18 ++++++- app/templates/account/signup.html | 5 +- .../app/blocks/your_books_grid_block.html | 2 +- app/templates/app/frames/shipping_cost.html | 2 +- .../app/includes/membership_card.html | 4 +- app/templates/base.html | 3 +- app/templatetags/setting.py | 18 +++++++ app/views.py | 52 ++++++++++--------- 13 files changed, 156 insertions(+), 63 deletions(-) diff --git a/app/forms.py b/app/forms.py index 2f02dece..d5531780 100644 --- a/app/forms.py +++ b/app/forms.py @@ -20,9 +20,13 @@ class MemberSignupForm(SignupForm): first_name = forms.CharField(max_length=150) last_name = forms.CharField(max_length=150) gdpr_email_consent = forms.BooleanField( - required=False, - label="Can we email you with news and updates from the Left Book Club?", + required=True, + label="LBC can email me about my books and membership (required)", ) + # promotional_consent = forms.BooleanField( + # required=False, + # label="LBC can email me about special offers and promotions", + # ) field_order = [ "email", @@ -32,7 +36,7 @@ class MemberSignupForm(SignupForm): "password1", # "password2", # ignored when not present "gdpr_email_consent", - "terms_and_conditions", + # "promotional_consent", ] def save(self, request): diff --git a/app/models/django.py b/app/models/django.py index 857a8041..3f8d3abf 100644 --- a/app/models/django.py +++ b/app/models/django.py @@ -1,5 +1,3 @@ -import json - import djstripe import stripe from allauth.account.models import EmailAddress @@ -17,7 +15,7 @@ subscription_with_promocode, ) -from .stripe import LBCProduct +from .stripe import LBCProduct, LBCSubscription def custom_user_casual_name(user: AbstractUser) -> str: @@ -94,10 +92,11 @@ def stripe_customer_id(self) -> str: ] @property - def active_subscription(self) -> djstripe.models.Subscription: + def active_subscription(self) -> LBCSubscription: try: sub = ( - self.stripe_customer.subscriptions.filter( + LBCSubscription.objects.filter( + customer=self.stripe_customer, # Was started + wasn't cancelled status__in=self.valid_subscription_statuses, # Is in period @@ -113,7 +112,7 @@ def active_subscription(self) -> djstripe.models.Subscription: return None @property - def old_subscription(self) -> djstripe.models.Subscription: + def old_subscription(self) -> LBCSubscription: try: sub = ( self.stripe_customer.subscriptions.filter( @@ -140,6 +139,10 @@ def has_overdue_payment(self): == djstripe.enums.SubscriptionStatus.past_due ) + @property + def is_cancelling_member(self): + return self.is_member and self.active_subscription.cancel_at is not None + @property def is_expired_member(self): return not self.is_member and self.old_subscription is not None @@ -161,7 +164,7 @@ def primary_product(self) -> LBCProduct: try: if self.active_subscription is not None: product = get_primary_product_for_djstripe_subscription( - self.active_subscription + self.active_subscription.lbc ) return product except: @@ -190,9 +193,7 @@ def gifts_bought(self): @property def gift_giver(self): try: - gift_giver_subscription = self.active_subscription.gift_giver_subscription - sub = djstripe.models.Subscription.objects.get(id=gift_giver_subscription) - user = sub.customer.subscriber + user = self.active_subscription.gift_giver_subscription.customer.subscriber return user except: return None diff --git a/app/models/stripe.py b/app/models/stripe.py index e731b708..ae80e0d3 100644 --- a/app/models/stripe.py +++ b/app/models/stripe.py @@ -45,9 +45,29 @@ def primary_product_id(self): def customer_id(self): return self.customer.id + @property + def gift_giver_subscription(self): + """ + If this subscription was created as a result of a neighbouring gift subscription + """ + related_subscription_id = self.metadata.get("gift_giver_subscription", None) + if related_subscription_id: + return LBCSubscription.objects.filter(id=related_subscription_id).first() + + @property + def gift_recipient_subscription(self): + """ + If this subscription was created as a result of a neighbouring gift subscription + """ + related_subscription_id = self.metadata.get("gift_recipient_subscription", None) + if related_subscription_id: + return LBCSubscription.objects.filter(id=related_subscription_id).first() + + @property def is_gift_giver(self): self.metadata.get("gift_mode", None) is not None + @property def is_gift_receiver(self): self.metadata.get("gift_giver_subscription", None) is not None @@ -143,14 +163,6 @@ def get_prices_for_country(self, iso_a2: str, **kwargs): product=self.id, active=True, metadata__shipping=zone.code, **kwargs ).order_by("unit_amount") - def gift_giver_subscription(self): - """ - If this subscription was created as a result of a neighbouring gift subscription - """ - related_subscription_id = self.metadata.get("gift_giver_subscription", None) - if related_subscription_id: - return djstripe.models.Subscription.get(id=related_subscription_id) - @property def book_types(self): book_types = self.metadata.get("book_types", None) @@ -159,6 +171,7 @@ def book_types(self): return book_types return list() + @property def current_book(self): from app.models.wagtail import BookPage diff --git a/app/templates/account/cancel.html b/app/templates/account/cancel.html index efc9da01..911f1119 100644 --- a/app/templates/account/cancel.html +++ b/app/templates/account/cancel.html @@ -5,20 +5,51 @@ {% block account_content %}
    {% if subscription and subscription.cancel_at %} -

    This subscription has been cancelled

    + {% comment %} Cancelling a cancelled subscription {% endcomment %} +

    Your subscription has been cancelled

    Membership will expire on {{subscription.cancel_at}}

    - {% elif gift_mode %} - {% comment %} Cancelling a gift plan {% endcomment %} + {% elif subscription.gift_recipient_subscription %} + {% comment %} Cancelling a gift giver subscription {% endcomment %}

    Thinking of cancelling this gift card?

    - You'll no longer be billed by LBC. The gift membership that was redeemed - {% if gift_recipient_subscription %} by {{ gift_recipient_subscription.customer.name }} {% endif %} - will end on {{ subscription.current_period_end }}. + {% if subscription.gift_recipient_subscription %} + This gift card was redeemed by {{ subscription.gift_recipient_subscription.customer.subscriber }}. + If you cancel, they'll stop receiving books on {{ subscription.current_period_end }}. + {% else %} + This gift card was never redeemed. + {% endif %} + You'll no longer be billed by LBC.

    {% csrf_token %} {% bootstrap_button button_class='btn-outline-danger' content="I really want to cancel" %}
    + {% elif subscription.gift_giver_subscription %} + {% comment %} Cancelling a gift recipient subscription {% endcomment %} +

    Thinking of cancelling your gifted membership?

    +

    + Your membership is being paid for by {{ user.gift_giver }}. If you cancel, they'll no longer pay your membership fee and your membership will will end on {{ subscription.current_period_end }}. +

    +
    + {% include "app/includes/membership_card.html" %} +
    + {% get_books since=user.active_subscription.created types=user.primary_product.book_types as books %} + {% if books|length > 0 %} +
    +
    +

    Books we've read together

    +
    +
    + {% for book in books %} + {% include "app/includes/simple_book_card.html" with book=book class='col-6 col-sm-4 col-lg-3 col-xl-2' %} + {% endfor %} +
    +
    + {% endif %} +
    + {% csrf_token %} + {% bootstrap_button button_class='btn-outline-danger' content="I really want to cancel" %} +
    {% elif request.user.is_member %} {% comment %} Cancelling your own plan {% endcomment %}

    Thinking of cancelling?

    @@ -33,7 +64,7 @@

    Books we've read together

    {% for book in books %} - {% include "app/includes/simple_book_card.html" with book=book class='col-12 col-md-6' %} + {% include "app/includes/simple_book_card.html" with book=book class='col-6 col-sm-4 col-lg-3 col-xl-2' %} {% endfor %}
    @@ -45,6 +76,7 @@

    Books we've read together

    {% bootstrap_button button_class='btn-outline-danger' content="Cancel" %} {% else %} + {% comment %} Cancelling a non-subscription {% endcomment %}

    You're not a member at the moment.

    diff --git a/app/templates/account/login.html b/app/templates/account/login.html index 9c43b37c..5a3fedc1 100644 --- a/app/templates/account/login.html +++ b/app/templates/account/login.html @@ -1,6 +1,6 @@ {% extends "account/modal_base.html" %} -{% load url i18n django_bootstrap5 account socialaccount %} +{% load url i18n django_bootstrap5 account socialaccount setting %} {% block head_title %}{% trans "Sign In" %}{% endblock %} @@ -8,7 +8,12 @@ {% block modal_content %} {% get_providers as socialaccount_providers %} -

    Log In

    +{% oauth_application_from_query as app %} +{% if app %} +

    Log in to {{ app.name }}

    +{% else %} +

    Log In

    +{% endif %}
    diff --git a/app/templates/account/membership.html b/app/templates/account/membership.html index 1362871d..15d82556 100644 --- a/app/templates/account/membership.html +++ b/app/templates/account/membership.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load active_link_tags wagtailsettings_tags account django_bootstrap5 gravatar setting gift_card i18n %} +{% load active_link_tags wagtailsettings_tags account django_bootstrap5 gravatar setting gift_card date i18n %} {% block content_padding %}py-5{% endblock %} @@ -21,6 +21,8 @@ Finish signup + {% elif user.is_cancelling_member %} +
    Membership cancelling {{ user.active_subscription.cancel_at|to_date|date:"d M Y" }}
    {% elif user.is_expired_member %}
    Expired member
    {% elif user.is_member %} @@ -57,18 +59,20 @@ {% endif %} {% if request.user.is_member or request.user.gifts_bought|length > 0 %} -
    +
    {% if request.user.is_member %}

    Shipping

    +
    {% for key, line in request.user.shipping_address.items %} {% if line %} {{ line }}
    {% endif %} {% endfor %} +
    {% url "customerportal" as portal_url %} {% bootstrap_button button_class='btn-secondary' href=portal_url content="Update shipping" %} @@ -82,6 +86,16 @@

    Billing

    + {% if user.gift_giver %} + + {% endif %} + {% if user.is_cancelling_member %} + + {% endif %} {% for si in user.active_subscription.items.all %}
    {{ si.plan.product.name }}
    {{ si.plan.human_readable_price }}
    diff --git a/app/templates/account/signup.html b/app/templates/account/signup.html index ee1f9de1..979c0270 100644 --- a/app/templates/account/signup.html +++ b/app/templates/account/signup.html @@ -3,7 +3,7 @@ {% load i18n %} {% load url django_bootstrap5 account socialaccount %} -{% block head_title %}{% trans "Create an account" %}BS{% endblock %} +{% block head_title %}{% trans "Create an account" %}{% endblock %} {% block modal_content %} {% get_providers as socialaccount_providers %} @@ -43,8 +43,9 @@

    {% trans "Let's get you set up" %}

    {% bootstrap_field form.last_name show_label=False %}
    - {% bootstrap_form form show_label=False exclude="email,first_name,last_name,gdpr_email_consent,password2" %} + {% bootstrap_form form show_label=False exclude="email,first_name,last_name,gdpr_email_consent,promotional_consent,password2" %} {% bootstrap_field form.gdpr_email_consent show_label=True %} + {% comment %} {% bootstrap_field form.promotional_consent show_label=True %} {% endcomment %} {% if redirect_field_value %} {% endif %} diff --git a/app/templates/app/blocks/your_books_grid_block.html b/app/templates/app/blocks/your_books_grid_block.html index 2fdd6a08..657bced0 100644 --- a/app/templates/app/blocks/your_books_grid_block.html +++ b/app/templates/app/blocks/your_books_grid_block.html @@ -7,7 +7,7 @@

    Books you've received

    {% for book in books %} - {% include "app/includes/simple_book_card.html" with book=book class='col-12 col-sm-6 col-md-4 col-lg-3 col-xl-2' %} + {% include "app/includes/simple_book_card.html" with book=book class='col-6 col-sm-4 col-lg-3 col-xl-2' %} {% endfor %}
    diff --git a/app/templates/app/frames/shipping_cost.html b/app/templates/app/frames/shipping_cost.html index da21302e..4af77eea 100644 --- a/app/templates/app/frames/shipping_cost.html +++ b/app/templates/app/frames/shipping_cost.html @@ -36,7 +36,7 @@ {% if request.GET.gift_mode %} {% bootstrap_alert "At checkout, please add your own shipping address, in case we need to send you any gift card materials. Your gift recipient will be able to enter their own address when they redeem." dismissible=False alert_type="warning" extra_classes='mb-2' %} {% endif %} - {% if user.is_member and not gift_mode %} + {% if user.is_member and not request.GET.gift_mode %}
    diff --git a/app/templates/app/includes/membership_card.html b/app/templates/app/includes/membership_card.html index d5c8e14e..a12b40ba 100644 --- a/app/templates/app/includes/membership_card.html +++ b/app/templates/app/includes/membership_card.html @@ -8,9 +8,9 @@
    Membership No. #{{ user.stripe_customer.invoice_prefix }}
    -
    {{ user.primary_product.name}}
    +
    {{ user.active_subscription.primary_product.name}}
    {% comment %}
    {{user.subscribed_price.human_readable_price}}
    {% endcomment %} - {% if user.primary_product.gift_giver_subscription %} + {% if user.active_subscription.gift_giver_subscription %}
    Gifted by {{user.gift_giver}}
    {% endif %}
    Since {{ user.active_subscription.created|date:"d M Y" }}
    diff --git a/app/templates/base.html b/app/templates/base.html index c9cf7c04..841ac7ff 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -11,6 +11,7 @@ + {% block head_title %}Left Book Club{% endblock %} {% include "wagtailseo/meta.html" %} {% vite_hmr_client %} @@ -48,7 +49,7 @@ src'https://www.facebook.com/tr?id={{ FACEBOOK_PIXEL }}&ev=PageView&noscript=1' /> - {% endif %} + {% endif %} diff --git a/app/templatetags/setting.py b/app/templatetags/setting.py index 1f9a12b4..13f20f61 100644 --- a/app/templatetags/setting.py +++ b/app/templatetags/setting.py @@ -1,9 +1,11 @@ import json +import urllib.parse from django import template from django.conf import settings from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ +from oauth2_provider.models import Application register = template.Library() @@ -29,3 +31,19 @@ def user_data(context): user_data = request.user.get_analytics_data() return {"user_data": mark_safe(json.dumps(user_data))} + + +@register.simple_tag(takes_context=True) +def oauth_application_from_query(context): + try: + request = context["request"] + next = request.GET.get("next", None) + if next is not None: + url_parts = urllib.parse.urlparse(next) + params = urllib.parse.parse_qs(url_parts.query) + client_id = params.get("client_id", None) + if client_id is not None and len(client_id) > 0: + app = Application.objects.filter(client_id__in=client_id).first() + return app + except: + return None diff --git a/app/views.py b/app/views.py index 55ed3d72..ad112cc5 100644 --- a/app/views.py +++ b/app/views.py @@ -28,7 +28,7 @@ from app import analytics from app.forms import CountrySelectorForm, GiftCodeForm, StripeShippingForm from app.models import LBCProduct -from app.models.stripe import ShippingZone +from app.models.stripe import LBCSubscription, ShippingZone from app.models.wagtail import MembershipPlanPrice from app.utils.mailchimp import tag_user_in_mailchimp from app.utils.shopify import create_shopify_order @@ -449,20 +449,14 @@ class CancellationView(LoginRequiredTemplateView): def get_context_data(self, subscription_id=None, **kwargs: Any) -> Dict[str, Any]: context = super().get_context_data(**kwargs) - if subscription_id and self.request.user.stripe_customer is not None: + if ( + subscription_id is not None + and self.request.user.stripe_customer is not None + ): try: - subscription_id = subscription_id - subscription = self.request.user.stripe_customer.subscriptions.get( - id=subscription_id - ) - context["subscription"] = subscription - if subscription.metadata.get("gift_mode", None) is not None: - context["gift_mode"] = True - promo_code_id = subscription.metadata.get("promo_code", None) - if promo_code_id is not None: - context[ - "gift_recipient_subscription" - ] = gift_recipient_subscription_from_code(promo_code_id) + context["subscription"] = LBCSubscription.objects.filter( + customer=self.request.user.stripe_customer, id=subscription_id + ).first() return context except djstripe.models.Subscription.DoesNotExist: raise Http404 @@ -474,15 +468,25 @@ def post(self, request, *args, subscription_id=None, **kwargs): if request.method == "POST": if subscription_id is None: subscription_id = request.user.active_subscription.id - if ( - request.user.stripe_customer is not None - and request.user.stripe_customer.subscriptions.filter( - id=subscription_id - ).exists() - ): - analytics.cancel_membership(request.user.stripe_customer.subscriber) - stripe.Subscription.modify(subscription_id, cancel_at_period_end=True) - return HttpResponseRedirect(reverse("account_membership")) + if request.user.stripe_customer is not None: + sub = LBCSubscription.objects.filter( + customer=request.user.stripe_customer, id=subscription_id + ).first() + if sub is not None: + analytics.cancel_membership(request.user.stripe_customer.subscriber) + stripe.Subscription.modify( + subscription_id, cancel_at_period_end=True + ) + if sub.gift_giver_subscription is not None: + stripe.Subscription.modify( + sub.gift_giver_subscription.id, cancel_at_period_end=True + ) + if sub.gift_recipient_subscription is not None: + stripe.Subscription.modify( + sub.gift_recipient_subscription.id, + cancel_at_period_end=True, + ) + return HttpResponseRedirect(reverse("account_membership")) raise Http404 @@ -512,7 +516,7 @@ def get_context_data( initial={"country": country_id} ), "url_pattern": ShippingCostView.url_pattern, - "current_book": product.current_book(), + "current_book": product.current_book, } )