Skip to content

Клиентская библиотека для контрольной кассовой техники АТОЛ

License

Notifications You must be signed in to change notification settings

kurbatov/atol4j

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Get help on Codementor

atol4j

atol4j - клиентская библиотека для контрольной кассовой техники (ККТ) АТОЛ, написанная на Java. Она позволяет управлять кассовым аппаратом АТОЛ из программы на языке Java.

atol4j реализует Протокол ККТ 3.1 как описано в Руководстве программиста (версия 3.1 от 18.04.2019). Этот документ можно найти в файловом архиве Центра загрузки АТОЛ (Контрольно кассовая техника -> Протокол работы ККМ 3.1 - Руководство программиста).

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

Возможности

  • Кроссплатформенная библиотека без нативных модулей
  • Подключение к устройству по USB и COM портам, WiFi или Ethernet (Bluetooth в планах)
  • Удобный документированный API позволяет исследовать возможности и ограничения протокола по ходу написания программы
  • Позволяет организовать управление устройством объединяя команды в цепочки
  • Команды исполняются асинхронно
  • Расширяемость: можно реализовать отсутствующие команды вне библиотеки
  • Позволяет отправить устройсту произвольные данные

Установка

Maven

Добавьте зависимость в pom.xml проекта:

<dependency>
    <groupId>com.github.kurbatov</groupId>
    <artifactId>atol4j</artifactId>
    <version>0.1.0</version>
</dependency>

Использование

Взаимодействие с ККТ состоит из трёх основных этапов:

  • подключение
  • отправка команд и обработка результатов их выполнения
  • отключение

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

После подключения происходит запрос идентификационных данных и текущего состояния ККТ. Устройство будет приведено в режим выбора, если текущий режим работы отличается.

Отключение - важный этап взаимодействия с ККТ. Устройство способно обслуживать единственное активное подключение. Если отключение не произойдёт, то следующая попытка подключения к ККТ завершится ошибкой.

Cинхронный сценарий

Рассмотрим пример синхронного подключения и отключения:

    // определяем порт для подключения к устройству
    String port = ... ;// может выглядеть как "COM3" или "/dev/ttyUSB0" в зависимости от ОС
    // создаём объект, представляющий ККТ, с указанием канала передачи данных и пароля
    CashRegister device = new CashRegister(new SerialTransport(port), new byte[]{0, 0});
    try {
        device.connect(); // подключаемся к устройству
        // далее происходит взаимодействие с устройством
        Result result = device.command()
            ... // здесь формируется список команд для ККТ
            .execute() // отправляем список команд на выполнение
            .get(); // и дожидаемся результата выполнения команд
        ... // обработка результата выполнения команд
    } catch (InterruptedException | ExecutionException | RuntimeException e) {
        // обрабатываем ошибки подключения и выполнения команд
        LOGGER.warn("Ошибка при попытке выполнения команды.", e);
    } finally {
        device.disconnect(); // отключаемся от устройства
    }

В этом примере device - объект с монопольным доступом к физическому устройству. Он организует работу с физическим устройством без риска смешивания команд из разных участков бизнес-логики приложения при конкурентном выполнении.

Асинхронный сценарий

    // определяем порт для подключения к устройству
    String port = ... ;// может выглядеть как "COM3" или "/dev/ttyUSB0" в зависимости от ОС
    // создаём объект, представляющий ККТ, с указанием канала передачи данных и пароля
    CashRegister device = new CashRegister(new SerialTransport(port), new byte[]{0, 0});
    try {
        device.connect(); // подключаемся к устройству
        // далее происходит взаимодействие с устройством
        device.command()
            ... // здесь формируется список команд для ККТ
            .execute() // отправляем список команд на выполнение
            .whenComplete((r, e) -> ...) // регистрируем обработчик результата
            .whenComplete((r, e) -> device.disconnect()); // регистрируем отключение от устройства по завершении
    } catch (RuntimeException e) { // обрабатываем ошибки подключения
        LOGGER.warn("Ошибка при попытке подключения.", e);
    }

При асинхронном выполнении команд поток выполнения не приостанавливает выполнение последующих инструкций в ожидании ответа ККТ. Результат будет последовательно передан в обработчики, зарегистрированные при помощи метода whenComplete. Последний из них совершает отключение от устройства вне зависимости от результатов выполнения.

Построение цепочки команд

Метод device.command() создаёт новую цепочку команд. atol4j делает допущение, что исходное состояние ККТ - режим выбора.

Отправка цепочки команд устройству осуществляется вызовом метода execute(). Этот метод не блокирует текущий поток исполнения. Он возвращает экземпляр CompletableFuture, который может быть использован для блокирования потока до момента получения результата или регистрации асинхронного обработчика результата.

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

Пример - закрытие смены (печать отчёта с гашением):

    device.command() // создаём новую цепочку команд
        .report((byte) 0x29) // добавляем переход в режим отчётов с указанием пароля доступа для режима
        .closeShiftWithReport() // добавляем закрытие смены
        .execute(); // отправляем команды на выполнение

Пример - формирование чека прихода (при продаже товара):

    // создаём цепочку команд, добавляем команды перехода в режим регистрации и
    // открытия чека прихода, а затем сохраняем ссылку на цепочку в переменной
    RegistrationCommandBuilder cb = device.command()
            .registration((byte) 0x29)
            .openBillIncome();
    for (Bill.Entry entry : receipt.getEntries()) { // для каждой записи в доменной модели чека
        // добавляем команду регистрации позиции в цепочку и сохраняем ссылку на
        // новую цепочку команд в той же переменной
        cb = cb.registerItem(entry.getProductName(), entry.getPrice() * 100, entry.getCount() * 1000);
        // умножение цены и количества на различные коэффициенты связано с
        // различием единиц измерения в доменной модели и команде регистрации позиции
    }
    if (cashless) { // если безналичный расчёт
        cb = cb.closeBillCashless(0); // добавляем команду закрытия чека с безналичным рассчётом (0 - внесение всей суммы)
    } else { // иначе - наличный рассчёт
        cb = cb.closeBillCash(0); // добавляем команду закрытия чека с наличным рассчётом (0 - внесение всей суммы)
    }
    Result r = cb.resetMode() // добавляем команду возврата в режим выбора
            .execute() // отправляем цепочку команд на выполнение
            .get(); // ожидаем результат от ККТ

Выполнение запросов

Запрос - это команда устройству сообщить данные о его состоянии. Запросы выполняются вне цепочек команд по одному. Построить запрос можно при помощи метода device.request(). Запрос будет отправлен на исполнение немедленно, а результат доступен через объект CompletableFuture.

Пример:

    device.request() // создаём построитель запросов
        .deviceState() // выполняем запрос состояния устройства
        .whenComplete((r, err) -> ...); // регистрируем обработчик ответа с данными о состоянии устройства

Выполнение отдельных команд

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

    Command beep = new BeepCommand(200, 100); // создаём команду воспроизведения звука с заданной частотой и длительностью
    device.execute(beep); // исполняем команду на выбранном устройстве

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

Развитие библиотеки

Помощь в развитии библиотеки всегда приветствуется. Если вы нашли ошибку или отсутствие функции, пожалуйста, создайте запрос с описанием.

Если вы хотите предложить улучшение, пожалуйста, сделайте следующее:

  1. Сделайте fork этого репозитория
  2. Склонируйте свой fork на локальный компьютер (git clone https://github.com/<your_username>/atol4j.git)
  3. Создайте feature branch (git checkout -b my-new-feature)
  4. Внесите необходимые изменения в код
  5. Примените ваши изменения(git commit -am 'Описание изменений')
  6. Отправьте изменения на сервер (git push origin my-new-feature)
  7. Создайте Pull Request

Изменения должны быть документированы. Язык документации этого проекта - русский.

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

Предлагаемые изменения могут быть дополнены перед включением в код проекта для более полного соответствия назначению, стилю, правилам именования и форматирования существующего кода.

Изменения принимаются в качестве добровольного безвозмездного пожертвования.

Лицензирование

Использование библиотеки допускается на условиях лицензии GNU GPLv3.

Если условия лицензии GNU GPLv3 не могут быть соблюдены, использование библиотеки должно быть лицензировано на условиях коммерческого лицензионного соглашения с автором.

Текст лицензии GNU GPLv3 находится в файле LICENSE. Перевод текста лицензии GNU GPLv3 на русский язык находится в файле LICENSE_RU.

About

Клиентская библиотека для контрольной кассовой техники АТОЛ

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages