You are here

public function ShipmentForm::form in Commerce Shipping 8.2

Gets the actual form array to be built.

Overrides ContentEntityForm::form

See also

\Drupal\Core\Entity\EntityForm::processForm()

\Drupal\Core\Entity\EntityForm::afterBuild()

File

src/Form/ShipmentForm.php, line 64

Class

ShipmentForm
Defines the shipment add/edit form.

Namespace

Drupal\commerce_shipping\Form

Code

public function form(array $form, FormStateInterface $form_state) {

  /** @var \Drupal\commerce_shipping\Entity\ShipmentInterface $shipment */
  $shipment = $this->entity;
  $order_id = $shipment
    ->get('order_id')->target_id;
  if (!$order_id) {
    $order_id = $this
      ->getRouteMatch()
      ->getRawParameter('commerce_order');
    $shipment
      ->set('order_id', $order_id);
  }

  /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
  $order = $shipment
    ->getOrder();

  /** @var \Drupal\profile\Entity\ProfileInterface $shipping_profile */
  $shipping_profile = $shipment
    ->getShippingProfile();
  if (!$shipping_profile) {

    /** @var \Drupal\commerce_shipping\Entity\ShipmentTypeInterface $shipment_type */
    $shipment_type = $this->entityTypeManager
      ->getStorage('commerce_shipment_type')
      ->load($shipment
      ->bundle());

    /** @var \Drupal\profile\Entity\ProfileInterface $shipping_profile */
    $shipping_profile = $this->entityTypeManager
      ->getStorage('profile')
      ->create([
      'type' => $shipment_type
        ->getProfileTypeId(),
      'uid' => 0,
    ]);
    $address = [
      '#type' => 'address',
      '#default_value' => [],
    ];
    $shipping_profile
      ->set('address', $address);
    $shipment
      ->setShippingProfile($shipping_profile);
  }

  // Store the original amount for ShipmentForm::save().
  $form_state
    ->set('original_amount', $shipment
    ->getAmount());
  $form = parent::form($form, $form_state);

  // The ShippingProfileWidget doesn't output a fieldset because that makes
  // sense in a checkout context, but on the admin form it is clearer for
  // profile fields to be visually grouped.
  $form['shipping_profile']['widget'][0]['#type'] = 'fieldset';

  // Fixes illegal choice has been detected message upon AJAX reload.
  if (empty($form['shipping_method']['widget'][0]['#options'])) {
    $form['shipping_method']['#access'] = FALSE;
  }

  // Prepare the form for ajax.
  // Not using Html::getUniqueId() on the wrapper ID to avoid #2675688.
  $form['#wrapper_id'] = 'shipping-information-wrapper';
  $form['#prefix'] = '<div id="' . $form['#wrapper_id'] . '">';
  $form['#suffix'] = '</div>';
  $package_types = $this->packageTypeManager
    ->getDefinitions();
  $package_type_options = [];
  foreach ($package_types as $package_type) {
    $unit = ' ' . array_pop($package_type['dimensions']);
    $dimensions = ' (' . implode(' x ', $package_type['dimensions']) . $unit . ')';
    $package_type_options[$package_type['id']] = $package_type['label'] . $dimensions;
  }
  $package_type = $shipment
    ->getPackageType();
  $form['package_type'] = [
    '#type' => 'select',
    '#title' => $this
      ->t('Package Type'),
    '#options' => $package_type_options,
    '#default_value' => $package_type ? $package_type
      ->getId() : '',
    '#access' => count($package_types) > 1,
  ];
  $order_items = $order
    ->getItems();

  /** @var \Drupal\commerce_shipping\ShipmentStorageInterface $shipment_storage */
  $shipment_storage = $this->entityTypeManager
    ->getStorage('commerce_shipment');

  // Get all of the shipments for the current order.
  $order_shipments = $shipment_storage
    ->loadMultipleByOrder($order);

  // Store order_items that are already tied to shipments on this order.
  $already_on_shipment = [];
  foreach ($order_shipments as $order_shipment) {
    if ($order_shipment
      ->id() != $shipment
      ->id()) {
      $shipment_items = $order_shipment
        ->getItems();
      foreach ($shipment_items as $shipment_item) {
        $order_item_id = $shipment_item
          ->getOrderItemId();
        $already_on_shipment[$order_item_id] = $order_item_id;
      }
    }
  }
  $shipment_item_options = [];

  // Populates the default values by looking at the items already in this
  // shipment.
  $shipment_item_defaults = [];
  $shipment_items = $shipment
    ->getItems();

  /** @var \Drupal\commerce_shipping\ShipmentItem $shipment_item */
  foreach ($shipment_items as $shipment_item) {
    $shipment_item_id = $shipment_item
      ->getOrderItemId();
    $shipment_item_defaults[$shipment_item_id] = $shipment_item_id;
    $shipment_item_options[$shipment_item_id] = $shipment_item
      ->getTitle();
  }

  /** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */
  foreach ($order_items as $order_item) {

    // Skip shipment items that are already on this shipment.
    if (isset($shipment_item_options[$order_item
      ->id()]) || !$order_item
      ->hasField('purchased_entity') || in_array($order_item
      ->id(), $already_on_shipment, TRUE)) {
      continue;
    }

    // Only allow items that aren't already on a shipment
    // have a purchasable entity and implement the shippable trait.
    $purchasable_entity = $order_item
      ->getPurchasedEntity();
    if (!empty($purchasable_entity) && $purchasable_entity
      ->hasField('weight')) {
      $shipment_item_options[$order_item
        ->id()] = $order_item
        ->label();
    }
  }
  $form['shipment_items'] = [
    '#type' => 'checkboxes',
    '#title' => $this
      ->t('Shipment items'),
    '#options' => $shipment_item_options,
    '#default_value' => $shipment_item_defaults,
    '#required' => TRUE,
    '#weight' => 48,
  ];
  $form['recalculate_shipping'] = [
    '#type' => 'button',
    '#value' => $this
      ->t('Recalculate shipping'),
    '#recalculate' => TRUE,
    '#ajax' => [
      'callback' => [
        get_class($this),
        'ajaxRefresh',
      ],
      'wrapper' => $form['#wrapper_id'],
    ],
    // The calculation process only needs a valid shipping profile.
    '#limit_validation_errors' => [
      array_merge($form['#parents'], [
        'shipping_profile',
      ]),
    ],
    '#weight' => 49,
    '#after_build' => [
      [
        static::class,
        'clearValues',
      ],
    ],
  ];
  return $form;
}