From 9d7964a6b5bc6820fc7bf0a94d2498346c283fc4 Mon Sep 17 00:00:00 2001 From: Thomas Groutars Date: Mon, 23 Mar 2015 15:33:15 +0100 Subject: [PATCH 1/7] [IMP] Add old values in context of on write automated actions --- addons/base_action_rule/base_action_rule.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py index 105fd4004a9..87d8a5e094b 100644 --- a/addons/base_action_rule/base_action_rule.py +++ b/addons/base_action_rule/base_action_rule.py @@ -208,6 +208,11 @@ class base_action_rule(osv.osv): for action in actions: pre_ids[action] = action_model._filter(cr, uid, action, action.filter_pre_id, ids, domain=action.filter_pre_domain, context=context) + # read old values before the update + old_values = {} + for old_vals in self.read(cr, uid, ids, list(vals), context=context): + old_values[old_vals.pop('id')] = old_vals + # call original method write.origin(self, cr, uid, ids, vals, context=context, **kwargs) @@ -215,7 +220,7 @@ class base_action_rule(osv.osv): for action in actions: post_ids = action_model._filter(cr, uid, action, action.filter_id, pre_ids[action], domain=action.filter_domain, context=context) if post_ids: - action_model._process(cr, uid, action, post_ids, context=context) + action_model._process(cr, uid, action, post_ids, context=dict(context, old_values=old_values)) return True return write From c9d41b409fd8edc4f0135217879511293dbda3a9 Mon Sep 17 00:00:00 2001 From: Thomas Groutars Date: Mon, 23 Mar 2015 14:55:08 +0100 Subject: [PATCH 2/7] [IMP] Allow 'On Deletion' automated actions --- addons/base_action_rule/base_action_rule.py | 31 ++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py index 87d8a5e094b..3de35a4ae74 100644 --- a/addons/base_action_rule/base_action_rule.py +++ b/addons/base_action_rule/base_action_rule.py @@ -50,6 +50,7 @@ class base_action_rule(osv.osv): [('on_create', 'On Creation'), ('on_write', 'On Update'), ('on_create_or_write', 'On Creation & Update'), + ('on_unlink', 'On Deletion'), ('on_time', 'Based on Timed Condition')], string='When to Run'), 'trg_date_id': fields.many2one('ir.model.fields', string='Trigger Date', @@ -91,7 +92,7 @@ class base_action_rule(osv.osv): def onchange_kind(self, cr, uid, ids, kind, context=None): clear_fields = [] - if kind in ['on_create', 'on_create_or_write']: + if kind in ['on_create', 'on_create_or_write', 'on_unlink']: clear_fields = ['filter_pre_id', 'trg_date_id', 'trg_date_range', 'trg_date_range_type'] elif kind in ['on_write', 'on_create_or_write']: clear_fields = ['trg_date_id', 'trg_date_range', 'trg_date_range_type'] @@ -225,6 +226,33 @@ class base_action_rule(osv.osv): return write + def make_unlink(): + def unlink(self, cr, uid, ids, context=None, **kwargs): + if context and context.get('action'): + return unlink.origin(self, cr, uid, ids, vals, context=context) + + # modify context + context = dict(context or {}, action=True) + ids = [ids] if isinstance(ids, (int, long, str)) else ids + + # retrieve the action rules to possibly execute + action_model = self.pool.get('base.action.rule') + action_dom = [('model', '=', self._name), + ('kind', '=', 'on_unlink')] + action_ids = action_model.search(cr, uid, action_dom, context=context) + actions = action_model.browse(cr, uid, action_ids, context=context) + + # check conditions, and execute actions on the records that satisfy them + for action in actions: + pre_ids = action_model._filter(cr, uid, action, action.filter_id, ids, domain=action.filter_domain, context=context) + if pre_ids: + action_model._process(cr, uid, action, pre_ids, context=context) + + # call original method + return unlink.origin(self, cr, uid, ids, context=context, **kwargs) + + return unlink + updated = False if ids is None: ids = self.search(cr, SUPERUSER_ID, []) @@ -235,6 +263,7 @@ class base_action_rule(osv.osv): # monkey-patch methods create and write model_obj._patch_method('create', make_create()) model_obj._patch_method('write', make_write()) + model_obj._patch_method('unlink', make_unlink()) model_obj.base_action_ruled = True updated = True From 3fe119957299ee3c3546363e194da7b4bce6fee8 Mon Sep 17 00:00:00 2001 From: Thomas Groutars Date: Wed, 25 Mar 2015 12:36:16 +0100 Subject: [PATCH 3/7] [IMP] Allow to define custom onchanges --- addons/base_action_rule/base_action_rule.py | 38 ++++++++++++++++++- .../base_action_rule_view.xml | 2 + openerp/addons/base/ir/ir_actions.py | 2 + 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py index 3de35a4ae74..535ed4e3847 100644 --- a/addons/base_action_rule/base_action_rule.py +++ b/addons/base_action_rule/base_action_rule.py @@ -51,6 +51,7 @@ class base_action_rule(osv.osv): ('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'), 'trg_date_id': fields.many2one('ir.model.fields', string='Trigger Date', @@ -83,6 +84,7 @@ class base_action_rule(osv.osv): 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('Last Run', readonly=1, copy=False), + 'on_change_field_ids' : fields.many2many('ir.model.fields', domain="[('model_id', '=', model_id)]", string="On Change Fields Trigger"), } _defaults = { @@ -148,6 +150,29 @@ class base_action_rule(osv.osv): return True + @openerp.api.multi + def _register_onchange(self): + def make_onchange(action_rule_id): + def base_action_rule_onchange(self): + action_rule = self.env['base.action.rule'].search([('id', '=', action_rule_id)]) + if not action_rule: + return + server_actions = action_rule.server_action_ids.with_context(active_model=self._name, onchange_self=self) + vals = {} + for server_action in server_actions: + res = server_action.run() + vals.update(res and res.get('value') or {}) + vals.pop('id', None) + self.update(self._convert_to_cache(vals, validate=False)) + return base_action_rule_onchange + + for action_rule in self: + if action_rule.kind != 'on_change': + continue + model = self.env[action_rule.model_id.model] + for field in action_rule.on_change_field_ids: + model._onchange_methods[field.name].append(make_onchange(action_rule.id)) + def _register_hook(self, cr, ids=None): """ Wrap the methods `create` and `write` of the models specified by the rules given by `ids` (or all existing rules if `ids` is `None`.) @@ -256,6 +281,7 @@ class base_action_rule(osv.osv): updated = False if ids is None: ids = self.search(cr, SUPERUSER_ID, []) + self._register_onchange(cr, SUPERUSER_ID, ids) for action_rule in self.browse(cr, SUPERUSER_ID, ids): model = action_rule.model_id.model model_obj = self.pool.get(model) @@ -278,6 +304,15 @@ class base_action_rule(osv.osv): return cron.toggle(model=self._name, domain=[('kind', '=', 'on_time')]) + @openerp.api.one + def _purge_custom_onchange(self): + if self.kind != 'on_change': + return + model = self.env[self.model_id.model] + for field in self.on_change_field_ids: + if model._onchange_methods.get(field.name): + model._onchange_methods[field.name] = [method for method in model._onchange_methods[field.name] if method.func_name != 'base_action_rule_onchange'] + def create(self, cr, uid, vals, context=None): res_id = super(base_action_rule, self).create(cr, uid, vals, context=context) if self._register_hook(cr, [res_id]): @@ -288,6 +323,7 @@ class base_action_rule(osv.osv): def write(self, cr, uid, ids, vals, context=None): if isinstance(ids, (int, long)): ids = [ids] + self._purge_custom_onchange(cr, uid, ids, context=context) super(base_action_rule, self).write(cr, uid, ids, vals, context=context) if self._register_hook(cr, ids): openerp.modules.registry.RegistryManager.signal_registry_change(cr.dbname) @@ -300,7 +336,7 @@ class base_action_rule(osv.osv): return res def onchange_model_id(self, cr, uid, ids, model_id, context=None): - data = {'model': False, 'filter_pre_id': False, 'filter_id': False} + data = {'model': False, 'filter_pre_id': False, 'filter_id': False, 'on_change_field_ids': False} if model_id: model = self.pool.get('ir.model').browse(cr, uid, model_id, context=context) data.update({'model': model.model}) diff --git a/addons/base_action_rule/base_action_rule_view.xml b/addons/base_action_rule/base_action_rule_view.xml index 8e5ac4a651c..71f3137006d 100644 --- a/addons/base_action_rule/base_action_rule_view.xml +++ b/addons/base_action_rule/base_action_rule_view.xml @@ -46,6 +46,8 @@ class="oe_inline" context="{'default_model_id': model}" on_change="onchange_filter_id(filter_id, context)"/> +