Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/kurbatov/atol4j

Клиентская библиотека для контрольной кассовой техники АТОЛ
https://github.com/kurbatov/atol4j

Last synced: 2 months ago
JSON representation

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

Awesome Lists containing this project

README

        

[![Get help on Codementor](https://cdn.codementor.io/badges/get_help_github.svg)](https://www.codementor.io/olegkurbatov?utm_source=github&utm_medium=button&utm_term=olegkurbatov&utm_campaign=github)

## atol4j

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

**atol4j** реализует `Протокол ККТ 3.1` как описано в Руководстве
программиста (версия 3.1 от 18.04.2019). Этот документ можно найти в файловом
архиве [Центра загрузки](http://fs.atol.ru/SitePages/%D0%A6%D0%B5%D0%BD%D1%82%D1%80%20%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BA%D0%B8.aspx)
АТОЛ (`Контрольно кассовая техника` -> `Протокол работы ККМ 3.1 - Руководство программиста`).

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

## Возможности

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

## Установка

### Maven

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

```xml

com.github.kurbatov
atol4j
0.1.0

```

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

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

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

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

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

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

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

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

```java
// определяем порт для подключения к устройству
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` - объект с монопольным доступом к физическому устройству.
Он организует работу с физическим устройством без риска смешивания команд
из разных участков бизнес-логики приложения при конкурентном выполнении.

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

```java
// определяем порт для подключения к устройству
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 во время написания исходного кода и
предотвращает возможность построения некорректной последовательности команд.
Например, команды режима регистрации можно добавить в цепочку только после
команды перехода в этот режим.

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

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

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

```java
// создаём цепочку команд, добавляем команды перехода в режим регистрации и
// открытия чека прихода, а затем сохраняем ссылку на цепочку в переменной
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`.

Пример:

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

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

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

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

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

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

Помощь в развитии библиотеки всегда приветствуется. Если вы нашли ошибку или
отсутствие функции, пожалуйста, [создайте запрос](https://github.com/kurbatov/atol4j/issues/new)
с описанием.

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

1. Сделайте `fork` этого репозитория
2. Склонируйте свой `fork` на локальный компьютер (`git clone https://github.com//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`.