diff --git a/modules/payment/src/Form/PaymentMethodAddForm.php b/modules/payment/src/Form/PaymentMethodAddForm.php index f4dc0472..5833525c 100644 --- a/modules/payment/src/Form/PaymentMethodAddForm.php +++ b/modules/payment/src/Form/PaymentMethodAddForm.php @@ -65,41 +65,88 @@ class PaymentMethodAddForm extends FormBase implements ContainerInjectionInterfa * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state, UserInterface $user = NULL) { - $payment_gateway = $form_state->get('payment_gateway'); - if (!$payment_gateway) { - /** @var \Drupal\commerce_payment\PaymentGatewayStorageInterface $payment_gateway_storage */ + $step = $form_state->get('step'); + if (!$step) { + $step = 'payment_gateway'; $payment_gateway_storage = $this->entityTypeManager->getStorage('commerce_payment_gateway'); - $payment_gateway = $payment_gateway_storage->loadForUser($user); - // @todo Move this check to the access handler. - if (!$payment_gateway || !($payment_gateway->getPlugin() instanceof SupportsStoredPaymentMethodsInterface)) { + $payment_gateways = $payment_gateway_storage->loadByProperties(['status' => TRUE]); + $payment_gateways = array_filter($payment_gateways, function ($payment_gateway) { + return $payment_gateway->getPlugin() instanceof SupportsStoredPaymentMethodsInterface; + }); + $form_state->set('payment_gateways', $payment_gateways); + $payment_gateways_count = count($payment_gateways); + if ($payment_gateways_count == 0) { throw new AccessDeniedHttpException(); } - $form_state->set('payment_gateway', $payment_gateway); + elseif ($payment_gateways_count == 1) { + $payment_gateway = reset($payment_gateways); + $form_state->set('payment_gateway', $payment_gateway); + $step = 'payment_method_type'; + } + else { + $step = 'payment_gateway'; + } + $form_state->set('step', $step); } - $step = $form_state->get('step'); - if (!$step) { - $step = 'payment_method_type'; + if ($step == 'payment_method_type') { // Skip the payment method type selection if there's only 1 type. + $payment_gateway = $form_state->get('payment_gateway'); $payment_method_types = $payment_gateway->getPlugin()->getPaymentMethodTypes(); if (count($payment_method_types) === 1) { /** @var \Drupal\commerce_payment\Plugin\Commerce\PaymentMethodType\PaymentMethodTypeInterface $payment_method_type */ $payment_method_type = reset($payment_method_types); $form_state->set('payment_method_type', $payment_method_type->getPluginId()); $step = 'payment_method'; + $form_state->set('step', $step); } - $form_state->set('step', $step); } - if ($step == 'payment_method_type') { + if ($step == 'payment_gateway') { + $form = $this->buildPaymentGatewayForm($form, $form_state); + } + elseif ($step == 'payment_method_type') { $form = $this->buildPaymentMethodTypeForm($form, $form_state); } elseif ($step == 'payment_method') { $form = $this->buildPaymentMethodForm($form, $form_state); } - return $form; } + /** + * Builds the form for selecting a payment gateway. + * + * @param array $form + * The parent form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the complete form. + * + * @return array + * The built form. + */ + protected function buildPaymentGatewayForm(array $form, FormStateInterface $form_state) { + $payment_gateways = $form_state->get('payment_gateways'); + $payment_gateway_options = array_map(function ($payment_gateway) { + /** @var \Drupal\commerce_payment\Entity\PaymentGateway $payment_gateway */ + return $payment_gateway->label(); + }, $payment_gateways); + + $form['payment_gateway'] = [ + '#type' => 'radios', + '#title' => $this->t('Payment gateway'), + '#options' => $payment_gateway_options, + '#default_value' => '', + '#required' => TRUE, + ]; + $form['actions']['submit'] = [ + '#type' => 'submit', + '#value' => $this->t('Continue'), + '#button_type' => 'primary', + ]; + + return $form; + } + /** * Builds the form for selecting a payment method type. * @@ -175,7 +222,13 @@ class PaymentMethodAddForm extends FormBase implements ContainerInjectionInterfa */ public function submitForm(array &$form, FormStateInterface $form_state) { $step = $form_state->get('step'); - if ($step == 'payment_method_type') { + if ($step == 'payment_gateway') { + $payment_gateway = $this->entityTypeManager->getStorage('commerce_payment_gateway')->load($form_state->getValue('payment_gateway')); + $form_state->set('payment_gateway', $payment_gateway); + $form_state->set('step', 'payment_method_type'); + $form_state->setRebuild(TRUE); + } + elseif ($step == 'payment_method_type') { $form_state->set('payment_method_type', $form_state->getValue('payment_method_type')); $form_state->set('step', 'payment_method'); $form_state->setRebuild(TRUE); diff --git a/modules/payment/tests/src/Functional/PaymentMethodTest.php b/modules/payment/tests/src/Functional/PaymentMethodTest.php index 22539305..0bbcb762 100644 --- a/modules/payment/tests/src/Functional/PaymentMethodTest.php +++ b/modules/payment/tests/src/Functional/PaymentMethodTest.php @@ -96,13 +96,12 @@ class PaymentMethodTest extends CommerceBrowserTestBase { 'address' => $default_address, ]); - /** @var \Drupal\commerce_payment_example\Plugin\Commerce\PaymentGateway\OnsiteInterface $plugin */ $this->drupalGet($this->collectionUrl); $this->getSession()->getPage()->clickLink('Add payment method'); $this->assertSession()->addressEquals($this->collectionUrl . '/add'); // Confirm that the default profile's address is rendered. + $prefix = 'payment_method[billing_information][address][0][address]'; foreach ($default_address as $property => $value) { - $prefix = 'payment_method[billing_information][address][0][address]'; $this->assertSession()->pageTextContains($value); $this->assertSession()->fieldNotExists($prefix . '[' . $property . ']'); } @@ -160,6 +159,60 @@ class PaymentMethodTest extends CommerceBrowserTestBase { $this->assertTrue($billing_profile->get('address')->equals($default_profile->get('address'))); } + /** + * Tests the payment method add form in case of multiple gateways. + */ + public function testPaymentMethodCreateWithMultipleGateways() { + $this->createEntity('commerce_payment_gateway', [ + 'id' => 'onsite_2', + 'label' => 'Onsite Example 2', + 'plugin' => 'example_onsite', + ]); + + $this->createEntity('commerce_payment_gateway', [ + 'id' => 'offsite', + 'label' => 'Offsite', + 'plugin' => 'example_offsite_redirect', + ]); + + $default_address = [ + 'country_code' => 'US', + 'administrative_area' => 'SC', + 'locality' => 'Greenville', + 'postal_code' => '29616', + 'address_line1' => '9 Drupal Ave', + 'given_name' => 'Bryan', + 'family_name' => 'Centarro', + ]; + $this->createEntity('profile', [ + 'type' => 'customer', + 'uid' => $this->user->id(), + 'address' => $default_address, + ]); + + $this->drupalGet($this->collectionUrl . '/add'); + $this->assertSession()-> elementExists('css', '[value="example"]'); + $this->assertSession()-> elementExists('css', '[value="onsite_2"]'); + $this->assertSession()-> elementNotExists('css', '[value="offsite"]'); + //$this->assertSession()-> fieldExists('onsite_2'); + //$this->assertSession()-> fieldNotExists('offsite'); + $this->submitForm(['payment_gateway' => 'onsite_2'], 'Continue'); + + $form_values = [ + 'payment_method[payment_details][number]' => '4111111111111111', + 'payment_method[payment_details][expiration][month]' => '01', + 'payment_method[payment_details][expiration][year]' => date('Y') + 1, + 'payment_method[payment_details][security_code]' => '111', + ]; + $this->submitForm($form_values, 'Save'); + $this->assertSession()->addressEquals($this->collectionUrl); + $this->assertSession()->pageTextContains('Visa ending in 1111 saved to your payment methods.'); + + $payment_method = PaymentMethod::load(1); + $this->assertEquals($payment_method->getPaymentGateway()->getPluginId(), 'example_onsite'); + $this->assertEquals($payment_method->getPaymentGateway()->id(), 'onsite_2'); + } + /** * Tests creating and updating a payment method without billing information. */ @@ -169,7 +222,6 @@ class PaymentMethodTest extends CommerceBrowserTestBase { ]); $this->paymentGateway->save(); - /** @var \Drupal\commerce_payment_example\Plugin\Commerce\PaymentGateway\OnsiteInterface $plugin */ $this->drupalGet($this->collectionUrl); $this->getSession()->getPage()->clickLink('Add payment method'); $this->assertSession()->addressEquals($this->collectionUrl . '/add'); @@ -208,7 +260,6 @@ class PaymentMethodTest extends CommerceBrowserTestBase { * Tests creating a payment method declined by the remote API. */ public function testPaymentMethodDecline() { - /** @var \Drupal\commerce_payment_example\Plugin\Commerce\PaymentGateway\OnsiteInterface $plugin */ $this->drupalGet($this->collectionUrl); $this->getSession()->getPage()->clickLink('Add payment method'); $this->assertSession()->addressEquals($this->collectionUrl . '/add');