add the copyright
[odoo/odoo.git] / bin / workflow / workitem.py
1 ##############################################################################
2 #
3 # Copyright (c) 2004-2008 Tiny SPRL (http://tiny.be) All Rights Reserved.
4 #
5 # $Id$
6 #
7 # WARNING: This program as such is intended to be used by professional
8 # programmers who take the whole responsability of assessing all potential
9 # consequences resulting from its eventual inadequacies and bugs
10 # End users who are looking for a ready-to-use solution with commercial
11 # garantees and support are strongly adviced to contract a Free Software
12 # Service Company
13 #
14 # This program is Free Software; you can redistribute it and/or
15 # modify it under the terms of the GNU General Public License
16 # as published by the Free Software Foundation; either version 2
17 # of the License, or (at your option) any later version.
18 #
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 # GNU General Public License for more details.
23 #
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27 ###############################################################################
28
29 #
30 # TODO:
31 # cr.execute('delete from wkf_triggers where model=%s and res_id=%d', (res_type,res_id))
32 #
33
34 import netsvc
35 import instance
36
37 import wkf_expr
38 import wkf_logs
39
40 def create(cr, act_datas, inst_id, ident, stack):
41         for act in act_datas:
42                 cr.execute("select nextval('wkf_workitem_id_seq')")
43                 id_new = cr.fetchone()[0]
44                 cr.execute("insert into wkf_workitem (id,act_id,inst_id,state) values (%d,%s,%s,'active')", (id_new, act['id'], inst_id))
45                 cr.execute('select * from wkf_workitem where id=%d',(id_new,))
46                 res = cr.dictfetchone()
47                 wkf_logs.log(cr,ident,act['id'],'active')
48                 process(cr, res, ident, stack=stack)
49
50 def process(cr, workitem, ident, signal=None, force_running=False, stack=None):
51         if stack is None:
52                 raise 'Error !!!'
53         result = True
54         cr.execute('select * from wkf_activity where id=%d', (workitem['act_id'],))
55         activity = cr.dictfetchone()
56
57         triggers = False
58         if workitem['state']=='active':
59                 triggers = True
60                 result = _execute(cr, workitem, activity, ident, stack)
61                 if not result:
62                         return False
63
64         if workitem['state']=='running':
65                 pass
66
67         if workitem['state']=='complete' or force_running:
68                 ok = _split_test(cr, workitem, activity['split_mode'], ident, signal, stack)
69                 triggers = triggers and not ok
70
71         if triggers:
72                 cr.execute('select * from wkf_transition where act_from=%d', (workitem['act_id'],))
73                 alltrans = cr.dictfetchall()
74                 for trans in alltrans:
75                         if trans['trigger_model']:
76                                 ids = wkf_expr._eval_expr(cr,ident,workitem,trans['trigger_expr_id'])
77                                 for res_id in ids:
78                                         cr.execute('select nextval(\'wkf_triggers_id_seq\')')
79                                         id =cr.fetchone()[0]
80                                         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))
81
82         return result
83
84
85 # ---------------------- PRIVATE FUNCS --------------------------------
86
87 def _state_set(cr, workitem, activity, state, ident):
88         cr.execute('update wkf_workitem set state=%s where id=%d', (state,workitem['id']))
89         workitem['state'] = state
90         wkf_logs.log(cr,ident,activity['id'],state)
91
92 def _execute(cr, workitem, activity, ident, stack):
93         result = True
94         #
95         # send a signal to parent workflow (signal: subflow.signal_name)
96         #
97         if (workitem['state']=='active') and activity['signal_send']:
98                 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'],))
99                 for i in cr.fetchall():
100                         instance.validate(cr, i[0], (ident[0],i[1],i[2]), activity['signal_send'], force_running=True)
101
102         if activity['kind']=='dummy':
103                 if workitem['state']=='active':
104                         _state_set(cr, workitem, activity, 'complete', ident)
105         elif activity['kind']=='function':
106                 if workitem['state']=='active':
107                         _state_set(cr, workitem, activity, 'running', ident)
108                         wkf_expr.execute(cr, ident, workitem, activity)
109                         if activity['action_id']:
110                                 res2 = wkf_expr.execute_action(cr, ident, workitem, activity)
111                                 # A client action has been returned
112                                 if res2:
113                                         stack.append(res2)
114                                         result=res2
115                         _state_set(cr, workitem, activity, 'complete', ident)
116         elif activity['kind']=='stopall':
117                 if workitem['state']=='active':
118                         _state_set(cr, workitem, activity, 'running', ident)
119                         cr.execute('delete from wkf_workitem where inst_id=%d and id<>%d', (workitem['inst_id'], workitem['id']))
120                         if activity['action']:
121                                 wkf_expr.execute(cr, ident, workitem, activity)
122                         _state_set(cr, workitem, activity, 'complete', ident)
123         elif activity['kind']=='subflow':
124                 if workitem['state']=='active':
125                         _state_set(cr, workitem, activity, 'running', ident)
126                         if activity.get('action', False):
127                                 id_new = wkf_expr.execute(cr, ident, workitem, activity)
128                                 if not (id_new):
129                                         cr.execute('delete from wkf_workitem where id=%s', (workitem['id'],))
130                                         return False
131                                 assert type(id_new)==type(1) or type(id_new)==type(1L), 'Wrong return value: '+str(id_new)+' '+str(type(id_new))
132                                 cr.execute('select id from wkf_instance where res_id=%d and wkf_id=%d', (id_new,activity['subflow_id']))
133                                 id_new = cr.fetchone()[0]
134                         else:
135                                 id_new = instance.create(cr, ident, activity['subflow_id'])
136                         cr.execute('update wkf_workitem set subflow_id=%d where id=%s', (id_new, workitem['id']))
137                         workitem['subflow_id'] = id_new
138                 if workitem['state']=='running':
139                         cr.execute("select state from wkf_instance where id=%d", (workitem['subflow_id'],))
140                         state= cr.fetchone()[0]
141                         if state=='complete':
142                                 _state_set(cr, workitem, activity, 'complete', ident)
143         return result
144
145 def _split_test(cr, workitem, split_mode, ident, signal=None, stack=None):
146         if stack is None:
147                 raise 'Error !!!'
148         cr.execute('select * from wkf_transition where act_from=%d', (workitem['act_id'],))
149         test = False
150         transitions = []
151         alltrans = cr.dictfetchall()
152         if split_mode=='XOR' or split_mode=='OR':
153                 for transition in alltrans:
154                         if wkf_expr.check(cr, workitem, ident, transition,signal):
155                                 test = True
156                                 transitions.append((transition['id'], workitem['inst_id']))
157                                 if split_mode=='XOR':
158                                         break
159         else:
160                 test = True
161                 for transition in alltrans:
162                         if not wkf_expr.check(cr, workitem, ident, transition,signal):
163                                 test = False
164                                 break
165                         cr.execute('select count(*) from wkf_witm_trans where trans_id=%d and inst_id=%d', (transition['id'], workitem['inst_id']))
166                         if not cr.fetchone()[0]:
167                                 transitions.append((transition['id'], workitem['inst_id']))
168         if test and len(transitions):
169                 cr.executemany('insert into wkf_witm_trans (trans_id,inst_id) values (%d,%d)', transitions)
170                 cr.execute('delete from wkf_workitem where id=%d', (workitem['id'],))
171                 for t in transitions:
172                         _join_test(cr, t[0], t[1], ident, stack)
173                 return True
174         return False
175
176 def _join_test(cr, trans_id, inst_id, ident, stack):
177         cr.execute('select * from wkf_activity where id=(select act_to from wkf_transition where id=%d)', (trans_id,))
178         activity = cr.dictfetchone()
179         if activity['join_mode']=='XOR':
180                 create(cr,[activity], inst_id, ident, stack)
181                 cr.execute('delete from wkf_witm_trans where inst_id=%d and trans_id=%d', (inst_id,trans_id))
182         else:
183                 cr.execute('select id from wkf_transition where act_to=%d', (activity['id'],))
184                 trans_ids = cr.fetchall()
185                 ok = True
186                 for (id,) in trans_ids:
187                         cr.execute('select count(*) from wkf_witm_trans where trans_id=%d and inst_id=%d', (id,inst_id))
188                         res = cr.fetchone()[0]
189                         if not res:
190                                 ok = False
191                                 break
192                 if ok:
193                         for (id,) in trans_ids:
194                                 cr.execute('delete from wkf_witm_trans where trans_id=%d and inst_id=%d', (id,inst_id))
195                         create(cr, [activity], inst_id, ident, stack)