feat: paygw_moneta 1.0.0, MONETA.Assistant payment gateway for Moodle
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace paygw_moneta\local\receipt;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use paygw_moneta\local\Money;
|
||||
|
||||
/**
|
||||
* Позиция чека — объект `inventPositions` (`kassaspecification.pdf`) и элемент
|
||||
* `items` JSON-ответа Check URL (`cmsspecification.pdf`).
|
||||
*
|
||||
* @package paygw_moneta
|
||||
* @copyright 2026 Moneta Labs {@link https://moneta.ru/}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
final class ReceiptItem
|
||||
{
|
||||
public const NAME_MAX_LENGTH = 128;
|
||||
|
||||
/** Максимальная цена позиции и произведения `price * quantity`. */
|
||||
public const PRICE_MAX = '42949672.95';
|
||||
|
||||
/** Пустое имя касса не примет; остаётся, если после чистки ничего нет. */
|
||||
private const FALLBACK_NAME = 'Услуга';
|
||||
|
||||
/** Единица измерения из перечня кассы; для доступа к курсу иной не бывает. */
|
||||
private const MEASURE = 'unit';
|
||||
|
||||
public readonly string $name;
|
||||
|
||||
public function __construct(
|
||||
string $name,
|
||||
public readonly Money $price,
|
||||
public readonly int $quantity,
|
||||
public readonly Vat $vat,
|
||||
public readonly PaymentMethod $paymentMethod,
|
||||
public readonly PaymentObject $paymentObject,
|
||||
) {
|
||||
$name = ReceiptText::validate($name, self::NAME_MAX_LENGTH);
|
||||
$this->name = ($name === '') ? self::FALLBACK_NAME : $name;
|
||||
|
||||
if ($quantity < 1 || $quantity > 99999) {
|
||||
throw new InvalidArgumentException('Количество позиции вне допустимых границ.');
|
||||
}
|
||||
|
||||
$max = Money::fromDecimal(self::PRICE_MAX)->toMinorUnits();
|
||||
if ($price->toMinorUnits() > $max || $this->total()->toMinorUnits() > $max) {
|
||||
throw new InvalidArgumentException('Цена позиции превышает потолок кассы.');
|
||||
}
|
||||
}
|
||||
|
||||
public function total(): Money
|
||||
{
|
||||
return $this->price->multiply($this->quantity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Элемент `items` для JSON-ответа Check URL: числа — числа, ставка — строкой `vat`.
|
||||
* Цена подставляется меткой, чтобы в JSON осталось ровно два знака (`100.00`).
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toCheckItem(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->name,
|
||||
'price' => JsonNumber::placeholder($this->price),
|
||||
'quantity' => $this->quantity,
|
||||
'measure' => self::MEASURE,
|
||||
'paymentMethod' => $this->paymentMethod->value,
|
||||
'paymentObject' => $this->paymentObject->value,
|
||||
'vat' => $this->vat->value,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Объект `inventPositions` для атрибута `INVENTORY`: цена и количество —
|
||||
* строками, как в примере спецификации Moneta.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function toInventoryPosition(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->name,
|
||||
'price' => $this->price->toDecimal(),
|
||||
'quantity' => (string) $this->quantity,
|
||||
'measure' => self::MEASURE,
|
||||
'vatTag' => $this->vat->tag(),
|
||||
'pm' => $this->paymentMethod->value,
|
||||
'po' => $this->paymentObject->value,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string|int>
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->name,
|
||||
'price' => $this->price->toDecimal(),
|
||||
'quantity' => $this->quantity,
|
||||
'vat' => $this->vat->value,
|
||||
'paymentMethod' => $this->paymentMethod->value,
|
||||
'paymentObject' => $this->paymentObject->value,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
name: (string) ($data['name'] ?? ''),
|
||||
price: Money::fromDecimal((string) ($data['price'] ?? '')),
|
||||
quantity: (int) ($data['quantity'] ?? 0),
|
||||
vat: Vat::from((string) ($data['vat'] ?? '')),
|
||||
paymentMethod: PaymentMethod::from((string) ($data['paymentMethod'] ?? '')),
|
||||
paymentObject: PaymentObject::from((string) ($data['paymentObject'] ?? '')),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user