Checkout (with Stripe SCA)



Management Commands

Retrieve the payment intent and update the checkout status: payment_intent_fulfillment

Retrieve the setup intent and update the checkout status: setup_intent_fulfillment

Send emails to customers asking them to login and pay (on-session): send_on_session_payment_emails


From Viewport meta tag requirements:

{% block meta_extra %}
  <meta name="viewport" content="width=device-width, initial-scale=1" />
{% endblock meta_extra %}

Add our _elements.html template:

{% block content %}
  <div class="pure-g">
    <div class="pure-u-1">
      {% include 'checkout/_elements.html' %}
{% endblock %}

Add our _elements.js.html template:

{% block script_extra %}
  {{ block.super }}
  {% include 'checkout/_elements.js.html' with override_do_success_action=True %}
    function doSuccessAction() {
      successUrl = "{{ success_url }}";
      if (!successUrl && console) console.log("No 'successUrl' returned");, '_self');
{% endblock script_extra %}


I am not clear on why we need override_do_success_action. Here are the notes from 14 Nov 2019, 18:31: The issue with the pay on session page is that it does not have a checkout form (id_checkout_form) it only has the stripe form (payment-form) so obviously the submit button on the checkout form never gets pressed and therefore the successUrl variable is never set. I’ve amended _elements.js.html to allow the doSuccessAction function to be overridden and defined a doSuccessAction function in checkout_pay_on_session.html in the … project.


To test the decline_code of authentication_required, use the card number:



This card requires authentication on all transactions, regardless of how the card is set up.

When testing Elements, you will be asked to enter a ZIP code. To allow entry of a UK postcode, use a UK/GB debit card number:



Don’t forget to run the Management Commands

Testing Payments for SCA:


  • We are not using the CustomerPayment model. It was used to take money from a customer. It probably needs to be updated to send an email to a customer asking them to authorise payment. I think CustomerCardRefreshFormView does something similar.

  • We have removed CustomerCheckoutRefreshUpdateView. It is used to update card details for a customer. I think we should probably send an email to the customer asking them to update their card details. CustomerCardRefreshFormView might do this (see below).

  • We have removed CustomerCardRefreshFormView. I am not sure what this view would achieve? Would it create a setup_intent? What would the customer expect us to do with the payment method?

  • Not sure if we need refresh_card_expiry_dates or report_card_expiry_dates. How would they work with the requirement for on-session authentication?

To Do

  • Write a task (+ management command) to iterate through payment plans with a CheckoutState of PAY_ON_SESSION. Send the user an email asking them to login and authenticate the payment. Make sure we send just one email… 27/08/2019, Complete (see ticket)

  • Test the transition from the old system (saving cards) to the new system (payment_methods). 27/08/2019, done without any issues. It just seems to work :)

To Do on MD’s 4075-stripe-sca-modal branch

  • Re-instated checkout_actions, checkout_can_charge (see checkout/tests/ and test_check_checkout (for the Customer). I was hoping we wouldn’t need these for the SCA version of checkout (search for PJK 04/09/2019).

  • Re-instated tests for is_expiring on the Customer model e.g. test_is_expiring_future. I was hoping we wouldn’t need these for the SCA version of checkout.

  • CustomerPayment has been re-instated. I was hoping we wouldn’t need these for the SCA version of checkout.

  • CustomerChargeCreateView has been re-instated. I was hoping we wouldn’t need these for the SCA version of checkout.

  • Write a test for Checkout, __str__. It fails with the following error when the checkout has no content_object:

    fails on the institute database with the error AttributeError:
    'NoneType' object has no attribute '_base_manager'



The email template for pay on session should check to see if the user has an account and has logged in within the last X months before deciding which template to use.


To find the pay on session instalments, use the pay_on_session_for_email method…

We need to create a redirect view which generates a checkout URL e.g:

checkout = Checkout.objects.create_checkout_pay_on_session(
    instalment, AnonymousUser()
url = reverse(
    "", args=[checkout.uuid]


This code is from send_on_session_payment_emails


  1. Our example SalesLedgerSessionRedirectView calls create_checkout.

  2. create_checkout also creates a payment intent and saves it’s ID with the Checkout object.

  3. The SalesLedgerCheckoutView inherits from CheckoutMixin.

  4. The CheckoutMixin adds the client_secret from the payment intent to the template context.

  5. The Stripe JavaScript code in the _elements.js.html template will collect the payment.

  6. The stripe_intent_fulfillment method (and management command) will update the state of pending checkout objects with the status of the intent.

Working on…

Step 5: Attach the PaymentMethod to a Customer after success:


The current checkout view allows users to choose payment, payment plan or invoice. Our customer site has an initial page where the user can choose how they want to pay - so our new checkout page should already know…


Current Models

  • Checkout (keep track of a payment request)

  • CheckoutAction (charge, card refresh, payment plan)

  • CheckoutAdditional (additional information e.g. address)

  • CheckoutSettings (default payment plan)

  • CheckoutState (pending, request, success)

  • Customer (Stripe customer - email address is the primary key)

  • CustomerPayment (payment taken from a customer) What is this for?

  • ObjectPaymentPlan (payment plan for a content_object)

  • ObjectPaymentPlanInstalment (payment plan instalment for a payment plan)

  • PaymentPlan (template)

  • PaymentRun (date of payment run)

  • PaymentRunItem (instalment for payment run)