Python client for ATOL libfptr10 fiscal printer driver
Project description
ORD — Python-клиент драйвера АТОЛ libfptr10
Тонкая обёртка над libfptr10 (драйвер ККТ АТОЛ v10.10.x) для типовых
кассовых сценариев: открытие/закрытие смены, регистрация чека продажи и
возврата, чтение состояния ФН и ОФД-обмена, регистрация ККТ, чтение и
запись device settings.
Используется в backend-проекте online-receipt/online-api (Flask + Celery)
для фискализации чеков на физических кассах АТОЛ 30Ф, ATOL Sigma и
совместимых моделях.
- Текущая версия:
1.12.2 - PyPI:
pip install ORD - Источник истины: GitLab
online-receipt/online-receipt-driver(этот репо) - Зеркало: GitHub
brandshopru/online-receipt-driver - Стек: Python 3.6+,
libfptr10>=10.10.0 - Лицензия: проприетарная, ООО «БШ СТОР» (brandshop.ru)
1. Установка
pip install ORD==1.12.2
Зависимость от libfptr10 (Python wrapper) ставится отдельно из дистрибутива
АТОЛ kit (fptr10-rpc-server*.deb + wrappers/python/libfptr10.py).
Минимальные системные требования:
- Python >=3.6 (3.6 в EOL, рекомендуется 3.8+)
libfptr10.sov10.10.x в/lib64/илиLD_LIBRARY_PATH- USB-устройство ATOL (
Vendor:Product 2912:0005) либо TCP/IP подключение - При работе через
atol-grpc-service— gRPC мост на127.0.0.1:4041/:4042
2. Архитектура
2.1. Структура
ORD/
├── __init__.py # public-экспорт классов
├── ord_core.py # Core (Singleton, IFptr wrapper)
├── ord_cash.py # Cash (state ККТ, регистрация)
├── ord_fn.py # Fn (ФН-операции, ОФД-обмен)
├── ord_receipt.py # Receipt (чек: open/registration/payment/close)
├── ord_shift.py # Shift (open/close смены)
├── ord_setting.py # Setting (device settings R/W)
└── exceptions.py # OrdError, OrdTimeoutError (§6.8 + §6.9, c 1.11.0)
2.2. Класс Core (Singleton)
Core — единая точка инициализации IFptr. Реализован как Singleton через
метакласс SingletonMeta с потокобезопасным threading.Lock. На процесс
гарантированно один экземпляр.
Дефолтные settings при Core():
| Параметр libfptr10 | Значение |
|---|---|
LIBFPTR_SETTING_MODEL |
LIBFPTR_MODEL_ATOL_AUTO (автоопределение) |
LIBFPTR_SETTING_PORT |
LIBFPTR_PORT_USB |
LIBFPTR_SETTING_USB_DEVICE_PATH |
"auto" |
LIBFPTR_SETTING_OFD_CHANNEL |
LIBFPTR_OFD_CHANNEL_AUTO |
LIBFPTR_SETTING_AUTO_TIME_SYNC |
True |
LIBFPTR_SETTING_AUTO_TIME_SYNC_TIME |
3600 (секунд, c 1.12.0; раньше было 15) |
Instance-level state Core.casher_info (c 1.10.0):
core = Core(path="", casher_name="Иванов И.И.", casher_inn="500100732259")
# или сменить runtime:
core.set_casher("Петров П.П.", inn="...")
Используется в _set_casher() перед каждой фискальной операцией
(setParam(1021, name), setParam(1203, inn), operatorLogin()). Если
casher_name пуст — operatorLogin пропускается (logon оператора
не происходит, чек/смена пишутся без тегов 1021/1203).
Жизненный цикл соединения:
__init__создаётIFptrinstance, читает версию, применяет settingsopen_connect()→fptr.open()— реальный коннект к ККТclose_connect()→fptr.close()__del__авто-закрывает еслиis_opened() == 1__enter__/__exit__(с 1.12.0) —with Core() as core:гарантируетclose_connect()даже при exception между open и close
2.3. Доменные классы
Cash, Fn, Receipt, Shift, Setting — потребители Core. Все принимают
один Core-экземпляр в конструктор и сохраняют self.fptr = core.fptr. Если
соединение закрыто, конструктор автоматически вызывает core.open_connect().
from ORD.ord_core import Core
from ORD.ord_receipt import Receipt
from ORD.ord_fn import Fn
core = Core() # Singleton
core.open_connect()
fn = Fn(core)
receipt = Receipt(core)
# ...
core.close_connect()
3. Типовой жизненный цикл чека
Псевдокод реального флоу из online-api/jobs/handlers.py:
core = Core()
core.open_connect()
# 1. Открыть смену (необязательно — первая фискальная операция откроет автоматически)
Shift(core).open_shift()
# 2. Открыть чек
receipt = Receipt(core)
receipt.open_receipt({
"docType": "SALE", # или "RETURN"
"printReceipt": False, # электронный
"email": "client@example.com",
"taxMode": "OSN", # OSN / USN_INCOME / ...
})
# 3. Регистрация каждой позиции
receipt.receipt_registration({
"name": "Кроссовки Nike",
"price": 10000,
"quantity": "1",
"vatTag": 1102, # 1102 — Сумма НДС по ставке 20%
"vat": 22, # ставка 22 → LIBFPTR_TAX_VAT22
"discSum": 0,
"nomenclatureCode": "0104680001234567...", # КМ Data Matrix, опционально
"codeCheck": "UUID=...&Time=...", # результат ПИоТ-проверки, опционально
})
# 4. Оплата
receipt.receipt_payment({"paymentType": "CARD", "sum": 10000})
# paymentType резолвится через Receipt.payment_type → LIBFPTR_PT_* (с 1.8.26.1)
# 5. Закрытие чека → ФН → ОФД
receipt.receipt_close()
# 6. Получить фискальные реквизиты
last = Fn(core).get_info_last_doc()
# → {"document_number": 123, "fiscal_sign": "1234567890", "date_time": "..."}
Закрытие смены (Z-отчёт): Shift(core).close_shift().
4. API Reference
4.1. Core
| Метод | Возврат | Назначение |
|---|---|---|
Core(path: str = '') |
— | Singleton-инициализация IFptr с дефолтными settings |
open_connect() |
bool |
fptr.open() — коннект к ККТ |
close_connect() |
bool |
fptr.close() |
is_opened() |
int |
0/1, см. §5.1 — не отражает реальное состояние |
get_version_driver() |
str |
версия libfptr10 |
get_current_datetime() |
str |
"%Y-%m-%d %H:%M:%S" от ККТ |
get_setting() |
dict |
текущие device settings |
reboot() |
bool |
fptr.deviceReboot() |
_set_casher() |
bool |
оператор тег 1021 + 1203 + operatorLogin() (приватный) |
_check_document_close() |
bool |
проверка checkDocumentClosed, допечатка (приватный) |
_error_log() |
— | пишет errorCode + errorDescription в журнал libfptr10 |
info_log(msg: str) |
— | пишет INFO в журнал libfptr10 |
4.2. Cash
| Метод | Возврат | Назначение |
|---|---|---|
Cash(core) |
— | Конструктор; авто-open_connect если закрыто |
get_cash_info() |
dict |
13 полей: модель, ФН, версия прошивки, состояние смены, ФФД |
get_cash_info_v2() |
dict |
31 поле: всё из v1 + флаги принтера/бумаги/ФН/блокировок |
get_uptime_cash() |
int |
секунды непрерывной работы ККТ |
cash_registration() |
bool |
Регистрация ККТ (МГМ). Хардкод реквизитов brandshop, см. §5.2 |
shift_stage mapping: 0→CLOSED, 1→OPENED, 2→EXPIRED.
4.3. Fn
| Метод | Возврат | Назначение |
|---|---|---|
Fn(core) |
— | Конструктор |
get_status_fn() |
str |
FNS_INITIAL/CONFIGURED/FISCAL_MODE/POSTFISCAL_MODE/ACCESS_ARCHIVE |
get_info_last_receipt() |
dict |
номер, тип, сумма, ФПД, datetime последнего чека |
get_info_last_doc() |
dict |
то же для последнего фискального документа |
get_version_ffd() |
dict |
device/fn/min/max версии ФФД (есть баг ключа, см. §5.8) |
get_info_doc(number_doc) |
dict |
тип, номер, ФПД, datetime, has_ofd_ticket для номера ФД |
get_ticket_ofd(number_doc) |
dict |
номер, datetime, OFD ФПД (bytearray) квитанции от ОФД |
get_ofd_document_by_number(n) |
list[dict] |
TLV-структуры ФД (tag_number, tag_name, tag_type, tag_value) |
get_fn_error() |
dict |
network / ofd / fn ошибки и их тексты |
get_exchange_status() |
dict |
статус ОФД-обмена, кол-во неотправленных |
get_registration_number() |
str |
РНМ ККТ (тег 1037) |
4.4. Receipt
| Метод | Возврат | Назначение |
|---|---|---|
Receipt(core) |
— | Конструктор |
open_receipt(receipt_data) |
bool |
Открытие чека (см. ниже) |
cancel_receipt() |
bool |
fptr.cancelReceipt() — отмена незакрытого чека |
receipt_registration(product) |
bool |
Регистрация одной позиции |
receipt_payment(money_position) |
bool |
Оплата (paymentType через Receipt.payment_type) |
receipt_total(money_position) |
bool |
Регистрация итога (необязательно) |
receipt_close() |
bool |
fptr.closeReceipt() → запись в ФН |
open_receipt(receipt_data) ожидает:
| Ключ | Тип | Значения |
|---|---|---|
docType |
str | см. Receipt.receipt_type: SALE/RETURN, SALE_CORRECTION/RETURN_CORRECTION, BUY/BUY_RETURN, BUY_CORRECTION/BUY_RETURN_CORRECTION |
printReceipt |
bool | False → electronic чек (LIBFPTR_PARAM_RECEIPT_ELECTRONICALLY=True) |
email |
str | тег 1008 — email клиента |
taxMode |
str | OSN/USN_INCOME/USN_INCOME_OUTCOME/ESN/PATENT |
Жёстко устанавливается тег 1125=1 («признак расчёта в интернете») — это
hard-coded для интернет-магазина brandshop.
receipt_registration(product) ожидает:
| Ключ | Тип | Назначение |
|---|---|---|
name |
str | LIBFPTR_PARAM_COMMODITY_NAME |
price |
int/float | LIBFPTR_PARAM_PRICE |
quantity |
str | LIBFPTR_PARAM_QUANTITY |
vat |
int | см. Receipt.vat_type: 0/5/7/10/20/22 + расчётные 5/105, 7/107, 10/110, 20/120, 22/122 + "NO" (без НДС) |
discSum |
int | LIBFPTR_PARAM_INFO_DISCOUNT_SUM (если > 0) |
nomenclatureCode |
str / None | КМ Data Matrix; запускает beginMarkingCodeValidation + polling + acceptMarkingCode |
codeCheck |
str / None | tag 1265 от ПИоТ; собирает TLV-тег 1260 (отраслевой реквизит предмета расчёта) |
vatTag |
int | поле в payload, но не используется в коде |
Цепочка libfptr10 для маркированного товара (упрощённо):
setParam(MARKING_CODE, km)
setParam(MARKING_CODE_STATUS, 2)
setParam(MARKING_PROCESSING_MODE, 0)
setParam(MEASUREMENT_UNIT, IU_PIECE)
beginMarkingCodeValidation()
while not getParamBool(MARKING_CODE_VALIDATION_READY):
getMarkingCodeValidationStatus()
validation_result = getParamInt(MARKING_CODE_ONLINE_VALIDATION_RESULT)
acceptMarkingCode()
# Если есть codeCheck (tag 1265 от ПИоТ) — формируется TLV-тег 1260.
# С 1.10.0 значения 1262/1263/1264 параметризованы через product['industry']:
setParam(1262, industry['mode']) # режим обработки (например, '030')
setParam(1263, industry['date']) # дата НПА (например, '21.11.2023')
setParam(1264, industry['num']) # номер НПА (например, '1944')
setParam(1265, codeCheck)
utilFormTlv() → tag 1260 TLV
setParam(1260, tlv)
setParam(1212, 33) # признак предмета расчёта: маркированный товар + услуга
4.5. Shift
| Метод | Возврат | Назначение |
|---|---|---|
Shift(core) |
— | Конструктор |
open_shift() |
bool |
_set_casher() → fptr.openShift() → проверка закрытия |
close_shift() |
bool |
_set_casher() → report(LIBFPTR_RT_CLOSE_SHIFT) → Z-отчёт |
4.6. Setting
| Метод | Возврат | Назначение |
|---|---|---|
Setting(core) |
— | Конструктор (composition, не наследуется от Core) |
init_setting() |
bool |
fptr.initSettings() |
get_device_setting_by_id(id, type) |
bool/int/str |
Чтение настройки ККТ (type ∈ int/string) |
set_device_setting_by_id(id, value) |
bool |
Запись настройки |
commit_setting() |
bool |
fptr.commitSettings() |
5. Известные ограничения и hidden behavior
Раздел оставлен только под активные ограничения by design. Все ранее
описанные баги и архитектурные дефекты закрыты в версиях 1.8.26.1 → 1.12.x
(полная история — в git log).
5.1. Core.is_opened() не отражает реальное состояние — by design libfptr10
Из docstring: «Результат метода не отражает текущее состояние подключения —
если с ККТ была разорвана связь, то метод всё также будет возвращать true».
Это особенность libfptr10.isOpened() — она проверяет только локальный флаг
сессии. Реально упало соединение или нет — узнаётся только на первом
вызове, который вернёт LIBFPTR_ERROR_NO_CONNECTION. ORD не может это
исправить — поведение задаётся нативной so-библиотекой.
5.2. cash_registration пишет в FN — by design (необратимо)
Метод реально вызывает fptr.fnOperation() с LIBFPTR_FNOP_REGISTRATION —
это необратимая операция перерегистрации ФН. Использовать только для
первоначальной активации новой ККТ или замены ФН, никогда не дёргать в
тестах. Это документированное поведение API libfptr10; защиту от
случайного вызова не добавляем — драйвер должен быть тонкой обёрткой.
6. Версионирование и релизы
Используется semver: MAJOR.MINOR.PATCH.
MAJOR— несовместимое API изменениеMINOR— новый функционал, обратно совместимыйPATCH— багфиксы
Процесс релиза:
- Внести изменения в feature-ветке (
feature-X.Y.Zили тематическая) - Открыть MR в
master, дождаться merge - Локально:
git checkout master && git pull, bumpversionвpyproject.toml - Сборка:
python -m build(артефакты вdist/, проверить черезtwine check dist/*) - Публикация:
twine upload dist/*(PyPI-токен в~/.pypircили черезTWINE_PASSWORD) - (Опционально) Tag:
git tag vX.Y.Z && git push origin --tags
Текущая версия: см. поле version в pyproject.toml или
pip show ORD. Источники синхронизированы:
- GitLab origin (master) —
https://brandshop.gitlab.yandexcloud.net/online-receipt/online-receipt-driver - PyPI —
https://pypi.org/project/ORD/ - Потребитель —
online-api/requirements.txt(ORD pinned)
Линии версий:
1.8.x→1.9.x→1.10.x→1.11.x→1.12.x— основная линия, все задачи roadmap были закрыты в этом окне (см.git logдля деталей).1.6.x(веткаlegacy-1.6.xв GitLab) — устаревшая, оставлена для исторической справки.denis— старая ветка экспериментов, не мерджена.
7. Тестирование
Unit-тесты на моках libfptr10.IFptr живут в этом же репо в tests/unit/,
прогоняются на любой машине без реальной кассы:
python3 -m venv .venv
.venv/bin/pip install -e '.[dev]'
.venv/bin/pytest tests/unit/ -v
E2e-тесты против реальной АТОЛ 30Ф находятся в проекте-потребителе
online-api (tests/e2e/test_fn_real.py) и запускаются на cashdev:
ssh volodya@cashdev 'cd /var/www/api/current && \
./venv/bin/pytest tests/ -m e2e -v'
В CI online-api (pipeline на development) e2e прогоняются автоматически
после каждого деплоя (deploy_all:dev step 9).
8. Контакты
- Автор: Vladimir Smirnov (volodya@brandshop.ru)
- Баги/MR: GitLab
online-receipt/online-receipt-driver
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ord-1.12.2.tar.gz.
File metadata
- Download URL: ord-1.12.2.tar.gz
- Upload date:
- Size: 24.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fe62e574d02a8d183d4f76394e6cfb29f085297797b357508988756d5af141c1
|
|
| MD5 |
14dab3426d9e2144160801b2fca46ee6
|
|
| BLAKE2b-256 |
20697612cbf87e18c2d8f1f3820be397a994d31f570e4134971747fe1264d7d5
|
File details
Details for the file ord-1.12.2-py3-none-any.whl.
File metadata
- Download URL: ord-1.12.2-py3-none-any.whl
- Upload date:
- Size: 28.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f581e7f75b441d7ac54040f18ee66a4bfcfc1fdfc4127983a3d66e02b579362
|
|
| MD5 |
e1cc92ff3aa8bc68876f91a755a40f97
|
|
| BLAKE2b-256 |
0450499d3a76023e1447fb2d16c7c2b799b8af4fa7ad62eb85630f56d804da8d
|