Skip to content

MIS Builder (Management Information System)

Last Updated: March 2026

MIS Builder is an OCA reporting module that lets IT administrators and accounting staff design custom financial reports from accounting data. It provides a template-based system where KPI definitions (formulas referencing account balances, queries, and Python expressions) are combined with configurable date periods to produce reports that can be previewed in-browser, exported to PDF or XLSX, and pinned to Odoo dashboards. At Scott Recycling, it is used primarily for management-level financial summaries such as profit and loss, balance sheets, and custom KPI dashboards.


MIS Builder adds menus under two areas of the Accounting app:

Accounting
 +-- Reporting
 |    +-- MIS Reporting
 |         +-- MIS Reports              (saved report instances — the reports you run)
 |         +-- Last Reports Generated   (temporary/unsaved report instances)
 +-- Configuration
      +-- MIS Reporting
           +-- MIS Report Templates     (the KPI definitions and formulas)
           +-- MIS Report Styles        (reusable formatting styles)
  • MIS Report Templates -- where you define what to calculate (KPIs, expressions, queries).
  • MIS Reports -- where you bind a template to specific dates and run it (report instances).
  • MIS Report Styles -- reusable formatting rules (colors, fonts, number format).

Core Concepts

MIS Builder separates the definition of a report from its execution:

Concept Model Purpose
Report Template mis.report Defines KPIs, expressions, queries, and sub-KPIs. No dates.
Report Instance mis.report.instance Binds a template to one or more date periods and runs it.
Period (Column) mis.report.instance.period A single column in an instance: has a date range and a data source.
KPI (Row) mis.report.kpi A single row in a template: has an expression that computes a value.
Style mis.report.style Reusable formatting: colors, font, number format, visibility.
Annotation mis.report.instance.annotation A user-created note attached to a specific cell in a report.

A typical workflow is: create a template with KPI formulas, then create one or more instances that use that template for specific date ranges (e.g., "Q1 2026 P&L", "Monthly Comparison").


Report Templates

Navigate to Accounting > Configuration > MIS Reporting > MIS Report Templates.

Template Fields

Field What It Means Example
Name Display name for the template. "Profit & Loss"
Description Optional description text. "Monthly P&L by account group"
Style Default style applied to all KPI rows unless overridden. "Bold Header"
Move Lines Source The model used for accounting data. Almost always account.move.line. account.move.line

Template Tabs

The template form has four tabs: KPIs, Queries, Sub KPIs, and Sub Reports.


KPIs Tab

Each KPI is a row in the final report. KPIs are evaluated in sequence order, and later KPIs can reference earlier ones by name.

Field What It Means Example
Description Human-readable label shown on the report. "Total Revenue"
Name Python variable name (auto-generated from description). Must be a valid Python identifier. total_revenue
Type Numeric, Percentage, or String. Controls rendering and comparison behavior. Numeric
Compare Method How to display comparisons: Difference, Percentage, or None. Percentage
Accumulation Method How values spanning different time periods are combined: Sum, Average, or None. Sum
Expression The formula that computes this KPI's value (see Expression Language below). balp[70%]
Style Optional per-KPI style override. "Subtotal Bold"
Style Expression A Python expression that returns a style name dynamically based on the KPI value. "Red" if total_revenue < 0 else None
Multi When checked, the KPI has a separate expression for each Sub-KPI. False
Display details by account When checked, the report expands this KPI into individual account lines. True
Style for account detail rows Style applied to the expanded account detail rows. "Indented"

KPI Ordering

KPIs are evaluated in sequence order. If KPI B references KPI A, make sure A has a lower sequence number than B. Circular references will cause an error.


Expression Language

KPI expressions are the heart of MIS Builder. They can be:

  1. Accounting expressions -- pull data from account.move.line
  2. Python expressions -- arithmetic on other KPIs or query results
  3. A mix of both -- e.g., balp[70%] + balp[71%]

Accounting Expression Syntax

The general form is:

{field}{mode}[account selector][optional move line domain]

Fields:

Code Meaning
bal Balance (debit minus credit)
deb Sum of debits
crd Sum of credits
pbal Positive balance only (returns 0 if negative)
nbal Negative balance only (returns 0 if positive)
fld Custom field (requires .fieldname suffix, e.g., fldp.quantity)

Modes:

Code Meaning
p Period variation (moves during the date range). This is the default if no mode is specified.
i Initial balance (balance at the start of the period)
e Ending balance (balance at the end of the period)
u Unallocated P&L (sum of P&L accounts from the beginning of time up to the start of the current fiscal year)

Account Selectors:

Syntax Meaning Example
[code] Exact account code bal[7000]
[code%] Wildcard on account code balp[70%]
[code1,code2] Multiple codes (comma-separated) bali[70,60]
[domain] Odoo domain on account.account balp[('code', '=like', '4%')]
[] All accounts balu[]

Move Line Domain (optional second bracket):

An additional Odoo domain filter applied to account.move.line. Useful for filtering by journal, analytic account, tags, etc.

Example What It Does
debp[55%][('journal_id.code', '=', 'BNK1')] Debits on account 55 in journal BNK1 during the period
balp[][('tax_line_id.tag_ids', '=', ref('l10n_be.tax_tag_56').id)] Balance of lines related to tax grid 56

Examples

Expression Meaning
balp[70%] Sum of balance changes on all accounts starting with "70" during the period
bali[1%] Initial balance of all accounts starting with "1" at the start of the period
bale[1%] Ending balance of all accounts starting with "1" at the end of the period
crdp[40%] Sum of all credits on accounts starting with "40" during the period
balu[] Unallocated profit/loss from previous fiscal years
total_revenue - total_expenses Python arithmetic referencing other KPIs by name
total_revenue / total_assets if total_assets else AccountingNone Safe division with AccountingNone fallback

Available Python Variables in Expressions

Variable Description
sum, min, max, len, avg Aggregate functions (work like Python builtins)
datetime, dateutil, time Standard Python modules
date_from, date_to Start and end date of the current period
AccountingNone A null value that behaves as 0 in arithmetic. Use this instead of None.
Other KPI names e.g., revenue, expenses -- reference previously computed KPIs
Query names e.g., my_query.field_name -- reference query results

AccountingNone

AccountingNone is not the same as 0 or None. It renders as a blank cell rather than "0". When you divide by a KPI that might be zero, use a guard: revenue / costs if costs else AccountingNone.


Queries Tab

Queries let you pull data from any Odoo model (not just accounting) and make the results available in KPI expressions.

Field What It Means Example
Name Python variable name for the query result. Must be a valid Python identifier. sale_totals
Model The Odoo model to query. sale.order
Fields to Fetch Which fields to read from the model. amount_total, amount_untaxed
Aggregate How to combine results: Sum, Average, Min, Max, or blank (return all records as a list). Sum
Date Field The date or datetime field used to filter records to the period. date_order
Company Field Optional field for multi-company filtering. company_id
Domain Optional Odoo domain to pre-filter records. [('state', '=', 'sale')]

When Aggregate is set (e.g., Sum), the query returns a single object with aggregated field values plus a .count attribute:

# In a KPI expression, if query name is "sale_totals":
sale_totals.amount_total    # aggregated sum
sale_totals.count           # number of matching records

When Aggregate is blank, the query returns a list of objects. You can use sum(), len(), etc. in your KPI expression:

sum(r.amount_total for r in sale_orders)

Sub KPIs Tab

Sub-KPIs add sub-columns within each period column. For example, if your report has a "Q1" column and you define sub-KPIs "Budget" and "Actual", the Q1 column will split into two sub-columns.

Field What It Means Example
Description Human-readable label for the sub-column header. "Budget"
Name Python identifier. budget
Sequence Display order within the sub-column group. 1, 2, 3...

When sub-KPIs are defined, each KPI marked as Multi gets a separate expression for each sub-KPI. Non-multi KPIs must return a tuple matching the number of sub-KPIs.


Sub Reports Tab

Sub-reports let one template reference the KPIs of another template. This is useful for composing complex reports from simpler building blocks.

