Coupon.php 11.2 KB
Newer Older
1
2
3
4
<?php

namespace Drupal\commerce_promotion\Entity;

5
use Drupal\commerce\Entity\CommerceContentEntityBase;
6
use Drupal\commerce_order\Entity\OrderInterface;
7
use Drupal\Core\Datetime\DrupalDateTime;
8
use Drupal\Core\Entity\EntityChangedTrait;
9
use Drupal\Core\Entity\EntityStorageInterface;
10
11
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Entity\EntityTypeInterface;
12
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
13
14
15
16
17
18
19

/**
 * Defines the Coupon entity.
 *
 * @ContentEntityType(
 *   id = "commerce_promotion_coupon",
 *   label = @Translation("Coupon"),
20
21
22
23
24
25
 *   label_singular = @Translation("coupon"),
 *   label_plural = @Translation("coupons"),
 *   label_count = @PluralTranslation(
 *     singular = "@count coupon",
 *     plural = "@count coupons",
 *   ),
26
 *   handlers = {
27
 *     "event" = "Drupal\commerce_promotion\Event\CouponEvent",
28
 *     "list_builder" = "Drupal\commerce_promotion\CouponListBuilder",
29
 *     "storage" = "Drupal\commerce_promotion\CouponStorage",
30
 *     "storage_schema" = "Drupal\commerce\CommerceContentEntityStorageSchema",
31
 *     "access" = "Drupal\commerce_promotion\CouponAccessControlHandler",
32
 *     "views_data" = "Drupal\commerce\CommerceEntityViewsData",
33
 *     "form" = {
34
35
 *       "add" = "Drupal\commerce_promotion\Form\CouponForm",
 *       "edit" = "Drupal\commerce_promotion\Form\CouponForm",
36
37
 *       "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm"
 *     },
38
39
40
 *    "local_task_provider" = {
 *       "default" = "Drupal\entity\Menu\DefaultEntityLocalTaskProvider",
 *     },
41
42
43
 *     "route_provider" = {
 *       "default" = "Drupal\commerce_promotion\CouponRouteProvider",
 *     },
44
45
 *   },
 *   base_table = "commerce_promotion_coupon",
46
 *   admin_permission = "administer commerce_promotion",
47
48
49
 *   field_indexes = {
 *     "code"
 *   },
50
51
52
53
54
55
 *   entity_keys = {
 *     "id" = "id",
 *     "label" = "code",
 *     "uuid" = "uuid",
 *     "status" = "status",
 *   },
56
57
58
59
60
61
 *   links = {
 *     "add-form" = "/promotion/{commerce_promotion}/coupons/add",
 *     "edit-form" = "/promotion/{commerce_promotion}/coupons/{commerce_promotion_coupon}/edit",
 *     "delete-form" = "/promotion/{commerce_promotion}/coupons/{commerce_promotion_coupon}/delete",
 *     "collection" = "/promotion/{commerce_promotion}/coupons",
 *   },
62
63
 * )
 */
64
class Coupon extends CommerceContentEntityBase implements CouponInterface {
65

66
67
  use EntityChangedTrait;

68
69
70
71
72
73
74
75
76
  /**
   * {@inheritdoc}
   */
  protected function urlRouteParameters($rel) {
    $uri_route_parameters = parent::urlRouteParameters($rel);
    $uri_route_parameters['commerce_promotion'] = $this->getPromotionId();
    return $uri_route_parameters;
  }

77
78
79
80
  /**
   * {@inheritdoc}
   */
  public function getPromotion() {
81
    return $this->getTranslatedReferencedEntity('promotion_id');
82
83
84
85
86
87
88
89
90
  }

