Files

112 lines
3.0 KiB
PHP

<?php
declare(strict_types=1);
namespace MonetaPhpShop\receipt;
use InvalidArgumentException;
use MonetaPhpShop\Money;
/**
* Êîëè÷åñòâî ïîçèöèè ÷åêà ñ òî÷íîñòüþ êàññû — òðè çíàêà ïîñëå òî÷êè (`kassaspecification.pdf`,
* â ñõåìå Check URL `multipleOf 0.001`). Õðàíèòñÿ öåëûì ÷èñëîì òûñÿ÷íûõ, êàê êîïåéêè â {@see Money}:
* Êîðçèíà ÿäðà õðàíèò êîëè÷åñòâî êàê åñòü.
*/
final class Quantity
{
private const SCALE = 1000;
/** Ïîòîëîê êàññû: 99999.999. */
public const MAX_THOUSANDTHS = 99999999;
/** @var int */
private $thousandths;
private function __construct(int $thousandths)
{
if (($thousandths < 1) || ($thousandths > self::MAX_THOUSANDTHS)) {
throw new InvalidArgumentException('Êîëè÷åñòâî ïîçèöèè ÷åêà âíå ãðàíèö êàññû.');
}
$this->thousandths = $thousandths;
}
public static function pieces(int $pieces): self
{
return new self($pieces * self::SCALE);
}
public static function fromThousandths(int $thousandths): self
{
return new self($thousandths);
}
/**
* Êîëè÷åñòâî èç êîðçèíû çàêàçà (`num`): ÷èñëî èëè ÷èñëîâàÿ ñòðîêà, îêðóãëÿåòñÿ äî òûñÿ÷íûõ.
* Íîëü, îòðèöàòåëüíîå, íå ÷èñëî èëè áîëüøå ïîòîëêà êàññû — null.
*
* @param mixed $raw
*/
public static function fromCart($raw): ?self
{
if (is_string($raw)) {
$raw = trim($raw);
}
if (!is_int($raw) && !is_float($raw) && !(is_string($raw) && is_numeric($raw))) {
return null;
}
$thousandths = (int) round((float) $raw * self::SCALE);
if (($thousandths < 1) || ($thousandths > self::MAX_THOUSANDTHS)) {
return null;
}
return new self($thousandths);
}
public function getThousandths(): int
{
return $this->thousandths;
}
/**
* Öåëîå ëè êîëè÷åñòâî: òîëüêî òàêóþ ñòðîêó ìîæíî ðåçàòü íà äâå ñ ðàçíèöåé öåí â êîïåéêó.
*/
public function isWhole(): bool
{
return $this->thousandths % self::SCALE === 0;
}
/**
* Öåëîå ÷èñëî øòóê; òîëüêî äëÿ {@see self::isWhole()}.
*/
public function getPieces(): int
{
return intdiv($this->thousandths, self::SCALE);
}
/**
* Äåñÿòè÷íàÿ çàïèñü áåç ëèøíèõ íóëåé: `2`, `2.5`, `0.125`.
*/
public function toDecimal(): string
{
if ($this->isWhole()) {
return (string) $this->getPieces();
}
return rtrim(
sprintf('%d.%03d', intdiv($this->thousandths, self::SCALE), $this->thousandths % self::SCALE),
'0',
);
}
/**
* Ñóììà ïîçèöèè: öåíà x êîëè÷åñòâî, îêðóãëåíèå äî êîïåéêè (ïîëîâèíà — ââåðõ).
*/
public function totalOf(Money $price): Money
{
return Money::fromMinorUnits(
intdiv(($price->toMinorUnits() * $this->thousandths) + intdiv(self::SCALE, 2), self::SCALE),
);
}
}