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

Інтеграція РРО в Python через загальну бібліотеку для різних РРО

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


SEO title: Технічне завдання: Інтеграція РРО в Python через ArtSoft Універсальний драйвер реєстраторів SEO description: Технічне завдання на реалізацію Python-сервісу для інтеграції з різними фізичними РРО через ArtSoft Універсальний драйвер реєстраторів: чеки продажу, повернення, службові операції, X/Z-звіти, зміни, статуси, помилки, драйверний адаптер, черги та журналювання. SEO keywords: Python, РРО, ArtSoft, універсальний драйвер реєстраторів, фіскальний реєстратор, каса, POS, FastAPI, K2 ERP, фіскальний чек, Z-звіт, X-звіт, OLE, DLL, Linux, Windows Alternative to:


Ознайомтесь з документацією від розробника універсального драйвера РРО: Керівництво програміста "АртСофт - Універсальний драйвер фіскальних реєстраторів для України"

Головна ідея: розробити Python-сервіс або Python-адаптер, який дозволяє K2 ERP / POS / CRM / обліковій системі працювати з різними фізичними РРО через ArtSoft Універсальний драйвер реєстраторів, не реалізовуючи окремий низькорівневий протокол для кожної моделі РРО.

Критично важливо: це інтеграція з фізичними РРО через проміжний драйвер, а не ПРРО типу Checkbox або Вчасно.Каса. Python-сервіс повинен працювати з драйвером ArtSoft, а не напряму з ДПС.

Важливо: ArtSoft-драйвер призначений для спрощення роботи з фіскальними реєстраторами: замість реалізації протоколу кожного РРО Python-інтеграція повинна викликати високорівневі команди драйвера.

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

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

1. Мета

Метою задачі є створення універсального Python-рішення для роботи з різними фізичними РРО через ArtSoft Універсальний драйвер реєстраторів.

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

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

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

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

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

3. Чому використовується ArtSoft-драйвер

ArtSoft Універсальний драйвер реєстраторів потрібен для того, щоб не писати окрему інтеграцію під кожну модель РРО.

Проблема без універсального драйвера Рішення через ArtSoft
Кожен РРО має власний протокол обміну. Python працює з єдиним високорівневим драйвером.
Потрібно реалізовувати контрольні суми, пакети, таймаути, коди помилок. Цю низькорівневу логіку бере на себе драйвер.
Складно підтримувати різні моделі РРО. Підтримка моделей централізується на стороні драйвера.
Важко оновлювати логіку під нові форми чеків. ArtSoft випускає оновлення драйвера.
Ризик помилок у фіскальному протоколі. Python працює через перевірені команди драйвера.

Рекомендовано для MVP: реалізувати інтеграцію Python не з конкретним РРО, а з ArtSoft-драйвером як із єдиним абстрактним шаром для всіх підтримуваних реєстраторів.

4. Технічні особливості ArtSoft-драйвера

Характеристика Опис
Тип рішення Програмне забезпечення для керування фіскальними реєстраторами.
Основне призначення Надати високорівневі команди для роботи з РРО без реалізації протоколу кожної моделі.
Сценарій використання Підключення облікових програм, POS-систем, касових місць до фізичних РРО.
Підтримка моделей Залежить від актуального списку підтримуваних моделей ArtSoft.
Оновлення Потрібно контролювати версію драйвера та оновлення підтримки нових РРО і форм чеків.
Інтеграційний шар DLL / OLE / інший програмний інтерфейс згідно з документацією ArtSoft.

На сторінці ArtSoft окремо вказано, що компанія випускає оновлення універсального драйвера для підтримки нових версій реєстраторів і нової друкованої форми чека. Це потрібно врахувати в експлуатації та оновленнях production-середовища. :contentReference[oaicite:1]{index=1}

5. Варіанти інтеграції Python з ArtSoft

5.1. Варіант 1. Через OLE / COM-інтерфейс

Python викликає об'єкти драйвера через COM/OLE.

Параметр Опис
Підходить для Windows POS, касових робочих місць.
Python-бібліотеки pywin32 або comtypes.
Переваги Зручний сценарій для Windows, якщо ArtSoft надає OLE-сервер.
Обмеження Потребує Windows, встановленого драйвера та коректної COM-реєстрації.

5.2. Варіант 2. Через DLL

