Siso SmartPOS

Direct Thermal Printing & Compliance Archiving for Odoo POS

No IoT Box. No Middleware. Just Print.

Contents

Introduction

About Siso SmartPOS

Siso SmartPOS is a direct-to-printer receipt module for Odoo Point of Sale. It replaces Odoo's default IoT Box–dependent printing with a browser-native approach: raw ESC/POS data is generated in the browser and sent directly to a thermal printer over USB, serial, or TCP — no additional hardware, no proxy service (except for network printers), no cloud dependency.

The module has three major components:

Part 1 of this document covers the day-to-day features available to cashiers and operators. Part 2 covers installation, configuration, and the administrative tools. Part 3 is a full reference for the receipt template language.

Browser Requirement

WebUSB and WebSerial are only available in Chrome and Edge. Firefox does not support these APIs. This restriction applies to the workstation physically connected to the printer; the Odoo server itself has no such constraint.


Part 1
Using SmartPOS

Day-to-day features for cashiers and POS operators.

Chapter 1

Printing Receipts

When SmartPOS is installed and configured, receipt printing works as it always has in Odoo POS — the operator completes a sale, and the receipt is printed automatically if the POS is configured to auto-print, or manually via the Print Receipt button on the receipt screen.

Behind the scenes, SmartPOS intercepts the print job before Odoo's default handler, generates ESC/POS data from the active receipt template, and sends it directly to the configured printer. The customer sees no difference; the operator sees a faster, more reliable print path.

Figure 1.1: Receipt Screen with SmartPOS Active
[Placeholder: POS receipt screen showing the Print Receipt button and the HTML receipt preview]
The receipt preview mirrors the printed output — what you see is what the printer receives.

Reprinting

Opening any past order from the Ticket Screen and clicking Print Receipt sends a reprint. SmartPOS tracks reprints as "copies" for compliance purposes — the copy counter increments and the reprint is recorded in the session's X/Z-report data.

Return Receipts

When a return (refund) order is finalised, it is automatically archived as a return receipt — a distinct document type from a standard sales receipt. The return count and amount are reported separately on X and Z reports.

First Print — Device Picker

The first time a print job is sent in a new browser session, Chrome or Edge will display a device-picker dialog. Select your printer and click Connect. The browser remembers the choice for all subsequent prints within the same browser session.

Chapter 3

X-Report — Interim Session Report

The X-Report is a non-closing snapshot of the current session's turnover. It shows accumulated totals, VAT breakdown, payment method summary, and correction counts — identical in structure to a Z-Report, but printing it does not close the session or reset any counters.

1
Click the X-Report button in the POS navbar (top-right area).
2
The report is printed immediately to the configured printer and archived in the Document Archive.
Figure 3.1: X-Report Button in the POS Navbar
[Placeholder: POS navbar with the X-Report button visible in the top-right area]

X-Reports use the X-Report Body template section, sharing the same Header and Footer as sales receipts. The body template is separately configurable so reports can be formatted differently from customer receipts.

Z-Report (End of Day)

The Z-Report is triggered automatically when you close the register via the Close button and complete the Closing Register routine. It is identical to an X-Report in content, but it generates a sequential Z-number and is the official end-of-day record. See Appendix B for compliance details.

Chapter 4

Sending a Receipt by Email

SmartPOS integrates with Odoo's built-in receipt email functionality. On the receipt screen, enter the customer's email address in the send-by-email field and click the send button.

When a customer is attached to the order, their email address is pre-filled automatically. SmartPOS generates the receipt as an HTML document (using the same template as the printed receipt) and sends it via Odoo's standard mail server.

Figure 4.1: Email Receipt Field
[Placeholder: Receipt screen showing the email field and send button]
Outgoing Mail Server

Email delivery requires an outgoing mail server to be configured in Settings → Technical → Email → Outgoing Mail Servers. If no mail server is configured, the email action will silently fail.


Part 2
Administration

Installation, configuration, and management for system administrators.

Chapter 6

Installing Siso SmartPOS

