Skip to content

Commit

Permalink
Issue #2902408 by chrisrockwell, bojanz: Applying a coupon saves the …
Browse files Browse the repository at this point in the history
…other checkout panes
  • Loading branch information
bojanz authored and bojanz committed Sep 14, 2017
1 parent 6e000f9 commit f1665ea
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,19 @@ protected function setUp() {
$this->promotion->save();

/** @var \Drupal\commerce_payment\Entity\PaymentGateway $gateway */
$gateway = PaymentGateway::create([
$offsite_gateway = PaymentGateway::create([
'id' => 'offsite',
'label' => 'Off-site',
'plugin' => 'example_offsite_redirect',
'configuration' => [
'redirect_method' => 'post',
'payment_method_types' => ['credit_card'],
],
]);
$offsite_gateway->save();

/** @var \Drupal\commerce_payment\Entity\PaymentGateway $gateway */
$onsite_gateway = PaymentGateway::create([
'id' => 'onsite',
'label' => 'On-site',
'plugin' => 'example_onsite',
Expand All @@ -111,7 +123,7 @@ protected function setUp() {
'payment_method_types' => ['credit_card'],
],
]);
$gateway->save();
$onsite_gateway->save();

$profile = $this->createEntity('profile', [
'type' => 'customer',
Expand Down Expand Up @@ -267,4 +279,47 @@ public function testCheckoutWithMainSubmit() {
$this->assertEquals(new Price('899.10', 'USD'), $this->cart->getTotalPrice());
}

/**
* Tests that adding/removing coupons does not submit other panes.
*/
public function testCheckoutSubmit() {
// Start checkout, and enter billing information.
$this->drupalGet(Url::fromRoute('commerce_checkout.form', ['commerce_order' => $this->cart->id()]));
$this->getSession()->getPage()->findField('Example')->check();
$this->waitForAjaxToFinish();
$this->submitForm([
'payment_information[billing_information][address][0][address][given_name]' => 'Johnny',
'payment_information[billing_information][address][0][address][family_name]' => 'Appleseed',
'payment_information[billing_information][address][0][address][address_line1]' => '123 New York Drive',
'payment_information[billing_information][address][0][address][locality]' => 'New York City',
'payment_information[billing_information][address][0][address][administrative_area]' => 'NY',
'payment_information[billing_information][address][0][address][postal_code]' => '10001',
], 'Continue to review');

// Go back and edit the billing information, but don't submit it.
$this->getSession()->getPage()->clickLink('Go back');
$address_prefix = 'payment_information[billing_information][address][0][address]';
$this->getSession()->getPage()->fillField($address_prefix . '[given_name]', 'John');
$this->getSession()->getPage()->fillField($address_prefix . '[family_name]', 'Smith');

// Add a coupon.
$coupons = $this->promotion->getCoupons();
$coupon = reset($coupons);
$page = $this->getSession()->getPage();
$page->fillField('Coupon code', $coupon->getCode());
$page->pressButton('Apply coupon');
$this->waitForAjaxToFinish();
$this->assertSession()->pageTextContains($coupon->getCode());
$this->assertSession()->fieldNotExists('Coupon code');
$this->assertSession()->buttonNotExists('Apply coupon');

// Refresh the page and ensure the billing information hasn't been modified.
$this->drupalGet(Url::fromRoute('commerce_checkout.form', ['commerce_order' => $this->cart->id(), 'step' => 'order_information']));
$page = $this->getSession()->getPage();
$given_name_field = $page->findField('payment_information[billing_information][address][0][address][given_name]');
$family_name_field = $page->findField('payment_information[billing_information][address][0][address][family_name]');
$this->assertEquals($given_name_field->getValue(), 'Johnny');
$this->assertEquals($family_name_field->getValue(), 'Appleseed');
}

}
43 changes: 39 additions & 4 deletions src/Element/CommerceElementTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Drupal\commerce\Element;

use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;

Expand Down Expand Up @@ -71,21 +72,55 @@ public static function validateElementSubmit(array &$element, FormStateInterface
* step of validation, allowing thrown exceptions to be converted into form
* errors.
*
* @param array $element
* The form element.
* @param array &$form
* The form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*/
public static function executeElementSubmitHandlers(array &$element, FormStateInterface $form_state) {
public static function executeElementSubmitHandlers(array &$form, FormStateInterface $form_state) {
if (!$form_state->isSubmitted() || $form_state->hasAnyErrors()) {
// The form wasn't submitted (#ajax in progress) or failed validation.
return;
}
// A submit button might need to process only a part of the form.
// For example, the "Apply coupon" button at checkout should apply coupons,
// but not save the payment information. Use #limit_validation_errors
// as a guideline for which parts of the form to submit.
$triggering_element = $form_state->getTriggeringElement();
if (isset($triggering_element['#limit_validation_errors']) && $triggering_element['#limit_validation_errors'] !== FALSE) {
// #limit_validation_errors => [], the button cares about nothing.
if (empty($triggering_element['#limit_validation_errors'])) {
return;
}

foreach ($triggering_element['#limit_validation_errors'] as $limit_validation_errors) {
$element = NestedArray::getValue($form, $limit_validation_errors);
if (!$element) {
// The element will be empty if #parents don't match #array_parents,
// the case for IEF widgets. In that case just submit everything.
$element = &$form;
}
self::doExecuteSubmitHandlers($element, $form_state);
}
}
else {
self::doExecuteSubmitHandlers($form, $form_state);
}
}

/**
* Calls the #commerce_element_submit callbacks recursively.
*
* @param array &$element
* The current element.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*/
public static function doExecuteSubmitHandlers(array &$element, FormStateInterface $form_state) {
// Recurse through all children.
foreach (Element::children($element) as $key) {
if (!empty($element[$key])) {
static::executeElementSubmitHandlers($element[$key], $form_state);
static::doExecuteSubmitHandlers($element[$key], $form_state);
}
}

Expand Down

0 comments on commit f1665ea

Please sign in to comment.