PriceListItem.php 9.78 KB
Newer Older
Andreas Radloff's avatar
Andreas Radloff committed
1 2 3 4
<?php

namespace Drupal\commerce_pricelist\Entity;

5
use Drupal\commerce\PurchasableEntityInterface;
6 7
use Drupal\commerce_price\Price;
use Drupal\commerce\Entity\CommerceContentEntityBase;
8
use Drupal\Core\Cache\Cache;
9 10
use Drupal\Core\Entity\EntityMalformedException;
use Drupal\Core\Entity\EntityStorageInterface;
Andreas Radloff's avatar
Andreas Radloff committed
11 12 13
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Entity\EntityChangedTrait;
use Drupal\Core\Entity\EntityTypeInterface;
14
use Drupal\user\EntityOwnerTrait;
Andreas Radloff's avatar
Andreas Radloff committed
15 16

/**
17
 * Defines the price list item entity.
Andreas Radloff's avatar
Andreas Radloff committed
18
 *
19
 * Called a "price" in the UI for UX reasons.
Andreas Radloff's avatar
Andreas Radloff committed
20 21
 *
 * @ContentEntityType(
22
 *   id = "commerce_pricelist_item",
Andreas Radloff's avatar
Andreas Radloff committed
23
 *   label = @Translation("Price list item"),
24 25 26
 *   label_collection = @Translation("Prices"),
 *   label_singular = @Translation("price"),
 *   label_plural = @Translation("prices"),
27
 *   label_count = @PluralTranslation(
28 29
 *     singular = "@count price",
 *     plural = "@count prices",
30
 *   ),
Andreas Radloff's avatar
Andreas Radloff committed
31
 *   handlers = {
32 33
 *     "event" = "Drupal\commerce_pricelist\Event\PriceListItemEvent",
 *     "storage" = "Drupal\commerce\CommerceContentEntityStorage",
34
 *     "list_builder" = "Drupal\commerce_pricelist\PriceListItemListBuilder",
Andreas Radloff's avatar
Andreas Radloff committed
35
 *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
36
 *     "views_data" = "Drupal\commerce\CommerceEntityViewsData",
Andreas Radloff's avatar
Andreas Radloff committed
37
 *     "form" = {
38 39
 *       "add" = "Drupal\commerce_pricelist\Form\PriceListItemForm",
 *       "edit" = "Drupal\commerce_pricelist\Form\PriceListItemForm",
40
 *       "duplicate" = "Drupal\commerce_pricelist\Form\PriceListItemForm",
41 42
 *       "delete" = "Drupal\commerce_pricelist\Form\PriceListItemDeleteForm",
 *     },
43 44 45
 *     "local_task_provider" = {
 *       "default" = "Drupal\entity\Menu\DefaultEntityLocalTaskProvider",
 *     },
46 47
 *     "route_provider" = {
 *       "default" = "Drupal\commerce_pricelist\PriceListItemRouteProvider",
Andreas Radloff's avatar
Andreas Radloff committed
48 49
 *     },
 *   },
50 51
 *   admin_permission = "administer commerce_pricelist",
 *   base_table = "commerce_pricelist_item",
Andreas Radloff's avatar
Andreas Radloff committed
52 53
 *   entity_keys = {
 *     "id" = "id",
54
 *     "bundle" = "type",
Andreas Radloff's avatar
Andreas Radloff committed
55
 *     "uuid" = "uuid",
56
 *     "status" = "status",
57 58
 *     "owner" = "uid",
 *     "uid" = "uid",
Andreas Radloff's avatar
Andreas Radloff committed
59
 *   },
60 61 62
 *   links = {
 *     "add-form" = "/price-list/{commerce_pricelist}/prices/add",
 *     "edit-form" = "/price-list/{commerce_pricelist}/prices/{commerce_pricelist_item}/edit",
63
 *     "duplicate-form" = "/price-list/{commerce_pricelist}/prices/{commerce_pricelist_item}/duplicate",
64
 *     "delete-form" = "/price-list/{commerce_pricelist}/prices/{commerce_pricelist_item}/delete",
65 66
 *     "export-form" = "/price-list/{commerce_pricelist}/prices/export",
 *     "import-form" = "/price-list/{commerce_pricelist}/prices/import",
67 68
 *     "collection" = "/price-list/{commerce_pricelist}/prices",
 *   },
Andreas Radloff's avatar
Andreas Radloff committed
69 70
 * )
 */
71
class PriceListItem extends CommerceContentEntityBase implements PriceListItemInterface {
72

Andreas Radloff's avatar
Andreas Radloff committed
73
  use EntityChangedTrait;
74
  use EntityOwnerTrait;
75

Andreas Radloff's avatar
Andreas Radloff committed
76 77 78
  /**
   * {@inheritdoc}
   */
79 80 81 82
  protected function urlRouteParameters($rel) {
    $uri_route_parameters = parent::urlRouteParameters($rel);
    $uri_route_parameters['commerce_pricelist'] = $this->getPriceListId();
    return $uri_route_parameters;
83 84 85 86 87
  }

