diff --git a/bin/addons/base/base.sql b/bin/addons/base/base.sql index 1584fd15bb8..911b90fe5da 100644 --- a/bin/addons/base/base.sql +++ b/bin/addons/base/base.sql @@ -93,24 +93,6 @@ create table ir_act_report_custom ( ) INHERITS (ir_actions); -CREATE TABLE ir_act_group ( - exec_type varchar(64) DEFAULT 'serial'::varchar NOT NULL, - primary key(id) -) -INHERITS (ir_actions); - -CREATE TABLE ir_act_group_link ( - aid integer NOT NULL, - gid integer NOT NULL -); - -CREATE TABLE ir_act_execute ( - func_name varchar(64) NOT NULL, - func_arg varchar(64), - primary key(id) -) -INHERITS (ir_actions); - CREATE TABLE ir_act_wizard ( wiz_name varchar(64) NOT NULL, primary key(id) @@ -124,6 +106,12 @@ CREATE TABLE ir_act_url ( ) INHERITS (ir_actions); +CREATE TABLE ir_act_server ( + primary key(id) +) +INHERITS (ir_actions); + + CREATE TABLE ir_ui_view ( id serial NOT NULL, name varchar(64) DEFAULT ''::varchar NOT NULL, diff --git a/bin/addons/base/base_security.xml b/bin/addons/base/base_security.xml index f356e401dfa..f4ce4f68777 100644 --- a/bin/addons/base/base_security.xml +++ b/bin/addons/base/base_security.xml @@ -56,42 +56,6 @@ - - Actions Execute - - - - - - - - Actions Execute - - - - - - - - - - Actions Group - - - - - - - - Actions Group - - - - - - - - Actions Report Custom diff --git a/bin/addons/base/ir/ir.xml b/bin/addons/base/ir/ir.xml index fdeb93cc942..89649ecb299 100644 --- a/bin/addons/base/ir/ir.xml +++ b/bin/addons/base/ir/ir.xml @@ -162,74 +162,6 @@ - - ir.actions.execute - ir.actions.execute - form - -
- - - - - - - -
- - ir.actions.execute.tree - ir.actions.execute - tree - - - - - - - - - - - Execute - ir.actions.act_window - ir.actions.execute - form - - - - - - ir.actions.group.form - ir.actions.group - form - -
- - - - -
- - ir.actions.group.tree - ir.actions.group - tree - - - - - - - - - - Group - ir.actions.act_window - ir.actions.group - form - - - - ir.actions.report.custom ir.actions.report.custom @@ -979,6 +911,10 @@ + + + + diff --git a/bin/addons/base/ir/ir_actions.py b/bin/addons/base/ir/ir_actions.py index f046bb98e28..d3e3db1a542 100644 --- a/bin/addons/base/ir/ir_actions.py +++ b/bin/addons/base/ir/ir_actions.py @@ -28,6 +28,7 @@ from osv import fields,osv import tools +import time class actions(osv.osv): _name = 'ir.actions.actions' @@ -35,38 +36,14 @@ class actions(osv.osv): _columns = { 'name': fields.char('Action Name', required=True, size=64), 'type': fields.char('Action Type', required=True, size=32), - 'usage': fields.char('Action Usage', size=32) + 'usage': fields.char('Action Usage', size=32), + 'parent_id': fields.many2one('ir.actions.server', 'Parent Action'), } _defaults = { 'usage': lambda *a: False, } actions() -class act_execute(osv.osv): - _name = 'ir.actions.execute' - _table = 'ir_act_execute' - _sequence = 'ir_actions_id_seq' - _columns = { - 'name': fields.char('name', size=64, required=True, translate=True), - 'type': fields.char('type', size=32, required=True), - 'func_name': fields.char('Function Name', size=64, required=True), - 'func_arg': fields.char('Function Argument', size=64), - 'usage': fields.char('Action Usage', size=32) - } -act_execute() - -class group(osv.osv): - _name = 'ir.actions.group' - _table = 'ir_act_group' - _sequence = 'ir_actions_id_seq' - _columns = { - 'name': fields.char('Group Name', size=64, required=True), - 'type': fields.char('Action Type', size=32, required=True), - 'exec_type': fields.char('Execution sequence', size=64, required=True), - 'usage': fields.char('Action Usage', size=32) - } -group() - class report_custom(osv.osv): _name = 'ir.actions.report.custom' _table = 'ir_act_report_custom' @@ -81,6 +58,7 @@ class report_custom(osv.osv): } _defaults = { 'multi': lambda *a: False, + 'type': lambda *a: 'ir.actions.report.custom', } report_custom() @@ -260,9 +238,10 @@ class act_url(osv.osv): 'type': fields.char('Action Type', size=32, required=True), 'url': fields.text('Action Url',required=True), 'target': fields.selection(( - ('new', 'New Window'), - ('self', 'This Window')), - 'Action Target', required=True) + ('new', 'New Window'), + ('self', 'This Window')), + 'Action Target', required=True + ) } _defaults = { 'type': lambda *a: 'ir.actions.act_url', @@ -270,3 +249,75 @@ class act_url(osv.osv): } act_url() +# +# Actions that are run on the server side +# +class actions_server(osv.osv): + _name = 'ir.actions.server' + _table = 'ir_act_server' + _sequence = 'ir_actions_id_seq' + _columns = { + 'name': fields.char('Action Name', required=True, size=64), + 'state': fields.selection([ + ('python','Python Code'), + ('dummy','Dummy'), + ('trigger','Trigger'), + ('email','Email'), + ('sms','SMS'), + ('object_create','Create Object'), + ('object_write','Write Object'), + ('client_action','Client Action'), + ('other','Others Actions'), + ], 'Action State', required=True, size=32), + 'code': fields.text('Python Code'), + 'sequence': fields.integer('Sequence'), + 'model_id': fields.many2one('ir.model', 'Model', required=True), + 'trigger_name': fields.char('Trigger Name', size=128), + 'trigger_object': fields.char('Trigger Object', size=128), + 'trigger_object_id': fields.char('Trigger Object ID', size=128), + 'message': fields.text('Message', translate=True), + 'address': fields.char('Address', size=128), + 'child_ids': fields.one2many('ir.actions.actions', 'parent_id', 'Others Actions'), + 'usage': fields.char('Action Usage', size=32), + 'type': fields.char('Report Type', size=32, required=True), + } + _defaults = { + 'state': lambda *a: 'dummy', + 'type': lambda *a: 'ir.actions.server', + 'sequence': lambda *a: 0, + 'code': lambda *a: """# You can use the following variables +# - object +# - object2 +# - time +# - cr +# - uid +# - ids +# If you plan to return an action, assign: action = {...} +""" + } + # + # Context should contains: + # ids : original ids + # id : current id of the object + # OUT: + # False : Finnished correctly + # ACTION_ID : Action to launch + def run(self, cr, uid, ids, context={}): + for action in self.browse(cr, uid, ids, context): + if action.state=='python': + localdict = { + 'self': self.pool.get(action.model_id.model), + 'context': context, + 'time': time, + 'ids': ids, + 'cr': cr, + 'uid': uid + } + print action.code + exec action.code in localdict + print localdict.keys() + if 'action' in localdict: + return localdict['action'] + return False +actions_server() + diff --git a/bin/addons/base/ir/workflow/workflow.py b/bin/addons/base/ir/workflow/workflow.py index 466c49005c7..cb55fd3d402 100644 --- a/bin/addons/base/ir/workflow/workflow.py +++ b/bin/addons/base/ir/workflow/workflow.py @@ -100,7 +100,8 @@ class wkf_activity(osv.osv): 'split_mode': fields.selection([('XOR', 'Xor'), ('OR','Or'), ('AND','And')], 'Split Mode', size=3, required=True), 'join_mode': fields.selection([('XOR', 'Xor'), ('AND', 'And')], 'Join Mode', size=3, required=True), 'kind': fields.selection([('dummy', 'Dummy'), ('function', 'Function'), ('subflow', 'Subflow'), ('stopall', 'Stop All')], 'Kind', size=64, required=True), - 'action': fields.char('Action', size=256), + 'action': fields.char('Python Action', size=256), + 'action_id': fields.many2one('ir.actions.server', 'Server Action', ondelete='set null'), 'flow_start': fields.boolean('Flow Start'), 'flow_stop': fields.boolean('Flow Stop'), 'subflow_id': fields.many2one('workflow', 'Subflow'), diff --git a/bin/addons/base/res/partner/partner_demo.xml b/bin/addons/base/res/partner/partner_demo.xml index c54031b0ed9..a534f4f4a86 100644 --- a/bin/addons/base/res/partner/partner_demo.xml +++ b/bin/addons/base/res/partner/partner_demo.xml @@ -7,8 +7,8 @@ --> partner - Pvt. Ltd - pvt ltd + Corp. + Corp./field> diff --git a/bin/osv/fields.py b/bin/osv/fields.py index 061399c62fc..619746e0235 100644 --- a/bin/osv/fields.py +++ b/bin/osv/fields.py @@ -262,6 +262,15 @@ class one2one(_column): def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None): return obj.pool.get(self._obj).search(cr, uid, args+self._domain+[('name','like',value)], offset, limit) +class many2one_memory(_column): + _classic_read = True + _classic_write = True + _type = 'many2one' + def __init__(self, obj, string='unknown', **args): + _column.__init__(self, string=string, **args) + self._obj = obj + + class many2one(_column): _classic_read = False @@ -333,6 +342,104 @@ class many2one(_column): def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None): return obj.pool.get(self._obj).search(cr, uid, args+self._domain+[('name','like',value)], offset, limit) +class one2many_memory(_column): + _classic_read = False + _classic_write = False + _type = 'one2many' + def __init__(self, obj, fields_id, string='unknown', limit=None, **args): + _column.__init__(self, string=string, **args) + self._obj = obj + self._fields_id = fields_id + self._limit = limit + assert(self.change_default != True) + + def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None): + print 'Get O2M' + if not context: + context = {} + if not values: + values = {} + res = {} + for id in ids: + res[id] = [] + ids2 = obj.pool.get(self._obj).search(cr, user, [(self._fields_id,'in',ids)], limit=self._limit) + for r in obj.pool.get(self._obj).read(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'): + if r[self._fields_id] in res: + res[r[self._fields_id]].append( r['id'] ) + print 'Ok', res + return res + + def set(self, cr, obj, id, field, values, user=None, context=None): + if not context: + context={} + if not values: + return + obj = obj.pool.get(self._obj) + for act in values: + if act[0]==0: + act[2][self._fields_id] = id + obj.create(cr, user, act[2], context=context) + elif act[0]==1: + obj.write(cr, user, [act[1]] , act[2], context=context) + elif act[0]==2: + obj.unlink(cr, user, [act[1]], context=context) + elif act[0]==3: + obj.datas[act[1]][self._fields_id] = False + elif act[0]==4: + obj.datas[act[1]] = id + elif act[0]==5: + for o in obj.datas.values(): + if o[self._fields_id]==id: + o[self._fields_id] = False + elif act[0]==6: + for id2 in (act[2] or []): + obj.datas[id2][self._fields_id] = id + + def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like'): + raise 'Not Implemented' + +class many2many_memory(_column): + _classic_read = False + _classic_write = False + _type = 'many2many' + + def __init__(self, obj, string='unknown', limit=None, **args): + _column.__init__(self, string=string, **args) + self._obj = obj + self._limit = limit + + def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None): + result = {} + for id in ids: + result[id] = obj.datas[id][name] + return result + + def set(self, cr, obj, id, name, values, user=None, context=None): + if not values: + return + for act in values: + if act[0]==0: + raise 'Not Implemented' + elif act[0]==1: + raise 'Not Implemented' + elif act[0]==2: + raise 'Not Implemented' + elif act[0]==3: + raise 'Not Implemented' + elif act[0]==4: + raise 'Not Implemented' + elif act[0]==5: + raise 'Not Implemented' + elif act[0]==6: + obj.datas[id][name] = act[2] + + # + # TODO: use a name_search + # + def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like'): + raise 'Not Implemented' + + class one2many(_column): _classic_read = False _classic_write = False diff --git a/bin/osv/orm.py b/bin/osv/orm.py index b60e98f3951..33d49217078 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -156,7 +156,7 @@ class browse_record(object): elif name in self._table._inherit_fields: col = self._table._inherit_fields[name][2] elif hasattr(self._table, name): - return getattr(self._table, name) + return lambda *args, **argv: getattr(self._table, name)(self._cr, self._uid, [self._id], *args, **argv) else: logger = netsvc.Logger() logger.notifyChannel('orm', netsvc.LOG_ERROR, "Programming error: field '%s' does not exist in object '%s' !" % (name, self._table._name)) @@ -1028,13 +1028,14 @@ class orm_template(object): class orm_memory(orm_template): _protected = ['read','write','create','default_get','perm_read','unlink','fields_get','fields_view_get','search','name_get','distinct_field_get','name_search','copy','import_data','search_count'] + _inherit_fields = {} def __init__(self, cr): super(orm_memory, self).__init__(cr) self.datas = {} self.next_id = 0 def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'): - print 'Read', ids + self.pool.get('ir.model.access').check(cr, user, self._name, 'read') if not fields: fields = self._columns.keys() result = [] @@ -1043,24 +1044,56 @@ class orm_memory(orm_template): for f in fields: r[f] = self.datas[id].get(f, False) result.append(r) + fields_post = filter(lambda x: x in self._columns and not getattr(self._columns[x], load), fields) + for f in fields_post: + res2 = self._columns[f].get(cr, self, ids, f, user, context=context, values=False) + for record in result: + record[f] = res2[record['id']] return result + def write(self, cr, user, ids, vals, context=None): + self.pool.get('ir.model.access').check(cr, user, self._name, 'write') + vals2 = {} + upd_todo = [] + for field in vals: + if self._columns[field]._classic_write: + vals2[field] = vals[field] + else: + upd_todo.append(field) + for id_new in ids: + self.datas[id_new].update(vals2) + for field in upd_todo: + self._columns[field].set(cr, self, id_new, field, vals[field], user, context) + self._validate(cr, user, [id_new]) + wf_service = netsvc.LocalService("workflow") + wf_service.trg_write(user, self._name, id_new, cr) + return id_new + + def create(self, cr, user, vals, context=None): + self.pool.get('ir.model.access').check(cr, user, self._name, 'create') self.next_id += 1 - nid = self.next_id + id_new = self.next_id default = [] - for f in self._columns.keys(): # + self._inherit_fields.keys(): + for f in self._columns.keys(): if not f in vals: default.append(f) if len(default): vals.update(self.default_get(cr, user, default, context)) - self.datas[nid] = vals - return nid - - def write(self, cr, user, ids, vals, context=None): - for id in ids: - self.datas[id].update(vals) - return True + vals2 = {} + upd_todo = [] + for field in vals: + if self._columns[field]._classic_write: + vals2[field] = vals[field] + else: + upd_todo.append(field) + self.datas[id_new] = vals2 + for field in upd_todo: + self._columns[field].set(cr, self, id_new, field, vals[field], user, context) + self._validate(cr, user, [id_new]) + wf_service = netsvc.LocalService("workflow") + wf_service.trg_create(user, self._name, id_new, cr) + return id_new def default_get(self, cr, uid, fields_list, context=None): if not context: @@ -1116,8 +1149,10 @@ class orm_memory(orm_template): return self.datas.keys() def unlink(self, cr, uid, ids, context=None): + self.pool.get('ir.model.access').check(cr, uid, self._name, 'unlink') for id in ids: - del self.datas[id] + if id in self.datas: + del self.datas[id] return True def perm_read(self, cr, user, ids, context=None, details=True): @@ -1640,6 +1675,7 @@ class orm(orm_template): else: vals[field] = False return res + def perm_read(self, cr, user, ids, context=None, details=True): if not context: context={} diff --git a/bin/osv/osv.py b/bin/osv/osv.py index 186d21cc31b..2a4d5a5f139 100644 --- a/bin/osv/osv.py +++ b/bin/osv/osv.py @@ -130,8 +130,7 @@ class osv_pool(netsvc.Service): def exec_workflow_cr(self, cr, uid, obj, method, *args): wf_service = netsvc.LocalService("workflow") - wf_service.trg_validate(uid, obj, args[0], method, cr) - return True + return wf_service.trg_validate(uid, obj, args[0], method, cr) def exec_workflow(self, db, uid, obj, method, *args): cr = pooler.get_db(db).cursor() @@ -184,27 +183,6 @@ class osv_pool(netsvc.Service): #pooler.get_pool(cr.dbname) = osv_pool() -# -# See if we can use the pool var instead of the class_pool one -# -# XXX no more used -#class inheritor(type): -# def __new__(cls, name, bases, d): -# parent_name = d.get('_inherit', None) -# if parent_name: -# parent_class = class_pool.get(parent_name) -# assert parent_class, "parent class %s does not exist !" % parent_name -# for s in ('_columns', '_defaults', '_inherits'): -# new_dict = copy.copy(getattr(parent_class, s)) -# new_dict.update(d.get(s, {})) -# d[s] = new_dict -# bases = (parent_class,) -# res = type.__new__(cls, name, bases, d) -# # -# # update _inherits of others objects -# # -# return res - class osv_memory(orm.orm_memory): #__metaclass__ = inheritor def __new__(cls): diff --git a/bin/workflow/instance.py b/bin/workflow/instance.py index 0701ccbcec7..8eb40b6cbd2 100644 --- a/bin/workflow/instance.py +++ b/bin/workflow/instance.py @@ -39,7 +39,8 @@ def create(cr, ident, wkf_id): cr.execute('insert into wkf_instance (id,res_type,res_id,uid,wkf_id) values (%d,%s,%s,%s,%s)', (id_new,res_type,res_id,uid,wkf_id)) cr.execute('select * from wkf_activity where flow_start=True and wkf_id=%d', (wkf_id,)) res = cr.dictfetchall() - workitem.create(cr, res, id_new, ident) + stack = [] + workitem.create(cr, res, id_new, ident, stack=stack) update(cr, id_new, ident) return id_new @@ -50,13 +51,20 @@ def delete(cr, ident): def validate(cr, inst_id, ident, signal, force_running=False): cr.execute("select * from wkf_workitem where inst_id=%d", (inst_id,)) for witem in cr.dictfetchall(): - workitem.process(cr, witem, ident, signal, force_running) - return _update_end(cr, inst_id, ident) + print '-----' + stack = [] + workitem.process(cr, witem, ident, signal, force_running, stack=stack) + # An action is returned + print '----- Got', stack + _update_end(cr, inst_id, ident) + return stack and stack[0] or False def update(cr, inst_id, ident): cr.execute("select * from wkf_workitem where inst_id=%d", (inst_id,)) for witem in cr.dictfetchall(): - workitem.process(cr, witem, ident) + stack = [] + workitem.process(cr, witem, ident, stack=stack) + print 'End Update' return _update_end(cr, inst_id, ident) def _update_end(cr, inst_id, ident): diff --git a/bin/workflow/wkf_expr.py b/bin/workflow/wkf_expr.py index 833c106d719..aec79f89163 100644 --- a/bin/workflow/wkf_expr.py +++ b/bin/workflow/wkf_expr.py @@ -55,18 +55,19 @@ class Env(dict): self.columns = self.obj._columns.keys() + self.obj._inherit_fields.keys() def __getitem__(self, key): - if (key in self.columns) and (not super(Env, self).__contains__(key)): - res=self.wf_service.execute_cr(self.cr, self.uid, self.model, 'read',\ - self.ids, [key])[0][key] - super(Env, self).__setitem__(key, res) - return res - elif key in dir(self.obj): - return EnvCall(self.wf_service, (self.cr, self.uid, self.model, key,\ - self.ids)) + if (key in self.columns) or (key in dir(self.obj)): + res = self.obj.browse(self.cr, self.uid, self.ids[0]) + return res[key] + #res=self.wf_service.execute_cr(self.cr, self.uid, self.model, 'read',\ + # self.ids, [key])[0][key] + #super(Env, self).__setitem__(key, res) + #return res + #elif key in dir(self.obj): + # return EnvCall(self.wf_service, (self.cr, self.uid, self.model, key,\ + # self.ids)) else: return super(Env, self).__getitem__(key) - def _eval_expr(cr, ident, workitem, action): ret=False for line in action.split('\n'): @@ -83,6 +84,15 @@ def _eval_expr(cr, ident, workitem, action): ret = eval(line, env) return ret +def execute_action(cr, ident, workitem, activity): + print 'Execute Action' + wf_service = netsvc.LocalService("object_proxy") + obj = pooler.get_pool(cr.dbname).get('ir.actions.server') + ctx = {'active_id':ident[2], 'active_ids':[ident[2]]} + result = obj.run(cr, ident[0], [activity['action_id']], ctx) + print 'Result', result + return result + def execute(cr, ident, workitem, activity): return _eval_expr(cr, ident, workitem, activity['action']) diff --git a/bin/workflow/wkf_service.py b/bin/workflow/wkf_service.py index 5700896181d..2a905d406c3 100644 --- a/bin/workflow/wkf_service.py +++ b/bin/workflow/wkf_service.py @@ -79,11 +79,15 @@ class workflow_service(netsvc.Service): instance.create(cr, ident, wkf_id) def trg_validate(self, uid, res_type, res_id, signal, cr): + result = False ident = (uid,res_type,res_id) # ids of all active workflow instances for a corresponding resource (id, model_nam) cr.execute('select id from wkf_instance where res_id=%d and res_type=%s and state=%s', (res_id, res_type, 'active')) for (id,) in cr.fetchall(): - instance.validate(cr, id, ident, signal) + res2 = instance.validate(cr, id, ident, signal) + print 'Inst val,', res2 + result = result or res2 + return result # make all workitems which are waiting for a (subflow) workflow instance # for the old resource point to the (first active) workflow instance for diff --git a/bin/workflow/workitem.py b/bin/workflow/workitem.py index 93991b2ef29..47b7834a1f6 100644 --- a/bin/workflow/workitem.py +++ b/bin/workflow/workitem.py @@ -37,7 +37,7 @@ import instance import wkf_expr import wkf_logs -def create(cr, act_datas, inst_id, ident): +def create(cr, act_datas, inst_id, ident, stack): for act in act_datas: cr.execute("select nextval('wkf_workitem_id_seq')") id_new = cr.fetchone()[0] @@ -45,23 +45,27 @@ def create(cr, act_datas, inst_id, ident): cr.execute('select * from wkf_workitem where id=%d',(id_new,)) res = cr.dictfetchone() wkf_logs.log(cr,ident,act['id'],'active') - process(cr, res, ident) + process(cr, res, ident, stack=stack) -def process(cr, workitem, ident, signal=None, force_running=False): +def process(cr, workitem, ident, signal=None, force_running=False, stack=None): + if stack is None: + raise 'Error !!!' + result = True cr.execute('select * from wkf_activity where id=%d', (workitem['act_id'],)) activity = cr.dictfetchone() triggers = False if workitem['state']=='active': triggers = True - if not _execute(cr, workitem, activity, ident): + result = _execute(cr, workitem, activity, ident, stack) + if not result: return False if workitem['state']=='running': pass if workitem['state']=='complete' or force_running: - ok = _split_test(cr, workitem, activity['split_mode'], ident, signal) + ok = _split_test(cr, workitem, activity['split_mode'], ident, signal, stack) triggers = triggers and not ok if triggers: @@ -75,7 +79,7 @@ def process(cr, workitem, ident, signal=None, force_running=False): id =cr.fetchone()[0] cr.execute('insert into wkf_triggers (model,res_id,instance_id,workitem_id,id) values (%s,%d,%d,%d,%d)', (trans['trigger_model'],res_id,workitem['inst_id'], workitem['id'], id)) - return True + return result # ---------------------- PRIVATE FUNCS -------------------------------- @@ -85,7 +89,8 @@ def _state_set(cr, workitem, activity, state, ident): workitem['state'] = state wkf_logs.log(cr,ident,activity['id'],state) -def _execute(cr, workitem, activity, ident): +def _execute(cr, workitem, activity, ident, stack): + result = True # # send a signal to parent workflow (signal: subflow.signal_name) # @@ -94,8 +99,6 @@ def _execute(cr, workitem, activity, ident): for i in cr.fetchall(): instance.validate(cr, i[0], (ident[0],i[1],i[2]), activity['signal_send'], force_running=True) - - if activity['kind']=='dummy': if workitem['state']=='active': _state_set(cr, workitem, activity, 'complete', ident) @@ -103,6 +106,12 @@ def _execute(cr, workitem, activity, ident): if workitem['state']=='active': _state_set(cr, workitem, activity, 'running', ident) wkf_expr.execute(cr, ident, workitem, activity) + if activity['action_id']: + res2 = wkf_expr.execute_action(cr, ident, workitem, activity) + # A client action has been returned + if res2: + stack.append(res2) + result=res2 _state_set(cr, workitem, activity, 'complete', ident) elif activity['kind']=='stopall': if workitem['state']=='active': @@ -131,9 +140,11 @@ def _execute(cr, workitem, activity, ident): state= cr.fetchone()[0] if state=='complete': _state_set(cr, workitem, activity, 'complete', ident) - return True + return result -def _split_test(cr, workitem, split_mode, ident, signal=None): +def _split_test(cr, workitem, split_mode, ident, signal=None, stack=None): + if stack is None: + raise 'Error !!!' cr.execute('select * from wkf_transition where act_from=%d', (workitem['act_id'],)) test = False transitions = [] @@ -158,15 +169,15 @@ def _split_test(cr, workitem, split_mode, ident, signal=None): cr.executemany('insert into wkf_witm_trans (trans_id,inst_id) values (%d,%d)', transitions) cr.execute('delete from wkf_workitem where id=%d', (workitem['id'],)) for t in transitions: - _join_test(cr, t[0], t[1], ident) + _join_test(cr, t[0], t[1], ident, stack) return True return False -def _join_test(cr, trans_id, inst_id, ident): +def _join_test(cr, trans_id, inst_id, ident, stack): cr.execute('select * from wkf_activity where id=(select act_to from wkf_transition where id=%d)', (trans_id,)) activity = cr.dictfetchone() if activity['join_mode']=='XOR': - create(cr,[activity], inst_id, ident) + create(cr,[activity], inst_id, ident, stack) cr.execute('delete from wkf_witm_trans where inst_id=%d and trans_id=%d', (inst_id,trans_id)) else: cr.execute('select id from wkf_transition where act_to=%d', (activity['id'],)) @@ -181,4 +192,4 @@ def _join_test(cr, trans_id, inst_id, ident): if ok: for (id,) in trans_ids: cr.execute('delete from wkf_witm_trans where trans_id=%d and inst_id=%d', (id,inst_id)) - create(cr, [activity], inst_id, ident) + create(cr, [activity], inst_id, ident, stack)