Field What It Means Example
Name Python variable name to reference the sub-report's KPIs. pl_report
Sub Report The other MIS Report Template to include. "Profit & Loss Detail"

In your KPI expressions, reference sub-report KPIs as subreport_name.kpi_name:

pl_report.net_income

No Circular References

A template cannot include itself as a sub-report, and circular chains (A includes B, B includes A) are detected and blocked.


Report Instances

Navigate to Accounting > Reporting > MIS Reporting > MIS Reports.

A report instance takes a template and runs it for specific date periods. The list view shows all saved instances with quick-action buttons for Preview, Print (PDF), and Export (XLSX).

Instance Fields

Field What It Means Example
Name Display name for this instance. "Q1 2026 Profit & Loss"
Template The MIS Report Template this instance uses. "Profit & Loss"
Currency Target currency (required if companies have different currencies). USD
Comparison Mode Unchecked: single date range. Checked: multiple columns with independent periods. Checked
Date Range (Simple mode) Select a predefined date range from the date_range module. "Q1 2026"
From / To (Simple mode) Start and end dates for the report. 01/01/2026 - 03/31/2026
Base Date (Comparison mode) The pivot date for relative period calculations. Defaults to today. 03/01/2026

Simple Mode vs. Comparison Mode

Simple Mode (Comparison Mode unchecked):

  • The report has one column.
  • You set a single date range (From/To or a predefined Date Range).
  • Quick and easy for a single-period view.

Comparison Mode (Comparison Mode checked):

  • The report can have multiple columns, each with its own date range and data source.
  • Columns are defined in the Columns tab.
  • Enables period-over-period comparisons, budget vs. actual, year-to-date, etc.

When to Use Comparison Mode

Use comparison mode any time you need more than one column, such as "This Month vs. Last Month", "Actual vs. Budget", or "Jan, Feb, Mar" side by side.


Columns Tab (Comparison Mode)

Each column in the Columns tab represents a period (column) in the report output.

Column Fields

Field What It Means Example
Label Column header text. "Jan 2026"
Source Where the column gets its data (see Source Types below). Actuals
Mode How dates are determined: Fixed dates, Relative to report base date, or No date filter. Relative
Period Type (Relative mode) Unit of time: Day, Week, Month, Year, or Date Range. Month
Offset (Relative mode) Number of periods to shift from the base date. Negative = past. -1 (previous month)
Duration (Relative mode) How many periods to span. 1
Year to Date (Relative mode) Forces the start date to January 1st of the relevant year. False
Date Range Type (Relative, Date Range type) The type of date range to use. "Fiscal Month"
Date Range (Fixed mode) Select a predefined date range. "Q1 2026"
From / To (Fixed mode) Manual start and end dates. 01/01/2026 - 01/31/2026
Sub KPI Filter Optionally show only specific sub-KPIs in this column. "Actual"
Analytic Domain Additional domain filter on move lines for this column only. [('analytic_account_id', '=', 5)]

Source Types

Source Description
Actuals Live data from the accounting system (account.move.line or the model defined on the template). Requires a date filter.
Actuals (alternative) Live data from an alternative move-line-like model (e.g., a budget model that has debit/credit/account_id/date fields). You select the model manually.
Sum columns Arithmetic combination of other columns. Specify columns to add (+) or subtract (-). No date filter allowed.
Compare columns Computes the comparison (difference or percentage change) between two other columns. No date filter allowed.

Source Constraints

Actuals and Actuals (alternative) columns must have a date filter. Sum and Compare columns must not have a date filter (mode = "No date filter"). Violating these constraints will raise a validation error.

Relative Period Examples

With a base date of March 1, 2026:

Type Offset Duration Resulting Period
Month 0 1 March 1 - March 31, 2026
Month -1 1 February 1 - February 28, 2026
Month -2 3 January 1 - March 31, 2026
Year 0 1 January 1 - December 31, 2026
Year -1 1 January 1 - December 31, 2025
Week 0 1 The current week (Mon-Sun)
Day 0 1 March 1, 2026

Filters Tab

