jaroslavtyc/granam-gpwebpay

View on GitHub
GpWebPay/CardPayRequestValues.php

Summary

Maintainability
D
2 days
Test Coverage
<?php declare(strict_types=1);

namespace Granam\GpWebPay;

use Granam\Boolean\Tools\ToBoolean;
use Granam\Float\Tools\ToFloat;
use Granam\GpWebPay\Codes\CurrencyCodes;
use Granam\GpWebPay\Codes\LanguageCodes;
use Granam\GpWebPay\Codes\PayMethodCodes;
use Granam\GpWebPay\Codes\RequestDigestKeys;
use Granam\GpWebPay\Codes\RequestPayloadKeys;
use Granam\Integer\Tools\ToInteger;
use Granam\Scalar\Tools\ToString;
use Granam\Strict\Object\StrictObject;
use \Granam\Scalar\Tools\Exceptions\Runtime as ConversionException;
use Granam\String\StringTools;

class CardPayRequestValues extends StrictObject
{

    // name => is required
    private static array $keysExpectedInArray = [
        // required
        RequestDigestKeys::ORDERNUMBER => true,
        RequestDigestKeys::AMOUNT => true,
        RequestDigestKeys::CURRENCY => true,
        RequestDigestKeys::DEPOSITFLAG => true,
        // optional
        RequestDigestKeys::MERORDERNUM => false,
        RequestDigestKeys::DESCRIPTION => false,
        RequestDigestKeys::MD => false,
        RequestDigestKeys::FASTPAYID => false,
        RequestDigestKeys::PAYMETHOD => false,
        RequestDigestKeys::DISABLEPAYMETHOD => false,
        RequestDigestKeys::PAYMETHODS => false,
        RequestDigestKeys::EMAIL => false,
        RequestDigestKeys::REFERENCENUMBER => false,
        RequestDigestKeys::ADDINFO => false,
        RequestPayloadKeys::LANG => false,
    ];
    private static array $integerKeysExpectedInArray = [
        RequestDigestKeys::ORDERNUMBER,
        RequestDigestKeys::CURRENCY,
        RequestDigestKeys::MERORDERNUM,
        RequestDigestKeys::FASTPAYID,
    ];
    private static array $booleanKeysExpectedInArray = [RequestDigestKeys::DEPOSITFLAG];
    private static array $floatKeysExpectedInArray = [RequestDigestKeys::AMOUNT]; // as float price like 3.25 EUR
    private static array $arrayWithStringKeysExpectedInArray = [RequestDigestKeys::PAYMETHODS];

    public const PRICE_INDEX = 'PRICE';

