ldc-boutique-cnc-sable/domain/Models/ValueObjects/BasketProduct.php
2026-10-27 09:58:12 +01:00

101 lines
2.9 KiB
PHP

<?php
declare(strict_types=1);
namespace Domain\Models\ValueObjects;
use Domain\Enums\ProductBrand;
use Domain\Enums\TaxRate;
use Domain\Enums\Units\OrderUnit;
use Domain\Models\ValueObjects\Entities\ProductId;
use Domain\Services\PricingService;
use Money\Money;
final readonly class BasketProduct
{
public function __construct(
public ProductId $id,
public string $name,
public int $qty,
public Money $unitPriceHt,
public Money $unitDiscount,
public TaxRate $taxRate,
public int $weightGrams,
public ?ProductBrand $brand,
public ?IncoId $incoId,
public OrderUnit $orderUnit,
public string $slug,
public ?string $picture,
public ?string $description,
public bool $weightVariable,
public float $discountRate,
public Money $priceKgTtc,
/** @var array<string,mixed> */
public array $options = []
) {
if (trim($name) === '') {
throw new \DomainException('name cannot be empty');
}
if (trim($slug) === '') {
throw new \DomainException('slug cannot be empty');
}
if ($qty <= 0) {
throw new \DomainException('qty has to be positive');
}
if (! $unitPriceHt->isPositive()) {
throw new \DomainException('unitPriceHt has to be positive');
}
if (! $unitDiscount->isPositive() && ! $unitDiscount->isZero()) {
throw new \DomainException('unitDiscount cannot be negative');
}
if (! $priceKgTtc->isPositive()) {
throw new \DomainException('priceKgTtc has to be positive');
}
if ($discountRate < 0 || $discountRate > 1) {
throw new \DomainException('discountRate has to be between 0 and 1');
}
}
public function unitPriceHt(): Money
{
return $this->unitPriceHt;
}
public function unitTtc(): Money
{
$unitPriceDiscounted = $this->unitPriceHt->subtract($this->unitDiscount);
// applyTo renvoie déjà le montant TTC (900 + 180 = 1080)
return $this->taxRate->applyTo($unitPriceDiscounted);
}
public function discountTotal(): Money
{
return $this->unitDiscount->multiply($this->qty, PricingService::ROUNDING);
}
public function priceTotalHt(): Money
{
return $this->unitPriceHt->multiply($this->qty, PricingService::ROUNDING);
}
public function subtotalHt(): Money
{
return $this->priceTotalHt()->subtract($this->discountTotal());
}
public function taxTotal(): Money
{
return $this->totalTtc()->subtract($this->subtotalHt());
}
public function totalTtc(): Money
{
return $this->taxRate->applyTo($this->subtotalHt());
}
public function weightTotal(): int
{
return $this->weightGrams * $this->qty;
}
}