Skip to main content

Reports

Reports generate a document (HTML or PDF) for a specific object using a Handlebars template. They are defined on a class alongside an optional context that brings in related objects, and triggered from a layout via an ACTION button.

Definition

{
"reports": [
{
"name": "invoicePDF",
"scope": "OBJECT",
"templateFile": "templates/invoicePDF",
"context": [
{ "relation": "invoiceLines", "sort": "lineNumber" }
]
}
]
}
PropertyTypeDescription
namestringUnique name for this report within the class.
scopeOBJECTOnly OBJECT is currently supported.
templateFilestringPath to a Handlebars template file in the repository, without the .hbs extension.
contextReportContext[]Multiple-valued relations to include in the template context.

What is automatically available

Single-valued relations (multiple: false) are always included in the template context one level deep — no declaration needed. If an invoice has a client relation, {{client.name}} works without adding anything to context.

context is needed in two cases:

  • Multiple-valued relations (one-to-many or many-to-many) — these become arrays in the template: {{#each invoiceLines}}.
  • Deeper nesting on a single-valued relation — if you need a multiple-valued relation on a related object (e.g. client.addresses), declare the single-valued relation in context with a nested context entry.

ReportContext

PropertyTypeDescription
relationstringThe relation name to include. Use the plural name for multiple-valued relations, the singular name for single-valued relations.
sortstringOptional sort order: "fieldName" for ascending, "fieldName,desc" for descending. Only applies to multiple-valued relations.
contextReportContext[]Nested context, resolved relative to each matched relation object.

Multiple-valued relation with nested context

A report on a project that includes each task's comments:

{
"context": [
{
"relation": "tasks",
"sort": "dueDate",
"context": [
{ "relation": "comments", "sort": "createdAt,desc" }
]
}
]
}

In the template, tasks is a list and each task has a comments list.

Single-valued relation with nested multiple-valued data

If client is a single-valued relation on the invoice, {{client.name}} is available automatically. To also access client.addresses (a multiple-valued relation on client), declare client in context with a nested entry:

{
"context": [
{
"relation": "client",
"context": [
{ "relation": "addresses" }
]
},
{ "relation": "invoiceLines", "sort": "lineNumber" }
]
}

In the template:

{{client.name}}
{{#each client.addresses}}
{{street}}, {{city}}
{{/each}}

Template

The template receives the main object's fields as top-level variables. Single-valued relations are available as nested objects; multiple-valued relations declared in context are available as arrays.

<h1>{{name}}</h1>
<p>Date: {{invoiceDate}}</p>
<p>Client: {{client.name}}</p> <!-- single-valued relation, no context declaration needed -->

<table>
<thead>
<tr><th>Description</th><th>Amount</th></tr>
</thead>
<tbody>
{{#each invoiceLines}} <!-- declared in context -->
<tr>
<td>{{description}}</td>
<td>{{amount}}</td>
</tr>
{{/each}}
</tbody>
</table>

<p>Total: {{total}}</p>

Template files use the .hbs extension and are stored in the repository alongside the class files. Reference them without the extension in templateFile.

Triggering from a layout

Add an ACTION item with actionType: "REPORT" to open the report in a new browser tab:

{
"type": "ACTION",
"name": "invoicePDF",
"label": "Print invoice",
"actionType": "REPORT"
}

The name must match a report defined on the same class. See Layouts — ACTION for the full ACTION item reference.

Complete example

An invoice class with a PDF report that includes its lines, sorted by line number:

{
"class": "my-project.invoice",
"type": "BASIC",
"inherits": "commons.item",

"valueTypes": [
{ "name": "invoiceDate", "dataType": "DATE" },
{ "name": "total", "dataType": "CURRENCY" }
],

"reports": [
{
"name": "invoicePDF",
"scope": "OBJECT",
"templateFile": "templates/invoicePDF",
"context": [
{ "relation": "invoiceLines", "sort": "lineNumber" }
]
}
],

"layouts": [
{
"type": "OBJECT_DASHBOARD",
"items": [
{ "name": "name", "header": true },
{ "name": "invoiceDate" },
{ "name": "total" },
{
"type": "ACTION",
"name": "invoicePDF",
"label": "Print invoice",
"actionType": "REPORT"
}
]
}
]
}