Перейти до вмісту

Інтеграція РРО в Python

Матеріал з K2 ERP Wiki Ukraine — База знань з автоматизації та санкцій в Україні


SEO title: Технічне завдання: Інтеграція РРО МІНІ-ФП54.01 для Python SEO description: Технічне завдання на реалізацію Python-сервісу для інтеграції з фізичним фіскальним реєстратором МІНІ-ФП54.01: продажі, повернення, відкриття та закриття зміни, X/Z-звіти, службове внесення/винесення, драйвер, COM/OLE/DLL, USB/RS232, черги, статуси та журналювання. SEO keywords: Python, РРО, МІНІ-ФП54.01, MINI-FP54.01, фіскальний реєстратор, Юнісістем, USB, RS232, OLE, DLL, FastAPI, POS, K2 ERP, фіскальний чек, Z-звіт, X-звіт Alternative to:



Головна ідея: розробити Python-сервіс або Python-адаптер для інтеграції ERP / POS / CRM / інтернет-магазину з фізичним фіскальним реєстратором МІНІ-ФП54.01 для друку та фіскалізації чеків, повернень, службових операцій, відкриття і закриття змін.

Критично важливо: це інтеграція з фізичним РРО, а не з хмарним ПРРО. Python-сервіс повинен працювати через драйвер, COM/OLE/DLL, протокол обміну, USB/RS232 або проміжний локальний агент.

Важливо: для МІНІ-ФП54.01 виробник надає USB-драйвер, OLE/DLL-бібліотеку для фіскальних реєстраторів, інструкції та документи щодо протоколу обміну. Перед розробкою потрібно завантажити та перевірити актуальні версії цих компонентів.

Рекомендована архітектура: Python POS Adapter працює локально на комп'ютері касира або POS-вузлі, має доступ до USB/RS232/COM/OLE/DLL-драйвера та приймає команди від ERP через HTTP API або локальну чергу.

Управлінський результат: керівник повинен бачити, скільки чеків надруковано, скільки повернень виконано, які зміни відкриті, які Z-звіти сформовані, які РРО мають помилки зв'язку або потребують уваги.

1. Мета

Метою задачі є створення Python-рішення для інтеграції з фізичним фіскальним реєстратором МІНІ-ФП54.01.

Рішення повинно забезпечити:

  • підключення до РРО через USB, RS232 або драйвер;
  • роботу через OLE/DLL-бібліотеку виробника або прямий протокол обміну;
  • перевірку стану РРО;
  • відкриття касової зміни;
  • друк і фіскалізацію чека продажу;
  • друк і фіскалізацію чека повернення;
  • службове внесення готівки;
  • службове винесення готівки;
  • формування X-звіту;
  • формування Z-звіту;
  • друк нефіскального тексту, якщо підтримується;
  • програмування товарів, податкових груп, касирів — якщо потрібно;
  • контроль помилок РРО;
  • журналювання команд і відповідей;
  • захист від дублювання чеків;
  • повторну обробку технічних помилок;
  • інтеграцію з K2 ERP / POS / CRM / сайтом.

2. Область застосування

Інтеграція призначена для:

  • фізичних магазинів;
  • аптек;
  • кафе, барів, ресторанів;
  • кіосків;
  • торгових точок із обмеженим простором;
  • виїзної торгівлі;
  • кур'єрської доставки;
  • інтернет-магазинів із друком фіскального чека на фізичному РРО;
  • POS-вузлів, де потрібна робота з реальним фіскальним реєстратором.

3. Особливості моделі МІНІ-ФП54.01

Параметр Значення / опис
Тип пристрою Фізичний фіскальний реєстратор.
Контрольна стрічка КСЕФ / КЛЕФ.
Передача даних у ДПС Через Ethernet або GSM/GPRS-модем.
Підключення до ПК USB, RS232.
Bluetooth Опція.
Кількість товарів 16 384.
Кількість відділів 64.
Кількість касирів 32.
Ширина чекової стрічки 58 мм.
Швидкість друку 8 рядків/с.
Дисплей покупця Вбудований 2x16.
Акумулятор Вбудована Li-Pol батарея.
Друк QR / штрих-коду Підтримується.
Грошова скринька Порт керування micro-jack 2,5 мм.

Критично важливо: Ethernet і GSM/GPRS у цій моделі використовуються для передачі даних РРО до ДПС, але інтеграція з Python для команд друку чеків зазвичай потребує USB/RS232 або драйвера/OLE/DLL на локальному комп'ютері.

4. Варіанти інтеграції Python з РРО

4.1. Варіант 1. Через OLE/DLL-бібліотеку виробника

Python взаємодіє з OLE/COM або DLL-бібліотекою, яку надає виробник.

Параметр Опис
Підходить для Windows POS, касових робочих місць, локальної інтеграції.
Переваги Використання офіційної бібліотеки виробника.
Обмеження Найчастіше потребує Windows, COM/OLE, драйверів і локального доступу до пристрою.
Python-підхід pywin32 / comtypes / ctypes залежно від типу бібліотеки.

