Setting up reports

Ticketmatic has powerful reporting capabilities. Use regular sql queries on the Ticketmatic public data model to quickly define new reports. Reports are automatically rendered in a good-looking uniform layout, allowing you to focus on the content of the report. The report layout will automatically adapt to the page size the user selects.


Layout

Reports are meant to have a ‘responsive’ layout, so they look good on whatever page size or export format that is selected. As a consequence, reports are not meant to generate ‘pixel-perfect’ documents like invoices or order summaries. Use Documents for this purpose.

Each report can be rendered by the user in multiple formats:

  • PDF: best format for displaying the report to users, can easily be printed or shared
  • Excel: best format if post-editing is needed or further calculations are necessary. Great care is taken that all data in the reports is kept editable in Excel: numbers stay numbers so you can add sums or averages, dates stay dates so you can change ordering or group dates in pivottables.
  • Json: best format for further automated processing. The report is provided in a structured json format and can be used to serve as input for other systems (e.g. dashboards)

Reports are managed in the Settings app. Click the button below to go to the Reports module:

Go to reports

Getting started: set up a new report

Go to the Reports module and click on the Add button. A new report is created with an empty definition:

1 {
2   "subtitles": [],
3   "content": {}
4 }

The definition is a json-structure, containing 2 main keys:

  • subtitles: an array containing the subtitles for the report
  • content: an array containing the actual content for the report

The content contains the main definition of the report and consists of an array of sections, where each section contains an array of content items.

For example, this is a report definition, whith 1 section, containing 1 content item:

 1 {
 2   "subtitles": [],
 3   "content": [
 4     [
 5       {
 6         "type": "table",
 7         "query": "select firstname,lastname from tm.contact",
 8         "columns": [
 9           {
10             "caption": "First name"
11           },
12           {
13             "caption": "Last name"
14           }
15         ]
16       }
17     ]
18   ]
19 }

This report will simply display a list of contacts in your account. In this example we use the content item table to display this list. There are 4 types of content items that can be used in sections:

  • table
  • groupedtable
  • pivottable
  • subreport

Preview and testing environment

While you are editing a report, you will see the Preview pane on the right displaying your changes in realtime. You can language and parameters to test how the report looks in that context.


Content types

Content item type table

This content item will be rendered as a simple table, with a header and optionally a summary row. For each column in the table, you can define a caption, type, width and summary value.

Consider this example:

 1 {
 2   "subtitles": [],
 3   "content": [
 4     [
 5       {
 6         "type": "table",
 7         "query": "select id,startts,nameen from tm.event order by startts",
 8         "columns": [
 9           {
10             "caption": "Id",
11             "width": "80px"
12           },
13           {
14             "caption": "Date",
15             "type": "dateminute",
16             "width": "120px"
17           },
18           {
19             "caption": "Name"
20           }
21         ]
22       }
23     ]
24   ]
25 }

This example will show a simple list of events. Remark following fields in the content item definition:

  • type: defines the type of content item, in this case table.
  • query: the query that is executed to retrieve the data for the table. you can use all views in the public data model here.
  • columns: array of column objects that define how individual columns should look

The number of columns should correspond exactly to the number of result columns from the query.

You can configure each column using the following keys:

KeyDescription
captionThe caption to be used in the header for this column
typedefines how this column should be visually rendered, for example “datetime” or “percentage”
widthwidth for the column, for example “120px”
summarydefines what to use for this column in the (optional) summary row

And these are the column types that can be used:

TypeDescription
numberright align
number0right align, rounded to 0 decimals
number2right align, rounded to 2 decimals
currencyright align, rounded to 2 decimals, formatted with €
currency0right align, rounded to 0 decimals, formatted with €
percentageright align, rounded to 2 decimals, formatted with %
percentage0right align, rounded to 0 decimals, formatted with %
dateDD/MM/YYYY
datetimeDD/MM/YYYY HH:MI:SS
dateminuteDD/MM/YYYY HH:MI
rightright align
centercenter align

