Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2863864 - Disable promotions via cron if end date or usage limit hit #708

Open
wants to merge 21 commits into
base: 8.x-2.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
527df0b
Disable expired promotions on cron run.
Apr 4, 2017
221cbd1
Merge branch '8.x-2.x' of https://github.com/swickham78/commerce into…
Apr 7, 2017
2b8f266
Issue #2863864: Moved max usage load of promotions to its own method …
Apr 7, 2017
caf23a5
Issue #2863864: Added tests for loading of expired and maxed usaged p…
Apr 7, 2017
863ce8f
Issue #2863864: Fix merge conflict w/ recent work.
Apr 7, 2017
24856a6
Merge branch '8.x-2.x' of https://github.com/swickham78/commerce into…
Apr 10, 2017
e7d8a40
Issue #2863864: Updates to meet coding standards.
Apr 10, 2017
0794a1b
Disable expired promotions on cron run.
Apr 4, 2017
e0f422f
Issue #2863864: Moved max usage load of promotions to its own method …
Apr 7, 2017
73e867a
Issue #2863864: Added tests for loading of expired and maxed usaged p…
Apr 7, 2017
70ce340
Issue #2863864: Updates to meet coding standards.
Apr 10, 2017
029e4c4
Added cron function test.
Jun 28, 2017
4cb8f54
Merge branch 'promotions_disable_expired' of https://github.com/swick…
Jun 28, 2017
a557186
Disable expired promotions on cron run.
Apr 4, 2017
f659ea1
Issue #2863864: Moved max usage load of promotions to its own method …
Apr 7, 2017
6bba454
Issue #2863864: Added tests for loading of expired and maxed usaged p…
Apr 7, 2017
4ac0f14
Issue #2863864: Updates to meet coding standards.
Apr 10, 2017
d3fda01
Issue #2863864: Moved max usage load of promotions to its own method …
Apr 7, 2017
9aef5f3
Issue #2863864: Updates to meet coding standards.
Apr 10, 2017
04ef19f
Added cron function test.
Jun 28, 2017
d5a4e42
Merge branch 'promotions_disable_expired' of https://github.com/swick…
Aug 11, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions modules/promotion/commerce_promotion.module
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,34 @@ function commerce_promotion_entity_base_field_info(EntityTypeInterface $entity_t
return $fields;
}
}

/**
* Implements hook_cron().
*/
function commerce_promotion_cron() {
/** @var \Drupal\commerce_promotion\PromotionStorageInterface $promotion_storage */
$promotion_storage = \Drupal::service('entity_type.manager')->getStorage('commerce_promotion');

// Disable any promotions that have passed their end date.
$promotions = $promotion_storage->loadExpired();

if (!empty($promotions)) {
/** @var \Drupal\commerce_promotion\Entity\PromotionInterface $promotion */
foreach ($promotions as $promotion) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bojanz I think this is fine versus a queue. There shouldn't be that much activity, generally.

$promotion->setEnabled(FALSE);
$promotion->save();
}
}

// Disable any promotions that have met their max usage.
$promotions = $promotion_storage->loadMaxedUsage();

if (!empty($promotions)) {
/** @var \Drupal\commerce_promotion\Entity\PromotionInterface $promotion */
foreach ($promotions as $promotion) {
$promotion->setEnabled(FALSE);
$promotion->save();
}
}

}
51 changes: 51 additions & 0 deletions modules/promotion/src/PromotionStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,55 @@ public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $st
return $promotions;
}

/**
* {@inheritdoc}
*/
public function loadExpired() {
$query = $this->getQuery();

$query
->condition('end_date', gmdate('Y-m-d'), '<')
->condition('status', TRUE);

$result = $query->execute();

if (empty($result)) {
return [];
}

return $this->loadMultiple($result);
}

