Начало работы по #5 и #6

- строгая типизация
- переработан класс `TestEnvParams`:
    - вынесен на уровень выше из под `AtolOnline\Constants`
    - вместо констант - две функции для получения актуальных параметров подключения по ФФД1.05 и ФФД1.2
- актуализированы `PaymentObjects` согласно #5
- исходники вынесены не уровень выше в `src`
- константы теперь enum через `myclabs/php-enum`
- новые константы `DocumentTypes`
- классы констант финализированы
- все исключения переименованы, а многие так или иначе отрефакторены (не полностью)
- новые исключения `InvalidSnoException`, `InvalidPaymentAddressException`
- `helpers.php` стал полноценным классом `Helpers`
- удалены трейты `HasEmail`, `HasInn`, `RublesKopeksConverter` (конвертация перенесена в `Helpers`)
- удалён хелпер `valid_strlen()`, вместо него теперь везде `mb_strlen()`
- сущности `Client` и `Company` получили свои имплементации для `email` и `inn`
- доработки в `BasicTestCase`
- полное покрытие тестами: `Client`, `Company`, `Helpers`
- поправлен `phpunit.xml`
- везде обновлены копирайты
- актуализированы и исправлены phpdoc, return types
- начато введение `strict_types=1`
- минимальный php теперь 8.0
- обновлены все зависимости
- подключен пакет коллекций laravel для будущего использования
- теперь можно `composer test` и `composer test-cov`
pull/10/head
Anthony Axenov 2021-11-18 12:24:30 +08:00
parent cc944a1dbb
commit 77481884ad
78 changed files with 4220 additions and 2712 deletions

View File

@ -16,10 +16,10 @@ jobs:
uses: php-actions/composer@40-env uses: php-actions/composer@40-env
with: with:
version: 2 version: 2
php_version: 7.4 php_version: 8.0
only_args: --prefer-dist --no-progress only_args: --prefer-dist --no-progress
- name: Run phpunit tests - name: Run phpunit tests
uses: php-actions/phpunit@v8 uses: php-actions/phpunit@v9
with: with:
configuration: ./phpunit.xml configuration: ./phpunit.xml

View File

@ -39,26 +39,30 @@
} }
], ],
"require": { "require": {
"php": ">=7.4", "php": ">=8.0",
"ext-json": "*", "ext-json": "*",
"guzzlehttp/guzzle": "^6.5", "ext-mbstring": "*",
"psr/log": "^1.1", "guzzlehttp/guzzle": "^7.4",
"ramsey/uuid": "^3.9" "psr/log": "^3",
"ramsey/uuid": "^4.2",
"myclabs/php-enum": "^1.8",
"illuminate/collections": "^8.70"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^8.5" "phpunit/phpunit": "^9.5"
}, },
"autoload": { "autoload": {
"classmap": [ "psr-4": {
"src/AtolOnline/Api/", "AtolOnline\\": "src/"
"src/AtolOnline/Exceptions/", }
"src/AtolOnline/Entities/", },
"src/AtolOnline/Traits/", "autoload-dev": {
"src/AtolOnline/Constants/", "psr-4": {
"tests/" "AtolOnline\\Tests\\": "tests/"
], }
"files": [ },
"src/helpers.php" "scripts": {
] "test": "vendor/bin/phpunit --colors=always",
"test-cov": "vendor/bin/phpunit --coverage-html coverage"
} }
} }

1997
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
~
~ This code is licensed under MIT.
~ Этот код распространяется по лицензии MIT.
~ https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
-->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd" xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false" backupGlobals="false"
@ -11,15 +19,14 @@
processIsolation="false" processIsolation="false"
stopOnFailure="false"> stopOnFailure="false">
<testsuites> <testsuites>
<testsuite name="Unit"> <testsuite name="All">
<file>ClientTest.php</file> <directory suffix="Test.php">./tests</directory>
<file>CompanyTest.php</file>
<file>VatTest.php</file>
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<file>ItemTest.php</file>
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite> </testsuite>
</testsuites> </testsuites>
<coverage>
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
</phpunit> </phpunit>

591
src/Api/Kkt.php 100644
View File

@ -0,0 +1,591 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline\Api;
use AtolOnline\{
Constants\Constraints,
Entities\Company,
Entities\Document,
Exceptions\AuthFailedException,
Exceptions\EmptyCorrectionInfoException,
Exceptions\EmptyKktLoginException,
Exceptions\EmptyKktPasswordException,
Exceptions\InvalidCallbackUrlException,
Exceptions\InvalidDocumentTypeException,
Exceptions\InvalidInnLengthException,
Exceptions\InvalidUuidException,
Exceptions\TooLongCallbackUrlException,
Exceptions\TooLongKktLoginException,
Exceptions\TooLongKktPasswordException,
Exceptions\TooLongPaymentAddressException,
Exceptions\TooManyItemsException,
Exceptions\TooManyVatsException,
TestEnvParams};
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Ramsey\Uuid\Uuid;
/**
* Класс для отправки запросов на ККТ
*
* @package AtolOnline\Api
*/
class Kkt extends Client
{
/**
* @var bool Флаг тестового режима работы
*/
protected bool $is_test_mode = false;
/**
* @var array Настройки доступа к ККТ
*/
protected array $kkt_config = [];
/**
* @var KktResponse|null Последний ответ сервера АТОЛ
*/
protected ?KktResponse $last_response;
/**
* @var string|null Токен авторизации
*/
private ?string $auth_token;
/**
* Kkt constructor.
*
* @param string|null $group
* @param string|null $login
* @param string|null $pass
* @param bool $test_mode Флаг тестового режима
* @param array $guzzle_config Конфигурация GuzzleHttp
* @throws EmptyKktLoginException Логин ККТ не может быть пустым
* @throws TooLongKktLoginException Слишком длинный логин ККТ
* @throws EmptyKktPasswordException Пароль ККТ не может быть пустым
* @throws TooLongKktPasswordException Слишком длинный пароль ККТ
* @see https://guzzle.readthedocs.io/en/latest/request-options.html
*/
public function __construct(
?string $group = null,
?string $login = null,
?string $pass = null,
bool $test_mode = false,
array $guzzle_config = []
) {
$this->resetKktConfig();
if ($group) {
$this->setGroup($group);
}
if ($login) {
$this->setLogin($login);
}
if ($login) {
$this->setPassword($pass);
}
$this->setTestMode($test_mode);
$guzzle_config['base_uri'] = $this->getEndpoint();
$guzzle_config['http_errors'] = $guzzle_config['http_errors'] ?? false;
parent::__construct($guzzle_config);
}
/**
* Устанавливает группу доступа к ККТ
*
* @param string $group
* @return $this
*/
public function setGroup(string $group): Kkt
{
$this->kkt_config['prod']['group'] = $group;
return $this;
}
/**
* Возвращает группу доступа к ККТ в соответствии с флагом тестового режима
*
* @return string
*/
public function getGroup(): string
{
return $this->kkt_config[$this->isTestMode() ? 'test' : 'prod']['group'];
}
/**
* Устанавливает логин доступа к ККТ
*
* @param string $login
* @return $this
* @throws EmptyKktLoginException Логин ККТ не может быть пустым
* @throws TooLongKktLoginException Слишком длинный логин ККТ
*/
public function setLogin(string $login): Kkt
{
if (empty($login)) {
throw new EmptyKktLoginException();
} elseif (mb_strlen($login) > Constraints::MAX_LENGTH_LOGIN) {
throw new TooLongKktLoginException($login, Constraints::MAX_LENGTH_LOGIN);
}
$this->kkt_config['prod']['login'] = $login;
return $this;
}
/**
* Возвращает логин доступа к ККТ в соответствии с флагом тестового режима
*
* @return string
*/
public function getLogin(): string
{
return $this->kkt_config[$this->isTestMode() ? 'test' : 'prod']['login'];
}
/**
* Устанавливает пароль доступа к ККТ
*
* @param string $password
* @return $this
* @throws EmptyKktPasswordException Пароль ККТ не может быть пустым
* @throws TooLongKktPasswordException Слишком длинный пароль ККТ
*/
public function setPassword(string $password): Kkt
{
if (empty($password)) {
throw new EmptyKktPasswordException();
} elseif (mb_strlen($password) > Constraints::MAX_LENGTH_PASSWORD) {
throw new TooLongKktPasswordException($password, Constraints::MAX_LENGTH_PASSWORD);
}
$this->kkt_config['prod']['pass'] = $password;
return $this;
}
/**
* Возвращает логин ККТ в соответствии с флагом тестового режима
*
* @return string
*/
public function getPassword(): string
{
return $this->kkt_config[$this->isTestMode() ? 'test' : 'prod']['pass'];
}
/**
* Устанавливает URL для приёма колбеков
*
* @param string $url
* @return $this
* @throws TooLongCallbackUrlException Слишком длинный Callback URL
* @throws InvalidCallbackUrlException Невалидный Callback URL
*/
public function setCallbackUrl(string $url): Kkt
{
if (mb_strlen($url) > Constraints::MAX_LENGTH_CALLBACK_URL) {
throw new TooLongCallbackUrlException($url, Constraints::MAX_LENGTH_CALLBACK_URL);
} elseif (!preg_match(Constraints::PATTERN_CALLBACK_URL, $url)) {
throw new InvalidCallbackUrlException('Callback URL not matches with pattern');
}
$this->kkt_config[$this->isTestMode() ? 'test' : 'prod']['callback_url'] = $url;
return $this;
}
/**
* Возвращает URL для приёма колбеков
*
* @return string
*/
public function getCallbackUrl(): string
{
return $this->kkt_config[$this->isTestMode() ? 'test' : 'prod']['callback_url'];
}
/**
* Возвращает последний ответ сервера
*
* @return KktResponse|null
*/
public function getLastResponse(): ?KktResponse
{
return $this->last_response;
}
/**
* Возвращает флаг тестового режима
*
* @return bool
*/
public function isTestMode(): bool
{
return $this->is_test_mode;
}
/**
* Устанавливает флаг тестового режима
*
* @param bool $test_mode
* @return $this
*/
public function setTestMode(bool $test_mode = true): Kkt
{
$this->is_test_mode = $test_mode;
return $this;
}
/**
* Регистрирует документ прихода
*
* @param Document $document Объект документа
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
* @return KktResponse
* @throws AuthFailedException Ошибка авторизации
* @throws EmptyCorrectionInfoException В документе есть данные коррекции
* @throws InvalidInnLengthException Некорректная длина ИНН
* @throws TooLongPaymentAddressException Слишком длинный адрес места расчётов
* @throws InvalidDocumentTypeException Некорректный тип документа
* @throws GuzzleException
*/
public function sell(Document $document, ?string $external_id = null): KktResponse
{
if ($document->getCorrectionInfo()) {
throw new EmptyCorrectionInfoException('Некорректная операция над документом коррекции');
}
return $this->registerDocument('sell', 'receipt', $document, $external_id);
}
/**
* Регистрирует документ возврата прихода
*
* @param Document $document Объект документа
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
* @return KktResponse
* @throws AuthFailedException Ошибка авторизации
* @throws EmptyCorrectionInfoException В документе есть данные коррекции
* @throws InvalidInnLengthException Некорректная длина ИНН
* @throws TooLongPaymentAddressException Слишком длинный адрес места расчётов
* @throws TooManyVatsException Слишком много ставок НДС
* @throws InvalidDocumentTypeException Некорректный тип документа
* @throws GuzzleException
*/
public function sellRefund(Document $document, ?string $external_id = null): KktResponse
{
if ($document->getCorrectionInfo()) {
throw new EmptyCorrectionInfoException('Invalid operation on correction document');
}
return $this->registerDocument('sell_refund', 'receipt', $document->clearVats(), $external_id);
}
/**
* Регистрирует документ коррекции прихода
*
* @param Document $document Объект документа
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
* @return KktResponse
* @throws AuthFailedException Ошибка авторизации
* @throws EmptyCorrectionInfoException В документе отсутствуют данные коррекции
* @throws InvalidInnLengthException Некорректная длина ИНН
* @throws TooLongPaymentAddressException Слишком длинный адрес места расчётов
* @throws TooManyItemsException Слишком много предметов расчёта
* @throws InvalidDocumentTypeException Некорректный тип документа
* @throws GuzzleException
*/
public function sellCorrection(Document $document, ?string $external_id = null): KktResponse
{
if (!$document->getCorrectionInfo()) {
throw new EmptyCorrectionInfoException();
}
$document->setClient(null)->setItems([]);
return $this->registerDocument('sell_correction', 'correction', $document, $external_id);
}
/**
* Регистрирует документ расхода
*
* @param Document $document
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
* @return KktResponse
* @throws AuthFailedException Ошибка авторизации
* @throws EmptyCorrectionInfoException В документе есть данные коррекции
* @throws InvalidInnLengthException Некорректная длина ИНН
* @throws TooLongPaymentAddressException Слишком длинный адрес места расчётов
* @throws InvalidDocumentTypeException Некорректный тип документа
* @throws GuzzleException
*/
public function buy(Document $document, ?string $external_id = null): KktResponse
{
if ($document->getCorrectionInfo()) {
throw new EmptyCorrectionInfoException('Invalid operation on correction document');
}
return $this->registerDocument('buy', 'receipt', $document, $external_id);
}
/**
* Регистрирует документ возврата расхода
*
* @param Document $document
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
* @return KktResponse
* @throws AuthFailedException Ошибка авторизации
* @throws EmptyCorrectionInfoException В документе есть данные коррекции
* @throws InvalidInnLengthException Некорректная длина ИНН
* @throws TooLongPaymentAddressException Слишком длинный адрес места расчётов
* @throws TooManyVatsException Слишком много ставок НДС
* @throws InvalidDocumentTypeException Некорректный тип документа
* @throws GuzzleException
*/
public function buyRefund(Document $document, ?string $external_id = null): KktResponse
{
if ($document->getCorrectionInfo()) {
throw new EmptyCorrectionInfoException('Invalid operation on correction document');
}
return $this->registerDocument('buy_refund', 'receipt', $document->clearVats(), $external_id);
}
/**
* Регистрирует документ коррекции расхода
*
* @param Document $document
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
* @return KktResponse
* @throws AuthFailedException Ошибка авторизации
* @throws EmptyCorrectionInfoException В документе отсутствуют данные коррекции
* @throws InvalidInnLengthException Некорректная длтина ИНН
* @throws TooLongPaymentAddressException Слишком длинный адрес места расчётов
* @throws TooManyItemsException Слишком много предметов расчёта
* @throws InvalidDocumentTypeException Некорректный тип документа
* @throws GuzzleException
*/
public function buyCorrection(Document $document, ?string $external_id = null): KktResponse
{
if (!$document->getCorrectionInfo()) {
throw new EmptyCorrectionInfoException();
}
$document->setClient(null)->setItems([]);
return $this->registerDocument('buy_correction', 'correction', $document, $external_id);
}
/**
* Проверяет статус чека на ККТ один раз
*
* @param string $uuid UUID регистрации
* @return KktResponse
* @throws AuthFailedException Ошибка авторизации
* @throws InvalidUuidException Некорректный UUID документа
* @throws GuzzleException
*/
public function getDocumentStatus(string $uuid): KktResponse
{
$uuid = trim($uuid);
if (!Uuid::isValid($uuid)) {
throw new InvalidUuidException($uuid);
}
$this->auth();
return $this->sendAtolRequest('GET', 'report/' . $uuid);
}
/**
* Проверяет статус чека на ККТ нужное количество раз с указанным интервалом.
* Вернёт результат как только при очередной проверке сменится статус регистрации документа.
*
* @param string $uuid UUID регистрации
* @param int $retry_count Количество попыток
* @param int $timeout Таймаут в секундах между попытками
* @return KktResponse
* @throws AuthFailedException Ошибка авторизации
* @throws InvalidUuidException Некорректный UUID документа
* @throws GuzzleException
*/
public function pollDocumentStatus(string $uuid, int $retry_count = 5, int $timeout = 1): KktResponse
{
$try = 0;
do {
$response = $this->getDocumentStatus($uuid);
if ($response->isValid() && $response->getContent()->status == 'done') {
break;
} else {
sleep($timeout);
}
++$try;
} while ($try < $retry_count);
return $response;
}
/**
* Возвращает текущий токен авторизации
*
* @return string
*/
public function getAuthToken(): ?string
{
return $this->auth_token;
}
/**
* Устанавливает заранее известный токен авторизации
*
* @param string|null $auth_token
* @return $this
*/
public function setAuthToken(?string $auth_token): Kkt
{
$this->auth_token = $auth_token;
return $this;
}
/**
* Сбрасывает настройки ККТ по умолчанию
*/
protected function resetKktConfig(): void
{
$this->kkt_config['prod']['group'] = '';
$this->kkt_config['prod']['login'] = '';
$this->kkt_config['prod']['pass'] = '';
$this->kkt_config['prod']['url'] = 'https://online.atol.ru/possystem/v4';
$this->kkt_config['prod']['callback_url'] = '';
$this->kkt_config['test']['group'] = TestEnvParams::FFD105()['group'];
$this->kkt_config['test']['login'] = TestEnvParams::FFD105()['login'];
$this->kkt_config['test']['pass'] = TestEnvParams::FFD105()['password'];
$this->kkt_config['test']['url'] = 'https://testonline.atol.ru/possystem/v4';
$this->kkt_config['test']['callback_url'] = '';
}
/**
* Возвращает набор заголовков для HTTP-запроса
*
* @return array
*/
protected function getHeaders(): array
{
$headers['Content-type'] = 'application/json; charset=utf-8';
if ($this->getAuthToken()) {
$headers['Token'] = $this->getAuthToken();
}
return $headers;
}
/**
* Возвращает адрес сервера в соответствии с флагом тестового режима
*
* @return string
*/
protected function getEndpoint(): string
{
return $this->kkt_config[$this->isTestMode() ? 'test' : 'prod']['url'];
}
/**
* Возвращает полный URL до метода API
*
* @param string $to_method
* @param array|null $get_parameters
* @return string
*/
protected function makeUrl(string $to_method, array $get_parameters = null): string
{
$url = $this->getEndpoint() . ($this->getAuthToken() ? '/' . $this->getGroup() : '') . '/' . $to_method;
if ($get_parameters && is_array($get_parameters)) {
$url .= '?' . http_build_query($get_parameters);
}
return $url;
}
/**
* Делает запрос, возвращает декодированный ответ
*
* @param string $http_method Метод HTTP (GET, POST и пр)
* @param string $api_method Метод API
* @param mixed $data Данные для передачи
* @param array|null $options Параметры Guzzle
* @return KktResponse
* @throws GuzzleException
* @see https://guzzle.readthedocs.io/en/latest/request-options.html
*/
protected function sendAtolRequest(
string $http_method,
string $api_method,
$data = null,
array $options = null
): KktResponse {
$http_method = strtoupper($http_method);
$options['headers'] = $this->getHeaders();
$url = $http_method == 'GET'
? $this->makeUrl($api_method, $data)
: $this->makeUrl($api_method, ['token' => $this->getAuthToken()]);
if ($http_method != 'GET') {
$options['json'] = $data;
}
$response = $this->request($http_method, $url, $options);
return $this->last_response = new KktResponse($response);
}
/**
* Производит авторизацию на ККТ и получает токен доступа для дальнейших HTTP-запросов
*
* @return bool
* @throws AuthFailedException Ошибка авторизации
* @throws GuzzleException
*/
protected function auth(): bool
{
if (!$this->getAuthToken()) {
$result = $this->sendAtolRequest('GET', 'getToken', [
'login' => $this->getLogin(),
'pass' => $this->getPassword(),
]);
if (!$result->isValid() || !$result->getContent()->token) {
throw new AuthFailedException($result);
}
$this->auth_token = $result->getContent()->token;
}
return true;
}
/**
* Отправляет документ на регистрацию
*
* @param string $api_method Метод API
* @param string $type Тип документа: receipt, correction
* @param Document $document Объект документа
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
* @return KktResponse
* @throws AuthFailedException Ошибка авторизации
* @throws InvalidDocumentTypeException Некорректный тип документа
* @throws InvalidInnLengthException Некорректная длина ИНН
* @throws TooLongPaymentAddressException Слишком длинный адрес места расчётов
* @throws GuzzleException
* @throws Exception
*/
protected function registerDocument(
string $api_method,
string $type,
Document $document,
?string $external_id = null
): KktResponse {
$type = trim($type);
if (!in_array($type, ['receipt', 'correction'])) {
throw new InvalidDocumentTypeException($type);
}
$this->auth();
if ($this->isTestMode()) {
$document->setCompany(($document->getCompany() ?: new Company())
->setInn(TestEnvParams::FFD105()['inn'])
->setSno(TestEnvParams::FFD105()['sno'])
->setPaymentAddress(TestEnvParams::FFD105()['payment_address']));
}
$data['timestamp'] = date('d.m.y H:i:s');
$data['external_id'] = $external_id ?: Uuid::uuid4()->toString();
$data[$type] = $document;
if ($this->getCallbackUrl()) {
$data['service'] = ['callback_url' => $this->getCallbackUrl()];
}
return $this->sendAtolRequest('POST', trim($api_method), $data);
}
}

View File

