[MERGE] ir_actions, ir_cron, base_automation: refactor server, scheduled and automated actions
This commit simplifies server code execution by allowing only server actions to execute code. Scheduled actions (ir.cron) and automated actions (base.action.rule renamed to base.automation) now delegate all code execution to their own server action, using inheritance. Those models now contain only fields related to cron details for scheduled actions, or triggers and filters for automated actions. Server actions have been simplified. Main options stay the same but complex options in creation / update have been removed. Those should be done using code-based server actions. A server action type to add followers has been added. Views have been updated accordingly. Base form view of server action is used as a base for scheduled and automated action. Editing a cron or an automated action looks like editing a server action with some added fields. Thanks to @fpodoo for the original idea and preliminary work. Thanks to @jpr-odoo for first developments and @tivisse for improving and cleaning the work. Thanks to @jem-odoo and @rco-odoo for reviewing.
This commit is contained in:
+3
-3
@@ -107,9 +107,9 @@ file_filter = addons/barcodes/i18n/<lang>.po
|
||||
source_file = addons/barcodes/i18n/barcodes.pot
|
||||
source_lang = en
|
||||
|
||||
[odoo-master.base_action_rule]
|
||||
file_filter = addons/base_action_rule/i18n/<lang>.po
|
||||
source_file = addons/base_action_rule/i18n/base_action_rule.pot
|
||||
[odoo-master.base_automation]
|
||||
file_filter = addons/base_automation/i18n/<lang>.po
|
||||
source_file = addons/base_automation/i18n/base_automation.pot
|
||||
source_lang = en
|
||||
|
||||
[odoo-master.base_gengo]
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding='UTF-8'?>
|
||||
<odoo>
|
||||
<record model="ir.cron" id="account_asset_cron">
|
||||
<field name="name">Generate Asset Entries</field>
|
||||
<record id="account_asset_cron" model="ir.cron">
|
||||
<field name="name">Account Asset: Generate asset entries</field>
|
||||
<field name="model_id" ref="model_account_asset_asset"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model._cron_generate_entries()</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">months</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False"/>
|
||||
<field name="model" eval="'account.asset.asset'"/>
|
||||
<field name="function" eval="'_cron_generate_entries'"/>
|
||||
<field name="args" eval="'()'" />
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,52 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="test_filter_draft" model="ir.filters">
|
||||
<field name="name">Test lead in state 'draft'</field>
|
||||
<field name="model_id">base.action.rule.lead.test</field>
|
||||
<field name="domain">[('state', '=', 'draft')]</field>
|
||||
</record>
|
||||
|
||||
<record id="test_filter_open" model="ir.filters">
|
||||
<field name="name">Test lead in state 'open'</field>
|
||||
<field name="model_id">base.action.rule.lead.test</field>
|
||||
<field name="domain">[('state', '=', 'open')]</field>
|
||||
</record>
|
||||
|
||||
<record id="test_filter_done" model="ir.filters">
|
||||
<field name="name">Test lead in state 'done'</field>
|
||||
<field name="model_id">base.action.rule.lead.test</field>
|
||||
<field name="domain">[('state', '=', 'done')]</field>
|
||||
</record>
|
||||
|
||||
<record id="test_rule_on_create" model="base.action.rule">
|
||||
<field name="name">Test rule on create</field>
|
||||
<field name="kind">on_create</field>
|
||||
<field name="model_id" ref="base_action_rule.model_base_action_rule_lead_test"/>
|
||||
<field name="act_user_id" ref="base.user_demo"/>
|
||||
<field name="filter_id" ref="test_filter_draft"/>
|
||||
</record>
|
||||
|
||||
<record id="test_rule_on_write" model="base.action.rule">
|
||||
<field name="name">Test rule on write</field>
|
||||
<field name="kind">on_write</field>
|
||||
<field name="model_id" ref="base_action_rule.model_base_action_rule_lead_test"/>
|
||||
<field name="act_user_id" ref="base.user_demo"/>
|
||||
<field name="filter_pre_id" ref="test_filter_open"/>
|
||||
<field name="filter_id" ref="test_filter_done"/>
|
||||
</record>
|
||||
|
||||
<record id="test_rule_on_recompute" model="base.action.rule">
|
||||
<field name="name">Test rule on recompute</field>
|
||||
<field name="kind">on_write</field>
|
||||
<field name="model_id" ref="base_action_rule.model_base_action_rule_lead_test"/>
|
||||
<field name="act_user_id" ref="base.user_demo"/>
|
||||
<field name="filter_domain">[('customer', '=', True)]</field>
|
||||
</record>
|
||||
|
||||
<record id="test_rule_on_line" model="base.action.rule">
|
||||
<field name="name">Test rule on secondary record</field>
|
||||
<field name="kind">on_create</field>
|
||||
<field name="model_id" ref="base_action_rule.model_base_action_rule_line_test"/>
|
||||
<field name="act_user_id" ref="base.user_demo"/>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,5 +0,0 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_base_action_rule,base.action.rule,model_base_action_rule,,1,0,0,0
|
||||
access_base_action_rule_config,base.action.rule config,model_base_action_rule,base.group_system,1,1,1,1
|
||||
access_base_action_rule_lead_test,access_base_action_rule_lead_test,model_base_action_rule_lead_test,base.group_system,1,1,1,1
|
||||
access_base_action_rule_line_test,access_base_action_rule_line_test,model_base_action_rule_line_test,base.group_system,1,1,1,1
|
||||
|
@@ -1,138 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Action Rule Form View -->
|
||||
<record id="view_base_action_rule_form" model="ir.ui.view">
|
||||
<field name="name">base.action.rule.form</field>
|
||||
<field name="model">base.action.rule</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Action Rule">
|
||||
<sheet>
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
<h1><field name="name"/></h1>
|
||||
<group>
|
||||
<group>
|
||||
<field name="model_id"/>
|
||||
<field name="model" invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="active"/>
|
||||
<field name="sequence"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Conditions">
|
||||
<group attrs="{'invisible': [('model', '!=', False)]}">
|
||||
<p><b>Please choose the document type before setting the conditions.</b></p>
|
||||
</group>
|
||||
<group attrs="{'invisible': [('model', '=', False)]}">
|
||||
<field name="kind"/>
|
||||
<label for="filter_pre_id" attrs="{'invisible': [('kind', '!=', 'on_write')]}"/>
|
||||
<div attrs="{'invisible': [('kind', '!=', 'on_write')]}">
|
||||
<field name="filter_pre_domain" widget="domain" options="{'model': 'model'}"
|
||||
class="o_row"/>
|
||||
<div class="oe_edit_only o_row">Set selection based on a search filter:
|
||||
<field name="filter_pre_id" domain="[('model_id', '=', model), '|', ('user_id', '=', uid), ('user_id', '=', False)]"
|
||||
class="o_row" context="{'default_model_id': model, 'default_active': False, 'active_test': False}"/></div>
|
||||
</div>
|
||||
<label for="filter_id"/>
|
||||
<div>
|
||||
<field name="filter_domain" widget="domain" options="{'model': 'model'}"
|
||||
class="o_row"/>
|
||||
<div class="oe_edit_only o_row">Set selection based on a search filter:
|
||||
<field name="filter_id" domain="[('model_id', '=', model), '|', ('user_id', '=', uid), ('user_id', '=', False)]"
|
||||
class="o_row" context="{'default_model_id': model, 'default_active': False, 'active_test': False}"/>
|
||||
</div>
|
||||
</div>
|
||||
<field name="on_change_fields"
|
||||
attrs="{'invisible': [('kind', '!=', 'on_change')], 'required': [('kind', '=', 'on_change')]}"/>
|
||||
<field name="trg_date_id"
|
||||
attrs="{'invisible': [('kind', '!=', 'on_time')], 'required': [('kind', '=', 'on_time')]}"/>
|
||||
<label for="trg_date_range" string="Delay After Trigger Date"
|
||||
attrs="{'invisible': [('trg_date_id','=',False)]}"/>
|
||||
<div attrs="{'invisible': [('trg_date_id','=',False)]}">
|
||||
<field name="trg_date_range" class="o_row"/>
|
||||
<field name="trg_date_range_type" class="o_row" attrs="{'required': [('trg_date_id','!=',False)]}"/>
|
||||
</div>
|
||||
<field name="trg_date_calendar_id" class="o_row"
|
||||
attrs="{'invisible': ['|', ('trg_date_id','=',False), ('trg_date_range_type', '!=', 'day')]}"/>
|
||||
</group>
|
||||
<div attrs="{'invisible': [('model', '=', False)]}">
|
||||
<p>Select when the action must be run, and choose records and/or timing conditions.</p>
|
||||
<p groups="base.group_no_one">You may also use filters instead of choosing records. In order to create a new filter:</p>
|
||||
<ul groups="base.group_no_one">
|
||||
<li>Go to your "Related Document Model" page and set the filter parameters in the "Search" view (Example of filter based on Leads/Opportunities: Creation Date "is equal to" 01/01/2012)</li>
|
||||
<li>In this same "Search" view, select the menu "Save Current Filter", enter the name (Ex: Create the 01/01/2012) and add the option "Share with all users"</li>
|
||||
</ul>
|
||||
</div>
|
||||
</page>
|
||||
<page string="Actions">
|
||||
<group name="action_field" col="4" string="Fields to Change">
|
||||
<field name="act_user_id"/>
|
||||
<field name="act_followers" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group name="action_server" string="Server actions to run">
|
||||
<field name="server_action_ids" domain="[('model_id','=', model_id)]" nolabel="1" context="{'default_model_id': model_id}">
|
||||
<tree string="Server Actions">
|
||||
<field name="sequence"/>
|
||||
<field name="name"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action Rule Tree View -->
|
||||
<record id="view_base_action_rule_tree" model="ir.ui.view">
|
||||
<field name="name">base.action.rule.tree</field>
|
||||
<field name="model">base.action.rule</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Action Rule">
|
||||
<field name="sequence"/>
|
||||
<field name="name"/>
|
||||
<field name="kind"/>
|
||||
<field name="model_id"/>
|
||||
<field name="filter_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_base_action_rule_search" model="ir.ui.view">
|
||||
<field name="name">base.action.rule.search</field>
|
||||
<field name="model">base.action.rule</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="name"/>
|
||||
<field name="model_id"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action Rule Action -->
|
||||
<record id="base_action_rule_act" model="ir.actions.act_window">
|
||||
<field name="name">Automated Actions</field>
|
||||
<field name="res_model">base.action.rule</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_base_action_rule_tree"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to setup a new automated action rule.
|
||||
</p><p>
|
||||
Use automated actions to automatically trigger actions for
|
||||
various screens. Example: a lead created by a specific user may
|
||||
be automatically set to a specific sales channel, or an
|
||||
opportunity which still has status pending after 14 days might
|
||||
trigger an automatic reminder email.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_base_action_rule_form"
|
||||
parent="base.menu_automation" action="base_action_rule_act" sequence="1"/>
|
||||
|
||||
</odoo>
|
||||
@@ -18,10 +18,10 @@ trigger an automatic reminder email.
|
||||
'depends': ['base', 'resource', 'mail'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'data/base_action_rule_data.xml',
|
||||
'views/base_action_rule_view.xml',
|
||||
'data/base_automation_data.xml',
|
||||
'views/base_automation_view.xml',
|
||||
],
|
||||
'demo': [
|
||||
'data/base_action_rule_demo.xml',
|
||||
'data/base_automation_demo.xml',
|
||||
],
|
||||
}
|
||||
+5
-7
@@ -1,18 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="ir_cron_crm_action" model="ir.cron">
|
||||
<field name="name">Check Action Rules</field>
|
||||
<record id="ir_cron_data_base_automation_check" model="ir.cron">
|
||||
<field name="name">Base Action Rule: check and execute</field>
|
||||
<field name="model_id" ref="model_base_automation"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model._check(True)</field>
|
||||
<field name="interval_number">4</field>
|
||||
<field name="interval_type">hours</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False"/>
|
||||
<field name="model" eval="'base.action.rule'"/>
|
||||
<field name="function" eval="'_check'"/>
|
||||
<field name="args" eval="'(True,)'"/>
|
||||
<field name="active" eval="False" />
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="test_filter_draft" model="ir.filters">
|
||||
<field name="name">Test lead in state 'draft'</field>
|
||||
<field name="model_id">base.automation.lead.test</field>
|
||||
<field name="domain">[('state', '=', 'draft')]</field>
|
||||
</record>
|
||||
|
||||
<record id="test_filter_open" model="ir.filters">
|
||||
<field name="name">Test lead in state 'open'</field>
|
||||
<field name="model_id">base.automation.lead.test</field>
|
||||
<field name="domain">[('state', '=', 'open')]</field>
|
||||
</record>
|
||||
|
||||
<record id="test_filter_done" model="ir.filters">
|
||||
<field name="name">Test lead in state 'done'</field>
|
||||
<field name="model_id">base.automation.lead.test</field>
|
||||
<field name="domain">[('state', '=', 'done')]</field>
|
||||
</record>
|
||||
|
||||
<record id="test_rule_on_create" model="base.automation">
|
||||
<field name="name">Base Automation: test rule on create</field>
|
||||
<field name="model_id" ref="base_automation.model_base_automation_lead_test"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code" eval="'records.write({\'user_id\': %s})' % ref('base.user_demo')"/>
|
||||
<field name="trigger">on_create</field>
|
||||
<field name="active" eval="True"/>
|
||||
<field name="model_id" ref="base_automation.model_base_automation_lead_test"/>
|
||||
<field name="filter_id" ref="test_filter_draft"/>
|
||||
</record>
|
||||
|
||||
<record id="test_rule_on_write" model="base.automation">
|
||||
<field name="name">Base Automation: test rule on write</field>
|
||||
<field name="model_id" ref="base_automation.model_base_automation_lead_test"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code" eval="'records.write({\'user_id\': %s})' % ref('base.user_demo')"/>
|
||||
<field name="trigger">on_write</field>
|
||||
<field name="active" eval="True"/>
|
||||
<field name="model_id" ref="base_automation.model_base_automation_lead_test"/>
|
||||
<field name="filter_pre_id" ref="test_filter_open"/>
|
||||
<field name="filter_id" ref="test_filter_done"/>
|
||||
</record>
|
||||
|
||||
<record id="test_rule_on_recompute" model="base.automation">
|
||||
<field name="name">Base Automation: test rule on recompute</field>
|
||||
<field name="model_id" ref="base_automation.model_base_automation_lead_test"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code" eval="'records.write({\'user_id\': %s})' % ref('base.user_demo')"/>
|
||||
<field name="trigger">on_write</field>
|
||||
<field name="active" eval="True"/>
|
||||
<field name="model_id" ref="base_automation.model_base_automation_lead_test"/>
|
||||
<field name="filter_domain">[('customer', '=', True)]</field>
|
||||
</record>
|
||||
|
||||
<record id="test_rule_on_line" model="base.automation">
|
||||
<field name="name">Base Automation: test rule on secondary model</field>
|
||||
<field name="model_id" ref="base_automation.model_base_automation_line_test"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code" eval="'records.write({\'user_id\': %s})' % ref('base.user_demo')"/>
|
||||
<field name="trigger">on_create</field>
|
||||
<field name="active" eval="True"/>
|
||||
<field name="model_id" ref="base_automation.model_base_automation_line_test"/>
|
||||
</record>
|
||||
</odoo>
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import base_action_rule
|
||||
import base_automation
|
||||
import ir_actions
|
||||
+62
-75
@@ -25,24 +25,24 @@ DATE_RANGE_FUNCTION = {
|
||||
}
|
||||
|
||||
|
||||
class BaseActionRule(models.Model):
|
||||
""" Base Action Rules """
|
||||
|
||||
_name = 'base.action.rule'
|
||||
_description = 'Action Rules'
|
||||
class BaseAutomation(models.Model):
|
||||
_name = 'base.automation'
|
||||
_description = 'Automated Action'
|
||||
_order = 'sequence'
|
||||
|
||||
name = fields.Char(string='Rule Name', required=True)
|
||||
model_id = fields.Many2one('ir.model', string='Related Document Model', required=True, domain=[('transient', '=', False)])
|
||||
model = fields.Char(related='model_id.model', readonly=True)
|
||||
action_server_id = fields.Many2one(
|
||||
'ir.actions.server', 'Server Actions',
|
||||
domain="[('model_id', '=', model_id)]",
|
||||
delegate=True, required=True, ondelete='restrict')
|
||||
active = fields.Boolean(default=True, help="When unchecked, the rule is hidden and will not be executed.")
|
||||
sequence = fields.Integer(help="Gives the sequence order when displaying a list of rules.")
|
||||
kind = fields.Selection([('on_create', 'On Creation'),
|
||||
('on_write', 'On Update'),
|
||||
('on_create_or_write', 'On Creation & Update'),
|
||||
('on_unlink', 'On Deletion'),
|
||||
('on_change', 'Based on Form Modification'),
|
||||
('on_time', 'Based on Timed Condition')], string='When to Run', required=True)
|
||||
trigger = fields.Selection([
|
||||
('on_create', 'On Creation'),
|
||||
('on_write', 'On Update'),
|
||||
('on_create_or_write', 'On Creation & Update'),
|
||||
('on_unlink', 'On Deletion'),
|
||||
('on_change', 'Based on Form Modification'),
|
||||
('on_time', 'Based on Timed Condition')
|
||||
], string='Trigger condition', required=True, oldname="kind")
|
||||
trg_date_id = fields.Many2one('ir.model.fields', string='Trigger Date',
|
||||
help="""When should the condition be triggered.
|
||||
If present, will be checked by the scheduler. If empty, will be checked at creation and update.""",
|
||||
@@ -55,34 +55,33 @@ class BaseActionRule(models.Model):
|
||||
string='Delay type', default='day')
|
||||
trg_date_calendar_id = fields.Many2one("resource.calendar", string='Use Calendar',
|
||||
help="When calculating a day-based timed condition, it is possible to use a calendar to compute the date based on working days.")
|
||||
act_user_id = fields.Many2one('res.users', string='Set Responsible')
|
||||
act_followers = fields.Many2many("res.partner", string="Add Followers")
|
||||
server_action_ids = fields.Many2many('ir.actions.server', string='Server Actions', domain="[('model_id', '=', model_id)]",
|
||||
help="Examples: email reminders, call object service, etc.")
|
||||
filter_pre_id = fields.Many2one("ir.filters", string='Before Update Filter', ondelete='restrict', domain="[('model_id', '=', model_id.model)]",
|
||||
filter_pre_id = fields.Many2one("ir.filters", string='Before Update Filter', ondelete='restrict',
|
||||
domain="[('model_id', '=', model_name)]",
|
||||
help="If present, this condition must be satisfied before the update of the record.")
|
||||
filter_pre_domain = fields.Char(string='Before Update Domain',
|
||||
help="If present, this condition must be satisfied before the update of the record.")
|
||||
filter_id = fields.Many2one("ir.filters", string='Filter', ondelete='restrict', domain="[('model_id', '=', model_id.model)]",
|
||||
filter_id = fields.Many2one("ir.filters", string='Filter', ondelete='restrict',
|
||||
domain="[('model_id', '=', model_name)]",
|
||||
help="If present, this condition must be satisfied before executing the action rule.")
|
||||
filter_domain = fields.Char(string='Domain', help="If present, this condition must be satisfied before executing the action rule.")
|
||||
last_run = fields.Datetime(readonly=True, copy=False)
|
||||
on_change_fields = fields.Char(string="On Change Fields Trigger", help="Comma-separated list of field names that triggers the onchange.")
|
||||
|
||||
# which fields have an impact on the registry
|
||||
CRITICAL_FIELDS = ['model_id', 'active', 'kind', 'on_change_fields']
|
||||
CRITICAL_FIELDS = ['model_id', 'active', 'trigger', 'on_change_fields']
|
||||
|
||||
@api.onchange('model_id')
|
||||
def onchange_model_id(self):
|
||||
self.filter_pre_id = self.filter_id = False
|
||||
self.model_name = self.model_id.model
|
||||
|
||||
@api.onchange('kind')
|
||||
def onchange_kind(self):
|
||||
if self.kind in ['on_create', 'on_create_or_write', 'on_unlink']:
|
||||
@api.onchange('trigger')
|
||||
def onchange_trigger(self):
|
||||
if self.trigger in ['on_create', 'on_create_or_write', 'on_unlink']:
|
||||
self.filter_pre_id = self.filter_pre_domain = self.trg_date_id = self.trg_date_range = self.trg_date_range_type = False
|
||||
elif self.kind in ['on_write', 'on_create_or_write']:
|
||||
elif self.trigger in ['on_write', 'on_create_or_write']:
|
||||
self.trg_date_id = self.trg_date_range = self.trg_date_range_type = False
|
||||
elif self.kind == 'on_time':
|
||||
elif self.trigger == 'on_time':
|
||||
self.filter_pre_id = self.filter_pre_domain = False
|
||||
|
||||
@api.onchange('filter_pre_id')
|
||||
@@ -95,14 +94,15 @@ class BaseActionRule(models.Model):
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
base_action_rule = super(BaseActionRule, self).create(vals)
|
||||
vals['usage'] = 'base_automation'
|
||||
base_automation = super(BaseAutomation, self).create(vals)
|
||||
self._update_cron()
|
||||
self._update_registry()
|
||||
return base_action_rule
|
||||
return base_automation
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
res = super(BaseActionRule, self).write(vals)
|
||||
res = super(BaseAutomation, self).write(vals)
|
||||
if set(vals).intersection(self.CRITICAL_FIELDS):
|
||||
self._update_cron()
|
||||
self._update_registry()
|
||||
@@ -110,7 +110,7 @@ class BaseActionRule(models.Model):
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
res = super(BaseActionRule, self).unlink()
|
||||
res = super(BaseAutomation, self).unlink()
|
||||
self._update_cron()
|
||||
self._update_registry()
|
||||
return res
|
||||
@@ -119,8 +119,8 @@ class BaseActionRule(models.Model):
|
||||
""" Activate the cron job depending on whether there exists action rules
|
||||
based on time conditions.
|
||||
"""
|
||||
cron = self.env.ref('base_action_rule.ir_cron_crm_action', raise_if_not_found=False)
|
||||
return cron and cron.toggle(model=self._name, domain=[('kind', '=', 'on_time')])
|
||||
cron = self.env.ref('base_automation.ir_cron_data_base_automation_check', raise_if_not_found=False)
|
||||
return cron and cron.toggle(model=self._name, domain=[('trigger', '=', 'on_time')])
|
||||
|
||||
def _update_registry(self):
|
||||
""" Update the registry after a modification on action rules. """
|
||||
@@ -131,13 +131,13 @@ class BaseActionRule(models.Model):
|
||||
registry = Registry.new(self._cr.dbname)
|
||||
registry.signal_registry_change()
|
||||
|
||||
def _get_actions(self, records, kinds):
|
||||
""" Return the actions of the given kinds for records' model. The
|
||||
def _get_actions(self, records, triggers):
|
||||
""" Return the actions of the given triggers for records' model. The
|
||||
returned actions' context contain an object to manage processing.
|
||||
"""
|
||||
if '__action_done' not in self._context:
|
||||
self = self.with_context(__action_done={})
|
||||
domain = [('model', '=', records._name), ('kind', 'in', kinds)]
|
||||
domain = [('model_name', '=', records._name), ('trigger', 'in', triggers)]
|
||||
actions = self.with_context(active_test=True).search(domain)
|
||||
return actions.with_env(self.env)
|
||||
|
||||
@@ -191,27 +191,14 @@ class BaseActionRule(models.Model):
|
||||
values = {}
|
||||
if 'date_action_last' in records._fields:
|
||||
values['date_action_last'] = fields.Datetime.now()
|
||||
if self.act_user_id and 'user_id' in records._fields:
|
||||
values['user_id'] = self.act_user_id.id
|
||||
if values:
|
||||
records.write(values)
|
||||
|
||||
# subscribe followers
|
||||
if self.act_followers and hasattr(records, 'message_subscribe'):
|
||||
followers = self.env['mail.followers'].sudo().search(
|
||||
[('res_model', '=', records._name),
|
||||
('res_id', 'in', records.ids),
|
||||
('partner_id', 'in', self.act_followers.ids),
|
||||
]
|
||||
)
|
||||
if not len(followers) == len(self.act_followers):
|
||||
records.message_subscribe(self.act_followers.ids)
|
||||
|
||||
# execute server actions
|
||||
if self.server_action_ids:
|
||||
if self.action_server_id:
|
||||
for record in records:
|
||||
ctx = {'active_model': record._name, 'active_ids': record.ids, 'active_id': record.id}
|
||||
self.server_action_ids.with_context(**ctx).run()
|
||||
self.action_server_id.with_context(**ctx).run()
|
||||
|
||||
@api.model_cr
|
||||
def _register_hook(self):
|
||||
@@ -232,7 +219,7 @@ class BaseActionRule(models.Model):
|
||||
@api.model
|
||||
def create(self, vals, **kw):
|
||||
# retrieve the action rules to possibly execute
|
||||
actions = self.env['base.action.rule']._get_actions(self, ['on_create', 'on_create_or_write'])
|
||||
actions = self.env['base.automation']._get_actions(self, ['on_create', 'on_create_or_write'])
|
||||
# call original method
|
||||
record = create.origin(self.with_env(actions.env), vals, **kw)
|
||||
# check postconditions, and execute actions on the records that satisfy them
|
||||
@@ -251,7 +238,7 @@ class BaseActionRule(models.Model):
|
||||
@api.multi
|
||||
def _write(self, vals, **kw):
|
||||
# retrieve the action rules to possibly execute
|
||||
actions = self.env['base.action.rule']._get_actions(self, ['on_write', 'on_create_or_write'])
|
||||
actions = self.env['base.automation']._get_actions(self, ['on_write', 'on_create_or_write'])
|
||||
records = self.with_env(actions.env)
|
||||
# check preconditions on records
|
||||
pre = {action: action._filter_pre(records) for action in actions}
|
||||
@@ -274,7 +261,7 @@ class BaseActionRule(models.Model):
|
||||
@api.multi
|
||||
def unlink(self, **kwargs):
|
||||
# retrieve the action rules to possibly execute
|
||||
actions = self.env['base.action.rule']._get_actions(self, ['on_unlink'])
|
||||
actions = self.env['base.automation']._get_actions(self, ['on_unlink'])
|
||||
records = self.with_env(actions.env)
|
||||
# check conditions, and execute actions on the records that satisfy them
|
||||
for action in actions:
|
||||
@@ -286,22 +273,22 @@ class BaseActionRule(models.Model):
|
||||
|
||||
def make_onchange(action_rule_id):
|
||||
""" Instanciate an onchange method for the given action rule. """
|
||||
def base_action_rule_onchange(self):
|
||||
action_rule = self.env['base.action.rule'].browse(action_rule_id)
|
||||
def base_automation_onchange(self):
|
||||
action_rule = self.env['base.automation'].browse(action_rule_id)
|
||||
result = {}
|
||||
for server_action in action_rule.server_action_ids.with_context(active_model=self._name, onchange_self=self):
|
||||
res = server_action.run()
|
||||
if res:
|
||||
if 'value' in res:
|
||||
res['value'].pop('id', None)
|
||||
self.update({key: val for key, val in res['value'].iteritems() if key in self._fields})
|
||||
if 'domain' in res:
|
||||
result.setdefault('domain', {}).update(res['domain'])
|
||||
if 'warning' in res:
|
||||
result['warning'] = res['warning']
|
||||
server_action = action_rule.action_server_id.with_context(active_model=self._name, onchange_self=self)
|
||||
res = server_action.run()
|
||||
if res:
|
||||
if 'value' in res:
|
||||
res['value'].pop('id', None)
|
||||
self.update({key: val for key, val in res['value'].iteritems() if key in self._fields})
|
||||
if 'domain' in res:
|
||||
result.setdefault('domain', {}).update(res['domain'])
|
||||
if 'warning' in res:
|
||||
result['warning'] = res['warning']
|
||||
return result
|
||||
|
||||
return base_action_rule_onchange
|
||||
return base_automation_onchange
|
||||
|
||||
patched_models = defaultdict(set)
|
||||
def patch(model, name, method):
|
||||
@@ -312,21 +299,21 @@ class BaseActionRule(models.Model):
|
||||
|
||||
# retrieve all actions, and patch their corresponding model
|
||||
for action_rule in self.with_context({}).search([]):
|
||||
Model = self.env[action_rule.model]
|
||||
if action_rule.kind == 'on_create':
|
||||
Model = self.env[action_rule.model_name]
|
||||
if action_rule.trigger == 'on_create':
|
||||
patch(Model, 'create', make_create())
|
||||
|
||||
elif action_rule.kind == 'on_create_or_write':
|
||||
elif action_rule.trigger == 'on_create_or_write':
|
||||
patch(Model, 'create', make_create())
|
||||
patch(Model, '_write', make_write())
|
||||
|
||||
elif action_rule.kind == 'on_write':
|
||||
elif action_rule.trigger == 'on_write':
|
||||
patch(Model, '_write', make_write())
|
||||
|
||||
elif action_rule.kind == 'on_unlink':
|
||||
elif action_rule.trigger == 'on_unlink':
|
||||
patch(Model, 'unlink', make_unlink())
|
||||
|
||||
elif action_rule.kind == 'on_change':
|
||||
elif action_rule.trigger == 'on_change':
|
||||
# register an onchange method for the action_rule
|
||||
method = make_onchange(action_rule.id)
|
||||
for field_name in action_rule.on_change_fields.split(","):
|
||||
@@ -352,7 +339,7 @@ class BaseActionRule(models.Model):
|
||||
|
||||
# retrieve all the action rules to run based on a timed condition
|
||||
eval_context = self._get_eval_context()
|
||||
for action in self.with_context(active_test=True).search([('kind', '=', 'on_time')]):
|
||||
for action in self.with_context(active_test=True).search([('trigger', '=', 'on_time')]):
|
||||
last_run = fields.Datetime.from_string(action.last_run) or datetime.datetime.utcfromtimestamp(0)
|
||||
|
||||
# retrieve all the records that satisfy the action's condition
|
||||
@@ -369,7 +356,7 @@ class BaseActionRule(models.Model):
|
||||
filter_meta = action.filter_id.get_metadata()[0]
|
||||
user_id = (filter_meta['write_uid'] or filter_meta['create_uid'])[0]
|
||||
context['lang'] = self.env['res.users'].browse(user_id).lang
|
||||
records = self.env[action.model].with_context(context).search(domain)
|
||||
records = self.env[action.model_name].with_context(context).search(domain)
|
||||
|
||||
# determine when action should occur for the records
|
||||
if action.trg_date_id.name == 'date_action_last' and 'create_date' in records._fields:
|
||||
@@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ServerAction(models.Model):
|
||||
_inherit = "ir.actions.server"
|
||||
|
||||
usage = fields.Selection(selection_add=[('base_automation', 'Automated Action')])
|
||||
@@ -0,0 +1,5 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_base_automation,base.automation,model_base_automation,,1,0,0,0
|
||||
access_base_automation_config,base.automation config,model_base_automation,base.group_system,1,1,1,1
|
||||
access_base_automation_lead_test,access_base_automation_lead_test,model_base_automation_lead_test,base.group_system,1,1,1,1
|
||||
access_base_automation_line_test,access_base_automation_line_test,model_base_automation_line_test,base.group_system,1,1,1,1
|
||||
|
+1
-1
@@ -2,4 +2,4 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import test_models
|
||||
import test_base_action_rule
|
||||
import test_base_automation
|
||||
+4
-4
@@ -6,10 +6,10 @@ from odoo.tests import common
|
||||
|
||||
@common.at_install(False)
|
||||
@common.post_install(True)
|
||||
class base_action_rule_test(common.TransactionCase):
|
||||
class base_automation_test(common.TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(base_action_rule_test, self).setUp()
|
||||
super(base_automation_test, self).setUp()
|
||||
self.user_admin = self.env.ref('base.user_root')
|
||||
self.user_demo = self.env.ref('base.user_demo')
|
||||
|
||||
@@ -19,7 +19,7 @@ class base_action_rule_test(common.TransactionCase):
|
||||
'user_id': self.user_admin.id,
|
||||
}
|
||||
vals.update(kwargs)
|
||||
return self.env['base.action.rule.lead.test'].create(vals)
|
||||
return self.env['base.automation.lead.test'].create(vals)
|
||||
|
||||
def test_00_check_to_state_open_pre(self):
|
||||
"""
|
||||
@@ -96,7 +96,7 @@ class base_action_rule_test(common.TransactionCase):
|
||||
"""
|
||||
Check that a rule is executed after creating a line record.
|
||||
"""
|
||||
line = self.env['base.action.rule.line.test'].create({'name': "Line"})
|
||||
line = self.env['base.automation.line.test'].create({'name': "Line"})
|
||||
self.assertEqual(line.user_id, self.user_demo)
|
||||
|
||||
def test_20_indirect_line(self):
|
||||
+4
-4
@@ -5,7 +5,7 @@ from odoo import fields, models
|
||||
|
||||
|
||||
class LeadTest(models.Model):
|
||||
_name = "base.action.rule.lead.test"
|
||||
_name = "base.automation.lead.test"
|
||||
_description = "Action Rule Test"
|
||||
|
||||
name = fields.Char(string='Subject', required=True, index=True)
|
||||
@@ -17,13 +17,13 @@ class LeadTest(models.Model):
|
||||
partner_id = fields.Many2one('res.partner', string='Partner')
|
||||
date_action_last = fields.Datetime(string='Last Action', readonly=True)
|
||||
customer = fields.Boolean(related='partner_id.customer', readonly=True, store=True)
|
||||
line_ids = fields.One2many('base.action.rule.line.test', 'lead_id')
|
||||
line_ids = fields.One2many('base.automation.line.test', 'lead_id')
|
||||
|
||||
|
||||
class LineTest(models.Model):
|
||||
_name = "base.action.rule.line.test"
|
||||
_name = "base.automation.line.test"
|
||||
_description = "Action Rule Line Test"
|
||||
|
||||
name = fields.Char()
|
||||
lead_id = fields.Many2one('base.action.rule.lead.test', ondelete='cascade')
|
||||
lead_id = fields.Many2one('base.automation.lead.test', ondelete='cascade')
|
||||
user_id = fields.Many2one('res.users')
|
||||
@@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- Automation Form View -->
|
||||
<record id="view_base_automation_form" model="ir.ui.view">
|
||||
<field name="name">Automations</field>
|
||||
<field name="model">base.automation</field>
|
||||
<field name="mode">primary</field>
|
||||
<field name="inherit_id" ref="base.view_server_action_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//button[@name='create_action']" position="replace">
|
||||
<button name="create_action_for_menu" string="Create Action" type="object"
|
||||
class="btn-primary"
|
||||
attrs="{'invisible':[('menu_ir_values_id','!=',False)]}"
|
||||
help="Display an option in the 'More' top-menu or related document, to run this action."/>
|
||||
</xpath>
|
||||
<xpath expr="//button[@name='unlink_action']" position="replace">
|
||||
<button name="unlink_action_for_menu" string="Remove Action" type="object"
|
||||
attrs="{'invisible':[('menu_ir_values_id','=',False)]}"
|
||||
help="Remove the contextual action related to this server action"/>
|
||||
</xpath>
|
||||
<xpath expr="//group[@name='action_wrapper']" position="inside">
|
||||
<group>
|
||||
<field name="trigger"/>
|
||||
|
||||
<label for="filter_pre_id" attrs="{'invisible': [('trigger', 'not in', ['on_write','on_create_or_write'])]}"/>
|
||||
<div attrs="{'invisible': [('trigger', 'not in', ['on_write','on_create_or_write'])]}">
|
||||
<field name="filter_pre_domain" widget="domain" options="{'model': 'model_name'}"
|
||||
class="o_row"/>
|
||||
<div class="oe_edit_only o_row">Set selection based on a search filter:
|
||||
<field name="filter_pre_id" domain="[('model_id', '=', model_name), '|', ('user_id', '=', uid), ('user_id', '=', False)]"
|
||||
class="o_row" context="{'default_model_id': model_name, 'default_active': False, 'active_test': False}"/></div>
|
||||
</div>
|
||||
|
||||
<label for="filter_id"/>
|
||||
<div>
|
||||
<field name="filter_domain" widget="domain" options="{'model': 'model_name'}"
|
||||
class="o_row"/>
|
||||
<div class="oe_edit_only o_row">Set selection based on a search filter:
|
||||
<field name="filter_id" domain="[('model_id', '=', model_name), '|', ('user_id', '=', uid), ('user_id', '=', False)]"
|
||||
class="o_row" context="{'default_model_id': model_name, 'default_active': False, 'active_test': False}"/>
|
||||
</div>
|
||||
</div>
|
||||
<field name="on_change_fields"
|
||||
attrs="{'invisible': [('trigger', '!=', 'on_change')], 'required': [('trigger', '=', 'on_change')]}"/>
|
||||
<field name="trg_date_id"
|
||||
attrs="{'invisible': [('trigger', '!=', 'on_time')], 'required': [('trigger', '=', 'on_time')]}"/>
|
||||
<label for="trg_date_range"
|
||||
attrs="{'invisible': [('trigger', '!=', 'on_time')]}"/>
|
||||
<div class="o_row" attrs="{'invisible': [('trigger', '!=', 'on_time')]}">
|
||||
<field name="trg_date_range" attrs="{'required': [('trigger','=','on_time')]}"/>
|
||||
<field name="trg_date_range_type" attrs="{'required': [('trigger','=','on_time')]}"/>
|
||||
</div>
|
||||
<field name="trg_date_calendar_id"
|
||||
attrs="{'invisible': ['|', ('trg_date_id','=',False), ('trg_date_range_type', '!=', 'day')]}"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- automation Tree View -->
|
||||
<record id="view_base_automation_tree" model="ir.ui.view">
|
||||
<field name="name">base.automation.tree</field>
|
||||
<field name="model">base.automation</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Automation">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="trigger"/>
|
||||
<field name="model_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- automation Action -->
|
||||
<record id="base_automation_act" model="ir.actions.act_window">
|
||||
<field name="name">Automated Actions</field>
|
||||
<field name="res_model">base.automation</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_base_automation_tree"/>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to setup a new automated automation.
|
||||
</p><p>
|
||||
Use automated actions to automatically trigger actions for
|
||||
various screens. Example: a lead created by a specific user may
|
||||
be automatically set to a specific sales channel, or an
|
||||
opportunity which still has status pending after 14 days might
|
||||
trigger an automatic reminder email.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_base_automation_form"
|
||||
parent="base.menu_automation" action="base_automation_act" sequence="1"/>
|
||||
|
||||
</odoo>
|
||||
@@ -3,28 +3,26 @@
|
||||
<data noupdate="1">
|
||||
<!--Scheduler sync Receive Request-->
|
||||
<record id="gengo_sync_receive_request_scheduler" model="ir.cron">
|
||||
<field name="name" >Gengo Sync Translation (Response)</field>
|
||||
<field eval="True" name="active"/>
|
||||
<field name="name">Gengo: Sync translation (Response)</field>
|
||||
<field name="model_id" ref="base_gengo.model_base_gengo_translations"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model._sync_response(20)</field>
|
||||
<field name="interval_number">6</field>
|
||||
<field name="interval_type">hours</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False" />
|
||||
<field name="model" eval="'base.gengo.translations'"></field>
|
||||
<field name="function" eval="'_sync_response'"/>
|
||||
<field name="args" eval="'(20,)'"/>
|
||||
</record>
|
||||
|
||||
<!--Scheduler Sync Send Request-->
|
||||
<record id="gengo_sync_send_request_scheduler" model="ir.cron">
|
||||
<field name="name" >Gengo Sync Translation (Request)</field>
|
||||
<field eval="True" name="active"/>
|
||||
<field name="name">Gengo: Sync translation (Request)</field>
|
||||
<field name="model_id" ref="base_gengo.model_base_gengo_translations"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model._sync_request(20)</field>
|
||||
<field name="interval_number">6</field>
|
||||
<field name="interval_type">hours</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False"/>
|
||||
<field name="model" eval="'base.gengo.translations'"></field>
|
||||
<field name="function" eval="'_sync_request'"/>
|
||||
<field name="args" eval="'(20,)'"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
'name': 'Calendar',
|
||||
'version': '1.0',
|
||||
'sequence': 130,
|
||||
'depends': ['base', 'mail', 'base_action_rule', 'web_calendar'],
|
||||
'depends': ['base', 'mail', 'web_calendar'],
|
||||
'summary': 'Personal & Shared Calendar',
|
||||
'description': """
|
||||
This is a full-featured calendar system.
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
<data noupdate="1">
|
||||
<!-- Scheduler for Event Alarm-->
|
||||
<record forcecreate="True" id="ir_cron_scheduler_alarm" model="ir.cron">
|
||||
<field name="name">Run Event Reminder</field>
|
||||
<field name="name">Calendar: Event Reminder</field>
|
||||
<field name="model_id" ref="model_calendar_alarm_manager"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.get_next_mail()</field>
|
||||
<field eval="False" name="active" />
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_number">30</field>
|
||||
<field name="interval_type">minutes</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall" />
|
||||
<field eval="'calendar.alarm_manager'" name="model" />
|
||||
<field eval="'get_next_mail'" name="function" />
|
||||
<!--<field eval="'(False,)'" name="args" />-->
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -29,7 +29,6 @@ Dashboard for CRM will include:
|
||||
""",
|
||||
'website': 'https://www.odoo.com/page/crm',
|
||||
'depends': [
|
||||
'base_action_rule',
|
||||
'base_setup',
|
||||
'sales_team',
|
||||
'mail',
|
||||
@@ -73,7 +72,6 @@ Dashboard for CRM will include:
|
||||
'data/crm_demo.xml',
|
||||
'data/mail_activity_demo.xml',
|
||||
'data/crm_lead_demo.xml',
|
||||
'data/base_action_rule_demo.xml',
|
||||
],
|
||||
'css': ['static/src/css/crm.css'],
|
||||
'installable': True,
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<!-- demo automated actions add messge on new lead after 5 days -->
|
||||
<record id="filter_draft_lead" model="ir.filters">
|
||||
<field name="name">Draft Leads</field>
|
||||
<field name="model_id">crm.lead</field>
|
||||
<field name="domain">[('stage_id.sequence', '=', 1)]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
</record>
|
||||
<record id="action_email_reminder_lead" model="ir.actions.server">
|
||||
<field name="name">Reminder to User</field>
|
||||
<field name="model_id" ref="model_crm_lead"/>
|
||||
<field name="condition">True</field>
|
||||
<field name="type">ir.actions.server</field>
|
||||
<field name="state">email</field>
|
||||
<field name="template_id" ref="email_template_opportunity_reminder_mail"/>
|
||||
</record>
|
||||
<record id="rule_set_reminder_lead" model="base.action.rule">
|
||||
<field name="name">Set Auto Reminder on leads which are not open since 5 days.</field>
|
||||
<field name="model_id" ref="model_crm_lead"/>
|
||||
<field name="sequence">1</field>
|
||||
<field name="kind">on_time</field>
|
||||
<field name="filter_domain">[('stage_id.sequence', '=', 1)]</field>
|
||||
<field name="trg_date_id" search="[('model','=','crm.lead'),('name','=','create_date')]"/>
|
||||
<field name="trg_date_range">5</field>
|
||||
<field name="trg_date_range_type">day</field>
|
||||
<field name="server_action_ids" eval="[(6,0,[ref('action_email_reminder_lead')])]"/>
|
||||
</record>
|
||||
|
||||
<!-- demo automated actions add a followers on urgent USA leads -->
|
||||
<record id="filter_usa_lead" model="ir.filters">
|
||||
<field name="name">Leads from USA</field>
|
||||
<field name="model_id">crm.lead</field>
|
||||
<field name="domain">[('country_id','=','United States')]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
</record>
|
||||
<record id="action_set_team_sales_department" model="ir.actions.server">
|
||||
<field name="name">Set team to Sales Department</field>
|
||||
<field name="model_id" ref="model_crm_lead"/>
|
||||
<field name="condition">True</field>
|
||||
<field name="type">ir.actions.server</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">record.write({'team_id': env.ref('sales_team.team_sales_department').id})</field>
|
||||
</record>
|
||||
<record id="rule_set_followers_lead" model="base.action.rule">
|
||||
<field name="name">Set Auto Followers on leads which are urgent and come from USA.</field>
|
||||
<field name="model_id" ref="model_crm_lead"/>
|
||||
<field name="sequence">2</field>
|
||||
<field name="kind">on_create</field>
|
||||
<field name="filter_id" ref="filter_usa_lead"/>
|
||||
<field name="act_user_id" ref="base.user_root"/>
|
||||
<field name="act_followers" eval="[(6,0,[ref('base.res_partner_4'), ref('base.res_partner_3'), ref('base.res_partner_1')])]"/>
|
||||
<field name="server_action_ids" eval="[(6,0,[ref('action_set_team_sales_department')])]"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -10,7 +10,6 @@ access_res_partner_category_manager,res.partner.category.crm.manager,base.model_
|
||||
access_res_partner,res.partner.crm.user,base.model_res_partner,sales_team.group_sale_salesman,1,1,1,0
|
||||
access_res_partner_category,res.partner.category.crm.user,base.model_res_partner_category,sales_team.group_sale_salesman,1,1,1,0
|
||||
mail_mailgate_thread,mail.thread,mail.model_mail_thread,sales_team.group_sale_salesman,1,1,1,1
|
||||
access_base_action_rule_manager,base.action.rule manager,base_action_rule.model_base_action_rule,sales_team.group_sale_manager,1,1,1,1
|
||||
access_crm_lead_partner_manager,crm.lead.partner.manager,model_crm_lead,base.group_partner_manager,1,0,0,0
|
||||
access_crm_lead_tag,crm_lead_tag,model_crm_lead_tag,base.group_user,1,0,0,0
|
||||
access_crm_lead_tag_salesman,crm_lead_tag salesman,model_crm_lead_tag,sales_team.group_sale_salesman,1,1,1,0
|
||||
|
||||
|
@@ -661,7 +661,7 @@
|
||||
'Mark as Lost' in action dropdown
|
||||
-->
|
||||
<record id="action_mark_as_lost" model="ir.actions.server">
|
||||
<field name="name">Mark as lost</field>
|
||||
<field name="name">Crm: Mark Leads as lost</field>
|
||||
<field name="model_id" ref="model_crm_lead"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
@@ -770,11 +770,10 @@ if record:
|
||||
</record>
|
||||
|
||||
<record id="action_your_pipeline" model="ir.actions.server">
|
||||
<field name="name">My Pipeline</field>
|
||||
<field name="name">Crm: My Pipeline</field>
|
||||
<field name="model_id" ref="crm.model_crm_team"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.action_your_pipeline()</field>
|
||||
<field eval="True" name="condition"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="crm_lead_opportunities_tree_view">
|
||||
|
||||
@@ -13,16 +13,15 @@
|
||||
|
||||
<!-- Event Mail Scheduler-->
|
||||
<record model="ir.cron" forcecreate="True" id="event_mail_scheduler">
|
||||
<field name="name">[event] mail scheduler</field>
|
||||
<field name="active">True</field>
|
||||
<field name="name">Event: Mail Scheduler</field>
|
||||
<field name="model_id" ref="model_event_mail"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.run(True)</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">hours</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False" />
|
||||
<field eval="'(True,)'" name="args"/>
|
||||
<field name="model">event.mail</field>
|
||||
<field name="function">run</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="ir_cron_mail_gateway_action" model="ir.cron">
|
||||
<field name="name">Fetchmail Service</field>
|
||||
<field name="name">Mail: Fetchmail Service</field>
|
||||
<field name="model_id" ref="model_fetchmail_server"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model._fetch_mails()</field>
|
||||
<field name="interval_number">5</field>
|
||||
<field name="interval_type">minutes</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False"/>
|
||||
<field name="model">fetchmail.server</field>
|
||||
<field name="function">_fetch_mails</field>
|
||||
<field name="args">()</field>
|
||||
<!-- Active flag is set on fetchmail_server.create/write -->
|
||||
<field name="active" eval="False"/>
|
||||
</record>
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record forcecreate="True" id="ir_cron_contract_costs_generator" model="ir.cron">
|
||||
<field name="name">Generation of contracts costs based on the costs frequency</field>
|
||||
<field eval="True" name="active" />
|
||||
<field name="name">Fleet: Generate contracts costs based on costs frequency</field>
|
||||
<field name="model_id" ref="model_fleet_vehicle_log_contract"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.run_scheduler()</field>
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall" />
|
||||
<field eval="'fleet.vehicle.log.contract'" name="model" />
|
||||
<field eval="'run_scheduler'" name="function" />
|
||||
<field eval="'()'" name="args" />
|
||||
</record>
|
||||
|
||||
<record id="type_service_service_1" model="fleet.service.type">
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record forcecreate="True" id="ir_cron_check_challenge"
|
||||
model="ir.cron">
|
||||
<field name="name">Run Goal Challenge Checker</field>
|
||||
<record forcecreate="True" id="ir_cron_check_challenge" model="ir.cron">
|
||||
<field name="name">Gamification: Goal Challenge Check</field>
|
||||
<field name="model_id" ref="model_gamification_challenge"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model._cron_update()</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall" />
|
||||
<field name="model">gamification.challenge</field>
|
||||
<field name="function">_cron_update</field>
|
||||
<field name="args">()</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
<odoo>
|
||||
<data>
|
||||
<record forcecreate="True" id="ir_cron_sync_all_cals" model="ir.cron">
|
||||
<field name="name">Calendar synchronization</field>
|
||||
<field eval="True" name="active" />
|
||||
<field name="name">Google Calendar: synchronization</field>
|
||||
<field name="model_id" ref="model_google_calendar"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.synchronize_events_cron()</field>
|
||||
<field name="user_id" ref="base.user_root" />
|
||||
<field name="interval_number">12</field>
|
||||
<field name="interval_type">hours</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall" />
|
||||
<field eval="'google.calendar'" name="model" />
|
||||
<field eval="'synchronize_events_cron'" name="function" />
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -17,11 +17,10 @@ Add all information on the employee form to manage contracts.
|
||||
You can assign several contracts per employee.
|
||||
""",
|
||||
'website': 'https://www.odoo.com/page/employees',
|
||||
'depends': ['base_action_rule', 'hr'],
|
||||
'depends': ['hr'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'data/hr_contract_data.xml',
|
||||
'views/base_action_rule_views.xml',
|
||||
'views/hr_contract_views.xml',
|
||||
],
|
||||
'demo': [],
|
||||
|
||||
@@ -41,71 +41,28 @@
|
||||
<field name="description">Contract about to expire</field>
|
||||
</record>
|
||||
|
||||
<!-- base action rule about "Expiring Soon" contracts -->
|
||||
<record id="contract_open" model="ir.filters">
|
||||
<field name="name">Open Contracts</field>
|
||||
<field name="model_id">hr.contract</field>
|
||||
<field name="domain">[('state', '=', 'open')]</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
</record>
|
||||
<record id="contract_set_as_pending" model="ir.actions.server">
|
||||
<field name="name">HR Contract: set as pending</field>
|
||||
<!-- Expired Soon -->
|
||||
<record id="ir_cron_data_contract_update_to_pending" model="ir.cron">
|
||||
<field name="name">HR Contract: update to pending</field>
|
||||
<field name="model_id" ref="model_hr_contract"/>
|
||||
<field name="condition">True</field>
|
||||
<field name="type">ir.actions.server</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">record.set_as_pending()</field>
|
||||
<field name="code">model.update_to_pending()</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
</record>
|
||||
<record id="rule_contract_1_set_as_pending" model="base.action.rule">
|
||||
<field name="name">HR Contract: check for pending</field>
|
||||
|
||||
<!-- Expired -->
|
||||
<record id="ir_cron_data_contract_update_to_close" model="ir.cron">
|
||||
<field name="name">HR Contract: update to closed</field>
|
||||
<field name="model_id" ref="model_hr_contract"/>
|
||||
<field name="sequence">50</field>
|
||||
<field name="kind">on_time</field>
|
||||
<field name="filter_id" ref="contract_open"/>
|
||||
<field name="trg_date_id" ref="hr_contract.field_hr_contract_date_end"/>
|
||||
<field name="trg_date_range">-7</field>
|
||||
<field name="trg_date_range_type">day</field>
|
||||
<field name="server_action_ids" eval="[(6, 0, [ref('contract_set_as_pending')])]"/>
|
||||
</record>
|
||||
<record id="rule_contract_2_set_as_pending" model="base.action.rule">
|
||||
<field name="name">HR Contract: check for pending</field>
|
||||
<field name="model_id" ref="model_hr_contract"/>
|
||||
<field name="sequence">51</field>
|
||||
<field name="kind">on_time</field>
|
||||
<field name="filter_id" ref="contract_open"/>
|
||||
<field name="trg_date_id" ref="hr_contract.field_hr_contract_visa_expire"/>
|
||||
<field name="trg_date_range">-60</field>
|
||||
<field name="trg_date_range_type">day</field>
|
||||
<field name="server_action_ids" eval="[(6, 0, [ref('contract_set_as_pending')])]"/>
|
||||
</record>
|
||||
<!-- base action rule about "Expired" contracts -->
|
||||
<record id="contract_set_as_close" model="ir.actions.server">
|
||||
<field name="name">HR Contract: set as close</field>
|
||||
<field name="model_id" ref="model_hr_contract"/>
|
||||
<field name="condition">True</field>
|
||||
<field name="type">ir.actions.server</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">record.set_as_close()</field>
|
||||
</record>
|
||||
<record id="rule_contract_3_set_as_close" model="base.action.rule">
|
||||
<field name="name">HR Contract: check for close</field>
|
||||
<field name="model_id" ref="model_hr_contract"/>
|
||||
<field name="sequence">52</field>
|
||||
<field name="kind">on_time</field>
|
||||
<field name="trg_date_id" ref="hr_contract.field_hr_contract_date_end"/>
|
||||
<field name="trg_date_range">1</field>
|
||||
<field name="trg_date_range_type">day</field>
|
||||
<field name="server_action_ids" eval="[(6, 0, [ref('contract_set_as_close')])]"/>
|
||||
</record>
|
||||
<record id="rule_contract_4_set_as_close" model="base.action.rule">
|
||||
<field name="name">HR Contract: check for close</field>
|
||||
<field name="model_id" ref="model_hr_contract"/>
|
||||
<field name="sequence">53</field>
|
||||
<field name="kind">on_time</field>
|
||||
<field name="trg_date_id" ref="hr_contract.field_hr_contract_visa_expire"/>
|
||||
<field name="trg_date_range">1</field>
|
||||
<field name="trg_date_range_type">day</field>
|
||||
<field name="server_action_ids" eval="[(6, 0, [ref('contract_set_as_close')])]"/>
|
||||
<field name="code">model.update_to_close()</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user