    /**
     * @param array $valuesFromGetOrPost
     * @param CurrencyCodes $currencyCodes
     * @return CardPayRequestValues
     * @throws \Granam\GpWebPay\Exceptions\InvalidArgumentException
     * @throws \Granam\GpWebPay\Exceptions\InvalidRequest
     * @throws \Granam\Float\Tools\Exceptions\WrongParameterType
     * @throws \Granam\Float\Tools\Exceptions\ValueLostOnCast
     * @throws \Granam\Integer\Tools\Exceptions\WrongParameterType
     * @throws \Granam\Integer\Tools\Exceptions\ValueLostOnCast
     * @throws \Granam\Scalar\Tools\Exceptions\WrongParameterType
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     * @throws \Granam\GpWebPay\Exceptions\UnknownCurrency
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     * @throws \Granam\GpWebPay\Exceptions\UnsupportedPayMethod
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     */
    public static function createFromArray(array $valuesFromGetOrPost, CurrencyCodes $currencyCodes): CardPayRequestValues
    {
        $withUpperCasedKeys = [];
        foreach ($valuesFromGetOrPost as $key => $value) {
            $withUpperCasedKeys[\strtoupper(\trim($key))] = $value;
        }
        if (($withUpperCasedKeys[RequestDigestKeys::AMOUNT] ?? null) === null
            && ($withUpperCasedKeys[self::PRICE_INDEX] ?? null) !== null
        ) {
            $withUpperCasedKeys[RequestDigestKeys::AMOUNT] = $withUpperCasedKeys[self::PRICE_INDEX];
        }
        $normalizedValues = self::normalizeValues($withUpperCasedKeys);

        return new static(
            $currencyCodes,
            $normalizedValues[RequestDigestKeys::ORDERNUMBER],
            $normalizedValues[RequestDigestKeys::AMOUNT],
            $normalizedValues[RequestDigestKeys::CURRENCY],
            $normalizedValues[RequestDigestKeys::DEPOSITFLAG],
            $normalizedValues[RequestDigestKeys::MERORDERNUM],
            $normalizedValues[RequestDigestKeys::DESCRIPTION],
            $normalizedValues[RequestDigestKeys::MD],
            $normalizedValues[RequestDigestKeys::FASTPAYID],
            $normalizedValues[RequestDigestKeys::PAYMETHOD],
            $normalizedValues[RequestDigestKeys::DISABLEPAYMETHOD],
            $normalizedValues[RequestDigestKeys::PAYMETHODS],
            $normalizedValues[RequestDigestKeys::EMAIL],
            $normalizedValues[RequestDigestKeys::REFERENCENUMBER],
            $normalizedValues[RequestDigestKeys::ADDINFO],
            $normalizedValues[RequestPayloadKeys::LANG]
        );
    }

    /**
     * @param array $withUpperCasedKeys
     * @return array
     * @throws \Granam\GpWebPay\Exceptions\InvalidArgumentException
     * @throws \Granam\GpWebPay\Exceptions\InvalidRequest
     */
    private static function normalizeValues(array $withUpperCasedKeys): array
    {
        $normalizedValues = [];
        foreach (self::$keysExpectedInArray as $key => $required) {
            if (($withUpperCasedKeys[$key] ?? null) === null) {
                if (!$required) {
                    $normalizedValues[$key] = null;
                    continue;
                }
                throw new Exceptions\InvalidRequest(
                    'Values to create ' . static::class . " are missing required '{$key}'"
                );
            }
            try {
                if (in_array($key, self::$integerKeysExpectedInArray, true)) {
                    $normalizedValues[$key] = ToInteger::toInteger($withUpperCasedKeys[$key]);
                } elseif (in_array($key, self::$floatKeysExpectedInArray, true)) {
                    $normalizedValues[$key] = ToFloat::toFloat($withUpperCasedKeys[$key]);
                } elseif (in_array($key, self::$booleanKeysExpectedInArray, true)) {
                    $normalizedValues[$key] = ToBoolean::toBoolean($withUpperCasedKeys[$key]);
                } elseif (in_array($key, self::$arrayWithStringKeysExpectedInArray, true)) {
                    $subArray = $withUpperCasedKeys[$key];
                    if (!is_array($subArray)) {
                        throw new Exceptions\InvalidRequest(
                            "Given '{$key}' should be an array, got " . \gettype($subArray)
                        );
                    }
                    $normalizedValues[$key] = $subArray;
                } else {
                    $normalizedValues[$key] = ToString::toString($withUpperCasedKeys[$key]);
                }
            } catch (ConversionException $conversionException) {
                throw new Exceptions\InvalidArgumentException(
                    "Value of key '{$key}' could not be converted to scalar: " . $conversionException->getMessage()
                );
            }
        }

        return $normalizedValues;
    }

    private ?int $orderNumber = null;
    private ?int $amount = null;
    private ?int $currency = null;
    private ?int $depositFlag = null;
    private ?int $merOrderNum = null;
    private ?string $description = null;
    /** @var string|null merchant data (note) */
    private ?string $md = null;
    private ?int $fastPayId = null;
    private ?string $payMethod = null;
    private ?string $disablePayMethod = null;
    private ?string $payMethods = null;
    private ?string $email = null;
    private ?string $referenceNumber = null;
    private ?string $addInfo = null;
    private ?string $lang = null;

