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

  1. Open Settings / Designer & Menu / Print Designer.
  2. Select the Print File to edit.
  3. Click Duplicate before editing an operational template.
  4. Edit Name when needed, but be careful with Group Design.
  5. Use Code for loops, conditions, calculations, and complex tables. Use WYSIWYG for simple text or layout changes.
  6. Set paper size, custom width/height, margins, and orientation.
  7. Click Save to store the design on the server.
  8. 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 as if, 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 use await; without it the value is undefined and 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

  • getDataFromTable is async, so it must be used with await. Without await you are holding a Promise, not the row.
  • Single quotes and backslashes in keyValue are escaped automatically. Do not add your own replace(/'/g, "''"): the value is then escaped twice and an id that contains an apostrophe is no longer found.
  • When keyValue is empty, null, or undefined, 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 data columns 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 example data.customername) should be used directly.
  • On a list design, data holds an array of rows, so the call belongs inside the loop and uses a field of each row, for example item.customerid. On a form design, data is a single transaction, for example data.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.

Top Buttons

Button Use
Refresh Reload the print file list from the server.
Import Load a JSON design file from the computer.
Duplicate Create a copy of the selected design before editing.
Save Save the current design to the server.
Save as JSON Download the design as JSON for backup or migration.
Delete Delete the design file after confirmation.

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.

  1. 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.
  2. 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.
  3. Click Apply to editor if the proposal fits, or Dismiss proposal if not. Applying or discarding a proposal uses no further credits.
  4. 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.
AI only receives the design source, never transaction data. Instructions are limited to 4,000 characters and the design to about 120 KB. SQL from AI is accepted only if it is a read-only query, and EJS templates are syntax-checked before they can be applied. File name, path, active status, and public status cannot be changed by AI. Always test the AI result with Preview before using it.

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 getDataFromTable is empty, check await and the key value first.
  • Delete only templates that are no longer used by active transactions.

Menu Location