• 15 апреля стартует «Курс «SQL-injection Master» ©» от команды The Codeby

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

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

    Запись на курс до 25 апреля. Получить промодоступ ...

Статья Принцип работы онлайн-кассы на примере АТОЛ и взаимодействие с ней через библиотеку

Привет Codeby !

main.jpg



Онлайн-касса ( ОК ), которую можно видеть сейчас в любом магазине, супермаркете, аптеке и так далее, представляет собой такое устройство. В каждой пятерочке или ашане, конечно, каждый видел подобный аппарат, кому-то приходилось нетерпеливо ожидать чека, когда времени мало, а инет в магазине видимо подтупливает)

kassa.png


Работа с этими аппаратами регламентируется 54 ФЗ "О применении контрольно-кассовой техники при осуществлении расчетов в Российской Федерации" и если кратко, то основное отличие онлайн-кассы от кассовых аппаратов, которые использовались раньше - это собственно слово "онлайн", а значит передача данных происходит через сеть и вся процедура продажи и отправки данных проходит в течении 2-5 секунд.

Весь аппарат по сути является принтером чеков, а основную функцию передачи выполняет фискальный накопитель (ФН, скрин ниже). Это устройство, которое вставляется в онлайн-кассу, получает, обрабатывает и передаёт данные об операциях на кассе оператору фискальных данных (ОФД), а тот – в налоговую инспекцию.

ОФД — компания-посредник, которая передает данные о платежах физических лиц в налоговую инспекцию. Все предприниматели обязаны самостоятельно заключить договор с одним из ОФД — это требование 54-ФЗ.

ОФД обрабатывает поступившую информацию, передает её в ФНС и направляет на онлайн-кассу специальный сигнал, который подтверждает, что процедура выполнена успешно.

fn.png


За сроком действия ФН кстати пристально следят, они покупаются на определенный срок (13, 15 и 36 месяцев) и их очень важно менять вовремя, иначе могут возникнуть проблемы с налоговой, штрафы и тд. Объем памяти таких ФН - около 250 000 записей. После окончания срока действия или объема памяти, ФН меняется и происходит процедура регистрации нового ФН.

Как для любого устройства подключаемого к ПК, для ОК необходим драйвер. Ставится он стандартно, и по умолчанию падает в C:\Program Files\Driver_version. Все функции и настройки находятся внутри него. По TCP/IP основной порт для работы - 5555. Хотя может кто-то использует и другие.

Безымянный.png


Основные функции выполняет библиотека fptr10.dll которая находится в папке bin. Когда я нашел официальную доку для работы с кассой, не мог понять где взять библиотеку libfptr10.py, которая используется в частности для питона (через pip она не ставится) Но все оказалось проще. Внутри драйвера нашел папку lang, внутри нее подкаталоги для различных ЯП. Там и go, java, c++, python и еще много чего. В общем библиотека которая мне нужна, лежала в папке python. Я лично предпочитаю забирать библиотеки .py и .dll в свой каталог и работать с ними там. Хотя можно и прописывать пути к директории драйвера.

Для примера скрипт работы с ОК может выглядеть так :

Python:
import os
from libfptr10 import IFptr
from datetime import datetime

# инициализация объекта драйвера
DRIVER_PATH = os.path.join(os.getcwd(), 'fptr10.dll')
fptr = IFptr(DRIVER_PATH)


STATUS_STATE_STR = ''
IP = '192.168.1.250'
PORT = "5555"
SOCKET_KKM = '{}:{}'.format(IP, PORT)

none_time = datetime(1970, 1, 1, 0)

# инициализация параметров ( по документации )
fptr.setSingleSetting(IFptr.LIBFPTR_SETTING_MODEL, str(IFptr.LIBFPTR_MODEL_ATOL_AUTO))
fptr.setSingleSetting(IFptr.LIBFPTR_SETTING_PORT, str(IFptr.LIBFPTR_PORT_TCPIP))
fptr.setSingleSetting(IFptr.LIBFPTR_SETTING_IPADDRESS, IP)
fptr.setSingleSetting(IFptr.LIBFPTR_SETTING_IPPORT, PORT)
result = fptr.applySingleSettings()

# проверка, есть ли коннект
try:
    fptr.open()
    isOpened = fptr.isOpened()
    if isOpened == 0:
        print('no connection\n')
    print('connection successful\n')

   # Установка параметров
    fptr.setParam(IFptr.LIBFPTR_PARAM_DATA_TYPE, IFptr.LIBFPTR_DT_STATUS)
    fptr.queryData()

   # Запрос внутренних параметров
    NUMBER_KKT = fptr.getParamString(IFptr.LIBFPTR_PARAM_SERIAL_NUMBER)
    #STATUS_STATE = fptr.getParamInt(IFptr.LIBFPTR_PARAM_SHIFT_STATE)
    KKM_TIME = fptr.getParamDateTime(IFptr.LIBFPTR_PARAM_DATE_TIME)

    # Запрос параметров обмена с ОФН
    fptr.setParam(IFptr.LIBFPTR_PARAM_FN_DATA_TYPE, IFptr.LIBFPTR_FNDT_OFD_EXCHANGE_STATUS)
    fptr.fnQueryData()

    NOT_TRANS_DOC = fptr.getParamInt(IFptr.LIBFPTR_PARAM_DOCUMENTS_COUNT)
    DATA_LAST_TRANS = fptr.getParamDateTime(IFptr.LIBFPTR_PARAM_DATE_TIME)
    DATA_FN_KEY = fptr.getParamDateTime(IFptr.LIBFPTR_PARAM_LAST_SUCCESSFUL_OKP)

    #if STATUS_STATE == 0:
        #STATUS_STATE_STR = 'Закрыта'
    #elif STATUS_STATE == 1:
        #STATUS_STATE_STR = 'Открыта'
    #elif STATUS_STATE == 2:
        #STATUS_STATE_STR = 'Истекла'


    if int(NOT_TRANS_DOC) > 0:
        if DATA_FN_KEY == none_time:
            print('{}; ККМ №: {}; Дата/Время: {}; Непереданные чеки: {}; Первый непереданный: {};'.format(
            SOCKET_KKM, NUMBER_KKT, KKM_TIME, NOT_TRANS_DOC, DATA_LAST_TRANS))
        else:
            print('{}; ККМ №: {}; Дата/Время: {}; Непереданные чеки: {}; Первый непереданный: {}; Дата/время последнего ОКП: {};'.format(
                SOCKET_KKM, NUMBER_KKT, KKM_TIME, NOT_TRANS_DOC, DATA_LAST_TRANS, DATA_FN_KEY))
    else:
        if DATA_FN_KEY == none_time:
            print('{}; ККМ №: {}; Дата/Время: {}; Непереданные чеки: {};'.format(
            SOCKET_KKM, NUMBER_KKT, KKM_TIME, NOT_TRANS_DOC))
        else:
            print('{}; ККМ №: {}; Дата/Время: {}; Непереданные чеки: {}; Дата/время последнего ОКП: {};'.format(
                SOCKET_KKM, NUMBER_KKT, KKM_TIME, NOT_TRANS_DOC, DATA_FN_KEY))


    # debugger
    # print(fptr.errorDescription())
    fptr.close()

except Exception as e:
    print(e)
    fptr.close()

Тут я запрашиваю информацию необходимую мне, но через библиотеку можно выполнить абсолютно любое действие, функций очень много, даже изучить всю доку займет несколько дней имхо)

Внутри библиотеки libfptr10.py находятся функции и настройки, вызываемые из библиотеки .dll через ctypes. Ctypes - предоставляет типы данных, совместимые с C, и позволяет вызывать функции в библиотеках DLL или совместно используемых библиотеках.

Безымянный1.png


Сам по себе скрипт опроса одной кассы - бесполезен. Ну вы можете узнать информацию на несколько секунд быстрее. Но если мы имеем около сотни-двух онлайн касс, подключаться к каждой через драйвер, переходить на нужные вкладки и запрашивать инфу - это ну очень долго. Поэтому и пришлось использовать для помощи в работе.

В общем, для того чтобы быстро начать работать через api, я думаю - все понятно. Ссылка на документацию
Можно глянуть что там вообще доступно, надо кстати тоже чекнуть функции, я ведь и не дочитал до конца, да и то что нужно, нашел не сразу ) Надеюсь, кому-то было интересно.


Спасибо за внимание.
 

han

One Level
06.05.2021
3
3
BIT
7
ну всех вопрос то интересует, как обьюзить эту штуку, чтобы дошики бесплатно покупать
 

Trixxx

Grey Team
04.04.2020
196
154
BIT
23
ну всех вопрос то интересует, как обьюзить эту штуку, чтобы дошики бесплатно покупать
Обьюзить эту штуку бесполезно т.к. это принтер чеков по сути. Есть там функции выплат и тд. можно сделать выплату на любую сумму или наоборот, внести деньги, но все что ты получишь - это расхождение отчетов сотрудников мужду реальными продажами и тем что натарговала касса в z отчете :)
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!