Automation Oca

automation_oca
REPOSITORY
REPOSITORYOCA/automation
GIT
GIThttps://github.com/OCA/automation.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/automation/tree/18.0/automation_oca
VERSION
VERSION 1.0.4
CATEGORY
CATEGORYAutomation
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), Dixmit
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), Dixmit
COMMITTERS
COMMITTERSEnric Tobella, Víctor Martínez, Mathieu Benoit, Weblate, OCA-git-bot, oca-ci, pilarvargas-tecnativa
WEBSITE
WEBSITEhttps://github.com/OCA/automation
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 19:30:18
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - mail
    - base
    - base_setup
    - web
    - bus
    - web_tour
    - html_editor
    - link_tracker
    - utm
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
This module allows to automate several process according to some rules.

This is useful for creating automated actions on your database like:

- Send a welcome email to all new partners (or filtered according to some rules)
- Remember to online customers that they forgot their basket with some items
- Send documents to sign to all new employees

Code Analysis

Views touched (25)
XML IDNameModelTypeStatus
automation_configuration_export_form_view automation.configuration.export form New
automation_configuration_form_view automation.configuration form New
automation_configuration_kanban_view automation.configuration kanban New
automation_configuration_search_view automation.configuration search New
automation_configuration_step_form_view automation.configuration.step form New
automation_configuration_step_search_view automation.configuration.step search New
automation_configuration_step_tree_view automation.configuration.step list New
automation_configuration_test_form_view automation.configuration.test form New
automation_configuration_tree_view automation.configuration list New
automation_filter_form_view automation.filter form New
automation_filter_search_view automation.filter search New
automation_filter_tree_view automation.filter list New
automation_record_form_view automation.record form New
automation_record_graph_view automation.record.graph automation.record graph New
automation_record_pivot_view automation.record.pivot automation.record pivot New
automation_record_search_view automation.record search New
automation_record_step_form_view automation.record.step form New
automation_record_step_graph_view automation.record.step.graph automation.record.step graph New
automation_record_step_pivot_view automation.record.step.pivot automation.record.step pivot New
automation_record_step_search_view automation.record.step.search automation.record.step search New
automation_record_step_tree_view automation.record.step list New
automation_record_tree_view automation.record list New
automation_tag_search_view automation.tag search New
automation_tag_tree_view automation.tag list New
link_tracker_click_search_view link.tracker.click.view.search.inherit.mass_mailing link.tracker.click xpath Inherits link_tracker.link_tracker_click_view_search
Models touched (13)

New fields (23)
  • active Boolean
    default=True
  • activity_action_count Integer
    compute='_compute_activity_count'
  • activity_mail_count Integer
    compute='_compute_activity_count'
  • automation_direct_step_ids One2many → automation.configuration.step
    domain=[('parent_id', '=', False)] inverse_name='configuration_id' args: 'automation.configuration.step'
  • automation_step_ids One2many → automation.configuration.step
    inverse_name='configuration_id' args: 'automation.configuration.step'
  • click_count Integer
    compute='_compute_click_count'
  • company_id Many2one → res.company
    args: 'res.company'
  • domain Char
    compute='_compute_domain' default='[]' help='\n Filter to apply\n Following special variable can be used in filter :\n * datetime\n * dateutil\n * time\n * user\n * ref ' required=True
  • editable_domain Char
    default='[]' help='Filter to apply\n Following special variable can be used in filter :\n * datetime\n * dateutil\n * time\n * user\n * ref ' required=True
  • field_id Many2one → ir.model.fields
    domain="[('model_id', '=', model_id), ('ttype', 'in', ['char', 'selection', 'integer', 'text', 'many2one'])]" help='Used to avoid duplicates' args: 'ir.model.fields'
  • filter_domain Binary
    compute='_compute_filter_domain'
  • filter_id Many2one → automation.filter
    args: 'automation.filter'
  • is_periodic Boolean
    help='Mark it if you want to make the execution periodic'
  • model Char
    related='model_id.model' string='Model'
  • model_id Many2one → ir.model
    domain=[('is_mail_thread', '=', True)] help='Model where the configuration is applied' ondelete='cascade' required=True string='Model ID' args: 'ir.model'
  • name Char
    required=True
  • next_execution_date Datetime
    compute='_compute_next_execution_date'
  • record_count Integer
    compute='_compute_record_count'
  • record_done_count Integer
    compute='_compute_record_count'
  • record_run_count Integer
    compute='_compute_record_count'
  • record_test_count Integer
    compute='_compute_record_test_count'
  • state Selection
    default='draft' group_expand='_group_expand_states' required=True args: [('draft', 'Draft'), ('periodic', 'Periodic'), ('ondemand', 'On demand'), ('done', 'Done')]
  • tag_ids Many2many → automation.tag
    args: 'automation.tag'
Public methods (8)
  • back_to_draft(self)
  • create_document_from_attachment(self, b64_data)
  • cron_automation(self)
  • done_automation(self)
  • export_configuration(self)
    Export the configuration to a JSON format. This method is used to export the configuration for external use.
  • run_automation(self)
  • save_filter(self)
  • start_automation(self)

New fields (3)
  • configuration_id Many2one → automation.configuration
    comodel_name='automation.configuration' required=True
  • file_content Binary
    readonly=True
  • file_name Char
Public methods (0)

No public methods.

New fields (43)
  • activity_date_deadline_range Integer
    compute='_compute_activity_info' readonly=False store=True string='Due Date In'
  • activity_date_deadline_range_type Selection
    compute='_compute_activity_info' default='days' readonly=False store=True string='Due type' args: [('days', 'Day(s)'), ('weeks', 'Week(s)'), ('months', 'Month(s)')]
  • activity_note Html
    compute='_compute_activity_info' readonly=False store=True args: 'Note'
  • activity_summary Char
    compute='_compute_activity_info' readonly=False store=True args: 'Summary'
  • activity_type_id Many2one → mail.activity.type
    compute='_compute_activity_info' domain="['|', ('res_model', '=', False), ('res_model', '=', model)]" ondelete='restrict' readonly=False store=True string='Activity' args: 'mail.activity.type'
  • activity_user_field_id Many2one → ir.model.fields
    compute='_compute_activity_info' readonly=False store=True args: 'ir.model.fields', 'User field name'
  • activity_user_id Many2one → res.users
    compute='_compute_activity_info' readonly=False store=True string='Responsible' args: 'res.users'
  • activity_user_type Selection
    compute='_compute_activity_info' help="Use 'Specific User' to always assign the same user on the next activity.\n Use 'Generic User From Record' to specify the field name of the user\n to choose on the record." readonly=False store=True args: [('specific', 'Specific User'), ('generic', 'Generic User From Record')]
  • activity_verification_domain Char
    default='[]' help='Filter to verify when the activity is done' required=True
  • activity_verification_domain_error Text
    help='Message to show when the activity domain is not as expected' translate=True
  • allow_expiry Boolean
    compute='_compute_allow_expiry'
  • applied_domain Char
    compute='_compute_applied_domain' recursive=True
  • apply_parent_domain Boolean
    default=True
  • child_ids One2many → automation.configuration.step
    inverse_name='parent_id' args: 'automation.configuration.step'
  • configuration_id Many2one → automation.configuration
    auto_join=True required=True args: 'automation.configuration'
  • domain Char
    default='[]' help='Filter to apply specifically' required=True
  • expiry Boolean
    compute='_compute_expiry' readonly=False store=True
  • expiry_interval Integer
  • expiry_interval_type Selection
    default='hours' required=True args: [('hours', 'Hour(s)'), ('days', 'Day(s)')]
  • graph_data Json
    compute='_compute_graph_data'
  • graph_done Integer
    compute='_compute_total_graph_data'
  • graph_error Integer
    compute='_compute_total_graph_data'
  • mail_author_id Many2one → res.partner
    default=<expr> required=True args: 'res.partner'
  • mail_template_id Many2one → mail.template
    domain="[('model_id', '=', model_id)]" args: 'mail.template'
  • model Char
    related='model_id.model' string='Model'
  • model_id Many2one
    related='configuration_id.model_id' string='Model ID'
  • name Char
    required=True
  • parent_id Many2one → automation.configuration.step
    ondelete='cascade' args: 'automation.configuration.step'
  • parent_position Integer
    compute='_compute_parent_position' recursive=True store=True
  • server_action_id Many2one → ir.actions.server
    domain="[('model_id', '=', model_id)]" args: 'ir.actions.server'
  • server_context Text
    default='{}'
  • step_icon Char
    compute='_compute_step_info'
  • step_name Char
    compute='_compute_step_info'
  • step_type Selection
    default='mail' required=True args: [('mail', 'Mail'), ('action', 'Server Action'), ('activity', 'Activity')]
  • trigger_child_types Json
    compute='_compute_trigger_child_types'
  • trigger_date_field Char
    related='trigger_date_field_id.field_description'
  • trigger_date_field_id Many2one → ir.model.fields
    domain="[('model_id', '=', model_id), ('ttype', 'in', ['date', 'datetime'])]" args: 'ir.model.fields'
  • trigger_date_kind Selection
    default='offset' required=True args: [('offset', 'Offset'), ('date', 'Force on Record Date')]
  • trigger_interval Integer
    help='Set a negative time trigger if you want the step to be executed\n immediately, in parallel with the previous step, without waiting for it to\n finish.'
  • trigger_interval_hours Integer
    compute='_compute_trigger_interval_hours' store=True
  • trigger_interval_type Selection
    default='hours' required=True args: [('hours', 'Hour(s)'), ('days', 'Day(s)')]
  • trigger_type Selection
    default='start' required=True selection='_trigger_type_selection'
  • trigger_type_data Json
    compute='_compute_trigger_type_data'
Public methods (0)

No public methods.

New fields (3)
  • configuration_id Many2one → automation.configuration
    required=True args: 'automation.configuration'
  • model Char
    related='configuration_id.model'
  • resource_ref Reference
    compute='_compute_resource_ref' readonly=False required=True selection='_selection_target_model' store=True
Public methods (1)
  • test_record(self)

New fields (4)
  • domain Char
    default='[]' help='Filter to apply' required=True
  • model Char
    related='model_id.model' string='Model'
  • model_id Many2one → ir.model
    domain=[('is_mail_thread', '=', True)] help='Model where the configuration is applied' ondelete='cascade' required=True string='Model ID' args: 'ir.model'
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (9)
  • automation_step_ids One2many → automation.record.step
    inverse_name='record_id' readonly=True args: 'automation.record.step'
  • configuration_id Many2one → automation.configuration
    readonly=True required=True args: 'automation.configuration'
  • is_orphan_record Boolean
    default=False help='Indicates if this record is a placeholder for a missing resource.' readonly=True
  • is_test Boolean
  • model Char
    index=True readonly=True required=False
  • name Char
    compute='_compute_name'
  • res_id Many2oneReference
    copy=False index=True model_field='model' readonly=True required=False string='Record'
  • resource_ref Reference
    compute='_compute_resource_ref' readonly=True selection='_selection_target_model'
  • state Selection
    compute='_compute_state' store=True args: [('run', 'Running'), ('done', 'Done')]
Public methods (3)
  • check_access(self, operation)
    In order to check if we can access a record, we are checking if we can access the related document
  • read(self, fields=None, load='_classic_read')
    Override to explicitely call check_access_rule, that is not called by the ORM. It instead directly fetches ir.rules and apply them.
  • write(self, vals)

New fields (27)
  • activity_cancel_on Datetime
    readonly=True
  • activity_done_on Datetime
    readonly=True
  • child_ids One2many → automation.record.step
    inverse_name='parent_id' args: 'automation.record.step'
  • configuration_id Many2one → automation.configuration
    compute='_compute_step_data' store=True args: 'automation.configuration'
  • configuration_step_id Many2one → automation.configuration.step
    args: 'automation.configuration.step'
  • do_not_wait Boolean
  • error_trace Text
    readonly=True
  • expiry_date Datetime
    readonly=True
  • is_test Boolean
    related='record_id.is_test' store=True
  • mail_clicked_on Datetime
    readonly=True
  • mail_opened_on Datetime
    readonly=True
  • mail_replied_on Datetime
    readonly=True
  • mail_status Selection
    readonly=True args: [('sent', 'Sent'), ('open', 'Opened'), ('bounce', 'Bounced'), ('reply', 'Replied')]
  • message_id Char
    readonly=True
  • name Char
    compute='_compute_step_data' store=True
  • parent_id Many2one → automation.record.step
    readonly=True args: 'automation.record.step'
  • parent_position Integer
    compute='_compute_parent_position' recursive=True store=True
  • processed_on Datetime
    readonly=True
  • record_id Many2one → automation.record
    ondelete='cascade' required=True args: 'automation.record'
  • scheduled_date Datetime
    readonly=True
  • state Selection
    default='scheduled' readonly=True args: [('scheduled', 'Scheduled'), ('done', 'Done'), ('expired', 'Expired'), ('rejected', 'Rejected'), ('error', 'Error'), ('cancel', 'Cancelled')]
  • step_actions Json
    compute='_compute_step_actions'
  • step_icon Char
    compute='_compute_step_info'
  • step_name Char
    compute='_compute_step_info'
  • step_type Selection
    compute='_compute_step_data' selection=<expr> store=True
  • trigger_type Selection
    compute='_compute_step_data' selection=<expr> store=True
  • trigger_type_data Json
    compute='_compute_trigger_type_data'
Public methods (3)
  • cancel(self)
  • retry(self)
    Retry the record step
  • run(self, trigger_activity=True)

New fields (3)
  • active Boolean
    default=True
  • color Integer
    default=<expr>
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (3)
  • automation_configuration_id Many2one
    related='automation_record_step_id.configuration_id' store=True
  • automation_configuration_step_id Many2one
    related='automation_record_step_id.configuration_step_id' store=True
  • automation_record_step_id Many2one → automation.record.step
    args: 'automation.record.step'
Public methods (1)
  • add_click(self, code, automation_record_step_id=False, **route_values)
    @api.model

New fields (1)
  • automation_record_step_id Many2one → automation.record.step
    args: 'automation.record.step'
Public methods (1)
  • unlink(self)

New fields (1)
  • automation_record_step_id Many2one → automation.record.step
    args: 'automation.record.step'
Public methods (0)

No public methods.

New fields (1)
  • automation_record_step_id Many2one → automation.record.step
    args: 'automation.record.step'
Public methods (1)
  • create(self, values_list)
    @api.model_create_multi

New fields (0)

No new fields.

Public methods (1)
  • get_automation_access(self, doc_ids, operation, model_name=False)
    @api.model
    Retrieve access policy. The behavior is similar to `mail.thread` and `mail.message` and it relies on the access rules defines on the related record. The behavior can be customized on the related model by defining `_automation_record_access`. By default `write`, otherwise the custom permission is returned.
REPOSITORY
REPOSITORYOCA/automation
GIT
GIThttps://github.com/OCA/automation.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/automation/tree/17.0/automation_oca
VERSION
VERSION 1.1.0
CATEGORY
CATEGORYAutomation
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), Dixmit
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), Dixmit
COMMITTERS
COMMITTERSPedro M. Baeza, Enric Tobella, Weblate, OCA-git-bot, oca-ci
WEBSITE
WEBSITEhttps://github.com/OCA/automation
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 19:20:10
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - mail
    - base
    - base_setup
    - web
    - bus
    - web_tour
    - link_tracker
    - utm
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
This module allows to automate several process according to some rules.

This is useful for creating automated actions on your database like:

- Send a welcome email to all new partners (or filtered according to some rules)
- Remember to online customers that they forgot their basket with some items
- Send documents to sign to all new employees

Code Analysis

Views touched (24)
XML IDNameModelTypeStatus
automation_configuration_form_view automation.configuration form New
automation_configuration_kanban_view automation.configuration kanban New
automation_configuration_search_view automation.configuration search New
automation_configuration_step_form_view automation.configuration.step form New
automation_configuration_step_search_view automation.configuration.step search New
automation_configuration_step_tree_view automation.configuration.step tree New
automation_configuration_test_form_view automation.configuration.test form New
automation_configuration_tree_view automation.configuration tree New
automation_filter_form_view automation.filter form New
automation_filter_search_view automation.filter search New
automation_filter_tree_view automation.filter tree New
automation_record_form_view automation.record form New
automation_record_graph_view automation.record.graph automation.record graph New
automation_record_pivot_view automation.record.pivot automation.record pivot New
automation_record_search_view automation.record search New
automation_record_step_form_view automation.record.step form New
automation_record_step_graph_view automation.record.step.graph automation.record.step graph New
automation_record_step_pivot_view automation.record.step.pivot automation.record.step pivot New
automation_record_step_search_view automation.record.step.search automation.record.step search New
automation_record_step_tree_view automation.record.step tree New
automation_record_tree_view automation.record tree New
automation_tag_search_view automation.tag search New
automation_tag_tree_view automation.tag tree New
link_tracker_click_search_view link.tracker.click.view.search.inherit.mass_mailing link.tracker.click xpath Inherits link_tracker.link_tracker_click_view_search
Models touched (12)

