Files

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;
}
}