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

Фіскальний реєстратор МІНІ-ФП54.01

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

Приклад smoke-тесту через OLE

</syntaxhighlight>

if self.connection and self.connection.is_open:
def open_port(self, port: int, baudrate: int = 115200):
 class FakeMiniFP54Driver(FiscalDriverInterface):
<syntaxhighlight lang="python"> import serial
|-
|Назва
|МІНІ-ФП54.01
|-
|Тип пристрою
|Фіскальний реєстратор
|-
|Виробник
|Юнісістем
|-
|реліз ПЗ
|5401F3
|-
|Підключення до ПК
|USB або RS-232
|-
|Передача даних
|Ethernet, GSM/GPRS
|-
|Bluetooth
|Опція
|-
|ключовий офіційно затверджений спосіб інтеграції
|DLL / OLE-сервер для Windows
|-
|Альтернативна інтеграційні функціональні можливості
|Пряма робота через протокол обміну
|}

 def get_status(self) -> str:
 assert result == "OK;RECEIPT_CLOSED;TOTAL=100.00"
 assert result == "OK;Z_REPORT_PRINTED"

Unit-тест помилки: чек без відкритої зміни

МІНІ-ФП54.01

"""

|- | style="background:#d4edda; color:#155724; font-weight:bold;" |Рекомендовано |Для Windows використовувати офіційно затверджений DLL / OLE-сервер |Це найшвидший шлях інтеграції з POS-системою або Python-застосунком через COM/OLE.; |}

!Призначення

 pip install pyserial
return "ERROR;SHIFT_NOT_OPEN"

</syntaxhighlight>

result = driver.sell_item("Кава", price=50.00, quantity=2)

Можна створити пару віртуальних serial-портів через `socat`.; pass Для Linux, macOS або embedded-систем можлива інтеграційні функціональні можливості через `pyserial`, але для цього потрібно реалізувати протокол обміну з пристроєм.; Для розробки без фізичного пристрою варто використовувати mock-драйвер або serial-емулятор.; # Переконатися, що застосовується тільки один інтерфейс.; Увімкнути фіскальний реєстратор.; payload = command.encode(self.config.encoding)

pass

!Примітка |- | style="background:#d4edda; color:#155724; font-weight:bold;" |Обовʼязково |Усі операції продажу мають проходити через фіскальний реєстратор.; return self.driver.GetSoftVersion()

command_name,
def __init__(self, config: MiniFP54SerialConfig):

!Коментар

Select-Object -First 50
driver = FakeMiniFP54Driver()
@abstractmethod
driver.open_receipt()

Тестування драйвера без пристрою

if amount < self.total:
return "ERROR;PAYMENT_LESS_THAN_TOTAL"
change = round(amount - self.total, 2)
return f"OK;PAYMENT_ACCEPTED;CHANGE={change:.2f}"
def close_receipt(self) -> str:

Недоліки: ├── errors.py

Python / C# / 1C / інше ПЗ </syntaxhighlight> !Статус Для macOS ситуація аналогічна Linux: готового офіційного OLE/DLL-драйвера немає, але можна працювати через serial-порт, якщо платформа бачить пристрій як `/dev/tty.*`.; |- | style="background:#d4edda; color:#155724; font-weight:bold;" |Корисно |Така структура підходить для побудови власного драйвера.; |- | style="background:#f8d7da; color:#721c24; font-weight:bold;" |Не запускати в production |Поки не перевірено на тестовому РРО або у нефіскальному режимі.; parity=serial.PARITY_NONE, </syntaxhighlight> !Коментар mini_fp54/ class FiscalDriverInterface(ABC): !Характеристика

Призначення файлів

/dev/pts/4

def close_shift(self) -> str:

driver.connect_to_ole()

return self.driver.GetStatus()
Це не повний драйвер.; |}

@dataclass class MiniFP54SerialConfig:

- парсинг статусів і помилок.; |-

| style="background:#f8d7da; color:#721c24; font-weight:bold;" |Не робити |Не підключати одночасно USB і RS-232 до одного ПК |Для роботи з ПК потрібно використовувати один інтерфейс підключення.; |- |Serial |pyserial |Windows / Linux / macOS |Потрібна реалізація протоколу обміну.; |- | style="background:#fff3cd; color:#856404; font-weight:bold;" |Уточнити |Потрібно знати реальний ProgID OLE-сервера і точні назви методів.; Окремо варто відзначити контрольну стрічку в електронній формі, інтерфейси підключення до ПК через USB або RS-232, а додатково канали передачі даних через Ethernet і GSM/GPRS.; |- | style="background:#fff3cd; color:#856404; font-weight:bold;" |Обовʼязково |Чи правильні назви методів.; За потреби виконувати повернення.; |- | style="background:#fff3cd; color:#856404; font-weight:bold;" |Не замінює РРО |Емулятор не перевіряє реальний фіскальний протокол.; |- | style="background:#fff3cd; color:#856404; font-weight:bold;" |Обовʼязково |Чи правильний COM-порт.;== Python-інтеграція == Драйвер або власна інтеграційні функціональні можливості |- | style="background:#d4edda; color:#155724; font-weight:bold;" |Добре |USB простіше використовувати на сучасних робочих місцях.; |- |RS-232 |Підключення до ПК |Зручний для serial-інтеграції.; Приклад через Python: FiscalDriverInterface

for index in range(total):
Реальний формат треба взяти з протоколу обміну.; Перевірити звʼязок із POS-системою.; |-

| style="background:#d4edda; color:#155724; font-weight:bold;" |Можливо |Для Linux/macOS можна реалізувати власний драйвер через serial-порт |Потрібна реалізація протоколу обміну з фіскальним реєстратором.; # Перевірити, який COM-порт отримав пристрій.; |- | style="background:#d4edda; color:#155724; font-weight:bold;" |Обовʼязково |Наприкінці зміни потрібно виконувати Z-звіт.; |- |Mock-драйвер |pytest / unittest |Будь-яка |Для тестування без фізичного пристрою.; Python можна використовувати через пакет `pywin32`, якщо встановлено та зареєстровано OLE-сервер.; # Перевірити передачу даних.; Це надає можливість перевірити POS-логіку, але не замінює тестування з реальним РРО.; Перевірити передачу даних.; Наприкінці дня друкувати Z-звіт.; портативний фіскальний реєстратор виробництва Юнісістем виступає ключовою рисою МІНІ-ФП54.01.; Пробивати чеки продажу.; 5.; time.sleep(delay)

  • залежність від Windows;
  • залежність від конкретної версії OLE-сервера;
  • потрібно встановити та зареєструвати COM/OLE-компонент;
  • потрібно знати ProgID і назви методів.; Такий варіант гнучкіший, але складніший і потребує повного тестування з реальним фіскальним реєстратором.; |-

| style="background:#f8d7da; color:#721c24; font-weight:bold;" |Не плутати |Ethernet/GSM не є собою основним інтерфейсом POS-команд |Ethernet і GSM/GPRS використовуються переважно для передачі даних до ДПС.; |- | style="background:#f8d7da; color:#721c24; font-weight:bold;" |Не достатньо |Без реалізації контрольної суми та службових байтів це не production-драйвер.; |}

return f"OK;RECEIPT_CLOSED;TOTAL={self.total:.2f}"
└── test_errors.py
@abstractmethod

!Що треба перевірити перед запуском

Варіанти інтеграції

level=logging.INFO,

Підключення до компʼютера

Встановлення залежності

PROG_ID = "PUT_REAL_PROG_ID_HERE"

self.receipt_opened = False
result = command()
"""