New fields (23)
  • active Boolean
    default=True
  • activity_action_count Integer
    compute='_compute_activity_count'
  • activity_mail_count Integer
    compute='_compute_activity_count'
  • automation_direct_step_ids One2many → automation.configuration.step
    domain=[('parent_id', '=', False)] inverse_name='configuration_id' args: 'automation.configuration.step'
  • automation_step_ids One2many → automation.configuration.step
    inverse_name='configuration_id' args: 'automation.configuration.step'
  • click_count Integer
    compute='_compute_click_count'
  • company_id Many2one → res.company
    args: 'res.company'
  • domain Char
    compute='_compute_domain' default='[]' help='\n Filter to apply\n Following special variable can be used in filter :\n * datetime\n * dateutil\n * time\n * user\n * ref ' required=True
  • editable_domain Char
    default='[]' help='Filter to apply\n Following special variable can be used in filter :\n * datetime\n * dateutil\n * time\n * user\n * ref ' required=True
  • field_id Many2one → ir.model.fields
    domain="[('model_id', '=', model_id), ('ttype', 'in', ['char', 'selection', 'integer', 'text', 'many2one'])]" help='Used to avoid duplicates' args: 'ir.model.fields'
  • filter_domain Binary
    compute='_compute_filter_domain'
  • filter_id Many2one → automation.filter
    args: 'automation.filter'
  • is_periodic Boolean
    help='Mark it if you want to make the execution periodic'
  • model Char
    related='model_id.model' string='Model'
  • model_id Many2one → ir.model
    domain=[('is_mail_thread', '=', True)] help='Model where the configuration is applied' ondelete='cascade' required=True string='Model ID' args: 'ir.model'
  • name Char
    required=True
  • next_execution_date Datetime
    compute='_compute_next_execution_date'
  • record_count Integer
    compute='_compute_record_count'
  • record_done_count Integer
    compute='_compute_record_count'
  • record_run_count Integer
    compute='_compute_record_count'
  • record_test_count Integer
    compute='_compute_record_test_count'
  • state Selection
    default='draft' group_expand='_group_expand_states' required=True args: [('draft', 'Draft'), ('periodic', 'Periodic'), ('ondemand', 'On demand'), ('done', 'Done')]
  • tag_ids Many2many → automation.tag
    args: 'automation.tag'
Public methods (6)
  • back_to_draft(self)
  • cron_automation(self)
  • done_automation(self)
  • run_automation(self)
  • save_filter(self)
  • start_automation(self)

New fields (43)
  • activity_date_deadline_range Integer
    compute='_compute_activity_info' readonly=False store=True string='Due Date In'
  • activity_date_deadline_range_type Selection
    compute='_compute_activity_info' default='days' readonly=False store=True string='Due type' args: [('days', 'Day(s)'), ('weeks', 'Week(s)'), ('months', 'Month(s)')]
  • activity_note Html
    compute='_compute_activity_info' readonly=False store=True args: 'Note'
  • activity_summary Char
    compute='_compute_activity_info' readonly=False store=True args: 'Summary'
  • activity_type_id Many2one → mail.activity.type
    compute='_compute_activity_info' domain="['|', ('res_model', '=', False), ('res_model', '=', model)]" ondelete='restrict' readonly=False store=True string='Activity' args: 'mail.activity.type'
  • activity_user_field_id Many2one → ir.model.fields
    compute='_compute_activity_info' readonly=False store=True args: 'ir.model.fields', 'User field name'
  • activity_user_id Many2one → res.users
    compute='_compute_activity_info' readonly=False store=True string='Responsible' args: 'res.users'
  • activity_user_type Selection
    compute='_compute_activity_info' help="Use 'Specific User' to always assign the same user on the next activity.\n Use 'Generic User From Record' to specify the field name of the user\n to choose on the record." readonly=False store=True args: [('specific', 'Specific User'), ('generic', 'Generic User From Record')]
  • activity_verification_domain Char
    default='[]' help='Filter to verify when the activity is done' required=True
  • activity_verification_domain_error Text
    help='Message to show when the activity domain is not as expected' translate=True
  • allow_expiry Boolean
    compute='_compute_allow_expiry'
  • applied_domain Char
    compute='_compute_applied_domain' recursive=True
  • apply_parent_domain Boolean
    default=True
  • child_ids One2many → automation.configuration.step
    inverse_name='parent_id' args: 'automation.configuration.step'
  • configuration_id Many2one → automation.configuration
    auto_join=True required=True args: 'automation.configuration'
  • domain Char
    default='[]' help='Filter to apply specifically' required=True
  • expiry Boolean
    compute='_compute_expiry' readonly=False store=True
  • expiry_interval Integer
  • expiry_interval_type Selection
    default='hours' required=True args: [('hours', 'Hour(s)'), ('days', 'Day(s)')]
  • graph_data Json
    compute='_compute_graph_data'
  • graph_done Integer
    compute='_compute_total_graph_data'
  • graph_error Integer
    compute='_compute_total_graph_data'
  • mail_author_id Many2one → res.partner
    default=<expr> required=True args: 'res.partner'
  • mail_template_id Many2one → mail.template
    domain="[('model_id', '=', model_id)]" args: 'mail.template'
  • model Char
    related='model_id.model' string='Model'
  • model_id Many2one
    related='configuration_id.model_id' string='Model ID'
  • name Char
    required=True
  • parent_id Many2one → automation.configuration.step
    ondelete='cascade' args: 'automation.configuration.step'
  • parent_position Integer
    compute='_compute_parent_position' recursive=True store=True
  • server_action_id Many2one → ir.actions.server
    domain="[('model_id', '=', model_id)]" args: 'ir.actions.server'
  • server_context Text
    default='{}'
  • step_icon Char
    compute='_compute_step_info'
  • step_name Char
    compute='_compute_step_info'
  • step_type Selection
    default='mail' required=True args: [('mail', 'Mail'), ('action', 'Server Action'), ('activity', 'Activity')]
  • trigger_child_types Json
    compute='_compute_trigger_child_types'
  • trigger_date_field Char
    related='trigger_date_field_id.field_description'
  • trigger_date_field_id Many2one → ir.model.fields
    domain="[('model_id', '=', model_id), ('ttype', 'in', ['date', 'datetime'])]" args: 'ir.model.fields'
  • trigger_date_kind Selection
    default='offset' required=True args: [('offset', 'Offset'), ('date', 'Force on Record Date')]
  • trigger_interval Integer
    help='Set a negative time trigger if you want the step to be executed\n immediately, in parallel with the previous step, without waiting for it to\n finish.'
  • trigger_interval_hours Integer
    compute='_compute_trigger_interval_hours' store=True
  • trigger_interval_type Selection
    default='hours' required=True args: [('hours', 'Hour(s)'), ('days', 'Day(s)')]
  • trigger_type Selection
    default='start' required=True selection='_trigger_type_selection'
  • trigger_type_data Json
    compute='_compute_trigger_type_data'
Public methods (0)

No public methods.

New fields (3)
  • configuration_id Many2one → automation.configuration
    required=True args: 'automation.configuration'
  • model Char
    related='configuration_id.model'
  • resource_ref Reference
    compute='_compute_resource_ref' readonly=False required=True selection='_selection_target_model' store=True
Public methods (1)
  • test_record(self)

New fields (4)
  • domain Char
    default='[]' help='Filter to apply' required=True
  • model Char
    related='model_id.model' string='Model'
  • model_id Many2one → ir.model
    domain=[('is_mail_thread', '=', True)] help='Model where the configuration is applied' ondelete='cascade' required=True string='Model ID' args: 'ir.model'
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (9)
  • automation_step_ids One2many → automation.record.step
    inverse_name='record_id' readonly=True args: 'automation.record.step'
  • configuration_id Many2one → automation.configuration
    readonly=True required=True args: 'automation.configuration'
  • is_orphan_record Boolean
    default=False help='Indicates if this record is a placeholder for a missing resource.' readonly=True
  • is_test Boolean
  • model Char
    index=True readonly=True required=False
  • name Char
    compute='_compute_name'
  • res_id Many2oneReference
    copy=False index=True model_field='model' readonly=True required=False string='Record'
  • resource_ref Reference
    compute='_compute_resource_ref' readonly=True selection='_selection_target_model'
  • state Selection
    compute='_compute_state' store=True args: [('run', 'Running'), ('done', 'Done')]
Public methods (3)
  • check_access_rule(self, operation)
    In order to check if we can access a record, we are checking if we can access the related document
  • read(self, fields=None, load='_classic_read')
    Override to explicitely call check_access_rule, that is not called by the ORM. It instead directly fetches ir.rules and apply them.
  • write(self, vals)

New fields (27)
  • activity_cancel_on Datetime
    readonly=True
  • activity_done_on Datetime
    readonly=True
  • child_ids One2many → automation.record.step
    inverse_name='parent_id' args: 'automation.record.step'
  • configuration_id Many2one → automation.configuration
    compute='_compute_step_data' store=True args: 'automation.configuration'
  • configuration_step_id Many2one → automation.configuration.step
    args: 'automation.configuration.step'
  • do_not_wait Boolean
  • error_trace Text
    readonly=True
  • expiry_date Datetime
    readonly=True
  • is_test Boolean
    related='record_id.is_test' store=True
  • mail_clicked_on Datetime
    readonly=True
  • mail_opened_on Datetime
    readonly=True
  • mail_replied_on Datetime
    readonly=True
  • mail_status Selection
    readonly=True args: [('sent', 'Sent'), ('open', 'Opened'), ('bounce', 'Bounced'), ('reply', 'Replied')]
  • message_id Char
    readonly=True
  • name Char
    compute='_compute_step_data' store=True
  • parent_id Many2one → automation.record.step
    readonly=True args: 'automation.record.step'
  • parent_position Integer
    compute='_compute_parent_position' recursive=True store=True
  • processed_on Datetime
    readonly=True
  • record_id Many2one → automation.record
    ondelete='cascade' required=True args: 'automation.record'
  • scheduled_date Datetime
    readonly=True
  • state Selection
    default='scheduled' readonly=True args: [('scheduled', 'Scheduled'), ('done', 'Done'), ('expired', 'Expired'), ('skipped', 'Skipped'), ('error', 'Error'), ('cancel', 'Cancelled')]
  • step_actions Json
    compute='_compute_step_actions'
  • step_icon Char
    compute='_compute_step_info'
  • step_name Char
    compute='_compute_step_info'
  • step_type Selection
    compute='_compute_step_data' selection=<expr> store=True
  • trigger_type Selection
    compute='_compute_step_data' selection=<expr> store=True
  • trigger_type_data Json
    compute='_compute_trigger_type_data'
Public methods (3)
  • cancel(self)
  • retry(self)
    Retry the record step
  • run(self, trigger_activity=True)