    private ?float $price = null;

    /**
     * @param CurrencyCodes $currencyCodes list of supported currencies in ISO 4217
     * @param int $orderNumber with max length of 15
     * @param float $price real price of the order (purchase) like 3.74 EUR
     * @param int $currencyNumericCode ISO 4217
     * @param bool $depositFlag (false = instant payment not required, true = requires immediate payment)
     * @param int|null $merchantOrderIdentification = null
     * @param string|null $description = null
     * @param string|null $merchantNote = null
     * @param string|null $fastPayId = null
     * @param string|null $payMethod = null
     * @param string|null $disabledPayMethod = null
     * @param array|null $payMethods = null
     * @param string|null $cardHolderEmail = null
     * @param string|null $referenceNumber = null
     * @param string|null $additionalInfo = null
     * @param string|null $languageTwoCharCode = null
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     * @throws \Granam\GpWebPay\Exceptions\UnknownCurrency
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     * @throws \Granam\GpWebPay\Exceptions\UnsupportedPayMethod
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     * @throws \Granam\Scalar\Tools\Exceptions\WrongParameterType
     */
    public function __construct(
        CurrencyCodes $currencyCodes,
        int $orderNumber,
        float $price,
        int $currencyNumericCode,
        bool $depositFlag, // false = instant payment not required, true = requires immediate payment
        int $merchantOrderIdentification = null,
        string $description = null,
        string $merchantNote = null,
        int $fastPayId = null,
        string $payMethod = null,
        string $disabledPayMethod = null,
        array $payMethods = null,
        string $cardHolderEmail = null,
        string $referenceNumber = null,
        string $additionalInfo = null,
        string $languageTwoCharCode = null
    )
    {
        // MERCHANTNUMBER is taken from Settings by CardPayRequest
        // OPERATION is handled by CardPayRequest
        $this->setOrderNumber($orderNumber);
        $this->setAmount($price, $currencyNumericCode, $currencyCodes);
        $this->setCurrency($currencyNumericCode, $currencyCodes);
        $this->setDepositFlag($depositFlag);
        $this->setMerOrderNum($merchantOrderIdentification);
        // URL is taken from Settings by CardPayRequest
        $this->setDescription($description);
        $this->setMd($merchantNote);
        $this->setFastPayId($fastPayId); // "This parameter is located behind the MD parameter", see GP_webpay_HTTP_EN.pdf page 15
        $this->setPayMethod($payMethod);
        $this->setDisabledPayMethod($disabledPayMethod);
        $this->setPayMethods($payMethods);
        $this->setEmail($cardHolderEmail);
        $this->setReferenceNumber($referenceNumber);
        $this->setAddInfo($additionalInfo);
        // DIGEST is handled by CardPayRequest
        $this->setLang($languageTwoCharCode);
    }

    const MAXIMAL_LENGTH_OF_ORDER_NUMBER = 15;

    /**
     * @param int $orderNumber
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     */
    private function setOrderNumber(int $orderNumber)
    {
        $this->guardMaximalLength($orderNumber, self::MAXIMAL_LENGTH_OF_ORDER_NUMBER, RequestDigestKeys::ORDERNUMBER);
        $this->orderNumber = $orderNumber;
    }

    /**
     * @param int|float|string $value
     * @param int $maximalLength
     * @param string $name
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     */
    private function guardMaximalLength($value, int $maximalLength, string $name)
    {
        if (\strlen((string)$value) > $maximalLength) {
            throw new Exceptions\ValueTooLong(
                "Maximal length of '{$name}' is {$maximalLength}, got one with length of "
                . \strlen((string)$value) . " and value '{$value}'"
            );
        }
    }

    const MAXIMAL_LENGTH_OF_AMOUNT = 15;

