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

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

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

assert result == "OK;Z_REPORT_PRINTED" </syntaxhighlight>

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

finally:

@abstractmethod
result = driver.open_receipt()
if command.startswith("SALE"):

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

|- |Назва |МІНІ-ФП54.01 |- |Тип пристрою |Фіскальний реєстратор |- |Виробник |Юнісістем |- |реліз системи ПЗ |5401F3 |- |Підключення до ПК |USB або RS-232 |- |Передача даних |Ethernet, GSM/GPRS |- |Bluetooth |Опція |- |базовий офіційний спосіб інтеграції |DLL / OLE-сервер для Windows |- |Альтернативна інтеграційні функції ERP |Пряма робота через протокол обміну |}

</syntaxhighlight> mini_fp54/

raise

!№

7.

!Параметр
 pass
)

МІНІ-ФП54.01

print(name)
self.driver = None

client.connect()

|- | style="background:#d4edda; color:#155724; font-weight:bold;" |Можливо |Linux здатна працювати з пристроєм через serial-порт. |- | style="background:#d4edda; color:#155724; font-weight:bold;" |Плюс |Можна використовувати Python через pywin32.</syntaxhighlight>

driver.pay_cash(50.00)

Приклад через PowerShell: Для Linux, macOS або embedded-систем можлива інтеграційні функції ERP через `pyserial`, але для цього потрібно реалізувати протокол обміну з пристроєм. |- |RS-232 |Підключення до ПК |Зручний для serial-інтеграції. # Виконати фіскалізацію. # Виконати тестовий друк або службову операцію.=== Приклад продажу через OLE ===

├── test_sale_flow.py
port: str
result,
  • кросплатформність;
  • незалежність від OLE;
  • можна запускати як локальний сервіс;
  • інтуїтивно для Docker, Linux POS, Raspberry Pi, embedded-терміналів.

├── __init__.py

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

driver.open_shift()

POS-система

if not self.shift_opened:
self.items = []

роздрібної торгівлі забезпечується через Модель підходить; так само реалізовано виїзної торгівлі, інтернет-магазинів, аптек, кафе, барів, ресторанів та сфери послуг. |}

├── serial_driver.py

return self.driver.Pay(payment_type, amount)
 Select-Object -First 50
 - повтори;
|-
| style="background:#d4edda; color:#155724; font-weight:bold;" |Добре
|Serial-протокол простіше реалізувати кросплатформно. filename="mini_fp54.log",
 def open_shift(self):

 result = driver.close_receipt()
 self.driver = win32com.client.Dispatch(self.prog_id)
!Статус

 print(response)
 return "ERROR;RECEIPT_NOT_OPEN"
!Висновок

!Характеристика
 - таймаути;
 ↓

!Коментар
 tax_group=1,
 self.receipt_opened = True

== Висновок ==
 return self.driver.GetSoftVersion()
 duration,
!Статус

 - ProgID потрібно взяти з реальної інсталяції OLE-сервера.== Рекомендована структура Python-проєкту ==
 duration,
{| class="wikitable"

 self.prog_id = prog_id
self.shift_opened = False print("Version:", driver.get_version()) /dev/ttyACM0 response = client.send_text_command("GET_STATUS") class FiscalCommandError(Exception): ↓
Помилка

Python через serial-порт

if not self.receipt_opened:

USB-підключення зручне для сучасних ПК і ноутбуків. |-

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-тести

def handle_command(command: str) -> str:

Fake-драйвер

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

Після запуску `socat` покаже два порти, як приклад:

Для macOS ситуація аналогічна Linux: готового офіційного OLE/DLL-драйвера немає, але можна працювати через serial-порт, якщо платформа бачить пристрій як `/dev/tty.*`. портативний фіскальний реєстратор виробництва '''Юнісістем''' виступає ключовою рисою '''МІНІ-ФП54.01'''. # Перевірити наявність паперу. |-
| style="background:#f8d7da; color:#721c24; font-weight:bold;" |Не для production
|Не можна вважати інтеграцію готовою без тестів із реальним пристроєм. |}

 self.connection.close()