Field What It Means Example
Target Moves All Posted Entries (excludes draft) or All Entries (includes draft). Always excludes cancelled. All Posted Entries
Multiple Companies Enable to search data across multiple companies. False
Company (Single company mode) Which company's data to use. "Scott Recycling"
Companies (Multi-company mode) Select which companies to include. "SR East, SR West"
Analytic Domain A domain filter applied to all move lines across all columns. Useful for filtering by analytic account, department, etc. [('analytic_account_id.name', '=', 'Operations')]

Layout Tab

Field What It Means Example
Landscape PDF Print the PDF report in landscape orientation. True
Disable account details expansion Suppress the auto-expand of account detail rows even if KPIs have it enabled. False
Display columns description Show the computed date range in column headers (e.g., "from 01/01/2026 to 03/31/2026"). True

Widget Tab

These settings control how the report renders in the interactive dashboard widget.

Field What It Means Example
Show filters box Display the search/filter bar in the widget view. True
Filter box search view The search view used for the filter bar. Auto-detected from the move lines source model. account.move.line search view
Show settings button Display a gear icon to jump to the instance settings form. False
Show Pivot Date Display a date picker in the widget to dynamically change the base date. False

Styles

Navigate to Accounting > Configuration > MIS Reporting > MIS Report Styles.

Styles control how KPI rows and cells are rendered in the preview, PDF, and XLSX exports. Each property has an "Inherit" checkbox -- when checked, that property is inherited from the parent style (template default or KPI style).

Style Fields

Number Formatting

Field What It Means Example
Rounding Decimal places for numeric values. 0 (whole numbers), 2 (cents)
Factor Divider applied before display. 1 = as-is, 1e3 = thousands, 1e6 = millions. 1e3 (display in thousands)
Prefix Text prepended to the value. "$"
Suffix Text appended to the value. "USD"

Colors

Field What It Means Example
Text Color Font color as RGB hex code. #FF0000 (red)
Background Color Cell background color as RGB hex code. #F0F0F0 (light gray)

Font

Field What It Means Example
Font Style Normal or Italic. Normal
Font Weight Normal or Bold. Bold
Font Size Size from xx-small to xx-large (maps to 5pt-17pt in XLSX). medium (11pt)

Layout

Field What It Means Example
Indent Level Number of em units to indent the row label. Useful for hierarchical reports. 2

Visibility

Field What It Means Example
Hide Empty Hide this row if all values are empty/zero. True
Hide Always Always hide this row (useful for intermediate calculation rows). False

Style Inheritance

Styles are merged in order: Template Default Style > KPI Style > Cell Style Expression. Each level only overrides properties where "Inherit" is unchecked. This lets you set company-wide defaults and override only what's needed per KPI.


Annotations

Annotations are cell-level notes that can be added to any KPI cell (not account detail rows) in a report instance. They appear as numbered footnotes in PDF exports and as comment markers in XLSX exports.

How Annotations Work

  1. In the report preview widget, click a cell to open the annotation dialog.
  2. Type your note and click Save.
  3. The cell displays a superscript number reference.
  4. In PDF exports, annotations appear as a numbered footnote table below the report.
  5. In XLSX exports, annotations appear as cell comments.

Annotations are stored per-cell and are context-aware (they respect the current company selection). This means the same report instance can have different annotations when viewed by different companies in multi-company mode.

Annotation Permissions

Annotations require specific group membership. Users in the "MIS Report: view annotations" group can see annotations. Users in the "MIS Report: add annotations" group can create, edit, and delete them. See the Security section below.


Common Tasks

1. Create a New Report Template

  1. Go to Accounting > Configuration > MIS Reporting > MIS Report Templates.
  2. Click New.
  3. Enter a Name (e.g., "Balance Sheet").
  4. Leave Move Lines Source as account.move.line unless you have a custom model.
  5. In the KPIs tab, click Add a line for each row you want in the report.
  6. For each KPI, enter a Description (display label) and an Expression (formula).
  7. Optionally assign a Style to format specific rows.
  8. Click Save.

