To reproduce:
- Enable the commerce_payment_example module.
- Create 2 "Example (On-site)" payment gateways.
- Grant the "Manage own payment methods" permission to authenticated users
- Login and go to /user/123/payment-methods
- Click "Add a new payment method".

Actual result:
We are presented a payment method add form for one of the payment gateways created above, without being able to choose which gateway we want to create a payment method for.

Expected result:
A multistep form where the first step is selecting the payment gateway.

--ORIGINAL ISSUE---

I am trying to add a new payment method as a custom user and I cannot seem to. I had a look at the routing.yml file and under here:
entity.commerce_payment_method.add_form:
path: '/user/{user}/payment-methods/add'
defaults:
_form: '\Drupal\commerce_payment\Form\PaymentMethodAddForm'
_title: 'Add payment method'
requirements:
_custom_access: '\Drupal\commerce_payment\Access\PaymentMethodAccessCheck::checkAccess'
options:
parameters:
user:
type: entity:user

the method checkAccess() returns the $return object true, ie:
$result->isNeutral() is false but isAllowed() is true and isForbidden() is false

but I still get a 403 when i try to add a payment method for a given user under:

/user/{user}/payment-methods/add

I can confirm that I can see the list of empty payment methods page OK .

I can also confirm that the permissions have been set to allow for manage own payment method for the user role .

Please help

Hittesh

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

hitteshahuja created an issue. See original summary.

hitteshahuja’s picture

Issue summary: View changes
czigor’s picture

The payment methods add page is only accessible if a payment gateway implementing SupportsStoredPaymentMethodsInterface is enabled. Can you check if this is the case?

czigor’s picture

Status: Active » Postponed (maintainer needs more info)
gdev2018’s picture

I have a similar problem. As a payment gateway, I have only PayPal module

czigor’s picture

@gdevashi Which payment gateway are you using? Express Checkout or Payflow?

gdev2018’s picture

@czigor Express Checkout

Aporie’s picture

Hi,

I have a similar issue. The fact is, as is, the module only load the first payment gateway in the list when a user click on "Add a payment method" in his user profile. So if you want your payment gateway to be accessible from this form, you should give it a name to be first in the list (alphabetic order).

To be more clear :

\Drupal\commerce_payment\Form\PaymentMethodAddForm::buildForm() {
      $payment_gateway_storage = $this->entityTypeManager->getStorage('commerce_payment_gateway');
      $payment_gateway = $payment_gateway_storage->loadForUser($user); // here
}
\Drupal\commerce_payment\PaymentGatewayStorage::loadForUser(UserInterface $account) {
    $payment_gateways = $this->loadByProperties(['status' => TRUE]);
    $payment_gateways = array_filter($payment_gateways, function ($payment_gateway) {
      return $payment_gateway->getPlugin() instanceof SupportsStoredPaymentMethodsInterface;
    });
    // @todo Implement resolving logic.
    $payment_gateway = reset($payment_gateways); // here

    return $payment_gateway;
}

I think this route should end to a controller displaying the list of payment available so the user can choose which one he wants to add.
Should we open a new ticket for it? I can take a look to it if I have time.

rszrama’s picture

Priority: Critical » Normal
tonifisler’s picture

I can confirm that this is an issue for me too. I need to be able to choose which payment gateway to use (same as in the checkout flow on the PaymentInformation pane) and this is only returning the first one.

PaymentMethodAddForm::buildForm seems to manage multiple payment methods, but not multiple payment gateways.

czigor’s picture

Title: Cannot Add Payment Method for individual user » Adding a payment method is only possible for one gateway
Issue summary: View changes
Status: Postponed (maintainer needs more info) » Needs review
FileSize
5.14 KB

Since we could not reproduce the original issue and this issue got hijacked anyway, let's reformulate the title and description.

Adding a patch to see what it breaks. It should make it possible to create a payment method for any gateway, not just the first one.

czigor’s picture

Issue summary: View changes
czigor’s picture

Status: Needs review » Needs work

It seems we need test coverage for the payment method add form.

czigor’s picture

Status: Needs work » Needs review
FileSize
9.51 KB

Added a test.

liquidcms’s picture

I think I am having the same issue.

I have 3 gateways enabled:
- Accept check
- Authorize.net
- Test Gateway

An admin goes to a cart to add a payment.

Issue 1 - i see only 2 of the 3 GWs: Acept Check and Authorize.net

Issue 2 - when i select A.net i see only 1 payment method: "American Express ending in 0002"; which i assume is a CC that i had used previously.

Main issue, i am not able to pay with a different CC.

BTW - this is all after applying the patch above, rel 2.14. Before applying the patch i had the exact same results.

A little confused about the topic of this issue. The titles says only can access 1 GW. Which, for me is not true. I have 2 GWs accessible; although i should have 3.

But bigger issue is i can't add a different payment method with the selected GW - but perhaps not this issue (although reading above comments; maybe it is now??).

I'll raise a new issue for the 2nd issue.

czigor’s picture

@liquidcms I think these are different issues. This ticket is about creating payment methods on the /user/123/payment-methods page. If I understand yours correctly, it's about checkout. That said, updating commerce to 2.17 is recommended and might even solve your issue.

liquidcms’s picture

@czigor, thanks for the clarification. I did raise the issues we are having as separate issues.

yes, possibly some things are fixed in 2.17 but have been holding out as long as possible as i accidentally (composer) upgraded to 2.16 a couple months ago and it took days to fix the mess it made. but sounds like time to try again.

liquidcms’s picture

@czigor, i updated to 2.17, added this patch: #2912996: Support admin order payments and the one from this issue and some of the "payment" issues we see are cleaned up now (not sure the one here is visible anywhere we have tested yet).

I just added this case: #3121414: Admin can not Add Payment for Gateway unless client has used that GW. which covers the last issue we see; which i can't help think is still somewhat related to this issue.. but possibly not.

Rob230’s picture

Patch #14 is working on the latest Commerce 2.19. Thanks.

Abhinand Gokhala K’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
56.26 KB

I have applied #14 patch. It is perfectly working for me.
It saved my time. Thanks

RTBC

Rob230’s picture

I've actually had to stop using this patch because it gives the user an option of "Braintree" and then a second page where they choose "Credit card" or "PayPal". This isn't desirable for us, we would want them to just have all the options on one page like they are on the checkout - "Braintree" is not relevant and the user won't know what it is.

nofue’s picture

Any news on this? Will this patch make it to the module, or are we required to use the patch after every update?

thenchev’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
826 bytes
9.61 KB

I noticed that some payment gateways (like paypal) have some additional checks for displaying the form. What do you think about an alter hook so we can do some additional filtering?
I can clean up the patch if we wan't to go this direction

shabana.navas’s picture

+++ b/modules/payment/src/Form/PaymentMethodAddForm.php
@@ -65,41 +65,89 @@ class PaymentMethodAddForm extends FormBase implements ContainerInjectionInterfa
+      \Drupal::service('module_handler')->alter('commerce_payment_payment_gateways', $payment_gateways);

Can't this be injected?

thenchev’s picture

@shabana.navas for sure. I was just checking if we want it and then i can clean up the code. There are unused variables that i can remove and clean up the if statements

thenchev’s picture

Injected the module handler

jsacksick’s picture

I applied and tested the patch from #14 and it looks good besides the fact that for example PayPal shows (as mentioned/outlined in comment #23).

@Rob230:

I've actually had to stop using this patch because it gives the user an option of "Braintree" and then a second page where they choose "Credit card" or "PayPal". This isn't desirable for us, we would want them to just have all the options on one page like they are on the checkout - "Braintree" is not relevant and the user won't know what it is.

The patch uses the payment gateway label, which can be changed in the admin? It's not using the plugin label|display label, so you can decide yourself what label to use.

@thenchev: Introducing a hook doesn't really make sense here as Commerce rarely uses hooks and tend to favor events.
Additionally, the hook name is generic... And you shouldn't have to write custom code for PayPal to disappear from that list.

I updated the filtering of payment gateways done in buildForm() to check if gateways are an instance of SupportsCreatingPaymentMethodsInterface.
That doesn't remove PayPal from the list, but this check looks more correct.

The logic for loading/filtering of gateways was copied from PaymentGatewayStorage::loadByUser() which makes me think whether we should introduce an additional method that loads/filters and return all gateways (not just one). Note that loadByUser() doesn't even use the $account parameter passed...

We could probably leave the code as is... Although I believe to properly filter out PayPal, it probably makes sense to expand the work done in #3137253: Allow payment gateways to explicitly support payment method creation outside of a payment transaction and introduce an additional interface.

I thought about introducing a new interface (SupportsCreatingReusablePaymentMethodsInterface) which explicitly indicates that the gateway support creating reusable payment methods, which isn't the case for PayPal.

Introducing this new interface would filter out PayPal from the list of available gateways by filtering gateways that are not an instance of that interface.
I believe this should be handled in a separate issue which I'm going to open.

In the meantime, uploading an updated version of the patch from #14 with minor fixes/improvements.

jsacksick’s picture

Same patch, with the phpcs violations fixed.

jsacksick’s picture

  • jsacksick committed 6c12fb0 on 8.x-2.x authored by czigor
    Issue #3015970 by thenchev, czigor, jsacksick: Adding a payment method...
