From 16e8bdc6b292082f962cfb6a193a21ef6cbda090 Mon Sep 17 00:00:00 2001
From: Yannick Vaucher
Date: Thu, 10 May 2012 15:50:20 +0200
Subject: [PATCH 01/49] [IMP] base_action_rule - Allow using any object dates
as a triggering date
bzr revid: yannick.vaucher@camptocamp.com-20120510135020-x7m08ojkxjzy4fs9
---
addons/base_action_rule/base_action_rule.py | 47 ++++++++-----------
.../base_action_rule_view.xml | 4 +-
2 files changed, 21 insertions(+), 30 deletions(-)
diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py
index 50ebd96a3c2..c558939470e 100644
--- a/addons/base_action_rule/base_action_rule.py
+++ b/addons/base_action_rule/base_action_rule.py
@@ -37,7 +37,7 @@ def get_datetime(date_field):
date_split = date_field.split(' ')
if len(date_split) == 1:
date_field = date_split[0] + " 00:00:00"
-
+
return datetime.strptime(date_field[:19], '%Y-%m-%d %H:%M:%S')
@@ -79,13 +79,10 @@ class base_action_rule(osv.osv):
it will allow you to hide the rule without removing it."),
'sequence': fields.integer('Sequence', help="Gives the sequence order \
when displaying a list of rules."),
- 'trg_date_type': fields.selection([
- ('none', 'None'),
- ('create', 'Creation Date'),
- ('action_last', 'Last Action Date'),
- ('date', 'Date'),
- ('deadline', 'Deadline'),
- ], 'Trigger Date', size=16),
+ 'trg_date_id': fields.many2one('ir.model.fields',
+ 'Trigger Date',
+ domain="[('model_id', '=', model_id),"
+ "('ttype','in',('date','datetime'))]"),
'trg_date_range': fields.integer('Delay after trigger date', \
help="Delay After Trigger Date,\
specifies you can put a negative number. If you need a delay before the \
@@ -132,7 +129,6 @@ the rule to mark CC(mail to any other person defined in actions)."),
_defaults = {
'active': lambda *a: True,
- 'trg_date_type': lambda *a: 'none',
'trg_date_range_type': lambda *a: 'day',
'act_mail_to_user': lambda *a: 0,
'act_remind_partner': lambda *a: 0,
@@ -168,7 +164,7 @@ the rule to mark CC(mail to any other person defined in actions)."),
obj = self.pool.get(obj_name)
# If the rule doesn't involve a time condition, run it immediately
# Otherwise we let the scheduler run the action
- if self.browse(cr, uid, rule_id, context=context).trg_date_type == 'none':
+ if not self.browse(cr, uid, rule_id, context=context).trg_date_id:
self._action(cr, uid, [rule_id], obj.browse(cr, uid, ids, context=context), context=context)
return True
@@ -185,7 +181,7 @@ the rule to mark CC(mail to any other person defined in actions)."),
self.post_action(cr, uid, [new_id], model, context=context)
return new_id
return wrapper
-
+
def _write(self, old_write, model, context=None):
"""
Return a wrapper around `old_write` calling both `old_write` and
@@ -230,7 +226,7 @@ the rule to mark CC(mail to any other person defined in actions)."),
def _check(self, cr, uid, automatic=False, use_new_cursor=False, \
context=None):
"""
- This Function is call by scheduler.
+ This Function is called by scheduler.
"""
rule_pool = self.pool.get('base.action.rule')
rule_ids = rule_pool.search(cr, uid, [], context=context)
@@ -248,22 +244,17 @@ the rule to mark CC(mail to any other person defined in actions)."),
obj = model_pool.browse(cr, uid, obj_id, context=context)
# Calculate when this action should next occur for this object
base = False
- if rule.trg_date_type=='create' and hasattr(obj, 'create_date'):
- base = obj.create_date
- elif (rule.trg_date_type=='action_last'
- and hasattr(obj, 'create_date')):
- if hasattr(obj, 'date_action_last') and obj.date_action_last:
- base = obj.date_action_last
- else:
- base = obj.create_date
- elif (rule.trg_date_type=='deadline'
- and hasattr(obj, 'date_deadline')
- and obj.date_deadline):
- base = obj.date_deadline
- elif (rule.trg_date_type=='date'
- and hasattr(obj, 'date')
- and obj.date):
- base = obj.date
+ if rule.trg_date_id:
+ date_type = rule.trg_date_id.name
+ if (date_type=='date_action_last'
+ and hasattr(obj, 'create_date')):
+ if hasattr(obj, 'date_action_last') and obj.date_action_last:
+ base = obj.date_action_last
+ else:
+ base = obj.create_date
+ elif (hasattr(obj, date_type)
+ and obj.read([date_type])[0][date_type]):
+ base = obj.read([date_type])[0][date_type]
if base:
fnct = {
'minutes': lambda interval: timedelta(minutes=interval),
diff --git a/addons/base_action_rule/base_action_rule_view.xml b/addons/base_action_rule/base_action_rule_view.xml
index 4ba7e6f9018..b041d322193 100644
--- a/addons/base_action_rule/base_action_rule_view.xml
+++ b/addons/base_action_rule/base_action_rule_view.xml
@@ -39,8 +39,8 @@
-
-
+
+
From db5a4e70751cc3f1bdd7f72cacdcf3c7292614c5 Mon Sep 17 00:00:00 2001
From: Arnaud Pineux
Date: Fri, 23 Nov 2012 11:31:13 +0100
Subject: [PATCH 02/49] [FIX] 1st test for automated action
bzr revid: api@openerp.com-20121123103113-x9rspq1oh1887153
---
addons/base_action_rule/base_action_rule.py | 50 +++++++++++++--------
addons/base_status/base_stage.py | 8 +---
addons/base_status/base_state.py | 3 +-
addons/crm/crm_action_rule.py | 4 +-
addons/crm/crm_lead.py | 13 ++++--
addons/crm_claim/crm_claim.py | 6 ++-
6 files changed, 51 insertions(+), 33 deletions(-)
diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py
index 856d2626f69..349721db8c4 100644
--- a/addons/base_action_rule/base_action_rule.py
+++ b/addons/base_action_rule/base_action_rule.py
@@ -109,7 +109,7 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
_order = 'sequence'
- def post_action(self, cr, uid, ids, model, context=None):
+ def post_action(self, cr, uid, ids, model, old_records_states=None, context=None):
# Searching for action rules
cr.execute("SELECT model.model, rule.id FROM base_action_rule rule \
LEFT JOIN ir_model model on (model.id = rule.model_id) \
@@ -117,11 +117,11 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
res = cr.fetchall()
# Check if any rule matching with current object
for obj_name, rule_id in res:
- obj = self.pool.get(obj_name)
+ model_pool = self.pool.get(obj_name)
# If the rule doesn't involve a time condition, run it immediately
# Otherwise we let the scheduler run the action
if self.browse(cr, uid, rule_id, context=context).trg_date_type == 'none':
- self._action(cr, uid, [rule_id], obj.browse(cr, uid, ids, context=context), context=context)
+ self._action(cr, uid, [rule_id], model_pool.browse(cr, uid, ids, context=context), old_records_states=old_records_states, context=context)
return True
def _create(self, old_create, model, context=None):
@@ -144,13 +144,23 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
`post_action`, in that order.
"""
def wrapper(cr, uid, ids, vals, context=context):
+ old_records_states = {}
if context is None:
context = {}
if isinstance(ids, (str, int, long)):
ids = [ids]
+ model_pool = self.pool.get(model)
+ # get the old records (before the write)
+ if model and ids:
+ for record in model_pool.browse(cr,uid,ids,context=context):
+ old_records_states[record.id] = record.state
+ #old_records = model_pool.browse(cr,uid,ids,context=context)
+ #print old_records[0]
+ #print old_records[0].state
old_write(cr, uid, ids, vals, context=context)
+ #print old_records[0].state
if not context.get('action'):
- self.post_action(cr, uid, ids, model, context=context)
+ self.post_action(cr, uid, ids, model, old_records_states=old_records_states, context=context)
return True
return wrapper
@@ -242,7 +252,7 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
- def do_check(self, cr, uid, action, obj, context=None):
+ def do_check(self, cr, uid, action, obj, old_records_states=None, context=None):
""" check Action """
if context is None:
context = {}
@@ -263,14 +273,21 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
(action.trg_partner_categ_id.id in map(lambda x: x.id, obj.partner_id.category_id or []))
)
)
- state_to = context.get('state_to', False)
- state = getattr(obj, 'state', False)
- if state:
- ok = ok and (not action.trg_state_from or action.trg_state_from==state)
- if state_to:
- ok = ok and (not action.trg_state_to or action.trg_state_to==state_to)
- elif action.trg_state_to:
- ok = False
+ #state_to = the state after a write or a create
+ state_to = getattr(obj, 'state', False)
+ #state_from = nothing or the state of old_records
+ state_from = ""
+ if old_records_states != None:
+ if old_records_states[obj.id]:
+ state_from = old_records_states[obj.id]
+ #if we have an action that check the status
+ if action.trg_state_from:
+ print action.trg_state_from, " and ", state_to
+ ok = ok and action.trg_state_from==state_to
+ if action.trg_state_to:
+ print action.trg_state_to, " for ", state_from, " and ", state_to
+ ok = state_from!=state_to
+ ok = ok and action.trg_state_to==state_to
reg_name = action.regex_name
result_name = True
if reg_name:
@@ -312,19 +329,16 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
model_obj.message_subscribe(cr, uid, [obj.id], new_followers, context=context)
return True
- def _action(self, cr, uid, ids, objects, scrit=None, context=None):
+ def _action(self, cr, uid, ids, objects, scrit=None, old_records_states=None, context=None):
""" Do Action """
if context is None:
context = {}
-
context.update({'action': True})
- if not scrit:
- scrit = []
if not isinstance(objects, list):
objects = [objects]
for action in self.browse(cr, uid, ids, context=context):
for obj in objects:
- if self.do_check(cr, uid, action, obj, context=context):
+ if self.do_check(cr, uid, action, obj, old_records_states=old_records_states, context=context):
self.do_action(cr, uid, action, obj, context=context)
context.update({'action': False})
diff --git a/addons/base_status/base_stage.py b/addons/base_status/base_stage.py
index 86edff46920..ba4f62a181a 100644
--- a/addons/base_status/base_stage.py
+++ b/addons/base_status/base_stage.py
@@ -19,6 +19,7 @@
#
##############################################################################
+import pdb
from osv import fields, osv
from tools.translate import _
@@ -280,15 +281,10 @@ class base_stage(object):
# 2. update values
if values_to_update:
self.write(cr, uid, ids, values_to_update, context=context)
- # 3. call _action for base action rule
- if new_state_name:
- self._action(cr, uid, cases, new_state_name, context=context)
- elif not (new_stage_id is None):
- new_state_name = self.read(cr, uid, ids, ['state'], context=context)[0]['state']
- self._action(cr, uid, cases, new_state_name, context=context)
return True
def _action(self, cr, uid, cases, state_to, scrit=None, context=None):
+ print "--- Base_Stage (_action) ---"
if context is None:
context = {}
context['state_to'] = state_to
diff --git a/addons/base_status/base_state.py b/addons/base_status/base_state.py
index cebf5537485..aad9129406e 100644
--- a/addons/base_status/base_state.py
+++ b/addons/base_status/base_state.py
@@ -157,13 +157,14 @@ class base_state(object):
:params: update_values: values that will be added with the state
update when writing values to the record.
"""
+ print "-------------------------BASE STATE--------------------------------"
cases = self.browse(cr, uid, ids, context=context)
cases[0].state # fill browse record cache, for _action having old and new values
if update_values is None:
update_values = {}
update_values['state'] = state_name
self.write(cr, uid, ids, update_values, context=context)
- self._action(cr, uid, cases, state_name, context=context)
+ #self._action(cr, uid, cases, state_name, context=context)
def _action(self, cr, uid, cases, state_to, scrit=None, context=None):
if context is None:
diff --git a/addons/crm/crm_action_rule.py b/addons/crm/crm_action_rule.py
index 4a8ee98fbae..d7caafd7d1d 100644
--- a/addons/crm/crm_action_rule.py
+++ b/addons/crm/crm_action_rule.py
@@ -43,8 +43,8 @@ class base_action_rule(osv.osv):
'act_categ_id': fields.many2one('crm.case.categ', 'Set Category to'),
}
- def do_check(self, cr, uid, action, obj, context=None):
- ok = super(base_action_rule, self).do_check(cr, uid, action, obj, context=context)
+ def do_check(self, cr, uid, action, obj, old_records_states=None, context=None):
+ ok = super(base_action_rule, self).do_check(cr, uid, action, obj, old_records_states=old_records_states, context=context)
if hasattr(obj, 'section_id'):
ok = ok and (not action.trg_section_id or action.trg_section_id.id == obj.section_id.id)
diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py
index 0a824aef83e..b9d92639e63 100644
--- a/addons/crm/crm_lead.py
+++ b/addons/crm/crm_lead.py
@@ -29,6 +29,7 @@ from tools.translate import _
from tools import html2plaintext
from base.res.res_partner import format_address
+import pdb
CRM_LEAD_PENDING_STATES = (
crm.AVAILABLE_STATES[2][0], # Cancelled
@@ -380,8 +381,10 @@ class crm_lead(base_stage, format_address, osv.osv):
""" Mark the case as lost: state=cancel and probability=0 """
for lead in self.browse(cr, uid, ids):
stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 0.0)], context=context)
- if stage_id:
- self.case_set(cr, uid, [lead.id], values_to_update={'probability': 0.0}, new_stage_id=stage_id, context=context)
+ if not stage_id:
+ return False
+ else:
+ self.write(cr, uid, ids, {'probability' : 0.0, 'stage_id' : stage_id}, context=context)
self.case_mark_lost_send_note(cr, uid, ids, context=context)
return True
@@ -389,8 +392,10 @@ class crm_lead(base_stage, format_address, osv.osv):
""" Mark the case as lost: state=done and probability=100 """
for lead in self.browse(cr, uid, ids):
stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 100.0)], context=context)
- if stage_id:
- self.case_set(cr, uid, [lead.id], values_to_update={'probability': 100.0}, new_stage_id=stage_id, context=context)
+ if not stage_id:
+ return False
+ else:
+ self.write(cr, uid, ids, {'probability' : 100.0, 'stage_id' : stage_id}, context=context)
self.case_mark_won_send_note(cr, uid, ids, context=context)
return True
diff --git a/addons/crm_claim/crm_claim.py b/addons/crm_claim/crm_claim.py
index 70dcc18baf7..5c141c81080 100644
--- a/addons/crm_claim/crm_claim.py
+++ b/addons/crm_claim/crm_claim.py
@@ -167,8 +167,10 @@ class crm_claim(base_stage, osv.osv):
""" Mark the case as refused: state=done and case_refused=True """
for lead in self.browse(cr, uid, ids):
stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, ['&', ('state', '=', 'done'), ('case_refused', '=', True)], context=context)
- if stage_id:
- self.case_set(cr, uid, [lead.id], values_to_update={}, new_stage_id=stage_id, context=context)
+ if not stage_id:
+ return False
+ else:
+ self.write(cr, uid, ids, {'stage_id' : stage_id}, context=context)
return self.case_refuse_send_note(cr, uid, ids, context=context)
def onchange_partner_id(self, cr, uid, ids, part, email=False):
From 72616d0ba2b355004f28590d3815ca18137c66c9 Mon Sep 17 00:00:00 2001
From: Arnaud Pineux
Date: Mon, 26 Nov 2012 12:22:48 +0100
Subject: [PATCH 03/49] [FIX] Automated Action Rules
bzr revid: api@openerp.com-20121126112248-oiq40hn9lgro0lq4
---
addons/base_action_rule/base_action_rule.py | 29 +++++++++++--------
.../base_action_rule_view.xml | 2 +-
2 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py
index 0e9db7fc60d..71b376f6946 100644
--- a/addons/base_action_rule/base_action_rule.py
+++ b/addons/base_action_rule/base_action_rule.py
@@ -23,6 +23,7 @@ from datetime import datetime
from datetime import timedelta
import re
import time
+from openerp import SUPERUSER_ID
from osv import fields, osv, orm
from tools.translate import _
@@ -54,7 +55,7 @@ class base_action_rule(osv.osv):
def state_get(self, cr, uid, context=None):
""" Get State """
- return [('', '')]
+ return [('', ''), ('na','N/A (No previous state)')]
def priority_get(self, cr, uid, context=None):
""" Get Priority """
@@ -86,8 +87,8 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
'trg_user_id': fields.many2one('res.users', 'Responsible'),
'trg_partner_id': fields.many2one('res.partner', 'Partner'),
'trg_partner_categ_id': fields.many2one('res.partner.category', 'Partner Category'),
- 'trg_state_from': fields.selection(_state_get, 'Status', size=16),
- 'trg_state_to': fields.selection(_state_get, 'Button Pressed', size=16),
+ 'trg_state_from': fields.selection(_state_get, 'and previously was', size=16),
+ 'trg_state_to': fields.selection(_state_get, 'Status changes to', size=16),
'act_user_id': fields.many2one('res.users', 'Set Responsible to'),
'act_state': fields.selection(_state_get, 'Set State to', size=16),
@@ -162,29 +163,30 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
return True
return wrapper
- def _register_hook(self, cr, uid, ids, context=None):
+ def _register_hook(self, cr):
"""
Wrap every `create` and `write` methods of the models specified by
the rules (given by `ids`).
"""
- for action_rule in self.browse(cr, uid, ids, context=context):
+ ids = self.search(cr,SUPERUSER_ID,[])
+ for action_rule in self.browse(cr, SUPERUSER_ID, ids, context=None):
model = action_rule.model_id.model
obj_pool = self.pool.get(model)
if not hasattr(obj_pool, 'base_action_ruled'):
- obj_pool.create = self._create(obj_pool.create, model, context=context)
- obj_pool.write = self._write(obj_pool.write, model, context=context)
+ obj_pool.create = self._create(obj_pool.create, model, context=None)
+ obj_pool.write = self._write(obj_pool.write, model, context=None)
obj_pool.base_action_ruled = True
return True
def create(self, cr, uid, vals, context=None):
res_id = super(base_action_rule, self).create(cr, uid, vals, context=context)
- self._register_hook(cr, uid, [res_id], context=context)
+ self._register_hook(cr)
return res_id
def write(self, cr, uid, ids, vals, context=None):
super(base_action_rule, self).write(cr, uid, ids, vals, context=context)
- self._register_hook(cr, uid, ids, context=context)
+ self._register_hook(cr)
return True
def _check(self, cr, uid, automatic=False, use_new_cursor=False, \
@@ -278,11 +280,14 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
if old_records != None:
for record in old_records:
state_from = record.state
+ else:
+ state_from = "na"
#if we have an action that check the status
- if action.trg_state_from:
- ok = ok and action.trg_state_from==state_to
if action.trg_state_to:
- ok = state_from!=state_to
+ if action.trg_state_from:
+ ok = ok and action.trg_state_from==state_from
+ else:
+ ok = state_from!=state_to
ok = ok and action.trg_state_to==state_to
reg_name = action.regex_name
result_name = True
diff --git a/addons/base_action_rule/base_action_rule_view.xml b/addons/base_action_rule/base_action_rule_view.xml
index bb711be9928..4815baa9ebb 100644
--- a/addons/base_action_rule/base_action_rule_view.xml
+++ b/addons/base_action_rule/base_action_rule_view.xml
@@ -33,8 +33,8 @@
-
+
From 041e43967c7a705a4a487d02577b476ff8ad8b57 Mon Sep 17 00:00:00 2001
From: Arnaud Pineux
Date: Mon, 26 Nov 2012 12:44:05 +0100
Subject: [PATCH 04/49] [IMP] add comment
bzr revid: api@openerp.com-20121126114405-s3b3lo6qncho2n37
---
addons/base_action_rule/base_action_rule.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py
index 71b376f6946..8892bec34f2 100644
--- a/addons/base_action_rule/base_action_rule.py
+++ b/addons/base_action_rule/base_action_rule.py
@@ -281,7 +281,7 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
for record in old_records:
state_from = record.state
else:
- state_from = "na"
+ state_from = "na" #it means that there was no state before (creation for example)
#if we have an action that check the status
if action.trg_state_to:
if action.trg_state_from:
From 8474567cdf5a0df9be8963abf6a8598eeabee17c Mon Sep 17 00:00:00 2001
From: Arnaud Pineux
Date: Mon, 26 Nov 2012 13:51:42 +0100
Subject: [PATCH 05/49] [FIX] Automated Action rule (register_hook)
bzr revid: api@openerp.com-20121126125142-9gpsupy7617vddya
---
addons/base_action_rule/base_action_rule.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py
index 8892bec34f2..693d46b9021 100644
--- a/addons/base_action_rule/base_action_rule.py
+++ b/addons/base_action_rule/base_action_rule.py
@@ -195,7 +195,7 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
This Function is call by scheduler.
"""
rule_ids = self.search(cr, uid, [], context=context)
- self._register_hook(cr, uid, rule_ids, context=context)
+ self._register_hook(cr)
if context is None:
context = {}
for rule in self.browse(cr, uid, rule_ids, context=context):
From 41e9eadc6197b9082ac6e32c45330956ee469096 Mon Sep 17 00:00:00 2001
From: Arnaud Pineux
Date: Mon, 26 Nov 2012 14:10:17 +0100
Subject: [PATCH 06/49] [FIX] _register_hook refactored
bzr revid: api@openerp.com-20121126131017-55e2x4e75nmabt27
---
addons/base_action_rule/base_action_rule.py | 23 +++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py
index 693d46b9021..11d62404502 100644
--- a/addons/base_action_rule/base_action_rule.py
+++ b/addons/base_action_rule/base_action_rule.py
@@ -169,7 +169,22 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
the rules (given by `ids`).
"""
ids = self.search(cr,SUPERUSER_ID,[])
- for action_rule in self.browse(cr, SUPERUSER_ID, ids, context=None):
+ return self._register_hook_(cr,SUPERUSER_ID,ids,context=None)
+ #for action_rule in self.browse(cr, SUPERUSER_ID, ids, context=None):
+ # model = action_rule.model_id.model
+ # obj_pool = self.pool.get(model)
+ # if not hasattr(obj_pool, 'base_action_ruled'):
+ # obj_pool.create = self._create(obj_pool.create, model, context=None)
+ # obj_pool.write = self._write(obj_pool.write, model, context=None)
+ # obj_pool.base_action_ruled = True
+ #return True
+
+ def _register_hook_(self, cr, uid, ids, context=None):
+ """
+ Wrap every `create` and `write` methods of the models specified by
+ the rules (given by `ids`).
+ """
+ for action_rule in self.browse(cr, uid, ids, context=context):
model = action_rule.model_id.model
obj_pool = self.pool.get(model)
if not hasattr(obj_pool, 'base_action_ruled'):
@@ -181,12 +196,12 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
def create(self, cr, uid, vals, context=None):
res_id = super(base_action_rule, self).create(cr, uid, vals, context=context)
- self._register_hook(cr)
+ self._register_hook_(cr, uid, res_id,context=context)
return res_id
def write(self, cr, uid, ids, vals, context=None):
super(base_action_rule, self).write(cr, uid, ids, vals, context=context)
- self._register_hook(cr)
+ self._register_hook_(cr, uid, ids, context=context)
return True
def _check(self, cr, uid, automatic=False, use_new_cursor=False, \
@@ -195,7 +210,7 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
This Function is call by scheduler.
"""
rule_ids = self.search(cr, uid, [], context=context)
- self._register_hook(cr)
+ self._register_hook_(cr, uid, rule_ids, context=context)
if context is None:
context = {}
for rule in self.browse(cr, uid, rule_ids, context=context):
From 9137243cdc48d5f3e89b16b7ec56f95cb1ef894a Mon Sep 17 00:00:00 2001
From: Arnaud Pineux
Date: Mon, 26 Nov 2012 14:32:57 +0100
Subject: [PATCH 07/49] [FIX] _register_hook refactored (test)
bzr revid: api@openerp.com-20121126133257-f9j7vfgdfkqjewyn
---
addons/base_action_rule/base_action_rule.py | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py
index 11d62404502..14da227a367 100644
--- a/addons/base_action_rule/base_action_rule.py
+++ b/addons/base_action_rule/base_action_rule.py
@@ -170,28 +170,24 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
"""
ids = self.search(cr,SUPERUSER_ID,[])
return self._register_hook_(cr,SUPERUSER_ID,ids,context=None)
- #for action_rule in self.browse(cr, SUPERUSER_ID, ids, context=None):
- # model = action_rule.model_id.model
- # obj_pool = self.pool.get(model)
- # if not hasattr(obj_pool, 'base_action_ruled'):
- # obj_pool.create = self._create(obj_pool.create, model, context=None)
- # obj_pool.write = self._write(obj_pool.write, model, context=None)
- # obj_pool.base_action_ruled = True
- #return True
def _register_hook_(self, cr, uid, ids, context=None):
"""
Wrap every `create` and `write` methods of the models specified by
the rules (given by `ids`).
"""
- for action_rule in self.browse(cr, uid, ids, context=context):
+ reg_ids = []
+ if not isinstance(ids, list):
+ reg_ids.append(ids)
+ else:
+ reg_ids.extend(ids)
+ for action_rule in self.browse(cr, uid, reg_ids, context=context):
model = action_rule.model_id.model
obj_pool = self.pool.get(model)
if not hasattr(obj_pool, 'base_action_ruled'):
obj_pool.create = self._create(obj_pool.create, model, context=None)
obj_pool.write = self._write(obj_pool.write, model, context=None)
obj_pool.base_action_ruled = True
-
return True
def create(self, cr, uid, vals, context=None):
From 100f3199e7120948dcc24aed555e8323ba0871aa Mon Sep 17 00:00:00 2001
From: Arnaud Pineux
Date: Mon, 26 Nov 2012 15:03:30 +0100
Subject: [PATCH 08/49] [IMP] Test for automated action rules
bzr revid: api@openerp.com-20121126140330-maut337p5q8fsglo
---
.../test/base_action_rule_test.py | 111 ++++++++++++++++++
1 file changed, 111 insertions(+)
create mode 100644 addons/base_action_rule/test/base_action_rule_test.py
diff --git a/addons/base_action_rule/test/base_action_rule_test.py b/addons/base_action_rule/test/base_action_rule_test.py
new file mode 100644
index 00000000000..41eb0e31746
--- /dev/null
+++ b/addons/base_action_rule/test/base_action_rule_test.py
@@ -0,0 +1,111 @@
+import tools
+from openerp.tests import common
+
+class myLead(orm.Model):
+
+ _name = name('base_action_rule.myLead')
+
+ _columns = {
+ 'partner_id': fields.many2one('res.partner', 'Partner', ondelete='set null',
+ select=True, help="Linked partner (optional). Usually created when converting the lead."),
+ 'id': fields.integer('ID', readonly=True),
+ 'name': fields.char('Subject', size=64, required=True, select=1),
+ 'active': fields.boolean('Active', required=False),
+ 'date_action_last': fields.datetime('Last Action', readonly=1),
+ 'date_action_next': fields.datetime('Next Action', readonly=1),
+ 'email_from': fields.char('Email', size=128, help="Email address of the contact", select=1),
+ 'section_id': fields.many2one('crm.case.section', 'Sales Team', \
+ select=True, help='When sending mails, the default email address is taken from the sales team.'),
+ 'create_date': fields.datetime('Creation Date' , readonly=True),
+ 'email_cc': fields.text('Global CC', size=252 , help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
+ 'description': fields.text('Notes'),
+ 'write_date': fields.datetime('Update Date' , readonly=True),
+ 'categ_ids': fields.many2many('crm.case.categ', 'crm_lead_category_rel', 'lead_id', 'category_id', 'Categories', \
+ domain="['|',('section_id','=',section_id),('section_id','=',False), ('object_id.model', '=', 'crm.lead')]"),
+ 'type_id': fields.many2one('crm.case.resource.type', 'Campaign', \
+ domain="['|',('section_id','=',section_id),('section_id','=',False)]", help="From which campaign (seminar, marketing campaign, mass mailing, ...) did this contact come from?"),
+ 'channel_id': fields.many2one('crm.case.channel', 'Channel', help="Communication channel (mail, direct, phone, ...)"),
+ 'contact_name': fields.char('Contact Name', size=64),
+ 'partner_name': fields.char("Customer Name", size=64,help='The name of the future partner company that will be created while converting the lead into opportunity', select=1),
+ 'opt_out': fields.boolean('Opt-Out', oldname='optout', help="If opt-out is checked, this contact has refused to receive emails or unsubscribed to a campaign."),
+ 'type':fields.selection([ ('lead','Lead'), ('opportunity','Opportunity'), ],'Type', help="Type is used to separate Leads and Opportunities"),
+ 'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority', select=True),
+ 'date_closed': fields.datetime('Closed', readonly=True),
+ 'stage_id': fields.many2one('crm.case.stage', 'Stage',
+ domain="['&', ('fold', '=', False), '&', '|', ('section_ids', '=', section_id), ('case_default', '=', True), '|', ('type', '=', type), ('type', '=', 'both')]"),
+ 'user_id': fields.many2one('res.users', 'Salesperson'),
+ 'referred': fields.char('Referred By', size=64),
+ 'date_open': fields.datetime('Opened', readonly=True),
+ 'day_open': fields.function(_compute_day, string='Days to Open', \
+ multi='day_open', type="float", store=True),
+ 'day_close': fields.function(_compute_day, string='Days to Close', \
+ multi='day_close', type="float", store=True),
+ 'state': fields.related('stage_id', 'state', type="selection", store=True,
+ selection=crm.AVAILABLE_STATES, string="Status", readonly=True,
+ help='The Status is set to \'Draft\', when a case is created. If the case is in progress the Status is set to \'Open\'. When the case is over, the Status is set to \'Done\'. If the case needs to be reviewed then the Status is set to \'Pending\'.'),
+
+ # Only used for type opportunity
+ 'probability': fields.float('Success Rate (%)',group_operator="avg"),
+ 'planned_revenue': fields.float('Expected Revenue'),
+ 'ref': fields.reference('Reference', selection=crm._links_get, size=128),
+ 'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128),
+ 'phone': fields.char("Phone", size=64),
+ 'date_deadline': fields.date('Expected Closing', help="Estimate of the date on which the opportunity will be won."),
+ 'date_action': fields.date('Next Action Date', select=True),
+ 'title_action': fields.char('Next Action', size=64),
+ 'color': fields.integer('Color Index'),
+ 'partner_address_name': fields.related('partner_id', 'name', type='char', string='Partner Contact Name', readonly=True),
+ 'partner_address_email': fields.related('partner_id', 'email', type='char', string='Partner Contact Email', readonly=True),
+ 'company_currency': fields.related('company_id', 'currency_id', type='many2one', string='Currency', readonly=True, relation="res.currency"),
+ 'user_email': fields.related('user_id', 'email', type='char', string='User Email', readonly=True),
+ 'user_login': fields.related('user_id', 'login', type='char', string='User Login', readonly=True),
+
+ # Fields for address, due to separation from crm and res.partner
+ 'street': fields.char('Street', size=128),
+ 'street2': fields.char('Street2', size=128),
+ 'zip': fields.char('Zip', change_default=True, size=24),
+ 'city': fields.char('City', size=128),
+ 'state_id': fields.many2one("res.country.state", 'State'),
+ 'country_id': fields.many2one('res.country', 'Country'),
+ 'phone': fields.char('Phone', size=64),
+ 'fax': fields.char('Fax', size=64),
+ 'mobile': fields.char('Mobile', size=64),
+ 'function': fields.char('Function', size=128),
+ 'title': fields.many2one('res.partner.title', 'Title'),
+ 'company_id': fields.many2one('res.company', 'Company', select=1),
+ 'payment_mode': fields.many2one('crm.payment.mode', 'Payment Mode', \
+ domain="[('section_id','=',section_id)]"),
+ 'planned_cost': fields.float('Planned Costs'),
+ }
+
+ _defaults = {
+ 'active': 1,
+ 'type': 'lead',
+ 'user_id': lambda s, cr, uid, c: s._get_default_user(cr, uid, c),
+ 'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
+ 'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
+ 'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
+ 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.lead', context=c),
+ 'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
+ 'color': 0,
+ }
+
+
+class base_action_rule_test(common.TransactionCase):
+
+ def setUp(self):
+ """*****setUp*****"""
+ super(base_action_rule_test, self).setUp()
+ cr, uid = self.cr, self.uid
+
+ """********TeamCreation******"""
+ self.team_pool = self.pool.get('crm.case.section')
+ self.team_1_id = self.team_pool.create(cr, uid, {
+
+ }, context=None)
+
+ self.myLead_pool = self.pool.get('base_action_rule.myLead')
+ self.new_myLead_id = self.myLead_pool.create(cr, uid, {
+ 'name' : "my_first_lead",
+ 'section_id' :
+ }, context=None)
From a8f351029755cfa4564c8c90931d28f3a3143420 Mon Sep 17 00:00:00 2001
From: Arnaud Pineux
Date: Tue, 27 Nov 2012 10:07:55 +0100
Subject: [PATCH 09/49] [TEST] automated action rule tests
bzr revid: api@openerp.com-20121127090755-03sfycnz8nw9ldnv
---
.../test/base_action_rule_test.py | 111 ------------------
addons/crm/tests/__init__.py | 27 +++++
addons/crm/tests/base_action_rule_test.py | 69 +++++++++++
3 files changed, 96 insertions(+), 111 deletions(-)
delete mode 100644 addons/base_action_rule/test/base_action_rule_test.py
create mode 100644 addons/crm/tests/__init__.py
create mode 100644 addons/crm/tests/base_action_rule_test.py
diff --git a/addons/base_action_rule/test/base_action_rule_test.py b/addons/base_action_rule/test/base_action_rule_test.py
deleted file mode 100644
index 41eb0e31746..00000000000
--- a/addons/base_action_rule/test/base_action_rule_test.py
+++ /dev/null
@@ -1,111 +0,0 @@
-import tools
-from openerp.tests import common
-
-class myLead(orm.Model):
-
- _name = name('base_action_rule.myLead')
-
- _columns = {
- 'partner_id': fields.many2one('res.partner', 'Partner', ondelete='set null',
- select=True, help="Linked partner (optional). Usually created when converting the lead."),
- 'id': fields.integer('ID', readonly=True),
- 'name': fields.char('Subject', size=64, required=True, select=1),
- 'active': fields.boolean('Active', required=False),
- 'date_action_last': fields.datetime('Last Action', readonly=1),
- 'date_action_next': fields.datetime('Next Action', readonly=1),
- 'email_from': fields.char('Email', size=128, help="Email address of the contact", select=1),
- 'section_id': fields.many2one('crm.case.section', 'Sales Team', \
- select=True, help='When sending mails, the default email address is taken from the sales team.'),
- 'create_date': fields.datetime('Creation Date' , readonly=True),
- 'email_cc': fields.text('Global CC', size=252 , help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
- 'description': fields.text('Notes'),
- 'write_date': fields.datetime('Update Date' , readonly=True),
- 'categ_ids': fields.many2many('crm.case.categ', 'crm_lead_category_rel', 'lead_id', 'category_id', 'Categories', \
- domain="['|',('section_id','=',section_id),('section_id','=',False), ('object_id.model', '=', 'crm.lead')]"),
- 'type_id': fields.many2one('crm.case.resource.type', 'Campaign', \
- domain="['|',('section_id','=',section_id),('section_id','=',False)]", help="From which campaign (seminar, marketing campaign, mass mailing, ...) did this contact come from?"),
- 'channel_id': fields.many2one('crm.case.channel', 'Channel', help="Communication channel (mail, direct, phone, ...)"),
- 'contact_name': fields.char('Contact Name', size=64),
- 'partner_name': fields.char("Customer Name", size=64,help='The name of the future partner company that will be created while converting the lead into opportunity', select=1),
- 'opt_out': fields.boolean('Opt-Out', oldname='optout', help="If opt-out is checked, this contact has refused to receive emails or unsubscribed to a campaign."),
- 'type':fields.selection([ ('lead','Lead'), ('opportunity','Opportunity'), ],'Type', help="Type is used to separate Leads and Opportunities"),
- 'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority', select=True),
- 'date_closed': fields.datetime('Closed', readonly=True),
- 'stage_id': fields.many2one('crm.case.stage', 'Stage',
- domain="['&', ('fold', '=', False), '&', '|', ('section_ids', '=', section_id), ('case_default', '=', True), '|', ('type', '=', type), ('type', '=', 'both')]"),
- 'user_id': fields.many2one('res.users', 'Salesperson'),
- 'referred': fields.char('Referred By', size=64),
- 'date_open': fields.datetime('Opened', readonly=True),
- 'day_open': fields.function(_compute_day, string='Days to Open', \
- multi='day_open', type="float", store=True),
- 'day_close': fields.function(_compute_day, string='Days to Close', \
- multi='day_close', type="float", store=True),
- 'state': fields.related('stage_id', 'state', type="selection", store=True,
- selection=crm.AVAILABLE_STATES, string="Status", readonly=True,
- help='The Status is set to \'Draft\', when a case is created. If the case is in progress the Status is set to \'Open\'. When the case is over, the Status is set to \'Done\'. If the case needs to be reviewed then the Status is set to \'Pending\'.'),
-
- # Only used for type opportunity
- 'probability': fields.float('Success Rate (%)',group_operator="avg"),
- 'planned_revenue': fields.float('Expected Revenue'),
- 'ref': fields.reference('Reference', selection=crm._links_get, size=128),
- 'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128),
- 'phone': fields.char("Phone", size=64),
- 'date_deadline': fields.date('Expected Closing', help="Estimate of the date on which the opportunity will be won."),
- 'date_action': fields.date('Next Action Date', select=True),
- 'title_action': fields.char('Next Action', size=64),
- 'color': fields.integer('Color Index'),
- 'partner_address_name': fields.related('partner_id', 'name', type='char', string='Partner Contact Name', readonly=True),
- 'partner_address_email': fields.related('partner_id', 'email', type='char', string='Partner Contact Email', readonly=True),
- 'company_currency': fields.related('company_id', 'currency_id', type='many2one', string='Currency', readonly=True, relation="res.currency"),
- 'user_email': fields.related('user_id', 'email', type='char', string='User Email', readonly=True),
- 'user_login': fields.related('user_id', 'login', type='char', string='User Login', readonly=True),
-
- # Fields for address, due to separation from crm and res.partner
- 'street': fields.char('Street', size=128),
- 'street2': fields.char('Street2', size=128),
- 'zip': fields.char('Zip', change_default=True, size=24),
- 'city': fields.char('City', size=128),
- 'state_id': fields.many2one("res.country.state", 'State'),
- 'country_id': fields.many2one('res.country', 'Country'),
- 'phone': fields.char('Phone', size=64),
- 'fax': fields.char('Fax', size=64),
- 'mobile': fields.char('Mobile', size=64),
- 'function': fields.char('Function', size=128),
- 'title': fields.many2one('res.partner.title', 'Title'),
- 'company_id': fields.many2one('res.company', 'Company', select=1),
- 'payment_mode': fields.many2one('crm.payment.mode', 'Payment Mode', \
- domain="[('section_id','=',section_id)]"),
- 'planned_cost': fields.float('Planned Costs'),
- }
-
- _defaults = {
- 'active': 1,
- 'type': 'lead',
- 'user_id': lambda s, cr, uid, c: s._get_default_user(cr, uid, c),
- 'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
- 'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
- 'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
- 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.lead', context=c),
- 'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
- 'color': 0,
- }
-
-
-class base_action_rule_test(common.TransactionCase):
-
- def setUp(self):
- """*****setUp*****"""
- super(base_action_rule_test, self).setUp()
- cr, uid = self.cr, self.uid
-
- """********TeamCreation******"""
- self.team_pool = self.pool.get('crm.case.section')
- self.team_1_id = self.team_pool.create(cr, uid, {
-
- }, context=None)
-
- self.myLead_pool = self.pool.get('base_action_rule.myLead')
- self.new_myLead_id = self.myLead_pool.create(cr, uid, {
- 'name' : "my_first_lead",
- 'section_id' :
- }, context=None)
diff --git a/addons/crm/tests/__init__.py b/addons/crm/tests/__init__.py
new file mode 100644
index 00000000000..a2de50226da
--- /dev/null
+++ b/addons/crm/tests/__init__.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Business Applications
+# Copyright (c) 2012-TODAY OpenERP S.A.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from . import base_action_rule_test
+
+checks = [
+ base_action_rule_test,
+]
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/crm/tests/base_action_rule_test.py b/addons/crm/tests/base_action_rule_test.py
new file mode 100644
index 00000000000..caca0c635da
--- /dev/null
+++ b/addons/crm/tests/base_action_rule_test.py
@@ -0,0 +1,69 @@
+import tools
+from openerp.tests import common
+
+class base_action_rule_test(common.TransactionCase):
+
+ def setUp(self):
+ """*****setUp*****"""
+ super(base_action_rule_test, self).setUp()
+ cr, uid = self.cr, self.uid
+
+ """*****TeamCreation******"""
+ self.team_pool = self.registry('crm.case.section')
+ self.team_1_id = self.team_pool.create(cr, uid, {
+ 'name' : "Team 1",
+ 'active' : 1,
+ 'user_id' : uid,
+ 'complete_name' : "Test / Team 1",
+ }, context=None)
+ self.team_2_id = self.team_pool.create(cr, uid, {
+ 'name' : "Team 2",
+ 'active' : 1,
+ 'user_id' : uid,
+ 'complete_name' : "Test / Team 2",
+ }, context=None)
+
+ def create_rule_1(self, cr, uid, context=None):
+ """
+ The "Rule 1" says that when a lead goes to the 'open' state, the team responsible for that lead changes to "Team 1"
+ """
+ self.action_pool = self.registry('base.action.rule')
+ self.rule_1_id = self.action_pool.create(cr,uid,{
+ 'name' : "Rule 1",
+ 'model_id' : self.registry('ir.model').search(cr, uid, [('model','=','crm.lead')], context=context)[0],
+ 'active' : 1,
+ 'trg_state_to' : 'open',
+ 'trg_date_type' : 'none',
+ 'act_section_id' : self.team_1_id,
+ }, context=context)
+
+ def create_rule_2(self, cr, uid, context=None):
+ """
+ The "Rule 2" says that when a lead goes from 'open' state to 'done' state, the team responsible for that lead changes to "Team 2"
+ """
+ self.action_pool = self.registry('base.action.rule')
+ self.rule_2_id = self.action_pool.create(cr,uid,{
+ 'name' : "Rule 2",
+ 'model_id' : self.registry('ir.model').search(cr, uid, [('model','=','crm.lead')], context=context)[0],
+ 'active' : 1,
+ 'trg_state_to' : 'done',
+ 'trg_state_from' : 'open',
+ 'trg_date_type' : 'none',
+ 'act_section_id' : self.team_2_id,
+ }, context=context)
+
+ def test_00_check_to_state_draft(self):
+ """
+ This test check that the team change when the state is open but doesn't change when the state is different
+ """
+ cr, uid = self.cr, self.uid
+ context = {}
+ #First we need to create the Rule 1
+ self.create_rule_1(cr, uid, context)
+ #Once it is done, we can create a new lead (with a state = 'draft')
+ #first we get our team 1
+ self.team_1 = self.team_pool.browse(cr,uid,self.team_1_id,context=context)
+ #We get a lead
+ self.lead_1 = self.registry('ir.model.data').get_object_reference(cr, uid, 'crm', 'crm_case_1')
+ #We change the team of crm_case_1
+
From 3df8c5fe9a048eac11d3c50e69bf3263f5b3b980 Mon Sep 17 00:00:00 2001
From: Arnaud Pineux
Date: Wed, 28 Nov 2012 10:29:28 +0100
Subject: [PATCH 10/49] [IMP] Base Action Rule (only filter conditions)
bzr revid: api@openerp.com-20121128092928-7kbs1d9g8ung4oul
---
addons/base_action_rule/__init__.py | 1 +
addons/base_action_rule/base_action_rule.py | 73 ++++-----
.../base_action_rule_view.xml | 32 ++--
addons/base_action_rule/test_models.py | 32 ++++
.../tests/__init__.py | 0
.../tests/base_action_rule_test.py | 142 ++++++++++++++++++
addons/crm/crm_action_rule.py | 4 +-
addons/crm/crm_action_rule_view.xml | 10 --
addons/crm/tests/base_action_rule_test.py | 69 ---------
9 files changed, 228 insertions(+), 135 deletions(-)
create mode 100644 addons/base_action_rule/test_models.py
rename addons/{crm => base_action_rule}/tests/__init__.py (100%)
create mode 100644 addons/base_action_rule/tests/base_action_rule_test.py
delete mode 100644 addons/crm/tests/base_action_rule_test.py
diff --git a/addons/base_action_rule/__init__.py b/addons/base_action_rule/__init__.py
index 207ed3cb30f..c8c827aaba2 100644
--- a/addons/base_action_rule/__init__.py
+++ b/addons/base_action_rule/__init__.py
@@ -20,5 +20,6 @@
##############################################################################
import base_action_rule
+import test_models
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py
index 14da227a367..2b6877a7c9c 100644
--- a/addons/base_action_rule/base_action_rule.py
+++ b/addons/base_action_rule/base_action_rule.py
@@ -97,7 +97,8 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
\ne.g.: 'urgent.*' will search for records having name starting with the string 'urgent'\
\nNote: This is case sensitive search."),
'server_action_ids': fields.one2many('ir.actions.server', 'action_rule_id', 'Server Action', help="Define Server actions.\neg:Email Reminders, Call Object Service, etc.."), #TODO: set domain [('model_id','=',model_id)]
- 'filter_id':fields.many2one('ir.filters', 'Filter', required=False), #TODO: set domain [('model_id','=',model_id.model)]
+ 'filter_id':fields.many2one('ir.filters', 'Precondition Filter', required=False), #TODO: set domain [('model_id','=',model_id.model)]
+ 'filter_post_id': fields.many2one('ir.filters', 'Postcondition Filter', required=False),
'last_run': fields.datetime('Last Run', readonly=1),
}
@@ -110,7 +111,7 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
_order = 'sequence'
- def post_action(self, cr, uid, ids, model, old_records=None, context=None):
+ def post_action(self, cr, uid, ids, model, precondition_ok=None, context=None):
# Searching for action rules
cr.execute("SELECT model.model, rule.id FROM base_action_rule rule \
LEFT JOIN ir_model model on (model.id = rule.model_id) \
@@ -122,7 +123,7 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
# If the rule doesn't involve a time condition, run it immediately
# Otherwise we let the scheduler run the action
if self.browse(cr, uid, rule_id, context=context).trg_date_type == 'none':
- self._action(cr, uid, [rule_id], model_pool.browse(cr, uid, ids, context=context), old_records=old_records, context=context)
+ self._action(cr, uid, [rule_id], model_pool.browse(cr, uid, ids, context=context), precondition_ok=precondition_ok, context=context)
return True
def _create(self, old_create, model, context=None):
@@ -134,8 +135,17 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
if context is None:
context = {}
new_id = old_create(cr, uid, vals, context=context)
+ #As it is a new record, we can assume that the precondition is true for every filter.
+ #(There is nothing before the create so no condition)
+ precondition_ok = {}
+ precondition_ok[new_id] = {}
+ for action in self.browse(cr, uid, self.search(cr, uid, [], context=context), context=context):
+ if action.filter_id:
+ precondition_ok[new_id][action.id] = False
+ else:
+ precondition_ok[new_id][action.id] = True
if not context.get('action'):
- self.post_action(cr, uid, [new_id], model, context=context)
+ self.post_action(cr, uid, [new_id], model, precondition_ok=precondition_ok, context=context)
return new_id
return wrapper
@@ -151,15 +161,22 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
if isinstance(ids, (str, int, long)):
ids = [ids]
model_pool = self.pool.get(model)
- # get the old records (before the write)
- if model and ids:
- old_records = model_pool.browse(cr,uid,ids,context=context)
- # look at records' states to fill the record cache
- for record in old_records:
- record.state
+ # We check for the pre-filter. We must apply it before the write
+ precondition_ok = {}
+ for id in ids:
+ precondition_ok[id] = {}
+ for action in self.browse(cr, uid, self.search(cr, uid, [], context=context), context=context):
+ precondition_ok[id][action.id] = True
+ if action.filter_id and action.model_id.model == action.filter_id.model_id:
+ ctx = dict(context)
+ ctx.update(eval(action.filter_id.context))
+ obj_ids = []
+ if self.pool.get(action.model_id.model)!=None:
+ obj_ids = self.pool.get(action.model_id.model).search(cr, uid, eval(action.filter_id.domain), context=ctx)
+ precondition_ok[id][action.id] = id in obj_ids
old_write(cr, uid, ids, vals, context=context)
if not context.get('action'):
- self.post_action(cr, uid, ids, model, old_records=old_records, context=context)
+ self.post_action(cr, uid, ids, model, precondition_ok=precondition_ok, context=context)
return True
return wrapper
@@ -263,15 +280,15 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
- def do_check(self, cr, uid, action, obj, old_records=None, context=None):
+ def do_check(self, cr, uid, action, obj, precondition_ok=True, context=None):
""" check Action """
if context is None:
context = {}
- ok = True
- if action.filter_id and action.model_id.model == action.filter_id.model_id:
+ ok = precondition_ok
+ if action.filter_post_id and action.model_id.model == action.filter_post_id.model_id:
ctx = dict(context)
- ctx.update(eval(action.filter_id.context))
- obj_ids = self.pool.get(action.model_id.model).search(cr, uid, eval(action.filter_id.domain), context=ctx)
+ ctx.update(eval(action.filter_post_id.context))
+ obj_ids = self.pool.get(action.model_id.model).search(cr, uid, eval(action.filter_post_id.domain), context=ctx)
ok = ok and obj.id in obj_ids
if getattr(obj, 'user_id', False):
ok = ok and (not action.trg_user_id.id or action.trg_user_id.id==obj.user_id.id)
@@ -284,22 +301,6 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
(action.trg_partner_categ_id.id in map(lambda x: x.id, obj.partner_id.category_id or []))
)
)
- #state_to = the state after a write or a create
- state_to = getattr(obj, 'state', False)
- #state_from = nothing or the state of old_records
- state_from = ""
- if old_records != None:
- for record in old_records:
- state_from = record.state
- else:
- state_from = "na" #it means that there was no state before (creation for example)
- #if we have an action that check the status
- if action.trg_state_to:
- if action.trg_state_from:
- ok = ok and action.trg_state_from==state_from
- else:
- ok = state_from!=state_to
- ok = ok and action.trg_state_to==state_to
reg_name = action.regex_name
result_name = True
if reg_name:
@@ -341,7 +342,7 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
model_obj.message_subscribe(cr, uid, [obj.id], new_followers, context=context)
return True
- def _action(self, cr, uid, ids, objects, scrit=None, old_records=None, context=None):
+ def _action(self, cr, uid, ids, objects, scrit=None, precondition_ok=None, context=None):
""" Do Action """
if context is None:
context = {}
@@ -350,9 +351,11 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
objects = [objects]
for action in self.browse(cr, uid, ids, context=context):
for obj in objects:
- if self.do_check(cr, uid, action, obj, old_records=old_records, context=context):
+ ok = True
+ if precondition_ok!=None:
+ ok = precondition_ok[obj.id][action.id]
+ if self.do_check(cr, uid, action, obj, precondition_ok=ok, context=context):
self.do_action(cr, uid, action, obj, context=context)
-
context.update({'action': False})
return True
diff --git a/addons/base_action_rule/base_action_rule_view.xml b/addons/base_action_rule/base_action_rule_view.xml
index 4815baa9ebb..3bd90457828 100644
--- a/addons/base_action_rule/base_action_rule_view.xml
+++ b/addons/base_action_rule/base_action_rule_view.xml
@@ -15,36 +15,31 @@
-
-
-
+
+
+
+ Select a filter or a timer as condition.
+ To create a new filter,
+ - Go to your Model's page and set the filter parameters in the "Search" view
+ - In this same "Search" view, select the menu "Save Current Filter", enter the name and add the option "Share with all users"
+ The filter must therefore be available in this page.
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
+
-
-
-
@@ -63,7 +58,6 @@
-
diff --git a/addons/base_action_rule/test_models.py b/addons/base_action_rule/test_models.py
new file mode 100644
index 00000000000..9469b42c705
--- /dev/null
+++ b/addons/base_action_rule/test_models.py
@@ -0,0 +1,32 @@
+from osv import osv, fields
+
+AVAILABLE_STATES = [
+ ('draft', 'New'),
+ ('cancel', 'Cancelled'),
+ ('open', 'In Progress'),
+ ('pending', 'Pending'),
+ ('done', 'Closed')
+]
+
+class lead_test(osv.Model):
+ _name = "base.action.rule.lead.test"
+
+ _columns = {
+ 'name': fields.char('Subject', size=64, required=True, select=1),
+ 'user_id': fields.many2one('res.users', 'Responsible'),
+ 'state': fields.selection(AVAILABLE_STATES, string="Status", readonly=True),
+ 'active': fields.boolean('Active', required=False),
+ 'partner_id': fields.many2one('res.partner', 'Partner', ondelete='set null'),
+ 'date_action_last': fields.datetime('Last Action', readonly=1),
+ }
+
+ _defaults = {
+ 'state' : 'draft',
+ 'active' : True,
+ }
+
+ def message_post(self, cr, uid, thread_id, body='', subject=None, type='notification', subtype=None, parent_id=False, attachments=None, context=None, **kwargs):
+ pass
+
+ def message_subscribe(self, cr, uid, ids, partner_ids, subtype_ids=None, context=None):
+ pass
diff --git a/addons/crm/tests/__init__.py b/addons/base_action_rule/tests/__init__.py
similarity index 100%
rename from addons/crm/tests/__init__.py
rename to addons/base_action_rule/tests/__init__.py
diff --git a/addons/base_action_rule/tests/base_action_rule_test.py b/addons/base_action_rule/tests/base_action_rule_test.py
new file mode 100644
index 00000000000..6f1c885df69
--- /dev/null
+++ b/addons/base_action_rule/tests/base_action_rule_test.py
@@ -0,0 +1,142 @@
+import tools
+from openerp.tests import common
+from .. import test_models
+
+class base_action_rule_test(common.TransactionCase):
+
+ def setUp(self):
+ """*****setUp*****"""
+ super(base_action_rule_test, self).setUp()
+ cr, uid = self.cr, self.uid
+ self.demo_user = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'user_demo')
+ self.admin_user = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'user_admin')
+
+ def create_filter_done(self, cr, uid, context=None):
+ filter_pool = self.registry('ir.filters')
+ return filter_pool.create(cr, uid, {
+ 'name': "Lead is in done state",
+ 'is_default': False,
+ 'model_id': 'base.action.rule.lead.test',
+ 'domain' : "[('state','=','done')]",
+ }, context=context)
+
+ def create_filter_draft(self, cr, uid, context=None):
+ filter_pool = self.registry('ir.filters')
+ return filter_pool.create(cr, uid, {
+ 'name': "Lead is in draft state",
+ 'is_default': False,
+ 'model_id': "base.action.rule.lead.test",
+ 'domain' : "[('state','=','draft')]",
+ }, context=context)
+
+ def create_lead_test_1(self, cr, uid, context=None):
+ """
+ Create a new lead_test
+ """
+ lead_pool = self.registry('base.action.rule.lead.test')
+ return lead_pool.create(cr, uid, {
+ 'name': "Lead Test 1",
+ 'user_id': self.admin_user[1],
+ }, context=context)
+
+ def create_rule(self, cr, uid, filter_id=None, filter_post_id=None, context=None):
+ """
+ The "Rule 1" says that when a lead goes to the 'draft' state, the responsible for that lead changes to "demo_user"
+ """
+ self.action_pool = self.registry('base.action.rule')
+ return self.action_pool.create(cr,uid,{
+ 'name' : "Rule 1",
+ 'model_id': self.registry('ir.model').search(cr, uid, [('model','=','base.action.rule.lead.test')], context=context)[0],
+ 'active' : 1,
+ 'trg_date_type' : 'none',
+ 'filter_post_id' : filter_post_id,
+ 'filter_id' : filter_id,
+ 'act_user_id': self.demo_user[1],
+ }, context=context)
+
+ def test_00_check_to_state_draft_pre(self):
+ """
+ Check that a new record (with state = draft) doesn't change its responsible when there is a precondition filter which check that the state is draft.
+ """
+ cr, uid = self.cr, self.uid
+ context = {}
+ filter_draft = self.create_filter_draft(cr, uid, context=context)
+ rule_1_id = self.create_rule(cr, uid, filter_id=filter_draft, context=context)
+ new_lead_id = self.create_lead_test_1(cr,uid,context=context)
+ new_lead = self.registry('base.action.rule.lead.test').browse(cr, uid, new_lead_id, context=context)
+ self.assertTrue(new_lead.state=='draft')
+ self.assertTrue(new_lead.user_id==self.registry('res.users').browse(cr, uid, self.admin_user[1], context=context))
+
+ def test_01_check_to_state_draft_post(self):
+ """
+ Check that a new record (with state = draft) changes its responsible when there is a postcondition filter which check that the state is draft.
+ """
+ cr, uid = self.cr, self.uid
+ context = {}
+ filter_draft = self.create_filter_draft(cr, uid, context=context)
+ rule_1_id = self.create_rule(cr, uid, filter_post_id=filter_draft, context=context)
+ new_lead_id = self.create_lead_test_1(cr,uid,context=context)
+ new_lead = self.registry('base.action.rule.lead.test').browse(cr, uid, new_lead_id, context=context)
+ self.assertTrue(new_lead.state=='draft')
+ self.assertTrue(new_lead.user_id==self.registry('res.users').browse(cr, uid, self.demo_user[1], context=context))
+
+ def test_02_check_from_draft_to_done_with_steps(self):
+ """
+ A new record will be created and will goes from draft to done state via the other states (open, pending and cancel)
+ We will create a rule that says in precondition that the record must be in the "draft" state while a postcondition filter says
+ that the record will be done. If the state goes from 'draft' to 'done' the responsible will change. If those two conditions aren't
+ verified, the responsible will stay the same
+ The responsible in that test will never change
+ """
+ cr, uid = self.cr, self.uid
+ context = {}
+ filter_draft = self.create_filter_draft(cr, uid, context=context)
+ filter_done = self.create_filter_done(cr, uid, context=context)
+ self.create_rule(cr, uid, filter_id=filter_draft, filter_post_id=filter_done, context=context)
+ new_lead_id = self.create_lead_test_1(cr,uid,context=context)
+ new_lead = self.registry('base.action.rule.lead.test').browse(cr, uid, new_lead_id, context=context)
+ self.assertTrue(new_lead.state=='draft')
+ self.assertTrue(new_lead.user_id==self.registry('res.users').browse(cr, uid, self.admin_user[1], context=context))
+ """ change the state of new_lead to open and check that responsible doen't change"""
+ new_lead.write({'state': 'open'}, context=context)
+ new_lead = self.registry('base.action.rule.lead.test').browse(cr, uid, new_lead_id, context=context)
+ self.assertTrue(new_lead.state=='open')
+ self.assertTrue(new_lead.user_id==self.registry('res.users').browse(cr, uid, self.admin_user[1], context=context))
+ """ change the state of new_lead to pending and check that responsible doen't change"""
+ new_lead.write({'state': 'pending'}, context=context)
+ new_lead = self.registry('base.action.rule.lead.test').browse(cr, uid, new_lead_id, context=context)
+ self.assertTrue(new_lead.state=='pending')
+ self.assertTrue(new_lead.user_id==self.registry('res.users').browse(cr, uid, self.admin_user[1], context=context))
+ """ change the state of new_lead to cancel and check that responsible doen't change"""
+ new_lead.write({'state': 'cancel'}, context=context)
+ new_lead = self.registry('base.action.rule.lead.test').browse(cr, uid, new_lead_id, context=context)
+ self.assertTrue(new_lead.state=='cancel')
+ self.assertTrue(new_lead.user_id==self.registry('res.users').browse(cr, uid, self.admin_user[1], context=context))
+ """ change the state of new_lead to done and check that responsible doen't change """
+ new_lead.write({'state': 'done'}, context=context)
+ new_lead = self.registry('base.action.rule.lead.test').browse(cr, uid, new_lead_id, context=context)
+ self.assertTrue(new_lead.state=='done')
+ self.assertTrue(new_lead.user_id==self.registry('res.users').browse(cr, uid, self.admin_user[1], context=context))
+
+ def test_02_check_from_draft_to_done_without_steps(self):
+ """
+ A new record will be created and will goes from draft to done in one operation
+ We will create a rule that says in precondition that the record must be in the "draft" state while a postcondition filter says
+ that the record will be done. If the state goes from 'draft' to 'done' the responsible will change. If those two conditions aren't
+ verified, the responsible will stay the same
+ The responsible in that test will change to "demo_user"
+ """
+ cr, uid = self.cr, self.uid
+ context = {}
+ filter_draft = self.create_filter_draft(cr, uid, context=context)
+ filter_done = self.create_filter_done(cr, uid, context=context)
+ self.create_rule(cr, uid, filter_id=filter_draft, filter_post_id=filter_done, context=context)
+ new_lead_id = self.create_lead_test_1(cr,uid,context=context)
+ new_lead = self.registry('base.action.rule.lead.test').browse(cr, uid, new_lead_id, context=context)
+ self.assertTrue(new_lead.state=='draft')
+ self.assertTrue(new_lead.user_id==self.registry('res.users').browse(cr, uid, self.admin_user[1], context=context))
+ """ change the state of new_lead to done and check that responsible change to Demo_user"""
+ new_lead.write({'state': 'done'}, context=context)
+ new_lead = self.registry('base.action.rule.lead.test').browse(cr, uid, new_lead_id, context=context)
+ self.assertTrue(new_lead.state=='done')
+ self.assertTrue(new_lead.user_id==self.registry('res.users').browse(cr, uid, self.demo_user[1], context=context))
\ No newline at end of file
diff --git a/addons/crm/crm_action_rule.py b/addons/crm/crm_action_rule.py
index 72582a1f21e..74fc749f33c 100644
--- a/addons/crm/crm_action_rule.py
+++ b/addons/crm/crm_action_rule.py
@@ -43,8 +43,8 @@ class base_action_rule(osv.osv):
'act_categ_id': fields.many2one('crm.case.categ', 'Set Category to'),
}
- def do_check(self, cr, uid, action, obj, old_records=None, context=None):
- ok = super(base_action_rule, self).do_check(cr, uid, action, obj, old_records=old_records, context=context)
+ def do_check(self, cr, uid, action, obj, precondition_ok=True, context=None):
+ ok = super(base_action_rule, self).do_check(cr, uid, action, obj, precondition_ok=precondition_ok, context=context)
if hasattr(obj, 'section_id'):
ok = ok and (not action.trg_section_id or action.trg_section_id.id == obj.section_id.id)
diff --git a/addons/crm/crm_action_rule_view.xml b/addons/crm/crm_action_rule_view.xml
index e21b74de382..347e54c46ac 100644
--- a/addons/crm/crm_action_rule_view.xml
+++ b/addons/crm/crm_action_rule_view.xml
@@ -7,16 +7,6 @@
base.action.rule
-
-
-
-
-
-
-
-
-
-
diff --git a/addons/crm/tests/base_action_rule_test.py b/addons/crm/tests/base_action_rule_test.py
deleted file mode 100644
index caca0c635da..00000000000
--- a/addons/crm/tests/base_action_rule_test.py
+++ /dev/null
@@ -1,69 +0,0 @@
-import tools
-from openerp.tests import common
-
-class base_action_rule_test(common.TransactionCase):
-
- def setUp(self):
- """*****setUp*****"""
- super(base_action_rule_test, self).setUp()
- cr, uid = self.cr, self.uid
-
- """*****TeamCreation******"""
- self.team_pool = self.registry('crm.case.section')
- self.team_1_id = self.team_pool.create(cr, uid, {
- 'name' : "Team 1",
- 'active' : 1,
- 'user_id' : uid,
- 'complete_name' : "Test / Team 1",
- }, context=None)
- self.team_2_id = self.team_pool.create(cr, uid, {
- 'name' : "Team 2",
- 'active' : 1,
- 'user_id' : uid,
- 'complete_name' : "Test / Team 2",
- }, context=None)
-
- def create_rule_1(self, cr, uid, context=None):
- """
- The "Rule 1" says that when a lead goes to the 'open' state, the team responsible for that lead changes to "Team 1"
- """
- self.action_pool = self.registry('base.action.rule')
- self.rule_1_id = self.action_pool.create(cr,uid,{
- 'name' : "Rule 1",
- 'model_id' : self.registry('ir.model').search(cr, uid, [('model','=','crm.lead')], context=context)[0],
- 'active' : 1,
- 'trg_state_to' : 'open',
- 'trg_date_type' : 'none',
- 'act_section_id' : self.team_1_id,
- }, context=context)
-
- def create_rule_2(self, cr, uid, context=None):
- """
- The "Rule 2" says that when a lead goes from 'open' state to 'done' state, the team responsible for that lead changes to "Team 2"
- """
- self.action_pool = self.registry('base.action.rule')
- self.rule_2_id = self.action_pool.create(cr,uid,{
- 'name' : "Rule 2",
- 'model_id' : self.registry('ir.model').search(cr, uid, [('model','=','crm.lead')], context=context)[0],
- 'active' : 1,
- 'trg_state_to' : 'done',
- 'trg_state_from' : 'open',
- 'trg_date_type' : 'none',
- 'act_section_id' : self.team_2_id,
- }, context=context)
-
- def test_00_check_to_state_draft(self):
- """
- This test check that the team change when the state is open but doesn't change when the state is different
- """
- cr, uid = self.cr, self.uid
- context = {}
- #First we need to create the Rule 1
- self.create_rule_1(cr, uid, context)
- #Once it is done, we can create a new lead (with a state = 'draft')
- #first we get our team 1
- self.team_1 = self.team_pool.browse(cr,uid,self.team_1_id,context=context)
- #We get a lead
- self.lead_1 = self.registry('ir.model.data').get_object_reference(cr, uid, 'crm', 'crm_case_1')
- #We change the team of crm_case_1
-
From 7e8533d278979a3f31c13c342aa9eafe757df493 Mon Sep 17 00:00:00 2001
From: Arnaud Pineux
Date: Wed, 28 Nov 2012 13:01:00 +0100
Subject: [PATCH 11/49] [FIX] old actions based on filters still work
bzr revid: api@openerp.com-20121128120100-58xrtp54txigz0b5
---
addons/base_action_rule/base_action_rule.py | 18 +++++++++---------
.../base_action_rule/base_action_rule_view.xml | 2 +-
.../tests/base_action_rule_test.py | 12 ++++++------
3 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py
index 2b6877a7c9c..de3362c6644 100644
--- a/addons/base_action_rule/base_action_rule.py
+++ b/addons/base_action_rule/base_action_rule.py
@@ -97,8 +97,8 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
\ne.g.: 'urgent.*' will search for records having name starting with the string 'urgent'\
\nNote: This is case sensitive search."),
'server_action_ids': fields.one2many('ir.actions.server', 'action_rule_id', 'Server Action', help="Define Server actions.\neg:Email Reminders, Call Object Service, etc.."), #TODO: set domain [('model_id','=',model_id)]
- 'filter_id':fields.many2one('ir.filters', 'Precondition Filter', required=False), #TODO: set domain [('model_id','=',model_id.model)]
- 'filter_post_id': fields.many2one('ir.filters', 'Postcondition Filter', required=False),
+ 'filter_id':fields.many2one('ir.filters', 'Postcondition Filter', required=False), #TODO: set domain [('model_id','=',model_id.model)]
+ 'filter_pre_id': fields.many2one('ir.filters', 'Precondition Filter', required=False),
'last_run': fields.datetime('Last Run', readonly=1),
}
@@ -140,7 +140,7 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
precondition_ok = {}
precondition_ok[new_id] = {}
for action in self.browse(cr, uid, self.search(cr, uid, [], context=context), context=context):
- if action.filter_id:
+ if action.filter_pre_id:
precondition_ok[new_id][action.id] = False
else:
precondition_ok[new_id][action.id] = True
@@ -167,12 +167,12 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
precondition_ok[id] = {}
for action in self.browse(cr, uid, self.search(cr, uid, [], context=context), context=context):
precondition_ok[id][action.id] = True
- if action.filter_id and action.model_id.model == action.filter_id.model_id:
+ if action.filter_pre_id and action.model_id.model == action.filter_pre_id.model_id:
ctx = dict(context)
- ctx.update(eval(action.filter_id.context))
+ ctx.update(eval(action.filter_pre_id.context))
obj_ids = []
if self.pool.get(action.model_id.model)!=None:
- obj_ids = self.pool.get(action.model_id.model).search(cr, uid, eval(action.filter_id.domain), context=ctx)
+ obj_ids = self.pool.get(action.model_id.model).search(cr, uid, eval(action.filter_pre_id.domain), context=ctx)
precondition_ok[id][action.id] = id in obj_ids
old_write(cr, uid, ids, vals, context=context)
if not context.get('action'):
@@ -285,10 +285,10 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
if context is None:
context = {}
ok = precondition_ok
- if action.filter_post_id and action.model_id.model == action.filter_post_id.model_id:
+ if action.filter_id and action.model_id.model == action.filter_id.model_id:
ctx = dict(context)
- ctx.update(eval(action.filter_post_id.context))
- obj_ids = self.pool.get(action.model_id.model).search(cr, uid, eval(action.filter_post_id.domain), context=ctx)
+ ctx.update(eval(action.filter_id.context))
+ obj_ids = self.pool.get(action.model_id.model).search(cr, uid, eval(action.filter_id.domain), context=ctx)
ok = ok and obj.id in obj_ids
if getattr(obj, 'user_id', False):
ok = ok and (not action.trg_user_id.id or action.trg_user_id.id==obj.user_id.id)
diff --git a/addons/base_action_rule/base_action_rule_view.xml b/addons/base_action_rule/base_action_rule_view.xml
index 3bd90457828..257465b490a 100644
--- a/addons/base_action_rule/base_action_rule_view.xml
+++ b/addons/base_action_rule/base_action_rule_view.xml
@@ -31,8 +31,8 @@
+
-
diff --git a/addons/base_action_rule/tests/base_action_rule_test.py b/addons/base_action_rule/tests/base_action_rule_test.py
index 6f1c885df69..0452401ce23 100644
--- a/addons/base_action_rule/tests/base_action_rule_test.py
+++ b/addons/base_action_rule/tests/base_action_rule_test.py
@@ -39,7 +39,7 @@ class base_action_rule_test(common.TransactionCase):
'user_id': self.admin_user[1],
}, context=context)
- def create_rule(self, cr, uid, filter_id=None, filter_post_id=None, context=None):
+ def create_rule(self, cr, uid, filter_id=None, filter_pre_id=None, context=None):
"""
The "Rule 1" says that when a lead goes to the 'draft' state, the responsible for that lead changes to "demo_user"
"""
@@ -49,7 +49,7 @@ class base_action_rule_test(common.TransactionCase):
'model_id': self.registry('ir.model').search(cr, uid, [('model','=','base.action.rule.lead.test')], context=context)[0],
'active' : 1,
'trg_date_type' : 'none',
- 'filter_post_id' : filter_post_id,
+ 'filter_pre_id' : filter_pre_id,
'filter_id' : filter_id,
'act_user_id': self.demo_user[1],
}, context=context)
@@ -61,7 +61,7 @@ class base_action_rule_test(common.TransactionCase):
cr, uid = self.cr, self.uid
context = {}
filter_draft = self.create_filter_draft(cr, uid, context=context)
- rule_1_id = self.create_rule(cr, uid, filter_id=filter_draft, context=context)
+ rule_1_id = self.create_rule(cr, uid, filter_pre_id=filter_draft, context=context)
new_lead_id = self.create_lead_test_1(cr,uid,context=context)
new_lead = self.registry('base.action.rule.lead.test').browse(cr, uid, new_lead_id, context=context)
self.assertTrue(new_lead.state=='draft')
@@ -74,7 +74,7 @@ class base_action_rule_test(common.TransactionCase):
cr, uid = self.cr, self.uid
context = {}
filter_draft = self.create_filter_draft(cr, uid, context=context)
- rule_1_id = self.create_rule(cr, uid, filter_post_id=filter_draft, context=context)
+ rule_1_id = self.create_rule(cr, uid, filter_id=filter_draft, context=context)
new_lead_id = self.create_lead_test_1(cr,uid,context=context)
new_lead = self.registry('base.action.rule.lead.test').browse(cr, uid, new_lead_id, context=context)
self.assertTrue(new_lead.state=='draft')
@@ -92,7 +92,7 @@ class base_action_rule_test(common.TransactionCase):
context = {}
filter_draft = self.create_filter_draft(cr, uid, context=context)
filter_done = self.create_filter_done(cr, uid, context=context)
- self.create_rule(cr, uid, filter_id=filter_draft, filter_post_id=filter_done, context=context)
+ self.create_rule(cr, uid, filter_pre_id=filter_draft, filter_id=filter_done, context=context)
new_lead_id = self.create_lead_test_1(cr,uid,context=context)
new_lead = self.registry('base.action.rule.lead.test').browse(cr, uid, new_lead_id, context=context)
self.assertTrue(new_lead.state=='draft')
@@ -130,7 +130,7 @@ class base_action_rule_test(common.TransactionCase):
context = {}
filter_draft = self.create_filter_draft(cr, uid, context=context)
filter_done = self.create_filter_done(cr, uid, context=context)
- self.create_rule(cr, uid, filter_id=filter_draft, filter_post_id=filter_done, context=context)
+ self.create_rule(cr, uid, filter_pre_id=filter_draft, filter_id=filter_done, context=context)
new_lead_id = self.create_lead_test_1(cr,uid,context=context)
new_lead = self.registry('base.action.rule.lead.test').browse(cr, uid, new_lead_id, context=context)
self.assertTrue(new_lead.state=='draft')
From ffe7fd9bcc800498681c20215141139478635b32 Mon Sep 17 00:00:00 2001
From: Christophe Matthieu
Date: Mon, 3 Dec 2012 09:51:16 +0100
Subject: [PATCH 12/49] [FIX] etherpad: When a user access to the edit mode
from a kanban view or list view, etherpad is dipslay on readonly mode but
with the oe_editing class. Why: The deferer for read only arrive after the
display of edit mode. Fix: check in the deferer if the etherpad is already in
readonly mode.
bzr revid: chm@openerp.com-20121203085116-jn83em3pd5le28rp
---
addons/pad/static/src/js/pad.js | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/addons/pad/static/src/js/pad.js b/addons/pad/static/src/js/pad.js
index 9e1b73e1f3b..5b33fd3eaa1 100644
--- a/addons/pad/static/src/js/pad.js
+++ b/addons/pad/static/src/js/pad.js
@@ -4,6 +4,16 @@ openerp.pad = function(instance) {
template: 'FieldPad',
configured: false,
content: "",
+ start: function() {
+ this._super.apply(this, arguments);
+ var self = this;
+ this.on('click', '.oe_pad_switch', function(){
+ self.$el.toggleClass('oe_pad_fullscreen');
+ });
+ this.on('change:effective_readonly',this,function(){
+ self.renderElement();
+ });
+ },
render_value: function() {
var self = this;
var _super = _.bind(this._super, this);
@@ -37,23 +47,23 @@ openerp.pad = function(instance) {
}else{
this.content = '
');
self.$('.oe_pad_readonly').html(data);
}).error(function(){
+ if(!self.get('effective_readonly')){
+ return false;
+ }
self.$('.oe_pad_content').text('Unable to load pad');
});
}
}
this._super();
this.$('.oe_pad_content').html(this.content);
- this.$('.oe_pad_switch').click(function(){
- self.$el.toggleClass('oe_pad_fullscreen');
- });
- this.on('change:effective_readonly',this,function(){
- self.renderElement();
- });
},
});
From b04a134a16e2559b594a536276928ef9cc6f56a4 Mon Sep 17 00:00:00 2001
From: Christophe Matthieu
Date: Tue, 4 Dec 2012 11:23:04 +0100
Subject: [PATCH 13/49] [FIX] view_form: m2m_tags, when a user quick create a
tag, select a tags in the list or blurred and click on the arrow, the last
selection is persistant. Overwrite onSetInputData to reset suggestions if
input is empty.
bzr revid: chm@openerp.com-20121204102304-iru8pcjlca8zh5fj
---
addons/web/static/src/js/view_form.js | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 21c3b3f43d9..5a573a1244e 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -3986,6 +3986,14 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
return item.name;
},
},
+ core: {
+ onSetInputData: function(e, data) {
+ if (data == '') {
+ this._plugins.autocomplete._suggestions = null;
+ }
+ this.input().val(data);
+ },
+ },
},
}).bind('getSuggestions', function(e, data) {
var _this = this;
From 638dcfce3488a6849a109a7220d8164e15bbd777 Mon Sep 17 00:00:00 2001
From: Arnaud Pineux
Date: Tue, 4 Dec 2012 16:36:17 +0100
Subject: [PATCH 14/49] [IMP] base_action_rule : delete unused fields and add
explanation
lp bug: https://launchpad.net/bugs/944197 fixed
bzr revid: api@openerp.com-20121204153617-ju3yyj2tt3d84jl9
---
addons/base_action_rule/base_action_rule.py | 57 -------------------
.../base_action_rule_view.xml | 8 +--
addons/crm/crm_action_rule.py | 32 -----------
addons/crm/crm_action_rule_demo.xml | 1 -
addons/crm/test/process/action_rule.yml | 20 -------
5 files changed, 4 insertions(+), 114 deletions(-)
delete mode 100644 addons/crm/test/process/action_rule.yml
diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py
index de3362c6644..00b179655f0 100644
--- a/addons/base_action_rule/base_action_rule.py
+++ b/addons/base_action_rule/base_action_rule.py
@@ -84,18 +84,9 @@ specifies you can put a negative number. If you need a delay before the \
trigger date, like sending a reminder 15 minutes before a meeting."),
'trg_date_range_type': fields.selection([('minutes', 'Minutes'), ('hour', 'Hours'), \
('day', 'Days'), ('month', 'Months')], 'Delay type'),
- 'trg_user_id': fields.many2one('res.users', 'Responsible'),
- 'trg_partner_id': fields.many2one('res.partner', 'Partner'),
- 'trg_partner_categ_id': fields.many2one('res.partner.category', 'Partner Category'),
- 'trg_state_from': fields.selection(_state_get, 'and previously was', size=16),
- 'trg_state_to': fields.selection(_state_get, 'Status changes to', size=16),
-
'act_user_id': fields.many2one('res.users', 'Set Responsible to'),
'act_state': fields.selection(_state_get, 'Set State to', size=16),
'act_followers': fields.many2many("res.partner", string="Set Followers"),
- 'regex_name': fields.char('Regex on Resource Name', size=128, help="Regular expression for matching name of the resource\
-\ne.g.: 'urgent.*' will search for records having name starting with the string 'urgent'\
-\nNote: This is case sensitive search."),
'server_action_ids': fields.one2many('ir.actions.server', 'action_rule_id', 'Server Action', help="Define Server actions.\neg:Email Reminders, Call Object Service, etc.."), #TODO: set domain [('model_id','=',model_id)]
'filter_id':fields.many2one('ir.filters', 'Postcondition Filter', required=False), #TODO: set domain [('model_id','=',model_id.model)]
'filter_pre_id': fields.many2one('ir.filters', 'Precondition Filter', required=False),
@@ -290,26 +281,6 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
ctx.update(eval(action.filter_id.context))
obj_ids = self.pool.get(action.model_id.model).search(cr, uid, eval(action.filter_id.domain), context=ctx)
ok = ok and obj.id in obj_ids
- if getattr(obj, 'user_id', False):
- ok = ok and (not action.trg_user_id.id or action.trg_user_id.id==obj.user_id.id)
- if getattr(obj, 'partner_id', False):
- ok = ok and (not action.trg_partner_id.id or action.trg_partner_id.id==obj.partner_id.id)
- ok = ok and (
- not action.trg_partner_categ_id.id or
- (
- obj.partner_id.id and
- (action.trg_partner_categ_id.id in map(lambda x: x.id, obj.partner_id.category_id or []))
- )
- )
- reg_name = action.regex_name
- result_name = True
- if reg_name:
- ptrn = re.compile(ustr(reg_name))
- _result = ptrn.search(ustr(obj.name))
- if not _result:
- result_name = False
- regex_n = not reg_name or result_name
- ok = ok and regex_n
return ok
def do_action(self, cr, uid, action, obj, context=None):
@@ -359,38 +330,10 @@ trigger date, like sending a reminder 15 minutes before a meeting."),
context.update({'action': False})
return True
-base_action_rule()
-
class actions_server(osv.osv):
_inherit = 'ir.actions.server'
_columns = {
'action_rule_id': fields.many2one("base.action.rule", string="Action Rule")
}
-actions_server()
-
-class ir_cron(osv.osv):
- _inherit = 'ir.cron'
- _init_done = False
-
- def _poolJobs(self, db_name, check=False):
- if not self._init_done:
- self._init_done = True
- try:
- db = pooler.get_db(db_name)
- except:
- return False
- cr = db.cursor()
- try:
- next = datetime.now().strftime('%Y-%m-%d %H:00:00')
- # Putting nextcall always less than current time in order to call it every time
- cr.execute('UPDATE ir_cron set nextcall = \'%s\' where numbercall<>0 and active and model=\'base.action.rule\' ' % (next))
- finally:
- cr.commit()
- cr.close()
-
- super(ir_cron, self)._poolJobs(db_name, check=check)
-
-ir_cron()
-
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/base_action_rule/base_action_rule_view.xml b/addons/base_action_rule/base_action_rule_view.xml
index 257465b490a..aab9ce0000c 100644
--- a/addons/base_action_rule/base_action_rule_view.xml
+++ b/addons/base_action_rule/base_action_rule_view.xml
@@ -23,10 +23,10 @@
- Select a filter or a timer as condition.
- To create a new filter,
- - Go to your Model's page and set the filter parameters in the "Search" view
- - In this same "Search" view, select the menu "Save Current Filter", enter the name and add the option "Share with all users"
+ Select a filter or a timer as condition. An action rule is checked when you create or modify the "Related Document Model". The precondition filter is checked right before the modification while the postcondition filter is checked after the modification. A precondition filter will therefore not work during a creation.
+ To create a new filter:
+ - 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)
+ - 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"
The filter must therefore be available in this page.
diff --git a/addons/crm/crm_action_rule.py b/addons/crm/crm_action_rule.py
index 74fc749f33c..1344b170b9a 100644
--- a/addons/crm/crm_action_rule.py
+++ b/addons/crm/crm_action_rule.py
@@ -35,42 +35,10 @@ class base_action_rule(osv.osv):
_description = 'Action Rules'
_columns = {
- 'trg_section_id': fields.many2one('crm.case.section', 'Sales Team'),
- 'trg_max_history': fields.integer('Maximum Communication History'),
- 'trg_categ_id': fields.many2one('crm.case.categ', 'Category'),
- 'regex_history' : fields.char('Regular Expression on Case History', size=128),
'act_section_id': fields.many2one('crm.case.section', 'Set Team to'),
'act_categ_id': fields.many2one('crm.case.categ', 'Set Category to'),
}
- def do_check(self, cr, uid, action, obj, precondition_ok=True, context=None):
- ok = super(base_action_rule, self).do_check(cr, uid, action, obj, precondition_ok=precondition_ok, context=context)
-
- if hasattr(obj, 'section_id'):
- ok = ok and (not action.trg_section_id or action.trg_section_id.id == obj.section_id.id)
- if hasattr(obj, 'categ_ids'):
- ok = ok and (not action.trg_categ_id or action.trg_categ_id.id in [x.id for x in obj.categ_ids])
-
- #Cheking for history
- regex = action.regex_history
- if regex:
- res = False
- ptrn = re.compile(ustr(regex))
- for history in obj.message_ids:
- _result = ptrn.search(ustr(history.subject))
- if _result:
- res = True
- break
- ok = ok and res
-
- if action.trg_max_history:
- res_count = False
- history_ids = filter(lambda x: x.email_from, obj.message_ids)
- if len(history_ids) <= action.trg_max_history:
- res_count = True
- ok = ok and res_count
- return ok
-
def do_action(self, cr, uid, action, obj, context=None):
res = super(base_action_rule, self).do_action(cr, uid, action, obj, context=context)
model_obj = self.pool.get(action.model_id.model)
diff --git a/addons/crm/crm_action_rule_demo.xml b/addons/crm/crm_action_rule_demo.xml
index 83f5681f311..31f07e59034 100644
--- a/addons/crm/crm_action_rule_demo.xml
+++ b/addons/crm/crm_action_rule_demo.xml
@@ -72,7 +72,6 @@ Thanks,
Set Auto Followers on leads which are urgent and come from USA.2
- urgent.*
diff --git a/addons/crm/test/process/action_rule.yml b/addons/crm/test/process/action_rule.yml
deleted file mode 100644
index f76e6c250bc..00000000000
--- a/addons/crm/test/process/action_rule.yml
+++ /dev/null
@@ -1,20 +0,0 @@
--
- I create a record rule.
--
- !python {model: base.action.rule}: |
- model_ids = self.pool.get("ir.model").search(cr, uid, [('model', '=', 'crm.lead')])
- from datetime import datetime
- new_id = self.create(cr, uid, {'name': 'New Rule', 'model_id': model_ids[0], 'trg_user_id': ref('base.user_root'), 'trg_partner_id': ref('base.res_partner_1'), 'act_user_id': ref('base.user_demo') })
- self._check(cr, uid)
--
- I create a new lead to check the record rule.
--
- !record {model: crm.lead, id: crm_lead_test_rules_id}:
- name: 'Test lead rules'
- partner_id: base.res_partner_1
--
- I check if the record rule is applied and the responsible is changed.
--
- !python {model: crm.lead}: |
- lead_user = self.browse(cr, uid, ref('crm_lead_test_rules_id'))
- assert lead_user.user_id.id == ref('base.user_demo'), "Responsible of lead is not changed."
From 5827f6c200dbf70e8b0e7aeb13facda32ac3c1bb Mon Sep 17 00:00:00 2001
From: Arnaud Pineux
Date: Tue, 4 Dec 2012 16:52:10 +0100
Subject: [PATCH 15/49] [IMP] base_action_rule : clear state and stage
lp bug: https://launchpad.net/bugs/944197 fixed
bzr revid: api@openerp.com-20121204155210-3cjh1153idyax1sh
---
addons/base_status/base_stage.py | 13 -------------
addons/base_status/base_state.py | 12 ------------
2 files changed, 25 deletions(-)
diff --git a/addons/base_status/base_stage.py b/addons/base_status/base_stage.py
index 5710a31d6a0..72d58553092 100644
--- a/addons/base_status/base_stage.py
+++ b/addons/base_status/base_stage.py
@@ -217,7 +217,6 @@ class base_stage(object):
self.write(cr, uid, [case.id], data, context=context)
case.case_escalate_send_note(case.section_id.parent_id, context=context)
cases = self.browse(cr, uid, ids, context=context)
- self._action(cr, uid, cases, 'escalate', context=context)
return True
def case_open(self, cr, uid, ids, context=None):
@@ -283,18 +282,6 @@ class base_stage(object):
self.write(cr, uid, ids, values_to_update, context=context)
return True
- def _action(self, cr, uid, cases, state_to, scrit=None, context=None):
- if context is None:
- context = {}
- context['state_to'] = state_to
- rule_obj = self.pool.get('base.action.rule')
- if not rule_obj:
- return True
- model_obj = self.pool.get('ir.model')
- model_ids = model_obj.search(cr, uid, [('model','=',self._name)], context=context)
- rule_ids = rule_obj.search(cr, uid, [('model_id','=',model_ids[0])], context=context)
- return rule_obj._action(cr, uid, rule_ids, cases, scrit=scrit, context=context)
-
def _check(self, cr, uid, ids=False, context=None):
""" Function called by the scheduler to process cases for date actions.
diff --git a/addons/base_status/base_state.py b/addons/base_status/base_state.py
index 97d70268bdf..e8a1dcc6b9f 100644
--- a/addons/base_status/base_state.py
+++ b/addons/base_status/base_state.py
@@ -107,7 +107,6 @@ class base_state(object):
raise osv.except_osv(_('Error !'), _('You can not escalate, you are already at the top level regarding your sales-team category.'))
self.write(cr, uid, [case.id], data, context=context)
case.case_escalate_send_note(parent_id, context=context)
- self._action(cr, uid, cases, 'escalate', context=context)
return True
def case_open(self, cr, uid, ids, context=None):
@@ -163,17 +162,6 @@ class base_state(object):
update_values = {}
update_values['state'] = state_name
self.write(cr, uid, ids, update_values, context=context)
- #self._action(cr, uid, cases, state_name, context=context)
-
- def _action(self, cr, uid, cases, state_to, scrit=None, context=None):
- if context is None:
- context = {}
- context['state_to'] = state_to
- rule_obj = self.pool.get('base.action.rule')
- model_obj = self.pool.get('ir.model')
- model_ids = model_obj.search(cr, uid, [('model','=',self._name)])
- rule_ids = rule_obj.search(cr, uid, [('model_id','=',model_ids[0])])
- return rule_obj._action(cr, uid, rule_ids, cases, scrit=scrit, context=context)
# ******************************
# Notifications
From 8381a0c92f5dd5d6c01e1dc53481509ad1ee7a1a Mon Sep 17 00:00:00 2001
From: Arnaud Pineux
Date: Tue, 4 Dec 2012 17:20:52 +0100
Subject: [PATCH 16/49] [FIX] base_stage & state
bzr revid: api@openerp.com-20121204162052-u3t2vvf4ttcppdic
---
addons/base_status/base_stage.py | 3 ---
1 file changed, 3 deletions(-)
diff --git a/addons/base_status/base_stage.py b/addons/base_status/base_stage.py
index 6e2313be4ac..f88a25c57b4 100644
--- a/addons/base_status/base_stage.py
+++ b/addons/base_status/base_stage.py
@@ -277,9 +277,6 @@ class base_stage(object):
def write(self, cr, uid, ids, vals, context=None):
res = super(base_stage,self).write(cr, uid, ids, vals, context)
- if vals.get('stage_id'):
- for case in self.browse(cr, uid, ids, context=context):
- self._action(cr, uid, case, case.stage_id.state, context=context)
return res
From 0ca480a80d4e87883941f84508c58d36c97d6329 Mon Sep 17 00:00:00 2001
From: Arnaud Pineux
Date: Tue, 4 Dec 2012 17:23:27 +0100
Subject: [PATCH 17/49] [FIX] base_stage & state
bzr revid: api@openerp.com-20121204162327-uu941ixjjojgc15v
---
addons/crm/__openerp__.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/addons/crm/__openerp__.py b/addons/crm/__openerp__.py
index 63d5d3da84b..a438dd2858e 100644
--- a/addons/crm/__openerp__.py
+++ b/addons/crm/__openerp__.py
@@ -111,7 +111,6 @@ Dashboard for CRM will include:
'test/process/lead2opportunity2win.yml',
'test/process/merge_opportunity.yml',
'test/process/cancel_lead.yml',
- 'test/process/action_rule.yml',
'test/process/segmentation.yml',
'test/process/phonecalls.yml',
'test/ui/crm_demo.yml',
From 23b6b96fbc4dccf5d6bba6eda2e04ddf8a9d3224 Mon Sep 17 00:00:00 2001
From: Christophe Matthieu
Date: Thu, 13 Dec 2012 15:57:14 +0100
Subject: [PATCH 18/49] [IMP] pad: add abord for $.get request
bzr revid: chm@openerp.com-20121213145714-b9d4f2u8iqdg8r1m
---
addons/pad/static/src/js/pad.js | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/addons/pad/static/src/js/pad.js b/addons/pad/static/src/js/pad.js
index 5b33fd3eaa1..5cd2ac622cb 100644
--- a/addons/pad/static/src/js/pad.js
+++ b/addons/pad/static/src/js/pad.js
@@ -7,9 +7,6 @@ openerp.pad = function(instance) {
start: function() {
this._super.apply(this, arguments);
var self = this;
- this.on('click', '.oe_pad_switch', function(){
- self.$el.toggleClass('oe_pad_fullscreen');
- });
this.on('change:effective_readonly',this,function(){
self.renderElement();
});
@@ -37,6 +34,9 @@ openerp.pad = function(instance) {
renderElement: function(){
var self = this;
var value = this.get('value');
+ if (this.pad_loading_request) {
+ this.pad_loading_request.abort();
+ }
if(!_.str.startsWith(value,'http')){
this.configured = false;
this.content = "";
@@ -46,24 +46,22 @@ openerp.pad = function(instance) {
this.content = '';
}else{
this.content = '
+ Select a filter or a timer as condition. An action rule is checked when you create or modify the "Related Document Model". The precondition filter is checked right before the modification while the postcondition filter is checked after the modification. A precondition filter will therefore not work during a creation.
+ To create a new filter:
+ - 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)
+ - 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"
+ The filter must therefore be available in this page.
+