diff --git a/packages/core/src/Pipelines/Order/Creation/CreateOrderLines.php b/packages/core/src/Pipelines/Order/Creation/CreateOrderLines.php index f1015e09c7..144a9675d9 100644 --- a/packages/core/src/Pipelines/Order/Creation/CreateOrderLines.php +++ b/packages/core/src/Pipelines/Order/Creation/CreateOrderLines.php @@ -5,6 +5,7 @@ use Closure; use Lunar\Models\Order; use Lunar\Models\OrderLine; +use Lunar\Utils\Arr; class CreateOrderLines { @@ -23,8 +24,13 @@ public function handle(Order $order, Closure $next) foreach ($cart->lines as $cartLine) { $orderLine = $order->lines->first(function ($line) use ($cartLine) { - return $line->purchasable_id == $cartLine->purchasable_id && - $line->purchasable_type == $cartLine->purchasable_type; + $diff = Arr::diff($line->meta, $cartLine->meta); + + return empty($diff->new) && + empty($diff->edited) && + empty($diff->removed) && + $line->purchasable_type == $cartLine->purchasable_type && + $line->purchasable_id == $cartLine->purchasable_id; }) ?: new OrderLine; $orderLine->fill([ diff --git a/packages/core/src/Pipelines/Order/Creation/MapDiscountBreakdown.php b/packages/core/src/Pipelines/Order/Creation/MapDiscountBreakdown.php index f4953c8fa2..e430bb752f 100644 --- a/packages/core/src/Pipelines/Order/Creation/MapDiscountBreakdown.php +++ b/packages/core/src/Pipelines/Order/Creation/MapDiscountBreakdown.php @@ -4,6 +4,7 @@ use Closure; use Lunar\Models\Order; +use Lunar\Utils\Arr; class MapDiscountBreakdown { @@ -18,7 +19,12 @@ public function handle(Order $order, Closure $next) foreach ($order->lines as $orderLine) { $cartLine = $cart->lines->first(function ($cartLine) use ($orderLine) { - return $cartLine->purchasable_type == $orderLine->purchasable_type && + $diff = Arr::diff($cartLine->meta, $orderLine->meta); + + return empty($diff->new) && + empty($diff->edited) && + empty($diff->removed) && + $cartLine->purchasable_type == $orderLine->purchasable_type && $cartLine->purchasable_id == $orderLine->purchasable_id; }); diff --git a/tests/core/Unit/Pipelines/Order/Creation/MapDiscountBreakdownTest.php b/tests/core/Unit/Pipelines/Order/Creation/MapDiscountBreakdownTest.php new file mode 100644 index 0000000000..04551d6887 --- /dev/null +++ b/tests/core/Unit/Pipelines/Order/Creation/MapDiscountBreakdownTest.php @@ -0,0 +1,125 @@ +create([ + 'code' => 'GBP', + 'decimal_places' => 2, + ]); + + Channel::factory()->create([ + 'default' => true, + ]); + + CustomerGroup::factory()->create([ + 'default' => true, + ]); +}); + +test('can map discount with same purchasable with different meta', function () { + $customerGroup = CustomerGroup::getDefault(); + + $channel = Channel::getDefault(); + + $currency = Currency::getDefault(); + + $purchasable = ProductVariant::factory()->create(); + + Price::factory()->create([ + 'price' => 100, + 'min_quantity' => 1, + 'currency_id' => $currency->id, + 'priceable_type' => $purchasable->getMorphClass(), + 'priceable_id' => $purchasable->id, + ]); + + $discount = Discount::factory()->create([ + 'type' => AmountOff::class, + 'name' => 'Test Coupon', + 'coupon' => '10OFF', + 'data' => [ + 'fixed_value' => false, + 'percentage' => 10, + ], + ]); + + $discount->customerGroups()->sync([ + $customerGroup->id => [ + 'enabled' => true, + 'starts_at' => now(), + ], + ]); + + $discount->channels()->sync([ + $channel->id => [ + 'enabled' => true, + 'starts_at' => now()->subHour(), + ], + ]); + + $cart = Cart::factory()->create([ + 'channel_id' => $channel->id, + 'currency_id' => $currency->id, + 'coupon_code' => '10OFF', + ]); + + $cart->lines()->create([ + 'purchasable_type' => $purchasable->getMorphClass(), + 'purchasable_id' => $purchasable->id, + 'quantity' => 1, + 'meta' => [ + 'personalization' => 'Love you mum xxx', + ], + ]); + + $cart->lines()->create([ + 'purchasable_type' => $purchasable->getMorphClass(), + 'purchasable_id' => $purchasable->id, + 'quantity' => 1, + 'meta' => [ + 'personalization' => 'Get well soon', + ], + ]); + + $order = Order::factory()->create([ + 'cart_id' => $cart->id, + ]); + + $cart->calculate(); + + app(CreateOrderLines::class)->handle($order, function ($order) { + return $order; + }); + + app(MapDiscountBreakdown::class)->handle($order, function ($order) { + return $order; + }); + + $appliedDiscount = $order->discount_breakdown->first(); + + $appliedDiscountLines = $appliedDiscount->lines->map(function ($line) { + return $line->line->only('purchasable_type', 'purchasable_id', 'meta'); + }); + + $orderLines = $order->lines->map(function ($line) { + return $line->only('purchasable_type', 'purchasable_id', 'meta'); + }); + + expect($appliedDiscountLines)->toHaveCount($orderLines->count()); + expect($appliedDiscountLines->toArray())->toEqual($orderLines->toArray()); +});