    /**
     * @param float $price
     * @param int $currencyCode
     * @param CurrencyCodes $currencyCodes
     * @throws \Granam\GpWebPay\Exceptions\UnknownCurrency
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     */
    private function setAmount(float $price, int $currencyCode, CurrencyCodes $currencyCodes)
    {
        $this->price = $price;
        $precision = $currencyCodes->getCurrencyPrecision($currencyCode);
        if ($precision > 0) {
            /** @noinspection CallableParameterUseCaseInTypeContextInspection */
            $price *= 10 ** $precision;
        }
        $amount = (int)\round($price);
        $this->guardMaximalLength($amount, self::MAXIMAL_LENGTH_OF_AMOUNT, RequestDigestKeys::AMOUNT);
        $this->amount = $amount;
    }

    /**
     * @param int $currencyCode
     * @param CurrencyCodes $currencyCodes
     * @throws \Granam\GpWebPay\Exceptions\UnknownCurrency
     */
    private function setCurrency(int $currencyCode, CurrencyCodes $currencyCodes)
    {
        if (!$currencyCodes->isCurrencyNumericCode($currencyCode)) {
            throw new Exceptions\UnknownCurrency(
                'Unknown ' . RequestDigestKeys::CURRENCY
                . " code given, got '{$currencyCode}', expected one of those defined by ISO 4217"
            );
        }
        $this->currency = $currencyCode;
    }

    /**
     * @param bool $depositFlag
     */
    private function setDepositFlag(bool $depositFlag)
    {
        $this->depositFlag = (int)$depositFlag; // 0 or 1
    }

    /*
     * Some banks uses shorter MEMORDERNUM (rest is truncated)
     * Komerční banka 16
     * Raiffiesen bank 10
     * UniCredit bank 12
     * (others are unknown - see GP_webpay_HTTP_EN.pdf / GP_webpay_HTTP.pdf)
     */
    const MAXIMAL_LENGTH_OF_MERORDERNUM = 30;

    /**
     * @param int|null $merchantOrderIdentification with maximal length of 30 characters
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     */
    private function setMerOrderNum(int $merchantOrderIdentification = null)
    {
        if ($merchantOrderIdentification === null) {
            return;
        }
        $this->guardMaximalLength($merchantOrderIdentification, self::MAXIMAL_LENGTH_OF_MERORDERNUM, RequestDigestKeys::MERORDERNUM);
        $this->merOrderNum = $merchantOrderIdentification;
    }

    const MAXIMAL_LENGTH_OF_DESCRIPTION = 255;

    /**
     * @param string|null $description with maximal length of 255 and ASCII characters in range of 0x20–0x7E (printable characters)
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     */
    private function setDescription(string $description = null)
    {
        if ($description === null) {
            return;
        }
        $description = \trim($description);
        $this->guardMaximalLength($description, self::MAXIMAL_LENGTH_OF_DESCRIPTION, RequestDigestKeys::DESCRIPTION);
        $this->description = $this->sanitizeAsciiRange($description, RequestDigestKeys::DESCRIPTION);
    }