The summary key allows you to define an optional summary row. Consider following example:

 1 {  
 2    "subtitles":[  
 3 
 4    ],
 5    "content":[  
 6       [  
 7          {  
 8             "type":"table",
 9             "query":"select \ntm.order.\nid, tm.order.createdts, \ncontact.lastname, \ncontact.firstname, \ntm.order.totalamount, \n(select count(*) from tm.ticket where orderid=tm.order.id) as nbroftickets\nfrom tm.order\nleft join tm.contact on tm.order.contactid=contact.id\norder by tm.order.id desc \nlimit 10",
10             "columns":[  
11                {  
12                   "caption":"Id",
13                   "width":"80px"
14                },
15                {  
16                   "caption":"Created",
17                   "type":"datetime",
18                   "width":"120px"
19                },
20                {  
21                   "caption":"Lastname"
22                },
23                {  
24                   "caption":"Firstname"
25                },
26                {  
27                   "caption":"Totalamount",
28                   "type":"currency",
29                   "summary":"SUM"
30                },
31                {  
32                   "caption":"# tickets",
33                   "type":"number",
34                   "summary":"SUM"
35                }
36             ]
37          }
38       ]
39    ]
40 }

This example will display a list of the last 10 orders, with the totalamount and the number of tickets per order. We add a summary row with the sum of all totalamounts and number of tickets by specifying "summary": "SUM" in the respective columns.

exclamation-circle

Remark in this example that the query contains \n characters that represent json-encoded newlines. This is done automatically for you when using the query editor in the Reports module: simply position the cursor in the query, and press the Edit query button. This will bring you to a query editor window where you can preview your query and format it over multiple lines. Correct json-encoding is done automatically.

Content item type groupedtable

This content item type will be rendered as a grouped table. The result from the base query will be grouped by the values of the first column. To render a correct report it is mandatory that you put the first column of the base query as first item in the order by-clause of the base query. You can specify an optional groupheader that will be shown before each group, and an optional summary that will be shown after each group and can contain summary values. Finally, you can specify a grandsummary that will be shown after all groups.

Consider this example:

 1 {
 2   "subtitles": [],
 3   "content": [
 4     [
 5       {
 6         "name": "Orders per sales channel per delivery scenario",
 7         "type": "groupedtable",
 8         "query": "select saleschannel.nameen as saleschannel, deliveryscenario.nameen as deliveryscenario, count(*) as nbroforders, sum(totalamount) as totalamount from tm.order\nleft join tm.saleschannel on saleschannelid=saleschannel.id\nleft join tm.deliveryscenario on deliveryscenarioid=deliveryscenario.id\n group by saleschannel.nameen, deliveryscenario.nameen\n order by saleschannel.nameen, deliveryscenario.nameen\n",
 9         "groupheader": "Sales channel {{ query.group }}",
10         "columns": [
11           {
12             "caption": "Delivery scenario"
13           },
14           {
15             "caption": "# orders",
16             "type": "number0",
17             "width": "15%"
18           },
19           {
20             "caption": "Totalamount",
21             "type": "currency",
22             "width": "15%"
23           }
24         ]
25       }
26     ]
27   ]
28 }

This example will display a table that is grouped by sales channel (= the first column in the query). For each sales channel, the number of orders and totalamount will be shown per delivery scenario.

The columns key should contain an array of columns for each column in the query, except the first column. You can specify the same keys per column as in the content item type table.

Remark the key groupheader: this will add a row for each group. You can use {{ query.group }} to reference the current value for the group. You can also use inline sql in the group header (see below).

