Робота з ПРРО (черга фіскалізації)
Документ описує як Каса фіскалізує чеки, операції з готівкою та зміни на сервері податкової (ДПС) через Абхард, а також дії касира у типових ситуаціях.
Початок роботи
Щоб каса могла працювати з РРО, потрібно у конфігурації профілю вказати ІД з таблиці R_RRO та мати активний абхард з активним же roo як у прикладі нижче:
---
location:
rro: 1
abhard:
enabled: true
url: http://192.168.12.34:4601/
rro:
enabled: true
type: eusign
name: default_prro
При запуску каси у такому випадку відпрацьовує ініціалізація ПРРО що складається з наступних кроків:
- Отримати інформацію про підприємця на котрого зареєстровано ПРРО і додати її у заголовок.
- Перевірити чи є незакрита попередня фіскальна зміна, уточнити у користувача що з нею робити.
- Перевірити чи є активна фіскальна зміна, отримати інформацію про неї якщо є.
- Запустити фоновий потік для роботи з фіскальними документами.
Вся робота з фоновими документами зараз ведеться виключно через фоновий потік, окремий підпроцес всередині каси що запускається при старті і працює весь час поки запущена програма.
Коли користувач створює новий фіскальний документ - чек продажу, повернення, сторно, службова видача/внесення готівки, відкриття/закриття зміни, Z-звіт - цей документ спершу записується у таблицю RRO_DOCS з параметрами DOC_STATUS=0, LAST_ERROR_KIND=0, та LAST_ATTEMPT_AT=NULL після чого фоновому потоку віддається сигнал "до роботи" і каса готова для подальшої взаємодії з користувачем.
Фіскалізація чеку
- Касир натискає «Фіскалізувати чек».
- Каса вставляє новий рядок у
RRO_DOCS(DOC_STATUS = 0) та чекає на відповідь до 2 секунд. - У штатній ситуації за цей час сервер ДПС встигає відповісти,
DOC_STATUSстає1, чек друкується разом з фіскальним номером. - Якщо сервер не відповів за 2 секунди — Каса показує повідомлення «Сервер ДПС не відповів за відведений час. Документ у черзі.» Касир продовжує роботу. Документ залишається в
RRO_DOCSзі статусом0і буде надісланий автоматично коли сервер відповість. У інтерфейсі каси з'являється кнопка роботи з чергою фіскалізації і повідомлення(у черзі ДПС: N; причина)деN— кількість документів у черзі, апричина— категорія проблеми верхнього документа (мережа,ВІДХИЛЕНО,внутрішня помилка).
Послідовність взаємодії
Діаграма нижче показує два можливих шляхи фіскалізації чеку — швидкий (сервер ДПС відповідає за відведені 2 секунди) і відкладений (відповідь не встигла надійти, документ залишається у черзі).
%%{init: {'sequence': {'actorFontSize': 18, 'messageFontSize': 16, 'noteFontSize': 15}}}%%
sequenceDiagram
autonumber
actor Касир
participant UI as Каса (UI)
participant DB as RRO_DOCS
participant Worker as Фоновий потік
participant Abhard
participant ДПС
Касир->>UI: Натиснути «Фіскалізувати чек»
UI->>DB: INSERT (DOC_STATUS=0, KIND=0)
UI->>Worker: Kick (TEvent)
UI->>UI: WaitForCompletion (≤ 2 с)
Worker->>DB: SELECT найстаріший pending
Worker->>DB: Згенерувати XML (RRO_CHECK)
Worker->>Abhard: RegisterDocument(XML)
Abhard->>ДПС: Передати документ
alt Швидкий шлях (відповідь за ≤ 2 с)
ДПС-->>Abhard: OrderTaxNum
Abhard-->>Worker: OrderTaxNum
Worker->>DB: UPDATE ordertaxnum,<br/>DOC_STATUS=1, KIND=10
Worker->>UI: SignalCompletion (TEvent)
UI-->>Касир: Друк чеку з фіск. номером
else Відкладений шлях (таймаут UI)
UI-->>Касир: «Документ у черзі»<br/>(показати btnFiscalQueue)
Note over Worker,ДПС: Спроби тривають у фоні
ДПС-->>Abhard: OrderTaxNum (пізніше)
Abhard-->>Worker: OrderTaxNum
Worker->>DB: UPDATE ordertaxnum,<br/>DOC_STATUS=1, KIND=10
Worker->>UI: UIRefresh (оновити лічильник черги)
end
Робота при недоступності серверів ДПС
Якщо сервери податкової недоступні, каса продовжує приймати документи у чергу фіскалізації. Кожна нова фіскалізація додає рядок у RRO_DOCS. Паралельно фоновий потік кожні 5 секунд повторює спроби фіскалізації поки сервер не відповість. Як тільки зв'язок відновлюється, черга обробляється підряд від найстарішого документа (з найменшим LOCALNUM); кожен документ реєструється одразу після попереднього.
Обмеження: одночасно в черзі може накопичитися до 10 нефіскалізованих документів на зміну. Це запобіжник від нескінченного росту черги при тривалій недоступності.
Робота декількох екземплярів Каси з одним ПРРО
З одним ПРРО можуть одночасно працювати декілька екземплярів Каси, що підключені до однієї бази даних. Це штатний сценарій — наприклад, два робочих місця касирів у магазині, що ділять один реєстратор. Координація між екземплярами повністю автоматична, без додаткових налаштувань.
Гарантії
- Один лідер на ПРРО в кожний момент часу. Кожна Каса має свій фоновий потік, але реально надсилає документи до Абхард тільки той, що тримає оренду в таблиці
RRO_DRAIN_LEASE. Інші просто очікують. Це виключає одночасне надсилання одного й того самого документа двома Касами та потенційні проблеми з подвійними нарахуваннями у ДПС. LOCALNUMзростає глобально. ЛічильникRRO_LOCALNUM_SEQ.LAST_NUMспільний для всіх екземплярів та оновлюється під час вставки вRRO_DOCS. Якщо Каса A вставила документ зLOCALNUM = 17, наступна вставка від Каси B отримаєLOCALNUM = 18, незалежно від того, чи був документ A надісланий до ДПС.- Автоматичне перебирання оренди. Якщо лідер «впав» (програма закрилася, машина перезавантажена, мережа зникла) — оренда автоматично переходить до іншого екземпляра не пізніше ніж за 30 секунд. Перевірка живості йде через службовий функціонал Firebird
mon$attachments.
Сценарій недоступності серверів ДПС
Розглянемо типовий сценарій з двома Касами A та B, обидві фіскалізують чеки, ДПС недоступний:
- Касир A натискає «Фіскалізувати чек». Каса A вставляє рядок у
RRO_DOCS, ловить таймаут на надсиланні, показує повідомлення «Документ у черзі», з'являється кнопкаbtnFiscalQueue. - Каса A стає лідером оренди (бере її першою) і періодично повторює надсилання у фоні.
- Касир B натискає «Фіскалізувати чек» на іншому робочому місці. Каса B вставляє свій рядок у
RRO_DOCS(з наступнимLOCALNUM), ловить такий самий таймаут, показує повідомлення «Документ у черзі». Тільки в цей момент касир B бачить, що мережа з ДПС зараз не працює. - Каса B спробує надіслати свій документ власним потоком, але оренда зайнята Касою A → потік B нічого не робить, лежить у режимі очікування.
- Коли ДПС повертається, Каса A послідовно реєструє свої документи, потім доходить до документа Каси B і так само реєструє його.
LOCALNUM-послідовність зберігається.
Чого Каса B не побачить автоматично
За винятком створення нової зміни (котре зараз автоматично "бачиться" всіма касами що працюють з одними і тим же ПРРО), решта індикаторів інтерфейсу оновлюється лише за власними діями кожної Каси. Поки касир B нічого не фіскалізує, інтерфейс Каси B не показує, що в Каси A з'явилась черга. Лічильник (у черзі ДПС: N) оновлюється тільки після власних дій касира B або після успішного кроку власного фонового потоку Каси B (коли B стане лідером оренди).
Особливість відкриття зміни
Якщо при першій фіскалізації дня зміна ще не відкрита, Каса відкриває її автоматично. Рядок у RRO_SHIFTS створюється одразу, тому навіть якщо сервер ДПС не підтвердив відкриття за 5 секунд, зміна локально вважається відкритою і касир може продовжити роботу. Документ відкриття зміни просто додається у чергу і буде надісланий разом з рештою документів коли зв'язок відновиться.
Як зрозуміти що пішло не так
Разом з чергою фіскалізації у касі з'являється кнопка для її перегляду та при потребі - очищення. Поля бази даних LAST_ERROR_KIND та LAST_ERROR_MSG верхнього документа черги (найменший LOCALNUM з
статусом DOC_STATUS = 0) мають наступні значення:
LAST_ERROR_KIND = 0— запис ще не опрацьовувався (спроб реєстрації не було).LAST_ERROR_KIND = 1(мережа) — Абхард не може зв'язатися з ДПС. Перевірте інтернет на робочому місці Абхард, статус серверів ДПС.LAST_ERROR_KIND = 2(відхилено) — ДПС відхилив документ. Текст уLAST_ERROR_MSG— це повідомлення від податкової.LAST_ERROR_KIND = 3(внутрішня помилка) — проблема у Касі або Абхарді, перевірте журнали обох застосунків. Текст уLAST_ERROR_MSG— це повідомлення від Абхарда.LAST_ERROR_KIND = 10— документ успішно зареєстровано (відповідаєDOC_STATUS = 1).
Проміжок між 3 і 10 залишено для майбутніх категорій помилок.
Поле LAST_ATTEMPT_AT містить момент останньої спроби фіскалізації.
Після успішної фіскалізації поле LAST_ERROR_MSG очищується.