Python викликає функції DLL через `ctypes` або `cffi`.

Параметр Опис
Підходить для Windows-сценаріїв, де доступна DLL-бібліотека.
Python-бібліотеки ctypes або cffi.
Переваги Прямі виклики бібліотеки.
Обмеження Потрібні точні сигнатури функцій, типи параметрів, коди відповідей і правила 32/64-bit сумісності.

5.3. Варіант 3. Через локальний ArtSoft-сервіс / агент

Якщо ArtSoft надає сервісний режим або локальний серверний компонент, Python може працювати з ним через локальний API або файловий/черговий обмін.

Параметр Опис
Підходить для POS-вузлів, де драйвер працює як окремий сервіс.
Python-підхід HTTP, TCP, файли обміну або інший механізм згідно з документацією.
Переваги Менше залежності від прямого COM/DLL-коду в бізнес-сервісі.
Обмеження Потрібно підтвердити підтримку такого режиму в ArtSoft.

5.4. Варіант 4. Локальний Python RRO Agent + K2 ERP API

На касовому ПК запускається Python RRO Agent. Він працює з ArtSoft-драйвером і приймає команди від K2 ERP.

Компонент Опис
K2 ERP / POS Створює продаж або повернення.
Python RRO Agent Локальний сервіс на касовому ПК.
ArtSoft Driver Універсальний драйвер реєстраторів.
Фізичний РРО Конкретна модель фіскального реєстратора.
Dashboard Центральний контроль чеків, змін і помилок.

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

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

K2 ERP / POS / CRM / Website
        |
        | 1. Продаж / повернення / службова операція
        v
Central Fiscal API
        |
        | 2. Черга, журнал, дедублікація
        v
Local Python RRO Agent
        |
        | 3. COM/OLE/DLL або інший API ArtSoft
        v
ArtSoft Універсальний драйвер реєстраторів
        |
        | 4. Високорівневі команди до РРО
        v
Фізичний РРО
        |
        | 5. Друк і фіскалізація чека
        v
Покупець / чекова стрічка
        |
        | 6. Передача фіскальних даних каналами РРО
        v
ДПС

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

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

8. User Story

8.1. Продаж

Як POS або K2 ERP, я хочу передати продаж у Python RRO Agent, щоб агент через ArtSoft-драйвер надрукував і фіскалізував чек на підключеному РРО.

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

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

8.3. Робота з різними моделями РРО

Як адміністратор, я хочу підключати різні моделі РРО через один драйвер, щоб не розробляти окрему Python-інтеграцію для кожної моделі.

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

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

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

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

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

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

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

9.1. Налаштування драйвера

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

Поле Тип Обов'язковість Опис
integration_name string Так Назва інтеграції.
driver_provider string Так artsoft.
driver_version string Так Версія ArtSoft-драйвера.
driver_connection_type enum Так OLE_COM, DLL, SERVICE, OTHER.
ole_progid string Ні ProgID OLE-сервера, якщо використовується OLE.
dll_path string Ні Шлях до DLL, якщо використовується DLL.
service_url string Ні URL локального сервісу, якщо використовується сервісний режим.
default_timeout_seconds integer Так Таймаут команди до драйвера.
log_raw_commands boolean Так Чи зберігати технічні команди і відповіді.
is_active boolean Так Чи активна інтеграція.

9.2. Налаштування РРО

Кожен фізичний РРО повинен мати окрему картку.

Поле Тип Обов'язковість Опис
device_name string Так Назва РРО.
device_model string Так Модель РРО.
device_serial_number string Так Серійний номер пристрою.
fiscal_number string Так Фіскальний номер РРО.
artsoft_device_id string Так Ідентифікатор або номер пристрою в ArtSoft-драйвері.
connection_port string Ні COM/USB/мережевий порт, якщо потрібен.
cashier_id string Ні Касир за замовчуванням.
tax_profile_id string Ні Профіль податкових ставок.
auto_open_shift boolean Так Автоматично відкривати зміну перед першим чеком.
allow_service_operations boolean Так Дозволити службове внесення/винесення.
is_active boolean Так Чи активний пристрій.

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

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

  • чи встановлено ArtSoft-драйвер;
  • чи доступний драйверний інтерфейс;
  • чи підключений РРО;
  • чи доступний порт;
  • чи є папір;
  • чи відкрита кришка;
  • чи є помилки живлення;
  • чи є зв'язок із фіскальним модулем;
  • чи відкрита зміна;
  • чи не заблокований РРО;
  • чи не переповнена пам'ять;
  • чи коректно встановлена дата і час;
  • чи готовий РРО до друку чека.

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

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