Для production-інтеграції потрібно логувати:

 raise RuntimeError("Serial port is not open")

* перевірити бізнес-логіку POS-системи;
* перевірити порядок команд;
* перевірити обробку помилок;
* перевірити логування;
* перевірити поведінку при timeout;
* перевірити поведінку при відсутності паперу;
* перевірити поведінку при розриві зʼєднання. |}

!Статус

 pass
 try:

* USB-драйвер;
* DLL-бібліотеку / OLE-сервер;
* програму UNI-PROGress для конфігурація РРО;
* Uniq Commander для конфігурація комунікаційного блоку;
* обробку для «1С:компанія-користувач». |-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Уточнити
|Потрібно знати реальний ProgID OLE-сервера і точні назви методів. !Примітка

Драйвер або власна інтеграційні функції ERP
 """
<syntaxhighlight lang="python"> import logging import time
Приклад:<pre>
 Увага:
|-
|Немає звʼязку з пристроєм
|Неправильний COM-порт або кабель
|Перевірити порт, кабель, драйвер, живлення
|-
|Timeout
|Пристрій не відповідає
|Повторити команду, перевірити стан РРО
|-
|Port busy
|Порт зайнятий іншою програмою
|Закрити інші програми, які використовують COM-порт
|-
|Немає паперу
|Закінчилась чекова стрічка
|Замінити папір і повторити операцію
|-
|Зміна не відкрита
|POS намагається пробити чек без відкритої зміни
|Спочатку виконати відкриття зміни
|-
|Чек уже відкритий
|Попередній чек не закритий
|Закрити або анулювати чек
|-
|Помилка передачі даних
|Немає Ethernet/GSM-звʼязку
|Перевірити інтернет, SIM-карту, конфігурація
|}

 response = handle_command(command)
 try:

 return "ERROR;UNKNOWN_COMMAND\n"
 self.total = 0.0
@dataclass class MiniFP54SerialConfig:
Пристрій має Ethernet-порт і GSM/GPRS-модем для передачі даних. За потреби виконувати повернення. # Перевірити, який COM-порт отримав пристрій. # Встановити DLL/OLE-сервер, якщо застосовують, коли потрібно Windows. |}

driver.connect_to_ole()

{| class="wikitable"
 port=self.config.port,
 def close_receipt(self):
 def send_raw(self, payload: bytes, read_size: int = 1024) -> bytes:

* не потрібно вручну реалізовувати низькорівневий протокол;
* простіше стартувати;
* можна викликати готові методи драйвера;
* підходить для POS-систем на Windows.=== Linux ===
=== Windows ===

 driver = FakeMiniFP54Driver()
 @abstractmethod

 @abstractmethod
{| class="wikitable"

)
Windows:

=== Перед запуском ===
== Варіанти інтеграції ==

 """
 driver.close_port()

 def send_text_command(self, command: str) -> str:

конкурентні переваги:

Production checklist

class MiniFP54OleDriver:

format="%(asctime)s %(levelname)s %(message)s",
return self.driver.ClosePort()

Варіант 1. Через OLE/DLL у Windows