/**
* {@inheritdoc}
*/
public function loadMaxedUsage() {
$query = $this->getQuery();

$query
->condition('usage_limit', 1, '>=')
->condition('status', TRUE);

$result = $query->execute();

if (empty($result)) {
return [];
}

$promotions = $this->loadMultiple($result);
$maxed_promotions = [];

// Get an array of each promotion's use count.
$promotion_uses = $this->usage->getUsageMultiple($promotions);

/** @var \Drupal\commerce_promotion\Entity\PromotionInterface $promotion */
foreach ($promotions as $promotion) {
if ($promotion_uses[$promotion->id()] >= $promotion->getUsageLimit()) {
$maxed_promotions[] = $promotion;
}
}

return $maxed_promotions;
}

}
16 changes: 16 additions & 0 deletions modules/promotion/src/PromotionStorageInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,20 @@ interface PromotionStorageInterface extends ContentEntityStorageInterface {
*/
public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $store);

/**
* Return active promotions that have passed their end date.
*
* @return \Drupal\commerce_promotion\Entity\PromotionInterface[]
* The expired promotion entities.
*/
public function loadExpired();

/**
* Returns active promotions which have a met their maximum usage.
*
* @return \Drupal\commerce_promotion\Entity\PromotionInterface[]
* Promotions with maxed usage.
*/
public function loadMaxedUsage();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bojanz name bikeshedding.


}
109 changes: 109 additions & 0 deletions modules/promotion/tests/src/Kernel/PromotionStorageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace Drupal\Tests\commerce_promotion\Kernel;

