> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dualentry.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Build a Custom Report with Data Analytics

> Build a report from DualEntry records in Data Analytics: join related records, filter, group, and add formulas, then export it or schedule email delivery.

Data Analytics builds reports directly from DualEntry records such as invoices, bills, sales orders, contracts, and journal entries. You pick a primary record, add its fields as columns, join related records, filter, group, and add formula columns, then save, export, or schedule the result. It lives under **Reports → Data Analytics**.

Use Data Analytics when you need a cut of transactional or master data that no standard report provides. To reshape a financial statement such as the income statement or balance sheet, use the [custom report builder](./custom-report-builder) instead, since it starts from the statement's accounting layout.

## Before you start

Data Analytics must be turned on for your organization, access is controlled by your role, and what a report returns is limited by your permissions on each record type. Check these before you build:

* **Organization access**: Data Analytics isn't turned on by default. If **Data Analytics** doesn't appear under **Reports** in the sidebar, contact your Account Executive to have it enabled for your organization.
* **Data Analytics permissions**: your role needs **View** on the **Data Analytics** module to open reports, **Create** to start new ones, **Edit** to save changes and schedule delivery, and **Archive** to archive reports. An admin sets these under user roles; see [roles and permissions](../platform-configuration/user-roles-and-permissions).
* **Record permissions**: each report also checks your view permission on the primary record and on every joined record type. Record types you can't view don't appear in the primary record list.

<Info>
  Data Analytics reads posted records only. Draft and archived transactions are excluded, so a report's totals reconcile to posted activity. Revenue schedules are the one exception: they include draft schedules, shown with the status **Scheduled**.
</Info>

## Start a report from a template or a blank report

Every Data Analytics report starts from the template gallery. In **Reports → Data Analytics**, choose **New report** or **Templates**, then pick one of these starting points in **Start from a template**:

* Unbilled sales orders by customer
* AR aging by customer
* Contracts expiring in 90 days
* Schedule roll-forward
* Revenue by customer and month
* Blank report

Templates come with their joins, columns, and grouping already set, and everything in them stays editable. **Blank report** starts on invoices with no columns. Starting from the template closest to your goal is usually faster than building from blank.

Choosing a template from the report library creates a new report. Choosing **Templates** from inside an open report replaces that report's setup instead.

## Choose the primary record and add fields

The primary record decides what one row of the report represents, so choose it first. In the builder's left panel, open **Primary record** and select a record type. Each option is tagged **Posting**, **Non-posting**, or **Record** (master data such as customers, vendors, items, and the chart of accounts).

1. Select the primary record. Changing it on a report that already has columns asks you to confirm with **Change record**, because it starts the report over.
2. Under **Fields**, search or browse the fields, grouped by record type, and select a field to add it as a column. Select it again to remove it. Custom fields are available alongside standard fields.
3. Under **Columns**, drag columns into the order you want, or move them with the arrow keys. The result grid follows the same order.

Fields marked with a **Line** badge come from line-level records such as invoice lines or journal entry lines. Choose a line record type (for example, **Invoice Lines**) as the primary record when you need one row per line rather than one row per document.

## Join related records

Joins add fields from records related to the primary record, such as the customer on an invoice or the account on a journal entry line. DualEntry works out how the records connect, so you never match raw columns yourself.

1. Under **Joins**, choose **Add join**.
2. Pick a path from **Suggested join paths from** your primary record. Each path is labeled **1-to-1**, **many-to-1**, or **1-to-many**.
3. Choose the join mode: **Left outer** (the default) keeps primary rows with no match, and **Inner** keeps only rows that have a match.
4. Add fields from the joined record under **Fields**.

A 1-to-many join, such as invoices to their payments, returns one row per match once you add a field from the joined record, so the row count can grow. The builder warns you before and after you add one. Joins always start from the primary record, and each related record type can be joined once.

Removing a join also removes that record's columns, filters, and grouping levels. Formula columns that referenced it stay in the report, marked **Invalid**, until you fix or remove them.

## Filter the results

Filters narrow a report to the rows you need, and they sit above the results as they do elsewhere in Reports. A filter can use any field from the primary record or a joined record, whether or not that field is a column in the report.

1. Choose **Add filter** and pick a field.
2. Search for and select a value. The list shows the values that exist in your organization's data, and **Load more** fetches more.
3. To remove a filter, select the remove control on its chip.

Each filter matches one exact value, in the form "field is value". Filters don't support ranges, "contains" matching, or several values for one field. To report on a date range, add the date field as a grouping level and read the groups you need, or export the report and filter the file.

If no rows match, the report lists the active filters so you can remove one or pick another value.

## Add a formula column

Formula columns calculate a value for each row from other columns in the report. Under **Formulas**, choose **Add formula column**.

1. Enter a **Column name** and choose a **Result type**: **Currency**, **Number**, or **Text**.
2. Build the expression. Select a column under **Insert a column** to add it, or type its name in square brackets, for example `[Amount]`.
3. Check **Preview (first row)** to confirm the result on the first row of the report.
4. Choose **Save column**. It stays disabled while the name or the expression has an error, and the editor explains the error.

The formula editor supports these functions:

| Function | Returns |
| - | - |
| `IF(condition, value_if_true, value_if_false)` | One of two values, depending on the condition |
| `COALESCE(value1, value2, ...)` | The first value that isn't empty |
| `TODAY()` | Today's date |
| `DATEDIFF(date1, date2)` | The number of days from `date2` to `date1` |
| `ABS(number)` | The absolute value |
| `ROUND(number, places)` | The number rounded to 0–10 decimal places (default 0) |

Use `+`, `-`, `*`, and `/` for arithmetic, and `>`, `<`, and `=` for comparisons. When either side of `+` is text, it joins the two values as text. For example, `DATEDIFF(TODAY(), [Due Date])` returns the days past due.

Formula columns show an **fx** marker in the **Columns** list. They can't be used as grouping levels.

## Group, total, and pivot the results

Grouping rolls rows up into subtotaled levels, such as revenue by customer and then by month. Under **Grouping**, choose **Add grouping level** and pick a field. Add more levels and drag them to reorder. Each level shows its own subtotal.

To choose how a column totals, open the menu on its header in the result grid and pick **Sum**, **Count**, **Count distinct**, **Avg**, **Min**, **Max**, or **None**. Number columns default to **Sum**, text columns to **Count**, and date and status columns to **None**. Text, date, and status columns offer only **Count**, **Count distinct**, and **None**.

Turn on **Pivot last grouping into columns** to spread the last grouping level across columns, for example months across the top. It needs at least one grouping level, and a pivot uses the first and last grouping levels with one value column.

The grand total stays pinned to the bottom of the result. In an ungrouped report, it covers every matching row, not only the rows loaded on screen. Rows load as you scroll and groups load their records as you expand them; use **Expand all** and **Collapse all** to open or close every group.

## Convert amounts in multiple currencies

Data Analytics shows each amount in its own transaction currency. When a group or total mixes currencies, its value reads **Mixed** and a banner reports that totals may not be comparable.

To total across currencies, choose **Convert to USD** in the banner. DualEntry converts each amount at the exchange rate for that record's date, or the latest available rate before it. Choose **Show source currencies** to return to the original amounts. Exports follow the same setting, so a converted report exports converted amounts.

For translating financial statements into a reporting currency, see [multi-currency reporting](./multi-currency-reporting).

## Save and manage reports

Saved reports keep their setup, not a snapshot of the numbers. Each time a saved report runs, it reads current data and checks the permissions of the person running it, so a report never shows someone data they can't otherwise see in DualEntry.

1. Choose **Save**. The **Unsaved changes** badge clears once the save succeeds. A report needs at least one column to save.
2. Find saved reports in **Reports → Data Analytics**, under **My reports**, **Shared with me**, or **Archived**. Search by name, and switch between list and grid views.
3. In list view, hover over a report name to preview its first 10 rows.
4. Use a report's row menu to **Open**, **Duplicate**, **Rename**, or **Archive** it. Restore an archived report from **Archived**.

New reports and duplicates are private to the person who creates them.

## Export a report

Exports write the full report to a file, including rows that aren't loaded on screen. Choose **Export / Schedule**, then select **Export now** in the **Export & delivery** dialog.

1. Pick **CSV** or **Excel**.
2. Start the export. A progress bar shows each stage, and the file downloads when it's ready. You can cancel an export in progress.

Group subtotals and formula columns are included as calculated values, along with the grand total. In Excel files, subtotal rows are written as Excel formulas, so they recalculate if you edit the data. For exporting standard financial statements and report packages, see [exporting and report packages](./exporting-and-report-groups).

## Schedule email delivery

A delivery schedule emails a saved report to members of your organization on a recurring basis. Choose **Export / Schedule**, then select **Schedule delivery**.

1. Pick a frequency: **Daily**, **Weekly (Mon)**, **Monthly (1st)**, or **On period close**. Daily, weekly, and monthly deliveries send at 08:00 UTC.
2. Pick the format: **CSV** or **Excel**.
3. Pick up to 50 recipients from your organization's active members. External email addresses aren't supported.
4. Save the schedule.

**On period close** sends the report when a company's period lock date moves forward. If the report filters on a specific company, it only sends when that company's period locks.

Schedules need a saved report and the Data Analytics **Edit** permission. A schedule always sends the saved version of the report, not unsaved changes. Files up to 9 MB arrive as attachments, and larger files arrive as a download link that expires after 24 hours.

Each schedule shows its next delivery, last delivery, and any failure. Use **Pause**, **Resume**, or **Delete** to manage it. A schedule runs with the permissions of its owner, and whoever last edits it becomes the owner. It pauses automatically if the owner loses access to the report or leaves the organization, or if the report is archived.

## Troubleshooting

This table lists common Data Analytics problems and how to resolve them.

| What you see | What to do |
| - | - |
| **Data Analytics** doesn't appear under **Reports** | It isn't turned on for your organization, or your role lacks the Data Analytics **View** permission. Contact your Account Executive to enable it, or ask an admin to check your role. |
| The row count jumped after adding a field or join | A line-level field or a 1-to-many join returns one row per line or match. Add a filter, or group the results to roll them up. |
| A total reads **Mixed** | The rows in that group use more than one currency. Choose **Convert to USD** in the banner. |
| A record type is missing from **Primary record** or the join list | You don't have view permission on that record type. Ask an admin to check your role. |
| The report shows an error that it has no column with a given name | A formula refers to a column that was removed. Edit the formula marked **Invalid** to use another column, or remove it. |
| A join is refused because it would add too many rows | A 1-to-many join can expand the report to at most 25,000 rows. Filter the primary record first, then add the join. |
| You can't add another column | A report holds up to 50 columns, including formula columns. Remove a column or split the report in two. |
| Draft invoices or bills are missing | Data Analytics reads posted records only. Post the transactions, or use the record's own list view for drafts. |
| A scheduled report stopped sending | Check the schedule's status. It pauses when its owner loses access or the report is archived. Edit and resume it to take over as owner. |

## Related pages

* [Custom report builder](./custom-report-builder)
* [Multi-currency reporting](./multi-currency-reporting)
* [Exporting and report packages](./exporting-and-report-groups)
* [Report packages](./report-packages)
* [Dashboards](./dashboards)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.