Skip to content
This repository has been archived by the owner on Nov 4, 2024. It is now read-only.

Commit

Permalink
docs: add ADR 5 for Stripe Custom Actions & update README.rst (#704)
Browse files Browse the repository at this point in the history
  • Loading branch information
pshiu authored Jan 27, 2023
1 parent 8387fcc commit e6b5a1b
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 1 deletion.
10 changes: 9 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Please tag **@edx/revenue-squad** on any PRs or issues. Thanks.
Introduction
------------

Micro-frontend for the single-page payment/checkout process; order history and receipt pages are still served by the ecommerce service. This application only supports PayPal and Cybersource credit card payments.
Micro-frontend for the single-page payment/checkout process; order history and receipt pages are still served by the ecommerce service. This application only supports PayPal, Cybersource, and Stripe credit card payments.

Getting Started
---------------
Expand Down Expand Up @@ -50,6 +50,12 @@ In ``Core > Site configurations > [YOUR CONFIG]``, set "Enable Microfrontend for

Devstack is configured this way by default.

Payment processors Cybersource and Paypal are enabled by default.

To enable Stripe and disable Cybersource, create and enable waffle flag ``enable_stripe_payment_processor`` in ecommerce Django admin under ``Waffle > Flag``.

This must be also done in Devstack.

API Documentation
-----------------

Expand Down Expand Up @@ -99,6 +105,8 @@ A descriptive paragraph of text which provides additional context on the purchas

Cybersource

Stripe

Apple Pay

PayPal
Expand Down
97 changes: 97 additions & 0 deletions docs/decisions/0005-stripe-custom-actions.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
5. Stripe Custom Actions
========================


Status
------

Draft

.. After acceptance, becomes, for example:
Accepted (2023-02-01
Context
-------

We have added Stripe as a payment processor suppported by frontend-app-payment.

`Stripe's default payment architecture`_ does not involve a service's backend until after payment. This means a user can pay before the backend service can evaluate the user's billing details.

Our `ecommerce` backend may deny checkout if a user's billing details are on a sanctions list. This is called the `SDN check`_. But for this, ecommerce must be involved before payment.

`Stripe Custom Actions`_ is an alternative architecture that sends payments through a backend before payment. Stripe Custom Actions preserves PCI compliance by sending sensitive financial information to Stripe and not the backend. However, it does not process payment until the payment is confirmed by the backend and allows inspection of non-sensitive billing details by the backend prior to payment.

Stripe Custom Actions also is similar to the architecture of Cybersource's Flex Microform SDK. Both architectures do not involve a pending state for baskets and involve the backend prior to payment. This similarity makes it easier to intially implement Stripe as `BasePaymentProcessor`_ in ecommerce.

.. _Stripe's default payment architecture: https://stripe.com/docs/payments/accept-a-payment?platform=web&ui=elements#web-create-intent
.. _ecommerce: https://github.com/openedx/ecommerce
.. _SDN check: https://github.com/openedx/ecommerce/blob/master/ecommerce/extensions/payment/core/sdn.py#L29
.. _BasePaymentProcessor: https://github.com/openedx/ecommerce/blob/7555353ae972563fd293558eea608ae6151c1186/ecommerce/extensions/payment/processors/__init__.py#L20


Decision
--------

We will use the architecture in the `Stripe Custom Actions`_ documentation for communication between frontend-app-payment, frontend-app-payment's backend (ecommerce) and Stripe.

.. _Stripe Custom Actions: https://stripe.com/docs/payments/run-custom-actions-before-confirmation


Consequences
------------

When frontend-app-payment loads, it will ask ecommerce for a Stripe ``client_secret`` using ecommerce's endpoint ``/bff/payment/v0/capture_context/``.

When a user submits a purchase, frontend-app-payment will:

#. Send the payment details to Stripe via ``stripe.updatePaymentIntent()``. (As opposed to executing payment via ``stripe.confirmPayment()``, which is what is usually done without Stripe Custom Actions. )

#. Let the ecommerce backend know the user wants to pay using endpoint ``/bff/payment/v0/payment/``.

This ADR extends ADR `4. iFrame Credit Card Handling`_. Like Cybersource, Stripe simplifies an operator's compliance requirements by sending credit card numbers, expiration dates, verification codes, and other protected data exclusively through a Stripe-hosted iframe. Developers must never collect these data in frontend-app-payment outside of a payment processor's hosted iframe.

In order to use Stripe, operators must:

* Request Stripe to enable custom actions on their Stripe account.

* Create and enable ecommerce waffle flag ``enable_stripe_payment_processor`` to have frontend-app-payment use Stripe instead of Cybersource.

.. _4. iFrame Credit Card Handling: https://github.com/openedx/frontend-app-payment/blob/8387fccfcf781db5170a0f9c1052c6cfc538f7eb/docs/decisions/0004-iframe-credit-card-handling.rst


Implementation
--------------

* Load Stripe.js in `Checkout.jsx <https://github.com/openedx/frontend-app-payment/blob/8387fccfcf781db5170a0f9c1052c6cfc538f7eb/src/payment/checkout/Checkout.jsx#L5>`__

* Fetch client_secret from ecommerce in `Checkout.jsx:componentDidMount() <https://github.com/openedx/frontend-app-payment/blob/8387fccfcf781db5170a0f9c1052c6cfc538f7eb/src/payment/checkout/Checkout.jsx#L28>`__, `service.js <https://github.com/openedx/frontend-app-payment/blob/8387fccfcf781db5170a0f9c1052c6cfc538f7eb/src/payment/data/service.js#L59-L64>`__

* Add enableStripePaymentProcessor prop based on enable_stripe_payment_processor ecommerce waffle flag

* Send waffle flag value in any PaymentApiLogicMixin (e.g. PaymentApiView, QuantityApiView, VoucherAddApiView, VoucherRemoveApiView) in `extensions/basket/views.py <https://github.com/openedx/ecommerce/blob/7555353ae972563fd293558eea608ae6151c1186/ecommerce/extensions/basket/views.py#L747-L750>`__

* Add API payload to Redux state in `reducers.js <https://github.com/openedx/frontend-app-payment/blob/8387fccfcf781db5170a0f9c1052c6cfc538f7eb/src/payment/data/reducers.js#L38>`__

* Ask React Redux to connect state to props in `PaymentPage.jsx:connect() <https://github.com/openedx/frontend-app-payment/blob/8387fccfcf781db5170a0f9c1052c6cfc538f7eb/src/payment/PaymentPage.jsx#L184>`__

* Split <StripePaymentForm> from (Cybersource) <PaymentForm> since Stripe collects card expiration and Cybersource does not in `StripePaymentForm <https://github.com/openedx/frontend-app-payment/blob/8387fccfcf781db5170a0f9c1052c6cfc538f7eb/src/payment/checkout/payment-form/StripePaymentForm.jsx#L25>`__

* Load <StripePaymentForm> within Stripe.js Elements or (Cybersource) <PaymentForm> based on enableStripePaymentProcessor in `Checkout.jsx <https://github.com/openedx/frontend-app-payment/blob/8387fccfcf781db5170a0f9c1052c6cfc538f7eb/src/payment/checkout/Checkout.jsx#L267-L290>`__

* Create payment processor to submit billing details to Stripe and handle post-payment processing in `stripe/service.js <https://github.com/openedx/frontend-app-payment/blob/8387fccfcf781db5170a0f9c1052c6cfc538f7eb/src/payment/payment-methods/stripe/service.js#L11-L18>`__


Sequence Diagram
----------------

TODO.


References
----------
* `Stripe Custom Actions`_
* `Stripe PCI Compliance`_

.. _Stripe PCI Compliance: https://stripe.com/docs/security/guide

0 comments on commit e6b5a1b

Please sign in to comment.