1
Deploy Files: Extract the siso_smartpos directory and place it in your Odoo addons path (e.g., /opt/odoo/addons).
2
Restart Server: Restart the Odoo service so the system detects the new module.
3
Update Apps List: Log in as a superuser, enable Debug Mode, navigate to Apps, and click Update Apps List.
4
Activate: Search for "smartpos", locate Siso SmartPOS, and click Activate.
5
Enable on Your Register: Go to Point of Sale → Configuration → Settings, open the target POS, scroll to the Siso SmartPOS Printer section, and enable Use Siso SmartPOS Printer.
Figure 6.1: SmartPOS Settings Section in POS Configuration
[Placeholder: POS Settings page with the Siso SmartPOS Printer section expanded]
Developer Mode Required

The Siso SmartPOS Printer section is only visible when Developer Mode is active. Enable it by appending ?debug=1 to the URL, or via Settings → Activate Developer Mode.

Chapter 7

Upgrading Siso SmartPOS

1
Backup: Always back up the existing siso_smartpos directory before proceeding.
2
Replace Files: Extract the new archive and replace the existing module directory.
3
Restart Server: Restart Odoo to load the new Python files.
4
Upgrade in Odoo: Navigate to Apps, search for siso_smartpos, click the three-dot menu, and select Upgrade.
5
Clear Asset Cache: In a database shell, run:
DELETE FROM ir_attachment WHERE url LIKE '/web/assets/%';
Then restart Odoo. This forces the browser to reload the new JavaScript bundle.
Asset Cache

Odoo aggressively caches JavaScript bundles. If you see old behaviour after an upgrade, clearing the ir_attachment rows as described above is almost always the fix. A hard reload (Ctrl+Shift+R) in the browser is also required after the cache is cleared.

Chapter 8

Printer Configuration

SmartPOS supports three connection types. All are configured in Point of Sale → Configuration → Settings under the Siso SmartPOS Printer section.

USB

Uses the browser's WebUSB API to send ESC/POS data directly over a USB connection. This is the fastest and most reliable connection type for a dedicated POS terminal.

FieldDescriptionExample
USB Vendor IDHexadecimal vendor ID of the printer.0x04b8 (Epson)
USB Product IDHexadecimal product ID of the printer.0x0e15

How to find your IDs:

Linux: Driver Conflict

Linux binds USB printers to the usblp kernel module, which blocks WebUSB. You must unbind the driver and create a udev rule. See Chapter 9 for the full procedure.

Serial (RS-232 / USB-Serial)

Uses the browser's WebSerial API. Suitable for older printers connected via RS-232 or USB-to-serial adapters.

FieldDescriptionExample
Serial PortSystem device name./dev/ttyUSB0 · COM3
Baud RateMust match the printer's hardware setting.9600 · 115200

The baud rate is set in the printer's hardware configuration (DIP switches or service menu). Check your printer's manual; 9600 is the most common default.

Network (TCP)

Sends ESC/POS data over TCP to a network-connected printer. Requires the Siso Local Bridge — a small service that runs on the POS workstation and relays print jobs from the browser to the printer.

FieldDescriptionExample
Printer IP AddressStatic IP of the network printer.192.168.1.200
Printer PortTCP port the printer listens on.9100
Why a Local Bridge?

Browsers block direct TCP connections to LAN devices for security reasons. The Siso Local Bridge listens on localhost:19100 and forwards raw ESC/POS data to the printer's IP and port. It must be running on the workstation before printing.

Printer Width

Set Printer Width (chars) to the number of characters that fit on one line at normal font size. This drives all column layout calculations.

Paper WidthTypical Characters
57 mm32
80 mm42 – 48

Run a self-test print from the printer itself — it typically prints a full-width line of characters you can count directly.

Chapter 9

OS-Level Setup for USB Printing

WebUSB requires the operating system to grant the browser access to the USB device. Each OS handles this differently.

Linux

Linux automatically binds USB printers to the usblp kernel module, which blocks WebUSB. You must unbind the driver and prevent it from re-attaching.

1
Find your printer's IDs:
lsusb
# Example: Bus 005 Device 003: ID 1504:003d Bixolon SRP-350plusIII
2
Create a udev rule (replace 1504 and 003d with your IDs):
sudo tee /etc/udev/rules.d/99-usb-printer.rules << 'EOF'
SUBSYSTEM=="usb", ATTRS{idVendor}=="1504", ATTRS{idProduct}=="003d", MODE="0666"
EOF
3
Blacklist the usblp module:
sudo tee /etc/modprobe.d/blacklist-usblp.conf << 'EOF'
blacklist usblp
EOF
4
Unbind the currently attached driver (avoids a replug):
# Find interface name — look for DRIVER=usblp
grep -r usblp /sys/bus/usb/drivers/usblp/*/uevent 2>/dev/null

# Unbind it (replace 5-1:1.0 with your interface name)
echo -n "5-1:1.0" | sudo tee /sys/bus/usb/drivers/usblp/unbind

sudo udevadm control --reload-rules
sudo udevadm trigger --attr-match=idVendor=1504

macOS

macOS does not need driver replacement. Chrome and Edge can access USB printers through WebUSB directly. If the printer does not appear in the device picker, try unplugging and replugging. On macOS Ventura and later, allow USB accessories access in System Settings → Privacy & Security → USB Accessories.

Windows

Windows assigns the usbprint.sys driver to USB printers, which blocks WebUSB. Replace it with the generic WinUSB driver using the free tool Zadig.

1
Download Zadig from zadig.akeo.ie and run it (no installation needed).
2
Go to Options → List All Devices, select your printer, choose WinUSB on the right side, and click Replace Driver.
3
Confirm in Device Manager that the printer now appears under Universal Serial Bus devices instead of Printers.
WinUSB and the Windows Print Spooler

After replacing the driver, the printer will no longer appear in the Windows print dialog. This is expected — SmartPOS sends raw ESC/POS data directly, bypassing the Windows print spooler entirely. To revert, uninstall the WinUSB device in Device Manager and let Windows reinstall the original driver.

Chapter 10

The Receipt Designer

The Receipt Designer is accessed from Point of Sale → Configuration → Receipt Templates. Each template consists of five separate sections printed in order:

SectionPrinted forTypical content
HeaderAll document typesCompany logo, name, address, VAT number
BodySales, return, training, and pro-forma receiptsOrder lines, totals, VAT table, payments
X-Report BodyX-ReportsSession totals, VAT breakdown, payment summary, counters
Z-Report BodyZ-ReportsSame as X-Report Body, plus Z-number and lifetime totals
FooterAll document typesQR code, website, thank-you message, paper cut
Figure 10.1: Receipt Template Designer
[Placeholder: Receipt template form with the Header, Body, and Footer tabs visible, and the HTML preview panel on the right]
The preview pane renders the HTML version of the template in real time.

Assigning a Template to a Register

Go to POS Settings for the target register and set the Receipt Template field. If no template is assigned, SmartPOS falls back to built-in default templates that satisfy basic compliance requirements.

Compliance Settings

Two compliance flags are available on each template:

Field Dump Template

SmartPOS ships with a special field dump template that prints every available context variable and its current value. Assign it temporarily to a register and print a test receipt to see exactly what data is available for your layout — useful when building a new template from scratch.

Chapter 11

The Document Archive

SmartPOS automatically archives every document it prints. Six document types are supported:

TypeWhen created
Sales ReceiptA completed sale is pushed to the server.
Return ReceiptA completed order with a negative total is pushed.
Training ReceiptA sale completed while the POS is in training mode.
Pro-forma / DraftThe Print Draft button is used before payment.
X-ReportThe X-Report button is clicked in the navbar.
Z-ReportThe register is closed via the Closing Register routine.

Each archive record stores three payloads:

Figure 11.1: Archived Document Form View
[Placeholder: Archive form view showing the HTML Preview tab and the Technical Data (JSON) tab]

Accessing the Archive

Navigate to Point of Sale → Reporting. Each document type has its own menu entry. The SmartPOS: Full Archive view (under Configuration) shows all types in a single filterable list.

Prevent Deletion

Enable Prevent Archive Deletion on the receipt template to protect records from being deleted through the Odoo interface. This is strongly recommended for regulated businesses.


Part 3
Template Reference

Complete reference for the SmartPOS XML template language.

Chapter 12

Template Language Overview

Receipt templates are written in a simple XML-based tag language. Each tag maps to one or more ESC/POS commands when printing, and to equivalent HTML for the preview and archive. Tags can be nested freely unless otherwise stated.

Placeholders

Dynamic values are inserted with curly-brace placeholders:

{variable}                 ← plain value
{variable:.2f}             ← numeric format (2 decimal places)
{variable:dd.MM.yyyy}      ← date format (Luxon tokens)

Variable names are case-sensitive dotted paths (e.g., head.company.name, line.price_total_incl). Unknown paths render as an empty string — they never cause an error.

Structure of a Typical Receipt

<!-- HEADER -->
<center><logo max-width="80"/></center>
<feed lines="1"/>
<center><x2>{head.company.name}</x2></center>
<center>{head.company.address.line1}</center>
<center>{head.company.address.postal_code} {head.company.address.city}</center>
<center>Org.nr: {head.company.vat_id}</center>
<hr/>
<center>{doc.type_label}</center>
<hr/>

<!-- BODY -->
<row><left>{order.name}</left><right>{head.date:dd.MM.yyyy HH:mm}</right></row>
<hr/>
<lines>
<table><tr>
  <td wrap="1">{line.name}</td>
  <td w="5" align="right">{line.qty}</td>
  <td w="8" align="right">{line.price_total_incl:.2f}</td>
</tr></table>
</lines>
<hr/>
<row bold="1"><left>TOTAL</left><right>{order.amount_total:.2f}</right></row>

<!-- FOOTER -->
<feed lines="1"/>
<center><qr size="4"/></center>
<feed lines="3"/><cut/>
Default Templates

SmartPOS ships with default templates for all five sections. Assign the built-in field dump template to your register and print a test receipt to see every available variable and its current value before designing your own layout.

Chapter 13

Context Variables

The following variables are available in all template sections unless noted otherwise.

Document (doc.*)

VariableDescription
{doc.type}Renderer type key: final · training · proforma · x_report · z_report
{doc.type_label}Localised label printed on the document (e.g., SALGSKVITTERING)
{doc.number}Order or document number
{doc.is_copy}true when printing a reprint
{doc.training_mode}true when the POS is in training mode
{doc.currency}ISO 4217 currency code (e.g., NOK)
{doc.currency_symbol}Currency symbol (e.g., kr)

Company (head.company.*)

VariableDescription
{head.company.name}Full legal company name
{head.company.address.line1}Street address
{head.company.address.postal_code}Postal / ZIP code
{head.company.address.city}City
{head.company.address.country}ISO 3166-1 country code
{head.company.phone}Phone number
{head.company.vat_id}VAT number incl. prefix (NO123456789MVA)
{head.company.website}Website URL

POS Terminal (head.pos.*)

VariableDescription
{head.pos.id}POS unit identifier (required in Norway by kassasystemforskriften § 2-8-2)
{head.pos.name}Human-readable POS name
{head.pos.software_name}Software name string

Date and Time

VariableDescription
{head.date}Transaction date (Luxon DateTime — use with a format specifier)
{head.time}Transaction time
{head.datetime.end}Full timestamp when the transaction was finalised

Order (order.*)

VariableDescription
{order.name}Order / receipt reference number
{order.date_order}Order date/time (Luxon DateTime)
{order.amount_untaxed}Order total excl. tax
{order.amount_total}Order total incl. tax

Customer (customer.*)

Only populated when a customer is attached to the order.

VariableDescription
{customer.name}Customer or company name
{customer.id}Internal CRM identifier
{customer.vat_id}Customer VAT number

Order Line Variables (inside <lines> loops)

VariableDescription
{line.name}Product name
{line.qty}Quantity sold
{line.unit.name}Unit of measure name (e.g., kg, stk)
{line.price_unit_incl}Unit price incl. tax
{line.price_unit_excl}Unit price excl. tax
{line.price_total_incl}Line total incl. tax
{line.price_total_excl}Line total excl. tax
{line.discount}Discount percentage (0–100)
{line.discount_amount_incl}Discount amount incl. tax
{line.has_discount}true if any discount is applied
{line.tax_name}Tax name string (e.g., MVA 25%)
{line.tax_rate}Tax rate as a number
{line.amount_tax}VAT amount for this line

Tax Variables (inside <taxes> loops)

VariableDescription
{tax.name}Tax name
{tax.rate}Tax rate (%)
{tax.base}Taxable base (excl. tax)
{tax.amount}Tax amount
{tax.total}Gross total (base + amount)

Payment Variables (inside <payments> loops)

VariableDescription
{payment.method}Payment method name
{payment.amount}Amount paid by this method

X/Z-Report Variables (z.*) — X-Report and Z-Report Body only

VariableDescription
{z.type}x_report or z_report
{z.number}Sequential Z-number (never resets)
{z.period.end}End of the reporting period
{z.counts.sales_receipts}Sales receipts issued this period
{z.counts.correction_posts}Correction / refund posts
{z.returns.count}Number of return receipts
{z.returns.amount}Total returned amount
{z.lifetime.gross_total}Accumulated gross turnover since commissioning
{z.lifetime.net_total}Accumulated net turnover
{z.lifetime.vat_total}Accumulated VAT
{z.lifetime.sales_receipts_count}Total receipts ever printed
Legacy Shortcuts

Short-form aliases like {company.name}, {order.name}, and {user.name} remain supported for backward compatibility. New templates should use the full head.* / doc.* paths.

Chapter 14

Text and Formatting Tags

Alignment

Alignment tags reset to left after the closing tag. They map to ESC a commands.

TagESC/POSDescription
<center>…</center>ESC a 1Centre-align
<right>…</right>ESC a 2Right-align
<left>…</left>ESC a 0Left-align (default)

Text Modifiers

All modifiers nest freely and reset on their closing tag.

TagESC/POSDescription
<b>…</b>ESC EBold. Aliases: <bold>, <strong>
<u>…</u>ESC -Underline. Alias: <underline>
<r>…</r>GS BReverse video (white on black). Alias: <reverse>
<red>…</red>ESC r 1Red text (dual-colour printers only)

Font Selection

TagESC/POSDescription
<fonta>…</fonta>ESC M 0Font A — standard size (default)
<fontb>…</fontb>ESC M 1Font B — smaller/condensed; fits more per line

Character Size

Size is set with GS !. Width and height are scaled independently; normal size is restored on the closing tag.

TagWidthHeightTypical use
<x1>…</x1>Normal (same as default)
<x2>…</x2>Wide subheadings
<x3>…</x3>Large labels
<x4>…</x4>Banner / section headers
<x5>…</x5>Tall text
<x6>…</x6>Large prominent text
Column Width with Wide Characters

Wide characters consume more physical space. A <x2> character is twice as wide as normal, so a 42-char printer effectively fits only 21 <x2> characters per line. Account for this when using size tags inside column layouts.

Whitespace and Rules

TagDescription
<br/>Line break — moves to the next line, no blank line added.
<feed lines="1"/>One blank line.
<feed lines="N"/>N blank lines.
<hr/>Full-width rule of - characters.
<hr char="="/>Full-width rule using a custom character.
<cut/>Paper cut (partial cut, GS V 41 3).
<br/> vs <feed>

<br/> is a line break — it ends the current line without adding a blank line. Use it to move to the next print line within flowing text. <feed lines="1"/> adds a visible blank line (an empty line of paper). Use feed to create vertical space between sections.

Chapter 15

Column and Row Layout

Two-Column Row (<row>)

Left-aligns the left side, right-aligns the right side, and fills the gap with spaces to exactly fill one line.

<row><left>Subtotal</left><right>{order.amount_untaxed:.2f}</right></row>
<row bold="1"><left>TOTAL</left><right>{order.amount_total:.2f}</right></row>

The optional bold="1" attribute makes the entire row bold.

Multi-Column Table (<table><tr><td>)

The preferred approach for new templates. Supports word-wrap and flexible column widths.

ElementAttributeDescription
<table>width="N"Override printer width for this table (useful inside <fontb>).
<tr>bold="1"Makes the entire row bold.
<td>w="N"Fixed column width in characters.
align="left|center|right"Cell alignment (default: left).
wrap="1"Enable word-wrap for long content; continuation lines are left-aligned.

Columns without a w attribute share the remaining width equally (flex behaviour).

<!-- 4-column line items table -->
<table>
  <tr bold="1">
    <td>Varenavn</td>
    <td w="5" align="right">Ant.</td>
    <td w="7" align="right">Pris</td>
    <td w="7" align="right">Sum</td>
  </tr>
</table>
<lines>
<table>
  <tr>
    <td wrap="1">{line.name}</td>
    <td w="5" align="right">{line.qty}</td>
    <td w="7" align="right">{line.price_unit_incl:.2f}</td>
    <td w="7" align="right">{line.price_total_incl:.2f}</td>
  </tr>
</table>
</lines>
Formatting Inside Cells

Formatting tags (<b>, <x2>, etc.) inside <td> are stripped — only their text content is used. Apply row-level bold via bold="1" on <tr>, or wrap the entire <table> in a formatting tag.

Dot-Column Layout (<dot><col>)

An older but fully supported column layout. Each <col> is allocated a fixed number of character positions; content is padded or truncated to fit.

AttributeExampleDescription
w="N"w="12"Fixed width of exactly N characters.
w="N%"w="50%"Width as a percentage of the line width.
(none)Flex: shares remaining width with other unsized columns.
alignalign="right"Default alignment when no child tag is present.

Both <table><tr><td> and <dot><col> can be mixed in the same template.

Chapter 16

Loop Sections

Loop tags iterate over a list from the rendering context. The content between the opening and closing tag is repeated once per item, with the item's fields available as short-form variables.

<lines> — Order Lines

Iterates once per order line. All {line.*} variables are available inside.

<lines>
<row><left>{line.name}</left><right>{line.price_total_incl:.2f}</right></row>
</lines>

<taxes> — Tax Breakdown

Iterates once per tax rate applied to the order. Satisfies the Norwegian requirement for per-rate VAT disclosure.

<taxes>
<row><left>MVA {tax.rate:.0f}%</left><right>{tax.amount:.2f}</right></row>
</taxes>

<payments> — Payment Lines

Iterates once per payment line on the order (e.g., cash, card, Vipps).

<payments>
<row><left>{payment.method}</left><right>{payment.amount:.2f}</right></row>
</payments>

<categories> and <products> — Report Loops

Available in X/Z-Report Body templates. Iterate over POS category sales and product sales for the session, respectively. Use {category.name}, {category.amount}, {product.name}, {product.qty}, {product.amount} inside these loops.

Chapter 17

Graphic Elements

Logo

<logo max-width="80"/>

Fetches the company logo, scales it to the specified percentage of the printer dot width, and rasterises it to 1-bit for GS v 0 printing.

AttributeDefaultDescription
max-width100Maximum width as a percentage of the print area (0–100).

QR Code

<qr size="4" error="M" data="{order.name}"/>

Prints a QR code via GS ( k (Model 2).

AttributeDefaultDescription
size4Module size in dots per cell (1–16).
errorMError correction: L (7%), M (15%), Q (25%), H (30%).
data(order name)Data string to encode; supports {placeholders}.

Barcode (CODE128)

<barcode height="50" text="1" data="{order.name}"/>

Prints a CODE128 barcode via GS k 73.

AttributeDefaultDescription
height50Bar height in dots.
text11 = print human-readable text below the bars; 0 = no text.
data(order name)Data string to encode; supports {placeholders}.

Appendix A
Format Specifiers

Inline formatting for numbers and dates in template placeholders.

Overview

Append a colon and a format string after any variable to control how its value is rendered: {variable:format}. If no format is given, the raw string representation is used.

Numeric Formats

Numeric format strings follow Python's format specification:

SyntaxExampleOutput (input 1250.5)
.2f{order.amount_total:.2f}1250.50
.0f{tax.rate:.0f}25
,.2f{order.amount_total:,.2f}1,250.50
+.2f{line.discount:+.2f}+12.50

Date/Time Formats

Date and datetime variables use Luxon format tokens:

SyntaxExampleOutput
dd.MM.yyyy{head.date:dd.MM.yyyy}16.05.2026
dd.MM.yyyy HH:mm{order.date_order:dd.MM.yyyy HH:mm}16.05.2026 14:32
HH:mm{head.time:HH:mm}14:32

Full Luxon token reference: moment.github.io/luxon.


Appendix B
Compliance Notes

Norwegian kassasystemloven and general regulatory context.

Norwegian Kassasystemloven

Norway's kassasystemforskriften (the Cash Register Regulation) mandates specific capabilities and data requirements for all electronic cash register systems used in business. The key sections relevant to SmartPOS are:

§ 2-8-2 — Mandatory Counters and Report Fields

X and Z reports must include the following data, which SmartPOS populates automatically:

RequirementTemplate variableStatus
Sequential Z-number (never resets){z.number}Implemented
POS unit identifier{head.pos.id}Implemented
Operator ID{head.user.id}Implemented
Count of sales receipts issued{z.counts.sales_receipts}Implemented
Count of correction/refund posts{z.counts.correction_posts}Implemented
Lifetime gross turnover (never resets){z.lifetime.gross_total}Implemented
Lifetime receipt count (never resets){z.lifetime.sales_receipts_count}Implemented
VAT breakdown by rate<taxes> loopImplemented
Payment method breakdown<payments> loopImplemented

§ 11 — Document Archiving

All documents generated by the cash register must be stored and retrievable for a minimum period. SmartPOS satisfies this requirement through its automatic Document Archive — every document type is archived with full content at the moment of printing.

Archive Deletion Protection

Enable Prevent Archive Deletion on your receipt template to ensure no archived records can be deleted through the Odoo user interface. This is required for full § 11 compliance.

Training Mode

When the POS is in training mode, receipts are printed with a ØVELSE (training) designation and archived as training_receipt — a distinct type that does not count toward official sales totals or lifetime counters.

Other Jurisdictions

SmartPOS's compliance engine is designed to be jurisdiction-neutral. The field catalog (field_catalog.md in the module source) documents planned fields for Germany (TSE fiscal signatures), France (CGI Art. 88 hashing), Italy (RT device integration), and other regulated markets. Contact Shinshout.com for current availability.


Appendix C
Tag Quick Reference

All supported template tags at a glance.

Complete Tag List

TagCategoryDescription
<center>AlignmentCentre-align text
<right>AlignmentRight-align text
<left>AlignmentLeft-align text (default)
<b> / <bold> / <strong>ModifierBold
<u> / <underline>ModifierUnderline
<r> / <reverse>ModifierReverse video
<red>ModifierRed text (dual-colour only)
<fonta>FontFont A (standard, default)
<fontb>FontFont B (condensed)
<x1><x6>SizeCharacter size multipliers (width × height)
<br/>WhitespaceLine break (no blank line)
<feed lines="N"/>WhitespaceN blank lines
<hr/>RuleFull-width horizontal rule (-)
<hr char="X"/>RuleFull-width rule with custom character
<cut/>ControlPaper cut
<row>LayoutTwo-column left/right row
<dot><col>LayoutMulti-column dot layout
<table><tr><td>LayoutMulti-column table with wrap support
<logo/>GraphicCompany logo (rasterised)
<qr/>GraphicQR code (GS ( k Model 2)
<barcode/>GraphicCODE128 barcode
<lines>LoopIterate order lines → {line.*}
<taxes>LoopIterate tax rates → {tax.*}
<payments>LoopIterate payment lines → {payment.*}
<categories>Loop (reports)Iterate category sales → {category.*}
<products>Loop (reports)Iterate product sales → {product.*}
<esc>LegacyCompound size/bold/underline (backward compat.)