jsacksick’s picture

Status: Needs review » Fixed

I went ahead and committed the patch from #28, we'll need to figure out #3218892: Allow payment gateways to explicitly indicate that they support creating reusable payment methods to properly wrap up this feature, but it's still better than what we currently have.

Rob230’s picture

@jsacksick The problem was more that it puts it on 2 steps, although the label was confusing as well. If the label was changed to 'Credit card' then they would effectively be choosing it twice.

We have multiple payment gateways and on the checkout all of the payment method type options are presented together as a choice - so you have 'Credit card' and 'PayPal' coming from Braintree, and other ones coming from other payment gateways, all listed as radio buttons in a single choice.

In this patch the user is presented with a choice of payment gateway first and then choice of payment method type on the next page. The client specifically asked us to remove this patch because they thought it was confusing customers so it's a shame it's been merged, will make upgrading Commerce tricky in the future

Is it impossible for it to behave the same as the payment method type choice during checkout?

  • jsacksick committed 6058d98 on 8.x-2.x
    Revert "Issue #3015970 by thenchev, czigor, jsacksick: Adding a payment...
jsacksick’s picture

Status: Fixed » Needs work

You're actually right, what was implemented makes more sense for an admin form... (I.e what was implemented as part of #2912996: Support admin order payments).

The user pages should mimic as much as possible what's done in Checkout.

In any event, perhaps it is/was a bad idea to solve this issue without actually figuring out how to properly figure out irrelevant options (as described in #3218892: Allow payment gateways to explicitly indicate that they support creating reusable payment methods.

jsacksick’s picture

Status: Needs work » Needs review
FileSize
20.86 KB

I took a completely different approach as suggested by @Rob230 in comment #32 and now the form works like the PaymentInformation pane in Checkout.

A single step, where you select your "payment_method" using radio buttons (when there's more than one), and changing payment method refreshes the form via Ajax.

Because it now uses Ajax, I had to switch to write a FunctionalJavascriptTest.

  • jsacksick committed 24e78b4 on 8.x-2.x
    Issue #3015970 by jsacksick: Adding a payment method is only possible...
jsacksick’s picture

Status: Needs review » Fixed

Committing the patch in the absence of feedback!

Status: Fixed » Closed (fixed)

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

s_m_5353’s picture

I'm getting this error when I add manual payment gateway. I have other gateways enabled but i want to add a new gateway also as manual gateway.

Drupal\Component\Plugin\Exception\PluginNotFoundException: The "" plugin does not exist. Valid plugin IDs for Drupal\commerce\ConditionManager are: commerce_conditions_plus_and_operator, commerce_conditions_plus_or_operator, order_billing_address, order_currency, order_customer, order_customer_role, order_email, order_item_purchased_entity:commerce_product_variation, order_purchased_entity:commerce_product_variation, order_shipping_address, order_store, order_total_price, order_type, order_payment_gateway, order_item_product, order_item_product_category, order_item_product_type, order_item_variation_type, order_product, order_product_category, order_product_type, order_variation_type, order_item_quantity, shipment_address, shipment_quantity, shipment_weight in Drupal\Core\Plugin\DefaultPluginManager->doGetDefinition() (line 53 of core/lib/Drupal/Component/Plugin/Discovery/DiscoveryTrait.php).
Drupal\Core\Plugin\DefaultPluginManager->getDefinition() (Line: 16)
Drupal\Core\Plugin\Factory\ContainerFactory->createInstance() (Line: 83)
Drupal\Component\Plugin\PluginManagerBase->createInstance() (Line: 324)
Drupal\commerce_conditions_plus\Element\ConditionsTable::addNewCondition()
call_user_func_array() (Line: 114)
Drupal\Core\Form\FormSubmitter->executeSubmitHandlers() (Line: 52)
Drupal\Core\Form\FormSubmitter->doSubmitForm() (Line: 595)
Drupal\Core\Form\FormBuilder->processForm() (Line: 323)
Drupal\Core\Form\FormBuilder->buildForm() (Line: 73)
Drupal\Core\Controller\FormController->getContentResult()
call_user_func_array() (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext() (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 169)
Symfony\Component\HttpKernel\HttpKernel->handleRaw() (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle() (Line: 58)
Drupal\Core\StackMiddleware\Session->handle() (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle() (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass() (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle() (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle() (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle() (Line: 23)
Stack\StackedHttpKernel->handle() (Line: 718)
Drupal\Core\DrupalKernel->handle() (Line: 19)

jsacksick’s picture

The only Commerce code I'm seeing in your backtrace is:
Drupal\commerce_conditions_plus\Element\ConditionsTable::addNewCondition()

Which is coming from the Commerce conditions plus module it seems.