Consider following example for adding summary and grandsummary rows:

 1 {
 2   "subtitles": [],
 3   "content": [
 4     [
 5       {
 6         "name": "Orders per sales channel per delivery scenario",
 7         "type": "groupedtable",
 8         "query": "select saleschannel.nameen as saleschannel, deliveryscenario.nameen as deliveryscenario, count(*) as nbroforders, sum(totalamount) as totalamount from tm.order\nleft join tm.saleschannel on saleschannelid=saleschannel.id\nleft join tm.deliveryscenario on deliveryscenarioid=deliveryscenario.id\ngroup by saleschannel.nameen, deliveryscenario.nameen\n order by saleschannel.nameen,deliveryscenario.nameen\n",
 9         "groupheader": "Sales channel {{ query.group }}",
10         "columns": [
11           {
12             "caption": "Delivery scenario",
13             "summary": "Total for {{ query.group }}",
14             "grandsummary": "Grand total"
15           },
16           {
17             "caption": "# orders",
18             "type": "number0",
19             "width": "15%",
20             "summary": "SUM",
21             "grandsummary": "SUM"
22           },
23           {
24             "caption": "Totalamount",
25             "type": "currency",
26             "width": "15%",
27             "summary": "SUM",
28             "grandsummary": "SUM"
29           }
30         ]
31       }
32     ]
33   ]
34 }

By specifying summary and/or grandsummary keys you can automatically add (sub)totals for groups or the whole grouped table.

Content item type pivottable

This content item type will be rendered as a pivot table with a dynamic number of columns and rows.

Consider following example:

 1 {
 2   "subtitles": [],
 3   "content": [
 4     [
 5       {
 6         "name": "Orders per delivery scenario per payment scenario",
 7         "type": "pivottable",
 8         "rowheaderquery": "select id,nameen from tm.paymentscenario order by id",
 9         "colheaderquery": "select id,nameen from tm.deliveryscenario order by id",
10         "valuequery": "select paymentscenarioid, deliveryscenarioid,count(*) from tm.order group by paymentscenarioid,deliveryscenarioid",
11         "valuewidth": "80px",
12         "valuetype": "number"
13       }
14     ]
15   ]
16 }

This example will display a table with the number of orders per delivery scenario and payment scenario.

The rowheaderquery should contain a query that returns an id and a caption for each row. Similarly, the columnheaderquery should contain a query that returns an id and a caption for each column.

The valuequery should contain a query that has 3 columns:

  • the id for the row
  • the id for the column
  • the value

You should make sure that there are no duplicates for the combination rowid, columnid in the valuequery resutl. The values from the valuequery will be placed in the correct cell, based on the ids for row and column.

You can add a row and/or column summary to the pivot table:

 1 {
 2   "subtitles": [],
 3   "content": [
 4     [
 5       {
 6         "name": "Orders per delivery scenario per payment scenario",
 7         "type": "pivottable",
 8         "rowheaderquery": "select id,nameen from tm.paymentscenario order by id",
 9         "colheaderquery": "select id,nameen from tm.deliveryscenario order by id",
10         "valuequery": "select paymentscenarioid, deliveryscenarioid,count(*) from tm.order group by paymentscenarioid,deliveryscenarioid",
11         "valuewidth": "80px",
12         "valuetype": "number",
13         "rowsummary": true,
14         "rowsummarycaption": "Total",
15         "rowsummarywidth": "70px",
16         "colsummary": true,
17         "colsummarycaption": "Total"
18       }
19     ]
20   ]
21 }

Content item type subreport

This content item type is actually a ‘meta’ content item type: it allows you to add a dynamic number of content items to a report, based on the results of a query.

Consider following example:

 1 {
 2   "subtitles": [],
 3   "content": [
 4     [
 5       {
 6         "type": "subreport",
 7         "name": "sub",
 8         "query": "select id,nameen from tm.saleschannel",
 9         "items": [
10           {
11             "name": "Orders per delivery scenario for sales channel {{ sub.nameen }}",
12             "type": "table",
13             "query": "select deliveryscenario.nameen, count(*) from tm.order\n left join tm.deliveryscenario on deliveryscenarioid=deliveryscenario.id\n where saleschannelid={{ sub.id }} \ngroup by deliveryscenario.nameen",
14             "columns": [
15               {
16                 "caption": "Delivery scenario"
17               },
18               {
19                 "caption": "Nbr"
20               }
21             ]
22           }
23         ]
24       }
25     ]
26   ]
27 }

You define the main query in the query key. For each resulting row, the items in the items key will be generated.

The items can contain all valid content item types, including other subreports, so you can nest multiple levels deep if needed.

