View source
<?php
namespace Drupal\commerce_shipping\Form;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_shipping\PackageTypeManagerInterface;
use Drupal\commerce_shipping\ShipmentItem;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\physical\Weight;
use Drupal\physical\WeightUnit;
use Drupal\profile\Entity\ProfileInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class ShipmentForm extends ContentEntityForm {
protected $packageTypeManager;
public function __construct(EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info, TimeInterface $time, PackageTypeManagerInterface $package_type_manager) {
parent::__construct($entity_repository, $entity_type_bundle_info, $time);
$this->packageTypeManager = $package_type_manager;
}
public static function create(ContainerInterface $container) {
return new static($container
->get('entity.repository'), $container
->get('entity_type.bundle.info'), $container
->get('datetime.time'), $container
->get('plugin.manager.commerce_package_type'));
}
public function form(array $form, FormStateInterface $form_state) {
$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);
}
$order = $shipment
->getOrder();
$shipping_profile = $shipment
->getShippingProfile();
if (!$shipping_profile) {
$shipment_type = $this->entityTypeManager
->getStorage('commerce_shipment_type')
->load($shipment
->bundle());
$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);
}
$form_state
->set('original_amount', $shipment
->getAmount());
$form = parent::form($form, $form_state);
$form['shipping_profile']['widget'][0]['#type'] = 'fieldset';
if (empty($form['shipping_method']['widget'][0]['#options'])) {
$form['shipping_method']['#access'] = FALSE;
}
$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();
$shipment_storage = $this->entityTypeManager
->getStorage('commerce_shipment');
$order_shipments = $shipment_storage
->loadMultipleByOrder($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 = [];
$shipment_item_defaults = [];
$shipment_items = $shipment
->getItems();
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();
}
foreach ($order_items as $order_item) {
if (isset($shipment_item_options[$order_item
->id()]) || !$order_item
->hasField('purchased_entity') || in_array($order_item
->id(), $already_on_shipment, TRUE)) {
continue;
}
$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'],
],
'#limit_validation_errors' => [
array_merge($form['#parents'], [
'shipping_profile',
]),
],
'#weight' => 49,
'#after_build' => [
[
static::class,
'clearValues',
],
],
];
return $form;
}
public static function ajaxRefresh(array $form, FormStateInterface $form_state) {
$triggering_element = $form_state
->getTriggeringElement();
$parents = array_slice($triggering_element['#parents'], 0, -1);
return NestedArray::getValue($form, $parents);
}
public static function clearValues(array $element, FormStateInterface $form_state) {
$triggering_element = $form_state
->getTriggeringElement();
if (!$triggering_element) {
return $element;
}
$triggering_element_name = end($triggering_element['#parents']);
if ($triggering_element_name === 'recalculate_shipping') {
$user_input =& $form_state
->getUserInput();
unset($user_input['shipping_method']);
}
return $element;
}
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
$triggering_element = $form_state
->getTriggeringElement();
$recalculate = !empty($triggering_element['#recalculate']);
if ($recalculate) {
$form_state
->set('recalculate_shipping', TRUE);
$shipment = $this->entity;
$shipment
->setTitle($form_state
->getValue('title'));
$base_form_key = [
'shipping_profile',
'0',
'profile',
];
$selected_profile_key = array_merge($base_form_key, [
'select_address',
]);
$selected_profile_id = $form_state
->getValue($selected_profile_key);
$address_key = array_merge($base_form_key, [
'address',
'0',
'address',
]);
$address = $form_state
->getValue($address_key);
if ($address !== NULL) {
$shipment
->getShippingProfile()
->get('address')
->setValue($address);
}
elseif ($selected_profile_id !== '_original') {
$profile_storage = $this->entityTypeManager
->getStorage('profile');
$selected_profile = $profile_storage
->load($selected_profile_id);
assert($selected_profile instanceof ProfileInterface);
$shipment
->getShippingProfile()
->set('address', $selected_profile
->get('address'));
}
$this
->addShippingItems($form, $form_state);
if (empty($form_state
->getValue('package_type'))) {
return;
}
$package_type = $this->packageTypeManager
->createInstance($form_state
->getValue('package_type'));
$shipment
->setPackageType($package_type);
}
}
public function save(array $form, FormStateInterface $form_state) {
$shipment = $this
->getEntity();
$this
->addShippingItems($form, $form_state);
$shipment
->setData('owned_by_packer', FALSE);
$shipment
->save();
$order = $shipment
->getOrder();
$order_shipments = $order
->get('shipments');
$shipment_exists = FALSE;
$save_order = FALSE;
foreach ($order_shipments
->getValue() as $order_shipment) {
if ($order_shipment['target_id'] == $shipment
->id()) {
$shipment_exists = TRUE;
}
}
if ($form_state
->get('original_amount') != $shipment
->getAmount()) {
$order
->setRefreshState(OrderInterface::REFRESH_ON_SAVE);
$save_order = TRUE;
}
if (!$shipment_exists) {
$order_shipments
->appendItem($shipment);
$save_order = TRUE;
}
if ($save_order) {
$order
->save();
}
$this
->messenger()
->addMessage($this
->t('Shipment for order @order created.', [
'@order' => $order
->getOrderNumber(),
]));
$form_state
->setRedirect('entity.commerce_shipment.collection', [
'commerce_order' => $order
->id(),
]);
}
protected function addShippingItems(array &$form, FormStateInterface $form_state) {
$shipment = $this->entity;
$shipment
->setItems([]);
foreach ($form_state
->getValue('shipment_items') as $key => $value) {
if ($value == 0) {
continue;
}
$order_item = $this->entityTypeManager
->getStorage('commerce_order_item')
->load($key);
$quantity = $order_item
->getQuantity();
$purchased_entity = $order_item
->getPurchasedEntity();
if ($purchased_entity
->get('weight')
->isEmpty()) {
$weight = new Weight(1, WeightUnit::GRAM);
}
else {
$weight_item = $purchased_entity
->get('weight')
->first();
$weight = $weight_item
->toMeasurement();
}
$shipment_item = new ShipmentItem([
'order_item_id' => $order_item
->id(),
'title' => $purchased_entity
->label(),
'quantity' => $quantity,
'weight' => $weight
->multiply($quantity),
'declared_value' => $order_item
->getTotalPrice(),
]);
$shipment
->addItem($shipment_item);
}
}
}