Рекомендовано для MVP: починати з OLE/DLL-бібліотеки виробника, якщо вона стабільно працює з моделлю МІНІ-ФП54.01 та підтримує всі потрібні команди.

4.2. Варіант 2. Через прямий протокол обміну RS232/USB-COM

Python відкриває COM-порт і відправляє команди згідно з протоколом обміну.

Параметр Опис
Підходить для Глибокої інтеграції, Linux/Windows-сценаріїв, embedded POS.
Переваги Менше залежності від COM/OLE, потенційно кросплатформено.
Обмеження Потрібно точно реалізувати протокол, контрольні суми, таймаути, кодування, стани помилок.
Python-підхід pyserial.

Важливо: прямий протокол потрібно реалізовувати тільки після отримання актуальної документації виробника щодо команд, форматів пакетів, контрольних сум і відповідей РРО.

4.3. Варіант 3. Локальний Python Agent + ERP API

На касовому ПК запускається локальний Python Agent, який працює з РРО. ERP надсилає йому HTTP-запити.

Компонент Опис
K2 ERP / POS Створює продаж або повернення.
Python Agent Локальний сервіс на касовому ПК.
РРО МІНІ-ФП54.01 Фізичний пристрій, підключений через USB/RS232.
Dashboard Центральний контроль чеків, змін і помилок.

Рекомендована схема для K2 ERP: K2 ERP не повинна напряму керувати COM-портом. Краще використовувати локальний Python Agent біля РРО, а K2 ERP працює з ним через API.

5. Загальна архітектура

K2 ERP / POS / CRM / Website
        |
        | 1. Продаж / повернення / службова операція
        v
Central Fiscal API
        |
        | 2. Черга, журнал, дедублікація
        v
Local Python RRO Agent
        |
        | 3. OLE/DLL або Serial Protocol
        v
МІНІ-ФП54.01
        |
        | 4. Друк та фіскалізація чека
        v
Покупець / чекова стрічка
        |
        | 5. Передача даних до ДПС самим РРО
        v
ДПС

6. Основні сутності

Сутність Опис
RRO Device Фізичний фіскальний реєстратор МІНІ-ФП54.01.
RRO Agent Локальний Python-сервіс, який керує пристроєм.
Cashier Касир, від імені якого виконується операція.
Shift Касова зміна.
Fiscal Receipt Фіскальний чек продажу.
Refund Receipt Чек повернення.
Service Operation Службове внесення або винесення.
X Report Проміжний звіт без закриття зміни.
Z Report Звіт із закриттям зміни.
RRO Command Команда, що відправляється до фіскального реєстратора.
RRO Response Відповідь пристрою.
RRO Error Помилка пристрою, драйвера або з'єднання.

7. User Story

7.1. Продаж

Як POS або K2 ERP, я хочу передати продаж у Python Agent, щоб агент надрукував і фіскалізував чек на МІНІ-ФП54.01.

7.2. Повернення

Як касир, я хочу створити чек повернення, щоб коректно повернути кошти покупцю та відобразити операцію в РРО.

7.3. Відкриття зміни

Як касир, я хочу відкрити зміну на РРО, щоб мати можливість друкувати фіскальні чеки.

7.4. Закриття зміни

Як касир або адміністратор, я хочу сформувати Z-звіт, щоб закрити касову зміну.

7.5. Контроль помилок

Як керівник або адміністратор, я хочу бачити помилки РРО, щоб швидко реагувати на проблеми з папером, зв'язком, портом, драйвером або фіскалізацією.

8. Функціональні вимоги

8.1. Налаштування пристрою

У K2 ERP або локальному агенті повинна бути картка РРО.

Поле Тип Обов'язковість Опис
device_name string Так Назва РРО.
device_model string Так МІНІ-ФП54.01.
device_serial_number string Так Серійний номер пристрою.
fiscal_number string Так Фіскальний номер РРО.
connection_type enum Так OLE_DLL, SERIAL, USB_COM.
com_port string Ні Наприклад COM3.
baud_rate integer Ні Швидкість порту, якщо використовується serial.
dll_path string Ні Шлях до DLL, якщо використовується DLL.
ole_progid string Ні ProgID OLE-сервера, якщо використовується OLE.
cashier_id string Ні Касир за замовчуванням.
tax_profile_id string Ні Профіль податкових ставок.
auto_open_shift boolean Так Автоматично відкривати зміну перед першим чеком.
allow_service_operations boolean Так Дозволити службове внесення/винесення.
is_active boolean Так Чи активний пристрій.

8.2. Перевірка стану РРО

