3 минут чтения
19 августа 2020 г.
Пишем клиент для нового API nalog.ru
UPD 29-09-2021: Мы обновили клиент. Теперь проходить аутентификацию можно по номеру телефона и подтверждению по SMS. Репозиторий на GitHub
Ранее в блоге мы рассказывали, как благодаря открытому API можно собирать данные от ФНС по нашим чекам из магазинов, обращаясь к приложению налоговой. С прошлой недели способ стал нерабочим: ФНС обновили методы приложения. Сегодня напишем свой клиент для nalog.ru, который проходит авторизацию и отправляет чеки на проверку.
Авторизация
Прежде чем начать пользоваться приложением, наш профиль необходимо авторизовать. В отличии от предыдущей версии, текущая требует прохождение капчи для авторизации по мобильному телефону — такой способ нам не подходит. Проще всего будет входить в профиль по ИНН и паролю от личного кабинета налогоплательщика. Для хранения этих данных создадим файл credentials.env. Переменную CLIENT_SECRET зададим согласно коду: она отвечает за авторизацию приложения. А ИНН и пароль подставляем свои.
INN =
PASSWORD =
CLIENT_SECRET=IyvrAbKt9h/8p6a7QPh8gpkXYQ4=
Теперь создадим файл nalog_python.py, в котором будет описан клиент. Библиотека dotenv используется для загрузки нашего логина и пароля из .env файла.
import os
import json
import requests
from dotenv import load_dotenv
Опишем класс NalogRuPython, и начнём с глобальных переменных класса. Здесь перечисляем headers, необходимые для отправки запроса.
class NalogRuPython:
HOST = ‘irkkt-mobile.nalog.ru:8888’
DEVICE_OS = ‘iOS’
CLIENT_VERSION = ‘2.9.0’
DEVICE_ID = ‘7C82010F-16CC-446B-8F66-FC4080C66521’
ACCEPT = ‘*/*’
USER_AGENT = ‘billchecker/2.9.0 (iPhone; iOS 13.6; Scale/2.00)’
ACCEPT_LANGUAGE = ‘ru-RU;q=1, en-US;q=0.9’
В конструкторе класса прочитаем данные из нашего окружения методом load_dotenv и вызовем метод set_session_id для получения __session_id, который сейчас опишем. Идентификатор сессии необходим для отправки прочих запросов к серверу налоговой, поэтому его получаем первым делом.
def __init__(self):
load_dotenv()
self.__session_id = None
self.set_session_id()
Метод set_session_id проводит авторизацию пользователя по ИНН и паролю от личного кабинета налогоплательщика и ничего не возвращает, только задаёт значение переменной __session_id. Отправляем по указанному в глобальных переменных HOST запрос с нашими данными от аккаунта и получаем идентификатор сессии в ответе.
def set_session_id(self) -> None:
if os.getenv(‘CLIENT_SECRET’) is None:
raise ValueError(‘OS environments not content «CLIENT_SECRET»‘)
if os.getenv(‘INN’) is None:
raise ValueError(‘OS environments not content «INN»‘)
if os.getenv(‘PASSWORD’) is None:
raise ValueError(‘OS environments not content «PASSWORD»‘)
url = f’https://{self.HOST}/v2/mobile/users/lkfl/auth’
payload = {
‘inn’: os.getenv(‘INN’),
‘client_secret’: os.getenv(‘CLIENT_SECRET’),
‘password’: os.getenv(‘PASSWORD’)
}
headers = {
‘Host’: self.HOST,
‘Accept’: self.ACCEPT,
‘Device-OS’: self.DEVICE_OS,
‘Device-Id’: self.DEVICE_ID,
‘clientVersion’: self.CLIENT_VERSION,
‘Accept-Language’: self.ACCEPT_LANGUAGE,
‘User-Agent’: self.USER_AGENT,
}
resp = requests.post(url, json=payload, headers=headers)
self.__session_id = resp.json()[‘sessionId’]
Получение идентификатора чека
Следующий шаг — получение ticket_id. Прежде чем отправить сам чек, необходимо получить его идентификатор для проверки. Опишем метод _get_ticket_id, который принимает строку с расшифрованным QR-кодом чека, отправляет соответствующий запрос на сервер и возвращает идентификатор для этой строки. В headers помимо указания глобальных переменных появился также __session_id, который требует метод /v2/ticket.
def _get_ticket_id(self, qr: str) -> str:
url = f’https://{self.HOST}/v2/ticket’
payload = {‘qr’: qr}
headers = {
‘Host’: self.HOST,
‘Accept’: self.ACCEPT,
‘Device-OS’: self.DEVICE_OS,
‘Device-Id’: self.DEVICE_ID,
‘clientVersion’: self.CLIENT_VERSION,
‘Accept-Language’: self.ACCEPT_LANGUAGE,
‘sessionId’: self.__session_id,
‘User-Agent’: self.USER_AGENT,
}
resp = requests.post(url, json=payload, headers=headers)
return resp.json()[«id»]
Расшифровка чека
Последний шаг — проверка чека. Формируем по ticket_id запрос к серверу и получаем подробную расшифровку чека в ответе. На этом клиент полностью описан и готов к работе.
def get_ticket(self, qr: str) -> dict:
ticket_id = self._get_ticket_id(qr)
url = f’https://{self.HOST}/v2/tickets/{ticket_id}’
headers = {
‘Host’: self.HOST,
‘sessionId’: self.__session_id,
‘Device-OS’: self.DEVICE_OS,
‘clientVersion’: self.CLIENT_VERSION,
‘Device-Id’: self.DEVICE_ID,
‘Accept’: self.ACCEPT,
‘User-Agent’: self.USER_AGENT,
‘Accept-Language’: self.ACCEPT_LANGUAGE,
}
resp = requests.get(url, headers=headers)
return resp.json()
Наконец, для удобства опишем пример работы клиента. Создадим экземпляр класса NalogRuPython, зададим для примера строку QR-кода и получим расшифрованный ticket, который затем напечатаем на экране.
if __name__ == ‘__main__’:
client = NalogRuPython()
qr_code = «t=20200727T1117&s=4850.00&fn=9287440300634471&i=13571&fp=3730902192&n=1»
ticket = client.get_ticket(qr_code)
print(json.dumps(ticket, indent=4))
Клиент можно использовать и в своих скриптах: для этого нужно импортировать класс, создать экземпляр и, как и в примере, вызвать метод get_ticket.
from nalog_python import NalogRuPython
client = NalogRuPython()
qr_code = «t=20200727T1117&s=4850.00&fn=9287440300634471&i=13571&fp=3730902192&n=1»
ticket = client.get_ticket(qr_code)
Комментарии
Добавить комментарий
[ Рекомендации ]
Читайте также
[ Связаться ]
Давайте раскроем потенциал вашего бизнеса вместе
Заполните форму на бесплатную консультацию
Привет!
В коде ещё требуется CLIENT_SECRET
Где его взять?
А пост читали? 🙂 У нас версия с авторизацией по личным данным кабинета в nalog.ru.
Добрый день!
Подскажите, пожалуйста, что я делаю не так.
Может я не совсем понял, ваш код, так как не владею Python.
Но я отправляю такой запрос (см. cUrl ниже) и получаю ошибку 400 — Bad request. Если не передать Device-OS или Device-Id то в описании еще указывается, что этот заголовок не передан, но для моего запроса никакого описания не выдает — наверное я неправильно составил запрос
curl -i -X POST \
-H «Device-OS:iOS» \
-H «Device-Id:7C82010F-16CC-446B-8F66-FC4080C66521» \
-H «Accept:*/*» \
-H «clientVersion:2.9.0» \
-H «Accept-Language:ru-RU;q=1, en-US;q=0.9» \
-H «User-Agent:billchecker/2.9.0 (iPhone; iOS 13.6; Scale/2.00)» \
-d \
’{
«inn»:«Мой ИНН»,
«password»:«Мой пароль»
}’ \
’https://irkkt-mobile.nalog.ru:8888/v2/mobile/users/lkfl/auth’
Попробуйте таким образом:
curl -H ‘Host: irkkt-mobile.nalog.ru:8888’ \
-H ‘Accept: */*’ \
-H ‘Device-OS: iOS’ \
-H ‘Device-Id: 7C82010F-16CC-446B-8F66-FC4080C66521’ \
-H ‘clientVersion: 2.9.0’ -H ‘Accept-Language: ru-RU;q=1, en-US;q=0.9’ \
-H ‘User-Agent: billchecker/2.9.0 (iPhone; iOS 13.6; Scale/2.00)’ \
-H ‘Content-Type: application/json’ \
—data-binary ‘{«inn»:»Мой ИНН»,»client_secret»:»IyvrAbKt9h\/8p6a7QPh8gpkXYQ4=»,»password»:»Мой пароль»}’ \
—compressed ‘https://irkkt-mobile.nalog.ru:8888/v2/mobile/users/lkfl/auth’
Николай, а вы код на который даёте ссылку читали? 🙂
Давайте я вам помогу, вот с этой строки: https://github.com/valiotti/get-receipts/blob/master/nalog_python.py#L27
Конечно, читал.
Прошу прощения, в теле заметки забыл указать CLIENT_SECRET, исправлено 🙂