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