Приклад через PowerShell:

- контрольну суму;

Python через OLE/DLL у Windows

if self.receipt_opened:

|- | style="background:#d4edda; color:#155724; font-weight:bold;" |Можливо |Linux має змогу працювати з пристроєм через serial-порт.; except OSError:

return "ERROR;SHIFT_ALREADY_OPEN"

Офіційних прикладів саме для Python на сторінці підтримки не знайдено.; # Встановити DLL/OLE-сервер, якщо застосовують, коли потрібно Windows.; Реальну команду потрібно брати з протоколу обміну.;

)
print("Version:", driver.get_version())
 import win32com.client
class MiniFP54OleDriver:
!Коментар
=== Типовий робочий цикл ===
 - повтори;
 assert result == "OK;PAYMENT_ACCEPTED;CHANGE=0.00"

!Висновок

if not self.shift_opened:

!Інтерфейс

Python-обгортка над OLE-сервером Юнісістем.;== Рекомендована структура Python-проєкту ==
↓
↓
self.driver = win32com.client.Dispatch(self.prog_id)

!Висновок |- |1 |Відкрити порт |Драйвер не повертає помилку |- |2 |Отримати статус |Пристрій відповідає |- |3 |Отримати версію ПЗ |Повертається реліз пристрою |- |4 |Перевірити папір |Немає помилки паперу |- |5 |Відкрити зміну |Зміна відкрита |- |6 |Відкрити чек |Чек відкритий |- |7 |Додати товар |Рядок товару надруковано або прийнято |- |8 |Провести оплату |Оплата прийнята |- |9 |Закрити чек |Чек закритий |- |10 |Надрукувати X-звіт |Звіт друкується без закриття зміни |- |11 |Надрукувати Z-звіт |Зміна закрита |- |12 |Перевірити передачу даних |інформаційні дані передаються через Ethernet або GSM/GPRS |}

