Skip to main content

Module for working with the ATOL cash register driver

Project description

ORD — Python-клиент драйвера АТОЛ libfptr10

Тонкая обёртка над libfptr10 (драйвер ККТ АТОЛ v10.10.x) для типовых кассовых сценариев: открытие/закрытие смены, регистрация чека продажи и возврата, чтение состояния ФН и ОФД-обмена, регистрация ККТ, чтение и запись device settings.

Используется в backend-проекте online-receipt/online-api (Flask + Celery) для фискализации чеков на физических кассах АТОЛ 30Ф, ATOL Sigma и совместимых моделях.

  • Текущая версия: 1.8.26.0
  • 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.8.26.0

Зависимость от libfptr10 (Python wrapper) ставится отдельно из дистрибутива АТОЛ kit (fptr10-rpc-server*.deb + wrappers/python/libfptr10.py).

Минимальные системные требования:

  • Python >=3.6 (3.6 в EOL, рекомендуется 3.8+)
  • libfptr10.so v10.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)
└── test/              # пока пустой шаблон, см. §6.10

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 15 (секунд)

Class-level state Core.casher_info:

casher_info = {"name": "СИС. АДМИНИСТРАТОР", "inn": ""}

Используется в _set_casher() перед каждой фискальной операцией (setParam(1021, name), setParam(1203, inn), operatorLogin()). См. §5.8 — это известное ограничение.

Жизненный цикл соединения:

  • __init__ создаёт IFptr instance, читает версию, применяет settings
  • open_connect()fptr.open() — реальный коннект к ККТ
  • close_connect()fptr.close()
  • __del__ авто-закрывает если is_opened() == 1

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 сейчас игнорируется, всегда LIBFPTR_PT_ELECTRONICALLY (см. §5.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.4 — не отражает реальное состояние
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.5

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.11)
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 Оплата (см. §5.1)
receipt_total(money_position) bool Регистрация итога (необязательно)
receipt_close() bool fptr.closeReceipt() → запись в ФН

open_receipt(receipt_data) ожидает:

Ключ Тип Значения
docType str "SALE"LIBFPTR_RT_SELL, "RETURN"LIBFPTR_RT_SELL_RETURN. Коррекций нет, см. §5.3
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 ставка (20 или 22, см. §5.2)
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:
setParam(1262, '030')                 # хардкод режима, см. §5.5
setParam(1263, '21.11.2023')          # хардкод даты, см. §5.5
setParam(1264, '1944')                # хардкод номера, см. §5.5
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) Конструктор (наследуется от Core, см. §5.6)
init_setting() bool fptr.initSettings()
get_device_setting_by_id(id, type) bool/int/str Чтение настройки ККТ (typeint/string)
set_device_setting_by_id(id, value) bool Запись настройки
commit_setting() bool fptr.commitSettings()

5. Известные ограничения и hidden behavior

5.1. paymentType хардкод в receipt_payment

Метод receipt_payment(money_position) читает только sum, а paymentType из аргумента игнорирует:

self.fptr.setParam(IFptr.LIBFPTR_PARAM_PAYMENT_TYPE, IFptr.LIBFPTR_PT_ELECTRONICALLY)
self.fptr.setParam(IFptr.LIBFPTR_PARAM_PAYMENT_SUM, sum)

То есть все оплаты регистрируются как безналичные независимо от того, что прислал клиент в paymentType. Для интернет-магазина это норм (всегда карта/electronic), но для оффлайн-кассы это юридически некорректно — наличные должны иметь LIBFPTR_PT_CASH. См. §6.1 в TODO.

5.2. VAT mapping ограничен: только 20% и 22%

В receipt_registration маппинг:

vat LIBFPTR
20 LIBFPTR_TAX_VAT20
22 LIBFPTR_TAX_VAT22
любое другое (включая 0/10/5/7/None) fallback → LIBFPTR_TAX_VAT22

Тихий fallback в 22% — юридический риск для товаров с НДС 0% (детское питание), 10% (книги, лекарства) или льготных ставок 5%/7%. См. §6.2.

5.3. docType поддерживает только SALE/RETURN

