66 lines
2.0 KiB
PHP
66 lines
2.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace MonetaPhpShop\protocol;
|
|
|
|
use MonetaPhpShop\Money;
|
|
use MonetaPhpShop\receipt\Quantity;
|
|
use RuntimeException;
|
|
|
|
/**
|
|
* Äåíåæíûå ÷èñëà â JSON áåç `float`: `cmsspecification.pdf` òðåáóåò «äâà çíàêà
|
|
* ïîñëå òî÷êè, äàæå åñëè ýòî íóëè», à `json_encode(100.0)` äàñò `100.0`. Ñóììà
|
|
* êîäèðóåòñÿ ìåòêîé è ïîñëå `json_encode` çàìåíÿåòñÿ íà äåñÿòè÷íóþ ñòðîêó áåç
|
|
* êàâû÷åê — ïîëó÷àåòñÿ ëèòåðàë `100.00`, âàëèäíûé JSON-number. Òàê æå — äðîáíîå êîëè÷åñòâî
|
|
* ïîçèöèè (`2.5`, äî òð¸õ çíàêîâ): `float` äàë áû `2.4999999…` íà íåóäà÷íûõ çíà÷åíèÿõ.
|
|
*/
|
|
final class JsonNumber
|
|
{
|
|
private const PREFIX = '__moneta_phpshop_number:';
|
|
|
|
private const QUANTITY_PREFIX = '__moneta_phpshop_quantity:';
|
|
|
|
private function __construct() {}
|
|
|
|
public static function placeholder(Money $amount): string
|
|
{
|
|
return self::PREFIX . $amount->toDecimal();
|
|
}
|
|
|
|
/**
|
|
* Êîëè÷åñòâî ïîçèöèè: öåëîå — êàê åñòü (`2`), äðîáíîå — ìåòêîé, â JSON ñòàíåò `2.5`.
|
|
*
|
|
* @return int|string
|
|
*/
|
|
public static function quantity(Quantity $quantity)
|
|
{
|
|
return $quantity->isWhole() ? $quantity->getPieces() : self::QUANTITY_PREFIX . $quantity->toDecimal();
|
|
}
|
|
|
|
/**
|
|
* @param array<mixed> $payload ñòðîêè â UTF-8
|
|
*/
|
|
public static function encode(array $payload): string
|
|
{
|
|
$json = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
|
if ($json === false) {
|
|
throw new RuntimeException('Íå óäàëîñü ñåðèàëèçîâàòü JSON: ' . json_last_error_msg());
|
|
}
|
|
|
|
$result = preg_replace(
|
|
[
|
|
'/"' . preg_quote(self::PREFIX, '/') . '([0-9]+\.[0-9]{2})"/',
|
|
'/"' . preg_quote(self::QUANTITY_PREFIX, '/') . '([0-9]+\.[0-9]{1,3})"/',
|
|
],
|
|
'$1',
|
|
$json,
|
|
);
|
|
if ($result === null) {
|
|
throw new RuntimeException('Íå óäàëîñü ïîäñòàâèòü ñóììû â JSON.');
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
}
|