Skip to content

Робота з ПРРО (черга фіскалізації)

Документ описує як Каса фіскалізує чеки, операції з готівкою та зміни на сервері податкової (ДПС) через Абхард, а також дії касира у типових ситуаціях.

Початок роботи

Щоб каса могла працювати з РРО, потрібно у конфігурації профілю вказати ІД з таблиці R_RRO та мати активний абхард з активним же roo як у прикладі нижче:

---
location:
  rro: 1
abhard:
  enabled: true
  url: http://192.168.12.34:4601/
  rro:
    enabled: true
    type: eusign
    name: default_prro

При запуску каси у такому випадку відпрацьовує ініціалізація ПРРО що складається з наступних кроків:

  1. Отримати інформацію про підприємця на котрого зареєстровано ПРРО і додати її у заголовок.
  2. Перевірити чи є незакрита попередня фіскальна зміна, уточнити у користувача що з нею робити.
  3. Перевірити чи є активна фіскальна зміна, отримати інформацію про неї якщо є.
  4. Запустити фоновий потік для роботи з фіскальними документами.

Вся робота з фоновими документами зараз ведеться виключно через фоновий потік, окремий підпроцес всередині каси що запускається при старті і працює весь час поки запущена програма. Коли користувач створює новий фіскальний документ - чек продажу, повернення, сторно, службова видача/внесення готівки, відкриття/закриття зміни, Z-звіт - цей документ спершу записується у таблицю RRO_DOCS з параметрами DOC_STATUS=0, LAST_ERROR_KIND=0, та LAST_ATTEMPT_AT=NULL після чого фоновому потоку віддається сигнал "до роботи" і каса готова для подальшої взаємодії з користувачем.

Фіскалізація чеку

  1. Касир натискає «Фіскалізувати чек».
  2. Каса вставляє новий рядок у RRO_DOCS (DOC_STATUS = 0) та чекає на відповідь до 2 секунд.
  3. У штатній ситуації за цей час сервер ДПС встигає відповісти, DOC_STATUS стає 1, чек друкується разом з фіскальним номером.
  4. Якщо сервер не відповів за 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, обидві фіскалізують чеки, ДПС недоступний:

  1. Касир A натискає «Фіскалізувати чек». Каса A вставляє рядок у RRO_DOCS, ловить таймаут на надсиланні, показує повідомлення «Документ у черзі», з'являється кнопка btnFiscalQueue.
  2. Каса A стає лідером оренди (бере її першою) і періодично повторює надсилання у фоні.
  3. Касир B натискає «Фіскалізувати чек» на іншому робочому місці. Каса B вставляє свій рядок у RRO_DOCS (з наступним LOCALNUM), ловить такий самий таймаут, показує повідомлення «Документ у черзі». Тільки в цей момент касир B бачить, що мережа з ДПС зараз не працює.
  4. Каса B спробує надіслати свій документ власним потоком, але оренда зайнята Касою A → потік B нічого не робить, лежить у режимі очікування.
  5. Коли ДПС повертається, Каса 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 очищується.