feat: add TaxRule base class

This commit is contained in:
Joel Male
2026-05-27 21:24:09 +10:00
parent 867daaf328
commit b5edbb8ec0
2 changed files with 116 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Wearepixel\Cart\Tax;
use Wearepixel\Cart\CartCondition;
use Wearepixel\Cart\Contracts\CartConditionable;
use Wearepixel\Cart\Exceptions\InvalidTaxRuleException;
abstract class TaxRule implements CartConditionable
{
protected string $name;
protected string $value;
protected string $target = 'subtotal';
protected ?float $minimum = null;
protected ?float $maximum = null;
abstract public function isApplicable(): bool;
public function toCondition(): CartCondition
{
if (! $this->isApplicable()) {
throw new InvalidTaxRuleException("Tax rule [{$this->name}] is not applicable.");
}
$data = [
'name' => $this->name,
'type' => 'tax',
'value' => $this->value,
'target' => $this->target,
];
if ($this->minimum !== null) {
$data['minimum'] = $this->minimum;
}
if ($this->maximum !== null) {
$data['maximum'] = $this->maximum;
}
return new CartCondition($data);
}
}
+68
View File
@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
use Wearepixel\Cart\CartCondition;
use Wearepixel\Cart\Tax\TaxRule;
use Wearepixel\Cart\Exceptions\InvalidTaxRuleException;
class AuGst extends TaxRule
{
protected string $name = 'GST';
protected string $value = '10%';
public function isApplicable(): bool
{
return true;
}
}
class NotApplicableTax extends TaxRule
{
protected string $name = 'VAT';
protected string $value = '20%';
public function isApplicable(): bool
{
return false;
}
}
describe('TaxRule', function () {
test('converts to a CartCondition', function () {
$condition = (new AuGst)->toCondition();
expect($condition)->toBeInstanceOf(CartCondition::class);
expect($condition->getName())->toBe('GST');
expect($condition->getValue())->toBe('10%');
expect($condition->getType())->toBe('tax');
expect($condition->getTarget())->toBe('subtotal');
});
test('isApplicable() returning false causes toCondition() to throw', function () {
expect(fn() => (new NotApplicableTax)->toCondition())
->toThrow(InvalidTaxRuleException::class);
});
test('supports total as target', function () {
$tax = new class extends TaxRule {
protected string $name = 'Sales Tax';
protected string $value = '8%';
protected string $target = 'total';
public function isApplicable(): bool { return true; }
};
expect($tax->toCondition()->getTarget())->toBe('total');
});
test('supports minimum threshold', function () {
$tax = new class extends TaxRule {
protected string $name = 'Luxury Tax';
protected string $value = '15%';
protected ?float $minimum = 500.0;
public function isApplicable(): bool { return true; }
};
expect($tax->toCondition()->getMinimum())->toBe(500.0);
});
});