Локальний endpoint:

POST /api/v1/rro/artsoft/shifts/open

Логіка:

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

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

Локальний endpoint:

POST /api/v1/rro/artsoft/receipts/sale

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

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

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

{
  "external_order_id": "ORDER-2026-000123",
  "idempotency_key": "ORDER-2026-000123-PAY-123456",
  "device_id": "rro-store-001",
  "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
}

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

Endpoint:

POST /api/v1/rro/artsoft/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 Ключ захисту від дублювання.

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

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

Endpoint:

POST /api/v1/rro/artsoft/service-operation

Приклад:

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

Типи:

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

9.9. X-звіт

Endpoint:

POST /api/v1/rro/artsoft/reports/x

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

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

9.10. Z-звіт

Endpoint:

POST /api/v1/rro/artsoft/reports/z

Логіка:

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

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

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

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

11. Статуси РРО та драйвера

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

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

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

13. Python RRO Agent

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

Python RRO Agent — це локальний сервіс, який встановлюється на касовий ПК і має доступ до ArtSoft-драйвера та фізичного РРО.

Він повинен:

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

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

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

Деякі сторонні описи ArtSoft-драйвера вказують підтримку Windows 7+ і Linux, а також наявність вбудованого емулятора фіскального реєстратора; ці можливості потрібно підтвердити на конкретній ліцензії та версії драйвера перед проєктуванням production-схеми. :contentReference[oaicite:2]{index=2}

13.3. Методи Python RRO Client

class ArtSoftRROClient:
    def check_driver(self) -> "DriverStatus":
        pass

    def check_connection(self, device_id: str) -> "RROStatus":
        pass

    def get_status(self, device_id: str) -> "RROStatus":
        pass

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

    def close_shift(self, device_id: str) -> "ZReportResponse":
        pass

    def print_x_report(self, device_id: str) -> "XReportResponse":
        pass

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

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

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

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

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

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

from pydantic_settings import BaseSettings


