MIS Builder

mis_builder
REPOSITORY
REPOSITORYOCA/mis-builder
GIT
GIThttps://github.com/OCA/mis-builder.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/mis-builder/tree/19.0/mis_builder
VERSION
VERSION 1.0.1
CATEGORY
CATEGORYReporting
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSStéphane Bidoul, Weblate, OCA-git-bot, oca-ci, Asta
WEBSITE
WEBSITEhttps://github.com/OCA/mis-builder
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 19:40:50
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/reporting-engine:
    - report_xlsx
OCA/server-ux:
    - date_range
odoo/odoo:
    - account
    - base_setup
    - base
    - web
    - onboarding
    - product
    - mail
    - bus
    - web_tour
    - html_editor
    - uom
    - analytic
    - portal
    - http_routing
    - auth_signup
    - digest
    - resource
    - board
    - spreadsheet_dashboard
    - spreadsheet
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES xlrd
xlsxwriter
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
This module allows you to build Management Information Systems
dashboards. Such style of reports presents KPI in rows and time periods
in columns. Reports mainly fetch data from account moves, but can also
combine data coming from arbitrary Odoo models. Reports can be exported
to PDF, Excel and they can be added to Odoo dashboards.

Code Analysis

Views touched (12)
XML IDNameModelTypeStatus
mis_report_instance_add_to_dashboard_form_view add.mis.report.instance.dashboard.wizard.view add.mis.report.instance.dashboard.wizard form New
mis_report_instance_period_view_form mis.report.instance.period form New
mis_report_instance_result_view_form mis.report.instance.result.view.form mis.report.instance form New
mis_report_instance_view_form mis.report.instance.view.form mis.report.instance form New
mis_report_instance_view_list mis.report.instance.view.list mis.report.instance list New
mis_report_style_view_form mis.report.style.view.form mis.report.style form New
mis_report_style_view_list mis.report.style.view.list mis.report.style list New
mis_report_view_form mis.report.view.form mis.report form New
mis_report_view_kpi_form mis.report.view.kpi.form mis.report.kpi form New
mis_report_view_list mis.report.view.list mis.report list New
report_mis_report_instance report_mis_report_instance ir.ui.view qweb New
wizard_mis_report_instance_view_form mis.report.instance field Inherits mis_builder.mis_report_instance_view_form
Models touched (16)

New fields (2)
  • dashboard_id Many2one → ir.actions.act_window
    domain="[('res_model', '=', 'board.board')]" required=True string='Dashboard' args: 'ir.actions.act_window'
  • name Char
    required=True
Public methods (2)
  • action_add_to_dashboard(self)
  • default_get(self, fields_list)
    @api.model

New fields (0)

No new fields.

Public methods (0)

No public methods.

New fields (7)
  • amount Float
  • date_from Date
    required=True string='From'
  • date_to Date
    required=True string='To'
  • kpi_expression_id Many2one → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' ondelete='restrict' required=True string='KPI'
  • name Char
    compute='_compute_name' required=False
  • seq1 Integer
    related='kpi_expression_id.kpi_id.sequence' store=True string='KPI Sequence'
  • seq2 Integer
    related='kpi_expression_id.subkpi_id.sequence' store=True string='Sub-KPI Sequence'
Public methods (0)

No public methods.

New fields (10)
  • account_model Char
    compute='_compute_account_model'
  • all_kpi_ids One2many → mis.report.kpi
    comodel_name='mis.report.kpi' compute='_compute_all_kpi_ids' help='KPIs of this report and subreports.'
  • description Char
    required=False translate=True
  • kpi_ids One2many → mis.report.kpi
    copy=True string="KPI's" args: 'mis.report.kpi', 'report_id'
  • move_lines_source Many2one → ir.model
    comodel_name='ir.model' default=<expr> domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields. This model is the data source for column Actuals." ondelete='cascade' required=True
  • name Char
    required=True translate=True
  • query_ids One2many → mis.report.query
    copy=True string='Queries' args: 'mis.report.query', 'report_id'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' string='Style'
  • subkpi_ids One2many → mis.report.subkpi
    copy=True string='Sub KPI' args: 'mis.report.subkpi', 'report_id'
  • subreport_ids One2many → mis.report.subreport
    copy=True string='Sub reports' args: 'mis.report.subreport', 'report_id'
Public methods (7)
  • copy(self, default=None)
  • declare_and_compute_period(self, kpi_matrix, col_key, col_label, col_description, aep, date_from, date_to, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None, locals_dict=None, aml_model=None, no_auto_expand_accounts=False)
  • evaluate(self, aep, date_from, date_to, target_move='posted', aml_model=None, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None)
    Simplified method to evaluate a report over a time period. :param aep: an AccountingExpressionProcessor instance created using _prepare_aep() :param date_from, date_to: the starting and ending date :param target_move: all|posted :param aml_model: the name of a model that is compatible with account.move.line (default: account.move.line) :param subkpis_filter: a list of subkpis to include in the evaluation (if empty, use all subkpis) :param get_additional_move_line_filter: a bound method that takes no arguments and returns a domain compatible with account.move.line :param get_additional_query_filter: a bound method that takes a single query argument and returns a domain compatible with the query underlying model :return: a dictionary where keys are KPI names, and values are the evaluated results; some additional keys might be present: these should be ignored as they might be removed in the future.
  • get_kpis_by_account_id(self, company)
    Return { account_id: set(kpi) }
  • get_wizard_report_action(self)
  • prepare_kpi_matrix(self, companies=None)
  • prepare_locals_dict(self)

New fields (31)
  • analytic_domain Text
    default='[]' help='A domain to additionally filter move lines considered in this report. Caution: when using different move line sources in different columns, such as budgets by account, make sure to use only fields that are available in all move line sources.'
  • company_id Many2one → res.company
    comodel_name='res.company' default=<expr> required=False string='Allowed company'
  • company_ids Many2many → res.company
    comodel_name='res.company' help='Select companies for which data will be searched.' string='Allowed companies'
  • comparison_mode Boolean
    compute='_compute_comparison_mode' inverse='_inverse_comparison_mode'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' help='Select target currency for the report. Required if companies have different currencies.' required=False string='Currency'
  • date Date
    help='Report base date (leave empty to use current date)' string='Base date'
  • date_from Date
    string='From'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_to Date
    string='To'
  • description Char
    related='report_id.description'
  • display_columns_description Boolean
    help='Display the date range details in the column headers.'
  • landscape_pdf Boolean
    string='Landscape PDF'
  • multi_company Boolean
    default=False help='Check if you wish to specify several companies to be searched for data.' string='Multiple companies'
  • name Char
    required=True translate=True
  • no_auto_expand_accounts Boolean
    string='Disable account details expansion'
  • period_ids One2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' copy=True inverse_name='report_instance_id' required=True string='Periods'
  • pivot_date Date
    compute='_compute_pivot_date'
  • query_company_ids Many2many → res.company
    comodel_name='res.company' compute='_compute_query_company_ids' help='Companies for which data will be searched.' string='Effective companies'
  • report_id Many2one → mis.report
    required=True string='Report' args: 'mis.report'
  • sequence Integer
    default=10
  • source_aml_model_id Many2one
    related='report_id.move_lines_source'
  • source_aml_model_name Char
    related='source_aml_model_id.model' related_sudo=True
  • target_move Selection
    default='posted' required=True string='Target Moves' args: [('posted', 'All Posted Entries'), ('all', 'All Entries')]
  • temporary Boolean
    default=False
  • user_can_edit_annotation Boolean
    compute='_compute_user_can_edit_annotation'
  • user_can_read_annotation Boolean
    compute='_compute_user_can_read_annotation'
  • wide_display_by_default Boolean
    string='Open report in wide mode by default'
  • widget_search_view_id Many2one → ir.ui.view
    comodel_name='ir.ui.view' compute='_compute_widget_search_view_id' domain='[("type", "=", "search"), ("model", "=", source_aml_model_name)]' help='Search view to customize the filter box in the report widget.' readonly=False store=True string='Filter box search view'
  • widget_show_filters Boolean
    default=True help='Show the filter bar in the report widget.' string='Show filters box'
  • widget_show_pivot_date Boolean
    default=False help='Show the Pivot Date in the report widget filter bar.' string='Show Pivot Date'
  • widget_show_settings_button Boolean
    default=False help='Show the settings button in the report widget.' string='Show settings button'
Public methods (11)
  • compute(self)
  • copy(self, default=None)
  • display_settings(self)
  • drilldown(self, arg)
  • export_xls(self)
  • get_filter_descriptions(self)
    @api.model
  • get_notes_by_cell_id(self) -> dict
  • get_views(self, views, options=None)
    @api.model
    Override to get correct form view on dashboard
  • preview(self)
  • print_pdf(self)
  • save_report(self)

New fields (5)
  • annotation_context Json
    help='\n Context used when adding annotation\n '
  • kpi_id Many2one → mis.report.kpi
    comodel_name='mis.report.kpi' ondelete='cascade' required=True
  • note Char
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True
  • subkpi_id Many2one → mis.report.subkpi
    comodel_name='mis.report.subkpi' ondelete='cascade'
Public methods (3)
  • init(self)
  • remove_annotation(self, cell_id, instance_id)
    @api.model
  • set_annotation(self, cell_id, instance_id, note)
    @api.model

New fields (27)
  • allowed_cmpcol_ids Many2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' compute='_compute_allowed_cmpcol_ids'
  • analytic_domain Text
    default='[]' help='A domain to additionally filter move lines considered in this column.'
  • date_from Date
    compute='_compute_dates' string='From (computed)'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_range_type_id Many2one → date.range.type
    comodel_name='date.range.type' domain=[('allow_overlap', '=', False)] string='Date Range Type'
  • date_to Date
    compute='_compute_dates' string='To (computed)'
  • duration Integer
    default=1 help='Number of periods'
  • is_ytd Boolean
    default=False help='Forces the start date to Jan 1st of the relevant year' string='Year to date'
  • manual_date_from Date
    string='From'
  • manual_date_to Date
    string='To'
  • mode Selection
    default=MODE_FIX required=True args: [(MODE_FIX, 'Fixed dates'), (MODE_REL, 'Relative to report base date'), (MODE_NONE, 'No date filter')]
  • name Char
    required=True string='Label' translate=True
  • normalize_factor Integer
    default=1 help='Factor to use to normalize the period (used in comparison' string='Factor'
  • offset Integer
    default=-1 help='Offset from current period'
  • report_id Many2one
    related='report_instance_id.report_id'
  • report_instance_id Many2one → mis.report.instance
    comodel_name='mis.report.instance' ondelete='cascade' required=True string='Report Instance'
  • sequence Integer
    default=100
  • source Selection
    default=SRC_ACTUALS help='Actuals: current data, from accounting and other queries.\nActuals (alternative): current data from an alternative source (eg a database view providing look-alike account move lines).\nSum columns: summation (+/-) of other columns.\nCompare to column: compare to other column.\n' required=True args: [(SRC_ACTUALS, 'Actuals'), (SRC_ACTUALS_ALT, 'Actuals (alternative)'), (SRC_SUMCOL, 'Sum columns'), (SRC_CMPCOL, 'Compare columns')]
  • source_aml_model_id Many2one → ir.model
    comodel_name='ir.model' compute='_compute_source_aml_model_id' domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id'), ('field_id.model_id.model', '!=', 'account.move.line')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields." readonly=False store=True string='Move lines source'
  • source_aml_model_name Char
    related='source_aml_model_id.model' string='Move lines source model name'
  • source_cmpcol_from_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='versus'
  • source_cmpcol_to_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='Compare'
  • source_sumcol_accdet Boolean
    string='Sum account details'
  • source_sumcol_ids One2many → mis.report.instance.period.sum
    comodel_name='mis.report.instance.period.sum' inverse_name='period_id' string='Columns to sum'
  • subkpi_ids Many2many → mis.report.subkpi
    string='Sub KPI Filter' args: 'mis.report.subkpi'
  • type Selection
    string='Period type' args: [('d', 'Day'), ('w', 'Week'), ('m', 'Month'), ('y', 'Year'), ('date_range', 'Date Range')]
  • valid Boolean
    compute='_compute_dates' type='boolean'
Public methods (1)
  • copy_data(self, default=None)

New fields (3)
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True string='Parent column'
  • period_to_sum_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='restrict' required=True string='Column'
  • sign Selection
    default='+' required=True args: [('+', '+'), ('-', '-')]
Public methods (0)

No public methods.

New fields (14)
  • accumulation_method Selection
    default=ACC_SUM help='Determines how values of this kpi spanning over a time period are transformed to match the reporting period. Sum: values of shorter period are added, values of longest or partially overlapping periods are adjusted pro-rata temporis.\nAverage: values of included period are averaged with a pro-rata temporis weight.' required=True args: [(ACC_SUM, 'Sum'), (ACC_AVG, 'Average'), (ACC_NONE, 'None')]
  • auto_expand_accounts Boolean
    string='Display details by account'
  • auto_expand_accounts_style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style for account detail rows'
  • compare_method Selection
    default=CMP_PCT required=True string='Comparison Method' args: [(CMP_DIFF, 'Difference'), (CMP_PCT, 'Percentage'), (CMP_NONE, 'None')]
  • description Char
    required=True translate=True
  • expression Char
    compute='_compute_expression' inverse='_inverse_expression'
  • expression_ids One2many → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' copy=True inverse_name='kpi_id' string='Expressions'
  • multi Boolean
  • name Char
    required=True
  • report_id Many2one → mis.report
    ondelete='cascade' required=True args: 'mis.report'
  • sequence Integer
    default=100
  • style_expression Char
    help='An expression that returns a style depending on the KPI value. Such style is applied on top of the row style.'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style'
  • type Selection
    default=TYPE_NUM required=True string='Value type' args: [(TYPE_NUM, 'Numeric'), (TYPE_PCT, 'Percentage'), (TYPE_STR, 'String')]
Public methods (0)

No public methods.

New fields (4)
  • kpi_id Many2one → mis.report.kpi
    ondelete='cascade' required=True args: 'mis.report.kpi'
  • name Char
    string='Expression'
  • sequence Integer
    related='subkpi_id.sequence' store=True
  • subkpi_id Many2one → mis.report.subkpi
    ondelete='cascade' readonly=False args: 'mis.report.subkpi'
Public methods (0)

No public methods.

New fields (9)
  • aggregate Selection
    args: [('sum', 'Sum'), ('avg', 'Average'), ('min', 'Min'), ('max', 'Max')]
  • company_field_id Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain="[('model_id', '=', model_id)]" help='Field that defines company on related model.When set, it will be automatically be added in search domain of query.' ondelete='set null'
  • date_field Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain="[('ttype', 'in', ('date', 'datetime')),('model_id', '=', model_id)]" ondelete='cascade' required=True
  • domain Char
  • field_ids Many2many → ir.model.fields
    required=True string='Fields to fetch' args: 'ir.model.fields'
  • field_names Char
    compute='_compute_field_names' string='Fetched fields name'
  • model_id Many2one → ir.model
    ondelete='cascade' required=True args: 'ir.model'
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
Public methods (0)

No public methods.

New fields (26)
  • background_color Char
    default='#FFFFFF' help='Background color in valid RGB code (from #000000 to #FFFFFF)'
  • background_color_inherit Boolean
    default=True
  • color Char
    default='#000000' help='Text color in valid RGB code (from #000000 to #FFFFFF)' string='Text color'
  • color_inherit Boolean
    default=True
  • description Html
    compute='_compute_description' help='Describe specific values that are not inherited'
  • divider Selection
    default='1' string='Factor' args: [('1e-6', 'µ'), ('1e-3', 'm'), ('1', '1'), ('1e3', 'k'), ('1e6', 'M')]
  • divider_inherit Boolean
    default=True
  • dp Integer
    default=0 string='Rounding'
  • dp_inherit Boolean
    default=True
  • font_size Selection
    selection=_font_size_selection
  • font_size_inherit Boolean
    default=True
  • font_style Selection
    selection=_font_style_selection
  • font_style_inherit Boolean
    default=True
  • font_weight Selection
    selection=_font_weight_selection
  • font_weight_inherit Boolean
    default=True
  • hide_always Boolean
    default=False
  • hide_always_inherit Boolean
    default=True
  • hide_empty Boolean
    default=False
  • hide_empty_inherit Boolean
    default=True
  • indent_level Integer
  • indent_level_inherit Boolean
    default=True
  • name Char
    required=True string='Style name'
  • prefix Char
  • prefix_inherit Boolean
    default=True
  • suffix Char
  • suffix_inherit Boolean
    default=True
Public methods (9)
  • check_positive_val(self)
    @api.constrains('indent_level')
  • compare_and_render(self, lang, style_props, var_type, compare_method, value, base_value, average_value=1, average_base_value=1)
    @api.model
    :param lang: res.lang record :param style_props: PropertyDict with style properties :param var_type: num, pct or str :param compare_method: diff, pct, none :param value: value to compare (value - base_value) :param base_value: value compared with (value - base_value) :param average_value: value = value / average_value :param average_base_value: base_value = base_value / average_base_value :return: tuple with 4 elements - delta = comparison result (Float or AccountingNone) - delta_r = delta rendered in formatted string (String) - delta_style = PropertyDict with style properties - delta_type = Type of the comparison result (num or pct)
  • merge(self, styles)
    @api.model
    Merge several styles, giving priority to the last. Returns a PropertyDict of style properties.
  • render(self, lang, style_props, var_type, value, sign='-')
    @api.model
  • render_num(self, lang, value, divider=1.0, dp=0, prefix=None, suffix=None, sign='-')
    @api.model
  • render_pct(self, lang, value, dp=1, sign='-')
    @api.model
  • render_str(self, lang, value)
    @api.model
  • to_css_style(self, props, no_indent=False)
    @api.model
  • to_xlsx_style(self, var_type, props, no_indent=False)
    @api.model

New fields (5)
  • description Char
    required=True translate=True
  • expression_ids One2many → mis.report.kpi.expression
    args: 'mis.report.kpi.expression', 'subkpi_id'
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • sequence Integer
    default=1
Public methods (0)

No public methods.

New fields (3)
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • subreport_id Many2one → mis.report
    comodel_name='mis.report' ondelete='restrict' required=True
Public methods (0)

No public methods.

New fields (3)
  • date Date
    compute=<expr> help='Dummy field that adapts searches on date to searches on date_from/date_to.' search='_search_date'
  • date_from Date
    required=True
  • date_to Date
    required=True
Public methods (0)

No public methods.

New fields (0)

No new fields.

Public methods (1)
  • generate_xlsx_report(self, workbook, data, objects)
REPOSITORY
REPOSITORYOCA/mis-builder
GIT
GIThttps://github.com/OCA/mis-builder.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/mis-builder/tree/18.0/mis_builder
VERSION
VERSION 1.8.3
CATEGORY
CATEGORYReporting
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSStéphane Bidoul, Sylvain LE GAL, Lois Rilo, Víctor Martínez, Weblate, OCA-git-bot, oca-ci, Zina Rasoamanana, ThiagoMForgeFlow, Fernando, Germán Bernabeu, Christoph Abenthung, Joel Estrada
WEBSITE
WEBSITEhttps://github.com/OCA/mis-builder
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 19:30:18
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/reporting-engine:
    - report_xlsx
OCA/server-ux:
    - date_range
odoo/odoo:
    - account
    - base_setup
    - base
    - web
    - onboarding
    - product
    - mail
    - bus
    - web_tour
    - html_editor
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
    - board
    - spreadsheet_dashboard
    - spreadsheet
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES openupgradelib
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
This module allows you to build Management Information Systems
dashboards. Such style of reports presents KPI in rows and time periods
in columns. Reports mainly fetch data from account moves, but can also
combine data coming from arbitrary Odoo models. Reports can be exported
to PDF, Excel and they can be added to Odoo dashboards.

Code Analysis

Views touched (12)
XML IDNameModelTypeStatus
mis_report_instance_add_to_dashboard_form_view add.mis.report.instance.dashboard.wizard.view add.mis.report.instance.dashboard.wizard form New
mis_report_instance_period_view_form mis.report.instance.period form New
mis_report_instance_result_view_form mis.report.instance.result.view.form mis.report.instance form New
mis_report_instance_view_form mis.report.instance.view.form mis.report.instance form New
mis_report_instance_view_list mis.report.instance.view.list mis.report.instance list New
mis_report_style_view_form mis.report.style.view.form mis.report.style form New
mis_report_style_view_list mis.report.style.view.list mis.report.style list New
mis_report_view_form mis.report.view.form mis.report form New
mis_report_view_kpi_form mis.report.view.kpi.form mis.report.kpi form New
mis_report_view_list mis.report.view.list mis.report list New
report_mis_report_instance report_mis_report_instance ir.ui.view qweb New
wizard_mis_report_instance_view_form mis.report.instance field Inherits mis_builder.mis_report_instance_view_form
Models touched (16)

New fields (2)
  • dashboard_id Many2one → ir.actions.act_window
    domain="[('res_model', '=', 'board.board')]" required=True string='Dashboard' args: 'ir.actions.act_window'
  • name Char
    required=True
Public methods (2)
  • action_add_to_dashboard(self)
  • default_get(self, fields_list)
    @api.model

New fields (0)

No new fields.

Public methods (0)

No public methods.

New fields (7)
  • amount Float
  • date_from Date
    required=True string='From'
  • date_to Date
    required=True string='To'
  • kpi_expression_id Many2one → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' ondelete='restrict' required=True string='KPI'
  • name Char
    compute='_compute_name' required=False
  • seq1 Integer
    related='kpi_expression_id.kpi_id.sequence' store=True string='KPI Sequence'
  • seq2 Integer
    related='kpi_expression_id.subkpi_id.sequence' store=True string='Sub-KPI Sequence'
Public methods (0)

No public methods.

New fields (10)
  • account_model Char
    compute='_compute_account_model'
  • all_kpi_ids One2many → mis.report.kpi
    comodel_name='mis.report.kpi' compute='_compute_all_kpi_ids' help='KPIs of this report and subreports.'
  • description Char
    required=False translate=True
  • kpi_ids One2many → mis.report.kpi
    copy=True string="KPI's" args: 'mis.report.kpi', 'report_id'
  • move_lines_source Many2one → ir.model
    comodel_name='ir.model' default=_default_move_lines_source domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields. This model is the data source for column Actuals." ondelete='cascade' required=True
  • name Char
    required=True translate=True
  • query_ids One2many → mis.report.query
    copy=True string='Queries' args: 'mis.report.query', 'report_id'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' string='Style'
  • subkpi_ids One2many → mis.report.subkpi
    copy=True string='Sub KPI' args: 'mis.report.subkpi', 'report_id'
  • subreport_ids One2many → mis.report.subreport
    copy=True string='Sub reports' args: 'mis.report.subreport', 'report_id'
Public methods (7)
  • copy(self, default=None)
  • declare_and_compute_period(self, kpi_matrix, col_key, col_label, col_description, aep, date_from, date_to, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None, locals_dict=None, aml_model=None, no_auto_expand_accounts=False)
  • evaluate(self, aep, date_from, date_to, target_move='posted', aml_model=None, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None)
    Simplified method to evaluate a report over a time period. :param aep: an AccountingExpressionProcessor instance created using _prepare_aep() :param date_from, date_to: the starting and ending date :param target_move: all|posted :param aml_model: the name of a model that is compatible with account.move.line (default: account.move.line) :param subkpis_filter: a list of subkpis to include in the evaluation (if empty, use all subkpis) :param get_additional_move_line_filter: a bound method that takes no arguments and returns a domain compatible with account.move.line :param get_additional_query_filter: a bound method that takes a single query argument and returns a domain compatible with the query underlying model :return: a dictionary where keys are KPI names, and values are the evaluated results; some additional keys might be present: these should be ignored as they might be removed in the future.
  • get_kpis_by_account_id(self, company)
    Return { account_id: set(kpi) }
  • get_wizard_report_action(self)
  • prepare_kpi_matrix(self, companies=None)
  • prepare_locals_dict(self)

New fields (31)
  • analytic_domain Text
    default='[]' help='A domain to additionally filter move lines considered in this report. Caution: when using different move line sources in different columns, such as budgets by account, make sure to use only fields that are available in all move line sources.'
  • company_id Many2one → res.company
    comodel_name='res.company' default=<expr> required=False string='Allowed company'
  • company_ids Many2many → res.company
    comodel_name='res.company' help='Select companies for which data will be searched.' string='Allowed companies'
  • comparison_mode Boolean
    compute='_compute_comparison_mode' inverse='_inverse_comparison_mode'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' help='Select target currency for the report. Required if companies have different currencies.' required=False string='Currency'
  • date Date
    help='Report base date (leave empty to use current date)' string='Base date'
  • date_from Date
    string='From'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_to Date
    string='To'
  • description Char
    related='report_id.description'
  • display_columns_description Boolean
    help='Display the date range details in the column headers.'
  • landscape_pdf Boolean
    string='Landscape PDF'
  • multi_company Boolean
    default=False help='Check if you wish to specify several companies to be searched for data.' string='Multiple companies'
  • name Char
    required=True translate=True
  • no_auto_expand_accounts Boolean
    string='Disable account details expansion'
  • period_ids One2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' copy=True inverse_name='report_instance_id' required=True string='Periods'
  • pivot_date Date
    compute='_compute_pivot_date'
  • query_company_ids Many2many → res.company
    comodel_name='res.company' compute='_compute_query_company_ids' help='Companies for which data will be searched.' string='Effective companies'
  • report_id Many2one → mis.report
    required=True string='Report' args: 'mis.report'
  • sequence Integer
    default=10
  • source_aml_model_id Many2one
    related='report_id.move_lines_source'
  • source_aml_model_name Char
    related='source_aml_model_id.model' related_sudo=True
  • target_move Selection
    default='posted' required=True string='Target Moves' args: [('posted', 'All Posted Entries'), ('all', 'All Entries')]
  • temporary Boolean
    default=False
  • user_can_edit_annotation Boolean
    compute='_compute_user_can_edit_annotation'
  • user_can_read_annotation Boolean
    compute='_compute_user_can_read_annotation'
  • wide_display_by_default Boolean
    string='Open report in wide mode by default'
  • widget_search_view_id Many2one → ir.ui.view
    comodel_name='ir.ui.view' compute='_compute_widget_search_view_id' domain='[("type", "=", "search"), ("model", "=", source_aml_model_name)]' help='Search view to customize the filter box in the report widget.' readonly=False store=True string='Filter box search view'
  • widget_show_filters Boolean
    default=True help='Show the filter bar in the report widget.' string='Show filters box'
  • widget_show_pivot_date Boolean
    default=False help='Show the Pivot Date in the report widget filter bar.' string='Show Pivot Date'
  • widget_show_settings_button Boolean
    default=False help='Show the settings button in the report widget.' string='Show settings button'
Public methods (11)
  • compute(self)
  • copy(self, default=None)
  • display_settings(self)
  • drilldown(self, arg)
  • export_xls(self)
  • get_filter_descriptions(self)
    @api.model
  • get_notes_by_cell_id(self) -> dict
  • get_views(self, views, options=None)
    @api.model
    Override to get correct form view on dashboard
  • preview(self)
  • print_pdf(self)
  • save_report(self)

New fields (5)
  • annotation_context Json
    help='\n Context used when adding annotation\n '
  • kpi_id Many2one → mis.report.kpi
    comodel_name='mis.report.kpi' ondelete='cascade' required=True
  • note Char
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True
  • subkpi_id Many2one → mis.report.subkpi
    comodel_name='mis.report.subkpi' ondelete='cascade'
Public methods (3)
  • init(self)
  • remove_annotation(self, cell_id, instance_id)
    @api.model
  • set_annotation(self, cell_id, instance_id, note)
    @api.model

New fields (27)
  • allowed_cmpcol_ids Many2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' compute='_compute_allowed_cmpcol_ids'
  • analytic_domain Text
    default='[]' help='A domain to additionally filter move lines considered in this column.'
  • date_from Date
    compute='_compute_dates' string='From (computed)'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_range_type_id Many2one → date.range.type
    comodel_name='date.range.type' domain=[('allow_overlap', '=', False)] string='Date Range Type'
  • date_to Date
    compute='_compute_dates' string='To (computed)'
  • duration Integer
    default=1 help='Number of periods'
  • is_ytd Boolean
    default=False help='Forces the start date to Jan 1st of the relevant year' string='Year to date'
  • manual_date_from Date
    string='From'
  • manual_date_to Date
    string='To'
  • mode Selection
    default=MODE_FIX required=True args: [(MODE_FIX, 'Fixed dates'), (MODE_REL, 'Relative to report base date'), (MODE_NONE, 'No date filter')]
  • name Char
    required=True string='Label' translate=True
  • normalize_factor Integer
    default=1 help='Factor to use to normalize the period (used in comparison' string='Factor'
  • offset Integer
    default=-1 help='Offset from current period'
  • report_id Many2one
    related='report_instance_id.report_id'
  • report_instance_id Many2one → mis.report.instance
    comodel_name='mis.report.instance' ondelete='cascade' required=True string='Report Instance'
  • sequence Integer
    default=100
  • source Selection
    default=SRC_ACTUALS help='Actuals: current data, from accounting and other queries.\nActuals (alternative): current data from an alternative source (eg a database view providing look-alike account move lines).\nSum columns: summation (+/-) of other columns.\nCompare to column: compare to other column.\n' required=True args: [(SRC_ACTUALS, 'Actuals'), (SRC_ACTUALS_ALT, 'Actuals (alternative)'), (SRC_SUMCOL, 'Sum columns'), (SRC_CMPCOL, 'Compare columns')]
  • source_aml_model_id Many2one → ir.model
    comodel_name='ir.model' compute='_compute_source_aml_model_id' domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id'), ('field_id.model_id.model', '!=', 'account.move.line')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields." readonly=False store=True string='Move lines source'
  • source_aml_model_name Char
    related='source_aml_model_id.model' string='Move lines source model name'
  • source_cmpcol_from_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='versus'
  • source_cmpcol_to_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='Compare'
  • source_sumcol_accdet Boolean
    string='Sum account details'
  • source_sumcol_ids One2many → mis.report.instance.period.sum
    comodel_name='mis.report.instance.period.sum' inverse_name='period_id' string='Columns to sum'
  • subkpi_ids Many2many → mis.report.subkpi
    string='Sub KPI Filter' args: 'mis.report.subkpi'
  • type Selection
    string='Period type' args: [('d', 'Day'), ('w', 'Week'), ('m', 'Month'), ('y', 'Year'), ('date_range', 'Date Range')]
  • valid Boolean
    compute='_compute_dates' type='boolean'
Public methods (1)
  • copy_data(self, default=None)

New fields (3)
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True string='Parent column'
  • period_to_sum_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='restrict' required=True string='Column'
  • sign Selection
    default='+' required=True args: [('+', '+'), ('-', '-')]
Public methods (0)

No public methods.

New fields (14)
  • accumulation_method Selection
    default=ACC_SUM help='Determines how values of this kpi spanning over a time period are transformed to match the reporting period. Sum: values of shorter period are added, values of longest or partially overlapping periods are adjusted pro-rata temporis.\nAverage: values of included period are averaged with a pro-rata temporis weight.' required=True args: [(ACC_SUM, 'Sum'), (ACC_AVG, 'Average'), (ACC_NONE, 'None')]
  • auto_expand_accounts Boolean
    string='Display details by account'
  • auto_expand_accounts_style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style for account detail rows'
  • compare_method Selection
    default=CMP_PCT required=True string='Comparison Method' args: [(CMP_DIFF, 'Difference'), (CMP_PCT, 'Percentage'), (CMP_NONE, 'None')]
  • description Char
    required=True translate=True
  • expression Char
    compute='_compute_expression' inverse='_inverse_expression'
  • expression_ids One2many → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' copy=True inverse_name='kpi_id' string='Expressions'
  • multi Boolean
  • name Char
    required=True
  • report_id Many2one → mis.report
    ondelete='cascade' required=True args: 'mis.report'
  • sequence Integer
    default=100
  • style_expression Char
    help='An expression that returns a style depending on the KPI value. Such style is applied on top of the row style.'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style'
  • type Selection
    default=TYPE_NUM required=True string='Value type' args: [(TYPE_NUM, 'Numeric'), (TYPE_PCT, 'Percentage'), (TYPE_STR, 'String')]
Public methods (0)

No public methods.

New fields (4)
  • kpi_id Many2one → mis.report.kpi
    ondelete='cascade' required=True args: 'mis.report.kpi'
  • name Char
    string='Expression'
  • sequence Integer
    related='subkpi_id.sequence' store=True
  • subkpi_id Many2one → mis.report.subkpi
    ondelete='cascade' readonly=False args: 'mis.report.subkpi'
Public methods (0)

No public methods.

New fields (9)
  • aggregate Selection
    args: [('sum', 'Sum'), ('avg', 'Average'), ('min', 'Min'), ('max', 'Max')]
  • company_field_id Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain="[('model_id', '=', model_id)]" help='Field that defines company on related model.When set, it will be automatically be added in search domain of query.' ondelete='set null'
  • date_field Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain="[('ttype', 'in', ('date', 'datetime')),('model_id', '=', model_id)]" ondelete='cascade' required=True
  • domain Char
  • field_ids Many2many → ir.model.fields
    required=True string='Fields to fetch' args: 'ir.model.fields'
  • field_names Char
    compute='_compute_field_names' string='Fetched fields name'
  • model_id Many2one → ir.model
    ondelete='cascade' required=True args: 'ir.model'
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
Public methods (0)

No public methods.

New fields (26)
  • background_color Char
    default='#FFFFFF' help='Background color in valid RGB code (from #000000 to #FFFFFF)'
  • background_color_inherit Boolean
    default=True
  • color Char
    default='#000000' help='Text color in valid RGB code (from #000000 to #FFFFFF)' string='Text color'
  • color_inherit Boolean
    default=True
  • description Html
    compute='_compute_description' help='Describe specific values that are not inherited'
  • divider Selection
    default='1' string='Factor' args: [('1e-6', 'µ'), ('1e-3', 'm'), ('1', '1'), ('1e3', 'k'), ('1e6', 'M')]
  • divider_inherit Boolean
    default=True
  • dp Integer
    default=0 string='Rounding'
  • dp_inherit Boolean
    default=True
  • font_size Selection
    selection=_font_size_selection
  • font_size_inherit Boolean
    default=True
  • font_style Selection
    selection=_font_style_selection
  • font_style_inherit Boolean
    default=True
  • font_weight Selection
    selection=_font_weight_selection
  • font_weight_inherit Boolean
    default=True
  • hide_always Boolean
    default=False
  • hide_always_inherit Boolean
    default=True
  • hide_empty Boolean
    default=False
  • hide_empty_inherit Boolean
    default=True
  • indent_level Integer
  • indent_level_inherit Boolean
    default=True
  • name Char
    required=True string='Style name'
  • prefix Char
  • prefix_inherit Boolean
    default=True
  • suffix Char
  • suffix_inherit Boolean
    default=True
Public methods (9)
  • check_positive_val(self)
    @api.constrains('indent_level')
  • compare_and_render(self, lang, style_props, var_type, compare_method, value, base_value, average_value=1, average_base_value=1)
    @api.model
    :param lang: res.lang record :param style_props: PropertyDict with style properties :param var_type: num, pct or str :param compare_method: diff, pct, none :param value: value to compare (value - base_value) :param base_value: value compared with (value - base_value) :param average_value: value = value / average_value :param average_base_value: base_value = base_value / average_base_value :return: tuple with 4 elements - delta = comparison result (Float or AccountingNone) - delta_r = delta rendered in formatted string (String) - delta_style = PropertyDict with style properties - delta_type = Type of the comparison result (num or pct)
  • merge(self, styles)
    @api.model
    Merge several styles, giving priority to the last. Returns a PropertyDict of style properties.
  • render(self, lang, style_props, var_type, value, sign='-')
    @api.model
  • render_num(self, lang, value, divider=1.0, dp=0, prefix=None, suffix=None, sign='-')
    @api.model
  • render_pct(self, lang, value, dp=1, sign='-')
    @api.model
  • render_str(self, lang, value)
    @api.model
  • to_css_style(self, props, no_indent=False)
    @api.model
  • to_xlsx_style(self, var_type, props, no_indent=False)
    @api.model

New fields (5)
  • description Char
    required=True translate=True
  • expression_ids One2many → mis.report.kpi.expression
    args: 'mis.report.kpi.expression', 'subkpi_id'
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • sequence Integer
    default=1
Public methods (0)

No public methods.

New fields (3)
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • subreport_id Many2one → mis.report
    comodel_name='mis.report' ondelete='restrict' required=True
Public methods (0)

No public methods.

New fields (3)
  • date Date
    compute=<expr> help='Dummy field that adapts searches on date to searches on date_from/date_to.' search='_search_date'
  • date_from Date
    required=True
  • date_to Date
    required=True
Public methods (0)

No public methods.

New fields (0)

No new fields.

Public methods (1)
  • generate_xlsx_report(self, workbook, data, objects)
REPOSITORY
REPOSITORYOCA/mis-builder
GIT
GIThttps://github.com/OCA/mis-builder.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/mis-builder/tree/17.0/mis_builder
VERSION
VERSION 1.5.0
CATEGORY
CATEGORYReporting
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSStéphane Bidoul, Víctor Martínez, Weblate, OCA-git-bot, David, oca-ci, Zina Rasoamanana, mpascual, chaule97
WEBSITE
WEBSITEhttps://github.com/OCA/mis-builder
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 19:20:10
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/reporting-engine:
    - report_xlsx
OCA/server-ux:
    - date_range
odoo/odoo:
    - account
    - base_setup
    - base
    - web
    - onboarding
    - product
    - mail
    - bus
    - web_tour
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
    - board
    - spreadsheet_dashboard
    - spreadsheet
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES xlrd
xlsxwriter
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
This module allows you to build Management Information Systems
dashboards. Such style of reports presents KPI in rows and time periods
in columns. Reports mainly fetch data from account moves, but can also
combine data coming from arbitrary Odoo models. Reports can be exported
to PDF, Excel and they can be added to Odoo dashboards.

Code Analysis

Views touched (12)
XML IDNameModelTypeStatus
mis_report_instance_add_to_dashboard_form_view add.mis.report.instance.dashboard.wizard.view add.mis.report.instance.dashboard.wizard form New
mis_report_instance_period_view_form mis.report.instance.period form New
mis_report_instance_result_view_form mis.report.instance.result.view.form mis.report.instance form New
mis_report_instance_view_form mis.report.instance.view.form mis.report.instance form New
mis_report_instance_view_tree mis.report.instance.view.tree mis.report.instance tree New
mis_report_style_view_form mis.report.style.view.form mis.report.style form New
mis_report_style_view_tree mis.report.style.view.tree mis.report.style tree New
mis_report_view_form mis.report.view.form mis.report form New
mis_report_view_kpi_form mis.report.view.kpi.form mis.report.kpi form New
mis_report_view_tree mis.report.view.tree mis.report tree New
report_mis_report_instance report_mis_report_instance ir.ui.view qweb New
wizard_mis_report_instance_view_form mis.report.instance field Inherits mis_builder.mis_report_instance_view_form
Models touched (16)

New fields (2)
  • dashboard_id Many2one → ir.actions.act_window
    domain="[('res_model', '=', 'board.board')]" required=True string='Dashboard' args: 'ir.actions.act_window'
  • name Char
    required=True
Public methods (2)
  • action_add_to_dashboard(self)
  • default_get(self, fields_list)
    @api.model

New fields (0)

No new fields.

Public methods (0)

No public methods.

New fields (7)
  • amount Float
  • date_from Date
    required=True string='From'
  • date_to Date
    required=True string='To'
  • kpi_expression_id Many2one → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' ondelete='restrict' required=True string='KPI'
  • name Char
    compute='_compute_name' required=False
  • seq1 Integer
    related='kpi_expression_id.kpi_id.sequence' store=True string='KPI Sequence'
  • seq2 Integer
    related='kpi_expression_id.subkpi_id.sequence' store=True string='Sub-KPI Sequence'
Public methods (0)

No public methods.

New fields (10)
  • account_model Char
    compute='_compute_account_model'
  • all_kpi_ids One2many → mis.report.kpi
    comodel_name='mis.report.kpi' compute='_compute_all_kpi_ids' help='KPIs of this report and subreports.'
  • description Char
    required=False translate=True
  • kpi_ids One2many → mis.report.kpi
    copy=True string="KPI's" args: 'mis.report.kpi', 'report_id'
  • move_lines_source Many2one → ir.model
    comodel_name='ir.model' default=_default_move_lines_source domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields. This model is the data source for column Actuals." ondelete='cascade' required=True
  • name Char
    required=True translate=True
  • query_ids One2many → mis.report.query
    copy=True string='Queries' args: 'mis.report.query', 'report_id'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' string='Style'
  • subkpi_ids One2many → mis.report.subkpi
    copy=True string='Sub KPI' args: 'mis.report.subkpi', 'report_id'
  • subreport_ids One2many → mis.report.subreport
    copy=True string='Sub reports' args: 'mis.report.subreport', 'report_id'
Public methods (7)
  • copy(self, default=None)
  • declare_and_compute_period(self, kpi_matrix, col_key, col_label, col_description, aep, date_from, date_to, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None, locals_dict=None, aml_model=None, no_auto_expand_accounts=False)
  • evaluate(self, aep, date_from, date_to, target_move='posted', aml_model=None, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None)
    Simplified method to evaluate a report over a time period. :param aep: an AccountingExpressionProcessor instance created using _prepare_aep() :param date_from, date_to: the starting and ending date :param target_move: all|posted :param aml_model: the name of a model that is compatible with account.move.line (default: account.move.line) :param subkpis_filter: a list of subkpis to include in the evaluation (if empty, use all subkpis) :param get_additional_move_line_filter: a bound method that takes no arguments and returns a domain compatible with account.move.line :param get_additional_query_filter: a bound method that takes a single query argument and returns a domain compatible with the query underlying model :return: a dictionary where keys are KPI names, and values are the evaluated results; some additional keys might be present: these should be ignored as they might be removed in the future.
  • get_kpis_by_account_id(self, company)
    Return { account_id: set(kpi) }
  • get_wizard_report_action(self)
  • prepare_kpi_matrix(self, multi_company=False)
  • prepare_locals_dict(self)

New fields (29)
  • analytic_domain Text
    default='[]' help='A domain to additionally filter move lines considered in this report. Caution: when using different move line sources in different columns, such as budgets by account, make sure to use only fields that are available in all move line sources.'
  • company_id Many2one → res.company
    comodel_name='res.company' default=<expr> required=False string='Allowed company'
  • company_ids Many2many → res.company
    comodel_name='res.company' help='Select companies for which data will be searched.' string='Allowed companies'
  • comparison_mode Boolean
    compute='_compute_comparison_mode' inverse='_inverse_comparison_mode'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' help='Select target currency for the report. Required if companies have different currencies.' required=False string='Currency'
  • date Date
    help='Report base date (leave empty to use current date)' string='Base date'
  • date_from Date
    string='From'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_to Date
    string='To'
  • description Char
    related='report_id.description'
  • display_columns_description Boolean
    help='Display the date range details in the column headers.'
  • landscape_pdf Boolean
    string='Landscape PDF'
  • multi_company Boolean
    default=False help='Check if you wish to specify several companies to be searched for data.' string='Multiple companies'
  • name Char
    required=True translate=True
  • no_auto_expand_accounts Boolean
    string='Disable account details expansion'
  • period_ids One2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' copy=True inverse_name='report_instance_id' required=True string='Periods'
  • pivot_date Date
    compute='_compute_pivot_date'
  • query_company_ids Many2many → res.company
    comodel_name='res.company' compute='_compute_query_company_ids' help='Companies for which data will be searched.' string='Effective companies'
  • report_id Many2one → mis.report
    required=True string='Report' args: 'mis.report'
  • source_aml_model_id Many2one
    related='report_id.move_lines_source'
  • source_aml_model_name Char
    related='source_aml_model_id.model' related_sudo=True
  • target_move Selection
    default='posted' required=True string='Target Moves' args: [('posted', 'All Posted Entries'), ('all', 'All Entries')]
  • temporary Boolean
    default=False
  • user_can_edit_annotation Boolean
    compute='_compute_user_can_edit_annotation'
  • user_can_read_annotation Boolean
    compute='_compute_user_can_read_annotation'
  • widget_search_view_id Many2one → ir.ui.view
    comodel_name='ir.ui.view' compute='_compute_widget_search_view_id' domain='[("type", "=", "search"), ("model", "=", source_aml_model_name)]' help='Search view to customize the filter box in the report widget.' readonly=False store=True string='Filter box search view'
  • widget_show_filters Boolean
    default=True help='Show the filter bar in the report widget.' string='Show filters box'
  • widget_show_pivot_date Boolean
    default=False help='Show the Pivot Date in the report widget filter bar.' string='Show Pivot Date'
  • widget_show_settings_button Boolean
    default=False help='Show the settings button in the report widget.' string='Show settings button'
Public methods (11)
  • compute(self)
  • copy(self, default=None)
  • display_settings(self)
  • drilldown(self, arg)
  • export_xls(self)
  • get_filter_descriptions(self)
    @api.model
  • get_notes_by_cell_id(self) -> dict
  • get_views(self, views, options=None)
    @api.model
    Override to get correct form view on dashboard
  • preview(self)
  • print_pdf(self)
  • save_report(self)

New fields (5)
  • annotation_context Json
    help='\n Context used when adding annotation\n '
  • kpi_id Many2one → mis.report.kpi
    comodel_name='mis.report.kpi' ondelete='cascade' required=True
  • note Char
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True
  • subkpi_id Many2one → mis.report.subkpi
    comodel_name='mis.report.subkpi' ondelete='cascade'
Public methods (3)
  • init(self)
  • remove_annotation(self, cell_id, instance_id)
    @api.model
  • set_annotation(self, cell_id, instance_id, note)
    @api.model

New fields (27)
  • allowed_cmpcol_ids Many2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' compute='_compute_allowed_cmpcol_ids'
  • analytic_domain Text
    default='[]' help='A domain to additionally filter move lines considered in this column.'
  • date_from Date
    compute='_compute_dates' string='From (computed)'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_range_type_id Many2one → date.range.type
    comodel_name='date.range.type' domain=[('allow_overlap', '=', False)] string='Date Range Type'
  • date_to Date
    compute='_compute_dates' string='To (computed)'
  • duration Integer
    default=1 help='Number of periods'
  • is_ytd Boolean
    default=False help='Forces the start date to Jan 1st of the relevant year' string='Year to date'
  • manual_date_from Date
    string='From'
  • manual_date_to Date
    string='To'
  • mode Selection
    default=MODE_FIX required=True args: [(MODE_FIX, 'Fixed dates'), (MODE_REL, 'Relative to report base date'), (MODE_NONE, 'No date filter')]
  • name Char
    required=True string='Label' translate=True
  • normalize_factor Integer
    default=1 help='Factor to use to normalize the period (used in comparison' string='Factor'
  • offset Integer
    default=-1 help='Offset from current period'
  • report_id Many2one
    related='report_instance_id.report_id'
  • report_instance_id Many2one → mis.report.instance
    comodel_name='mis.report.instance' ondelete='cascade' required=True string='Report Instance'
  • sequence Integer
    default=100
  • source Selection
    default=SRC_ACTUALS help='Actuals: current data, from accounting and other queries.\nActuals (alternative): current data from an alternative source (eg a database view providing look-alike account move lines).\nSum columns: summation (+/-) of other columns.\nCompare to column: compare to other column.\n' required=True args: [(SRC_ACTUALS, 'Actuals'), (SRC_ACTUALS_ALT, 'Actuals (alternative)'), (SRC_SUMCOL, 'Sum columns'), (SRC_CMPCOL, 'Compare columns')]
  • source_aml_model_id Many2one → ir.model
    comodel_name='ir.model' compute='_compute_source_aml_model_id' domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id'), ('field_id.model_id.model', '!=', 'account.move.line')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields." readonly=False store=True string='Move lines source'
  • source_aml_model_name Char
    related='source_aml_model_id.model' string='Move lines source model name'
  • source_cmpcol_from_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='versus'
  • source_cmpcol_to_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='Compare'
  • source_sumcol_accdet Boolean
    string='Sum account details'
  • source_sumcol_ids One2many → mis.report.instance.period.sum
    comodel_name='mis.report.instance.period.sum' inverse_name='period_id' string='Columns to sum'
  • subkpi_ids Many2many → mis.report.subkpi
    string='Sub KPI Filter' args: 'mis.report.subkpi'
  • type Selection
    string='Period type' args: [('d', _('Day')), ('w', _('Week')), ('m', _('Month')), ('y', _('Year')), ('date_range', _('Date Range'))]
  • valid Boolean
    compute='_compute_dates' type='boolean'
Public methods (1)
  • copy_data(self, default=None)

New fields (3)
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True string='Parent column'
  • period_to_sum_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='restrict' required=True string='Column'
  • sign Selection
    default='+' required=True args: [('+', '+'), ('-', '-')]
Public methods (0)

No public methods.

New fields (14)
  • accumulation_method Selection
    default=ACC_SUM help='Determines how values of this kpi spanning over a time period are transformed to match the reporting period. Sum: values of shorter period are added, values of longest or partially overlapping periods are adjusted pro-rata temporis.\nAverage: values of included period are averaged with a pro-rata temporis weight.' required=True args: [(ACC_SUM, _('Sum')), (ACC_AVG, _('Average')), (ACC_NONE, _('None'))]
  • auto_expand_accounts Boolean
    string='Display details by account'
  • auto_expand_accounts_style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style for account detail rows'
  • compare_method Selection
    default=CMP_PCT required=True string='Comparison Method' args: [(CMP_DIFF, _('Difference')), (CMP_PCT, _('Percentage')), (CMP_NONE, _('None'))]
  • description Char
    required=True translate=True
  • expression Char
    compute='_compute_expression' inverse='_inverse_expression'
  • expression_ids One2many → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' copy=True inverse_name='kpi_id' string='Expressions'
  • multi Boolean
  • name Char
    required=True
  • report_id Many2one → mis.report
    ondelete='cascade' required=True args: 'mis.report'
  • sequence Integer
    default=100
  • style_expression Char
    help='An expression that returns a style depending on the KPI value. Such style is applied on top of the row style.'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style'
  • type Selection
    default=TYPE_NUM required=True string='Value type' args: [(TYPE_NUM, _('Numeric')), (TYPE_PCT, _('Percentage')), (TYPE_STR, _('String'))]
Public methods (0)

No public methods.

New fields (4)
  • kpi_id Many2one → mis.report.kpi
    ondelete='cascade' required=True args: 'mis.report.kpi'
  • name Char
    string='Expression'
  • sequence Integer
    related='subkpi_id.sequence' store=True
  • subkpi_id Many2one → mis.report.subkpi
    ondelete='cascade' readonly=False args: 'mis.report.subkpi'
Public methods (0)

No public methods.

New fields (9)
  • aggregate Selection
    args: [('sum', _('Sum')), ('avg', _('Average')), ('min', _('Min')), ('max', _('Max'))]
  • company_field_id Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain="[('model_id', '=', model_id)]" help='Field that defines company on related model.When set, it will be automatically be added in search domain of query.' ondelete='set null'
  • date_field Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain="[('ttype', 'in', ('date', 'datetime')),('model_id', '=', model_id)]" ondelete='cascade' required=True
  • domain Char
  • field_ids Many2many → ir.model.fields
    required=True string='Fields to fetch' args: 'ir.model.fields'
  • field_names Char
    compute='_compute_field_names' string='Fetched fields name'
  • model_id Many2one → ir.model
    ondelete='cascade' required=True args: 'ir.model'
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
Public methods (0)

No public methods.

New fields (25)
  • background_color Char
    default='#FFFFFF' help='Background color in valid RGB code (from #000000 to #FFFFFF)'
  • background_color_inherit Boolean
    default=True
  • color Char
    default='#000000' help='Text color in valid RGB code (from #000000 to #FFFFFF)' string='Text color'
  • color_inherit Boolean
    default=True
  • divider Selection
    default='1' string='Factor' args: [('1e-6', _('µ')), ('1e-3', _('m')), ('1', _('1')), ('1e3', _('k')), ('1e6', _('M'))]
  • divider_inherit Boolean
    default=True
  • dp Integer
    default=0 string='Rounding'
  • dp_inherit Boolean
    default=True
  • font_size Selection
    selection=_font_size_selection
  • font_size_inherit Boolean
    default=True
  • font_style Selection
    selection=_font_style_selection
  • font_style_inherit Boolean
    default=True
  • font_weight Selection
    selection=_font_weight_selection
  • font_weight_inherit Boolean
    default=True
  • hide_always Boolean
    default=False
  • hide_always_inherit Boolean
    default=True
  • hide_empty Boolean
    default=False
  • hide_empty_inherit Boolean
    default=True
  • indent_level Integer
  • indent_level_inherit Boolean
    default=True
  • name Char
    required=True string='Style name'
  • prefix Char
  • prefix_inherit Boolean
    default=True
  • suffix Char
  • suffix_inherit Boolean
    default=True
Public methods (9)
  • check_positive_val(self)
    @api.constrains('indent_level')
  • compare_and_render(self, lang, style_props, var_type, compare_method, value, base_value, average_value=1, average_base_value=1)
    @api.model
    :param lang: res.lang record :param style_props: PropertyDict with style properties :param var_type: num, pct or str :param compare_method: diff, pct, none :param value: value to compare (value - base_value) :param base_value: value compared with (value - base_value) :param average_value: value = value / average_value :param average_base_value: base_value = base_value / average_base_value :return: tuple with 4 elements - delta = comparison result (Float or AccountingNone) - delta_r = delta rendered in formatted string (String) - delta_style = PropertyDict with style properties - delta_type = Type of the comparison result (num or pct)
  • merge(self, styles)
    @api.model
    Merge several styles, giving priority to the last. Returns a PropertyDict of style properties.
  • render(self, lang, style_props, var_type, value, sign='-')
    @api.model
  • render_num(self, lang, value, divider=1.0, dp=0, prefix=None, suffix=None, sign='-')
    @api.model
  • render_pct(self, lang, value, dp=1, sign='-')
    @api.model
  • render_str(self, lang, value)
    @api.model
  • to_css_style(self, props, no_indent=False)
    @api.model
  • to_xlsx_style(self, var_type, props, no_indent=False)
    @api.model

New fields (5)
  • description Char
    required=True translate=True
  • expression_ids One2many → mis.report.kpi.expression
    args: 'mis.report.kpi.expression', 'subkpi_id'
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • sequence Integer
    default=1
Public methods (0)

No public methods.

New fields (3)
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • subreport_id Many2one → mis.report
    comodel_name='mis.report' ondelete='restrict' required=True
Public methods (0)

No public methods.

New fields (3)
  • date Date
    compute=<expr> help='Dummy field that adapts searches on date to searches on date_from/date_to.' search='_search_date'
  • date_from Date
    required=True
  • date_to Date
    required=True
Public methods (1)
  • read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True)
    @api.model
    Override read_group to perform pro-rata temporis adjustments. When read_group is invoked with a domain that filters on a time period (date >= from and date <= to, or date_from <= to and date_to >= from), adjust the accumulated values pro-rata temporis.

New fields (0)

No new fields.

Public methods (1)
  • generate_xlsx_report(self, workbook, data, objects)
REPOSITORY
REPOSITORYOCA/mis-builder
GIT
GIThttps://github.com/OCA/mis-builder.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/mis-builder/tree/16.0/mis_builder
VERSION
VERSION 5.8.0
CATEGORY
CATEGORYReporting
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSStéphane Bidoul, Holger Brunn, GitHub, Enric Tobella, Miquel Raïch, Víctor Martínez, Weblate, OCA-git-bot, David, oca-ci, Emilio Pascual, Eduardo de Miguel, Zina Rasoamanana, Laurent Stukkens, hda, Dũng (Trần Đình), mle, Dora Jurcevic, Ivan Sokolov, Joel Estrada, Camila
WEBSITE
WEBSITEhttps://github.com/OCA/mis-builder
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:53:57
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/reporting-engine:
    - report_xlsx
OCA/server-ux:
    - date_range
odoo/odoo:
    - account
    - base_setup
    - base
    - web
    - product
    - mail
    - bus
    - web_tour
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
    - board
    - spreadsheet_dashboard
    - spreadsheet
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (12)
XML IDNameModelTypeStatus
mis_report_instance_add_to_dashboard_form_view add.mis.report.instance.dashboard.wizard.view add.mis.report.instance.dashboard.wizard form New
mis_report_instance_period_view_form mis.report.instance.period form New
mis_report_instance_result_view_form mis.report.instance.result.view.form mis.report.instance form New
mis_report_instance_view_form mis.report.instance.view.form mis.report.instance form New
mis_report_instance_view_tree mis.report.instance.view.tree mis.report.instance tree New
mis_report_style_view_form mis.report.style.view.form mis.report.style form New
mis_report_style_view_tree mis.report.style.view.tree mis.report.style tree New
mis_report_view_form mis.report.view.form mis.report form New
mis_report_view_kpi_form mis.report.view.kpi.form mis.report.kpi form New
mis_report_view_tree mis.report.view.tree mis.report tree New
report_mis_report_instance report_mis_report_instance ir.ui.view qweb New
wizard_mis_report_instance_view_form mis.report.instance field Inherits mis_builder.mis_report_instance_view_form
Models touched (16)

New fields (2)
  • dashboard_id Many2one → ir.actions.act_window
    domain="[('res_model', '=', 'board.board')]" required=True string='Dashboard' args: 'ir.actions.act_window'
  • name Char
    required=True
Public methods (2)
  • action_add_to_dashboard(self)
  • default_get(self, fields_list)
    @api.model

New fields (0)

No new fields.

Public methods (0)

No public methods.

New fields (7)
  • amount Float
  • date_from Date
    required=True string='From'
  • date_to Date
    required=True string='To'
  • kpi_expression_id Many2one → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' ondelete='restrict' required=True string='KPI'
  • name Char
    compute='_compute_name' readonly=True required=False
  • seq1 Integer
    readonly=True related='kpi_expression_id.kpi_id.sequence' store=True string='KPI Sequence'
  • seq2 Integer
    readonly=True related='kpi_expression_id.subkpi_id.sequence' store=True string='Sub-KPI Sequence'
Public methods (0)

No public methods.

New fields (10)
  • account_model Char
    compute='_compute_account_model'
  • all_kpi_ids One2many → mis.report.kpi
    comodel_name='mis.report.kpi' compute='_compute_all_kpi_ids' help='KPIs of this report and subreports.'
  • description Char
    required=False translate=True
  • kpi_ids One2many → mis.report.kpi
    copy=True string="KPI's" args: 'mis.report.kpi', 'report_id'
  • move_lines_source Many2one → ir.model
    comodel_name='ir.model' default=_default_move_lines_source domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields. This model is the data source for column Actuals." ondelete='cascade' required=True
  • name Char
    required=True translate=True
  • query_ids One2many → mis.report.query
    copy=True string='Queries' args: 'mis.report.query', 'report_id'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' string='Style'
  • subkpi_ids One2many → mis.report.subkpi
    copy=True string='Sub KPI' args: 'mis.report.subkpi', 'report_id'
  • subreport_ids One2many → mis.report.subreport
    copy=True string='Sub reports' args: 'mis.report.subreport', 'report_id'
Public methods (7)
  • copy(self, default=None)
  • declare_and_compute_period(self, kpi_matrix, col_key, col_label, col_description, aep, date_from, date_to, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None, locals_dict=None, aml_model=None, no_auto_expand_accounts=False)
  • evaluate(self, aep, date_from, date_to, target_move='posted', aml_model=None, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None)
    Simplified method to evaluate a report over a time period. :param aep: an AccountingExpressionProcessor instance created using _prepare_aep() :param date_from, date_to: the starting and ending date :param target_move: all|posted :param aml_model: the name of a model that is compatible with account.move.line (default: account.move.line) :param subkpis_filter: a list of subkpis to include in the evaluation (if empty, use all subkpis) :param get_additional_move_line_filter: a bound method that takes no arguments and returns a domain compatible with account.move.line :param get_additional_query_filter: a bound method that takes a single query argument and returns a domain compatible with the query underlying model :return: a dictionary where keys are KPI names, and values are the evaluated results; some additional keys might be present: these should be ignored as they might be removed in the future.
  • get_kpis_by_account_id(self, company)
    Return { account_id: set(kpi) }
  • get_wizard_report_action(self)
  • prepare_kpi_matrix(self, multi_company=False)
  • prepare_locals_dict(self)

New fields (31)
  • analytic_domain Text
    default='[]' help='A domain to additionally filter move lines considered in this report. Caution: when using different move line sources in different columns, such as budgets by account, make sure to use only fields that are available in all move line sources.'
  • company_id Many2one → res.company
    comodel_name='res.company' default=<expr> required=False string='Allowed company'
  • company_ids Many2many → res.company
    comodel_name='res.company' help='Select companies for which data will be searched.' string='Allowed companies'
  • comparison_mode Boolean
    compute='_compute_comparison_mode' inverse='_inverse_comparison_mode'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' help='Select target currency for the report. Required if companies have different currencies.' required=False string='Currency'
  • date Date
    help='Report base date (leave empty to use current date)' string='Base date'
  • date_from Date
    string='From'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_to Date
    string='To'
  • description Char
    readonly=True related='report_id.description'
  • display_columns_description Boolean
    help='Display the date range details in the column headers.'
  • landscape_pdf Boolean
    string='Landscape PDF'
  • multi_company Boolean
    default=False help='Check if you wish to specify several companies to be searched for data.' string='Multiple companies'
  • name Char
    required=True translate=True
  • no_auto_expand_accounts Boolean
    string='Disable account details expansion'
  • period_ids One2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' copy=True inverse_name='report_instance_id' required=True string='Periods'
  • pivot_date Date
    compute='_compute_pivot_date'
  • query_company_ids Many2many → res.company
    comodel_name='res.company' compute='_compute_query_company_ids' help='Companies for which data will be searched.' string='Effective companies'
  • report_id Many2one → mis.report
    required=True string='Report' args: 'mis.report'
  • sequence Integer
    default=10
  • source_aml_model_id Many2one
    readonly=True related='report_id.move_lines_source'
  • source_aml_model_name Char
    readonly=True related='source_aml_model_id.model' related_sudo=True
  • target_move Selection
    default='posted' required=True string='Target Moves' args: [('posted', 'All Posted Entries'), ('all', 'All Entries')]
  • temporary Boolean
    default=False
  • user_can_edit_annotation Boolean
    compute='_compute_user_can_edit_annotation'
  • user_can_read_annotation Boolean
    compute='_compute_user_can_read_annotation'
  • wide_display_by_default Boolean
    string='Open report in wide mode by default'
  • widget_search_view_id Many2one → ir.ui.view
    comodel_name='ir.ui.view' compute='_compute_widget_search_view_id' domain='[("type", "=", "search"), ("model", "=", source_aml_model_name)]' help='Search view to customize the filter box in the report widget.' readonly=False store=True string='Filter box search view'
  • widget_show_filters Boolean
    default=True help='Show the filter bar in the report widget.' string='Show filters box'
  • widget_show_pivot_date Boolean
    default=False help='Show the Pivot Date in the report widget filter bar.' string='Show Pivot Date'
  • widget_show_settings_button Boolean
    default=False help='Show the settings button in the report widget.' string='Show settings button'
Public methods (11)
  • compute(self)
  • copy(self, default=None)
  • display_settings(self)
  • drilldown(self, arg)
  • export_xls(self)
  • get_filter_descriptions(self)
    @api.model
  • get_notes_by_cell_id(self) -> dict
  • get_views(self, views, options=None)
    @api.model
    Override to get correct form view on dashboard
  • preview(self)
  • print_pdf(self)
  • save_report(self)

New fields (5)
  • annotation_context Json
    help='\n Context used when adding annotation\n '
  • kpi_id Many2one → mis.report.kpi
    comodel_name='mis.report.kpi' ondelete='cascade' required=True
  • note Char
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True
  • subkpi_id Many2one → mis.report.subkpi
    comodel_name='mis.report.subkpi' ondelete='cascade'
Public methods (3)
  • init(self)
  • remove_annotation(self, cell_id, instance_id)
    @api.model
  • set_annotation(self, cell_id, instance_id, note)
    @api.model

New fields (27)
  • allowed_cmpcol_ids Many2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' compute='_compute_allowed_cmpcol_ids'
  • analytic_domain Text
    default='[]' help='A domain to additionally filter move lines considered in this column.'
  • date_from Date
    compute='_compute_dates' string='From (computed)'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_range_type_id Many2one → date.range.type
    comodel_name='date.range.type' domain=[('allow_overlap', '=', False)] string='Date Range Type'
  • date_to Date
    compute='_compute_dates' string='To (computed)'
  • duration Integer
    default=1 help='Number of periods'
  • is_ytd Boolean
    default=False help='Forces the start date to Jan 1st of the relevant year' string='Year to date'
  • manual_date_from Date
    string='From'
  • manual_date_to Date
    string='To'
  • mode Selection
    default=MODE_FIX required=True args: [(MODE_FIX, 'Fixed dates'), (MODE_REL, 'Relative to report base date'), (MODE_NONE, 'No date filter')]
  • name Char
    required=True string='Label' translate=True
  • normalize_factor Integer
    default=1 help='Factor to use to normalize the period (used in comparison' string='Factor'
  • offset Integer
    default=-1 help='Offset from current period'
  • report_id Many2one
    related='report_instance_id.report_id'
  • report_instance_id Many2one → mis.report.instance
    comodel_name='mis.report.instance' ondelete='cascade' required=True string='Report Instance'
  • sequence Integer
    default=100
  • source Selection
    default=SRC_ACTUALS help='Actuals: current data, from accounting and other queries.\nActuals (alternative): current data from an alternative source (eg a database view providing look-alike account move lines).\nSum columns: summation (+/-) of other columns.\nCompare to column: compare to other column.\n' required=True args: [(SRC_ACTUALS, 'Actuals'), (SRC_ACTUALS_ALT, 'Actuals (alternative)'), (SRC_SUMCOL, 'Sum columns'), (SRC_CMPCOL, 'Compare columns')]
  • source_aml_model_id Many2one → ir.model
    comodel_name='ir.model' compute='_compute_source_aml_model_id' domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id'), ('field_id.model_id.model', '!=', 'account.move.line')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields." readonly=False store=True string='Move lines source'
  • source_aml_model_name Char
    related='source_aml_model_id.model' string='Move lines source model name'
  • source_cmpcol_from_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='versus'
  • source_cmpcol_to_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='Compare'
  • source_sumcol_accdet Boolean
    string='Sum account details'
  • source_sumcol_ids One2many → mis.report.instance.period.sum
    comodel_name='mis.report.instance.period.sum' inverse_name='period_id' string='Columns to sum'
  • subkpi_ids Many2many → mis.report.subkpi
    string='Sub KPI Filter' args: 'mis.report.subkpi'
  • type Selection
    string='Period type' args: [('d', _('Day')), ('w', _('Week')), ('m', _('Month')), ('y', _('Year')), ('date_range', _('Date Range'))]
  • valid Boolean
    compute='_compute_dates' type='boolean'
Public methods (1)
  • copy_data(self, default=None)

New fields (3)
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True string='Parent column'
  • period_to_sum_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='restrict' required=True string='Column'
  • sign Selection
    default='+' required=True args: [('+', '+'), ('-', '-')]
Public methods (0)

No public methods.

New fields (14)
  • accumulation_method Selection
    default=ACC_SUM help='Determines how values of this kpi spanning over a time period are transformed to match the reporting period. Sum: values of shorter period are added, values of longest or partially overlapping periods are adjusted pro-rata temporis.\nAverage: values of included period are averaged with a pro-rata temporis weight.' required=True args: [(ACC_SUM, _('Sum')), (ACC_AVG, _('Average')), (ACC_NONE, _('None'))]
  • auto_expand_accounts Boolean
    string='Display details by account'
  • auto_expand_accounts_style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style for account detail rows'
  • compare_method Selection
    default=CMP_PCT required=True string='Comparison Method' args: [(CMP_DIFF, _('Difference')), (CMP_PCT, _('Percentage')), (CMP_NONE, _('None'))]
  • description Char
    required=True translate=True
  • expression Char
    compute='_compute_expression' inverse='_inverse_expression'
  • expression_ids One2many → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' copy=True inverse_name='kpi_id' string='Expressions'
  • multi Boolean
  • name Char
    required=True
  • report_id Many2one → mis.report
    ondelete='cascade' required=True args: 'mis.report'
  • sequence Integer
    default=100
  • style_expression Char
    help='An expression that returns a style depending on the KPI value. Such style is applied on top of the row style.'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style'
  • type Selection
    default=TYPE_NUM required=True string='Value type' args: [(TYPE_NUM, _('Numeric')), (TYPE_PCT, _('Percentage')), (TYPE_STR, _('String'))]
Public methods (2)
  • name_get(self)
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (4)
  • kpi_id Many2one → mis.report.kpi
    ondelete='cascade' required=True args: 'mis.report.kpi'
  • name Char
    string='Expression'
  • sequence Integer
    readonly=True related='subkpi_id.sequence' store=True
  • subkpi_id Many2one → mis.report.subkpi
    ondelete='cascade' readonly=False args: 'mis.report.subkpi'
Public methods (2)
  • name_get(self)
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (9)
  • aggregate Selection
    args: [('sum', _('Sum')), ('avg', _('Average')), ('min', _('Min')), ('max', _('Max'))]
  • company_field_id Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain="[('model_id', '=', model_id)]" help='Field that defines company on related model.When set, it will be automatically be added in search domain of query.' ondelete='set null'
  • date_field Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain="[('ttype', 'in', ('date', 'datetime')),('model_id', '=', model_id)]" ondelete='cascade' required=True
  • domain Char
  • field_ids Many2many → ir.model.fields
    required=True string='Fields to fetch' args: 'ir.model.fields'
  • field_names Char
    compute='_compute_field_names' string='Fetched fields name'
  • model_id Many2one → ir.model
    ondelete='cascade' required=True args: 'ir.model'
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
Public methods (0)

No public methods.

New fields (25)
  • background_color Char
    default='#FFFFFF' help='Background color in valid RGB code (from #000000 to #FFFFFF)'
  • background_color_inherit Boolean
    default=True
  • color Char
    default='#000000' help='Text color in valid RGB code (from #000000 to #FFFFFF)' string='Text color'
  • color_inherit Boolean
    default=True
  • divider Selection
    default='1' string='Factor' args: [('1e-6', _('µ')), ('1e-3', _('m')), ('1', _('1')), ('1e3', _('k')), ('1e6', _('M'))]
  • divider_inherit Boolean
    default=True
  • dp Integer
    default=0 string='Rounding'
  • dp_inherit Boolean
    default=True
  • font_size Selection
    selection=_font_size_selection
  • font_size_inherit Boolean
    default=True
  • font_style Selection
    selection=_font_style_selection
  • font_style_inherit Boolean
    default=True
  • font_weight Selection
    selection=_font_weight_selection
  • font_weight_inherit Boolean
    default=True
  • hide_always Boolean
    default=False
  • hide_always_inherit Boolean
    default=True
  • hide_empty Boolean
    default=False
  • hide_empty_inherit Boolean
    default=True
  • indent_level Integer
  • indent_level_inherit Boolean
    default=True
  • name Char
    required=True string='Style name'
  • prefix Char
  • prefix_inherit Boolean
    default=True
  • suffix Char
  • suffix_inherit Boolean
    default=True
Public methods (9)
  • check_positive_val(self)
    @api.constrains('indent_level')
  • compare_and_render(self, lang, style_props, var_type, compare_method, value, base_value, average_value=1, average_base_value=1)
    @api.model
    :param lang: res.lang record :param style_props: PropertyDict with style properties :param var_type: num, pct or str :param compare_method: diff, pct, none :param value: value to compare (value - base_value) :param base_value: value compared with (value - base_value) :param average_value: value = value / average_value :param average_base_value: base_value = base_value / average_base_value :return: tuple with 4 elements - delta = comparison result (Float or AccountingNone) - delta_r = delta rendered in formatted string (String) - delta_style = PropertyDict with style properties - delta_type = Type of the comparison result (num or pct)
  • merge(self, styles)
    @api.model
    Merge several styles, giving priority to the last. Returns a PropertyDict of style properties.
  • render(self, lang, style_props, var_type, value, sign='-')
    @api.model
  • render_num(self, lang, value, divider=1.0, dp=0, prefix=None, suffix=None, sign='-')
    @api.model
  • render_pct(self, lang, value, dp=1, sign='-')
    @api.model
  • render_str(self, lang, value)
    @api.model
  • to_css_style(self, props, no_indent=False)
    @api.model
  • to_xlsx_style(self, var_type, props, no_indent=False)
    @api.model

New fields (5)
  • description Char
    required=True translate=True
  • expression_ids One2many → mis.report.kpi.expression
    args: 'mis.report.kpi.expression', 'subkpi_id'
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • sequence Integer
    default=1
Public methods (0)

No public methods.

New fields (3)
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • subreport_id Many2one → mis.report
    comodel_name='mis.report' ondelete='restrict' required=True
Public methods (0)

No public methods.

New fields (3)
  • date Date
    compute=<expr> help='Dummy field that adapts searches on date to searches on date_from/date_to.' search='_search_date'
  • date_from Date
    required=True
  • date_to Date
    required=True
Public methods (1)
  • read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True)
    @api.model
    Override read_group to perform pro-rata temporis adjustments. When read_group is invoked with a domain that filters on a time period (date >= from and date <= to, or date_from <= to and date_to >= from), adjust the accumulated values pro-rata temporis.

New fields (0)

No new fields.

Public methods (1)
  • generate_xlsx_report(self, workbook, data, objects)
REPOSITORY
REPOSITORYOCA/mis-builder
GIT
GIThttps://github.com/OCA/mis-builder.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/mis-builder/tree/15.0/mis_builder
VERSION
VERSION 4.1.6
CATEGORY
CATEGORYReporting
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSStéphane Bidoul, GitHub, OCA Transbot, Miquel Raïch, Víctor Martínez, Denis Leemann, Weblate, OCA-git-bot, Marçal Isern, oca-ci, Maksym Yankin, hitrosol
WEBSITE
WEBSITEhttps://github.com/OCA/mis-builder
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:46:42
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/reporting-engine:
    - report_xlsx
OCA/server-ux:
    - date_range
odoo/odoo:
    - account
    - base_setup
    - base
    - web
    - product
    - mail
    - bus
    - web_tour
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
    - board
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES xlrd
xlsxwriter
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (12)
XML IDNameModelTypeStatus
mis_report_instance_add_to_dashboard_form_view add.mis.report.instance.dashboard.wizard.view add.mis.report.instance.dashboard.wizard form New
mis_report_instance_period_view_form mis.report.instance.period form New
mis_report_instance_result_view_form mis.report.instance.result.view.form mis.report.instance form New
mis_report_instance_view_form mis.report.instance.view.form mis.report.instance form New
mis_report_instance_view_tree mis.report.instance.view.tree mis.report.instance tree New
mis_report_style_view_form mis.report.style.view.form mis.report.style form New
mis_report_style_view_tree mis.report.style.view.tree mis.report.style tree New
mis_report_view_form mis.report.view.form mis.report form New
mis_report_view_kpi_form mis.report.view.kpi.form mis.report.kpi form New
mis_report_view_tree mis.report.view.tree mis.report tree New
report_mis_report_instance report_mis_report_instance ir.ui.view qweb New
wizard_mis_report_instance_view_form mis.report.instance field Inherits mis_builder.mis_report_instance_view_form
Models touched (15)

New fields (2)
  • dashboard_id Many2one → ir.actions.act_window
    domain="[('res_model', '=', 'board.board')]" required=True string='Dashboard' args: 'ir.actions.act_window'
  • name Char
    required=True
Public methods (2)
  • action_add_to_dashboard(self)
  • default_get(self, fields_list)
    @api.model

New fields (0)

No new fields.

Public methods (0)

No public methods.

New fields (7)
  • amount Float
  • date_from Date
    required=True string='From'
  • date_to Date
    required=True string='To'
  • kpi_expression_id Many2one → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' ondelete='restrict' required=True string='KPI'
  • name Char
    compute='_compute_name' readonly=True required=False
  • seq1 Integer
    readonly=True related='kpi_expression_id.kpi_id.sequence' store=True string='KPI Sequence'
  • seq2 Integer
    readonly=True related='kpi_expression_id.subkpi_id.sequence' store=True string='Sub-KPI Sequence'
Public methods (0)

No public methods.

New fields (10)
  • account_model Char
    compute='_compute_account_model'
  • all_kpi_ids One2many → mis.report.kpi
    comodel_name='mis.report.kpi' compute='_compute_all_kpi_ids' help='KPIs of this report and subreports.'
  • description Char
    required=False translate=True
  • kpi_ids One2many → mis.report.kpi
    copy=True string="KPI's" args: 'mis.report.kpi', 'report_id'
  • move_lines_source Many2one → ir.model
    comodel_name='ir.model' default=_default_move_lines_source domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields. This model is the data source for column Actuals." ondelete='cascade' required=True
  • name Char
    required=True translate=True
  • query_ids One2many → mis.report.query
    copy=True string='Queries' args: 'mis.report.query', 'report_id'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' string='Style'
  • subkpi_ids One2many → mis.report.subkpi
    copy=True string='Sub KPI' args: 'mis.report.subkpi', 'report_id'
  • subreport_ids One2many → mis.report.subreport
    copy=True string='Sub reports' args: 'mis.report.subreport', 'report_id'
Public methods (7)
  • copy(self, default=None)
  • declare_and_compute_period(self, kpi_matrix, col_key, col_label, col_description, aep, date_from, date_to, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None, locals_dict=None, aml_model=None, no_auto_expand_accounts=False)
  • evaluate(self, aep, date_from, date_to, target_move='posted', aml_model=None, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None)
    Simplified method to evaluate a report over a time period. :param aep: an AccountingExpressionProcessor instance created using _prepare_aep() :param date_from, date_to: the starting and ending date :param target_move: all|posted :param aml_model: the name of a model that is compatible with account.move.line (default: account.move.line) :param subkpis_filter: a list of subkpis to include in the evaluation (if empty, use all subkpis) :param get_additional_move_line_filter: a bound method that takes no arguments and returns a domain compatible with account.move.line :param get_additional_query_filter: a bound method that takes a single query argument and returns a domain compatible with the query underlying model :return: a dictionary where keys are KPI names, and values are the evaluated results; some additional keys might be present: these should be ignored as they might be removed in the future.
  • get_kpis_by_account_id(self, company)
    Return { account_id: set(kpi) }
  • get_wizard_report_action(self)
  • prepare_kpi_matrix(self, multi_company=False)
  • prepare_locals_dict(self)

New fields (24)
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' string='Analytic Account'
  • analytic_group_id Many2one → account.analytic.group
    comodel_name='account.analytic.group' string='Analytic Account Group'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' string='Analytic Tags'
  • company_id Many2one → res.company
    comodel_name='res.company' default=<expr> required=False string='Allowed company'
  • company_ids Many2many → res.company
    comodel_name='res.company' help='Select companies for which data will be searched.' string='Allowed companies'
  • comparison_mode Boolean
    compute='_compute_comparison_mode' inverse='_inverse_comparison_mode'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' help='Select target currency for the report. Required if companies have different currencies.' required=False string='Currency'
  • date Date
    help='Report base date (leave empty to use current date)' string='Base date'
  • date_from Date
    string='From'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_to Date
    string='To'
  • description Char
    readonly=True related='report_id.description'
  • display_columns_description Boolean
    help='Display the date range details in the column headers.'
  • hide_analytic_filters Boolean
    default=True
  • landscape_pdf Boolean
    string='Landscape PDF'
  • multi_company Boolean
    default=False help='Check if you wish to specify several companies to be searched for data.' string='Multiple companies'
  • name Char
    required=True translate=True
  • no_auto_expand_accounts Boolean
    string='Disable account details expansion'
  • period_ids One2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' copy=True inverse_name='report_instance_id' required=True string='Periods'
  • pivot_date Date
    compute='_compute_pivot_date'
  • query_company_ids Many2many → res.company
    comodel_name='res.company' compute='_compute_query_company_ids' help='Companies for which data will be searched.' string='Effective companies'
  • report_id Many2one → mis.report
    required=True string='Report' args: 'mis.report'
  • target_move Selection
    default='posted' required=True string='Target Moves' args: [('posted', 'All Posted Entries'), ('all', 'All Entries')]
  • temporary Boolean
    default=False
Public methods (9)
  • compute(self)
  • copy(self, default=None)
  • display_settings(self)
  • drilldown(self, arg)
  • export_xls(self)
  • get_filter_descriptions_from_context(self)
    @api.model
  • preview(self)
  • print_pdf(self)
  • save_report(self)

New fields (29)
  • allowed_cmpcol_ids Many2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' compute='_compute_allowed_cmpcol_ids'
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' help='Filter column on journal entries that match this analytic account.This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Account'
  • analytic_group_id Many2one → account.analytic.group
    comodel_name='account.analytic.group' help='Filter column on journal entries that match this analytic account group. This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Account Group'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' help='Filter column on journal entries that have all these analytic tags.This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Tags'
  • date_from Date
    compute='_compute_dates' string='From (computed)'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_range_type_id Many2one → date.range.type
    comodel_name='date.range.type' domain=[('allow_overlap', '=', False)] string='Date Range Type'
  • date_to Date
    compute='_compute_dates' string='To (computed)'
  • duration Integer
    default=1 help='Number of periods'
  • is_ytd Boolean
    default=False help='Forces the start date to Jan 1st of the relevant year' string='Year to date'
  • manual_date_from Date
    string='From'
  • manual_date_to Date
    string='To'
  • mode Selection
    default=MODE_FIX required=True args: [(MODE_FIX, 'Fixed dates'), (MODE_REL, 'Relative to report base date'), (MODE_NONE, 'No date filter')]
  • name Char
    required=True string='Label' translate=True
  • normalize_factor Integer
    default=1 help='Factor to use to normalize the period (used in comparison' string='Factor'
  • offset Integer
    default=-1 help='Offset from current period'
  • report_id Many2one
    related='report_instance_id.report_id'
  • report_instance_id Many2one → mis.report.instance
    comodel_name='mis.report.instance' ondelete='cascade' required=True string='Report Instance'
  • sequence Integer
    default=100
  • source Selection
    default=SRC_ACTUALS help='Actuals: current data, from accounting and other queries.\nActuals (alternative): current data from an alternative source (eg a database view providing look-alike account move lines).\nSum columns: summation (+/-) of other columns.\nCompare to column: compare to other column.\n' required=True args: [(SRC_ACTUALS, 'Actuals'), (SRC_ACTUALS_ALT, 'Actuals (alternative)'), (SRC_SUMCOL, 'Sum columns'), (SRC_CMPCOL, 'Compare columns')]
  • source_aml_model_id Many2one → ir.model
    comodel_name='ir.model' domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id'), ('field_id.model_id.model', '!=', 'account.move.line')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields." string='Move lines source'
  • source_aml_model_name Char
    related='source_aml_model_id.model' string='Move lines source model name'
  • source_cmpcol_from_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='versus'
  • source_cmpcol_to_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='Compare'
  • source_sumcol_accdet Boolean
    string='Sum account details'
  • source_sumcol_ids One2many → mis.report.instance.period.sum
    comodel_name='mis.report.instance.period.sum' inverse_name='period_id' string='Columns to sum'
  • subkpi_ids Many2many → mis.report.subkpi
    string='Sub KPI Filter' args: 'mis.report.subkpi'
  • type Selection
    string='Period type' args: [('d', _('Day')), ('w', _('Week')), ('m', _('Month')), ('y', _('Year')), ('date_range', _('Date Range'))]
  • valid Boolean
    compute='_compute_dates' type='boolean'
Public methods (1)
  • copy_data(self, default=None)

New fields (3)
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True string='Parent column'
  • period_to_sum_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='restrict' required=True string='Column'
  • sign Selection
    default='+' required=True args: [('+', '+'), ('-', '-')]
Public methods (0)

No public methods.

New fields (14)
  • accumulation_method Selection
    default=ACC_SUM help='Determines how values of this kpi spanning over a time period are transformed to match the reporting period. Sum: values of shorter period are added, values of longest or partially overlapping periods are adjusted pro-rata temporis.\nAverage: values of included period are averaged with a pro-rata temporis weight.' required=True args: [(ACC_SUM, _('Sum')), (ACC_AVG, _('Average')), (ACC_NONE, _('None'))]
  • auto_expand_accounts Boolean
    string='Display details by account'
  • auto_expand_accounts_style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style for account detail rows'
  • compare_method Selection
    default=CMP_PCT required=True string='Comparison Method' args: [(CMP_DIFF, _('Difference')), (CMP_PCT, _('Percentage')), (CMP_NONE, _('None'))]
  • description Char
    required=True translate=True
  • expression Char
    compute='_compute_expression' inverse='_inverse_expression'
  • expression_ids One2many → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' copy=True inverse_name='kpi_id' string='Expressions'
  • multi Boolean
  • name Char
    required=True
  • report_id Many2one → mis.report
    ondelete='cascade' required=True args: 'mis.report'
  • sequence Integer
    default=100
  • style_expression Char
    help='An expression that returns a style depending on the KPI value. Such style is applied on top of the row style.'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style'
  • type Selection
    default=TYPE_NUM required=True string='Value type' args: [(TYPE_NUM, _('Numeric')), (TYPE_PCT, _('Percentage')), (TYPE_STR, _('String'))]
Public methods (2)
  • name_get(self)
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (4)
  • kpi_id Many2one → mis.report.kpi
    ondelete='cascade' required=True args: 'mis.report.kpi'
  • name Char
    string='Expression'
  • sequence Integer
    readonly=True related='subkpi_id.sequence' store=True
  • subkpi_id Many2one → mis.report.subkpi
    ondelete='cascade' readonly=False args: 'mis.report.subkpi'
Public methods (2)
  • name_get(self)
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (8)
  • aggregate Selection
    args: [('sum', _('Sum')), ('avg', _('Average')), ('min', _('Min')), ('max', _('Max'))]
  • date_field Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain=[('ttype', 'in', ('date', 'datetime'))] ondelete='cascade' required=True
  • domain Char
  • field_ids Many2many → ir.model.fields
    required=True string='Fields to fetch' args: 'ir.model.fields'
  • field_names Char
    compute='_compute_field_names' string='Fetched fields name'
  • model_id Many2one → ir.model
    ondelete='cascade' required=True args: 'ir.model'
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
Public methods (0)

No public methods.

New fields (25)
  • background_color Char
    default='#FFFFFF' help='Background color in valid RGB code (from #000000 to #FFFFFF)'
  • background_color_inherit Boolean
    default=True
  • color Char
    default='#000000' help='Text color in valid RGB code (from #000000 to #FFFFFF)' string='Text color'
  • color_inherit Boolean
    default=True
  • divider Selection
    default='1' string='Factor' args: [('1e-6', _('µ')), ('1e-3', _('m')), ('1', _('1')), ('1e3', _('k')), ('1e6', _('M'))]
  • divider_inherit Boolean
    default=True
  • dp Integer
    default=0 string='Rounding'
  • dp_inherit Boolean
    default=True
  • font_size Selection
    selection=_font_size_selection
  • font_size_inherit Boolean
    default=True
  • font_style Selection
    selection=_font_style_selection
  • font_style_inherit Boolean
    default=True
  • font_weight Selection
    selection=_font_weight_selection
  • font_weight_inherit Boolean
    default=True
  • hide_always Boolean
    default=False
  • hide_always_inherit Boolean
    default=True
  • hide_empty Boolean
    default=False
  • hide_empty_inherit Boolean
    default=True
  • indent_level Integer
  • indent_level_inherit Boolean
    default=True
  • name Char
    required=True string='Style name'
  • prefix Char
  • prefix_inherit Boolean
    default=True
  • suffix Char
  • suffix_inherit Boolean
    default=True
Public methods (9)
  • check_positive_val(self)
    @api.constrains('indent_level')
  • compare_and_render(self, lang, style_props, type, compare_method, value, base_value, average_value=1, average_base_value=1)
    @api.model
    :param lang: res.lang record :param style_props: PropertyDict with style properties :param type: num, pct or str :param compare_method: diff, pct, none :param value: value to compare (value - base_value) :param base_value: value compared with (value - base_value) :param average_value: value = value / average_value :param average_base_value: base_value = base_value / average_base_value :return: tuple with 4 elements - delta = comparison result (Float or AccountingNone) - delta_r = delta rendered in formatted string (String) - delta_style = PropertyDict with style properties - delta_type = Type of the comparison result (num or pct)
  • merge(self, styles)
    @api.model
    Merge several styles, giving priority to the last. Returns a PropertyDict of style properties.
  • render(self, lang, style_props, type, value, sign='-')
    @api.model
  • render_num(self, lang, value, divider=1.0, dp=0, prefix=None, suffix=None, sign='-')
    @api.model
  • render_pct(self, lang, value, dp=1, sign='-')
    @api.model
  • render_str(self, lang, value)
    @api.model
  • to_css_style(self, props, no_indent=False)
    @api.model
  • to_xlsx_style(self, type, props, no_indent=False)
    @api.model

New fields (5)
  • description Char
    required=True translate=True
  • expression_ids One2many → mis.report.kpi.expression
    args: 'mis.report.kpi.expression', 'subkpi_id'
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • sequence Integer
    default=1
Public methods (0)

No public methods.

New fields (3)
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • subreport_id Many2one → mis.report
    comodel_name='mis.report' ondelete='restrict' required=True
Public methods (0)

No public methods.

New fields (3)
  • date Date
    compute=<expr> help='Dummy field that adapts searches on date to searches on date_from/date_to.' search='_search_date'
  • date_from Date
    required=True
  • date_to Date
    required=True
Public methods (1)
  • read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True)
    @api.model
    Override read_group to perform pro-rata temporis adjustments. When read_group is invoked with a domain that filters on a time period (date >= from and date <= to, or date_from <= to and date_to >= from), adjust the accumulated values pro-rata temporis.

New fields (0)

No new fields.

Public methods (1)
  • generate_xlsx_report(self, workbook, data, objects)
REPOSITORY
REPOSITORYOCA/mis-builder
GIT
GIThttps://github.com/OCA/mis-builder.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/mis-builder/tree/14.0/mis_builder
VERSION
VERSION 4.3.0
CATEGORY
CATEGORYReporting
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSStéphane Bidoul, Alexis de Lattre, Pedro M. Baeza, Cédric Pigeon, OCA Transbot, Miquel Raïch, Víctor Martínez, Sébastien Alix, João Marques, oca-travis, Weblate, OCA-git-bot, oca-ci, oca-git-bot, daniel-chionne, mle, Dora Jurcevic
WEBSITE
WEBSITEhttps://github.com/OCA/mis-builder
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:41:10
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/reporting-engine:
    - report_xlsx
OCA/server-ux:
    - date_range
odoo/odoo:
    - account
    - base_setup
    - base
    - web
    - product
    - mail
    - bus
    - web_tour
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
    - board
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (14)
XML IDNameModelTypeStatus
assets_backend mis_builder ir.ui.view qweb Inherits web.assets_backend
assets_report assets_report ir.ui.view qweb Inherits web.report_assets_common
mis_report_instance_add_to_dashboard_form_view add.mis.report.instance.dashboard.wizard.view add.mis.report.instance.dashboard.wizard form New
mis_report_instance_period_view_form mis.report.instance.period form New
mis_report_instance_result_view_form mis.report.instance.result.view.form mis.report.instance form New
mis_report_instance_view_form mis.report.instance.view.form mis.report.instance form New
mis_report_instance_view_tree mis.report.instance.view.tree mis.report.instance tree New
mis_report_style_view_form mis.report.style.view.form mis.report.style form New
mis_report_style_view_tree mis.report.style.view.tree mis.report.style tree New
mis_report_view_form mis.report.view.form mis.report form New
mis_report_view_kpi_form mis.report.view.kpi.form mis.report.kpi form New
mis_report_view_tree mis.report.view.tree mis.report tree New
report_mis_report_instance report_mis_report_instance ir.ui.view qweb New
wizard_mis_report_instance_view_form mis.report.instance field Inherits mis_builder.mis_report_instance_view_form
Models touched (15)

New fields (2)
  • dashboard_id Many2one → ir.actions.act_window
    domain="[('res_model', '=', 'board.board')]" required=True string='Dashboard' args: 'ir.actions.act_window'
  • name Char
    required=True
Public methods (2)
  • action_add_to_dashboard(self)
  • default_get(self, fields_list)
    @api.model

New fields (0)

No new fields.

Public methods (0)

No public methods.

New fields (7)
  • amount Float
  • date_from Date
    required=True string='From'
  • date_to Date
    required=True string='To'
  • kpi_expression_id Many2one → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' ondelete='restrict' required=True string='KPI'
  • name Char
    compute='_compute_name' readonly=True required=False
  • seq1 Integer
    readonly=True related='kpi_expression_id.kpi_id.sequence' store=True string='KPI Sequence'
  • seq2 Integer
    readonly=True related='kpi_expression_id.subkpi_id.sequence' store=True string='Sub-KPI Sequence'
Public methods (0)

No public methods.

New fields (10)
  • account_model Char
    compute='_compute_account_model'
  • all_kpi_ids One2many → mis.report.kpi
    comodel_name='mis.report.kpi' compute='_compute_all_kpi_ids' help='KPIs of this report and subreports.'
  • description Char
    required=False translate=True
  • kpi_ids One2many → mis.report.kpi
    copy=True string="KPI's" args: 'mis.report.kpi', 'report_id'
  • move_lines_source Many2one → ir.model
    comodel_name='ir.model' default=_default_move_lines_source domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields. This model is the data source for column Actuals." ondelete='cascade' required=True
  • name Char
    required=True translate=True
  • query_ids One2many → mis.report.query
    copy=True string='Queries' args: 'mis.report.query', 'report_id'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' string='Style'
  • subkpi_ids One2many → mis.report.subkpi
    copy=True string='Sub KPI' args: 'mis.report.subkpi', 'report_id'
  • subreport_ids One2many → mis.report.subreport
    copy=True string='Sub reports' args: 'mis.report.subreport', 'report_id'
Public methods (7)
  • copy(self, default=None)
  • declare_and_compute_period(self, kpi_matrix, col_key, col_label, col_description, aep, date_from, date_to, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None, locals_dict=None, aml_model=None, no_auto_expand_accounts=False)
  • evaluate(self, aep, date_from, date_to, target_move='posted', aml_model=None, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None)
    Simplified method to evaluate a report over a time period. :param aep: an AccountingExpressionProcessor instance created using _prepare_aep() :param date_from, date_to: the starting and ending date :param target_move: all|posted :param aml_model: the name of a model that is compatible with account.move.line (default: account.move.line) :param subkpis_filter: a list of subkpis to include in the evaluation (if empty, use all subkpis) :param get_additional_move_line_filter: a bound method that takes no arguments and returns a domain compatible with account.move.line :param get_additional_query_filter: a bound method that takes a single query argument and returns a domain compatible with the query underlying model :return: a dictionary where keys are KPI names, and values are the evaluated results; some additional keys might be present: these should be ignored as they might be removed in the future.
  • get_kpis_by_account_id(self, company)
    Return { account_id: set(kpi) }
  • get_wizard_report_action(self)
  • prepare_kpi_matrix(self, multi_company=False)
  • prepare_locals_dict(self)

New fields (27)
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' string='Analytic Account'
  • analytic_domain Text
    default='[]' help='A domain to additionally filter move lines considered in this report. Caution: when using different move line sources in different columns, such as budgets by account, make sure to use only fields that are available in all move line sources.'
  • analytic_group_id Many2one → account.analytic.group
    comodel_name='account.analytic.group' string='Analytic Account Group'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' string='Analytic Tags'
  • company_id Many2one → res.company
    comodel_name='res.company' default=<expr> required=False string='Allowed company'
  • company_ids Many2many → res.company
    comodel_name='res.company' help='Select companies for which data will be searched.' string='Allowed companies'
  • comparison_mode Boolean
    compute='_compute_comparison_mode' inverse='_inverse_comparison_mode'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' help='Select target currency for the report. Required if companies have different currencies.' required=False string='Currency'
  • date Date
    help='Report base date (leave empty to use current date)' string='Base date'
  • date_from Date
    string='From'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_to Date
    string='To'
  • description Char
    readonly=True related='report_id.description'
  • display_columns_description Boolean
    help='Display the date range details in the column headers.'
  • hide_analytic_filters Boolean
    default=True
  • landscape_pdf Boolean
    string='Landscape PDF'
  • multi_company Boolean
    default=False help='Check if you wish to specify several companies to be searched for data.' string='Multiple companies'
  • name Char
    required=True translate=True
  • no_auto_expand_accounts Boolean
    string='Disable account details expansion'
  • period_ids One2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' copy=True inverse_name='report_instance_id' required=True string='Periods'
  • pivot_date Date
    compute='_compute_pivot_date'
  • query_company_ids Many2many → res.company
    comodel_name='res.company' compute='_compute_query_company_ids' help='Companies for which data will be searched.' string='Effective companies'
  • report_id Many2one → mis.report
    required=True string='Report' args: 'mis.report'
  • source_aml_model_id Many2one
    readonly=True related='report_id.move_lines_source'
  • source_aml_model_name Char
    readonly=True related='source_aml_model_id.model' related_sudo=True
  • target_move Selection
    default='posted' required=True string='Target Moves' args: [('posted', 'All Posted Entries'), ('all', 'All Entries')]
  • temporary Boolean
    default=False
Public methods (9)
  • compute(self)
  • copy(self, default=None)
  • display_settings(self)
  • drilldown(self, arg)
  • export_xls(self)
  • get_filter_descriptions_from_context(self)
    @api.model
  • preview(self)
  • print_pdf(self)
  • save_report(self)

New fields (30)
  • allowed_cmpcol_ids Many2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' compute='_compute_allowed_cmpcol_ids'
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' help='Filter column on journal entries that match this analytic account.This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Account'
  • analytic_domain Text
    default='[]' help='A domain to additionally filter move lines considered in this column.'
  • analytic_group_id Many2one → account.analytic.group
    comodel_name='account.analytic.group' help='Filter column on journal entries that match this analytic account group. This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Account Group'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' help='Filter column on journal entries that have all these analytic tags.This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Tags'
  • date_from Date
    compute='_compute_dates' string='From (computed)'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_range_type_id Many2one → date.range.type
    comodel_name='date.range.type' domain=[('allow_overlap', '=', False)] string='Date Range Type'
  • date_to Date
    compute='_compute_dates' string='To (computed)'
  • duration Integer
    default=1 help='Number of periods'
  • is_ytd Boolean
    default=False help='Forces the start date to Jan 1st of the relevant year' string='Year to date'
  • manual_date_from Date
    string='From'
  • manual_date_to Date
    string='To'
  • mode Selection
    default=MODE_FIX required=True args: [(MODE_FIX, 'Fixed dates'), (MODE_REL, 'Relative to report base date'), (MODE_NONE, 'No date filter')]
  • name Char
    required=True string='Label' translate=True
  • normalize_factor Integer
    default=1 help='Factor to use to normalize the period (used in comparison' string='Factor'
  • offset Integer
    default=-1 help='Offset from current period'
  • report_id Many2one
    related='report_instance_id.report_id'
  • report_instance_id Many2one → mis.report.instance
    comodel_name='mis.report.instance' ondelete='cascade' required=True string='Report Instance'
  • sequence Integer
    default=100
  • source Selection
    default=SRC_ACTUALS help='Actuals: current data, from accounting and other queries.\nActuals (alternative): current data from an alternative source (eg a database view providing look-alike account move lines).\nSum columns: summation (+/-) of other columns.\nCompare to column: compare to other column.\n' required=True args: [(SRC_ACTUALS, 'Actuals'), (SRC_ACTUALS_ALT, 'Actuals (alternative)'), (SRC_SUMCOL, 'Sum columns'), (SRC_CMPCOL, 'Compare columns')]
  • source_aml_model_id Many2one → ir.model
    comodel_name='ir.model' compute='_compute_source_aml_model_id' domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id'), ('field_id.model_id.model', '!=', 'account.move.line')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields." readonly=False store=True string='Move lines source'
  • source_aml_model_name Char
    related='source_aml_model_id.model' string='Move lines source model name'
  • source_cmpcol_from_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='versus'
  • source_cmpcol_to_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='Compare'
  • source_sumcol_accdet Boolean
    string='Sum account details'
  • source_sumcol_ids One2many → mis.report.instance.period.sum
    comodel_name='mis.report.instance.period.sum' inverse_name='period_id' string='Columns to sum'
  • subkpi_ids Many2many → mis.report.subkpi
    string='Sub KPI Filter' args: 'mis.report.subkpi'
  • type Selection
    string='Period type' args: [('d', _('Day')), ('w', _('Week')), ('m', _('Month')), ('y', _('Year')), ('date_range', _('Date Range'))]
  • valid Boolean
    compute='_compute_dates' type='boolean'
Public methods (1)
  • copy_data(self, default=None)

New fields (3)
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True string='Parent column'
  • period_to_sum_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='restrict' required=True string='Column'
  • sign Selection
    default='+' required=True args: [('+', '+'), ('-', '-')]
Public methods (0)

No public methods.

New fields (14)
  • accumulation_method Selection
    default=ACC_SUM help='Determines how values of this kpi spanning over a time period are transformed to match the reporting period. Sum: values of shorter period are added, values of longest or partially overlapping periods are adjusted pro-rata temporis.\nAverage: values of included period are averaged with a pro-rata temporis weight.' required=True args: [(ACC_SUM, _('Sum')), (ACC_AVG, _('Average')), (ACC_NONE, _('None'))]
  • auto_expand_accounts Boolean
    string='Display details by account'
  • auto_expand_accounts_style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style for account detail rows'
  • compare_method Selection
    default=CMP_PCT required=True string='Comparison Method' args: [(CMP_DIFF, _('Difference')), (CMP_PCT, _('Percentage')), (CMP_NONE, _('None'))]
  • description Char
    required=True translate=True
  • expression Char
    compute='_compute_expression' inverse='_inverse_expression'
  • expression_ids One2many → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' copy=True inverse_name='kpi_id' string='Expressions'
  • multi Boolean
  • name Char
    required=True
  • report_id Many2one → mis.report
    ondelete='cascade' required=True args: 'mis.report'
  • sequence Integer
    default=100
  • style_expression Char
    help='An expression that returns a style depending on the KPI value. Such style is applied on top of the row style.'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style'
  • type Selection
    default=TYPE_NUM required=True string='Value type' args: [(TYPE_NUM, _('Numeric')), (TYPE_PCT, _('Percentage')), (TYPE_STR, _('String'))]
Public methods (2)
  • name_get(self)
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (4)
  • kpi_id Many2one → mis.report.kpi
    ondelete='cascade' required=True args: 'mis.report.kpi'
  • name Char
    string='Expression'
  • sequence Integer
    readonly=True related='subkpi_id.sequence' store=True
  • subkpi_id Many2one → mis.report.subkpi
    ondelete='cascade' readonly=False args: 'mis.report.subkpi'
Public methods (2)
  • name_get(self)
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (8)
  • aggregate Selection
    args: [('sum', _('Sum')), ('avg', _('Average')), ('min', _('Min')), ('max', _('Max'))]
  • date_field Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain=[('ttype', 'in', ('date', 'datetime'))] ondelete='cascade' required=True
  • domain Char
  • field_ids Many2many → ir.model.fields
    required=True string='Fields to fetch' args: 'ir.model.fields'
  • field_names Char
    compute='_compute_field_names' string='Fetched fields name'
  • model_id Many2one → ir.model
    ondelete='cascade' required=True args: 'ir.model'
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
Public methods (0)

No public methods.

New fields (25)
  • background_color Char
    default='#FFFFFF' help='Background color in valid RGB code (from #000000 to #FFFFFF)'
  • background_color_inherit Boolean
    default=True
  • color Char
    default='#000000' help='Text color in valid RGB code (from #000000 to #FFFFFF)' string='Text color'
  • color_inherit Boolean
    default=True
  • divider Selection
    default='1' string='Factor' args: [('1e-6', _('µ')), ('1e-3', _('m')), ('1', _('1')), ('1e3', _('k')), ('1e6', _('M'))]
  • divider_inherit Boolean
    default=True
  • dp Integer
    default=0 string='Rounding'
  • dp_inherit Boolean
    default=True
  • font_size Selection
    selection=_font_size_selection
  • font_size_inherit Boolean
    default=True
  • font_style Selection
    selection=_font_style_selection
  • font_style_inherit Boolean
    default=True
  • font_weight Selection
    selection=_font_weight_selection
  • font_weight_inherit Boolean
    default=True
  • hide_always Boolean
    default=False
  • hide_always_inherit Boolean
    default=True
  • hide_empty Boolean
    default=False
  • hide_empty_inherit Boolean
    default=True
  • indent_level Integer
  • indent_level_inherit Boolean
    default=True
  • name Char
    required=True string='Style name'
  • prefix Char
  • prefix_inherit Boolean
    default=True
  • suffix Char
  • suffix_inherit Boolean
    default=True
Public methods (9)
  • check_positive_val(self)
    @api.constrains('indent_level')
  • compare_and_render(self, lang, style_props, type, compare_method, value, base_value, average_value=1, average_base_value=1)
    @api.model
    :param lang: res.lang record :param style_props: PropertyDict with style properties :param type: num, pct or str :param compare_method: diff, pct, none :param value: value to compare (value - base_value) :param base_value: value compared with (value - base_value) :param average_value: value = value / average_value :param average_base_value: base_value = base_value / average_base_value :return: tuple with 4 elements - delta = comparison result (Float or AccountingNone) - delta_r = delta rendered in formatted string (String) - delta_style = PropertyDict with style properties - delta_type = Type of the comparison result (num or pct)
  • merge(self, styles)
    @api.model
    Merge several styles, giving priority to the last. Returns a PropertyDict of style properties.
  • render(self, lang, style_props, type, value, sign='-')
    @api.model
  • render_num(self, lang, value, divider=1.0, dp=0, prefix=None, suffix=None, sign='-')
    @api.model
  • render_pct(self, lang, value, dp=1, sign='-')
    @api.model
  • render_str(self, lang, value)
    @api.model
  • to_css_style(self, props, no_indent=False)
    @api.model
  • to_xlsx_style(self, type, props, no_indent=False)
    @api.model

New fields (5)
  • description Char
    required=True translate=True
  • expression_ids One2many → mis.report.kpi.expression
    args: 'mis.report.kpi.expression', 'subkpi_id'
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • sequence Integer
    default=1
Public methods (0)

No public methods.

New fields (3)
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • subreport_id Many2one → mis.report
    comodel_name='mis.report' ondelete='restrict' required=True
Public methods (0)

No public methods.

New fields (3)
  • date Date
    compute=<expr> help='Dummy field that adapts searches on date to searches on date_from/date_to.' search='_search_date'
  • date_from Date
    required=True
  • date_to Date
    required=True
Public methods (1)
  • read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True)
    @api.model
    Override read_group to perform pro-rata temporis adjustments. When read_group is invoked with a domain that filters on a time period (date >= from and date <= to, or date_from <= to and date_to >= from), adjust the accumulated values pro-rata temporis.

New fields (0)

No new fields.

Public methods (1)
  • generate_xlsx_report(self, workbook, data, objects)
REPOSITORY
REPOSITORYOCA/mis-builder
GIT
GIThttps://github.com/OCA/mis-builder.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/mis-builder/tree/13.0/mis_builder
VERSION
VERSION 4.1.1
CATEGORY
CATEGORYReporting
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSStéphane Bidoul, Pedro M. Baeza, Lois Rilo, OCA Transbot, Víctor Martínez, oca-travis, Weblate, OCA-git-bot, oca-ci, oca-git-bot
WEBSITE
WEBSITEhttps://github.com/OCA/mis-builder
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:34:19
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/reporting-engine:
    - report_xlsx
OCA/server-ux:
    - date_range
odoo/odoo:
    - account
    - base_setup
    - base
    - web
    - product
    - mail
    - bus
    - web_tour
    - uom
    - analytic
    - portal
    - web_editor
    - http_routing
    - auth_signup
    - digest
    - resource
    - board
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (14)
XML IDNameModelTypeStatus
assets_backend mis_builder ir.ui.view qweb Inherits web.assets_backend
assets_report assets_report ir.ui.view qweb Inherits web.report_assets_common
mis_report_instance_add_to_dashboard_form_view add.mis.report.instance.dashboard.wizard.view add.mis.report.instance.dashboard.wizard form New
mis_report_instance_period_view_form mis.report.instance.period form New
mis_report_instance_result_view_form mis.report.instance.result.view.form mis.report.instance form New
mis_report_instance_view_form mis.report.instance.view.form mis.report.instance form New
mis_report_instance_view_tree mis.report.instance.view.tree mis.report.instance tree New
mis_report_style_view_form mis.report.style.view.form mis.report.style form New
mis_report_style_view_tree mis.report.style.view.tree mis.report.style tree New
mis_report_view_form mis.report.view.form mis.report form New
mis_report_view_kpi_form mis.report.view.kpi.form mis.report.kpi form New
mis_report_view_tree mis.report.view.tree mis.report tree New
report_mis_report_instance report_mis_report_instance ir.ui.view qweb New
wizard_mis_report_instance_view_form mis.report.instance field Inherits mis_builder.mis_report_instance_view_form
Models touched (15)

New fields (2)
  • dashboard_id Many2one → ir.actions.act_window
    domain="[('res_model', '=', 'board.board')]" required=True string='Dashboard' args: 'ir.actions.act_window'
  • name Char
    required=True
Public methods (2)
  • action_add_to_dashboard(self)
  • default_get(self, fields_list)
    @api.model

New fields (0)

No new fields.

Public methods (1)
  • render_qweb_pdf(self, res_ids=None, data=None)

New fields (7)
  • amount Float
  • date_from Date
    required=True string='From'
  • date_to Date
    required=True string='To'
  • kpi_expression_id Many2one → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' ondelete='restrict' required=True string='KPI'
  • name Char
    compute='_compute_name' readonly=True required=False
  • seq1 Integer
    readonly=True related='kpi_expression_id.kpi_id.sequence' store=True string='KPI Sequence'
  • seq2 Integer
    readonly=True related='kpi_expression_id.subkpi_id.sequence' store=True string='Sub-KPI Sequence'
Public methods (0)

No public methods.

New fields (10)
  • account_model Char
    compute='_compute_account_model'
  • all_kpi_ids One2many → mis.report.kpi
    comodel_name='mis.report.kpi' compute='_compute_all_kpi_ids' help='KPIs of this report and subreports.'
  • description Char
    required=False translate=True
  • kpi_ids One2many → mis.report.kpi
    copy=True string="KPI's" args: 'mis.report.kpi', 'report_id'
  • move_lines_source Many2one → ir.model
    comodel_name='ir.model' default=_default_move_lines_source domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields. This model is the data source for column Actuals." required=True
  • name Char
    required=True translate=True
  • query_ids One2many → mis.report.query
    copy=True string='Queries' args: 'mis.report.query', 'report_id'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' string='Style'
  • subkpi_ids One2many → mis.report.subkpi
    copy=True string='Sub KPI' args: 'mis.report.subkpi', 'report_id'
  • subreport_ids One2many → mis.report.subreport
    copy=True string='Sub reports' args: 'mis.report.subreport', 'report_id'
Public methods (7)
  • copy(self, default=None)
  • declare_and_compute_period(self, kpi_matrix, col_key, col_label, col_description, aep, date_from, date_to, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None, locals_dict=None, aml_model=None, no_auto_expand_accounts=False)
  • evaluate(self, aep, date_from, date_to, target_move='posted', aml_model=None, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None)
    Simplified method to evaluate a report over a time period. :param aep: an AccountingExpressionProcessor instance created using _prepare_aep() :param date_from, date_to: the starting and ending date :param target_move: all|posted :param aml_model: the name of a model that is compatible with account.move.line (default: account.move.line) :param subkpis_filter: a list of subkpis to include in the evaluation (if empty, use all subkpis) :param get_additional_move_line_filter: a bound method that takes no arguments and returns a domain compatible with account.move.line :param get_additional_query_filter: a bound method that takes a single query argument and returns a domain compatible with the query underlying model :return: a dictionary where keys are KPI names, and values are the evaluated results; some additional keys might be present: these should be ignored as they might be removed in the future.
  • get_kpis_by_account_id(self, company)
    Return { account_id: set(kpi) }
  • get_wizard_report_action(self)
  • prepare_kpi_matrix(self, multi_company=False)
  • prepare_locals_dict(self)

New fields (24)
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' string='Analytic Account'
  • analytic_group_id Many2one → account.analytic.group
    comodel_name='account.analytic.group' string='Analytic Account Group'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' string='Analytic Tags'
  • company_id Many2one → res.company
    comodel_name='res.company' default=<expr> required=False string='Allowed company'
  • company_ids Many2many → res.company
    comodel_name='res.company' help='Select companies for which data will be searched.' string='Allowed companies'
  • comparison_mode Boolean
    compute='_compute_comparison_mode' inverse='_inverse_comparison_mode'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' help='Select target currency for the report. Required if companies have different currencies.' required=False string='Currency'
  • date Date
    help='Report base date (leave empty to use current date)' string='Base date'
  • date_from Date
    string='From'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_to Date
    string='To'
  • description Char
    readonly=True related='report_id.description'
  • display_columns_description Boolean
    help='Display the date range details in the column headers.'
  • hide_analytic_filters Boolean
    default=True
  • landscape_pdf Boolean
    string='Landscape PDF'
  • multi_company Boolean
    default=False help='Check if you wish to specify several companies to be searched for data.' string='Multiple companies'
  • name Char
    required=True translate=True
  • no_auto_expand_accounts Boolean
    string='Disable account details expansion'
  • period_ids One2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' copy=True inverse_name='report_instance_id' required=True string='Periods'
  • pivot_date Date
    compute='_compute_pivot_date'
  • query_company_ids Many2many → res.company
    comodel_name='res.company' compute='_compute_query_company_ids' help='Companies for which data will be searched.' string='Effective companies'
  • report_id Many2one → mis.report
    required=True string='Report' args: 'mis.report'
  • target_move Selection
    default='posted' required=True string='Target Moves' args: [('posted', 'All Posted Entries'), ('all', 'All Entries')]
  • temporary Boolean
    default=False
Public methods (9)
  • compute(self)
  • copy(self, default=None)
  • display_settings(self)
  • drilldown(self, arg)
  • export_xls(self)
  • get_filter_descriptions_from_context(self)
    @api.model
  • preview(self)
  • print_pdf(self)
  • save_report(self)

New fields (28)
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' help='Filter column on journal entries that match this analytic account.This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Account'
  • analytic_group_id Many2one → account.analytic.group
    comodel_name='account.analytic.group' help='Filter column on journal entries that match this analytic account group. This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Account Group'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' help='Filter column on journal entries that have all these analytic tags.This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Tags'
  • date_from Date
    compute='_compute_dates' string='From (computed)'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_range_type_id Many2one → date.range.type
    comodel_name='date.range.type' domain=[('allow_overlap', '=', False)] string='Date Range Type'
  • date_to Date
    compute='_compute_dates' string='To (computed)'
  • duration Integer
    default=1 help='Number of periods'
  • is_ytd Boolean
    default=False help='Forces the start date to Jan 1st of the relevant year' string='Year to date'
  • manual_date_from Date
    string='From'
  • manual_date_to Date
    string='To'
  • mode Selection
    default=MODE_FIX required=True args: [(MODE_FIX, 'Fixed dates'), (MODE_REL, 'Relative to report base date'), (MODE_NONE, 'No date filter')]
  • name Char
    required=True string='Label' translate=True
  • normalize_factor Integer
    default=1 help='Factor to use to normalize the period (used in comparison' string='Factor'
  • offset Integer
    default=-1 help='Offset from current period'
  • report_id Many2one
    related='report_instance_id.report_id'
  • report_instance_id Many2one → mis.report.instance
    comodel_name='mis.report.instance' ondelete='cascade' required=True string='Report Instance'
  • sequence Integer
    default=100
  • source Selection
    default=SRC_ACTUALS help='Actuals: current data, from accounting and other queries.\nActuals (alternative): current data from an alternative source (eg a database view providing look-alike account move lines).\nSum columns: summation (+/-) of other columns.\nCompare to column: compare to other column.\n' required=True args: [(SRC_ACTUALS, 'Actuals'), (SRC_ACTUALS_ALT, 'Actuals (alternative)'), (SRC_SUMCOL, 'Sum columns'), (SRC_CMPCOL, 'Compare columns')]
  • source_aml_model_id Many2one → ir.model
    comodel_name='ir.model' domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id'), ('field_id.model_id.model', '!=', 'account.move.line')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields." string='Move lines source'
  • source_aml_model_name Char
    related='source_aml_model_id.model' string='Move lines source model name'
  • source_cmpcol_from_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='versus'
  • source_cmpcol_to_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='Compare'
  • source_sumcol_accdet Boolean
    string='Sum account details'
  • source_sumcol_ids One2many → mis.report.instance.period.sum
    comodel_name='mis.report.instance.period.sum' inverse_name='period_id' string='Columns to sum'
  • subkpi_ids Many2many → mis.report.subkpi
    string='Sub KPI Filter' args: 'mis.report.subkpi'
  • type Selection
    string='Period type' args: [('d', _('Day')), ('w', _('Week')), ('m', _('Month')), ('y', _('Year')), ('date_range', _('Date Range'))]
  • valid Boolean
    compute='_compute_dates' type='boolean'
Public methods (1)
  • copy_data(self, default=None)

New fields (3)
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True string='Parent column'
  • period_to_sum_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='restrict' required=True string='Column'
  • sign Selection
    default='+' required=True args: [('+', '+'), ('-', '-')]
Public methods (0)

No public methods.

New fields (14)
  • accumulation_method Selection
    default=ACC_SUM help='Determines how values of this kpi spanning over a time period are transformed to match the reporting period. Sum: values of shorter period are added, values of longest or partially overlapping periods are adjusted pro-rata temporis.\nAverage: values of included period are averaged with a pro-rata temporis weight.' required=True args: [(ACC_SUM, _('Sum')), (ACC_AVG, _('Average')), (ACC_NONE, _('None'))]
  • auto_expand_accounts Boolean
    string='Display details by account'
  • auto_expand_accounts_style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style for account detail rows'
  • compare_method Selection
    default=CMP_PCT required=True string='Comparison Method' args: [(CMP_DIFF, _('Difference')), (CMP_PCT, _('Percentage')), (CMP_NONE, _('None'))]
  • description Char
    required=True translate=True
  • expression Char
    compute='_compute_expression' inverse='_inverse_expression'
  • expression_ids One2many → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' copy=True inverse_name='kpi_id' string='Expressions'
  • multi Boolean
  • name Char
    required=True
  • report_id Many2one → mis.report
    ondelete='cascade' required=True args: 'mis.report'
  • sequence Integer
    default=100
  • style_expression Char
    help='An expression that returns a style depending on the KPI value. Such style is applied on top of the row style.'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style'
  • type Selection
    default=TYPE_NUM required=True string='Value type' args: [(TYPE_NUM, _('Numeric')), (TYPE_PCT, _('Percentage')), (TYPE_STR, _('String'))]
Public methods (2)
  • name_get(self)
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (4)
  • kpi_id Many2one → mis.report.kpi
    ondelete='cascade' required=True args: 'mis.report.kpi'
  • name Char
    string='Expression'
  • sequence Integer
    readonly=True related='subkpi_id.sequence' store=True
  • subkpi_id Many2one → mis.report.subkpi
    ondelete='cascade' readonly=False args: 'mis.report.subkpi'
Public methods (2)
  • name_get(self)
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (8)
  • aggregate Selection
    args: [('sum', _('Sum')), ('avg', _('Average')), ('min', _('Min')), ('max', _('Max'))]
  • date_field Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain=[('ttype', 'in', ('date', 'datetime'))] ondelete='restrict' required=True
  • domain Char
  • field_ids Many2many → ir.model.fields
    required=True string='Fields to fetch' args: 'ir.model.fields'
  • field_names Char
    compute='_compute_field_names' string='Fetched fields name'
  • model_id Many2one → ir.model
    ondelete='restrict' required=True args: 'ir.model'
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
Public methods (0)

No public methods.

New fields (25)
  • background_color Char
    default='#FFFFFF' help='Background color in valid RGB code (from #000000 to #FFFFFF)'
  • background_color_inherit Boolean
    default=True
  • color Char
    default='#000000' help='Text color in valid RGB code (from #000000 to #FFFFFF)' string='Text color'
  • color_inherit Boolean
    default=True
  • divider Selection
    default='1' string='Factor' args: [('1e-6', _('µ')), ('1e-3', _('m')), ('1', _('1')), ('1e3', _('k')), ('1e6', _('M'))]
  • divider_inherit Boolean
    default=True
  • dp Integer
    default=0 string='Rounding'
  • dp_inherit Boolean
    default=True
  • font_size Selection
    selection=_font_size_selection
  • font_size_inherit Boolean
    default=True
  • font_style Selection
    selection=_font_style_selection
  • font_style_inherit Boolean
    default=True
  • font_weight Selection
    selection=_font_weight_selection
  • font_weight_inherit Boolean
    default=True
  • hide_always Boolean
    default=False
  • hide_always_inherit Boolean
    default=True
  • hide_empty Boolean
    default=False
  • hide_empty_inherit Boolean
    default=True
  • indent_level Integer
  • indent_level_inherit Boolean
    default=True
  • name Char
    required=True string='Style name'
  • prefix Char
  • prefix_inherit Boolean
    default=True
  • suffix Char
  • suffix_inherit Boolean
    default=True
Public methods (9)
  • check_positive_val(self)
    @api.constrains('indent_level')
  • compare_and_render(self, lang, style_props, type, compare_method, value, base_value, average_value=1, average_base_value=1)
    @api.model
    :param lang: res.lang record :param style_props: PropertyDict with style properties :param type: num, pct or str :param compare_method: diff, pct, none :param value: value to compare (value - base_value) :param base_value: value compared with (value - base_value) :param average_value: value = value / average_value :param average_base_value: base_value = base_value / average_base_value :return: tuple with 4 elements - delta = comparison result (Float or AccountingNone) - delta_r = delta rendered in formatted string (String) - delta_style = PropertyDict with style properties - delta_type = Type of the comparison result (num or pct)
  • merge(self, styles)
    @api.model
    Merge several styles, giving priority to the last. Returns a PropertyDict of style properties.
  • render(self, lang, style_props, type, value, sign='-')
    @api.model
  • render_num(self, lang, value, divider=1.0, dp=0, prefix=None, suffix=None, sign='-')
    @api.model
  • render_pct(self, lang, value, dp=1, sign='-')
    @api.model
  • render_str(self, lang, value)
    @api.model
  • to_css_style(self, props, no_indent=False)
    @api.model
  • to_xlsx_style(self, type, props, no_indent=False)
    @api.model

New fields (5)
  • description Char
    required=True translate=True
  • expression_ids One2many → mis.report.kpi.expression
    args: 'mis.report.kpi.expression', 'subkpi_id'
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • sequence Integer
    default=1
Public methods (0)

No public methods.

New fields (3)
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • subreport_id Many2one → mis.report
    comodel_name='mis.report' ondelete='restrict' required=True
Public methods (0)

No public methods.

New fields (3)
  • date Date
    compute=<expr> help='Dummy field that adapts searches on date to searches on date_from/date_to.' search='_search_date'
  • date_from Date
    required=True
  • date_to Date
    required=True
Public methods (1)
  • read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True)
    @api.model
    Override read_group to perform pro-rata temporis adjustments. When read_group is invoked with a domain that filters on a time period (date >= from and date <= to, or date_from <= to and date_to >= from), adjust the accumulated values pro-rata temporis.

New fields (0)

No new fields.

Public methods (1)
  • generate_xlsx_report(self, workbook, data, objects)
REPOSITORY
REPOSITORYOCA/mis-builder
GIT
GIThttps://github.com/OCA/mis-builder.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/mis-builder/tree/12.0/mis_builder
VERSION
VERSION 3.7.7
CATEGORY
CATEGORYReporting
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSStéphane Bidoul, Stefan Rijnhart, eLBati, Stéphane Bidoul (ACSONE), Alexey Pelykh, OCA Transbot, David Dufresne, oca-travis, Weblate, OCA-git-bot, Hans Henrik Gabelgaard, oca-ci
WEBSITE
WEBSITEhttps://github.com/OCA/mis-builder
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:29:24
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/reporting-engine:
    - report_xlsx
OCA/server-ux:
    - date_range
OCA/web:
    - web_widget_color
odoo/odoo:
    - account
    - base_setup
    - base
    - web
    - product
    - decimal_precision
    - mail
    - bus
    - web_tour
    - uom
    - analytic
    - portal
    - http_routing
    - digest
    - board
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES xlrd
xlsxwriter
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (14)
XML IDNameModelTypeStatus
assets_backend mis_builder ir.ui.view qweb Inherits web.assets_backend
assets_report assets_report ir.ui.view qweb Inherits web.report_assets_common
mis_report_instance_add_to_dashboard_form_view add.mis.report.instance.dashboard.wizard.view add.mis.report.instance.dashboard.wizard form New
mis_report_instance_period_view_form mis.report.instance.period form New
mis_report_instance_result_view_form mis.report.instance.result.view.form mis.report.instance form New
mis_report_instance_view_form mis.report.instance.view.form mis.report.instance form New
mis_report_instance_view_tree mis.report.instance.view.tree mis.report.instance tree New
mis_report_style_view_form mis.report.style.view.form mis.report.style form New
mis_report_style_view_tree mis.report.style.view.tree mis.report.style tree New
mis_report_view_form mis.report.view.form mis.report form New
mis_report_view_kpi_form mis.report.view.kpi.form mis.report.kpi form New
mis_report_view_tree mis.report.view.tree mis.report tree New
report_mis_report_instance report_mis_report_instance ir.ui.view qweb New
wizard_mis_report_instance_view_form mis.report.instance field Inherits mis_builder.mis_report_instance_view_form
Models touched (15)

New fields (2)
  • dashboard_id Many2one → ir.actions.act_window
    domain="[('res_model', '=', 'board.board')]" required=True string='Dashboard' args: 'ir.actions.act_window'
  • name Char
    required=True args: 'Name'
Public methods (2)
  • action_add_to_dashboard(self)
  • default_get(self, fields_list)
    @api.model

New fields (0)

No new fields.

Public methods (1)
  • render_qweb_pdf(self, res_ids=None, data=None)

New fields (7)
  • amount Float
  • date_from Date
    required=True string='From'
  • date_to Date
    required=True string='To'
  • kpi_expression_id Many2one → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' ondelete='restrict' required=True string='KPI'
  • name Char
    compute='_compute_name' readonly=True required=False
  • seq1 Integer
    readonly=True related='kpi_expression_id.kpi_id.sequence' store=True string='KPI Sequence'
  • seq2 Integer
    readonly=True related='kpi_expression_id.subkpi_id.sequence' store=True string='Sub-KPI Sequence'
Public methods (0)

No public methods.

New fields (10)
  • account_model Char
    compute='_compute_account_model' string='Account model'
  • all_kpi_ids One2many → mis.report.kpi
    comodel_name='mis.report.kpi' compute='_compute_all_kpi_ids' help='KPIs of this report and subreports.'
  • description Char
    required=False string='Description' translate=True
  • kpi_ids One2many → mis.report.kpi
    copy=True string="KPI's" args: 'mis.report.kpi', 'report_id'
  • move_lines_source Many2one → ir.model
    comodel_name='ir.model' default=_default_move_lines_source domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields. This model is the data source for column Actuals." required=True string='Move lines source'
  • name Char
    required=True string='Name' translate=True
  • query_ids One2many → mis.report.query
    copy=True string='Queries' args: 'mis.report.query', 'report_id'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' string='Style'
  • subkpi_ids One2many → mis.report.subkpi
    copy=True string='Sub KPI' args: 'mis.report.subkpi', 'report_id'
  • subreport_ids One2many → mis.report.subreport
    copy=True string='Sub reports' args: 'mis.report.subreport', 'report_id'
Public methods (7)
  • copy(self, default=None)
  • declare_and_compute_period(self, kpi_matrix, col_key, col_label, col_description, aep, date_from, date_to, target_move, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None, locals_dict=None, aml_model=None, no_auto_expand_accounts=False)
  • evaluate(self, aep, date_from, date_to, target_move='posted', aml_model=None, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None)
    Simplified method to evaluate a report over a time period. :param aep: an AccountingExpressionProcessor instance created using _prepare_aep() :param date_from, date_to: the starting and ending date :param target_move: all|posted :param aml_model: the name of a model that is compatible with account.move.line :param subkpis_filter: a list of subkpis to include in the evaluation (if empty, use all subkpis) :param get_additional_move_line_filter: a bound method that takes no arguments and returns a domain compatible with account.move.line :param get_additional_query_filter: a bound method that takes a single query argument and returns a domain compatible with the query underlying model :return: a dictionary where keys are KPI names, and values are the evaluated results; some additional keys might be present: these should be ignored as they might be removed in the future.
  • get_kpis_by_account_id(self, company)
    Return { account_id: set(kpi) }
  • get_wizard_report_action(self)
  • prepare_kpi_matrix(self, multi_company=False)
  • prepare_locals_dict(self)

New fields (24)
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' oldname='account_analytic_id' string='Analytic Account'
  • analytic_group_id Many2one → account.analytic.group
    comodel_name='account.analytic.group' string='Analytic Account Group'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' string='Analytic Tags'
  • company_id Many2one → res.company
    comodel_name='res.company' default=_default_company_id required=True string='Company'
  • company_ids Many2many → res.company
    comodel_name='res.company' help='Select companies for which data will be searched.' string='Companies'
  • comparison_mode Boolean
    compute='_compute_comparison_mode' inverse='_inverse_comparison_mode'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' help='Select target currency for the report. Required if companies have different currencies.' required=False string='Currency'
  • date Date
    help='Report base date (leave empty to use current date)' string='Base date'
  • date_from Date
    string='From'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_to Date
    string='To'
  • description Char
    readonly=True related='report_id.description'
  • display_columns_description Boolean
    help='Display the date range details in the column headers.'
  • hide_analytic_filters Boolean
    default=True
  • landscape_pdf Boolean
    string='Landscape PDF'
  • multi_company Boolean
    default=False help='Check if you wish to specify children companies to be searched for data.' string='Multiple companies'
  • name Char
    required=True string='Name' translate=True
  • no_auto_expand_accounts Boolean
    string='Disable account details expansion'
  • period_ids One2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' copy=True inverse_name='report_instance_id' required=True string='Periods'
  • pivot_date Date
    compute='_compute_pivot_date' string='Pivot date'
  • query_company_ids Many2many → res.company
    comodel_name='res.company' compute='_compute_query_company_ids' help='Companies for which data will be searched.'
  • report_id Many2one → mis.report
    required=True string='Report' args: 'mis.report'
  • target_move Selection
    default='posted' required=True string='Target Moves' args: [('posted', 'All Posted Entries'), ('all', 'All Entries')]
  • temporary Boolean
    default=False
Public methods (9)
  • compute(self)
  • copy(self, default=None)
  • display_settings(self)
  • drilldown(self, arg)
  • export_xls(self)
  • get_filter_descriptions_from_context(self)
    @api.model
  • preview(self)
  • print_pdf(self)
  • save_report(self)

New fields (28)
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' help='Filter column on journal entries that match this analytic account.This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Account'
  • analytic_group_id Many2one → account.analytic.group
    comodel_name='account.analytic.group' help='Filter column on journal entries that match this analytic account group. This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Account Group'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' help='Filter column on journal entries that have all these analytic tags.This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Tags'
  • date_from Date
    compute='_compute_dates' string='From (computed)'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_range_type_id Many2one → date.range.type
    comodel_name='date.range.type' domain=[('allow_overlap', '=', False)] string='Date Range Type'
  • date_to Date
    compute='_compute_dates' string='To (computed)'
  • duration Integer
    default=1 help='Number of periods' string='Duration'
  • is_ytd Boolean
    default=False help='Forces the start date to Jan 1st of the relevant year' string='Year to date'
  • manual_date_from Date
    string='From'
  • manual_date_to Date
    string='To'
  • mode Selection
    default=MODE_FIX required=True args: [(MODE_FIX, 'Fixed dates'), (MODE_REL, 'Relative to report base date'), (MODE_NONE, 'No date filter')]
  • name Char
    required=True string='Label' translate=True
  • normalize_factor Integer
    default=1 help='Factor to use to normalize the period (used in comparison' string='Factor'
  • offset Integer
    default=-1 help='Offset from current period' string='Offset'
  • report_id Many2one
    related='report_instance_id.report_id'
  • report_instance_id Many2one → mis.report.instance
    comodel_name='mis.report.instance' ondelete='cascade' required=True string='Report Instance'
  • sequence Integer
    default=100 string='Sequence'
  • source Selection
    default=SRC_ACTUALS help='Actuals: current data, from accounting and other queries.\nActuals (alternative): current data from an alternative source (eg a database view providing look-alike account move lines).\nSum columns: summation (+/-) of other columns.\nCompare to column: compare to other column.\n' required=True args: [(SRC_ACTUALS, 'Actuals'), (SRC_ACTUALS_ALT, 'Actuals (alternative)'), (SRC_SUMCOL, 'Sum columns'), (SRC_CMPCOL, 'Compare columns')]
  • source_aml_model_id Many2one → ir.model
    comodel_name='ir.model' domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id'), ('field_id.model_id.model', '!=', 'account.move.line')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields." string='Move lines source'
  • source_aml_model_name Char
    related='source_aml_model_id.model' string='Move lines source model name'
  • source_cmpcol_from_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='versus'
  • source_cmpcol_to_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='Compare'
  • source_sumcol_accdet Boolean
    string='Sum account details'
  • source_sumcol_ids One2many → mis.report.instance.period.sum
    comodel_name='mis.report.instance.period.sum' inverse_name='period_id' string='Columns to sum'
  • subkpi_ids Many2many → mis.report.subkpi
    string='Sub KPI Filter' args: 'mis.report.subkpi'
  • type Selection
    string='Period type' args: [('d', _('Day')), ('w', _('Week')), ('m', _('Month')), ('y', _('Year')), ('date_range', _('Date Range'))]
  • valid Boolean
    compute='_compute_dates' string='Valid' type='boolean'
Public methods (0)

No public methods.

New fields (3)
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True string='Parent column'
  • period_to_sum_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='restrict' required=True string='Column'
  • sign Selection
    default='+' required=True args: [('+', '+'), ('-', '-')]
Public methods (0)

No public methods.

New fields (14)
  • accumulation_method Selection
    default=ACC_SUM help='Determines how values of this kpi spanning over a time period are transformed to match the reporting period. Sum: values of shorter period are added, values of longest or partially overlapping periods are adjusted pro-rata temporis.\nAverage: values of included period are averaged with a pro-rata temporis weight.' required=True string='Accumulation Method' args: [(ACC_SUM, _('Sum')), (ACC_AVG, _('Average')), (ACC_NONE, _('None'))]
  • auto_expand_accounts Boolean
    string='Display details by account'
  • auto_expand_accounts_style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style for account detail rows'
  • compare_method Selection
    default=CMP_PCT required=True string='Comparison Method' args: [(CMP_DIFF, _('Difference')), (CMP_PCT, _('Percentage')), (CMP_NONE, _('None'))]
  • description Char
    required=True string='Description' translate=True
  • expression Char
    compute='_compute_expression' inverse='_inverse_expression' string='Expression'
  • expression_ids One2many → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' copy=True inverse_name='kpi_id' string='Expressions'
  • multi Boolean
  • name Char
    required=True string='Name'
  • report_id Many2one → mis.report
    ondelete='cascade' required=True string='Report' args: 'mis.report'
  • sequence Integer
    default=100 string='Sequence'
  • style_expression Char
    help='An expression that returns a style depending on the KPI value. Such style is applied on top of the row style.' string='Style expression'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style'
  • type Selection
    default=TYPE_NUM required=True string='Value type' args: [(TYPE_NUM, _('Numeric')), (TYPE_PCT, _('Percentage')), (TYPE_STR, _('String'))]
Public methods (2)
  • name_get(self)
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (4)
  • kpi_id Many2one → mis.report.kpi
    ondelete='cascade' required=True args: 'mis.report.kpi'
  • name Char
    string='Expression'
  • sequence Integer
    readonly=True related='subkpi_id.sequence' store=True
  • subkpi_id Many2one → mis.report.subkpi
    ondelete='cascade' readonly=False args: 'mis.report.subkpi'
Public methods (2)
  • name_get(self)
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (8)
  • aggregate Selection
    string='Aggregate' args: [('sum', _('Sum')), ('avg', _('Average')), ('min', _('Min')), ('max', _('Max'))]
  • date_field Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain=[('ttype', 'in', ('date', 'datetime'))] ondelete='restrict' required=True
  • domain Char
    string='Domain'
  • field_ids Many2many → ir.model.fields
    required=True string='Fields to fetch' args: 'ir.model.fields'
  • field_names Char
    compute='_compute_field_names' string='Fetched fields name'
  • model_id Many2one → ir.model
    ondelete='restrict' required=True string='Model' args: 'ir.model'
  • name Char
    required=True string='Name'
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True string='Report'
Public methods (0)

No public methods.

New fields (25)
  • background_color Char
    default='#FFFFFF' help='Background color in valid RGB code (from #000000 to #FFFFFF)'
  • background_color_inherit Boolean
    default=True
  • color Char
    default='#000000' help='Text color in valid RGB code (from #000000 to #FFFFFF)' string='Text color'
  • color_inherit Boolean
    default=True
  • divider Selection
    default='1' string='Factor' args: [('1e-6', _('µ')), ('1e-3', _('m')), ('1', _('1')), ('1e3', _('k')), ('1e6', _('M'))]
  • divider_inherit Boolean
    default=True
  • dp Integer
    default=0 string='Rounding'
  • dp_inherit Boolean
    default=True
  • font_size Selection
    selection=_font_size_selection
  • font_size_inherit Boolean
    default=True
  • font_style Selection
    selection=_font_style_selection
  • font_style_inherit Boolean
    default=True
  • font_weight Selection
    selection=_font_weight_selection
  • font_weight_inherit Boolean
    default=True
  • hide_always Boolean
    default=False
  • hide_always_inherit Boolean
    default=True
  • hide_empty Boolean
    default=False
  • hide_empty_inherit Boolean
    default=True
  • indent_level Integer
  • indent_level_inherit Boolean
    default=True
  • name Char
    required=True string='Style name'
  • prefix Char
    string='Prefix'
  • prefix_inherit Boolean
    default=True
  • suffix Char
    string='Suffix'
  • suffix_inherit Boolean
    default=True
Public methods (9)
  • check_positive_val(self)
    @api.constrains('indent_level')
  • compare_and_render(self, lang, style_props, type, compare_method, value, base_value, average_value=1, average_base_value=1)
    @api.model
    :param lang: res.lang record :param style_props: PropertyDict with style properties :param type: num, pct or str :param compare_method: diff, pct, none :param value: value to compare (value - base_value) :param base_value: value compared with (value - base_value) :param average_value: value = value / average_value :param average_base_value: base_value = base_value / average_base_value :return: tuple with 4 elements - delta = comparison result (Float or AccountingNone) - delta_r = delta rendered in formatted string (String) - delta_style = PropertyDict with style properties - delta_type = Type of the comparison result (num or pct)
  • merge(self, styles)
    @api.model
    Merge several styles, giving priority to the last. Returns a PropertyDict of style properties.
  • render(self, lang, style_props, type, value, sign='-')
    @api.model
  • render_num(self, lang, value, divider=1.0, dp=0, prefix=None, suffix=None, sign='-')
    @api.model
  • render_pct(self, lang, value, dp=1, sign='-')
    @api.model
  • render_str(self, lang, value)
    @api.model
  • to_css_style(self, props, no_indent=False)
    @api.model
  • to_xlsx_style(self, type, props, no_indent=False)
    @api.model

New fields (5)
  • description Char
    required=True string='Description' translate=True
  • expression_ids One2many → mis.report.kpi.expression
    args: 'mis.report.kpi.expression', 'subkpi_id'
  • name Char
    required=True string='Name'
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • sequence Integer
    default=1
Public methods (0)

No public methods.

New fields (3)
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • subreport_id Many2one → mis.report
    comodel_name='mis.report' ondelete='restrict' required=True
Public methods (0)

No public methods.

New fields (3)
  • date Date
    compute=<expr> help='Dummy field that adapts searches on date to searches on date_from/date_to.' search='_search_date'
  • date_from Date
    required=True
  • date_to Date
    required=True
Public methods (1)
  • read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True)
    @api.model
    Override read_group to perform pro-rata temporis adjustments. When read_group is invoked with a domain that filters on a time period (date >= from and date <= to, or date_from <= to and date_to >= from), adjust the accumulated values pro-rata temporis.

New fields (0)

No new fields.

Public methods (1)
  • generate_xlsx_report(self, workbook, data, objects)
REPOSITORY
REPOSITORYOCA/mis-builder
GIT
GIThttps://github.com/OCA/mis-builder.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/mis-builder/tree/11.0/mis_builder
VERSION
VERSION 3.6.9
CATEGORY
CATEGORYReporting
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSStéphane Bidoul, Pedro M. Baeza, GitHub, Stéphane Bidoul (ACSONE), Bhavesh Odedra, OCA Transbot, oca-travis, Weblate, OCA-git-bot, OCA Git Bot, Maxence Groine, oca-ci
WEBSITE
WEBSITEhttps://github.com/OCA/mis-builder
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:24:01
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/reporting-engine:
    - report_xlsx
OCA/server-ux:
    - date_range
OCA/web:
    - web_widget_color
odoo/odoo:
    - account
    - base_setup
    - base
    - web
    - product
    - decimal_precision
    - mail
    - bus
    - web_tour
    - analytic
    - web_planner
    - portal
    - http_routing
    - board
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES xlrd
xlsxwriter
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (14)
XML IDNameModelTypeStatus
assets_backend mis_builder ir.ui.view qweb Inherits web.assets_backend
assets_report assets_report ir.ui.view qweb Inherits web.report_assets_common
mis_report_instance_add_to_dashboard_form_view add.mis.report.instance.dashboard.wizard.view add.mis.report.instance.dashboard.wizard form New
mis_report_instance_period_view_form mis.report.instance.period form New
mis_report_instance_result_view_form mis.report.instance.result.view.form mis.report.instance form New
mis_report_instance_view_form mis.report.instance.view.form mis.report.instance form New
mis_report_instance_view_tree mis.report.instance.view.tree mis.report.instance tree New
mis_report_style_view_form mis.report.style.view.form mis.report.style form New
mis_report_style_view_tree mis.report.style.view.tree mis.report.style tree New
mis_report_view_form mis.report.view.form mis.report form New
mis_report_view_kpi_form mis.report.view.kpi.form mis.report.kpi form New
mis_report_view_tree mis.report.view.tree mis.report tree New
report_mis_report_instance report_mis_report_instance ir.ui.view qweb New
wizard_mis_report_instance_view_form mis.report.instance field Inherits mis_builder.mis_report_instance_view_form
Models touched (15)

New fields (2)
  • dashboard_id Many2one → ir.actions.act_window
    domain="[('res_model', '=', 'board.board')]" required=True string='Dashboard' args: 'ir.actions.act_window'
  • name Char
    required=True args: 'Name'
Public methods (2)
  • action_add_to_dashboard(self)
  • default_get(self, fields_list)
    @api.model

New fields (0)

No new fields.

Public methods (1)
  • render_qweb_pdf(self, res_ids=None, data=None)

New fields (7)
  • amount Float
  • date_from Date
    required=True string='From'
  • date_to Date
    required=True string='To'
  • kpi_expression_id Many2one → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' ondelete='restrict' required=True string='KPI'
  • name Char
    compute='_compute_name' readonly=True required=False
  • seq1 Integer
    readonly=True related='kpi_expression_id.kpi_id.sequence' store=True string='KPI Sequence'
  • seq2 Integer
    readonly=True related='kpi_expression_id.subkpi_id.sequence' store=True string='Sub-KPI Sequence'
Public methods (0)

No public methods.

New fields (10)
  • account_model Char
    compute='_compute_account_model' string='Account model'
  • all_kpi_ids One2many → mis.report.kpi
    comodel_name='mis.report.kpi' compute='_compute_all_kpi_ids' help='KPIs of this report and subreports.'
  • description Char
    required=False string='Description' translate=True
  • kpi_ids One2many → mis.report.kpi
    copy=True string="KPI's" args: 'mis.report.kpi', 'report_id'
  • move_lines_source Many2one → ir.model
    comodel_name='ir.model' default=_default_move_lines_source domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields. This model is the data source for column Actuals." required=True string='Move lines source'
  • name Char
    required=True string='Name' translate=True
  • query_ids One2many → mis.report.query
    copy=True string='Queries' args: 'mis.report.query', 'report_id'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' string='Style'
  • subkpi_ids One2many → mis.report.subkpi
    copy=True string='Sub KPI' args: 'mis.report.subkpi', 'report_id'
  • subreport_ids One2many → mis.report.subreport
    copy=True string='Sub reports' args: 'mis.report.subreport', 'report_id'
Public methods (7)
  • copy(self, default=None)
  • declare_and_compute_period(self, kpi_matrix, col_key, col_label, col_description, aep, date_from, date_to, target_move, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None, locals_dict=None, aml_model=None, no_auto_expand_accounts=False)
  • evaluate(self, aep, date_from, date_to, target_move='posted', aml_model=None, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None)
    Simplified method to evaluate a report over a time period. :param aep: an AccountingExpressionProcessor instance created using _prepare_aep() :param date_from, date_to: the starting and ending date :param target_move: all|posted :param aml_model: the name of a model that is compatible with account.move.line :param subkpis_filter: a list of subkpis to include in the evaluation (if empty, use all subkpis) :param get_additional_move_line_filter: a bound method that takes no arguments and returns a domain compatible with account.move.line :param get_additional_query_filter: a bound method that takes a single query argument and returns a domain compatible with the query underlying model :return: a dictionary where keys are KPI names, and values are the evaluated results; some additional keys might be present: these should be ignored as they might be removed in the future.
  • get_kpis_by_account_id(self, company)
    Return { account_id: set(kpi) }
  • get_wizard_report_action(self)
  • prepare_kpi_matrix(self, multi_company=False)
  • prepare_locals_dict(self)

New fields (23)
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' oldname='account_analytic_id' string='Analytic Account'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' string='Analytic Tags'
  • company_id Many2one → res.company
    comodel_name='res.company' default=_default_company_id required=True string='Company'
  • company_ids Many2many → res.company
    comodel_name='res.company' help='Select companies for which data will be searched.' string='Companies'
  • comparison_mode Boolean
    compute='_compute_comparison_mode' inverse='_inverse_comparison_mode'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' help='Select target currency for the report. Required if companies have different currencies.' required=False string='Currency'
  • date Date
    help='Report base date (leave empty to use current date)' string='Base date'
  • date_from Date
    string='From'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_to Date
    string='To'
  • description Char
    readonly=True related='report_id.description'
  • display_columns_description Boolean
    help='Display the date range details in the column headers.'
  • hide_analytic_filters Boolean
    default=True
  • landscape_pdf Boolean
    string='Landscape PDF'
  • multi_company Boolean
    default=False help='Check if you wish to specify children companies to be searched for data.' string='Multiple companies'
  • name Char
    required=True string='Name' translate=True
  • no_auto_expand_accounts Boolean
    string='Disable account details expansion'
  • period_ids One2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' copy=True inverse_name='report_instance_id' required=True string='Periods'
  • pivot_date Date
    compute='_compute_pivot_date' string='Pivot date'
  • query_company_ids Many2many → res.company
    comodel_name='res.company' compute='_compute_query_company_ids' help='Companies for which data will be searched.'
  • report_id Many2one → mis.report
    required=True string='Report' args: 'mis.report'
  • target_move Selection
    default='posted' required=True string='Target Moves' args: [('posted', 'All Posted Entries'), ('all', 'All Entries')]
  • temporary Boolean
    default=False
Public methods (9)
  • compute(self)
  • copy(self, default=None)
  • display_settings(self)
  • drilldown(self, arg)
  • export_xls(self)
  • get_filter_descriptions_from_context(self)
    @api.model
  • preview(self)
  • print_pdf(self)
  • save_report(self)

New fields (27)
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' help='Filter column on journal entries that match this analytic account.This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Account'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' help='Filter column on journal entries that have all these analytic tags.This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Tags'
  • date_from Date
    compute='_compute_dates' string='From (computed)'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_range_type_id Many2one → date.range.type
    comodel_name='date.range.type' domain=[('allow_overlap', '=', False)] string='Date Range Type'
  • date_to Date
    compute='_compute_dates' string='To (computed)'
  • duration Integer
    default=1 help='Number of periods' string='Duration'
  • is_ytd Boolean
    default=False help='Forces the start date to Jan 1st of the relevant year' string='Year to date'
  • manual_date_from Date
    string='From'
  • manual_date_to Date
    string='To'
  • mode Selection
    default=MODE_FIX required=True args: [(MODE_FIX, 'Fixed dates'), (MODE_REL, 'Relative to report base date'), (MODE_NONE, 'No date filter')]
  • name Char
    required=True string='Label' translate=True
  • normalize_factor Integer
    default=1 help='Factor to use to normalize the period (used in comparison' string='Factor'
  • offset Integer
    default=-1 help='Offset from current period' string='Offset'
  • report_id Many2one
    related='report_instance_id.report_id'
  • report_instance_id Many2one → mis.report.instance
    comodel_name='mis.report.instance' ondelete='cascade' required=True string='Report Instance'
  • sequence Integer
    default=100 string='Sequence'
  • source Selection
    default=SRC_ACTUALS help='Actuals: current data, from accounting and other queries.\nActuals (alternative): current data from an alternative source (eg a database view providing look-alike account move lines).\nSum columns: summation (+/-) of other columns.\nCompare to column: compare to other column.\n' required=True args: [(SRC_ACTUALS, 'Actuals'), (SRC_ACTUALS_ALT, 'Actuals (alternative)'), (SRC_SUMCOL, 'Sum columns'), (SRC_CMPCOL, 'Compare columns')]
  • source_aml_model_id Many2one → ir.model
    comodel_name='ir.model' domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id'), ('field_id.model_id.model', '!=', 'account.move.line')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields." string='Move lines source'
  • source_aml_model_name Char
    related='source_aml_model_id.model' string='Move lines source model name'
  • source_cmpcol_from_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='versus'
  • source_cmpcol_to_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='Compare'
  • source_sumcol_accdet Boolean
    string='Sum account details'
  • source_sumcol_ids One2many → mis.report.instance.period.sum
    comodel_name='mis.report.instance.period.sum' inverse_name='period_id' string='Columns to sum'
  • subkpi_ids Many2many → mis.report.subkpi
    string='Sub KPI Filter' args: 'mis.report.subkpi'
  • type Selection
    string='Period type' args: [('d', _('Day')), ('w', _('Week')), ('m', _('Month')), ('y', _('Year')), ('date_range', _('Date Range'))]
  • valid Boolean
    compute='_compute_dates' string='Valid' type='boolean'
Public methods (0)

No public methods.

New fields (3)
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True string='Parent column'
  • period_to_sum_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='restrict' required=True string='Column'
  • sign Selection
    default='+' required=True args: [('+', '+'), ('-', '-')]
Public methods (0)

No public methods.

New fields (14)
  • accumulation_method Selection
    default=ACC_SUM help='Determines how values of this kpi spanning over a time period are transformed to match the reporting period. Sum: values of shorter period are added, values of longest or partially overlapping periods are adjusted pro-rata temporis.\nAverage: values of included period are averaged with a pro-rata temporis weight.' required=True string='Accumulation Method' args: [(ACC_SUM, _('Sum')), (ACC_AVG, _('Average')), (ACC_NONE, _('None'))]
  • auto_expand_accounts Boolean
    string='Display details by account'
  • auto_expand_accounts_style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style for account detail rows'
  • compare_method Selection
    default=CMP_PCT required=True string='Comparison Method' args: [(CMP_DIFF, _('Difference')), (CMP_PCT, _('Percentage')), (CMP_NONE, _('None'))]
  • description Char
    required=True string='Description' translate=True
  • expression Char
    compute='_compute_expression' inverse='_inverse_expression' string='Expression'
  • expression_ids One2many → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' copy=True inverse_name='kpi_id' string='Expressions'
  • multi Boolean
  • name Char
    required=True string='Name'
  • report_id Many2one → mis.report
    ondelete='cascade' required=True string='Report' args: 'mis.report'
  • sequence Integer
    default=100 string='Sequence'
  • style_expression Char
    help='An expression that returns a style depending on the KPI value. Such style is applied on top of the row style.' string='Style expression'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style'
  • type Selection
    default=TYPE_NUM required=True string='Value type' args: [(TYPE_NUM, _('Numeric')), (TYPE_PCT, _('Percentage')), (TYPE_STR, _('String'))]
Public methods (2)
  • name_get(self)
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (4)
  • kpi_id Many2one → mis.report.kpi
    ondelete='cascade' required=True args: 'mis.report.kpi'
  • name Char
    string='Expression'
  • sequence Integer
    readonly=True related='subkpi_id.sequence' store=True
  • subkpi_id Many2one → mis.report.subkpi
    ondelete='cascade' readonly=False args: 'mis.report.subkpi'
Public methods (2)
  • name_get(self)
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (8)
  • aggregate Selection
    string='Aggregate' args: [('sum', _('Sum')), ('avg', _('Average')), ('min', _('Min')), ('max', _('Max'))]
  • date_field Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain=[('ttype', 'in', ('date', 'datetime'))] ondelete='restrict' required=True
  • domain Char
    string='Domain'
  • field_ids Many2many → ir.model.fields
    required=True string='Fields to fetch' args: 'ir.model.fields'
  • field_names Char
    compute='_compute_field_names' string='Fetched fields name'
  • model_id Many2one → ir.model
    ondelete='restrict' required=True string='Model' args: 'ir.model'
  • name Char
    required=True string='Name'
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True string='Report'
Public methods (0)

No public methods.

New fields (25)
  • background_color Char
    default='#FFFFFF' help='Background color in valid RGB code (from #000000 to #FFFFFF)'
  • background_color_inherit Boolean
    default=True
  • color Char
    default='#000000' help='Text color in valid RGB code (from #000000 to #FFFFFF)' string='Text color'
  • color_inherit Boolean
    default=True
  • divider Selection
    default='1' string='Factor' args: [('1e-6', _('µ')), ('1e-3', _('m')), ('1', _('1')), ('1e3', _('k')), ('1e6', _('M'))]
  • divider_inherit Boolean
    default=True
  • dp Integer
    default=0 string='Rounding'
  • dp_inherit Boolean
    default=True
  • font_size Selection
    selection=_font_size_selection
  • font_size_inherit Boolean
    default=True
  • font_style Selection
    selection=_font_style_selection
  • font_style_inherit Boolean
    default=True
  • font_weight Selection
    selection=_font_weight_selection
  • font_weight_inherit Boolean
    default=True
  • hide_always Boolean
    default=False
  • hide_always_inherit Boolean
    default=True
  • hide_empty Boolean
    default=False
  • hide_empty_inherit Boolean
    default=True
  • indent_level Integer
  • indent_level_inherit Boolean
    default=True
  • name Char
    required=True string='Style name'
  • prefix Char
    string='Prefix'
  • prefix_inherit Boolean
    default=True
  • suffix Char
    string='Suffix'
  • suffix_inherit Boolean
    default=True
Public methods (9)
  • check_positive_val(self)
    @api.constrains('indent_level')
  • compare_and_render(self, lang, style_props, type, compare_method, value, base_value, average_value=1, average_base_value=1)
    @api.model
    :param lang: res.lang record :param style_props: PropertyDict with style properties :param type: num, pct or str :param compare_method: diff, pct, none :param value: value to compare (value - base_value) :param base_value: value compared with (value - base_value) :param average_value: value = value / average_value :param average_base_value: base_value = base_value / average_base_value :return: tuple with 4 elements - delta = comparison result (Float or AccountingNone) - delta_r = delta rendered in formatted string (String) - delta_style = PropertyDict with style properties - delta_type = Type of the comparison result (num or pct)
  • merge(self, styles)
    @api.model
    Merge several styles, giving priority to the last. Returns a PropertyDict of style properties.
  • render(self, lang, style_props, type, value, sign='-')
    @api.model
  • render_num(self, lang, value, divider=1.0, dp=0, prefix=None, suffix=None, sign='-')
    @api.model
  • render_pct(self, lang, value, dp=1, sign='-')
    @api.model
  • render_str(self, lang, value)
    @api.model
  • to_css_style(self, props, no_indent=False)
    @api.model
  • to_xlsx_style(self, type, props, no_indent=False)
    @api.model

New fields (5)
  • description Char
    required=True string='Description' translate=True
  • expression_ids One2many → mis.report.kpi.expression
    args: 'mis.report.kpi.expression', 'subkpi_id'
  • name Char
    required=True string='Name'
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • sequence Integer
    default=1
Public methods (0)

No public methods.

New fields (3)
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • subreport_id Many2one → mis.report
    comodel_name='mis.report' ondelete='restrict' required=True
Public methods (0)

No public methods.

New fields (3)
  • date Date
    compute=<expr> help='Dummy field that adapts searches on date to searches on date_from/date_to.' search='_search_date'
  • date_from Date
    required=True
  • date_to Date
    required=True
Public methods (1)
  • read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True)
    @api.model
    Override read_group to perform pro-rata temporis adjustments. When read_group is invoked with a domain that filters on a time period (date >= from and date <= to, or date_from <= to and date_to >= from), adjust the accumulated values pro-rata temporis.

New fields (0)

No new fields.

Public methods (1)
  • generate_xlsx_report(self, workbook, data, objects)
REPOSITORY
REPOSITORYOCA/mis-builder
GIT
GIThttps://github.com/OCA/mis-builder.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/mis-builder/tree/10.0/mis_builder
VERSION
VERSION 3.6.5
CATEGORY
CATEGORYReporting
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSStéphane Bidoul, OCA Transbot, oca-travis, Weblate, OCA-git-bot, Maxence Groine
WEBSITE
WEBSITEhttps://github.com/OCA/mis-builder/
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:20:02
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/reporting-engine:
    - report_xlsx
OCA/server-tools:
    - date_range
OCA/web:
    - web_widget_color
odoo/odoo:
    - account
    - base_setup
    - base
    - web_kanban
    - web
    - product
    - decimal_precision
    - mail
    - bus
    - web_tour
    - report
    - analytic
    - web_planner
    - board
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES xlsxwriter
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (14)
XML IDNameModelTypeStatus
assets_backend mis_builder ir.ui.view qweb Inherits web.assets_backend
assets_report assets_report ir.ui.view qweb Inherits report.assets_common
mis_report_instance_add_to_dashboard_form_view add.mis.report.instance.dashboard.wizard.view add.mis.report.instance.dashboard.wizard form New
mis_report_instance_period_view_form mis.report.instance.period form New
mis_report_instance_result_view_form mis.report.instance.result.view.form mis.report.instance form New
mis_report_instance_view_form mis.report.instance.view.form mis.report.instance form New
mis_report_instance_view_tree mis.report.instance.view.tree mis.report.instance tree New
mis_report_style_view_form mis.report.style.view.form mis.report.style form New
mis_report_style_view_tree mis.report.style.view.tree mis.report.style tree New
mis_report_view_form mis.report.view.form mis.report form New
mis_report_view_kpi_form mis.report.view.kpi.form mis.report.kpi form New
mis_report_view_tree mis.report.view.tree mis.report tree New
report_mis_report_instance report_mis_report_instance ir.ui.view qweb New
wizard_mis_report_instance_view_form mis.report.instance field Inherits mis_builder.mis_report_instance_view_form
Models touched (14)

New fields (2)
  • dashboard_id Many2one → ir.actions.act_window
    domain="[('res_model', '=', 'board.board')]" required=True string='Dashboard' args: 'ir.actions.act_window'
  • name Char
    required=True args: 'Name'
Public methods (2)
  • action_add_to_dashboard(self)
  • default_get(self, fields_list)
    @api.model

New fields (7)
  • amount Float
  • date_from Date
    required=True string='From'
  • date_to Date
    required=True string='To'
  • kpi_expression_id Many2one → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' ondelete='restrict' required=True string='KPI'
  • name Char
    compute='_compute_name' readonly=True required=False
  • seq1 Integer
    readonly=True related='kpi_expression_id.kpi_id.sequence' store=True string='KPI Sequence'
  • seq2 Integer
    readonly=True related='kpi_expression_id.subkpi_id.sequence' store=True string='Sub-KPI Sequence'
Public methods (0)

No public methods.

New fields (10)
  • account_model Char
    compute='_compute_account_model' string='Account model'
  • all_kpi_ids One2many → mis.report.kpi
    comodel_name='mis.report.kpi' compute='_compute_all_kpi_ids' help='KPIs of this report and subreports.'
  • description Char
    required=False string='Description' translate=True
  • kpi_ids One2many → mis.report.kpi
    copy=True string="KPI's" args: 'mis.report.kpi', 'report_id'
  • move_lines_source Many2one → ir.model
    comodel_name='ir.model' default=_default_move_lines_source domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields. This model is the data source for column Actuals." required=True string='Move lines source'
  • name Char
    required=True string='Name' translate=True
  • query_ids One2many → mis.report.query
    copy=True string='Queries' args: 'mis.report.query', 'report_id'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' string='Style'
  • subkpi_ids One2many → mis.report.subkpi
    copy=True string='Sub KPI' args: 'mis.report.subkpi', 'report_id'
  • subreport_ids One2many → mis.report.subreport
    copy=True string='Sub reports' args: 'mis.report.subreport', 'report_id'
Public methods (7)
  • copy(self, default=None)
  • declare_and_compute_period(self, kpi_matrix, col_key, col_label, col_description, aep, date_from, date_to, target_move, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None, locals_dict=None, aml_model=None, no_auto_expand_accounts=False)
  • evaluate(self, aep, date_from, date_to, target_move='posted', aml_model=None, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None)
    Simplified method to evaluate a report over a time period. :param aep: an AccountingExpressionProcessor instance created using _prepare_aep() :param date_from, date_to: the starting and ending date :param target_move: all|posted :param aml_model: the name of a model that is compatible with account.move.line :param subkpis_filter: a list of subkpis to include in the evaluation (if empty, use all subkpis) :param get_additional_move_line_filter: a bound method that takes no arguments and returns a domain compatible with account.move.line :param get_additional_query_filter: a bound method that takes a single query argument and returns a domain compatible with the query underlying model :return: a dictionary where keys are KPI names, and values are the evaluated results; some additional keys might be present: these should be ignored as they might be removed in the future.
  • get_kpis_by_account_id(self, company)
    Return { account_id: set(kpi) }
  • get_wizard_report_action(self)
  • prepare_kpi_matrix(self, multi_company=False)
  • prepare_locals_dict(self)

New fields (23)
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' oldname='account_analytic_id' string='Analytic Account'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' string='Analytic Tags'
  • company_id Many2one → res.company
    comodel_name='res.company' default=_default_company_id required=True string='Company'
  • company_ids Many2many → res.company
    comodel_name='res.company' help='Select companies for which data will be searched.' string='Companies'
  • comparison_mode Boolean
    compute='_compute_comparison_mode' inverse='_inverse_comparison_mode'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' help='Select target currency for the report. Required if companies have different currencies.' required=False string='Currency'
  • date Date
    help='Report base date (leave empty to use current date)' string='Base date'
  • date_from Date
    string='From'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_to Date
    string='To'
  • description Char
    readonly=True related='report_id.description'
  • display_columns_description Boolean
    help='Display the date range details in the column headers.'
  • hide_analytic_filters Boolean
    default=True
  • landscape_pdf Boolean
    string='Landscape PDF'
  • multi_company Boolean
    default=False help='Check if you wish to specify children companies to be searched for data.' string='Multiple companies'
  • name Char
    required=True string='Name' translate=True
  • no_auto_expand_accounts Boolean
    string='Disable account details expansion'
  • period_ids One2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' copy=True inverse_name='report_instance_id' required=True string='Periods'
  • pivot_date Date
    compute='_compute_pivot_date' string='Pivot date'
  • query_company_ids Many2many → res.company
    comodel_name='res.company' compute='_compute_query_company_ids' help='Companies for which data will be searched.'
  • report_id Many2one → mis.report
    required=True string='Report' args: 'mis.report'
  • target_move Selection
    default='posted' required=True string='Target Moves' args: [('posted', 'All Posted Entries'), ('all', 'All Entries')]
  • temporary Boolean
    default=False
Public methods (9)
  • compute(self)
  • copy(self, default=None)
  • display_settings(self)
  • drilldown(self, arg)
  • export_xls(self)
  • get_filter_descriptions_from_context(self)
    @api.model
  • preview(self)
  • print_pdf(self)
  • save_report(self)

New fields (27)
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' help='Filter column on journal entries that match this analytic account.This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Account'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' help='Filter column on journal entries that have all these analytic tags.This filter is combined with a AND with the report-level filters and cannot be modified in the preview.' string='Analytic Tags'
  • date_from Date
    compute='_compute_dates' string='From (computed)'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_range_type_id Many2one → date.range.type
    comodel_name='date.range.type' domain=[('allow_overlap', '=', False)] string='Date Range Type'
  • date_to Date
    compute='_compute_dates' string='To (computed)'
  • duration Integer
    default=1 help='Number of periods' string='Duration'
  • is_ytd Boolean
    default=False help='Forces the start date to Jan 1st of the relevant year' string='Year to date'
  • manual_date_from Date
    string='From'
  • manual_date_to Date
    string='To'
  • mode Selection
    default=MODE_FIX required=True args: [(MODE_FIX, 'Fixed dates'), (MODE_REL, 'Relative to report base date'), (MODE_NONE, 'No date filter')]
  • name Char
    required=True string='Label' translate=True
  • normalize_factor Integer
    default=1 help='Factor to use to normalize the period (used in comparison' string='Factor'
  • offset Integer
    default=-1 help='Offset from current period' string='Offset'
  • report_id Many2one
    related='report_instance_id.report_id'
  • report_instance_id Many2one → mis.report.instance
    comodel_name='mis.report.instance' ondelete='cascade' required=True string='Report Instance'
  • sequence Integer
    default=100 string='Sequence'
  • source Selection
    default=SRC_ACTUALS help='Actuals: current data, from accounting and other queries.\nActuals (alternative): current data from an alternative source (eg a database view providing look-alike account move lines).\nSum columns: summation (+/-) of other columns.\nCompare to column: compare to other column.\n' required=True args: [(SRC_ACTUALS, 'Actuals'), (SRC_ACTUALS_ALT, 'Actuals (alternative)'), (SRC_SUMCOL, 'Sum columns'), (SRC_CMPCOL, 'Compare columns')]
  • source_aml_model_id Many2one → ir.model
    comodel_name='ir.model' domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id'), ('field_id.model_id.model', '!=', 'account.move.line')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields." string='Move lines source'
  • source_aml_model_name Char
    related='source_aml_model_id.model' string='Move lines source model name'
  • source_cmpcol_from_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='versus'
  • source_cmpcol_to_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='Compare'
  • source_sumcol_accdet Boolean
    string='Sum account details'
  • source_sumcol_ids One2many → mis.report.instance.period.sum
    comodel_name='mis.report.instance.period.sum' inverse_name='period_id' string='Columns to sum'
  • subkpi_ids Many2many → mis.report.subkpi
    string='Sub KPI Filter' args: 'mis.report.subkpi'
  • type Selection
    string='Period type' args: [('d', _('Day')), ('w', _('Week')), ('m', _('Month')), ('y', _('Year')), ('date_range', _('Date Range'))]
  • valid Boolean
    compute='_compute_dates' string='Valid' type='boolean'
Public methods (0)

No public methods.

New fields (3)
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True string='Parent column'
  • period_to_sum_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='restrict' required=True string='Column'
  • sign Selection
    default='+' required=True args: [('+', '+'), ('-', '-')]
Public methods (0)

No public methods.

New fields (14)
  • accumulation_method Selection
    default=ACC_SUM help='Determines how values of this kpi spanning over a time period are transformed to match the reporting period. Sum: values of shorter period are added, values of longest or partially overlapping periods are adjusted pro-rata temporis.\nAverage: values of included period are averaged with a pro-rata temporis weight.' required=True string='Accumulation Method' args: [(ACC_SUM, _('Sum')), (ACC_AVG, _('Average')), (ACC_NONE, _('None'))]
  • auto_expand_accounts Boolean
    string='Display details by account'
  • auto_expand_accounts_style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style for account detail rows'
  • compare_method Selection
    default=CMP_PCT required=True string='Comparison Method' args: [(CMP_DIFF, _('Difference')), (CMP_PCT, _('Percentage')), (CMP_NONE, _('None'))]
  • description Char
    required=True string='Description' translate=True
  • expression Char
    compute='_compute_expression' inverse='_inverse_expression' string='Expression'
  • expression_ids One2many → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' copy=True inverse_name='kpi_id' string='Expressions'
  • multi Boolean
  • name Char
    required=True string='Name'
  • report_id Many2one → mis.report
    ondelete='cascade' required=True string='Report' args: 'mis.report'
  • sequence Integer
    default=100 string='Sequence'
  • style_expression Char
    help='An expression that returns a style depending on the KPI value. Such style is applied on top of the row style.' string='Style expression'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style'
  • type Selection
    default=TYPE_NUM required=True string='Value type' args: [(TYPE_NUM, _('Numeric')), (TYPE_PCT, _('Percentage')), (TYPE_STR, _('String'))]
Public methods (2)
  • name_get(self)
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (4)
  • kpi_id Many2one → mis.report.kpi
    ondelete='cascade' required=True args: 'mis.report.kpi'
  • name Char
    string='Expression'
  • sequence Integer
    readonly=True related='subkpi_id.sequence' store=True
  • subkpi_id Many2one → mis.report.subkpi
    ondelete='cascade' readonly=False args: 'mis.report.subkpi'
Public methods (2)
  • name_get(self)
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (8)
  • aggregate Selection
    string='Aggregate' args: [('sum', _('Sum')), ('avg', _('Average')), ('min', _('Min')), ('max', _('Max'))]
  • date_field Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain=[('ttype', 'in', ('date', 'datetime'))] ondelete='restrict' required=True
  • domain Char
    string='Domain'
  • field_ids Many2many → ir.model.fields
    required=True string='Fields to fetch' args: 'ir.model.fields'
  • field_names Char
    compute='_compute_field_names' string='Fetched fields name'
  • model_id Many2one → ir.model
    ondelete='restrict' required=True string='Model' args: 'ir.model'
  • name Char
    required=True string='Name'
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True string='Report'
Public methods (0)

No public methods.

New fields (25)
  • background_color Char
    default='#FFFFFF' help='Background color in valid RGB code (from #000000 to #FFFFFF)'
  • background_color_inherit Boolean
    default=True
  • color Char
    default='#000000' help='Text color in valid RGB code (from #000000 to #FFFFFF)' string='Text color'
  • color_inherit Boolean
    default=True
  • divider Selection
    default='1' string='Factor' args: [('1e-6', _('µ')), ('1e-3', _('m')), ('1', _('1')), ('1e3', _('k')), ('1e6', _('M'))]
  • divider_inherit Boolean
    default=True
  • dp Integer
    default=0 string='Rounding'
  • dp_inherit Boolean
    default=True
  • font_size Selection
    selection=_font_size_selection
  • font_size_inherit Boolean
    default=True
  • font_style Selection
    selection=_font_style_selection
  • font_style_inherit Boolean
    default=True
  • font_weight Selection
    selection=_font_weight_selection
  • font_weight_inherit Boolean
    default=True
  • hide_always Boolean
    default=False
  • hide_always_inherit Boolean
    default=True
  • hide_empty Boolean
    default=False
  • hide_empty_inherit Boolean
    default=True
  • indent_level Integer
  • indent_level_inherit Boolean
    default=True
  • name Char
    required=True string='Style name'
  • prefix Char
    string='Prefix'
  • prefix_inherit Boolean
    default=True
  • suffix Char
    string='Suffix'
  • suffix_inherit Boolean
    default=True
Public methods (9)
  • check_positive_val(self)
    @api.constrains('indent_level')
  • compare_and_render(self, lang, style_props, type, compare_method, value, base_value, average_value=1, average_base_value=1)
    @api.model
    :param lang: res.lang record :param style_props: PropertyDict with style properties :param type: num, pct or str :param compare_method: diff, pct, none :param value: value to compare (value - base_value) :param base_value: value compared with (value - base_value) :param average_value: value = value / average_value :param average_base_value: base_value = base_value / average_base_value :return: tuple with 4 elements - delta = comparison result (Float or AccountingNone) - delta_r = delta rendered in formatted string (String) - delta_style = PropertyDict with style properties - delta_type = Type of the comparison result (num or pct)
  • merge(self, styles)
    @api.model
    Merge several styles, giving priority to the last. Returns a PropertyDict of style properties.
  • render(self, lang, style_props, type, value, sign='-')
    @api.model
  • render_num(self, lang, value, divider=1.0, dp=0, prefix=None, suffix=None, sign='-')
    @api.model
  • render_pct(self, lang, value, dp=1, sign='-')
    @api.model
  • render_str(self, lang, value)
    @api.model
  • to_css_style(self, props, no_indent=False)
    @api.model
  • to_xlsx_style(self, type, props, no_indent=False)
    @api.model

New fields (5)
  • description Char
    required=True string='Description' translate=True
  • expression_ids One2many → mis.report.kpi.expression
    args: 'mis.report.kpi.expression', 'subkpi_id'
  • name Char
    required=True string='Name'
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • sequence Integer
    default=1
Public methods (0)

No public methods.

New fields (3)
  • name Char
    required=True
  • report_id Many2one → mis.report
    comodel_name='mis.report' required=True
  • subreport_id Many2one → mis.report
    comodel_name='mis.report' required=True
Public methods (0)

No public methods.

New fields (3)
  • date Date
    compute=<expr> help='Dummy field that adapts searches on date to searches on date_from/date_to.' search='_search_date'
  • date_from Date
    required=True
  • date_to Date
    required=True
Public methods (1)
  • read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True)
    @api.model
    Override read_group to perform pro-rata temporis adjustments. When read_group is invoked with a domain that filters on a time period (date >= from and date <= to, or date_from <= to and date_to >= from), adjust the accumulated values pro-rata temporis.

New fields (0)

No new fields.

Public methods (1)
  • get_pdf(self, docids, report_name, html=None, data=None)
    @api.model
REPOSITORY
REPOSITORYOCA/mis-builder
GIT
GIThttps://github.com/OCA/mis-builder.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/mis-builder/tree/9.0/mis_builder
VERSION
VERSION 3.5.0
CATEGORY
CATEGORYReporting
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSStéphane Bidoul, Arnaud Pineux, Alexandre Fayolle, Pedro M. Baeza, GitHub, sebalix, Denis Roussel, Andrea, Enric Tobella, Stéphane Bidoul (ACSONE), Jordi Ballester Alomar, Richard deMeester, OCA Transbot, Thomas Binsfeld, Sébastien BEAU, Adrien Peiffer (ACSONE), oca-travis, OCA-git-bot, OCA Git Bot, Davor Bojkić, elicoidal, Benjamin Willig, Travis CI User, Alain Van Utterbeeck
WEBSITE
WEBSITEhttps://github.com/OCA/mis-builder/
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:15:24
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/reporting-engine:
    - report_xlsx
OCA/server-tools:
    - date_range
OCA/web:
    - web_widget_color
odoo/odoo:
    - account
    - base_setup
    - base
    - web_kanban
    - web
    - product
    - decimal_precision
    - mail
    - bus
    - report
    - analytic
    - web_tip
    - web_planner
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES xlsxwriter
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (14)
XML IDNameModelTypeStatus
assets_backend mis_builder ir.ui.view qweb Inherits web.assets_backend
assets_report assets_report ir.ui.view qweb Inherits report.assets_common
mis_report_instance_add_to_dashboard_form_view add.mis.report.instance.dashboard.wizard.view add.mis.report.instance.dashboard.wizard form New
mis_report_instance_period_view_form mis.report.instance.period form New
mis_report_instance_result_view_form mis.report.instance.result.view.form mis.report.instance form New
mis_report_instance_view_form mis.report.instance.view.form mis.report.instance form New
mis_report_instance_view_tree mis.report.instance.view.tree mis.report.instance tree New
mis_report_style_view_form mis.report.style.view.form mis.report.style form New
mis_report_style_view_tree mis.report.style.view.tree mis.report.style tree New
mis_report_view_form mis.report.view.form mis.report form New
mis_report_view_kpi_form mis.report.view.kpi.form mis.report.kpi form New
mis_report_view_tree mis.report.view.tree mis.report tree New
report_mis_report_instance report_mis_report_instance ir.ui.view qweb New
wizard_mis_report_instance_view_form mis.report.instance field Inherits mis_builder.mis_report_instance_view_form
Models touched (12)

New fields (2)
  • dashboard_id Many2one → ir.actions.act_window
    domain="[('res_model', '=', 'board.board')]" required=True string='Dashboard' args: 'ir.actions.act_window'
  • name Char
    required=True size=32 args: 'Name'
Public methods (2)
  • action_add_to_dashboard(self)
    @api.multi
  • default_get(self, fields)
    @api.model

New fields (5)
  • amount Float
  • date_from Date
    required=True string='From'
  • date_to Date
    required=True string='To'
  • kpi_expression_id Many2one → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' ondelete='restrict' required=True string='KPI'
  • name Char
    compute='_compute_name' readonly=True required=False
Public methods (0)

No public methods.

New fields (8)
  • account_model Char
    compute='_compute_account_model' string='Account model'
  • description Char
    required=False string='Description' translate=True
  • kpi_ids One2many → mis.report.kpi
    copy=True string="KPI's" args: 'mis.report.kpi', 'report_id'
  • move_lines_source Many2one → ir.model
    comodel_name='ir.model' default=_default_move_lines_source domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields. This model is the data source for column Actuals." required=True string='Move lines source'
  • name Char
    required=True string='Name' translate=True
  • query_ids One2many → mis.report.query
    copy=True string='Queries' args: 'mis.report.query', 'report_id'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' string='Style'
  • subkpi_ids One2many → mis.report.subkpi
    copy=True string='Sub KPI' args: 'mis.report.subkpi', 'report_id'
Public methods (7)
  • copy(self, default=None)
    @api.multi
  • declare_and_compute_period(self, kpi_matrix, col_key, col_label, col_description, aep, date_from, date_to, target_move, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None, locals_dict=None, aml_model=None, no_auto_expand_accounts=False)
    @api.multi
    Evaluate a report for a given period, populating a KpiMatrix. :param kpi_matrix: the KpiMatrix object to be populated created with prepare_kpi_matrix() :param col_key: the period key to use when populating the KpiMatrix :param aep: an AccountingExpressionProcessor instance created using _prepare_aep() :param date_from, date_to: the starting and ending date :param target_move: all|posted :param subkpis_filter: a list of subkpis to include in the evaluation (if empty, use all subkpis) :param get_additional_move_line_filter: a bound method that takes no arguments and returns a domain compatible with account.move.line :param get_additional_query_filter: a bound method that takes a single query argument and returns a domain compatible with the query underlying model :param locals_dict: personalized locals dictionary used as evaluation context for the KPI expressions :param aml_model: the name of a model that is compatible with account.move.line :param no_auto_expand_accounts: disable expansion of account details
  • evaluate(self, aep, date_from, date_to, target_move='posted', aml_model=None, subkpis_filter=None, get_additional_move_line_filter=None, get_additional_query_filter=None)
    @api.multi
    Simplified method to evaluate a report over a time period. :param aep: an AccountingExpressionProcessor instance created using _prepare_aep() :param date_from, date_to: the starting and ending date :param target_move: all|posted :param aml_model: the name of a model that is compatible with account.move.line :param subkpis_filter: a list of subkpis to include in the evaluation (if empty, use all subkpis) :param get_additional_move_line_filter: a bound method that takes no arguments and returns a domain compatible with account.move.line :param get_additional_query_filter: a bound method that takes a single query argument and returns a domain compatible with the query underlying model :return: a dictionary where keys are KPI names, and values are the evaluated results; some additional keys might be present: these should be ignored as they might be removed in the future.
  • get_kpis_by_account_id(self, company)
    Return { account_id: set(kpi) }
  • get_wizard_report_action(self)
    @api.multi
  • prepare_kpi_matrix(self, multi_company=False)
    @api.multi
  • prepare_locals_dict(self)

New fields (23)
  • analytic_account_id Many2one → account.analytic.account
    comodel_name='account.analytic.account' oldname='account_analytic_id' string='Analytic Account'
  • analytic_tag_ids Many2many → account.analytic.tag
    comodel_name='account.analytic.tag' string='Analytic Tags'
  • company_id Many2one → res.company
    comodel_name='res.company' default=_default_company_id required=True string='Company'
  • company_ids Many2many → res.company
    comodel_name='res.company' help='Select companies for which data will be searched.' string='Companies'
  • comparison_mode Boolean
    compute='_compute_comparison_mode' inverse='_inverse_comparison_mode'
  • currency_id Many2one → res.currency
    comodel_name='res.currency' help='Select target currency for the report. Required if companies have different currencies.' required=False string='Currency'
  • date Date
    help='Report base date (leave empty to use current date)' string='Base date'
  • date_from Date
    string='From'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_to Date
    string='To'
  • description Char
    readonly=True related='report_id.description'
  • display_columns_description Boolean
    help='Display the date range details in the column headers.'
  • hide_analytic_filters Boolean
    default=True
  • landscape_pdf Boolean
    string='Landscape PDF'
  • multi_company Boolean
    default=False help='Check if you wish to specify children companies to be searched for data.' string='Multiple companies'
  • name Char
    required=True string='Name' translate=True
  • no_auto_expand_accounts Boolean
    string='Disable account details expansion'
  • period_ids One2many → mis.report.instance.period
    comodel_name='mis.report.instance.period' copy=True inverse_name='report_instance_id' required=True string='Periods'
  • pivot_date Date
    compute='_compute_pivot_date' string='Pivot date'
  • query_company_ids Many2many → res.company
    comodel_name='res.company' compute='_compute_query_company_ids' help='Companies for which data will be searched.'
  • report_id Many2one → mis.report
    required=True string='Report' args: 'mis.report'
  • target_move Selection
    default='posted' required=True string='Target Moves' args: [('posted', 'All Posted Entries'), ('all', 'All Entries')]
  • temporary Boolean
    default=False
Public methods (9)
  • compute(self)
    @api.multi
  • copy(self, default=None)
    @api.multi
  • display_settings(self)
    @api.multi
  • drilldown(self, arg)
    @api.multi
  • export_xls(self)
    @api.multi
  • get_filter_descriptions_from_context(self)
    @api.model
  • preview(self)
    @api.multi
  • print_pdf(self)
    @api.multi
  • save_report(self)
    @api.multi

New fields (25)
  • date_from Date
    compute='_compute_dates' string='From (computed)'
  • date_range_id Many2one → date.range
    comodel_name='date.range' string='Date Range'
  • date_range_type_id Many2one → date.range.type
    comodel_name='date.range.type' domain=[('allow_overlap', '=', False)] string='Date Range Type'
  • date_to Date
    compute='_compute_dates' string='To (computed)'
  • duration Integer
    default=1 help='Number of periods' string='Duration'
  • is_ytd Boolean
    default=False help='Forces the start date to Jan 1st of the relevant year' string='Year to date'
  • manual_date_from Date
    string='From'
  • manual_date_to Date
    string='To'
  • mode Selection
    default=MODE_FIX required=True args: [(MODE_FIX, 'Fixed dates'), (MODE_REL, 'Relative to report base date'), (MODE_NONE, 'No date filter')]
  • name Char
    required=True size=32 string='Label' translate=True
  • normalize_factor Integer
    default=1 help='Factor to use to normalize the period (used in comparison' string='Factor'
  • offset Integer
    default=-1 help='Offset from current period' string='Offset'
  • report_id Many2one
    related='report_instance_id.report_id'
  • report_instance_id Many2one → mis.report.instance
    comodel_name='mis.report.instance' ondelete='cascade' required=True string='Report Instance'
  • sequence Integer
    default=100 string='Sequence'
  • source Selection
    default=SRC_ACTUALS help='Actuals: current data, from accounting and other queries.\nActuals (alternative): current data from an alternative source (eg a database view providing look-alike account move lines).\nSum columns: summation (+/-) of other columns.\nCompare to column: compare to other column.\n' required=True args: [(SRC_ACTUALS, 'Actuals'), (SRC_ACTUALS_ALT, 'Actuals (alternative)'), (SRC_SUMCOL, 'Sum columns'), (SRC_CMPCOL, 'Compare columns')]
  • source_aml_model_id Many2one → ir.model
    comodel_name='ir.model' domain=[('field_id.name', '=', 'debit'), ('field_id.name', '=', 'credit'), ('field_id.name', '=', 'account_id'), ('field_id.name', '=', 'date'), ('field_id.name', '=', 'company_id')] help="A 'move line like' model, ie having at least debit, credit, date, account_id and company_id fields." string='Move lines source'
  • source_aml_model_name Char
    related='source_aml_model_id.model' string='Move lines source model name'
  • source_cmpcol_from_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='versus'
  • source_cmpcol_to_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' string='Compare'
  • source_sumcol_accdet Boolean
    string='Sum account details'
  • source_sumcol_ids One2many → mis.report.instance.period.sum
    comodel_name='mis.report.instance.period.sum' inverse_name='period_id' string='Columns to sum'
  • subkpi_ids Many2many → mis.report.subkpi
    string='Sub KPI Filter' args: 'mis.report.subkpi'
  • type Selection
    string='Period type' args: [('d', _('Day')), ('w', _('Week')), ('m', _('Month')), ('y', _('Year')), ('date_range', _('Date Range'))]
  • valid Boolean
    compute='_compute_dates' string='Valid' type='boolean'
Public methods (0)

No public methods.

New fields (3)
  • period_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='cascade' required=True string='Parent column'
  • period_to_sum_id Many2one → mis.report.instance.period
    comodel_name='mis.report.instance.period' ondelete='restrict' required=True string='Column'
  • sign Selection
    default='+' required=True args: [('+', '+'), ('-', '-')]
Public methods (0)

No public methods.

New fields (14)
  • accumulation_method Selection
    default=ACC_SUM help='Determines how values of this kpi spanning over a time period are transformed to match the reporting period. Sum: values of shorter period are added, values of longest or partially overlapping periods are adjusted pro-rata temporis.\nAverage: values of included period are averaged with a pro-rata temporis weight.' required=True string='Accumulation Method' args: [(ACC_SUM, _('Sum')), (ACC_AVG, _('Average')), (ACC_NONE, _('None'))]
  • auto_expand_accounts Boolean
    string='Display details by account'
  • auto_expand_accounts_style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style for account detail rows'
  • compare_method Selection
    default=CMP_PCT required=True string='Comparison Method' args: [(CMP_DIFF, _('Difference')), (CMP_PCT, _('Percentage')), (CMP_NONE, _('None'))]
  • description Char
    required=True string='Description' translate=True
  • expression Char
    compute='_compute_expression' inverse='_inverse_expression' string='Expression'
  • expression_ids One2many → mis.report.kpi.expression
    comodel_name='mis.report.kpi.expression' copy=True inverse_name='kpi_id' string='Expressions'
  • multi Boolean
  • name Char
    required=True size=32 string='Name'
  • report_id Many2one → mis.report
    ondelete='cascade' required=True string='Report' args: 'mis.report'
  • sequence Integer
    default=100 string='Sequence'
  • style_expression Char
    help='An expression that returns a style depending on the KPI value. Such style is applied on top of the row style.' string='Style expression'
  • style_id Many2one → mis.report.style
    comodel_name='mis.report.style' required=False string='Style'
  • type Selection
    default=TYPE_NUM required=True string='Value type' args: [(TYPE_NUM, _('Numeric')), (TYPE_PCT, _('Percentage')), (TYPE_STR, _('String'))]
Public methods (2)
  • name_get(self)
    @api.multi
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (4)
  • kpi_id Many2one → mis.report.kpi
    ondelete='cascade' required=True args: 'mis.report.kpi'
  • name Char
    string='Expression'
  • sequence Integer
    readonly=True related='subkpi_id.sequence' store=True
  • subkpi_id Many2one → mis.report.subkpi
    ondelete='cascade' readonly=False args: 'mis.report.subkpi'
Public methods (2)
  • name_get(self)
    @api.multi
  • name_search(self, name='', args=None, operator='ilike', limit=100)
    @api.model

New fields (8)
  • aggregate Selection
    string='Aggregate' args: [('sum', _('Sum')), ('avg', _('Average')), ('min', _('Min')), ('max', _('Max'))]
  • date_field Many2one → ir.model.fields
    comodel_name='ir.model.fields' domain=[('ttype', 'in', ('date', 'datetime'))] ondelete='restrict' required=True
  • domain Char
    string='Domain'
  • field_ids Many2many → ir.model.fields
    required=True string='Fields to fetch' args: 'ir.model.fields'
  • field_names Char
    compute='_compute_field_names' string='Fetched fields name'
  • model_id Many2one → ir.model
    ondelete='restrict' required=True string='Model' args: 'ir.model'
  • name Char
    required=True size=32 string='Name'
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True string='Report'
Public methods (0)

No public methods.

New fields (25)
  • background_color Char
    default='#FFFFFF' help='Background color in valid RGB code (from #000000 to #FFFFFF)'
  • background_color_inherit Boolean
    default=True
  • color Char
    default='#000000' help='Text color in valid RGB code (from #000000 to #FFFFFF)' string='Text color'
  • color_inherit Boolean
    default=True
  • divider Selection
    default='1' string='Factor' args: [('1e-6', _('µ')), ('1e-3', _('m')), ('1', _('1')), ('1e3', _('k')), ('1e6', _('M'))]
  • divider_inherit Boolean
    default=True
  • dp Integer
    default=0 string='Rounding'
  • dp_inherit Boolean
    default=True
  • font_size Selection
    selection=_font_size_selection
  • font_size_inherit Boolean
    default=True
  • font_style Selection
    selection=_font_style_selection
  • font_style_inherit Boolean
    default=True
  • font_weight Selection
    selection=_font_weight_selection
  • font_weight_inherit Boolean
    default=True
  • hide_always Boolean
    default=False
  • hide_always_inherit Boolean
    default=True
  • hide_empty Boolean
    default=False
  • hide_empty_inherit Boolean
    default=True
  • indent_level Integer
  • indent_level_inherit Boolean
    default=True
  • name Char
    required=True string='Style name'
  • prefix Char
    size=16 string='Prefix'
  • prefix_inherit Boolean
    default=True
  • suffix Char
    size=16 string='Suffix'
  • suffix_inherit Boolean
    default=True
Public methods (9)
  • check_positive_val(self)
    @api.constrains('indent_level')
  • compare_and_render(self, lang, style_props, type, compare_method, value, base_value, average_value=1, average_base_value=1)
    @api.model
    :param lang: res.lang record :param style_props: PropertyDict with style properties :param type: num, pct or str :param compare_method: diff, pct, none :param value: value to compare (value - base_value) :param base_value: value compared with (value - base_value) :param average_value: value = value / average_value :param average_base_value: base_value = base_value / average_base_value :return: tuple with 4 elements - delta = comparison result (Float or AccountingNone) - delta_r = delta rendered in formatted string (String) - delta_style = PropertyDict with style properties - delta_type = Type of the comparison result (num or pct)
  • merge(self, styles)
    @api.model
    Merge several styles, giving priority to the last. Returns a PropertyDict of style properties.
  • render(self, lang, style_props, type, value, sign='-')
    @api.model
  • render_num(self, lang, value, divider=1.0, dp=0, prefix=None, suffix=None, sign='-')
    @api.model
  • render_pct(self, lang, value, dp=1, sign='-')
    @api.model
  • render_str(self, lang, value)
    @api.model
  • to_css_style(self, props, no_indent=False)
    @api.model
  • to_xlsx_style(self, type, props, no_indent=False)
    @api.model

New fields (5)
  • description Char
    required=True string='Description' translate=True
  • expression_ids One2many → mis.report.kpi.expression
    args: 'mis.report.kpi.expression', 'subkpi_id'
  • name Char
    required=True size=32 string='Name'
  • report_id Many2one → mis.report
    comodel_name='mis.report' ondelete='cascade' required=True
  • sequence Integer
    default=1
Public methods (0)

No public methods.

New fields (0)

No new fields.

Public methods (2)
  • get_pdf(self, cr, uid, ids, report_name, html=None, data=None, context=None)
    @api.v7
  • get_pdf(self, records, report_name, html=None, data=None)
    @api.v8
REPOSITORY
REPOSITORYOCA/mis-builder
GIT
GIThttps://github.com/OCA/mis-builder.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/mis-builder/tree/8.0/mis_builder
VERSION
VERSION 1.0.2
CATEGORY
CATEGORYReporting
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSStéphane Bidoul, Alexis de Lattre, Leonardo Pistone, Holger Brunn, Pedro M. Baeza, GitHub, Cédric Pigeon, Laurent Mignon (ACSONE), Stéphane Bidoul (ACSONE), Alex Comba, OCA Transbot, Thomas Binsfeld, Adrien Peiffer (ACSONE), beau sebastien, jbeficent, oca-travis, Weblate, Mathias Francke, Davor Bojkić, kmatthes
WEBSITE
WEBSITEhttp://acsone.eu
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:11:27
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/reporting-engine:
    - report_xls
odoo/odoo:
    - account
    - base_setup
    - base
    - web_kanban
    - web
    - product
    - decimal_precision
    - mail
    - report
    - analytic
    - board
    - edi
    - email_template
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES xlwt
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION

Code Analysis

Views touched (8)
XML IDNameModelTypeStatus
assets_backend mis_builder ir.ui.view qweb Inherits web.assets_backend
mis_report_instance_add_to_dashboard_form_view add.mis.report.instance.dashboard.wizard.view add.mis.report.instance.dashboard.wizard form New
mis_report_instance_result_view_form mis.report.instance.result.view.form mis.report.instance form New
mis_report_instance_view_form mis.report.instance.view.form mis.report.instance form New
mis_report_instance_view_tree mis.report.instance.view.tree mis.report.instance tree New
mis_report_view_form mis.report.view.form mis.report form New
mis_report_view_tree mis.report.view.tree mis.report tree New
report_mis_report_instance report_mis_report_instance ir.ui.view qweb New
Models touched (8)

New fields (2)
  • dashboard_id Many2one → ir.actions.act_window
    domain="[('res_model', '=', 'board.board')]" required=True string='Dashboard' args: 'ir.actions.act_window'
  • name Char
    required=True size=32 args: 'Name'
Public methods (2)
  • action_add_to_dashboard(self)
    @api.multi
  • default_get(self, fields)
    @api.model

New fields (4)
  • description Char
    required=False string='Description' translate=True
  • kpi_ids One2many → mis.report.kpi
    copy=True string="KPI's" args: 'mis.report.kpi', 'report_id'
  • name Char
    required=True string='Name' translate=True
  • query_ids One2many → mis.report.query
    copy=True string='Queries' args: 'mis.report.query', 'report_id'
Public methods (1)
  • copy(self, default=None)
    @api.one

New fields (10)
  • company_id Many2one → res.company
    comodel_name='res.company' readonly=True related='root_account.company_id' store=True string='Company'
  • date Date
    help='Report base date (leave empty to use current date)' string='Base date'
  • description Char
    required=False string='Description' translate=True
  • landscape_pdf Boolean
    string='Landscape PDF'
  • name Char
    required=True string='Name' translate=True
  • period_ids One2many → mis.report.instance.period
    copy=True required=True string='Periods' args: 'mis.report.instance.period', 'report_instance_id'
  • pivot_date Date
    compute='_compute_pivot_date' string='Pivot date'
  • report_id Many2one → mis.report
    required=True string='Report' args: 'mis.report'
  • root_account Many2one → account.account
    comodel_name='account.account' domain='[("parent_id", "=", False)]' required=True string='Account chart'
  • target_move Selection
    default='posted' required=True string='Target Moves' args: [('posted', 'All Posted Entries'), ('all', 'All Entries')]
Public methods (6)
  • compute(self)
    @api.multi
  • copy(self, default=None)
    @api.one
  • display_settings(self)
    @api.multi
  • export_xls(self)
    @api.multi
  • preview(self)
    @api.multi
  • print_pdf(self)
    @api.multi

New fields (13)
  • comparison_column_ids Many2many → mis.report.instance.period
    column1='period_id' column2='compare_period_id' comodel_name='mis.report.instance.period' relation='mis_report_instance_period_rel' string='Compare with'
  • date_from Date
    compute='_compute_dates' string='From'
  • date_to Date
    compute='_compute_dates' string='To'
  • duration Integer
    default=1 help='Number of periods' string='Duration'
  • name Char
    required=True size=32 string='Description' translate=True
  • normalize_factor Integer
    default=1 help='Factor to use to normalize the period (used in comparison' string='Factor'
  • offset Integer
    default=-1 help='Offset from current period' string='Offset'
  • period_from Many2one → account.period
    comodel_name='account.period' compute='_compute_dates' string='From period'
  • period_to Many2one → account.period
    comodel_name='account.period' compute='_compute_dates' string='To period'
  • report_instance_id Many2one → mis.report.instance
    ondelete='cascade' string='Report Instance' args: 'mis.report.instance'
  • sequence Integer
    default=100 string='Sequence'
  • type Selection
    required=True string='Period type' args: [('d', _('Day')), ('w', _('Week')), ('fp', _('Fiscal Period'))]
  • valid Boolean
    compute='_compute_dates' string='Valid' type='boolean'
Public methods (1)
  • drilldown(self, expr)
    @api.multi

New fields (13)
  • compare_method Selection
    default='pct' required=True string='Comparison Method' args: [('diff', _('Difference')), ('pct', _('Percentage')), ('none', _('None'))]
  • css_style Char
    string='CSS style expression'
  • default_css_style Char
    string='Default CSS style'
  • description Char
    required=True string='Description' translate=True
  • divider Selection
    default='1' string='Factor' args: [('1e-6', _('µ')), ('1e-3', _('m')), ('1', _('1')), ('1e3', _('k')), ('1e6', _('M'))]
  • dp Integer
    default=0 string='Rounding'
  • expression Char
    required=True string='Expression'
  • name Char
    required=True size=32 string='Name'
  • prefix Char
    size=16 string='Prefix'
  • report_id Many2one → mis.report
    ondelete='cascade' string='Report' args: 'mis.report'
  • sequence Integer
    default=100 string='Sequence'
  • suffix Char
    size=16 string='Suffix'
  • type Selection
    default='num' required=True string='Type' args: [('num', _('Numeric')), ('pct', _('Percentage')), ('str', _('String'))]
Public methods (2)
  • render(self, lang_id, value)
    render a KPI value as a unicode string, ready for display
  • render_comparison(self, lang_id, value, base_value, average_value, average_base_value)
    render the comparison of two KPI values, ready for display If the difference is 0, an empty string is returned.

New fields (8)
  • aggregate Selection
    string='Aggregate' args: [('sum', _('Sum')), ('avg', _('Average')), ('min', _('Min')), ('max', _('Max'))]
  • date_field Many2one → ir.model.fields
    domain=[('ttype', 'in', ('date', 'datetime'))] required=True string='Date field' args: 'ir.model.fields'
  • domain Char
    string='Domain'
  • field_ids Many2many → ir.model.fields
    required=True string='Fields to fetch' args: 'ir.model.fields'
  • field_names Char
    compute='_compute_field_names' string='Fetched fields name'
  • model_id Many2one → ir.model
    required=True string='Model' args: 'ir.model'
  • name Char
    required=True size=32 string='Name'
  • report_id Many2one → mis.report
    ondelete='cascade' string='Report' args: 'mis.report'
Public methods (0)

No public methods.

New fields (0)

No new fields.

Public methods (2)
  • get_pdf(self, cr, uid, ids, report_name, html=None, data=None, context=None)
    @api.v7
  • get_pdf(self, docids, report_name, html=None, data=None)
    @api.v8

New fields (0)

No new fields.

Public methods (1)
  • render_html(self, data=None)
    @api.multi
REPOSITORY
REPOSITORYOCA/mis-builder
GIT
GIThttps://github.com/OCA/mis-builder.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/mis-builder/tree/7.0/mis_builder
VERSION
VERSION 0.2
CATEGORY
CATEGORYReporting
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONYes
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), ACSONE SA/NV
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), ACSONE SA/NV
COMMITTERS
COMMITTERSStéphane Bidoul, Laetitia Gangloff, OCA Transbot, Laurent Mignon
WEBSITE
WEBSITEhttp://acsone.eu
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 00:07:16
ODOO DEPENDENCIES
ODOO DEPENDENCIES OCA/reporting-engine:
    - report_xls
odoo/odoo:
    - account
    - base_setup
    - base
    - web_kanban
    - web
    - product
    - process
    - decimal_precision
    - mail
    - analytic
    - board
    - edi
    - email_template
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES xlwt
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
    :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
    :alt: License: AGPL-3
===========
MIS Builder
===========

This module allows you to build Management Information Systems dashboards.
Such style of reports presents KPI in rows and time periods in columns.
Reports mainly fetch data from account moves, but can also combine data coming
from arbitrary Odoo models. Reports can be exported to PDF, Excel and they
can be added to Odoo dashboards.

Installation
============

There is no specific installation procedure for this module.

Configuration and Usage
=======================

To configure this module, you need to:

* Go to Accounting > Configuration > Financial Reports > MIS Report Templates
where you can create report templates by defining KPI's. KPI's constitute
the rows of your reports. Such report templates are time independent.

* Then in Accounting > Reporting > MIS Reports you can create report instance
by binding the templates to time period, hence defining the columns of your
reports.

* From the MIS Report view, you can preview the report, add it to and Odoo
dashboard, and export it to Excel.

Developer notes
===============

A typical extension is to provide a mechanism to filter reports on analytic
dimensions or operational units. To implement this, you can override
_get_additional_move_line_filter and _get_additional_filter to further
filter move lines or queries based on a user selection. A typical use case
could be to add an analytic account field on mis.report.instance, or even
on mis.report.instance.period if you want different columns to show different
analytic accounts.

Known issues / Roadmap
======================

* Add 'Fiscal Year' period type.

* Allow selecting accounts by type. This is currently possible by expressing
  a query such as balp[][('account_id.user_type.code', '=', ...)].
  This will work but would be more efficient if one could write balp[
  user_type=...], as it would involve much less queries to the database.

* More tests should be added. The first part is creating test data, then it
will be easier. At the minimum, We need the following test data:

  * one account charts with a few normal accounts and view accounts,
  * two fiscal years,
  * an opening entry in the second fiscal year,
  * to test multi-company consolidation, we need a second company with it's own
    account chart and two fiscal years, but without opening entry; we also need
    a third company which is the parent of the other two and has a
    consolidation chart of account.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues
<https://github.com/OCA/account-financial-reporting/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and
welcomed feedback `here <https://github.com/OCA/account-financial-reporting
/issues/new?body=module:%20mis_builder%0Aversion:%208.0%0A%0A**Steps%20to%20
reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior
**>`_.

Credits
=======

Contributors
------------

* Stéphane Bidoul <stephane.bidoul@acsone.eu>
* Laetitia Gangloff <laetitia.gangloff@acsone.eu>
* Adrien Peiffer <adrien.peiffer@acsone.eu>
* Jordi Ballester <jordi.ballester@eficent.com>

Maintainer
----------

.. image:: https://odoo-community.org/logo.png
   :alt: Odoo Community Association
   :target: https://odoo-community.org

This module is maintained by the OCA.

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

To contribute to this module, please visit http://odoo-community.org.
    

Code Analysis

Views touched (6)
XML IDNameModelTypeStatus
mis_report_instance_add_to_dashboard_form_view add.mis.report.instance.dashboard.wizard.view add.mis.report.instance.dashboard.wizard form New
mis_report_instance_result_view_form mis.report.instance.result.view.form mis.report.instance form New
mis_report_instance_view_form mis.report.instance.view.form mis.report.instance form New
mis_report_instance_view_tree mis.report.instance.view.tree mis.report.instance tree New
mis_report_view_form mis.report.view.form mis.report form New
mis_report_view_tree mis.report.view.tree mis.report tree New
Models touched (6)

New fields (0)

No new fields.

Public methods (2)
  • action_add_to_dashboard(self, cr, uid, ids, context=None)
  • default_get(self, cr, uid, fields, context=None)

New fields (0)

No new fields.

Public methods (2)
  • create(self, cr, uid, vals, context=None)
  • write(self, cr, uid, ids, vals, context=None)

New fields (0)

No new fields.

Public methods (4)
  • compute(self, cr, uid, _id, context=None)
  • create(self, cr, uid, vals, context=None)
  • preview(self, cr, uid, ids, context=None)
  • write(self, cr, uid, ids, vals, context=None)

New fields (0)

No new fields.

Public methods (1)
  • drilldown(self, cr, uid, _id, expr, context=None)

New fields (0)

No new fields.

Public methods (4)
  • onchange_description(self, cr, uid, ids, description, name, context=None)
    construct name from description
  • onchange_name(self, cr, uid, ids, name, context=None)
  • onchange_type(self, cr, uid, ids, kpi_type, context=None)
  • render(self, cr, uid, lang_id, kpi, value, context=None)

New fields (0)

No new fields.

Public methods (1)
  • onchange_field_ids(self, cr, uid, ids, field_ids, context=None)