diff --git a/src/Models/Product.php b/src/Models/Product.php index ff811838b..30d4469ce 100644 --- a/src/Models/Product.php +++ b/src/Models/Product.php @@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasOne; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Rapidez\Core\Facades\Rapidez; use Rapidez\Core\Models\Relations\BelongsToManyCallback; @@ -241,7 +242,9 @@ public function getUnitPrice(int $quantity = 1, int $customerGroup = 0) // NOTE: We always need the option with the lowest matching value, *not* the one with the highest matching qty! // It wouldn't make sense to select a tier with a higher qty if the price is higher. - return $tierPrice ?? $this->price; + $prices = Arr::whereNotNull([$tierPrice, $this->price, $this->specialPrice]); + + return $prices ? min($prices) : null; } public function getPrice(int $quantity = 1, int $customerGroup = 0) diff --git a/src/Models/ProductTierPrice.php b/src/Models/ProductTierPrice.php index 5d336a08a..f386a52b4 100644 --- a/src/Models/ProductTierPrice.php +++ b/src/Models/ProductTierPrice.php @@ -13,6 +13,8 @@ class ProductTierPrice extends Model protected $primaryKey = 'value_id'; + protected $guarded = []; + public function product(): BelongsTo { return $this->belongsTo( diff --git a/tests/Unit/ProductPriceTest.php b/tests/Unit/ProductPriceTest.php index 49dcf78d3..2c9c6b566 100644 --- a/tests/Unit/ProductPriceTest.php +++ b/tests/Unit/ProductPriceTest.php @@ -55,7 +55,51 @@ public function product_catalog_price_rules_apply() #[Test] public function product_can_have_tier_prices() { - $this->assertTrue(true); - // TODO: Base DB doesn't have tier prices. Test this some other way. + $product = Product::find(4); + + $product->tierPrices()->create(['qty' => 2, 'value' => 50, 'website_id' => 1, 'all_groups' => 1, 'customer_group_id' => 0]); + $product->tierPrices()->create(['qty' => 5, 'value' => 40, 'website_id' => 1, 'all_groups' => 1, 'customer_group_id' => 0]); + $product->tierPrices()->create(['qty' => 10, 'value' => 35, 'website_id' => 1, 'all_groups' => 1, 'customer_group_id' => 0]); + $product->tierPrices()->create(['qty' => 15, 'value' => 40, 'website_id' => 1, 'all_groups' => 1, 'customer_group_id' => 0]); + + $product->tierPrices()->create(['qty' => 1, 'value' => 43, 'website_id' => 1, 'all_groups' => 0, 'customer_group_id' => 2]); + $product->tierPrices()->create(['qty' => 5, 'value' => 39, 'website_id' => 1, 'all_groups' => 0, 'customer_group_id' => 2]); + $product->tierPrices()->create(['qty' => 15, 'value' => 34, 'website_id' => 1, 'all_groups' => 0, 'customer_group_id' => 2]); + + $product->tierPrices()->create(['qty' => 20, 'value' => 30, 'website_id' => 0, 'all_groups' => 1, 'customer_group_id' => 0]); + + // All groups + $this->assertEquals(45 * 4, $product->getPrice(4), 'Tier price for all groups, qty 4'); + $this->assertEquals(40 * 5, $product->getPrice(5), 'Tier price for all groups, qty 5'); + $this->assertEquals(35 * 12, $product->getPrice(12), 'Tier price for all groups, qty 12'); + $this->assertEquals(35 * 15, $product->getPrice(15), 'Tier price for all groups, qty 15'); + $this->assertEquals(30 * 23, $product->getPrice(23), 'Tier price for all groups, qty 23'); + + // Specifically customer group 2 + $this->assertEquals(43 * 4, $product->getPrice(4, 2), 'Tier price for group 2, qty 4'); + $this->assertEquals(39 * 5, $product->getPrice(5, 2), 'Tier price for group 2, qty 5'); + $this->assertEquals(35 * 12, $product->getPrice(12, 2), 'Tier price for group 2, qty 12'); + $this->assertEquals(34 * 15, $product->getPrice(15, 2), 'Tier price for group 2, qty 15'); + $this->assertEquals(30 * 22, $product->getPrice(22, 2), 'Tier price for group 2, qty 22'); + + // This is technically not valid, but without creating a whole new website this is the best we can do in a unit test. + config()->set('rapidez.website', 0); + $this->assertEquals(45 * 15, $product->getPrice(15, 2), 'Tier price on website 0 for group 2, qty 15'); + $this->assertEquals(45 * 15, $product->getPrice(15), 'Tier price on website 0 for all groups, qty 15'); + $this->assertEquals(30 * 21, $product->getPrice(21), 'Tier price on website 0 for all groups, qty 21'); + } + + #[Test] + public function product_can_combine_tier_prices_and_special_price() + { + $product = Product::find(10); + + $product->tierPrices()->create(['qty' => 5, 'value' => 30, 'website_id' => 1, 'all_groups' => 1, 'customer_group_id' => 0]); + $product->tierPrices()->create(['qty' => 10, 'value' => 20, 'website_id' => 1, 'all_groups' => 1, 'customer_group_id' => 0]); + + // All groups + $this->assertEquals(24 * 4, $product->getPrice(4), 'Tier price (should be special price) for all groups, qty 4'); + $this->assertEquals(24 * 5, $product->getPrice(5), 'Tier price (should be special price) for all groups, qty 5'); + $this->assertEquals(20 * 12, $product->getPrice(12), 'Tier price for all groups, qty 12'); } }