@ -1,12 +1,14 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Api; namespace AtolOnline\Api;
use JsonSerializable; use JsonSerializable;
@ -16,6 +18,7 @@ use stdClass;
/** /**
* Класс AtolResponse, описывающий ответ от ККТ * Класс AtolResponse, описывающий ответ от ККТ
* *
* @property mixed $error
* @package AtolOnline\Api * @package AtolOnline\Api
*/ */
class KktResponse implements JsonSerializable class KktResponse implements JsonSerializable
@ -23,28 +26,28 @@ class KktResponse implements JsonSerializable
/** /**
* @var int Код ответа сервера * @var int Код ответа сервера
*/ */
protected $code; protected int $code;
/** /**
* @var \stdClass Содержимое ответа сервера * @var stdClass Содержимое ответа сервера
*/ */
protected $content; protected $content;
/** /**
* @var array Заголовки ответа * @var array Заголовки ответа
*/ */
protected $headers; protected array $headers;
/** /**
* AtolResponse constructor. * AtolResponse constructor.
* *
* @param \Psr\Http\Message\ResponseInterface $response * @param ResponseInterface $response
*/ */
public function __construct(ResponseInterface $response) public function __construct(ResponseInterface $response)
{ {
$this->code = $response->getStatusCode(); $this->code = $response->getStatusCode();
$this->headers = $response->getHeaders(); $this->headers = $response->getHeaders();
$this->content = json_decode($response->getBody()); $this->content = json_decode((string)$response->getBody());
} }
/** /**
@ -93,12 +96,12 @@ class KktResponse implements JsonSerializable
* *
* @return bool * @return bool
*/ */
public function isValid() public function isValid(): bool
{ {
return !empty($this->getCode()) return !empty($this->getCode())
&& !empty($this->getContent()) && !empty($this->getContent())
&& empty($this->getContent()->error) && empty($this->getContent()->error)
&& (int)$this->getCode() < 400; && $this->getCode() < 400;
} }
/** /**

View File

@ -1,576 +0,0 @@
<?php
/**
* Copyright (c) Антон Аксенов (aka Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Api;
use AtolOnline\{Constants\Constraints,
Constants\TestEnvParams,
Entities\Company,
Entities\Document,
Exceptions\AtolAuthFailedException,
Exceptions\AtolCallbackUrlTooLongException,
Exceptions\AtolCorrectionInfoException,
Exceptions\AtolInvalidCallbackUrlException,
Exceptions\AtolInvalidUuidException,
Exceptions\AtolKktLoginEmptyException,
Exceptions\AtolKktLoginTooLongException,
Exceptions\AtolKktPasswordEmptyException,
Exceptions\AtolKktPasswordTooLongException,
Exceptions\AtolWrongDocumentTypeException
};
use GuzzleHttp\Client;
use Ramsey\Uuid\Uuid;
/**
* Класс для отправки запросов на ККТ
*
* @package AtolOnline\Api
*/
class Kkt extends Client
{
/**
* @var bool Флаг тестового режима работы
*/
protected $is_test_mode = false;
/**
* @var array Настройки доступа к ККТ
*/
protected $kkt_config = [];
/**
* @var \AtolOnline\Api\KktResponse|null Последний ответ сервера АТОЛ
*/
protected $last_response;
/**
* @var string|null Токен авторизации
*/
private $auth_token;
/**
* Kkt constructor.
*
* @param string|null $group
* @param string|null $login
* @param string|null $pass
* @param bool $test_mode Флаг тестового режима
* @param array $guzzle_config Конфигурация GuzzleHttp
* @throws \AtolOnline\Exceptions\AtolKktLoginEmptyException Логин ККТ не может быть пустым
* @throws \AtolOnline\Exceptions\AtolKktLoginTooLongException Слишком длинный логин ККТ
* @throws \AtolOnline\Exceptions\AtolKktPasswordEmptyException Пароль ККТ не может быть пустым
* @throws \AtolOnline\Exceptions\AtolKktPasswordTooLongException Слишком длинный пароль ККТ
* @see https://guzzle.readthedocs.io/en/latest/request-options.html
*/
public function __construct(
?string $group = null,
?string $login = null,
?string $pass = null,
bool $test_mode = false,
array $guzzle_config = []
) {
$this->resetKktConfig();
if ($group) {
$this->setGroup($group);
}
if ($login) {
$this->setLogin($login);
}
if ($login) {
$this->setPassword($pass);
}
$this->setTestMode($test_mode);
$guzzle_config['base_uri'] = $this->getEndpoint();
$guzzle_config['http_errors'] = $guzzle_config['http_errors'] ?? false;
parent::__construct($guzzle_config);
}
/**
* Устанавливает группу доступа к ККТ
*
* @param string $group
* @return $this
*/
public function setGroup(string $group)
{
$this->kkt_config['prod']['group'] = $group;
return $this;
}
/**
* Возвращает группу доступа к ККТ в соответствии с флагом тестового режима
*
* @return string
*/
public function getGroup(): string
{
return $this->kkt_config[$this->isTestMode() ? 'test' : 'prod']['group'];
}
/**
* Устанавливает логин доступа к ККТ
*
* @param string $login
* @return $this
* @throws \AtolOnline\Exceptions\AtolKktLoginEmptyException Логин ККТ не может быть пустым
* @throws \AtolOnline\Exceptions\AtolKktLoginTooLongException Слишком длинный логин ККТ
*/
public function setLogin(string $login)
{
if (empty($login)) {
throw new AtolKktLoginEmptyException();
} elseif (valid_strlen($login) > Constraints::MAX_LENGTH_LOGIN) {
throw new AtolKktLoginTooLongException($login, Constraints::MAX_LENGTH_LOGIN);
}
$this->kkt_config['prod']['login'] = $login;
return $this;
}
/**
* Возвращает логин доступа к ККТ в соответствии с флагом тестового режима
*
* @return string
*/
public function getLogin(): string
{
return $this->kkt_config[$this->isTestMode() ? 'test' : 'prod']['login'];
}
/**
* Устанавливает пароль доступа к ККТ
*
* @param string $password
* @return $this
* @throws \AtolOnline\Exceptions\AtolKktPasswordEmptyException Пароль ККТ не может быть пустым
* @throws \AtolOnline\Exceptions\AtolKktPasswordTooLongException Слишком длинный пароль ККТ
*/
public function setPassword(string $password)
{
if (empty($password)) {
throw new AtolKktPasswordEmptyException();
} elseif (valid_strlen($password) > Constraints::MAX_LENGTH_PASSWORD) {
throw new AtolKktPasswordTooLongException($password, Constraints::MAX_LENGTH_PASSWORD);
}
$this->kkt_config['prod']['pass'] = $password;
return $this;
}
/**
* Возвращает логин ККТ в соответствии с флагом тестового режима
*
* @return string
*/
public function getPassword(): string
{
return $this->kkt_config[$this->isTestMode() ? 'test' : 'prod']['pass'];
}
/**
* Устанавливает URL для приёма колбеков
*
* @param string $url
* @return $this
* @throws \AtolOnline\Exceptions\AtolCallbackUrlTooLongException Слишком длинный Callback URL
* @throws \AtolOnline\Exceptions\AtolInvalidCallbackUrlException Невалидный Callback URL
*/
public function setCallbackUrl(string $url)
{
if (valid_strlen($url) > Constraints::MAX_LENGTH_CALLBACK_URL) {
throw new AtolCallbackUrlTooLongException($url, Constraints::MAX_LENGTH_CALLBACK_URL);
} elseif (!preg_match(Constraints::PATTERN_CALLBACK_URL, $url)) {
throw new AtolInvalidCallbackUrlException('Callback URL not matches with pattern');
}
$this->kkt_config[$this->isTestMode() ? 'test' : 'prod']['callback_url'] = $url;
return $this;
}
/**
* Возвращает URL для приёма колбеков
*
* @return string
*/
public function getCallbackUrl(): string
{
return $this->kkt_config[$this->isTestMode() ? 'test' : 'prod']['callback_url'];
}
/**
* Возвращает последний ответ сервера
*
* @return mixed
*/
public function getLastResponse()
{
return $this->last_response;
}
/**
* Возвращает флаг тестового режима
*
* @return bool
*/
public function isTestMode(): bool
{
return $this->is_test_mode;
}
/**
* Устанавливает флаг тестового режима
*
* @param bool $test_mode
* @return $this
*/
public function setTestMode(bool $test_mode = true)
{
$this->is_test_mode = $test_mode;
return $this;
}
/**
* Регистрирует документ прихода
*
* @param \AtolOnline\Entities\Document $document Объект документа
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
* @return \AtolOnline\Api\KktResponse
* @throws \AtolOnline\Exceptions\AtolAuthFailedException Ошибка авторизации
* @throws \AtolOnline\Exceptions\AtolCorrectionInfoException В документе есть данные коррекции
* @throws \AtolOnline\Exceptions\AtolInnWrongLengthException Некорректная длина ИНН
* @throws \AtolOnline\Exceptions\AtolPaymentAddressTooLongException Слишком длинный адрес места расчётов
* @throws \AtolOnline\Exceptions\AtolWrongDocumentTypeException Некорректный тип документа
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function sell(Document $document, ?string $external_id = null)
{
if ($document->getCorrectionInfo()) {
throw new AtolCorrectionInfoException('Некорректная операция над документом коррекции');
}
return $this->registerDocument('sell', 'receipt', $document, $external_id);
}
/**
* Регистрирует документ возврата прихода
*
* @param \AtolOnline\Entities\Document $document Объект документа
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
* @return \AtolOnline\Api\KktResponse
* @throws \AtolOnline\Exceptions\AtolAuthFailedException Ошибка авторизации
* @throws \AtolOnline\Exceptions\AtolCorrectionInfoException В документе есть данные коррекции
* @throws \AtolOnline\Exceptions\AtolInnWrongLengthException Некорректная длина ИНН
* @throws \AtolOnline\Exceptions\AtolPaymentAddressTooLongException Слишком длинный адрес места расчётов
* @throws \AtolOnline\Exceptions\AtolPriceTooHighException Слишком большая сумма
* @throws \AtolOnline\Exceptions\AtolTooManyVatsException Слишком много ставок НДС
* @throws \AtolOnline\Exceptions\AtolWrongDocumentTypeException Некорректный тип документа
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function sellRefund(Document $document, ?string $external_id = null)
{
if ($document->getCorrectionInfo()) {
throw new AtolCorrectionInfoException('Invalid operation on correction document');
}
return $this->registerDocument('sell_refund', 'receipt', $document->clearVats(), $external_id);
}
/**
* Регистрирует документ коррекции прихода
*
* @param \AtolOnline\Entities\Document $document Объект документа
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
* @return \AtolOnline\Api\KktResponse
* @throws \AtolOnline\Exceptions\AtolAuthFailedException Ошибка авторизации
* @throws \AtolOnline\Exceptions\AtolCorrectionInfoException В документе отсутствуют данные коррекции
* @throws \AtolOnline\Exceptions\AtolInnWrongLengthException Некорректная длина ИНН
* @throws \AtolOnline\Exceptions\AtolPaymentAddressTooLongException Слишком длинный адрес места расчётов
* @throws \AtolOnline\Exceptions\AtolTooManyItemsException Слишком много предметов расчёта
* @throws \AtolOnline\Exceptions\AtolWrongDocumentTypeException Некорректный тип документа
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function sellCorrection(Document $document, ?string $external_id = null)
{
if (!$document->getCorrectionInfo()) {
throw new AtolCorrectionInfoException();
}
$document->setClient(null)->setItems([]);
return $this->registerDocument('sell_correction', 'correction', $document, $external_id);
}
/**
* Регистрирует документ расхода
*
* @param \AtolOnline\Entities\Document $document
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
* @return \AtolOnline\Api\KktResponse
* @throws \AtolOnline\Exceptions\AtolAuthFailedException Ошибка авторизации
* @throws \AtolOnline\Exceptions\AtolCorrectionInfoException В документе есть данные коррекции
* @throws \AtolOnline\Exceptions\AtolInnWrongLengthException Некорректная длина ИНН
* @throws \AtolOnline\Exceptions\AtolPaymentAddressTooLongException Слишком длинный адрес места расчётов
* @throws \AtolOnline\Exceptions\AtolWrongDocumentTypeException Некорректный тип документа
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function buy(Document $document, ?string $external_id = null)
{
if ($document->getCorrectionInfo()) {
throw new AtolCorrectionInfoException('Invalid operation on correction document');
}
return $this->registerDocument('buy', 'receipt', $document, $external_id);
}
/**
* Регистрирует документ возврата расхода
*
* @param \AtolOnline\Entities\Document $document
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
* @return \AtolOnline\Api\KktResponse
* @throws \AtolOnline\Exceptions\AtolAuthFailedException Ошибка авторизации
* @throws \AtolOnline\Exceptions\AtolCorrectionInfoException В документе есть данные коррекции
* @throws \AtolOnline\Exceptions\AtolInnWrongLengthException Некорректная длина ИНН
* @throws \AtolOnline\Exceptions\AtolPaymentAddressTooLongException Слишком длинный адрес места расчётов
* @throws \AtolOnline\Exceptions\AtolPriceTooHighException Слишком большая сумма
* @throws \AtolOnline\Exceptions\AtolTooManyVatsException Слишком много ставок НДС
* @throws \AtolOnline\Exceptions\AtolWrongDocumentTypeException Некорректный тип документа
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function buyRefund(Document $document, ?string $external_id = null)
{
if ($document->getCorrectionInfo()) {
throw new AtolCorrectionInfoException('Invalid operation on correction document');
}
return $this->registerDocument('buy_refund', 'receipt', $document->clearVats(), $external_id);
}
/**
* Регистрирует документ коррекции расхода
*
* @param \AtolOnline\Entities\Document $document
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
* @return \AtolOnline\Api\KktResponse
* @throws \AtolOnline\Exceptions\AtolAuthFailedException Ошибка авторизации
* @throws \AtolOnline\Exceptions\AtolCorrectionInfoException В документе отсутствуют данные коррекции
* @throws \AtolOnline\Exceptions\AtolInnWrongLengthException Некорректная длтина ИНН
* @throws \AtolOnline\Exceptions\AtolPaymentAddressTooLongException Слишком длинный адрес места расчётов
* @throws \AtolOnline\Exceptions\AtolTooManyItemsException Слишком много предметов расчёта
* @throws \AtolOnline\Exceptions\AtolWrongDocumentTypeException Некорректный тип документа
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function buyCorrection(Document $document, ?string $external_id = null)
{
if (!$document->getCorrectionInfo()) {
throw new AtolCorrectionInfoException();
}
$document->setClient(null)->setItems([]);
return $this->registerDocument('buy_correction', 'correction', $document, $external_id);
}
/**
* Проверяет статус чека на ККТ один раз
*
* @param string $uuid UUID регистрации
* @return \AtolOnline\Api\KktResponse
* @throws \AtolOnline\Exceptions\AtolAuthFailedException Ошибка авторизации
* @throws \AtolOnline\Exceptions\AtolInvalidUuidException Некорректный UUID документа
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function getDocumentStatus(string $uuid)
{
$uuid = trim($uuid);
if (!Uuid::isValid($uuid)) {
throw new AtolInvalidUuidException($uuid);
}
$this->auth();
return $this->sendAtolRequest('GET', 'report/'.$uuid);
}
/**
* Проверяет статус чека на ККТ нужное количество раз с указанным интервалом.
* Вернёт результат как только при очередной проверке сменится статус регистрации документа.
*
* @param string $uuid UUID регистрации
* @param int $retry_count Количество попыток
* @param int $timeout Таймаут в секундах между попытками
* @return \AtolOnline\Api\KktResponse
* @throws \AtolOnline\Exceptions\AtolAuthFailedException Ошибка авторизации
* @throws \AtolOnline\Exceptions\AtolInvalidUuidException Некорректный UUID документа
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function pollDocumentStatus(string $uuid, int $retry_count = 5, int $timeout = 1)
{
$try = 0;
do {
$response = $this->getDocumentStatus($uuid);
if ($response->isValid() && $response->getContent()->status == 'done') {
break;
} else {
sleep($timeout);
}
++$try;
} while ($try < $retry_count);
return $response;
}
/**
* Возвращает текущий токен авторизации
*
* @return string
*/
public function getAuthToken(): ?string
{
return $this->auth_token;
}
/**
* Устанавливает заранее известный токен авторизации
*
* @param string|null $auth_token
* @return $this
*/
public function setAuthToken(?string $auth_token)
{
$this->auth_token = $auth_token;
return $this;
}
/**
* Сбрасывает настройки ККТ по умолчанию
*/
protected function resetKktConfig(): void
{
$this->kkt_config['prod']['group'] = '';
$this->kkt_config['prod']['login'] = '';
$this->kkt_config['prod']['pass'] = '';
$this->kkt_config['prod']['url'] = 'https://online.atol.ru/possystem/v4';
$this->kkt_config['prod']['callback_url'] = '';
$this->kkt_config['test']['group'] = TestEnvParams::GROUP;
$this->kkt_config['test']['login'] = TestEnvParams::LOGIN;
$this->kkt_config['test']['pass'] = TestEnvParams::PASSWORD;
$this->kkt_config['test']['url'] = 'https://testonline.atol.ru/possystem/v4';
$this->kkt_config['test']['callback_url'] = '';
}
/**
* Возвращает набор заголовков для HTTP-запроса
*
* @return array
*/
protected function getHeaders()
{
$headers['Content-type'] = 'application/json; charset=utf-8';
if ($this->getAuthToken()) {
$headers['Token'] = $this->getAuthToken();
}
return $headers;
}
/**
* Возвращает адрес сервера в соответствии с флагом тестового режима
*
* @return string
*/
protected function getEndpoint(): string
{
return $this->kkt_config[$this->isTestMode() ? 'test' : 'prod']['url'];
}
/**
* Возвращает полный URL до метода API
*
* @param string $to_method
* @param array|null $get_parameters
* @return string
*/
protected function makeUrl(string $to_method, array $get_parameters = null)
{
$url = $this->getEndpoint().($this->getAuthToken() ? '/'.$this->getGroup() : '').'/'.$to_method;
if ($get_parameters && is_array($get_parameters)) {
$url .= '?'.http_build_query($get_parameters);
}
return $url;
}
/**
* Делает запрос, возвращает декодированный ответ
*
* @param string $http_method Метод HTTP (GET, POST и пр)
* @param string $api_method Метод API
* @param mixed $data Данные для передачи
* @param array|null $options Параметры Guzzle
* @return \AtolOnline\Api\KktResponse
* @throws \GuzzleHttp\Exception\GuzzleException
* @see https://guzzle.readthedocs.io/en/latest/request-options.html
*/
protected function sendAtolRequest(string $http_method, string $api_method, $data = null, array $options = null)
{
$http_method = strtoupper($http_method);
$options['headers'] = $this->getHeaders();
$url = $http_method == 'GET'
? $this->makeUrl($api_method, $data)
: $this->makeUrl($api_method, ['token' => $this->getAuthToken()]);
if ($http_method != 'GET') {
$options['json'] = $data;
}
$response = $this->request($http_method, $url, $options);
return $this->last_response = new KktResponse($response);
}
/**
* Производит авторизацию на ККТ и получает токен доступа для дальнейших HTTP-запросов
*
* @return bool
* @throws \AtolOnline\Exceptions\AtolAuthFailedException Ошибка авторизации
* @throws \GuzzleHttp\Exception\GuzzleException
*/
protected function auth()
{
if (!$this->getAuthToken()) {
$result = $this->sendAtolRequest('GET', 'getToken', [
'login' => $this->getLogin(),
'pass' => $this->getPassword(),
]);
if (!$result->isValid() || !$result->getContent()->token) {
throw new AtolAuthFailedException($result);
}
$this->auth_token = $result->getContent()->token;
}
return true;
}
/**
* Отправляет документ на регистрацию
*
* @param string $api_method Метод API
* @param string $type Тип документа: receipt, correction
* @param \AtolOnline\Entities\Document $document Объект документа
* @param string|null $external_id Уникальный код документа (если не указан, то будет создан UUID)
* @return \AtolOnline\Api\KktResponse
* @throws \AtolOnline\Exceptions\AtolAuthFailedException Ошибка авторизации
* @throws \AtolOnline\Exceptions\AtolWrongDocumentTypeException Некорректный тип документа
* @throws \AtolOnline\Exceptions\AtolInnWrongLengthException Некорректная длина ИНН
* @throws \AtolOnline\Exceptions\AtolPaymentAddressTooLongException Слишком длинный адрес места расчётов
* @throws \GuzzleHttp\Exception\GuzzleException
*/
protected function registerDocument(string $api_method, string $type, Document $document, ?string $external_id = null)
{
$type = trim($type);
if (!in_array($type, ['receipt', 'correction'])) {
throw new AtolWrongDocumentTypeException($type);
}
$this->auth();
if ($this->isTestMode()) {
$document->setCompany(($document->getCompany() ?: new Company())
->setInn(TestEnvParams::INN)
->setSno(TestEnvParams::SNO)
->setPaymentAddress(TestEnvParams::PAYMENT_ADDRESS));
}
$data['timestamp'] = date('d.m.y H:i:s');
$data['external_id'] = $external_id ?: Uuid::uuid4()->toString();
$data[$type] = $document;
if ($this->getCallbackUrl()) {
$data['service'] = ['callback_url' => $this->getCallbackUrl()];
}
return $this->sendAtolRequest('POST', trim($api_method), $data);
}
}

View File

@ -1,53 +0,0 @@
<?php
/**
* Copyright (c) Антон Аксенов (aka Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Constants;
/**
* Константы, определяющие виды оплат. Тег ФФД - 1031, 1081, 1215, 1216, 1217.
*
* @package AtolOnline\Constants
*/
class PaymentTypes
{
/**
* Расчёт наличными. Тег ФФД - 1031.
*/
const CASH = 0;
/**
* Расчёт безналичными. Тег ФФД - 1081.
*/
const ELECTRON = 1;
/**
* Предварительная оплата (зачет аванса). Тег ФФД - 1215.
*/
const PRE_PAID = 2;
/**
* Предварительная оплата (кредит). Тег ФФД - 1216.
*/
const CREDIT = 3;
/**
* Иная форма оплаты (встречное предоставление). Тег ФФД - 1217.
*/
const OTHER = 4;
/**
* Расширенный типы оплаты
* Для каждого фискального типа оплаты можно указать расширенный тип оплаты
*/
const ADD_5 = 5;
const ADD_6 = 6;
const ADD_7 = 7;
const ADD_8 = 8;
const ADD_9 = 9;
}

View File

@ -1,49 +0,0 @@
<?php
/**
* Copyright (c) Антон Аксенов (aka Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Constants;
/**
* Константы, определяющие параметры тестовой среды
*
* @see https://online.atol.ru/files/ffd/test_sreda.txt
* @package AtolOnline\Constants
*/
class TestEnvParams
{
/**
* Логин
*/
const LOGIN = 'v4-online-atol-ru';
/**
* Пароль
*/
const PASSWORD = 'iGFFuihss';
/**
* Группа
*/
const GROUP = 'v4-online-atol-ru_4179';
/**
* Система налогообложения
*/
const SNO = SnoTypes::OSN;
/**
* ИНН
*/
const INN = '5544332219';
/**
* Адрес места расчётов
*/
const PAYMENT_ADDRESS = 'https://v4.online.atol.ru';
}

View File

@ -1,149 +0,0 @@
<?php
/**
* Copyright (c) Антон Аксенов (aka Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Entities;
use AtolOnline\{Constants\Constraints, Exceptions\AtolNameTooLongException, Exceptions\AtolPhoneTooLongException, Traits\HasEmail, Traits\HasInn};
/**
* Класс Client, описывающий сущность покупателя
*
* @package AtolOnline\Entities
*/
class Client extends Entity
{
use
/**
* Покупатель может иметь почту. Тег ФФД - 1008.
*/
HasEmail,
/**
* Покупатель может иметь ИНН. Тег ФФД - 1228.
*/
HasInn;
/**
* @var string Телефон покупателя. Тег ФФД - 1008.
*/
protected $phone;
/**
* @var string Имя покупателя. Тег ФФД - 1227.
*/
protected $name;
/**
* Client constructor.
*
* @param string|null $name Наименование
* @param string|null $phone Телефон
* @param string|null $email Email
* @param string|null $inn ИНН
* @throws \AtolOnline\Exceptions\AtolEmailTooLongException Слишком длинный email
* @throws \AtolOnline\Exceptions\AtolEmailValidateException Невалидный email
* @throws \AtolOnline\Exceptions\AtolInnWrongLengthException Некорректная длина ИНН
* @throws \AtolOnline\Exceptions\AtolNameTooLongException Слишком длинное имя
* @throws \AtolOnline\Exceptions\AtolPhoneTooLongException СЛишком длинный номер телефона
*/
public function __construct(?string $name = null, ?string $phone = null, ?string $email = null, ?string $inn = null)
{
if ($name) {
$this->setName($name);
}
if ($email) {
$this->setEmail($email);
}
if ($phone) {
$this->setPhone($phone);
}
if ($inn) {
$this->setInn($inn);
}
}
/**
* Возвращает имя покупателя. Тег ФФД - 1227.
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Устанавливает имя покупателя
* Тег ФФД - 1227.
*
* @param string $name
* @return $this
* @throws AtolNameTooLongException
*/
public function setName(string $name)
{
$name = trim($name);
if (valid_strlen($name) > Constraints::MAX_LENGTH_CLIENT_NAME) {
throw new AtolNameTooLongException($name, Constraints::MAX_LENGTH_CLIENT_NAME);
}
$this->name = $name;
return $this;
}
/**
* Возвращает телефон покупателя.
* Тег ФФД - 1008.
*
* @return string
*/
public function getPhone()
{
return $this->phone ?? '';
}
/**
* Устанавливает телефон покупателя.
* Тег ФФД - 1008.
* Входная строка лишается всех знаков, кроме цифр и знака '+'.
*
* @param string $phone
* @return $this
* @throws AtolPhoneTooLongException
*/
public function setPhone(string $phone)
{
$phone = preg_replace("/[^0-9+]/", '', $phone);
if (valid_strlen($phone) > Constraints::MAX_LENGTH_CLIENT_PHONE) {
throw new AtolPhoneTooLongException($phone, Constraints::MAX_LENGTH_CLIENT_PHONE);
}
$this->phone = $phone;
return $this;
}
/**
* @inheritDoc
*/
public function jsonSerialize()
{
$json = [];
if ($this->getName()) {
$json['name'] = $this->getName() ?? '';
}
if ($this->getEmail()) {
$json['email'] = $this->getEmail() ?? '';
}
if ($this->getPhone()) {
$json['phone'] = $this->getPhone() ?? '';
}
if ($this->getInn()) {
$json['inn'] = $this->getInn() ?? '';
}
return $json;
}
}

View File

@ -1,138 +0,0 @@
<?php
/**
* Copyright (c) Антон Аксенов (aka Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Entities;
use AtolOnline\{Constants\Constraints,
Exceptions\AtolEmailTooLongException,
Exceptions\AtolEmailValidateException,
Exceptions\AtolInnWrongLengthException,
Exceptions\AtolPaymentAddressTooLongException,
Traits\HasEmail,
Traits\HasInn
};
/**
* Класс, описывающий сущность компании-продавца
*
* @package AtolOnline\Entities
*/
class Company extends Entity
{
use
/**
* Продавец должен иметь почту. Тег ФФД - 1117.
*/
HasEmail,
/**
* Продавец должен иметь ИНН. Тег ФФД - 1018.
*/
HasInn;
/**
* @var string Система налогообложения продавца. Тег ФФД - 1055.
*/
protected $sno;
/**
* @var string Место расчётов (адрес интернет-магазина). Тег ФФД - 1187.
*/
protected $payment_address;
/**
* Company constructor.
*
* @param string|null $sno
* @param string|null $inn
* @param string|null $paymentAddress
* @param string|null $email
* @throws AtolEmailTooLongException Слишком длинный email
* @throws AtolEmailValidateException Невалидный email
* @throws AtolInnWrongLengthException Некорректная длина ИНН
* @throws AtolPaymentAddressTooLongException Слишком длинный адрес места расчётов
*/
public function __construct(string $sno = null, string $inn = null, string $paymentAddress = null, string $email = null)
{
if ($sno) {
$this->setSno($sno);
}
if ($inn) {
$this->setInn($inn);
}
if ($paymentAddress) {
$this->setPaymentAddress($paymentAddress);
}
if ($email) {
$this->setEmail($email);
}
}
/**
* Возвращает установленный тип налогообложения. Тег ФФД - 1055.
*
* @return string
*/
public function getSno()
{
return $this->sno;
}
/**
* Устанавливает тип налогообложения. Тег ФФД - 1055.
*
* @param string $sno
* @return $this
*/
public function setSno(string $sno)
{
$this->sno = trim($sno);
return $this;
}
/**
* Возвращает установленный адрес места расчётов. Тег ФФД - 1187.
*
* @return string
*/
public function getPaymentAddress()
{
return $this->payment_address;
}
/**
* Устанавливает адрес места расчётов. Тег ФФД - 1187.
*
* @param string $payment_address
* @return $this
* @throws AtolPaymentAddressTooLongException Слишком длинный адрес места расчётов
*/
public function setPaymentAddress(string $payment_address)
{
$payment_address = trim($payment_address);
if (valid_strlen($payment_address) > Constraints::MAX_LENGTH_PAYMENT_ADDRESS) {
throw new AtolPaymentAddressTooLongException($payment_address, Constraints::MAX_LENGTH_PAYMENT_ADDRESS);
}
$this->payment_address = $payment_address;
return $this;
}
/**
* @inheritDoc
*/
public function jsonSerialize()
{
return [
'email' => $this->getEmail(),
'sno' => $this->getSno(),
'inn' => $this->getInn(),
'payment_address' => $this->getPaymentAddress(),
];
}
}

View File

@ -1,41 +0,0 @@
<?php
/**
* Copyright (c) Антон Аксенов (aka Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Exceptions;
use Throwable;
/**
* Исключение, возникающее при ошибке валидации email
*
* @package AtolOnline\Exceptions
*/
class AtolEmailValidateException extends AtolException
{
/**
* @inheritDoc
*/
protected $ffd_tags = [
1008,
1117,
];
/**
* AtolEmailValidateException constructor.
*
* @param $email
* @param string $message
* @param int $code
* @param \Throwable|null $previous
*/
public function __construct($email, $message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message ?: 'Invalid email: '.$email, $code, $previous);
}
}

View File

@ -1,44 +0,0 @@
<?php
/**
* Copyright (c) Антон Аксенов (aka Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Exceptions;
use Throwable;
/**
* Исключение, возникающее при попытке указать ИНН некорректной длины
*
* @package AtolOnline\Exceptions
*/
class AtolInnWrongLengthException extends AtolException
{
/**
* @inheritDoc
*/
protected $ffd_tags = [
1016,
1018,
1226,
1228,
];
/**
* AtolInnWrongLengthException constructor.
*
* @param $inn
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct($inn, $message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message ?: 'INN length must be 10 or 12 digits only, but actual is '.
valid_strlen($inn), $code, $previous);
}
}

View File

@ -1,33 +0,0 @@
<?php
/**
* Copyright (c) Антон Аксенов (aka Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Exceptions;
use Throwable;
/**
* Исключение, возникающее при попытке указать некорректный тип документа
*
* @package AtolOnline\Exceptions
*/
class AtolWrongDocumentTypeException extends AtolException
{
/**
* AtolWrongDocumentTypeException constructor.
*
* @param $type
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct($type, $message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message ?: "Wrong document type: 'receipt' or 'correction' expected, but '$type' provided", $code, $previous);
}
}

View File

@ -1,55 +0,0 @@
<?php
/**
* Copyright (c) Антон Аксенов (aka Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Traits;
use AtolOnline\{Constants\Constraints, Exceptions\AtolEmailTooLongException, Exceptions\AtolEmailValidateException};
/**
* Добавляет объекту функционал для работы с email
*
* @package AtolOnline\Traits
*/
trait HasEmail
{
/**
* @var string Почта
*/
protected $email;
/**
* Возвращает установленную почту. Тег ФФД: 1008, 1117.
*
* @return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Устанавливает почту. Тег ФФД: 1008, 1117.
*
* @param string $email
* @return $this
* @throws \AtolOnline\Exceptions\AtolEmailTooLongException Слишком длинный email
* @throws \AtolOnline\Exceptions\AtolEmailValidateException Невалидный email
*/
public function setEmail(string $email)
{
$email = trim($email);
if (valid_strlen($email) > Constraints::MAX_LENGTH_EMAIL) {
throw new AtolEmailTooLongException($email, Constraints::MAX_LENGTH_EMAIL);
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new AtolEmailValidateException($email);
}
$this->email = $email;
return $this;
}
}

View File

@ -1,54 +0,0 @@
<?php
/**
* Copyright (c) Антон Аксенов (aka Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Traits;
use AtolOnline\Constants\Constraints;
use AtolOnline\Exceptions\AtolInnWrongLengthException;
/**
* Добавляет объекту функционал для работы с ИНН
*
* @package AtolOnline\Traits
*/
trait HasInn
{
/**
* @var string ИНН
*/
protected $inn;
/**
* Возвращает установленный ИНН. Тег ФФД: 1228, 1018.
*
* @return string
*/
public function getInn()
{
return $this->inn ?? '';
}
/**
* Устанавливает ИНН. Тег ФФД: 1228, 1018.
* Входная строка лишается всех знаков, кроме цифр.
*
* @param string $inn
* @return $this
* @throws AtolInnWrongLengthException Некорректная длина ИНН
*/
public function setInn(string $inn)
{
$inn = preg_replace("/[^0-9]/", '', $inn);
if (preg_match_all(Constraints::PATTERN_INN, $inn) == 0) {
throw new AtolInnWrongLengthException($inn);
}
$this->inn = $inn;
return $this;
}
}

View File

@ -1,40 +0,0 @@
<?php
/**
* Copyright (c) Антон Аксенов (aka Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Traits;
/**
* Свойство класса, позволяющее конвертировать рубли <-> копейки
*
* @package AtolOnline\Traits
*/
trait RublesKopeksConverter
{
/**
* Конвертирует рубли в копейки, учитывая только 2 знака после запятой
*
* @param float|null $rubles Рубли
* @return int Копейки
*/
protected static function toKop(?float $rubles = null)
{
return $rubles === null ? null : (int)round($rubles * 100, 2);
}
/**
* Конвертирует копейки в рубли, оставляя только 2 знака после запятой
*
* @param int|null $kopeks Копейки
* @return float Рубли
*/
protected static function toRub(?int $kopeks = null)
{
return $kopeks === null ? null : round($kopeks / 100, 2);
}
}

View File

@ -1,19 +1,26 @@
<?php <?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline\Constants; namespace AtolOnline\Constants;
/** /**
* Класс с константами ограничений: максимальные длины, правила валидации значений * Класс с константами ограничений
*
* @package AtolOnline\Constants
*/ */
class Constraints final class Constraints
{ {
/** /**
* Максимальная длина Callback URL * Максимальная длина Callback URL
*/ */
const MAX_LENGTH_CALLBACK_URL = 256; const MAX_LENGTH_CALLBACK_URL = 256;
/** /**
* Максимальная длина email * Максимальная длина email
*/ */

View File

@ -1,28 +1,34 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Constants; namespace AtolOnline\Constants;
use MyCLabs\Enum\Enum;
/** /**
* Константы, определяющие типы документов коррекции * Константы, определяющие типы документов коррекции
* *
* @package AtolOnline\Constants * Тег ФФД - 1173
*
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 35 (correction_info)
*/ */
class CorrectionTypes final class CorrectionTypes extends Enum
{ {
/** /**
* Самостоятельно * Самостоятельно
*/ */
const SELF = 'self'; const SELF = 'self';
/** /**
* По предписанию * По предписанию
*/ */
const INSTRUCTION = 'instruction'; const INSTRUCTION = 'instruction';
} }

View File

@ -0,0 +1,30 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline\Constants;
use MyCLabs\Enum\Enum;
/**
* Константы, определяющие типы документов
*/
final class DocumentTypes extends Enum
{
/**
* Чек прихода, возврата прихода, расхода, возврата расхода
*/
const RECEIPT = 'receipt';
/**
* Чек коррекции
*/
const CORRECTION = 'correction';
}

View File

@ -1,54 +1,59 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Constants; namespace AtolOnline\Constants;
use MyCLabs\Enum\Enum;
/** /**
* Константы, определяющие признаки способов расчёта. Тег ФФД - 1214. * Константы, определяющие признаки способов расчёта
* *
* @package AtolOnline\Constants * Тег ФФД - 1214
*
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 22 (payment_method)
*/ */
class PaymentMethods final class PaymentMethods extends Enum
{ {
/** /**
* Предоплата 100% до передачи предмета расчёта * Предоплата 100% до передачи предмета расчёта
*/ */
const FULL_PREPAYMENT = 'full_prepayment'; const FULL_PREPAYMENT = 'full_prepayment';
/** /**
* Частичная предоплата до передачи предмета расчёта * Частичная предоплата до передачи предмета расчёта
*/ */
const PREPAYMENT = 'prepayment'; const PREPAYMENT = 'prepayment';
/** /**
* Аванс * Аванс
*/ */
const ADVANCE = 'advance'; const ADVANCE = 'advance';
/** /**
* Полная оплата с учётом аванса/предоплаты в момент передачи предмета расчёта * Полная оплата с учётом аванса/предоплаты в момент передачи предмета расчёта
*/ */
const FULL_PAYMENT = 'full_payment'; const FULL_PAYMENT = 'full_payment';
/** /**
* Частичный расчёт в момент передачи предмета расчёта (дальнейшая оплата в кредит) * Частичный расчёт в момент передачи предмета расчёта (дальнейшая оплата в кредит)
*/ */
const PARTIAL_PAYMENT = 'partial_payment'; const PARTIAL_PAYMENT = 'partial_payment';
/** /**
* Передача предмета расчёта в кредит * Передача предмета расчёта в кредит
*/ */
const CREDIT = 'credit'; const CREDIT = 'credit';
/** /**
* Оплата кредита * Оплата кредита
*/ */
const CREDIT_PAYMENT = 'credit_payment'; const CREDIT_PAYMENT = 'credit_payment';
} }

View File

@ -1,108 +1,161 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Constants; namespace AtolOnline\Constants;
use MyCLabs\Enum\Enum;
/** /**
* Константы, определяющие признаки предметов расчёта. Тег ФФД - 1212. * Константы, определяющие признаки предметов расчёта
* *
* @package AtolOnline\Constants * Тег ФФД - 1212
*
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 23 (payment_object)
*/ */
class PaymentObjects final class PaymentObjects extends Enum
{ {
/** /**
* Товар, кроме подакцизного * Товар, кроме подакцизного
*/ */
const COMMODITY = 'commodity'; const COMMODITY = 'commodity';
/** /**
* Товар подакцизный * Товар подакцизный
*/ */
const EXCISE = 'excise'; const EXCISE = 'excise';
/** /**
* Работа * Работа
*/ */
const JOB = 'job'; const JOB = 'job';
/** /**
* Услуга * Услуга
*/ */
const SERVICE = 'service'; const SERVICE = 'service';
/** /**
* Ставка азартной игры * Ставка азартной игры
*/ */
const GAMBLING_BET = 'gambling_bet'; const GAMBLING_BET = 'gambling_bet';
/** /**
* Выигрыш азартной игры * Выигрыш азартной игры
*/ */
const GAMBLING_PRIZE = 'gambling_prize'; const GAMBLING_PRIZE = 'gambling_prize';
/** /**
* Лотерея * Лотерея
*/ */
const LOTTERY = 'lottery'; const LOTTERY = 'lottery';
/** /**
* Выигрыш лотереи * Выигрыш лотереи
*/ */
const LOTTERY_PRIZE = 'lottery_prize'; const LOTTERY_PRIZE = 'lottery_prize';
/** /**
* Предоставление результатов интеллектуальной деятельности * Предоставление результатов интеллектуальной деятельности
*/ */
const INTELLECTUAL_ACTIVITY = 'intellectual_activity'; const INTELLECTUAL_ACTIVITY = 'intellectual_activity';
/** /**
* Платёж (задаток, кредит, аванс, предоплата, пеня, штраф, бонус и пр.) * Платёж (задаток, кредит, аванс, предоплата, пеня, штраф, бонус и пр.)
*/ */
const PAYMENT = 'payment'; const PAYMENT = 'payment';
/** /**
* Агентское вознаграждение * Агентское вознаграждение
*/ */
const AGENT_COMMISSION = 'agent_commission'; const AGENT_COMMISSION = 'agent_commission';
/** /**
* Составной предмет расчёта * Составной предмет расчёта
* @deprecated Более не используется согласно ФФД 1.05
* @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 25 (payment_object)
*/ */
const COMPOSITE = 'composite'; const COMPOSITE = 'composite';
/** /**
* Другой предмет расчёта * Другой предмет расчёта
*/ */
const ANOTHER = 'another'; const ANOTHER = 'another';
/** /**
* Имущественное право * Имущественное право
*/ */
const PROPERTY_RIGHT = 'property_right'; const PROPERTY_RIGHT = 'property_right';
/** /**
* Внереализационный доход * Внереализационный доход
*/ */
const NON_OPERATING_GAIN = 'non-operating_gain'; const NON_OPERATING_GAIN = 'non-operating_gain';
/** /**
* Страховые взносы * Страховые взносы
*/ */
const INSURANCE_PREMIUM = 'insurance_premium'; const INSURANCE_PREMIUM = 'insurance_premium';
/** /**
* Торговый сбор * Торговый сбор
*/ */
const SALES_TAX = 'sales_tax'; const SALES_TAX = 'sales_tax';
/** /**
* Курортный сбор * Курортный сбор
*/ */
const RESORT_FEE = 'resort_fee'; const RESORT_FEE = 'resort_fee';
/**
* Взнос в счёт оплаты пени, штрафе, вознаграждении, бонусе и ином аналогичном предмете расчета
*/
const AWARD = 'award';
/**
* Залог
*/
const DEPOSIT = 'deposit';
/**
* Расход, уменьшающий доход (в соответствии со статьей 346.16 НК РФ)
*/
const EXPENSE = 'expense';
/**
* Взнос на ОПС ИП
*/
const PEN_INSURANCE_IP = 'pension_insurance_ip';
/**
* Взнос на ОПС
*/
const PEN_INSURANCE = 'pension_insurance';
/**
* Взнос на ОМС ИП
*/
const MED_INSURANCE_IP = 'medical_insurance_ip';
/**
* Взнос на ОМС
*/
const MED_INSURANCE = 'medical_insurance';
/**
* Взнос на ОСС
*/
const SOC_INSURANCE = 'social_insurance';
/**
* Платёж казино
*/
const CASINO_PAYMENT = 'casino_payment';
} }

View File

@ -0,0 +1,77 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline\Constants;
use MyCLabs\Enum\Enum;
/**
* Константы, определяющие виды оплат
*
* Теги ФФД: 1031, 1081, 1215, 1216, 1217
*/
final class PaymentTypes extends Enum
{
/**
* Расчёт наличными. Тег ФФД - 1031.
*/
const CASH = 0;
/**
* Расчёт безналичными. Тег ФФД - 1081.
*/
const ELECTRON = 1;
/**
* Предварительная оплата (зачёт аванса). Тег ФФД - 1215.
*/
const PRE_PAID = 2;
/**
* Предварительная оплата (кредит). Тег ФФД - 1216.
*/
const CREDIT = 3;
/**
* Иная форма оплаты (встречное предоставление). Тег ФФД - 1217.
*/
const OTHER = 4;
/**
* Расширенный типы оплаты (5)
* Для каждого фискального типа оплаты можно указать расширенный тип оплаты
*/
const ADD_5 = 5;
/**
* Расширенный типы оплаты (6)
* Для каждого фискального типа оплаты можно указать расширенный тип оплаты
*/
const ADD_6 = 6;
/**
* Расширенный типы оплаты (7)
* Для каждого фискального типа оплаты можно указать расширенный тип оплаты
*/
const ADD_7 = 7;
/**
* Расширенный типы оплаты (8)
* Для каждого фискального типа оплаты можно указать расширенный тип оплаты
*/
const ADD_8 = 8;
/**
* Расширенный типы оплаты (9)
* Для каждого фискального типа оплаты можно указать расширенный тип оплаты
*/
const ADD_9 = 9;
}

View File

@ -1,48 +1,50 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Constants; namespace AtolOnline\Constants;
use MyCLabs\Enum\Enum;
/** /**
* Константы, определяющие типы операций (чеков) * Константы, определяющие типы операций (чеков)
*
* @package AtolOnline\Constants
*/ */
class ReceiptOperationTypes final class ReceiptOperationTypes extends Enum
{ {
/** /**
* Приход (мы продали) * Приход (мы продали)
*/ */
const SELL = 'sell'; const SELL = 'sell';
/** /**
* Возврат прихода (нам вернули предмет расчёта, мы вернули деньги) * Возврат прихода (нам вернули предмет расчёта, мы вернули средства)
*/ */
const SELL_REFUND = 'sell_refund'; const SELL_REFUND = 'sell_refund';
/** /**
* Коррекция прихода * Коррекция прихода
*/ */
const SELL_CORRECTION = 'sell_correction'; const SELL_CORRECTION = 'sell_correction';
/** /**
* Расход (мы купили) * Расход (мы купили)
*/ */
const BUY = 'buy'; const BUY = 'buy';
/** /**
* Возврат расхода (мы вернули предмет расчёта, нам вернули деньги) * Возврат расхода (мы вернули предмет расчёта, нам вернули средства)
*/ */
const BUY_REFUND = 'buy_refund'; const BUY_REFUND = 'buy_refund';
/** /**
* Коррекция прихода * Коррекция прихода (догоняем неучтённые средства)
*/ */
const BUY_CORRECTION = 'buy_correction'; const BUY_CORRECTION = 'buy_correction';
} }

View File

@ -1,46 +1,50 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Constants; namespace AtolOnline\Constants;
use MyCLabs\Enum\Enum;
/** /**
* Константы, определяющие типы налогообложения * Константы, определяющие типы налогообложения
* *
* @package AtolOnline\Constants * Тег ФДД - 1055
*/ */
class SnoTypes final class SnoTypes extends Enum
{ {
/** /**
* Общая СН * Общая СН
*/ */
const OSN = 'osn'; const OSN = 'osn';
/** /**
* Упрощенная СН (доходы) * Упрощенная СН (доходы)
*/ */
const USN_INCOME = 'usn_income'; const USN_INCOME = 'usn_income';
/** /**
* Упрощенная СН (доходы минус расходы) * Упрощенная СН (доходы минус расходы)
*/ */
const USN_INCOME_OUTCOME = 'usn_income_outcome'; const USN_INCOME_OUTCOME = 'usn_income_outcome';
/** /**
* Единый налог на вмененный доход * Единый налог на вмененный доход
*/ */
const ENDV = 'envd'; const ENDV = 'envd';
/** /**
* Единый сельскохозяйственный налог * Единый сельскохозяйственный налог
*/ */
const ESN = 'esn'; const ESN = 'esn';
/** /**
* Патентная СН * Патентная СН
*/ */

View File

@ -1,56 +1,60 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Constants; namespace AtolOnline\Constants;
use MyCLabs\Enum\Enum;
/** /**
* Константы, определяющие типы ставок НДС * Константы, определяющие типы ставок НДС
* *
* @package AtolOnline\Constants * Теги ФФД: 1199, 1105, 1104, 1103, 1102, 1107, 1106
*/ */
class VatTypes final class VatTypes extends Enum
{ {
/** /**
* Без НДС * Без НДС
*/ */
const NONE = 'none'; const NONE = 'none';
/** /**
* НДС 0% * НДС 0%
*/ */
const VAT0 = 'vat0'; const VAT0 = 'vat0';
/** /**
* НДС 10% * НДС 10%
*/ */
const VAT10 = 'vat10'; const VAT10 = 'vat10';
/** /**
* НДС 18% * НДС 18%
*/ */
const VAT18 = 'vat18'; const VAT18 = 'vat18';
/** /**
* НДС 20% * НДС 20%
*/ */
const VAT20 = 'vat20'; const VAT20 = 'vat20';
/** /**
* НДС 10/110% * НДС 10/110%
*/ */
const VAT110 = 'vat110'; const VAT110 = 'vat110';
/** /**
* НДС 18/118% * НДС 18/118%
*/ */
const VAT118 = 'vat118'; const VAT118 = 'vat118';
/** /**
* НДС 20/120% * НДС 20/120%
*/ */

View File

@ -0,0 +1,213 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline\Entities;
use AtolOnline\{
Constants\Constraints,
Exceptions\InvalidEmailException,
Exceptions\InvalidInnLengthException,
Exceptions\TooLongEmailException,
Exceptions\TooLongNameException,
Exceptions\TooLongPhoneException};
/**
* Класс Client, описывающий сущность покупателя
*
* @package AtolOnline\Entities
*/
class Client extends Entity
{
/**
* @var string|null Наименование. Тег ФФД - 1227.
*/
protected ?string $name = null;
/**
* @var string|null Email. Тег ФФД - 1008.
*/
protected ?string $email = null;
/**
* @var string|null Телефон покупателя. Тег ФФД - 1008.
*/
protected ?string $phone = null;
/**
* @var string|null ИНН. Тег ФФД - 1228.
*/
protected ?string $inn = null;
/**
* Конструктор объекта покупателя
*
* @param string|null $name Наименование. Тег ФФД - 1227.
* @param string|null $phone Email. Тег ФФД - 1008.
* @param string|null $email Телефон покупателя. Тег ФФД - 1008.
* @param string|null $inn ИНН. Тег ФФД - 1228.
* @throws TooLongNameException Слишком длинное имя
* @throws TooLongPhoneException Слишком длинный телефон
* @throws TooLongEmailException Слишком длинный email
* @throws InvalidEmailException Невалидный email
* @throws InvalidInnLengthException Некорректная длина ИНН
*/
public function __construct(
?string $name = null,
?string $email = null,
?string $phone = null,
?string $inn = null
) {
$name && $this->setName($name);
$email && $this->setEmail($email);
$phone && $this->setPhone($phone);
$inn && $this->setInn($inn);
}
/**
* Возвращает наименование покупателя
*
* Тег ФФД - 1227
*
* @return string|null
*/
public function getName(): ?string
{
return $this->name;
}
/**
* Устанавливает наименование покупателя
*
* Тег ФФД - 1227
*
* @param string|null $name
* @return $this
* @throws TooLongNameException
*/
public function setName(?string $name): Client
{
if (is_string($name)) {
$name = preg_replace('/[\n\r\t]/', '', trim($name));
if (mb_strlen($name) > Constraints::MAX_LENGTH_CLIENT_NAME) {
throw new TooLongNameException($name, Constraints::MAX_LENGTH_CLIENT_NAME);
}
}
$this->name = empty($name) ? null : $name;
return $this;
}
/**
* Возвращает установленный email
*
* @return string|null
*/
public function getEmail(): ?string
{
return $this->email;
}
/**
* Устанавливает email
*
* @param string|null $email
* @return $this
* @throws TooLongEmailException Слишком длинный email
* @throws InvalidEmailException Невалидный email
*/
public function setEmail(?string $email): self
{
if (is_string($email)) {
$email = preg_replace('/[\n\r\t]/', '', trim($email));
if (mb_strlen($email) > Constraints::MAX_LENGTH_EMAIL) {
throw new TooLongEmailException($email, Constraints::MAX_LENGTH_EMAIL);
} elseif (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
throw new InvalidEmailException($email);
}
}
$this->email = empty($email) ? null : $email;
return $this;
}
/**
* Возвращает установленный телефон
*
* Тег ФФД - 1008
*
* @return string|null
*/
public function getPhone(): ?string
{
return $this->phone;
}
/**
* Устанавливает телефон
*
* Тег ФФД - 1008
*
* @param string|null $phone Номер телефона
* @return $this
* @throws TooLongPhoneException
*/
public function setPhone(?string $phone): Client
{
if (is_string($phone)) {
$phone = preg_replace('/[^\d]/', '', trim($phone));
if (mb_strlen($phone) > Constraints::MAX_LENGTH_CLIENT_PHONE) {
throw new TooLongPhoneException($phone, Constraints::MAX_LENGTH_CLIENT_PHONE);
}
}
$this->phone = empty($phone) ? null : "+$phone";
return $this;
}
/**
* Возвращает установленный ИНН
*
* @return string|null
*/
public function getInn(): ?string
{
return $this->inn;
}
/**
* Устанавливает ИНН
*
* @param string|null $inn
* @return $this
* @throws InvalidInnLengthException Некорректная длина ИНН
*/
public function setInn(?string $inn): self
{
if (is_string($inn)) {
$inn = preg_replace('/[^\d]/', '', trim($inn));
if (preg_match_all(Constraints::PATTERN_INN, $inn) === 0) {
throw new InvalidInnLengthException($inn);
}
}
$this->inn = empty($inn) ? null : $inn;
return $this;
}
/**
* @inheritDoc
*/
public function jsonSerialize(): object
{
$json = [];
$this->getName() && $json['name'] = $this->getName();
$this->getEmail() && $json['email'] = $this->getEmail();
$this->getPhone() && $json['phone'] = $this->getPhone();
$this->getInn() && $json['inn'] = $this->getInn();
return (object)$json;
}
}

View File

@ -0,0 +1,227 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline\Entities;
use AtolOnline\{
Constants\Constraints,
Constants\SnoTypes,
Exceptions\InvalidEmailException,
Exceptions\InvalidInnLengthException,
Exceptions\InvalidPaymentAddressException,
Exceptions\InvalidSnoException,
Exceptions\TooLongEmailException,
Exceptions\TooLongPaymentAddressException};
/**
* Класс, описывающий сущность компании-продавца
*
* @package AtolOnline\Entities
*/
class Company extends Entity
{
/**
* @var string|null Почта. Тег ФФД - 1117.
*/
protected ?string $email;
/**
* @var string|null Система налогообложения продавца. Тег ФФД - 1055.
*/
protected ?string $sno;
/**
* @var string|null ИНН. Тег ФФД - 1018.
*/
protected ?string $inn;
/**
* @var string|null Место расчётов (адрес интернет-магазина). Тег ФФД - 1187.
*/
protected ?string $payment_address;
/**
* Company constructor.
*
* @param string $sno
* @param string $inn
* @param string $payment_address
* @param string $email
* @throws InvalidEmailException
* @throws InvalidInnLengthException
* @throws InvalidPaymentAddressException
* @throws InvalidSnoException
* @throws TooLongEmailException
* @throws TooLongPaymentAddressException
*/
public function __construct(
string $email,
string $sno,
string $inn,
string $payment_address,
) {
$this->setEmail($email);
$this->setSno($sno);
$this->setInn($inn);
$this->setPaymentAddress($payment_address);
}
/**
* Возвращает установленный email
*
* @return string
*/
public function getEmail(): string
{
return $this->email;
}
/**
* Устанавливает email
*
* @param string $email
* @return $this
* @throws TooLongEmailException Слишком длинный email
* @throws InvalidEmailException Невалидный email
*/
public function setEmail(string $email): self
{
$email = preg_replace('/[\n\r\t]/', '', trim($email));
if (mb_strlen($email) > Constraints::MAX_LENGTH_EMAIL) {
throw new TooLongEmailException($email, Constraints::MAX_LENGTH_EMAIL);
} elseif (empty($email) || filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
throw new InvalidEmailException($email);
}
$this->email = $email;
return $this;
}
/**
* Возвращает установленный тип налогообложения
*
* Тег ФФД - 1055
*
* @return string
*/
public function getSno(): string
{
return $this->sno;
}
/**
* Устанавливает тип налогообложения
*
* Тег ФФД - 1055
*
* @param string $sno
* @return $this
* @throws InvalidSnoException
*/
public function setSno(string $sno): Company
{
$sno = trim($sno);
if (empty($sno) || !in_array($sno, SnoTypes::toArray())) {
throw new InvalidSnoException($sno);
}
$this->sno = $sno;
return $this;
}
/**
* Возвращает установленный ИНН
*
* Тег ФФД - 1018
*
* @return string
*/
public function getInn(): string
{
return $this->inn;
}
/**
* Устанавливает ИНН
*
* Тег ФФД - 1018
*
* @param string $inn
* @return $this
* @throws InvalidInnLengthException
*/
public function setInn(string $inn): self
{
$inn = preg_replace('/[^\d]/', '', trim($inn));
if (empty($inn) || preg_match_all(Constraints::PATTERN_INN, $inn) === 0) {
throw new InvalidInnLengthException($inn);
}
$this->inn = $inn;
return $this;
}
/**
* Возвращает установленный адрес места расчётов
*
* Тег ФФД - 1187
*
* @return string
*/
public function getPaymentAddress(): string
{
return $this->payment_address;
}
/**
* Устанавливает адрес места расчётов
*
* Тег ФФД - 1187
*
* @param string $payment_address
* @return $this
* @throws TooLongPaymentAddressException
* @throws InvalidPaymentAddressException
*/
public function setPaymentAddress(string $payment_address): Company
{
$payment_address = trim($payment_address);
if (empty($payment_address)) {
throw new InvalidPaymentAddressException();
} elseif (mb_strlen($payment_address) > Constraints::MAX_LENGTH_PAYMENT_ADDRESS) {
throw new TooLongPaymentAddressException($payment_address, Constraints::MAX_LENGTH_PAYMENT_ADDRESS);
}
$this->payment_address = $payment_address;
return $this;
}
/**
* @inheritDoc
* @throws InvalidEmailException
* @throws InvalidSnoException
* @throws InvalidInnLengthException
* @throws InvalidPaymentAddressException
*/
public function jsonSerialize(): object
{
return (object)[
'email' => $this->email
? $this->getEmail()
: throw new InvalidEmailException(),
'sno' => $this->sno
? $this->getSno()
: throw new InvalidSnoException(),
'inn' => $this->inn
? $this->getInn()
: throw new InvalidInnLengthException(),
'payment_address' => $this->payment_address
? $this->getPaymentAddress()
: throw new InvalidPaymentAddressException(),
];
}
}

View File

@ -1,40 +1,40 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Entities; namespace AtolOnline\Entities;
/** /**
* Класс CorrectionInfo, описывающий данные коррекции * Класс CorrectionInfo, описывающий данные чек коррекции
*
* @package AtolOnline\Entities
*/ */
class CorrectionInfo extends Entity class CorrectionInfo extends Entity
{ {
/** /**
* @var int Тип коррекции. Тег ФФД - 1173. * @var string Тип коррекции. Тег ФФД - 1173.
*/ */
protected $type; protected string $type;
/** /**
* @var string Дата документа основания для коррекции. Тег ФФД - 1178. * @var string Дата документа основания для коррекции. Тег ФФД - 1178.
*/ */
protected $base_date; protected string $base_date;
/** /**
* @var string Номер документа основания для коррекции. Тег ФФД - 1179. * @var string Номер документа основания для коррекции. Тег ФФД - 1179.
*/ */
protected $base_number; protected string $base_number;
/** /**
* @var string Описание коррекции. Тег ФФД - 1177. * @var string Описание коррекции. Тег ФФД - 1177.
*/ */
protected $base_name; protected string $base_name;
/** /**
* CorrectionInfo constructor. * CorrectionInfo constructor.
@ -78,7 +78,7 @@ class CorrectionInfo extends Entity
* @param string $number * @param string $number
* @return $this * @return $this
*/ */
public function setNumber(string $number) public function setNumber(string $number): CorrectionInfo
{ {
$this->base_number = trim($number); $this->base_number = trim($number);
return $this; return $this;
@ -102,7 +102,7 @@ class CorrectionInfo extends Entity
* @param string $name * @param string $name
* @return $this * @return $this
*/ */
public function setName(string $name) public function setName(string $name): CorrectionInfo
{ {
$this->base_name = trim($name); $this->base_name = trim($name);
return $this; return $this;
@ -126,7 +126,7 @@ class CorrectionInfo extends Entity
* @param string $date Строка в формате d.m.Y * @param string $date Строка в формате d.m.Y
* @return $this * @return $this
*/ */
public function setDate(string $date) public function setDate(string $date): CorrectionInfo
{ {
$this->base_date = $date; $this->base_date = $date;
return $this; return $this;
@ -150,7 +150,7 @@ class CorrectionInfo extends Entity
* @param string $type * @param string $type
* @return $this * @return $this
*/ */
public function setType(string $type) public function setType(string $type): CorrectionInfo
{ {
$this->type = $type; $this->type = $type;
return $this; return $this;

View File

@ -1,18 +1,34 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Entities; namespace AtolOnline\Entities;
use AtolOnline\Constants\Constraints; use AtolOnline\Constants\Constraints;
use AtolOnline\Exceptions\AtolCashierTooLongException;
use AtolOnline\Exceptions\AtolException; use AtolOnline\Exceptions\AtolException;
use AtolOnline\Exceptions\AtolInvalidJsonException; use AtolOnline\Exceptions\BasicTooManyException;
use AtolOnline\Exceptions\InvalidEmailException;
use AtolOnline\Exceptions\InvalidInnLengthException;
use AtolOnline\Exceptions\InvalidJsonException;
use AtolOnline\Exceptions\TooHighPriceException;
use AtolOnline\Exceptions\TooLongCashierException;
use AtolOnline\Exceptions\TooLongEmailException;
use AtolOnline\Exceptions\TooLongNameException;
use AtolOnline\Exceptions\TooLongPaymentAddressException;
use AtolOnline\Exceptions\TooLongPhoneException;
use AtolOnline\Exceptions\TooLongUnitException;
use AtolOnline\Exceptions\TooLongUserdataException;
use AtolOnline\Exceptions\TooManyItemsException;
use AtolOnline\Exceptions\TooManyPaymentsException;
use AtolOnline\Exceptions\TooManyVatsException;
use Exception;
/** /**
* Класс, описывающий документ * Класс, описывающий документ
@ -22,44 +38,44 @@ use AtolOnline\Exceptions\AtolInvalidJsonException;
class Document extends Entity class Document extends Entity
{ {
/** /**
* @var \AtolOnline\Entities\ItemArray Массив предметов расчёта * @var ItemArray Массив предметов расчёта
*/ */
protected $items; protected ItemArray $items;
/** /**
* @var \AtolOnline\Entities\VatArray Массив ставок НДС * @var VatArray Массив ставок НДС
*/ */
protected $vats; protected VatArray $vats;
/** /**
* @var \AtolOnline\Entities\PaymentArray Массив оплат * @var PaymentArray Массив оплат
*/ */
protected $payments; protected PaymentArray $payments;
/** /**
* @var \AtolOnline\Entities\Company Объект компании (продавца) * @var Company Объект компании (продавца)
*/ */
protected $company; protected Company $company;
/** /**
* @var \AtolOnline\Entities\Client Объект клиента (покупателя) * @var Client Объект клиента (покупателя)
*/ */
protected $client; protected Client $client;
/** /**
* @var int Итоговая сумма чека. Тег ФФД - 1020. * @var float Итоговая сумма чека. Тег ФФД - 1020.
*/ */
protected $total = 0; protected float $total = 0;
/** /**
* @var string ФИО кассира. Тег ФФД - 1021. * @var string ФИО кассира. Тег ФФД - 1021.
*/ */
protected $cashier; protected string $cashier;
/** /**
* @var \AtolOnline\Entities\CorrectionInfo Данные коррекции * @var CorrectionInfo Данные коррекции
*/ */
protected $correction_info; protected CorrectionInfo $correction_info;
/** /**
* Document constructor. * Document constructor.
@ -70,66 +86,65 @@ class Document extends Entity
$this->payments = new PaymentArray(); $this->payments = new PaymentArray();
$this->items = new ItemArray(); $this->items = new ItemArray();
} }
/** /**
* Удаляет все налоги из документа и предметов расчёта * Удаляет все налоги из документа и предметов расчёта
* *
* @return $this * @return $this
* @throws \AtolOnline\Exceptions\AtolPriceTooHighException Слишком большая сумма * @throws TooManyVatsException Слишком много ставок НДС
* @throws \AtolOnline\Exceptions\AtolTooManyVatsException Слишком много ставок НДС
*/ */
public function clearVats() public function clearVats(): Document
{ {
$this->setVats([]); $this->setVats([]);
return $this; return $this;
} }
/** /**
* Добавляет новую ставку НДС в массив ставок НДС * Добавляет новую ставку НДС в массив ставок НДС
* *
* @param \AtolOnline\Entities\Vat $vat Объект ставки НДС * @param Vat $vat Объект ставки НДС
* @return $this * @return $this
* @throws \AtolOnline\Exceptions\AtolTooManyVatsException Слишком много ставок НДС * @throws TooManyVatsException Слишком много ставок НДС
*/ */
public function addVat(Vat $vat) public function addVat(Vat $vat): Document
{ {
$this->vats->add($vat); $this->vats->add($vat);
return $this; return $this;
} }
/** /**
* Возвращает массив ставок НДС * Возвращает массив ставок НДС
* *
* @return \AtolOnline\Entities\Vat[] * @return Vat[]
*/ */
public function getVats(): array public function getVats(): array
{ {
return $this->vats->get(); return $this->vats->get();
} }
/** /**
* Устанавливает массив ставок НДС * Устанавливает массив ставок НДС
* *
* @param \AtolOnline\Entities\Vat[] $vats Массив ставок НДС * @param Vat[] $vats Массив ставок НДС
* @return $this * @return $this
* @throws \AtolOnline\Exceptions\AtolTooManyVatsException Слишком много ставок НДС * @throws TooManyVatsException Слишком много ставок НДС
* @throws \Exception * @throws Exception
*/ */
public function setVats(array $vats) public function setVats(array $vats): Document
{ {
$this->vats->set($vats); $this->vats->set($vats);
return $this; return $this;
} }
/** /**
* Добавляет новую оплату в массив оплат * Добавляет новую оплату в массив оплат
* *
* @param \AtolOnline\Entities\Payment $payment Объект оплаты * @param Payment $payment Объект оплаты
* @return $this * @return $this
* @throws \Exception * @throws Exception
* @throws \AtolOnline\Exceptions\AtolTooManyPaymentsException Слишком много оплат * @throws TooManyPaymentsException Слишком много оплат
*/ */
public function addPayment(Payment $payment) public function addPayment(Payment $payment): Document
{ {
if (count($this->getPayments()) == 0 && !$payment->getSum()) { if (count($this->getPayments()) == 0 && !$payment->getSum()) {
$payment->setSum($this->calcTotal()); $payment->setSum($this->calcTotal());
@ -137,61 +152,61 @@ class Document extends Entity
$this->payments->add($payment); $this->payments->add($payment);
return $this; return $this;
} }
/** /**
* Возвращает массив оплат * Возвращает массив оплат
* *
* @return \AtolOnline\Entities\Payment[] * @return Payment[]
*/ */
public function getPayments(): array public function getPayments(): array
{ {
return $this->payments->get(); return $this->payments->get();
} }
/** /**
* Устанавливает массив оплат * Устанавливает массив оплат
* *
* @param \AtolOnline\Entities\Payment[] $payments Массив оплат * @param Payment[] $payments Массив оплат
* @return $this * @return $this
* @throws \AtolOnline\Exceptions\AtolTooManyPaymentsException Слишком много оплат * @throws TooManyPaymentsException Слишком много оплат
*/ */
public function setPayments(array $payments) public function setPayments(array $payments): Document
{ {
$this->payments->set($payments); $this->payments->set($payments);
return $this; return $this;
} }
/** /**
* Добавляет новый предмет расчёта в массив предметов расчёта * Добавляет новый предмет расчёта в массив предметов расчёта
* *
* @param \AtolOnline\Entities\Item $item Объект предмета расчёта * @param Item $item Объект предмета расчёта
* @return $this * @return $this
* @throws \AtolOnline\Exceptions\AtolTooManyItemsException Слишком много предметов расчёта * @throws TooManyItemsException Слишком много предметов расчёта
*/ */
public function addItem(Item $item) public function addItem(Item $item): Document
{ {
$this->items->add($item); $this->items->add($item);
return $this; return $this;
} }
/** /**
* Возвращает массив предметов расчёта * Возвращает массив предметов расчёта
* *
* @return \AtolOnline\Entities\Item[] * @return Item[]
*/ */
public function getItems(): array public function getItems(): array
{ {
return $this->items->get(); return $this->items->get();
} }
/** /**
* Устанавливает массив предметов расчёта * Устанавливает массив предметов расчёта
* *
* @param \AtolOnline\Entities\Item[] $items Массив предметов расчёта * @param Item[] $items Массив предметов расчёта
* @return $this * @return $this
* @throws \AtolOnline\Exceptions\AtolTooManyItemsException Слишком много предметов расчёта * @throws TooManyItemsException Слишком много предметов расчёта
*/ */
public function setItems(array $items) public function setItems(array $items): Document
{ {
$this->items->set($items); $this->items->set($items);
return $this; return $this;
@ -213,7 +228,7 @@ class Document extends Entity
* @param Client|null $client * @param Client|null $client
* @return $this * @return $this
*/ */
public function setClient(?Client $client) public function setClient(?Client $client): Document
{ {
$this->client = $client; $this->client = $client;
return $this; return $this;
@ -235,7 +250,7 @@ class Document extends Entity
* @param Company|null $company * @param Company|null $company
* @return $this * @return $this
*/ */
public function setCompany(?Company $company) public function setCompany(?Company $company): Document
{ {
$this->company = $company; $this->company = $company;
return $this; return $this;
@ -250,55 +265,55 @@ class Document extends Entity
{ {
return $this->cashier; return $this->cashier;
} }
/** /**
* Устанавливает ФИО кассира. Тег ФФД - 1021. * Устанавливает ФИО кассира. Тег ФФД - 1021.
* *
* @param string|null $cashier * @param string|null $cashier
* @return $this * @return $this
* @throws \AtolOnline\Exceptions\AtolCashierTooLongException * @throws TooLongCashierException
*/ */
public function setCashier(?string $cashier) public function setCashier(?string $cashier): Document
{ {
if ($cashier !== null) { if ($cashier !== null) {
$cashier = trim($cashier); $cashier = trim($cashier);
if (valid_strlen($cashier) > Constraints::MAX_LENGTH_CASHIER_NAME) { if (mb_strlen($cashier) > Constraints::MAX_LENGTH_CASHIER_NAME) {
throw new AtolCashierTooLongException($cashier, Constraints::MAX_LENGTH_CASHIER_NAME); throw new TooLongCashierException($cashier, Constraints::MAX_LENGTH_CASHIER_NAME);
} }
} }
$this->cashier = $cashier; $this->cashier = $cashier;
return $this; return $this;
} }
/** /**
* Возвращает данные коррекции * Возвращает данные коррекции
* *
* @return \AtolOnline\Entities\CorrectionInfo|null * @return CorrectionInfo|null
*/ */
public function getCorrectionInfo(): ?CorrectionInfo public function getCorrectionInfo(): ?CorrectionInfo
{ {
return $this->correction_info; return $this->correction_info;
} }
/** /**
* Устанавливает данные коррекции * Устанавливает данные коррекции
* *
* @param \AtolOnline\Entities\CorrectionInfo|null $correction_info * @param CorrectionInfo|null $correction_info
* @return $this * @return $this
*/ */
public function setCorrectionInfo(?CorrectionInfo $correction_info) public function setCorrectionInfo(?CorrectionInfo $correction_info): Document
{ {
$this->correction_info = $correction_info; $this->correction_info = $correction_info;
return $this; return $this;
} }
/** /**
* Пересчитывает, сохраняет и возвращает итоговую сумму чека по всем позициям (включая НДС). Тег ФФД - 1020. * Пересчитывает, сохраняет и возвращает итоговую сумму чека по всем позициям (включая НДС). Тег ФФД - 1020.
* *
* @return float * @return float
* @throws \Exception * @throws Exception
*/ */
public function calcTotal() public function calcTotal(): float
{ {
$sum = 0; $sum = 0;
$this->clearVats(); $this->clearVats();
@ -318,32 +333,33 @@ class Document extends Entity
{ {
return $this->total; return $this->total;
} }
/** /**
* Собирает объект документа из сырой json-строки * Собирает объект документа из сырой json-строки
* *
* @param string $json * @param string $json
* @return \AtolOnline\Entities\Document * @return Document
* @throws \AtolOnline\Exceptions\AtolEmailTooLongException * @throws TooLongEmailException
* @throws \AtolOnline\Exceptions\AtolEmailValidateException * @throws InvalidEmailException
* @throws \AtolOnline\Exceptions\AtolException * @throws AtolException
* @throws \AtolOnline\Exceptions\AtolInnWrongLengthException * @throws InvalidInnLengthException
* @throws \AtolOnline\Exceptions\AtolInvalidJsonException * @throws InvalidJsonException
* @throws \AtolOnline\Exceptions\AtolNameTooLongException * @throws TooLongNameException
* @throws \AtolOnline\Exceptions\AtolPaymentAddressTooLongException * @throws TooLongPaymentAddressException
* @throws \AtolOnline\Exceptions\AtolPhoneTooLongException * @throws TooLongPhoneException
* @throws \AtolOnline\Exceptions\AtolPriceTooHighException * @throws TooHighPriceException
* @throws \AtolOnline\Exceptions\AtolTooManyException * @throws BasicTooManyException
* @throws \AtolOnline\Exceptions\AtolTooManyItemsException * @throws TooManyItemsException
* @throws \AtolOnline\Exceptions\AtolTooManyPaymentsException * @throws TooManyPaymentsException
* @throws \AtolOnline\Exceptions\AtolUnitTooLongException * @throws TooLongUnitException
* @throws \AtolOnline\Exceptions\AtolUserdataTooLongException * @throws TooLongUserdataException
* @throws Exception
*/ */
public static function fromRaw(string $json) public static function fromRaw(string $json): Document
{ {
$array = json_decode($json, true); $array = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) { if (json_last_error() !== JSON_ERROR_NONE) {
throw new AtolInvalidJsonException(); throw new InvalidJsonException();
} }
$doc = new self(); $doc = new self();
if (isset($array['company'])) { if (isset($array['company'])) {
@ -416,13 +432,13 @@ class Document extends Entity
} }
return $doc; return $doc;
} }
/** /**
* Возвращает массив для кодирования в json * Возвращает массив для кодирования в json
* *
* @throws \Exception * @throws Exception
*/ */
public function jsonSerialize() public function jsonSerialize(): array
{ {
if ($this->getCompany()) { if ($this->getCompany()) {
$json['company'] = $this->getCompany()->jsonSerialize(); // обязательно $json['company'] = $this->getCompany()->jsonSerialize(); // обязательно

View File

@ -1,25 +1,28 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Entities; namespace AtolOnline\Entities;
use JsonSerializable; use JsonSerializable;
use Stringable;
/** /**
* Абстрактное описание любой сущности, представляемой как JSON * Абстрактное описание любой сущности, представляемой как json
*
* @package AtolOnline\Entities
*/ */
abstract class Entity implements JsonSerializable abstract class Entity implements JsonSerializable, Stringable
{ {
/** /**
* @inheritDoc * Возвращает строковое представление json-структуры объекта
*
* @return false|string
*/ */
public function __toString() public function __toString()
{ {

View File

@ -1,22 +1,23 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Entities; namespace AtolOnline\Entities;
use AtolOnline\{Constants\Constraints, use AtolOnline\{
Exceptions\AtolNameTooLongException, Constants\Constraints,
Exceptions\AtolPriceTooHighException, Exceptions\BasicTooManyException,
Exceptions\AtolTooManyException, Exceptions\TooHighPriceException,
Exceptions\AtolUnitTooLongException, Exceptions\TooLongNameException,
Exceptions\AtolUserdataTooLongException, Exceptions\TooLongUnitException,
Traits\RublesKopeksConverter Exceptions\TooLongUserdataException};
};
/** /**
* Предмет расчёта (товар, услуга) * Предмет расчёта (товар, услуга)
@ -25,74 +26,72 @@ use AtolOnline\{Constants\Constraints,
*/ */
class Item extends Entity class Item extends Entity
{ {
use RublesKopeksConverter;
/** /**
* @var string Наименование. Тег ФФД - 1030. * @var string Наименование. Тег ФФД - 1030.
*/ */
protected $name; protected string $name;
/** /**
* @var int Цена в копейках (с учётом скидок и наценок). Тег ФФД - 1079. * @var int Цена в копейках (с учётом скидок и наценок). Тег ФФД - 1079.
*/ */
protected $price = 0; protected int $price = 0;
/** /**
* @var float Количество, вес. Тег ФФД - 1023. * @var float Количество, вес. Тег ФФД - 1023.
*/ */
protected $quantity = 0.0; protected float $quantity = 0.0;
/** /**
* @var float Сумма в копейках. Тег ФФД - 1043. * @var float Сумма в копейках. Тег ФФД - 1043.
*/ */
protected $sum = 0; protected float $sum = 0;
/** /**
* @var string Единица измерения количества. Тег ФФД - 1197. * @var string Единица измерения количества. Тег ФФД - 1197.
*/ */
protected $measurement_unit; protected string $measurement_unit;
/** /**
* @var Vat Ставка НДС * @var Vat|null Ставка НДС
*/ */
protected $vat; protected ?Vat $vat;
/** /**
* @var string Признак способа расчёта. Тег ФФД - 1214. * @var string Признак способа расчёта. Тег ФФД - 1214.
*/ */
protected $payment_method; protected string $payment_method;
/** /**
* @var string Признак объекта расчёта. Тег ФФД - 1212. * @var string Признак объекта расчёта. Тег ФФД - 1212.
*/ */
protected $payment_object; protected string $payment_object;
/** /**
* @var string Дополнительный реквизит. Тег ФФД - 1191. * @var string Дополнительный реквизит. Тег ФФД - 1191.
*/ */
protected $user_data; protected string $user_data;
/** /**
* Item constructor. * Item constructor.
* *
* @param string|null $name Наименование * @param string|null $name Наименование
* @param float|null $price Цена за одну единицу * @param float|null $price Цена за одну единицу
* @param float|null $quantity Количество * @param float|null $quantity Количество
* @param string|null $measurement_unit Единица измерения * @param string|null $measurement_unit Единица измерения
* @param string|null $vat_type Ставка НДС * @param string|null $vat_type Ставка НДС
* @param string|null $payment_object Признак * @param string|null $payment_object Признак
* @param string|null $payment_method Способ расчёта * @param string|null $payment_method Способ расчёта
* @throws AtolNameTooLongException Слишком длинное наименование * @throws TooLongNameException Слишком длинное наименование
* @throws AtolPriceTooHighException Слишком высокая цена за одну единицу * @throws TooHighPriceException Слишком высокая цена за одну единицу
* @throws AtolTooManyException Слишком большое количество * @throws BasicTooManyException Слишком большое количество
* @throws AtolUnitTooLongException Слишком длинное название единицы измерения * @throws TooLongUnitException Слишком длинное название единицы измерения
*/ */
public function __construct( public function __construct(
?string $name = null, ?string $name = null,
?float $price = null, ?float $price = null,
?float $quantity = null, ?float $quantity = null,
?string $measurement_unit = null, ?string $measurement_unit = null,
$vat_type = null, ?string $vat_type = null,
?string $payment_object = null, ?string $payment_object = null,
?string $payment_method = null ?string $payment_method = null
) { ) {
@ -124,23 +123,23 @@ class Item extends Entity
* *
* @return string * @return string
*/ */
public function getName() public function getName(): string
{ {
return $this->name; return $this->name;
} }
/** /**
* Устаналивает наименование. Тег ФФД - 1030. * Устаналивает наименование. Тег ФФД - 1030.
* *
* @param string $name Наименование * @param string $name Наименование
* @return $this * @return $this
* @throws AtolNameTooLongException Слишком длинное имя/наименование * @throws TooLongNameException Слишком длинное имя/наименование
*/ */
public function setName(string $name) public function setName(string $name): self
{ {
$name = trim($name); $name = trim($name);
if (valid_strlen($name) > Constraints::MAX_LENGTH_ITEM_NAME) { if (mb_strlen($name) > Constraints::MAX_LENGTH_ITEM_NAME) {
throw new AtolNameTooLongException($name, Constraints::MAX_LENGTH_ITEM_NAME); throw new TooLongNameException($name, Constraints::MAX_LENGTH_ITEM_NAME);
} }
$this->name = $name; $this->name = $name;
return $this; return $this;
@ -151,24 +150,24 @@ class Item extends Entity
* *
* @return float * @return float
*/ */
public function getPrice() public function getPrice(): float
{ {
return self::toRub($this->price); return rubles($this->price);
} }
/** /**
* Устанавливает цену в рублях. Тег ФФД - 1079. * Устанавливает цену в рублях. Тег ФФД - 1079.
* *
* @param float $rubles Цена за одну единицу в рублях * @param float $rubles Цена за одну единицу в рублях
* @return $this * @return $this
* @throws AtolPriceTooHighException Слишком высокая цена за одну единицу * @throws TooHighPriceException Слишком высокая цена за одну единицу
*/ */
public function setPrice(float $rubles) public function setPrice(float $rubles): Item
{ {
if ($rubles > 42949672.95) { if ($rubles > 42949672.95) {
throw new AtolPriceTooHighException($rubles, 42949672.95); throw new TooHighPriceException($rubles, 42949672.95);
} }
$this->price = self::toKop($rubles); $this->price = kopeks($rubles);
$this->calcSum(); $this->calcSum();
return $this; return $this;
} }
@ -182,22 +181,22 @@ class Item extends Entity
{ {
return $this->quantity; return $this->quantity;
} }
/** /**
* Устанавливает количество. Тег ФФД - 1023. * Устанавливает количество. Тег ФФД - 1023.
* *
* @param float $quantity Количество * @param float $quantity Количество
* @param string|null $measurement_unit Единица измерения количества * @param string|null $measurement_unit Единица измерения количества
* @return $this * @return $this
* @throws AtolTooManyException Слишком большое количество * @throws BasicTooManyException Слишком большое количество
* @throws AtolPriceTooHighException Слишком высокая общая стоимость * @throws TooHighPriceException Слишком высокая общая стоимость
* @throws AtolUnitTooLongException Слишком длинное название единицы измерения * @throws TooLongUnitException Слишком длинное название единицы измерения
*/ */
public function setQuantity(float $quantity, string $measurement_unit = null) public function setQuantity(float $quantity, string $measurement_unit = null): Item
{ {
$quantity = round($quantity, 3); $quantity = round($quantity, 3);
if ($quantity > 99999.999) { if ($quantity > 99999.999) {
throw new AtolTooManyException($quantity, 99999.999); throw new BasicTooManyException($quantity, 99999.999);
} }
$this->quantity = $quantity; $this->quantity = $quantity;
$this->calcSum(); $this->calcSum();
@ -216,19 +215,19 @@ class Item extends Entity
{ {
return $this->measurement_unit; return $this->measurement_unit;
} }
/** /**
* Устанавливает единицу измерения количества. Тег ФФД - 1197. * Устанавливает единицу измерения количества. Тег ФФД - 1197.
* *
* @param string $measurement_unit Единица измерения количества * @param string $measurement_unit Единица измерения количества
* @return $this * @return $this
* @throws AtolUnitTooLongException Слишком длинное название единицы измерения * @throws TooLongUnitException Слишком длинное название единицы измерения
*/ */
public function setMeasurementUnit(string $measurement_unit) public function setMeasurementUnit(string $measurement_unit): Item
{ {
$measurement_unit = trim($measurement_unit); $measurement_unit = trim($measurement_unit);
if (valid_strlen($measurement_unit) > Constraints::MAX_LENGTH_MEASUREMENT_UNIT) { if (mb_strlen($measurement_unit) > Constraints::MAX_LENGTH_MEASUREMENT_UNIT) {
throw new AtolUnitTooLongException($measurement_unit, Constraints::MAX_LENGTH_MEASUREMENT_UNIT); throw new TooLongUnitException($measurement_unit, Constraints::MAX_LENGTH_MEASUREMENT_UNIT);
} }
$this->measurement_unit = $measurement_unit; $this->measurement_unit = $measurement_unit;
return $this; return $this;
@ -251,7 +250,7 @@ class Item extends Entity
* @return $this * @return $this
* @todo Проверка допустимых значений * @todo Проверка допустимых значений
*/ */
public function setPaymentMethod(string $payment_method) public function setPaymentMethod(string $payment_method): Item
{ {
$this->payment_method = trim($payment_method); $this->payment_method = trim($payment_method);
return $this; return $this;
@ -274,30 +273,30 @@ class Item extends Entity
* @return $this * @return $this
* @todo Проверка допустимых значений * @todo Проверка допустимых значений
*/ */
public function setPaymentObject(string $payment_object) public function setPaymentObject(string $payment_object): Item
{ {
$this->payment_object = trim($payment_object); $this->payment_object = trim($payment_object);
return $this; return $this;
} }
/** /**
* Возвращает ставку НДС * Возвращает ставку НДС
* *
* @return \AtolOnline\Entities\Vat|null * @return Vat|null
*/ */
public function getVat(): ?Vat public function getVat(): ?Vat
{ {
return $this->vat; return $this->vat;
} }
/** /**
* Устанавливает ставку НДС * Устанавливает ставку НДС
* *
* @param string|null $vat_type Тип ставки НДС. Передать null, чтобы удалить ставку. * @param string|null $vat_type Тип ставки НДС. Передать null, чтобы удалить ставку.
* @return $this * @return $this
* @throws \AtolOnline\Exceptions\AtolPriceTooHighException * @throws TooHighPriceException
*/ */
public function setVatType(?string $vat_type) public function setVatType(?string $vat_type): Item
{ {
if ($vat_type) { if ($vat_type) {
$this->vat $this->vat
@ -319,19 +318,19 @@ class Item extends Entity
{ {
return $this->user_data; return $this->user_data;
} }
/** /**
* Устанавливает дополнительный реквизит. Тег ФФД - 1191. * Устанавливает дополнительный реквизит. Тег ФФД - 1191.
* *
* @param string $user_data Дополнительный реквизит. Тег ФФД - 1191. * @param string $user_data Дополнительный реквизит. Тег ФФД - 1191.
* @return $this * @return $this
* @throws AtolUserdataTooLongException Слишком длинный дополнительный реквизит * @throws TooLongUserdataException Слишком длинный дополнительный реквизит
*/ */
public function setUserData(string $user_data) public function setUserData(string $user_data): self
{ {
$user_data = trim($user_data); $user_data = trim($user_data);
if (valid_strlen($user_data) > Constraints::MAX_LENGTH_USER_DATA) { if (mb_strlen($user_data) > Constraints::MAX_LENGTH_USER_DATA) {
throw new AtolUserdataTooLongException($user_data, Constraints::MAX_LENGTH_USER_DATA); throw new TooLongUserdataException($user_data, Constraints::MAX_LENGTH_USER_DATA);
} }
$this->user_data = $user_data; $this->user_data = $user_data;
return $this; return $this;
@ -344,24 +343,24 @@ class Item extends Entity
*/ */
public function getSum(): float public function getSum(): float
{ {
return self::toRub($this->sum); return rubles($this->sum);
} }
/** /**
* Расчитывает стоимость и размер НДС на неё * Расчитывает стоимость и размер НДС на неё
* *
* @return float * @return float
* @throws AtolPriceTooHighException Слишком большая сумма * @throws TooHighPriceException Слишком большая сумма
*/ */
public function calcSum() public function calcSum(): float
{ {
$sum = $this->quantity * $this->price; $sum = $this->quantity * $this->price;
if (self::toRub($sum) > 42949672.95) { if (rubles($sum) > 42949672.95) {
throw new AtolPriceTooHighException($sum, 42949672.95); throw new TooHighPriceException($sum, 42949672.95);
} }
$this->sum = $sum; $this->sum = $sum;
if ($this->vat) { if ($this->vat) {
$this->vat->setSum(self::toRub($sum)); $this->vat->setSum(rubles($sum));
} }
return $this->getSum(); return $this->getSum();
} }

View File

@ -1,15 +1,17 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Entities; namespace AtolOnline\Entities;
use AtolOnline\Exceptions\AtolTooManyItemsException; use AtolOnline\Exceptions\TooManyItemsException;
/** /**
* Класс, описывающий массив предметов расчёта * Класс, описывающий массив предметов расчёта
@ -28,13 +30,13 @@ class ItemArray extends Entity
/** /**
* @var Item[] Массив предметов расчёта * @var Item[] Массив предметов расчёта
*/ */
private $items = []; private array $items = [];
/** /**
* ItemArray constructor. * ItemArray constructor.
* *
* @param Item[]|null $items Массив предметов расчёта * @param Item[]|null $items Массив предметов расчёта
* @throws AtolTooManyItemsException Слишком много предметов расчёта * @throws TooManyItemsException Слишком много предметов расчёта
*/ */
public function __construct(?array $items = null) public function __construct(?array $items = null)
{ {
@ -42,30 +44,30 @@ class ItemArray extends Entity
$this->set($items); $this->set($items);
} }
} }
/** /**
* Устанавливает массив предметов расчёта * Устанавливает массив предметов расчёта
* *
* @param Item[] $items Массив предметов расчёта * @param Item[] $items Массив предметов расчёта
* @return $this * @return $this
* @throws AtolTooManyItemsException Слишком много предметов расчёта * @throws TooManyItemsException Слишком много предметов расчёта
*/ */
public function set(array $items) public function set(array $items): ItemArray
{ {
if ($this->validateCount($items)) { if ($this->validateCount($items)) {
$this->items = $items; $this->items = $items;
} }
return $this; return $this;
} }
/** /**
* Добавляет предмет расчёта в массив * Добавляет предмет расчёта в массив
* *
* @param Item $item Объект предмета расчёта * @param Item $item Объект предмета расчёта
* @return $this * @return $this
* @throws AtolTooManyItemsException Слишком много предметов расчёта * @throws TooManyItemsException Слишком много предметов расчёта
*/ */
public function add(Item $item) public function add(Item $item): ItemArray
{ {
if ($this->validateCount()) { if ($this->validateCount()) {
$this->items[] = $item; $this->items[] = $item;
@ -78,7 +80,7 @@ class ItemArray extends Entity
* *
* @return Item[] * @return Item[]
*/ */
public function get() public function get(): array
{ {
return $this->items; return $this->items;
} }
@ -94,19 +96,19 @@ class ItemArray extends Entity
} }
return $result; return $result;
} }
/** /**
* Проверяет количество предметов расчёта * Проверяет количество предметов расчёта
* *
* @param Item[]|null $items Если передать массив, то проверит количество его элементов. * @param Item[]|null $items Если передать массив, то проверит количество его элементов.
* Иначе проверит количество уже присвоенных элементов. * Иначе проверит количество уже присвоенных элементов.
* @return bool true если всё хорошо, иначе выбрасывает исключение * @return bool true если всё хорошо, иначе выбрасывает исключение
* @throws AtolTooManyItemsException Слишком много предметов расчёта * @throws TooManyItemsException Слишком много предметов расчёта
*/ */
protected function validateCount(?array $items = null): bool protected function validateCount(?array $items = null): bool
{ {
if ((!empty($items) && count($items) >= self::MAX_COUNT) || count($this->items) >= self::MAX_COUNT) { if ((!empty($items) && count($items) >= self::MAX_COUNT) || count($this->items) >= self::MAX_COUNT) {
throw new AtolTooManyItemsException(count($items), self::MAX_COUNT); throw new TooManyItemsException(count($items), self::MAX_COUNT);
} }
return true; return true;
} }

View File

@ -1,12 +1,14 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Entities; namespace AtolOnline\Entities;
use AtolOnline\Constants\PaymentTypes; use AtolOnline\Constants\PaymentTypes;
@ -21,12 +23,12 @@ class Payment extends Entity
/** /**
* @var int Тип оплаты * @var int Тип оплаты
*/ */
protected $type; protected int $type;
/** /**
* @var float Сумма оплаты * @var float Сумма оплаты
*/ */
protected $sum; protected float $sum;
/** /**
* Payment constructor. * Payment constructor.
@ -56,7 +58,7 @@ class Payment extends Entity
* @param int $type * @param int $type
* @return $this * @return $this
*/ */
public function setType(int $type) public function setType(int $type): Payment
{ {
$this->type = $type; $this->type = $type;
return $this; return $this;
@ -78,7 +80,7 @@ class Payment extends Entity
* @param float $sum * @param float $sum
* @return $this * @return $this
*/ */
public function setSum(float $sum) public function setSum(float $sum): Payment
{ {
$this->sum = $sum; $this->sum = $sum;
return $this; return $this;

View File

@ -1,15 +1,17 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Entities; namespace AtolOnline\Entities;
use AtolOnline\Exceptions\AtolTooManyPaymentsException; use AtolOnline\Exceptions\TooManyPaymentsException;
/** /**
* Класс, описывающий массив оплат * Класс, описывающий массив оплат
@ -26,13 +28,13 @@ class PaymentArray extends Entity
/** /**
* @var Payment[] Массив оплат * @var Payment[] Массив оплат
*/ */
private $payments = []; private array $payments = [];
/** /**
* ItemArray constructor. * ItemArray constructor.
* *
* @param Payment[]|null $payments Массив оплат * @param Payment[]|null $payments Массив оплат
* @throws AtolTooManyPaymentsException Слишком много оплат * @throws TooManyPaymentsException Слишком много оплат
*/ */
public function __construct(?array $payments = null) public function __construct(?array $payments = null)
{ {
@ -40,30 +42,30 @@ class PaymentArray extends Entity
$this->set($payments); $this->set($payments);
} }
} }
/** /**
* Устанавливает массив оплат * Устанавливает массив оплат
* *
* @param Payment[] $payments * @param Payment[] $payments
* @return $this * @return $this
* @throws AtolTooManyPaymentsException Слишком много оплат * @throws TooManyPaymentsException Слишком много оплат
*/ */
public function set(array $payments) public function set(array $payments): PaymentArray
{ {
if ($this->validateCount($payments)) { if ($this->validateCount($payments)) {
$this->payments = $payments; $this->payments = $payments;
} }
return $this; return $this;
} }
/** /**
* Добавляет новую оплату к заданным * Добавляет новую оплату к заданным
* *
* @param Payment $payment Объект оплаты * @param Payment $payment Объект оплаты
* @return $this * @return $this
* @throws AtolTooManyPaymentsException Слишком много оплат * @throws TooManyPaymentsException Слишком много оплат
*/ */
public function add(Payment $payment) public function add(Payment $payment): PaymentArray
{ {
if ($this->validateCount()) { if ($this->validateCount()) {
$this->payments[] = $payment; $this->payments[] = $payment;
@ -76,7 +78,7 @@ class PaymentArray extends Entity
* *
* @return Payment[] * @return Payment[]
*/ */
public function get() public function get(): array
{ {
return $this->payments; return $this->payments;
} }
@ -92,19 +94,19 @@ class PaymentArray extends Entity
} }
return $result; return $result;
} }
/** /**
* Проверяет количество налоговых ставок * Проверяет количество налоговых ставок
* *
* @param Payment[]|null $payments Если передать массив, то проверит количество его элементов. * @param Payment[]|null $payments Если передать массив, то проверит количество его элементов.
* Иначе проверит количество уже присвоенных элементов. * Иначе проверит количество уже присвоенных элементов.
* @return bool true если всё хорошо, иначе выбрасывает исключение * @return bool true если всё хорошо, иначе выбрасывает исключение
* @throws AtolTooManyPaymentsException Слишком много оплат * @throws TooManyPaymentsException Слишком много оплат
*/ */
protected function validateCount(?array $payments = null): bool protected function validateCount(?array $payments = null): bool
{ {
if ((!empty($payments) && count($payments) >= self::MAX_COUNT) || count($this->payments) >= self::MAX_COUNT) { if ((!empty($payments) && count($payments) >= self::MAX_COUNT) || count($this->payments) >= self::MAX_COUNT) {
throw new AtolTooManyPaymentsException(count($payments), self::MAX_COUNT); throw new TooManyPaymentsException(count($payments), self::MAX_COUNT);
} }
return true; return true;
} }

View File

@ -1,15 +1,17 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Entities; namespace AtolOnline\Entities;
use AtolOnline\{Constants\VatTypes, Traits\RublesKopeksConverter}; use AtolOnline\Constants\VatTypes;
/** /**
* Класс, описывающий ставку НДС * Класс, описывающий ставку НДС
@ -18,22 +20,20 @@ use AtolOnline\{Constants\VatTypes, Traits\RublesKopeksConverter};
*/ */
class Vat extends Entity class Vat extends Entity
{ {
use RublesKopeksConverter;
/** /**
* @var string Выбранный тип ставки НДС. Тег ФФД - 1199, 1105, 1104, 1103, 1102, 1107, 1106. * @var string Выбранный тип ставки НДС. Тег ФФД - 1199, 1105, 1104, 1103, 1102, 1107, 1106.
*/ */
private $type; private string $type;
/** /**
* @var int Сумма в копейках, от которой пересчитывается размер НДС * @var int Сумма в копейках, от которой пересчитывается размер НДС
*/ */
private $sum_original = 0; private int $sum_original = 0;
/** /**
* @var int Сумма НДС в копейках * @var int Сумма НДС в копейках
*/ */
private $sum_final = 0; private int $sum_final = 0;
/** /**
* Vat constructor. * Vat constructor.
@ -99,7 +99,7 @@ class Vat extends Entity
* @param string $type Тип ставки НДС * @param string $type Тип ставки НДС
* @return $this * @return $this
*/ */
public function setType(string $type) public function setType(string $type): Vat
{ {
$this->type = $type; $this->type = $type;
$this->setFinal(); $this->setFinal();
@ -111,9 +111,9 @@ class Vat extends Entity
* *
* @return float * @return float
*/ */
public function getFinalSum() public function getFinalSum(): float
{ {
return self::toRub($this->sum_final); return rubles($this->sum_final);
} }
/** /**
@ -123,9 +123,9 @@ class Vat extends Entity
* @param float $rubles Сумма в рублях за предмет расчёта, из которой высчитывается размер НДС * @param float $rubles Сумма в рублях за предмет расчёта, из которой высчитывается размер НДС
* @return $this * @return $this
*/ */
public function setSum(float $rubles) public function setSum(float $rubles): Vat
{ {
$this->sum_original = self::toKop($rubles); $this->sum_original = kopeks($rubles);
$this->setFinal(); $this->setFinal();
return $this; return $this;
} }
@ -137,7 +137,7 @@ class Vat extends Entity
*/ */
public function getSum(): float public function getSum(): float
{ {
return self::toRub($this->sum_original); return rubles($this->sum_original);
} }
/** /**
@ -147,9 +147,9 @@ class Vat extends Entity
* @param float $rubles * @param float $rubles
* @return $this * @return $this
*/ */
public function addSum(float $rubles) public function addSum(float $rubles): Vat
{ {
$this->sum_original += self::toKop($rubles); $this->sum_original += kopeks($rubles);
$this->setFinal(); $this->setFinal();
return $this; return $this;
} }
@ -163,7 +163,7 @@ class Vat extends Entity
*/ */
public function calc(float $rubles): float public function calc(float $rubles): float
{ {
return self::toRub(self::calculator($this->type, self::toKop($rubles))); return rubles(self::calculator($this->type, kopeks($rubles)));
} }
/** /**
@ -180,7 +180,7 @@ class Vat extends Entity
/** /**
* Расчитывает и устанавливает итоговый размер ставки от исходной суммы в копейках * Расчитывает и устанавливает итоговый размер ставки от исходной суммы в копейках
*/ */
protected function setFinal() protected function setFinal(): Vat
{ {
$this->sum_final = self::calculator($this->type, $this->sum_original); $this->sum_final = self::calculator($this->type, $this->sum_original);
return $this; return $this;

View File

@ -1,15 +1,17 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Entities; namespace AtolOnline\Entities;
use AtolOnline\Exceptions\AtolTooManyVatsException; use AtolOnline\Exceptions\TooManyVatsException;
/** /**
* Класс, описывающий массив ставок НДС * Класс, описывающий массив ставок НДС
@ -26,13 +28,13 @@ class VatArray extends Entity
/** /**
* @var Vat[] Массив ставок НДС * @var Vat[] Массив ставок НДС
*/ */
private $vats = []; private array $vats = [];
/** /**
* VatArray constructor. * VatArray constructor.
* *
* @param Vat[]|null $vats Массив ставок НДС * @param Vat[]|null $vats Массив ставок НДС
* @throws AtolTooManyVatsException Слишком много ставок НДС * @throws TooManyVatsException Слишком много ставок НДС
*/ */
public function __construct(?array $vats = null) public function __construct(?array $vats = null)
{ {
@ -40,30 +42,30 @@ class VatArray extends Entity
$this->set($vats); $this->set($vats);
} }
} }
/** /**
* Устанавливает массив ставок НДС * Устанавливает массив ставок НДС
* *
* @param Vat[] $vats Массив ставок НДС * @param Vat[] $vats Массив ставок НДС
* @return $this * @return $this
* @throws AtolTooManyVatsException Слишком много ставок НДС * @throws TooManyVatsException Слишком много ставок НДС
*/ */
public function set(array $vats) public function set(array $vats): VatArray
{ {
if ($this->validateCount($vats)) { if ($this->validateCount($vats)) {
$this->vats = $vats; $this->vats = $vats;
} }
return $this; return $this;
} }
/** /**
* Добавляет новую ставку НДС в массив * Добавляет новую ставку НДС в массив
* *
* @param Vat $vat Объект ставки НДС * @param Vat $vat Объект ставки НДС
* @return $this * @return $this
* @throws AtolTooManyVatsException Слишком много ставок НДС * @throws TooManyVatsException Слишком много ставок НДС
*/ */
public function add(Vat $vat) public function add(Vat $vat): VatArray
{ {
if ($this->validateCount()) { if ($this->validateCount()) {
if (isset($this->vats[$vat->getType()])) { if (isset($this->vats[$vat->getType()])) {
@ -80,7 +82,7 @@ class VatArray extends Entity
* *
* @return Vat[] * @return Vat[]
*/ */
public function get() public function get(): array
{ {
return $this->vats; return $this->vats;
} }
@ -96,19 +98,19 @@ class VatArray extends Entity
} }
return $result; return $result;
} }
/** /**
* Проверяет количество налоговых ставок * Проверяет количество налоговых ставок
* *
* @param Vat[]|null $vats Если передать массив, то проверит количество его элементов. * @param Vat[]|null $vats Если передать массив, то проверит количество его элементов.
* Иначе проверит количество уже присвоенных элементов. * Иначе проверит количество уже присвоенных элементов.
* @return bool true если всё хорошо, иначе выбрасывает исключение * @return bool true если всё хорошо, иначе выбрасывает исключение
* @throws AtolTooManyVatsException Слишком много ставок НДС * @throws TooManyVatsException Слишком много ставок НДС
*/ */
protected function validateCount(?array $vats = null): bool protected function validateCount(?array $vats = null): bool
{ {
if ((!empty($vats) && count($vats) >= self::MAX_COUNT) || count($this->vats) >= self::MAX_COUNT) { if ((!empty($vats) && count($vats) >= self::MAX_COUNT) || count($this->vats) >= self::MAX_COUNT) {
throw new AtolTooManyVatsException(count($vats), self::MAX_COUNT); throw new TooManyVatsException(count($vats), self::MAX_COUNT);
} }
return true; return true;
} }

View File

@ -1,12 +1,14 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
use Exception; use Exception;
@ -14,22 +16,20 @@ use Throwable;
/** /**
* Исключение, возникающее при работе с АТОЛ Онлайн * Исключение, возникающее при работе с АТОЛ Онлайн
*
* @package AtolOnline\Exceptions
*/ */
class AtolException extends Exception class AtolException extends Exception
{ {
/** /**
* @var int[] Теги ФФД * @var int[] Теги ФФД
*/ */
protected $ffd_tags = null; protected array $ffd_tags = [];
/** /**
* AtolException constructor. * AtolException constructor.
* *
* @param string $message * @param string $message
* @param int $code * @param int $code
* @param \Throwable|null $previous * @param Throwable|null $previous
*/ */
public function __construct($message = "", $code = 0, Throwable $previous = null) public function __construct($message = "", $code = 0, Throwable $previous = null)
{ {
@ -39,13 +39,13 @@ class AtolException extends Exception
} }
parent::__construct($message, $code, $previous); parent::__construct($message, $code, $previous);
} }
/** /**
* Возвращает теги ФФД, с которыми связано исключение * Возвращает теги ФФД, с которыми связано исключение
* *
* @return array|null * @return array
*/ */
protected function getFfdTags(): ?array protected function getFfdTags(): array
{ {
return $this->ffd_tags; return $this->ffd_tags;
} }

View File

@ -1,12 +1,14 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
use AtolOnline\Api\KktResponse; use AtolOnline\Api\KktResponse;
@ -15,26 +17,24 @@ use Throwable;
/** /**
* Исключение, возникающее при работе с АТОЛ Онлайн * Исключение, возникающее при работе с АТОЛ Онлайн
*
* @package AtolOnline\Exceptions
*/ */
class AtolAuthFailedException extends Exception class AuthFailedException extends Exception
{ {
/** /**
* AtolAuthFailedException constructor. * Конструктор
* *
* @param \AtolOnline\Api\KktResponse $last_response * @param KktResponse $last_response
* @param string $message * @param string $message
* @param int $code * @param int $code
* @param \Throwable|null $previous * @param Throwable|null $previous
*/ */
public function __construct(KktResponse $last_response, $message = "", $code = 0, Throwable $previous = null) public function __construct(KktResponse $last_response, $message = "", $code = 0, Throwable $previous = null)
{ {
$message = $last_response->isValid() $message = $last_response->isValid()
? $message ? $message
: '['.$last_response->error->code.'] '.$last_response->error->text. : '[' . $last_response->error->code . '] ' . $last_response->error->text .
'. ERROR_ID: '.$last_response->error->error_id. '. ERROR_ID: ' . $last_response->error->error_id .
'. TYPE: '.$last_response->error->type; '. TYPE: ' . $last_response->error->type;
$code = $last_response->isValid() ? $code : $last_response->error->code; $code = $last_response->isValid() ? $code : $last_response->error->code;
parent::__construct($message, $code, $previous); parent::__construct($message, $code, $previous);
} }

View File

@ -1,40 +1,40 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
use Throwable; use Throwable;
/** /**
* Исключение, возникающее при попытке указать слишком длинное что-либо * Исключение, возникающее при попытке указать слишком длинное что-либо
*
* @package AtolOnline\Exceptions
*/ */
class AtolTooLongException extends AtolException class BasicTooLongException extends AtolException
{ {
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке
*/ */
protected $message = 'Parameter is too long'; protected $message = 'Parameter is too long';
/** /**
* AtolTooLongException constructor. * AtolTooLongException constructor.
* *
* @param $string * @param $string
* @param $max * @param $max
* @param string $message * @param string $message
* @param int $code * @param int $code
* @param Throwable|null $previous * @param Throwable|null $previous
*/ */
public function __construct($string, $max, $message = "", $code = 0, Throwable $previous = null) public function __construct($string, $max, $message = "", int $code = 0, Throwable $previous = null)
{ {
parent::__construct($message ?: $this->message.' (max length - '.$max.', actual length - '. parent::__construct($message ?: $this->message . ' (max length - ' . $max . ', actual length - ' .
valid_strlen($string), $code, $previous); mb_strlen($string), $code, $previous);
} }
} }

View File

@ -1,40 +1,43 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
use Throwable; use Throwable;
/** /**
* Исключение, возникающее при попытке указать слишком большое количество чего-либо * Исключение, возникающее при попытке указать слишком большое количество чего-либо
*
* @package AtolOnline\Exceptions
*/ */
class AtolTooManyException extends AtolException class BasicTooManyException extends AtolException
{ {
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке
*/ */
protected $message = 'Quantity is too high'; protected $message = 'Quantity is too high';
/** /**
* AtolTooManyException constructor. * AtolTooManyException constructor.
* *
* @param $quantity * @param float $quantity
* @param $max * @param float $max
* @param string $message * @param string $message
* @param int $code * @param int $code
* @param Throwable|null $previous * @param Throwable|null $previous
*/ */
public function __construct($quantity, $max, $message = "", $code = 0, Throwable $previous = null) public function __construct(float $quantity, float $max, $message = "", int $code = 0, Throwable $previous = null)
{ {
$message = $message ?: $this->message.' (max - '.$max.', actual - '.$quantity.')'; parent::__construct(
parent::__construct($message, $code, $previous); $message ?: $this->message . ' (max - ' . $max . ', actual - ' . $quantity . ')',
$code,
$previous
);
} }
} }

View File

@ -1,20 +1,20 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке зарегистрировать документ без данных коррекции * Исключение, возникающее при попытке зарегистрировать документ без данных коррекции
*
* @package AtolOnline\Exceptions
*/ */
class AtolCorrectionInfoException extends AtolException class EmptyCorrectionInfoException extends AtolException
{ {
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке

View File

@ -1,29 +1,29 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать пустой email * Исключение, возникающее при попытке указать пустой email
*
* @package AtolOnline\Exceptions
*/ */
class AtolEmailEmptyException extends AtolException class EmptyEmailException extends AtolException
{ {
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $ffd_tags = [ protected array $ffd_tags = [
1008, 1008,
1117, 1117,
]; ];
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке
*/ */

View File

@ -1,20 +1,20 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать пустой логин ККТ * Исключение, возникающее при попытке указать пустой логин ККТ
*
* @package AtolOnline\Exceptions
*/ */
class AtolKktLoginEmptyException extends AtolException class EmptyKktLoginException extends AtolException
{ {
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке

View File

@ -1,20 +1,20 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать пустой пароль ККТ * Исключение, возникающее при попытке указать пустой пароль ККТ
*
* @package AtolOnline\Exceptions
*/ */
class AtolKktPasswordEmptyException extends AtolException class EmptyKktPasswordException extends AtolException
{ {
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке

View File

@ -1,20 +1,20 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать невалидный callback_url * Исключение, возникающее при попытке указать невалидный callback_url
*
* @package AtolOnline\Exceptions
*/ */
class AtolInvalidCallbackUrlException extends AtolException class InvalidCallbackUrlException extends AtolException
{ {
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке

View File

@ -0,0 +1,38 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline\Exceptions;
use AtolOnline\Constants\DocumentTypes;
use Throwable;
/**
* Исключение, возникающее при попытке указать некорректный тип документа
*/
class InvalidDocumentTypeException extends AtolException
{
/**
* Конструктор
*
* @param string $type
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct($type = '', $message = "", $code = 0, Throwable $previous = null)
{
parent::__construct(
$message ?: "Wrong document type: '$type'. Valid ones: " . implode(', ', DocumentTypes::toArray()),
$code,
$previous
);
}
}

View File

@ -0,0 +1,41 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline\Exceptions;
use Throwable;
/**
* Исключение, возникающее при ошибке валидации email
*/
class InvalidEmailException extends AtolException
{
/**
* @inheritDoc
*/
protected array $ffd_tags = [
1008,
1117,
];
/**
* AtolEmailValidateException constructor.
*
* @param string $email
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $email = '', $message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message ?: "Invalid email: '$email'", $code, $previous);
}
}

View File

@ -0,0 +1,47 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline\Exceptions;
use Throwable;
/**
* Исключение, возникающее при попытке указать ИНН некорректной длины
*/
class InvalidInnLengthException extends AtolException
{
/**
* @inheritDoc
*/
protected array $ffd_tags = [
1016,
1018,
1226,
1228,
];
/**
* AtolInnWrongLengthException constructor.
*
* @param string $inn
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct($inn = '', $message = "", $code = 0, Throwable $previous = null)
{
parent::__construct(
$message ?: 'INN length must be 10 or 12 digits only, actual is ' . strlen($inn),
$code,
$previous
);
}
}

View File

@ -1,32 +1,36 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
use Throwable; use Throwable;
/** /**
* Исключение, возникающее при работе с невалидным JSON * Исключение, возникающее при работе с невалидным JSON
*
* @package AtolOnline\Exceptions
*/ */
class AtolInvalidJsonException extends AtolException class InvalidJsonException extends AtolException
{ {
/** /**
* AtolInnWrongLengthException constructor. * AtolInnWrongLengthException constructor.
* *
* @param string $message * @param string $message
* @param int $code * @param int $code
* @param Throwable|null $previous * @param Throwable|null $previous
*/ */
public function __construct($message = "", $code = 0, Throwable $previous = null) public function __construct($message = "", $code = 0, Throwable $previous = null)
{ {
parent::__construct($message ?: 'Invalid JSON: ['.json_last_error().'] '.json_last_error_msg(), $code, $previous); parent::__construct(
$message ?: 'Invalid JSON: [' . json_last_error() . '] ' . json_last_error_msg(),
$code,
$previous
);
} }
} }

View File

@ -0,0 +1,44 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline\Exceptions;
use Throwable;
/**
* Исключение, возникающее при попытке указать некорректный платёжный адрес
*/
class InvalidPaymentAddressException extends AtolException
{
/**
* @inheritDoc
*/
protected array $ffd_tags = [
1187,
];
/**
* Конструктор
*
* @param string $address
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct($address = '', $message = "", $code = 0, Throwable $previous = null)
{
parent::__construct(
$message ?: "Wrong payment address: '$address'",
$code,
$previous
);
}
}

View File

@ -0,0 +1,45 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline\Exceptions;
use AtolOnline\Constants\SnoTypes;
use Throwable;
/**
* Исключение, возникающее при попытке указать некорректную СНО
*/
class InvalidSnoException extends AtolException
{
/**
* @inheritDoc
*/
protected array $ffd_tags = [
1055,
];
/**
* Конструктор
*
* @param string $sno
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct($sno = '', $message = "", $code = 0, Throwable $previous = null)
{
parent::__construct(
$message ?: "Wrong SNO: '$sno'. Valid ones: " . implode(', ', SnoTypes::toArray()),
$code,
$previous
);
}
}

View File

@ -1,30 +1,30 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
use Throwable; use Throwable;
/** /**
* Исключение, возникающее при ошибке валидации UUID * Исключение, возникающее при ошибке валидации UUID
*
* @package AtolOnline\Exceptions
*/ */
class AtolInvalidUuidException extends AtolException class InvalidUuidException extends AtolException
{ {
/** /**
* AtolInvalidUuidException constructor. * AtolInvalidUuidException constructor.
* *
* @param $uuid * @param $uuid
* @param string $message * @param string $message
* @param int $code * @param int $code
* @param \Throwable|null $previous * @param Throwable|null $previous
*/ */
public function __construct($uuid, $message = "", $code = 0, Throwable $previous = null) public function __construct($uuid, $message = "", $code = 0, Throwable $previous = null)
{ {

View File

@ -1,28 +1,28 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать слишком высокую цену (сумму) * Исключение, возникающее при попытке указать слишком высокую цену (сумму)
*
* @package AtolOnline\Exceptions
*/ */
class AtolPriceTooHighException extends AtolTooManyException class TooHighPriceException extends BasicTooManyException
{ {
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $ffd_tags = [ protected array $ffd_tags = [
1079, 1079,
]; ];
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке
*/ */

View File

@ -1,20 +1,20 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать слишком длинный callback_url * Исключение, возникающее при попытке указать слишком длинный callback_url
*
* @package AtolOnline\Exceptions
*/ */
class AtolCallbackUrlTooLongException extends AtolTooLongException class TooLongCallbackUrlException extends BasicTooLongException
{ {
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке

View File

@ -1,28 +1,28 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать слишком длинное имя кассира * Исключение, возникающее при попытке указать слишком длинное имя кассира
*
* @package AtolOnline\Exceptions
*/ */
class AtolCashierTooLongException extends AtolTooLongException class TooLongCashierException extends BasicTooLongException
{ {
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $ffd_tags = [ protected array $ffd_tags = [
1021, 1021,
]; ];
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке
*/ */

View File

@ -1,29 +1,29 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать слишком длинный email * Исключение, возникающее при попытке указать слишком длинный email
*
* @package AtolOnline\Exceptions
*/ */
class AtolEmailTooLongException extends AtolTooLongException class TooLongEmailException extends BasicTooLongException
{ {
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $ffd_tags = [ protected array $ffd_tags = [
1008, 1008,
1117, 1117,
]; ];
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке
*/ */

View File

@ -1,20 +1,20 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать слишком длинный логин ККТ * Исключение, возникающее при попытке указать слишком длинный логин ККТ
*
* @package AtolOnline\Exceptions
*/ */
class AtolKktLoginTooLongException extends AtolTooLongException class TooLongKktLoginException extends BasicTooLongException
{ {
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке

View File

@ -1,20 +1,20 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать слишком длинный пароль ККТ * Исключение, возникающее при попытке указать слишком длинный пароль ККТ
*
* @package AtolOnline\Exceptions
*/ */
class AtolKktPasswordTooLongException extends AtolTooLongException class TooLongKktPasswordException extends BasicTooLongException
{ {
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке

View File

@ -1,25 +1,25 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать слишком длинное имя * Исключение, возникающее при попытке указать слишком длинное имя
*
* @package AtolOnline\Exceptions
*/ */
class AtolNameTooLongException extends AtolTooLongException class TooLongNameException extends BasicTooLongException
{ {
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $ffd_tags = [ protected array $ffd_tags = [
1026, 1026,
1030, 1030,
1085, 1085,

View File

@ -1,28 +1,28 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать слишком длинный платёжный адрес * Исключение, возникающее при попытке указать слишком длинный платёжный адрес
*
* @package AtolOnline\Exceptions
*/ */
class AtolPaymentAddressTooLongException extends AtolException class TooLongPaymentAddressException extends AtolException
{ {
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $ffd_tags = [ protected array $ffd_tags = [
1187, 1187,
]; ];
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке
*/ */

View File

@ -1,25 +1,25 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать слишком длинный телефон * Исключение, возникающее при попытке указать слишком длинный телефон
*
* @package AtolOnline\Exceptions
*/ */
class AtolPhoneTooLongException extends AtolTooLongException class TooLongPhoneException extends BasicTooLongException
{ {
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $ffd_tags = [ protected array $ffd_tags = [
1008, 1008,
1073, 1073,
1074, 1074,

View File

@ -1,28 +1,28 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать слишком длинный телефон * Исключение, возникающее при попытке указать слишком длинный телефон
*
* @package AtolOnline\Exceptions
*/ */
class AtolUnitTooLongException extends AtolTooLongException class TooLongUnitException extends BasicTooLongException
{ {
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $ffd_tags = [ protected array $ffd_tags = [
1197, 1197,
]; ];
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке
*/ */

View File

@ -1,28 +1,28 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке указать слишком длинный дополнительный реквизит * Исключение, возникающее при попытке указать слишком длинный дополнительный реквизит
*
* @package AtolOnline\Exceptions
*/ */
class AtolUserdataTooLongException extends AtolTooLongException class TooLongUserdataException extends BasicTooLongException
{ {
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $ffd_tags = [ protected array $ffd_tags = [
1191, 1191,
]; ];
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке
*/ */

View File

@ -1,20 +1,20 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке добавить слишком много предметов расчёта в массив * Исключение, возникающее при попытке добавить слишком много предметов расчёта в массив
*
* @package AtolOnline\Exceptions
*/ */
class AtolTooManyItemsException extends AtolTooManyException class TooManyItemsException extends BasicTooManyException
{ {
/** /**
* @var string Сообщение об ошибке * @var string Сообщение об ошибке

View File

@ -1,25 +1,25 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке добавить слишком много платежей в массив * Исключение, возникающее при попытке добавить слишком много платежей в массив
*
* @package AtolOnline\Exceptions
*/ */
class AtolTooManyPaymentsException extends AtolTooManyException class TooManyPaymentsException extends BasicTooManyException
{ {
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $ffd_tags = [ protected array $ffd_tags = [
1031, 1031,
1081, 1081,
1215, 1215,

View File

@ -1,25 +1,25 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Exceptions; namespace AtolOnline\Exceptions;
/** /**
* Исключение, возникающее при попытке добавить слишком много ставок НДС в массив * Исключение, возникающее при попытке добавить слишком много ставок НДС в массив
*
* @package AtolOnline\Exceptions
*/ */
class AtolTooManyVatsException extends AtolTooManyException class TooManyVatsException extends BasicTooManyException
{ {
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $ffd_tags = [ protected array $ffd_tags = [
1102, 1102,
1103, 1103,
1104, 1104,

55
src/Helpers.php 100644
View File

@ -0,0 +1,55 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline;
/**
* Класс с функциями-хелперами
*/
final class Helpers
{
/**
* Конвертирует копейки в рубли, оставляя только 2 знака после запятой
*
* @param int|null $kopeks Копейки
* @return float Рубли
*/
public static function KopToRub(?int $kopeks): float
{
return round(abs((int)$kopeks) / 100, 2);
}
/**
* Конвертирует рубли в копейки, учитывая только 2 знака после запятой
*
* @param float|null $rubles Рубли
* @return int Копейки
*/
public static function RubToKop(?float $rubles): int
{
return (int)round(abs((float)$rubles) * 100, 2);
}
/**
* Генерирует случайную строку указанной длины
*
* @param int $length Длина, по умолчнанию 8
* @param bool $with_digits Включать ли цифры
* @return string
*/
public static function randomStr(int $length = 8, bool $with_digits = true): string
{
$alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' . ($with_digits ? '0123456789' : '');
$result = '';
for ($i = 0; $i < abs($length); $i++) {
$result .= $alphabet[mt_rand(0, strlen($alphabet) - 1)];
}
return $result;
}
}

View File

@ -0,0 +1,58 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline;
/**
* Константы, определяющие параметры тестовой среды для ФФД 1.05
*
* @see https://online.atol.ru/files/ffd/test_sreda.txt Параметры настройки тестовых сред
*/
class TestEnvParams
{
/**
* Возвращает данные для работы с тестовой средой АТОЛ Онлайн ФФД 1.05
*
* @return string[]
*/
public static function FFD105(): array
{
return [
'endpoint' => 'https://testonline.atol.ru/possystem/v4/',
'company_name' => 'АТОЛ',
'inn' => '5544332219',
'payment_address' => 'https://v4.online.atol.ru',
'group' => 'v4-online-atol-ru_4179',
'login' => 'v4-online-atol-ru',
'password' => 'iGFFuihss',
'endpoint_ofd' => 'https://consumer.1-ofd-test.ru/v1',
];
}
/**
* Возвращает данные для работы с тестовой средой АТОЛ Онлайн ФФД 1.2
*
* @return string[]
*/
public static function FFD12(): array
{
return [
'endpoint' => 'https://testonline.atol.ru/possystem/v5/',
'company_name' => 'АТОЛ',
'inn' => '5544332219',
'payment_address' => 'https://v5.online.atol.ru',
'group' => 'v5-online-atol-ru_5179',
'login' => 'v5-online-atol-ru',
'password' => 'zUr0OxfI',
'endpoint_ofd' => '',
];
}
}

View File

@ -1,16 +0,0 @@
<?php
if (!function_exists('valid_strlen')) {
/**
* Возвращает корректную длину строки
*
* @param string $value
* @return int
*/
function valid_strlen(string $value): int
{
return function_exists('mb_strlen')
? mb_strlen($value)
: strlen($value);
}
}

View File

@ -1,12 +1,16 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
declare(strict_types = 1);
namespace AtolOnline\Tests;
use AtolOnline\Entities\Entity; use AtolOnline\Entities\Entity;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@ -16,7 +20,7 @@ use PHPUnit\Framework\TestCase;
class BasicTestCase extends TestCase class BasicTestCase extends TestCase
{ {
/** /**
* * @todo требуется рефакторинг
*/ */
public function setUp(): void public function setUp(): void
{ {
@ -26,38 +30,56 @@ class BasicTestCase extends TestCase
defined('ATOL_KKT_PASS') ?: define('ATOL_KKT_PASS', 'iGFFuihss'); defined('ATOL_KKT_PASS') ?: define('ATOL_KKT_PASS', 'iGFFuihss');
defined('ATOL_CALLBACK_URL') ?: define('ATOL_CALLBACK_URL', 'http://example.com/callback'); defined('ATOL_CALLBACK_URL') ?: define('ATOL_CALLBACK_URL', 'http://example.com/callback');
} }
/** /**
* Тестирует является ли объект приводимым к json-строке согласно схеме АТОЛ Онлайн
*
* @param Entity $entity * @param Entity $entity
* @return $this * @param array $json_structure
* @covers \AtolOnline\Entities\Entity::jsonSerialize
* @covers \AtolOnline\Entities\Entity::__toString
*/ */
public function checkAtolEntity(Entity $entity) public function assertAtolable(Entity $entity, array $json_structure = []): void
{ {
$this->assertIsObject($entity);
$this->assertIsObject($entity->jsonSerialize());
$this->assertIsString((string)$entity);
$this->assertJson((string)$entity); $this->assertJson((string)$entity);
return $this; if ($json_structure) {
} $this->assertEquals(json_encode($json_structure), (string)$entity);
/**
*
*/
public function tearDown(): void
{
//parent::tearDown();
}
/**
* Возвращает случайную строку указанной длины
*
* @param int $length
* @return string
*/
protected static function randomString($length = 8)
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$string = '';
for ($i = 0; $i < $length; $i++) {
$string .= $characters[mt_rand(0, strlen($characters) - 1)];
} }
return $string; }
/**
* Провайдер валидных телефонов
*
* @return array<array<string, string>>
*/
public function providerValidPhones(): array
{
return [
['+79991234567', '+79991234567'],
['79991234567', '+79991234567'],
['89991234567', '+89991234567'],
['+7 999 123 45 67', '+79991234567'],
['+7 (999) 123-45-67', '+79991234567'],
["+7 %(?9:9\"9')abc\r123\n45\t67\0", '+79991234567'],
];
}
/**
* Провайдер валидных email-ов
*
* @return array<array<string>>
*/
public function providerValidEmails(): array
{
return [
['abc@mail.com'],
['abc-d@mail.com'],
['abc.def@mail.com'],
['abc.def@mail.org'],
['abc.def@mail-archive.com'],
];
} }
} }

View File

@ -0,0 +1,317 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Tests;
use AtolOnline\{
Entities\Client,
Exceptions\InvalidEmailException,
Exceptions\InvalidInnLengthException,
Exceptions\TooLongEmailException,
Exceptions\TooLongNameException,
Exceptions\TooLongPhoneException,
Helpers};
/**
* Набор тестов для проверки работы класс покупателя
*/
class ClientTest extends BasicTestCase
{
/**
* Провайдер строк, которые приводятся к null
*
* @return array<array<string|null>>
*/
public function providerNullableStrings(): array
{
return [
[''],
[' '],
[null],
["\n\r\t"],
];
}
/**
* Провайдер телефонов, которые приводятся к null
*
* @return array<array<string>>
*/
public function providerNullablePhones(): array
{
return array_merge(
$this->providerNullableStrings(),
[
[Helpers::randomStr(10, false)],
["asdfgvs \n\rtt\t*/(*&%^*$%"],
]
);
}
/**
* Провайдер невалидных email-ов
*
* @return array<array<string>>
*/
public function providerInvalidEmails(): array
{
return [
['@example'],
[Helpers::randomStr(15)],
['@example.com'],
['abc.def@mail'],
['.abc@mail.com'],
['example@example'],
['abc..def@mail.com'],
['abc.def@mail..com'],
['abc.def@mail#archive.com'],
];
}
//------------------------------------------------------------------------------------------------------------------
/**
* Тестирует приведение покупателя к json
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::jsonSerialize
*/
public function testAtolable(): void
{
$this->assertAtolable(new Client());
}
/**
* Тестирует конструктор покупателя без передачи значений
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::jsonSerialize
*/
public function testConstructorWithoutArgs(): void
{
$this->assertEquals('{}', (string)(new Client()));
}
/**
* Тестирует конструктор с передачей значений (внутри работают сеттеры)
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::jsonSerialize
* @covers \AtolOnline\Entities\Client::setName
* @covers \AtolOnline\Entities\Client::setPhone
* @covers \AtolOnline\Entities\Client::setEmail
* @covers \AtolOnline\Entities\Client::setInn
*/
public function testConstructorWithArgs(): void
{
$customer = new Client(
'John Doe',
'john@example.com',
'+1/22/99*73s dsdas654 5s6', // +122997365456
'+fasd3\qe3fs_=nac99013928czc' // 3399013928
);
$this->assertAtolable($customer, [
'name' => 'John Doe',
'email' => 'john@example.com',
'phone' => '+122997365456',
'inn' => '3399013928',
]);
}
//------------------------------------------------------------------------------------------------------------------
/**
* Тестирует установку имён покупателя, которые приводятся к null
*
* @param mixed $name
* @dataProvider providerNullableStrings
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setName
* @covers \AtolOnline\Entities\Client::getName
* @throws TooLongNameException
*/
public function testNullableNames(mixed $name): void
{
$customer = (new Client())->setName($name);
$this->assertNull($customer->getName());
}
/**
* Тестирует установку валидного имени покупателя
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setName
* @covers \AtolOnline\Entities\Client::getName
* @throws TooLongNameException
*/
public function testValidName(): void
{
$name = Helpers::randomStr();
$customer = (new Client())->setName($name);
$this->assertEquals($name, $customer->getName());
}
/**
* Тестирует установку невалидного имени покупателя
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setName
* @covers \AtolOnline\Exceptions\TooLongNameException
* @throws TooLongNameException
*/
public function testInvalidName(): void
{
$this->expectException(TooLongNameException::class);
(new Client())->setName(Helpers::randomStr(400));
}
//------------------------------------------------------------------------------------------------------------------
/**
* Тестирует установку телефонов покупателя, которые приводятся к null
*
* @param mixed $phone
* @dataProvider providerNullablePhones
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setPhone
* @covers \AtolOnline\Entities\Client::getPhone
* @throws TooLongPhoneException
*/
public function testNullablePhones(mixed $phone): void
{
$customer = (new Client())->setPhone($phone);
$this->assertNull($customer->getPhone());
}
/**
* Тестирует установку валидного телефона покупателя
*
* @dataProvider providerValidPhones
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setPhone
* @covers \AtolOnline\Entities\Client::getPhone
* @throws TooLongPhoneException
*/
public function testValidPhone(string $input, string $output): void
{
$customer = (new Client())->setPhone($input);
$this->assertEquals($output, $customer->getPhone());
}
/**
* Тестирует установку невалидного телефона покупателя
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setPhone
* @covers \AtolOnline\Exceptions\TooLongPhoneException
* @throws TooLongPhoneException
*/
public function testInvalidPhone(): void
{
$this->expectException(TooLongPhoneException::class);
(new Client())->setPhone('99999999999999999999999999999999999999999999999999999999999999999999999999');
}
//------------------------------------------------------------------------------------------------------------------
/**
* Тестирует установку валидных email-ов покупателя
*
* @param mixed $email
* @dataProvider providerValidEmails
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setEmail
* @covers \AtolOnline\Entities\Client::getEmail
* @throws TooLongEmailException
* @throws InvalidEmailException
*/
public function testValidEmails(mixed $email): void
{
$customer = (new Client())->setEmail($email);
$this->assertEquals($email, $customer->getEmail());
}
/**
* Тестирует установку слишком длинного email покупателя
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setEmail
* @covers \AtolOnline\Exceptions\TooLongEmailException
* @throws TooLongEmailException
* @throws InvalidEmailException
*/
public function testTooLongEmail(): void
{
$this->expectException(TooLongEmailException::class);
(new Client())->setEmail(Helpers::randomStr(65));
}
/**
* Тестирует установку невалидного email покупателя
*
* @param mixed $email
* @dataProvider providerInvalidEmails
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setEmail
* @covers \AtolOnline\Exceptions\InvalidEmailException
* @throws TooLongEmailException
* @throws InvalidEmailException
*/
public function testInvalidEmail(mixed $email): void
{
$this->expectException(InvalidEmailException::class);
(new Client())->setEmail($email);
}
//------------------------------------------------------------------------------------------------------------------
/**
* Тестирует исключение о корректной длине ИНН
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setInn
* @covers \AtolOnline\Entities\Client::getInn
* @throws InvalidInnLengthException
*/
public function testValidInn(): void
{
$customer = (new Client())->setInn('1234567890');
$this->assertEquals('1234567890', $customer->getInn());
$customer = $customer->setInn('123456789012');
$this->assertEquals('123456789012', $customer->getInn());
}
/**
* Тестирует исключение о некорректной длине ИНН (10 цифр)
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setInn
* @covers \AtolOnline\Exceptions\InvalidInnLengthException
* @throws InvalidInnLengthException
*/
public function testInvalidInn10(): void
{
$this->expectException(InvalidInnLengthException::class);
(new Client())->setInn('12345678901');
}
/**
* Тестирует исключение о некорректной длине ИНН (12 цифр)
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setInn
* @covers \AtolOnline\Exceptions\InvalidInnLengthException
* @throws InvalidInnLengthException
*/
public function testInvalidInn12(): void
{
$this->expectException(InvalidInnLengthException::class);
(new Client())->setInn('1234567890123');
}
}

View File

@ -0,0 +1,134 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Tests;
use AtolOnline\{
Constants\SnoTypes,
Entities\Company,
Exceptions\InvalidEmailException,
Exceptions\InvalidInnLengthException,
Exceptions\InvalidPaymentAddressException,
Exceptions\InvalidSnoException,
Exceptions\TooLongEmailException,
Exceptions\TooLongPaymentAddressException,
Helpers};
/**
* Набор тестов для проверки работы класс продавца
*/
class CompanyTest extends BasicTestCase
{
/**
* Тестирует конструктор с сеттерами и приведение к json с геттерами
*
* @covers \AtolOnline\Entities\Company
* @covers \AtolOnline\Entities\Company::jsonSerialize
* @covers \AtolOnline\Entities\Company::setEmail
* @covers \AtolOnline\Entities\Company::setSno
* @covers \AtolOnline\Entities\Company::setInn
* @covers \AtolOnline\Entities\Company::setPaymentAddress
* @covers \AtolOnline\Entities\Company::getEmail
* @covers \AtolOnline\Entities\Company::getSno
* @covers \AtolOnline\Entities\Company::getInn
* @covers \AtolOnline\Entities\Company::getPaymentAddress
*/
public function testConstructor()
{
$this->assertAtolable(new Company(
$email = 'company@example.com',
$sno = SnoTypes::OSN,
$inn = '1234567890',
$payment_address = 'https://example.com',
), [
'email' => $email,
'sno' => $sno,
'inn' => $inn,
'payment_address' => $payment_address,
]);
}
/**
* Тестирует исключение о слишком длинном email
*
* @covers \AtolOnline\Entities\Company
* @covers \AtolOnline\Entities\Company::setEmail
* @covers \AtolOnline\Exceptions\TooLongEmailException
*/
public function testEmailTooLongException()
{
$this->expectException(TooLongEmailException::class);
new Company(Helpers::randomStr(65), SnoTypes::OSN, '1234567890', 'https://example.com');
}
/**
* Тестирует исключение о невалидном email
*
* @covers \AtolOnline\Entities\Company
* @covers \AtolOnline\Entities\Company::setEmail
* @covers \AtolOnline\Exceptions\InvalidEmailException
*/
public function testInvalidEmailException()
{
$this->expectException(InvalidEmailException::class);
new Company('company@examas%^*.com', SnoTypes::OSN, '1234567890', 'https://example.com');
}
/**
* Тестирует исключение о слишком длинном платёжном адресе
*
* @covers \AtolOnline\Entities\Company
* @covers \AtolOnline\Entities\Company::setSno
* @covers \AtolOnline\Exceptions\InvalidSnoException
*/
public function testInvalidSnoException()
{
$this->expectException(InvalidSnoException::class);
new Company('company@example.com', 'test', '1234567890', 'https://example.com');
}
/**
* Тестирует исключение о слишком длинном платёжном адресе
*
* @covers \AtolOnline\Entities\Company
* @covers \AtolOnline\Entities\Company::setInn
* @covers \AtolOnline\Exceptions\InvalidInnLengthException
*/
public function testInvalidInnLengthException()
{
$this->expectException(InvalidInnLengthException::class);
new Company('company@example.com', SnoTypes::OSN, Helpers::randomStr(13), 'https://example.com');
}
/**
* Тестирует исключение о слишком длинном платёжном адресе
*
* @covers \AtolOnline\Entities\Company
* @covers \AtolOnline\Entities\Company::setPaymentAddress
* @covers \AtolOnline\Exceptions\TooLongPaymentAddressException
*/
public function testTooLongPaymentAddressException()
{
$this->expectException(TooLongPaymentAddressException::class);
new Company('company@example.com', SnoTypes::OSN, '1234567890', Helpers::randomStr(257));
}
/**
* Тестирует исключение о невалидном платёжном адресе
*
* @covers \AtolOnline\Entities\Company
* @covers \AtolOnline\Entities\Company::setPaymentAddress
* @covers \AtolOnline\Exceptions\InvalidPaymentAddressException
*/
public function testInvalidPaymentAddressException()
{
$this->expectException(InvalidPaymentAddressException::class);
new Company('company@example.com', SnoTypes::OSN, '1234567890', '');
}
}

View File

@ -0,0 +1,123 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Tests;
use AtolOnline\Helpers;
/**
* Набор тестов для проверки работы функций-хелперов
*/
class HelpersTest extends BasicTestCase
{
/**
* Провайдер копеек для перевода в рубли
*
* @return array<array<int|null, float>>
*/
public function providerKopeksToRubles(): array
{
return [
[null, 0],
[0, 0],
[1, 0.01],
[12, 0.12],
[123, 1.23],
[1234, 12.34],
[12345, 123.45],
[-1, 0.01],
[-12, 0.12],
[-123, 1.23],
[-1234, 12.34],
[-12345, 123.45],
];
}
/**
* Провайдер рублей для перевода в копейки
*
* @return array<array<float|null, int>>
*/
public function providerRublesToKopeks(): array
{
return [
[null, 0],
[0, 0],
[0.01, 1],
[0.12, 12],
[1.23, 123],
[12.34, 1234],
[123.45, 12345],
[-0.01, 1],
[-0.12, 12],
[-1.23, 123],
[-12.34, 1234],
[-123.45, 12345],
];
}
/**
* Провайдер для тестирования генерации рандомной строки
*
* @return array<array<int, int>>
*/
public function providerRandomStr(): array
{
return [
[0, 0],
[1, 1],
[5, 5],
[-1, 1],
[-5, 5],
];
}
//------------------------------------------------------------------------------------------------------------------
/**
* Тестирует перевод копеек в рубли
*
* @dataProvider providerKopeksToRubles
* @covers \AtolOnline\Helpers::KopToRub
*/
public function testKopeksToRubles(?int $kopeks, float $rubles): void
{
$result = Helpers::KopToRub($kopeks);
$this->assertIsFloat($result);
$this->assertEquals($result, $rubles);
}
/**
* Тестирует перевод копеек в рубли
*
* @dataProvider providerRublesToKopeks
* @covers \AtolOnline\Helpers::RubToKop
*/
public function testRublesToKopeks(?float $rubles, int $kopeks): void
{
$result = Helpers::RubToKop($rubles);
$this->assertIsInt($result);
$this->assertEquals($result, $kopeks);
}
/**
* Тестирует длину рандомной строки
*
* @param int $input
* @param int $output
* @dataProvider providerRandomStr
*/
public function testRandomString(int $input, int $output): void
{
$result = Helpers::randomStr($input);
$this->assertIsString($result);
$this->assertEquals($output, strlen($result));
// тестировать на наличие цифр быссмысленно
}
}

View File

@ -1,34 +1,37 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
use AtolOnline\{Constants\PaymentMethods, namespace AtolOnline\Tests;
use AtolOnline\{
Constants\PaymentMethods,
Constants\PaymentObjects, Constants\PaymentObjects,
Constants\VatTypes, Constants\VatTypes,
Entities\Item, Entities\Item,
Exceptions\AtolNameTooLongException, Exceptions\BasicTooManyException,
Exceptions\AtolPriceTooHighException, Exceptions\TooHighPriceException,
Exceptions\AtolTooManyException, Exceptions\TooLongNameException,
Exceptions\AtolUnitTooLongException, Exceptions\TooLongUnitException,
Exceptions\AtolUserdataTooLongException}; Exceptions\TooLongUserdataException,};
/** /**
* Class ItemTest * Class ItemTest
*/ */
class ItemTest extends BasicTestCase class ItemTestTodo extends BasicTestCase
{ {
/** /**
* Тестирует установку параметров через конструктор * Тестирует установку параметров через конструктор
* *
* @throws AtolOnline\Exceptions\AtolNameTooLongException * @throws AtolOnline\Exceptions\TooLongNameException
* @throws AtolOnline\Exceptions\AtolPriceTooHighException * @throws AtolOnline\Exceptions\TooHighPriceException
* @throws AtolOnline\Exceptions\AtolTooManyException * @throws AtolOnline\Exceptions\BasicTooManyException
* @throws AtolOnline\Exceptions\AtolUnitTooLongException * @throws AtolOnline\Exceptions\TooLongUnitException
*/ */
public function testConstructor() public function testConstructor()
{ {
@ -41,7 +44,7 @@ class ItemTest extends BasicTestCase
PaymentObjects::COMMODITY, PaymentObjects::COMMODITY,
PaymentMethods::FULL_PAYMENT PaymentMethods::FULL_PAYMENT
); );
$this->checkAtolEntity($item); $this->assertAtolable($item);
$this->assertEquals('Банан', $item->getName()); $this->assertEquals('Банан', $item->getName());
$this->assertEquals(65.99, $item->getPrice()); $this->assertEquals(65.99, $item->getPrice());
$this->assertEquals(2.74, $item->getQuantity()); $this->assertEquals(2.74, $item->getQuantity());
@ -50,15 +53,15 @@ class ItemTest extends BasicTestCase
$this->assertEquals(PaymentObjects::COMMODITY, $item->getPaymentObject()); $this->assertEquals(PaymentObjects::COMMODITY, $item->getPaymentObject());
$this->assertEquals(PaymentMethods::FULL_PAYMENT, $item->getPaymentMethod()); $this->assertEquals(PaymentMethods::FULL_PAYMENT, $item->getPaymentMethod());
} }
/** /**
* Тестирует установку параметров через сеттеры * Тестирует установку параметров через сеттеры
* *
* @throws AtolOnline\Exceptions\AtolNameTooLongException * @throws AtolOnline\Exceptions\TooLongNameException
* @throws AtolOnline\Exceptions\AtolPriceTooHighException * @throws AtolOnline\Exceptions\TooHighPriceException
* @throws AtolOnline\Exceptions\AtolTooManyException * @throws AtolOnline\Exceptions\BasicTooManyException
* @throws AtolOnline\Exceptions\AtolUnitTooLongException * @throws AtolOnline\Exceptions\TooLongUnitException
* @throws AtolOnline\Exceptions\AtolUserdataTooLongException * @throws AtolOnline\Exceptions\TooLongUserdataException
*/ */
public function testSetters() public function testSetters()
{ {
@ -71,7 +74,7 @@ class ItemTest extends BasicTestCase
$item->setPaymentObject(PaymentObjects::COMMODITY); $item->setPaymentObject(PaymentObjects::COMMODITY);
$item->setPaymentMethod(PaymentMethods::FULL_PAYMENT); $item->setPaymentMethod(PaymentMethods::FULL_PAYMENT);
$item->setUserData('Some user data'); $item->setUserData('Some user data');
$this->checkAtolEntity($item); $this->assertAtolable($item);
$this->assertEquals('Банан', $item->getName()); $this->assertEquals('Банан', $item->getName());
$this->assertEquals(65.99, $item->getPrice()); $this->assertEquals(65.99, $item->getPrice());
$this->assertEquals(2.74, $item->getQuantity()); $this->assertEquals(2.74, $item->getQuantity());
@ -81,11 +84,11 @@ class ItemTest extends BasicTestCase
$this->assertEquals(PaymentMethods::FULL_PAYMENT, $item->getPaymentMethod()); $this->assertEquals(PaymentMethods::FULL_PAYMENT, $item->getPaymentMethod());
$this->assertEquals('Some user data', $item->getUserData()); $this->assertEquals('Some user data', $item->getUserData());
} }
/** /**
* Тестирует установку ставки НДС разными путями * Тестирует установку ставки НДС разными путями
* *
* @throws \AtolOnline\Exceptions\AtolPriceTooHighException * @throws TooHighPriceException
*/ */
public function testSetVat() public function testSetVat()
{ {
@ -95,66 +98,66 @@ class ItemTest extends BasicTestCase
$item->setVatType(VatTypes::VAT20); $item->setVatType(VatTypes::VAT20);
$this->assertEquals(VatTypes::VAT20, $item->getVat()->getType()); $this->assertEquals(VatTypes::VAT20, $item->getVat()->getType());
} }
/** /**
* Тестирует исключение о слишком длинном наименовании * Тестирует исключение о слишком длинном наименовании
* *
* @throws \AtolOnline\Exceptions\AtolNameTooLongException * @throws TooLongNameException
*/ */
public function testAtolNameTooLongException() public function testAtolNameTooLongException()
{ {
$item = new Item(); $item = new Item();
$this->expectException(AtolNameTooLongException::class); $this->expectException(TooLongNameException::class);
$item->setName(self::randomString(130)); $item->setName(Helpers::randomStr(130));
} }
/** /**
* Тестирует исключение о слишком высоком количестве * Тестирует исключение о слишком высоком количестве
* *
* @throws \AtolOnline\Exceptions\AtolPriceTooHighException * @throws TooHighPriceException
* @throws \AtolOnline\Exceptions\AtolTooManyException * @throws BasicTooManyException
* @throws \AtolOnline\Exceptions\AtolUnitTooLongException * @throws TooLongUnitException
*/ */
public function testAtolQuantityTooHighException() public function testAtolQuantityTooHighException()
{ {
$item = new Item(); $item = new Item();
$this->expectException(AtolTooManyException::class); $this->expectException(BasicTooManyException::class);
$item->setQuantity(100000.1); $item->setQuantity(100000.1);
} }
/** /**
* Тестирует исключение о слишком высокой цене * Тестирует исключение о слишком высокой цене
* *
* @throws \AtolOnline\Exceptions\AtolPriceTooHighException * @throws TooHighPriceException
*/ */
public function testAtolPriceTooHighException() public function testAtolPriceTooHighException()
{ {
$item = new Item(); $item = new Item();
$this->expectException(AtolPriceTooHighException::class); $this->expectException(TooHighPriceException::class);
$item->setPrice(42949673.1); $item->setPrice(42949673.1);
} }
/** /**
* Тестирует исключение о слишком длинных польз. данных * Тестирует исключение о слишком длинных польз. данных
* *
* @throws \AtolOnline\Exceptions\AtolUserdataTooLongException * @throws TooLongUserdataException
*/ */
public function testAtolUserdataTooLongException() public function testAtolUserdataTooLongException()
{ {
$item = new Item(); $item = new Item();
$this->expectException(AtolUserdataTooLongException::class); $this->expectException(TooLongUserdataException::class);
$item->setUserData('User data User data User data User data User data User data User data'); $item->setUserData('User data User data User data User data User data User data User data');
} }
/** /**
* Тестирует исключение о слишком длинной единице измерения * Тестирует исключение о слишком длинной единице измерения
* *
* @throws \AtolOnline\Exceptions\AtolUnitTooLongException * @throws TooLongUnitException
*/ */
public function testAtolUnitTooLongException() public function testAtolUnitTooLongException()
{ {
$item = new Item(); $item = new Item();
$this->expectException(AtolUnitTooLongException::class); $this->expectException(TooLongUnitException::class);
$item->setMeasurementUnit('кг кг кг кг кг кг кг кг кг '); $item->setMeasurementUnit('кг кг кг кг кг кг кг кг кг ');
} }
} }

View File

@ -1,103 +0,0 @@
<?php
/**
* Copyright (c) Антон Аксенов (aka Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
use AtolOnline\{Entities\Client,
Exceptions\AtolEmailTooLongException,
Exceptions\AtolEmailValidateException,
Exceptions\AtolInnWrongLengthException,
Exceptions\AtolNameTooLongException,
Exceptions\AtolPhoneTooLongException
};
/**
* Class ClientTest
*/
class ClientTest extends BasicTestCase
{
/**
* Тестирует установку параметров
*/
public function testConstructor()
{
$customer = new Client(
'John Doe',
'+1/22/99*73s dsdas654 5s6', // +122997365456
'john@example.com',
'+fasd3\qe3fs_=nac99013928czc' // 3399013928
);
$this->checkAtolEntity($customer);
$this->assertEquals('John Doe', $customer->getName());
$this->assertEquals('+122997365456', $customer->getPhone());
$this->assertEquals('john@example.com', $customer->getEmail());
$this->assertEquals('3399013928', $customer->getInn());
}
/**
* Тестирует исключение о слишком длинном имени
*
* @throws \AtolOnline\Exceptions\AtolNameTooLongException
*/
public function testAtolNameTooLongException()
{
$customer = new Client();
$this->expectException(AtolNameTooLongException::class);
$customer->setName(self::randomString(257));
}
/**
* Тестирует исключение о слишком длинном телефоне
*
* @throws \AtolOnline\Exceptions\AtolPhoneTooLongException
*/
public function testAtolPhoneTooLongException()
{
$customer = new Client();
$this->expectException(AtolPhoneTooLongException::class);
$customer->setPhone('99999999999999999999999999999999999999999999999999999999999999999999999999');
}
/**
* Тестирует исключение о слишком длинной почте
*
* @throws \AtolOnline\Exceptions\AtolEmailTooLongException
* @throws \AtolOnline\Exceptions\AtolEmailValidateException
*/
public function testAtolEmailTooLongException()
{
$customer = new Client();
$this->expectException(AtolEmailTooLongException::class);
$customer->setEmail(self::randomString(65));
}
/**
* Тестирует исключение о некорректной почте
*
* @throws \AtolOnline\Exceptions\AtolEmailTooLongException
* @throws \AtolOnline\Exceptions\AtolEmailValidateException
*/
public function testAtolEmailValidateException()
{
$customer = new Client();
$this->expectException(AtolEmailValidateException::class);
$customer->setEmail(self::randomString(15));
}
/**
* Тестирует исключение о некорректной длине ИНН
*
* @throws \AtolOnline\Exceptions\AtolInnWrongLengthException
*/
public function testAtolInnWrongLengthException()
{
$company = new Client();
$this->expectException(AtolInnWrongLengthException::class);
$company->setInn('123456789');
$company->setInn('1234567890123');
}
}

View File

@ -1,91 +0,0 @@
<?php
/**
* Copyright (c) Антон Аксенов (aka Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
use AtolOnline\{Constants\SnoTypes,
Entities\Company,
Exceptions\AtolEmailTooLongException,
Exceptions\AtolEmailValidateException,
Exceptions\AtolInnWrongLengthException,
Exceptions\AtolPaymentAddressTooLongException
};
/**
* Class CompanyTest
*/
class CompanyTest extends BasicTestCase
{
/**
* Тестирует установку параметров через конструктор
*/
public function testConstructor()
{
$company = new Company(
SnoTypes::OSN,
'5544332219',
'https://v4.online.atol.ru',
'company@example.com'
);
$this->checkAtolEntity($company);
$this->assertEquals(SnoTypes::OSN, $company->getSno());
$this->assertEquals('5544332219', $company->getInn());
$this->assertEquals('https://v4.online.atol.ru', $company->getPaymentAddress());
$this->assertEquals('company@example.com', $company->getEmail());
}
/**
* Тестирует исключение о некорректной длине ИНН
*
* @throws \AtolOnline\Exceptions\AtolInnWrongLengthException
*/
public function testAtolInnWrongLengthException()
{
$company = new Company();
$this->expectException(AtolInnWrongLengthException::class);
$company->setInn('321');
$company->setInn('1234567890123');
}
/**
* Тестирует исключение о слишком длинном платёжном адресе
*
* @throws \AtolOnline\Exceptions\AtolPaymentAddressTooLongException
*/
public function testAtolPaymentAddressTooLongException()
{
$company = new Company();
$this->expectException(AtolPaymentAddressTooLongException::class);
$company->setPaymentAddress(self::randomString(257));
}
/**
* Тестирует исключение о слишком длинной почте
*
* @throws \AtolOnline\Exceptions\AtolEmailTooLongException
* @throws \AtolOnline\Exceptions\AtolEmailValidateException
*/
public function testAtolEmailTooLongException()
{
$company = new Company();
$this->expectException(AtolEmailTooLongException::class);
$company->setEmail(self::randomString(65));
}
/**
* Тестирует исключение о некорректной почте
*
* @throws \AtolOnline\Exceptions\AtolEmailTooLongException
* @throws \AtolOnline\Exceptions\AtolEmailValidateException
*/
public function testAtolEmailValidateException()
{
$company = new Company();
$this->expectException(AtolEmailValidateException::class);
$company->setEmail(self::randomString(15));
}
}

View File

@ -1,39 +1,43 @@
<?php <?php
/** /*
* Copyright (c) Антон Аксенов (aka Anthony Axenov) * Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
* *
* This code is licensed under MIT. * This code is licensed under MIT.
* Этот код распространяется по лицензии MIT. * Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE * https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/ */
use AtolOnline\{Constants\VatTypes, Entities\Vat}; namespace AtolOnline\Tests;
use AtolOnline\{
Constants\VatTypes,
Entities\Vat};
/** /**
* Class VatTest * Class VatTest
*/ */
class VatTest extends BasicTestCase class VatTestTodo extends BasicTestCase
{ {
/** /**
* Тестирует каждый тип ставки НДС * Тестирует каждый тип ставки НДС
* *
* @dataProvider vatProvider * @dataProvider vatProvider
* @param string $vat_type Тип НДС * @param string $vat_type Тип НДС
* @param float $sum Исходная сумма * @param float $sum Исходная сумма
* @param float $expected_set Ожидаемый результат после установки суммы * @param float $expected_set Ожидаемый результат после установки суммы
* @param float $expected_add Ожидаемый результат после прибавления 20р * @param float $expected_add Ожидаемый результат после прибавления 20р
*/ */
public function testVat(string $vat_type, float $sum, float $expected_set, float $expected_add) public function testVat(string $vat_type, float $sum, float $expected_set, float $expected_add)
{ {
$vat = new Vat($vat_type); $vat = new Vat($vat_type);
$this->assertEquals(0, $vat->getFinalSum(), 'Test '.$vat_type.' | 1 step'); $this->assertEquals(0, $vat->getFinalSum(), 'Test ' . $vat_type . ' | 1 step');
$vat->setSum($sum); $vat->setSum($sum);
$this->assertEquals($expected_set, $vat->getFinalSum(), 'Test '.$vat_type.' | 2 step'); $this->assertEquals($expected_set, $vat->getFinalSum(), 'Test ' . $vat_type . ' | 2 step');
$vat->addSum(20); $vat->addSum(20);
$this->assertEquals($expected_add, $vat->getFinalSum(), 'Test '.$vat_type.' | 3 step'); $this->assertEquals($expected_add, $vat->getFinalSum(), 'Test ' . $vat_type . ' | 3 step');
$vat->addSum(-20); $vat->addSum(-20);
} }
/** /**
* Провайдер данных для тестирования разных типов ставок НДС * Провайдер данных для тестирования разных типов ставок НДС
* *