feat: moneta 2.0, MONETA.Assistant payment module for PHPShop 6.7+

This commit is contained in:
2026-10-27 11:45:22 +03:00
parent 78b7405637
commit f8c12ce44a
82 changed files with 7387 additions and 58 deletions
@@ -0,0 +1,183 @@
<?php
declare(strict_types=1);
namespace MonetaPhpShop\protocol;
use InvalidArgumentException;
use MonetaPhpShop\Money;
/**
* Âõîäÿùèé çàïðîñ ñåðâèñà íà Check URL (`MNT_COMMAND=CHECK`) èëè Pay URL.
*/
final class CallbackNotification
{
private const ACCOUNT_ID_MAX_LENGTH = 20;
private const TRANSACTION_ID_MAX_LENGTH = 255;
private const OPERATION_ID_MAX_LENGTH = 255;
/**
* Íîìåð îïåðàöèè MONETA.RU â Pay URL — òîëüêî öèôðû
*/
private const PAY_OPERATION_ID = '/\A[0-9]{1,20}\z/';
private const SUBSCRIBER_ID_MAX_LENGTH = 255;
private const CURRENCY_LENGTH = 3;
private const SIGNATURE_LENGTH = 32;
/** @var string */
private $command;
/** @var string */
private $accountId;
/** @var string */
private $transactionId;
/** @var string */
private $operationId;
/** @var string */
private $rawAmount;
/** @var Money|null */
private $amount;
/** @var string */
private $currency;
/** @var string */
private $subscriberId;
/** @var string */
private $rawTestMode;
/** @var string */
private $signature;
/**
* @param array<string, mixed> $fields ïàðàìåòðû çàïðîñà ($_POST èëè $_GET — ìåòîä çàäà¸òñÿ â íàñòðîéêàõ ñ÷¸òà)
*/
public function __construct(array $fields)
{
$this->command = self::optional($fields, 'MNT_COMMAND', strlen(AssistantProtocol::COMMAND_CHECK));
if (($this->command !== '') && ($this->command !== AssistantProtocol::COMMAND_CHECK)) {
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', strlen(Money::MAX));
$this->amount = $this->rawAmount === '' ? null : Money::fromDecimal($this->rawAmount);
$this->currency = self::required($fields, 'MNT_CURRENCY_CODE', self::CURRENCY_LENGTH);
$this->subscriberId = self::optional($fields, 'MNT_SUBSCRIBER_ID', self::SUBSCRIBER_ID_MAX_LENGTH);
$this->rawTestMode = self::required($fields, 'MNT_TEST_MODE', 1);
if (($this->rawTestMode !== '0') && ($this->rawTestMode !== '1')) {
throw new InvalidArgumentException('Íåäîïóñòèìîå çíà÷åíèå MNT_TEST_MODE.');
}
$this->signature = self::required($fields, 'MNT_SIGNATURE', self::SIGNATURE_LENGTH);
if (
(($this->amount === null) || (preg_match(self::PAY_OPERATION_ID, $this->operationId) !== 1))
&& !$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;
}
/**
* Ñóììà êàê ïðèøëà — òîëüêî äëÿ ïîäïèñè; äëÿ ñâåðêè — {@see self::getAmount()}.
*/
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): 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;
}
}