  /**
   * {@inheritdoc}
   */
88 89 90 91 92 93 94 95
  public function label() {
    if ($this->isNew()) {
      return '';
    }
    $purchasable_entity_label = $this->getPurchasableEntity()->label();
    $currency_formatter = \Drupal::service('commerce_price.currency_formatter');
    $price = $this->getPrice();
    $formatted_price = $currency_formatter->format($price->getNumber(), $price->getCurrencyCode());
96

97
    return sprintf('%s: %s', $purchasable_entity_label, $formatted_price);
98 99 100 101 102
  }

  /**
   * {@inheritdoc}
   */
103 104
  public function getPriceList() {
    return $this->get('price_list_id')->entity;
Andreas Radloff's avatar
Andreas Radloff committed
105 106 107 108 109
  }

  /**
   * {@inheritdoc}
   */
110 111
  public function getPriceListId() {
    return $this->get('price_list_id')->target_id;
Andreas Radloff's avatar
Andreas Radloff committed
112 113
  }

114 115 116
  /**
   * {@inheritdoc}
   */
117 118
  public function getPurchasableEntity() {
    return $this->getTranslatedReferencedEntity('purchasable_entity');
119 120 121 122 123
  }

  /**
   * {@inheritdoc}
   */
124 125
  public function setPurchasableEntity(PurchasableEntityInterface $purchasable_entity) {
    return $this->set('purchasable_entity', $purchasable_entity);
126 127
  }

Andreas Radloff's avatar
Andreas Radloff committed
128 129 130
  /**
   * {@inheritdoc}
   */
131 132
  public function getPurchasableEntityId() {
    return $this->get('purchasable_entity')->target_id;
Andreas Radloff's avatar
Andreas Radloff committed
133 134 135 136 137
  }

  /**
   * {@inheritdoc}
   */
138 139
  public function setPurchasableEntityId($purchasable_entity_id) {
    return $this->set('purchasable_entity', $purchasable_entity_id);
Andreas Radloff's avatar
Andreas Radloff committed
140 141
  }

142 143 144
  /**
   * {@inheritdoc}
   */
145 146
  public function getQuantity() {
    return $this->get('quantity')->value;
147 148 149 150 151
  }

  /**
   * {@inheritdoc}
   */
152 153
  public function setQuantity($quantity) {
    $this->set('quantity', (string) $quantity);
154 155 156
    return $this;
  }

157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
  /**
   * {@inheritdoc}
   */
  public function getListPrice() {
    if (!$this->get('list_price')->isEmpty()) {
      return $this->get('list_price')->first()->toPrice();
    }
  }

  /**
   * {@inheritdoc}
   */
  public function setListPrice(Price $list_price) {
    return $this->set('list_price', $list_price);
  }

Andreas Radloff's avatar
Andreas Radloff committed
173 174 175
  /**
   * {@inheritdoc}
   */
Andreas Radloff's avatar
Andreas Radloff committed
176
  public function getPrice() {
177 178 179 180 181 182 183 184
    if (!$this->get('price')->isEmpty()) {
      return $this->get('price')->first()->toPrice();
    }
  }

  /**
   * {@inheritdoc}
   */
185 186
  public function setPrice(Price $price) {
    return $this->set('price', $price);
187 188 189 190 191
  }

  /**
   * {@inheritdoc}
   */
192
  public function isEnabled() {
Andreas Radloff's avatar
Andreas Radloff committed
193 194 195 196 197 198
    return (bool) $this->getEntityKey('status');
  }

  /**
   * {@inheritdoc}
   */
199 200
  public function setEnabled($enabled) {
    $this->set('status', (bool) $enabled);
Andreas Radloff's avatar
Andreas Radloff committed
201 202 203
    return $this;
  }

204 205 206 207 208 209 210 211 212 213 214 215
  /**
   * {@inheritdoc}
   */
  public function preSave(EntityStorageInterface $storage) {
    parent::preSave($storage);

    $price_list_id = $this->getPriceListId();
    if (empty($price_list_id)) {
      throw new EntityMalformedException(sprintf('Required price list item field "price_list_id" is empty.'));
    }
  }

216 217 218 219 220 221 222 223 224 225 226 227
  /**
   * {@inheritdoc}
   */
  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
    parent::postSave($storage, $update);

    if ($purchasable_entity = $this->getPurchasableEntity()) {
      // Invalidate caches to allow the new pricing to come into effect.
      Cache::invalidateTags($purchasable_entity->getCacheTagsToInvalidate());
    }
  }

