Receipt Layout
Layout

For printing a fiscal transaction, the data has to be formatted, which is done using the HTML templating engine PUG (former JADE). Language details can be found on pugjs.org.
For Slovakian fiscal printers the item description and additional text lines may be formatted freely, but referring amounts are printed in a format that's predetermined by the printer.
The following rules occur for bbox eKasa fiscal receipts:
- All lines up to 48 characters
- Barcodes may be printed on the footer
- Paper is cut after print completion
You can start http://localhost:5618/peri/pugedit for layout configuration, it works as a WYSIWYG editor.
Besides fiscal.pug, different non-fiscal layout files can be provided in directory /EFR/rn/def/cfg, the exclusively lowercase file name is derived from the NF or DT tag:
NF="Login" => "login.pug"`
Transaction Time
The fiscal printer itself has a clock. Date and time printed on the receipt are printer time.
PUG Editor
Workflow:
- Start http://localhost:5618/peri/pugedit with a browser
- [Open] e.g. file
/EFR/rn/def/cfg/fiscal.pug - Copy your sample transaction data into the textbox at the left side
- The right side box shows the transaction data transformed to HTML
- Modifications in PUG code (center box) are shown immediately
- When finished [download] e.g. as fiscal.pug and copy it to
/EFR/rn/def/cfg/
The EFR now transforms every transaction into HTML and renders it to the line printer. By their nature, fiscal printers provide only very limited formatting functionality.
At the moment, the editor implementation is fairly basic, but it is going to be evolved as base technique for transaction rendering and print layout.
Layout Example
//- fiscal.pug - Layout for Fiscal Transactions
-
function fStr(str) { return str || str === 0 ? str.toString().replace(/\r/g, '') : '' }
function fDec(dec) { return fStr(dec).replace(/\./, ',') }
function fAmt(Amt) { return fDec(Amt && Amt.toFixed ? Amt.toFixed(2) : Amt) }
function fPrc(Prc) { return fDec((Prc+'%').replace(/%%$/, '%')) }
function fD(D) { return D.substr(8, 2) + '-' + D.substr(5, 2) + '-' + D.substr(2, 2) }
function fTime(D) { return D.substr(11, 8).replace(/^0/, '') }
mixin pos(p)
if p.Qty && p.Pri
.DscTxt= fDec(p.Qty) + ' ' + fStr(p.QtyU) + ' x ' + fAmt(p.Pri)
if p.TaxG
.Dsc= fStr(p.Dsc)
.TaxG= fStr(p.TaxG)
else
.Dsc2= fStr(p.Dsc)
if p.Amt
.Amt= fAmt(p.Amt)
else
.Amt= fStr(p.LAmt)
mixin tot(t)
hr
.Tot
.Dsc2 TOTAL
.Amt= fAmt(t)
hr
mixin pay(p)
if p.Amt
.DscTxt= fStr(p.Dsc)
.Amt= fAmt(p.Amt)
else
.DscTxt= ' ' + fStr(p.Dsc)
.Amt= fStr(p.LAmt)
mixin tax(t)
.DscTax
.Prc= fPrc(t.Prc)
.Net= fAmt(t.Net)
.TAmt= fAmt(t.TAmt)
.TaxG= fStr(t.TaxG)
.Amt= fAmt(t.Amt)
mixin head(h)
if h
br
each v, k in h
if '_' !== k
.Txt= v._ ? fStr(v.value) : fStr(v)
mixin foot(f)
if f
br
each v, k in f
if '_' !== k
.TxtCenter= v._ ? fStr(v.value) : fStr(v)
html
head
title= ESR.DT||ESR.NF||'Receipt'
style(type='text/css').
body {
font-family: Consolas, 'Courier New';
width: 46ch;
background-color: white;
}
.Txt { white-space: pre; }
.TxtCenter {
white-space: pre;
text-align: center;
}
.Net, .TAmt, .TaxG, .Amt { text-align: right; }
.Pos, .Mod, .Lin, .Tot, .Pay, .Tax, .ItemHead {
display: grid;
grid-template-columns: 37ch 1ch 8ch;
}
.Dsc { grid-column: 1; }
.Dsc2, .DscTxt { grid-column: 1 / span 2; }
.DscTxt { white-space: pre; }
.TaxG { grid-column: 2; }
.Amt { grid-column: 3; }
.DscTax {
width: 90%;
display: grid;
grid-template-columns: 4fr 10fr 10fr;
}
.Print { display: none; }
@media fiscal {
.Disp, .Tax, .Tot { display: none; }
.Print { display: block; }
}
body
//- Header
+head(ESR.Head)
//- Itemheader
hr
.Lin.Disp
.Dsc Item
.TaxG %
.Amt Amt
.Disp
hr
//- required, do not change
each p in ESR.PosA||[]
div(class=p._)
+pos(p)
+tot(ESR.T)
each p in ESR.PayA||[]
div(class=p._)
+pay(p)
if ESR.TaxA
br
each t in ESR.TaxA
div(class=t._)
+tax(t)
//- Footer
.Print
br
+foot(ESR.Foot)
hr
.TxtCenter= 'Terminal: ' + fStr(ESR.TL) + '/' + fStr(ESR.TT) + ' ' + fStr(ESR.DT || ESR.NF || 'Receipt') + ': ' + fStr(ESR.TN)
.TxtCenter= fD(ESR.D) + ' ' + fTime(ESR.D)
Restrictions
The fiscal printer allows only layout of header and footer lines and item text, amounts are formatted by the printer.
Although transaction data usually is provided with UTF-8 encoding, not all characters can be printed. e.g. printing of the Euro symbol is not allowed.
Barcode
To add a barcode to a fiscal or non-fiscal layout enter:
div
img(data-barcode="type=ean13" data-value="123456789012" style="width:30ch;height:3ch")
The data-barcode attribute defines barcode parameters, data-value the content. Style (local or CSS) is used for dimensioning.
data-barcode - Bbox eKasa
| Type | Character set (as regular expression) |
|---|---|
| ean13 | [0-9]{12,13} |
| ean8 | [0-9]{7,8} |
| code39 | [0-9A-Z $%*+-./]{1,34} |
| code128 | [\u0000-\u007f^{&omid}]{1,98} |
| code128c | [0-9]{1,98} (default) |
Optional further parameters - Bbox eKasa
| Parameter | Description |
|---|---|
| pos | Position, center only |
| w | Module width, can be between 1 and 5 (default: 3) |
| h | Barcode height, can be between 1 and 255 (default: 100) |
| hri | Human readable interface: 0=no, 1=above, 2=below (default), 3=above and below |
- If the values put into
worhexceed the valid range, they will automatically be reset to the default values. - When the width or height are set through CSS styles, they will be mapped over the default values. But values provided as
data-barcodewill override any CSS styles and need to be within the valid range. - If the string of
data-valueis missing or too long to fit onto the receipt, the text will not be printed, even when the values are set correctly.
Example of a very small barcode (code128):
div
img(data-barcode="w=1;h=30" data-value="This is a test")
data-value
The data-value can be set programmatically:
div
- var x = ESR.TL + ("0" + ESR.TT).slice(-2) + ("00000" + ESR.TN).slice(-6)
img(data-value=x style="width:30ch;height:3ch")
Example Response
As long as the printer is not set to fiscal mode (by an official representative), the printout will be marked "NEFISKÁLNY DOKLAD”.
Bbox eKasa Response
- XML
- JSON
<TraC SQ="140">
<Result RC="OK"/>
<Fis D="2019-06-15T15:30:57" FN="O-CCDCF2062A354F269CF2062A35E-TEST" DN="00095" OKP="4fe6d770-0c165912-20d0830c-a5765304-18de6c29"/>
</TraC>
{
"TraC":{"SQ":144,
"Result":{"RC":"OK"},
"Fis":{
"D":"2019-06-15T15:55:00",
"FN":"O-4CEE5F91A07F4E51AE5F91A07FD-TEST",
"DN":"00098",
"OKP":"fb1afece-c55788c9-423aa65e-11e5a6e1-adf9bb0c"
}
}
}