client = MiniFP54SerialClient(

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

</syntaxhighlight>

Базовий serial-клієнт

payment_type = 0
pass

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

pass
quantity=1,
if not raw:
pass
def open_receipt(self) -> str:
return self.driver.Sale(name, quantity, price, tax_group)

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

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

def connect(self):
/dev/ttyUSB0
def open_port(self, port: int, baudrate: int = 115200):
baudrate: int = 115200

!Статус

Робота в реальному режимі

PROG_ID = "PUT_REAL_PROG_ID_HERE"

def open_receipt(self):

!Статус

return result

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

Варіант 2. Через serial-порт напряму

"""

Python через OLE/DLL у Windows

def __init__(self):
Where-Object { $_.Name -match "Ecr|T400|MINI|FP|Unisystem|Uni" } |
@abstractmethod
f"SHIFT_OPENED={self.shift_opened};"

|- | style="background:#fff3cd; color:#856404; font-weight:bold;" |Обовʼязково |Чи правильний ProgID OLE-сервера. # Перевірити заряд акумулятора або живлення. pass

  • залежність від Windows;
  • залежність від конкретної версії OLE-сервера;
  • потрібно встановити та зареєструвати COM/OLE-компонент;
  • потрібно знати ProgID і назви методів. if command == "CLOSE_RECEIPT":
  • потрібно реалізувати протокол обміну;
  • потрібно опрацьовувати контрольні суми, ACK/NAK, таймаути, повтори;
  • складніше тестувати;
  • потрібна офіційна документація протоколу. |-

|GSM/GPRS |Передача даних через мобільну мережу

|Дає змогу працювати без дротового інтернету.

 def test_open_receipt_without_shift():

{| class="wikitable"
== Підключення до компʼютера ==
├── ole_driver.py

{| class="wikitable"
 result = driver.close_shift()

 assert result == "ERROR;SHIFT_NOT_OPEN"

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

timeout=3.0,
driver = FakeMiniFP54Driver()

!Інтерфейс └── tests/

baudrate=115200,
pass
 import win32com.client
 )
Python-сервіс

 except Exception as exc:

 duration = round(time.time() - started_at, 3)
 """
 driver.close_receipt()

 def open_receipt(self) -> str:
 )
 encoding: str = "cp1251"

 except OSError:
 def pay_cash(self, amount: float) -> str:
 command = raw.decode("cp1251", errors="replace")

!Що робити
!Висновок

Linux:
stopbits=serial.STOPBITS_ONE,
return "OK;MINI-FP54.01;5401F3\n"

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

"""

2. |- |Bluetooth |Опційне підключення |здатна використовуватися зі смартфоном або планшетом за наявності сумісного ПЗ. # Налаштувати касирів. 4. # Налаштувати податкові групи. |- | style="background:#d4edda; color:#155724; font-weight:bold;" |Можливо |Для Linux/macOS можна реалізувати власний драйвер через serial-порт |Потрібна реалізація протоколу обміну з фіскальним реєстратором. |- | style="background:#f8d7da; color:#721c24; font-weight:bold;" |Небезпечно |Не можна ігнорувати помилки фіскального реєстратора. |- | style="background:#fff3cd; color:#856404; font-weight:bold;" |Обовʼязково |Чи правильний COM-порт. try: logging.basicConfig(

конкурентні переваги:

</syntaxhighlight> !Статус !Коментар

level=logging.INFO,
raw = ser.readline()
self.total = 0.0
def close_receipt(self) -> str:
if not self.receipt_opened:

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

/dev/tty.usbserial-*
└── test_errors.py
if not self.receipt_opened:

Мінімальний чек-лист smoke-тесту

Рекомендована схема для Windows:

Для розробки без фізичного пристрою варто використовувати mock-драйвер або serial-емулятор. |}

 total = winreg.QueryInfoKey(root)[0]

├── interfaces.py

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

 ↓
== Python-інтеграція ==
Без фізичного МІНІ-ФП54.01 можна тестувати не сам фіскальний реєстратор, а логіку інтеграції. |-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Обережно
|Офіційних Python-прикладів не знайдено
|Python можна використовувати через pywin32 або pyserial, але готового SDK саме для Python на сторінці підтримки немає. Реальна назва методу здатна бути OpenPort, openPort або іншою. |-
| style="background:#f8d7da; color:#721c24; font-weight:bold;" |Не достатньо
|Без реалізації контрольної суми та службових байтів це не production-драйвер. |-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Обовʼязково
|Чи правильні назви методів. def get_version(self):
 return "ERROR;SHIFT_NOT_OPEN"
Недоліки:
 - ACK/NAK;
=== USB-підключення ===
 Базовий serial-клієнт для МІНІ-ФП54.01.== Джерела ==
 def __init__(self, config: MiniFP54SerialConfig):
!Причина
 ser.flush()
!Пакет Python
|-
| style="background:#d4edda; color:#155724; font-weight:bold;" |Добре для розробки
|Емулятор дає можливість тестувати POS-сценарії без фізичного пристрою. |-
| style="background:#d4edda; color:#155724; font-weight:bold;" |Обовʼязково
|Наприкінці зміни потрібно виконувати Z-звіт. |-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Перевірити
|Потрібно встановити USB-драйвер виробника. |-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Перевірити
|Потрібен фізичний COM-порт або USB-RS232 адаптер. for attempt in range(1, retries + 1):

 self.connection: serial.Serial | None = None
 def open_shift(self) -> str:
 try:

!Що треба перевірити перед запуском
 def close_shift(self):

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

 time.sleep(delay)
=== macOS ===

Linux не виступає як основною цільовою платформою для офіційного OLE/DLL-драйвера. |-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Потрібно
|Реалізувати протокол обміну. |-
| style="background:#d4edda; color:#155724; font-weight:bold;" |Рекомендовано
|Для Windows використовувати офіційний DLL / OLE-сервер
|Це найшвидший шлях інтеграції з POS-системою або Python-застосунком через COM/OLE. |-
| style="background:#f8d7da; color:#721c24; font-weight:bold;" |Немає
|Готового офіційного Python SDK для Linux не знайдено. Наприкінці дня друкувати Z-звіт.=== Підготовка ===
try:
<syntaxhighlight lang="python"> from abc import ABC, abstractmethod
Схема:<pre>
 f"RECEIPT_OPENED={self.receipt_opened}"
POS-система / касова програма
{| class="wikitable"
|-
|OLE/DLL
|pywin32
|Windows
|Найпростіший варіант, якщо встановлено OLE-сервер. Реальну команду потрібно брати з протоколу обміну. Перевірити звʼязок із POS-системою. |-
|Ethernet
|Передача даних через інтернет
|застосовується для для звʼязку з ДПС. |-
| style="background:#f8d7da; color:#721c24; font-weight:bold;" |Ризик
|Дешеві USB-RS232 адаптери можуть давати нестабільний звʼязок. Але Python можна використовувати у двох режимах:

!Перевірка

!Статус
)

def execute_with_retry(command, retries: int = 3, delay: float = 1.0):

"OK;"

МІНІ-ФП54.01

if not self.shift_opened:
@abstractmethod
command_name,
- контрольну суму;
 def test_payment_less_than_total():

 
Unit / integration tests

<syntaxhighlight lang="python"> from mini_fp54_ole import MiniFP54OleDriver
 if self.shift_opened:

3. !Примітка
{| class="wikitable"
 
macOS:
 return response.decode(self.config.encoding, errors="replace")
 def get_status(self) -> str:
|-
| style="background:#d4edda; color:#155724; font-weight:bold;" |Рекомендовано
|Windows  найпростіша ОС для інтеграції через офіційний OLE/DLL. Python можна використовувати через пакет `pywin32`, якщо встановлено та зареєстровано OLE-сервер. |}

 pass
 MiniFP54SerialConfig(

!Статус

Типові помилки інтеграції

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

assert result == "ERROR;PAYMENT_LESS_THAN_TOTAL"

</syntaxhighlight>

Емуляція serial-пристрою без фізичного РРО

Для тестування serial-драйвера без пристрою можна зробити локальний емулятор.

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

return self.connection.read(read_size)
started_at = time.time()
pass

!Статус

return "ERROR;SHIFT_ALREADY_OPEN"

Базова структура Python-обгортки

/dev/pts/3

payload = command.encode(self.config.encoding)

!Коментар

- довжину;

class MiniFP54SerialClient:

Python-обгортка над OLE-сервером Юнісістем. # Перевірити Ethernet або GSM/GPRS для передачі даних. |}
for index in range(total):
timeout: float = 3.0
Очікуваний результат
Кількість товарів 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-порт. return "OK;SHIFT_OPENED"
 socat -d -d pty,raw,echo=0 pty,raw,echo=0
if any(keyword.lower() in name.lower() for keyword in keywords):

!Висновок

Типовий робочий цикл

Це не повний драйвер. # Підключити пристрій через USB або RS-232. |-

| style="background:#d4edda; color:#155724; font-weight:bold;" |Корисно |Така структура підходить для побудови власного драйвера. |}

COM3, COM4, COM5 ... Це дає можливість перевірити POS-логіку, але не замінює тестування з реальним РРО. # Виконати команду отримання статусу. print("Status:", driver.get_status())

assert result == "OK;PAYMENT_ACCEPTED;CHANGE=0.00"

Python / C# / 1C / інше ПЗ

  • дату й час команди;
  • тип команди;
  • параметри команди;
  • відповідь пристрою;
  • код помилки;
  • COM-порт;
  • тривалість виконання;
  • номер чека;
  • номер зміни. Реальний формат треба взяти з протоколу обміну. name="Кава",

driver = MiniFP54OleDriver(PROG_ID)

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

|- |USB |Підключення до ПК |базовий варіант для POS-інтеграції. |}

driver.sell_item("Кава", price=50.00, quantity=2)
def sell_item(self, name: str, price: float, quantity: float) -> str:
return f"OK;RECEIPT_CLOSED;TOTAL={self.total:.2f}"

!Статус

 def test_success_sale_flow():

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

 def sell_item(self, name: str, price: float, quantity: float) -> str:
МІНІ-ФП54.01
!Статус
 

Типова схема підключення:<pre>

 if self.receipt_opened:

<syntaxhighlight lang="python"> import winreg

!ОС
== Ethernet, GSM/GPRS і Bluetooth ==

=== Приклад smoke-тесту через OLE ===
 timeout=self.config.timeout,
finally:
{| class="wikitable"
USB або COM
 def disconnect(self):
=== Рекомендований retry-механізм ===
 print("Open port:", driver.open_port(port=3, baudrate=115200))
 def close_shift(self) -> str:
 driver.open_shift()
 def __init__(self, prog_id: str):
|-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |критично
|Назва ProgID у прикладах нижче умовна. def get_status(self) -> str:
 result = command()
 return (
</pre>
 command_name,
 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:
 self.connection.write(payload)
 Приклад. # Виконати персоналізацію. |}

{| class="wikitable"
 assert result == "OK;RECEIPT_CLOSED;TOTAL=100.00"
 driver.open_receipt()
9.=== Встановлення залежності ===
 def open_shift(self) -> str:
├── config.py
<syntaxhighlight lang="python"> class FakeMiniFP54Driver(FiscalDriverInterface):
<syntaxhighlight lang="python"> import time
 @abstractmethod
 result = driver.sell_item("Кава", price=50.00, quantity=2)
!Варіант
POS-система
/dev/ttyUSB0 або /dev/ttyS0
!Значення

МІНІ-ФП54.01 найпростіше інтегрувати у Windows через офіційний DLL/OLE-сервер. # Перевірити передачу даних. |-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Контроль
|Потрібно перевіряти статус передачі даних. Після встановлення USB-драйвера пристрій зазвичай функціонує як віртуальний COM-порт. Окремо варто відзначити контрольну стрічку в електронній формі, інтерфейси підключення до ПК через '''USB''' або '''RS-232''', а так само канали передачі даних через '''Ethernet''' і '''GSM/GPRS'''. Але інтеграційні функції ERP можлива через serial-порт, якщо реалізувати протокол обміну. Пробивати чеки продажу. result = driver.pay_cash(50.00)
 def connect_to_ole(self):
 driver = FakeMiniFP54Driver()
|-
| style="background:#d4edda; color:#155724; font-weight:bold;" |Обовʼязково
|Усі операції продажу мають проходити через фіскальний реєстратор. # Налаштувати типи оплат. |-
|Serial
|pyserial
|Windows / Linux / macOS
|Потрібна реалізація протоколу обміну. За потреби друкувати X-звіт. Перевірити передачу даних. OLE/DLL Юнісістем
 client.disconnect()
 return result
 - Назви методів потрібно звірити з документацією до конкретної версії OLE. # Перевірити роботу POS-системи з реальним драйвером. duration = round(time.time() - started_at, 3)
!Коментар
=== Пошук ProgID OLE-сервера ===
class FiscalDriverInterface(ABC):
 """
1. return "OK;RECEIPT_OPENED"
 def get_status(self):

 return self.driver.ZReport()
 name = winreg.EnumKey(root, index)
)
8.

Простий Python-емулятор

return "OK;PAYMENT_ACCEPTED\n"
"command=%s duration=%s result=%s",
 from mini_fp54_serial import MiniFP54SerialClient, MiniFP54SerialConfig

 print(f"Fake MINI-FP54.01 emulator started on {PORT}")
 driver.open_receipt()
 price=50.00,

PORT = "/dev/pts/4" BAUDRATE = 115200

 return "ERROR;RECEIPT_IS_OPEN"
Офіційних прикладів саме для Python на сторінці підтримки не знайдено. # Провести тестовий день роботи.== Логування ==
 - службові байти;
== Обробка помилок ==

 return "ERROR;RECEIPT_ALREADY_OPEN"
try:
if not self.items:

keywords = ["Ecr", "T400", "MINI", "FP", "Unisystem", "Uni"]

!Коментар Перед production-запуском потрібно: !Тест

Пристрій має акумулятор. - парсинг статусів і помилок. ser.write(response.encode("cp1251")) Можна створити пару віртуальних serial-портів через `socat`. # Налаштувати заголовок і підвал чека. Відкрити зміну. ├── logger.py

last_error = result
if command.startswith("PAY"):
↓
self.config = config
exc,
return "ERROR;EMPTY_RECEIPT"

Приклад логування в Python

FakeMiniFP54Driver

"""

RS-232 підходить для класичних POS-систем, касових терміналів і embedded-рішень.== Основні характеристики ==

driver.sell_item(
return "ERROR;RECEIPT_NOT_OPEN"

</syntaxhighlight>

print("Close port:", driver.close_port())
 pip install pyserial

технічна архітектура тестування без пристрою

</syntaxhighlight>

Один порт використовує тестовий POS-драйвер, інший — емулятор пристрою. command = command.strip()

FiscalDriverInterface

if not self.connection or not self.connection.is_open:
↓
 import serial
</pre>
def log_fiscal_command(command_name: str, callback):
!Файл
 logging.info(
|-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Умовний приклад
|Команда GET_STATUS наведена як приклад. result = driver.pay_cash(100.00)
 """
<syntaxhighlight lang="powershell"> Get-ChildItem "Registry::HKEY_CLASSES_ROOT" |
 def close_port(self):
{| class="wikitable"
|-
|1
|Відкрити порт
|Драйвер не повертає помилку
|-
|2
|Отримати статус
|Пристрій відповідає
|-
|3
|Отримати версію ПЗ
|Повертається реліз системи пристрою
|-
|4
|Перевірити папір
|Немає помилки паперу
|-
|5
|Відкрити зміну
|Зміна відкрита
|-
|6
|Відкрити чек
|Чек відкритий
|-
|7
|Додати товар
|Рядок товару надруковано або прийнято
|-
|8
|Провести оплату
|Оплата прийнята
|-
|9
|Закрити чек
|Чек закритий
|-
|10
|Надрукувати X-звіт
|Звіт друкується без закриття зміни
|-
|11
|Надрукувати Z-звіт
|Зміна закрита
|-
|12
|Перевірити передачу даних
|інформаційні дані передаються через Ethernet або GSM/GPRS
|}

 self.shift_opened = False
driver = MiniFP54OleDriver("PUT_REAL_PROG_ID_HERE") driver.connect_to_ole()