В open_receipt обрабатываются только "SALE" и "RETURN". Чеки коррекции (SELL_CORRECTION, SELL_RETURN_CORRECTION), BUY и BUY_RETURN не реализованы — else: return False. См. §6.3.

5.4. Core.is_opened() не отражает реальное состояние

Из docstring: «Результат метода не отражает текущее состояние подключения — если с ККТ была разорвана связь, то метод всё также будет возвращать true». Это особенность libfptr10.isOpened() — она проверяет только локальный флаг сессии. Реально упало соединение или нет — узнаётся только на первом вызове, который вернёт LIBFPTR_ERROR_NO_CONNECTION.

5.5. Хардкод бизнес-данных brandshop

Несколько мест в коде содержат жёстко зашитые реквизиты ООО «БШ СТОР»:

  • Cash.cash_registration() — ИНН 9705112246, адрес «127051, г. Москва, Петровский б-р, 21», email volodya@brandshop.ru, ОФД nalog.ru, ОФД-ИНН 9715260691, ОФД-имя «ООО ПС СТ», тег 1037 = 0000000001030584
  • Receipt.receipt_registration() для маркированных товаров: тег 1262 = '030', тег 1263 = '21.11.2023', тег 1264 = '1944'
  • Core.casher_info class-level: "СИС. АДМИНИСТРАТОР"

Эти константы не должны быть в opensource-обёртке. См. §6.4, §6.5.

5.6. Setting наследуется от Core

class Setting(Core):
    def __init__(self, core):
        self.core = core
        ...

Странная конструкция: Setting одновременно наследник Core (class Setting(Core):) и хранит ссылку на core-экземпляр (self.core =). Из-за SingletonMeta Setting(core) создаст другой Singleton-ключ, и Setting.is_opened() будет работать с собственным self.fptr (унаследованным от Core.__init__ во время «первого» вызова класса). Архитектурный дефект. См. §6.6.

5.7. cash_registration пишет в FN

Метод реально вызывает fptr.fnOperation() с LIBFPTR_FNOP_REGISTRATION — это необратимая операция перерегистрации ФН. Использовать только для первоначальной активации новой ККТ или замены ФН, никогда не дёргать в тестах. Логирования предупреждения нет.

5.8. casher_info class-level

Реквизиты кассира (name, inn) — это class-level переменная Core, а не instance. Это значит, что изменение из одного места приложения повлияет на все будущие вызовы _set_casher(). Для multi-tenant сценариев (несколько касс в одном процессе) — баг.

5.9. Молчаливая обработка ошибок

Все методы возвращают False при ошибке libfptr10 и пишут описание через logWrite. Никаких исключений. Это удобно для batch-обработки чеков, но затрудняет отладку — приходится парсить логи libfptr10 (/var/log/...) и коррелировать с приложением. См. §6.8.

5.10. _check_document_close infinite loop

Цикл while self.fptr.checkDocumentClosed() < 0: ... без timeout. Если ККТ отвалилась (LIBFPTR_ERROR_NO_CONNECTION) — поток зависнет навсегда. Аналогично для while self.fptr.continuePrint() < 0. См. §6.9.

5.11. get_version_ffd баг ключа

В строке 334 ord_fn.py:

version_ffd.update({"document_number": self.ffd_version.get(min_ffd_version)})

Ключ должен быть "min_ffd_version", а не "document_number". Опечатка скрывает значение min_ffd_version в возвращаемом dict.


6. Задачи на доработку (TODO)

6.1. receipt_payment: учитывать paymentType

Приоритет: P0 (юридический риск).

Текущий хардкод LIBFPTR_PT_ELECTRONICALLY заменить на маппинг:

payment_type_map = {
    "CASH":           IFptr.LIBFPTR_PT_CASH,
    "CARD":           IFptr.LIBFPTR_PT_ELECTRONICALLY,
    "ELECTRONICALLY": IFptr.LIBFPTR_PT_ELECTRONICALLY,
    "PREPAID":        IFptr.LIBFPTR_PT_PREPAID,
    "CREDIT":         IFptr.LIBFPTR_PT_CREDIT,
    "OTHER":          IFptr.LIBFPTR_PT_OTHER,
    # PT_6..PT_10 — для спец-сценариев (рассрочка, частичная оплата)
}

