# REPORT TEMPLATE EDITOR

AyaNova report templates are html based template documents that are used with the [Handlebars](https://handlebarsjs.com/) templating language to generate html documents that are rendered to .PDF [Portable document format](https://en.wikipedia.org/wiki/PDF) files.

HTML and Javascript along with Handlebars templates are used to customize the existing reports in AyaNova and make new ones.

AyaNova comes with a built in report template editor and reports can be created or customized directly within AyaNova.


## Render process

When a report is rendered the following steps take place behind the scenes:

* A request is made to the server providing a report template ID, selected business object id's or a DataList name and filter / sort options.
* The server retrieves the report template from the database, "re-hydrates" the business objects in memory and feeds the data to the report template to be processed by the Handlebars templating engine
* The resulting HTML document is rendered and converted to a .PDF format document and a download URL is sent back to the user's browser to download and open the .pdf document.

### Linking directly to a rendered report

The AyaNova client supports directly linking to a report in an URL, primarily for Customer notification purposes. Only single objects can be linked to for reporting, not lists of objects.

The AyaNova client application expects report urls format as follows: `[PATH_TO_AYANOVA_APP_URL]/viewreport?oid=[objectid]&rid=[reportid]` 

If the user is not already logged in, they will be prompted to login first before the report is rendered.

## Report designer template sections

A report template contains several sections: 

### Properties 

These are the properties of the report outside of the actual report template itself:

* `Name` the name of the report as it is displayed to users for selection.  As with all named objects in AyaNova it must be unique, no two reports can have the same name.
* `Active` this controls report availability to users.  Set to inactive to keep a report template in the databse but not make it available to users.
* `Roles` this sets which User Roles are allowed to access the report.  (*Security note*: no matter what is set here, the server will still not provide data to a report if that data is outside of the Roles of the current user so reporting is not a way to get access to information that is not permitted for a User)
* `Notes` about the template, only displayed in the designer UI, usually reference notes for the people involved in designing the reports.

### Template 

The main HTML / Handlebars template. This is where the report is defined and is required to render a report.  A template is a mixture of both source HTML and Handlebars templates combined with data to generate the final report HTML.  

In order to get up to speed quickly with report design we recommend looking over the stock reports provided as well as referring to the [Handlebars documentation](https://handlebarsjs.com/guide/#what-is-handlebars)




### CSS 

This section is provided to define the HTML Cascading Style Sheet for the report document.  This section is optional.


### Prepare

This section is provided as a way to change the data provided to the report *before* it is rendered. 

Typically this function is used to retrieve and / or alter data that is fed to the report template.  

Use of the `ayPrepareData` function is optional but the function *must* be present in it's default format even if not used as it is *always* called by the rendering process and will result in an error if missing.  

This is the minimum required default definition:

```
async function ayPrepareData(ayAllData) {    
    return ayAllData;
}
```

`ayAllData` parameter is an object containing all data provided for the report and is detailed below in the Report Data Objects section.

Note that the SAMPLE DATA section of the user interface in the report designer shows the raw data *before* it is passed to this function, not how it would look *after* this function is run.  If you need to see how the data is shaped after a ayPrepareData you can make use of the `ayJSON` helper documented below to view the raw data on the rendered report itself.

A common use for the ayPrepareData function would be to insert or re-shape data based on calculations or data fetched from external API's or the AyaNova API itself (see the section regarding API usage below for details).

### Helpers

This section is for custom [Handlebars helper functions](https://handlebarsjs.com/guide/#custom-helpers) defined by the user.  AyaNova comes with many pre-defined helpers documented below, but this section is where you can add your own.  Any helper compatible with Handlebars can be defined here.  You can even use AyaNova API methods in your helpers if required (see the section regarding API usage below for details).

### Sample Data 

This is displayed in the report designer user interface when the report designer is opened via a business object.  The sample data is temporary and displayed for the purpose of assisting during report design as a reference to the field names available to the report.  

If you do not see this section it means the report designer was opened directly without passing through a business object first so there is no current data to display but you can still edit the report as normal.  This can happen if you open a report from a History form or use the browser back button to go back to a report that was previously edited or open a report URL directly. 


## Report data objects

When a report template is processed, business object data is provided to the template along with other data. Some of this data is used internally by the provided helpers and you have full access to these data values in your templates and helper / pre-render scripts.

The object provided has the following format:

```{
    ayReportData:[...array of business object data...],
    ayClientMetaData:{...Client / User data object...},
    ayServerMetaData:{...Server data object... }    
    }
```

### ayReportData

This is the main business object data provided to the template.  It will be identical to the object you see in the `SAMPLE DATA` area of the report designer user interface and is fetched from the server using the same method that populates the report when rendered ensuring consistency between design and rendered report.

It is *always* provided as an Array.  In the case of a single object it will be an array of one, in the case of multiple objects it will be the same object definition but repeated for each object. 

This means that any report should be designed with one or multiple objects in mind so that the same report can be used for both a single object or a collection.

For example if you are reporting off a Customer you would design a report that can handle one or multiple Customer objects so that the same report can be used when viewing a single Customer or a whole list of Customers.

The data provided to the report consists of the same fields visible in the user interface when editing that record and in addition, where appropriate, extra fields to bring in commonly required data from other objects that are linked.

#### Custom fields

In AyaNova an object can have up to 16 customizable fields of extra data.  In the `SAMPLE DATA` area of the reported editor interface you can see the custom field data, for example:

```
"CustomFields": {
			"c1": "2019-11-02T00:28:03.3193287Z",
			"c2": "Aperiam sequi dolores consequatur temporibus ducimus rerum.",
			"c3": 81510873,
			"c4": false,
			"c5": 0.119726536851249
		},
```

In the above example you can see that there are four custom fields containing data.  To access this data in your report template use dot notation to drill down to the custom field desired, for example {{ CustomFields.c1 }} in the template would return the date and time stamp in the above example.  

To format that data into local time zone and display format you would use a date time helper exactly as with non custom fields: {{ ayDT CustomFields.c1 }} would format the time stamp correctly for the user's browser settings.

Empty or non existent custom fields reference will simply result in nothing being returned for that value, so if your template had {{ CustomFields.c6 }} using the above record would simply return nothing / empty string.

The if the custom field definitions are changed for an object then the reports would need to also be changed to match, so for example if the c1 value was turned into a text field instead of a datetime field then the reports would need to be changed to match (for example removing the ayDT helper as it would now be a text field).


#### Localization

Localization, the display of Dates, Times, Numbers and AyaNova translated text is a *Client* responsibility in AyaNova.  

The server is Locale agnostic and doesn't normally process data into localized format but rather leaves that to the Client AyaNova software running on the web browser.  

However, because reports are processed *at* the server, the server uses the locale information provided by the Client when requesting the report in the ayClientMetaData property in conjunction with the Helpers provided to localize the data to display according to the Client that requested the report.  

Localizable values should display the same in a report as they do in the AyaNova user interface in the browser.

##### Date and time values

Date and time values are always stored at the server and provided in the ayReportData object in UTC / GMT time and [ISO-8601](https://en.wikipedia.org/wiki/ISO_8601) universal time format.  The values are converted to the user's local time zone and display format in the AyaNova client software and reports.  The `ayDateTime`, `ayDate` and `ayTime` Helpers are used to display this data in the Client default format and time zone.

##### Currency / decimal

Currency and decimal number values are provided in simple decimal notation and formatted for display using the `ayCurrency` / `ayDecimal` Handlebars helpers and the Client default language and currency settings.

##### Translations

Translated text is displayed in the current logged in User's default Translation setting using the `ayT` Handlebars helper. 

### ayClientMetaData 

When a report is rendered some settings from the Client browser are sent along with the report and are used as required to localize date, time and currency display formats as well as the current logged in User's API credential Bearer token and some other Client dependent settings.

You can see what data is provided by using the ayJson helper as in the example above on the report. As of the time of this writing the current values provided are:

```
ayClientMetaData: 
{ 
    "UserName": "AyaNova username", 
    "Authorization": "Bearer eJhbGciO...token...data...hb9JyjcWl3Tib", 
    "TimeZoneName": "America/Los_Angeles", 
    "LanguageName": "en-US",
    "Hour12": true, 
    "CurrencyName": "USD", 
    "DefaultLocale": "en" 
}
```

### ayServerMetaData

When a report is rendered some settings from the local AyaNova Server are injected into the report data and are used as required to access local server relative settings.  For example the URL path to the local AyaNova server's API so that API methods can be called directly in the report template relative to the server's local path.

You can see what data is provided by using the ayJson helper as in the example above on the report. As of the time of this writing the current values provided are:

```
ayServerMetaData: 
{ 
    "ayApiUrl": "http://127.0.0.1:7575/api/v8/" 
}
```

(Note: The value is an example only, your server may report a different value for the api url)


## Built in helpers

Several helpers are pre-defined for use with reports:

### ayBC

Bar code helper used to render any of over 100 types of bar codes on reports.  

This helper uses the [bwip-js](https://github.com/metafloor/bwip-js) open source bar code library to generate the bar codes and insert them and returns them into the generated HTML as an image element.

The helper is coded to accept two parameters, the data object template field name first and the options to pass to the bar code generator as a string of JSON encoded text corresponding to the [options](https://github.com/metafloor/bwip-js#working-with-bwip-js-methods) property of the bar code writer.

`bcid` is the only *required* part of the option parameter that must be provided and identifies which type of bar code will be rendered, there are [many bar code types](https://github.com/metafloor/bwip-js/wiki/BWIPP-Barcode-Types) available.

In AyaNova the `text` option of the `options` property is automatically set to the report template field data for you.  

#### Gotchas

* Quotes: Be careful how you specify quotation marks around the options property, use full quotes for the inner field and property values and single quotes to enclose the whole string of JSON as in this example:

```{{ ayBC ReportFieldName '{ "bcid": "code128"}' }}```

* Validity: certain bar codes (such as UPC) have a built in checksum validity check and will not render if the value is not valid.  So, for example, you cannot use any random number as a UPC code, it *must* contain valid checksum characters.  Or for example an EAN-13 code *must* contain 13 characters or it will not be valid either.

If you are using bar codes only for internal purposes there are many forgiving options available such as Code39 barcodes (or Code 3 of 9) which do not require a check digit and can store up to 39 digits or QR Code or PDF417 '2d' bar codes which can store alphanumeric and ad-hoc data suitable for scanning with camera devices.

* Size: Some experimentation scaling and size options maybe be required to ensure bar codes are scannable depending on the rendering medium / equipment and scanner.

#### Advanced usage

For full details please refer to the examples and direct links to the open source documentation above on each type of bar code specifically and advanced options usage. 

### ayCaps

Format value as all capitals: 

```{{ ayCaps ReportFieldName }}```


### ayCurrency

Formats a raw currency decimal value into a currency value formatted for the locale of the Client or server / report default

```{{ ayCurrency cost }}```

### ayDate

Formats a raw DateTime stamp into a short date only (no time) in the locale format of the Client or server / report default

```{{ ayDate startDate }}```

### ayDateTime

Formats a raw DateTime stamp into a short date and short time in the locale format of the Client or server / report default

```{{ ayDateTime startDate }}```


### ayDecimal

Formats a raw decimal number value into a floating point value formatted for the locale of the Client or server / report default

```{{ ayDecimal quantity }}```

### ayJSON

Outputs a block of javascript in JSON format.  Used primarily for diagnosing issues when using the designer to view script or data objects as text data right in the report, for example:

```{{ ayJSON ayClientMetaData }}```

Will output the Client meta data sent along with the report request from the Client as text viewable on the report.


### ayLink

Format an URL properly in the displayed document:

```{{ ayLink text_displayed url_link }}```

e.g. 

```{{ ayLink 'AyaNova website' 'https://www.ayanova.com' }}```

Will display as text and url: [AyaNova website](https://www.ayanova.com)


### ayLogo

Used to display your business logo that was previusly uploaded via the [Global settings logo page](form-adm-global-logo.md)
This helper takes a parameter indicating which size of logo is desired and must be one of the following values: `small`, `medium`, `large`

For example:

```{{ ayLogo "small" }}```

Will render the small sized logo as an image tag set to the correct API Url.  Note that if you do not upload a logo then this will display a broken image icon instead.

### ayT

Translates an AyaNova translation key into the language indicated by the current logged in user or the server default:

```{{ ayT 'Customer' }}```

You can view all the translations keys available in the [Translations](form-adm-translations.md) form.


### ayTime

Formats a raw DateTime stamp into a short time only (no date) in the locale format of the Client or server / report default

```{{ ayTime startDate }}```

### ayWiki

Format a Wiki Markdown formatted field such as a Wiki field on an object into HTML in a similar manner to how they are displayed in the AyaNova user interface WIKI fields:

```{{ ayMarkdown wiki }}```

This is what you use to display a Wiki (or any Markdown formatted text) in a report.  AyaNova uses the [Marked](https://marked.js.org/) library to turn Markdown into HTML for display both in the user interface and in reports.

## API Usage

Note that you can use the full power of the [AyaNova developer's API](api-intro.md) with your reports to incorporate data from anywhere in AyaNova as required.

The currently logged in User's API Bearer access token is provided for accessing API routes via the `ayClientMetaData.Authorization` value (see above). 

You should not store a static copy of an API Bearer access token or hard code it into your templates because it changes regularly and will expire the moment the User logs in to AyaNova.  

While it is possible to login via a script using alternate credentials and access the API with alternative access to the current logged in user, this opens a security hole as you would need to hard code credentials into the report script and is **absolutely NOT recommended**.


### API convenience functions

Two functions are provided with the report to assist with API usage from your ayPrepareData custom function:

*GET*

The ayGetFromAPI function works with GET routes in the API:

```async function ayGetFromAPI(route, token) {...```


*POST*

The ayPostToAPI function works with POST routes in the API:

```async function ayPostToAPI(route, data, token) {...```

The `token` parameter is optional and if not provided will be set by default to the current User's access token.
The `route` parameter will be automatically prepended with the server local api url if you do not provide the starting "http" in the URL.  Do not include the initial slash.

*Parameters*

The `route` parameter is required and will automatically include the current API server URL prepended if not provided (it looks for "http" at the start).  For example you can specifiy the `route` parameter as simply the end portion of the route without the slash: "server-info" or the full route to the server from the server URL meta property.  For example the full route to fetch data from the `server-info` API route can be constructed as follows:
```let route=`${reportData.ayServerMetaData.ayApiUrl}server-info`;```

The `token` parameter is optional and if not provided will be set by default to the current User's access token or you can specify it by using the authorization token provided in the Client data as follows:
```let token=reportData.ayClientMetaData.Authorization;```

The `data` parameter of a POST route differs for each route and is documented in the developer's API documentation.


The following is an example of accessing the API with both a GET and POST action:

```
async function ayPrepareData(reportData) {
   
    //Example API GET method 
    //to fetch data from API server 
    //using the "server-info" route
   

    //Add the data to the main report data object 
    //so it's available to the template
    reportData.myData=
    {
        ServerInfo:await ayGetFromAPI(
            "server-info"
        )
    };

    //Example API POST method to fetch data from api server
    //using the "search" route
   
    //construct the POST object 
    let searchPostData={phrase: "Fish"};

    reportData.myData.SearchResults = await ayPostToAPI(
        "search",
        searchPostData
    );
    return reportData;
}
```