2. Create a Report Instance (Single Period)

  1. Go to Accounting > Reporting > MIS Reporting > MIS Reports.
  2. Click New.
  3. Enter a Name (e.g., "January 2026 P&L").
  4. Select your Template.
  5. Leave Comparison Mode unchecked.
  6. Set From and To dates (or select a Date Range).
  7. Click Save, then click Preview to see the report.

3. Create a Multi-Period Comparison Report

  1. Go to Accounting > Reporting > MIS Reporting > MIS Reports.
  2. Click New.
  3. Enter a Name and select your Template.
  4. Check Comparison Mode.
  5. Optionally set a Base Date (defaults to today).
  6. In the Columns tab, click Add a line for each period:
    • Set Label (e.g., "This Month").
    • Set Source to "Actuals".
    • Set Mode to "Relative to report base date".
    • Set Period Type to "Month", Offset to 0, Duration to 1.
  7. Add a second column for the previous month (Offset = -1).
  8. Optionally add a third column with Source = "Compare columns" to show the difference.
  9. Click Save, then Preview.

4. Add a Year-to-Date Column

  1. Open a report instance in Comparison Mode.
  2. In the Columns tab, add a new column.
  3. Set Source to "Actuals", Mode to "Relative", Period Type to "Month".
  4. Set Offset to 0, Duration to 1.
  5. Check Year to Date -- this forces the start date to January 1st.
  6. Save and preview.

5. Export to PDF

  1. Open the report instance (either from the list or the preview).
  2. Click Print (the printer icon).
  3. The PDF is generated using QWeb and downloads automatically.
  4. For wide reports, check Landscape PDF in the Layout tab first.

6. Export to XLSX

  1. Open the report instance.
  2. Click Export (the download icon).
  3. The XLSX file includes all styling (bold, colors, number formats), column headers, and annotation comments.
  4. A timestamp footer shows when the export was generated.

7. Add a Report to the Dashboard

  1. Open the report instance form (not the preview).
  2. Click Add to dashboard.
  3. In the popup, enter a Name for the dashboard widget and select the Dashboard.
  4. Click Add to dashboard.
  5. The report now appears as a live widget on the selected dashboard, with optional filter bar and pivot date picker.

8. Use Drilldown

  1. In the report preview, click on any blue/underlined value that has an accounting expression.
  2. Odoo opens a list view of the underlying account.move.line records (or the alternative model) filtered to the exact accounts, date range, and domain that produced that value.
  3. You can switch to pivot, graph, or form view from the drilldown results.

Drilldown Availability

Drilldown is only available for cells computed from accounting expressions (bal, deb, crd, etc.). Cells computed from pure Python expressions or queries do not support drilldown.

9. Quick-Run a Template

  1. Go to Accounting > Configuration > MIS Reporting > MIS Report Templates.
  2. Open a template.
  3. In the template form, there is a built-in action to create a temporary instance.
  4. Set dates in the popup and click Preview or Print.
  5. Temporary instances are auto-deleted after 24 hours by a scheduled cron job.

Accumulation Methods

Accumulation controls how KPI values are adjusted when the reporting period does not perfectly align with the underlying data period (pro-rata temporis).

Method Behavior Use For
Sum Values from shorter periods are added together. Values from longer or partially overlapping periods are adjusted pro-rata. Revenue, expenses, counts
Average Values from overlapping periods are averaged with a pro-rata weight based on the number of overlapping days. Rates, percentages, averages
None No accumulation or adjustment. String values, flags

Multi-Company Support

Report instances support both single-company and multi-company modes:

  • Single Company: Set the Company field in the Filters tab. Data is searched only for that company.
  • Multi-Company: Check Multiple Companies and select the companies to include. Data from all selected companies is combined. If companies use different currencies, you must set the Currency field to specify a common target currency.

When multi-company is enabled, the "Display details by account" feature shows the company name in brackets after each account: 1000 Cash [Scott Recycling East].


Scheduled Automation

MIS Builder includes one scheduled action:

Cron Job Schedule Purpose
Vacuum temporary reports Every 4 hours Deletes temporary report instances (created from the quick-run wizard) that are older than 24 hours.

This cron runs automatically. No configuration is needed.


Security

Groups

MIS Builder uses Odoo's standard accounting group plus two custom annotation groups:

Group Who Has It What They Can Do
Internal User (base.group_user) All employees Read-only access to all MIS models (templates, instances, styles, etc.)
Invoicing / Accounting Manager (account.group_account_manager) Accounting managers, IT admins Full CRUD on all MIS models: create/edit/delete templates, instances, styles, periods
MIS Report: view annotations (mis_builder.group_read_annotation) Assigned manually Read annotations on report cells
MIS Report: add annotations (mis_builder.group_edit_annotation) Admin users (by default), plus anyone assigned manually Create, edit, and delete annotations. Automatically includes "view annotations" permission.

Record Rules

Rule Effect
MIS Report Instance multi company Users can only see report instances where the instance's company matches one of the user's allowed companies (or where no company is set).

Practical Access Summary

Role Can Create Templates Can Create Instances Can View Reports Can Annotate
Regular employee No No Yes (read-only) Only if in annotation group
Accounting Manager Yes Yes Yes Only if in annotation group
Admin Yes Yes Yes Yes (in edit annotation group by default)

Annotation Group Setup

The annotation groups are not automatically assigned to accounting managers. If your accounting team needs to add notes to reports, an admin must manually add them to the "MIS Report: add annotations" group under Settings > Users > (user) > MIS Builder section.


Troubleshooting

"KPI name must be a valid python identifier"

KPI names, query names, sub-KPI names, and sub-report names must all be valid Python identifiers: letters, digits, and underscores only, cannot start with a digit. If you enter a Description, the Name is auto-generated from it by replacing invalid characters with underscores.

A column shows as red in the Columns list

Red rows in the Columns tab mean the period dates could not be computed (the valid field is False). Common causes:

  • Relative mode is set but the base date does not fall within any defined date range of the specified type.
  • Fixed mode is set but the From/To dates are missing.
  • The source is Actuals but the mode is "No date filter" (or vice versa for Sum/Compare sources).

Values show as blank instead of zero

This is by design. AccountingNone (no data) renders as blank, while actual 0 renders as "0". If an account has no moves in the period, the balance returns AccountingNone. To force zero display, you can wrap an expression: balp[70%] or 0.

Drilldown does nothing when I click a cell

Drilldown only works for cells computed from accounting expressions (bal, deb, crd, pbal, nbal, fld). Pure Python expressions and query-derived values do not support drilldown.

"Columns are not comparable" error

This occurs when you create a Compare column referencing two columns that have incompatible sub-KPI structures. Both columns must share at least one common sub-KPI for comparison to work.

XLSX export has wrong number formatting

Check the style assigned to the KPI. The Factor (divider) setting affects how values are displayed. For example, if Factor is 1e3 (thousands), the XLSX value is divided by 1000 and the number format reflects this. Make sure the Factor and Rounding settings match your expectations.


Technical Reference

Models

Model Table Description
mis.report Report template Holds KPIs, queries, sub-KPIs, sub-reports
mis.report.kpi KPI definition A row in the report with its expression
mis.report.kpi.expression KPI expression Individual expression (one per sub-KPI for multi KPIs)
mis.report.subkpi Sub-KPI definition Defines sub-columns within a report
mis.report.query Custom query Non-accounting data source
mis.report.subreport Sub-report link References another template's KPIs
mis.report.instance Report instance A runnable report bound to dates
mis.report.instance.period Period/column A column in a report instance
mis.report.instance.period.sum Sum column entry Defines which columns to add/subtract in a Sum column
mis.report.style Style definition Reusable formatting properties
mis.report.instance.annotation Cell annotation A note attached to a specific cell
mis.kpi.data KPI data (abstract) Base class for manually entered KPI values
prorata.read_group.mixin Pro-rata mixin (abstract) Adapts models with date_from/date_to for pro-rata temporis aggregation

Dependencies

MIS Builder depends on these modules:

Module Source Purpose
account Odoo Core Accounting data (account.move.line, account.account)
board Odoo Core Dashboard integration for embedding report widgets
report_xlsx OCA (reporting-engine) XLSX export engine
date_range OCA (server-ux) Predefined date range types and periods