View source
<?php
namespace Drupal\commerce_promotion\Entity;
use Drupal\commerce\ConditionGroup;
use Drupal\commerce\EntityOwnerTrait;
use Drupal\commerce\Entity\CommerceContentEntityBase;
use Drupal\commerce\Plugin\Commerce\Condition\ConditionInterface;
use Drupal\commerce\Plugin\Commerce\Condition\ParentEntityAwareInterface;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_price\Calculator;
use Drupal\commerce_promotion\Plugin\Commerce\PromotionOffer\OrderItemPromotionOfferInterface;
use Drupal\commerce_promotion\Plugin\Commerce\PromotionOffer\PromotionOfferInterface;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Entity\EntityChangedTrait;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
class Promotion extends CommerceContentEntityBase implements PromotionInterface {
use EntityChangedTrait;
use EntityOwnerTrait;
public function toUrl($rel = 'canonical', array $options = []) {
if ($rel == 'canonical') {
$rel = 'edit-form';
}
return parent::toUrl($rel, $options);
}
public function createDuplicate() {
$duplicate = parent::createDuplicate();
$duplicate
->set('coupons', []);
return $duplicate;
}
public function getName() {
return $this
->get('name')->value;
}
public function setName($name) {
$this
->set('name', $name);
return $this;
}
public function getDisplayName() {
return $this
->get('display_name')->value;
}
public function setDisplayName($display_name) {
$this
->set('display_name', $display_name);
return $this;
}
public function getDescription() {
return $this
->get('description')->value;
}
public function setDescription($description) {
$this
->set('description', $description);
return $this;
}
public function getCreatedTime() {
return $this
->get('created')->value;
}
public function setCreatedTime($timestamp) {
$this
->set('created', $timestamp);
return $this;
}
public function getOrderTypes() {
return $this
->get('order_types')
->referencedEntities();
}
public function setOrderTypes(array $order_types) {
$this
->set('order_types', $order_types);
return $this;
}
public function getOrderTypeIds() {
$order_type_ids = [];
foreach ($this
->get('order_types') as $field_item) {
$order_type_ids[] = $field_item->target_id;
}
return $order_type_ids;
}
public function setOrderTypeIds(array $order_type_ids) {
$this
->set('order_types', $order_type_ids);
return $this;
}
public function getStores() {
return $this
->getTranslatedReferencedEntities('stores');
}
public function setStores(array $stores) {
$this
->set('stores', $stores);
return $this;
}
public function getStoreIds() {
$store_ids = [];
foreach ($this
->get('stores') as $field_item) {
$store_ids[] = $field_item->target_id;
}
return $store_ids;
}
public function setStoreIds(array $store_ids) {
$this
->set('stores', $store_ids);
return $this;
}
public function getOffer() {
if (!$this
->get('offer')
->isEmpty()) {
return $this
->get('offer')
->first()
->getTargetInstance();
}
}
public function setOffer(PromotionOfferInterface $offer) {
$this
->set('offer', [
'target_plugin_id' => $offer
->getPluginId(),
'target_plugin_configuration' => $offer
->getConfiguration(),
]);
return $this;
}
public function getConditions() {
$conditions = [];
foreach ($this
->get('conditions') as $field_item) {
$condition = $field_item
->getTargetInstance();
if ($condition instanceof ParentEntityAwareInterface) {
$condition
->setParentEntity($this);
}
$conditions[] = $condition;
}
return $conditions;
}
public function setConditions(array $conditions) {
$this
->set('conditions', []);
foreach ($conditions as $condition) {
if ($condition instanceof ConditionInterface) {
$this
->get('conditions')
->appendItem([
'target_plugin_id' => $condition
->getPluginId(),
'target_plugin_configuration' => $condition
->getConfiguration(),
]);
}
}
return $this;
}
public function getConditionOperator() {
return $this
->get('condition_operator')->value;
}
public function setConditionOperator($condition_operator) {
$this
->set('condition_operator', $condition_operator);
return $this;
}
public function getCouponIds() {
$coupon_ids = [];
foreach ($this
->get('coupons') as $field_item) {
$coupon_ids[] = $field_item->target_id;
}
return $coupon_ids;
}
public function getCoupons() {
$coupons = $this
->get('coupons')
->referencedEntities();
return $coupons;
}
public function setCoupons(array $coupons) {
$this
->set('coupons', $coupons);
return $this;
}
public function hasCoupons() {
return !$this
->get('coupons')
->isEmpty();
}
public function addCoupon(CouponInterface $coupon) {
if (!$this
->hasCoupon($coupon)) {
$this
->get('coupons')
->appendItem($coupon);
}
return $this;
}
public function removeCoupon(CouponInterface $coupon) {
$index = $this
->getCouponIndex($coupon);
if ($index !== FALSE) {
$this
->get('coupons')
->offsetUnset($index);
}
return $this;
}
public function hasCoupon(CouponInterface $coupon) {
return in_array($coupon
->id(), $this
->getCouponIds());
}
protected function getCouponIndex(CouponInterface $coupon) {
return array_search($coupon
->id(), $this
->getCouponIds());
}
public function getUsageLimit() {
return $this
->get('usage_limit')->value;
}
public function setUsageLimit($usage_limit) {
$this
->set('usage_limit', $usage_limit);
return $this;
}
public function getCustomerUsageLimit() {
return $this
->get('usage_limit_customer')->value;
}
public function setCustomerUsageLimit($usage_limit_customer) {
$this
->set('usage_limit_customer', $usage_limit_customer);
return $this;
}
public function getStartDate($store_timezone = 'UTC') {
return new DrupalDateTime($this
->get('start_date')->value, $store_timezone);
}
public function setStartDate(DrupalDateTime $start_date) {
$this
->get('start_date')->value = $start_date
->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT);
return $this;
}
public function getEndDate($store_timezone = 'UTC') {
if (!$this
->get('end_date')
->isEmpty()) {
return new DrupalDateTime($this
->get('end_date')->value, $store_timezone);
}
}
public function setEndDate(DrupalDateTime $end_date = NULL) {
$this
->get('end_date')->value = NULL;
if ($end_date) {
$this
->get('end_date')->value = $end_date
->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT);
}
}
public function getCompatibility() {
return $this
->get('compatibility')->value;
}
public function setCompatibility($compatibility) {
if (!in_array($compatibility, [
self::COMPATIBLE_NONE,
self::COMPATIBLE_ANY,
])) {
throw new \InvalidArgumentException('Invalid compatibility type');
}
$this
->get('compatibility')->value = $compatibility;
return $this;
}
public function isEnabled() {
return (bool) $this
->getEntityKey('status');
}
public function setEnabled($enabled) {
$this
->set('status', (bool) $enabled);
return $this;
}
public function getWeight() {
return (int) $this
->get('weight')->value;
}
public function setWeight($weight) {
$this
->set('weight', $weight);
return $this;
}
public function available(OrderInterface $order) {
if (!$this
->isEnabled()) {
return FALSE;
}
if (!in_array($order
->bundle(), $this
->getOrderTypeIds())) {
return FALSE;
}
if (!in_array($order
->getStoreId(), $this
->getStoreIds())) {
return FALSE;
}
$date = $order
->getCalculationDate();
$store_timezone = $date
->getTimezone()
->getName();
$start_date = $this
->getStartDate($store_timezone);
if ($start_date
->format('U') > $date
->format('U')) {
return FALSE;
}
$end_date = $this
->getEndDate($store_timezone);
if ($end_date && $end_date
->format('U') <= $date
->format('U')) {
return FALSE;
}
$usage_limit = $this
->getUsageLimit();
$usage_limit_customer = $this
->getCustomerUsageLimit();
if (!$usage_limit && !$usage_limit_customer) {
return TRUE;
}
$usage = \Drupal::service('commerce_promotion.usage');
if ($usage_limit && $usage_limit <= $usage
->load($this)) {
return FALSE;
}
if ($usage_limit_customer) {
if (!($email = $order
->getEmail())) {
return FALSE;
}
if ($usage_limit_customer <= $usage
->load($this, $email)) {
return FALSE;
}
}
return TRUE;
}
public function applies(OrderInterface $order) {
switch ($this
->getCompatibility()) {
case self::COMPATIBLE_NONE:
foreach ($order
->collectAdjustments() as $adjustment) {
if ($adjustment
->getType() == 'promotion') {
return FALSE;
}
}
break;
case self::COMPATIBLE_ANY:
break;
}
$conditions = $this
->getConditions();
if (!$conditions) {
return TRUE;
}
$conditions = array_filter($conditions, function ($condition) {
return $condition
->getEntityTypeId() == 'commerce_order';
});
$condition_group = new ConditionGroup($conditions, $this
->getConditionOperator());
return $condition_group
->evaluate($order);
}
public function apply(OrderInterface $order) {
$offer = $this
->getOffer();
if ($offer instanceof OrderItemPromotionOfferInterface) {
$offer_conditions = new ConditionGroup($offer
->getConditions(), $offer
->getConditionOperator());
foreach ($order
->getItems() as $order_item) {
if (!$order_item
->getUnitPrice() || Calculator::compare($order_item
->getQuantity(), '0') === 0) {
continue;
}
if ($offer_conditions
->evaluate($order_item)) {
$offer
->apply($order_item, $this);
}
}
}
else {
$offer
->apply($order, $this);
}
}
public function clear(OrderInterface $order) {
$offer = $this
->getOffer();
if ($offer instanceof OrderItemPromotionOfferInterface) {
foreach ($order
->getItems() as $order_item) {
$offer
->clear($order_item, $this);
}
}
else {
$offer
->clear($order, $this);
}
}
public function preSave(EntityStorageInterface $storage) {
parent::preSave($storage);
foreach (array_keys($this
->getTranslationLanguages()) as $langcode) {
$translation = $this
->getTranslation($langcode);
if ($translation
->getOwner()
->isAnonymous()) {
$translation
->setOwnerId(0);
}
}
}
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
parent::postSave($storage, $update);
foreach ($this
->getCoupons() as $coupon) {
if (!$coupon
->getPromotionId()) {
$coupon->promotion_id = $this
->id();
$coupon
->save();
}
}
}
public static function postDelete(EntityStorageInterface $storage, array $entities) {
$coupons = [];
foreach ($entities as $entity) {
foreach ($entity
->getCoupons() as $coupon) {
$coupons[] = $coupon;
}
}
$coupon_storage = \Drupal::service('entity_type.manager')
->getStorage('commerce_promotion_coupon');
$coupon_storage
->delete($coupons);
$usage = \Drupal::service('commerce_promotion.usage');
$usage
->delete($entities);
}
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
$fields = parent::baseFieldDefinitions($entity_type);
$fields += static::ownerBaseFieldDefinitions($entity_type);
$fields['name'] = BaseFieldDefinition::create('string')
->setLabel(t('Name'))
->setDescription(t('The promotion name.'))
->setRequired(TRUE)
->setTranslatable(TRUE)
->setSettings([
'default_value' => '',
'max_length' => 255,
])
->setDisplayOptions('form', [
'type' => 'string_textfield',
'weight' => 0,
])
->setDisplayConfigurable('view', TRUE)
->setDisplayConfigurable('form', TRUE);
$fields['uid']
->setLabel(t('Owner'))
->setDescription(t('The promotion owner.'))
->setDisplayConfigurable('view', TRUE)
->setDisplayConfigurable('form', TRUE);
$fields['display_name'] = BaseFieldDefinition::create('string')
->setLabel(t('Display name'))
->setDescription(t('If provided, shown on the order instead of "@translated".', [
'@translated' => t('Discount'),
]))
->setTranslatable(TRUE)
->setSettings([
'display_description' => TRUE,
'default_value' => '',
'max_length' => 255,
])
->setDisplayOptions('form', [
'type' => 'string_textfield',
'weight' => 0,
])
->setDisplayConfigurable('view', TRUE)
->setDisplayConfigurable('form', TRUE);
$fields['description'] = BaseFieldDefinition::create('string_long')
->setLabel(t('Description'))
->setDescription(t('Additional information about the promotion to show to the customer'))
->setTranslatable(TRUE)
->setDefaultValue('')
->setDisplayOptions('form', [
'type' => 'string_textarea',
'weight' => 1,
'settings' => [
'rows' => 3,
],
])
->setDisplayConfigurable('view', TRUE)
->setDisplayConfigurable('form', TRUE);
$fields['created'] = BaseFieldDefinition::create('created')
->setLabel(t('Created'))
->setTranslatable(TRUE)
->setDescription(t('The time when the promotion was created.'));
$fields['changed'] = BaseFieldDefinition::create('changed')
->setLabel(t('Changed'))
->setTranslatable(TRUE)
->setDescription(t('The time when the promotion was last edited.'))
->setDisplayConfigurable('view', TRUE);
$fields['order_types'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Order types'))
->setDescription(t('The order types for which the promotion is valid.'))
->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
->setRequired(TRUE)
->setSetting('target_type', 'commerce_order_type')
->setSetting('handler', 'default')
->setDisplayOptions('form', [
'type' => 'commerce_entity_select',
'weight' => 2,
]);
$fields['stores'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Stores'))
->setDescription(t('The stores for which the promotion is valid.'))
->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
->setRequired(TRUE)
->setSetting('target_type', 'commerce_store')
->setSetting('handler', 'default')
->setDisplayOptions('form', [
'type' => 'commerce_entity_select',
'weight' => 2,
]);
$fields['offer'] = BaseFieldDefinition::create('commerce_plugin_item:commerce_promotion_offer')
->setLabel(t('Offer type'))
->setCardinality(1)
->setRequired(TRUE)
->setDisplayOptions('form', [
'type' => 'commerce_plugin_select',
'weight' => 3,
]);
$fields['conditions'] = BaseFieldDefinition::create('commerce_plugin_item:commerce_condition')
->setLabel(t('Conditions'))
->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
->setRequired(FALSE)
->setDisplayOptions('form', [
'type' => 'commerce_conditions',
'weight' => 3,
'settings' => [
'entity_types' => [
'commerce_order',
],
],
]);
$fields['condition_operator'] = BaseFieldDefinition::create('list_string')
->setLabel(t('Condition operator'))
->setDescription(t('The condition operator.'))
->setRequired(TRUE)
->setSetting('allowed_values', [
'AND' => t('All conditions must pass'),
'OR' => t('Only one condition must pass'),
])
->setDisplayOptions('form', [
'type' => 'options_buttons',
'weight' => 4,
])
->setDisplayConfigurable('form', TRUE)
->setDefaultValue('AND');
$fields['coupons'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Coupons'))
->setDescription(t('Coupons which allow promotion to be redeemed.'))
->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
->setRequired(FALSE)
->setSetting('target_type', 'commerce_promotion_coupon')
->setSetting('handler', 'default');
$fields['usage_limit'] = BaseFieldDefinition::create('integer')
->setLabel(t('Usage limit'))
->setDescription(t('The maximum number of times the promotion can be used. 0 for unlimited.'))
->setDefaultValue(0)
->setDisplayOptions('form', [
'type' => 'commerce_usage_limit',
'weight' => 4,
]);
$fields['usage_limit_customer'] = BaseFieldDefinition::create('integer')
->setLabel(t('Customer usage limit'))
->setDescription(t('The maximum number of times the promotion can be used by a customer. 0 for unlimited.'))
->setDefaultValue(0)
->setDisplayOptions('form', [
'type' => 'commerce_usage_limit',
'weight' => 4,
]);
$fields['start_date'] = BaseFieldDefinition::create('datetime')
->setLabel(t('Start date'))
->setDescription(t('The date the promotion becomes valid.'))
->setRequired(TRUE)
->setSetting('datetime_type', 'datetime')
->setDefaultValueCallback('Drupal\\commerce_promotion\\Entity\\Promotion::getDefaultStartDate')
->setDisplayOptions('form', [
'type' => 'commerce_store_datetime',
'weight' => 5,
]);
$fields['end_date'] = BaseFieldDefinition::create('datetime')
->setLabel(t('End date'))
->setDescription(t('The date after which the promotion is invalid.'))
->setRequired(FALSE)
->setSetting('datetime_type', 'datetime')
->setSetting('datetime_optional_label', t('Provide an end date'))
->setDisplayOptions('form', [
'type' => 'commerce_store_datetime',
'weight' => 6,
]);
$fields['compatibility'] = BaseFieldDefinition::create('list_string')
->setLabel(t('Compatibility with other promotions'))
->setSetting('allowed_values_function', [
'\\Drupal\\commerce_promotion\\Entity\\Promotion',
'getCompatibilityOptions',
])
->setRequired(TRUE)
->setDefaultValue(self::COMPATIBLE_ANY)
->setDisplayOptions('form', [
'type' => 'options_buttons',
'weight' => 4,
]);
$fields['status'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Status'))
->setDescription(t('Whether the promotion is enabled.'))
->setDefaultValue(TRUE)
->setRequired(TRUE)
->setSettings([
'on_label' => t('Enabled'),
'off_label' => t('Disabled'),
])
->setDisplayOptions('form', [
'type' => 'options_buttons',
'weight' => 0,
]);
$fields['weight'] = BaseFieldDefinition::create('integer')
->setLabel(t('Weight'))
->setDescription(t('The weight of this promotion in relation to others.'))
->setDefaultValue(0);
return $fields;
}
public static function getDefaultStartDate() {
$timestamp = \Drupal::time()
->getRequestTime();
return gmdate(DateTimeItemInterface::DATETIME_STORAGE_FORMAT, $timestamp);
}
public static function sort(PromotionInterface $a, PromotionInterface $b) {
$a_weight = $a
->getWeight();
$b_weight = $b
->getWeight();
if ($a_weight == $b_weight) {
$a_label = $a
->label();
$b_label = $b
->label();
return strnatcasecmp($a_label, $b_label);
}
return $a_weight < $b_weight ? -1 : 1;
}
public static function getCompatibilityOptions() {
return [
self::COMPATIBLE_ANY => t('Any promotion'),
self::COMPATIBLE_NONE => t('Not with any other promotions'),
];
}
}