код `vat`. */ private const BY_PERCENT = [ 0 => 'vat0', 5 => 'vat5', 7 => 'vat7', 10 => 'vat10', 20 => 'vat20', 22 => 'vat22', ]; /** * Код `vat` (`cmsspecification.pdf`) -> `vatTag` (`kassaspecification.pdf`). */ private const TAGS = [ self::NONE => '1105', 'vat0' => '1104', 'vat5' => '1108', 'vat7' => '1109', 'vat10' => '1103', 'vat20' => '1102', 'vat22' => '1113', 'vat105' => '1110', 'vat107' => '1111', 'vat110' => '1107', 'vat120' => '1106', 'vat122' => '1114', ]; /** @var string */ private $code; private function __construct(string $code) { $this->code = $code; } public static function none(): self { return new self(self::NONE); } /** * Ставка по коду `vat`; неизвестный код — null. */ public static function fromCode(string $code): ?self { return isset(self::TAGS[$code]) ? new self($code) : null; } /** * Ставка из настроек PHPShop — свободное число процентов (`nds`, `ofd_nds` доставки). * Пусто или ставки нет в перечне кассы — «без НДС»: неизвестную ставку не угадываем. */ public static function fromPercent(string $percent): self { return self::tryFromPercent($percent) ?? self::none(); } /** * Как {@see self::fromPercent()}, но пустое или неизвестное значение — null: вызывающий * предупреждает мерчанта, что позиция уйдёт в чек «без НДС». */ public static function tryFromPercent(string $percent): ?self { $percent = trim($percent); if (preg_match('/\A[0-9]{1,3}(?:[.,]0+)?\z/', $percent) !== 1) { return null; } $value = (int) $percent; return isset(self::BY_PERCENT[$value]) ? new self(self::BY_PERCENT[$value]) : null; } public function getCode(): string { return $this->code; } public function getTag(): string { return self::TAGS[$this->code]; } public function equals(self $other): bool { return ($this->code === $other->code); } }