summaryrefslogtreecommitdiff
path: root/bin/workflow
diff options
context:
space:
mode:
authorpinky <>2006-12-07 13:41:40 +0000
committerpinky <>2006-12-07 13:41:40 +0000
commit004a0b996ff8f269451e07346f71a129a1f3fbaf (patch)
tree48f43c1fc2ca4c1f4d5648e7e73553d3f4ccae06 /bin/workflow
New trunk
bzr revid: pinky-3f10ee12cea3c4c75cef44ab04ad33ef47432907
Diffstat (limited to 'bin/workflow')
-rw-r--r--bin/workflow/__init__.py31
-rw-r--r--bin/workflow/common.py32
-rw-r--r--bin/workflow/instance.py81
-rw-r--r--bin/workflow/wkf_expr.py91
-rw-r--r--bin/workflow/wkf_logs.py35
-rw-r--r--bin/workflow/wkf_service.py98
-rw-r--r--bin/workflow/workitem.py184
7 files changed, 552 insertions, 0 deletions
diff --git a/bin/workflow/__init__.py b/bin/workflow/__init__.py
new file mode 100644
index 00000000000..2f7247b929c
--- /dev/null
+++ b/bin/workflow/__init__.py
@@ -0,0 +1,31 @@
+##############################################################################
+#
+# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
+# Fabien Pinckaers <fp@tiny.Be>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+
+import wkf_service
+
diff --git a/bin/workflow/common.py b/bin/workflow/common.py
new file mode 100644
index 00000000000..152485ffd48
--- /dev/null
+++ b/bin/workflow/common.py
@@ -0,0 +1,32 @@
+##############################################################################
+#
+# copyright (c) 2004 TINY SPRL. (http://tiny.be)
+# copyright (c) 2004 Fabien Pinckaers <fp@tiny.be>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contact a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+class except_wkf(Exception):
+ def __init__(self, name, value):
+ self.name = name
+ self.value = value
diff --git a/bin/workflow/instance.py b/bin/workflow/instance.py
new file mode 100644
index 00000000000..0701ccbcec7
--- /dev/null
+++ b/bin/workflow/instance.py
@@ -0,0 +1,81 @@
+##############################################################################
+#
+# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
+# Fabien Pinckaers <fp@tiny.Be>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+import wkf_logs
+import workitem
+
+import netsvc
+import pooler
+
+def create(cr, ident, wkf_id):
+ (uid,res_type,res_id) = ident
+ cr.execute("select nextval('wkf_instance_id_seq')")
+ id_new = cr.fetchone()[0]
+ 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)
+ update(cr, id_new, ident)
+ return id_new
+
+def delete(cr, ident):
+ (uid,res_type,res_id) = ident
+ cr.execute('delete from wkf_instance where res_id=%d and res_type=%s', (res_id,res_type))
+
+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)
+
+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)
+ return _update_end(cr, inst_id, ident)
+
+def _update_end(cr, inst_id, ident):
+ cr.execute('select wkf_id from wkf_instance where id=%d', (inst_id,))
+ wkf_id = cr.fetchone()[0]
+ cr.execute('select state,flow_stop from wkf_workitem w left join wkf_activity a on (a.id=w.act_id) where w.inst_id=%d', (inst_id,))
+ ok=True
+ for r in cr.fetchall():
+ if (r[0]<>'complete') or not r[1]:
+ ok=False
+ break
+ if ok:
+ cr.execute('select distinct a.name from wkf_activity a left join wkf_workitem w on (a.id=w.act_id) where w.inst_id=%d', (inst_id,))
+ act_names = cr.fetchall()
+ cr.execute("update wkf_instance set state='complete' where id=%d", (inst_id,))
+ cr.execute("update wkf_workitem set state='complete' where subflow_id=%d", (inst_id,))
+ cr.execute("select i.id,w.osv,i.res_id from wkf_instance i left join wkf w on (i.wkf_id=w.id) where i.id in (select inst_id from wkf_workitem where subflow_id=%d)", (inst_id,))
+ for i in cr.fetchall():
+ for act_name in act_names:
+ validate(cr, i[0], (ident[0],i[1],i[2]), 'subflow.'+act_name[0])
+ return ok
+
diff --git a/bin/workflow/wkf_expr.py b/bin/workflow/wkf_expr.py
new file mode 100644
index 00000000000..0245e9e0bd6
--- /dev/null
+++ b/bin/workflow/wkf_expr.py
@@ -0,0 +1,91 @@
+##############################################################################
+#
+# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
+#
+# $Id: wkf_expr.py 1304 2005-09-08 14:35:42Z nicoe $
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+import sys
+import netsvc
+import osv as base
+import pooler
+
+def _inst_value_get(ident, field):
+ service = netsvc.LocalService("object_proxy")
+ res = service.execute(ident[0], ident[1], 'read', [ident[2]], [field])
+ return res[0][field]
+
+#
+# TODO: improve evaluation expression
+# VERY SLOW !!! read all !!!
+#
+class _eval_call(object):
+ def __init__(self,wf_service,d_arg):
+ self.wf_service=wf_service
+ self.d_arg=d_arg
+ def __call__(self,*args):
+ arg=self.d_arg+args
+ return self.wf_service.execute_cr(*arg)
+
+def _eval_expr(cr, ident, workitem, action):
+ ret=False
+ for line in action.split('\n'):
+ uid=ident[0]
+ model=ident[1]
+ ids=[ident[2]]
+ if line =='True':
+ ret=True
+ elif line =='False':
+ ret=False
+ else:
+ wf_service = netsvc.LocalService("object_proxy")
+ res=wf_service.execute_cr(cr, uid, model, 'read', ids, None)
+ if res:
+ env=res[0]
+ if '(' in line:
+ pool=pooler.get_pool(cr.dbname)
+ obj=pool.get(model)
+ for i in dir(obj):
+ attr=getattr(obj,i)
+ if not i.startswith('_') and callable(attr):
+ env[i]=_eval_call(wf_service,(cr,uid,model,i,ids))
+ ret=eval(line,env)
+ return ret
+
+def execute(cr, ident, workitem, activity):
+ return _eval_expr(cr, ident, workitem, activity['action'])
+
+def check(cr, workitem, ident, transition, signal):
+ ok = True
+ if transition['signal']:
+ ok = (signal==transition['signal'])
+
+ if transition['role_id']:
+ uid = ident[0]
+ serv = netsvc.LocalService('object_proxy')
+ user_roles = serv.execute_cr(cr, uid, 'res.users', 'read', [uid], ['roles_id'])[0]['roles_id']
+ ok = ok and serv.execute_cr(cr, uid, 'res.roles', 'check', user_roles, transition['role_id'])
+ ok = ok and _eval_expr(cr, ident, workitem, transition['condition'])
+ return ok
+
diff --git a/bin/workflow/wkf_logs.py b/bin/workflow/wkf_logs.py
new file mode 100644
index 00000000000..abefc6348ba
--- /dev/null
+++ b/bin/workflow/wkf_logs.py
@@ -0,0 +1,35 @@
+##############################################################################
+#
+# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
+# Fabien Pinckaers <fp@tiny.Be>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+#
+# May be uncommented to logs workflows modifications
+#
+
+def log(cr,ident,act_id,info=''):
+ pass
+ #cr.execute('insert into wkf_logs (res_type, res_id, uid, act_id, time, info) values (%s,%d,%d,%d,current_time,%s)', (ident[1],int(ident[2]),int(ident[0]),int(act_id),info))
diff --git a/bin/workflow/wkf_service.py b/bin/workflow/wkf_service.py
new file mode 100644
index 00000000000..707ce97eb9c
--- /dev/null
+++ b/bin/workflow/wkf_service.py
@@ -0,0 +1,98 @@
+##############################################################################
+#
+# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
+# Fabien Pinckaers <fp@tiny.Be>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+import wkf_logs
+import workitem
+import instance
+
+import netsvc
+import pooler
+
+class workflow_service(netsvc.Service):
+ def __init__(self, name='workflow', audience='*'):
+ netsvc.Service.__init__(self, name, audience)
+ self.exportMethod(self.trg_write)
+ self.exportMethod(self.trg_delete)
+ self.exportMethod(self.trg_create)
+ self.exportMethod(self.trg_validate)
+ self.exportMethod(self.trg_redirect)
+ self.exportMethod(self.trg_trigger)
+
+ def trg_write(self, uid, res_type, res_id, cr):
+ ident = (uid,res_type,res_id)
+ 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.update(cr, id, ident)
+
+ def trg_trigger(self, uid, res_type, res_id, cr):
+ cr.execute('select instance_id from wkf_triggers where res_id=%d and model=%s', (res_id,res_type))
+ res = cr.fetchall()
+ for (instance_id,) in res:
+ cr.execute('select uid,res_type,res_id from wkf_instance where id=%d', (instance_id,))
+ ident = cr.fetchone()
+ instance.update(cr, instance_id, ident)
+
+ def trg_delete(self, uid, res_type, res_id, cr):
+ ident = (uid,res_type,res_id)
+ instance.delete(cr, ident)
+
+ def trg_create(self, uid, res_type, res_id, cr):
+ ident = (uid,res_type,res_id)
+ cr.execute('select id from wkf where osv=%s and on_create=True', (res_type,))
+ for (wkf_id,) in cr.fetchall():
+ instance.create(cr, ident, wkf_id)
+
+ def trg_validate(self, uid, res_type, res_id, signal, cr):
+ 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)
+
+ # make all workitems which are waiting for a (subflow) workflow instance
+ # for the old resource point to the (first active) workflow instance for
+ # the new resource
+ def trg_redirect(self, uid, res_type, res_id, new_rid, cr):
+ # get ids of wkf instances for the old resource (res_id)
+#CHECKME: shouldn't we get only active instances?
+ cr.execute('select id, wkf_id from wkf_instance where res_id=%d and res_type=%s', (res_id, res_type))
+ for old_inst_id, wkf_id in cr.fetchall():
+ # first active instance for new resource (new_rid), using same wkf
+ cr.execute(
+ 'SELECT id '\
+ 'FROM wkf_instance '\
+ 'WHERE res_id=%d AND res_type=%s AND wkf_id=%d AND state=%s',
+ (new_rid, res_type, wkf_id, 'active'))
+ new_id = cr.fetchone()
+ if new_id:
+ # select all workitems which "wait" for the old instance
+ cr.execute('select id from wkf_workitem where subflow_id=%d', (old_inst_id,))
+ for (item_id,) in cr.fetchall():
+ # redirect all those workitems to the wkf instance of the new resource
+ cr.execute('update wkf_workitem set subflow_id=%d where id=%d', (new_id[0], item_id))
+workflow_service()
diff --git a/bin/workflow/workitem.py b/bin/workflow/workitem.py
new file mode 100644
index 00000000000..b01c9fbed3d
--- /dev/null
+++ b/bin/workflow/workitem.py
@@ -0,0 +1,184 @@
+##############################################################################
+#
+# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
+# Fabien Pinckaers <fp@tiny.Be>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+#
+# TODO:
+# cr.execute('delete from wkf_triggers where model=%s and res_id=%d', (res_type,res_id))
+#
+
+import netsvc
+import instance
+
+import wkf_expr
+import wkf_logs
+
+def create(cr, act_datas, inst_id, ident):
+ for act in act_datas:
+ cr.execute("select nextval('wkf_workitem_id_seq')")
+ id_new = cr.fetchone()[0]
+ cr.execute("insert into wkf_workitem (id,act_id,inst_id,state) values (%d,%s,%s,'active')", (id_new, act['id'], inst_id))
+ 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)
+
+def process(cr, workitem, ident, signal=None, force_running=False):
+ 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):
+ return False
+
+ if workitem['state']=='running':
+ pass
+
+ if workitem['state']=='complete' or force_running:
+ ok = _split_test(cr, workitem, activity['split_mode'], ident, signal)
+ triggers = triggers and not ok
+
+ if triggers:
+ cr.execute('select * from wkf_transition where act_from=%d', (workitem['act_id'],))
+ alltrans = cr.dictfetchall()
+ for trans in alltrans:
+ if trans['trigger_model']:
+ ids = wkf_expr._eval_expr(cr,ident,workitem,trans['trigger_expr_id'])
+ for id in ids:
+ cr.execute('insert into wkf_triggers (model,res_id,instance_id,workitem_id) values (%s,%d,%d,%d)', (trans['trigger_model'],id,workitem['inst_id'], workitem['id']))
+
+ return True
+
+
+# ---------------------- PRIVATE FUNCS --------------------------------
+
+def _state_set(cr, workitem, activity, state, ident):
+ cr.execute('update wkf_workitem set state=%s where id=%d', (state,workitem['id']))
+ workitem['state'] = state
+ wkf_logs.log(cr,ident,activity['id'],state)
+
+def _execute(cr, workitem, activity, ident):
+ #
+ # send a signal to parent workflow (signal: subflow.signal_name)
+ #
+ if (workitem['state']=='active') and activity['signal_send']:
+ cr.execute("select i.id,w.osv,i.res_id from wkf_instance i left join wkf w on (i.wkf_id=w.id) where i.id in (select inst_id from wkf_workitem where subflow_id=%d)", (workitem['inst_id'],))
+ 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)
+ elif activity['kind']=='function':
+ if workitem['state']=='active':
+ _state_set(cr, workitem, activity, 'running', ident)
+ wkf_expr.execute(cr, ident, workitem, activity)
+ _state_set(cr, workitem, activity, 'complete', ident)
+ elif activity['kind']=='stopall':
+ if workitem['state']=='active':
+ _state_set(cr, workitem, activity, 'running', ident)
+ cr.execute('delete from wkf_workitem where inst_id=%d and id<>%d', (workitem['inst_id'], workitem['id']))
+ if activity['action']:
+ wkf_expr.execute(cr, ident, workitem, activity)
+ _state_set(cr, workitem, activity, 'complete', ident)
+ elif activity['kind']=='subflow':
+ if workitem['state']=='active':
+ _state_set(cr, workitem, activity, 'running', ident)
+ if activity.get('action', False):
+ id_new = wkf_expr.execute(cr, ident, workitem, activity)
+ if not (id_new):
+ cr.execute('delete from wkf_workitem where id=%s', (workitem['id'],))
+ return False
+ assert type(id_new)==type(1) or type(id_new)==type(1L), 'Wrong return value: '+str(id_new)+' '+str(type(id_new))
+ cr.execute('select id from wkf_instance where res_id=%d and wkf_id=%d', (id_new,activity['subflow_id']))
+ id_new = cr.fetchone()[0]
+ else:
+ id_new = instance.create(cr, ident, activity['subflow_id'])
+ cr.execute('update wkf_workitem set subflow_id=%d where id=%s', (id_new, workitem['id']))
+ workitem['subflow_id'] = id_new
+ if workitem['state']=='running':
+ cr.execute("select state from wkf_instance where id=%d", (workitem['subflow_id'],))
+ state= cr.fetchone()[0]
+ if state=='complete':
+ _state_set(cr, workitem, activity, 'complete', ident)
+ return True
+
+def _split_test(cr, workitem, split_mode, ident, signal=None):
+ cr.execute('select * from wkf_transition where act_from=%d', (workitem['act_id'],))
+ test = False
+ transitions = []
+ alltrans = cr.dictfetchall()
+ if split_mode=='XOR' or split_mode=='OR':
+ for transition in alltrans:
+ if wkf_expr.check(cr, workitem, ident, transition,signal):
+ test = True
+ transitions.append((transition['id'], workitem['inst_id']))
+ if split_mode=='XOR':
+ break
+ else:
+ test = True
+ for transition in alltrans:
+ if not wkf_expr.check(cr, workitem, ident, transition,signal):
+ test = False
+ break
+ cr.execute('select count(*) from wkf_witm_trans where trans_id=%d and inst_id=%d', (transition['id'], workitem['inst_id']))
+ if not cr.fetchone()[0]:
+ transitions.append((transition['id'], workitem['inst_id']))
+ if not test:
+ pass
+ if test and len(transitions):
+ 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)
+ return True
+ return False
+
+def _join_test(cr, trans_id, inst_id, ident):
+ 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)
+ 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'],))
+ trans_ids = cr.fetchall()
+ ok = True
+ for (id,) in trans_ids:
+ cr.execute('select count(*) from wkf_witm_trans where trans_id=%d and inst_id=%d', (id,inst_id))
+ res = cr.fetchone()[0]
+ if not res:
+ ok = False
+ break
+ 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)