You are here

commerce_checkout.module in Commerce Core 8.2

Same filename and directory in other branches
  1. 7 modules/checkout/commerce_checkout.module

Provides configurable checkout flows.

File

modules/checkout/commerce_checkout.module
View source
<?php

/**
 * @file
 * Provides configurable checkout flows.
 */
use Drupal\commerce\EntityHelper;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\views\Form\ViewsForm;

/**
 * Implements hook_theme().
 */
function commerce_checkout_theme() {
  $theme = [
    'commerce_checkout_progress' => [
      'variables' => [
        'steps' => [],
      ],
    ],
    'commerce_checkout_completion_message' => [
      'variables' => [
        'order_entity' => NULL,
        'message' => NULL,
        'payment_instructions' => NULL,
      ],
    ],
    'commerce_checkout_form' => [
      'render element' => 'form',
    ],
    'commerce_checkout_form__with_sidebar' => [
      'base hook' => 'commerce_checkout_form',
    ],
    'commerce_checkout_order_summary' => [
      'variables' => [
        'order_entity' => NULL,
        'checkout_step' => '',
      ],
    ],
    'commerce_checkout_pane' => [
      'render element' => 'elements',
    ],
    'commerce_checkout_completion_register' => [
      'render element' => 'form',
    ],
  ];
  return $theme;
}

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function commerce_checkout_theme_suggestions_commerce_checkout_form(array $variables) {
  $original = $variables['theme_hook_original'];
  $suggestions = [];

  // If the checkout form has a sidebar, suggest the enhanced layout.
  if (isset($variables['form']['sidebar']) && Element::isVisibleElement($variables['form']['sidebar'])) {
    $suggestions[] = $original . '__with_sidebar';
  }
  return $suggestions;
}

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function commerce_checkout_theme_suggestions_commerce_checkout_pane(array $variables) {
  $original = $variables['theme_hook_original'];
  $suggestions = [];
  $suggestions[] = $original . '__' . $variables['elements']['#pane_id'];
  return $suggestions;
}

/**
 * Implements hook_preprocess_HOOK().
 */
function commerce_checkout_preprocess_commerce_checkout_order_summary(&$variables) {

  /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
  $order = $variables['order_entity'];

  /** @var \Drupal\commerce_order\OrderTotalSummaryInterface $order_total_summary */
  $order_total_summary = \Drupal::service('commerce_order.order_total_summary');
  $variables['totals'] = $order_total_summary
    ->buildTotals($order);
  $variables['rendered_totals'] = [
    '#theme' => 'commerce_order_total_summary',
    '#order_entity' => $order,
    '#totals' => $variables['totals'],
  ];
}

/**
 * Implements hook_entity_base_field_info().
 */
function commerce_checkout_entity_base_field_info(EntityTypeInterface $entity_type) {
  if ($entity_type
    ->id() === 'commerce_order') {
    $fields['checkout_flow'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Checkout flow'))
      ->setSetting('target_type', 'commerce_checkout_flow')
      ->setSetting('handler', 'default')
      ->setDisplayOptions('form', [
      'region' => 'hidden',
    ])
      ->setDisplayConfigurable('view', FALSE)
      ->setDisplayConfigurable('form', FALSE);

    // @todo Implement a custom widget that shows itself when the flow is set
    // and allows a step to be chosen from a dropdown.
    $fields['checkout_step'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Checkout step'))
      ->setDisplayOptions('form', [
      'region' => 'hidden',
    ])
      ->setDisplayConfigurable('view', FALSE)
      ->setDisplayConfigurable('form', FALSE);
    return $fields;
  }
}

/**
 * Implements hook_form_FORM_ID_alter() for 'commerce_order_type_form'.
 */
function commerce_checkout_form_commerce_order_type_form_alter(array &$form, FormStateInterface $form_state) {

  /** @var \Drupal\commerce_order\Entity\OrderTypeInterface $order_type */
  $order_type = $form_state
    ->getFormObject()
    ->getEntity();
  $storage = \Drupal::entityTypeManager()
    ->getStorage('commerce_checkout_flow');
  $checkout_flows = $storage
    ->loadMultiple();
  $form['commerce_checkout'] = [
    '#type' => 'details',
    '#title' => t('Checkout settings'),
    '#weight' => 5,
    '#open' => TRUE,
  ];
  $form['commerce_checkout']['checkout_flow'] = [
    '#type' => 'select',
    '#title' => t('Checkout flow'),
    '#options' => EntityHelper::extractLabels($checkout_flows),
    '#default_value' => $order_type
      ->getThirdPartySetting('commerce_checkout', 'checkout_flow', 'default'),
    '#required' => TRUE,
  ];
  $form['actions']['submit']['#submit'][] = 'commerce_checkout_order_type_form_submit';
}

/**
 * Submission handler for commerce_checkout_form_commerce_order_type_form_alter().
 */
function commerce_checkout_order_type_form_submit($form, FormStateInterface $form_state) {

  /** @var \Drupal\commerce_order\Entity\OrderTypeInterface $order_type */
  $order_type = $form_state
    ->getFormObject()
    ->getEntity();
  $settings = $form_state
    ->getValue([
    'commerce_checkout',
  ]);
  $order_type
    ->setThirdPartySetting('commerce_checkout', 'checkout_flow', $settings['checkout_flow']);
  $order_type
    ->save();
}

/**
 * Implements hook_form_alter().
 */
function commerce_checkout_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if ($form_state
    ->getFormObject() instanceof ViewsForm) {

    /** @var \Drupal\views\ViewExecutable $view */
    $view = reset($form_state
      ->getBuildInfo()['args']);

    // Only add the Checkout button if the cart form view has order items.
    if ($view->storage
      ->get('tag') == 'commerce_cart_form' && !empty($view->result)) {
      $form['actions']['checkout'] = [
        '#type' => 'submit',
        '#value' => t('Checkout'),
        '#weight' => 5,
        '#access' => \Drupal::currentUser()
          ->hasPermission('access checkout'),
        '#submit' => array_merge($form['#submit'], [
          'commerce_checkout_order_item_views_form_submit',
        ]),
        '#order_id' => $view->argument['order_id']->value[0],
        '#update_cart' => TRUE,
        '#show_update_message' => FALSE,
      ];
    }
  }
}

/**
 * Submit handler used to redirect to the checkout page.
 */
function commerce_checkout_order_item_views_form_submit($form, FormStateInterface $form_state) {
  $order_id = $form_state
    ->getTriggeringElement()['#order_id'];
  $form_state
    ->setRedirect('commerce_checkout.form', [
    'commerce_order' => $order_id,
  ]);
}