Provide a new "Add payment" form

Created on 26 July 2025, 28 days ago

The current "Add payment" form approach reverses a normal merchant's logic. Where a merchant might say, "I'd like to charge $25 to this card," our form currently asks, "What card would you like to charge? How much? Ok, a full charge or just an authorization?"

We should fix the logic and also provide more helpful information on the form, such as the order items and the effect of any previous payments, including a textual representation of the current order balance (instead of just defaulting the current balance in the payment amount field).

This is an in-browser mock-up of the new approach:

Note that it shows the actual order items and also includes in the order totals area a line showing how much has already been paid and what the remaining balance is. We do need to ensure this is backwards compatible, so we should:

  1. Define a new controller for this new form approach.
  2. Default Drupal Commerce to using this new controller.
  3. Look for a setting variable that if set edits the route to use the old controller. Perhaps something as simple as a setting called use_two_step_add_payment_form.
  4. Mark the old controller as deprecated so it can be deleted in 4.x.
  5. Embed the order items table atop the form, along with the order total summary.
  6. Add lines to the summary for the total paid and outstanding balance.
  7. Put the payment details inside a fieldset to visually match the order comments form on the view page.
  8. Float the currency selector if present. This isn't a strict requirement, because it can be a pain in the neck to get the vertical alignment right in the abstract. But this would be nicer than vertical stacking.
  9. Note the changed label, from "Payment option" to "Payment method."
  10. If the merchant is reusing a payment method, no problem, we process payment on submit.
  11. If the merchant is entering a new payment method, update the form to include the necessary elements.
  12. Create the payment method on submit and charge the payment as before.

I'll make a separate ticket specific to supporting a return from an offsite payment solution. The scope of this ticket is primarily to make the form ready for that while also providing a much nicer UX to merchants.

โœจ Feature request
Status

Active

Version

3.0

Component

Payment

Created by

๐Ÿ‡บ๐Ÿ‡ธUnited States rszrama

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

Merge Requests

Comments & Activities

  • Issue created by @rszrama
  • ๐Ÿ‡จ๐Ÿ‡ดColombia i'mbatman

    imbatman โ†’ made their first commit to this issueโ€™s fork.

  • Pipeline finished with Failed
    25 days ago
    #560109
  • Pipeline finished with Failed
    24 days ago
    Total: 692s
    #561168
  • Pipeline finished with Failed
    23 days ago
    Total: 1375s
    #561989
  • Pipeline finished with Failed
    17 days ago
    #566706
  • ๐Ÿ‡จ๐Ÿ‡ดColombia i'mbatman
  • Pipeline finished with Failed
    17 days ago
    #566717
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States rszrama

    Quick fix needed: the logic of the use_two_step_add_payment_form setting is backwards. If it's set to TRUE, then we should use the old style two step form, not if it's set to FALSE.

    From an update standpoint, I think it's fine for the new version of the form to be the default. Howver, it is fair to question whether or not that breaks backend interfaces or test suites for existing sites. We'll certainly document the change in the release notes, but let's also add an update hook that doesn't actually change anything but displays the following message to users who update:

    Your payment add form has been updated to a new single page format. If you depend on the old two step method, you will need to set a variable in settings.php to preserve it. See the release notes for Commerce Core x.y.z for more information.

    Otherwise this looks and functions great! Still ways we can improve the styling of the form (e.g., fixing order total summaries, limiting the form width, etc.), but let's consider that out of scope for this ticket.

  • Pipeline finished with Failed
    2 days ago
    Total: 844s
    #578568
  • ๐Ÿ‡ฎ๐Ÿ‡ฑIsrael jsacksick

    @imbatman: Thank you for this.

    I haven't tested this manually, but we have to fix the broken tests. I think we need to keep the tests coverage for the existing form, since we're retaining it, while also introducing tests for the new form.

    Additionally, couple of possible improvements:

    1. We can leverage the AjaxFormTrait instead of redefining an ajax callback etc (We need to see if this works ofc).
    2. From the event subscriber, let's import the class so we can do: PaymentForm::class (this prevents mistakes).
    3. I'm suggesting we rename PaymentForm (which is too generic) to indicate that this form is for adding a payment for an order. So perhaps OrderPaymentAddForm or just OrderPaymentForm?
    4. We can probably remove the buildPaymentOptionLabels() helper method in favor of EntityHelper::extractLabels()

    Overall, what's actually really good about the new approach is that the logic was broken down into separate methods, which allows a child implementation to override specific parts of the code.

Production build 0.71.5 2024