{| class="wikitable"
 baudrate=self.config.baudrate,

# Зареєструвати РРО. |-
| style="background:#f8d7da; color:#721c24; font-weight:bold;" |Не запускати в production
|Поки не перевірено на тестовому РРО або у нефіскальному режимі. |-
| style="background:#f8d7da; color:#721c24; font-weight:bold;" |Не робити
|Не підключати одночасно USB і RS-232 до одного ПК
|Для роботи з ПК потрібно використовувати один інтерфейс підключення. |-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Не замінює РРО
|Емулятор не перевіряє реальний фіскальний протокол. |-
| style="background:#f8d7da; color:#721c24; font-weight:bold;" |Не готово з коробки
|Офіційного macOS SDK не знайдено.<pre>
 driver.open_port(port=3, baudrate=115200)
=== Unit-тест успішного продажу ===
 @abstractmethod
Реальний режим — це робота з фіскалізованим пристроєм, який застосовується для для реєстрації розрахункових операцій. Її треба уточнити після встановлення реального OLE-сервера. Увімкнути фіскальний реєстратор. 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:
|-
| style="background:#d4edda; color:#155724; font-weight:bold;" |Добре
|USB простіше використовувати на сучасних робочих місцях. with serial.Serial(PORT, BAUDRATE, timeout=1) as ser:
 parity=serial.PARITY_NONE,
 if self.receipt_opened:

 return self.driver.GetStatus()
 return "OK;Z_REPORT_PRINTED"



Мета тестування без пристрою:
 result = callback()

!Статус

6. |}

 )
assert result == "OK;ITEM_ADDED;100.00"
- формат пакета;
self.connection.flush()

Недоліки: Це найпростіший варіант для Windows. Перевірити папір. |- |Mock-драйвер |pytest / unittest |Будь-яка |Для тестування без фізичного пристрою. except Exception as exc:

Умовний приклад текстової команди. return "ERROR;SHIFT_NOT_OPEN"
Значення
bytesize=serial.EIGHTBITS,
def pay_cash(self, amount: float): ├── fake_driver.py def close_shift(self) -> str: continue last_error = None return self.driver.OpenReceipt() return self.driver.OpenShift() while True: response = self.send_raw(payload) 5. |} return "ERROR;RECEIPT_NOT_OPEN"
Висновок
self.shift_opened = True
"command=%s duration=%s error=%s",
↓
return self.driver.OpenPort(port, baudrate)
USB або RS-232 ├── errors.py raise FiscalCommandError(f"Command failed after {retries} retries: {last_error}") if self.connection and self.connection.is_open: port="COM3", # Linux: "/dev/ttyUSB0" finally: self.receipt_opened = False with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, "") as root:
 Для реальної роботи потрібно реалізувати офіційний протокол:
 logging.exception(
 )

RS-232 / COM-порт

├── test_fake_driver.py self.connection = serial.Serial( if isinstance(result, str) and result.startswith("OK"):
return "OK;ITEM_ADDED\n" assert driver.open_shift() == "OK;SHIFT_OPENED" assert driver.open_receipt() == "OK;RECEIPT_OPENED"

Короткий SEO-опис

↓ Цей варіант підходить для Windows, Linux, macOS та embedded-систем. pyserial self.items = []
 import serial from dataclasses import dataclass
 def sell_item(self, name: str, price: float, quantity: float, tax_group: int = 1):
|-
| style="background:#fff3cd; color:#856404; font-weight:bold;" |Можливо
|Потрібна власна serial-інтеграція. # Переконатися, що застосовується для тільки один інтерфейс.== Операційні системи ==

{| class="wikitable"

!Коментар
 self.receipt_opened = False
↓ last_error = exc Python → pyserial → протокол обміну → USB/COM або RS-232 → МІНІ-ФП54.01 return "OK;RECEIPT_CLOSED\n"
 pip install pywin32
Після встановлення OLE-сервера потрібно знайти його ProgID. !Призначення return self.driver.CloseReceipt() POS-система * Офіційна сторінка МІНІ-ФП54.01: https://unisystem.ua/catalog/fiskalnye-registratory/fiskalnyj-registrator-mini-fp54-01/ * Сторінка підтримки Юнісістем: https://unisystem.ua/podderzhka/