New fields (3)
  • active Boolean
    default=True
  • color Integer
    default=<expr>
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (3)
  • automation_configuration_id Many2one
    related='automation_record_step_id.configuration_id' store=True
  • automation_configuration_step_id Many2one
    related='automation_record_step_id.configuration_step_id' store=True
  • automation_record_step_id Many2one → automation.record.step
    args: 'automation.record.step'
Public methods (1)
  • add_click(self, code, automation_record_step_id=False, **route_values)
    @api.model

New fields (1)
  • automation_record_step_id Many2one → automation.record.step
    args: 'automation.record.step'
Public methods (1)
  • unlink(self)

New fields (1)
  • automation_record_step_id Many2one → automation.record.step
    args: 'automation.record.step'
Public methods (0)

No public methods.

New fields (1)
  • automation_record_step_id Many2one → automation.record.step
    args: 'automation.record.step'
Public methods (1)
  • create(self, values_list)
    @api.model_create_multi

New fields (0)

No new fields.

Public methods (1)
  • get_automation_access(self, doc_ids, operation, model_name=False)
    @api.model
    Retrieve access policy. The behavior is similar to `mail.thread` and `mail.message` and it relies on the access rules defines on the related record. The behavior can be customized on the related model by defining `_automation_record_access`. By default `write`, otherwise the custom permission is returned.
REPOSITORY
REPOSITORYOCA/automation
GIT
GIThttps://github.com/OCA/automation.git
GIT FOLDER
GIT FOLDERhttps://github.com/OCA/automation/tree/16.0/automation_oca
VERSION
VERSION 1.6.2
CATEGORY
CATEGORYAutomation
LICENSE
LICENSEAGPL-3
APPLICATION
APPLICATIONNo
AUTO-INSTALLABLE
AUTO-INSTALLABLENo
AUTHORS
AUTHORSOdoo Community Association (OCA), Dixmit
MAINTAINERS
MAINTAINERSOdoo Community Association (OCA), Dixmit
COMMITTERS
COMMITTERSEnric Tobella, Weblate, OCA-git-bot, oca-ci, Ariel Barreiros, gaelTorrecillas
WEBSITE
WEBSITEhttps://github.com/OCA/automation
LAST TRACKING UPDATE
LAST TRACKING UPDATE2026-07-06 19:12:06
ODOO DEPENDENCIES
ODOO DEPENDENCIES odoo/odoo:
    - mail
    - base
    - base_setup
    - web
    - bus
    - web_tour
    - link_tracker
    - utm
PYTHON DEPENDENCIES
PYTHON DEPENDENCIES Not have
SYSTEM DEPENDENCIES
SYSTEM DEPENDENCIES Not have
DESCRIPTION
DESCRIPTION
This module allows to automate several process according to some rules.

This is useful for creating automated actions on your database like:

- Send a welcome email to all new partners (or filtered according to some rules)
- Remember to online customers that they forgot their basket with some items
- Send documents to sign to all new employees

Code Analysis

Views touched (25)
XML IDNameModelTypeStatus
automation_configuration_export_form_view automation.configuration.export form New
automation_configuration_form_view automation.configuration form New
automation_configuration_kanban_view automation.configuration kanban New
automation_configuration_search_view automation.configuration search New
automation_configuration_step_form_view automation.configuration.step form New
automation_configuration_step_search_view automation.configuration.step search New
automation_configuration_step_tree_view automation.configuration.step tree New
automation_configuration_test_form_view automation.configuration.test form New
automation_configuration_tree_view automation.configuration tree New
automation_filter_form_view automation.filter form New
automation_filter_search_view automation.filter search New
automation_filter_tree_view automation.filter tree New
automation_record_form_view automation.record form New
automation_record_graph_view automation.record.graph automation.record graph New
automation_record_pivot_view automation.record.pivot automation.record pivot New
automation_record_search_view automation.record search New
automation_record_step_form_view automation.record.step form New
automation_record_step_graph_view automation.record.step.graph automation.record.step graph New
automation_record_step_pivot_view automation.record.step.pivot automation.record.step pivot New
automation_record_step_search_view automation.record.step.search automation.record.step search New
automation_record_step_tree_view automation.record.step tree New
automation_record_tree_view automation.record tree New
automation_tag_search_view automation.tag search New
automation_tag_tree_view automation.tag tree New
link_tracker_click_search_view link.tracker.click.view.search.inherit.mass_mailing link.tracker.click xpath Inherits link_tracker.link_tracker_click_view_search
Models touched (13)

New fields (23)
  • active Boolean
    default=True
  • activity_action_count Integer
    compute='_compute_activity_count'
  • activity_mail_count Integer
    compute='_compute_activity_count'
  • automation_direct_step_ids One2many → automation.configuration.step
    domain=[('parent_id', '=', False)] inverse_name='configuration_id' args: 'automation.configuration.step'
  • automation_step_ids One2many → automation.configuration.step
    inverse_name='configuration_id' args: 'automation.configuration.step'
  • click_count Integer
    compute='_compute_click_count'
  • company_id Many2one → res.company
    args: 'res.company'
  • domain Char
    compute='_compute_domain' default='[]' help='\n Filter to apply\n Following special variable can be used in filter :\n * datetime\n * dateutil\n * time\n * user\n * ref ' required=True
  • editable_domain Char
    default='[]' help='Filter to apply\n Following special variable can be used in filter :\n * datetime\n * dateutil\n * time\n * user\n * ref ' required=True
  • field_id Many2one → ir.model.fields
    domain="[('model_id', '=', model_id), ('ttype', 'in', ['char', 'selection', 'integer', 'text', 'many2one'])]" help='Used to avoid duplicates' args: 'ir.model.fields'
  • filter_domain Binary
    compute='_compute_filter_domain'
  • filter_id Many2one → automation.filter
    args: 'automation.filter'
  • is_periodic Boolean
    help='Mark it if you want to make the execution periodic'
  • model Char
    related='model_id.model'
  • model_id Many2one → ir.model
    domain=[('is_mail_thread', '=', True)] help='Model where the configuration is applied' ondelete='cascade' required=True args: 'ir.model'
  • name Char
    required=True
  • next_execution_date Datetime
    compute='_compute_next_execution_date'
  • record_count Integer
    compute='_compute_record_count'
  • record_done_count Integer
    compute='_compute_record_count'
  • record_run_count Integer
    compute='_compute_record_count'
  • record_test_count Integer
    compute='_compute_record_test_count'
  • state Selection
    default='draft' group_expand='_group_expand_states' required=True args: [('draft', 'Draft'), ('periodic', 'Periodic'), ('ondemand', 'On demand'), ('done', 'Done')]
  • tag_ids Many2many → automation.tag
    args: 'automation.tag'
Public methods (8)
  • back_to_draft(self)
  • create_document_from_attachment(self, b64_data)
  • cron_automation(self)
  • done_automation(self)
  • export_configuration(self)
    Export the configuration to a JSON format. This method is used to export the configuration for external use.
  • run_automation(self)
  • save_filter(self)
  • start_automation(self)

New fields (3)
  • configuration_id Many2one → automation.configuration
    comodel_name='automation.configuration' required=True
  • file_content Binary
    readonly=True
  • file_name Char
Public methods (0)

No public methods.

New fields (43)
  • activity_date_deadline_range Integer
    compute='_compute_activity_info' readonly=False store=True string='Due Date In'
  • activity_date_deadline_range_type Selection
    compute='_compute_activity_info' default='days' readonly=False store=True string='Due type' args: [('days', 'Day(s)'), ('weeks', 'Week(s)'), ('months', 'Month(s)')]
  • activity_note Html
    compute='_compute_activity_info' readonly=False store=True args: 'Note'
  • activity_summary Char
    compute='_compute_activity_info' readonly=False store=True args: 'Summary'
  • activity_type_id Many2one → mail.activity.type
    compute='_compute_activity_info' domain="['|', ('res_model', '=', False), ('res_model', '=', model)]" ondelete='restrict' readonly=False store=True string='Activity' args: 'mail.activity.type'
  • activity_user_field_id Many2one → ir.model.fields
    compute='_compute_activity_info' readonly=False store=True args: 'ir.model.fields', 'User field name'
  • activity_user_id Many2one → res.users
    compute='_compute_activity_info' readonly=False store=True string='Responsible' args: 'res.users'
  • activity_user_type Selection
    compute='_compute_activity_info' help="Use 'Specific User' to always assign the same user on the next activity.\n Use 'Generic User From Record' to specify the field name of the user\n to choose on the record." readonly=False store=True args: [('specific', 'Specific User'), ('generic', 'Generic User From Record')]
  • activity_verification_domain Char
    default='[]' help='Filter to verify when the activity is done' required=True
  • activity_verification_domain_error Text
    help='Message to show when the activity domain is not as expected' translate=True
  • allow_expiry Boolean
    compute='_compute_allow_expiry'
  • applied_domain Char
    compute='_compute_applied_domain' recursive=True
  • apply_parent_domain Boolean
    default=True
  • child_ids One2many → automation.configuration.step
    inverse_name='parent_id' args: 'automation.configuration.step'
  • configuration_id Many2one → automation.configuration
    auto_join=True required=True args: 'automation.configuration'
  • domain Char
    default='[]' help='Filter to apply specifically' required=True
  • expiry Boolean
    compute='_compute_expiry' readonly=False store=True
  • expiry_interval Integer
  • expiry_interval_type Selection
    default='hours' required=True args: [('hours', 'Hour(s)'), ('days', 'Day(s)')]
  • graph_data Json
    compute='_compute_graph_data'
  • graph_done Integer
    compute='_compute_total_graph_data'
  • graph_error Integer
    compute='_compute_total_graph_data'
  • mail_author_id Many2one → res.partner
    default=<expr> required=True args: 'res.partner'
  • mail_template_id Many2one → mail.template
    domain="[('model_id', '=', model_id)]" args: 'mail.template'
  • model Char
    related='model_id.model'
  • model_id Many2one
    related='configuration_id.model_id'
  • name Char
    required=True
  • parent_id Many2one → automation.configuration.step
    ondelete='cascade' args: 'automation.configuration.step'
  • parent_position Integer
    compute='_compute_parent_position' recursive=True store=True
  • server_action_id Many2one → ir.actions.server
    domain="[('model_id', '=', model_id)]" args: 'ir.actions.server'
  • server_context Text
    default='{}'
  • step_icon Char
    compute='_compute_step_info'
  • step_name Char
    compute='_compute_step_info'
  • step_type Selection
    default='mail' required=True args: [('mail', 'Mail'), ('action', 'Server Action'), ('activity', 'Activity')]
  • trigger_child_types Json
    compute='_compute_trigger_child_types'
  • trigger_date_field Char
    related='trigger_date_field_id.field_description'
  • trigger_date_field_id Many2one → ir.model.fields
    domain="[('model_id', '=', model_id), ('ttype', 'in', ['date', 'datetime'])]" args: 'ir.model.fields'
  • trigger_date_kind Selection
    default='offset' required=True args: [('offset', 'Offset'), ('date', 'Force on Record Date')]
  • trigger_interval Integer
    help='Set a negative time trigger if you want the step to be executed\n immediately, in parallel with the previous step, without waiting for it to\n finish.'
  • trigger_interval_hours Integer
    compute='_compute_trigger_interval_hours' store=True
  • trigger_interval_type Selection
    default='hours' required=True args: [('hours', 'Hour(s)'), ('days', 'Day(s)')]
  • trigger_type Selection
    default='start' required=True selection='_trigger_type_selection'
  • trigger_type_data Json
    compute='_compute_trigger_type_data'
Public methods (0)

No public methods.

New fields (3)
  • configuration_id Many2one → automation.configuration
    required=True args: 'automation.configuration'
  • model Char
    related='configuration_id.model'
  • resource_ref Reference
    compute='_compute_resource_ref' readonly=False required=True selection='_selection_target_model' store=True
Public methods (1)
  • test_record(self)

New fields (4)
  • domain Char
    default='[]' help='Filter to apply' required=True
  • model Char
    related='model_id.model'
  • model_id Many2one → ir.model
    domain=[('is_mail_thread', '=', True)] help='Model where the configuration is applied' ondelete='cascade' required=True args: 'ir.model'
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (9)
  • automation_step_ids One2many → automation.record.step
    inverse_name='record_id' readonly=True args: 'automation.record.step'
  • configuration_id Many2one → automation.configuration
    readonly=True required=True args: 'automation.configuration'
  • is_orphan_record Boolean
    default=False help='Indicates if this record is a placeholder for a missing resource.' readonly=True
  • is_test Boolean
  • model Char
    index=True readonly=True required=False
  • name Char
    compute='_compute_name'
  • res_id Many2oneReference
    copy=False index=True model_field='model' readonly=True required=False string='Record'
  • resource_ref Reference
    compute='_compute_resource_ref' readonly=True selection='_selection_target_model'
  • state Selection
    compute='_compute_state' store=True args: [('run', 'Running'), ('done', 'Done')]
Public methods (3)
  • check_access_rule(self, operation)
    In order to check if we can access a record, we are checking if we can access the related document
  • read(self, fields=None, load='_classic_read')
    Override to explicitely call check_access_rule, that is not called by the ORM. It instead directly fetches ir.rules and apply them.
  • write(self, vals)

New fields (27)
  • activity_cancel_on Datetime
    readonly=True
  • activity_done_on Datetime
    readonly=True
  • child_ids One2many → automation.record.step
    inverse_name='parent_id' args: 'automation.record.step'
  • configuration_id Many2one → automation.configuration
    compute='_compute_step_data' store=True args: 'automation.configuration'
  • configuration_step_id Many2one → automation.configuration.step
    args: 'automation.configuration.step'
  • do_not_wait Boolean
  • error_trace Text
    readonly=True
  • expiry_date Datetime
    readonly=True
  • is_test Boolean
    related='record_id.is_test' store=True
  • mail_clicked_on Datetime
    readonly=True
  • mail_opened_on Datetime
    readonly=True
  • mail_replied_on Datetime
    readonly=True
  • mail_status Selection
    readonly=True args: [('sent', 'Sent'), ('open', 'Opened'), ('bounce', 'Bounced'), ('reply', 'Replied')]
  • message_id Char
    readonly=True
  • name Char
    compute='_compute_step_data' store=True
  • parent_id Many2one → automation.record.step
    readonly=True args: 'automation.record.step'
  • parent_position Integer
    compute='_compute_parent_position' recursive=True store=True
  • processed_on Datetime
    readonly=True
  • record_id Many2one → automation.record
    ondelete='cascade' required=True args: 'automation.record'
  • scheduled_date Datetime
    readonly=True
  • state Selection
    default='scheduled' readonly=True args: [('scheduled', 'Scheduled'), ('done', 'Done'), ('expired', 'Expired'), ('rejected', 'Rejected'), ('error', 'Error'), ('cancel', 'Cancelled')]
  • step_actions Json
    compute='_compute_step_actions'
  • step_icon Char
    compute='_compute_step_info'
  • step_name Char
    compute='_compute_step_info'
  • step_type Selection
    compute='_compute_step_data' selection=<expr> store=True
  • trigger_type Selection
    compute='_compute_step_data' selection=<expr> store=True
  • trigger_type_data Json
    compute='_compute_trigger_type_data'
Public methods (3)
  • cancel(self)
  • retry(self)
    Retry the record step
  • run(self, trigger_activity=True)

New fields (3)
  • active Boolean
    default=True
  • color Integer
    default=<expr>
  • name Char
    required=True
Public methods (0)

No public methods.

New fields (3)
  • automation_configuration_id Many2one
    related='automation_record_step_id.configuration_id' store=True
  • automation_configuration_step_id Many2one
    related='automation_record_step_id.configuration_step_id' store=True
  • automation_record_step_id Many2one → automation.record.step
    args: 'automation.record.step'
Public methods (1)
  • add_click(self, code, automation_record_step_id=False, **route_values)
    @api.model

New fields (1)
  • automation_record_step_id Many2one → automation.record.step
    args: 'automation.record.step'
Public methods (1)
  • unlink(self)

New fields (1)
  • automation_record_step_id Many2one → automation.record.step
    args: 'automation.record.step'
Public methods (1)
  • get_mail_values(self, res_ids)

New fields (1)
  • automation_record_step_id Many2one → automation.record.step
    args: 'automation.record.step'
Public methods (1)
  • create(self, values_list)
    @api.model_create_multi

New fields (0)

No new fields.

Public methods (1)
  • get_automation_access(self, doc_ids, operation, model_name=False)
    @api.model
    Retrieve access policy. The behavior is similar to `mail.thread` and `mail.message` and it relies on the access rules defines on the related record. The behavior can be customized on the related model by defining `_automation_record_access`. By default `write`, otherwise the custom permission is returned.