*/ use BaseEnum; case TVA_20 = 1; case TVA_5_5 = 2; /** * Optional labels definition * * @phpstan-ignore-next-line classConstant.unused (Base enum usage) */ private const LABELS = [ self::TVA_20->name => 'TVA 20%', self::TVA_5_5->name => 'TVA 5.5%', ]; public function percent(): float { return match ($this) { self::TVA_20 => 20.0, self::TVA_5_5 => 5.5, }; } public static function fromPercent(float $percent): self { return match ($percent) { self::TVA_20->percent() => self::TVA_20, self::TVA_5_5->percent() => self::TVA_5_5, default => self::tryFrom((int) $percent) ?? throw new \UnexpectedValueException( sprintf('Unhandled tax rate: %s', $percent) ), }; } public function rate(): float { return $this->percent() / 100; } /** * Exact decimal multiplier (1 + rate), as a string to avoid any float rounding. * * @return numeric-string */ public function multiplier(): string { return match ($this) { self::TVA_20 => '1.2', self::TVA_5_5 => '1.055', }; } public function applyTo(Money $price): Money { return $price->multiply($this->multiplier(), Product::ROUNDING); } }