From 8374340df863ad644edf272dde02b0875d6c8a74 Mon Sep 17 00:00:00 2001 From: Usman Khan Date: Mon, 24 Aug 2026 22:27:00 +0500 Subject: [PATCH] Store automatically added BuyXGetY reward lines using the morph map --- packages/core/src/DiscountTypes/BuyXGetY.php | 2 +- .../core/Unit/DiscountTypes/BuyXGetYTest.php | 95 +++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/packages/core/src/DiscountTypes/BuyXGetY.php b/packages/core/src/DiscountTypes/BuyXGetY.php index 32ceb017cd..d54168a9f0 100644 --- a/packages/core/src/DiscountTypes/BuyXGetY.php +++ b/packages/core/src/DiscountTypes/BuyXGetY.php @@ -268,7 +268,7 @@ private function processAutomaticRewards(CartContract $cart, int $remainingRewar if (! $rewardLine) { $rewardLine = $cart->lines()->make([ - 'purchasable_type' => get_class($purchasable), + 'purchasable_type' => $purchasable->getMorphClass(), 'purchasable_id' => $purchasable->id, 'quantity' => 1, ]); diff --git a/tests/core/Unit/DiscountTypes/BuyXGetYTest.php b/tests/core/Unit/DiscountTypes/BuyXGetYTest.php index 68db8e0f0d..30f105646d 100644 --- a/tests/core/Unit/DiscountTypes/BuyXGetYTest.php +++ b/tests/core/Unit/DiscountTypes/BuyXGetYTest.php @@ -4,6 +4,7 @@ use Lunar\DiscountTypes\AmountOff; use Lunar\DiscountTypes\BuyXGetY; use Lunar\Models\Cart; +use Lunar\Models\CartLine; use Lunar\Models\Channel; use Lunar\Models\Collection; use Lunar\Models\Currency; @@ -1548,3 +1549,97 @@ // productC (not in collection) should not be discounted expect($lineC->discountTotal->value)->toEqual(0); }); + +test('can store an automatically added reward line using the morph map', function () { + $customerGroup = CustomerGroup::factory()->create([ + 'default' => true, + ]); + + $channel = Channel::factory()->create([ + 'default' => true, + ]); + + $currency = Currency::factory()->create([ + 'code' => 'GBP', + ]); + + $cart = Cart::factory()->create([ + 'channel_id' => $channel->id, + 'currency_id' => $currency->id, + ]); + + $productA = Product::factory()->create(); + $productB = Product::factory()->create(); + + $purchasableA = ProductVariant::factory()->create([ + 'product_id' => $productA->id, + ]); + $purchasableB = ProductVariant::factory()->create([ + 'product_id' => $productB->id, + ]); + + Price::factory()->create([ + 'price' => 1000, // £10 + 'min_quantity' => 1, + 'currency_id' => $currency->id, + 'priceable_type' => $purchasableA->getMorphClass(), + 'priceable_id' => $purchasableA->id, + ]); + + Price::factory()->create([ + 'price' => 1000, // £10 + 'min_quantity' => 1, + 'currency_id' => $currency->id, + 'priceable_type' => $purchasableB->getMorphClass(), + 'priceable_id' => $purchasableB->id, + ]); + + $cart->lines()->create([ + 'purchasable_type' => $purchasableA->getMorphClass(), + 'purchasable_id' => $purchasableA->id, + 'quantity' => 1, + ]); + + $discount = Discount::factory()->create([ + 'type' => BuyXGetY::class, + 'name' => 'Test Product Discount', + 'data' => [ + 'min_qty' => 1, + 'reward_qty' => 1, + 'automatically_add_rewards' => true, + ], + ]); + + $discount->customerGroups()->sync([ + $customerGroup->id => [ + 'enabled' => true, + 'starts_at' => now(), + ], + ]); + + $discount->channels()->sync([ + $channel->id => [ + 'enabled' => true, + 'starts_at' => now()->subHour(), + ], + ]); + + $discount->discountableConditions()->create([ + 'discountable_type' => $productA->getMorphClass(), + 'discountable_id' => $productA->id, + ]); + + $discount->discountableRewards()->create([ + 'discountable_type' => $productB->getMorphClass(), + 'discountable_id' => $productB->id, + 'type' => 'reward', + ]); + + $cart->calculate(); + + $rewardLine = CartLine::where('cart_id', $cart->id) + ->where('purchasable_id', $purchasableB->id) + ->first(); + + expect($rewardLine->purchasable_type)->toEqual($purchasableB->getMorphClass()); +});