diff --git a/packages/core/src/DiscountTypes/AbstractDiscountType.php b/packages/core/src/DiscountTypes/AbstractDiscountType.php index 87735a83c1..3683185fe4 100644 --- a/packages/core/src/DiscountTypes/AbstractDiscountType.php +++ b/packages/core/src/DiscountTypes/AbstractDiscountType.php @@ -84,8 +84,8 @@ protected function checkDiscountConditions(CartContract $cart): bool $validMaxUses = $this->discount->max_uses ? $this->discount->uses < $this->discount->max_uses : true; - if ($validMaxUses && $this->discount->max_uses_per_user) { - $validMaxUses = $cart->user && ($this->usesByUser($cart->user) < $this->discount->max_uses_per_user); + if ($validMaxUses && $this->discount->max_uses_per_user && $cart->user) { + $validMaxUses = $this->usesByUser($cart->user) < $this->discount->max_uses_per_user; } return $validCoupon && $validMinSpend && $validMaxUses; diff --git a/tests/core/Unit/DiscountTypes/AbstractDiscountTypeTest.php b/tests/core/Unit/DiscountTypes/AbstractDiscountTypeTest.php index 4f41c2b3ee..36abf7b365 100644 --- a/tests/core/Unit/DiscountTypes/AbstractDiscountTypeTest.php +++ b/tests/core/Unit/DiscountTypes/AbstractDiscountTypeTest.php @@ -11,6 +11,7 @@ use Lunar\Models\Product; use Lunar\Models\ProductVariant; use Lunar\Tests\Core\Stubs\TestAbstractDiscount; +use Lunar\Tests\Core\Stubs\User; use Lunar\Tests\Core\TestCase; uses(TestCase::class); @@ -93,3 +94,151 @@ expect($cart->subTotalDiscounted->value)->toBe(900); }); + +test('applies a discount with max uses per user on a guest cart', function () { + $channel = Channel::getDefault(); + $currency = Currency::getDefault(); + + $cart = Cart::factory()->create([ + 'channel_id' => $channel->id, + 'currency_id' => $currency->id, + 'coupon_code' => '10OFF', + ]); + + Discount::factory()->create([ + 'type' => TestAbstractDiscount::class, + 'name' => 'Test Coupon', + 'coupon' => '10OFF', + 'max_uses_per_user' => 1, + 'data' => [ + 'fixed_value' => true, + 'fixed_values' => [ + 'GBP' => 10, + ], + ], + ]); + + $purchasable = ProductVariant::factory()->create([ + 'product_id' => Product::factory(), + ]); + + Price::factory()->create([ + 'price' => 1000, + 'min_quantity' => 1, + 'currency_id' => $currency->id, + 'priceable_type' => $purchasable->getMorphClass(), + 'priceable_id' => $purchasable->id, + ]); + + $cart->lines()->create([ + 'purchasable_type' => $purchasable->getMorphClass(), + 'purchasable_id' => $purchasable->id, + 'quantity' => 1, + ]); + + $cart->calculate(); + + expect($cart->subTotalDiscounted->value)->toBe(900); +}); + +test('applies a discount when the user is under the per-user limit', function () { + setAuthUserConfig(); + + $channel = Channel::getDefault(); + $currency = Currency::getDefault(); + $user = User::factory()->create(); + + $cart = Cart::factory()->create([ + 'channel_id' => $channel->id, + 'currency_id' => $currency->id, + 'coupon_code' => '10OFF', + 'user_id' => $user->id, + ]); + + Discount::factory()->create([ + 'type' => TestAbstractDiscount::class, + 'name' => 'Test Coupon', + 'coupon' => '10OFF', + 'max_uses_per_user' => 2, + 'data' => [ + 'fixed_value' => true, + 'fixed_values' => [ + 'GBP' => 10, + ], + ], + ]); + + $purchasable = ProductVariant::factory()->create([ + 'product_id' => Product::factory(), + ]); + + Price::factory()->create([ + 'price' => 1000, + 'min_quantity' => 1, + 'currency_id' => $currency->id, + 'priceable_type' => $purchasable->getMorphClass(), + 'priceable_id' => $purchasable->id, + ]); + + $cart->lines()->create([ + 'purchasable_type' => $purchasable->getMorphClass(), + 'purchasable_id' => $purchasable->id, + 'quantity' => 1, + ]); + + $cart->calculate(); + + expect($cart->subTotalDiscounted->value)->toBe(900); +}); + +test('does not apply a discount when the user is at the per-user limit', function () { + setAuthUserConfig(); + + $channel = Channel::getDefault(); + $currency = Currency::getDefault(); + $user = User::factory()->create(); + + $cart = Cart::factory()->create([ + 'channel_id' => $channel->id, + 'currency_id' => $currency->id, + 'coupon_code' => '10OFF', + 'user_id' => $user->id, + ]); + + $discountModel = Discount::factory()->create([ + 'type' => TestAbstractDiscount::class, + 'name' => 'Test Coupon', + 'coupon' => '10OFF', + 'max_uses_per_user' => 1, + 'data' => [ + 'fixed_value' => true, + 'fixed_values' => [ + 'GBP' => 10, + ], + ], + ]); + + $discountModel->users()->attach($user->id); + + $purchasable = ProductVariant::factory()->create([ + 'product_id' => Product::factory(), + ]); + + Price::factory()->create([ + 'price' => 1000, + 'min_quantity' => 1, + 'currency_id' => $currency->id, + 'priceable_type' => $purchasable->getMorphClass(), + 'priceable_id' => $purchasable->id, + ]); + + $cart->lines()->create([ + 'purchasable_type' => $purchasable->getMorphClass(), + 'purchasable_id' => $purchasable->id, + 'quantity' => 1, + ]); + + $cart->calculate(); + + expect($cart->subTotalDiscounted->value)->toBe(1000); +});