В даному розділі розміщені рекомендації по інтеграції і роботі з застосунком Device Manager (далі ДМ).
Рекомендований таймаут на очікування відповіді буде відрізнятись залежно від пристрою та схеми роботи:
20
секунд.6
секунд.310
секунд.Чому саме такі таймаути?
Робота з ПРРО: 99% часу фіскалізація чеку займає до 1 секунди часу, проте відкриття або закриття зміни може тривати довше, в середньому до 5 секунд, але це не основне. Бувають випадки коли є проблеми які унеможливлюють роботу в онлайн режимі, наприклад збої в роботі серверу ДПС або АЦСК ключа, або проблеми в мережі, в таких випадках застосунок, на основі внутрішніх таймаутів чи помилок, ініціює автоматичний перехід каси в офлайн. Саме на час такого переходу процес фіскалізації може затримуватись. Тому щоб не було проблем коли облікова програма не отримала відповіді на API запит - рекомендований таймаут не менше 20 секунд.
Робота з принтером: Таймаут для друку 5 секунд, якщо протягом 5 секунд не вдалось доставити завдання для друку на принтер - Device Manager повертає помилку.
Робота з терміналом: В середньому час проведення однієї оплати після прикладання картки 10 секунд, проте, час на очікування прикладання картки за замовчуванням варіюється від 40 до 60 секунд також сюди додається час авторизації оплати чи іншої операції на стороні банку який фактично не має як такого таймауту. Тому щоб уникнути проблем з отриманням відповіді від терміналу коли він може працювати повільно рекомендовано поставити саме таймаут 310
секунд. За замовчуванням таймаут очікування відповіді від терміналу 300 секунд, це значення можна змінити в налаштуваннях терміналу в будь який час якщо цього часу забагато або недостатньо, тоді облікова система має мати таймаут: час таймауту в налаштуваннях терміналу + орієнтовно 10 секунд
ДМ стандартно працює повністю паралельно, тобто можна відправляти кілька різних API запитів і всі вони будуть оброблені одночасно.
Проте наявні певні обмеження які залежать від бази даних та самого API запиту.
Якщо ДМ працює під управлінням стандартної SQLite бази даних - абсолютно всі запити які повертають якусь інформацію про ПРРО, чеки, термінал чи принтер, редагування налаштувань та фіскалізація чеку будуть виконуватись згідно внутрішньої черги.
Наприклад в ДМ працює 2 каси, з фронт системи приходить одночасно 2 запити на фіскалізацію чеку (по одному на кожну із кас), в такому випадку фіскалізація чеків буде здійснюватись по черзі по кожній касі, ці затримки можуть бути не помітні на швидких накопичувачах на пристрої, проте при великій кількості запитів та повільній роботі накопичувача можливі затримки.
При роботі з базою даних MS SQL або Postgresql при такому сценації 2 чеки будуть проводитись одночасно як і можуть одночасно виконуватись інші запити.
ПРРО, принтера та термінали як окремі пристрої в ДМ передбачають виключно синхронний режим роботи по запитам на ендпоінти /dm/execute
, /dm/execute-prn
та /dm/execute-pkg
.
Це означає що API запити з 2-х і більше місць одночасно на одну касу, принтер чи термінал оброблюватись не будуть.
Запит який дійшов перший - буде оброблюватись, на всі наступні запити до завершення першого буде повернуто помилку з кодом 1105:
{
"ver": 6,
"resp_ver": 4,
"source": "",
"device": "postgres1",
"tag": "",
"task_status": 3,
"type": 1,
"task": 1,
"dt": "20250725075425311",
"res": 1105,
"res_action": 1,
"errortxt": "Пристрій зайнятий",
"aq_errortxt": "",
"warnings": []
}
При роботі з ПРРО по наступному запиту буде повертатись одразу помилка з кодом 1105 в той час як по терміналам та принтерам реалізовано функціонал міні-черги: якщо за 15 секунд перший запит по терміналу або принтеру не завершено, тільки тоді буде повернуто помилку, у випадку завершення раніше - запит буде виконано.
Що стосується інших ендпоінтів окрім /dm/execute
, /dm/execute-prn
та /dm/execute-pkg
API запити по ним виконуються паралельно і не видають помилку з кодом 1105, проте повертаючись до першого пункту, у разі використання SQLite абсолютно всі запити які повертають якусь інформацію про ПРРО, чеки, термінал чи принтер, редагування налаштувань та фіскалізація чеку будуть виконуватись згідно внутрішньої черги.
При роботі з ПРРО рекомендовано реалізувати транзакційний режим для забезпечення цілісності даних між обліковою програмою та ДМ.
Основна ціль даного функціоналу в можливості повторно отримати результат уже проведеного чеку або точно переконатись що чеку із заданим значенням унікального ключа не було створено раніше.
Це потрібно для випадків коли:
Також транзакційний режим можна використовувати при роботі з терміналами окремо від ПРРО. Покриває даний режим ті ж самі випадки що і при роботі з ПРРО.
"tag"
."tag"
- має мати унікальне значення для кожного нового запиту на фіскалізацію в рамках кожного ПРРО створеного в ДМ. Максимальна довжина 200 символів.Наприклад маємо ситуацію:
Облікова система відправляє чек з "tag": "b57f3011-1d42-47f1-8690-e9e0ea65df45"
ДМ перед фіскалізацією чеку перевіряє чи немає в проведеного раніше чеку з tag b57f3011-1d42-47f1-8690-e9e0ea65df45
Якщо немає - відбувається фіскалізація нового чеку.
Якщо було знайдено - повертається з відповідь з інформацією про фіскалізований раніше чек, фіскалізації не відбувається.
Звертаємо увагу що по значенню
tag
повторно можна отримати лише успішно виконані операції, тобто успішно створені чеки чи звіти.
Коли потрібно лише перевірити наявність фіскалізованого чеку із зазначеним tag без фіскалізації, якщо чек не було знайдено - в корінь JSON запиту передається "type": 0
замість "type": 1
, можна також передавати скорочений JSON без зазначення "type": 0
(скорочений JSON підійде у випадку якщо потрібно лише отримати дані по чеку без його друку на принтері)
наприклад:
curl --location 'http://localhost:3939/dm/execute' \
--header 'Content-Type: application/json' \
--data '{
"device": "postgres1",
"tag": "DC7A45F1-41BF-4AFE-B072-7CC2CBA282F0"
}'
Якщо по касі з назвою postgres1
чек з значенням tag DC7A45F1-41BF-4AFE-B072-7CC2CBA282F0
було знайдено - буде повернуто повну відповідь по цьому чеку із значенням "task_status": 2
Якщо його не було знайдено - буде наступна відповідь:
{
"ver": 6,
"resp_ver": 4,
"source": "",
"device": "postgres1",
"tag": "DC7A45F1-41BF-4AFE-B072-7CC2CBA282F0",
"task_status": 3,
"type": 0,
"task": -1,
"dt": "",
"res": 1058,
"res_action": 1,
"errortxt": "Чек з кодом синхронізації DC7A45F1-41BF-4AFE-B072-7CC2CBA282F0 не знайдено",
"aq_errortxt": "",
"warnings": []
}
"task": 0
)"task": 1
)"task": 2
)"task": 3
, "task": 4
)"task": 11
)"task": 14
)"task": 15
, "task": 16
)Так як tag обов'язково є у кожного з перерахованих вище завданнь, якшо його не передано в JSON запиті наприклад на чек продажу, ДМ сформує його сам у форматі uuid і поверне у відповідь.
Тип відправленого завдання, додатково до значення tag, не перевіряється. Тобто якщо раніше був сформований чек продажу ("task": 1
) з "tag": "b57f3011-1d42-47f1-8690-e9e0ea65df45"
, а пізніше відправлено запит на повернення ("task": 2
) чи на формування Z-звіту ("task": 11
) з цим же значенням tag
, ДМ у відповідь на ці завдання поверне сформований раніше чек.
Всі інші операції не мають tag - виконуються кожного разу з новими даними, тому реалізація повторних запитів з використанням tag для них не потрібна.
"res"
завжди буде більше 0.Визначення коли краще робити повторний запит, а коли можна бути точно впевненим що чек фіскалізовано можна робити наступним чином:
"res_action"
.Значення "res_action"
можуть бути наступні:
0 - Завдання пройшло. Означає успішне виконання завдання ДМ-ом, наприклад чек чи звіт фіскалізовано, при цьому значення "res"
в даному випадку завжди буде рівним 0
.
1 – Помилка при проведенні завдання, завдання не пройшло, наприклад чек не було фіскалізовано із за помилки підписання і ПРРО не може, з певних причин, перейти в офлайн режим, при цьому значення "res"
в даному випадку завжди буде більше 0. Можна повторити запит з тим же значенням tag.
Приклад відповіді:
{
"ver": 6,
"source": "",
"device": "postgres1",
"tag": "97052EA9-1837-48DE-81EE-FB82478211D6",
"task_status": 3,
"type": 1,
"task": 0,
"dt": "20230906171959722",
"res": 1069,
"res_action": 1,
"errortxt": "Виникла помилка при підписанні контенту електронним підписом: Помилка підписання даних у рядку. Виникла помилка при отриманні позначки часу. TSP-сервер не доступний (проблеми з комунікаційними засобами) або не пройдено автентифікацію на proxy-сервері(65)",
"aq_errortxt": "",
"warnings": []
}
2 - Помилка + колізія. Колізія може виникнути у випадку якщо чек було відправлено, але не отримано відповіді про те чи цей чек було фіскалізовано (або отримано помилку) та ПРРО не може, з певних причин, перейти в офлайн режим. Виправлення колізії відбувається автоматично при відправці будь-якого наступного завдання, але для збереження транзакційності рекомендується виконати повтор останнього завдання з тим же значенням tag. Значення "res"
в даному випадку завжди буде більше 0.
Приклад відповіді:
{
"ver": 6,
"resp_ver": 1,
"source": "",
"device": "postgres1",
"tag": "EC53AAA2-B327-4F4A-AADE-3ACCC29824BA",
"task_status": 3,
"type": 1,
"task": 2,
"dt": "20240507190920264",
"res": 1121,
"res_action": 2,
"errortxt": "Дата на пристрої не співпадає з поточною датою на сервері. (Status: 0; У чеці вказано час у майбутньому. Фіскалізувати такий чек неможливо. Будь ласка, виправіть час на вашому девайсі та повторіть спробу.; )",
"aq_errortxt": "",
"warnings": []
}
3 - Помилка, потрібне коригування даних. Може бути помилка у відправлених в запиті даних, помилка виконання операції із за статусу в якому знаходиться ПРРО або помилка в самому застосунку, яку потрібно вирішувати через техпідтримку, при цьому значення "res"
в даному випадку завжди буде більше 0. В даному випадку без виправлення вхідних даних або вирішення помилки - повторний запит ситуації не змінить.
Приклад відповіді:
{
"ver": 6,
"source": "",
"device": "Test1",
"tag": "C473FEE9-4B6C-41E7-97AA-9B29C50A3C42",
"task_status": 3,
"type": 1,
"task": 1,
"dt": "20230906171629056",
"res": 1092,
"res_action": 3,
"errortxt": "Зміна по даному ПРРО закрита. Для фіскалізації чеків необхідно відкрити зміну.",
"aq_errortxt": "",
"warnings": []
}
Дана інформація відноситься до API роботи з терміналами, роботи ПРРО в пакетному режимі даний функціонал не стосується.
При відправці запитів на банківський термінал також доступний транзакційний режим проте в даному випадку він працює дешо інакше як з ПРРО та поділяється на 2 можливості:
Для роботи в даному режимі обов'язково використовується 2 ключа:
transaction_id
- UUID (v5). Ідентифікатор транзакції що використовується як мітка для завдання для пошуку при повторному запиті. Якщо передати значення відмінне від UUID формату, воно буде замінено на UUID що згенерував ДМ та повернуто у відповідь.transaction_search
- Параметр дій з пошуком транзакції.transaction_id
може бути не унікальним навідміну від tag
який є завжди унікальним. В такому випадку у разі наявності в базі даних 2-х і більше операцій з однаковим значенням transaction_id
буде повертатись остання по даті.
Розберемо на прикладі:
ДМ має збережені дані про проведену оплату на терміналі із значенням transaction_id
рівним f535206e-fe64-11ef-bfc2-00505680badb
проте облікова/касова програма не має інформації про цю операцію, лише збережений transaction_id
.
"transaction_id": "f535206e-fe64-11ef-bfc2-00505680badb"
"transaction_search": 0
Відбудеться відправка запиту на термінал на нову оплату.
"transaction_id": "f535206e-fe64-11ef-bfc2-00505680badb"
"transaction_search": 1
Так як така транзакція уже існує - буде повернуто всю інформацію про дану транзакцію без відправки запит на термінал.
"transaction_id": "f535206e-fe64-11ef-bfc2-00505680badb"
"transaction_search": 2
Аналогічно попередньому так як така транзакція уже існує - буде повернуто всю інформацію про дану транзакцію без відправки запит на термінал.
transaction_id
та transaction_search
відбудеться відправка запиту на термінал.Звертаємо увагу що навідміну від ПРРО, по терміналам зберігається результат виконання операції, тобто можуть як успішні оплати чи інші операції так і помилки при з'єднанні з терміналом або помилки від самого терміналу.
Кожна операція з цього списку буде обов'язково мати transaction_id
.
1) Оплата ("task": 1
)
2) Повернення по оплаті("task": 2
)
3) Скасування операції на терміналі ("task": 3
)
4) P2P переказ ("task": 4
);
5) Універсальний сервіс. ("task": 5
);
6) Запит на зчитування карти з подальшим очікуванням підтвердження/корекцією. ("task": 6
);
7) Завершення запиту підтвердження/корекції ("task": 7
);
8) Зчитування дисконтної карти ("task": 8
);
9) X-Баланс. Друк підсумків без закриття батчу. ("task": 10
);
10) Загальний звіт. Закриття батчу та друк підсумків. ("task": 11
);
11) Видача коштів. Оплата товару/послуги + видача готівки. ("task": 14
);
12) Оформлення оплати частинами. ("task": 15
);
13) Повернення по оплаті частинами. ("task": 16
);
14) Отримання проведеної раніше операції по терміналу або отримання останньої операції ("task": 17
).
Тип відправленого завдання, додатково до значення transaction_id
, не перевіряється, так само як і в ПРРО.
Всі інші операції (наприклад отримання списку мерчантів) не мають transaction_id
- виконуються кожного разу з новими даними, тому реалізація повторних запитів для них не потрібна.
Для цього використовується окремий функціонал отримання проведеної раніше операції по терміналу або отримання останньої операції ("task": 17
).
При роботі в пакетному режимі також допускається і рекомендується використання ключа tag
, але при цьому не використовуються значення transaction_id
та transaction_search
як при роботі з терміналами окремо.
Процес виглядає наступним чином:
tag
на співпадіння з раніше проведеними операціями по ПРРО."skipprint": true
.Звертаємо увагу що по ключам tag
для ПРРО та transaction_id
для терміналів можна отримати лише дані які збережені локально в базі даних Device Manager, якщо локально даних немає - їх буде не можливо отримати.
Стандартно чеки зберігаються за останні 40 днів, а операції з терміналами за останні 90 днів.
Налаштуваннями часу збереження можна керувати через сторінку налаштування в ДМ.
Рекомендовано дотримуватись передачі значень в JSON body запиту у типі даних визначеному в описі API. Наприклад якщо передбачається JSON number значення для параметру "sum"
значення має бути, наприклад, 23.44
.
При серіалізації/десеріалізації JSON при обробці запиту всередині застосунку можливі наступні варіації:
"24.33"
без помилок. Пусте значення можна передавати через ""
..
) може конвертуватись в number 24.33
без помилок.[]
Якщо передати будь яке інше значення, наприклад в "code_aa": ""
коли для code_aa
очікується array - це викличе помилку.
Ці нюанси потрібно врахувати при розробці рішення.