Інтеграція РРО в Python через загальну бібліотеку для різних РРО
Ознайомтесь з документацією від розробника універсального драйвера РРО: Керівництво програміста "АртСофт - Універсальний драйвер фіскальних реєстраторів для України"
Головна ідея: розробити 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. Відкриті питання
- Який саме API надає ArtSoft у вашій ліцензії: OLE, DLL, локальний сервіс чи інший механізм?
- На якій ОС працюватиме касовий ПК: Windows чи Linux?
- Чи потрібно запускати Python Agent як Windows Service?
- Чи потрібно інтегрувати агент із K2 ERP?
- Скільки РРО буде на одному касовому ПК?
- Які моделі РРО потрібно підтримати в MVP?
- Чи є доступ до емулятора фіскального реєстратора?
- Чи потрібно програмувати товари в РРО?
- Чи потрібно програмувати податкові ставки з Python?
- Чи потрібно друкувати QR-код у чеку?
- Чи потрібно відкривати грошову скриньку?
- Чи буде один РРО на декілька касирів?
- Чи потрібен централізований dashboard по декількох торгових точках?
- Які типи оплат підтримуються: готівка, картка, змішана оплата?
- Чи потрібна інтеграція з банківським POS-терміналом?
- Як обробляти ситуацію, коли результат друку невідомий?
32. Джерела
- https://artsoft.ua/ua/programne-zabezpechennja/artsoft-universalnij-drajver-restratoriv-pz/
- https://artsoft.ua/ua/programne-zabezpechennja/onovlennja-artsoft-universalnij-drajver-restratoriv-pz5/
- Документація ArtSoft Універсальний драйвер реєстраторів.
- Документація OLE/DLL API ArtSoft.
- Список підтримуваних моделей ArtSoft.
- Інструкції до конкретних моделей РРО.
- Тестовий емулятор фіскального реєстратора, якщо доступний.
33. Див. також
- Python
- FastAPI
- K2 ERP
- РРО
- Фіскальний реєстратор
- ArtSoft
- ArtSoft Універсальний драйвер реєстраторів
- Фіскальний чек
- Касова зміна
- Z-звіт
- X-звіт
- POS
- OLE
- DLL
- COM
- Windows Service
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=Категорія:Інтеграції