Andreas Radloff's avatar
Andreas Radloff committed
228 229 230 231
  /**
   * {@inheritdoc}
   */
  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
232
    $fields = parent::baseFieldDefinitions($entity_type);
233 234 235 236 237
    $fields += static::ownerBaseFieldDefinitions($entity_type);

    $fields['uid']
      ->setLabel(t('Owner'))
      ->setDescription(t('The user that owns this price list item.'));
238

Andreas Radloff's avatar
Andreas Radloff committed
239 240
    $fields['price_list_id'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Price list'))
241 242
      ->setDescription(t('The parent price list.'))
      ->setSetting('target_type', 'commerce_pricelist')
243 244
      ->setDisplayConfigurable('form', TRUE)
      ->setRequired(TRUE)
245
      ->setReadOnly(TRUE);
Andreas Radloff's avatar
Andreas Radloff committed
246

247 248 249
    $fields['purchasable_entity'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Purchasable entity'))
      ->setDescription(t('The purchasable entity.'))
Andreas Radloff's avatar
Andreas Radloff committed
250 251
      ->setRequired(TRUE)
      ->setDisplayOptions('form', [
Andreas Radloff's avatar
Andreas Radloff committed
252 253 254 255 256 257 258
        'type' => 'entity_reference_autocomplete',
        'weight' => -1,
        'settings' => [
          'match_operator' => 'CONTAINS',
          'size' => '60',
          'placeholder' => '',
        ],
259
      ]);
260 261 262 263 264
    // Provide a default target_type for Views, which uses
    // base field definitions without bundle overrides.
    if (\Drupal::moduleHandler()->moduleExists('commerce_product')) {
      $fields['purchasable_entity']->setSetting('target_type', 'commerce_product_variation');
    }
265

266
    $fields['quantity'] = BaseFieldDefinition::create('decimal')
267
      ->setLabel(t('Quantity'))
268
      ->setDescription(t('The quantity tier.'))
269
      ->setRequired(TRUE)
270 271 272
      ->setSetting('unsigned', TRUE)
      ->setSetting('min', 0)
      ->setDefaultValue(1)
273
      ->setDisplayOptions('form', [
274 275
        'type' => 'commerce_quantity',
      ]);
Andreas Radloff's avatar
Andreas Radloff committed
276

277 278 279 280 281 282 283 284
    $fields['list_price'] = BaseFieldDefinition::create('commerce_price')
      ->setLabel(t('List price'))
      ->setDescription(t('The list price.'))
      ->setDisplayOptions('view', [
        'label' => 'above',
        'type' => 'commerce_price_default',
      ])
      ->setDisplayOptions('form', [
285
        'type' => 'commerce_list_price',
286 287
      ]);

Andreas Radloff's avatar
Andreas Radloff committed
288 289
    $fields['price'] = BaseFieldDefinition::create('commerce_price')
      ->setLabel(t('Price'))
290
      ->setDescription(t('The price.'))
291
      ->setRequired(TRUE)
Andreas Radloff's avatar
Andreas Radloff committed
292 293 294 295 296 297
      ->setDisplayOptions('view', [
        'label' => 'above',
        'type' => 'commerce_price_default',
      ])
      ->setDisplayOptions('form', [
        'type' => 'commerce_price_default',
298
      ]);
299

300
    $fields['status'] = BaseFieldDefinition::create('boolean')
301
      ->setLabel(t('Status'))
302
      ->setDescription(t('Whether the price list item is enabled.'))
303
      ->setDefaultValue(TRUE)
304 305 306 307 308
      ->setRequired(TRUE)
      ->setSettings([
        'on_label' => t('Enabled'),
        'off_label' => t('Disabled'),
      ])
309
      ->setDisplayOptions('form', [
310
        'type' => 'options_buttons',
311
      ]);
Andreas Radloff's avatar
Andreas Radloff committed
312 313 314

    $fields['changed'] = BaseFieldDefinition::create('changed')
      ->setLabel(t('Changed'))
315
      ->setDescription(t('The time when the price list item was last edited.'))
316
      ->setTranslatable(TRUE);
Andreas Radloff's avatar
Andreas Radloff committed
317 318 319 320

    return $fields;
  }

321 322 323 324
  /**
   * {@inheritdoc}
   */
  public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
325
    $purchasable_entity_type = \Drupal::entityTypeManager()->getDefinition($bundle);
326
    $fields = [];
327 328 329
    $fields['purchasable_entity'] = clone $base_field_definitions['purchasable_entity'];
    $fields['purchasable_entity']->setSetting('target_type', $purchasable_entity_type->id());
    $fields['purchasable_entity']->setLabel($purchasable_entity_type->getLabel());
330 331 332 333

    return $fields;
  }

Andreas Radloff's avatar
Andreas Radloff committed
334
}