From 527df0b3e29bdd7f2fffa97989e388f702a17c90 Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Tue, 4 Apr 2017 00:00:09 -0700 Subject: [PATCH 01/16] Disable expired promotions on cron run. --- modules/promotion/commerce_promotion.module | 27 +++++++++++++ modules/promotion/src/PromotionStorage.php | 40 +++++++++++++++++++ .../src/PromotionStorageInterface.php | 11 +++++ 3 files changed, 78 insertions(+) diff --git a/modules/promotion/commerce_promotion.module b/modules/promotion/commerce_promotion.module index 2132fe1772..4e4ca96e3b 100644 --- a/modules/promotion/commerce_promotion.module +++ b/modules/promotion/commerce_promotion.module @@ -79,3 +79,30 @@ function commerce_promotion_entity_base_field_info(EntityTypeInterface $entity_t return $fields; } } + +/** + * Implements hook_cron() + */ +function commerce_promotion_cron() { + commerce_promotion_disabled_expired(); +} + +/** + * Get all expired promotions that are still active and disable them. + */ +function commerce_promotion_disabled_expired() { + /** @var \Drupal\commerce_promotion\PromotionStorageInterface $promotion_storage */ + $promotion_storage = \Drupal::service('entity_type.manager')->getStorage('commerce_promotion'); + + // Get query for all expired promotions. + $promotions = $promotion_storage->loadExpired(); + + if ($promotions !== FALSE) { + // Disable all expired promotions. + foreach ($promotions as $promotion) { + $promotion->setEnabled(FALSE); + $promotion->save(); + } + } +} + diff --git a/modules/promotion/src/PromotionStorage.php b/modules/promotion/src/PromotionStorage.php index a84f1bc150..0ee6a07d3f 100644 --- a/modules/promotion/src/PromotionStorage.php +++ b/modules/promotion/src/PromotionStorage.php @@ -106,6 +106,46 @@ public function loadByCoupon(OrderTypeInterface $order_type, StoreInterface $sto return reset($promotions); } + /** + * Builds a query that will load all promotions that are no longer valid + * determined by the base field limiting values. + * + * @param bool $only_enabled + * Only include currently enabled promotions that have expired. + * @return array|bool|\Drupal\Core\Entity\EntityInterface[] + * The expired promotion entities. Returns FALSE if none found. + */ + public function loadExpired($only_enabled = TRUE) { + // Subquery to determine the amount of times a coupon has been used. + $usage_query = $this->database->select('commerce_promotion_usage', 'cpu'); + $usage_query->addExpression('COUNT(cpu.promotion_id)', 'count'); + $usage_query->where('cpu.promotion_id = cpd.promotion_id'); + $usage_query->groupBy('cpu.promotion_id'); + + $query = $this->database->select($this->getDataTable(), 'cpd'); + + // We want to get results of queries that have passed their final date or + // have met their max usage. + $or_condition = $query->orConditionGroup() + ->condition('cpd.end_date', gmdate('Y-m-d'), '<=') + ->condition('cpd.usage_limit', $usage_query, '<='); + + $query->addField('cpd', 'promotion_id'); + $query->condition($or_condition); + + if ($only_enabled) { + $query->condition('cpd.status', 1); + } + + $result = $query->execute()->fetchCol(0); + + if (empty($result)) { + return FALSE; + } + + return $this->loadMultiple($result); + } + /** * Builds the base query for loading valid promotions. * diff --git a/modules/promotion/src/PromotionStorageInterface.php b/modules/promotion/src/PromotionStorageInterface.php index 7bb18e8064..126e6a7ea2 100644 --- a/modules/promotion/src/PromotionStorageInterface.php +++ b/modules/promotion/src/PromotionStorageInterface.php @@ -40,4 +40,15 @@ public function loadValid(OrderTypeInterface $order_type, StoreInterface $store) */ public function loadByCoupon(OrderTypeInterface $order_type, StoreInterface $store, CouponInterface $coupon); + /** + * Builds a query that will load all promotions that are no longer valid + * determined by the base field limiting values. + * + * @param bool $only_enabled + * Only include currently enabled promotions that have expired. + * @return array|bool|\Drupal\Core\Entity\EntityInterface[] + * The expired promotion entities. Returns FALSE if none found. + */ + public function loadExpired($only_enabled); + } From 2b8f2661de33c7101e80a96834bb00270b0b1560 Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Fri, 7 Apr 2017 01:24:12 -0700 Subject: [PATCH 02/16] Issue #2863864: Moved max usage load of promotions to its own method making use of existing service. --- modules/promotion/commerce_promotion.module | 24 ++++--- modules/promotion/src/PromotionStorage.php | 70 ++++++++++++------- .../src/PromotionStorageInterface.php | 21 ++++-- 3 files changed, 71 insertions(+), 44 deletions(-) diff --git a/modules/promotion/commerce_promotion.module b/modules/promotion/commerce_promotion.module index 4e4ca96e3b..c6296d132c 100644 --- a/modules/promotion/commerce_promotion.module +++ b/modules/promotion/commerce_promotion.module @@ -84,25 +84,27 @@ function commerce_promotion_entity_base_field_info(EntityTypeInterface $entity_t * Implements hook_cron() */ function commerce_promotion_cron() { - commerce_promotion_disabled_expired(); -} - -/** - * Get all expired promotions that are still active and disable them. - */ -function commerce_promotion_disabled_expired() { /** @var \Drupal\commerce_promotion\PromotionStorageInterface $promotion_storage */ $promotion_storage = \Drupal::service('entity_type.manager')->getStorage('commerce_promotion'); - // Get query for all expired promotions. + // Disable any promotions that have passed their end date. $promotions = $promotion_storage->loadExpired(); - if ($promotions !== FALSE) { - // Disable all expired promotions. + if (!empty($promotions)) { foreach ($promotions as $promotion) { $promotion->setEnabled(FALSE); $promotion->save(); } } -} + // Disable any promotions that have met their max usage. + $promotions = $promotion_storage->loadMaxedUsage(); + + if (!empty($promotions)) { + foreach ($promotions as $promotion) { + $promotion->setEnabled(FALSE); + $promotion->save(); + } + } + +} diff --git a/modules/promotion/src/PromotionStorage.php b/modules/promotion/src/PromotionStorage.php index 0ee6a07d3f..46793c52e5 100644 --- a/modules/promotion/src/PromotionStorage.php +++ b/modules/promotion/src/PromotionStorage.php @@ -107,43 +107,61 @@ public function loadByCoupon(OrderTypeInterface $order_type, StoreInterface $sto } /** - * Builds a query that will load all promotions that are no longer valid - * determined by the base field limiting values. + * Return all active promotions that are no longer valid determined by their + * end date. * - * @param bool $only_enabled - * Only include currently enabled promotions that have expired. - * @return array|bool|\Drupal\Core\Entity\EntityInterface[] - * The expired promotion entities. Returns FALSE if none found. + * @return array|\Drupal\Core\Entity\EntityInterface[] + * The expired promotion entities. */ - public function loadExpired($only_enabled = TRUE) { - // Subquery to determine the amount of times a coupon has been used. - $usage_query = $this->database->select('commerce_promotion_usage', 'cpu'); - $usage_query->addExpression('COUNT(cpu.promotion_id)', 'count'); - $usage_query->where('cpu.promotion_id = cpd.promotion_id'); - $usage_query->groupBy('cpu.promotion_id'); - - $query = $this->database->select($this->getDataTable(), 'cpd'); + public function loadExpired() { + $query = $this->getQuery(); - // We want to get results of queries that have passed their final date or - // have met their max usage. - $or_condition = $query->orConditionGroup() - ->condition('cpd.end_date', gmdate('Y-m-d'), '<=') - ->condition('cpd.usage_limit', $usage_query, '<='); + $query + ->condition('end_date', gmdate('Y-m-d'), '<') + ->condition('status', TRUE); - $query->addField('cpd', 'promotion_id'); - $query->condition($or_condition); + $result = $query->execute(); - if ($only_enabled) { - $query->condition('cpd.status', 1); + if (empty($result)) { + return []; } - $result = $query->execute()->fetchCol(0); + return $this->loadMultiple($result); + } + + /** + * Returns any promotions which are still active and have a met their maximum + * usage. + * + * @return array|\Drupal\Core\Entity\EntityInterface[] + * Promotions with maxed usage. + */ + public function loadMaxedUsage() { + $query = $this->getQuery(); + + $query + ->condition('usage_limit', 1, '>=') + ->condition('status', TRUE); + + $result = $query->execute(); if (empty($result)) { - return FALSE; + return []; } - return $this->loadMultiple($result); + $promotions = $this->loadMultiple($result); + $maxed_promotions = []; + + // Get an array of each promotion's use count. + $promotion_uses = $this->usage->getUsageMultiple($promotions); + + foreach ($promotions as $promotion) { + if ($promotion_uses[$promotion->id()] >= $promotion->getUsageLimit()) { + $maxed_promotions[] = $promotion; + } + } + + return $maxed_promotions; } /** diff --git a/modules/promotion/src/PromotionStorageInterface.php b/modules/promotion/src/PromotionStorageInterface.php index 126e6a7ea2..7df4017b0e 100644 --- a/modules/promotion/src/PromotionStorageInterface.php +++ b/modules/promotion/src/PromotionStorageInterface.php @@ -41,14 +41,21 @@ public function loadValid(OrderTypeInterface $order_type, StoreInterface $store) public function loadByCoupon(OrderTypeInterface $order_type, StoreInterface $store, CouponInterface $coupon); /** - * Builds a query that will load all promotions that are no longer valid - * determined by the base field limiting values. + * Return all active promotions that are no longer valid determined by their + * end date. * - * @param bool $only_enabled - * Only include currently enabled promotions that have expired. - * @return array|bool|\Drupal\Core\Entity\EntityInterface[] - * The expired promotion entities. Returns FALSE if none found. + * @return array|\Drupal\Core\Entity\EntityInterface[] + * The expired promotion entities. */ - public function loadExpired($only_enabled); + public function loadExpired(); + + /** + * Returns any promotions which are still active and have a met their maximum + * usage. + * + * @return array|\Drupal\Core\Entity\EntityInterface[] + * Promotions with maxed usage. + */ + public function loadMaxedUsage(); } From caf23a5b6f8b35bf171815009fdc80037d4da825 Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Fri, 7 Apr 2017 01:24:43 -0700 Subject: [PATCH 03/16] Issue #2863864: Added tests for loading of expired and maxed usaged promotions. --- .../tests/src/Kernel/PromotionStorageTest.php | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php index 9e56c0d74b..021668d9ed 100644 --- a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php +++ b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php @@ -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; @@ -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. * @@ -55,6 +71,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' => 'test@example.com', + 'ip_address' => '127.0.0.1', + 'order_id' => '6', + 'order_number' => '6', + 'store_id' => $this->store, + 'uid' => $this->createUser()->id(), + 'order_items' => [], + ]); } /** @@ -252,4 +287,58 @@ public function testWeight() { $this->assertEquals($promotion1->label(), $promotion->label()); } + public function testLoadExpired() { + $valid_promotion = Promotion::create([ + 'name' => 'Valid Promotion', + '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', + '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->assertEquals(sizeof($promotions), 1); + + $promotion = reset($promotions); + $this->assertEquals($expired_promotion->label(), $promotion->label()); + } + + public function testLoadUsed() { + $promotion1 = Promotion::create([ + 'name' => 'Promotion 1', + 'status' => TRUE, + 'usage_limit' => 1, + ]); + $this->assertEquals(SAVED_NEW, $promotion1->save()); + $this->usage->addUsage($this->order, $promotion1); + + $promotion2 = Promotion::create([ + 'name' => 'Promotion 2', + 'status' => TRUE, + 'usage_limit' => 2, + ]); + $this->assertEquals(SAVED_NEW, $promotion2->save()); + $this->usage->addUsage($this->order, $promotion2); + + $promotion3 = Promotion::create([ + 'name' => 'Promotion 3', + 'status' => TRUE, + ]); + $this->assertEquals(SAVED_NEW, $promotion3->save()); + + $promotions = $this->promotionStorage->loadMaxedUsage(); + $this->assertEquals(sizeof($promotions), 1); + + $promotion = reset($promotions); + $this->assertEquals($promotion1->label(), $promotion->label()); + } + } From e7d8a408ead05d44da16bcc57b57e1beea08e972 Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Mon, 10 Apr 2017 16:25:46 -0700 Subject: [PATCH 04/16] Issue #2863864: Updates to meet coding standards. --- modules/promotion/commerce_promotion.module | 4 +++- modules/promotion/src/PromotionStorage.php | 11 +++++------ modules/promotion/src/PromotionStorageInterface.php | 10 ++++------ .../tests/src/Kernel/PromotionStorageTest.php | 10 ++++++++-- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/modules/promotion/commerce_promotion.module b/modules/promotion/commerce_promotion.module index c6296d132c..5b3ce868fb 100644 --- a/modules/promotion/commerce_promotion.module +++ b/modules/promotion/commerce_promotion.module @@ -81,7 +81,7 @@ function commerce_promotion_entity_base_field_info(EntityTypeInterface $entity_t } /** - * Implements hook_cron() + * Implements hook_cron(). */ function commerce_promotion_cron() { /** @var \Drupal\commerce_promotion\PromotionStorageInterface $promotion_storage */ @@ -91,6 +91,7 @@ function commerce_promotion_cron() { $promotions = $promotion_storage->loadExpired(); if (!empty($promotions)) { + /** @var \Drupal\commerce_promotion\Entity\PromotionInterface $promotion */ foreach ($promotions as $promotion) { $promotion->setEnabled(FALSE); $promotion->save(); @@ -101,6 +102,7 @@ function commerce_promotion_cron() { $promotions = $promotion_storage->loadMaxedUsage(); if (!empty($promotions)) { + /** @var \Drupal\commerce_promotion\Entity\PromotionInterface $promotion */ foreach ($promotions as $promotion) { $promotion->setEnabled(FALSE); $promotion->save(); diff --git a/modules/promotion/src/PromotionStorage.php b/modules/promotion/src/PromotionStorage.php index c2c0af260b..9a6c0c8a13 100644 --- a/modules/promotion/src/PromotionStorage.php +++ b/modules/promotion/src/PromotionStorage.php @@ -105,10 +105,9 @@ public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $st } /** - * Return all active promotions that are no longer valid determined by their - * end date. + * Return active promotions that have passed their end date. * - * @return array|\Drupal\Core\Entity\EntityInterface[] + * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] * The expired promotion entities. */ public function loadExpired() { @@ -128,10 +127,9 @@ public function loadExpired() { } /** - * Returns any promotions which are still active and have a met their maximum - * usage. + * Returns active promotions which have a met their maximum usage. * - * @return array|\Drupal\Core\Entity\EntityInterface[] + * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] * Promotions with maxed usage. */ public function loadMaxedUsage() { @@ -153,6 +151,7 @@ public function loadMaxedUsage() { // 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; diff --git a/modules/promotion/src/PromotionStorageInterface.php b/modules/promotion/src/PromotionStorageInterface.php index b17af3ab5e..bfdabf1bf9 100644 --- a/modules/promotion/src/PromotionStorageInterface.php +++ b/modules/promotion/src/PromotionStorageInterface.php @@ -25,19 +25,17 @@ interface PromotionStorageInterface extends ContentEntityStorageInterface { public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $store); /** - * Return all active promotions that are no longer valid determined by their - * end date. + * Return active promotions that have passed their end date. * - * @return array|\Drupal\Core\Entity\EntityInterface[] + * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] * The expired promotion entities. */ public function loadExpired(); /** - * Returns any promotions which are still active and have a met their maximum - * usage. + * Returns active promotions which have a met their maximum usage. * - * @return array|\Drupal\Core\Entity\EntityInterface[] + * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] * Promotions with maxed usage. */ public function loadMaxedUsage(); diff --git a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php index d5ea545295..ff78d03752 100644 --- a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php +++ b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php @@ -250,6 +250,9 @@ public function testWeight() { $this->assertEquals($promotion1->label(), $promotion->label()); } + /** + * Tests that active promotions which have expired are loaded. + */ public function testLoadExpired() { $valid_promotion = Promotion::create([ 'name' => 'Valid Promotion', @@ -268,12 +271,15 @@ public function testLoadExpired() { $this->assertEquals(SAVED_NEW, $expired_promotion->save()); $promotions = $this->promotionStorage->loadExpired(); - $this->assertEquals(sizeof($promotions), 1); + $this->assertEquals(count($promotions), 1); $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() { $promotion1 = Promotion::create([ 'name' => 'Promotion 1', @@ -298,7 +304,7 @@ public function testLoadUsed() { $this->assertEquals(SAVED_NEW, $promotion3->save()); $promotions = $this->promotionStorage->loadMaxedUsage(); - $this->assertEquals(sizeof($promotions), 1); + $this->assertEquals(count($promotions), 1); $promotion = reset($promotions); $this->assertEquals($promotion1->label(), $promotion->label()); From 0794a1bdb01df2f20b33c4b0a83113ff940b0949 Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Tue, 4 Apr 2017 00:00:09 -0700 Subject: [PATCH 05/16] Disable expired promotions on cron run. --- modules/promotion/commerce_promotion.module | 27 +++++++++ modules/promotion/src/PromotionStorage.php | 57 +++++++++++++++++++ .../src/PromotionStorageInterface.php | 11 ++++ 3 files changed, 95 insertions(+) diff --git a/modules/promotion/commerce_promotion.module b/modules/promotion/commerce_promotion.module index 9bb5fc59e3..4cdaf00fea 100644 --- a/modules/promotion/commerce_promotion.module +++ b/modules/promotion/commerce_promotion.module @@ -82,3 +82,30 @@ function commerce_promotion_entity_base_field_info(EntityTypeInterface $entity_t return $fields; } } + +/** + * Implements hook_cron() + */ +function commerce_promotion_cron() { + commerce_promotion_disabled_expired(); +} + +/** + * Get all expired promotions that are still active and disable them. + */ +function commerce_promotion_disabled_expired() { + /** @var \Drupal\commerce_promotion\PromotionStorageInterface $promotion_storage */ + $promotion_storage = \Drupal::service('entity_type.manager')->getStorage('commerce_promotion'); + + // Get query for all expired promotions. + $promotions = $promotion_storage->loadExpired(); + + if ($promotions !== FALSE) { + // Disable all expired promotions. + foreach ($promotions as $promotion) { + $promotion->setEnabled(FALSE); + $promotion->save(); + } + } +} + diff --git a/modules/promotion/src/PromotionStorage.php b/modules/promotion/src/PromotionStorage.php index 63ec779417..981d526218 100644 --- a/modules/promotion/src/PromotionStorage.php +++ b/modules/promotion/src/PromotionStorage.php @@ -118,4 +118,61 @@ public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $st return $promotions; } + /** + * Return active promotions that have passed their end date. + * + * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] + * The expired promotion entities. + */ + 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); + } + + /** + * Returns active promotions which have a met their maximum usage. + * + * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] + * Promotions with maxed usage. + */ + 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; + } + } diff --git a/modules/promotion/src/PromotionStorageInterface.php b/modules/promotion/src/PromotionStorageInterface.php index 5690751034..25b551526d 100644 --- a/modules/promotion/src/PromotionStorageInterface.php +++ b/modules/promotion/src/PromotionStorageInterface.php @@ -24,4 +24,15 @@ interface PromotionStorageInterface extends ContentEntityStorageInterface { */ public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $store); + /** + * Builds a query that will load all promotions that are no longer valid + * determined by the base field limiting values. + * + * @param bool $only_enabled + * Only include currently enabled promotions that have expired. + * @return array|bool|\Drupal\Core\Entity\EntityInterface[] + * The expired promotion entities. Returns FALSE if none found. + */ + public function loadExpired($only_enabled); + } From e0f422fbe59ce0ec2b9ce08c77a9e9f6c9b28707 Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Fri, 7 Apr 2017 01:24:12 -0700 Subject: [PATCH 06/16] Issue #2863864: Moved max usage load of promotions to its own method making use of existing service. --- modules/promotion/commerce_promotion.module | 24 ++++++++++--------- .../src/PromotionStorageInterface.php | 21 ++++++++++------ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/modules/promotion/commerce_promotion.module b/modules/promotion/commerce_promotion.module index 4cdaf00fea..80d69a6d96 100644 --- a/modules/promotion/commerce_promotion.module +++ b/modules/promotion/commerce_promotion.module @@ -87,25 +87,27 @@ function commerce_promotion_entity_base_field_info(EntityTypeInterface $entity_t * Implements hook_cron() */ function commerce_promotion_cron() { - commerce_promotion_disabled_expired(); -} - -/** - * Get all expired promotions that are still active and disable them. - */ -function commerce_promotion_disabled_expired() { /** @var \Drupal\commerce_promotion\PromotionStorageInterface $promotion_storage */ $promotion_storage = \Drupal::service('entity_type.manager')->getStorage('commerce_promotion'); - // Get query for all expired promotions. + // Disable any promotions that have passed their end date. $promotions = $promotion_storage->loadExpired(); - if ($promotions !== FALSE) { - // Disable all expired promotions. + if (!empty($promotions)) { foreach ($promotions as $promotion) { $promotion->setEnabled(FALSE); $promotion->save(); } } -} + // Disable any promotions that have met their max usage. + $promotions = $promotion_storage->loadMaxedUsage(); + + if (!empty($promotions)) { + foreach ($promotions as $promotion) { + $promotion->setEnabled(FALSE); + $promotion->save(); + } + } + +} diff --git a/modules/promotion/src/PromotionStorageInterface.php b/modules/promotion/src/PromotionStorageInterface.php index 25b551526d..b17af3ab5e 100644 --- a/modules/promotion/src/PromotionStorageInterface.php +++ b/modules/promotion/src/PromotionStorageInterface.php @@ -25,14 +25,21 @@ interface PromotionStorageInterface extends ContentEntityStorageInterface { public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $store); /** - * Builds a query that will load all promotions that are no longer valid - * determined by the base field limiting values. + * Return all active promotions that are no longer valid determined by their + * end date. * - * @param bool $only_enabled - * Only include currently enabled promotions that have expired. - * @return array|bool|\Drupal\Core\Entity\EntityInterface[] - * The expired promotion entities. Returns FALSE if none found. + * @return array|\Drupal\Core\Entity\EntityInterface[] + * The expired promotion entities. */ - public function loadExpired($only_enabled); + public function loadExpired(); + + /** + * Returns any promotions which are still active and have a met their maximum + * usage. + * + * @return array|\Drupal\Core\Entity\EntityInterface[] + * Promotions with maxed usage. + */ + public function loadMaxedUsage(); } From 73e867ab738ac85d6a4af89a1db86b207f76e9c2 Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Fri, 7 Apr 2017 01:24:43 -0700 Subject: [PATCH 07/16] Issue #2863864: Added tests for loading of expired and maxed usaged promotions. --- .../tests/src/Kernel/PromotionStorageTest.php | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php index 2310061a28..161df970b3 100644 --- a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php +++ b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php @@ -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; @@ -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. * @@ -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' => 'test@example.com', + 'ip_address' => '127.0.0.1', + 'order_id' => '6', + 'order_number' => '6', + 'store_id' => $this->store, + 'uid' => $this->createUser()->id(), + 'order_items' => [], + ]); } /** @@ -213,4 +248,58 @@ public function testWeight() { $this->assertEquals($promotion1->label(), $promotion->label()); } + public function testLoadExpired() { + $valid_promotion = Promotion::create([ + 'name' => 'Valid Promotion', + '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', + '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->assertEquals(sizeof($promotions), 1); + + $promotion = reset($promotions); + $this->assertEquals($expired_promotion->label(), $promotion->label()); + } + + public function testLoadUsed() { + $promotion1 = Promotion::create([ + 'name' => 'Promotion 1', + 'status' => TRUE, + 'usage_limit' => 1, + ]); + $this->assertEquals(SAVED_NEW, $promotion1->save()); + $this->usage->addUsage($this->order, $promotion1); + + $promotion2 = Promotion::create([ + 'name' => 'Promotion 2', + 'status' => TRUE, + 'usage_limit' => 2, + ]); + $this->assertEquals(SAVED_NEW, $promotion2->save()); + $this->usage->addUsage($this->order, $promotion2); + + $promotion3 = Promotion::create([ + 'name' => 'Promotion 3', + 'status' => TRUE, + ]); + $this->assertEquals(SAVED_NEW, $promotion3->save()); + + $promotions = $this->promotionStorage->loadMaxedUsage(); + $this->assertEquals(sizeof($promotions), 1); + + $promotion = reset($promotions); + $this->assertEquals($promotion1->label(), $promotion->label()); + } + } From 70ce34085862813b31300158afdd815dad2ef644 Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Mon, 10 Apr 2017 16:25:46 -0700 Subject: [PATCH 08/16] Issue #2863864: Updates to meet coding standards. --- modules/promotion/commerce_promotion.module | 4 +++- modules/promotion/src/PromotionStorageInterface.php | 10 ++++------ .../tests/src/Kernel/PromotionStorageTest.php | 10 ++++++++-- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/modules/promotion/commerce_promotion.module b/modules/promotion/commerce_promotion.module index 80d69a6d96..0eec63d035 100644 --- a/modules/promotion/commerce_promotion.module +++ b/modules/promotion/commerce_promotion.module @@ -84,7 +84,7 @@ function commerce_promotion_entity_base_field_info(EntityTypeInterface $entity_t } /** - * Implements hook_cron() + * Implements hook_cron(). */ function commerce_promotion_cron() { /** @var \Drupal\commerce_promotion\PromotionStorageInterface $promotion_storage */ @@ -94,6 +94,7 @@ function commerce_promotion_cron() { $promotions = $promotion_storage->loadExpired(); if (!empty($promotions)) { + /** @var \Drupal\commerce_promotion\Entity\PromotionInterface $promotion */ foreach ($promotions as $promotion) { $promotion->setEnabled(FALSE); $promotion->save(); @@ -104,6 +105,7 @@ function commerce_promotion_cron() { $promotions = $promotion_storage->loadMaxedUsage(); if (!empty($promotions)) { + /** @var \Drupal\commerce_promotion\Entity\PromotionInterface $promotion */ foreach ($promotions as $promotion) { $promotion->setEnabled(FALSE); $promotion->save(); diff --git a/modules/promotion/src/PromotionStorageInterface.php b/modules/promotion/src/PromotionStorageInterface.php index b17af3ab5e..bfdabf1bf9 100644 --- a/modules/promotion/src/PromotionStorageInterface.php +++ b/modules/promotion/src/PromotionStorageInterface.php @@ -25,19 +25,17 @@ interface PromotionStorageInterface extends ContentEntityStorageInterface { public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $store); /** - * Return all active promotions that are no longer valid determined by their - * end date. + * Return active promotions that have passed their end date. * - * @return array|\Drupal\Core\Entity\EntityInterface[] + * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] * The expired promotion entities. */ public function loadExpired(); /** - * Returns any promotions which are still active and have a met their maximum - * usage. + * Returns active promotions which have a met their maximum usage. * - * @return array|\Drupal\Core\Entity\EntityInterface[] + * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] * Promotions with maxed usage. */ public function loadMaxedUsage(); diff --git a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php index 161df970b3..e461bc37f6 100644 --- a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php +++ b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php @@ -248,6 +248,9 @@ public function testWeight() { $this->assertEquals($promotion1->label(), $promotion->label()); } + /** + * Tests that active promotions which have expired are loaded. + */ public function testLoadExpired() { $valid_promotion = Promotion::create([ 'name' => 'Valid Promotion', @@ -266,12 +269,15 @@ public function testLoadExpired() { $this->assertEquals(SAVED_NEW, $expired_promotion->save()); $promotions = $this->promotionStorage->loadExpired(); - $this->assertEquals(sizeof($promotions), 1); + $this->assertEquals(count($promotions), 1); $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() { $promotion1 = Promotion::create([ 'name' => 'Promotion 1', @@ -296,7 +302,7 @@ public function testLoadUsed() { $this->assertEquals(SAVED_NEW, $promotion3->save()); $promotions = $this->promotionStorage->loadMaxedUsage(); - $this->assertEquals(sizeof($promotions), 1); + $this->assertEquals(count($promotions), 1); $promotion = reset($promotions); $this->assertEquals($promotion1->label(), $promotion->label()); From 029e4c4cca648663236172e5dd0243ea19dd7cd1 Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Tue, 27 Jun 2017 17:16:57 -0700 Subject: [PATCH 09/16] Added cron function test. --- modules/promotion/src/PromotionStorage.php | 10 +--- .../tests/src/Kernel/PromotionStorageTest.php | 18 +++++- .../promotion/tests/src/Kernel/UsageTest.php | 56 +++++++++++++++++++ 3 files changed, 74 insertions(+), 10 deletions(-) diff --git a/modules/promotion/src/PromotionStorage.php b/modules/promotion/src/PromotionStorage.php index 981d526218..11bc5b082f 100644 --- a/modules/promotion/src/PromotionStorage.php +++ b/modules/promotion/src/PromotionStorage.php @@ -119,10 +119,7 @@ public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $st } /** - * Return active promotions that have passed their end date. - * - * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] - * The expired promotion entities. + * {@inheritdoc} */ public function loadExpired() { $query = $this->getQuery(); @@ -141,10 +138,7 @@ public function loadExpired() { } /** - * Returns active promotions which have a met their maximum usage. - * - * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] - * Promotions with maxed usage. + * {@inheritdoc} */ public function loadMaxedUsage() { $query = $this->getQuery(); diff --git a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php index e461bc37f6..4e2b7ae9ae 100644 --- a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php +++ b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php @@ -252,8 +252,12 @@ public function testWeight() { * 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), @@ -262,6 +266,8 @@ public function testLoadExpired() { $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), @@ -269,7 +275,7 @@ public function testLoadExpired() { $this->assertEquals(SAVED_NEW, $expired_promotion->save()); $promotions = $this->promotionStorage->loadExpired(); - $this->assertEquals(count($promotions), 1); + $this->assertCount(1, $promotions); $promotion = reset($promotions); $this->assertEquals($expired_promotion->label(), $promotion->label()); @@ -279,8 +285,12 @@ public function testLoadExpired() { * 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, ]); @@ -289,6 +299,8 @@ public function testLoadUsed() { $promotion2 = Promotion::create([ 'name' => 'Promotion 2', + 'order_types' => [$order_type], + 'stores' => [$this->store->id()], 'status' => TRUE, 'usage_limit' => 2, ]); @@ -297,12 +309,14 @@ public function testLoadUsed() { $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->assertEquals(count($promotions), 1); + $this->assertCount(1, $promotions); $promotion = reset($promotions); $this->assertEquals($promotion1->label(), $promotion->label()); diff --git a/modules/promotion/tests/src/Kernel/UsageTest.php b/modules/promotion/tests/src/Kernel/UsageTest.php index faa08ecb3a..82eb8c15f8 100644 --- a/modules/promotion/tests/src/Kernel/UsageTest.php +++ b/modules/promotion/tests/src/Kernel/UsageTest.php @@ -103,6 +103,7 @@ protected function setUp() { 'state' => 'draft', 'mail' => 'test@example.com', 'ip_address' => '127.0.0.1', + 'order_id' => '6', 'order_number' => '6', 'store_id' => $this->store, 'uid' => $this->createUser(), @@ -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); + + } + } From a557186d74c78787bec588d2c788d032b5ae38f4 Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Tue, 4 Apr 2017 00:00:09 -0700 Subject: [PATCH 10/16] Disable expired promotions on cron run. --- modules/promotion/commerce_promotion.module | 27 +++++++++++++++++++ .../src/PromotionStorageInterface.php | 11 ++++++++ 2 files changed, 38 insertions(+) diff --git a/modules/promotion/commerce_promotion.module b/modules/promotion/commerce_promotion.module index 9bb5fc59e3..4cdaf00fea 100644 --- a/modules/promotion/commerce_promotion.module +++ b/modules/promotion/commerce_promotion.module @@ -82,3 +82,30 @@ function commerce_promotion_entity_base_field_info(EntityTypeInterface $entity_t return $fields; } } + +/** + * Implements hook_cron() + */ +function commerce_promotion_cron() { + commerce_promotion_disabled_expired(); +} + +/** + * Get all expired promotions that are still active and disable them. + */ +function commerce_promotion_disabled_expired() { + /** @var \Drupal\commerce_promotion\PromotionStorageInterface $promotion_storage */ + $promotion_storage = \Drupal::service('entity_type.manager')->getStorage('commerce_promotion'); + + // Get query for all expired promotions. + $promotions = $promotion_storage->loadExpired(); + + if ($promotions !== FALSE) { + // Disable all expired promotions. + foreach ($promotions as $promotion) { + $promotion->setEnabled(FALSE); + $promotion->save(); + } + } +} + diff --git a/modules/promotion/src/PromotionStorageInterface.php b/modules/promotion/src/PromotionStorageInterface.php index 5690751034..25b551526d 100644 --- a/modules/promotion/src/PromotionStorageInterface.php +++ b/modules/promotion/src/PromotionStorageInterface.php @@ -24,4 +24,15 @@ interface PromotionStorageInterface extends ContentEntityStorageInterface { */ public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $store); + /** + * Builds a query that will load all promotions that are no longer valid + * determined by the base field limiting values. + * + * @param bool $only_enabled + * Only include currently enabled promotions that have expired. + * @return array|bool|\Drupal\Core\Entity\EntityInterface[] + * The expired promotion entities. Returns FALSE if none found. + */ + public function loadExpired($only_enabled); + } From f659ea1d71f59562e2da8b0dcf0092405ae11b57 Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Fri, 7 Apr 2017 01:24:12 -0700 Subject: [PATCH 11/16] Issue #2863864: Moved max usage load of promotions to its own method making use of existing service. --- modules/promotion/commerce_promotion.module | 24 ++++++++++--------- .../src/PromotionStorageInterface.php | 21 ++++++++++------ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/modules/promotion/commerce_promotion.module b/modules/promotion/commerce_promotion.module index 4cdaf00fea..80d69a6d96 100644 --- a/modules/promotion/commerce_promotion.module +++ b/modules/promotion/commerce_promotion.module @@ -87,25 +87,27 @@ function commerce_promotion_entity_base_field_info(EntityTypeInterface $entity_t * Implements hook_cron() */ function commerce_promotion_cron() { - commerce_promotion_disabled_expired(); -} - -/** - * Get all expired promotions that are still active and disable them. - */ -function commerce_promotion_disabled_expired() { /** @var \Drupal\commerce_promotion\PromotionStorageInterface $promotion_storage */ $promotion_storage = \Drupal::service('entity_type.manager')->getStorage('commerce_promotion'); - // Get query for all expired promotions. + // Disable any promotions that have passed their end date. $promotions = $promotion_storage->loadExpired(); - if ($promotions !== FALSE) { - // Disable all expired promotions. + if (!empty($promotions)) { foreach ($promotions as $promotion) { $promotion->setEnabled(FALSE); $promotion->save(); } } -} + // Disable any promotions that have met their max usage. + $promotions = $promotion_storage->loadMaxedUsage(); + + if (!empty($promotions)) { + foreach ($promotions as $promotion) { + $promotion->setEnabled(FALSE); + $promotion->save(); + } + } + +} diff --git a/modules/promotion/src/PromotionStorageInterface.php b/modules/promotion/src/PromotionStorageInterface.php index 25b551526d..b17af3ab5e 100644 --- a/modules/promotion/src/PromotionStorageInterface.php +++ b/modules/promotion/src/PromotionStorageInterface.php @@ -25,14 +25,21 @@ interface PromotionStorageInterface extends ContentEntityStorageInterface { public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $store); /** - * Builds a query that will load all promotions that are no longer valid - * determined by the base field limiting values. + * Return all active promotions that are no longer valid determined by their + * end date. * - * @param bool $only_enabled - * Only include currently enabled promotions that have expired. - * @return array|bool|\Drupal\Core\Entity\EntityInterface[] - * The expired promotion entities. Returns FALSE if none found. + * @return array|\Drupal\Core\Entity\EntityInterface[] + * The expired promotion entities. */ - public function loadExpired($only_enabled); + public function loadExpired(); + + /** + * Returns any promotions which are still active and have a met their maximum + * usage. + * + * @return array|\Drupal\Core\Entity\EntityInterface[] + * Promotions with maxed usage. + */ + public function loadMaxedUsage(); } From 6bba45473b94d34804a4ad182ff7a9969d5d2d48 Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Fri, 7 Apr 2017 01:24:43 -0700 Subject: [PATCH 12/16] Issue #2863864: Added tests for loading of expired and maxed usaged promotions. --- .../tests/src/Kernel/PromotionStorageTest.php | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php index 2310061a28..161df970b3 100644 --- a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php +++ b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php @@ -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; @@ -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. * @@ -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' => 'test@example.com', + 'ip_address' => '127.0.0.1', + 'order_id' => '6', + 'order_number' => '6', + 'store_id' => $this->store, + 'uid' => $this->createUser()->id(), + 'order_items' => [], + ]); } /** @@ -213,4 +248,58 @@ public function testWeight() { $this->assertEquals($promotion1->label(), $promotion->label()); } + public function testLoadExpired() { + $valid_promotion = Promotion::create([ + 'name' => 'Valid Promotion', + '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', + '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->assertEquals(sizeof($promotions), 1); + + $promotion = reset($promotions); + $this->assertEquals($expired_promotion->label(), $promotion->label()); + } + + public function testLoadUsed() { + $promotion1 = Promotion::create([ + 'name' => 'Promotion 1', + 'status' => TRUE, + 'usage_limit' => 1, + ]); + $this->assertEquals(SAVED_NEW, $promotion1->save()); + $this->usage->addUsage($this->order, $promotion1); + + $promotion2 = Promotion::create([ + 'name' => 'Promotion 2', + 'status' => TRUE, + 'usage_limit' => 2, + ]); + $this->assertEquals(SAVED_NEW, $promotion2->save()); + $this->usage->addUsage($this->order, $promotion2); + + $promotion3 = Promotion::create([ + 'name' => 'Promotion 3', + 'status' => TRUE, + ]); + $this->assertEquals(SAVED_NEW, $promotion3->save()); + + $promotions = $this->promotionStorage->loadMaxedUsage(); + $this->assertEquals(sizeof($promotions), 1); + + $promotion = reset($promotions); + $this->assertEquals($promotion1->label(), $promotion->label()); + } + } From 4ac0f14ccf3900df2ddb4e70d77373bc6782235f Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Mon, 10 Apr 2017 16:25:46 -0700 Subject: [PATCH 13/16] Issue #2863864: Updates to meet coding standards. --- modules/promotion/commerce_promotion.module | 4 +- modules/promotion/src/PromotionStorage.php | 57 +++++++++++++++++++ .../src/PromotionStorageInterface.php | 10 ++-- .../tests/src/Kernel/PromotionStorageTest.php | 10 +++- 4 files changed, 72 insertions(+), 9 deletions(-) diff --git a/modules/promotion/commerce_promotion.module b/modules/promotion/commerce_promotion.module index 80d69a6d96..0eec63d035 100644 --- a/modules/promotion/commerce_promotion.module +++ b/modules/promotion/commerce_promotion.module @@ -84,7 +84,7 @@ function commerce_promotion_entity_base_field_info(EntityTypeInterface $entity_t } /** - * Implements hook_cron() + * Implements hook_cron(). */ function commerce_promotion_cron() { /** @var \Drupal\commerce_promotion\PromotionStorageInterface $promotion_storage */ @@ -94,6 +94,7 @@ function commerce_promotion_cron() { $promotions = $promotion_storage->loadExpired(); if (!empty($promotions)) { + /** @var \Drupal\commerce_promotion\Entity\PromotionInterface $promotion */ foreach ($promotions as $promotion) { $promotion->setEnabled(FALSE); $promotion->save(); @@ -104,6 +105,7 @@ function commerce_promotion_cron() { $promotions = $promotion_storage->loadMaxedUsage(); if (!empty($promotions)) { + /** @var \Drupal\commerce_promotion\Entity\PromotionInterface $promotion */ foreach ($promotions as $promotion) { $promotion->setEnabled(FALSE); $promotion->save(); diff --git a/modules/promotion/src/PromotionStorage.php b/modules/promotion/src/PromotionStorage.php index 63ec779417..981d526218 100644 --- a/modules/promotion/src/PromotionStorage.php +++ b/modules/promotion/src/PromotionStorage.php @@ -118,4 +118,61 @@ public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $st return $promotions; } + /** + * Return active promotions that have passed their end date. + * + * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] + * The expired promotion entities. + */ + 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); + } + + /** + * Returns active promotions which have a met their maximum usage. + * + * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] + * Promotions with maxed usage. + */ + 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; + } + } diff --git a/modules/promotion/src/PromotionStorageInterface.php b/modules/promotion/src/PromotionStorageInterface.php index b17af3ab5e..bfdabf1bf9 100644 --- a/modules/promotion/src/PromotionStorageInterface.php +++ b/modules/promotion/src/PromotionStorageInterface.php @@ -25,19 +25,17 @@ interface PromotionStorageInterface extends ContentEntityStorageInterface { public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $store); /** - * Return all active promotions that are no longer valid determined by their - * end date. + * Return active promotions that have passed their end date. * - * @return array|\Drupal\Core\Entity\EntityInterface[] + * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] * The expired promotion entities. */ public function loadExpired(); /** - * Returns any promotions which are still active and have a met their maximum - * usage. + * Returns active promotions which have a met their maximum usage. * - * @return array|\Drupal\Core\Entity\EntityInterface[] + * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] * Promotions with maxed usage. */ public function loadMaxedUsage(); diff --git a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php index 161df970b3..e461bc37f6 100644 --- a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php +++ b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php @@ -248,6 +248,9 @@ public function testWeight() { $this->assertEquals($promotion1->label(), $promotion->label()); } + /** + * Tests that active promotions which have expired are loaded. + */ public function testLoadExpired() { $valid_promotion = Promotion::create([ 'name' => 'Valid Promotion', @@ -266,12 +269,15 @@ public function testLoadExpired() { $this->assertEquals(SAVED_NEW, $expired_promotion->save()); $promotions = $this->promotionStorage->loadExpired(); - $this->assertEquals(sizeof($promotions), 1); + $this->assertEquals(count($promotions), 1); $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() { $promotion1 = Promotion::create([ 'name' => 'Promotion 1', @@ -296,7 +302,7 @@ public function testLoadUsed() { $this->assertEquals(SAVED_NEW, $promotion3->save()); $promotions = $this->promotionStorage->loadMaxedUsage(); - $this->assertEquals(sizeof($promotions), 1); + $this->assertEquals(count($promotions), 1); $promotion = reset($promotions); $this->assertEquals($promotion1->label(), $promotion->label()); From d3fda01dc4c792c8fa7b8147137f25f3cb22f84a Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Fri, 7 Apr 2017 01:24:12 -0700 Subject: [PATCH 14/16] Issue #2863864: Moved max usage load of promotions to its own method making use of existing service. --- modules/promotion/src/PromotionStorageInterface.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/promotion/src/PromotionStorageInterface.php b/modules/promotion/src/PromotionStorageInterface.php index bfdabf1bf9..b17af3ab5e 100644 --- a/modules/promotion/src/PromotionStorageInterface.php +++ b/modules/promotion/src/PromotionStorageInterface.php @@ -25,17 +25,19 @@ interface PromotionStorageInterface extends ContentEntityStorageInterface { public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $store); /** - * Return active promotions that have passed their end date. + * Return all active promotions that are no longer valid determined by their + * end date. * - * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] + * @return array|\Drupal\Core\Entity\EntityInterface[] * The expired promotion entities. */ public function loadExpired(); /** - * Returns active promotions which have a met their maximum usage. + * Returns any promotions which are still active and have a met their maximum + * usage. * - * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] + * @return array|\Drupal\Core\Entity\EntityInterface[] * Promotions with maxed usage. */ public function loadMaxedUsage(); From 9aef5f30d3a907f472f9df2401f43edc83b41ef7 Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Mon, 10 Apr 2017 16:25:46 -0700 Subject: [PATCH 15/16] Issue #2863864: Updates to meet coding standards. --- modules/promotion/src/PromotionStorageInterface.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/promotion/src/PromotionStorageInterface.php b/modules/promotion/src/PromotionStorageInterface.php index b17af3ab5e..bfdabf1bf9 100644 --- a/modules/promotion/src/PromotionStorageInterface.php +++ b/modules/promotion/src/PromotionStorageInterface.php @@ -25,19 +25,17 @@ interface PromotionStorageInterface extends ContentEntityStorageInterface { public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $store); /** - * Return all active promotions that are no longer valid determined by their - * end date. + * Return active promotions that have passed their end date. * - * @return array|\Drupal\Core\Entity\EntityInterface[] + * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] * The expired promotion entities. */ public function loadExpired(); /** - * Returns any promotions which are still active and have a met their maximum - * usage. + * Returns active promotions which have a met their maximum usage. * - * @return array|\Drupal\Core\Entity\EntityInterface[] + * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] * Promotions with maxed usage. */ public function loadMaxedUsage(); From 04ef19f2bc7f50a4595c70fa70e944286737489b Mon Sep 17 00:00:00 2001 From: Sean Wickham Date: Tue, 27 Jun 2017 17:16:57 -0700 Subject: [PATCH 16/16] Added cron function test. --- modules/promotion/src/PromotionStorage.php | 10 +--- .../tests/src/Kernel/PromotionStorageTest.php | 18 +++++- .../promotion/tests/src/Kernel/UsageTest.php | 56 +++++++++++++++++++ 3 files changed, 74 insertions(+), 10 deletions(-) diff --git a/modules/promotion/src/PromotionStorage.php b/modules/promotion/src/PromotionStorage.php index 981d526218..11bc5b082f 100644 --- a/modules/promotion/src/PromotionStorage.php +++ b/modules/promotion/src/PromotionStorage.php @@ -119,10 +119,7 @@ public function loadAvailable(OrderTypeInterface $order_type, StoreInterface $st } /** - * Return active promotions that have passed their end date. - * - * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] - * The expired promotion entities. + * {@inheritdoc} */ public function loadExpired() { $query = $this->getQuery(); @@ -141,10 +138,7 @@ public function loadExpired() { } /** - * Returns active promotions which have a met their maximum usage. - * - * @return \Drupal\commerce_promotion\Entity\PromotionInterface[] - * Promotions with maxed usage. + * {@inheritdoc} */ public function loadMaxedUsage() { $query = $this->getQuery(); diff --git a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php index e461bc37f6..4e2b7ae9ae 100644 --- a/modules/promotion/tests/src/Kernel/PromotionStorageTest.php +++ b/modules/promotion/tests/src/Kernel/PromotionStorageTest.php @@ -252,8 +252,12 @@ public function testWeight() { * 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), @@ -262,6 +266,8 @@ public function testLoadExpired() { $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), @@ -269,7 +275,7 @@ public function testLoadExpired() { $this->assertEquals(SAVED_NEW, $expired_promotion->save()); $promotions = $this->promotionStorage->loadExpired(); - $this->assertEquals(count($promotions), 1); + $this->assertCount(1, $promotions); $promotion = reset($promotions); $this->assertEquals($expired_promotion->label(), $promotion->label()); @@ -279,8 +285,12 @@ public function testLoadExpired() { * 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, ]); @@ -289,6 +299,8 @@ public function testLoadUsed() { $promotion2 = Promotion::create([ 'name' => 'Promotion 2', + 'order_types' => [$order_type], + 'stores' => [$this->store->id()], 'status' => TRUE, 'usage_limit' => 2, ]); @@ -297,12 +309,14 @@ public function testLoadUsed() { $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->assertEquals(count($promotions), 1); + $this->assertCount(1, $promotions); $promotion = reset($promotions); $this->assertEquals($promotion1->label(), $promotion->label()); diff --git a/modules/promotion/tests/src/Kernel/UsageTest.php b/modules/promotion/tests/src/Kernel/UsageTest.php index 4a9f7068d4..f97cfd7d0d 100644 --- a/modules/promotion/tests/src/Kernel/UsageTest.php +++ b/modules/promotion/tests/src/Kernel/UsageTest.php @@ -103,6 +103,7 @@ protected function setUp() { 'state' => 'draft', 'mail' => 'test@example.com', 'ip_address' => '127.0.0.1', + 'order_id' => '6', 'order_number' => '6', 'store_id' => $this->store, 'uid' => $this->createUser(), @@ -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); + + } + }