Commit 19a0833d authored by Erik Petra's avatar Erik Petra
Browse files

Issue #3320672 - Can't continue checkout after changing the shipping country...

Issue #3320672 - Can't continue checkout after changing the shipping country while using a non-Packeta shipping method on the checkout form
parent a7521d37
Loading
Loading
Loading
Loading
+104 −8
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ namespace Drupal\commerce_packeta\Plugin\Commerce\CheckoutPane;
use Drupal\commerce\InlineFormManager;
use Drupal\commerce_checkout\Plugin\Commerce\CheckoutFlow\CheckoutFlowInterface;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_shipping\Entity\ShipmentInterface;
use Drupal\commerce_shipping\OrderShipmentSummaryInterface;
use Drupal\commerce_shipping\PackerManagerInterface;
use Drupal\commerce_shipping\Plugin\Commerce\CheckoutPane\ShippingInformation;
@@ -65,10 +66,6 @@ class PickupCapableShippingInformation extends ShippingInformation {
   * {@inheritdoc}
   */
  public function buildPaneForm(array $pane_form, FormStateInterface $form_state, array &$complete_form) {
    $pane_form = parent::buildPaneForm($pane_form, $form_state, $complete_form);

    unset($pane_form['recalculate_shipping']);

    $store = $this->order->getStore();
    $available_countries = [];
    foreach ($store->get('shipping_countries') as $country_item) {
@@ -95,20 +92,101 @@ class PickupCapableShippingInformation extends ShippingInformation {
        'shipping_method' => $shipping_method,
      ], $this->getShippingProfilePickup(TRUE));
    }

    // Prepare the form for ajax.
    // Not using Html::getUniqueId() on the wrapper ID to avoid #2675688.
    $pane_form['#wrapper_id'] = 'shipping-information-wrapper';
    $pane_form['#prefix'] = '<div id="' . $pane_form['#wrapper_id'] . '">';
    $pane_form['#suffix'] = '</div>';
    // Auto recalculation is enabled only when a shipping profile is required.
    $pane_form['#auto_recalculate'] = !empty($this->configuration['auto_recalculate']) && !empty($this->configuration['require_shipping_profile']);
    $pane_form['#after_build'][] = [static::class, 'autoRecalculateProcess'];

    $pane_form['shipping_profile'] = [
      '#parents' => array_merge($pane_form['#parents'], ['shipping_profile']),
      '#inline_form' => $inline_form,
    ];
    $pane_form['shipping_profile'] = $inline_form->buildInlineForm($pane_form['shipping_profile'], $form_state);
    // The shipping_profile should always exist in form state
    if (!$form_state->has('shipping_profile')) {
    $triggering_element = $form_state->getTriggeringElement();
    // The shipping_profile should always exist in form state (and not just
    // after "Recalculate shipping" is clicked).
    if (!$form_state->has('shipping_profile') ||
      // For some reason, when the address selected is changed, the shipping
      // profile in form state is stale.
      (isset($triggering_element['#parents']) && in_array('select_address', $triggering_element['#parents'], TRUE))) {
      $form_state->set('shipping_profile', $inline_form->getEntity());
    }

    // Pickup custom: place at top.
    $pane_form['shipments']['#weight'] = -999;
    $class = get_class($this);
    // Ensure selecting a different address refreshes the entire form.
    if (isset($pane_form['shipping_profile']['select_address'])) {
      $pane_form['shipping_profile']['select_address']['#ajax'] = [
        'callback' => [$class, 'ajaxRefreshForm'],
        'element' => $pane_form['#parents'],
      ];
      // Selecting a different address should trigger a recalculation.
      $pane_form['shipping_profile']['select_address']['#recalculate'] = TRUE;
    }

    $pane_form['recalculate_shipping'] = [
      '#type' => 'button',
      '#value' => $this->t('Recalculate shipping'),
      '#recalculate' => TRUE,
      '#ajax' => [
        'callback' => [$class, 'ajaxRefreshForm'],
        'element' => $pane_form['#parents'],
      ],
      // The calculation process only needs a valid shipping profile.
      '#limit_validation_errors' => [
        array_merge($pane_form['#parents'], ['shipping_profile']),
      ],
      '#after_build' => [
        [static::class, 'clearValues'],
      ],
    ];
    $pane_form['removed_shipments'] = [
      '#type' => 'value',
      '#value' => [],
    ];
    $pane_form['shipments'] = [
      '#type' => 'container',
    ];

    $shipping_profile = $form_state->get('shipping_profile');
    $shipments = $this->order->get('shipments')->referencedEntities();
    $recalculate_shipping = $form_state->get('recalculate_shipping');
    $can_calculate_rates = $this->canCalculateRates($shipping_profile);

    // If the shipping recalculation is triggered, ensure the rates can
    // be recalculated (i.e a valid address is entered).
    if ($recalculate_shipping && !$can_calculate_rates) {
      $recalculate_shipping = FALSE;
      $shipments = [];
    }

    // Ensure the profile is saved with the latest address, it's necessary
    // to do that in case the profile isn't new, otherwise the shipping profile
    // referenced by the shipment won't reflect the updated address.
    if (!$shipping_profile->isNew() &&
      $shipping_profile->hasTranslationChanges() &&
      $can_calculate_rates) {
      $shipping_profile->save();
      $inline_form->setEntity($shipping_profile);
    }

    $force_packing = empty($shipments) && $can_calculate_rates;
    if ($recalculate_shipping || $force_packing) {
      // We're still relying on the packer manager for packing the order since
      // we don't want the shipments to be saved for performance reasons.
      // The shipments are saved on pane submission.
      [$shipments, $removed_shipments] = $this->packerManager->packToShipments($this->order, $shipping_profile, $shipments);

      // Store the IDs of removed shipments for submitPaneForm().
      $pane_form['removed_shipments']['#value'] = array_map(function ($shipment) {
        /** @var \Drupal\commerce_shipping\Entity\ShipmentInterface $shipment */
        return $shipment->id();
      }, $removed_shipments);
    }

    $single_shipment = count($shipments) === 1;
    foreach ($shipments as $index => $shipment) {
@@ -136,6 +214,24 @@ class PickupCapableShippingInformation extends ShippingInformation {
      ];
    }

    // Update the shipments and save the order if no rate was explicitly
    // selected, that usually occurs when changing addresses, this will ensure
    // the default rate is selected/applied.
    if (!$this->hasRateSelected($pane_form, $form_state) && ($recalculate_shipping || $force_packing)) {
      array_map(function (ShipmentInterface $shipment) {
        if (!$shipment->isNew()) {
          $shipment->save();
        }
      }, $shipments);
      $this->order->set('shipments', $shipments);
      $this->order->save();
    }

    // Pickup custom: place at top.
    $pane_form['shipments']['#weight'] = -999;

    unset($pane_form['recalculate_shipping']);

    return $pane_form;
  }

+5 −0
Original line number Diff line number Diff line
@@ -43,6 +43,11 @@ final class ProfileFieldCopyWithoutPickup extends ProfileFieldCopy {
    $order = self::getOrder($form_state);
    $form = $form_state->getCompleteForm()['packeta_capable_shipping_information'];

    if (!$form) {
      parent::submitForm($inline_form, $form_state);
      return;
    }

    if (PickupCapableShippingInformation::isPickupSelected($form, $form_state, $order)) {
      $form_state->setError($inline_form, t('Can not use "Billing same as shipping while choosing this shipping method"'));
    }