class ArtSoftRROSettings(BaseSettings):
    driver_connection_type: str = "OLE_COM"
    ole_progid: str | None = None
    dll_path: str | None = None
    service_url: 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`:

ARTSOFT_DRIVER_CONNECTION_TYPE=OLE_COM
ARTSOFT_OLE_PROGID=ArtSoft.Driver.Placeholder
ARTSOFT_DLL_PATH=C:\ArtSoft\Driver\driver.dll
ARTSOFT_TIMEOUT_SECONDS=30
ARTSOFT_RETRY_COUNT=2
ARTSOFT_AUTO_OPEN_SHIFT=true
ARTSOFT_LOG_RAW_COMMANDS=true

Важливо: значення OLE ProgID, назви DLL, назви функцій і параметри команд потрібно брати з офіційної документації ArtSoft до конкретної версії драйвера.

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

Перед відправкою на ArtSoft-драйвер система повинна перевірити:

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

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

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

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

Ключ Призначення
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 не повинен друкувати другий фіскальний чек. Він повинен повернути результат уже виконаної операції.

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

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

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

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

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

18. Абстрактна модель драйвера

18.1. Навіщо потрібна абстракція

Навіть якщо використовується ArtSoft як єдина бібліотека, в Python-коді потрібно зробити власний інтерфейс `FiscalDriver`.

Це дозволить:

  • замінити ArtSoft на інший драйвер у майбутньому;
  • тестувати бізнес-логіку без фізичного РРО;
  • використовувати mock-драйвер;
  • підтримувати декілька реалізацій: ArtSoft OLE, ArtSoft DLL, ArtSoft Service;
  • не прив'язувати K2 ERP до конкретного драйвера.

18.2. Інтерфейс FiscalDriver

from abc import ABC, abstractmethod


class FiscalDriver(ABC):
    @abstractmethod
    def check_driver(self) -> dict:
        pass

    @abstractmethod
    def get_device_status(self, device_id: str) -> dict:
        pass

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

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

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

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

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

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

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

19. Приклад ArtSoft OLE Adapter

class ArtSoftOleFiscalDriver(FiscalDriver):
    def __init__(self, ole_progid: str):
        self.ole_progid = ole_progid
        self.driver = None

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

    def ensure_connected(self) -> None:
        if self.driver is None:
            self.connect()

    def check_driver(self) -> dict:
        self.ensure_connected()
        # Назва методу залежить від документації ArtSoft.
        result = self.driver.GetDriverStatus()
        return {"raw": result}

    def get_device_status(self, device_id: str) -> dict:
        self.ensure_connected()
        result = self.driver.GetDeviceStatus(device_id)
        return {"raw": result}

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

    def close_shift(self, device_id: str) -> dict:
        self.ensure_connected()
        result = self.driver.ZReport(device_id)
        return {"raw": result}

    def x_report(self, device_id: str) -> dict:
        self.ensure_connected()
        result = self.driver.XReport(device_id)
        return {"raw": result}

    def sale_receipt(self, device_id: str, receipt: dict) -> dict:
        self.ensure_connected()

        self.driver.OpenReceipt(device_id, "SALE")

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

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

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

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

20. Приклад ArtSoft DLL Adapter

import ctypes
from ctypes import c_char_p, c_double


class ArtSoftDllFiscalDriver(FiscalDriver):
    def __init__(self, dll_path: str):
        self.dll_path = dll_path
        self.dll = None

    def connect(self) -> None:
        self.dll = ctypes.WinDLL(self.dll_path)

        # Сигнатури функцій потрібно задати згідно з документацією ArtSoft.
        # Нижче наведено тільки архітектурний приклад.
        self.dll.OpenShift.argtypes = [c_char_p, c_char_p]
        self.dll.OpenShift.restype = c_char_p

    def ensure_connected(self) -> None:
        if self.dll is None:
            self.connect()

    def check_driver(self) -> dict:
        self.ensure_connected()
        result = self.dll.GetDriverStatus()
        return {"raw": result}

    def get_device_status(self, device_id: str) -> dict:
        self.ensure_connected()
        result = self.dll.GetDeviceStatus(device_id.encode("utf-8"))
        return {"raw": result}

    def open_shift(self, device_id: str, cashier_id: str) -> dict:
        self.ensure_connected()
        result = self.dll.OpenShift(
            device_id.encode("utf-8"),
            cashier_id.encode("utf-8"),
        )
        return {"raw": result}

Критично важливо: DLL-інтеграція без точних сигнатур функцій небезпечна. Потрібно мати офіційну документацію ArtSoft щодо DLL API, типів параметрів, кодування рядків, кодів помилок і 32/64-bit сумісності.

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

21.1. fiscal_driver_integrations

Поле Тип Опис
id uuid ID інтеграції.
provider varchar artsoft.
driver_version varchar Версія драйвера.
connection_type varchar OLE_COM, DLL, SERVICE.
ole_progid varchar ProgID OLE.
dll_path varchar Шлях до DLL.
service_url varchar URL сервісу, якщо використовується.
status varchar Активна, помилка, вимкнена.
is_active boolean Активність.

21.2. rro_devices

Поле Тип Опис
id uuid ID пристрою.
integration_id uuid ID інтеграції ArtSoft.
model varchar Модель РРО.
serial_number varchar Серійний номер.
fiscal_number varchar Фіскальний номер.
artsoft_device_id varchar ID пристрою у драйвері.
status varchar Поточний стан.
current_shift_id uuid Поточна зміна.
is_active boolean Активність.

21.3. 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 Помилка.

21.4. 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 Повідомлення помилки.

21.5. 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 Знижка.

21.6. rro_events

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

22. API Python Agent

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

GET /api/v1/health

22.2. Перевірка стану драйвера

GET /api/v1/rro/artsoft/driver/status

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

GET /api/v1/rro/artsoft/devices/{device_id}/status

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

POST /api/v1/rro/artsoft/shifts/open

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

POST /api/v1/rro/artsoft/reports/z

22.6. X-звіт

POST /api/v1/rro/artsoft/reports/x

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

POST /api/v1/rro/artsoft/receipts/sale

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

POST /api/v1/rro/artsoft/receipts/refund

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

POST /api/v1/rro/artsoft/service-operation

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

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

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

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

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

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

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

23.2. Retry-логіка

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

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

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

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

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

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

24.1. Основні KPI

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

24.2. Приклад dashboard

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

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

Час РРО Замовлення Сума Статус Помилка Дія
10:42 РРО #001 ORDER-123 570.00 Помилка драйвера ArtSoft недоступний Перевірити драйвер
11:05 РРО #001 ORDER-124 1200.00 Потребує повтору Немає паперу Замінити папір і повторити
12:10 РРО #002 SHIFT-55 - Зміна відкрита Не закрито Z-звіт Закрити зміну
12:30 РРО #003 ORDER-125 700.00 Ручна перевірка Невідомо, чи чек надруковано Перевірити на РРО

25. Безпека

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

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

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

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

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

27. Acceptance Criteria

27.1. Підключення драйвера

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

27.2. Підключення РРО

Критерій Очікуваний результат
AC-4 Адміністратор додає РРО. РРО доступний у списку пристроїв.
AC-5 Python Agent перевіряє РРО. Система повертає READY або помилку пристрою.
AC-6 РРО не підключений. Система показує DEVICE_DISCONNECTED червоним кольором.

27.3. Продаж

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

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

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

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

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

27.6. Ручна перевірка

Критерій Очікуваний результат
AC-18 Після збою результат чека невідомий. Система переводить чек у MANUAL_REVIEW.
AC-19 Чек у MANUAL_REVIEW. Автоматичний retry заблокований.
AC-20 Адміністратор підтвердив результат вручну. Статус оновлюється з коментарем і записом в аудит.

28. MVP

До MVP входить:

  • локальний Python RRO Agent;
  • налаштування ArtSoft-драйвера;
  • налаштування декількох РРО;
  • перевірка стану драйвера;
  • перевірка стану РРО;
  • відкриття зміни;
  • друк чека продажу;
  • друк чека повернення;
  • службове внесення / винесення;
  • X-звіт;
  • Z-звіт;
  • локальна БД чеків;
  • дедублікація;
  • журнал команд і відповідей;
  • базовий dashboard API;
  • обробка помилок драйвера, РРО, паперу, зміни;
  • retry для безпечних ситуацій;
  • MANUAL_REVIEW для невідомого результату.

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

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

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

Етап 1. Аналіз ArtSoft-драйвера

  • придбати або отримати демо-версію ArtSoft Універсального драйвера;
  • отримати документацію розробника;
  • визначити сценарій інтеграції: OLE, DLL, service;
  • перевірити підтримувані моделі РРО;
  • перевірити версію драйвера;
  • перевірити тестовий РРО або емулятор.

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

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

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

  • реалізувати FiscalDriver interface;
  • реалізувати ArtSoftOleFiscalDriver або ArtSoftDllFiscalDriver;
  • реалізувати check_driver;
  • реалізувати check_device;
  • реалізувати 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;
  • протестувати типові помилки РРО;
  • протестувати оновлення ArtSoft-драйвера.

30. Ризики

Ризик Опис Як зменшити
Немає документації до API драйвера Без документації неможливо коректно викликати OLE/DLL. Отримати документацію ArtSoft до початку розробки.
Несумісність 32/64-bit Python, DLL і драйвер можуть мати різну архітектуру. Узгодити bitness Python і драйвера.
Драйвер працює тільки на Windows Обмеження для Linux-серверів. Виносити інтеграцію в локальний Windows Agent.
Дублювання чеків Повторний запит може надрукувати другий чек. Idempotency key, локальна БД, журнал статусів.
Невідомий стан після збою Невідомо, чи чек надрукований. MANUAL_REVIEW замість автоматичного повтору.
Немає паперу Чек не може бути надрукований. Статус PAPER_OUT, повтор після заміни паперу.
Драйвер недоступний ArtSoft не запущений або неправильно встановлений. Healthcheck, monitoring, auto-restart.
Оновлення драйвера Оновлення може змінити поведінку команд. Тестове середовище і regression-тести.
Різні моделі РРО Моделі можуть мати різні обмеження. Таблиця можливостей device_capabilities.

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

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

32. Джерела

33. Див. також

index.php?title=Категорія:Технічні завдання index.php?title=Категорія:Python index.php?title=Категорія:РРО index.php?title=Категорія:Фіскальні реєстратори index.php?title=Категорія:ArtSoft index.php?title=Категорія:POS index.php?title=Категорія:K2 ERP index.php?title=Категорія:Інтеграції