Технічне завдання: інтеграція Вчасно каса для Python
Головна ідея: розробити Python-сервіс, який інтегрує ERP / CRM / інтернет-магазин / POS-систему з «Вчасно.Каса» для автоматичної фіскалізації чеків, контролю касових змін, повернень, статусів, помилок та друку або відправки електронних чеків покупцям.
Критично важливо: інтеграція з ПРРО не повинна втрачати чеки. Кожна операція продажу, повернення, відкриття зміни, закриття зміни та помилка фіскалізації повинні мати внутрішній ID, статус, журнал подій і можливість повторної обробки без створення дубля.
Важливо: у «Вчасно.Каса» можуть використовуватись різні сценарії інтеграції: хмарне API, Device Manager, інтеграція з обліковою системою, сайтом або POS. Конкретний сценарій потрібно зафіксувати в налаштуваннях інтеграції.
Технічний стек: Python 3.11+, FastAPI, PostgreSQL, SQLAlchemy, Alembic, httpx, Pydantic, Celery/RQ/APScheduler, Redis, Docker.
Управлінський результат: керівник повинен бачити, скільки чеків сформовано, скільки фіскалізовано, скільки помилок, які каси відкриті, які зміни не закриті, скільки повернень і які операції потребують уваги.
1. Мета
Метою задачі є створення Python-сервісу для інтеграції з «Вчасно.Каса» з метою автоматизації фіскалізації продажів, повернень і касових операцій.
Сервіс повинен забезпечити:
- прийом замовлень, продажів або оплат із зовнішньої системи;
- створення фіскального чека;
- створення чека повернення;
- контроль відкриття касової зміни;
- контроль закриття касової зміни;
- формування X-звіту;
- формування Z-звіту;
- отримання статусів чеків;
- збереження фіскальних номерів;
- збереження посилання на чек або PDF/HTML-візуалізацію, якщо доступна;
- відправку електронного чека покупцю, якщо підтримується API або налаштуваннями сервісу;
- журналювання всіх API-запитів;
- повторну обробку помилкових операцій;
- захист від дублювання чеків;
- передачу статусів назад в ERP / CRM / сайт / POS.
2. Область застосування
Функціонал використовується для:
- інтернет-магазинів;
- POS-систем;
- CRM;
- ERP;
- служб доставки;
- маркетплейсів;
- сервісів підписок;
- систем обліку продажів;
- компаній, які хочуть автоматизувати фіскалізацію оплат.
До області задачі входить:
- Python API для прийому продажів;
- клієнт інтеграції з «Вчасно.Каса»;
- підтримка фіскалізації чеків;
- підтримка повернень;
- відкриття та закриття змін;
- збереження чеків;
- збереження статусів;
- журнал помилок;
- retry-механізм;
- dashboard / API для контролю;
- інтеграція з внутрішньою системою.
До першої версії не входить:
- повноцінний POS-інтерфейс касира;
- власна реалізація ПРРО без «Вчасно.Каса»;
- самостійна реєстрація ПРРО в ДПС через Python-сервіс;
- власний модуль КЕП;
- інтеграція з усіма еквайрингами;
- складний UI для касира;
- заміна кабінету «Вчасно.Каса».
3. Джерела інтеграції
| Компонент | Призначення | Коментар |
|---|---|---|
| «Вчасно.Каса» | ПРРО-сервіс для фіскалізації чеків. | Основний зовнішній сервіс інтеграції. |
| Хмарне API «Вчасно.Каса» | Пряма інтеграція з кабінетом та фіскалізацією чеків. | Підходить для хмарних систем. |
| Device Manager | Локальний або інтеграційний застосунок для роботи з ПРРО, POS-пристроями та фіскалізацією. | Підходить для інтеграцій з локальними системами, POS, принтерами. |
| Python-сервіс | Інтеграційний шар між ERP / сайтом / CRM / POS та «Вчасно.Каса». | Реалізується в межах цього ТЗ. |
| ERP / CRM / сайт / POS | Джерело продажів, повернень, оплат і даних покупця. | Наприклад K2 ERP або інша система. |
| ДПС | Кінцевий отримувач фіскальних даних через ПРРО. | Python-сервіс напряму з ДПС у MVP не працює. |
4. Передумови
Для реалізації задачі необхідно отримати:
- акаунт у «Вчасно.Каса»;
- зареєстрований суб'єкт господарювання;
- зареєстровану торгову точку;
- зареєстрований ПРРО;
- зареєстрованого касира;
- активний доступ до API або Device Manager;
- токен інтеграції;
- тестову касу або тестовий режим, якщо доступний;
- перелік кас, які будуть використовуватись;
- перелік касирів;
- правила відкриття і закриття зміни;
- правила формування чеків;
- правила повернень;
- формат оплати;
- формат товарних позицій;
- формат податків і ставок;
- вимоги до відправки електронного чека покупцю.
Критично важливо: до початку розробки потрібно визначити сценарій інтеграції: хмарне API або Device Manager. Від цього залежить архітектура, мережеві налаштування, обробка офлайн-ситуацій і друк чеків.
5. Варіанти інтеграції
5.1. Варіант 1. Хмарне API
Python-сервіс напряму викликає хмарне API «Вчасно.Каса».
| Параметр | Опис |
|---|---|
| Підходить для | Хмарних ERP, CRM, інтернет-магазинів, SaaS-систем. |
| Переваги | Немає локального застосунку, простіша інфраструктура. |
| Обмеження | Потрібен стабільний інтернет і доступ до зовнішнього API. |
| Основні операції | Створення чеків, повернень, отримання статусів, робота з касами. |
5.2. Варіант 2. Device Manager
Python-сервіс взаємодіє з Device Manager, який виконує інтеграційні функції локально або в середовищі клієнта.
| Параметр | Опис |
|---|---|
| Підходить для | POS-систем, локальних облікових систем, магазинів із чековими принтерами. |
| Переваги | Можливість роботи з POS-пристроями, принтерами, локальною інфраструктурою. |
| Обмеження | Потрібна інсталяція та підтримка Device Manager. |
| Основні операції | Фіскалізація чеків, друк, робота з POS-пристроями, X/Z-звіти. |
5.3. Варіант 3. Гібридна схема
Python-сервіс підтримує обидва способи інтеграції.
| Сценарій | Опис |
|---|---|
| Хмарні продажі | Через хмарне API. |
| Фізичні магазини | Через Device Manager. |
| Загальна БД чеків | Усі чеки зберігаються в єдиній БД Python-сервісу. |
| Єдиний dashboard | Керівник бачить усі чеки, каси, статуси й помилки в одному місці. |
6. Основні сутності
| Сутність | Опис |
|---|---|
| Cash Register | Каса / ПРРО, через яку фіскалізуються чеки. |
| Cashier | Касир, від імені якого виконується операція. |
| Shift | Касова зміна. |
| Receipt | Фіскальний чек продажу. |
| Refund Receipt | Чек повернення. |
| Receipt Item | Товарна або послугова позиція в чеку. |
| Payment | Оплата в чеку: готівка, картка, онлайн-еквайринг тощо. |
| Fiscal Status | Статус фіскалізації. |
| X Report | Проміжний звіт без закриття зміни. |
| Z Report | Звіт із закриттям зміни. |
| API Event | Технічна подія інтеграції. |
7. User Story
7.1. Фіскалізація продажу
Як система продажів, я хочу передати інформацію про оплату в Python-сервіс, щоб він автоматично створив фіскальний чек у «Вчасно.Каса».
7.2. Повернення
Як оператор або ERP, я хочу створити чек повернення, щоб коректно відобразити повернення коштів покупцю.
7.3. Контроль зміни
Як касир або адміністратор, я хочу бачити, чи відкрита касова зміна, щоб розуміти, чи можна фіскалізувати чеки.
7.4. Повторна обробка
Як адміністратор, я хочу повторити фіскалізацію після технічної помилки, щоб не втратити продаж.
7.5. Контроль керівника
Як керівник, я хочу бачити dashboard по касах і чеках, щоб контролювати фіскалізацію, помилки, повернення і незакриті зміни.
8. Функціональні вимоги
8.1. Налаштування інтеграції
Система повинна дозволяти створити налаштування підключення до «Вчасно.Каса».
| Поле | Тип | Обов'язковість | Опис |
|---|---|---|---|
| integration_name | string | Так | Назва інтеграції. |
| integration_mode | enum | Так | cloud_api, device_manager, hybrid. |
| base_url | string | Так | Базова адреса API або Device Manager. |
| api_token | secret | Так | Токен інтеграції. |
| organization_id | string | Так | Внутрішній ID організації. |
| cash_register_id | string | Так | ID каси / ПРРО. |
| cashier_id | string | Ні | ID касира за замовчуванням. |
| default_tax_group | string | Ні | Податкова група за замовчуванням. |
| auto_open_shift | boolean | Так | Автоматично відкривати зміну перед першим чеком. |
| auto_close_shift | boolean | Ні | Автоматично закривати зміну за розкладом. |
| send_receipt_to_customer | boolean | Ні | Відправляти чек покупцю. |
| is_active | boolean | Так | Ознака активності інтеграції. |
8.2. Створення чека продажу
Python-сервіс повинен приймати дані продажу та створювати фіскальний чек.
Логічний endpoint Python-сервісу:
POST /api/v1/fiscal/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 | decimal | Загальна сума чека. |
| currency | string | Валюта. |
8.3. Приклад запиту на чек
{
"external_order_id": "ORDER-2026-000123",
"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": 2,
"price": 250.00,
"amount": 500.00,
"tax_group": "VAT_20",
"unit": "шт"
},
{
"name": "Доставка",
"sku": "DELIVERY",
"quantity": 1,
"price": 70.00,
"amount": 70.00,
"tax_group": "NO_VAT",
"unit": "послуга"
}
],
"payments": [
{
"type": "card",
"amount": 570.00,
"provider": "liqpay",
"payment_id": "PAY-123456"
}
],
"total_amount": 570.00,
"currency": "UAH"
}
8.4. Чек повернення
Система повинна підтримувати створення чека повернення.
Логічний endpoint:
POST /api/v1/fiscal/refund-receipts
Мінімальні дані:
| Поле | Тип | Опис |
|---|---|---|
| original_receipt_id | uuid | Внутрішній ID первинного чека. |
| original_fiscal_number | string | Фіскальний номер первинного чека. |
| external_refund_id | string | ID повернення у зовнішній системі. |
| items | array | Позиції, які повертаються. |
| payments | array | Сума повернення. |
| reason | string | Причина повернення. |
Критично важливо: чек повернення повинен бути пов'язаний із первинним чеком. Система не повинна дозволяти створювати повернення на суму більшу, ніж залишок доступний до повернення.
8.5. Відкриття зміни
Система повинна підтримувати відкриття касової зміни.
Логічний endpoint:
POST /api/v1/fiscal/shifts/open
Сценарії:
| Сценарій | Опис |
|---|---|
| Ручне відкриття | Користувач або адміністратор відкриває зміну. |
| Автоматичне відкриття | Система відкриває зміну перед першим чеком. |
| Перевірка перед чеком | Якщо зміна вже відкрита, повторно не відкривати. |
8.6. Закриття зміни
Система повинна підтримувати закриття касової зміни та формування Z-звіту.
Логічний endpoint:
POST /api/v1/fiscal/shifts/{shift_id}/close
Система повинна:
- перевірити відкриту зміну;
- перевірити незавершені чеки;
- сформувати Z-звіт;
- зберегти результат;
- змінити статус зміни на Closed;
- записати подію в журнал.
8.7. X-звіт
Система повинна підтримувати отримання проміжного X-звіту без закриття зміни.
POST /api/v1/fiscal/shifts/{shift_id}/x-report
8.8. Отримання статусу чека
Система повинна підтримувати синхронізацію статусу чека з «Вчасно.Каса».
POST /api/v1/fiscal/receipts/{receipt_id}/sync-status
8.9. Відправка чека покупцю
Якщо API або налаштування «Вчасно.Каса» підтримують електронну відправку чека, Python-сервіс повинен передавати email або телефон покупця.
Канали:
- email;
- SMS;
- Viber;
- інший канал, якщо підтримується сервісом.
9. Статуси чеків
| Статус | Код | Опис | Колір |
|---|---|---|---|
| Чернетка | DRAFT | Чек створено у Python-сервісі, але ще не відправлено. | Сірий |
| Очікує фіскалізації | PENDING | Чек у черзі на відправку. | Жовтий |
| Відправляється | SENDING | Виконується API-запит. | Блакитний |
| Фіскалізовано | FISCALIZED | Чек успішно фіскалізовано. | Зелений |
| Помилка фіскалізації | FISCALIZATION_ERROR | Виникла помилка при фіскалізації. | Червоний |
| Потребує повтору | NEEDS_RETRY | Можна повторити відправку. | Помаранчевий |
| Скасовано | CANCELLED | Операцію скасовано. | Сірий |
| Повернення створено | REFUNDED | По чеку є повне або часткове повернення. | Фіолетовий |
10. Статуси зміни
| Статус | Код | Опис | Колір |
|---|---|---|---|
| Не відкрита | CLOSED | Зміна закрита або ще не відкривалась. | Сірий |
| Відкривається | OPENING | Виконується відкриття зміни. | Блакитний |
| Відкрита | OPEN | Можна фіскалізувати чеки. | Зелений |
| Закривається | 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
Vchasno Kasa Adapter
|
| 3. Cloud API або Device Manager
v
Вчасно.Каса
|
| 4. Фіскалізація через ПРРО
v
ДПС
|
| 5. Фіскальний результат
v
Вчасно.Каса
|
| 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 | Черга задач на фіскалізацію. |
| Vchasno Kasa Client | Python-клієнт для API «Вчасно.Каса» або Device Manager. |
| Shift Service | Відкриття, контроль і закриття змін. |
| Receipt Service | Створення чеків продажу. |
| Refund Service | Створення чеків повернення. |
| Status Sync Worker | Оновлення статусів чеків. |
| Audit Logger | Журнал API-запитів, відповідей, помилок і змін статусів. |
| Dashboard API | Дані для керівника: чеки, зміни, помилки, обороти. |
13. Vchasno Kasa Client
13.1. Призначення
Vchasno Kasa Client — це Python-клас або пакет, який інкапсулює роботу з API «Вчасно.Каса» або Device Manager.
13.2. Основні методи
class VchasnoKasaClient:
def check_connection(self) -> "ConnectionStatus":
pass
def open_shift(self, cash_register_id: str, cashier_id: str) -> "ShiftResponse":
pass
def close_shift(self, shift_id: str) -> "ZReportResponse":
pass
def create_x_report(self, shift_id: str) -> "XReportResponse":
pass
def create_receipt(self, payload: "ReceiptPayload") -> "ReceiptResponse":
pass
def create_refund_receipt(self, payload: "RefundReceiptPayload") -> "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_pdf(self, receipt_id: str) -> bytes:
pass
13.3. Конфігурація клієнта
from pydantic_settings import BaseSettings
class VchasnoKasaSettings(BaseSettings):
integration_mode: str = "cloud_api"
base_url: str
api_token: str
organization_id: 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
Приклад змінних середовища:
VCHASNO_KASA_INTEGRATION_MODE=cloud_api VCHASNO_KASA_BASE_URL=https://api.example.vchasno-kasa VCHASNO_KASA_API_TOKEN=******** VCHASNO_KASA_ORGANIZATION_ID=org-001 VCHASNO_KASA_DEFAULT_CASH_REGISTER_ID=cash-register-001 VCHASNO_KASA_DEFAULT_CASHIER_ID=cashier-001 VCHASNO_KASA_TIMEOUT_SECONDS=30 VCHASNO_KASA_RETRY_COUNT=3 VCHASNO_KASA_RETRY_BACKOFF_SECONDS=5
Заборонено: зберігати API token, ключі, паролі касирів або інші секрети у коді, Git-репозиторії, відкритих логах або frontend-змінних.
14. Валідація чека
Перед фіскалізацією система повинна перевірити:
- наявність external_order_id;
- відсутність уже фіскалізованого чека по цьому external_order_id;
- наявність каси;
- наявність касира;
- наявність відкритої зміни або можливість її відкрити;
- наявність хоча б однієї позиції;
- коректність кількості;
- коректність ціни;
- коректність суми рядка;
- відповідність total_amount сумі товарів і оплат;
- коректність типу оплати;
- коректність податкових груп;
- коректність email або телефону покупця, якщо чек потрібно відправити.
15. Дедублікація
Система повинна не допускати дублювання чеків.
Ключі дедублікації:
| Ключ | Призначення |
|---|---|
| external_order_id | Основний ключ від зовнішньої системи. |
| external_payment_id | Додатковий ключ від платіжної системи. |
| idempotency_key | Унікальний ключ запиту. |
| receipt_hash | Hash товарів, сум, оплат і замовлення. |
Приклад hash:
sha256(external_order_id + total_amount + payment_id + cash_register_id)
Критично важливо: повторний запит із тим самим idempotency_key не повинен створити другий фіскальний чек. Він повинен повернути результат уже створеної операції.
16. Черга фіскалізації
Для підвищення надійності фіскалізація повинна виконуватись через чергу.
16.1. Логіка черги
1. API приймає запит на створення чека. 2. Дані проходять валідацію. 3. Створюється запис receipt зі статусом PENDING. 4. Задача додається в чергу. 5. Worker викликає API «Вчасно.Каса». 6. Результат зберігається в БД. 7. ERP / CRM / сайт отримує статус.
16.2. Пріоритети задач
| Тип задачі | Пріоритет | Коментар |
|---|---|---|
| Фіскалізація продажу | Високий | Основний бізнес-процес. |
| Повернення | Високий | Важлива фінансова операція. |
| Закриття зміни | Критичний | Не можна залишати зміну незакритою. |
| Синхронізація статусів | Середній | Може виконуватись фоново. |
| Завантаження PDF | Низький | Не блокує фіскалізацію. |
17. Модель даних
17.1. fiscal_integrations
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID інтеграції. |
| provider | varchar | vchasno_kasa. |
| integration_mode | varchar | cloud_api, device_manager, hybrid. |
| name | varchar | Назва інтеграції. |
| base_url | varchar | URL API. |
| api_token_encrypted | text | Зашифрований токен. |
| organization_id | varchar | Організація. |
| 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 каси у «Вчасно.Каса». |
| 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 зміни у «Вчасно.Каса». |
| status | varchar | OPEN, CLOSED, ERROR тощо. |
| opened_at | timestamp | Дата відкриття. |
| closed_at | timestamp | Дата закриття. |
| z_report_number | varchar | Номер Z-звіту. |
| error_message | text | Остання помилка. |
17.4. fiscal_receipts
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | Внутрішній ID чека. |
| integration_id | uuid | ID інтеграції. |
| cash_register_id | uuid | Каса. |
| shift_id | uuid | Зміна. |
| external_order_id | varchar | ID замовлення. |
| external_payment_id | varchar | ID оплати. |
| idempotency_key | varchar | Ключ дедублікації. |
| receipt_type | varchar | sale або refund. |
| status | varchar | Статус чека. |
| total_amount | numeric | Загальна сума. |
| 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 | numeric | Кількість. |
| unit | varchar | Одиниця виміру. |
| price | numeric | Ціна. |
| amount | numeric | Сума. |
| tax_group | varchar | Податкова група. |
| discount_amount | numeric | Знижка. |
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 | numeric | Сума оплати. |
| 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/integrations
18.2. Перевірка підключення
POST /api/v1/fiscal/integrations/{integration_id}/check-connection
18.3. Створення чека продажу
POST /api/v1/fiscal/receipts
18.4. Створення чека повернення
POST /api/v1/fiscal/refund-receipts
18.5. Отримання чека
GET /api/v1/fiscal/receipts/{receipt_id}
18.6. Синхронізація статусу чека
POST /api/v1/fiscal/receipts/{receipt_id}/sync-status
18.7. Повторна фіскалізація
POST /api/v1/fiscal/receipts/{receipt_id}/retry
18.8. Відкриття зміни
POST /api/v1/fiscal/shifts/open
18.9. Закриття зміни
POST /api/v1/fiscal/shifts/{shift_id}/close
18.10. X-звіт
POST /api/v1/fiscal/shifts/{shift_id}/x-report
18.11. Dashboard
GET /api/v1/fiscal/dashboard?date_from=2026-05-01&date_to=2026-05-07
19. Приклад Python-логіки
19.1. Створення чека
from uuid import UUID
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={
"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_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_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_vchasno_payload(receipt, shift)
response = vchasno_kasa_client.create_receipt(payload)
receipt.status = "FISCALIZED"
receipt.fiscal_number = response.fiscal_number
receipt.fiscal_url = response.fiscal_url
receipt.qr_code = response.qr_code
receipt.raw_response = response.raw_payload
receipt.fiscalized_at = datetime.now(timezone.utc)
audit_logger.log(
entity_type="receipt",
entity_id=receipt.id,
event_type="RECEIPT_FISCALIZED",
payload={
"fiscal_number": response.fiscal_number,
"fiscal_url": response.fiscal_url,
},
)
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()
20. Обробка помилок
20.1. Типи помилок
| Тип помилки | Опис | Дія системи |
|---|---|---|
| ValidationError | Некоректні дані чека. | Не відправляти чек, повернути список помилок. |
| AuthError | Невірний API token або відсутній доступ. | Зупинити інтеграцію, повідомити адміністратора. |
| CashRegisterError | Каса не знайдена або неактивна. | Заборонити фіскалізацію. |
| ShiftError | Помилка відкриття або закриття зміни. | Записати помилку, дозволити повтор. |
| FiscalApiError | API повернув помилку. | Зберегти raw-відповідь, перевести в NEEDS_RETRY або ERROR. |
| TimeoutError | Перевищено час очікування. | Виконати retry. |
| DuplicateReceiptError | Чек уже створено. | Повернути існуючий чек. |
| RefundLimitError | Сума повернення перевищує доступний залишок. | Заборонити повернення. |
20.2. Retry-логіка
Retry застосовується для:
- timeout;
- тимчасової недоступності API;
- HTTP 429;
- HTTP 500;
- HTTP 502;
- HTTP 503;
- HTTP 504;
- мережевих помилок;
- тимчасової помилки Device Manager.
Retry не застосовується для:
- помилок валідації;
- неправильного токена;
- дублювання чека;
- некоректних сум;
- неправильних податкових груп;
- повернення понад доступну суму.
21. Dashboard керівника
21.1. Основні KPI
| KPI | Опис | Колір |
|---|---|---|
| Чеків створено | Загальна кількість чеків за період. | Інформаційний |
| Фіскалізовано | Кількість успішних чеків. | Норма |
| Очікують | Чеки в черзі. | Увага |
| Помилки | Чеки з помилкою. | Критично |
| Повернення | Кількість чеків повернення. | Спеціальні операції |
| Незакриті зміни | Каси з відкритими змінами. | Потрібна дія |
21.2. Приклад dashboard
| Показник | Значення | Стан |
|---|---|---|
| Чеків за день | 1240 | Інформація |
| Фіскалізовано | 1218 | Норма |
| Очікують у черзі | 12 | Увага |
| Помилки фіскалізації | 7 | Критично |
| Повернення | 14 | Контроль |
| Незакриті зміни | 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 або в зашифрованому вигляді;
- заборону логування токенів;
- маскування персональних даних покупців;
- обмеження доступу до чеків;
- контроль доступу до повернень;
- окремі права на закриття зміни;
- журнал усіх дій;
- HTTPS для API-запитів;
- перевірку SSL;
- обмеження повторних запитів;
- захист від дублювання чеків.
23. Логування та аудит
Система повинна логувати:
| Подія | Що зберігати |
|---|---|
| Створення чека | external_order_id, сума, каса, касир. |
| Відправка в API | endpoint, час, request_id. |
| Успішна фіскалізація | fiscal_number, fiscal_url, дата. |
| Помилка фіскалізації | код помилки, повідомлення, raw-відповідь. |
| Повторна обробка | хто запустив, коли, результат. |
| Повернення | первинний чек, сума, причина. |
| Відкриття зміни | каса, касир, час. |
| Закриття зміни | Z-звіт, час, результат. |
| Зміна налаштувань | користувач, старі та нові параметри. |
24. Acceptance Criteria
24.1. Інтеграція
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-1 | Адміністратор створює інтеграцію. | Інтеграція зберігається в системі. |
| AC-2 | Адміністратор перевіряє підключення. | Система повертає успішний або помилковий статус. |
| AC-3 | Токен неправильний. | Система показує AuthError і не виконує фіскалізацію. |
24.2. Чеки
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-4 | ERP передає продаж. | Python-сервіс створює чек зі статусом PENDING. |
| AC-5 | API «Вчасно.Каса» повертає успіх. | Чек отримує статус FISCALIZED. |
| AC-6 | Чек фіскалізовано. | У БД зберігається fiscal_number. |
| AC-7 | Повторний запит має той самий idempotency_key. | Другий чек не створюється. |
| AC-8 | API повертає тимчасову помилку. | Чек переходить у NEEDS_RETRY. |
24.3. Повернення
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-9 | Користувач створює повернення. | Система створює чек повернення. |
| AC-10 | Сума повернення більша за суму продажу. | Система блокує операцію. |
| AC-11 | Повернення успішне. | Первинний чек отримує ознаку повного або часткового повернення. |
24.4. Зміни
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-12 | Перед першим чеком зміна закрита. | Система відкриває зміну, якщо auto_open_shift = true. |
| AC-13 | Користувач закриває зміну. | Система формує Z-звіт. |
| AC-14 | Є незавершені чеки. | Система попереджає перед закриттям зміни. |
24.5. Dashboard
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-15 | Керівник відкриває dashboard. | Він бачить кількість чеків, помилок, повернень і незакритих змін. |
| AC-16 | Є помилки фіскалізації. | Вони підсвічуються червоним. |
| AC-17 | Є незакриті зміни. | Вони підсвічуються помаранчевим. |
25. MVP
До MVP входить:
- створення інтеграції;
- перевірка підключення;
- створення чека продажу;
- створення чека повернення;
- валідація чеків;
- дедублікація;
- черга фіскалізації;
- відкриття зміни;
- закриття зміни;
- отримання статусу чека;
- збереження fiscal_number;
- журнал подій;
- retry-механізм;
- dashboard API;
- базові unit-тести;
- mock API для інтеграційних тестів.
До MVP не входить:
- повноцінний POS UI;
- власний ПРРО;
- інтеграція з усіма еквайрингами;
- складна аналітика;
- автоматична реєстрація ПРРО в ДПС;
- підтримка всіх нестандартних податкових сценаріїв;
- повна офлайн-робота без Device Manager.
26. Етапи реалізації
Етап 1. Базова структура сервісу
- створити FastAPI-проєкт;
- налаштувати PostgreSQL;
- створити моделі інтеграції, кас, змін, чеків;
- налаштувати Alembic;
- реалізувати healthcheck.
Етап 2. Налаштування інтеграції
- реалізувати створення інтеграції;
- реалізувати зберігання токена;
- реалізувати check-connection;
- реалізувати права доступу.
Етап 3. Vchasno Kasa Client
- реалізувати клієнт API;
- реалізувати авторизацію;
- реалізувати open_shift;
- реалізувати close_shift;
- реалізувати create_receipt;
- реалізувати create_refund_receipt;
- реалізувати get_status;
- реалізувати обробку помилок.
Етап 4. Чеки
- реалізувати створення чеків;
- реалізувати валідацію;
- реалізувати дедублікацію;
- реалізувати чергу;
- реалізувати worker фіскалізації.
Етап 5. Повернення
- реалізувати чек повернення;
- перевірити доступний залишок повернення;
- зв'язати повернення з первинним чеком.
Етап 6. Зміни та звіти
- реалізувати відкриття зміни;
- реалізувати закриття зміни;
- реалізувати X-звіт;
- реалізувати контроль незакритих змін.
Етап 7. Dashboard та аудит
- реалізувати dashboard API;
- реалізувати журнал подій;
- реалізувати фільтри;
- реалізувати експорт, якщо потрібно.
Етап 8. Production hardening
- додати rate limiting;
- додати alerting;
- додати retry policy;
- додати dead letter queue;
- додати моніторинг;
- додати резервне копіювання.
27. Ризики
| Ризик | Опис | Як зменшити |
|---|---|---|
| Дублювання чеків | Повторний запит може створити другий чек. | Idempotency key і дедублікація. |
| Втрата чека | API недоступне під час продажу. | Черга, retry, статус NEEDS_RETRY. |
| Незакрита зміна | Касир або система не закрили зміну. | Dashboard, нагадування, авто-закриття за правилом. |
| Невірні суми | Сума товарів не відповідає оплатам. | Валідація перед фіскалізацією. |
| Помилки токена | Токен змінено або відкликано. | Check-connection і сповіщення адміністратора. |
| Невірна податкова група | Товар передано з неправильним податком. | Довідник tax_group і валідація. |
| Device Manager недоступний | Локальний застосунок не відповідає. | Healthcheck і fallback-сценарій. |
28. Відкриті питання
- Який сценарій інтеграції використовується: хмарне API, Device Manager або гібрид?
- Чи потрібна підтримка локального друку чеків?
- Чи потрібно відправляти чек покупцю через email/SMS/Viber?
- Які типи оплат підтримуються?
- Які платіжні провайдери використовуються?
- Чи потрібна інтеграція з POS-терміналами?
- Чи потрібно автоматично відкривати зміну?
- Чи потрібно автоматично закривати зміну?
- Чи потрібна підтримка часткових повернень?
- Чи потрібна підтримка змішаних оплат?
- Чи потрібно зберігати PDF чека локально?
- Який SLA по фіскалізації?
- Чи потрібен dashboard у UI, чи тільки API?
- Чи потрібна інтеграція з K2 ERP?
- Які податкові групи товарів використовуються?
- Чи потрібна підтримка декількох юридичних осіб?
- Чи потрібна підтримка декількох торгових точок?
29. Джерела
- https://service.vchasno.ua/tech-doc-kasa
- https://wiki-kasa.vchasno.ua/uk/DeviceManager/Functionality/API
- https://kasa.vchasno.com.ua/check-list
- https://kasa.vchasno.com.ua/integraciya
- https://kasa.vchasno.com.ua/devise-manager
- https://wiki-kasa.vchasno.ua/uk/DeviceManager/Start/Create_prro
- https://wiki-kasa.vchasno.ua/uk/DeviceManager/Functionality/Emulator