    /**
     * @link https://en.wikipedia.org/wiki/ASCII#Printable_characters
     * @param string $value
     * @param string $nameOfParameter
     * @param array $characterRanges
     * @return string
     */
    private function sanitizeAsciiRange(
        string $value,
        string $nameOfParameter,
        array $characterRanges = [[' ' /* 0x20 = space */, '~' /* 0x7E = tilde */]]
    ): string
    {
        $changes = [];
        $regexpWithRange = '~(?<outOfRange>[^';
        foreach ($characterRanges as $characterRange) {
            $regexpWithRange .= \preg_quote(\reset($characterRange), '~') . '-' . \preg_quote(\end($characterRange), '~');
        }
        $regexpWithRange .= '])~';
        $sanitized = \preg_replace_callback(
            '~(?<character>\w)~u',
            function (array $characterMatch) use (&$changes, $regexpWithRange) {
                $character = $characterMatch['character'];
                if (!\preg_match($regexpWithRange, $character)) {
                    return $character; // character is in the allowed range
                }

                $withoutDiacritics = StringTools::removeDiacritics($character);
                $replacement = \preg_replace_callback(
                    $regexpWithRange,
                    fn(string $stillOutOfRange) => \str_repeat('?', \mb_strlen($stillOutOfRange)),
                    $withoutDiacritics
                );
                $changes[] = [$character => $replacement];

                return $replacement;
            },
            $value
        );
        if (\count($changes) > 0) {
            \trigger_error("'{$nameOfParameter}' contains " . \count($changes)
                . ' characters out of allowed ASCII range(s) ' . $this->describeAsciiRange($characterRanges)
                . ' , replacements have to be made: ' . \var_export($changes, true),
                E_USER_WARNING
            );
        }
        if ($sanitized === null) { // like for ASCII 128
            \trigger_error("'{$nameOfParameter}' contains some characters out of allowed ASCII range(s) "
                . $this->describeAsciiRange($characterRanges)
                . ' which was not detected by regexp. Given string as ASCII chain: '
                . \implode(
                    ',',
                    \array_map(
                        fn($character) => \ord($character),
                        \str_split($value)
                    )
                ),
                E_USER_WARNING
            );

            return '';
        }

        return $sanitized;
    }

    /**
     * @param array $characterRanges
     * @return string
     */
    private function describeAsciiRange(array $characterRanges): string
    {
        return \implode(
            ',',
            \array_map(
                function (array $characterRange) {
                    $start = \reset($characterRange);
                    if (\count($characterRange) === 1) {
                        return "'{$start}'(0x" . \dechex(\ord($start)) . ')';
                    }
                    $end = \end($characterRange);

                    return "'{$start}'(0x" . \dechex(\ord($start)) . ')'
                        . "-'{$end}'(0x" . \dechex(\ord($end)) . ')';
                },
                $characterRanges
            )
        );
    }

    const MAXIMAL_LENGTH_OF_MD = 255;

    /**
     * @param string $merchantNote with maximal length of 255 and ASCII characters in range of 0x20–0x7E (printable characters)
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     */
    private function setMd(string $merchantNote = null)
    {
        if ($merchantNote === null) {
            return;
        }
        $merchantNote = \trim($merchantNote);
        $this->guardMaximalLength($merchantNote, self::MAXIMAL_LENGTH_OF_MD, RequestDigestKeys::MD . ' (merchant note)');
        $this->md = $this->sanitizeAsciiRange($merchantNote, RequestDigestKeys::MD . ' (merchant note)');
    }

    const MAXIMAL_LENGTH_OF_FASTPAYID = 15;

    /**
     * @param int|null $fastPayId with maximal length of 15
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     */
    private function setFastPayId(?int $fastPayId)
    {
        if ($fastPayId === null) {
            return;
        }
        $this->guardMaximalLength($fastPayId, self::MAXIMAL_LENGTH_OF_FASTPAYID, RequestDigestKeys::FASTPAYID);
        $this->fastPayId = $fastPayId;
    }

    /**
     * @param string|null $payMethod supported val: CRD – payment card | MCM – MasterCard Mobile | MPS – MasterPass | BTNCS - PLATBA 24
     * @throws \Granam\GpWebPay\Exceptions\UnsupportedPayMethod
     */
    private function setPayMethod(string $payMethod = null)
    {
        if ($payMethod === null) {
            return;
        }
        $payMethod = \trim($payMethod);
        $upperPayMethod = \strtoupper($payMethod);
        if (!PayMethodCodes::isSupportedPaymentMethod($upperPayMethod)) {
            throw new Exceptions\UnsupportedPayMethod(
                'Given ' . RequestDigestKeys::PAYMETHOD . " '{$payMethod}' is not supported, use one of "
                . \implode(',', PayMethodCodes::getPayMethodCodes())
            );
        }
        $this->payMethod = $upperPayMethod;
    }

