commerce-8.x-2.8/modules/order/src/Entity/Order.php
modules/order/src/Entity/Order.php
<?php
namespace Drupal\commerce_order\Entity;
use Drupal\commerce\Entity\CommerceContentEntityBase;
use Drupal\commerce_order\Adjustment;
use Drupal\commerce_store\Entity\StoreInterface;
use Drupal\Core\Entity\EntityChangedTrait;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\user\UserInterface;
use Drupal\profile\Entity\ProfileInterface;
/**
* Defines the order entity class.
*
* @ContentEntityType(
* id = "commerce_order",
* label = @Translation("Order"),
* label_collection = @Translation("Orders"),
* label_singular = @Translation("order"),
* label_plural = @Translation("orders"),
* label_count = @PluralTranslation(
* singular = "@count order",
* plural = "@count orders",
* ),
* bundle_label = @Translation("Order type"),
* handlers = {
* "event" = "Drupal\commerce_order\Event\OrderEvent",
* "storage" = "Drupal\commerce_order\OrderStorage",
* "access" = "Drupal\commerce_order\OrderAccessControlHandler",
* "permission_provider" = "Drupal\commerce_order\OrderPermissionProvider",
* "list_builder" = "Drupal\commerce_order\OrderListBuilder",
* "views_data" = "Drupal\commerce\CommerceEntityViewsData",
* "form" = {
* "default" = "Drupal\commerce_order\Form\OrderForm",
* "add" = "Drupal\commerce_order\Form\OrderForm",
* "edit" = "Drupal\commerce_order\Form\OrderForm",
* "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
* "unlock" = "Drupal\commerce_order\Form\OrderUnlockForm",
* },
* "route_provider" = {
* "default" = "Drupal\commerce_order\OrderRouteProvider",
* "delete-multiple" = "Drupal\entity\Routing\DeleteMultipleRouteProvider",
* },
* },
* base_table = "commerce_order",
* admin_permission = "administer commerce_order",
* permission_granularity = "bundle",
* entity_keys = {
* "id" = "order_id",
* "label" = "order_number",
* "uuid" = "uuid",
* "bundle" = "type"
* },
* links = {
* "canonical" = "/admin/commerce/orders/{commerce_order}",
* "edit-form" = "/admin/commerce/orders/{commerce_order}/edit",
* "delete-form" = "/admin/commerce/orders/{commerce_order}/delete",
* "delete-multiple-form" = "/admin/commerce/orders/delete",
* "reassign-form" = "/admin/commerce/orders/{commerce_order}/reassign",
* "unlock-form" = "/admin/commerce/orders/{commerce_order}/unlock",
* "collection" = "/admin/commerce/orders"
* },
* bundle_entity_type = "commerce_order_type",
* field_ui_base_route = "entity.commerce_order_type.edit_form"
* )
*/
class Order extends CommerceContentEntityBase implements OrderInterface {
use EntityChangedTrait;
/**
* {@inheritdoc}
*/
public function getOrderNumber() {
return $this->get('order_number')->value;
}
/**
* {@inheritdoc}
*/
public function setOrderNumber($order_number) {
$this->set('order_number', $order_number);
return $this;
}
/**
* {@inheritdoc}
*/
public function getStore() {
return $this->getTranslatedReferencedEntity('store_id');
}
/**
* {@inheritdoc}
*/
public function setStore(StoreInterface $store) {
$this->set('store_id', $store->id());
return $this;
}
/**
* {@inheritdoc}
*/
public function getStoreId() {
return $this->get('store_id')->target_id;
}
/**
* {@inheritdoc}
*/
public function setStoreId($store_id) {
$this->set('store_id', $store_id);
return $this;
}
/**
* {@inheritdoc}
*/
public function getCustomer() {
return $this->get('uid')->entity;
}
/**
* {@inheritdoc}
*/
public function setCustomer(UserInterface $account) {
$this->set('uid', $account->id());
return $this;
}
/**
* {@inheritdoc}
*/
public function getCustomerId() {
return $this->get('uid')->target_id;
}
/**
* {@inheritdoc}
*/
public function setCustomerId($uid) {
$this->set('uid', $uid);
return $this;
}
/**
* {@inheritdoc}
*/
public function getEmail() {
return $this->get('mail')->value;
}
/**
* {@inheritdoc}
*/
public function setEmail($mail) {
$this->set('mail', $mail);
return $this;
}
/**
* {@inheritdoc}
*/
public function getIpAddress() {
return $this->get('ip_address')->value;
}
/**
* {@inheritdoc}
*/
public function setIpAddress($ip_address) {
$this->set('ip_address', $ip_address);
return $this;
}
/**
* {@inheritdoc}
*/
public function getBillingProfile() {
return $this->get('billing_profile')->entity;
}
/**
* {@inheritdoc}
*/
public function setBillingProfile(ProfileInterface $profile) {
$this->set('billing_profile', $profile);
return $this;
}
/**
* {@inheritdoc}
*/
public function getItems() {
return $this->get('order_items')->referencedEntities();
}
/**
* {@inheritdoc}
*/
public function setItems(array $order_items) {
$this->set('order_items', $order_items);
$this->recalculateTotalPrice();
return $this;
}
/**
* {@inheritdoc}
*/
public function hasItems() {
return !$this->get('order_items')->isEmpty();
}
/**
* {@inheritdoc}
*/
public function addItem(OrderItemInterface $order_item) {
if (!$this->hasItem($order_item)) {
$this->get('order_items')->appendItem($order_item);
$this->recalculateTotalPrice();
}
return $this;
}
/**
* {@inheritdoc}
*/
public function removeItem(OrderItemInterface $order_item) {
$index = $this->getItemIndex($order_item);
if ($index !== FALSE) {
$this->get('order_items')->offsetUnset($index);
$this->recalculateTotalPrice();
}
return $this;
}
/**
* {@inheritdoc}
*/
public function hasItem(OrderItemInterface $order_item) {
return $this->getItemIndex($order_item) !== FALSE;
}
/**
* Gets the index of the given order item.
*
* @param \Drupal\commerce_order\Entity\OrderItemInterface $order_item
* The order item.
*
* @return int|bool
* The index of the given order item, or FALSE if not found.
*/
protected function getItemIndex(OrderItemInterface $order_item) {
$values = $this->get('order_items')->getValue();
$order_item_ids = array_map(function ($value) {
return $value['target_id'];
}, $values);
return array_search($order_item->id(), $order_item_ids);
}
/**
* {@inheritdoc}
*/
public function getAdjustments() {
return $this->get('adjustments')->getAdjustments();
}
/**
* {@inheritdoc}
*/
public function setAdjustments(array $adjustments) {
$this->set('adjustments', $adjustments);
$this->recalculateTotalPrice();
return $this;
}
/**
* {@inheritdoc}
*/
public function addAdjustment(Adjustment $adjustment) {
$this->get('adjustments')->appendItem($adjustment);
$this->recalculateTotalPrice();
return $this;
}
/**
* {@inheritdoc}
*/
public function removeAdjustment(Adjustment $adjustment) {
$this->get('adjustments')->removeAdjustment($adjustment);
$this->recalculateTotalPrice();
return $this;
}
/**
* {@inheritdoc}
*/
public function clearAdjustments() {
$locked_callback = function ($adjustment) {
/** @var \Drupal\commerce_order\Adjustment $adjustment */
return $adjustment->isLocked();
};
// Remove all unlocked adjustments.
foreach ($this->getItems() as $order_item) {
/** @var \Drupal\commerce_order\Adjustment[] $adjustments */
$adjustments = array_filter($order_item->getAdjustments(), $locked_callback);
// Convert legacy locked adjustments.
if ($adjustments && $order_item->usesLegacyAdjustments()) {
foreach ($adjustments as $index => $adjustment) {
$adjustments[$index] = $adjustment->multiply($order_item->getQuantity());
}
}
$order_item->set('uses_legacy_adjustments', FALSE);
$order_item->setAdjustments($adjustments);
}
$adjustments = array_filter($this->getAdjustments(), $locked_callback);
$this->setAdjustments($adjustments);
return $this;
}
/**
* {@inheritdoc}
*/
public function collectAdjustments() {
$adjustments = [];
foreach ($this->getItems() as $order_item) {
foreach ($order_item->getAdjustments() as $adjustment) {
if ($order_item->usesLegacyAdjustments()) {
$adjustment = $adjustment->multiply($order_item->getQuantity());
}
$adjustments[] = $adjustment;
}
}
foreach ($this->getAdjustments() as $adjustment) {
$adjustments[] = $adjustment;
}
return $adjustments;
}
/**
* {@inheritdoc}
*/
public function getSubtotalPrice() {
/** @var \Drupal\commerce_price\Price $subtotal_price */
$subtotal_price = NULL;
if ($this->hasItems()) {
foreach ($this->getItems() as $order_item) {
if ($order_item_total = $order_item->getTotalPrice()) {
$subtotal_price = $subtotal_price ? $subtotal_price->add($order_item_total) : $order_item_total;
}
}
}
return $subtotal_price;
}
/**
* {@inheritdoc}
*/
public function recalculateTotalPrice() {
/** @var \Drupal\commerce_price\Price $total_price */
$total_price = NULL;
if ($this->hasItems()) {
foreach ($this->getItems() as $order_item) {
if ($order_item_total = $order_item->getTotalPrice()) {
$total_price = $total_price ? $total_price->add($order_item_total) : $order_item_total;
}
}
$adjustments = $this->collectAdjustments();
if ($adjustments) {
/** @var \Drupal\commerce_order\AdjustmentTransformerInterface $adjustment_transformer */
$adjustment_transformer = \Drupal::service('commerce_order.adjustment_transformer');
$adjustments = $adjustment_transformer->combineAdjustments($adjustments);
$adjustments = $adjustment_transformer->roundAdjustments($adjustments);
foreach ($adjustments as $adjustment) {
if (!$adjustment->isIncluded()) {
$total_price = $total_price->add($adjustment->getAmount());
}
}
}
}
$this->total_price = $total_price;
return $this;
}
/**
* {@inheritdoc}
*/
public function getTotalPrice() {
if (!$this->get('total_price')->isEmpty()) {
return $this->get('total_price')->first()->toPrice();
}
}
/**
* {@inheritdoc}
*/
public function getState() {
return $this->get('state')->first();
}
/**
* {@inheritdoc}
*/
public function getRefreshState() {
return $this->getData('refresh_state');
}
/**
* {@inheritdoc}
*/
public function setRefreshState($refresh_state) {
return $this->setData('refresh_state', $refresh_state);
}
/**
* {@inheritdoc}
*/
public function getData($key, $default = NULL) {
$data = [];
if (!$this->get('data')->isEmpty()) {
$data = $this->get('data')->first()->getValue();
}
return isset($data[$key]) ? $data[$key] : $default;
}
/**
* {@inheritdoc}
*/
public function setData($key, $value) {
$this->get('data')->__set($key, $value);
return $this;
}
/**
* {@inheritdoc}
*/
public function isLocked() {
return !empty($this->get('locked')->value);
}
/**
* {@inheritdoc}
*/
public function lock() {
$this->set('locked', TRUE);
return $this;
}
/**
* {@inheritdoc}
*/
public function unlock() {
$this->set('locked', FALSE);
return $this;
}
/**
* {@inheritdoc}
*/
public function getCreatedTime() {
return $this->get('created')->value;
}
/**
* {@inheritdoc}
*/
public function setCreatedTime($timestamp) {
$this->set('created', $timestamp);
return $this;
}
/**
* {@inheritdoc}
*/
public function getPlacedTime() {
return $this->get('placed')->value;
}
/**
* {@inheritdoc}
*/
public function setPlacedTime($timestamp) {
$this->set('placed', $timestamp);
return $this;
}
/**
* {@inheritdoc}
*/
public function getCompletedTime() {
return $this->get('completed')->value;
}
/**
* {@inheritdoc}
*/
public function setCompletedTime($timestamp) {
$this->set('completed', $timestamp);
return $this;
}
/**
* {@inheritdoc}
*/
public function preSave(EntityStorageInterface $storage) {
parent::preSave($storage);
if ($this->isNew()) {
if (!$this->getIpAddress()) {
$this->setIpAddress(\Drupal::request()->getClientIp());
}
}
if (!$this->getEmail() && $customer = $this->getCustomer()) {
$this->setEmail($customer->getEmail());
}
// Maintain the completed timestamp.
$state = $this->getState()->value;
$original_state = isset($this->original) ? $this->original->getState()->value : '';
if ($state == 'completed' && $original_state != 'completed') {
if (empty($this->getCompletedTime())) {
$this->setCompletedTime(\Drupal::time()->getRequestTime());
}
}
// Refresh draft orders on every save.
if ($this->getState()->value == 'draft' && empty($this->getRefreshState())) {
$this->setRefreshState(self::REFRESH_ON_SAVE);
}
}
/**
* {@inheritdoc}
*/
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
parent::postSave($storage, $update);
// Ensure there's a back-reference on each order item.
foreach ($this->getItems() as $order_item) {
if ($order_item->order_id->isEmpty()) {
$order_item->order_id = $this->id();
$order_item->save();
}
}
}
/**
* {@inheritdoc}
*/
public static function postDelete(EntityStorageInterface $storage, array $entities) {
parent::postDelete($storage, $entities);
// Delete the order items of a deleted order.
$order_items = [];
/** @var \Drupal\commerce_order\Entity\OrderInterface $entity */
foreach ($entities as $entity) {
foreach ($entity->getItems() as $order_item) {
$order_items[$order_item->id()] = $order_item;
}
}
/** @var \Drupal\commerce_order\OrderItemStorageInterface $order_item_storage */
$order_item_storage = \Drupal::service('entity_type.manager')->getStorage('commerce_order_item');
$order_item_storage->delete($order_items);
}
/**
* {@inheritdoc}
*/
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
$fields = parent::baseFieldDefinitions($entity_type);
$fields['order_number'] = BaseFieldDefinition::create('string')
->setLabel(t('Order number'))
->setDescription(t('The order number displayed to the customer.'))
->setRequired(TRUE)
->setDefaultValue('')
->setSetting('max_length', 255)
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
$fields['store_id'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Store'))
->setDescription(t('The store to which the order belongs.'))
->setCardinality(1)
->setRequired(TRUE)
->setSetting('target_type', 'commerce_store')
->setSetting('handler', 'default')
->setTranslatable(TRUE)
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
$fields['uid'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Customer'))
->setDescription(t('The customer.'))
->setSetting('target_type', 'user')
->setSetting('handler', 'default')
->setDefaultValueCallback('Drupal\commerce_order\Entity\Order::getCurrentUserId')
->setTranslatable(TRUE)
->setDisplayOptions('view', [
'label' => 'above',
'type' => 'author',
'weight' => 0,
])
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
$fields['mail'] = BaseFieldDefinition::create('email')
->setLabel(t('Contact email'))
->setDescription(t('The email address associated with the order.'))
->setDefaultValue('')
->setSetting('max_length', 255)
->setDisplayOptions('view', [
'label' => 'above',
'type' => 'string',
'weight' => 0,
])
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
$fields['ip_address'] = BaseFieldDefinition::create('string')
->setLabel(t('IP address'))
->setDescription(t('The IP address of the order.'))
->setDefaultValue('')
->setSetting('max_length', 128)
->setDisplayOptions('view', [
'label' => 'above',
'type' => 'string',
'weight' => 0,
])
->setDisplayOptions('form', [
'region' => 'hidden',
'weight' => 0,
])
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
$fields['billing_profile'] = BaseFieldDefinition::create('entity_reference_revisions')
->setLabel(t('Billing information'))
->setDescription(t('Billing profile'))
->setSetting('target_type', 'profile')
->setSetting('handler', 'default')
->setSetting('handler_settings', ['target_bundles' => ['customer']])
->setTranslatable(TRUE)
->setDisplayOptions('form', [
'type' => 'commerce_billing_profile',
'weight' => 0,
'settings' => [],
])
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
$fields['adjustments'] = BaseFieldDefinition::create('commerce_adjustment')
->setLabel(t('Adjustments'))
->setRequired(FALSE)
->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
->setDisplayOptions('form', [
'type' => 'commerce_adjustment_default',
'weight' => 0,
])
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', FALSE);
$fields['total_price'] = BaseFieldDefinition::create('commerce_price')
->setLabel(t('Total price'))
->setDescription(t('The total price of the order.'))
->setReadOnly(TRUE)
->setDisplayOptions('view', [
'label' => 'hidden',
'type' => 'commerce_order_total_summary',
'weight' => 0,
])
->setDisplayConfigurable('form', FALSE)
->setDisplayConfigurable('view', TRUE);
$fields['state'] = BaseFieldDefinition::create('state')
->setLabel(t('State'))
->setDescription(t('The order state.'))
->setRequired(TRUE)
->setSetting('max_length', 255)
->setDisplayOptions('view', [
'label' => 'hidden',
'type' => 'state_transition_form',
'weight' => 10,
])
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE)
->setSetting('workflow_callback', ['\Drupal\commerce_order\Entity\Order', 'getWorkflowId']);
$fields['data'] = BaseFieldDefinition::create('map')
->setLabel(t('Data'))
->setDescription(t('A serialized array of additional data.'));
$fields['locked'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Locked'))
->setSettings([
'on_label' => t('Yes'),
'off_label' => t('No'),
])
->setDefaultValue(FALSE);
$fields['created'] = BaseFieldDefinition::create('created')
->setLabel(t('Created'))
->setDescription(t('The time when the order was created.'));
$fields['changed'] = BaseFieldDefinition::create('changed')
->setLabel(t('Changed'))
->setDescription(t('The time when the order was last edited.'))
->setDisplayConfigurable('view', TRUE);
$fields['placed'] = BaseFieldDefinition::create('timestamp')
->setLabel(t('Placed'))
->setDescription(t('The time when the order was placed.'))
->setDisplayOptions('view', [
'label' => 'above',
'type' => 'timestamp',
'weight' => 0,
])
->setDisplayConfigurable('view', TRUE);
$fields['completed'] = BaseFieldDefinition::create('timestamp')
->setLabel(t('Completed'))
->setDescription(t('The time when the order was completed.'))
->setDisplayOptions('view', [
'label' => 'above',
'type' => 'timestamp',
'weight' => 0,
])
->setDisplayConfigurable('view', TRUE);
return $fields;
}
/**
* Default value callback for 'uid' base field definition.
*
* @see ::baseFieldDefinitions()
*
* @return array
* An array of default values.
*/
public static function getCurrentUserId() {
return [\Drupal::currentUser()->id()];
}
/**
* Gets the workflow ID for the state field.
*
* @param \Drupal\commerce_order\Entity\OrderInterface $order
* The order.
*
* @return string
* The workflow ID.
*/
public static function getWorkflowId(OrderInterface $order) {
$workflow = OrderType::load($order->bundle())->getWorkflowId();
return $workflow;
}
}
