Skip to content

Instantly share code, notes, and snippets.

@sasin91
Created December 11, 2024 15:11
Show Gist options
  • Save sasin91/20c8a2613762e1eee4b25ed14b0b47fa to your computer and use it in GitHub Desktop.
Save sasin91/20c8a2613762e1eee4b25ed14b0b47fa to your computer and use it in GitHub Desktop.
PriceMatrix.php
<?php
namespace App;
use App\Enums\Discount;
use Brick\Money\Money;
use Illuminate\Contracts\Support\Arrayable;
use InvalidArgumentException;
use WeakMap;
class PriceMatrix implements Arrayable
{
public Money $raw;
public readonly Money $vat;
public Money $total;
/**
* The applied discounts.
* The money value is the total
* when the discount was applied.
*
* @var WeakMap<Discount, Money>
*/
public readonly WeakMap $discounts;
public function __construct($initialAmount = 0, string $currency = 'DKK')
{
$this->discounts = new WeakMap();
if (is_numeric($initialAmount)) {
$initialAmount = Money::of($initialAmount, $currency);
}
if ($initialAmount instanceof Money) {
$initialAmount = $initialAmount->getAmount();
}
$this->raw = Money::of($initialAmount, $currency);
$this->vat = Money::of($initialAmount->multipliedBy(0.25), $currency);
$this->calculateTotal();
}
public function calculateTotal(): static
{
$this->total = Money::of(
$this->raw->plus($this->vat)->getAmount(),
$this->raw->getCurrency()
);
return $this;
}
public function addDiscount(Discount $discount): static
{
$this->discounts[$discount] = $this->raw;
$this->raw = $this->raw->minus(
$discount->calculate($this->raw)
);
$this->calculateTotal();
return $this;
}
public function subtractDiscount(Discount $discount): static
{
[$appliedDiscount, $rawAmount] = $this->findDiscount($discount);
if ($appliedDiscount === null) {
throw new InvalidArgumentException(
sprintf(
"No %s Discount was applied.",
$discount->value
)
);
}
$this->raw = $rawAmount;
$this->calculateTotal();
unset($this->discounts[$appliedDiscount]);
return $this;
}
public function findDiscount(Discount $discount): array
{
if (isset($this->discounts[$discount])) {
return [$discount, $this->discounts[$discount]];
}
foreach ($this->discounts as $registeredDiscount => $rawAmount)
{
if ($registeredDiscount->value === $discount->value) {
return [$registeredDiscount, $rawAmount];
}
}
return [null, null];
}
public function toArray()
{
return [
'raw' => $this->raw,
'vat' => $this->vat,
'total' => $this->total,
'discounts' => iterator_to_array($this->discounts)
];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment