summaryrefslogtreecommitdiff
path: root/bin/addons/base/ir/workflow/print_instance.py
diff options
context:
space:
mode:
Diffstat (limited to 'bin/addons/base/ir/workflow/print_instance.py')
-rw-r--r--bin/addons/base/ir/workflow/print_instance.py172
1 files changed, 172 insertions, 0 deletions
diff --git a/bin/addons/base/ir/workflow/print_instance.py b/bin/addons/base/ir/workflow/print_instance.py
new file mode 100644
index 00000000000..6aaef8abdd3
--- /dev/null
+++ b/bin/addons/base/ir/workflow/print_instance.py
@@ -0,0 +1,172 @@
+##############################################################################
+#
+# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
+# Fabien Pinckaers <fp@tiny.Be>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+import time, os
+
+import netsvc
+import report,pooler,tools
+
+
+def graph_get(cr, graph, wkf_id, nested=False, workitem={}):
+ import pydot
+ cr.execute('select * from wkf_activity where wkf_id=%d', (wkf_id,))
+ nodes = cr.dictfetchall()
+ activities = {}
+ actfrom = {}
+ actto = {}
+ for n in nodes:
+ activities[n['id']] = n
+ if n['subflow_id'] and nested:
+ cr.execute('select * from wkf where id=%d', (n['subflow_id'],))
+ wkfinfo = cr.dictfetchone()
+ graph2 = pydot.Cluster('subflow'+str(n['subflow_id']), fontsize=10, label = "Subflow: "+n['name']+'\\nOSV: '+wkfinfo['osv'])
+ (s1,s2) = graph_get(cr, graph2, n['subflow_id'], nested,workitem)
+ graph.add_subgraph(graph2)
+ actfrom[n['id']] = s2
+ actto[n['id']] = s1
+ else:
+ args = {}
+ if n['flow_start'] or n['flow_stop']:
+ args['style']='filled'
+ args['color']='lightgrey'
+ args['label']=n['name']
+ if n['subflow_id']:
+ args['shape'] = 'box'
+ if n['id'] in workitem:
+ args['label']+='\\nx '+str(workitem[n['id']])
+ args['color'] = "red"
+ graph.add_node(pydot.Node(n['id'], **args))
+ actfrom[n['id']] = (n['id'],{})
+ actto[n['id']] = (n['id'],{})
+ cr.execute('select * from wkf_transition where act_from in ('+','.join(map(lambda x: str(x['id']),nodes))+')')
+ transitions = cr.dictfetchall()
+ for t in transitions:
+ args = {}
+ args['label'] = str(t['condition'])
+ if t['signal']:
+ args['label'] += '\\n'+str(t['signal'])
+ args['style'] = 'bold'
+
+ if activities[t['act_from']]['split_mode']=='AND':
+ args['arrowtail']='box'
+ elif str(activities[t['act_from']]['split_mode'])=='OR ':
+ args['arrowtail']='inv'
+
+ if activities[t['act_to']]['join_mode']=='AND':
+ args['arrowhead']='crow'
+
+ activity_from = actfrom[t['act_from']][1].get(t['signal'], actfrom[t['act_from']][0])
+ activity_to = actto[t['act_to']][1].get(t['signal'], actto[t['act_to']][0])
+ graph.add_edge(pydot.Edge( activity_from ,activity_to, fontsize=8, **args))
+ nodes = cr.dictfetchall()
+ cr.execute('select id from wkf_activity where flow_start=True and wkf_id=%d limit 1', (wkf_id,))
+ start = cr.fetchone()[0]
+ cr.execute("select 'subflow.'||name,id from wkf_activity where flow_stop=True and wkf_id=%d", (wkf_id,))
+ stop = cr.fetchall()
+ stop = (stop[0][1], dict(stop))
+ return ((start,{}),stop)
+
+
+def graph_instance_get(cr, graph, inst_id, nested=False):
+ workitems = {}
+ cr.execute('select * from wkf_instance where id=%d', (inst_id,))
+ inst = cr.dictfetchone()
+
+ def workitem_get(instance):
+ cr.execute('select act_id,count(*) from wkf_workitem where inst_id=%d group by act_id', (instance,))
+ workitems = dict(cr.fetchall())
+
+ cr.execute('select subflow_id from wkf_workitem where inst_id=%d', (instance,))
+ for (subflow_id,) in cr.fetchall():
+ workitems.update(workitem_get(subflow_id))
+ return workitems
+ graph_get(cr, graph, inst['wkf_id'], nested, workitem_get(inst_id))
+
+#
+# TODO: pas clean: concurrent !!!
+#
+
+class report_graph_instance(object):
+ def __init__(self, cr, uid, ids, data):
+ try:
+ import pydot
+ except Exception,e:
+ print 'Import Error for pydot, you will not be able to render workflows'
+ print 'Consider Installing PyDot or dependencies: http://dkbza.org/pydot.html'
+ raise e
+ self.done = False
+
+ try:
+ cr.execute('select * from wkf where osv=%s limit 1', (data['model'],))
+ wkfinfo = cr.dictfetchone()
+ cr.execute('select id from wkf_instance where res_id=%d and wkf_id=%d order by state limit 1', (data['id'],wkfinfo['id']))
+ inst_id = cr.fetchone()[0]
+
+ graph = pydot.Dot(fontsize=16, label="\\n\\nWorkflow: %s\\n OSV: %s" % (wkfinfo['name'],wkfinfo['osv']))
+ graph_instance_get(cr, graph, inst_id, data.get('nested', False))
+ ps_string = graph.create_ps(prog='dot')
+ except:
+ # string is in PS, like the success message would have been
+ ps_string = '''%PS-Adobe-3.0
+/inch {72 mul} def
+/Times-Roman findfont 50 scalefont setfont
+1.5 inch 15 inch moveto
+(No workflow available) show
+showpage'''
+ input, output = os.popen2('ps2pdf -sPAPERSIZE=a3 - -')
+ input.write(ps_string)
+ input.close()
+ self.result = output.read()
+ output.close()
+ self.done = True
+
+ def is_done(self):
+ return self.done
+
+ def get(self):
+ if self.done:
+ return self.result
+ else:
+ return None
+
+class report_graph(report.interface.report_int):
+ def __init__(self, name, table):
+ report.interface.report_int.__init__(self, name)
+ self.table = table
+
+ def result(self):
+ if self.obj.is_done():
+ return (True, self.obj.get(), 'pdf')
+ else:
+ return (False, False, False)
+
+ def create(self, cr, uid, ids, data, context={}):
+ self.obj = report_graph_instance(cr, uid, ids, data)
+ return (self.obj.get(), 'pdf')
+
+report_graph('report.workflow.instance.graph', 'ir.workflow')