Технічне завдання: інтеграція ПРРО Checkbox для Python
Головна ідея: розробити Python-сервіс, який інтегрує ERP / CRM / інтернет-магазин / POS-систему з ПРРО Checkbox для автоматичної фіскалізації чеків, контролю касових змін, повернень, службових операцій, статусів, помилок та відправки електронних чеків покупцям.
Критично важливо: інтеграція з ПРРО не повинна втрачати чеки. Кожна операція продажу, повернення, відкриття зміни, закриття зміни, службове внесення / винесення готівки та помилка фіскалізації повинні мати внутрішній ID, статус, журнал подій і можливість безпечного повтору без створення дубля.
Важливо: Checkbox має декілька сценаріїв роботи: WebAPI для eCommerce, Checkbox Kasa Manager для retail/POS-сценаріїв, мобільний застосунок та кабінет. У межах цього ТЗ основний сценарій — Python-сервіс, який працює з API Checkbox.
Технічний стек: Python 3.11+, FastAPI, PostgreSQL, SQLAlchemy, Alembic, httpx, Pydantic, Celery/RQ/APScheduler, Redis, Docker.
Управлінський результат: керівник повинен бачити, скільки чеків створено, скільки фіскалізовано, скільки чеків очікують, скільки помилок, які каси відкриті, які зміни не закриті, скільки повернень і які операції потребують уваги.
1. Мета
Метою задачі є створення Python-сервісу для інтеграції з ПРРО Checkbox з метою автоматизації фіскалізації продажів, повернень, службових операцій і касових змін.
Сервіс повинен забезпечити:
- прийом замовлень, продажів або оплат із зовнішньої системи;
- створення фіскального чека продажу;
- створення чека повернення;
- створення службового внесення готівки;
- створення службового винесення готівки;
- контроль відкриття касової зміни;
- контроль закриття касової зміни;
- формування X-звіту;
- формування Z-звіту;
- отримання статусів чеків;
- отримання статусів змін;
- збереження фіскальних номерів;
- збереження посилання або візуалізації чека;
- отримання HTML / PNG / TXT / QR-візуалізації чека, якщо потрібно;
- відправку електронного чека покупцю, якщо підтримується налаштуваннями;
- журналювання всіх API-запитів;
- повторну обробку помилкових операцій;
- захист від дублювання чеків;
- передачу статусів назад в ERP / CRM / сайт / POS.
2. Область застосування
Функціонал використовується для:
- інтернет-магазинів;
- POS-систем;
- CRM;
- ERP;
- служб доставки;
- маркетплейсів;
- сервісів підписок;
- систем обліку продажів;
- компаній, які хочуть автоматизувати фіскалізацію оплат.
До області задачі входить:
- Python API для прийому продажів;
- клієнт інтеграції з Checkbox API;
- підтримка фіскалізації чеків продажу;
- підтримка повернень;
- підтримка службового внесення та винесення готівки;
- відкриття та закриття змін;
- збереження чеків;
- збереження статусів;
- журнал помилок;
- retry-механізм;
- dashboard / API для контролю;
- інтеграція з внутрішньою системою.
До першої версії не входить:
- повноцінний POS-інтерфейс касира;
- власна реалізація ПРРО без Checkbox;
- самостійна реєстрація ПРРО в ДПС через Python-сервіс;
- власний модуль КЕП;
- інтеграція з усіма еквайрингами;
- складний UI для касира;
- заміна кабінету Checkbox;
- повна офлайн-робота без окремого погодженого сценарію.
3. Джерела інтеграції
| Компонент | Призначення | Коментар |
|---|---|---|
| Checkbox | ПРРО-сервіс для фіскалізації чеків. | Основний зовнішній сервіс інтеграції. |
| Checkbox API | REST API для інтеграції з eCommerce / ERP / CRM / POS. | Основний канал для Python-сервісу. |
| Checkbox Kasa Manager | Фронт-агент для retail/POS-сценаріїв. | Може використовуватись у локальних інтеграціях. |
| Особистий кабінет Checkbox | Керування торговими точками, касами, касирами. | Використовується для налаштування. |
| Python-сервіс | Інтеграційний шар між ERP / сайтом / CRM / POS та Checkbox. | Реалізується в межах цього ТЗ. |
| ERP / CRM / сайт / POS | Джерело продажів, повернень, оплат і даних покупця. | Наприклад K2 ERP або інша система. |
| ДПС | Кінцевий отримувач фіскальних даних через ПРРО. | Python-сервіс напряму з ДПС у MVP не працює. |
4. Передумови
Для реалізації задачі необхідно отримати:
- акаунт у Checkbox;
- зареєстрованого торговця;
- торгову точку;
- зареєстровану касу / ПРРО;
- касира;
- спосіб підпису чеків;
- доступ до API;
- токен авторизації;
- license key каси;
- назву інтеграції для заголовка X-Client-Name;
- версію інтеграції для заголовка X-Client-Version;
- тестове середовище або тестову касу, якщо доступно;
- перелік кас, які будуть використовуватись;
- перелік касирів;
- правила відкриття і закриття зміни;
- правила формування чеків;
- правила повернень;
- формат оплати;
- формат товарних позицій;
- формат податкових ставок;
- вимоги до відправки електронного чека покупцю.
Критично важливо: якщо зміна відкривається через API, потрібно уникати паралельних дій через інші фронт-агенти по тій самій касі, щоб не отримати неконсистентні стани, помилкові звіти або конфлікти в роботі каси.
5. Варіанти інтеграції
5.1. Варіант 1. WebAPI для eCommerce
Python-сервіс напряму викликає Checkbox API.
| Параметр | Опис |
|---|---|
| Підходить для | Хмарних ERP, CRM, інтернет-магазинів, SaaS-систем. |
| Переваги | Пряме API, зручна автоматизація, можливість працювати з чергою. |
| Обмеження | Потрібен стабільний інтернет, коректне керування змінами та токенами. |
| Основні операції | Створення чеків, повернень, службових операцій, отримання статусів, робота зі змінами. |
5.2. Варіант 2. Checkbox Kasa Manager
Використовується для retail/POS-сценаріїв, коли касовий вузол має локальний агент.
| Параметр | Опис |
|---|---|
| Підходить для | Фізичних магазинів, POS-систем, торгових точок. |
| Переваги | Зручніше для касового вузла, retail-логіки, локальної роботи. |
| Обмеження | Потрібна інсталяція й підтримка агентів. |
| Основні операції | Фіскалізація чеків, робота касира, контроль зміни. |
5.3. Варіант 3. Гібридна схема
Python-сервіс підтримує централізований облік чеків, але різні торгові точки можуть використовувати різні канали.
| Сценарій | Опис |
|---|---|
| Онлайн-продажі | Через WebAPI. |
| Фізичні магазини | Через Checkbox Kasa Manager або інший фронт-агент. |
| Загальна БД чеків | Усі чеки зберігаються в єдиній БД Python-сервісу. |
| Єдиний dashboard | Керівник бачить усі чеки, каси, статуси й помилки в одному місці. |
6. Основні сутності
| Сутність | Опис |
|---|---|
| Cash Register | Каса / ПРРО, через яку фіскалізуються чеки. |
| Cashier | Касир, від імені якого виконується операція. |
| License Key | Ключ ліцензії каси, який використовується в запитах до API. |
| Shift | Касова зміна. |
| Receipt | Фіскальний чек продажу. |
| Refund Receipt | Чек повернення. |
| Service Receipt | Службове внесення або винесення готівки. |
| Receipt Item | Товарна або послугова позиція в чеку. |
| Payment | Оплата в чеку: готівка, картка, онлайн-еквайринг тощо. |
| Fiscal Status | Статус фіскалізації. |
| X Report | Проміжний звіт без закриття зміни. |
| Z Report | Звіт із закриттям зміни. |
| API Event | Технічна подія інтеграції. |
7. User Story
7.1. Фіскалізація продажу
Як система продажів, я хочу передати інформацію про оплату в Python-сервіс, щоб він автоматично створив фіскальний чек у Checkbox.
7.2. Повернення
Як оператор або ERP, я хочу створити чек повернення, щоб коректно відобразити повернення коштів покупцю.
7.3. Службове внесення / винесення
Як адміністратор каси, я хочу фіксувати службове внесення або винесення готівки, щоб касові операції були відображені в системі.
7.4. Контроль зміни
Як касир або адміністратор, я хочу бачити, чи відкрита касова зміна, щоб розуміти, чи можна фіскалізувати чеки.
7.5. Повторна обробка
Як адміністратор, я хочу повторити фіскалізацію після технічної помилки, щоб не втратити продаж.
7.6. Контроль керівника
Як керівник, я хочу бачити dashboard по касах і чеках, щоб контролювати фіскалізацію, помилки, повернення і незакриті зміни.
8. Функціональні вимоги
8.1. Налаштування інтеграції
Система повинна дозволяти створити налаштування підключення до Checkbox.
| Поле | Тип | Обов'язковість | Опис |
|---|---|---|---|
| integration_name | string | Так | Назва інтеграції. |
| base_url | string | Так | Базова адреса API Checkbox. |
| api_token | secret | Так | Токен авторизації. |
| x_client_name | string | Так | Назва інтеграції для заголовка X-Client-Name. |
| x_client_version | string | Так | Версія інтеграції для заголовка X-Client-Version. |
| organization_id | string | Так | Внутрішній ID організації. |
| cash_register_id | string | Так | ID каси / ПРРО у локальній системі. |
| license_key | secret | Так | License key каси. |
| cashier_id | string | Ні | ID касира за замовчуванням. |
| default_tax_group | string | Ні | Податкова група за замовчуванням. |
| auto_open_shift | boolean | Так | Автоматично відкривати зміну перед першим чеком. |
| auto_close_shift | boolean | Ні | Автоматично закривати зміну за розкладом. |
| send_receipt_to_customer | boolean | Ні | Відправляти чек покупцю. |
| allow_offline_mode | boolean | Ні | Чи дозволена офлайн-робота. |
| is_active | boolean | Так | Ознака активності інтеграції. |
8.2. Створення чека продажу
Python-сервіс повинен приймати дані продажу та створювати фіскальний чек.
Логічний endpoint Python-сервісу:
POST /api/v1/fiscal/checkbox/receipts
Мінімальні дані:
| Поле | Тип | Опис |
|---|---|---|
| external_order_id | string | ID замовлення у зовнішній системі. |
| fiscal_operation_type | string | sale. |
| cash_register_id | string | Каса / ПРРО. |
| cashier_id | string | Касир. |
| customer | object | Дані покупця. |
| items | array | Позиції чека. |
| payments | array | Оплати. |
| total_amount | integer | Загальна сума чека в копійках. |
| currency | string | Валюта. |
| idempotency_key | string | Ключ захисту від дублювання. |
Важливо: для інтеграції з Checkbox зручно зберігати суми в копійках, щоб уникати помилок округлення у фінансових операціях.
8.3. Приклад запиту на чек продажу
{
"external_order_id": "ORDER-2026-000123",
"idempotency_key": "ORDER-2026-000123-PAY-123456",
"fiscal_operation_type": "sale",
"cash_register_id": "cash-register-001",
"cashier_id": "cashier-001",
"customer": {
"name": "Іван Петренко",
"email": "customer@example.com",
"phone": "+380501112233"
},
"items": [
{
"name": "Товар 1",
"sku": "SKU-001",
"quantity": 2000,
"price": 25000,
"amount": 50000,
"tax_group": "VAT_20",
"unit": "шт"
},
{
"name": "Доставка",
"sku": "DELIVERY",
"quantity": 1000,
"price": 7000,
"amount": 7000,
"tax_group": "NO_VAT",
"unit": "послуга"
}
],
"payments": [
{
"type": "CARD",
"amount": 57000,
"provider": "liqpay",
"payment_id": "PAY-123456"
}
],
"total_amount": 57000,
"currency": "UAH"
}
8.4. Чек повернення
Система повинна підтримувати створення чека повернення.
Логічний endpoint:
POST /api/v1/fiscal/checkbox/refund-receipts
Мінімальні дані:
| Поле | Тип | Опис |
|---|---|---|
| original_receipt_id | uuid | Внутрішній ID первинного чека. |
| original_fiscal_number | string | Фіскальний номер первинного чека. |
| external_refund_id | string | ID повернення у зовнішній системі. |
| items | array | Позиції, які повертаються. |
| payments | array | Сума повернення. |
| reason | string | Причина повернення. |
| idempotency_key | string | Ключ захисту від дублювання повернення. |
Критично важливо: чек повернення повинен бути пов'язаний із первинним чеком. Система не повинна дозволяти створювати повернення на суму більшу, ніж залишок доступний до повернення.
8.5. Службове внесення та винесення готівки
Система повинна підтримувати службові касові операції:
- службове внесення готівки;
- службове винесення готівки.
Логічний endpoint Python-сервісу:
POST /api/v1/fiscal/checkbox/service-receipts
Мінімальні дані:
| Поле | Тип | Опис |
|---|---|---|
| operation_type | enum | cash_in або cash_out. |
| cash_register_id | string | Каса. |
| cashier_id | string | Касир. |
| value | integer | Сума в копійках. |
| reason | string | Коментар або причина. |
| idempotency_key | string | Ключ дедублікації. |
8.6. Відкриття зміни
Система повинна підтримувати відкриття касової зміни.
Логічний endpoint:
POST /api/v1/fiscal/checkbox/shifts/open
Сценарії:
| Сценарій | Опис |
|---|---|
| Ручне відкриття | Користувач або адміністратор відкриває зміну. |
| Автоматичне відкриття | Система відкриває зміну перед першим чеком. |
| Перевірка перед чеком | Якщо зміна вже відкрита, повторно не відкривати. |
| Офлайн-відкриття | Дозволяється тільки за окремим налаштуванням і правилами Checkbox. |
8.7. Закриття зміни
Система повинна підтримувати закриття касової зміни та формування Z-звіту.
Логічний endpoint:
POST /api/v1/fiscal/checkbox/shifts/{shift_id}/close
Система повинна:
- перевірити відкриту зміну;
- перевірити незавершені чеки;
- сформувати Z-звіт;
- зберегти результат;
- змінити статус зміни на Closed;
- записати подію в журнал.
8.8. X-звіт
Система повинна підтримувати отримання проміжного X-звіту без закриття зміни.
POST /api/v1/fiscal/checkbox/shifts/{shift_id}/x-report
8.9. Отримання статусу чека
Система повинна підтримувати синхронізацію статусу чека з Checkbox.
POST /api/v1/fiscal/checkbox/receipts/{receipt_id}/sync-status
8.10. Отримання візуалізації чека
Система повинна підтримувати отримання візуалізації чека.
Формати:
- HTML;
- PNG;
- TXT;
- QR-code.
Логічні endpoint-и Python-сервісу:
GET /api/v1/fiscal/checkbox/receipts/{receipt_id}/html
GET /api/v1/fiscal/checkbox/receipts/{receipt_id}/png
GET /api/v1/fiscal/checkbox/receipts/{receipt_id}/text
GET /api/v1/fiscal/checkbox/receipts/{receipt_id}/qrcode
8.11. Відправка чека покупцю
Якщо налаштування Checkbox або інтеграції підтримують електронну відправку чека, Python-сервіс повинен передавати email або телефон покупця.
Канали:
- email;
- SMS;
- месенджер, якщо підтримується налаштуваннями;
- посилання на чек через зовнішню систему.
9. Статуси чеків
| Статус | Код | Опис | Колір |
|---|---|---|---|
| Чернетка | DRAFT | Чек створено у Python-сервісі, але ще не відправлено. | Сірий |
| Очікує фіскалізації | PENDING | Чек у черзі на відправку. | Жовтий |
| Відправляється | SENDING | Виконується API-запит. | Блакитний |
| Створено в Checkbox | CREATED_IN_CHECKBOX | Чек створено в Checkbox, очікується фінальний статус. | Блакитний |
| Фіскалізовано | FISCALIZED | Чек успішно фіскалізовано. | Зелений |
| Помилка фіскалізації | FISCALIZATION_ERROR | Виникла помилка при фіскалізації. | Червоний |
| Потребує повтору | NEEDS_RETRY | Можна повторити відправку. | Помаранчевий |
| Скасовано | CANCELLED | Операцію скасовано. | Сірий |
| Повернення створено | REFUNDED | По чеку є повне або часткове повернення. | Фіолетовий |
10. Статуси зміни
| Статус | Код | Опис | Колір |
|---|---|---|---|
| Не відкрита | CLOSED | Зміна закрита або ще не відкривалась. | Сірий |
| Створюється | CREATED | Створено запит на відкриття зміни. | Жовтий |
| Відкривається | OPENING | Виконується відкриття зміни. | Блакитний |
| Відкрита | OPENED | Можна фіскалізувати чеки. | Зелений |
| Закривається | CLOSING | Виконується закриття зміни. | Блакитний |
| Закрита | CLOSED_WITH_Z_REPORT | Зміна закрита із Z-звітом. | Зелений |
| Помилка | ERROR | Помилка відкриття або закриття зміни. | Червоний |
11. Єдина логіка кольорів
| Колір | HTML | Значення | Де використовується |
|---|---|---|---|
| Зелений | #c8e6c9 | Успішно: чек фіскалізовано, зміна відкрита або закрита коректно. | Dashboard, список чеків, касові зміни. |
| Блакитний | #bbdefb | Операція виконується або в роботі. | Черга, статуси API. |
| Жовтий | #fff9c4 | Очікування або попередження. | Черга чеків, pending-операції. |
| Помаранчевий | #ffcc80 | Потрібна дія або повтор. | Retry, незавершені операції. |
| Червоний | #ef9a9a | Помилка або критична ситуація. | Помилки фіскалізації, незакрита зміна. |
| Фіолетовий | #f3e5f5 | Повернення або спеціальна операція. | Refund, сторно, коригування. |
| Сірий | #eeeeee | Неактивно або скасовано. | Draft, Cancelled, Closed. |
12. Архітектура рішення
12.1. Загальна схема
ERP / CRM / Website / POS
|
| 1. Продаж / оплата / повернення
v
Python Fiscal Service
|
| 2. Валідація, дедублікація, черга
v
Checkbox Adapter
|
| 3. Checkbox API
v
Checkbox
|
| 4. Фіскалізація через ПРРО
v
ДПС
|
| 5. Фіскальний результат
v
Checkbox
|
| 6. Статус / номер / посилання / візуалізація
v
Python Fiscal Service
|
| 7. Оновлення ERP / CRM / POS
v
ERP / CRM / Website / POS
12.2. Основні компоненти Python-сервісу
| Компонент | Опис |
|---|---|
| API Layer | REST API для прийому продажів, повернень, службових операцій, команд зміни. |
| Validation Layer | Перевіряє товари, суми, оплати, податки, касу, касира. |
| Deduplication Service | Захищає від повторної фіскалізації одного продажу. |
| Fiscal Queue | Черга задач на фіскалізацію. |
| Checkbox Client | Python-клієнт для Checkbox API. |
| Shift Service | Відкриття, контроль і закриття змін. |
| Receipt Service | Створення чеків продажу. |
| Refund Service | Створення чеків повернення. |
| Service Receipt Service | Службове внесення та винесення готівки. |
| Status Sync Worker | Оновлення статусів чеків і змін. |
| Audit Logger | Журнал API-запитів, відповідей, помилок і змін статусів. |
| Dashboard API | Дані для керівника: чеки, зміни, помилки, обороти. |
13. Checkbox Client
13.1. Призначення
Checkbox Client — це Python-клас або пакет, який інкапсулює роботу з Checkbox API.
13.2. Основні методи
class CheckboxClient:
def check_connection(self) -> "ConnectionStatus":
pass
def open_shift(self, payload: "OpenShiftPayload") -> "ShiftResponse":
pass
def close_shift(self, shift_id: str) -> "ZReportResponse":
pass
def create_x_report(self, shift_id: str) -> "XReportResponse":
pass
def create_sell_receipt(self, payload: "SellReceiptPayload") -> "ReceiptResponse":
pass
def create_refund_receipt(self, payload: "RefundReceiptPayload") -> "ReceiptResponse":
pass
def create_service_receipt(self, payload: "ServiceReceiptPayload") -> "ReceiptResponse":
pass
def get_receipt_status(self, receipt_id: str) -> "ReceiptStatusResponse":
pass
def get_shift_status(self, shift_id: str) -> "ShiftStatusResponse":
pass
def get_receipt_html(self, receipt_id: str) -> str:
pass
def get_receipt_png(self, receipt_id: str) -> bytes:
pass
def get_receipt_text(self, receipt_id: str) -> str:
pass
def get_receipt_qrcode(self, receipt_id: str) -> bytes:
pass
13.3. Конфігурація клієнта
from pydantic_settings import BaseSettings
class CheckboxSettings(BaseSettings):
base_url: str
api_token: str
x_client_name: str
x_client_version: str
default_license_key: str | None = None
default_cash_register_id: str | None = None
default_cashier_id: str | None = None
timeout_seconds: int = 30
retry_count: int = 3
retry_backoff_seconds: int = 5
verify_ssl: bool = True
allow_offline_mode: bool = False
Приклад змінних середовища:
CHECKBOX_BASE_URL=https://api.checkbox.ua CHECKBOX_API_TOKEN=******** CHECKBOX_X_CLIENT_NAME=K2-ERP-Integration CHECKBOX_X_CLIENT_VERSION=1.0.0 CHECKBOX_DEFAULT_LICENSE_KEY=******** CHECKBOX_DEFAULT_CASH_REGISTER_ID=cash-register-001 CHECKBOX_DEFAULT_CASHIER_ID=cashier-001 CHECKBOX_TIMEOUT_SECONDS=30 CHECKBOX_RETRY_COUNT=3 CHECKBOX_RETRY_BACKOFF_SECONDS=5 CHECKBOX_ALLOW_OFFLINE_MODE=false
Заборонено: зберігати API token, license key, ключі, паролі касирів або інші секрети у коді, Git-репозиторії, відкритих логах або frontend-змінних.
14. Валідація чека
Перед фіскалізацією система повинна перевірити:
- наявність external_order_id;
- наявність idempotency_key;
- відсутність уже фіскалізованого чека по цьому external_order_id;
- наявність каси;
- наявність license key;
- наявність касира;
- наявність відкритої зміни або можливість її відкрити;
- наявність хоча б однієї позиції;
- коректність кількості;
- коректність ціни;
- коректність суми рядка;
- відповідність total_amount сумі товарів і оплат;
- коректність типу оплати;
- коректність податкових груп;
- коректність email або телефону покупця, якщо чек потрібно відправити;
- коректність формату UUID для операцій, які вимагають UUID.
15. Дедублікація
Система повинна не допускати дублювання чеків.
Ключі дедублікації:
| Ключ | Призначення |
|---|---|
| external_order_id | Основний ключ від зовнішньої системи. |
| external_payment_id | Додатковий ключ від платіжної системи. |
| idempotency_key | Унікальний ключ запиту. |
| receipt_uuid | UUID чека, який передається в Checkbox. |
| receipt_hash | Hash товарів, сум, оплат і замовлення. |
Приклад hash:
sha256(external_order_id + total_amount + payment_id + cash_register_id)
Критично важливо: повторний запит із тим самим idempotency_key або receipt_uuid не повинен створити другий фіскальний чек. Він повинен повернути результат уже створеної операції.
16. Черга фіскалізації
Для підвищення надійності фіскалізація повинна виконуватись через чергу.
16.1. Логіка черги
1. API приймає запит на створення чека. 2. Дані проходять валідацію. 3. Створюється запис receipt зі статусом PENDING. 4. Задача додається в чергу. 5. Worker перевіряє зміну. 6. Якщо зміна не відкрита і auto_open_shift = true, worker відкриває зміну. 7. Worker викликає Checkbox API. 8. Результат зберігається в БД. 9. ERP / CRM / сайт отримує статус.
16.2. Пріоритети задач
| Тип задачі | Пріоритет | Коментар |
|---|---|---|
| Фіскалізація продажу | Високий | Основний бізнес-процес. |
| Повернення | Високий | Важлива фінансова операція. |
| Закриття зміни | Критичний | Не можна залишати зміну незакритою. |
| Службове внесення / винесення | Середній | Касова технічна операція. |
| Синхронізація статусів | Середній | Може виконуватись фоново. |
| Завантаження візуалізації чека | Низький | Не блокує фіскалізацію. |
17. Модель даних
17.1. fiscal_integrations
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID інтеграції. |
| provider | varchar | checkbox. |
| name | varchar | Назва інтеграції. |
| base_url | varchar | URL API. |
| api_token_encrypted | text | Зашифрований токен. |
| x_client_name | varchar | Назва інтеграції. |
| x_client_version | varchar | Версія інтеграції. |
| organization_id | varchar | Організація. |
| allow_offline_mode | boolean | Чи дозволений офлайн. |
| is_active | boolean | Активність. |
| created_at | timestamp | Дата створення. |
| updated_at | timestamp | Дата оновлення. |
17.2. cash_registers
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | Внутрішній ID каси. |
| integration_id | uuid | ID інтеграції. |
| external_cash_register_id | varchar | ID каси у Checkbox або локальній системі. |
| license_key_encrypted | text | Зашифрований license key. |
| name | varchar | Назва каси. |
| fiscal_number | varchar | Фіскальний номер ПРРО, якщо доступний. |
| status | varchar | Активна, неактивна, помилка. |
| current_shift_id | uuid | Поточна зміна. |
| is_active | boolean | Чи використовується. |
17.3. fiscal_shifts
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID зміни. |
| cash_register_id | uuid | Каса. |
| cashier_id | varchar | Касир. |
| external_shift_id | varchar | ID зміни у Checkbox. |
| status | varchar | CREATED, OPENED, CLOSED, ERROR тощо. |
| opened_at | timestamp | Дата відкриття. |
| closed_at | timestamp | Дата закриття. |
| z_report_id | varchar | ID Z-звіту. |
| z_report_number | varchar | Номер Z-звіту. |
| raw_request | jsonb | Запит. |
| raw_response | jsonb | Відповідь. |
| error_message | text | Остання помилка. |
17.4. fiscal_receipts
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | Внутрішній ID чека. |
| integration_id | uuid | ID інтеграції. |
| cash_register_id | uuid | Каса. |
| shift_id | uuid | Зміна. |
| receipt_uuid | uuid | UUID чека, який передається в Checkbox. |
| external_order_id | varchar | ID замовлення. |
| external_payment_id | varchar | ID оплати. |
| idempotency_key | varchar | Ключ дедублікації. |
| receipt_type | varchar | sale, refund, service. |
| status | varchar | Статус чека. |
| total_amount | integer | Загальна сума в копійках. |
| currency | varchar | Валюта. |
| fiscal_number | varchar | Фіскальний номер. |
| fiscal_url | varchar | Посилання на чек, якщо доступне. |
| qr_code | text | QR або дані QR, якщо доступні. |
| raw_request | jsonb | Запит до API. |
| raw_response | jsonb | Відповідь API. |
| error_message | text | Остання помилка. |
| created_at | timestamp | Дата створення. |
| fiscalized_at | timestamp | Дата фіскалізації. |
17.5. fiscal_receipt_items
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID позиції. |
| receipt_id | uuid | ID чека. |
| name | varchar | Назва товару або послуги. |
| sku | varchar | Артикул. |
| quantity | integer | Кількість у мінімальних одиницях, якщо використовується масштабування. |
| unit | varchar | Одиниця виміру. |
| price | integer | Ціна в копійках. |
| amount | integer | Сума в копійках. |
| tax_group | varchar | Податкова група. |
| discount_amount | integer | Знижка в копійках. |
17.6. fiscal_payments
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID оплати. |
| receipt_id | uuid | ID чека. |
| payment_type | varchar | CASH, CARD, ONLINE, MIXED. |
| provider | varchar | LiqPay, WayForPay, Mono, terminal тощо. |
| amount | integer | Сума оплати в копійках. |
| external_payment_id | varchar | ID оплати в платіжній системі. |
17.7. fiscal_events
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID події. |
| entity_type | varchar | receipt, shift, integration. |
| entity_id | uuid | ID сутності. |
| event_type | varchar | Тип події. |
| old_status | varchar | Попередній статус. |
| new_status | varchar | Новий статус. |
| payload | jsonb | Технічні дані. |
| created_at | timestamp | Дата події. |
18. API Python-сервісу
18.1. Створення інтеграції
POST /api/v1/fiscal/checkbox/integrations
18.2. Перевірка підключення
POST /api/v1/fiscal/checkbox/integrations/{integration_id}/check-connection
18.3. Створення чека продажу
POST /api/v1/fiscal/checkbox/receipts
18.4. Створення чека повернення
POST /api/v1/fiscal/checkbox/refund-receipts
18.5. Службове внесення / винесення
POST /api/v1/fiscal/checkbox/service-receipts
18.6. Отримання чека
GET /api/v1/fiscal/checkbox/receipts/{receipt_id}
18.7. Синхронізація статусу чека
POST /api/v1/fiscal/checkbox/receipts/{receipt_id}/sync-status
18.8. Повторна фіскалізація
POST /api/v1/fiscal/checkbox/receipts/{receipt_id}/retry
18.9. Відкриття зміни
POST /api/v1/fiscal/checkbox/shifts/open
18.10. Закриття зміни
POST /api/v1/fiscal/checkbox/shifts/{shift_id}/close
18.11. X-звіт
POST /api/v1/fiscal/checkbox/shifts/{shift_id}/x-report
18.12. Dashboard
GET /api/v1/fiscal/checkbox/dashboard?date_from=2026-05-01&date_to=2026-05-07
19. Приклад Python-логіки
19.1. Створення чека
from uuid import UUID, uuid4
from datetime import datetime, timezone
def create_fiscal_receipt(command: "CreateReceiptCommand", db: "Session") -> "FiscalReceipt":
existing = receipt_repository.get_by_idempotency_key(
db=db,
idempotency_key=command.idempotency_key,
)
if existing:
return existing
validation_service.validate_receipt(command)
receipt = receipt_repository.create(
db=db,
data={
"receipt_uuid": uuid4(),
"external_order_id": command.external_order_id,
"external_payment_id": command.external_payment_id,
"idempotency_key": command.idempotency_key,
"receipt_type": "sale",
"status": "PENDING",
"total_amount": command.total_amount,
"currency": command.currency,
"raw_request": command.model_dump(),
},
)
fiscal_queue.enqueue(
task_name="fiscalize_checkbox_receipt",
payload={"receipt_id": str(receipt.id)},
)
audit_logger.log(
entity_type="receipt",
entity_id=receipt.id,
event_type="RECEIPT_QUEUED",
payload={"external_order_id": command.external_order_id},
)
db.commit()
return receipt
19.2. Worker фіскалізації
def fiscalize_checkbox_receipt(receipt_id: UUID, db: "Session") -> None:
receipt = receipt_repository.get_by_id(db, receipt_id)
if receipt.status == "FISCALIZED":
return
try:
receipt.status = "SENDING"
db.commit()
shift = shift_service.ensure_open_shift(
cash_register_id=receipt.cash_register_id,
cashier_id=receipt.cashier_id,
db=db,
)
payload = receipt_mapper.to_checkbox_sell_payload(receipt, shift)
response = checkbox_client.create_sell_receipt(payload)
receipt.status = "CREATED_IN_CHECKBOX"
receipt.raw_response = response.raw_payload
status_response = checkbox_client.get_receipt_status(response.id)
if status_response.is_fiscalized:
receipt.status = "FISCALIZED"
receipt.fiscal_number = status_response.fiscal_number
receipt.fiscal_url = status_response.fiscal_url
receipt.qr_code = status_response.qr_code
receipt.fiscalized_at = datetime.now(timezone.utc)
audit_logger.log(
entity_type="receipt",
entity_id=receipt.id,
event_type="RECEIPT_SENT_TO_CHECKBOX",
payload={
"checkbox_receipt_id": response.id,
"status": receipt.status,
},
)
except TemporaryFiscalError as exc:
receipt.status = "NEEDS_RETRY"
receipt.error_message = str(exc)
except Exception as exc:
receipt.status = "FISCALIZATION_ERROR"
receipt.error_message = str(exc)
finally:
db.commit()
19.3. Відкриття зміни
def open_checkbox_shift(
cash_register_id: UUID,
cashier_id: str,
db: "Session",
) -> "FiscalShift":
cash_register = cash_register_repository.get_by_id(db, cash_register_id)
current_shift = shift_repository.get_current_open_shift(
db=db,
cash_register_id=cash_register.id,
)
if current_shift:
return current_shift
shift = shift_repository.create(
db=db,
data={
"cash_register_id": cash_register.id,
"cashier_id": cashier_id,
"status": "CREATED",
},
)
payload = {
"id": str(shift.id)
}
response = checkbox_client.open_shift(payload)
shift.external_shift_id = response.id
shift.status = response.status
shift.raw_response = response.raw_payload
audit_logger.log(
entity_type="shift",
entity_id=shift.id,
event_type="SHIFT_OPEN_REQUESTED",
payload={"checkbox_shift_id": response.id},
)
db.commit()
return shift
20. Обробка помилок
20.1. Типи помилок
| Тип помилки | Опис | Дія системи |
|---|---|---|
| ValidationError | Некоректні дані чека. | Не відправляти чек, повернути список помилок. |
| AuthError | Невірний API token або відсутній доступ. | Зупинити інтеграцію, повідомити адміністратора. |
| LicenseKeyError | Невірний або відсутній license key. | Заборонити операції по касі. |
| CashRegisterError | Каса не знайдена або неактивна. | Заборонити фіскалізацію. |
| ShiftError | Помилка відкриття або закриття зміни. | Записати помилку, дозволити повтор. |
| FiscalApiError | API повернув помилку. | Зберегти raw-відповідь, перевести в NEEDS_RETRY або ERROR. |
| TimeoutError | Перевищено час очікування. | Виконати retry. |
| DuplicateReceiptError | Чек уже створено. | Повернути існуючий чек. |
| RefundLimitError | Сума повернення перевищує доступний залишок. | Заборонити повернення. |
| OfflineModeError | Помилка офлайн-режиму або перевищення лімітів. | Заблокувати офлайн-операцію та повідомити адміністратора. |
20.2. Retry-логіка
Retry застосовується для:
- timeout;
- тимчасової недоступності API;
- HTTP 429;
- HTTP 500;
- HTTP 502;
- HTTP 503;
- HTTP 504;
- мережевих помилок;
- тимчасових помилок статусу.
Retry не застосовується для:
- помилок валідації;
- неправильного токена;
- неправильного license key;
- дублювання чека;
- некоректних сум;
- неправильних податкових груп;
- повернення понад доступну суму;
- офлайн-операцій без дозволеного режиму.
21. Dashboard керівника
21.1. Основні KPI
| KPI | Опис | Колір |
|---|---|---|
| Чеків створено | Загальна кількість чеків за період. | Інформаційний |
| Фіскалізовано | Кількість успішних чеків. | Норма |
| Очікують | Чеки в черзі. | Увага |
| Помилки | Чеки з помилкою. | Критично |
| Повернення | Кількість чеків повернення. | Спеціальні операції |
| Службові операції | Кількість внесень і винесень готівки. | Контроль |
| Незакриті зміни | Каси з відкритими змінами. | Потрібна дія |
21.2. Приклад dashboard
| Показник | Значення | Стан |
|---|---|---|
| Чеків за день | 1240 | Інформація |
| Фіскалізовано | 1218 | Норма |
| Очікують у черзі | 12 | Увага |
| Помилки фіскалізації | 7 | Критично |
| Повернення | 14 | Контроль |
| Службові внесення / винесення | 6 | Контроль |
| Незакриті зміни | 2 | Потрібна дія |
21.3. Список проблемних операцій
| Час | Каса | Замовлення | Сума | Статус | Помилка | Дія |
|---|---|---|---|---|---|---|
| 10:42 | Каса 1 | ORDER-123 | 570.00 | Помилка | Timeout API | Повторити |
| 11:05 | Каса 2 | ORDER-124 | 1200.00 | Потребує повтору | Тимчасова помилка | Повторити |
| 12:10 | Каса 3 | SHIFT-55 | - | Зміна відкрита | Не закрито Z-звіт | Закрити зміну |
22. Безпека
Система повинна забезпечити:
- зберігання токенів тільки у secret storage або в зашифрованому вигляді;
- зберігання license key тільки у secret storage або в зашифрованому вигляді;
- заборону логування токенів;
- маскування персональних даних покупців;
- обмеження доступу до чеків;
- контроль доступу до повернень;
- окремі права на закриття зміни;
- окремі права на службове винесення готівки;
- журнал усіх дій;
- HTTPS для API-запитів;
- перевірку SSL;
- обмеження повторних запитів;
- захист від дублювання чеків.
23. Логування та аудит
Система повинна логувати:
| Подія | Що зберігати |
|---|---|
| Створення чека | external_order_id, сума, каса, касир. |
| Відправка в API | endpoint, час, request_id. |
| Успішна фіскалізація | fiscal_number, fiscal_url, дата. |
| Помилка фіскалізації | код помилки, повідомлення, raw-відповідь. |
| Повторна обробка | хто запустив, коли, результат. |
| Повернення | первинний чек, сума, причина. |
| Службова операція | тип, сума, каса, касир. |
| Відкриття зміни | каса, касир, час. |
| Закриття зміни | Z-звіт, час, результат. |
| Зміна налаштувань | користувач, старі та нові параметри. |
24. Acceptance Criteria
24.1. Інтеграція
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-1 | Адміністратор створює інтеграцію Checkbox. | Інтеграція зберігається в системі. |
| AC-2 | Адміністратор перевіряє підключення. | Система повертає успішний або помилковий статус. |
| AC-3 | Токен неправильний. | Система показує AuthError і не виконує фіскалізацію. |
| AC-4 | License key неправильний. | Система блокує операції по касі. |
24.2. Чеки
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-5 | ERP передає продаж. | Python-сервіс створює чек зі статусом PENDING. |
| AC-6 | Checkbox повертає успіх. | Чек отримує статус FISCALIZED. |
| AC-7 | Чек фіскалізовано. | У БД зберігається fiscal_number. |
| AC-8 | Повторний запит має той самий idempotency_key. | Другий чек не створюється. |
| AC-9 | API повертає тимчасову помилку. | Чек переходить у NEEDS_RETRY. |
24.3. Повернення
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-10 | Користувач створює повернення. | Система створює чек повернення. |
| AC-11 | Сума повернення більша за суму продажу. | Система блокує операцію. |
| AC-12 | Повернення успішне. | Первинний чек отримує ознаку повного або часткового повернення. |
24.4. Зміни
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-13 | Перед першим чеком зміна закрита. | Система відкриває зміну, якщо auto_open_shift = true. |
| AC-14 | Користувач закриває зміну. | Система формує Z-звіт. |
| AC-15 | Є незавершені чеки. | Система попереджає перед закриттям зміни. |
| AC-16 | Статус зміни змінився у Checkbox. | Python-сервіс синхронізує локальний статус. |
24.5. Службові операції
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-17 | Користувач створює службове внесення. | Система створює service receipt. |
| AC-18 | Користувач створює службове винесення. | Система створює service receipt з відповідним напрямком суми. |
| AC-19 | Сума службової операції некоректна. | Система блокує операцію. |
24.6. Dashboard
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-20 | Керівник відкриває dashboard. | Він бачить кількість чеків, помилок, повернень, службових операцій і незакритих змін. |
| AC-21 | Є помилки фіскалізації. | Вони підсвічуються червоним. |
| AC-22 | Є незакриті зміни. | Вони підсвічуються помаранчевим. |
25. MVP
До MVP входить:
- створення інтеграції Checkbox;
- перевірка підключення;
- збереження token і license key;
- створення чека продажу;
- створення чека повернення;
- службове внесення / винесення готівки;
- валідація чеків;
- дедублікація;
- черга фіскалізації;
- відкриття зміни;
- закриття зміни;
- отримання статусу чека;
- отримання статусу зміни;
- збереження fiscal_number;
- журнал подій;
- retry-механізм;
- dashboard API;
- базові unit-тести;
- mock API для інтеграційних тестів.
До MVP не входить:
- повноцінний POS UI;
- власний ПРРО;
- інтеграція з усіма еквайрингами;
- складна аналітика;
- автоматична реєстрація ПРРО в ДПС;
- повна підтримка офлайн-режиму;
- повна підтримка всіх нестандартних податкових сценаріїв.
26. Етапи реалізації
Етап 1. Базова структура сервісу
- створити FastAPI-проєкт;
- налаштувати PostgreSQL;
- створити моделі інтеграції, кас, змін, чеків;
- налаштувати Alembic;
- реалізувати healthcheck.
Етап 2. Налаштування інтеграції
- реалізувати створення інтеграції;
- реалізувати зберігання токена;
- реалізувати зберігання license key;
- реалізувати check-connection;
- реалізувати права доступу.
Етап 3. Checkbox Client
- реалізувати клієнт API;
- реалізувати авторизацію;
- реалізувати заголовки X-Client-Name, X-Client-Version, X-License-Key;
- реалізувати open_shift;
- реалізувати close_shift;
- реалізувати create_sell_receipt;
- реалізувати create_refund_receipt;
- реалізувати create_service_receipt;
- реалізувати get_status;
- реалізувати отримання візуалізації;
- реалізувати обробку помилок.
Етап 4. Чеки
- реалізувати створення чеків;
- реалізувати валідацію;
- реалізувати дедублікацію;
- реалізувати чергу;
- реалізувати worker фіскалізації.
Етап 5. Повернення
- реалізувати чек повернення;
- перевірити доступний залишок повернення;
- зв'язати повернення з первинним чеком.
Етап 6. Службові операції
- реалізувати службове внесення;
- реалізувати службове винесення;
- реалізувати права доступу до службових операцій;
- реалізувати аудит.
Етап 7. Зміни та звіти
- реалізувати відкриття зміни;
- реалізувати закриття зміни;
- реалізувати X-звіт;
- реалізувати контроль незакритих змін.
Етап 8. Dashboard та аудит
- реалізувати dashboard API;
- реалізувати журнал подій;
- реалізувати фільтри;
- реалізувати експорт, якщо потрібно.
Етап 9. Production hardening
- додати rate limiting;
- додати alerting;
- додати retry policy;
- додати dead letter queue;
- додати моніторинг;
- додати резервне копіювання.
27. Ризики
| Ризик | Опис | Як зменшити |
|---|---|---|
| Дублювання чеків | Повторний запит може створити другий чек. | Idempotency key, receipt_uuid і дедублікація. |
| Втрата чека | API недоступне під час продажу. | Черга, retry, статус NEEDS_RETRY. |
| Незакрита зміна | Касир або система не закрили зміну. | Dashboard, нагадування, авто-закриття за правилом. |
| Невірні суми | Сума товарів не відповідає оплатам. | Валідація перед фіскалізацією. |
| Помилки токена | Токен змінено або відкликано. | Check-connection і сповіщення адміністратора. |
| Невірний license key | Каса не може виконувати операції. | Валідація налаштувань каси. |
| Невірна податкова група | Товар передано з неправильним податком. | Довідник tax_group і валідація. |
| Конфлікт фронт-агентів | По одній касі одночасно працюють різні інтеграції. | Заборонити змішування сценаріїв для однієї каси. |
| Офлайн-режим | Є обмеження й додаткові правила для офлайн-операцій. | Вмикати тільки після окремого погодження. |
28. Відкриті питання
- Який сценарій інтеграції використовується: WebAPI, Checkbox Kasa Manager або гібрид?
- Чи потрібна підтримка локального друку чеків?
- Чи потрібно відправляти чек покупцю через email/SMS?
- Які типи оплат підтримуються?
- Які платіжні провайдери використовуються?
- Чи потрібна інтеграція з POS-терміналами?
- Чи потрібно автоматично відкривати зміну?
- Чи потрібно автоматично закривати зміну?
- Чи потрібна підтримка часткових повернень?
- Чи потрібна підтримка змішаних оплат?
- Чи потрібно зберігати HTML/PNG/TXT чека локально?
- Чи потрібен QR-code у внутрішній системі?
- Який SLA по фіскалізації?
- Чи потрібен dashboard у UI, чи тільки API?
- Чи потрібна інтеграція з K2 ERP?
- Які податкові групи товарів використовуються?
- Чи потрібна підтримка декількох юридичних осіб?
- Чи потрібна підтримка декількох торгових точок?
- Чи дозволяється офлайн-режим?
- Чи потрібна підтримка службового внесення / винесення готівки?
29. Джерела
- https://checkbox.ua/
- https://checkbox.ua/api-integration/
- https://wiki.checkbox.ua/api
- https://wiki.checkbox.ua/api/shifts
- https://wiki.checkbox.ua/api/receipts
- https://wiki.checkbox.ua/uk/api/local_api_specification
- https://api.checkbox.in.ua/