Stripe checkout #104411

Merged
Anna Sirota merged 61 commits from stripe into main 2024-06-17 18:08:41 +02:00
6 changed files with 28 additions and 44 deletions
Showing only changes of commit 2b29a7ab2a - Show all commits

View File

@ -210,12 +210,6 @@ class PayExistingOrderForm(forms.Form): # TODO
price = forms.CharField(widget=forms.HiddenInput(), required=True) price = forms.CharField(widget=forms.HiddenInput(), required=True)
class ChangePaymentMethodForm(forms.Form): # TODO
"""Add full billing address to the change payment form."""
pass
class CancelSubscriptionForm(forms.Form): class CancelSubscriptionForm(forms.Form):
"""Confirm cancellation of a subscription.""" """Confirm cancellation of a subscription."""

View File

@ -93,10 +93,10 @@
{% if not subscription.is_cancelled %} {% if not subscription.is_cancelled %}
<div class="col-auto"> <div class="col-auto">
<a class="small" <form method="POST" action="{% url 'subscriptions:payment-method-change' subscription_id=subscription.id %}">
href="{% url 'subscriptions:payment-method-change' subscription_id=subscription.id %}"> {% csrf_token %}
Change <button type="submit" class="small">Change</button>
</a> </form>
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@ -41,9 +41,17 @@ urlpatterns = [
), ),
path( path(
'subscription/<int:subscription_id>/payment-method/change/', 'subscription/<int:subscription_id>/payment-method/change/',
settings.PaymentMethodChangeView.as_view(), looper_settings.PaymentMethodChangeView.as_view(
success_url='subscriptions:payment-method-change-done',
cancel_url='user-settings-billing', # FIXME: go back to subscription manage instead
),
name='payment-method-change', name='payment-method-change',
), ),
path(
'subscription/<int:subscription_id>/payment-method/change/<stripe_session_id>/',
settings.PaymentMethodChangeDoneView.as_view(),
name='payment-method-change-done',
),
path( path(
'subscription/order/<int:order_id>/pay/', 'subscription/order/<int:order_id>/pay/',
settings.PayExistingOrderView.as_view(), settings.PayExistingOrderView.as_view(),

View File

@ -5,7 +5,7 @@ import logging
from django.shortcuts import redirect from django.shortcuts import redirect
from django.views.generic import FormView from django.views.generic import FormView
from looper.views.checkout_braintree import AbstractPaymentView from looper.views.checkout_stripe import CheckoutStripeView
import looper.gateways import looper.gateways
import looper.middleware import looper.middleware
import looper.models import looper.models
@ -20,7 +20,7 @@ logger.setLevel(logging.DEBUG)
class _PlanSelectorMixin: class _PlanSelectorMixin:
get_currency = AbstractPaymentView.get_currency get_currency = CheckoutStripeView.get_currency
select_team_plans = False select_team_plans = False
plan_variation = None plan_variation = None
plan = None plan = None

View File

@ -1,6 +1,7 @@
"""Views handling subscription management.""" """Views handling subscription management."""
import logging import logging
from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.http import HttpResponseForbidden from django.http import HttpResponseForbidden
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
@ -14,7 +15,6 @@ import looper.views.settings_braintree
from subscriptions.forms import ( from subscriptions.forms import (
CancelSubscriptionForm, CancelSubscriptionForm,
ChangePaymentMethodForm,
PayExistingOrderForm, PayExistingOrderForm,
TeamForm, TeamForm,
) )
@ -47,35 +47,17 @@ class CancelSubscriptionView(SingleSubscriptionMixin, FormView):
return super().form_valid(form) return super().form_valid(form)
class PaymentMethodChangeView(looper.views.settings_braintree.PaymentMethodChangeView): class PaymentMethodChangeDoneView(looper.views.settings.PaymentMethodChangeDoneView):
"""Use the Braintree drop-in UI to switch a subscription's payment method.""" """Change payment method in response to a successful payment setup."""
template_name = 'subscriptions/payment_method_change.html' @property
form_class = ChangePaymentMethodForm def success_url(self):
success_url = reverse_lazy('user-settings-billing') """Return to this subscription's manage page."""
messages.add_message(self.request, messages.INFO, 'Payment method updated')
subscription: looper.models.Subscription return reverse(
'subscriptions:manage',
def get_initial(self) -> dict: kwargs={'subscription_id': self.kwargs['subscription_id']},
"""Modify initial form data.""" )
initial = super().get_initial()
initial['next_url_after_done'] = self.success_url
# Looper's view uses customer full_name, we don't
initial.pop('full_name', None)
# Only set initial values if they aren't already saved to the billing address.
# Initial values always override form data, which leads to confusing issues with views.
if not (self.customer and self.customer.billing_address.full_name):
# Fall back to user's full name, if no full name set already in the billing address:
if self.request.user.full_name:
initial['full_name'] = self.request.user.full_name
return initial
def form_invalid(self, form):
"""Temporarily log all validation errors."""
logger.exception('Validation error in ChangePaymentMethodForm: %s', form.errors)
return super().form_invalid(form)
class PayExistingOrderView(looper.views.checkout_braintree.CheckoutExistingOrderView): class PayExistingOrderView(looper.views.checkout_braintree.CheckoutExistingOrderView):

View File

@ -2,7 +2,7 @@
from collections import defaultdict from collections import defaultdict
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from looper.views.checkout_braintree import AbstractPaymentView from looper.views.checkout_stripe import CheckoutStripeView
import looper.models import looper.models
import subscriptions.models import subscriptions.models
@ -11,7 +11,7 @@ import subscriptions.models
class TeamsLanding(TemplateView): class TeamsLanding(TemplateView):
"""Display a selection of team plans and existing sponsors.""" """Display a selection of team plans and existing sponsors."""
get_currency = AbstractPaymentView.get_currency get_currency = CheckoutStripeView.get_currency
template_name = 'subscriptions/teams_landing.html' template_name = 'subscriptions/teams_landing.html'
@staticmethod @staticmethod