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