Problem/Motivation

SupportsUpdatingStoredPaymentMethodsInterface is already added to the payment module, but it does not do anything at the moment. Let's enable updates for payment methods with gateways implementing this interface.

Proposed resolution

We identified the following reasons for needing to update a payment method instead of replacing the payment method (retokenizing.)

  • The customer's billing information has changed, and AVS validation is performed by the merchant's gateway.
  • The card is expired, or near expiration, and the customer has a new expiration date to provide so that payment does not fail.

That means we can render the masked credit card number that we already have and just prompt the customer for the expiration date information.

Remaining tasks

Add route support for updating the payment method
Expose updating a payment method's billing information
Expose updating a payment method's expiration dates

Relevant links for payment gateway APIs:

Comments

czigor created an issue. See original summary.

czigor’s picture

Status: Active » Needs review
StatusFileSize
new21.16 KB

The patch
- Fixes the "Add payment method" form by allowing adding payment methods for all possible gateways, not just one.
- Also changes the "Add payment method" form from being a 2 step form to an AJAX one, copying logic from the Payment information pane.
- Implements the edit functionality inside payment module
- Updates the payment_example Onsite payment gateway to implement SupportsUpdatingStoredPaymentMethodsInterface
- Adds a test for payment method edits.

Status: Needs review » Needs work

The last submitted patch, 2: commerce-2952193-edit_payment_methods-2.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

czigor’s picture

Status: Needs work » Needs review
StatusFileSize
new23.23 KB

My local test env is broken atm, so I just hope this is going to fix the tests.

Status: Needs review » Needs work

The last submitted patch, 4: commerce-2952193-edit_payment_methods-4.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

czigor’s picture

Status: Needs work » Needs review
StatusFileSize
new23.23 KB

Local env fixed, and so are the tests.

czigor’s picture

czigor’s picture

StatusFileSize
new44.73 KB

To avoid code duplication, the attached patch creates a commerce_payment_method_form form element that is used on the PaymentInformation checkout pane and on the "Add payment method" form. However, because of the form element everything got one level deeper in the form structure which breaks tests. They are easy to fix, but i'm not sure we want to go this way and break selectors on existing sites.

Status: Needs review » Needs work

The last submitted patch, 8: commerce-2952193-edit_payment_methods-8.patch, failed testing. View results

czigor’s picture

Rerolling patch to apply it to latest dev.

There's another issue: PaymentMethodForm::ajaxRefresh() returns an element one level higher than it should.

czigor’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 10: commerce-2952193-edit_payment_methods-10.patch, failed testing. View results

czigor’s picture

Since https://developer.cardinalcommerce.com/try-it-now.shtml provides only a test visa number, I'm not sure about the mastercard responses regarding the cavv/eci numbers (afaik they have different names there).
Wrong issue.

bojanz’s picture

The patch here will need to be reworked, since we've decided that PaymentMethodEditForm should not share code with any other forms.
The sprit of the patch in #10 was completed in #2858599: Move a portion of the PaymentInformation pane logic to a PaymentOptionsBuilder

We just need a simple form that edits the billing profile, and a matching gateway method to call.

bojanz’s picture

Status: Needs work » Needs review
StatusFileSize
new9.89 KB

Here is a rebuilt, minimal patch, allowing only billing profile updates.

It might make sense to also support modifying the expiration date, either in the main form or at least in the one for the Onsite example gateway.

czigor’s picture

Status: Needs review » Needs work

Can't we pass $payment_details to updatePaymentMethod() too, just like to createPaymentMethod()? That way we could update the remote payment method with non-persistent data from the form.

czigor’s picture

For some gateways not allowing submitting masked credit card numbers for payment method updates this might even be required.

bojanz’s picture

Well, I assumed we wouldn't want to support retokenization, people would add a new payment method for that.
The use cases here are 1) Update the billing info 2) Update the expiration date, when supported (usually supported without PCI implications)

czigor’s picture

Allowing retokenization would simplify card expiration handling for recurring payments. Doesn't seem to be a big deal to support it, should we open another issue for it?

czigor’s picture

StatusFileSize
new11.68 KB
new1.8 KB

Attached patch adds the gateway js library to the user add and edit payment method forms, just like we do it for the payment pane. I understand we add the js libraries there only to work around a drupal core js bug, but the gateway annotation suggests that commerce core takes care of attaching the library to the form, so I think we should do that.

Patch also removes a needless variable re-initialization.

czigor’s picture

Status: Needs work » Needs review
mglaman’s picture

Discussed with bojanz. We identified the following reasons for needing to update a payment method instead of replacing the payment method (retokenizing.)

  • The customer's billing information has changed, and AVS validation is performed by the merchant's gateway.
  • The card is expired, or near expiration, and the customer has a new expiration date to provide so that payment does not fail.

After reviewing the various payment gateway APIs, it is possible to pass a new expiration date along with a remote payment method ID to update a payment method without full retokenization of the card.

That means we can render the masked credit card number that we already have and just prompt the customer for the expiration date information. I'm resetting the patches back to #15 and we will work from there.

Relevant links for payment gateway APIs:

mglaman’s picture

Also want to update title and issue summary because this feature will be 💯💯💯💯💯💯

mglaman’s picture

Issue summary: View changes
Issue tags: -Needs issue summary update

Update issue summary.

mglaman’s picture

StatusFileSize
new14.57 KB
new7.66 KB

Here is my update. Allows editing the expiration information. Displays the card type image, updates the payment method's expiring time as well. Then passes it to the payment gateway.

mglaman’s picture

StatusFileSize
new14.84 KB

I forgot to update the test.

Status: Needs review » Needs work

The last submitted patch, 26: 2952193-26.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

mglaman’s picture

+++ b/modules/payment/tests/src/Functional/PaymentMethodTest.php
@@ -100,7 +100,35 @@ class PaymentMethodTest extends CommerceBrowserTestBase {
+      'payment_method[payment_details][expiration][year]' => '2026',
...
+    $this->assertSession()->pageTextContains('2/2024');

.. of course it failed.

mglaman’s picture

Status: Needs work » Needs review
StatusFileSize
new14.84 KB

Here is the updated patch and test.

bojanz’s picture

+      '#template' => '<span class="payment-method-icon payment-method-icon--{{ type }}"></span>Credit card ending in {{ mask }}',

This isn't translatable, no? Can we just use $payment_method->label()? That would give us "Visa ending in 1111"

mglaman’s picture

Yeah, dumb. Too long in client land. That makes more sense.

  • mglaman committed f42b5b2 on 8.x-2.x
    Issue #2952193 by czigor, mglaman, bojanz: Editing reusable payment...
mglaman’s picture

Status: Needs review » Fixed

\o/ Committed!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.