Python Agent повинен уміти перевіряти:

  • чи підключений РРО;
  • чи доступний порт;
  • чи доступний драйвер/OLE/DLL;
  • чи є папір;
  • чи відкрита кришка;
  • чи є помилки живлення;
  • чи є зв'язок з ДПС через канали пристрою;
  • чи відкрита зміна;
  • чи не заблокований РРО;
  • чи не переповнена пам'ять;
  • чи коректно встановлена дата і час;
  • чи готовий РРО до друку чека.

Критично важливо: перед друком фіскального чека агент повинен перевірити готовність РРО. Якщо РРО має критичну помилку, чек не повинен переходити в статус «Фіскалізовано».

8.3. Відкриття зміни

Локальний endpoint:

POST /api/v1/rro/shifts/open

Логіка:

1. Перевірити підключення до РРО.
2. Перевірити стан касира.
3. Перевірити, чи зміна вже відкрита.
4. Якщо зміна не відкрита — виконати команду відкриття зміни.
5. Зберегти локальний статус.
6. Повернути результат у K2 ERP / POS.

8.4. Чек продажу

Локальний endpoint:

POST /api/v1/rro/receipts/sale

Мінімальні дані:

Поле Тип Опис
external_order_id string ID замовлення у K2 ERP / POS.
idempotency_key string Ключ захисту від дублювання.
cashier_id string Касир.
items array Позиції чека.
payments array Оплати.
total_amount decimal Загальна сума.
customer object Дані покупця, якщо потрібні.
print_qr boolean Чи друкувати QR-код.

8.5. Приклад запиту на чек продажу

{
  "external_order_id": "ORDER-2026-000123",
  "idempotency_key": "ORDER-2026-000123-PAY-123456",
  "cashier_id": "cashier-001",
  "items": [
    {
      "name": "Товар 1",
      "sku": "SKU-001",
      "quantity": 2,
      "price": 250.00,
      "amount": 500.00,
      "tax_group": "VAT_20",
      "department": 1,
      "unit": "шт"
    },
    {
      "name": "Доставка",
      "sku": "DELIVERY",
      "quantity": 1,
      "price": 70.00,
      "amount": 70.00,
      "tax_group": "NO_VAT",
      "department": 2,
      "unit": "послуга"
    }
  ],
  "payments": [
    {
      "type": "CARD",
      "amount": 570.00,
      "provider": "terminal",
      "payment_id": "PAY-123456"
    }
  ],
  "total_amount": 570.00,
  "print_qr": true
}

8.6. Чек повернення

Endpoint:

POST /api/v1/rro/receipts/refund

Мінімальні дані:

Поле Тип Опис
original_receipt_id uuid Внутрішній ID первинного чека.
original_fiscal_number string Фіскальний номер первинного чека, якщо доступний.
external_refund_id string ID повернення в ERP / POS.
items array Позиції, які повертаються.
payments array Сума повернення.
reason string Причина повернення.
idempotency_key string Ключ захисту від дублювання.

Критично важливо: чек повернення не повинен перевищувати залишок по первинному чеку. Для часткових повернень система повинна вести залишок доступної до повернення суми та кількості.

8.7. Службове внесення / винесення

Endpoint:

POST /api/v1/rro/service-operation

Приклад:

{
  "operation_type": "CASH_IN",
  "amount": 1000.00,
  "cashier_id": "cashier-001",
  "comment": "Службове внесення на початок зміни",
  "idempotency_key": "CASH-IN-2026-05-07-001"
}

Типи:

Тип Опис
CASH_IN Службове внесення готівки.
CASH_OUT Службове винесення готівки.

8.8. X-звіт

Endpoint:

POST /api/v1/rro/reports/x

Призначення:

  • отримати проміжний звіт без закриття зміни;
  • перевірити обороти;
  • перевірити стан каси;
  • показати керівнику поточні підсумки.

8.9. Z-звіт

Endpoint:

POST /api/v1/rro/reports/z

Логіка:

1. Перевірити підключення до РРО.
2. Перевірити відкриту зміну.
3. Перевірити незавершені чеки.
4. Виконати команду формування Z-звіту.
5. Зберегти номер і результат Z-звіту.
6. Закрити локальну зміну.
7. Передати результат у K2 ERP.

Критично важливо: Z-звіт є операцією закриття зміни. Система повинна обмежувати доступ до цієї дії та логувати, хто її виконав.

9. Статуси чеків

Статус Код Опис Колір
Чернетка DRAFT Чек створено в Python-сервісі, але не відправлено на РРО. Сірий
Очікує друку PENDING Чек у черзі на друк. Жовтий
Відправляється на РРО SENDING_TO_RRO Команда передається в драйвер або COM-порт. Блакитний
Друкується PRINTING РРО виконує друк. Блакитний
Фіскалізовано FISCALIZED Чек успішно надруковано і зареєстровано РРО. Зелений
Помилка РРО RRO_ERROR РРО повернув помилку. Червоний
Помилка з'єднання CONNECTION_ERROR Немає зв'язку з РРО або драйвером. Червоний
Потребує повтору NEEDS_RETRY Операцію можна повторити. Помаранчевий
Скасовано CANCELLED Операцію скасовано до друку. Сірий
Повернення REFUNDED По чеку створено повне або часткове повернення. Фіолетовий

