Print Designer
Print Designer is used to maintain / modify print templates used by transactions, such as receipts, invoices, notes, and other printed documents.
Menu Route
Settings Designer & Menu
/printdesigner
When to Use
- When a print format needs to be adjusted, for example adding logo, changing title, arranging columns, or changing paper size.
- When implementors need template variations without changing the main application.
- When an old design should be duplicated before editing.
- When templates need to be moved between servers using JSON export and import.
Basic Concepts
- Print File is the print design selected from the server.
- Name is a friendly template name.
- Group Design is the design code/path called by other forms. Do not change it carelessly when already used.
- Template is HTML/EJS. HTML controls layout; EJS reads transaction data, loops detail lines, and prints totals.
- Code is safer for structure and EJS. WYSIWYG is useful for simple visual edits.
- EJS chip protects EJS code in visual mode so
<%= ... %>does not break. - Default Page Setup controls paper size, orientation, custom width/height, and margins.
Workflow
- Open Settings / Designer & Menu / Print Designer.
- Select the Print File to edit.
- Click Duplicate before editing an operational template.
- Edit Name when needed, but be careful with Group Design.
- Use Code for loops, conditions, calculations, and complex tables. Use WYSIWYG for simple text or layout changes.
- Set paper size, custom width/height, margins, and orientation.
- Click Save to store the design on the server.
- Use Save as JSON for backup and Import for templates from another server.
How to Read a Template
- Normal text in the template is printed as-is.
<%= ... %>displays a value such as transaction number, date, customer, or total.<% ... %>is logic such asif,for, subtotal calculation, or variable preparation.- Tables usually contain a header row and a detail row. Repeated detail rows are usually controlled by an EJS loop.
- Use Code mode when the template contains many conditions and loops.
- Templates are rendered as an async function. A call that returns a Promise, such as
getDataFromTable, must useawait; without it the value isundefinedand EJS prints an empty cell without any error.
Reading Other Tables (getDataFromTable)
Some printed columns are not available in the transaction data and must be read from another table, for example the customer name, address, or phone number from the customer table. Templates use getDataFromTable for this. The function reads one row by one key column and returns every column of that row.
The call looks like this:
const row = await getDataFromTable(tableName, columnName, keyValue)
| Parameter | Content | Example |
|---|---|---|
tableName |
Source table name. Write it as a fixed name in the design, never from user input. | 'customer' |
columnName |
Key column used to find the row. | 'id' |
keyValue |
Value to look for. Numbers or text are accepted, including text that contains a single quote. | data.customerid |
The result is one data row, or an empty object when no row matches. Example on a Sales Invoice design that completes the customer name and address from data.customerid:
<%
const customer = await getDataFromTable('customer', 'id', data.customerid)
%>
<td><%= customer.name || '' %></td>
<td><%= customer.address || '' %></td>
When only one column is used, the call can be written inline:
<%= (await getDataFromTable('customer', 'id', data.customerid)).mobilephone || '' %>
Things to Keep in Mind
getDataFromTableis async, so it must be used withawait. Withoutawaityou are holding a Promise, not the row.- Single quotes and backslashes in
keyValueare escaped automatically. Do not add your ownreplace(/'/g, "''"): the value is then escaped twice and an id that contains an apostrophe is no longer found. - When
keyValueis empty,null, orundefined, no query is sent and the function returns an empty object right away. - A missing row, a request refused by the server, and an expired session all produce an empty object without a message. If every call comes back empty while other
datacolumns print normally, check the table/column names and the login state first. - Read-only (SELECT) only. A template cannot change data; the server refuses it.
- One call is one request to the server. Do not call it inside a long loop; data that already exists in
data(for exampledata.customername) should be used directly. - On a list design,
dataholds an array of rows, so the call belongs inside the loop and uses a field of each row, for exampleitem.customerid. On a form design,datais a single transaction, for exampledata.customerid. - The function is not available on the queue kiosk ticket (printed without a user session) and is not executed in the Print Designer preview. Test the result through a real transaction Preview.
Common Mistakes
| Written in the template | Result |
|---|---|
<%= getDataFromTable('customer', 'id', data.customerid).name %> |
Empty. .name is read from a Promise, is undefined, and EJS prints an empty string without an error. |
<%= getDataFromTable('customer', 'id', data.customerid) %> |
Prints [object Promise]. |
<%= (await getDataFromTable('customer', 'id', data.customerid)).name %> |
Correct. The customer name is printed. |
data.customerid is empty |
Empty object. No query is sent, so the cell stays empty as well. |
Default Page Setup
| Setting | Explanation |
|---|---|
| Paper Size | Standard paper size or custom size for the printout. |
| Orientation | Portrait or landscape. Use landscape for wide tables. |
| Custom Width / Height | Useful for thermal printers and special paper. |
| Margins | Controls left, right, top, and bottom spacing. |
| Active | Marks whether the template should still be used. |
EJS Chips in WYSIWYG Mode
- EJS chips protect template code while users edit visually.
- Click Edit on a chip to change the EJS expression.
- Use Code mode when the chip represents loops, conditions, or calculations.
- After visual editing, preview or print a sample document before using it operationally.
Modify Design with AI
The Modify design with AI panel helps change a design without writing code yourself. It is available to users whose role has Allow AI, and it uses the same credit balance as the AI Assistant.
- Select the design to change, then describe what you need in Requested changes. Example: fit the receipt to 80 mm paper, enlarge the company name, and add a signature area.
- Click Propose changes. AI shows a summary and a comparison of Before and AI proposal; the credits used and the remaining balance are shown too.
- Click Apply to editor if the proposal fits, or Dismiss proposal if not. Applying or discarding a proposal uses no further credits.
- Check the result in the editor, then save with the designer's usual save button. Undo AI changes restores the design from before it was applied, as long as no other edit has been made.
Things to Check
- Export JSON or Duplicate before changing a template used in operations.
- Small EJS mistakes can make printing fail.
- If output is too wide or cut off, check paper size, orientation, and margins.
- If transaction data does not appear, check EJS field names. If only the result of
getDataFromTableis empty, checkawaitand the key value first. - Delete only templates that are no longer used by active transactions.
Menu Location
- Settings / Designer & Menu / Print Designer
/printdesigner