152 lines
4.6 KiB
PHP
152 lines
4.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace paygw_moneta\local\protocol;
|
|
|
|
use InvalidArgumentException;
|
|
use paygw_moneta\local\Money;
|
|
|
|
/**
|
|
* @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 CallbackNotification
|
|
{
|
|
private const ACCOUNT_ID_MAX_LENGTH = 20;
|
|
private const TRANSACTION_ID_MAX_LENGTH = 255;
|
|
private const OPERATION_ID_MAX_LENGTH = 255;
|
|
private const SUBSCRIBER_ID_MAX_LENGTH = 255;
|
|
|
|
private readonly string $command;
|
|
private readonly string $accountId;
|
|
private readonly string $transactionId;
|
|
private readonly string $operationId;
|
|
private readonly string $rawAmount;
|
|
private readonly ?Money $amount;
|
|
private readonly string $currency;
|
|
private readonly string $subscriberId;
|
|
private readonly string $rawTestMode;
|
|
private readonly string $signature;
|
|
|
|
/**
|
|
* @param array<string, mixed> $fields
|
|
*/
|
|
public function __construct(array $fields)
|
|
{
|
|
$this->command = self::optional($fields, 'MNT_COMMAND');
|
|
if (!in_array($this->command, ['', AssistantProtocol::COMMAND_CHECK], true)) {
|
|
throw new InvalidArgumentException('Неизвестная команда уведомления.');
|
|
}
|
|
$this->accountId = self::required($fields, 'MNT_ID', self::ACCOUNT_ID_MAX_LENGTH);
|
|
$this->transactionId = self::required($fields, 'MNT_TRANSACTION_ID', self::TRANSACTION_ID_MAX_LENGTH);
|
|
$this->operationId = self::optional($fields, 'MNT_OPERATION_ID', self::OPERATION_ID_MAX_LENGTH);
|
|
$this->rawAmount = self::optional($fields, 'MNT_AMOUNT');
|
|
$this->amount = $this->rawAmount === '' ? null : Money::fromDecimal($this->rawAmount);
|
|
$this->currency = self::required($fields, 'MNT_CURRENCY_CODE', 3);
|
|
$this->subscriberId = self::optional($fields, 'MNT_SUBSCRIBER_ID', self::SUBSCRIBER_ID_MAX_LENGTH);
|
|
$this->rawTestMode = self::required($fields, 'MNT_TEST_MODE', 1);
|
|
if (!in_array($this->rawTestMode, ['0', '1'], true)) {
|
|
throw new InvalidArgumentException('Недопустимое значение MNT_TEST_MODE.');
|
|
}
|
|
$this->signature = self::required($fields, 'MNT_SIGNATURE', 32);
|
|
if (($this->amount === null || $this->operationId === '') && !$this->isCheck()) {
|
|
throw new InvalidArgumentException('Уведомлению об оплате нужны сумма и номер операции.');
|
|
}
|
|
}
|
|
|
|
public function isCheck(): bool
|
|
{
|
|
return $this->command === AssistantProtocol::COMMAND_CHECK;
|
|
}
|
|
|
|
public function getCommand(): string
|
|
{
|
|
return $this->command;
|
|
}
|
|
|
|
public function getAccountId(): string
|
|
{
|
|
return $this->accountId;
|
|
}
|
|
|
|
public function getTransactionId(): string
|
|
{
|
|
return $this->transactionId;
|
|
}
|
|
|
|
public function getOperationId(): string
|
|
{
|
|
return $this->operationId;
|
|
}
|
|
|
|
public function getRawAmount(): string
|
|
{
|
|
return $this->rawAmount;
|
|
}
|
|
|
|
public function getAmount(): ?Money
|
|
{
|
|
return $this->amount;
|
|
}
|
|
|
|
public function getCurrency(): string
|
|
{
|
|
return $this->currency;
|
|
}
|
|
|
|
public function getSubscriberId(): string
|
|
{
|
|
return $this->subscriberId;
|
|
}
|
|
|
|
public function getRawTestMode(): string
|
|
{
|
|
return $this->rawTestMode;
|
|
}
|
|
|
|
public function isTestMode(): bool
|
|
{
|
|
return $this->rawTestMode === '1';
|
|
}
|
|
|
|
public function isSignedBy(Signature $signature): bool
|
|
{
|
|
return Signature::equals($signature->forNotification($this), $this->signature);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $fields
|
|
*/
|
|
private static function required(array $fields, string $name, int $maxLength): string
|
|
{
|
|
$value = self::optional($fields, $name, $maxLength);
|
|
if ($value === '') {
|
|
throw new InvalidArgumentException("Не передано поле {$name}.");
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $fields
|
|
*/
|
|
private static function optional(array $fields, string $name, int $maxLength = 255): string
|
|
{
|
|
if (!array_key_exists($name, $fields)) {
|
|
return '';
|
|
}
|
|
|
|
$value = $fields[$name];
|
|
if (!is_string($value)) {
|
|
throw new InvalidArgumentException("Поле {$name} должно быть строкой.");
|
|
}
|
|
if (strlen($value) > $maxLength) {
|
|
throw new InvalidArgumentException("Поле {$name} длиннее допустимого.");
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
}
|