You can reference columns from the main query by using syntax {{ <subreport name>.<column name> }}. For example {{ sub.nameen }} in the example will be replaced by the name of the sales channel for that row.

Inline sql

You can use inline sql in the report definition in all places where a string is expected: for example the name of the report or the groupheader in a grouped table.

For example: <inlinesql>select name{{ lang }} from tm.event where id={{ id }}</inlinesql> will display the name of the event with id {{ id }}.

The result of the query should always be a single string value.

Translation

A report definition can be made multi-language:

  • in queries you can use the {{ lang }} variable, that will be substituted with the current languagecode.
  • strings can be translated using the translation module.

Multiple sections

All content items in a section are rendered to a grid with the same number and size of columns. This allows you to easily have multiple content items that are layed out coherently under each other. Different sections in a report are rendered to separate grids. (In excel for example they will be rendered as separate tab pages). This allows you to merge multiple data tables in a single report.


Report settings

Go to the settings tab to configure the settings for the report:

SettingDescription
Report info
Namethe name of the report
Descriptiona short description of the contents of the report that is useful for the user generating the report. Can contain an explanation of how the numbers in the report are calculated
Typethe report type defines the parameters that need to be filled in by a user when generating the report (see below)
Use inwhere to use the report. Sales will make the report available in the Orders app. External sales will make the report available for External sales users
Output
Default formatdefault format for the report. A user can always choose the format he prefers.
PDF page sizePDF-specific option defining the paper size of the pdf when rendering the report. It can be specified by using keywords like A4, A4 landscape or US-letter, or by specifying actual sizes in cm or mm for example 10cm 20cm for a page of 10cm wide and 20cm high.
Excel page widthExcel-specific option defining the page width
Excel scalingExcel-specific option for scaling the width

Report type and parameters

An important property of a report is the type. Depending on the report type the user generating the report will need to fill in certain parameters. These parameters are available in the report definition to use in queries.

The table below displays the available report types and the corresponding parameters:

TypeDescription
1 - Simplenone
3 - Parameter Event{{ eventid }}
5 - Parameter Period{{ start }}, {{ end }}
9 - Parameter Period User{{ start }}, {{ end }}, {{ userid }}
10 - Parameter Multi Event{{ eventids }}
11 - Parameter Period And Multi Event{{ start }}, {{ end }}, {{ eventids }}
12 - Parameter 2 Period{{ start }}, {{ end }}, {{ start2 }}, {{ end2 }}

For example, when selecting type Parameter period, the user will need to enter a start and end date when generating the report. These dates can then be used in the report definition. Consider this example report that will generate a list of the number of orders and totalamount of order per day, for a selected period.

 1 {
 2   "subtitles": [],
 3   "content": [
 4     [
 5       {
 6         "type": "table",
 7         "query": "select date_trunc('day',createdts),count(*), sum(totalamount) from tm.order where createdts between {{ start }}::timestamp and {{ end }}::timestamp group by date_trunc('day',createdts) order by date_trunc('day', createdts)",
 8         "columns": [
 9           {
10             "caption": "Date",
11             "type": "date"
12           },
13           {
14             "caption": "# Orders"
15           },
16           {
17             "caption": "Totalamount"
18           }
19         ]
20       }
21     ]
22   ]
23 }

{{ start }} and {{ end }} will be replaced by the actual parameter values selected by the user.


Exporting and importing reports

You can export one or more reports in order to transfer them between accounts:

  • Select the reports you want to export
  • Click on the Export button
  • A textarea appears containing a structured version of the selected reports. You can copy this and store it in a textfile for later reference

In order to import one or more reports:

  • Click on the Import button
  • Paste the exported report definitions in the textarea and press Import

Scheduling reports

Use the scheduling options in the report settings to periodically send the report to a selected list of recipients:

schedule

You can send a report once a week or once a month at a specified time. You can define one or more recipients, CC and BCC addresses.

exclamation-circle

Only reports of report type ‘Simple’ can be scheduled.


Questions?

We're always happy to help! Send us an e-mail