Ensure Payment Method Entity is Created After Payment Confirmation

Created on 7 September 2023, about 1 year ago
Updated 28 September 2023, about 1 year ago

We need to ensure that a Payment Method entity is created for the Payment in Drupal with the token needed to process subsequent payments using the same credit card. This should look like:

  1. As you can see in https://stripe.com/docs/payments/quickstart#show-status-message, we do get the client secret appended to the return URL, which will be available in StripePaymentElement::onReturn().
  2. With the client secret, we can retrieve the payment intent from Stripe to decide if payment succeeded or not, and in that payment intent object, we can actually get the same payment method ID that is used in the Card Element context to create a reusable payment method when the Payment information checkout pane is processed: https://stripe.com/docs/api/payment_intents/object#payment_intent_object...
  3. When we create the payment intent prior to rendering the Payment Element, we do need to ensure we pass in the correct value for setup_future_usage per https://stripe.com/docs/payments/payment-intents#future-usage. In the Card Element context, this is an option on the StripeReview pane, but in the Payment Element context, we should move this into the gateway configuration. This should be a radios element labeled "Payment method usage", a help text of "This value will be passed as the setup_future_usage parameter in your payment intents." and have two options:
    1. on_session | "On-session: the customer will always initiate payments in checkout"
    2. off_session | "Off-session or mixed: the site may process payments on the customer's behalf (e.g., recurring billing)"
  4. What we need to do to tie it all together is fetch the payment intent in StripePaymentElement::onReturn(), which is invoked when PaymentCheckoutController::returnPage() processes the return. (We should be able to use the expand property on the API request to fetch the full payment method object at this time, not just the ID.) We can then do two things:
    1. Check the status of the payment intent and act accordingly, as shown in the example code of https://stripe.com/docs/payments/quickstart#show-status-message
      1. For succeeded, we proceed as normal.
      2. For processing, we should still be able to create a payment method and a payment entity, but the state of the payment should not be completed, just new , until it gets updated later by a webhook.
      3. For requires_payment_method (or for any other status, e.g. the default block in the sample code), we should throw a Drupal\commerce_payment\Exception\DeclineException exception and not create a payment method or payment entity. This will be caught by the controller, and the customer will be sent backward with an error message.
    2. Create a payment method entity in Drupal using the payment method ID in the intent. (I don’t believe we can use StripePaymentElement::createPaymentMethod() as copied from Stripe::createPaymentMethod(), because it attempts to create one locally and remotely, which we don't need ... it already exists remotely.) We should also be referencing this payment method ID when we create the payment.
      1. Note: when you create a payment method, you specify whether or not it will be reusable. Regardless of the setup_future_usage option in the original payment intent, we need to review the payment method type at Stripe and set reusability accordingly. If the type is one of those listed inhttps://stripe.com/docs/payments/payment-methods/integration-options#add... as supporting reusability, then it should be created as reusable. (Since PayPal transactions are reusable but may not be identified by the type alone, we would need to look for the paypal property on the payment method.)
  5. To make use of a previously saved payment method, the StripePaymentElementInterface should also implement SupportsStoredPaymentMethodsInterface. This will lead the Payment process pane to call StripePaymentElement::createPayment() instead of following the offsite flow.
    1. Note that this function benefits from using the StripeReview pane to create the payment intent before you get to this point. This means we need to ensure the StripeReview pane supports StripePaymentElement payments - it’s currently only visible for Stripe payments, and there may be other elements of the implementation we need to update. Not 100% sure, but we at least need to ensure it can be placed on the review step where we would otherwise be placing the Payment Element iframe.
  6. After completing all the above, we then need to start testing things!
    1. Test complete checkout with a new card.
    2. Test complete checkout with a reused card.
    3. Test both of the above with a card that requires 3D Secure.
    4. Evaluate what our options are in the user account’s Payment methods interface … we may need to customize things there, as I think our only option may be to support deletion, not editing an existing saved payment method.
    5. I’m also not sure what a bank transfer payment method may look like here, because we are using what is theoretically a “credit card” payment gateway that may generate reusable bank transfer payment methods. Resolving this particular point can be deferred until later with a priority on credit card / wallet payments for now.
📌 Task
Status

Fixed

Version

1.0

Component

Payment Element

Created by

🇺🇸United States thenyouDi Asheville, North Carolina

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024