1. Przygotowanie pliku z danymi JSON.
Plik wsadowy składa się z jednego głównego obiektu nadrzędnego, w którym wyróżniamy cztery kluczowe sekcje logiczne. Taki podział gwarantuje porządek w danych i ułatwia późniejsze mapowanie pól w lewym panelu edytora.

Poniższy plik JSON zawiera pełne, ustrukturyzowane dane transakcji dla fikcyjnego sklepu elektronicznego, uwzględniające rabaty, podziały stawek VAT oraz informacje o płatności.
{
"receipt_details": {
"store_info": {
"company_name": "TechNova Sp. z o.o.",
"brand_name": "TechNova - Strefa Elektroniki",
"address": "31-154 Krakow, ul. Pawia 5",
"city_address": "Galeria Nova, Poziom +1",
"bdo_number": "000099887",
"nip_number": "525-00-11-222"
},
"transaction_info": {
"print_date": "2026-05-25",
"print_time": "14:35",
"print_number": "412533/0892",
"transaction_number": "28471",
"cashier_number": "104",
"pos_id": "POS-03"
},
"totals": {
"total_amount": "234,40",
"discount_total": "15,00",
"payment_method": "KARTA PLATNICZA"
},
"vat_aggregates": {
"vat_typeA_base": "154,39",
"vat_typeA_amount": "35,51",
"vat_typeA_rate": "23,00%",
"vat_typeB_base": "41,20",
"vat_typeB_amount": "3,30",
"vat_typeB_rate": "08,00%",
"vat_total_amount": "38,81"
},
"items": [
{
"product_name": "Sluchawki BT NovaSound",
"quantity": 1,
"unit_price": "149,90",
"total_price": "149,90 A"
},
{
"product_name": "Kabel USB-C Premium 2m",
"quantity": 2,
"unit_price": "19,75",
"total_price": "39,50 B"
},
{
"product_name": "Ladowarka Sieciowa 30W",
"quantity": 1,
"unit_price": "60,00",
"total_price": "60,00 A"
}
],
"marketing": {
"loyalty_card": "9876543210",
"points_earned": "45",
"footer_promo": "Zyskaj 10% rabatu na kolejne zakupy!"
}
}
}
Dane Sprzedawcy (store_info) – Zawiera stałe dane teleadresowe sklepu lub firmy. Wszystkie pola w tej sekcji są tekstowe (String).
- company_name: Oficjalna nazwa rejestrowa spółki.
- brand_name: Nazwa handlowa widoczna na samej górze paragonu.
- address & city_address: Dane lokalizacyjne.
- nip_number & bdo_number: Numery identyfikacji podatkowej i środowiskowej.
Metryka Transakcji (transaction_info)Te dane zmieniają się przy każdym wydruku.
- print_date & print_time: Data i godzina (rekomendowany format: YYYY-MM-DD oraz HH:MM).
- print_number: Unikalny licznik wydruku z danej drukarki.
- transaction_number: Numer zamówienia lub transakcji z systemu POS.
- cashier_number: Identyfikator pracownika (może być liczbą lub tekstem).
Podsumowanie Finansowe (totals)Kluczowe pola liczbowe, przekazywane jako tekst z separatorem dziesiętnym w postaci przecinka (ułatwia to poprawne formatowanie bezpośrednio na drukarce).
- total_amount: Ostateczna kwota do zapłaty.
- payment_method: Sposób płatności (np. KARTA, GOTÓWKA, BLIK).
Agregaty Podatkowe (vat_aggregates)Słownik przechowujący podsumowanie stawek VAT. W przypadku systemów niefiskalnych OPOS, każdą stawkę (A, B, C…) opisujemy trzema polami:
- base: Podstawa opodatkowania w danej stawce.
- amount: Kwota naliczonego podatku.
- rate: Procentowa wartość stawki (np. „23,00%”).
Wykaz Pozycji – Kolekcja Dynamiczna (items)To najważniejsza część struktury – tablica (oznaczona nawiasami kwadratowymi […]), która zawiera listę zakupionych towarów. Każdy produkt na liście musi być osobnym obiektem posiadającym dokładnie te same klucze:
- product_name (String): Nazwa towaru.
- quantity (Integer/Numeric): Ilość zakupionych sztuk.
- unit_price (String): Cena za jedną sztukę.
- total_price (String): Cena łączna (ilość x cena jednostkowa) uzupełniona o literowe oznaczenie stawki VAT (np.
- „149,90 A”), co jest standardem dla czytelności paragonu.
Gotowy plik należy zapisać w formacie JSON, następnie zaimportować do Comarch sPrint Wydruki OPOS wybierając „Prześlij plik z danymi”

Można skorzystać z opcji „Przeciągnij i upuść” lub „wybierz plik”

2. Przygotowanie definicji wydruku JSON.
Po zainicjowaniu nowego projektu szablonu wydruku OPOS w aplikacji, w obszarze roboczym automatycznie generowana jest struktura startowa. Stan ten przedstawia poniższy zrzut ekranu:

Wyjaśnienie elementów startowych:
- maxlength: Globalny parametr określający maksymalną szerokość linii w znakach. Domyślna wartość 56 jest optymalna dla szerszych taśm papieru. Na potrzeby naszego case study (standardowa węższa rolka) wartość tę zmodyfikujemy do 42, aby zapewnić idealne wyrównanie kolumn na wydruku o szerokości około 58 mm.
- body: Główna tablica (kontener), wewnątrz której będziemy umieszczać kolejne sekcje, linie i komendy sterujące drukarką (takie jak bloki tekstu, pętle czy polecenie cięcia papieru).
Budując profesjonalny szablon paragonu dla sklepu TechNova, wykorzystamy pełen wachlarz narzędzi systemu sPrint. Poniżej opisujemy kluczowe moduły szablonu wraz ze wskazaniem odpowiednich tagów i funkcji.
Podstawowym elementem budulcowym każdej definicji wydruku OPOS jest linia, reprezentowana w kodzie jako obiekt o typie Line. Każda instancja tego obiektu odpowiada za wyrenderowanie dokładnie jednego fizycznego, poziomego wiersza tekstu na taśmie papieru.
Gdzie wstawić kod nowej linii? Wszystkie linie tworzące strukturę paragonu muszą znajdować się wewnątrz nawiasów kwadratowych głównej tablicy „body”: [].
W standardzie JSON nawiasy kwadratowe oznaczają listę (tablicę) elementów, które na wydruku będą układane chronologicznie – od góry do dołu.
Wstawianie pierwszej linii: Obiekt należy umieścić bezpośrednio wewnątrz pustych nawiasów
"body": [
/* Miejsce na nowe linie*/
]
Dodawanie kolejnych linii: Każdy kolejny obiekt linii musi być bezwzględnie oddzielony od poprzedniego przecinkiem np.:
}, {W przypadku korzystania z narzędziownika i użycia ikony „Wstaw linię”, program automatycznie weryfikuje pozycję kursora. Jeżeli kursor znajduje się wewnątrz sekcji body, edytor samoczynnie dba o poprawność struktury i automatycznie wstawia wymagane przecinki separujące.

W momencie wywołania funkcji „Wstaw linię”, aplikacja generuje w obszarze roboczym pełny szablon obiektu zawierający wszystkie domyślne parametry formatowania. Eliminuje to konieczność pamiętania nazw właściwości sterujących sterownikiem OPOS.

Każdy z wygenerowanych automatycznie parametrów odpowiada za określone zachowanie wiersza na fizycznym wydruku:
- Type („Line”): Identyfikator typu obiektu. Informuje silnik renderujący o utworzeniu nowego fizycznego wiersza.
- Items: Tablica (kontener) na elementy składowe wiersza. Domyślnie system umieszcza w niej jeden pusty obiekt tekstowy („Type”: „Text”, „Value”: „”), w którym docelowo wpisuje się statyczny tekst lub zamienia go na obiekt dynamiczny („Type„: „Data„).
- Bold / Italic / Underline (false): Flagowe sterowniki stylów czcionki (kolejno: pogrubienie, kursywa, podkreślenie). Zmiana wartości na true aktywuje dany styl dla całego tekstu znajdującego się w tej linii.
- DoubleWide / DoubleHeight (false): Parametry odpowiedzialne za sprzętowe powiększenie czcionki przez drukarkę. DoubleWide rozciąga znaki w poziomie, a DoubleHeight w pionie. Aktywacja obu parametrów jednocześnie (true) pozwala na uzyskanie efektu dużej, czytelnej czcionki tytułowej lub sumarycznej.
- Align („Left”): Globalne wyrównanie zawartości linii na papierze. Domyślnie tekst dosuwany jest do lewej krawędzi. Dostępne wartości to również „Center” (wyśrodkowanie – stosowane w nagłówkach) oraz „Right” (wyrównanie do prawej).
- MaxLines (1): Kluczowy parametr bezpieczeństwa układu graficznego. Wartość 1 gwarantuje, że jeśli dane wstrzyknięte do linii będą dłuższe niż pozwala na to szerokość papieru (zdefiniowana w maxlength), tekst zostanie bezpiecznie przycięty w jednej linii, co zapobiega niekontrolowanemu zawinięciu i rozbiciu struktury kolejnych wierszy poniżej.
Połączenie tekstu statycznego z danymi dynamicznymi
Przed przystąpieniem do budowy zaawansowanych pętli dynamicznych, zaleca się oswojenie z mechanizmem interpretacji danych przez silnik sPrint. W tym celu w strukturze body należy umieścić dwa podstawowe wiersze: jeden reprezentujący treść niezmienną, a drugi mapujący informację bezpośrednio z pliku źródłowego JSON.
Poniższy kod ilustruje poprawnie zainicjowany początek sekcji nagłówkowej w obszarze roboczym:
{
"maxlength": 42,
"body": [
{
"Type": "Line",
"Items": [
{
"Type": "Text",
"Value": "TechNova - Strefa Elektroniki"
}
],
"Bold": true,
"Align": "Center",
"MaxLines": 1
},
{
"Type": "Line",
"Items": [
{
"Type": "Text",
"Value": "NIP: "
},
{
"Type": "Data",
"Path": "receipt_details.store_info.nip_number"
}
],
"Align": "Center",
"MaxLines": 1
}
]
}
Struktura tablicy body: Widoczne są dwa obiekty typu Line ułożone jeden po drugim, oddzielone obowiązkowym przecinkiem. Na fizycznym wydruku przełoży się to na dwa osobne, wycentrowane wiersze.
Użycie obiektu Text (Linia 1): W pierwszej linii parametr Value przechowuje sztywny ciąg znaków „TechNova – Strefa Elektroniki”. Tekst ten będzie identyczny dla każdego generowanego dokumentu. Dodatkowo włączono pogrubienie („Bold”: true).
Użycie obiektu Data (Linia 2): Druga linia demonstruje łączenie etykiety statycznej z parametrem dynamicznym wewnątrz jednej tablicy Items.
- Pierwszy element to stały napis „NIP: „.
- Drugi element to obiekt typu „Type”: „Data”. Nie posiada on parametru Value, lecz parametr Path (ścieżkę). Wskazuje ona bezpośrednio na pole receipt_details.store_info.nip_number w pliku wsadowym klienta. Podczas generowania wydruku system automatycznie podstawi tam wartość „525-00-11-222”.
Taki schemat działania stanowi bazę dla wszystkich kolejnych operacji na szablonie.
Pobieranie ścieżek z panelu bocznego (Parametr Path)
W lewym panelu bocznym aplikacja wizualizuje strukturę danych w postaci interaktywnego drzewa. Obok każdej zmiennej dostępna jest ikona plusa + („Dodaj do definicji”). Kliknięcie ikony lub przeciągnięcie elementu wprost do obszaru roboczego powoduje automatyczne wygenerowanie i wklejenie poprawnej ścieżki kropkowej w miejscu kursora (np. „receipt_details.store_info.nip_number”).
Autouzupełnianie składni (Skrót klawiszowy Ctrl + Space)
Ręczne wpisywanie znaczników strukturalnych nie jest wymagane, co zapobiega powstawaniu błędw w strukturze pliku JSON.

- Wywołanie kontekstowe: Po ustawieniu kursora wewnątrz cudzysłowu dla parametru „Type”: „” i naciśnięciu kombinacji klawiszy Ctrl + Space, system automatycznie wyświetli rozwijaną listę z poprawnymi, predefiniowanymi typami składników wydruku (np. Barcode, Line, NewLine, PaperCut).
- Podpowiedzi dla właściwości: Skrót działa również wewnątrz obiektów. Po wpisaniu znaku cudzysłowu na początku pustej linii, naciśnięcie Ctrl + Space wywołuje listę parametrów i stylów dostępnych dla danego elementu (np. Align, Bold, Italic, Length, Underline).
Zamiast ręcznego wpisywania komend, wybiera się żądany element bezpośrednio za pomocą myszy lub strzałek klawiatury. Zapobiega to powstawaniu błędów składniowych, takich jak literówki czy niepoprawnie domknięte cudzysłowy w pliku JSON.
Dynamiczne generowanie pozycji towarowych za pomocą pętli (Type: Repeat)
Dynamiczne generowanie pozycji towarowych za pomocą pętli (Type: Repeat) W celu sprawnego generowania list produktów na wydruku, których liczba zmienia się w zależności od transakcji, stosuje się obiekt typu Repeat. Działa on jak pętla programistyczna, która iteruje po wskazanej kolekcji danych i powiela zdefiniowany wewnątrz niej układ graficzny.
Inicjalizacja pętli w edytorze
Obiekt Repeat umieszcza się jako kolejny element nadrzędny w tablicy „body”: []. Można go wywołać bezpośrednio z narzędziownika, klikając ikonę z dwiema strzałkami i etykietą „Powtarzaj elementy”.

Po wywołaniu tej funkcji, w obszarze roboczym generowany jest następujący, czysty kod startowy:
{
"Type": "Repeat",
"DataMember": "",
"Items": []
}
Type („Repeat„): Identyfikator informujący silnik sPrint, że ten blok kodu odpowiada za operację cyklicznego powtarzania elementów.
DataMember: Puste pole tekstowe, w którym należy wskazać ścieżkę do tablicy (kolekcji obiektów) z pliku źródłowego JSON.
Items: Pusta tablica przeznaczona na umieszczenie szablonu wiersza (obiektu Line), który ma być powielany dla każdego elementu z pliku danych.
Konfiguracja i mapowanie kolekcji krok po kroku
Po wstawieniu bloku startowego, proces konfiguracji przebiega dwuetapowo: wskazanie źródła danych oraz zdefiniowanie wyglądu wiersza.
1. Określenie źródła danych
W polu DataMember należy podać ścieżkę do kolekcji produktów. Najwygodniejszym sposobem jest skorzystanie z lewego panelu bocznego, odnalezienie sekcji zawierającej listę (w omawianym przypadku jest to sekcja items) i kliknięcie znajdującej się przy niej ikony plusa +. Ścieżka zostanie automatycznie wstrzyknięta do kodu:
"DataMember": "receipt_details.items"
2. Wstawienie wzorca wiersza do tablicy Items
Pętla Repeat wymaga zdefiniowania układu graficznego dla pojedynczego towaru. W tym celu należy ustawić kursor wewnątrz pustej tablicy „Items„: [] i kliknąć znaną z poprzedniego kroku ikonę „Wstaw linię„. Edytor automatycznie wygeneruje pełny obiekt typu Line wewnątrz pętli:
{
"Type": "Repeat",
"DataMember": "receipt_details.items",
"Items": [
{
"Type": "Line",
"Items": [
{
"Type": "Data",
"Path": "receipt_details.items.product_name",
"Length": 22
},
{
"Type": "Data",
"Path": "receipt_details.items.quantity",
"Length": 3,
"Align": "Right"
},
{
"Type": "Text",
"Value": " x "
},
{
"Type": "Data",
"Path": "receipt_details.items.unit_price",
"Length": 7,
"Align": "Right"
},
{
"Type": "Text",
"Value": " = "
},
{
"Type": "Data",
"Path": "receipt_details.items.total_price",
"Length": 8,
"Align": "Right"
}
],
"Align": "Left",
"MaxLines": 1
}
]
}
Podczas renderowania pozycji asortymentowych sPrint przetwarza zagnieżdżone elementy w następujący sposób:
- Pętla sprzętowa: System sprawdza wielkość tablicy w pliku wsadowym i automatycznie powiela obiekt Line dokładnie tyle razy, ile pozycji zakupił klient.
- Wielopoziomowy parametr Path: Podelementy typu „Type„: „Data” wewnątrz pętli odnoszą się bezpośrednio do pól pojedynczego obiektu z listy (np. product_name, quantity). Ścieżki te zachowują notację kropkową rozpoczynającą się od nazwy kolekcji.
- Wyrównanie kolumnowe (Formatowanie tabelaryczne): Poprzez nadanie sztywnych szerokości za pomocą parametru Length (22 dla nazwy, 3 dla ilości, 7 dla ceny jednostkowej, 8 dla sumy) oraz znaków oddzielających Text (dwukrotnie po 3 znaki ze spacjami), uzyskuje się łączną szerokość linii równą dokładnie 42 znakom (23 + 3 + 3 + 7 + 3 + 8 = 42). Sprawia to, że dane na wydruku układają się w równe sekcje pionowe, a zastosowanie „Align„: „Right” dla wartości liczbowych gwarantuje ich czytelne dosunięcie do prawej krawędzi kolumn.
Implementacja instrukcji warunkowej (Type: Conditional)
W celu wprowadzenia logiki biznesowej do wydruku (np. wyświetlania sekcji marketingu lub danych karty lojalnościowej tylko wtedy, gdy klient ją posiada) stosuje się strukturę warunkową.
Inicjalizacja instrukcji warunkowej
Instrukcję wprowadza się do tablicy body poprzez kliknięcie ikony „if” na pasku narzędziowym lub za pomocą skrótu Ctrl + Space i wybrania opcji Conditional z listy autouzupełniania.

Po wywołaniu funkcji, w obszarze roboczym generowany jest następujący czysty kod startowy:
{
"Type": "Conditional",
"Expression": "",
"Fulfilled": [],
"Unfulfilled": []
}
Expression: Pole tekstowe, w którym definiuje się warunek logiczny (np. sprawdzenie, czy pole z numerem karty klienta nie jest puste).
Fulfilled: Tablica (kontener), w której umieszcza się obiekty (np. Line), które mają zostać wyrenderowane na paragonie wyłącznie wtedy, gdy warunek wpisany w Expression jest spełniony (true).
Unfulfilled: Tablica (kontener) przeznaczona na elementy, które mają się pojawić na wydruku tylko w sytuacji, gdy warunek nie jest spełniony (false) (odpowiednik instrukcji else).
Praktyczny przykład (Sekcja karty lojalnościowej)
Poniższy kod przedstawia kompletną strukturę warunkową, która drukuje szczegółowe informacje o karcie w momencie jej wykrycia, natomiast w przypadku jej braku wyświetla ogólny komunikat zachęcający do dołączenia do programu lojalnościowego:
{
"Type": "Conditional",
"Expression": "receipt_details.marketing.loyalty_card != null",
"Fulfilled": [
{
"Type": "Line",
"Items": [
{
"Type": "Text",
"Value": "Karta Klienta: "
},
{
"Type": "Data",
"Path": "receipt_details.marketing.loyalty_card"
}
],
"Align": "Center",
"MaxLines": 1
}
],
"Unfulfilled": [
{
"Type": "Line",
"Items": [
{
"Type": "Text",
"Value": "Dolacz do Klubu i zbieraj punkty!"
}
],
"Align": "Center",
"MaxLines": 1
}
]
}
Blok podsumowania finansowego (DoubleWide, DoubleHeight)
Ostateczna kwota do zapłaty (SUMA PLN) stanowi najważniejszą informację handlową na dokumencie, w związku z czym wymaga zastosowania wyraźnego wyróżnienia wizualnego.
Do tablicy body dodaje się standardowy obiekt Line, wykorzystując parametry sprzętowego powiększenia wielkości czcionki:
{
"Type": "Line",
"Items": [
{
"Type": "Text",
"Value": "SUMA PLN",
"Length": 10
},
{
"Type": "Data",
"Path": "receipt_details.totals.total_amount",
"Align": "Right",
"Length": 11
}
],
"Bold": true,
"DoubleWide": true,
"DoubleHeight": true,
"Align": "Left",
"MaxLines": 1
}
Analiza techniczna parametrów podsumowania:
Łączenie stylów rozmiaru: Zgodnie ze specyfikacją silnika sPrint, jednoczesne ustawienie parametrów „DoubleWide„: true oraz „DoubleHeight”: true działa tożsamo z parametrem DoubleSize, aktywując czcionkę o podwójnej wysokości i szerokości.
Kalkulacja szerokości kolumn: Ponieważ czcionka w tym trybie jest fizycznie dwukrotnie szersza, efektywna pojemność linii na papierze maleje o połowę (ze standardowych 42 znaków na 21). Z tego powodu sumaryczna długość pól zdefiniowanych w parametrach Length (10 dla etykiety tekstowej oraz 11 dla dynamicznej kwoty) wynosi dokładnie 21, co idealnie równoważy szerokość paragonu i zapobiega błędom zawijania lub obcinania znaków.
Zakończenie wydruku i komendy sterujące (FeedLine, PaperCut)
Ostatnim etapem definiowania struktury dokumentu jest fizyczne zarządzanie wysuwem taśmy papieru oraz wywołanie mechanizmu gilotyny drukarki. W tym celu na samym końcu tablicy body umieszcza się sekwencyjnie dwa autonomiczne obiekty sterujące pracą urządzenia.
1. Wysunięcie paragonu (Type: FeedLine)
Polecenie wysunięcia papieru wprowadza się poprzez kliknięcie ikony z pionową strzałką i poziomą kreską oznaczającej „Wysuń paragon” (lub wybierając opcję FeedLine z menu rozwijanego / listy podpowiedzi).

Po wywołaniu tej funkcji, edytor generuje następujący, czysty kod strukturalny:
{
"Type": "FeedLine"
}2. Odcięcie paragonu (Type: PaperCut)
Polecenie aktywacji gilotyny wprowadza się poprzez kliknięcie ikony z symbolem nożyczek/kreski nacięcia oznaczającej „Odetnij paragon” (lub wybierając opcję PaperCut z menu rozwijanego / listy podpowiedzi).

Po wywołaniu tej funkcji, edytor generuje w obszarze roboczym obiekt kończący dokument:
{
"Type": "PaperCut"
}
Type („PaperCut„): Wysyła niskopoziomowy sygnał sterujący bezpośrednio do gilotyny urządzenia, co wywołuje fizyczne odcięcie gotowego paragonu.
3. Weryfikacja i podgląd końcowy wydruku
Po zakończeniu implementacji kodu JSON w obszarze roboczym , proces projektowania kończy się walidacją w prawym panelu aplikacji:
3.1. Aktywacja podglądu graficznego
Po zakończeniu implementacji kodu JSON w obszarze roboczym , proces projektowania kończy się walidacją w prawym panelu aplikacji:

Aplikacja pobiera rzeczywiste wartości z załadowanego pliku źródłowego i prezentuje dokładną wizualizację formatowania, tabelarycznego wyrównania kolumn oraz powiększeń czcionki w skali 1:1.
3.2. Interaktywne powiązanie podglądu z kodem
Prawy panel oferuje zaawansowaną funkcję dwukierunkowej interaktywności. Kliknięcie myszką bezpośrednio na dowolny element graficzny wyświetlony na podglądzie paragonu (np. na kwotę główną lub numer transakcji) skutkuje natychmiastowym przejściem kursora i podświetleniem odpowiadającej mu linii kodu JSON w centralnym obszarze roboczym. Pozwala to na błyskawiczne lokalizowanie i modyfikowanie poszczególnych sekcji dokumentu.

Przykładowy plik z danymi wsadowymi oraz definicja wydruku w formacie JSON są dostępne na stronach walidowanych dla partnerów.