Пишем клиент для нового API nalog.ru - LEFT JOIN

Свяжитесь с нами в любой удобной для вас форме

Менеджер

Написать в телеграмм

Онлайн
Телеграмм
или
Заполните форму

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)

Полный код проекта на GitHub

6849 просмотров

Комментарии

  • Василий
    Василий

    Привет!
    В коде ещё требуется 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, исправлено 🙂

Добавить комментарий

[ Рекомендации ]

Читайте также

1 минута чтения

*

10 июля 2020

Устанавливаем Clickhouse на AWS

2 минут чтения

*

8 декабря 2021

How to: Yandex Datasphere

[ Дальше ]