/dev/ttyACM0
if not self.receipt_opened:
pass
assert result == "OK;ITEM_ADDED;100.00"
  1. Зареєструвати РРО.;</syntaxhighlight>
- Назви методів потрібно звірити з документацією до конкретної версії OLE.; if isinstance(result, str) and result.startswith("OK"): port: str Мета тестування без пристрою: return "ERROR;UNKNOWN_COMMAND\n"
  • кросплатформність;
  • незалежність від OLE;
  • можна запускати як локальний сервіс;
  • комфортно для Docker, Linux POS, Raspberry Pi, embedded-терміналів.; # Перевірити заряд акумулятора або живлення.; |-
Ризик - Bluetooth Опційне підключення має змогу використовуватися зі смартфоном або планшетом за наявності сумісного ПЗ.;== Основні характеристики ==

/dev/pts/3

filename="mini_fp54.log",
duration,

OLE/DLL Юнісістем

def open_receipt(self) -> str:
raise

Linux не є собою основною цільовою платформою для офіційного OLE/DLL-драйвера.; |}

macOS

for attempt in range(1, retries + 1):
Після запуску `socat` покаже два порти, як ілюстрація:
<pre>
 logging.info(
├── logger.py
FakeMiniFP54Driver
 response = self.send_raw(payload)
 duration,
 name = winreg.EnumKey(root, index)
!Причина
 except Exception as exc:

!Висновок

 @abstractmethod
{| class="wikitable"
 def get_status(self) -> str:
<syntaxhighlight lang="python"> import serial from dataclasses import dataclass
 self.total = 0.0
|-
|Немає звʼязку з пристроєм
|Неправильний COM-порт або кабель
|Перевірити порт, кабель, драйвер, живлення
|-
|Timeout
|Пристрій не відповідає
|Повторити команду, перевірити стан РРО
|-
|Port busy
|Порт зайнятий іншою програмою
|Закрити інші програми, які використовують COM-порт
|-
|Немає паперу
|Закінчилась чекова стрічка
|Замінити папір і повторити операцію
|-
|Зміна не відкрита
|POS намагається пробити чек без відкритої зміни
|Спочатку виконати відкриття зміни
|-
|Чек уже відкритий
|Попередній чек не закритий
|Закрити або анулювати чек
|-
|Помилка передачі даних
|Немає Ethernet/GSM-звʼязку
|Перевірити інтернет, SIM-карту, конфігурація
|}

!Коментар
!Правило

 assert driver.open_shift() == "OK;SHIFT_OPENED"
 assert driver.open_receipt() == "OK;RECEIPT_OPENED"
 """
 pass
== Python через serial-порт ==

 """
9.; !Статус
!Статус

 /dev/tty.usbmodem-*
 if command == "CLOSE_RECEIPT":

 total = winreg.QueryInfoKey(root)[0]
POS-система

 started_at = time.time()
 def connect(self):

 pass
!Помилка
 /dev/ttyUSB0
 """
 return "OK;RECEIPT_OPENED"
keywords = ["Ecr", "T400", "MINI", "FP", "Unisystem", "Uni"]
|-
| style="background:#d4edda; color:#155724; font-weight:bold;" |Добре для розробки
|Емулятор надає можливість тестувати POS-сценарії без фізичного пристрою.; Реальний режим — це робота з фіскалізованим пристроєм, який застосовується для реєстрації розрахункових операцій.; 7.; |-
| style="background:#f8d7da; color:#721c24; font-weight:bold;" |Не для production
|Не можна вважати інтеграцію готовою без тестів із реальним пристроєм.; |}

 encoding: str = "cp1251"

 return "ERROR;RECEIPT_NOT_OPEN"

# Встановити USB-драйвер виробника.; return result
Python-сервіс
├── __init__.py
USB або COM
 def __init__(self, prog_id: str):
== Production checklist ==

 - ProgID потрібно взяти з реальної інсталяції OLE-сервера.; # Налаштувати типи оплат.; """

 ↓

 if not self.shift_opened:

Для Windows виробник надає:

 assert result == "ERROR;SHIFT_NOT_OPEN"
</syntaxhighlight>

=== Unit-тест помилки: оплата менша за суму чека ===
 ↓

 @abstractmethod
МІНІ-ФП54.01 найпростіше інтегрувати у Windows через офіційно затверджений DLL/OLE-сервер.; |}

 driver.open_port(port=3, baudrate=115200)

 result = driver.close_receipt()
