Skip to content

Commit 5aef045

Browse files
author
Stephane Wirtel
committed
[REF] Merge a refactoring of the workflow (lp:~openerp-dev/openobject-server/trunk-refactor-workflow-stw)
bzr revid: [email protected]
2 parents 552c76c + 1c398cd commit 5aef045

File tree

6 files changed

+554
-372
lines changed

6 files changed

+554
-372
lines changed

openerp/workflow/__init__.py

+15-53
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# -*- coding: utf-8 -*-
22
##############################################################################
3-
#
3+
#
44
# OpenERP, Open Source Management Solution
5-
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
5+
# Copyright (C) 2004-2014 Tiny SPRL (<http://tiny.be>).
66
#
77
# This program is free software: you can redistribute it and/or modify
88
# it under the terms of the GNU Affero General Public License as
@@ -15,16 +15,17 @@
1515
# GNU Affero General Public License for more details.
1616
#
1717
# 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/>.
18+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1919
#
2020
##############################################################################
2121

22-
import instance
22+
from openerp.workflow.service import WorkflowService
2323

24-
wkf_on_create_cache = {}
24+
# The new API is in openerp.workflow.workflow_service
25+
# OLD API of the Workflow
2526

2627
def clear_cache(cr, uid):
27-
wkf_on_create_cache[cr.dbname]={}
28+
WorkflowService.clear_cache(cr.dbname)
2829

2930
def trg_write(uid, res_type, res_id, cr):
3031
"""
@@ -36,10 +37,7 @@ def trg_write(uid, res_type, res_id, cr):
3637
:param res_id: the model instance id the workflow belongs to
3738
:param cr: a database cursor
3839
"""
39-
ident = (uid,res_type,res_id)
40-
cr.execute('select id from wkf_instance where res_id=%s and res_type=%s and state=%s', (res_id or None,res_type or None, 'active'))
41-
for (id,) in cr.fetchall():
42-
instance.update(cr, id, ident)
40+
return WorkflowService.new(cr, uid, res_type, res_id).write()
4341

4442
def trg_trigger(uid, res_type, res_id, cr):
4543
"""
@@ -52,12 +50,7 @@ def trg_trigger(uid, res_type, res_id, cr):
5250
:param res_id: the model instance id the workflow belongs to
5351
:param cr: a database cursor
5452
"""
55-
cr.execute('select instance_id from wkf_triggers where res_id=%s and model=%s', (res_id,res_type))
56-
res = cr.fetchall()
57-
for (instance_id,) in res:
58-
cr.execute('select %s,res_type,res_id from wkf_instance where id=%s', (uid, instance_id,))
59-
ident = cr.fetchone()
60-
instance.update(cr, instance_id, ident)
53+
return WorkflowService.new(cr, uid, res_type, res_id).trigger()
6154

6255
def trg_delete(uid, res_type, res_id, cr):
6356
"""
@@ -67,8 +60,7 @@ def trg_delete(uid, res_type, res_id, cr):
6760
:param res_id: the model instance id the workflow belongs to
6861
:param cr: a database cursor
6962
"""
70-
ident = (uid,res_type,res_id)
71-
instance.delete(cr, ident)
63+
return WorkflowService.new(cr, uid, res_type, res_id).delete()
7264

7365
def trg_create(uid, res_type, res_id, cr):
7466
"""
@@ -78,16 +70,7 @@ def trg_create(uid, res_type, res_id, cr):
7870
:param res_id: the model instance id to own the created worfklow instance
7971
:param cr: a database cursor
8072
"""
81-
ident = (uid,res_type,res_id)
82-
wkf_on_create_cache.setdefault(cr.dbname, {})
83-
if res_type in wkf_on_create_cache[cr.dbname]:
84-
wkf_ids = wkf_on_create_cache[cr.dbname][res_type]
85-
else:
86-
cr.execute('select id from wkf where osv=%s and on_create=True', (res_type,))
87-
wkf_ids = cr.fetchall()
88-
wkf_on_create_cache[cr.dbname][res_type] = wkf_ids
89-
for (wkf_id,) in wkf_ids:
90-
instance.create(cr, ident, wkf_id)
73+
return WorkflowService.new(cr, uid, res_type, res_id).create()
9174

9275
def trg_validate(uid, res_type, res_id, signal, cr):
9376
"""
@@ -98,14 +81,8 @@ def trg_validate(uid, res_type, res_id, signal, cr):
9881
:signal: the signal name to be fired
9982
:param cr: a database cursor
10083
"""
101-
result = False
102-
ident = (uid,res_type,res_id)
103-
# ids of all active workflow instances for a corresponding resource (id, model_nam)
104-
cr.execute('select id from wkf_instance where res_id=%s and res_type=%s and state=%s', (res_id, res_type, 'active'))
105-
for (id,) in cr.fetchall():
106-
res2 = instance.validate(cr, id, ident, signal)
107-
result = result or res2
108-
return result
84+
assert isinstance(signal, basestring)
85+
return WorkflowService.new(cr, uid, res_type, res_id).validate(signal)
10986

