Repository: lunarphp/lunar (php)

Issue:
AmountOff percentage is cast to an int, even though it could contain a decimal value
The admin panel allows you to enter a decimal value when creating an AmountOff Discount with a percentage discount. However, it gets cast to an int in the AmountOff class, which results in the percentage being rounded and the discount amount being slightly off.

You could argue that usually percentage discounts are given as whole numbers, but since the admin panel already supports decimal values, I think this should be changed.

I'll include a PR to address this.

Pull request description:
Fix an issue where the AmountOff percentage is cast to an int, even t…
The admin panel allows you to enter a decimal value when creating an AmountOff Discount with a percentage discount. However, it gets cast to an int in the AmountOff class, which results in the percentage being rounded and the discount amount being slightly off.

You could argue that usually percentage discounts are given as whole numbers, but since the admin panel already supports decimal values, I think this should be changed.

Fixes #2003

Patch:
diff --git a/packages/admin/src/Support/Resources/Pages/ManageUrlsRelatedRecords.php b/packages/admin/src/Support/Resources/Pages/ManageUrlsRelatedRecords.php
index 3d8cc834..d644f000 100644
--- a/packages/admin/src/Support/Resources/Pages/ManageUrlsRelatedRecords.php
+++ b/packages/admin/src/Support/Resources/Pages/ManageUrlsRelatedRecords.php
@@ -55,7 +55,7 @@ public function form(Form $form): Form
                             ignoreRecord: true,
                             modifyRuleUsing: function (Unique $rule, callable $get) {
                                 return $rule
-                                    ->where('element_type', static::$model)
+                                    ->where('element_type', (new static::$model)->getMorphClass())
                                     ->where('language_id', $get('language_id'));
                             }
                         )
diff --git a/packages/core/src/DiscountTypes/AmountOff.php b/packages/core/src/DiscountTypes/AmountOff.php
index 105bca64..a915a6f4 100644
--- a/packages/core/src/DiscountTypes/AmountOff.php
+++ b/packages/core/src/DiscountTypes/AmountOff.php
@@ -224,7 +224,7 @@ protected function getEligibleLines(Cart $cart): \Illuminate\Support\Collection
     /**
      * Apply the percentage to the cart line.
      */
-    private function applyPercentage(int $value, Cart $cart): Cart
+    private function applyPercentage(float $value, Cart $cart): Cart
     {
         $lines = $this->getEligibleLines($cart);
 


Test patch:
diff --git a/tests/core/Unit/DiscountTypes/AmountOffTest.php b/tests/core/Unit/DiscountTypes/AmountOffTest.php
index 06e9a03b..f7729fc8 100644
--- a/tests/core/Unit/DiscountTypes/AmountOffTest.php
+++ b/tests/core/Unit/DiscountTypes/AmountOffTest.php
@@ -784,7 +784,16 @@
     expect($lastLine->discountTotal->value)->toEqual(333);
 });
 
-test('can apply percentage discount', function () {
+test('can apply percentage discount', function (
+    string $coupon,
+    float $percentage,
+    int $discountTotalForOne,
+    int $taxTotalForOne,
+    int $totalForOne,
+    int $discountTotalForTwo,
+    int $taxTotalForTwo,
+    int $totalForTwo
+) {
     $customerGroup = CustomerGroup::getDefault();
 
     $channel = Channel::getDefault();
@@ -794,7 +803,7 @@
     $cart = Cart::factory()->create([
         'channel_id' => $channel->id,
         'currency_id' => $currency->id,
-        'coupon_code' => '10PERCENTOFF',
+        'coupon_code' => $coupon,
     ]);
 
     $purchasable = ProductVariant::factory()->create();
@@ -816,9 +825,9 @@
     $discount = Discount::factory()->create([
         'type' => AmountOff::class,
         'name' => 'Test Coupon',
-        'coupon' => '10PERCENTOFF',
+        'coupon' => $coupon,
         'data' => [
-            'percentage' => 10,
+            'percentage' => $percentage,
             'fixed_value' => false,
         ],
     ]);
@@ -843,9 +852,9 @@
 
     $cart = $cart->calculate();
 
-    expect($cart->discountTotal->value)->toEqual(100);
-    expect($cart->taxTotal->value)->toEqual(180);
-    expect($cart->total->value)->toEqual(1080);
+    expect($cart->discountTotal->value)->toEqual($discountTotalForOne);
+    expect($cart->taxTotal->value)->toEqual($taxTotalForOne);
+    expect($cart->total->value)->toEqual($totalForOne);
 
     $cart->lines()->delete();
 
@@ -857,10 +866,14 @@
 
     $cart = $cart->refresh()->calculate();
 
-    expect($cart->discountTotal->value)->toEqual(200);
-    expect($cart->taxTotal->value)->toEqual(360);
-    expect($cart->total->value)->toEqual(2160);
-});
+    expect($cart->discountTotal->value)->toEqual($discountTotalForTwo);
+    expect($cart->taxTotal->value)->toEqual($taxTotalForTwo);
+    expect($cart->total->value)->toEqual($totalForTwo);
+})->with([
+    '10% Discount' => ['10PERCENTOFF', 10, 100, 180, 1080, 200, 360, 2160],
+    '10.25% Discount' => ['10PT25PERCENTOFF', 10.25, 103, 179, 1076, 205, 359, 2154],
+    '10.5% Discount' => ['10PT5PERCENTOFF', 10.5, 105, 179, 1074, 210, 358, 2148],
+]);
 
 test('can only same discount to line once', function () {
     $customerGroup = CustomerGroup::getDefault();