Default — ELECTRONICALLY (для обратной совместимости).

6.2. VAT mapping: полная таблица ставок

Приоритет: P0 (юридический риск).

Сейчас только 20% и 22%, остальное тихо в 22%. Добавить:

vat LIBFPTR Реальная ставка
0 LIBFPTR_TAX_VAT0 НДС 0%
5 LIBFPTR_TAX_VAT5 НДС 5% (льготная)
7 LIBFPTR_TAX_VAT7 НДС 7% (льготная)
10 LIBFPTR_TAX_VAT10 НДС 10%
20 LIBFPTR_TAX_VAT20 НДС 20% (старая ставка)
22 LIBFPTR_TAX_VAT22 НДС 22% (с 2026-01-01)
None/"NO" LIBFPTR_TAX_NO не облагается
"22/122" LIBFPTR_TAX_VAT122 расчётная 22/122 (предоплата с НДС 22%)
"20/120" LIBFPTR_TAX_VAT120 расчётная 20/120
"10/110" LIBFPTR_TAX_VAT110 расчётная 10/110
"5/105" LIBFPTR_TAX_VAT105 расчётная 5/105
"7/107" LIBFPTR_TAX_VAT107 расчётная 7/107

При неизвестном vatraise ValueError, не тихий fallback.

6.3. docType: коррекции и чеки расхода

Приоритет: P1.

Добавить в open_receipt обработку:

  • SALE_CORRECTIONLIBFPTR_RT_SELL_CORRECTION
  • SALE_RETURN_CORRECTIONLIBFPTR_RT_SELL_RETURN_CORRECTION
  • BUYLIBFPTR_RT_BUY
  • BUY_RETURNLIBFPTR_RT_BUY_RETURN
  • BUY_CORRECTIONLIBFPTR_RT_BUY_CORRECTION
  • BUY_RETURN_CORRECTIONLIBFPTR_RT_BUY_RETURN_CORRECTION

6.4. Вынести бизнес-реквизиты brandshop в конфигурацию

Приоритет: P1.

Cash.cash_registration() хардкодит ИНН/адрес/ОФД конкретной организации. Принимать параметром registration_data: dict либо читать из ENV (ORD_KKT_INN, ORD_KKT_ADDRESS, ORD_OFD_*).

6.5. Параметризовать отраслевой реквизит (тег 1260)

Приоритет: P1.

В receipt_registration теги 1262/1263/1264 хардкод ('030', '21.11.2023', '1944'). Это режим обработки 030 = разрешительный режим, дата документа НПА = 21 ноября 2023, номер = 1944. Это конкретный НПА. Должно приходить из payload:

"industry": {
    "mode":  "030",
    "date":  "2023-11-21",
    "num":   "1944",
    # tag 1265 — это codeCheck от ПИоТ, остаётся как есть
}

6.6. Рефакторинг Setting(Core)Setting

Приоритет: P2.

Убрать наследование от Core, использовать composition (как у остальных доменных классов: Cash(core), Fn(core), Receipt(core)).

6.7. casher_info — instance-level

Приоритет: P1.

Перевести Core.casher_info из class-level в instance + принимать в конструкторе. Альтернатива — передавать в open_receipt/open_shift и ставить только локально в рамках конкретной операции.

6.8. Опциональные исключения вместо False

Приоритет: P2.

Добавить параметр Core(raise_on_error=True). При активации все методы поднимают OrdError(error_code, error_description) вместо return False. Сохранить дефолт False для обратной совместимости. Это даст:

  • Stacktrace в логах приложения
  • Возможность except OrdError для конкретных кодов libfptr10
  • Прекращение «тихих фейлов» когда False игнорируется вызывающим кодом

6.9. Timeout в _check_document_close / continuePrint

Приоритет: P1.

Бесконечные while ... < 0: continue без выхода. Заменить на:

import time
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
    if self.fptr.checkDocumentClosed() >= 0:
        break
    self._error_log()
    time.sleep(0.5)
else:
    raise OrdTimeoutError(...)

6.10. Тесты

Приоритет: P0.

ORD/test/ORD_test.py сейчас 207 байт (пустой шаблон). Добавить:

  • Unit-тесты с моком IFptr — каждый метод проверяет правильность setParam-цепочки (без реальной кассы). Минимум 30 тестов.
  • Integration-тесты против реальной АТОЛ 30Ф (cashdev, 172.16.0.7) — реальные пробития чеков, чтение ФН. Маркер @pytest.mark.real_kkt, skip-by-default.
  • Покрытие минимум 70%.

Использовать pytest + pytest-mock. Сейчас вообще нет покрытия.

6.11. pyproject.toml вместо setup.py

Приоритет: P2.

Перейти на PEP 517 build (pyproject.toml + setuptools.build_meta). Убрать setup.py+setup.cfg, перенести метаданные:

[build-system]
requires = ["setuptools>=64", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "ORD"
version = "1.9.0"
description = "Python client for ATOL libfptr10 fiscal printer driver"
authors = [{name = "Vladimir Smirnov", email = "volodya@brandshop.ru"}]
readme = "README.md"
license = {text = "Proprietary"}
requires-python = ">=3.8"
dependencies = []  # libfptr10 ставится отдельно

[project.urls]
Repository = "https://brandshop.gitlab.yandexcloud.net/online-receipt/online-receipt-driver"
Mirror = "https://github.com/brandshopru/online-receipt-driver"

6.12. Type hints

Приоритет: P3.

Сейчас код без аннотаций. Добавить:

  • Возвращаемые типы у всех публичных методов
  • TypedDict или dataclass для словарей-результатов (CashInfo, FnDocInfo, OfdExchangeStatus, ...)
  • Конкретные перечисления для docType, paymentType, taxMode через enum.StrEnum (Python 3.11) или Literal[...]

6.13. Обновить минимальную версию Python: 3.6 → 3.8+

Приоритет: P2.

Python 3.6 в EOL с 23 декабря 2021. На cashdev сейчас стоит 3.6.8. Согласовать миграцию: 3.8 или 3.10 как минимум. Это снимет ограничения mock-3.0.5 / pytest-6.2.5 в проекте-потребителе online-api.

6.14. CI/CD в GitLab

Приоритет: P1.

Добавить .gitlab-ci.yml:

  • lintruff check ORD/ + mypy ORD/
  • testpytest tests/ (без real_kkt маркера)
  • buildpython -m build → артефакты dist/*.whl + *.tar.gz
  • publish — на tag запускать twine upload dist/* -u __token__ -p $PYPI_TOKEN
  • mirror — push на GitHub после успешного релиза в master

6.15. CHANGELOG.md

Приоритет: P2.

Сейчас отсутствует. Восстановить ретроспективно (по тэгам 1.6.x — 1.8.x) и продолжать в формате Keep a Changelog.

6.16. Контекст-менеджеры

Приоритет: P3.

Поддержать with Core() as core: (__enter__/__exit__). Гарантирует закрытие коннекта даже при exception между open и close. Сейчас полагается на __del__, который не вызывается при kill -9.

6.17. Thread-safety guarantee

Приоритет: P2.

SingletonMeta потокобезопасен на создание. Но операции над одним fptr — нет: setParam → queryData → getParam — это «stateful цепочка», и если две задачи параллельно зовут разные методы, состояние перемешается.

Опции:

  • Документировать «один процесс, один поток» как требование
  • Добавить Core._operation_lock = threading.Lock() и оборачивать им каждый публичный метод
  • Сделать Core per-thread (threading.local)

6.18. AutoTimeSyncTime: 15 секунд избыточно

Приоритет: P3.

LIBFPTR_SETTING_AUTO_TIME_SYNC_TIME = 15 означает синк раз в 15 секунд — это нагружает ФН без необходимости. ФНС требует синхронизацию раз в сутки. Поставить 3600 (раз в час) или 86400 (раз в сутки).

6.19. Логирование в стандартный logging

Приоритет: P2.

Сейчас _error_log/info_log пишут через fptr.logWrite — внутренний журнал libfptr10. Добавить параллельно вывод в стандартный logging.getLogger("ORD") чтобы интегрироваться с системным логированием приложения.

6.20. Документация кода

Приоритет: P3.

Docstrings есть, но в смешанном стиле (русский комментарий с английским именем параметров, иногда отсутствие :param:/:return:). Привести к единому формату (Google или Numpy style).

6.21. Исправить опечатку cancel_reciept.py

Приоритет: P3.

Файл в корне репо называется cancel_reciept.py (reciept → receipt). Переименовать.

6.22. Удалить артефакты из .gitignore

Приоритет: P3.

ORD.egg-info/, build/, dist/, __pycache__/, venv/ сейчас неотслеживаемые, но не добавлены в .gitignore. Добавить.


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

Используется semver: MAJOR.MINOR.PATCH[.HOTFIX].

  • MAJOR — несовместимое API изменение
  • MINOR — новый функционал, обратно совместимый
  • PATCH — багфиксы

Процесс релиза:

  1. Внести изменения в feature-ветке
  2. Merge в master после ревью
  3. Bump версии в setup.py (потом — в pyproject.toml)
  4. Поставить tag: git tag X.Y.Z && git push origin --tags
  5. Сборка: python -m build
  6. Публикация: twine upload dist/*
  7. После §6.14 — CI делает всё начиная с tag автоматически

Текущая ситуация (на 2026-06-25):

Источник Версия master
Локально (IdeaProjects/online-receipt-driver) 1.8.26.0
GitLab origin (master) 1.8.26.0
GitHub зеркало (master) 1.8.26.0
PyPI ORD 1.8.26.0
Production: online-api/venv на cashdev 1.8.26.0

Все источники синхронизированы.

История версий:

  • 1.8.x — текущая линия (НДС 22%, AutoTimeSync, разрешительный режим 030)
  • 1.6.x (ветка legacy-1.6.x в GitLab) — заброшенная ветка с устаревшим API, оставлена для исторической справки
  • denis — старая ветка экспериментов, не мерджена

8. Тестирование

До настоящего момента тесты для ORD делались только в проекте-потребителе online-api (см. online-api/tests/unit/test_piot_client_mock.py, tests/e2e/test_fn_real.py). Прогон против реальной АТОЛ 30Ф на cashdev:

ssh volodya@cashdev 'cd /var/www/api/current && \
  ./venv/bin/pytest tests/e2e/ -m e2e -v'

После §6.10 тесты переедут в этот репо.


9. Контакты

  • Автор: Vladimir Smirnov (volodya@brandshop.ru)
  • Баги/MR: GitLab online-receipt/online-receipt-driver

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ord-1.8.26.1.tar.gz (44.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ord-1.8.26.1-py3-none-any.whl (27.4 kB view details)

Uploaded Python 3

File details

Details for the file ord-1.8.26.1.tar.gz.

File metadata

  • Download URL: ord-1.8.26.1.tar.gz
  • Upload date:
  • Size: 44.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for ord-1.8.26.1.tar.gz
Algorithm Hash digest
SHA256 e8e995626a13bd1104c0596116d29f7f0bcf4a26452613a379cce6a0b123250c
MD5 0eab48a8859bb9605fb0d477014553d5
BLAKE2b-256 96620e5fab5ed68f9424a9c270c25067a1c1570ad3772c480ae8ca812f4a7eb2

See more details on using hashes here.

File details

Details for the file ord-1.8.26.1-py3-none-any.whl.

File metadata

  • Download URL: ord-1.8.26.1-py3-none-any.whl
  • Upload date:
  • Size: 27.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for ord-1.8.26.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ee482635cb46216b58252b4aa5211c7666659c312ce0f8c71374a60bb79efafd
MD5 3d9a5c874c5af57b6141337fd93b8664
BLAKE2b-256 2a7660689f6fad03b12231cc41c4c36b9701b2c133e2f6d067e9ec8e7d70508b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page