10. Статуси РРО

Статус Код Опис Колір
Готовий READY РРО готовий до роботи. Зелений
Не підключений DISCONNECTED Немає зв'язку з пристроєм. Червоний
Немає паперу PAPER_OUT Потрібно замінити рулон. Помаранчевий
Відкрита кришка COVER_OPEN Кришка принтера відкрита. Помаранчевий
Помилка фіскальної пам'яті FISCAL_MEMORY_ERROR Критична помилка. Червоний
Немає зв'язку з ДПС TAX_SERVER_CONNECTION_ERROR Пристрій не може передати дані. Помаранчевий
Зміна відкрита SHIFT_OPEN Можна друкувати фіскальні чеки. Зелений
Зміна закрита SHIFT_CLOSED Перед продажем потрібно відкрити зміну. Сірий
Заблоковано BLOCKED Робота неможлива. Червоний

11. Єдина логіка кольорів

Колір HTML Значення Де використовується
Зелений #c8e6c9 Успішна операція або нормальний стан. Dashboard, список чеків, статус РРО.
Блакитний #bbdefb Операція виконується. Черга, друк, передача команди.
Жовтий #fff9c4 Очікування або попередження. Черга чеків, очікування друку.
Помаранчевий #ffcc80 Потрібна дія користувача. Немає паперу, кришка, повтор.
Червоний #ef9a9a Критична помилка. Помилка РРО, порт недоступний, фіскальна помилка.
Фіолетовий #f3e5f5 Повернення або спеціальна операція. Refund, службові операції.
Сірий #eeeeee Неактивно або скасовано. Чернетка, зміна закрита.

12. Python RRO Agent

12.1. Призначення

Python RRO Agent — це локальний сервіс, який встановлюється на касовий ПК і має доступ до РРО через USB/RS232/OLE/DLL.

Він повинен:

  • приймати HTTP-запити від K2 ERP / POS;
  • керувати РРО;
  • виконувати друк чеків;
  • повертати статуси;
  • зберігати локальний журнал;
  • працювати навіть при тимчасовій недоступності центральної системи, якщо це дозволено сценарієм;
  • синхронізувати результати з центральною БД.

12.2. Рекомендований стек агента

Компонент Технологія
Мова Python 3.11+
API FastAPI
Доступ до COM/OLE pywin32 або comtypes
Доступ до DLL ctypes або cffi
Доступ до COM-порту pyserial
Локальна БД SQLite або PostgreSQL
Черга SQLite queue / Redis / RQ
Логи structlog / logging
Упаковка Windows Service / Docker для Linux-сценаріїв, якщо serial

12.3. Методи Python RRO Client

class MiniFP54Client:
    def check_connection(self) -> "RROStatus":
        pass

    def get_status(self) -> "RROStatus":
        pass

    def open_shift(self, cashier_id: str) -> "ShiftResponse":
        pass

    def close_shift(self) -> "ZReportResponse":
        pass

    def print_x_report(self) -> "XReportResponse":
        pass

    def print_sale_receipt(self, payload: "SaleReceiptPayload") -> "ReceiptResponse":
        pass

    def print_refund_receipt(self, payload: "RefundReceiptPayload") -> "ReceiptResponse":
        pass

    def service_cash_in(self, amount: float, comment: str | None = None) -> "ServiceOperationResponse":
        pass

    def service_cash_out(self, amount: float, comment: str | None = None) -> "ServiceOperationResponse":
        pass

    def print_non_fiscal_text(self, lines: list[str]) -> "PrintResponse":
        pass

13. Приклад конфігурації

from pydantic_settings import BaseSettings


class MiniFP54Settings(BaseSettings):
    connection_type: str = "OLE_DLL"
    com_port: str | None = "COM3"
    baud_rate: int = 115200
    dll_path: str | None = None
    ole_progid: str | None = None
    timeout_seconds: int = 30
    retry_count: int = 2
    retry_backoff_seconds: int = 3
    auto_open_shift: bool = True
    log_raw_commands: bool = True
    allow_refunds: bool = True
    allow_service_operations: bool = True

Приклад `.env`:

MINI_FP54_CONNECTION_TYPE=OLE_DLL
MINI_FP54_COM_PORT=COM3
MINI_FP54_BAUD_RATE=115200
MINI_FP54_TIMEOUT_SECONDS=30
MINI_FP54_RETRY_COUNT=2
MINI_FP54_AUTO_OPEN_SHIFT=true
MINI_FP54_LOG_RAW_COMMANDS=true

14. Валідація чека