11087
def trg_redirect(uid, res_type, res_id, new_rid, cr):
11188
"""
@@ -120,22 +97,7 @@ def trg_redirect(uid, res_type, res_id, new_rid, cr):
12097
:param new_rid: the model instance id to own the worfklow instance
12198
:param cr: a database cursor
12299
"""
123-
# get ids of wkf instances for the old resource (res_id)
124-
#CHECKME: shouldn't we get only active instances?
125-
cr.execute('select id, wkf_id from wkf_instance where res_id=%s and res_type=%s', (res_id, res_type))
126-
for old_inst_id, wkf_id in cr.fetchall():
127-
# first active instance for new resource (new_rid), using same wkf
128-
cr.execute(
129-
'SELECT id '\
130-
'FROM wkf_instance '\
131-
'WHERE res_id=%s AND res_type=%s AND wkf_id=%s AND state=%s',
132-
(new_rid, res_type, wkf_id, 'active'))
133-
new_id = cr.fetchone()
134-
if new_id:
135-
# select all workitems which "wait" for the old instance
136-
cr.execute('select id from wkf_workitem where subflow_id=%s', (old_inst_id,))
137-
for (item_id,) in cr.fetchall():
138-
# redirect all those workitems to the wkf instance of the new resource
139-
cr.execute('update wkf_workitem set subflow_id=%s where id=%s', (new_id[0], item_id))
100+
assert isinstance(new_rid, (long, int))
101+
return WorkflowService.new(cr, uid, res_type, res_id).redirect(new_rid)
140102

141103
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

openerp/workflow/helpers.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import openerp.sql_db
2+
3+
class Session(object):
4+
def __init__(self, cr, uid):
5+
assert isinstance(cr, openerp.sql_db.Cursor)
6+
assert isinstance(uid, (int, long))
7+
self.cr = cr
8+
self.uid = uid
9+
10+
class Record(object):
11+
def __init__(self, model, record_id):
12+
assert isinstance(model, basestring)
13+
assert isinstance(record_id, (int, long))
14+
self.model = model
15+
self.id = record_id
16+
17+
class WorkflowActivity(object):
18+
KIND_FUNCTION = 'function'
19+
KIND_DUMMY = 'dummy'
20+
KIND_STOPALL = 'stopall'
21+
KIND_SUBFLOW = 'subflow'
22+

openerp/workflow/instance.py

+107-50
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
##############################################################################
33
#
44
# OpenERP, Open Source Management Solution
5-
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
5+
# Copyright (C) 2004-2014 Tiny SPRL (<http://tiny.be>).
66
#
77
# This program is free software: you can redistribute it and/or modify
88
# it under the terms of the GNU Affero General Public License as
@@ -19,58 +19,115 @@
1919
#
2020
##############################################################################
2121
import workitem
22+
from openerp.workflow.helpers import Session
23+
from openerp.workflow.helpers import Record
24+
from openerp.workflow.workitem import WorkflowItem
2225