    /**
     * Explicitly disable use of a payment method, even if is technically possible.
     *
     * @param string|null $disabledPayMethod supported val: CRD – payment card | MCM – MasterCard Mobile | MPS – MasterPass | BTNCS - PLATBA 24
     * @throws \Granam\GpWebPay\Exceptions\UnsupportedPayMethod
     */
    private function setDisabledPayMethod(string $disabledPayMethod = null)
    {
        if ($disabledPayMethod === null) {
            return;
        }
        $disabledPayMethod = \trim($disabledPayMethod);
        $upperDisabledPayMethod = \strtoupper($disabledPayMethod);
        if (!PayMethodCodes::isSupportedPaymentMethod($upperDisabledPayMethod)) {
            throw new Exceptions\UnsupportedPayMethod(
                'Can not disable ' . RequestDigestKeys::DISABLEPAYMETHOD . " by unknown pay method '{$disabledPayMethod}',"
                . ' use one of ' . \implode(',', PayMethodCodes::getPayMethodCodes())
            );
        }
        $this->disablePayMethod = $upperDisabledPayMethod;
    }

    /**
     * Sets allowed pay methods, therefore disable those non-listed there, even if they are technically possible.
     * If DISABLEPAYMETHOD is set as well than an intersection of both rules is used.
     *
     * @param array|string[] $payMethods supported val: CRD – payment card | MCM – MasterCard Mobile | MPS – MasterPass | BTNCS - PLATBA 24
     * @throws \Granam\Scalar\Tools\Exceptions\WrongParameterType
     * @throws \Granam\GpWebPay\Exceptions\UnsupportedPayMethod
     */
    private function setPayMethods(array $payMethods = null)
    {
        if ($payMethods === null) {
            return;
        }
        $upperPayMethods = [];
        foreach ($payMethods as $payMethod) {
            $upperPayMethods[$payMethod] = \strtoupper(\trim(ToString::toString($payMethod)));
        }
        $unknownPayMethods = array_diff($upperPayMethods, PayMethodCodes::getPayMethodCodes());
        if (\count($unknownPayMethods) > 0) {
            $unknownOriginalPayMethods = [];
            foreach ($unknownPayMethods as $unknownPayMethod) {
                $unknownOriginalPayMethods[] = array_search($unknownPayMethod, $upperPayMethods, true);
            }
            throw new Exceptions\UnsupportedPayMethod(
                'Can not set \'' . RequestDigestKeys::PAYMETHODS . '\' by unknown pay method ' . \implode(',', $unknownOriginalPayMethods)
                . '; use only ' . \implode(',', PayMethodCodes::getPayMethodCodes())
            );
        }
        if (\count($upperPayMethods) === 0) {
            trigger_error(
                'Empty array of \'' . RequestDigestKeys::PAYMETHODS . '\' provided, which would disable all of them.'
                . ' That is considered as a mistake and NO restriction to payment methods will be used instead'
                . ' (via NULL)',
                E_USER_WARNING
            );

            return;
        }
        $this->payMethods = \implode(',', $upperPayMethods);
    }

    const MAXIMAL_LENGTH_OF_EMAIL = 255;

