diff --git a/CHANGELOG.md b/CHANGELOG.md index e10ad9f365..ac2c59aefb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Fixed a bug where sales weren’t respecting site element statuses. ([#3328](https://github.com/craftcms/commerce/issues/3328)) - Fixed a bug where soft-deleted order statuses and line item statuses would not being restored when applying project config changes. ([#3164](https://github.com/craftcms/commerce/issues/3164)) - Fixed a bug where carts weren’t being restored after logging in. +- Fixed a bug where guest customers could use a discount with a per-user usage limit. ([#3326](https://github.com/craftcms/commerce/issues/3326)) - Fixed a bug where orders with a processing transaction weren’t being completed. ## 4.3.2 - 2023-10-31 diff --git a/src/services/Discounts.php b/src/services/Discounts.php index d2ce95d36d..c363c26d50 100644 --- a/src/services/Discounts.php +++ b/src/services/Discounts.php @@ -423,10 +423,8 @@ public function orderCouponAvailable(Order $order, string &$explanation = null): $explanation = Craft::t('commerce', 'Discount use has reached its limit.'); return false; } - - $user = $order->getCustomer(); - - if (!$this->_isDiscountPerUserUsageValid($discount, $user)) { + + if (!$this->_isDiscountPerUserUsageValid($discount, $order->getCustomer())) { $explanation = Craft::t('commerce', 'This coupon is for registered users and limited to {limit} uses.', [ 'limit' => $discount->perUserLimit, ]); @@ -600,13 +598,11 @@ public function matchOrder(Order $order, Discount $discount): bool return false; } - $user = $order->getCustomer(); - if (!$this->_isDiscountTotalUseLimitValid($discount)) { return false; } - - if (!$this->_isDiscountPerUserUsageValid($discount, $user)) { + + if (!$this->_isDiscountPerUserUsageValid($discount, $order->getCustomer())) { return false; } @@ -1124,6 +1120,15 @@ private function _isDiscountPerUserUsageValid(Discount $discount, ?User $user): return false; } + if (Craft::$app->getRequest()->getIsSiteRequest()) { + $currentUser = Craft::$app->getUser()->getIdentity(); + $isCustomerCurrentUser = ($currentUser && $currentUser->id == $user->id); + + if (!$isCustomerCurrentUser) { + return false; + } + } + $usage = (new Query()) ->select(['uses']) ->from([Table::CUSTOMER_DISCOUNTUSES]) diff --git a/tests/unit/services/DiscountsTest.php b/tests/unit/services/DiscountsTest.php index d55ea74861..bc7729a9a1 100644 --- a/tests/unit/services/DiscountsTest.php +++ b/tests/unit/services/DiscountsTest.php @@ -825,9 +825,15 @@ protected function orderCouponAvailableTest(array $orderConfig, bool $desiredRes protected function _before() { parent::_before(); - $this->discounts = Plugin::getInstance()->getDiscounts(); $customerFixture = $this->tester->grabFixture('customers'); $this->_user = $customerFixture->getElement('customer1'); + Craft::$app->getUser()->setIdentity($this->_user); + } + + protected function _after() + { + Craft::$app->getUser()->setIdentity(null); + parent::_after(); } }