<pre>

<syntaxhighlight lang="python"> from mini_fp54_ole import MiniFP54OleDriver
pyserial

 self.shift_opened = False

try:
 return "OK;MINI-FP54.01;5401F3\n"
Після встановлення OLE-сервера потрібно знайти його ProgID.;<pre>

</syntaxhighlight>
 ser.flush()
 duration = round(time.time() - started_at, 3)

Один порт використовує тестовий POS-драйвер, інший — емулятор пристрою.; |}
try:
"""
self.connection.write(payload)
Варіант
Кількість товарів 16 384
Кількість відділів 64
Кількість касирів 32
Кількість символів у рядку 32
Кількість символів у назві товару 48
Початкове повідомлення 12 рядків
Заключне повідомлення 2 рядки
Дисплей покупця Вбудований, 2×16 символів
Друк Термодрук
Ширина стрічки 58 мм
Швидкість друку 8 рядків/с
Живлення Вбудований Li-Pol акумулятор
Акумулятор 7,4 В; 2 А·год, опційно 3,6 А·год
RS-232 1 порт
USB 1 порт
Bluetooth Опція
Грошова скринька micro-jack 2,5 мм
Ethernet є собою
GSM/GPRS Вбудований
Габарити 181 × 123 × 102 мм
Маса 0,73 кг

Інтерфейс драйвера

Підготовка

  • USB;
  • RS-232 / COM-порт.;
     def test_payment_less_than_total():
    Для production-інтеграції потрібно логувати:
    
    with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, "") as root:
     result = driver.close_shift()
    <syntaxhighlight lang="python"> import logging import time
     self.items = []
     timeout: float = 3.0
    
     def open_receipt(self) -> str:
     def pay_cash(self, amount: float):
    
     def close_shift(self):
     return "OK;Z_REPORT_PRINTED"
     pass
    
     Умовний приклад текстової команди.; |-
    |USB
    |Підключення до ПК
    |ключовий варіант для POS-інтеграції.;=== Windows ===
    !Висновок
     - службові байти;
    
     if command.startswith("SALE"):
    macOS:
     self.connection.flush()
    
    Linux:
    !Статус
    
    Без фізичного МІНІ-ФП54.01 можна тестувати не сам фіскальний реєстратор, а логіку інтеграції.; 
     duration = round(time.time() - started_at, 3)
    |-
    |OLE/DLL
    |pywin32
    |Windows
    |Найпростіший варіант, якщо встановлено OLE-сервер.; 
    !Очікуваний результат
    {| class="wikitable"
     def open_shift(self) -> str:
     def __init__(self):
     if not raw:
     self.config = config
     Where-Object { $_.Name -match "Ecr|T400|MINI|FP|Unisystem|Uni" } |
     self.receipt_opened = True
    
    <syntaxhighlight lang="python"> from abc import ABC, abstractmethod
    !Статус
    
     raise FiscalCommandError(f"Command failed after {retries} retries: {last_error}")
     return result
     return "OK;ITEM_ADDED\n"
    
    === Unit-тест успішного продажу ===
    === Приклад логування в Python ===
    Unit / integration tests
    
    {| class="wikitable"
    === Встановлення залежності ===
     def close_port(self):
     def open_shift(self) -> str:
    2.; )
     )
    3.; |-
    | style="background:#fff3cd; color:#856404; font-weight:bold;" |Перевірити
    |Потрібно встановити USB-драйвер виробника.; За потреби друкувати X-звіт.; def open_receipt(self):
     @abstractmethod
     except Exception as exc:
     """
    |-
    | style="background:#fff3cd; color:#856404; font-weight:bold;" |Обовʼязково
    |Чи правильний ProgID OLE-сервера.; # Перевірити роботу POS-системи з реальним драйвером.;== Операційні системи ==
    
     @abstractmethod
    
    </pre>
     return self.connection.read(read_size)
    
     return self.driver.Pay(payment_type, amount)
     while True:
     return (
    !Статус
     driver.sell_item(
     last_error = None
    
    POS-система
    6.; |}
    
     if self.receipt_opened:
    
    !Коментар
     logging.exception(
    
     timeout=self.config.timeout,
     raw = ser.readline()
    
    !Призначення
    1.; |}
    
     MiniFP54SerialConfig(
     driver.sell_item("Кава", price=50.00, quantity=2)
    
     if not self.items:
    
    * перевірити бізнес-логіку POS-системи;
    * перевірити порядок команд;
    * перевірити обробку помилок;
    * перевірити логування;
    * перевірити поведінку при timeout;
    * перевірити поведінку при відсутності паперу;
    * перевірити поведінку при розриві зʼєднання.; if not self.receipt_opened:
     return "ERROR;EMPTY_RECEIPT"
     driver.close_port()
    |-
    | style="background:#d4edda; color:#155724; font-weight:bold;" |Добре
    |Serial-протокол простіше реалізувати кросплатформно.; |-
    | style="background:#f8d7da; color:#721c24; font-weight:bold;" |Ризик
    |У різних ОС назва порту буде різною, з цієї причини її не можна жорстко зашивати в код.; # Перевірити наявність паперу.; |}
    
     result = callback()
    
     baudrate: int = 115200
    === Fake-драйвер ===
     driver.close_receipt()
    |-
    | style="background:#fff3cd; color:#856404; font-weight:bold;" |Можливо
    |Потрібна власна serial-інтеграція.; # Виконати тестовий друк або службову операцію.; |-
    |Ethernet
    |Передача даних через інтернет
    |застосовується для звʼязку з ДПС.;=== Варіант 1.; Через OLE/DLL у Windows ===
    
     return "OK;RECEIPT_CLOSED\n"
    Типова схема підключення:<pre>
     print(response)
    {| class="wikitable"
    
    ├── fake_driver.py
    </pre>
    !Перевірка
    
    </pre>
    {| class="wikitable"
     )
    
    !Статус
     quantity=1,
     driver = FakeMiniFP54Driver()
    
    </pre>переважні аспекти:
     continue
     @abstractmethod
    
    </pre>
     /dev/tty.usbserial-*
    <syntaxhighlight lang="python"> from mini_fp54_serial import MiniFP54SerialClient, MiniFP54SerialConfig
    
    !Статус
    8.; МІНІ-ФП54.01
    Windows:
     baudrate=self.config.baudrate,
     last_error = result
    !Файл
    
response = handle_command(command)

client = MiniFP54SerialClient(

USB-підключення зручне для сучасних ПК і ноутбуків.; Після встановлення USB-драйвера пристрій зазвичай функціонує як віртуальний COM-порт.; driver.open_shift() )

"command=%s duration=%s result=%s",

!Параметр |- | style="background:#fff3cd; color:#856404; font-weight:bold;" |істотно |Назва ProgID у прикладах нижче умовна.; if command == "GET_STATUS":

return "OK;READY\n"
if command == "GET_VERSION":

!ОС

!Тест

command = command.strip()
Для реальної роботи потрібно реалізувати офіційно затверджений протокол:
response = client.send_text_command("GET_STATUS")
f"SHIFT_OPENED={self.shift_opened};" return "ERROR;RECEIPT_NOT_OPEN" "OK;" pass

RS-232 / COM-порт

self.items = []
Статус
driver.pay_cash(50.00)
Базовий serial-клієнт для МІНІ-ФП54.01.; |}
return "ERROR;RECEIPT_ALREADY_OPEN"
if price <= 0: return "ERROR;INVALID_PRICE" if quantity <= 0: return "ERROR;INVALID_QUANTITY" amount = round(price * quantity, 2) self.items.append( { "name": name, "price": price, "quantity": quantity, "amount": amount, } ) self.total = round(self.total + amount, 2) return f"OK;ITEM_ADDED;{amount:.2f}" def pay_cash(self, amount: float) -> str:
 def test_success_sale_flow():
 if not self.connection or not self.connection.is_open:

* не потрібно вручну реалізовувати низькорівневий протокол;
* простіше стартувати;
* можна викликати готові методи драйвера;
* підходить для POS-систем на Windows.; Її треба уточнити після встановлення реального OLE-сервера.; |-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Перевірити
|Потрібен фізичний COM-порт або USB-RS232 адаптер.;<pre>
 format="%(asctime)s %(levelname)s %(message)s",
4.; # Налаштувати податкові групи.; return self.driver.OpenShift()

* потрібно реалізувати протокол обміну;
* потрібно обробляти контрольні суми, ACK/NAK, таймаути, повтори;
* складніше тестувати;
* потрібна офіційна документація протоколу.; try:
 return self.driver.ClosePort()

 return "OK;SHIFT_OPENED"
{| class="wikitable"

├── ole_driver.py
== Логування ==

try:
 timeout=3.0,

{| class="wikitable"
 def disconnect(self):

=== Linux ===
 command = raw.decode("cp1251", errors="replace")

!Статус
COM3, COM4, COM5 ...; # Перевірити Ethernet або GSM/GPRS для передачі даних.; |}

=== Базова структура Python-обгортки ===
 port="COM3", # Linux: "/dev/ttyUSB0"

 stopbits=serial.STOPBITS_ONE,
Недоліки:
</pre>переважні аспекти:

{| class="wikitable"
 if command.startswith("PAY"):
=== Базовий serial-клієнт ===
=== Пошук ProgID OLE-сервера ===

 def close_receipt(self):
 ├── test_fake_driver.py
client.connect()

== Важливі висновки для інтеграції ==
!Коментар

 Увага:
 return self.driver.OpenPort(port, baudrate)
def execute_with_retry(command, retries: int = 3, delay: float = 1.0):
 print("Close port:", driver.close_port())
 def close_shift(self) -> str:
Пристрій має Ethernet-порт і GSM/GPRS-модем для передачі даних.; # Виконати персоналізацію.; # Виконати фіскалізацію.; Перед production-запуском потрібно:
 def pay_cash(self, amount: float) -> str:
 def send_text_command(self, command: str) -> str:
{| class="wikitable"
 Приклад.; |-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Потрібно
|Реалізувати протокол обміну.; МІНІ-ФП54.01
<syntaxhighlight lang="powershell"> Get-ChildItem "Registry::HKEY_CLASSES_ROOT" |

 return "ERROR;RECEIPT_NOT_OPEN"
 return self.driver.OpenReceipt()
<syntaxhighlight lang="python"> from mini_fp54_ole import MiniFP54OleDriver

 if any(keyword.lower() in name.lower() for keyword in keywords):
== Робота в реальному режимі ==

 return self.driver.Sale(name, quantity, price, tax_group)

== Висновок ==
 self.prog_id = prog_id
class FiscalCommandError(Exception):
{| class="wikitable"
 driver = FakeMiniFP54Driver()
!Статус
 

</pre>
 name="Кава",

{| class="wikitable"
 self.total = 0.0

 return "ERROR;SHIFT_NOT_OPEN"
 payment_type = 0
=== Типові помилки інтеграції ===
/dev/ttyUSB0 або /dev/ttyS0
 if self.shift_opened:
├── config.py
 - таймаути;

!Що робити

{| class="wikitable"
== Обробка помилок ==
 self.connection: serial.Serial | None = None
with serial.Serial(PORT, BAUDRATE, timeout=1) as ser:
 def sell_item(self, name: str, price: float, quantity: float) -> str:
 ser.write(response.encode("cp1251"))
 if not self.receipt_opened:
{| class="wikitable"
)
|-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Умовний приклад
|Команда GET_STATUS наведена як приклад.; return "ERROR;RECEIPT_IS_OPEN"
PORT = "/dev/pts/4" BAUDRATE = 115200
=== Рекомендований retry-механізм ===
 baudrate=115200,
 port=self.config.port,
 ├── test_sale_flow.py
 result,
logging.basicConfig(
=== технічна архітектура тестування без пристрою ===

RS-232 підходить для класичних POS-систем, касових терміналів і embedded-рішень.; Перевірити папір.; Але Python можна використовувати у двох режимах:

!Пакет Python

 def close_receipt(self) -> str:
=== Мінімальний чек-лист smoke-тесту ===

{| class="wikitable"
Рекомендована схема для Windows:<pre>

* дату й час команди;
* тип команди;
* параметри команди;
* відповідь пристрою;
* код помилки;
* COM-порт;
* тривалість виконання;
* номер чека;
* номер зміни.; |-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Обережно
|Офіційних Python-прикладів не знайдено
|Python можна використовувати через pywin32 або pyserial, але готового SDK саме для Python на сторінці підтримки немає.; # Налаштувати заголовок і підвал чека.; return self.driver.CloseReceipt()

МІНІ-ФП54.01 має змогу підключатися до компʼютера через:

def get_status(self):
- довжину;
self.shift_opened = False

└── tests/

Приклад:
 def sell_item(self, name: str, price: float, quantity: float, tax_group: int = 1):
Це найпростіший варіант для Windows.; Але інтеграційні функціональні можливості можлива через serial-порт, якщо реалізувати протокол обміну.; # Налаштувати касирів.; try:

<syntaxhighlight lang="bash"> socat -d -d pty,raw,echo=0 pty,raw,echo=0 </syntaxhighlight>

=== Варіант 2.; Через serial-порт напряму ===
<syntaxhighlight lang="python"> import winreg
== Джерела ==
 ↓
 exc,
роздрібної торгівлі забезпечується через Модель підходить; додатково реалізовано виїзної торгівлі, інтернет-магазинів, аптек, кафе, барів, ресторанів та сфери послуг.; |-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Контроль
|Потрібно перевіряти статус передачі даних.; # Провести тестовий день роботи.; |-
|GSM/GPRS
|Передача даних через мобільну мережу
|Дає змогу працювати без дротового інтернету.; |-
| style="background:#f8d7da; color:#721c24; font-weight:bold;" |Небезпечно
|Не можна ігнорувати помилки фіскального реєстратора.; Відкрити зміну.;</syntaxhighlight>
finally:

 def open_shift(self):
<syntaxhighlight lang="bash"> pip install pywin32 </syntaxhighlight>

driver = MiniFP54OleDriver("PUT_REAL_PROG_ID_HERE") driver.connect_to_ole()
 )

 result = driver.open_receipt()
def handle_command(command: str) -> str:
USB або RS-232

finally:
 result = driver.pay_cash(50.00)

 print(f"Fake MINI-FP54.01 emulator started on {PORT}")
 result = driver.pay_cash(100.00)
 print(name)

 self.connection = serial.Serial(

=== Приклад smoke-тесту через serial ===
=== USB-підключення ===
def log_fiscal_command(command_name: str, callback):

class MiniFP54SerialClient:
 def get_version(self):
== Короткий характеристика ==

 ↓
├── serial_driver.py
<syntaxhighlight lang="python"> def test_open_receipt_without_shift():

 ↓
</syntaxhighlight>

 command_name,

== Ethernet, GSM/GPRS і Bluetooth ==

=== Простий Python-емулятор ===
 f"RECEIPT_OPENED={self.receipt_opened}"
 self.driver = None
 def connect_to_ole(self):
<pre>
 tax_group=1,
 self.connection.close()

 raise RuntimeError("Serial port is not open")
 price=50.00,
 last_error = exc

 pass

!Статус
</syntaxhighlight>

!№
 assert result == "ERROR;PAYMENT_LESS_THAN_TOTAL"
</syntaxhighlight>

== Емуляція serial-пристрою без фізичного РРО ==
Для тестування serial-драйвера без пристрою можна зробити локальний емулятор.

=== Варіант для Linux/macOS ===

pass
)

Цей варіант підходить для Windows, Linux, macOS та embedded-систем.; |-

Немає Готового офіційного Python SDK для Linux не знайдено.; POS-система / касова програма
Рекомендовано Windows — найпростіша ОС для інтеграції через офіційно затверджений OLE/DLL.; print("Open port:", driver.open_port(port=3, baudrate=115200))

├── interfaces.py <syntaxhighlight lang="python"> import time

Приклад продажу через OLE

Python → pyserial → протокол обміну → USB/COM або RS-232 → МІНІ-ФП54.01 Пристрій має акумулятор.; # Виконати команду отримання статусу.; |}

Python → pywin32 → OLE-сервер → USB/COM → МІНІ-ФП54.01

return "OK;PAYMENT_ACCEPTED\n"

Перед запуском

  • USB-драйвер;
  • DLL-бібліотеку / OLE-сервер;
  • програму UNI-PROGress для конфігурація РРО;
  • Uniq Commander для конфігурація комунікаційного блоку;
  • обробку для «1С:організація».; |-
Не готово з коробки Офіційного macOS SDK не знайдено.; # Підключити пристрій через USB або RS-232.; ↓
self.receipt_opened = False
↓
def sell_item(self, name: str, price: float, quantity: float) -> str:
Значення
Реальна назва методу має змогу бути OpenPort, openPort або іншою.; |-
Плюс Можна використовувати Python через pywin32.; return response.decode(self.config.encoding, errors="replace")
print("Status:", driver.get_status())
driver.open_receipt()

POS-система

client.disconnect()
bytesize=serial.EIGHTBITS,

try:

def send_raw(self, payload: bytes, read_size: int = 1024) -> bytes:
return self.driver.ZReport()
self.shift_opened = True
- формат пакета;
Значення
interfaces.py Спільний інтерфейс драйвера
ole_driver.py Робота через OLE/DLL у Windows
serial_driver.py Робота через serial-порт
fake_driver.py Mock-драйвер для тестів
errors.py Власні класи помилок
logger.py Логування команд і відповідей
config.py конфігурація порту, швидкості, режиму роботи
tests/ Unit та integration-тести
"command=%s duration=%s error=%s",
- ACK/NAK;

Тестування з реальним пристроєм

USB-драйвер встановлено
OLE/DLL встановлено, якщо застосовується Windows
COM-порт визначено
Отримання статусу функціонує
Відкриття зміни функціонує
Продаж товару функціонує
Оплата готівкою функціонує
Оплата карткою функціонує
Закриття чека функціонує
X-звіт функціонує
Z-звіт функціонує
Передача даних функціонує
Перевірено поведінку при timeout
Перевірено поведінку при відсутності паперу
Перевірено поведінку при втраті інтернету
Немає hardcoded COM-порту в production-коді
Немає ігнорування помилок РРО
Примітка

finally:

Схема:

driver = MiniFP54OleDriver(PROG_ID)

 driver.open_shift()

* Офіційна сторінка МІНІ-ФП54.01: https://unisystem.ua/catalog/fiskalnye-registratory/fiskalnyj-registrator-mini-fp54-01/
* Сторінка підтримки Юнісістем: https://unisystem.ua/podderzhka/