Перейти до вмісту

Інтеграція РРО в Python

Матеріал з K2 ERP Wiki

щоб оперативно реагувати на проблеми з папером, зв'язком, портом, драйвером або фіскалізацією.; "amount": 500.00,

18.5.; X-звіт

timeout_seconds: int = 30

|- | external_order_id | string | ID замовлення у K2 ERP / POS.; float(item ["price"]),

25. MVP

timeout=self.timeout,
; Черга, журнал, дедублікація

19.3.; Приклад Serial-драйвера

істотно: МІНІ-ФП54.01 має обмеження на кількість символів у рядку та в назві товару.; | Dashboard показує помаранчеве попередження.; | РРО друкує X-звіт без закриття зміни.; Продаж / повернення / службова операційна дія

7.3.; Відкриття зміни

2.; Колір

</syntaxhighlight>

; характеристика
|-
| AC-1
| Адміністратор налаштовує РРО.; |-
| style="background:#f3e5f5;" | Фіолетовий
| #f3e5f5
| Повернення або спеціальна операційна дія.;<pre>

* уже фіскалізованого чека;
* повернення понад доступну суму;
* некоректної суми;
* помилки фіскальної пам'яті;
* невідомого стану, коли неможливо визначити, чи чек уже надруковано.; |-
| connection_type
| varchar
| OLE_DLL, SERIAL, USB_COM.; | Відкрити зміну, якщо дозволено.; Код

 "idempotency_key": "CASH-IN-2026-05-07-001"

=== Етап 2.; Локальний Python Agent ===
 "name": "Товар 1",
=== 8.2.; Перевірка стану РРО ===

18.7.; Чек повернення

</syntaxhighlight>
|-
| original_receipt_id
| uuid
| Внутрішній ID первинного чека.; |
 | 3.; |-
| device_model
| string
| Так
| МІНІ-ФП54.01.; {| class="wikitable"

!; |-
| serial_number
| varchar
| Серійний номер.; | Помилка РРО, порт недоступний, фіскальна помилка.; Worker друкує чек.; |-
| idempotency_key
| varchar
| Ключ дедублікації.; |-
| Чек повернення
| Високий
| Фінансова операційна дія.; |-
| tax_group
| varchar
| Податкова група.; import serial
 pass
 pass
<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
Приклад:
== 26.; Етапи реалізації ==
!; |-
| fiscal_number
| string
| Так
| Фіскальний номер РРО.; Значення

 def send_command(self, command: bytes) -> bytes:

 ole_progid: str | None = None
Покупець / чекова стрічка
</syntaxhighlight>
|-
| CASH_IN
| Службове внесення готівки.; |-
| AC-13
| Касир формує Z-звіт.;=== 18.3.; Відкриття зміни ===
"price": 70.00,

Python відкриває COM-порт і відправляє команди згідно з протоколом обміну.; Ключ

; характеристика
@abstractmethod
response = self.send_command(command)
- CoverOpenError Кришка відкрита.; Компонент - Z Report - Python Agent - shift_id uuid }
def connect(self) -> None:
style="background:#eeeeee;" | Сірий
Заблоковано BLOCKED - AC-12 style="background:#bbdefb;" | Блакитний
Друкується PRINTING }
}
8.; |-
external_payment_id - Python-підхід style="background:#c8e6c9;" | Зелений
Зміна закрита SHIFT_CLOSED style="background:#ffcc80;" | Помаранчевий
Відкрита кришка COVER_OPEN - raw_command text/jsonb - Дублювання чеків class="wikitable" </syntaxhighlight>
def get_status(self) -> dict:

12.2.; Рекомендований стек агента

19.1.; Абстрактний інтерфейс драйвера

def print_refund_receipt(self, payload: "RefundReceiptPayload") -> "ReceiptResponse":

Endpoint:

8.6.; Чек повернення

self.serial = None
  • підключення до РРО через USB, RS232 або драйвер;
  • роботу через OLE/DLL-бібліотеку виробника або прямий протокол обміну;
  • перевірку стану РРО;
  • відкриття касової зміни;
  • друк і фіскалізацію чека продажу;
  • друк і фіскалізацію чека повернення;
  • службове внесення готівки;
  • службове винесення готівки;
  • формування X-звіту;
  • формування Z-звіту;
  • друк нефіскального тексту, якщо підтримується;
  • програмування товарів, податкових груп, касирів — якщо потрібно;
  • контроль помилок РРО;
  • журналювання команд і відповідей;
  • захист від дублювання чеків;
  • повторну обробку технічних помилок;
  • інтеграцію з K2 ERP / POS / CRM / сайтом.; |-
Акумулятор - status varchar - Чек повернення Первинний чек, сума, причина.; №
def open_shift(self, cashier_id: str) -> "ShiftResponse":

!; |-
| model
| varchar
| MINI_FP54_01.; | Dashboard, нагадування, блок попереджень.; Чек потрапляє в чергу друку.; Worker перевіряє стан РРО.; | style="background:#fff9c4;" | Жовтий
|-
| Відправляється на РРО
| SENDING_TO_RRO
| Команда передається в драйвер або COM-порт.; | Зупинити друк, показати помаранчевий статус.; Статус

POST /api/v1/rro/receipts/sale

'''Управлінський результат:''' керівник повинен бачити, скільки чеків надруковано, скільки повернень виконано, які зміни відкриті, які Z-звіти сформовані, які РРО мають помилки зв'язку або потребують уваги.; Колір

Логіка:
<syntaxhighlight lang="python">
 connection_type: str = "OLE_DLL"

POST /api/v1/rro/receipts/{receipt_id}/retry

 return {"raw": result}

{| class="wikitable"
платформа повинна не допускати дублювання чеків.; | РРО закриває зміну.; Python Agent повинен уміти перевіряти:
POST /api/v1/rro/reports/x
 "print_qr": true
<pre>
 self.device.Sale(
!; Час
1.;== 6.; Основні сутності ==

 for payment in receipt ["payments"]:
!; # Чи потрібно інтегрувати агент із K2 ERP?; |-
| style="background:#bbdefb;" | Блакитний
| #bbdefb
| операційна дія виконується.; OLE/DLL або Serial Protocol
=== 16.2.; Пріоритети ===
 def open_shift(self, cashier_id: str) -> dict:
 |
 | 4.; |-
| is_active
| boolean
| Активність.; Поле

!; | style="background:#ffcc80;" | Потрібна дія
|-
| Незакриті зміни
| Відкриті зміни без Z-звіту.; |}

!; Реальні назви методів, параметри та коди відповідей потрібно взяти з актуального керівництва програміста / OLE-сервера виробника.; # Чи потрібен централізований dashboard по декількох торгових точках?; * ПЗ Uniq Commander.; Призначення
}
 "type": "CARD",
|-
| id
| uuid
| ID зміни.; Що зберігати
<pre>

Ключі дедублікації:

 import win32com.client
=== 21.3.; Проблемні операції ===
!; |}

!; |-
| Підключення до ПК
| USB, RS232.; | Другий чек не друкується.; |-
| ConnectionError
| Немає зв'язку з РРО.; |-
| Відкриття зміни
| Касир, час, відповідь РРО.; Дія
 result = self.device.CloseReceipt()
|-
| Чек продажу
| Високий
| Основна операційна дія.; ERP надсилає йому HTTP-запити.; | Критична помилка, заборонити друк.; |-
| ShiftClosedError
| Зміна закрита.; |}

 "cashier_id": "cashier-001",

<div style="border-left: 6px solid #2e7d32; background: #e8f5e9; padding: 12px 16px; margin: 16px 0;">

* тимчасової втрати зв'язку;
* зайнятого COM-порту;
* timeout;
* тимчасової помилки драйвера;
* очікування готовності РРО;
* відновлення після відсутності паперу, якщо чек не був завершений.; №
{{SEO
|title=Технічне завдання: Інтеграція РРО МІНІ-ФП54.01 для Python
|description=Технічне завдання на реалізацію Python-сервісу для інтеграції з фізичним фіскальним реєстратором МІНІ-ФП54.01: продажі, повернення, відкриття та закриття зміни, X/Z-звіти, службове внесення/винесення, драйвер, COM/OLE/DLL, USB/RS232, черги, статуси та журналювання.
|keywords=Python, РРО, МІНІ-ФП54.01, MINI-FP54.01, фіскальний реєстратор, Юнісістем, USB, RS232, OLE, DLL, FastAPI, POS, K2 ERP, фіскальний чек, Z-звіт, X-звіт
}}
!; def __init__(self, ole_progid: str):

=== 24.4.; Зміни та звіти ===

=== Етап 7.; Production hardening ===
<syntaxhighlight lang="json">
 return {"raw": response.hex()}
{| class="wikitable"
</div>
 command = b"X_REPORT_COMMAND_PLACEHOLDER"
=== 7.1.; Продаж ===
!; Параметр
{| class="wikitable"
1.; |}

<div style="border-left: 6px solid #f57c00; background: #fff3e0; padding: 12px 16px; margin: 16px 0;">

 pass

!; self.serial.write(command)
 "unit": "послуга"
=== Варіант 3.; 4.3.; Локальний Python Agent + ERP API ===

</div>
 "department": 1,
 log_raw_commands: bool = True

Central Fiscal API
!;== 2.; Область сфера застосування ==
== 12. Python RRO Agent ==

 self.device = None

виконати команду відкриття зміни виступає ключовою рисою 4.; Перевірити підключення до РРО.; | Refund, службові операції.; | Черга чеків, очікування друку.; {| class="wikitable"
 return {"raw": result}
я хочу сформувати Z-звіт, 
 pass
 def x_report(self) -> dict:
!; |-
| original_fiscal_number
| string
| Фіскальний номер первинного чека, якщо доступний.; Код
|-
| AC-15
| Керівник відкриває dashboard.; Критерій
=== 18.2.; Перевірка стану РРО ===
|-
| ValidationError
| Некоректні інформаційні дані чека.; |-
| entity_id
| uuid
| ID сутності.; |}

 def get_status(self) -> "RROStatus":

Як касир, 
 "tax_group": "NO_VAT",
 port=self.port,
!; |-
| cashier_id
| string
| Ні
| Касир за замовчуванням.; |-
| CASH_OUT
| Службове винесення готівки.; |}

!; # Чи потрібна локальна БД на касовому ПК?; |}

<pre>

 pass
'''Критично істотно:''' якщо після збою неможливо визначити, чи чек був надрукований, платформа повинна перевести операцію в статус MANUAL_REVIEW, а не автономно друкувати повторно.;== 29.; Джерела ==

* приймати HTTP-запити від K2 ERP / POS;
* керувати РРО;
* виконувати друк чеків;
* повертати статуси;
* зберігати локальний журнал;
* працювати навіть при тимчасовій недоступності центральної системи, якщо це дозволено сценарієм;
* синхронізувати результати з центральною БД.; | style="background:#eeeeee;" | Сірий
|-
| Очікує друку
| PENDING
| Чек у черзі на друк.; # Чи потрібно програмувати податкові ставки з Python?; Перевірити, чи зміна вже відкрита.; |-
| error_message
| text
| Помилка.; |-
| Немає паперу
| Чек не має змогу бути надрукований.; Тип

Retry дозволений для:
 {
=== 4.1.; Варіант 1.; Через OLE/DLL-бібліотеку виробника ===
|-
| Підходить для
| Windows POS, касових робочих місць, локальної інтеграції.; |-
| external_order_id
| varchar
| ID замовлення.; характеристика
== 23.; Логування та аудит ==

 pass

 pass
5.; |-
| DuplicateReceiptError
| Чек уже надруковано.; def get_status(self) -> dict:
 "idempotency_key": "ORDER-2026-000123-PAY-123456",
{| class="wikitable"

 "amount": 70.00,

[[Категорія:МІНІ-ФП54.01]]

щоб коректно повернути кошти покупцю та відобразити операцію в РРО.; |}

 pass

{| class="wikitable"
!; * [[Python]]
* [[FastAPI]]
* [[K2 ERP]]
* [[РРО]]
* [[Фіскальний реєстратор]]
* [[МІНІ-ФП54.01]]
* [[Фіскальний чек]]
* [[Касова зміна]]
* [[Z-звіт]]
* [[X-звіт]]
* [[POS]]
* [[USB]]
* [[RS232]]
* [[OLE]]
* [[DLL]]
* [[COM-порт]]

 v
!; | Повторити після паузи або заблокувати чергу.; Поле

{| class="wikitable"
 @abstractmethod
 |
 | 1.; Ризик
<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
щоб агент надрукував і фіскалізував чек на МІНІ-ФП54.01.; |-
| items
| array
| Позиції чека.; характеристика
== 20.; Обробка помилок ==
платформа повинна логувати:
 "amount": 570.00,
!; |}

!; Значення
 retry_backoff_seconds: int = 3
=== 18.4.; Закриття зміни / Z-звіт ===
 def close_shift(self) -> "ZReportResponse":
5.; Для serial-інтеграції обов'язково потрібен офіційно затверджений протокол обміну з точним форматом команд, відповідей, кодування та контрольних сум.; Локальний endpoint:
=== 24.3.; Повернення ===
def sale_receipt(self, receipt: dict) -> dict:
; РРО
def open_shift(self, cashier_id: str) -> dict:

щоб мати можливість друкувати фіскальні чеки.; {| class="wikitable"

pass
pass
; Очікуваний результат
item ["tax_group"],
pass
Готовий READY }
@abstractmethod
def service_cash_out(self, amount: float, comment: str | None = None) -> "ServiceOperationResponse":

істотно: для МІНІ-ФП54.01 виробник надає USB-драйвер, OLE/DLL-бібліотеку для фіскальних реєстраторів, інструкції та документи щодо протоколу обміну.; Поле

- Python-підхід Перевести чек у CONNECTION_ERROR або NEEDS_RETRY.; Тип ; Тип задачі
v
{

Python взаємодіє з OLE/COM або DLL-бібліотекою, яку надає виробник.; |-

device_id uuid - Грошова скринька style="background:#eeeeee;" | Сірий
Повернення REFUNDED - items array - new_status varchar style="background:#ef9a9a;" | Червоний
Потребує повтору NEEDS_RETRY Операцію можна повторити.; Показник

16.1.; Логіка черги

POST /api/v1/rro/service-operation

def close_shift(self) -> dict:

Мінімальні інформаційні дані: MINI_FP54_CONNECTION_TYPE=OLE_DLL

18.1.; Перевірка стану агента

return {"raw": result}
;
AC-8 платформа показує DISCONNECTED червоним кольором.; | Повернути існуючий результат.; |- AC-10 - DriverError Помилка OLE/DLL/драйвера.; Поле

Критично істотно: Z-звіт є собою операцією закриття зміни.;=== 12.3.; Методи Python RRO Client ===

  • реалізувати dashboard API;
  • реалізувати список помилок;
  • реалізувати синхронізацію з K2 ERP;
  • реалізувати експорт журналу, якщо потрібно.; | style="background:#ef9a9a;" | Червоний
Помилка з'єднання CONNECTION_ERROR - Cashier Касир, від імені якого виконується операційна дія.;
RRO Device Фізичний фіскальний реєстратор МІНІ-ФП54.01.; Передача даних до ДПС самим РРО
def x_report(self) -> dict:
- raw_close_response jsonb/text Друкується чек повернення.;
== 7. User Story ==


=== Етап 4.; Чеки ===
!; Виконати команду формування Z-звіту.; | Зупинити друк, чек лишити в NEEDS_RETRY.; |-
| auto_open_shift
| boolean
| Так
| автономно відкривати зміну перед першим чеком.; |-
| AC-9
| Сума повернення перевищує продаж.; характеристика

</div>

Local Python RRO Agent

 "operation_type": "CASH_IN",
{| class="wikitable"
!; | style="background:#ffcc80;" | Помаранчевий
|-
| Скасовано
| CANCELLED
| Операцію скасовано до друку.; |}

 "tax_group": "VAT_20",

Endpoint:
 pass
|-
| AC-11
| Касир відкриває зміну.; | Використовувати OLE/DLL або отримати документацію виробника.;== 9.; Статуси чеків ==
 self.device = win32com.client.Dispatch(self.ole_progid)
 "sku": "DELIVERY",

sha256(external_order_id + total_amount + payment_id + device_serial_number)

MINI_FP54_TIMEOUT_SECONDS=30
MINI_FP54_BAUD_RATE=115200
'''Рекомендована схема для K2 ERP:''' K2 ERP не повинна напряму керувати COM-портом.; Колір
<pre>
=== 17.2. rro_shifts ===

 def print_non_fiscal_text(self, lines: list [str]) -> "PrintResponse":

</pre>
=== 20.2.; Retry-логіка ===
 "quantity": 2,

'''Критично істотно:''' чек повернення не повинен перевищувати залишок по первинному чеку.; |-
| receipt_id
| uuid
| ID чека.; | Чек друкується і переходить у FISCALIZED.; {| class="wikitable"
{| class="wikitable"

=== 21.2.; Приклад dashboard ===
=== Етап 1.; Аналіз драйвера та протоколу ===
<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">

я хочу відкрити зміну на РРО, 
!; return {"raw": response.hex()}
=== 12.1.; Призначення ===
== 4.; Варіанти інтеграції Python з РРО ==
|-
| Перевірка РРО
| Статус, помилки, час.; Тип
7.; Він повинен повернути результат уже виконаної операції.; характеристика
class MiniFP54Client:
!; |-
| PaperOutError
| Немає паперу.; |-
| переважні аспекти
| Використання офіційної бібліотеки виробника.; # Чи буде декілька РРО на одному ПК?; |-
| price
| numeric
| Ціна.; |-
| com_port
| string
| Ні
| як ілюстрація COM3.; Передати результат у K2 ERP.; def connect(self) -> None:

 def sale_receipt(self, receipt: dict) -> dict:
=== 24.1.; Підключення ===
!;== 11.; Єдина логіка кольорів ==

 ],

* фізичних магазинів;
* аптек;
* кафе, барів, ресторанів;
* кіосків;
* торгових точок із обмеженим простором;
* виїзної торгівлі;
* кур'єрської доставки;
* інтернет-магазинів із друком фіскального чека на фізичному РРО;
* POS-вузлів, де потрібна робота з реальним фіскальним реєстратором.; result = self.device.XReport()
!; |-
| FiscalMemoryError
| Помилка фіскальної пам'яті.; |}

 pass

{| class="wikitable"

* чи підключений РРО;
* чи доступний порт;
* чи доступний драйвер/OLE/DLL;
* чи є собою папір;
* чи відкрита кришка;
* чи є собою помилки живлення;
* чи є собою зв'язок з ДПС через канали пристрою;
* чи відкрита зміна;
* чи не заблокований РРО;
* чи не переповнена пам'ять;
* чи коректно встановлена дата і час;
* чи готовий РРО до друку чека.; Параметр

</div>
!; Краще використовувати локальний Python Agent біля РРО, а K2 ERP функціонує з ним через API.; Закрити локальну зміну.; Результат зберігається локально.; # Які типи оплат підтримуються: готівка, картка, змішана оплата?; "payment_id": "PAY-123456"
 @abstractmethod
[[Категорія:РРО]]
!; |-
| PortBusyError
| COM-порт зайнятий.; |-
| Службова операційна дія
| Тип, сума, касир.; |-
| Refund Receipt
| Чек повернення.;=== Етап 6.; Dashboard і синхронізація ===

* реалізувати sale receipt;
* реалізувати refund receipt;
* реалізувати валідацію;
* реалізувати дедублікацію;
* реалізувати чергу друку.; | платформа блокує операцію.; Пріоритет

!; Замовлення

Як керівник або адміністратор, 
Типи:
def connect(self) -> None:
; Коментар Dashboard, список чеків, статус РРО.; Python Agent виконує валідацію.; | Заборонити паралельний доступ.; |- device_serial_number string Так }

Retry заборонений для:

Мінімальні інформаційні дані:

 self.device.Payment(payment ["type"], float(payment ["amount"]))

== 1.; Мета ==

=== 18.6.; Чек продажу ===
== 16.; Черга друку ==
 "external_order_id": "ORDER-2026-000123",
|-
| Підходить для
| Глибокої інтеграції, Linux/Windows-сценаріїв, embedded POS.; |-
| com_port
| varchar
| COM-порт.; |-
| print_qr
| boolean
| Чи друкувати QR-код.; self.device.OpenReceipt(0)

* https://unisystem.ua/catalog/fiskalnye-registratory/fiskalnyj-registrator-mini-fp54-01/
* Інструкція з експлуатації МІНІ-ФП54.01.; характеристика
!; |-
| event_type
| varchar
| Тип події.; Статус
!; POST /api/v1/rro/service-operation
|-
| AC-4
| POS передає продаж.; # Чи потрібно програмувати товари в РРО?; Параметр

До MVP входить:

; Критерій
  • отримати проміжний звіт без закриття зміни;
  • перевірити обороти;
  • перевірити стан каси;
  • показати керівнику поточні підсумки.; Перевірити підключення до РРО.; # На якій ОС працюватиме касовий ПК: Windows чи Linux?; Критично істотно: перед друком фіскального чека агент повинен перевірити готовність РРО.; |-
Нефіскальний друк Низький - current_shift_id uuid Поточна зміна.; ; Поле ; Стан
def service_cash_in(self, amount: float, comment: str | None = None) -> "ServiceOperationResponse":

K2 ERP / POS / CRM / Website

return {"raw": result}
}
Вони підсвічуються помаранчевим.; pass

я хочу створити чек повернення,

</div>
 def __init__(self, port: str, baud_rate: int, timeout: int = 30):
 def print_sale_receipt(self, payload: "SaleReceiptPayload") -> "ReceiptResponse":

 command = b"STATUS_COMMAND_PLACEHOLDER"

from abc import ABC, abstractmethod
POST /api/v1/rro/reports/x
!; |-
| ole_progid
| varchar
| ProgID OLE.; характеристика
Він повинен:
<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">

class MiniFP54OleDriver(RRODriver):

2.; |-
| customer
| object
| інформаційні дані покупця, якщо потрібні.; |-
| payments
| array
| Оплати.; |-
| Передача даних у ДПС
| Через Ethernet або GSM/GPRS-модем.; |-
| payments
| array
| Сума повернення.; |-
| AC-2
| Python Agent перевіряє статус РРО.; |-
| baud_rate
| integer
| Ні
| Швидкість порту, якщо застосовують, коли потрібно serial.; POS / K2 ERP надсилає запит на чек.; |-
| z_report_number
| varchar
| Номер Z-звіту.; | style="background:#e3f2fd;" | відомості
|-
| Фіскалізовано
| Кількість успішних чеків.; |-
| error_message
| text
| Повідомлення помилки.; dll_path: str | None = None
 item ["name"],
</pre>
МІНІ-ФП54.01

 def print_x_report(self) -> "XReportResponse":
class MiniFP54SerialDriver(RRODriver):
== 14.; Валідація чека ==
 if self.serial is None or not self.serial.is_open:

 retry_count: int = 2
 return response
class RRODriver(ABC):
 "name": "Доставка",
</pre>

POST /api/v1/rro/reports/z
=== 20.1.; Типи помилок ===
!; |-
| allow_service_operations
| boolean
| Так
| Дозволити службове внесення/винесення.; | style="background:#ffcc80;" | Помаранчевий
|-
| Помилка фіскальної пам'яті
| FISCAL_MEMORY_ERROR
| Критична помилка.; Критерій
== 15.; Дедублікація ==
|-
| 10:42
| MINI-FP54.01 #001
| ORDER-123
| 570.00
| style="background:#ef9a9a;" | Помилка
| Немає зв'язку з COM-портом
| Перевірити підключення
|-
| 11:05
| MINI-FP54.01 #001
| ORDER-124
| 1200.00
| style="background:#ffcc80;" | Потребує повтору
| Немає паперу
| Замінити папір і повторити
|-
| 12:10
| MINI-FP54.01 #002
| SHIFT-55
| -
| style="background:#ffcc80;" | Зміна відкрита
| Не закрито Z-звіт
| Закрити зміну
|}

{| class="wikitable"

 response = self.send_command(command)

* доступ до локального агента тільки з дозволених IP або через токен;
* HTTPS або локальну захищену мережу;
* авторизацію запитів від K2 ERP / POS;
* розмежування прав: продаж, повернення, X-звіт, Z-звіт, службові операції;
* журнал дій користувачів;
* захист від дублювання чеків;
* заборону прямого доступу до драйвера з кількох процесів;
* шифрування конфігурацій, якщо містять чутливі інформаційні дані;
* маскування персональних даних покупців у логах.; '''істотно:''' прямий протокол потрібно реалізовувати тільки після отримання актуальної документації виробника щодо команд, форматів пакетів, контрольних сум і відповідей РРО.; # Чи потрібна інтеграційні функціональні можливості з банківським POS-терміналом?; Тип
== 18. API Python Agent ==

!; self.connect()

9.; | Виносити інтеграцію в локальний Windows Agent.; | style="background:#f3e5f5;" | Фіолетовий
|}

== 22.; Безпека ==

[[Категорія:Технічні завдання]]
 result = self.device.OpenShift(cashier_id)
!; '''Критично істотно:''' це інтеграційні функціональні можливості з фізичним РРО, а не з хмарним ПРРО.; |-
| quantity
| numeric
| Кількість.; |-
| name
| varchar
| Назва товару.; |-
| AC-14
| Зміна не закрита наприкінці дня.; |-
| ole_progid
| string
| Ні
| ProgID OLE-сервера, якщо застосовується OLE.; | РРО переходить у стан SHIFT_OPEN.; Поле

* наявність external_order_id;
* наявність idempotency_key;
* відсутність уже фіскалізованого чека з таким ключем;
* наявність відкритої зміни або можливість її відкрити;
* готовність РРО;
* наявність паперу;
* відсутність критичних помилок;
* наявність хоча б однієї позиції;
* коректність кількості;
* коректність ціни;
* коректність суми рядка;
* відповідність total_amount сумі товарів і оплат;
* коректність типу оплати;
* коректність податкових груп;
* довжину назви товару;
* довжину рядка чека;
* наявність відділу, якщо він обов'язковий;
* коректність QR-коду, якщо він друкується.; Якщо зміна не відкрита.; |-
| total_amount
| decimal
| Загальна сума.; |-
| RRO Agent
| Локальний Python-сервіс, який керує пристроєм.; |-
| idempotency_key
| string
| Ключ захисту від дублювання.; |-
| Невідомий стан після збою
| Невідомо, чи чек надрукований.; | Немає паперу, кришка, повтор.; # Чи потрібно запускати Python Agent як Windows Service?; # Тут наведено тільки архітектурний приклад.; |}

<pre>
=== 17.5. rro_events ===
POST /api/v1/rro/reports/z

 "total_amount": 570.00,

!; |-
| idempotency_key
| ключовий ключ повторного запиту.; | style="background:#ef9a9a;" | Критично
|-
| Потребують повтору
| Чеки у NEEDS_RETRY.; |-
| style="background:#fff9c4;" | Жовтий
| #fff9c4
| Очікування або попередження.; |-
| style="background:#ef9a9a;" | Червоний
| #ef9a9a
| Критична помилка.; |-
| Bluetooth
| Опція.; |-
| cashier_id
| string
| Касир.; |-
| РРО МІНІ-ФП54.01
| Фізичний пристрій, підключений через USB/RS232.; |-
| AC-16
| є собою помилки РРО.;=== 8.5.; Приклад запиту на чек продажу ===

* реалізувати cash_in;
* реалізувати cash_out;
* реалізувати права доступу;
* реалізувати аудит.; |-
| Кількість касирів
| 32.; HTML
Мова Python 3.11+
API FastAPI
Доступ до COM/OLE pywin32 або comtypes
Доступ до DLL ctypes або cffi
Доступ до COM-порту pyserial
Локальна БД SQLite або PostgreSQL
Черга SQLite queue / Redis / RQ
Логи structlog / logging
Упаковка Windows Service / Docker для Linux-сценаріїв, якщо serial
; for item in receipt ["items"]:
def close_shift(self) -> dict:
"provider": "terminal",
self.baud_rate = baud_rate
- Помаранчевий #ffcc80 - cashier_id varchar Касир.; Критерій

я хочу бачити помилки РРО,

; № - printed_at timestamp - receipt_hash Hash товарів, сум, оплат і каси.;

24. Acceptance Criteria

<pre>
=== 8.1.; конфігурація пристрою ===

</pre>

[[Категорія:Фіскальні реєстратори]]

{| class="wikitable"
{


!; |-
| Кількість товарів
| 16 384.; | Записати raw-помилку, повідомити адміністратора.; Очікуваний результат
 command = b"OPEN_SHIFT_COMMAND_PLACEHOLDER"

4.; |}

[[Категорія:K2 ERP]]

== 19.; Приклад Python-логіки ==
{| class="wikitable"
[[Категорія:Інтеграції]]
6.; Помилка
 self.port = port
<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">

{{DISPLAYTITLE:Технічне завдання: Інтеграція РРО МІНІ-ФП54.01 для Python}}
=== 8.3.; Відкриття зміни ===

!; {
'''істотно:''' назви методів OLE/DLL у прикладі є собою умовними.; Подія
!; |}

 allow_refunds: bool = True

=== 17.1. rro_devices ===
2.; pass
 self.ole_progid = ole_progid
=== 8.9.; Z-звіт ===
<pre>
Python-сервіс повинен працювати через драйвер, COM/OLE/DLL, протокол обміну, USB/RS232 або проміжний локальний агент.; # Чи потрібна офлайн-робота при недоступності центральної ERP?; |-
| payload
| jsonb/text
| інформаційні дані події.; |-
| AC-3
| РРО не підключений.; характеристика
|-
| Немає актуального протоколу
| Без документації неможливо безпечно реалізувати serial-інтеграцію.; платформа повинна забезпечити:

* реалізувати RRODriver interface;
* реалізувати MiniFP54OleDriver або MiniFP54SerialDriver;
* реалізувати check_status;
* реалізувати open_shift;
* реалізувати X/Z-звіти.; |-
| X-звіт
| Час, РРО, відповідь.; |-
| Shift
| Касова зміна.; |-
| RefundLimitError
| Повернення перевищує доступну суму.; | MANUAL_REVIEW замість автоматичного повтору.; | style="background:#ef9a9a;" | Червоний
|-
| Немає зв'язку з ДПС
| TAX_SERVER_CONNECTION_ERROR
| Пристрій не має змогу передати інформаційні дані.; |-
| discount_amount
| numeric
| Знижка.; '''Критично істотно:''' повторний запит із тим самим idempotency_key не повинен друкувати другий фіскальний чек.; Перед відправкою на РРО платформа повинна перевірити:

* створити FastAPI-сервіс;
* реалізувати healthcheck;
* реалізувати локальну БД;
* реалізувати модель пристрою;
* реалізувати логування.; | style="background:#c8e6c9;" | Зелений
|-
| Не підключений
| DISCONNECTED
| Немає зв'язку з пристроєм.; | платформа зменшує доступний залишок до повернення.; pass

інтеграційні функціональні можливості призначена для:
</div>
!; | style="background:#ef9a9a;" | Критично
|}

6.; 6.; Технологія
 return {"raw": response.hex()}
2.; |-
| reason
| string
| Причина повернення.; Повернути результат у K2 ERP / POS.; Результат синхронізується з центральною системою.; |-
| amount
| numeric
| Сума.; |-
| opened_at
| timestamp
| Дата відкриття.; |-
| Обмеження
| Найчастіше потребує Windows, COM/OLE, драйверів і локального доступу до пристрою.; |-
| OLE/DLL функціонує тільки на Windows
| Обмеження для Linux-серверів.; !; Для часткових повернень платформа повинна вести залишок доступної до повернення суми та кількості.; |-
| Швидкість друку
| 8 рядків/с.; |}

'''Критично істотно:''' Ethernet і GSM/GPRS у цій моделі використовуються для передачі даних РРО до ДПС, але інтеграційні функціональні можливості з Python для команд друку чеків зазвичай потребує USB/RS232 або драйвера/OLE/DLL на локальному комп'ютері.; |-
| created_at
| timestamp
| Дата події.; характеристика

* повна реалізація всього протоколу обміну;
* автоматичне програмування всієї номенклатури;
* повний POS UI;
* власна фіскальна логіка замість РРО;
* складна офлайн-синхронізація;
* інтеграційні функціональні можливості з усіма моделями РРО;
* супровід Linux, якщо обрано OLE/DLL для Windows.; command = b"Z_REPORT_COMMAND_PLACEHOLDER"
</pre>
<pre>
 v
 pass
|-
| style="background:#c8e6c9;" | Зелений
| #c8e6c9
| Успішна операційна дія або нормальний стан.; |-
| fiscal_number
| varchar
| Фіскальний номер або номер чека, якщо доступний.; def service_cash_out(self, amount: float, comment: str | None = None) -> dict:

'''Рекомендована технічна архітектура:''' Python POS Adapter функціонує локально на комп'ютері касира або POS-вузлі, має доступ до USB/RS232/COM/OLE/DLL-драйвера та приймає команди від ERP через HTTP API або локальну чергу.; Очікуваний результат
 @abstractmethod
=== 18.9.; Повторити чек ===

=== 8.4.; Чек продажу ===

</div>

ДПС
}
{| class="wikitable"

 @abstractmethod

4.; Тип
5.; Дія системи
 @abstractmethod
 auto_open_shift: bool = True

У K2 ERP або локальному агенті повинна бути картка РРО.; Колір

я хочу передати продаж у Python Agent, 

{| class="wikitable"
 "payments": [
 response = self.serial.read_until()

<pre>

Як касир, 
== 5.; Загальна технічна архітектура ==
== Див.; 30.; додатково ==

</pre>

 pass
!; | Чек переходить у NEEDS_RETRY або RRO_ERROR.; |-
| Z-звіт
| Критичний
| Закриття зміни.; характеристика
|-
| Тип пристрою
| Фізичний фіскальний реєстратор.; |-
| Dashboard
| Центральний контроль чеків, змін і помилок.; | Не відправляти на РРО.; | Python Agent створює чек у статусі PENDING.; |-
| raw_response
| text/jsonb
| Відповідь РРО.; характеристика
</div>
 response = self.send_command(command)

На касовому ПК запускається локальний Python Agent, який функціонує з РРО.; |-
| RRO Response
| Відповідь пристрою.; !; Як зменшити
=== 24.5. Dashboard ===

!; # Чи потрібно відкривати грошову скриньку?; Тип
- entity_type varchar device, shift, receipt.; Поле

27.; Ризики

"cashier_id": "cashier-001",
- external_payment_id varchar - переважні аспекти class="wikitable"

POST /api/v1/rro/shifts/open

def check_connection(self) -> "RROStatus":
"sku": "SKU-001",
"department": 2,
allow_service_operations: bool = True
"quantity": 1,

17.; Модель даних

Чеків за день - Ширина чекової стрічки - Контрольна стрічка - sku varchar Артикул.; Де застосовується ; Компонент

Особливості моделі МІНІ-ФП54.; 3.01

MINI_FP54_RETRY_COUNT=2

; Друк та фіскалізація чека
"items": [

8.; Функціональні вимоги

- external_refund_id string style="background:#ffcc80;" | Потрібна дія
РРО не підключені }

<syntaxhighlight lang="python">

- Помилка драйвера Код, текст, raw-відповідь.; {
result = self.device.GetStatus()

Як POS або K2 ERP,

|-
| device_name
| string
| Так
| Назва РРО.; |-
| dll_path
| string
| Ні
| Шлях до DLL, якщо застосовується DLL.; |-
| idempotency_key
| string
| Ключ захисту від дублювання.; |-
| AC-5
| РРО готовий.; |-
| baud_rate
| integer
| Швидкість порту.; |-
| Друк QR / штрих-коду
| Підтримується.; | style="background:#ffcc80;" | Помаранчевий
|-
| Зміна відкрита
| SHIFT_OPEN
| Можна друкувати фіскальні чеки.; |-
| dll_path
| varchar
| Шлях до DLL.; # Чи потрібно друкувати QR-код у чеку?; * Зміни до протоколу обміну.; |-
| Не закрито зміну
| Касир забув зробити Z-звіт.; |-
| Service Operation
| Службове внесення або винесення.; |-
| connection_type
| enum
| Так
| OLE_DLL, SERIAL, USB_COM.; Очікуваний результат

!; |-
| AC-6
| Немає паперу.; baudrate=self.baud_rate,
MINI_FP54_LOG_RAW_COMMANDS=true
{| class="wikitable"

 def close_shift(self) -> dict:

Призначення:
'''Заборонено:''' використовувати placeholder-команди в production.; ],

  • завантажити інструкцію з експлуатації;
  • завантажити зміни до протоколу обміну;
  • завантажити OLE/DLL-бібліотеку;
  • завантажити USB-драйвер;
  • перевірити підключення РРО до ПК;
  • визначити робочий сценарій: OLE/DLL або serial.; характеристика

Етап 5.; Службові операції

id uuid Чернетка, зміна закрита.; |}
result = self.device.ZReport()
@abstractmethod
  • локальний Python Agent;
  • конфігурація підключення до МІНІ-ФП54.01;
  • перевірка стану РРО;
  • відкриття зміни;
  • друк чека продажу;
  • друк чека повернення;
  • службове внесення / винесення;
  • X-звіт;
  • Z-звіт;
  • локальна БД чеків;
  • дедублікація;
  • журнал команд і відповідей;
  • базовий dashboard API;
  • обробка помилок паперу, порту, драйвера, зміни;
  • retry для безпечних ситуацій.; |-
raw_open_response jsonb/text - Fiscal Receipt Фіскальний чек продажу.; характеристика

GET /api/v1/rro/status Endpoint: <syntaxhighlight lang="python">

Пристрій зберігається в системі.; | Заборонити операцію.; |- RRO Command - COM-порт зайнятий Інший бізнес-процес використовує РРО.; * OLE/DLL-бібліотека виробника.; Значення / характеристика

10.; Статуси РРО

 v
<pre>
=== 8.7.; Службове внесення / винесення ===
 def get_status(self) -> dict:
com_port: str | None = "COM3"

рішення для бізнесу повинно забезпечити:

; характеристика
MINI_FP54_COM_PORT=COM3
[[Категорія:POS]]
=== 21.1.; Основні KPI ===
 )

== 21.; Dashboard керівника ==
</div>
До MVP не входить:

# Назви методів залежать від документації OLE-сервера виробника.; def refund_receipt(self, receipt: dict) -> dict:

POST /api/v1/rro/receipts/refund

GET /api/v1/rro/events?date_from=2026-05-01&date_to=2026-05-07

;=== 8.8.; X-звіт ===
def x_report(self) -> dict:

3.; Тип

28.; Відкриті питання

POST /api/v1/rro/receipts/sale

Етап 3.; Драйверний шар

; характеристика

Рекомендовано для MVP: починати з OLE/DLL-бібліотеки виробника, якщо вона стабільно функціонує з моделлю МІНІ-ФП54.01 та підтримує роботу всі потрібні команди.; |-

department integer Відділ.; № ;=== 24.2.; Продаж === - Чек продажу Замовлення, сума, позиції, статус.; Зберегти номер і результат Z-звіту.; from pydantic_settings import BaseSettings

POST /api/v1/rro/shifts/open

- Дисплей покупця Вбудований 2x16.; характеристика Python RRO Agent — це локальний сервіс, який встановлюється на касовий ПК і має доступ до РРО через USB/RS232/OLE/DLL.; Якщо РРО має критичну помилку, чек не повинен переходити в статус «Фіскалізовано».; |-
unit varchar - status varchar - is_active boolean Так Чи активний пристрій.; Обов'язковість
},
id uuid - Службове внесення / винесення Середній Касова операційна дія.; self.timeout = timeout


- Обмеження - device_id uuid ID РРО.; №
id uuid - Сірий #eeeeee - fiscal_number varchar }

# Який варіант інтеграції обираємо: OLE/DLL чи прямий serial-протокол?; | style="background:#c8e6c9;" | Норма
Повернення Кількість чеків повернення.; Локальний endpoint: "price": 250.00,

18.10.; Отримати журнал подій

; Якщо потрібно — відкриває зміну.;

18.8.; Службова операційна дія

Приклад: MINI_FP54_AUTO_OPEN_SHIFT=true
Чеків за день 384 відомості
Фіскалізовано 378 Норма
Повернення 9 Контроль
Помилки РРО 4 Критично
Потребують повтору 3 Потрібна дія
Незакриті зміни 1 Потрібна дія
item.get("department", 1), pass

13.; Приклад конфігурації

3.; |} "unit": "шт" @abstractmethod float(item ["quantity"]),

19.2.; Приклад OLE-драйвера

Endpoint:
; Тип

17.4. rro_receipt_items

1.; Поле Приклад `.env`: def open_shift(self, cashier_id: str) -> dict: інтеграції ERP / POS / CRM / інтернет-магазину з фізичним фіскальним реєстратором МІНІ-ФП54.01 для друку та фіскалізації чеків забезпечується через Головна ідея: розробити Python-сервіс або Python-адаптер; додатково реалізовано повернень, службових операцій, відкриття і закриття змін.; Зберегти локальний статус.; |-
receipt_type varchar style="background:#ef9a9a;" | Червоний
щоб закрити касову зміну.; | style="background:#bbdefb;" | Блакитний
Фіскалізовано FISCALIZED - RRO Error - status varchar } return {"raw": result}

Варіант 2.; 4.2.; Через прямий протокол обміну RS232/USB-COM

Метою задачі є собою створення Python-рішення для інтеграції з фізичним фіскальним реєстратором МІНІ-ФП54.01.; | Вони підсвічуються червоним.; |-
Кількість відділів 64.; Логіка: * реалізувати Windows Service; * додати моніторинг агента; * додати auto-restart; * додати резервне копіювання локальної БД; * додати alerting; * протестувати типові помилки РРО.; |} ; Тип Черга, друк, передача команди.; |- old_status varchar Старий статус.; Очікуваний результат

7.2.; Повернення

GET /api/v1/health response = self.send_command(command) Як касир або адміністратор, )
style="background:#f3e5f5;" | Контроль
Помилки РРО Кількість помилкових операцій.; Перевірити незавершені чеки.;=== 17.3. rro_receipts === ; Тип
K2 ERP / POS Статус PAPER_OUT, повтор після заміни паперу.; Сума - AC-7 Повторний запит має той самий idempotency_key.; !; Критерій

7.5.; Контроль помилок

v "comment": "Службове внесення на початок зміни",
- AC-17 - X-звіт Середній - total_amount numeric - external_order_id Idempotency key, локальна БД, журнал статусів.; |- Z-звіт Час, номер звіту, результат.; характеристика self.serial = serial.Serial( style="background:#ef9a9a;" | Червоний
Немає паперу PAPER_OUT платформа повертає READY або конкретну помилку.; |- X Report Проміжний звіт без закриття зміни.; Створюється локальний запис receipt зі статусом PENDING.; Сутність
id uuid ID події.; KPI class MiniFP54Settings(BaseSettings): "amount": 1000.00,
Чернетка DRAFT - tax_profile_id string Ні - closed_at timestamp - error_code varchar style="background:#c8e6c9;" | Зелений
Помилка РРО RRO_ERROR Він бачить чеки, повернення, помилки, незакриті зміни.; return {"raw": response.hex()} POST /api/v1/rro/receipts/refund - Повторна операційна дія Хто запустив, причина, результат.; Статус def service_cash_in(self, amount: float, comment: str | None = None) -> dict: baud_rate: int = 115200 === 7.4.; Закриття зміни ===