Skip to content

Commit

Permalink
Added the CartMinimumValue promotion rule
Browse files Browse the repository at this point in the history
  • Loading branch information
fulopattila122 committed Aug 26, 2024
1 parent 04475dd commit c191588
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/Promotion/Providers/ModuleServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Vanilo\Promotion\Models\PromotionRule;
use Vanilo\Promotion\PromotionActionTypes;
use Vanilo\Promotion\PromotionRuleTypes;
use Vanilo\Promotion\Rules\CartMinimumValue;
use Vanilo\Promotion\Rules\CartQuantity;

class ModuleServiceProvider extends BaseModuleServiceProvider
Expand All @@ -28,6 +29,7 @@ public function boot()
{
parent::boot();

PromotionRuleTypes::register(CartMinimumValue::DEFAULT_ID, CartMinimumValue::class);
PromotionRuleTypes::register(CartQuantity::ID, CartQuantity::class);
PromotionActionTypes::register(CartFixedDiscount::DEFAULT_ID, CartFixedDiscount::class);
PromotionActionTypes::register(CartPercentageDiscount::DEFAULT_ID, CartPercentageDiscount::class);
Expand Down
62 changes: 62 additions & 0 deletions src/Promotion/Rules/CartMinimumValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

/**
* Contains the CartMinimumValue rule class.
*
* @copyright Copyright (c) 2024 Vanilo UG
* @author Attila Fulop
* @license MIT
* @since 2024-08-26
*
*/

namespace Vanilo\Promotion\Rules;

use Nette\Schema\Expect;
use Nette\Schema\Processor;
use Nette\Schema\Schema;
use Vanilo\Promotion\Contracts\PromotionRuleType;

class CartMinimumValue implements PromotionRuleType
{
public const DEFAULT_ID = 'cart_minimum_value';

public static function getName(): string
{
return __('Cart Minimum Value');
}

public function getTitle(array $configuration): string
{
if (null === $amount = $configuration['amount'] ?? null) {
return __('At least X cart value [Invalid Configuration: The `:parameter` parameter is missing]', ['parameter' => 'amount']);
}

return __('At least :amount cart value', ['amount' => (int) $amount]);
}

public function getSchema(): Schema
{
return Expect::structure(['amount' => Expect::anyOf(Expect::float(0), Expect::int(0))->required()])->castTo('array');
}

public function getSchemaSample(array $mergeWith = null): array
{
return ['amount' => 19.99];
}

public function isPassing(object $subject, array $configuration): bool
{
$amount = match (true) {
method_exists($subject, 'preAdjustmentTotal') => $subject->preAdjustmentTotal(),
method_exists($subject, 'itemsTotal') => $subject->itemsTotal(),
default => throw new \InvalidArgumentException('The cart minimum value promotion rule requires either `preAdjustmentsTotal()` or `itemsTotal()` method on its subject'),
};

$configuration = (new Processor())->process($this->getSchema(), $configuration);

return $amount >= $configuration['amount'];
}
}
2 changes: 1 addition & 1 deletion src/Promotion/Rules/CartQuantity.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class CartQuantity implements PromotionRuleType

public static function getName(): string
{
return __('Cart Quantity');
return __('Cart Minimum Quantity');
}

public function getTitle(array $configuration): string
Expand Down
98 changes: 98 additions & 0 deletions src/Promotion/Tests/Examples/DummyAdjustableCart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php

declare(strict_types=1);

namespace Vanilo\Promotion\Tests\Examples;


use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Support\Collection;
use Vanilo\Adjustments\Contracts\Adjustable;
use Vanilo\Adjustments\Contracts\AdjustmentCollection;
use Vanilo\Cart\Contracts\Cart;
use Vanilo\Cart\Contracts\CartItem;
use Vanilo\Contracts\Buyable;

class DummyAdjustableCart implements Cart, Adjustable
{
public function __construct(
private float $preAdjustmentTotal
) {
}

public function preAdjustmentTotal(): float
{
return $this->preAdjustmentTotal;
}

public function invalidateAdjustments(): void
{
// TODO: Implement invalidateAdjustments() method.
}

public function adjustments(): AdjustmentCollection
{
// TODO: Implement adjustments() method.
}

public function adjustmentsRelation(): MorphMany
{
// TODO: Implement adjustmentsRelation() method.
}

public function recalculateAdjustments(): void
{
// TODO: Implement recalculateAdjustments() method.
}

public function addItem(Buyable $product, float|int $qty = 1, array $params = []): CartItem
{
// TODO: Implement addItem() method.
}

public function removeItem(CartItem $item): void
{
// TODO: Implement removeItem() method.
}

public function removeProduct(Buyable $product): void
{
// TODO: Implement removeProduct() method.
}

public function clear(): void
{
// TODO: Implement clear() method.
}

public function itemCount(): int
{
// TODO: Implement itemCount() method.
}

public function getUser(): ?Authenticatable
{
// TODO: Implement getUser() method.
}

public function setUser(int|Authenticatable|string|null $user): void
{
// TODO: Implement setUser() method.
}

public function getItems(): Collection
{
// TODO: Implement getItems() method.
}

public function itemsTotal(): float
{
// TODO: Implement itemsTotal() method.
}

public function total(): float
{
// TODO: Implement total() method.
}
}
5 changes: 3 additions & 2 deletions src/Promotion/Tests/Examples/DummyCart.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
class DummyCart implements Cart
{
public function __construct(
private int $itemCount = 5
private int $itemCount = 5,
private float $itemsTotal = 0,
) {
}

Expand Down Expand Up @@ -59,7 +60,7 @@ public function getItems(): Collection

public function itemsTotal(): float
{
// TODO: Implement itemsTotal() method.
return $this->itemsTotal;
}

public function total(): float
Expand Down
90 changes: 90 additions & 0 deletions src/Promotion/Tests/Rules/CartMinimumValueTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

declare(strict_types=1);

/**
* Contains the CartMinimumValueTest class.
*
* @copyright Copyright (c) 2024 Vanilo UG
* @author Attila Fulop
* @license MIT
* @since 2024-08-26
*
*/

namespace Rules;

use Nette\Schema\ValidationException;
use Vanilo\Promotion\PromotionRuleTypes;
use Vanilo\Promotion\Rules\CartMinimumValue;
use Vanilo\Promotion\Tests\Examples\DummyAdjustableCart;
use Vanilo\Promotion\Tests\Examples\DummyCart;
use Vanilo\Promotion\Tests\TestCase;

class CartMinimumValueTest extends TestCase
{
/** @test */
public function it_can_be_created()
{
$ruleType = PromotionRuleTypes::make(CartMinimumValue::DEFAULT_ID);

$this->assertInstanceOf(CartMinimumValue::class, $ruleType);
}

/** @test */
public function it_throws_an_exception_if_the_configuration_is_empty()
{
$this->expectException(ValidationException::class);
$rule = PromotionRuleTypes::make(CartMinimumValue::DEFAULT_ID);

$rule->isPassing(new DummyCart(), []);
}

/** @test */
public function it_passes_if_the_rule_is_valid_and_the_items_total_is_above_the_threshold()
{
$rule = new CartMinimumValue();

$this->assertTrue($rule->isPassing(new DummyCart(1, 20), ['amount' => 19.99]));
}

/** @test */
public function it_passes_if_the_items_total_equals_the_threshold()
{
$rule = new CartMinimumValue();

$this->assertTrue($rule->isPassing(new DummyCart(1, 19.99), ['amount' => 19.99]));
}

/** @test */
public function it_does_not_pass_if_the_items_total_is_below_the_threshold()
{
$rule = new CartMinimumValue();

$this->assertFalse($rule->isPassing(new DummyCart(1, 19.98), ['amount' => 19.99]));
}

/** @test */
public function it_passes_if_the_pre_adjustment_total_is_above_the_threshold()
{
$rule = new CartMinimumValue();

$this->assertTrue($rule->isPassing(new DummyAdjustableCart(20), ['amount' => 19.99]));
}

/** @test */
public function it_passes_if_the_pre_adjustment_total_equals_the_threshold()
{
$rule = new CartMinimumValue();

$this->assertTrue($rule->isPassing(new DummyAdjustableCart(19.99), ['amount' => 19.99]));
}

/** @test */
public function it_does_not_pass_if_the_pre_adjustment_total_is_below_the_threshold()
{
$rule = new CartMinimumValue();

$this->assertFalse($rule->isPassing(new DummyAdjustableCart(19.98), ['amount' => 19.99]));
}
}

0 comments on commit c191588

Please sign in to comment.