23-
def create(cr, ident, wkf_id):
24-
(uid,res_type,res_id) = ident
25-
cr.execute('insert into wkf_instance (res_type,res_id,uid,wkf_id) values (%s,%s,%s,%s) RETURNING id', (res_type,res_id,uid,wkf_id))
26-
id_new = cr.fetchone()[0]
27-
cr.execute('select * from wkf_activity where flow_start=True and wkf_id=%s', (wkf_id,))
28-
res = cr.dictfetchall()
29-
stack = []
30-
workitem.create(cr, res, id_new, ident, stack=stack)
31-
update(cr, id_new, ident)
32-
return id_new
33-
34-
def delete(cr, ident):
35-
(uid,res_type,res_id) = ident
36-
cr.execute('delete from wkf_instance where res_id=%s and res_type=%s', (res_id,res_type))
37-
38-
def validate(cr, inst_id, ident, signal, force_running=False):
39-
cr.execute("select * from wkf_workitem where inst_id=%s", (inst_id,))
40-
stack = []
41-
for witem in cr.dictfetchall():
26+
class WorkflowInstance(object):
27+
def __init__(self, session, record, values):
28+
assert isinstance(session, Session)
29+
assert isinstance(record, Record)
30+
self.session = session
31+
self.record = record
32+
33+
if not values:
34+
values = {}
35+
36+
assert isinstance(values, dict)
37+
self.instance = values
38+
39+
@classmethod
40+
def create(cls, session, record, workflow_id):
41+
assert isinstance(session, Session)
42+
assert isinstance(record, Record)
43+
assert isinstance(workflow_id, (int, long))
44+
45+
cr = session.cr
46+
cr.execute('insert into wkf_instance (res_type,res_id,uid,wkf_id) values (%s,%s,%s,%s) RETURNING id', (record.model, record.id, session.uid, workflow_id))
47+
instance_id = cr.fetchone()[0]
48+
49+
cr.execute('select * from wkf_activity where flow_start=True and wkf_id=%s', (workflow_id,))
4250
stack = []
43-
workitem.process(cr, witem, ident, signal, force_running, stack=stack)
44-
# An action is returned
45-
_update_end(cr, inst_id, ident)
46-
return stack and stack[0] or False
47-
48-
def update(cr, inst_id, ident):
49-
cr.execute("select * from wkf_workitem where inst_id=%s", (inst_id,))
50-
for witem in cr.dictfetchall():
51+
52+
activities = cr.dictfetchall()
53+
for activity in activities:
54+
WorkflowItem.create(session, record, activity, instance_id, stack)
55+
56+
cr.execute('SELECT * FROM wkf_instance WHERE id = %s', (instance_id,))
57+
values = cr.dictfetchone()
58+
wi = WorkflowInstance(session, record, values)
59+
wi.update()
60+
61+
return wi
62+
63+
def delete(self):
64+
self.session.cr.execute('delete from wkf_instance where res_id=%s and res_type=%s', (self.record.id, self.record.model))
65+
66+
def validate(self, signal, force_running=False):
67+
assert isinstance(signal, basestring)
68+
assert isinstance(force_running, bool)
69+
70+
cr = self.session.cr
71+
cr.execute("select * from wkf_workitem where inst_id=%s", (self.instance['id'],))
5172
stack = []
52-
workitem.process(cr, witem, ident, stack=stack)
53-
return _update_end(cr, inst_id, ident)
54-
55-
def _update_end(cr, inst_id, ident):
56-
cr.execute('select wkf_id from wkf_instance where id=%s', (inst_id,))
57-
wkf_id = cr.fetchone()[0]
58-
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=%s', (inst_id,))
59-
ok=True
60-
for r in cr.fetchall():
61-
if (r[0]<>'complete') or not r[1]:
62-
ok=False
63-
break
64-
if ok:
65-
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=%s', (inst_id,))
66-
act_names = cr.fetchall()
67-
cr.execute("update wkf_instance set state='complete' where id=%s", (inst_id,))
68-
cr.execute("update wkf_workitem set state='complete' where subflow_id=%s", (inst_id,))
69-
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)", (inst_id,))
70-
for i in cr.fetchall():
71-
for act_name in act_names:
72-
validate(cr, i[0], (ident[0],i[1],i[2]), 'subflow.'+act_name[0])
73-
return ok
73+
for work_item_values in cr.dictfetchall():
74+
wi = WorkflowItem(self.session, self.record, work_item_values)
75+
wi.process(signal=signal, force_running=force_running, stack=stack)
76+
# An action is returned
77+
self._update_end()
78+
return stack and stack[0] or False
79+
80+
def update(self):
81+
cr = self.session.cr
82+
83+
cr.execute("select * from wkf_workitem where inst_id=%s", (self.instance['id'],))
84+
for work_item_values in cr.dictfetchall():
85+
stack = []
86+
WorkflowItem(self.session, self.record, work_item_values).process(stack=stack)
87+
return self._update_end()
88+
89+
def _update_end(self):
90+
cr = self.session.cr
91+
instance_id = self.instance['id']
92+
cr.execute('select wkf_id from wkf_instance where id=%s', (instance_id,))
93+
wkf_id = cr.fetchone()[0]
94+
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=%s', (instance_id,))
95+
ok=True
96+
for r in cr.fetchall():
97+
if (r[0]<>'complete') or not r[1]:
98+
ok=False
99+
break
100+
if ok:
101+
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=%s', (instance_id,))
102+
act_names = cr.fetchall()
103+
cr.execute("update wkf_instance set state='complete' where id=%s", (instance_id,))
104+
cr.execute("update wkf_workitem set state='complete' where subflow_id=%s", (instance_id,))
105+
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)", (instance_id,))
106+
for cur_instance_id, cur_model_name, cur_record_id in cr.fetchall():
107+
cur_record = Record(cur_model_name, cur_record_id)
108+
for act_name in act_names:
109+
WorkflowInstance(self.session, cur_record, {'id':cur_instance_id}).validate('subflow.{}'.format(act_name[0]))
110+
111+
return ok
112+
113+
114+
115+
116+
117+
def create(session, record, workflow_id):
118+
return WorkflowInstance(session, record).create(workflow_id)
119+
120+
def delete(session, record):
121+
return WorkflowInstance(session, record).delete()
122+
123+
def validate(session, record, instance_id, signal, force_running=False):
124+
return WorkflowInstance(session, record).validate(instance_id, signal, force_running)
125+
126+
def update(session, record, instance_id):
127+
return WorkflowInstance(session, record).update(instance_id)
128+
129+
def _update_end(session, record, instance_id):
130+
return WorkflowInstance(session, record)._update_end(instance_id)
74131

75132

76133
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

0 commit comments

Comments
 (0)