Перед відправкою на РРО система повинна перевірити:

  • наявність external_order_id;
  • наявність idempotency_key;
  • відсутність уже фіскалізованого чека з таким ключем;
  • наявність відкритої зміни або можливість її відкрити;
  • готовність РРО;
  • наявність паперу;
  • відсутність критичних помилок;
  • наявність хоча б однієї позиції;
  • коректність кількості;
  • коректність ціни;
  • коректність суми рядка;
  • відповідність total_amount сумі товарів і оплат;
  • коректність типу оплати;
  • коректність податкових груп;
  • довжину назви товару;
  • довжину рядка чека;
  • наявність відділу, якщо він обов'язковий;
  • коректність QR-коду, якщо він друкується.

Важливо: МІНІ-ФП54.01 має обмеження на кількість символів у рядку та в назві товару. Python Agent повинен або обрізати рядки за правилом, або повертати помилку валідації.

15. Дедублікація

Система повинна не допускати дублювання чеків.

Ключі дедублікації:

Ключ Призначення
external_order_id ID замовлення у зовнішній системі.
external_payment_id ID оплати.
idempotency_key Основний ключ повторного запиту.
receipt_hash Hash товарів, сум, оплат і каси.

Приклад:

sha256(external_order_id + total_amount + payment_id + device_serial_number)

Критично важливо: повторний запит із тим самим idempotency_key не повинен друкувати другий фіскальний чек. Він повинен повернути результат уже виконаної операції.

16. Черга друку

16.1. Логіка черги

1. POS / K2 ERP надсилає запит на чек.
2. Python Agent виконує валідацію.
3. Створюється локальний запис receipt зі статусом PENDING.
4. Чек потрапляє в чергу друку.
5. Worker перевіряє стан РРО.
6. Якщо потрібно — відкриває зміну.
7. Worker друкує чек.
8. Результат зберігається локально.
9. Результат синхронізується з центральною системою.

16.2. Пріоритети

Тип задачі Пріоритет Коментар
Чек продажу Високий Основна операція.
Чек повернення Високий Фінансова операція.
Z-звіт Критичний Закриття зміни.
X-звіт Середній Контрольний звіт.
Службове внесення / винесення Середній Касова операція.
Нефіскальний друк Низький Не блокує продажі.

17. Модель даних

17.1. rro_devices

Поле Тип Опис
id uuid ID пристрою.
model varchar MINI_FP54_01.
serial_number varchar Серійний номер.
fiscal_number varchar Фіскальний номер.
connection_type varchar OLE_DLL, SERIAL, USB_COM.
com_port varchar COM-порт.
baud_rate integer Швидкість порту.
dll_path varchar Шлях до DLL.
ole_progid varchar ProgID OLE.
status varchar Поточний стан.
current_shift_id uuid Поточна зміна.
is_active boolean Активність.

17.2. rro_shifts

Поле Тип Опис
id uuid ID зміни.
device_id uuid ID РРО.
cashier_id varchar Касир.
status varchar OPEN, CLOSED, ERROR.
opened_at timestamp Дата відкриття.
closed_at timestamp Дата закриття.
z_report_number varchar Номер Z-звіту.
raw_open_response jsonb/text Відповідь відкриття.
raw_close_response jsonb/text Відповідь закриття.
error_message text Помилка.

17.3. rro_receipts

Поле Тип Опис
id uuid ID чека.
device_id uuid РРО.
shift_id uuid Зміна.
external_order_id varchar ID замовлення.
external_payment_id varchar ID оплати.
idempotency_key varchar Ключ дедублікації.
receipt_type varchar sale, refund, service.
status varchar Статус.
total_amount numeric Загальна сума.
fiscal_number varchar Фіскальний номер або номер чека, якщо доступний.
printed_at timestamp Дата друку.
raw_command text/jsonb Команда до РРО.
raw_response text/jsonb Відповідь РРО.
error_code varchar Код помилки.
error_message text Повідомлення помилки.

17.4. rro_receipt_items

Поле Тип Опис
id uuid ID позиції.
receipt_id uuid ID чека.
name varchar Назва товару.
sku varchar Артикул.
quantity numeric Кількість.
unit varchar Одиниця.
price numeric Ціна.
amount numeric Сума.
tax_group varchar Податкова група.
department integer Відділ.
discount_amount numeric Знижка.

17.5. rro_events

Поле Тип Опис
id uuid ID події.
entity_type varchar device, shift, receipt.
entity_id uuid ID сутності.
event_type varchar Тип події.
old_status varchar Старий статус.
new_status varchar Новий статус.
payload jsonb/text Дані події.
created_at timestamp Дата події.

18. API Python Agent

18.1. Перевірка стану агента

GET /api/v1/health

18.2. Перевірка стану РРО

GET /api/v1/rro/status

18.3. Відкриття зміни

POST /api/v1/rro/shifts/open

18.4. Закриття зміни / Z-звіт

POST /api/v1/rro/reports/z

18.5. X-звіт

POST /api/v1/rro/reports/x

18.6. Чек продажу

POST /api/v1/rro/receipts/sale

18.7. Чек повернення

POST /api/v1/rro/receipts/refund

18.8. Службова операція

POST /api/v1/rro/service-operation

18.9. Повторити чек

POST /api/v1/rro/receipts/{receipt_id}/retry

18.10. Отримати журнал подій

GET /api/v1/rro/events?date_from=2026-05-01&date_to=2026-05-07

19. Приклад Python-логіки

19.1. Абстрактний інтерфейс драйвера

from abc import ABC, abstractmethod


class RRODriver(ABC):
    @abstractmethod
    def connect(self) -> None:
        pass

    @abstractmethod
    def get_status(self) -> dict:
        pass

    @abstractmethod
    def open_shift(self, cashier_id: str) -> dict:
        pass

    @abstractmethod
    def close_shift(self) -> dict:
        pass

    @abstractmethod
    def x_report(self) -> dict:
        pass

    @abstractmethod
    def sale_receipt(self, receipt: dict) -> dict:
        pass

    @abstractmethod
    def refund_receipt(self, receipt: dict) -> dict:
        pass

    @abstractmethod
    def service_cash_in(self, amount: float, comment: str | None = None) -> dict:
        pass

    @abstractmethod
    def service_cash_out(self, amount: float, comment: str | None = None) -> dict:
        pass

19.2. Приклад OLE-драйвера

class MiniFP54OleDriver(RRODriver):
    def __init__(self, ole_progid: str):
        self.ole_progid = ole_progid
        self.device = None

    def connect(self) -> None:
        import win32com.client
        self.device = win32com.client.Dispatch(self.ole_progid)

    def get_status(self) -> dict:
        # Назви методів залежать від документації OLE-сервера виробника.
        # Тут наведено тільки архітектурний приклад.
        result = self.device.GetStatus()
        return {"raw": result}

    def open_shift(self, cashier_id: str) -> dict:
        result = self.device.OpenShift(cashier_id)
        return {"raw": result}

    def close_shift(self) -> dict:
        result = self.device.ZReport()
        return {"raw": result}

    def x_report(self) -> dict:
        result = self.device.XReport()
        return {"raw": result}

    def sale_receipt(self, receipt: dict) -> dict:
        self.device.OpenReceipt(0)

        for item in receipt["items"]:
            self.device.Sale(
                item["name"],
                float(item["price"]),
                float(item["quantity"]),
                item["tax_group"],
                item.get("department", 1),
            )

        for payment in receipt["payments"]:
            self.device.Payment(payment["type"], float(payment["amount"]))

        result = self.device.CloseReceipt()
        return {"raw": result}

Важливо: назви методів OLE/DLL у прикладі є умовними. Реальні назви методів, параметри та коди відповідей потрібно взяти з актуального керівництва програміста / OLE-сервера виробника.

19.3. Приклад Serial-драйвера

class MiniFP54SerialDriver(RRODriver):
    def __init__(self, port: str, baud_rate: int, timeout: int = 30):
        self.port = port
        self.baud_rate = baud_rate
        self.timeout = timeout
        self.serial = None

    def connect(self) -> None:
        import serial
        self.serial = serial.Serial(
            port=self.port,
            baudrate=self.baud_rate,
            timeout=self.timeout,
        )

    def send_command(self, command: bytes) -> bytes:
        if self.serial is None or not self.serial.is_open:
            self.connect()

        self.serial.write(command)
        response = self.serial.read_until()
        return response

    def get_status(self) -> dict:
        command = b"STATUS_COMMAND_PLACEHOLDER"
        response = self.send_command(command)
        return {"raw": response.hex()}

    def open_shift(self, cashier_id: str) -> dict:
        command = b"OPEN_SHIFT_COMMAND_PLACEHOLDER"
        response = self.send_command(command)
        return {"raw": response.hex()}

    def close_shift(self) -> dict:
        command = b"Z_REPORT_COMMAND_PLACEHOLDER"
        response = self.send_command(command)
        return {"raw": response.hex()}

    def x_report(self) -> dict:
        command = b"X_REPORT_COMMAND_PLACEHOLDER"
        response = self.send_command(command)
        return {"raw": response.hex()}

Заборонено: використовувати placeholder-команди в production. Для serial-інтеграції обов'язково потрібен офіційний протокол обміну з точним форматом команд, відповідей, кодування та контрольних сум.

20. Обробка помилок

20.1. Типи помилок

Тип Опис Дія системи
ValidationError Некоректні дані чека. Не відправляти на РРО.
ConnectionError Немає зв'язку з РРО. Перевести чек у CONNECTION_ERROR або NEEDS_RETRY.
DriverError Помилка OLE/DLL/драйвера. Записати raw-помилку, повідомити адміністратора.
PortBusyError COM-порт зайнятий. Повторити після паузи або заблокувати чергу.
PaperOutError Немає паперу. Зупинити друк, показати помаранчевий статус.
CoverOpenError Кришка відкрита. Зупинити друк, чек лишити в NEEDS_RETRY.
FiscalMemoryError Помилка фіскальної пам'яті. Критична помилка, заборонити друк.
ShiftClosedError Зміна закрита. Відкрити зміну, якщо дозволено.
DuplicateReceiptError Чек уже надруковано. Повернути існуючий результат.
RefundLimitError Повернення перевищує доступну суму. Заборонити операцію.

20.2. Retry-логіка

Retry дозволений для:

  • тимчасової втрати зв'язку;
  • зайнятого COM-порту;
  • timeout;
  • тимчасової помилки драйвера;
  • очікування готовності РРО;
  • відновлення після відсутності паперу, якщо чек не був завершений.

Retry заборонений для:

  • уже фіскалізованого чека;
  • повернення понад доступну суму;
  • некоректної суми;
  • помилки фіскальної пам'яті;
  • невідомого стану, коли неможливо визначити, чи чек уже надруковано.

Критично важливо: якщо після збою неможливо визначити, чи чек був надрукований, система повинна перевести операцію в статус MANUAL_REVIEW, а не автоматично друкувати повторно.

21. Dashboard керівника

21.1. Основні KPI

KPI Опис Колір
Чеків за день Кількість чеків продажу. Інформація
Фіскалізовано Кількість успішних чеків. Норма
Повернення Кількість чеків повернення. Контроль
Помилки РРО Кількість помилкових операцій. Критично
Потребують повтору Чеки у NEEDS_RETRY. Потрібна дія
Незакриті зміни Відкриті зміни без Z-звіту. Потрібна дія
РРО не підключені Пристрої без зв'язку. Критично

21.2. Приклад dashboard

Показник Значення Стан
Чеків за день 384 Інформація
Фіскалізовано 378 Норма
Повернення 9 Контроль
Помилки РРО 4 Критично
Потребують повтору 3 Потрібна дія
Незакриті зміни 1 Потрібна дія

21.3. Проблемні операції

Час РРО Замовлення Сума Статус Помилка Дія
10:42 MINI-FP54.01 #001 ORDER-123 570.00 Помилка Немає зв'язку з COM-портом Перевірити підключення
11:05 MINI-FP54.01 #001 ORDER-124 1200.00 Потребує повтору Немає паперу Замінити папір і повторити
12:10 MINI-FP54.01 #002 SHIFT-55 - Зміна відкрита Не закрито Z-звіт Закрити зміну

22. Безпека

Система повинна забезпечити:

  • доступ до локального агента тільки з дозволених IP або через токен;
  • HTTPS або локальну захищену мережу;
  • авторизацію запитів від K2 ERP / POS;
  • розмежування прав: продаж, повернення, X-звіт, Z-звіт, службові операції;
  • журнал дій користувачів;
  • захист від дублювання чеків;
  • заборону прямого доступу до драйвера з кількох процесів;
  • шифрування конфігурацій, якщо містять чутливі дані;
  • маскування персональних даних покупців у логах.

23. Логування та аудит

Система повинна логувати:

Подія Що зберігати
Перевірка РРО Статус, помилки, час.
Відкриття зміни Касир, час, відповідь РРО.
Чек продажу Замовлення, сума, позиції, статус.
Чек повернення Первинний чек, сума, причина.
Службова операція Тип, сума, касир.
X-звіт Час, РРО, відповідь.
Z-звіт Час, номер звіту, результат.
Помилка драйвера Код, текст, raw-відповідь.
Повторна операція Хто запустив, причина, результат.

24. Acceptance Criteria

24.1. Підключення

Критерій Очікуваний результат
AC-1 Адміністратор налаштовує РРО. Пристрій зберігається в системі.
AC-2 Python Agent перевіряє статус РРО. Система повертає READY або конкретну помилку.
AC-3 РРО не підключений. Система показує DISCONNECTED червоним кольором.

24.2. Продаж

Критерій Очікуваний результат
AC-4 POS передає продаж. Python Agent створює чек у статусі PENDING.
AC-5 РРО готовий. Чек друкується і переходить у FISCALIZED.
AC-6 Немає паперу. Чек переходить у NEEDS_RETRY або RRO_ERROR.
AC-7 Повторний запит має той самий idempotency_key. Другий чек не друкується.

24.3. Повернення

Критерій Очікуваний результат
AC-8 Касир створює повернення. Друкується чек повернення.
AC-9 Сума повернення перевищує продаж. Система блокує операцію.
AC-10 Повернення часткове. Система зменшує доступний залишок до повернення.

24.4. Зміни та звіти

Критерій Очікуваний результат
AC-11 Касир відкриває зміну. РРО переходить у стан SHIFT_OPEN.
AC-12 Касир формує X-звіт. РРО друкує X-звіт без закриття зміни.
AC-13 Касир формує Z-звіт. РРО закриває зміну.
AC-14 Зміна не закрита наприкінці дня. Dashboard показує помаранчеве попередження.

24.5. Dashboard

Критерій Очікуваний результат
AC-15 Керівник відкриває dashboard. Він бачить чеки, повернення, помилки, незакриті зміни.
AC-16 Є помилки РРО. Вони підсвічуються червоним.
AC-17 Є чеки, що потребують повтору. Вони підсвічуються помаранчевим.

25. MVP

До MVP входить:

  • локальний Python Agent;
  • налаштування підключення до МІНІ-ФП54.01;
  • перевірка стану РРО;
  • відкриття зміни;
  • друк чека продажу;
  • друк чека повернення;
  • службове внесення / винесення;
  • X-звіт;
  • Z-звіт;
  • локальна БД чеків;
  • дедублікація;
  • журнал команд і відповідей;
  • базовий dashboard API;
  • обробка помилок паперу, порту, драйвера, зміни;
  • retry для безпечних ситуацій.

До MVP не входить:

  • повна реалізація всього протоколу обміну;
  • автоматичне програмування всієї номенклатури;
  • повний POS UI;
  • власна фіскальна логіка замість РРО;
  • складна офлайн-синхронізація;
  • інтеграція з усіма моделями РРО;
  • підтримка Linux, якщо обрано OLE/DLL для Windows.

26. Етапи реалізації

Етап 1. Аналіз драйвера та протоколу

  • завантажити інструкцію з експлуатації;
  • завантажити зміни до протоколу обміну;
  • завантажити OLE/DLL-бібліотеку;
  • завантажити USB-драйвер;
  • перевірити підключення РРО до ПК;
  • визначити робочий сценарій: OLE/DLL або serial.

Етап 2. Локальний Python Agent

  • створити FastAPI-сервіс;
  • реалізувати healthcheck;
  • реалізувати локальну БД;
  • реалізувати модель пристрою;
  • реалізувати логування.

Етап 3. Драйверний шар

  • реалізувати RRODriver interface;
  • реалізувати MiniFP54OleDriver або MiniFP54SerialDriver;
  • реалізувати check_status;
  • реалізувати open_shift;
  • реалізувати X/Z-звіти.

Етап 4. Чеки

  • реалізувати sale receipt;
  • реалізувати refund receipt;
  • реалізувати валідацію;
  • реалізувати дедублікацію;
  • реалізувати чергу друку.

Етап 5. Службові операції

  • реалізувати cash_in;
  • реалізувати cash_out;
  • реалізувати права доступу;
  • реалізувати аудит.

Етап 6. Dashboard і синхронізація

  • реалізувати dashboard API;
  • реалізувати список помилок;
  • реалізувати синхронізацію з K2 ERP;
  • реалізувати експорт журналу, якщо потрібно.

Етап 7. Production hardening

  • реалізувати Windows Service;
  • додати моніторинг агента;
  • додати auto-restart;
  • додати резервне копіювання локальної БД;
  • додати alerting;
  • протестувати типові помилки РРО.

27. Ризики

Ризик Опис Як зменшити
Немає актуального протоколу Без документації неможливо безпечно реалізувати serial-інтеграцію. Використовувати OLE/DLL або отримати документацію виробника.
OLE/DLL працює тільки на Windows Обмеження для Linux-серверів. Виносити інтеграцію в локальний Windows Agent.
Дублювання чеків Повторний запит може надрукувати другий чек. Idempotency key, локальна БД, журнал статусів.
Невідомий стан після збою Невідомо, чи чек надрукований. MANUAL_REVIEW замість автоматичного повтору.
Немає паперу Чек не може бути надрукований. Статус PAPER_OUT, повтор після заміни паперу.
COM-порт зайнятий Інший процес використовує РРО. Заборонити паралельний доступ.
Не закрито зміну Касир забув зробити Z-звіт. Dashboard, нагадування, блок попереджень.

28. Відкриті питання

  1. Який варіант інтеграції обираємо: OLE/DLL чи прямий serial-протокол?
  2. На якій ОС працюватиме касовий ПК: Windows чи Linux?
  3. Чи потрібно запускати Python Agent як Windows Service?
  4. Чи потрібно інтегрувати агент із K2 ERP?
  5. Чи потрібна локальна БД на касовому ПК?
  6. Чи потрібна офлайн-робота при недоступності центральної ERP?
  7. Чи потрібно програмувати товари в РРО?
  8. Чи потрібно програмувати податкові ставки з Python?
  9. Чи потрібно друкувати QR-код у чеку?
  10. Чи потрібно відкривати грошову скриньку?
  11. Чи буде декілька РРО на одному ПК?
  12. Чи буде один РРО на декілька касирів?
  13. Чи потрібен централізований dashboard по декількох торгових точках?
  14. Які типи оплат підтримуються: готівка, картка, змішана оплата?
  15. Чи потрібна інтеграція з банківським POS-терміналом?

29. Джерела

30. Див. також