feat: moneta 2.0, MONETA.Assistant payment module for PHPShop 6.7+
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MonetaPhpShop;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Äåíåæíàÿ ñóììà â ôîðìàòå MONETA.Assistant: äåñÿòè÷íàÿ ñòðîêà ðîâíî ñ äâóìÿ
|
||||
* çíàêàìè ïîñëå òî÷êè (`120.25`, `100.00`), áåç çíàêà è ðàçäåëèòåëåé òûñÿ÷.
|
||||
*
|
||||
* Âíóòðè — òîëüêî ñòðîêà è öåëûå êîïåéêè; `float` ïîÿâëÿåòñÿ ëèøü íà ãðàíèöå
|
||||
* ñ õîñòîì ({@see self::fromFloat()}): PHPShop õðàíèò `phpshop_orders.sum` êàê FLOAT.
|
||||
*/
|
||||
final class Money
|
||||
{
|
||||
/** Âåðõíÿÿ ãðàíèöà ñóììû ïî JSON-ñõåìå Check URL (`number_amount.maximum`, `cmsspecification.pdf`). */
|
||||
public const MAX = '10000000000000.00';
|
||||
|
||||
/** Öåëàÿ ÷àñòü — äî 14 çíàêîâ áåç âåäóùèõ íóëåé, äðîáíàÿ — ðîâíî äâà. */
|
||||
private const PATTERN = '/\A(?:0|[1-9][0-9]{0,13})\.[0-9]{2}\z/';
|
||||
|
||||
/** @var string */
|
||||
private $value;
|
||||
|
||||
private function __construct(string $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ñòðîãèé ðàçáîð äåñÿòè÷íîé ñòðîêè; âñ¸, ÷òî íå `^\d+\.\d{2}$`, îòêëîíÿåòñÿ.
|
||||
*/
|
||||
public static function fromDecimal(string $value): self
|
||||
{
|
||||
if (preg_match(self::PATTERN, $value) !== 1) {
|
||||
throw new InvalidArgumentException('Ñóììà äîëæíà áûòü äåñÿòè÷íîé ñòðîêîé ñ äâóìÿ çíàêàìè ïîñëå òî÷êè.');
|
||||
}
|
||||
|
||||
$money = new self($value);
|
||||
if ($money->toMinorUnits() > (new self(self::MAX))->toMinorUnits()) {
|
||||
throw new InvalidArgumentException('Ñóììà ïðåâûøàåò äîïóñòèìûé ìàêñèìóì.');
|
||||
}
|
||||
|
||||
return $money;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ñóììà â êîïåéêàõ.
|
||||
*/
|
||||
public static function fromMinorUnits(int $minorUnits): self
|
||||
{
|
||||
if ($minorUnits < 0) {
|
||||
throw new InvalidArgumentException('Ñóììà íå ìîæåò áûòü îòðèöàòåëüíîé.');
|
||||
}
|
||||
|
||||
return self::fromDecimal(sprintf('%d.%02d', intdiv($minorUnits, 100), $minorUnits % 100));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ãðàíèöà ñ õîñòîì: îêðóãëåíèå äî êîïååê äåëàåòñÿ çäåñü îäèí ðàç, äàëüøå `float` íå èñïîëüçóåòñÿ.
|
||||
*/
|
||||
public static function fromFloat(float $amount): self
|
||||
{
|
||||
if (($amount < 0) || !is_finite($amount)) {
|
||||
throw new InvalidArgumentException('Ñóììà õîñòà äîëæíà áûòü êîíå÷íûì íåîòðèöàòåëüíûì ÷èñëîì.');
|
||||
}
|
||||
|
||||
return self::fromDecimal(number_format($amount, 2, '.', ''));
|
||||
}
|
||||
|
||||
public function toDecimal(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function toMinorUnits(): int
|
||||
{
|
||||
[$units, $cents] = explode('.', $this->value);
|
||||
|
||||
return ((int) $units * 100) + (int) $cents;
|
||||
}
|
||||
|
||||
public function isPositive(): bool
|
||||
{
|
||||
return ($this->value !== '0.00');
|
||||
}
|
||||
|
||||
public function equals(self $other): bool
|
||||
{
|
||||
return ($this->value === $other->value);
|
||||
}
|
||||
|
||||
public function add(self $other): self
|
||||
{
|
||||
return self::fromMinorUnits($this->toMinorUnits() + $other->toMinorUnits());
|
||||
}
|
||||
|
||||
public function multiply(int $quantity): self
|
||||
{
|
||||
if ($quantity < 0) {
|
||||
throw new InvalidArgumentException('Êîëè÷åñòâî íå ìîæåò áûòü îòðèöàòåëüíûì.');
|
||||
}
|
||||
|
||||
return self::fromMinorUnits($this->toMinorUnits() * $quantity);
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user