Analytic Structure ================== What is it ? ------------ The module provides a way of defining dynamic relationships between objects. We use the following concepts: - Dimensions, represented by ``analytic.dimension`` - Structure, represented by ``analytic.structure`` - Codes, represented by ``analytic.code`` These objects can be seen in ``Technical >> Analytics`` under ``Settings``. Dimensions act as labels for data points that can be used to perform analyses. Structures define mappings between models and dimensions, they can be configured through the *Settings* menu. Codes are the objects that are bound to instances of dimension models, they allow us to define dynamic relationships. Example: Your company has several product lines and you would like to analyse expenses related to these product lines in your accounting system. You would then define a *product line* dimension and some structures that bind the *product line* dimension to ``product.product``, ``invoice.line``, ``account.move.line`` models. How does it work ? ------------------ Analytic Structure provides the ``MetaAnalytic`` metaclass (see MetaAnalytic_) that injects new behaviors into Odoo models. Dimension models and models that define analytic fields must use ``MetaAnalytic`` and define various class attributes. A dimension model is declared with the ``_dimension`` attribute (see AnalyticDimensions_). The metaclass automatically creates ``analytic.dimension`` records for each dimension model. Once a model is declared as a dimension, every new instance will automatically create a new ``analytic.code`` record that points to the relevant ``analytic.dimension`` record. A model that is declared with the ``_analytic`` attribute (see AnalyticFields_) can reference dimension objects. The ``MetaAnalytic`` will automatically create a number of M2O fields that point to analytic codes. The number of fields that will be added depends on the configuration (See ConfigureAnalyticFields_). They are named with a predefined prefix and a number or slot eg. ``a1_id``, ``a2_id``, ``a3_id``, ... These analytic fields will be displayed in views with the names of the dimensions they point to thanks to view manipulation magic. Schematic:: | AnalyticModel Code DimensionModel Dimension | ----- ---- -------------- --------- | an_id ----------> id,name <-- analytic_code_id | | n_id ---------------------> id,name The relationship between a model and a dimension is configured by *analytic structures*. Structure define how models point to dimensions and what analytic field to use. Example: You have a dimension ``D`` you wish to bind to model ``A``. You would create an ``analytic.structure`` record for ``A`` that references ``D`` through the ``Analysis 1`` slot. This would allow you to use the ``a1_id`` field (assuming the default prefix is used) to reference ``D`` records. Integrity of analytic codes --------------------------- You cannot delete analytic codes that are referenced by objects. The goal of this constraint is to ensure the integrity of your analyses. .. _ConfigureAnalyticFields: Configure your OpenERP server for analytic fields ------------------------------------------------- In your OpenERP server's configuration file, you can set several optional parameters related to the analytic module.:: [analytic] key = value ... Those options must be grouped under the [analytic] category. If the category doesn't exist, add it to your configuration file. key (default value): description analytic_size (5): define the maximum number of analytic dimensions that can be associated with a model. translate (False): enable or disable the translation of field values on analytic dimensions (name) and codes (name and description). .. _MetaAnalytic: Add the MetaAnalytic metaclass to a model ----------------------------------------- At the beginning of the source file, import the MetaAnalytic metaclass: from openerp.addons.analytic_structure.MetaAnalytic import MetaAnalytic Inside your Model class, define MetaAnalytic to be used as metaclass: .. code:: python __metaclass__ = MetaAnalytic .. _AnalyticFields: Add analytic fields to a model ------------------------------ First of all, make sure you are using the MetaAnalytic metaclass. Then, add the _analytic attribute to your class, using the following syntax. Use the analytic fields associated with the model: .. code:: python _analytic = True Use analytic fields associated with another model: .. code:: python _analytic = 'account_move_line' Use several analytic field structures, associated with different prefixes: .. code:: python _analytic = { 'a': 'account_asset_asset', 't': 'account_move_line', } Add analytic fields to a view ----------------------------- Analytic fields can be added to the view individually, like any other field: .. code:: xml <field name="a1_id" /> 'a' is the prefix associated with the structure. By default, it is 'a'. '1' is the dimension's ordering as defined by the analytic structure. You can also use a field named 'analytic_dimensions' to insert every analytic field within a given structure (defined by its prefix) that wasn't explicitly placed in the view. This field is automatically generated when you call the Metaclass .. code:: xml <field name="analytic_dimensions" required="1" prefix="t" /> The prefix can be omitted for a structure that uses the default prefix 'a'. Any other attribute will be propagated to the analytic fields. Warning: analytic fields should generally not be used inside nested sub-views. If possible, create a separate record and use the context to specify the view: .. code:: xml <field name="order_line" colspan="4" nolabel="1" context="{ 'form_view_ref' : 'module.view_id', 'tree_view_ref' : 'module.view_id' }"/> Advanced: Para-analytic fields ------------------------------ Para-analytic fields are a more advanced feature of analytic_structure. They differ from ordinary analytics fields in two ways: - They are entirely configurable, meaning that you decide their type and parameters - They don't have predefined behaviors Para-analytic fields are defined in with the ``_para_analytic`` attribute. For each entry in ``_para_analytic`` the ``MetaAnalytic`` metaclass will create a number fields. The number of fields depend on ``analytic_size`` in the configuration file (see ConfigureAnalyticFields_). Each entry is key-value pair of a dict where the key is a (prefix, suffix) tuple and the value a dict containing the following: ``model`` the name of the referenced dimension model (doesn't do anything special) ``type`` a field class, the field type to use ``default`` default value for the fields ``args`` list of arguments to inject in ``type`` constructor ``kwargs`` dict of keyword arguments to inject in ``type`` constructor. Here is declaration that will create fields with the names ``a1_b``, ``a2_b``, ``a3_b``, ... .. code:: python from openerp import fields # ... # Inside a class _para_analytic = { ('a', 'b'): { 'model': 'account_move_line', 'type': fields.Boolean, 'default': True, 'args': ("field is optional"), 'kwargs': dict(required=True), a,} } Validation hook for analytic fields ----------------------------------- Models that define the ``_analytic`` attribute can override the ``_validate_analytic_fields`` to perform validation on analytic fields. The method is called every time the model's ``create`` and ``write`` methods are called. Odoo 8.0 Method signature: .. code::python def validate_analytic_fields(self, analytic): where ``analytic`` is a dict containing in the same information given in the ``_analytic`` class attribute, in the expanded form. The method signals failure by raising an exception, just like methods decorated with ``api.constrains()``. .. _AnalyticDimensions: Bind an analytic dimension to a model ------------------------------------- First of all, make sure you are using the MetaAnalytic metaclass. Then, add the _dimension attribute to your class, using the following syntax. Bind the model to an analytic dimension named after the model, using default values: .. code:: python _dimension = True Bind the model to an analytic dimension with a specified name, using default values: .. code:: python _dimension = 'Funding Source' Bind the model to an analytic dimension, using either custom or default values: .. code:: python _dimension = { 'name': 'School', 'column': 'analytic_code_id', 'ref_id': 'school_analytic_dimension', 'ref_module': 'my_module', 'sync_parent': False, 'rel_description': True, 'rel_active': (u"Active", 'active_code'), 'use_inherits': False, 'use_code_name_methods': False, } key (default value): description ``name`` (= ``_description`` or ``_name``): The name of the analytic dimension. This name is only used when creating the dimension in the database. column (analytic_id): The field that links each record to an analytic code. ``ref_id`` (= ``_name`` + ``analytic_dimension_id``): The external ID that will be used by the analytic dimension. By setting this value, you can allow two models to use the same dimension, or a model to use an already existing one. ``ref_module`` (empty string): The name of the module associated with the dimension record. Change this value in order to use a dimension defined in a data file. ``sync_parent`` (``False``): Controls the synchronization of the codes' parent-child hierarchy with that of the model. When using an inherited, renamed parent field, you must give the parent field name rather than simply ``True``. ``use_inherits`` (special): Determines whether the analytic codes should be bound to the records by inheritance, or through a simple many2one field. Inheritance allows for better synchronization, but can only be used if there are no duplicate fields between the two objects. The default value is ``True`` if the model has no 'name' and 'code_parent_id' field as well as no inheritance of any kind, and ``False`` otherwise. If the object has inheritances that do not cause conflicts, you can set it to ``True``. ``rel_active`` (``False``): Create a related field in the model, targeting the analytic code field 'active' and with an appropriate store parameter. This is useful when the model doesn't inherit analytic_code and/or when it already has a field named 'active'. Can take a pair of string values: (field label, field name). If given a string, the default field name 'active' will be used. If given ``True``, the default field label 'Active' will also be used. ``rel_description`` (``False``): Same as rel_active for the code field 'description'. If given a string, the default field name 'description' will be used. If given ``True``, the default field label 'Description' will also be used. ``use_code_name_methods`` (``False``): Set to ``True`` in order to override the methods name_get and name_search, using those of analytic code. This allows the analytic code's description to be displayed (and searched) along with the entry's name in many2one fields targeting the model. Active / View type / Disabled in my company ------------------------------------------- Differences between the various "active" fields: - Active: Determines whether an analytic code is in the referential. - View type: Determines whether an analytic code is not selectable (but still in the referential). - Disabled per company: Determines whether an analytic code is disabled for the current company.