    /**
     * @param string $email with maximal length of 255
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     */
    private function setEmail(string $email = null)
    {
        if ($email === null) {
            return;
        }
        $email = \trim($email);
        $this->guardMaximalLength($email, self::MAXIMAL_LENGTH_OF_EMAIL, RequestDigestKeys::EMAIL);
        if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
            trigger_error("Given user email '{$email}' has invalid format, email will not be used", E_USER_WARNING);

            return;
        }
        $this->email = $email;
    }

    const MAXIMAL_LENGTH_OF_REFERENCENUMBER = 20;

    /**
     * Merchant internal ID of an order
     *
     * @param string|null $referenceNumber with maximal length of 20
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     */
    private function setReferenceNumber(string $referenceNumber = null)
    {
        if ($referenceNumber === null) {
            return;
        }
        $referenceNumber = \trim($referenceNumber);
        $this->guardMaximalLength($referenceNumber, self::MAXIMAL_LENGTH_OF_REFERENCENUMBER, RequestDigestKeys::REFERENCENUMBER);
        $this->referenceNumber = $this->sanitizeAsciiRange(
            $referenceNumber,
            RequestDigestKeys::REFERENCENUMBER,
            [
                [' ' /* 0x20 */], ['#' /* 0x23 */, '$' /* 0x24 */], ['*' /* 0x2A */, ';' /* 0x3B */], ['=' /* 0x3D */],
                ['@' /* 0x40 */, 'Z' /* 0x5A */], ['^' /* 0x5E */, '_' /* 0x5F */], ['a' /* 0x61 */, 'z' /* 0x7A */],
            ]
        );
    }

    const MAXIMAL_LENGTH_OF_ADDINFO = 24000;

    /**
     * XML schema
     *
     * @param string $addInfo with maximal length of 24000
     * @throws \Granam\GpWebPay\Exceptions\ValueTooLong
     */
    private function setAddInfo(string $addInfo = null)
    {
        if ($addInfo === null) {
            return;
        }
        $addInfo = \trim($addInfo);
        $this->guardMaximalLength($addInfo, self::MAXIMAL_LENGTH_OF_ADDINFO, RequestDigestKeys::ADDINFO);
        $this->addInfo = $addInfo;
    }

    /**
     * Note: LANG is not part of digest
     *
     * @param string|null $lang
     */
    private function setLang(string $lang = null)
    {
        if ($lang === null) {
            return;
        }
        $lang = \trim($lang);
        if (!LanguageCodes::isLanguageSupported($lang)) {
            trigger_error(
                "Unsupported language code '{$lang}', GPWebPay auto-detection of a language will be used."
                . ' Supported languages are ' . \implode(',', LanguageCodes::getLanguageCodes()),
                E_USER_WARNING
            );

            return;
        }
        $this->lang = $lang;
    }

    /**
     * @return int
     */
    public function getOrderNumber(): int
    {
        return $this->orderNumber;
    }

    /**
     * Originally provided price
     *
     * @return float
     */
    public function getPrice(): float
    {
        return $this->price;
    }

    /**
     * Price turned to its integer representation according to provided currency
     * precision, @return int
     * @see CurrencyCodes::getCurrencyPrecision()
     *
     */
    public function getAmount(): int
    {
        return $this->amount;
    }

    /**
     * @return int
     */
    public function getCurrency(): int
    {
        return $this->currency;
    }

    /**
     * @return int
     */
    public function getDepositFlag(): int
    {
        return $this->depositFlag;
    }

    /**
     * @return null|string
     */
    public function getMd()
    {
        return $this->md;
    }

    /**
     * @return null|string
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * @return int|null
     */
    public function getMerOrderNum()
    {
        return $this->merOrderNum;
    }

    /**
     * @return null|string
     */
    public function getLang()
    {
        return $this->lang;
    }

    /**
     * @return null|string
     */
    public function getPayMethod()
    {
        return $this->payMethod;
    }

    /**
     * @return null|string
     */
    public function getDisablePayMethod()
    {
        return $this->disablePayMethod;
    }

    /**
     * @return null|string
     */
    public function getPayMethods()
    {
        return $this->payMethods;
    }

    /**
     * @return null|string
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * @return null|string
     */
    public function getReferenceNumber()
    {
        return $this->referenceNumber;
    }

    /**
     * @return null|string
     */
    public function getAddInfo()
    {
        return $this->addInfo;
    }

    /**
     * @return int|null
     */
    public function getFastPayId()
    {
        return $this->fastPayId;
    }
}