  /**
   * {@inheritdoc}
   */
  public function getPromotionId() {
    return $this->get('promotion_id')->target_id;
  }

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  /**
   * {@inheritdoc}
   */
  public function getCode() {
    return $this->get('code')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setCode($code) {
    $this->set('code', $code);
    return $this;
  }

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  /**
   * {@inheritdoc}
   */
  public function getCreatedTime() {
    return $this->get('created')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setCreatedTime($timestamp) {
    $this->set('created', $timestamp);
    return $this;
  }

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  /**
   * {@inheritdoc}
   */
  public function getUsageLimit() {
    return $this->get('usage_limit')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setUsageLimit($usage_limit) {
    $this->set('usage_limit', $usage_limit);
    return $this;
  }

136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  /**
   * {@inheritdoc}
   */
  public function getCustomerUsageLimit() {
    return $this->get('usage_limit_customer')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setCustomerUsageLimit($usage_limit_customer) {
    $this->set('usage_limit_customer', $usage_limit_customer);
    return $this;
  }

151
152
153
  /**
   * {@inheritdoc}
   */
154
  public function isEnabled() {
155
156
157
158
159
160
    return (bool) $this->getEntityKey('status');
  }

  /**
   * {@inheritdoc}
   */
161
162
  public function setEnabled($enabled) {
    $this->set('status', (bool) $enabled);
163
164
165
    return $this;
  }

166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
  /**
   * {@inheritdoc}
   */
  public function getStartDate($store_timezone = 'UTC') {
    if (!$this->get('start_date')->isEmpty()) {
      return new DrupalDateTime($this->get('start_date')->value, $store_timezone);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function setStartDate(DrupalDateTime $start_date) {
    $this->get('start_date')->value = $start_date->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getEndDate($store_timezone = 'UTC') {
    if (!$this->get('end_date')->isEmpty()) {
      return new DrupalDateTime($this->get('end_date')->value, $store_timezone);
    }
  }

  /**
   * {@inheritdoc}
   */
  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);
    }
  }

202
203
204
205
206
207
208
209
210
211
  /**
   * {@inheritdoc}
   */
  public function available(OrderInterface $order) {
    if (!$this->isEnabled()) {
      return FALSE;
    }
    if (!$this->getPromotion()->available($order)) {
      return FALSE;
    }
212
213
214
215
216
217
218
219
220
221
    $date = $order->getCalculationDate();
    $store_timezone = $date->getTimezone()->getName();
    $start_date = $this->getStartDate($store_timezone);
    if ($start_date && ($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;
    }
222
223
224
225
226
227
228
229
230
231

    $usage_limit = $this->getUsageLimit();
    $usage_limit_customer = $this->getCustomerUsageLimit();
    // If there are no usage limits, the coupon is available.
    if (!$usage_limit && !$usage_limit_customer) {
      return TRUE;
    }
    /** @var \Drupal\commerce_promotion\PromotionUsageInterface $usage */
    $usage = \Drupal::service('commerce_promotion.usage');

232
233
234
235
236
    // Check the global usage limit fist.
    if ($usage_limit && $usage_limit <= $usage->loadByCoupon($this)) {
      return FALSE;
    }

237
238
239
240
    // Only check customer usage when email address is known.
    if ($usage_limit_customer) {
      $email = $order->getEmail();
      if ($email && $usage_limit_customer <= $usage->loadByCoupon($this, $email)) {
241
242
243
        return FALSE;
      }
    }
244
245
246
247

    return TRUE;
  }

248
249
250
251
252
253
254
255
256
257
258
259
260
261
  /**
   * {@inheritdoc}
   */
  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
    parent::postSave($storage, $update);

    // Ensure there's a reference on each promotion.
    $promotion = $this->getPromotion();
    if ($promotion && !$promotion->hasCoupon($this)) {
      $promotion->addCoupon($this);
      $promotion->save();
    }
  }

262
263
264
265
266
267
268
269
  /**
   * {@inheritdoc}
   */
  public static function postDelete(EntityStorageInterface $storage, array $entities) {
    // Delete the related usage.
    /** @var \Drupal\commerce_promotion\PromotionUsageInterface $usage */
    $usage = \Drupal::service('commerce_promotion.usage');
    $usage->deleteByCoupon($entities);
270
271
272
273
274
275
276
277
278
279
280
281
    // Delete references to those coupons in promotions.
    foreach ($entities as $coupon) {
      $coupons_id[] = $coupon->id();
    }
    $promotions = \Drupal::entityTypeManager()->getStorage('commerce_promotion')->loadByProperties(['coupons' => $coupons_id]);
    /** @var \Drupal\commerce_promotion\Entity\PromotionInterface $promotion */
    foreach ($promotions as $promotion) {
      foreach ($entities as $entity) {
        $promotion->removeCoupon($entity);
      }
      $promotion->save();
    }
282
283
  }

284
285
286
287
288
289
  /**
   * {@inheritdoc}
   */
  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
    $fields = parent::baseFieldDefinitions($entity_type);

290
291
292
293
294
295
296
297
    // The promotion backreference, populated by Promotion::postSave().
    $fields['promotion_id'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Promotion'))
      ->setDescription(t('The parent promotion.'))
      ->setSetting('target_type', 'commerce_promotion')
      ->setReadOnly(TRUE)
      ->setDisplayConfigurable('view', TRUE);

298
299
    $fields['code'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Coupon code'))
300
      ->setDescription(t('The unique, machine-readable identifier for a coupon.'))
301
      ->addConstraint('CouponCode')
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
      ->setSettings([
        'max_length' => 50,
        'text_processing' => 0,
      ])
      ->setDefaultValue('')
      ->setDisplayOptions('view', [
        'label' => 'inline',
        'type' => 'string',
        'weight' => -4,
      ])
      ->setDisplayOptions('form', [
        'type' => 'string_textfield',
        'weight' => -4,
      ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
    $fields['start_date'] = BaseFieldDefinition::create('datetime')
      ->setLabel(t('Start date'))
      ->setDescription(t('The date the coupon becomes valid.'))
      ->setRequired(FALSE)
      ->setSetting('datetime_type', 'datetime')
      ->setSetting('datetime_optional_label', t('Provide a start date'))
      ->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 coupon 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,
      ]);

342
343
344
345
346
347
348
349
350
    $fields['created'] = BaseFieldDefinition::create('created')
      ->setLabel(t('Created'))
      ->setDescription(t('The time when the coupon was created.'));

    $fields['changed'] = BaseFieldDefinition::create('changed')
      ->setLabel(t('Changed'))
      ->setDescription(t('The time when the coupon was last edited.'))
      ->setDisplayConfigurable('view', TRUE);

351
352
353
354
355
356
357
358
359
    $fields['usage_limit'] = BaseFieldDefinition::create('integer')
      ->setLabel(t('Usage limit'))
      ->setDescription(t('The maximum number of times the coupon can be used. 0 for unlimited.'))
      ->setDefaultValue(0)
      ->setDisplayOptions('form', [
        'type' => 'commerce_usage_limit',
        'weight' => 4,
      ]);

360
361
362
363
364
365
366
367
368
    $fields['usage_limit_customer'] = BaseFieldDefinition::create('integer')
      ->setLabel(t('Customer usage limit'))
      ->setDescription(t('The maximum number of times the coupon can be used by a customer. 0 for unlimited.'))
      ->setDefaultValue(0)
      ->setDisplayOptions('form', [
        'type' => 'commerce_usage_limit',
        'weight' => 4,
      ]);

369
    $fields['status'] = BaseFieldDefinition::create('boolean')
370
371
      ->setLabel(t('Status'))
      ->setDescription(t('Whether the coupon is enabled.'))
372
      ->setDefaultValue(TRUE)
373
374
375
376
      ->setRequired(TRUE)
      ->setSettings([
        'on_label' => t('Enabled'),
        'off_label' => t('Disabled'),
377
      ])
378
379
380
381
      ->setDisplayOptions('form', [
        'type' => 'options_buttons',
        'weight' => 0,
      ]);
382
383
384
385
386

    return $fields;
  }

}