use Drupal\commerce_order\Entity\Order;
use Drupal\commerce_order\Entity\OrderType;
use Drupal\commerce_order\Entity\OrderItemType;
use Drupal\commerce_promotion\Entity\Coupon;
use Drupal\commerce_promotion\Entity\Promotion;
use Drupal\Core\Datetime\DrupalDateTime;
Expand All @@ -22,6 +24,20 @@ class PromotionStorageTest extends CommerceKernelTestBase {
*/
protected $promotionStorage;

/**
* The usage.
*
* @var \Drupal\commerce_promotion\PromotionUsageInterface
*/
protected $usage;

/**
* The test order.
*
* @var \Drupal\commerce_order\Entity\OrderInterface
*/
protected $order;

/**
* Modules to enable.
*
Expand Down Expand Up @@ -54,6 +70,25 @@ protected function setUp() {
$this->installSchema('commerce_promotion', ['commerce_promotion_usage']);

$this->promotionStorage = $this->container->get('entity_type.manager')->getStorage('commerce_promotion');
$this->usage = $this->container->get('commerce_promotion.usage');

OrderItemType::create([
'id' => 'test',
'label' => 'Test',
'orderType' => 'default',
])->save();

$this->order = Order::create([
'type' => 'default',
'state' => 'completed',
'mail' => '[email protected]',
'ip_address' => '127.0.0.1',
'order_id' => '6',
'order_number' => '6',
'store_id' => $this->store,
'uid' => $this->createUser()->id(),
'order_items' => [],
]);
}

/**
Expand Down Expand Up @@ -213,4 +248,78 @@ public function testWeight() {
$this->assertEquals($promotion1->label(), $promotion->label());
}

/**
* Tests that active promotions which have expired are loaded.
*/
public function testLoadExpired() {
$order_type = OrderType::load('default');

$valid_promotion = Promotion::create([
'name' => 'Valid Promotion',
'order_types' => [$order_type],
'stores' => [$this->store->id()],
'status' => TRUE,
'start_date' => gmdate('Y-m-d', time()),
'end_date' => gmdate('Y-m-d', time() + 86400),
]);
$this->assertEquals(SAVED_NEW, $valid_promotion->save());

$expired_promotion = Promotion::create([
'name' => 'Expired Promotion',
'order_types' => [$order_type],
'stores' => [$this->store->id()],
'status' => TRUE,
'start_date' => gmdate('Y-m-d', time() - 172800),
'end_date' => gmdate('Y-m-d', time() - 86400),
]);
$this->assertEquals(SAVED_NEW, $expired_promotion->save());

$promotions = $this->promotionStorage->loadExpired();
$this->assertCount(1, $promotions);

$promotion = reset($promotions);
$this->assertEquals($expired_promotion->label(), $promotion->label());
}

/**
* Tests that active promotions which have met their maximum usage are loaded.
*/
public function testLoadUsed() {
$order_type = OrderType::load('default');

$promotion1 = Promotion::create([
'name' => 'Promotion 1',
'order_types' => [$order_type],
'stores' => [$this->store->id()],
'status' => TRUE,
'usage_limit' => 1,
]);
$this->assertEquals(SAVED_NEW, $promotion1->save());
$this->usage->addUsage($this->order, $promotion1);

$promotion2 = Promotion::create([
'name' => 'Promotion 2',
'order_types' => [$order_type],
'stores' => [$this->store->id()],
'status' => TRUE,
'usage_limit' => 2,
]);
$this->assertEquals(SAVED_NEW, $promotion2->save());
$this->usage->addUsage($this->order, $promotion2);

$promotion3 = Promotion::create([
'name' => 'Promotion 3',
'order_types' => [$order_type],
'stores' => [$this->store->id()],
'status' => TRUE,
]);
$this->assertEquals(SAVED_NEW, $promotion3->save());

$promotions = $this->promotionStorage->loadMaxedUsage();
$this->assertCount(1, $promotions);

$promotion = reset($promotions);
$this->assertEquals($promotion1->label(), $promotion->label());
}

}
56 changes: 56 additions & 0 deletions modules/promotion/tests/src/Kernel/UsageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ protected function setUp() {
'state' => 'draft',
'mail' => '[email protected]',
'ip_address' => '127.0.0.1',
'order_id' => '6',
'order_number' => '6',
'store_id' => $this->store,
'uid' => $this->createUser(),
Expand Down Expand Up @@ -237,4 +238,59 @@ public function testPromotionFiltering() {
$this->assertEmpty($valid_promotions);
}

/**
* Tests the Promotions module cron job.
*/
public function testPromotionCron() {
$order_type = OrderType::load($this->order->bundle());

// Date restricted promotions.
$valid_promotion = Promotion::create([
'name' => 'Valid Promotion',
'order_types' => [$order_type],
'stores' => [$this->store->id()],
'status' => TRUE,
'start_date' => gmdate('Y-m-d', time()),
'end_date' => gmdate('Y-m-d', time() + 86400),
]);
$this->assertEquals(SAVED_NEW, $valid_promotion->save());

$expired_promotion = Promotion::create([
'name' => 'Expired Promotion',
'order_types' => [$order_type],
'stores' => [$this->store->id()],
'status' => TRUE,
'start_date' => gmdate('Y-m-d', time() - 172800),
'end_date' => gmdate('Y-m-d', time() - 86400),
]);
$this->assertEquals(SAVED_NEW, $expired_promotion->save());

// Usage restricted promotions.
$promotion1 = Promotion::create([
'name' => 'Promotion 1',
'order_types' => [$order_type],
'stores' => [$this->store->id()],
'status' => TRUE,
'usage_limit' => 1,
]);
$this->assertEquals(SAVED_NEW, $promotion1->save());
$this->usage->addUsage($this->order, $promotion1);

$promotion2 = Promotion::create([
'name' => 'Promotion 2',
'order_types' => [$order_type],
'stores' => [$this->store->id()],
'status' => TRUE,
'usage_limit' => 2,
]);
$this->assertEquals(SAVED_NEW, $promotion2->save());
$this->usage->addUsage($this->order, $promotion2);

commerce_promotion_cron();

$valid_promotions = $this->promotionStorage->loadAvailable($order_type, $this->store);
$this->assertCount(2, $valid_promotions);

}

}