[REF] First step, use the same vocabulary for the cr, uid, res_type and res_id
=> Session, Record. * a Session is a container of one cursor and one user * a Record is a container for the res_type and res_id, in this object, the right names are model and id. Examples: session = Session(cr, uid) record = Record(res_type, res_id) record.mode, record.id A new class named 'WorkflowService' is a wrapper for the instance.* functions. bzr revid: stw@openerp.com-20131023125343-uo0bq52n86ae0fb0
This commit is contained in:
parent
5696282656
commit
c7afc04be3
|
@ -1,6 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# OpenERP, Open Source Management Solution
|
# OpenERP, Open Source Management Solution
|
||||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||||
#
|
#
|
||||||
|
@ -15,16 +15,17 @@
|
||||||
# GNU Affero General Public License for more details.
|
# GNU Affero General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
import instance
|
from openerp.workflow.service import WorkflowService
|
||||||
|
|
||||||
wkf_on_create_cache = {}
|
# The new API is in openerp.workflow.workflow_service
|
||||||
|
# OLD API of the Workflow
|
||||||
|
|
||||||
def clear_cache(cr, uid):
|
def clear_cache(cr, uid):
|
||||||
wkf_on_create_cache[cr.dbname]={}
|
WorkflowService.clear_cache(cr.dbname)
|
||||||
|
|
||||||
def trg_write(uid, res_type, res_id, cr):
|
def trg_write(uid, res_type, res_id, cr):
|
||||||
"""
|
"""
|
||||||
|
@ -36,10 +37,7 @@ def trg_write(uid, res_type, res_id, cr):
|
||||||
:param res_id: the model instance id the workflow belongs to
|
:param res_id: the model instance id the workflow belongs to
|
||||||
:param cr: a database cursor
|
:param cr: a database cursor
|
||||||
"""
|
"""
|
||||||
ident = (uid,res_type,res_id)
|
return WorkflowService.new(cr, uid, res_type, res_id).write()
|
||||||
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'))
|
|
||||||
for (id,) in cr.fetchall():
|
|
||||||
instance.update(cr, id, ident)
|
|
||||||
|
|
||||||
def trg_trigger(uid, res_type, res_id, cr):
|
def trg_trigger(uid, res_type, res_id, cr):
|
||||||
"""
|
"""
|
||||||
|
@ -52,12 +50,7 @@ def trg_trigger(uid, res_type, res_id, cr):
|
||||||
:param res_id: the model instance id the workflow belongs to
|
:param res_id: the model instance id the workflow belongs to
|
||||||
:param cr: a database cursor
|
:param cr: a database cursor
|
||||||
"""
|
"""
|
||||||
cr.execute('select instance_id from wkf_triggers where res_id=%s and model=%s', (res_id,res_type))
|
return WorkflowService.new(cr, uid, res_type, res_id).trigger()
|
||||||
res = cr.fetchall()
|
|
||||||
for (instance_id,) in res:
|
|
||||||
cr.execute('select %s,res_type,res_id from wkf_instance where id=%s', (uid, instance_id,))
|
|
||||||
ident = cr.fetchone()
|
|
||||||
instance.update(cr, instance_id, ident)
|
|
||||||
|
|
||||||
def trg_delete(uid, res_type, res_id, cr):
|
def trg_delete(uid, res_type, res_id, cr):
|
||||||
"""
|
"""
|
||||||
|
@ -67,8 +60,7 @@ def trg_delete(uid, res_type, res_id, cr):
|
||||||
:param res_id: the model instance id the workflow belongs to
|
:param res_id: the model instance id the workflow belongs to
|
||||||
:param cr: a database cursor
|
:param cr: a database cursor
|
||||||
"""
|
"""
|
||||||
ident = (uid,res_type,res_id)
|
return WorkflowService.new(cr, uid, res_type, res_id).delete()
|
||||||
instance.delete(cr, ident)
|
|
||||||
|
|
||||||
def trg_create(uid, res_type, res_id, cr):
|
def trg_create(uid, res_type, res_id, cr):
|
||||||
"""
|
"""
|
||||||
|
@ -78,16 +70,7 @@ def trg_create(uid, res_type, res_id, cr):
|
||||||
:param res_id: the model instance id to own the created worfklow instance
|
:param res_id: the model instance id to own the created worfklow instance
|
||||||
:param cr: a database cursor
|
:param cr: a database cursor
|
||||||
"""
|
"""
|
||||||
ident = (uid,res_type,res_id)
|
return WorkflowService.new(cr, uid, res_type, res_id).create()
|
||||||
wkf_on_create_cache.setdefault(cr.dbname, {})
|
|
||||||
if res_type in wkf_on_create_cache[cr.dbname]:
|
|
||||||
wkf_ids = wkf_on_create_cache[cr.dbname][res_type]
|
|
||||||
else:
|
|
||||||
cr.execute('select id from wkf where osv=%s and on_create=True', (res_type,))
|
|
||||||
wkf_ids = cr.fetchall()
|
|
||||||
wkf_on_create_cache[cr.dbname][res_type] = wkf_ids
|
|
||||||
for (wkf_id,) in wkf_ids:
|
|
||||||
instance.create(cr, ident, wkf_id)
|
|
||||||
|
|
||||||
def trg_validate(uid, res_type, res_id, signal, cr):
|
def trg_validate(uid, res_type, res_id, signal, cr):
|
||||||
"""
|
"""
|
||||||
|
@ -98,14 +81,8 @@ def trg_validate(uid, res_type, res_id, signal, cr):
|
||||||
:signal: the signal name to be fired
|
:signal: the signal name to be fired
|
||||||
:param cr: a database cursor
|
:param cr: a database cursor
|
||||||
"""
|
"""
|
||||||
result = False
|
assert isinstance(signal, basestring)
|
||||||
ident = (uid,res_type,res_id)
|
return WorkflowService.new(cr, uid, res_type, res_id).validate(signal)
|
||||||
# ids of all active workflow instances for a corresponding resource (id, model_nam)
|
|
||||||
cr.execute('select id from wkf_instance where res_id=%s and res_type=%s and state=%s', (res_id, res_type, 'active'))
|
|
||||||
for (id,) in cr.fetchall():
|
|
||||||
res2 = instance.validate(cr, id, ident, signal)
|
|
||||||
result = result or res2
|
|
||||||
return result
|
|
||||||
|
|
||||||
def trg_redirect(uid, res_type, res_id, new_rid, cr):
|
def trg_redirect(uid, res_type, res_id, new_rid, cr):
|
||||||
"""
|
"""
|
||||||
|
@ -120,22 +97,7 @@ def trg_redirect(uid, res_type, res_id, new_rid, cr):
|
||||||
:param new_rid: the model instance id to own the worfklow instance
|
:param new_rid: the model instance id to own the worfklow instance
|
||||||
:param cr: a database cursor
|
:param cr: a database cursor
|
||||||
"""
|
"""
|
||||||
# get ids of wkf instances for the old resource (res_id)
|
assert isinstance(new_rid, (long, int))
|
||||||
#CHECKME: shouldn't we get only active instances?
|
return WorkflowService.new(cr, uid, res_type, res_id).redirect(new_rid)
|
||||||
cr.execute('select id, wkf_id from wkf_instance where res_id=%s and res_type=%s', (res_id, res_type))
|
|
||||||
for old_inst_id, wkf_id in cr.fetchall():
|
|
||||||
# first active instance for new resource (new_rid), using same wkf
|
|
||||||
cr.execute(
|
|
||||||
'SELECT id '\
|
|
||||||
'FROM wkf_instance '\
|
|
||||||
'WHERE res_id=%s AND res_type=%s AND wkf_id=%s AND state=%s',
|
|
||||||
(new_rid, res_type, wkf_id, 'active'))
|
|
||||||
new_id = cr.fetchone()
|
|
||||||
if new_id:
|
|
||||||
# select all workitems which "wait" for the old instance
|
|
||||||
cr.execute('select id from wkf_workitem where subflow_id=%s', (old_inst_id,))
|
|
||||||
for (item_id,) in cr.fetchall():
|
|
||||||
# redirect all those workitems to the wkf instance of the new resource
|
|
||||||
cr.execute('update wkf_workitem set subflow_id=%s where id=%s', (new_id[0], item_id))
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import openerp.sql_db
|
||||||
|
|
||||||
|
class Session(object):
|
||||||
|
def __init__(self, cr, uid):
|
||||||
|
assert isinstance(cr, openerp.sql_db.Cursor)
|
||||||
|
assert isinstance(uid, (int, long))
|
||||||
|
self.cr = cr
|
||||||
|
self.uid = uid
|
||||||
|
|
||||||
|
class Record(object):
|
||||||
|
def __init__(self, model, record_id):
|
||||||
|
assert isinstance(model, basestring)
|
||||||
|
assert isinstance(record_id, (int, long))
|
||||||
|
self.model = model
|
||||||
|
self.id = record_id
|
|
@ -19,57 +19,84 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
import workitem
|
import workitem
|
||||||
|
from helpers import Session
|
||||||
|
from helpers import Record
|
||||||
|
|
||||||
def create(cr, ident, wkf_id):
|
def create(session, record, workflow_id):
|
||||||
(uid,res_type,res_id) = ident
|
assert isinstance(session, Session)
|
||||||
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))
|
assert isinstance(record, Record)
|
||||||
id_new = cr.fetchone()[0]
|
assert isinstance(workflow_id, (int, long))
|
||||||
cr.execute('select * from wkf_activity where flow_start=True and wkf_id=%s', (wkf_id,))
|
|
||||||
res = cr.dictfetchall()
|
cr = session.cr
|
||||||
|
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))
|
||||||
|
instance_id = cr.fetchone()[0]
|
||||||
|
cr.execute('select * from wkf_activity where flow_start=True and wkf_id=%s', (workflow_id,))
|
||||||
|
activities = cr.dictfetchall()
|
||||||
stack = []
|
stack = []
|
||||||
workitem.create(cr, res, id_new, ident, stack=stack)
|
workitem.create(session, record, activities, instance_id, stack=stack)
|
||||||
update(cr, id_new, ident)
|
update(session, record, instance_id)
|
||||||
return id_new
|
return instance_id
|
||||||
|
|
||||||
def delete(cr, ident):
|
def delete(session, record):
|
||||||
(uid,res_type,res_id) = ident
|
assert isinstance(session, Session)
|
||||||
cr.execute('delete from wkf_instance where res_id=%s and res_type=%s', (res_id,res_type))
|
assert isinstance(record, Record)
|
||||||
|
|
||||||
def validate(cr, inst_id, ident, signal, force_running=False):
|
session.cr.execute('delete from wkf_instance where res_id=%s and res_type=%s', (record.id, record.model))
|
||||||
cr.execute("select * from wkf_workitem where inst_id=%s", (inst_id,))
|
|
||||||
|
def validate(session, record, instance_id, signal, force_running=False):
|
||||||
|
assert isinstance(session, Session)
|
||||||
|
assert isinstance(record, Record)
|
||||||
|
assert isinstance(instance_id, (long, int))
|
||||||
|
assert isinstance(signal, basestring)
|
||||||
|
assert isinstance(force_running, bool)
|
||||||
|
|
||||||
|
cr = session.cr
|
||||||
|
cr.execute("select * from wkf_workitem where inst_id=%s", (instance_id,))
|
||||||
stack = []
|
stack = []
|
||||||
for witem in cr.dictfetchall():
|
for work_item in cr.dictfetchall():
|
||||||
stack = []
|
stack = []
|
||||||
workitem.process(cr, witem, ident, signal, force_running, stack=stack)
|
workitem.process(session, record, work_item, signal, force_running, stack=stack)
|
||||||
# An action is returned
|
# An action is returned
|
||||||
_update_end(cr, inst_id, ident)
|
_update_end(session, record, instance_id)
|
||||||
return stack and stack[0] or False
|
return stack and stack[0] or False
|
||||||
|
|
||||||
def update(cr, inst_id, ident):
|
def update(session, record, instance_id):
|
||||||
cr.execute("select * from wkf_workitem where inst_id=%s", (inst_id,))
|
assert isinstance(session, Session)
|
||||||
|
assert isinstance(record, Record)
|
||||||
|
assert isinstance(instance_id, (long, int))
|
||||||
|
|
||||||
|
cr = session.cr
|
||||||
|
cr.execute("select * from wkf_workitem where inst_id=%s", (instance_id,))
|
||||||
for witem in cr.dictfetchall():
|
for witem in cr.dictfetchall():
|
||||||
stack = []
|
stack = []
|
||||||
workitem.process(cr, witem, ident, stack=stack)
|
workitem.process(session, record, witem, stack=stack)
|
||||||
return _update_end(cr, inst_id, ident)
|
return _update_end(session, record, instance_id)
|
||||||
|
|
||||||
def _update_end(cr, inst_id, ident):
|
def _update_end(session, record, instance_id):
|
||||||
cr.execute('select wkf_id from wkf_instance where id=%s', (inst_id,))
|
assert isinstance(session, Session)
|
||||||
|
assert isinstance(record, Record)
|
||||||
|
assert isinstance(instance_id, (long, int))
|
||||||
|
|
||||||
|
cr = session.cr
|
||||||
|
cr.execute('select wkf_id from wkf_instance where id=%s', (instance_id,))
|
||||||
wkf_id = cr.fetchone()[0]
|
wkf_id = cr.fetchone()[0]
|
||||||
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,))
|
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,))
|
||||||
ok=True
|
ok=True
|
||||||
for r in cr.fetchall():
|
for r in cr.fetchall():
|
||||||
if (r[0]<>'complete') or not r[1]:
|
if (r[0]<>'complete') or not r[1]:
|
||||||
ok=False
|
ok=False
|
||||||
break
|
break
|
||||||
if ok:
|
if ok:
|
||||||
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,))
|
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,))
|
||||||
act_names = cr.fetchall()
|
act_names = cr.fetchall()
|
||||||
cr.execute("update wkf_instance set state='complete' where id=%s", (inst_id,))
|
cr.execute("update wkf_instance set state='complete' where id=%s", (instance_id,))
|
||||||
cr.execute("update wkf_workitem set state='complete' where subflow_id=%s", (inst_id,))
|
cr.execute("update wkf_workitem set state='complete' where subflow_id=%s", (instance_id,))
|
||||||
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,))
|
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,))
|
||||||
for i in cr.fetchall():
|
for cur_instance_id, cur_model_name, cur_record_id in cr.fetchall():
|
||||||
|
cur_record = Record(cur_model_name, cur_record_id)
|
||||||
for act_name in act_names:
|
for act_name in act_names:
|
||||||
validate(cr, i[0], (ident[0],i[1],i[2]), 'subflow.'+act_name[0])
|
validate(session, cur_record, cur_instance_id, 'subflow.%s' % act_name[0])
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# OpenERP, Open Source Management Solution
|
||||||
|
# Copyright (C) 2004-TODAY OpenERP S.A. (<http://openerp.com>).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
from helpers import Session
|
||||||
|
from helpers import Record
|
||||||
|
|
||||||
|
import instance
|
||||||
|
|
||||||
|
|
||||||
|
class WorkflowService(object):
|
||||||
|
CACHE = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def clear_cache(cls, dbname):
|
||||||
|
cls.CACHE[dbname] = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def new(cls, cr, uid, model_name, record_id):
|
||||||
|
return cls(Session(cr, uid), Record(model_name, record_id))
|
||||||
|
|
||||||
|
def __init__(self, session, record):
|
||||||
|
assert isinstance(session, Session)
|
||||||
|
assert isinstance(record, Record)
|
||||||
|
|
||||||
|
self.session = session
|
||||||
|
self.record = record
|
||||||
|
|
||||||
|
self.cr = self.session.cr
|
||||||
|
|
||||||
|
def write(self):
|
||||||
|
self.cr.execute('select id from wkf_instance where res_id=%s and res_type=%s and state=%s',
|
||||||
|
(self.record.id or None, self.record.model or None, 'active')
|
||||||
|
)
|
||||||
|
for (instance_id,) in self.cr.fetchall():
|
||||||
|
instance.update(self.session, self.record, instance_id)
|
||||||
|
|
||||||
|
def trigger(self):
|
||||||
|
self.cr.execute('select instance_id from wkf_triggers where res_id=%s and model=%s', (self.record.id, self.record.model))
|
||||||
|
res = self.cr.fetchall()
|
||||||
|
for (instance_id,) in res:
|
||||||
|
self.cr.execute('select %s,res_type,res_id from wkf_instance where id=%s', (self.session.uid, instance_id,))
|
||||||
|
current_uid, current_model_name, current_record_id = self.cr.fetchone()
|
||||||
|
|
||||||
|
current_session = Session(self.session.cr, current_uid)
|
||||||
|
current_record = Record(current_model_name, current_record_id)
|
||||||
|
|
||||||
|
instance.update(current_session, current_record, instance_id)
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
instance.delete(self.session, self.record)
|
||||||
|
|
||||||
|
def create(self):
|
||||||
|
WorkflowService.CACHE.setdefault(self.cr.dbname, {})
|
||||||
|
|
||||||
|
wkf_ids = WorkflowService.CACHE[self.cr.dbname].get(self.record.model, None)
|
||||||
|
|
||||||
|
if not wkf_ids:
|
||||||
|
self.cr.execute('select id from wkf where osv=%s and on_create=True', (self.record.model,))
|
||||||
|
wkf_ids = self.cr.fetchall()
|
||||||
|
WorkflowService.CACHE[self.cr.dbname][self.record.model] = wkf_ids
|
||||||
|
|
||||||
|
for (wkf_id, ) in wkf_ids:
|
||||||
|
instance.create(self.session, self.record, wkf_id)
|
||||||
|
|
||||||
|
def validate(self, signal):
|
||||||
|
result = False
|
||||||
|
# ids of all active workflow instances for a corresponding resource (id, model_nam)
|
||||||
|
self.cr.execute('select id from wkf_instance where res_id=%s and res_type=%s and state=%s', (self.record.id, self.record.model, 'active'))
|
||||||
|
for (instance_id,) in self.cr.fetchall():
|
||||||
|
res2 = instance.validate(self.session, self.record, instance_id, signal)
|
||||||
|
result = result or res2
|
||||||
|
return result
|
||||||
|
|
||||||
|
def redirect(self, new_rid):
|
||||||
|
# get ids of wkf instances for the old resource (res_id)
|
||||||
|
# CHECKME: shouldn't we get only active instances?
|
||||||
|
self.cr.execute('select id, wkf_id from wkf_instance where res_id=%s and res_type=%s', (self.record.id, self.record.model))
|
||||||
|
|
||||||
|
for old_inst_id, workflow_id in self.cr.fetchall():
|
||||||
|
# first active instance for new resource (new_rid), using same wkf
|
||||||
|
self.cr.execute(
|
||||||
|
'SELECT id '\
|
||||||
|
'FROM wkf_instance '\
|
||||||
|
'WHERE res_id=%s AND res_type=%s AND wkf_id=%s AND state=%s',
|
||||||
|
(new_rid, self.record.model, workflow_id, 'active'))
|
||||||
|
new_id = self.cr.fetchone()
|
||||||
|
if new_id:
|
||||||
|
# select all workitems which "wait" for the old instance
|
||||||
|
self.cr.execute('select id from wkf_workitem where subflow_id=%s', (old_inst_id,))
|
||||||
|
for (item_id,) in self.cr.fetchall():
|
||||||
|
# redirect all those workitems to the wkf instance of the new resource
|
||||||
|
self.cr.execute('update wkf_workitem set subflow_id=%s where id=%s', (new_id[0], item_id))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# OpenERP, Open Source Management Solution
|
# OpenERP, Open Source Management Solution
|
||||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||||
#
|
#
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
# GNU Affero General Public License for more details.
|
# GNU Affero General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
@ -51,13 +51,12 @@ class Env(dict):
|
||||||
else:
|
else:
|
||||||
return super(Env, self).__getitem__(key)
|
return super(Env, self).__getitem__(key)
|
||||||
|
|
||||||
def _eval_expr(cr, ident, workitem, lines):
|
def _eval_expr(session, record, workitem, lines):
|
||||||
"""
|
"""
|
||||||
Evaluate each line of ``lines`` with the ``Env`` environment, returning
|
Evaluate each line of ``lines`` with the ``Env`` environment, returning
|
||||||
the value of the last line.
|
the value of the last line.
|
||||||
"""
|
"""
|
||||||
assert lines, 'You used a NULL action in a workflow, use dummy node instead.'
|
assert lines, 'You used a NULL action in a workflow, use dummy node instead.'
|
||||||
uid, model, id = ident
|
|
||||||
result = False
|
result = False
|
||||||
for line in lines.split('\n'):
|
for line in lines.split('\n'):
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
|
@ -68,30 +67,29 @@ def _eval_expr(cr, ident, workitem, lines):
|
||||||
elif line == 'False':
|
elif line == 'False':
|
||||||
result = False
|
result = False
|
||||||
else:
|
else:
|
||||||
env = Env(cr, uid, model, id)
|
env = Env(session.cr, session.uid, record.model, record.id)
|
||||||
result = eval(line, env, nocopy=True)
|
result = eval(line, env, nocopy=True)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def execute_action(cr, ident, workitem, activity):
|
def execute_action(session, record, workitem, activity):
|
||||||
"""
|
"""
|
||||||
Evaluate the ir.actions.server action specified in the activity.
|
Evaluate the ir.actions.server action specified in the activity.
|
||||||
"""
|
"""
|
||||||
uid, model, id = ident
|
ir_actions_server = openerp.registry(session.cr.dbname)['ir.actions.server']
|
||||||
ir_actions_server = openerp.registry(cr.dbname)['ir.actions.server']
|
context = { 'active_model': record.model, 'active_id': record.id, 'active_ids': [record.id] }
|
||||||
context = { 'active_model': model, 'active_id': id, 'active_ids': [id] }
|
result = ir_actions_server.run(session.cr, session.uid, [activity['action_id']], context)
|
||||||
result = ir_actions_server.run(cr, uid, [activity['action_id']], context)
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def execute(cr, ident, workitem, activity):
|
def execute(session, record, workitem, activity):
|
||||||
"""
|
"""
|
||||||
Evaluate the action specified in the activity.
|
Evaluate the action specified in the activity.
|
||||||
"""
|
"""
|
||||||
return _eval_expr(cr, ident, workitem, activity['action'])
|
return _eval_expr(session, record, workitem, activity['action'])
|
||||||
|
|
||||||
def check(cr, workitem, ident, transition, signal):
|
def check(session, record, workitem, transition, signal):
|
||||||
"""
|
"""
|
||||||
Test if a transition can be taken. The transition can be taken if:
|
Test if a transition can be taken. The transition can be taken if:
|
||||||
|
|
||||||
- the signal name matches,
|
- the signal name matches,
|
||||||
- the uid is SUPERUSER_ID or the user groups contains the transition's
|
- the uid is SUPERUSER_ID or the user groups contains the transition's
|
||||||
group,
|
group,
|
||||||
|
@ -100,14 +98,13 @@ def check(cr, workitem, ident, transition, signal):
|
||||||
if transition['signal'] and signal != transition['signal']:
|
if transition['signal'] and signal != transition['signal']:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
uid = ident[0]
|
if session.uid != openerp.SUPERUSER_ID and transition['group_id']:
|
||||||
if uid != openerp.SUPERUSER_ID and transition['group_id']:
|
registry = openerp.registry(session.cr.dbname)
|
||||||
registry = openerp.registry(cr.dbname)
|
user_groups = registry['res.users'].read(session.cr, session.uid, [session.uid], ['groups_id'])[0]['groups_id']
|
||||||
user_groups = registry['res.users'].read(cr, uid, [uid], ['groups_id'])[0]['groups_id']
|
|
||||||
if transition['group_id'] not in user_groups:
|
if transition['group_id'] not in user_groups:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return _eval_expr(cr, ident, workitem, transition['condition'])
|
return _eval_expr(session, record, workitem, transition['condition'])
|
||||||
|
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# OpenERP, Open Source Management Solution
|
# OpenERP, Open Source Management Solution
|
||||||
|
@ -28,41 +28,59 @@ import logging
|
||||||
import instance
|
import instance
|
||||||
|
|
||||||
import wkf_expr
|
import wkf_expr
|
||||||
|
from helpers import Session
|
||||||
|
from helpers import Record
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def create(cr, act_datas, inst_id, ident, stack):
|
def create(session, record, activities, instance_id, stack):
|
||||||
for act in act_datas:
|
assert isinstance(session, Session)
|
||||||
|
assert isinstance(record, Record)
|
||||||
|
assert isinstance(activities, list)
|
||||||
|
assert isinstance(instance_id, (long, int))
|
||||||
|
assert isinstance(stack, list)
|
||||||
|
cr = session.cr
|
||||||
|
|
||||||
|
ident = session.uid, record.model, record.id
|
||||||
|
for activity in activities:
|
||||||
cr.execute("select nextval('wkf_workitem_id_seq')")
|
cr.execute("select nextval('wkf_workitem_id_seq')")
|
||||||
id_new = cr.fetchone()[0]
|
id_new = cr.fetchone()[0]
|
||||||
cr.execute("insert into wkf_workitem (id,act_id,inst_id,state) values (%s,%s,%s,'active')", (id_new, act['id'], inst_id))
|
cr.execute("insert into wkf_workitem (id,act_id,inst_id,state) values (%s,%s,%s,'active')", (id_new, activity['id'], instance_id))
|
||||||
cr.execute('select * from wkf_workitem where id=%s',(id_new,))
|
cr.execute('select * from wkf_workitem where id=%s',(id_new,))
|
||||||
res = cr.dictfetchone()
|
work_item = cr.dictfetchone()
|
||||||
logger.info('Created workflow item in activity %s',
|
logger.info('Created workflow item in activity %s',
|
||||||
act['id'], extra={'ident': ident})
|
activity['id'],
|
||||||
process(cr, res, ident, stack=stack)
|
extra={'ident': (session.uid, record.model, record.id)})
|
||||||
|
|
||||||
|
process(session, record, work_item, stack=stack)
|
||||||
|
|
||||||
|
def process(session, record, workitem, signal=None, force_running=False, stack=None):
|
||||||
|
assert isinstance(session, Session)
|
||||||
|
assert isinstance(record, Record)
|
||||||
|
assert isinstance(force_running, bool)
|
||||||
|
|
||||||
def process(cr, workitem, ident, signal=None, force_running=False, stack=None):
|
|
||||||
assert stack is not None
|
assert stack is not None
|
||||||
|
|
||||||
|
cr = session.cr
|
||||||
|
|
||||||
cr.execute('select * from wkf_activity where id=%s', (workitem['act_id'],))
|
cr.execute('select * from wkf_activity where id=%s', (workitem['act_id'],))
|
||||||
activity = cr.dictfetchone()
|
activity = cr.dictfetchone()
|
||||||
|
|
||||||
triggers = False
|
triggers = False
|
||||||
if workitem['state'] == 'active':
|
if workitem['state'] == 'active':
|
||||||
triggers = True
|
triggers = True
|
||||||
if not _execute(cr, workitem, activity, ident, stack):
|
if not _execute(session, record, workitem, activity, stack):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if force_running or workitem['state'] == 'complete':
|
if force_running or workitem['state'] == 'complete':
|
||||||
ok = _split_test(cr, workitem, activity['split_mode'], ident, signal, stack)
|
ok = _split_test(session, record, workitem, activity['split_mode'], signal, stack)
|
||||||
triggers = triggers and not ok
|
triggers = triggers and not ok
|
||||||
|
|
||||||
if triggers:
|
if triggers:
|
||||||
cr.execute('select * from wkf_transition where act_from=%s', (workitem['act_id'],))
|
cr.execute('select * from wkf_transition where act_from=%s', (workitem['act_id'],))
|
||||||
for trans in cr.dictfetchall():
|
for trans in cr.dictfetchall():
|
||||||
if trans['trigger_model']:
|
if trans['trigger_model']:
|
||||||
ids = wkf_expr._eval_expr(cr,ident,workitem,trans['trigger_expr_id'])
|
ids = wkf_expr._eval_expr(session, record, workitem, trans['trigger_expr_id'])
|
||||||
for res_id in ids:
|
for res_id in ids:
|
||||||
cr.execute('select nextval(\'wkf_triggers_id_seq\')')
|
cr.execute('select nextval(\'wkf_triggers_id_seq\')')
|
||||||
id =cr.fetchone()[0]
|
id =cr.fetchone()[0]
|
||||||
|
@ -73,26 +91,32 @@ def process(cr, workitem, ident, signal=None, force_running=False, stack=None):
|
||||||
|
|
||||||
# ---------------------- PRIVATE FUNCS --------------------------------
|
# ---------------------- PRIVATE FUNCS --------------------------------
|
||||||
|
|
||||||
def _state_set(cr, workitem, activity, state, ident):
|
# def new_state_set(session, record, workitem, activity, state):
|
||||||
cr.execute('update wkf_workitem set state=%s where id=%s', (state,workitem['id']))
|
|
||||||
workitem['state'] = state
|
|
||||||
logger.info("Changed state of work item %s to \"%s\" in activity %s",
|
|
||||||
workitem['id'], state, activity['id'], extra={'ident': ident})
|
|
||||||
|
|
||||||
def _execute(cr, workitem, activity, ident, stack):
|
def _state_set(session, record, workitem, activity, state):
|
||||||
|
session.cr.execute('update wkf_workitem set state=%s where id=%s', (state, workitem['id']))
|
||||||
|
workitem['state'] = state
|
||||||
|
logger.info('Changed state of work item %s to "%s" in activity %s',
|
||||||
|
workitem['id'], state, activity['id'],
|
||||||
|
extra={'ident': (session.uid, record.model, record.id)})
|
||||||
|
|
||||||
|
def _execute(session, record, workitem, activity, stack):
|
||||||
result = True
|
result = True
|
||||||
#
|
#
|
||||||
# send a signal to parent workflow (signal: subflow.signal_name)
|
# send a signal to parent workflow (signal: subflow.signal_name)
|
||||||
#
|
#
|
||||||
|
cr = session.cr
|
||||||
|
ident = (session.uid, record.model, record.id)
|
||||||
signal_todo = []
|
signal_todo = []
|
||||||
if (workitem['state']=='active') and activity['signal_send']:
|
if (workitem['state']=='active') and activity['signal_send']:
|
||||||
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'],))
|
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'],))
|
||||||
for i in cr.fetchall():
|
for instance_id, model_name, record_id in cr.fetchall():
|
||||||
signal_todo.append((i[0], (ident[0],i[1],i[2]), activity['signal_send']))
|
record = Record(model_name, record_id)
|
||||||
|
signal_todo.append((instance_id, record, activity['signal_send']))
|
||||||
|
|
||||||
if activity['kind']=='dummy':
|
if activity['kind']=='dummy':
|
||||||
if workitem['state']=='active':
|
if workitem['state']=='active':
|
||||||
_state_set(cr, workitem, activity, 'complete', ident)
|
_state_set(session, record, workitem, activity, 'complete')
|
||||||
if activity['action_id']:
|
if activity['action_id']:
|
||||||
res2 = wkf_expr.execute_action(cr, ident, workitem, activity)
|
res2 = wkf_expr.execute_action(cr, ident, workitem, activity)
|
||||||
if res2:
|
if res2:
|
||||||
|
@ -100,29 +124,29 @@ def _execute(cr, workitem, activity, ident, stack):
|
||||||
result=res2
|
result=res2
|
||||||
elif activity['kind']=='function':
|
elif activity['kind']=='function':
|
||||||
if workitem['state']=='active':
|
if workitem['state']=='active':
|
||||||
_state_set(cr, workitem, activity, 'running', ident)
|
_state_set(session, record, workitem, activity, 'running')
|
||||||
returned_action = wkf_expr.execute(cr, ident, workitem, activity)
|
returned_action = wkf_expr.execute(session, record, workitem, activity)
|
||||||
if type(returned_action) in (dict,):
|
if type(returned_action) in (dict,):
|
||||||
stack.append(returned_action)
|
stack.append(returned_action)
|
||||||
if activity['action_id']:
|
if activity['action_id']:
|
||||||
res2 = wkf_expr.execute_action(cr, ident, workitem, activity)
|
res2 = wkf_expr.execute_action(session, record, workitem, activity)
|
||||||
# A client action has been returned
|
# A client action has been returned
|
||||||
if res2:
|
if res2:
|
||||||
stack.append(res2)
|
stack.append(res2)
|
||||||
result=res2
|
result=res2
|
||||||
_state_set(cr, workitem, activity, 'complete', ident)
|
_state_set(session, record, workitem, activity, 'complete')
|
||||||
elif activity['kind']=='stopall':
|
elif activity['kind']=='stopall':
|
||||||
if workitem['state']=='active':
|
if workitem['state']=='active':
|
||||||
_state_set(cr, workitem, activity, 'running', ident)
|
_state_set(session, record, workitem, activity, 'running')
|
||||||
cr.execute('delete from wkf_workitem where inst_id=%s and id<>%s', (workitem['inst_id'], workitem['id']))
|
cr.execute('delete from wkf_workitem where inst_id=%s and id<>%s', (workitem['inst_id'], workitem['id']))
|
||||||
if activity['action']:
|
if activity['action']:
|
||||||
wkf_expr.execute(cr, ident, workitem, activity)
|
wkf_expr.execute(session, record, workitem, activity)
|
||||||
_state_set(cr, workitem, activity, 'complete', ident)
|
_state_set(session, record, workitem, activity, 'complete')
|
||||||
elif activity['kind']=='subflow':
|
elif activity['kind']=='subflow':
|
||||||
if workitem['state']=='active':
|
if workitem['state']=='active':
|
||||||
_state_set(cr, workitem, activity, 'running', ident)
|
_state_set(session, record, workitem, activity, 'running')
|
||||||
if activity.get('action', False):
|
if activity.get('action', False):
|
||||||
id_new = wkf_expr.execute(cr, ident, workitem, activity)
|
id_new = wkf_expr.execute(session, record, workitem, activity)
|
||||||
if not id_new:
|
if not id_new:
|
||||||
cr.execute('delete from wkf_workitem where id=%s', (workitem['id'],))
|
cr.execute('delete from wkf_workitem where id=%s', (workitem['id'],))
|
||||||
return False
|
return False
|
||||||
|
@ -130,27 +154,29 @@ def _execute(cr, workitem, activity, ident, stack):
|
||||||
cr.execute('select id from wkf_instance where res_id=%s and wkf_id=%s', (id_new,activity['subflow_id']))
|
cr.execute('select id from wkf_instance where res_id=%s and wkf_id=%s', (id_new,activity['subflow_id']))
|
||||||
id_new = cr.fetchone()[0]
|
id_new = cr.fetchone()[0]
|
||||||
else:
|
else:
|
||||||
id_new = instance.create(cr, ident, activity['subflow_id'])
|
id_new = instance.create(session, record, activity['subflow_id'])
|
||||||
cr.execute('update wkf_workitem set subflow_id=%s where id=%s', (id_new, workitem['id']))
|
cr.execute('update wkf_workitem set subflow_id=%s where id=%s', (id_new, workitem['id']))
|
||||||
workitem['subflow_id'] = id_new
|
workitem['subflow_id'] = id_new
|
||||||
if workitem['state']=='running':
|
if workitem['state']=='running':
|
||||||
cr.execute("select state from wkf_instance where id=%s", (workitem['subflow_id'],))
|
cr.execute("select state from wkf_instance where id=%s", (workitem['subflow_id'],))
|
||||||
state= cr.fetchone()[0]
|
state= cr.fetchone()[0]
|
||||||
if state=='complete':
|
if state=='complete':
|
||||||
_state_set(cr, workitem, activity, 'complete', ident)
|
_state_set(session, record, workitem, activity, 'complete')
|
||||||
for t in signal_todo:
|
|
||||||
instance.validate(cr, t[0], t[1], t[2], force_running=True)
|
for instance_id, record, signal_send in signal_todo:
|
||||||
|
instance.validate(session, record, signal_send, force_running=True)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _split_test(cr, workitem, split_mode, ident, signal=None, stack=None):
|
def _split_test(session, record, workitem, split_mode, signal, stack):
|
||||||
|
cr = session.cr
|
||||||
cr.execute('select * from wkf_transition where act_from=%s', (workitem['act_id'],))
|
cr.execute('select * from wkf_transition where act_from=%s', (workitem['act_id'],))
|
||||||
test = False
|
test = False
|
||||||
transitions = []
|
transitions = []
|
||||||
alltrans = cr.dictfetchall()
|
alltrans = cr.dictfetchall()
|
||||||
if split_mode=='XOR' or split_mode=='OR':
|
if split_mode=='XOR' or split_mode=='OR':
|
||||||
for transition in alltrans:
|
for transition in alltrans:
|
||||||
if wkf_expr.check(cr, workitem, ident, transition,signal):
|
if wkf_expr.check(session, record, workitem, transition,signal):
|
||||||
test = True
|
test = True
|
||||||
transitions.append((transition['id'], workitem['inst_id']))
|
transitions.append((transition['id'], workitem['inst_id']))
|
||||||
if split_mode=='XOR':
|
if split_mode=='XOR':
|
||||||
|
@ -158,7 +184,7 @@ def _split_test(cr, workitem, split_mode, ident, signal=None, stack=None):
|
||||||
else:
|
else:
|
||||||
test = True
|
test = True
|
||||||
for transition in alltrans:
|
for transition in alltrans:
|
||||||
if not wkf_expr.check(cr, workitem, ident, transition,signal):
|
if not wkf_expr.check(session, record, workitem, transition,signal):
|
||||||
test = False
|
test = False
|
||||||
break
|
break
|
||||||
cr.execute('select count(*) from wkf_witm_trans where trans_id=%s and inst_id=%s', (transition['id'], workitem['inst_id']))
|
cr.execute('select count(*) from wkf_witm_trans where trans_id=%s and inst_id=%s', (transition['id'], workitem['inst_id']))
|
||||||
|
@ -168,15 +194,17 @@ def _split_test(cr, workitem, split_mode, ident, signal=None, stack=None):
|
||||||
cr.executemany('insert into wkf_witm_trans (trans_id,inst_id) values (%s,%s)', transitions)
|
cr.executemany('insert into wkf_witm_trans (trans_id,inst_id) values (%s,%s)', transitions)
|
||||||
cr.execute('delete from wkf_workitem where id=%s', (workitem['id'],))
|
cr.execute('delete from wkf_workitem where id=%s', (workitem['id'],))
|
||||||
for t in transitions:
|
for t in transitions:
|
||||||
_join_test(cr, t[0], t[1], ident, stack)
|
_join_test(session, record, t[0], t[1], stack)
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _join_test(cr, trans_id, inst_id, ident, stack):
|
def _join_test(session, record, trans_id, inst_id, stack):
|
||||||
|
# cr, trans_id, inst_id, ident, stack):
|
||||||
|
cr = session.cr
|
||||||
cr.execute('select * from wkf_activity where id=(select act_to from wkf_transition where id=%s)', (trans_id,))
|
cr.execute('select * from wkf_activity where id=(select act_to from wkf_transition where id=%s)', (trans_id,))
|
||||||
activity = cr.dictfetchone()
|
activity = cr.dictfetchone()
|
||||||
if activity['join_mode']=='XOR':
|
if activity['join_mode']=='XOR':
|
||||||
create(cr,[activity], inst_id, ident, stack)
|
create(session, record, [activity], inst_id, stack)
|
||||||
cr.execute('delete from wkf_witm_trans where inst_id=%s and trans_id=%s', (inst_id,trans_id))
|
cr.execute('delete from wkf_witm_trans where inst_id=%s and trans_id=%s', (inst_id,trans_id))
|
||||||
else:
|
else:
|
||||||
cr.execute('select id from wkf_transition where act_to=%s', (activity['id'],))
|
cr.execute('select id from wkf_transition where act_to=%s', (activity['id'],))
|
||||||
|
@ -191,7 +219,7 @@ def _join_test(cr, trans_id, inst_id, ident, stack):
|
||||||
if ok:
|
if ok:
|
||||||
for (id,) in trans_ids:
|
for (id,) in trans_ids:
|
||||||
cr.execute('delete from wkf_witm_trans where trans_id=%s and inst_id=%s', (id,inst_id))
|
cr.execute('delete from wkf_witm_trans where trans_id=%s and inst_id=%s', (id,inst_id))
|
||||||
create(cr, [activity], inst_id, ident, stack)
|
create(session, record, [activity], inst_id, stack)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue