Commit 0da61e23 authored by lisastreeter's avatar lisastreeter Committed by mglaman

Issue #2902495 by lisastreeter, agoradesign, mglaman, heddn, bojanz: Allow...

Issue #2902495 by lisastreeter, agoradesign, mglaman, heddn, bojanz: Allow promotion usage to be limited per-customer
parent 9bc8c4f7
......@@ -141,3 +141,22 @@ function commerce_promotion_update_8204() {
->setDisplayConfigurable('form', TRUE);
$entity_definition_update->installFieldStorageDefinition('display_name', 'commerce_promotion', 'commerce_promotion', $storage_definition);
}
/**
* Add the usage_limit_customer field to promotions and coupons.
*/
function commerce_promotion_update_8205() {
$entity_definition_update = \Drupal::entityDefinitionUpdateManager();
$storage_definition = 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,
]);
$entity_definition_update->installFieldStorageDefinition('usage_limit_customer', 'commerce_promotion', 'commerce_promotion', $storage_definition);
$entity_definition_update->installFieldStorageDefinition('usage_limit_customer', 'commerce_promotion_coupon', 'commerce_promotion', $storage_definition);
}
......@@ -84,6 +84,7 @@ class CouponListBuilder extends EntityListBuilder {
public function buildHeader() {
$header['code'] = $this->t('Code');
$header['usage'] = $this->t('Usage');
$header['customer_limit'] = $this->t('Per-customer limit');
return $header + parent::buildHeader();
}
......@@ -95,11 +96,14 @@ class CouponListBuilder extends EntityListBuilder {
$current_usage = $this->usageCounts[$entity->id()];
$usage_limit = $entity->getUsageLimit();
$usage_limit = $usage_limit ?: $this->t('Unlimited');
$customer_limit = $entity->getCustomerUsageLimit();
$customer_limit = $customer_limit ?: $this->t('Unlimited');
$row['code'] = $entity->label();
if (!$entity->isEnabled()) {
$row['code'] .= ' (' . $this->t('Disabled') . ')';
}
$row['usage'] = $current_usage . ' / ' . $usage_limit;
$row['customer_limit'] = $customer_limit;
return $row + parent::buildRow($entity);
}
......
......@@ -109,6 +109,21 @@ class Coupon extends ContentEntityBase implements CouponInterface {
return $this;
}
/**
* {@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;
}
/**
* {@inheritdoc}
*/
......@@ -134,10 +149,20 @@ class Coupon extends ContentEntityBase implements CouponInterface {
if (!$this->getPromotion()->available($order)) {
return FALSE;
}
if ($usage_limit = $this->getUsageLimit()) {
/** @var \Drupal\commerce_promotion\PromotionUsageInterface $usage */
$usage = \Drupal::service('commerce_promotion.usage');
if ($usage_limit <= $usage->loadByCoupon($this)) {
$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');
// 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)) {
return FALSE;
}
}
......@@ -225,6 +250,15 @@ class Coupon extends ContentEntityBase implements CouponInterface {
'weight' => 4,
]);
$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,
]);
$fields['status'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Status'))
->setDescription(t('Whether the coupon is enabled.'))
......
......@@ -65,6 +65,27 @@ interface CouponInterface extends ContentEntityInterface {
*/
public function setUsageLimit($usage_limit);
/**
* Gets the per customer coupon usage limit.
*
* Represents the maximum number of times the coupon can be used by a customer.
* 0 for unlimited.
*
* @return int
* The per customer coupon usage limit.
*/
public function getCustomerUsageLimit();
/**
* Sets the per customer coupon usage limit.
*
* @param int $usage_limit_customer
* The per customer coupon usage limit.
*
* @return $this
*/
public function setCustomerUsageLimit($usage_limit_customer);
/**
* Gets whether the coupon is enabled.
*
......
......@@ -376,6 +376,21 @@ class Promotion extends CommerceContentEntityBase implements PromotionInterface
return $this;
}
/**
* {@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;
}
/**
* {@inheritdoc}
*/
......@@ -481,10 +496,25 @@ class Promotion extends CommerceContentEntityBase implements PromotionInterface
if ($end_date && $end_date->format('U') <= $date->format('U')) {
return FALSE;
}
if ($usage_limit = $this->getUsageLimit()) {
/** @var \Drupal\commerce_promotion\PromotionUsageInterface $usage */
$usage = \Drupal::service('commerce_promotion.usage');
if ($usage_limit <= $usage->load($this)) {
$usage_limit = $this->getUsageLimit();
$usage_limit_customer = $this->getCustomerUsageLimit();
// If there are no usage limits, the promotion is available.
if (!$usage_limit && !$usage_limit_customer) {
return TRUE;
}
/** @var \Drupal\commerce_promotion\PromotionUsageInterface $usage */
$usage = \Drupal::service('commerce_promotion.usage');
if ($usage_limit && $usage_limit <= $usage->load($this)) {
return FALSE;
}
if ($usage_limit_customer) {
// Promotion cannot apply to orders without email addresses.
if (!$email = $order->getEmail()) {
return FALSE;
}
if ($usage_limit_customer <= $usage->load($this, $email)) {
return FALSE;
}
}
......@@ -713,6 +743,15 @@ class Promotion extends CommerceContentEntityBase implements PromotionInterface
'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.'))
......
......@@ -251,6 +251,27 @@ interface PromotionInterface extends ContentEntityInterface, EntityStoresInterfa
*/
public function setUsageLimit($usage_limit);
/**
* Gets the per customer promotion usage limit.
*
* Represents the maximum number of times the promotion can be used by a customer.
* 0 for unlimited.
*
* @return int
* The per customer promotion usage limit.
*/
public function getCustomerUsageLimit();
/**
* Sets the per customer promotion usage limit.
*
* @param int $usage_limit_customer
* The per customer promotion usage limit.
*
* @return $this
*/
public function setCustomerUsageLimit($usage_limit_customer);
/**
* Gets the promotion start date/time.
*
......
......@@ -140,6 +140,27 @@ class CouponGenerateForm extends FormBase {
],
],
];
$form['limit_customer'] = [
'#type' => 'radios',
'#title' => $this->t('Number of uses per customer per coupon'),
'#options' => [
0 => $this->t('Unlimited'),
1 => $this->t('Limited number of uses'),
],
'#default_value' => 1,
];
$form['usage_limit_customer'] = [
'#type' => 'number',
'#title' => $this->t('Number of uses per customer'),
'#title_display' => 'invisible',
'#default_value' => 1,
'#min' => 1,
'#states' => [
'invisible' => [
':input[name="limit_customer"]' => ['value' => 0],
],
],
];
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = [
'#type' => 'submit',
......@@ -183,6 +204,7 @@ class CouponGenerateForm extends FormBase {
$coupon_values = [
'promotion_id' => $this->promotion->id(),
'usage_limit' => $values['limit'] ? $values['usage_limit'] : 0,
'usage_limit_customer' => $values['usage_limit_customer'],
];
$pattern = new CouponCodePattern($values['format'], $values['prefix'], $values['suffix'], $values['length']);
......
......@@ -99,6 +99,7 @@ class PromotionForm extends ContentEntityForm {
'start_date' => 'date_details',
'end_date' => 'date_details',
'usage_limit' => 'usage_details',
'usage_limit_customer' => 'usage_details',
'compatibility' => 'compatibility_details',
];
foreach ($field_details_mapping as $field => $group) {
......
......@@ -73,37 +73,52 @@ class UsageLimitWidget extends WidgetBase implements ContainerFactoryPluginInter
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$value = isset($items[$delta]->value) ? $items[$delta]->value : NULL;
$usage = 0;
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = $items[$delta]->getEntity();
if (!$entity->isNew()) {
if ($entity instanceof PromotionInterface) {
$usage = $this->usage->load($entity);
}
elseif ($entity instanceof CouponInterface) {
$usage = $this->usage->loadByCoupon($entity);
$field_name = $this->fieldDefinition->getName();
if ($field_name == 'usage_limit_customer') {
$title = $this->t('Total per customer');
$default_count = 1;
$radios_field = 'limit_customer';
$description = '';
}
else {
$title = $this->t('Total available');
$default_count = 10;
$radios_field = 'limit';
$usage = 0;
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = $items[$delta]->getEntity();
if (!$entity->isNew()) {
if ($entity instanceof PromotionInterface) {
$usage = $this->usage->load($entity);
}
elseif ($entity instanceof CouponInterface) {
$usage = $this->usage->loadByCoupon($entity);
}
}
$formatted_usage = $this->formatPlural($usage, '1 use', '@count uses');
$description = $this->t('Current usage: @usage.', ['@usage' => $formatted_usage]);
}
$formatted_usage = $this->formatPlural($usage, '1 use', '@count uses');
$radio_parents = array_merge($form['#parents'], [$this->fieldDefinition->getName(), 0, 'limit']);
$radio_parents = array_merge($form['#parents'], [$field_name, 0, $radios_field]);
$radio_path = array_shift($radio_parents);
$radio_path .= '[' . implode('][', $radio_parents) . ']';
$element['limit'] = [
$element[$radios_field] = [
'#type' => 'radios',
'#title' => $this->t('Total available'),
'#title' => $title,
'#options' => [
0 => $this->t('Unlimited'),
1 => $this->t('Limited number of uses'),
],
'#default_value' => $value ? 1 : 0,
];
$element['usage_limit'] = [
$element[$field_name] = [
'#type' => 'number',
'#title' => $this->t('Number of uses'),
'#title_display' => 'invisible',
'#default_value' => $value ?: 10,
'#description' => $this->t('Current usage: @usage.', ['@usage' => $formatted_usage]),
'#default_value' => $value ?: $default_count,
'#description' => $description,
'#states' => [
'invisible' => [
':input[name="' . $radio_path . '"]' => ['value' => 0],
......@@ -118,12 +133,14 @@ class UsageLimitWidget extends WidgetBase implements ContainerFactoryPluginInter
* {@inheritdoc}
*/
public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
$field_name = $this->fieldDefinition->getName();
$radios_field = ($field_name == 'usage_limit_customer') ? 'limit_customer' : 'limit';
$new_values = [];
foreach ($values as $key => $value) {
if (empty($value['limit'])) {
if (empty($value[$radios_field])) {
continue;
}
$new_values[$key] = $value['usage_limit'];
$new_values[$key] = $value[$field_name];
}
return $new_values;
}
......@@ -134,7 +151,9 @@ class UsageLimitWidget extends WidgetBase implements ContainerFactoryPluginInter
public static function isApplicable(FieldDefinitionInterface $field_definition) {
$entity_type = $field_definition->getTargetEntityTypeId();
$field_name = $field_definition->getName();
return in_array($entity_type, ['commerce_promotion', 'commerce_promotion_coupon']) && $field_name == 'usage_limit';
$applicable_entity_type = in_array($entity_type, ['commerce_promotion', 'commerce_promotion_coupon']);
$applicable_field_name = in_array($field_name, ['usage_limit', 'usage_limit_customer']);
return $applicable_entity_type && $applicable_field_name;
}
}
......@@ -110,6 +110,7 @@ class PromotionListBuilder extends EntityListBuilder implements FormInterface {
public function buildHeader() {
$header['name'] = $this->t('Name');
$header['usage'] = $this->t('Usage');
$header['customer_limit'] = $this->t('Per-customer limit');
$header['start_date'] = $this->t('Start date');
$header['end_date'] = $this->t('End date');
if ($this->hasTableDrag) {
......@@ -125,6 +126,8 @@ class PromotionListBuilder extends EntityListBuilder implements FormInterface {
$current_usage = $this->usageCounts[$entity->id()];
$usage_limit = $entity->getUsageLimit();
$usage_limit = $usage_limit ?: $this->t('Unlimited');
$customer_limit = $entity->getCustomerUsageLimit();
$customer_limit = $customer_limit ?: $this->t('Unlimited');
/** @var \Drupal\commerce_promotion\Entity\PromotionInterface $entity */
$row['#attributes']['class'][] = 'draggable';
$row['#weight'] = $entity->getWeight();
......@@ -133,6 +136,7 @@ class PromotionListBuilder extends EntityListBuilder implements FormInterface {
$row['name'] .= ' (' . $this->t('Disabled') . ')';
}
$row['usage'] = $current_usage . ' / ' . $usage_limit;
$row['customer_limit'] = $customer_limit;
$row['start_date'] = $entity->getStartDate()->format('M jS Y H:i:s');
$row['end_date'] = $entity->getEndDate() ? $entity->getEndDate()->format('M jS Y H:i:s') : '—';
if ($this->hasTableDrag) {
......@@ -187,6 +191,7 @@ class PromotionListBuilder extends EntityListBuilder implements FormInterface {
$row = $this->buildRow($entity);
$row['name'] = ['#markup' => $row['name']];
$row['usage'] = ['#markup' => $row['usage']];
$row['customer_limit'] = ['#markup' => $row['customer_limit']];
$row['start_date'] = ['#markup' => $row['start_date']];
$row['end_date'] = ['#markup' => $row['end_date']];
if (isset($row['weight'])) {
......
......@@ -116,7 +116,7 @@ class PromotionStorage extends CommerceContentEntityStorage implements Promotion
}
$promotions = $this->loadMultiple($result);
// Remove any promotions that have hit their usage limit.
// Remove any promotions that do not have a usage limit.
$promotions_with_usage_limits = array_filter($promotions, function ($promotion) {
/** @var \Drupal\commerce_promotion\Entity\PromotionInterface $promotion */
return !empty($promotion->getUsageLimit());
......@@ -128,6 +128,27 @@ class PromotionStorage extends CommerceContentEntityStorage implements Promotion
unset($promotions[$promotion_id]);
}
}
// Remove any promotions that do not have a customer usage limit.
$promotions_with_customer_usage_limits = array_filter($promotions, function ($promotion) {
/** @var \Drupal\commerce_promotion\Entity\PromotionInterface $promotion */
return !empty($promotion->getCustomerUsageLimit());
});
// Email is required for promotions that have customer usage limits.
$email = $order->getEmail();
if (!$email) {
foreach ($promotions_with_customer_usage_limits as $promotion_id => $promotion) {
unset($promotions[$promotion_id]);
}
}
else {
$customer_usages = $this->usage->loadMultiple($promotions_with_customer_usage_limits, $email);
foreach ($promotions_with_customer_usage_limits as $promotion_id => $promotion) {
/** @var \Drupal\commerce_promotion\Entity\PromotionInterface $promotion */
if ($promotion->getCustomerUsageLimit() <= $customer_usages[$promotion_id]) {
unset($promotions[$promotion_id]);
}
}
}
// Sort the remaining promotions.
uasort($promotions, [$this->entityType->getClass(), 'sort']);
......
......@@ -119,6 +119,7 @@ class CouponTest extends CommerceBrowserTestBase {
'code' => $this->randomMachineName(8),
'status' => FALSE,
'usage_limit' => 0,
'usage_limit_customer' => 0,
]);
$this->drupalGet($coupon->toUrl('delete-form'));
$this->assertSession()->statusCodeEquals(200);
......
......@@ -71,7 +71,8 @@ class PromotionTest extends CommerceWebDriverTestBase {
$this->getSession()->getPage()->fillField('conditions[form][order][order_total_price][configuration][form][amount][number]', '50.00');
// Confirm that the usage limit widget works properly.
$this->getSession()->getPage()->hasCheckedField(' Unlimited');
$this->assertSession()->fieldExists('usage_limit[0][limit]');
$this->assertSession()->fieldValueEquals('usage_limit[0][limit]', 0);
$usage_limit_xpath = '//input[@type="number" and @name="usage_limit[0][usage_limit]"]';
$this->assertFalse($this->getSession()->getDriver()->isVisible($usage_limit_xpath));
// Select 'Limited number of uses'.
......@@ -79,6 +80,15 @@ class PromotionTest extends CommerceWebDriverTestBase {
$this->assertTrue($this->getSession()->getDriver()->isVisible($usage_limit_xpath));
$this->getSession()->getPage()->fillField('usage_limit[0][usage_limit]', '99');
// Confirm that the customer usage limit widget works properly.
$this->assertSession()->fieldExists('usage_limit_customer[0][limit_customer]');
$this->assertSession()->fieldValueEquals('usage_limit_customer[0][limit_customer]', 0);
$customer_usage_limit_xpath = '//input[@type="number" and @name="usage_limit_customer[0][usage_limit_customer]"]';
$this->assertFalse($this->getSession()->getDriver()->isVisible($customer_usage_limit_xpath));
$this->getSession()->getPage()->selectFieldOption('usage_limit_customer[0][limit_customer]', '1');
$this->assertTrue($this->getSession()->getDriver()->isVisible($customer_usage_limit_xpath));
$this->getSession()->getPage()->fillField('usage_limit_customer[0][usage_limit_customer]', '5');
$this->setRawFieldValue('start_date[0][value][date]', '2019-11-29');
$this->setRawFieldValue('start_date[0][value][time]', '10:30:00');
$this->submitForm([], t('Save'));
......@@ -96,12 +106,18 @@ class PromotionTest extends CommerceWebDriverTestBase {
$condition = reset($conditions);
$this->assertEquals('50.00', $condition->getConfiguration()['amount']['number']);
$this->assertEquals('99', $promotion->getUsageLimit());
$this->assertEquals('5', $promotion->getCustomerUsageLimit());
$this->assertEquals('2019-11-29 10:30:00', $promotion->getStartDate()->format('Y-m-d H:i:s'));
$this->assertNull($promotion->getEndDate());
$this->drupalGet($promotion->toUrl('edit-form'));
$this->getSession()->getPage()->hasCheckedField('Limited number of uses');
$this->assertSession()->fieldExists('usage_limit[0][limit]');
$this->assertSession()->fieldValueEquals('usage_limit[0][limit]', 1);
$this->assertTrue($this->getSession()->getDriver()->isVisible($usage_limit_xpath));
$this->assertSession()->fieldExists('usage_limit_customer[0][limit_customer]');
$this->assertSession()->fieldValueEquals('usage_limit_customer[0][limit_customer]', 1);
$this->assertTrue($this->getSession()->getDriver()->isVisible($customer_usage_limit_xpath));
}
/**
......
......@@ -69,6 +69,7 @@ class CouponCodeGeneratorTest extends OrderKernelTestBase {
'promotion_id' => $promotion->id(),
'code' => 'COUPON' . $i,
'usage_limit' => 1,
'usage_limit_customer' => 1,
'status' => 1,
]);
$coupon->save();
......
......@@ -46,6 +46,8 @@ class CouponTest extends OrderKernelTestBase {
* @covers ::setCode
* @covers ::getUsageLimit
* @covers ::setUsageLimit
* @covers ::getCustomerUsageLimit
* @covers ::setCustomerUsageLimit
* @covers ::isEnabled
* @covers ::setEnabled
*/
......@@ -70,6 +72,9 @@ class CouponTest extends OrderKernelTestBase {
$coupon->setUsageLimit(10);
$this->assertEquals(10, $coupon->getUsageLimit());
$coupon->setCustomerUsageLimit(1);
$this->assertEquals(1, $coupon->getCustomerUsageLimit());
$coupon->setEnabled(TRUE);
$this->assertEquals(TRUE, $coupon->isEnabled());
}
......@@ -101,6 +106,7 @@ class CouponTest extends OrderKernelTestBase {
'order_types' => ['default'],
'stores' => [$this->store->id()],
'usage_limit' => 1,
'usage_limit_customer' => 1,
'start_date' => '2017-01-01',
'status' => TRUE,
]);
......@@ -110,6 +116,7 @@ class CouponTest extends OrderKernelTestBase {
'promotion_id' => $promotion->id(),
'code' => 'coupon_code',
'usage_limit' => 1,
'usage_limit_customer' => 1,
'status' => TRUE,
]);
$coupon->save();
......@@ -121,6 +128,25 @@ class CouponTest extends OrderKernelTestBase {
$this->container->get('commerce_promotion.usage')->register($order, $promotion, $coupon);
$this->assertFalse($coupon->available($order));
// Test limit coupon usage by customer.
$promotion->setUsageLimit(0);
$promotion->setCustomerUsageLimit(0);
$promotion->save();
$promotion = $this->reloadEntity($promotion);
$coupon->setUsageLimit(0);
$coupon->save();
$coupon = $this->reloadEntity($coupon);
$this->assertFalse($coupon->available($order));
$order->setEmail('another@example.com');
$order->setRefreshState(Order::REFRESH_SKIP);
$order->save();
$order = $this->reloadEntity($order);
$this->assertTrue($coupon->available($order));
\Drupal::service('commerce_promotion.usage')->register($order, $promotion, $coupon);
$this->assertFalse($coupon->available($order));
}
}
......@@ -69,6 +69,8 @@ class PromotionTest extends OrderKernelTestBase {
* @covers ::hasCoupon
* @covers ::getUsageLimit
* @covers ::setUsageLimit
* @covers ::getUsageLimit
* @covers ::setUsageLimit
* @covers ::getStartDate
* @covers ::setStartDate
* @covers ::getEndDate
......@@ -151,6 +153,9 @@ class PromotionTest extends OrderKernelTestBase {
$promotion->setUsageLimit(10);
$this->assertEquals(10, $promotion->getUsageLimit());
$promotion->setCustomerUsageLimit(2);
$this->assertEquals(2, $promotion->getCustomerUsageLimit());
$date_pattern = DateTimeItemInterface::DATETIME_STORAGE_FORMAT;
$time = $this->container->get('datetime.time');
$default_start_date = gmdate($date_pattern, $time->getRequestTime());
......
......@@ -74,6 +74,7 @@ class PromotionAvailabilityTest extends OrderKernelTestBase {
'order_types' => ['default'],
'stores' => [$this->store->id()],
'usage_limit' => 2,
'usage_limit_customer' => 0,
'start_date' => '2019-01-01T00:00:00',
'status' => TRUE,
]);
......@@ -101,6 +102,7 @@ class PromotionAvailabilityTest extends OrderKernelTestBase {
'order_types' => ['default'],
'stores' => [$this->store->id()],
'usage_limit' => 1,
'usage_limit_customer' => 0,
'status' => TRUE,
]);
$promotion->save();
......@@ -130,6 +132,7 @@ class PromotionAvailabilityTest extends OrderKernelTestBase {
'order_types' => ['default'],
'stores' => [$this->store->id()],
'usage_limit' => 1,
'usage_limit_customer' => 0,