1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
24 # cr.execute('delete from wkf_triggers where model=%s and res_id=%s', (res_type,res_id))
32 logger = logging.getLogger(__name__)
34 def create(cr, act_datas, inst_id, ident, stack):
36 cr.execute("select nextval('wkf_workitem_id_seq')")
37 id_new = cr.fetchone()[0]
38 cr.execute("insert into wkf_workitem (id,act_id,inst_id,state) values (%s,%s,%s,'active')", (id_new, act['id'], inst_id))
39 cr.execute('select * from wkf_workitem where id=%s',(id_new,))
40 res = cr.dictfetchone()
41 logger.info('Created workflow item in activity %s',
42 act['id'], extra={'ident': ident})
43 process(cr, res, ident, stack=stack)
45 def process(cr, workitem, ident, signal=None, force_running=False, stack=None):
46 assert stack is not None
48 cr.execute('select * from wkf_activity where id=%s', (workitem['act_id'],))
49 activity = cr.dictfetchone()
52 if workitem['state'] == 'active':
54 if not _execute(cr, workitem, activity, ident, stack):
57 if force_running or workitem['state'] == 'complete':
58 ok = _split_test(cr, workitem, activity['split_mode'], ident, signal, stack)
59 triggers = triggers and not ok
62 cr.execute('select * from wkf_transition where act_from=%s', (workitem['act_id'],))
63 for trans in cr.dictfetchall():
64 if trans['trigger_model']:
65 ids = wkf_expr._eval_expr(cr,ident,workitem,trans['trigger_expr_id'])
67 cr.execute('select nextval(\'wkf_triggers_id_seq\')')
69 cr.execute('insert into wkf_triggers (model,res_id,instance_id,workitem_id,id) values (%s,%s,%s,%s,%s)', (trans['trigger_model'],res_id,workitem['inst_id'], workitem['id'], id))
74 # ---------------------- PRIVATE FUNCS --------------------------------
76 def _state_set(cr, workitem, activity, state, ident):
77 cr.execute('update wkf_workitem set state=%s where id=%s', (state,workitem['id']))
78 workitem['state'] = state
79 logger.info("Changed state of work item %s to \"%s\" in activity %s",
80 workitem['id'], state, activity['id'], extra={'ident': ident})
82 def _execute(cr, workitem, activity, ident, stack):
85 # send a signal to parent workflow (signal: subflow.signal_name)
88 if (workitem['state']=='active') and activity['signal_send']:
89 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=%s)", (workitem['inst_id'],))
90 for i in cr.fetchall():
91 signal_todo.append((i[0], (ident[0],i[1],i[2]), activity['signal_send']))
93 if activity['kind']=='dummy':
94 if workitem['state']=='active':
95 _state_set(cr, workitem, activity, 'complete', ident)
96 if activity['action_id']:
97 res2 = wkf_expr.execute_action(cr, ident, workitem, activity)
101 elif activity['kind']=='function':
102 if workitem['state']=='active':
103 _state_set(cr, workitem, activity, 'running', ident)
104 returned_action = wkf_expr.execute(cr, ident, workitem, activity)
105 if type(returned_action) in (dict,):
106 stack.append(returned_action)
107 if activity['action_id']:
108 res2 = wkf_expr.execute_action(cr, ident, workitem, activity)
109 # A client action has been returned
113 _state_set(cr, workitem, activity, 'complete', ident)
114 elif activity['kind']=='stopall':
115 if workitem['state']=='active':
116 _state_set(cr, workitem, activity, 'running', ident)
117 cr.execute('delete from wkf_workitem where inst_id=%s and id<>%s', (workitem['inst_id'], workitem['id']))
118 if activity['action']:
119 wkf_expr.execute(cr, ident, workitem, activity)
120 _state_set(cr, workitem, activity, 'complete', ident)
121 elif activity['kind']=='subflow':
122 if workitem['state']=='active':
123 _state_set(cr, workitem, activity, 'running', ident)
124 if activity.get('action', False):
125 id_new = wkf_expr.execute(cr, ident, workitem, activity)
127 cr.execute('delete from wkf_workitem where id=%s', (workitem['id'],))
129 assert type(id_new)==type(1) or type(id_new)==type(1L), 'Wrong return value: '+str(id_new)+' '+str(type(id_new))
130 cr.execute('select id from wkf_instance where res_id=%s and wkf_id=%s', (id_new,activity['subflow_id']))
131 id_new = cr.fetchone()[0]
133 id_new = instance.create(cr, ident, activity['subflow_id'])
134 cr.execute('update wkf_workitem set subflow_id=%s where id=%s', (id_new, workitem['id']))
135 workitem['subflow_id'] = id_new
136 if workitem['state']=='running':
137 cr.execute("select state from wkf_instance where id=%s", (workitem['subflow_id'],))
138 state= cr.fetchone()[0]
139 if state=='complete':
140 _state_set(cr, workitem, activity, 'complete', ident)
141 for t in signal_todo:
142 instance.validate(cr, t[0], t[1], t[2], force_running=True)
146 def _split_test(cr, workitem, split_mode, ident, signal=None, stack=None):
147 cr.execute('select * from wkf_transition where act_from=%s', (workitem['act_id'],))
150 alltrans = cr.dictfetchall()
151 if split_mode=='XOR' or split_mode=='OR':
152 for transition in alltrans:
153 if wkf_expr.check(cr, workitem, ident, transition,signal):
155 transitions.append((transition['id'], workitem['inst_id']))
156 if split_mode=='XOR':
160 for transition in alltrans:
161 if not wkf_expr.check(cr, workitem, ident, transition,signal):
164 cr.execute('select count(*) from wkf_witm_trans where trans_id=%s and inst_id=%s', (transition['id'], workitem['inst_id']))
165 if not cr.fetchone()[0]:
166 transitions.append((transition['id'], workitem['inst_id']))
167 if test and len(transitions):
168 cr.executemany('insert into wkf_witm_trans (trans_id,inst_id) values (%s,%s)', transitions)
169 cr.execute('delete from wkf_workitem where id=%s', (workitem['id'],))
170 for t in transitions:
171 _join_test(cr, t[0], t[1], ident, stack)
175 def _join_test(cr, trans_id, inst_id, ident, stack):
176 cr.execute('select * from wkf_activity where id=(select act_to from wkf_transition where id=%s)', (trans_id,))
177 activity = cr.dictfetchone()
178 if activity['join_mode']=='XOR':
179 create(cr,[activity], inst_id, ident, stack)
180 cr.execute('delete from wkf_witm_trans where inst_id=%s and trans_id=%s', (inst_id,trans_id))
182 cr.execute('select id from wkf_transition where act_to=%s', (activity['id'],))
183 trans_ids = cr.fetchall()
185 for (id,) in trans_ids:
186 cr.execute('select count(*) from wkf_witm_trans where trans_id=%s and inst_id=%s', (id,inst_id))
187 res = cr.fetchone()[0]
192 for (id,) in trans_ids:
193 cr.execute('delete from wkf_witm_trans where trans_id=%s and inst_id=%s', (id,inst_id))
194 create(cr, [activity], inst_id, ident, stack)
196 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: