Взаимодействие с API ФНС по протоколу SOAP(кассовые чеки)

v1.2.1 2021-03-17 10:55 UTC

This package is auto-updated.

Last update: 2024-04-10 00:32:02 UTC


README

68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f61676f616c6f66616c6966652f666e736170692f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572

Пакет предоставляет возможность работы по проверке чеков через официальное API ФНС (Федеральной Налоговая службы России).

Установка

composer require agoalofalife/fnsapi

Аутентификация

Для начала работы с сервисом, вам необходимо получить временный токен. На момент написания документации, время его жизни был один час.

$cachePSR16 = new Sarahman\SimpleCache\FileSystemCache(__DIR__);
$master_token = 'ourMasterToken';
$auth = new Fns\Auth\AuthRequest($master_token, $cachePSR16);
$auth->authenticate();

Вам надо передать мастер токен, который выдали в ФНС и хранилище, которое реализует PSR-16.

В хранилище будет своевременно обновляться новый токен, который реализуется в PSR-16 параметром ttl.

PSR-16 позволяет использовать пакет во многих современных фреймворках и т.д

Класс имеет исключение UnexpectedValueException в случае если токен не будет получен.

Временная зона

Время жизни токена устанавливается в соответствии с вашей настройкой PHP: Настройка во время выполнения - Manual date.timezone Рекомендуется проверить ваш файл php.ini и установить соответствующую временную зону.

Создать Ticket (кассовый чек)

Для того чтобы получить информацию по чеку, вам надо создать объект класса Ticket Подробнее о данных написано в коде и официальной документации ФНС.

$ticket = new \Fns\Ticket();
$ticket->setDate('2019-12-16T12:22:00');
$ticket->setFiscalDocumentId(11222);
$ticket->setFiscalSign(111111122);
$ticket->setFn(1234000123440000);
$ticket->setSum(11220);
$ticket->setTypeOperation(1);
// случайные данные

Создание SOAP Client

Отлично мы создали чек и заполнили его данными. Теперь надо создать SOAP client. Это очень осведомленный клиент, он знает что мы работает с ФНС, поэтому он требует:

  • Уникальную строку, для сессии. Это строка будет кодироваться в base64(который примерно на 30% увеличивают длину), не должна превышать 160 символов.
  • И то же хранилище данных, PSR-16, тот созданный объект, который передавался для получения временного токена.
  • Включить режим debug(по-умолчанию false), можно просматривать запросы с помощью таких методов как __getLastRequest и так далее.
$client = new \Fns\ClientSoap('uniqueStringOrNumber', $cache);

Проверка или информация по чеку

Отлично, вы создали чек и клиента. И уже все готово для работы! Осталось уже выбрать:

  • Проверить чек \Fns\GetMessage\CheckTicketRequest
  • Получить по нему подробную информацию \Fns\GetMessage\GetTicketRequest
Для справки
API ФНС реализованно через асинхроннсть.
Для начала вам надо отправить запрос для получения `MessageId`
с информацией по чеку и типом(проверка или полной информацией по чеку)
Далее новым запросом с  `MessageId` получить информацию.

Нюанс заключается в том, что последующий запрос, имеет время исполнения и сетевые задержки.
К примеру вы можете получить информацию по `MessageId` в течении 60 секунд.
Для своей реализации обработки timeout читайте в разделе  Алгоритмы обработки timeout
  • создание обьекта с типом запроса

  • Внедрить свою стратегию обработки timeout реализующий интерфейс Fns\Contracts\TimeoutStrategyHandler

  • Создать объект SendMessageRequest передать клиента которого мы создали ранее и объект конкретного запроса.

  • Передать чек

  • И выполнить запрос execute который возвращает интерфейс ResponseSendMessage

  • Получить информацию по запросу код и тело ответа.

$message = new \Fns\GetMessage\GetTicketRequest();
$message->setTimeoutStrategy(new ExponentialBackoff($message));
// можно установить свое максимальное значение time out
$message->setTimeoutStrategy(new ExponentialBackoff($message), 600000000);

$request = new SendMessageRequest($client, $message);
$request->setTicket($ticket);
$response = $request->execute();

if ($response->getCode() === 200) {
    dump(json_decode($response->getBody()));
    // или получить в виде структуры
    $response->getReceipt();
}

Ответ возвращается в json или в обекте Receipt.

Response в готовой структуре

Ответ по чеку можно получить в виде готовой структуры, которая содержит:

  • Класс Receipt
  • Класс ProductCollection
  • Класс Product

и решает такие проблемы как:

  • Более явное получение данных
  • Инкапсуляция преобразования их для более простой модификации и безболезности в клиентском коде.

но вы всегда можете получить сырой вариант.

Проверка чека CheckTicketRequest

Для получения информации что чек корректен, достаточно сравнить код ответа с кодом 200.

Из старой документации
если 200, то "Отправленные данные корректны"
если 400, то "Формат отправленных данных некорректен"
если 406, то "Данные не прошли проверку"
если 503, то "Сервис недоступен".

Получении информации по чеку GetTicketRequest

Из старой документации
Содержимое ФД, если код возврата равен 200
если 400, то "Формат отправленных данных некорректен"
если 404, то "Чек не найден"
если 406, то "Данные не прошли проверку"
если 453, то "Чек неккоректен".
Из нового сервиса опытным путем:
452 - Запрос не соответствует формату hsm
454 - Обращение к hsm было произведено и получен отрицательный результат проверки
455 - Не найдены данные в сервисе поиска чека
531 - "" (Происходит когда были отпроавлены неккоректные данные)

528 - Фискальный признак не может быть проверен, поскольку в hsm отсутствует необходимый ключ
531 - "" (Происходит когда были отпроавлены неккоректные данные)
После обновления API пока не предоставлен конечный список ответов!

Алгоритмы обработки timeout

Чтобы получить информацию по чеку, надо сделать запрос SendMessageRequest c параметром messageId При первом(вторым и т.д) запросе, сразу после получения messageId, может отсутствовать информацию по чеку. По-умолчанию в пакете реализовывается Exponential Backoff

Вы можете реализовать свой алгоритм реализуя интерфейс Fns\Contracts\TimeoutStrategyHandler\TimeoutStrategyHandler

Для контроля процесса выполнения запроса и его результата, передайте в конструктор Fns\Contracts\RequestsManager

Для примера вы можете реализовать свой алгоритм Interval Который будет опрашивать сервер через константный промежуток времени.

Дополнительная информация от автора

В данный момент все выполняется в синхронном режиме. Можно разделить процесс получения messageId и информации по нему, на два различных процесса. Для начальной версии пакета, пока остаётся так.

Угостить чаем 😌

Этот пакет был создан для экономии вашего времени на безвозмездной основе. Надеюсь у меня получилось это сделать и я буду рад любым формам спасибо. Звезда или скромный донат - окажут мне поддержку и веру в людей. https://money.yandex.ru/to/410019109036855