Use function name in workflow instead of python code
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
* Remove use of python code in workflow XML
|
||||
* Remove ir.action.wizard_size
|
||||
* Rename expand and fill attributes into yexpand and yfill
|
||||
* Add xalign and yalign as field attributes
|
||||
|
||||
@@ -105,12 +105,12 @@ CREATE TABLE wkf_activity (
|
||||
subflow BIGINT,
|
||||
split_mode VARCHAR(255),
|
||||
join_mode VARCHAR(255),
|
||||
kind VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(255),
|
||||
signal_send VARCHAR(255),
|
||||
flow_start BOOLEAN NOT NULL,
|
||||
flow_stop BOOLEAN NOT NULL,
|
||||
action TEXT,
|
||||
stop_other BOOLEAN NOT NULL,
|
||||
action VARCHAR(255),
|
||||
PRIMARY KEY(id),
|
||||
CONSTRAINT wkf_activity_workflow_fkey FOREIGN KEY (workflow) REFERENCES wkf (id) ON DELETE CASCADE,
|
||||
CONSTRAINT wkf_activity_subflow_fkey FOREIGN KEY (subflow) REFERENCES wkf (id) ON DELETE SET NULL
|
||||
|
||||
@@ -127,12 +127,12 @@ CREATE TABLE wkf_activity (
|
||||
subflow INTEGER,
|
||||
split_mode VARCHAR NOT NULL,
|
||||
join_mode VARCHAR NOT NULL,
|
||||
kind VARCHAR NOT NULL,
|
||||
name VARCHAR NOT NULL,
|
||||
signal_send VARCHAR,
|
||||
flow_start BOOLEAN NOT NULL,
|
||||
flow_stop BOOLEAN NOT NULL,
|
||||
action TEXT,
|
||||
stop_other BOOLEAN NOT NULL,
|
||||
action VARCHAR,
|
||||
PRIMARY KEY(id),
|
||||
FOREIGN KEY (workflow) REFERENCES wkf (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (subflow) REFERENCES wkf (id) ON DELETE SET NULL
|
||||
|
||||
@@ -90,12 +90,12 @@ CREATE TABLE wkf_activity (
|
||||
subflow INTEGER,
|
||||
split_mode VARCHAR,
|
||||
join_mode VARCHAR,
|
||||
kind VARCHAR,
|
||||
name VARCHAR,
|
||||
signal_send VARCHAR,
|
||||
flow_start BOOLEAN,
|
||||
flow_stop BOOLEAN,
|
||||
action TEXT
|
||||
stop_other BOOLEAN,
|
||||
action VARCHAR
|
||||
);
|
||||
|
||||
CREATE TABLE wkf_transition (
|
||||
|
||||
@@ -9,3 +9,4 @@ from export_data import *
|
||||
from trigger import *
|
||||
from access import *
|
||||
from wizard import *
|
||||
from workflow import *
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
'description': '''A module for unittest.
|
||||
''',
|
||||
'active': True,
|
||||
'depends': ['ir', 'res'],
|
||||
'depends': ['ir', 'res', 'workflow'],
|
||||
'xml': [
|
||||
'import_data.xml',
|
||||
'sequence.xml',
|
||||
'workflow.xml',
|
||||
],
|
||||
'translation': [
|
||||
],
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of this
|
||||
# repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model import ModelSQL, ModelWorkflow, fields
|
||||
|
||||
|
||||
class WorkflowedModel(ModelWorkflow, ModelSQL):
|
||||
_name = 'test.workflowed'
|
||||
|
||||
name = fields.Char('Name')
|
||||
state = fields.Char('State')
|
||||
value = fields.Integer('Value')
|
||||
|
||||
def default_transitions(self):
|
||||
return 0
|
||||
|
||||
def default_value(self):
|
||||
return 0
|
||||
|
||||
def workflow_start(self, workflowed):
|
||||
self.write([workflowed.id], {'state': 'Start'})
|
||||
|
||||
def workflow_middle(self, workflowed):
|
||||
self.write([workflowed.id], {'state': 'Middle'})
|
||||
|
||||
def workflow_end(self, workflowed):
|
||||
self.write([workflowed.id], {'state': 'End'})
|
||||
|
||||
def start_middle_ok(self, workflowed):
|
||||
return workflowed.value > 4
|
||||
|
||||
def middle_end_ok(self, workflowed):
|
||||
return workflowed.value < 8
|
||||
|
||||
WorkflowedModel()
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of this
|
||||
repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
<record model="workflow" id="test_workflow">
|
||||
<field name="name">Test workflow</field>
|
||||
<field name="model">test.workflowed</field>
|
||||
<field name="on_create" eval="True" />
|
||||
</record>
|
||||
<record model="workflow.activity" id="test_activity_start">
|
||||
<field name="name">Start</field>
|
||||
<field name="method">workflow_start</field>
|
||||
<field name="workflow" ref="test_workflow" />
|
||||
<field name="flow_start" eval="True" />
|
||||
</record>
|
||||
<record model="workflow.activity" id="test_activity_middle">
|
||||
<field name="name">Middle</field>
|
||||
<field name="method">workflow_middle</field>
|
||||
<field name="workflow" ref="test_workflow" />
|
||||
</record>
|
||||
<record model="workflow.activity" id="test_activity_end">
|
||||
<field name="name">End</field>
|
||||
<field name="method">workflow_end</field>
|
||||
<field name="workflow" ref="test_workflow" />
|
||||
<field name="flow_stop" eval="True" />
|
||||
</record>
|
||||
<record model="workflow.transition"
|
||||
id="test_transition_start_middle">
|
||||
<field name="act_from" ref="test_activity_start" />
|
||||
<field name="act_to" ref="test_activity_middle" />
|
||||
<field name="condition">start_middle_ok</field>
|
||||
</record>
|
||||
<record model="workflow.transition"
|
||||
id="tes_transition_middle_end">
|
||||
<field name="act_from" ref="test_activity_middle" />
|
||||
<field name="act_to" ref="test_activity_end" />
|
||||
<field name="condition">middle_end_ok</field>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
@@ -0,0 +1,66 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of this
|
||||
# repository contains the full copyright notices and license terms.
|
||||
|
||||
import unittest
|
||||
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.tests.test_tryton import (POOL, DB_NAME, USER, CONTEXT,
|
||||
install_module)
|
||||
|
||||
|
||||
class WorkflowTestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
install_module('test')
|
||||
self.workflow_obj = POOL.get('test.workflowed')
|
||||
|
||||
def test0010object_creation(self):
|
||||
'Test workflow object creation'
|
||||
with Transaction().start(DB_NAME, USER, CONTEXT) as transaction:
|
||||
wkf_id = self.workflow_obj.create({
|
||||
'name': 'value = 3',
|
||||
'value': 3,
|
||||
})
|
||||
self.assertEqual(self.workflow_obj.read(wkf_id)['state'], 'Start')
|
||||
|
||||
wkf_id = self.workflow_obj.create({
|
||||
'name': 'value = 10',
|
||||
'value': 10,
|
||||
})
|
||||
self.assertEqual(self.workflow_obj.read(wkf_id)['state'], 'Middle')
|
||||
|
||||
wkf_id = self.workflow_obj.create({
|
||||
'name': 'value = 6',
|
||||
'value': 6,
|
||||
})
|
||||
self.assertEqual(self.workflow_obj.read(wkf_id)['state'], 'End')
|
||||
|
||||
transaction.cursor.rollback()
|
||||
|
||||
def test0020object_modification(self):
|
||||
'Test workflow object modification'
|
||||
with Transaction().start(DB_NAME, USER, CONTEXT):
|
||||
wkf_id = self.workflow_obj.create({
|
||||
'name': 'value = 3',
|
||||
'value': 3,
|
||||
})
|
||||
wkf_id = self.workflow_obj.create({
|
||||
'name': 'value = 10',
|
||||
'value': 10,
|
||||
})
|
||||
|
||||
wkf_id, = self.workflow_obj.search([('name', '=', 'value = 3')])
|
||||
self.workflow_obj.write(wkf_id, {'value': 11})
|
||||
self.assertEqual(self.workflow_obj.read(wkf_id)['state'], 'Middle')
|
||||
|
||||
wkf_id, = self.workflow_obj.search([('name', '=', 'value = 10')])
|
||||
self.workflow_obj.write(wkf_id, {'value': 6})
|
||||
self.assertEqual(self.workflow_obj.read(wkf_id)['state'], 'End')
|
||||
|
||||
|
||||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromTestCase(WorkflowTestCase)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.TextTestRunner(verbosity=2).run(suite())
|
||||
@@ -1,80 +0,0 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
from trytond.pool import Pool
|
||||
from trytond.tools import safe_eval
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
|
||||
class EnvCall(object):
|
||||
|
||||
def __init__(self, obj, method, obj_id):
|
||||
self.obj = obj
|
||||
self.method = method
|
||||
self.obj_id = obj_id
|
||||
|
||||
def __call__(self, *args, **kargs):
|
||||
return getattr(self.obj, self.method)(self.obj_id, *args, **kargs)
|
||||
|
||||
|
||||
class Env(dict):
|
||||
|
||||
def __init__(self, model, obj_id):
|
||||
super(Env, self).__init__()
|
||||
self.model = model
|
||||
self.obj_id = obj_id
|
||||
self.obj = Pool(Transaction().cursor.dbname).get(model)
|
||||
self.browse = self.obj.browse(obj_id)
|
||||
self.columns = self.obj._columns.keys() + \
|
||||
self.obj._inherit_fields.keys()
|
||||
|
||||
def __getitem__(self, key):
|
||||
if key == 'context':
|
||||
return Transaction().context
|
||||
elif key in self.columns:
|
||||
res = self.browse[key]
|
||||
return res
|
||||
elif key in dir(self.obj):
|
||||
return EnvCall(self.obj, key, self.obj_id)
|
||||
else:
|
||||
return super(Env, self).__getitem__(key)
|
||||
|
||||
def eval_expr(model, obj_id, action):
|
||||
res = False
|
||||
env = Env(model, obj_id)
|
||||
for line in action.split('\n'):
|
||||
if line == 'True':
|
||||
res = True
|
||||
elif line =='False':
|
||||
res = False
|
||||
else:
|
||||
res = safe_eval(line, env)
|
||||
return res
|
||||
|
||||
def execute(model, obj_id, activity):
|
||||
'''
|
||||
Execute
|
||||
|
||||
:param model: the model name
|
||||
:param obj_id: the record id
|
||||
:param activity: a BrowseRecord of workflow.activity
|
||||
'''
|
||||
return eval_expr(model, obj_id, activity.action)
|
||||
|
||||
def check(model, obj_id, transition, signal):
|
||||
'''
|
||||
Check
|
||||
|
||||
:param model: the model name
|
||||
:param obj_id: the record id
|
||||
:param transition: a BrowseRecord of workflow.transition
|
||||
'''
|
||||
if transition.signal:
|
||||
if signal != transition.signal:
|
||||
return False
|
||||
|
||||
if transition.group and Transaction().user != 0:
|
||||
user_obj = Pool(Transaction().cursor.dbname).get('res.user')
|
||||
user_groups = user_obj.get_groups()
|
||||
if transition.group.id not in user_groups:
|
||||
return False
|
||||
return eval_expr(model, obj_id, transition.condition)
|
||||
@@ -1,13 +1,12 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
import os
|
||||
import expr
|
||||
import base64
|
||||
from trytond.model import ModelView, ModelSQL, fields
|
||||
from trytond.report import Report
|
||||
from trytond.tools import exec_command_pipe
|
||||
from trytond.backend import TableHandler
|
||||
from trytond.pyson import Eval, Equal, Not
|
||||
from trytond.pyson import Eval, Equal, Not, Bool
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.pool import Pool
|
||||
|
||||
@@ -63,30 +62,27 @@ class WorkflowActivity(ModelSQL, ModelView):
|
||||
('XOR', 'Xor'),
|
||||
('AND', 'And'),
|
||||
], 'Join Mode', required=True)
|
||||
kind = fields.Selection([
|
||||
('dummy', 'Dummy'),
|
||||
('function', 'Function'),
|
||||
('subflow', 'Subflow'),
|
||||
('stopall', 'Stop All'),
|
||||
], 'Kind', required=True)
|
||||
action = fields.Text('Action', states={
|
||||
'readonly': Equal(Eval('kind'), 'dummy'),
|
||||
'required': Equal(Eval('kind'), 'function'),
|
||||
})
|
||||
method = fields.Char('Method')
|
||||
flow_start = fields.Boolean('Flow Start')
|
||||
flow_stop = fields.Boolean('Flow Stop')
|
||||
subflow = fields.Many2One('workflow', 'Subflow', states={
|
||||
'readonly': Not(Equal(Eval('kind'), 'subflow')),
|
||||
'required': Equal(Eval('kind'), 'subflow'),
|
||||
})
|
||||
stop_other = fields.Boolean('Stop Other')
|
||||
subflow = fields.Many2One('workflow', 'Subflow')
|
||||
signal_send = fields.Char('Signal (subflow.*)')
|
||||
out_transitions = fields.One2Many('workflow.transition', 'act_from',
|
||||
'Outgoing transitions')
|
||||
in_transitions = fields.One2Many('workflow.transition', 'act_to',
|
||||
'Incoming transitions')
|
||||
|
||||
#TODO add a _constraint on subflow without action
|
||||
#to have the same model than the workflow
|
||||
def init(self, module_name):
|
||||
super(WorkflowActivity, self).init(module_name)
|
||||
cursor = Transaction().cursor
|
||||
table = TableHandler(cursor, self, module_name)
|
||||
|
||||
# Migration from 2.0
|
||||
if table.column_exist('kind'):
|
||||
cursor.execute('UPDATE "%s" SET stop_other = %%s '
|
||||
"WHERE kind='stopall'" % self._table, (True,))
|
||||
table.drop_column('kind', exception=True)
|
||||
|
||||
def default_kind(self):
|
||||
return 'dummy'
|
||||
@@ -103,6 +99,9 @@ class WorkflowActivity(ModelSQL, ModelView):
|
||||
def default_flow_stop(self):
|
||||
return False
|
||||
|
||||
def default_stop_other(self):
|
||||
return False
|
||||
|
||||
WorkflowActivity()
|
||||
|
||||
|
||||
@@ -113,7 +112,9 @@ class WorkflowTransition(ModelSQL, ModelView):
|
||||
_rec_name = 'signal'
|
||||
_description = __doc__
|
||||
trigger_model = fields.Char('Trigger Type')
|
||||
trigger_expr_id = fields.Char('Trigger Expr ID')
|
||||
trigger_ids = fields.Char('Trigger Expr ID', states={
|
||||
'required': Bool(Eval('trigger_model')),
|
||||
})
|
||||
signal = fields.Char('Signal (button Name)')
|
||||
group = fields.Many2One('res.group', 'Group Required')
|
||||
condition = fields.Char('Condition', required=True)
|
||||
@@ -125,7 +126,7 @@ class WorkflowTransition(ModelSQL, ModelView):
|
||||
'trans_id', 'inst_id', 'Instances')
|
||||
|
||||
def default_condition(self):
|
||||
return 'True'
|
||||
return ''
|
||||
|
||||
WorkflowTransition()
|
||||
|
||||
@@ -327,19 +328,20 @@ class WorkflowWorkitem(ModelSQL, ModelView):
|
||||
triggers = triggers and not res
|
||||
|
||||
if triggers:
|
||||
for transition in activity.out_transitions:
|
||||
if transition.trigger_model:
|
||||
ids = expr.eval_expr( workitem.instance.res_type,
|
||||
workitem.instance.res_id,
|
||||
transition.trigger_expr_id)
|
||||
with Transaction().set_user(0):
|
||||
for res_id in ids:
|
||||
trigger_obj.create({
|
||||
'model': transition.trigger_model,
|
||||
'res_id': res_id,
|
||||
'instance': workitem.instance.id,
|
||||
'workitem': workitem.id,
|
||||
})
|
||||
trigger_transitions = (t for t in activity.out_transitions
|
||||
if t.trigger_model)
|
||||
for transition in trigger_transitions:
|
||||
model_obj = pool.get(workitem.instance.res_type)
|
||||
model_ids_fct = getattr(model_obj, transition.trigger_ids)
|
||||
ids = model_ids_fct(model_obj.browse(workitem.instance.res_id))
|
||||
with Transaction().set_user(0):
|
||||
for res_id in ids:
|
||||
trigger_obj.create({
|
||||
'model': transition.trigger_model,
|
||||
'res_id': res_id,
|
||||
'instance': workitem.instance.id,
|
||||
'workitem': workitem.id,
|
||||
})
|
||||
return True
|
||||
|
||||
def _state_set(self, workitem, state):
|
||||
@@ -358,18 +360,9 @@ class WorkflowWorkitem(ModelSQL, ModelView):
|
||||
instance_obj.validate(overflow.instance, activity.signal_send,
|
||||
force_running=True)
|
||||
|
||||
if activity.kind == 'dummy':
|
||||
if workitem.state == 'active':
|
||||
self._state_set(workitem, 'complete')
|
||||
elif activity.kind == 'function':
|
||||
if workitem.state == 'active':
|
||||
self._state_set(workitem, 'running')
|
||||
expr.execute(workitem.instance.res_type,
|
||||
workitem.instance.res_id, activity)
|
||||
self._state_set(workitem, 'complete')
|
||||
elif activity.kind == 'stopall':
|
||||
if workitem.state == 'active':
|
||||
self._state_set(workitem, 'running')
|
||||
if workitem.state == 'active':
|
||||
self._state_set(workitem, 'running')
|
||||
if activity.stop_other:
|
||||
ids = self.search([
|
||||
('instance', '=', workitem.instance.id),
|
||||
('id', '!=', workitem.id),
|
||||
@@ -377,41 +370,64 @@ class WorkflowWorkitem(ModelSQL, ModelView):
|
||||
#XXX check if delete must not be replace by _state_set 'complete'
|
||||
with Transaction().set_user(0):
|
||||
self.delete(ids)
|
||||
if activity.action:
|
||||
expr.execute(workitem.instance.res_type,
|
||||
workitem.instance.res_id, activity)
|
||||
self._state_set(workitem, 'complete')
|
||||
elif activity.kind == 'subflow':
|
||||
if workitem.state == 'active':
|
||||
self._state_set(workitem, 'running')
|
||||
if activity.action:
|
||||
id_new = expr.execute(workitem.instance.res_type,
|
||||
workitem.instance.res_id, activity)
|
||||
if not id_new:
|
||||
with Transaction().set_user(0):
|
||||
self.delete(workitem.id)
|
||||
return False
|
||||
if activity.method:
|
||||
id_new = self._execute_action(workitem, activity)
|
||||
else:
|
||||
id_new = None
|
||||
if activity.subflow:
|
||||
if activity.method and id_new:
|
||||
with Transaction().set_user(0):
|
||||
instance_id = instance_obj.search([
|
||||
('res_id', '=', id_new),
|
||||
('workflow', '=', activity.subflow.id),
|
||||
], limit=1)[0]
|
||||
else:
|
||||
elif not activity.method:
|
||||
instance_id = instance_obj.create({
|
||||
'res_type': workitem.instance.res_type,
|
||||
'res_id': workitem.instance.res_id,
|
||||
'workflow': activity.subflow.id,
|
||||
})
|
||||
else:
|
||||
with Transaction().set_user(0):
|
||||
self.delete(workitem.id)
|
||||
return False
|
||||
self.write(workitem.id, {
|
||||
'subflow': instance_id,
|
||||
})
|
||||
#XXX must be changed with a cache reset on BrowseRecord
|
||||
workitem._data[workitem.id]['subflow'] = instance_id
|
||||
elif workitem.state == 'running':
|
||||
if workitem.subflow.state == 'complete':
|
||||
self._state_set(workitem, 'complete')
|
||||
else:
|
||||
self._state_set(workitem, 'complete')
|
||||
elif workitem.state == 'running' and activity.subflow:
|
||||
if workitem.subflow.state == 'complete':
|
||||
self._state_set(workitem, 'complete')
|
||||
|
||||
return True
|
||||
|
||||
def _execute_action(self, workitem, activity):
|
||||
model_obj = Pool().get(workitem.instance.res_type)
|
||||
wkf_action = getattr(model_obj, activity.method)
|
||||
return wkf_action(model_obj.browse(workitem.instance.res_id))
|
||||
|
||||
def _activate_transition(self, workitem, transition, signal):
|
||||
pool = Pool()
|
||||
user_obj = pool.get('res.user')
|
||||
if transition.signal:
|
||||
if signal != transition.signal:
|
||||
return False
|
||||
|
||||
if transition.group and Transaction().user != 0:
|
||||
user_groups = user_obj.get_groups()
|
||||
if transition.group.id not in user_groups:
|
||||
return False
|
||||
|
||||
model_obj = pool.get(workitem.instance.res_type)
|
||||
if transition.condition:
|
||||
test_fct = getattr(model_obj, transition.condition)
|
||||
return test_fct(model_obj.browse(workitem.instance.res_id))
|
||||
else:
|
||||
return True
|
||||
|
||||
def _split_test(self, workitem, split_mode, signal=None):
|
||||
pool = Pool()
|
||||
instance_obj = pool.get('workflow.instance')
|
||||
@@ -419,8 +435,7 @@ class WorkflowWorkitem(ModelSQL, ModelView):
|
||||
transitions = []
|
||||
if split_mode == 'XOR' or split_mode == 'OR':
|
||||
for transition in workitem.activity.out_transitions:
|
||||
if expr.check(workitem.instance.res_type,
|
||||
workitem.instance.res_id, transition, signal):
|
||||
if self._activate_transition(workitem, transition, signal):
|
||||
test = True
|
||||
transitions.append(transition)
|
||||
if split_mode == 'XOR':
|
||||
@@ -428,8 +443,7 @@ class WorkflowWorkitem(ModelSQL, ModelView):
|
||||
else:
|
||||
test = True
|
||||
for transition in workitem.activity.out_transitions:
|
||||
if not expr.check(workitem.instance.res_type,
|
||||
workitem.instance.res_id, transition, signal):
|
||||
if not self._activate_transition(workitem, transition, signal):
|
||||
test = False
|
||||
break
|
||||
if transition.id not in \
|
||||
|
||||
@@ -88,10 +88,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="name" colspan="3"/>
|
||||
<label name="workflow"/>
|
||||
<field name="workflow"/>
|
||||
<label name="kind"/>
|
||||
<field name="kind"/>
|
||||
<label name="action"/>
|
||||
<field name="action" colspan="3"/>
|
||||
<label name="method"/>
|
||||
<field name="method"/>
|
||||
<label name="subflow"/>
|
||||
<field name="subflow"/>
|
||||
<label name="signal_send"/>
|
||||
@@ -112,7 +110,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="group"/>
|
||||
<field name="condition"/>
|
||||
<field name="trigger_model"/>
|
||||
<field name="trigger_expr_id"/>
|
||||
<field name="trigger_ids"/>
|
||||
</tree>
|
||||
<form string="Transition">
|
||||
<label name="act_to"/>
|
||||
@@ -126,8 +124,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="group"/>
|
||||
<label name="trigger_model"/>
|
||||
<field name="trigger_model"/>
|
||||
<label name="trigger_expr_id"/>
|
||||
<field name="trigger_expr_id"/>
|
||||
<label name="trigger_ids"/>
|
||||
<field name="trigger_ids"/>
|
||||
</form>
|
||||
</field>
|
||||
<field name="in_transitions" colspan="4">
|
||||
@@ -137,7 +135,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="group"/>
|
||||
<field name="condition"/>
|
||||
<field name="trigger_model"/>
|
||||
<field name="trigger_expr_id"/>
|
||||
<field name="trigger_ids"/>
|
||||
</tree>
|
||||
<form string="Transition">
|
||||
<label name="act_from"/>
|
||||
@@ -151,8 +149,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="group"/>
|
||||
<label name="trigger_model"/>
|
||||
<field name="trigger_model"/>
|
||||
<label name="trigger_expr_id"/>
|
||||
<field name="trigger_expr_id"/>
|
||||
<label name="trigger_ids"/>
|
||||
<field name="trigger_ids"/>
|
||||
</form>
|
||||
</field>
|
||||
</form>
|
||||
@@ -167,7 +165,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<tree string="Activity">
|
||||
<field name="name" select="1"/>
|
||||
<field name="workflow" select="1"/>
|
||||
<field name="kind" select="1"/>
|
||||
<field name="method"/>
|
||||
<field name="flow_start"/>
|
||||
<field name="flow_stop"/>
|
||||
</tree>
|
||||
@@ -230,8 +228,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="group"/>
|
||||
<label name="trigger_model"/>
|
||||
<field name="trigger_model"/>
|
||||
<label name="trigger_expr_id"/>
|
||||
<field name="trigger_expr_id"/>
|
||||
<label name="trigger_ids"/>
|
||||
<field name="trigger_ids"/>
|
||||
</form>
|
||||
]]>
|
||||
</field>
|
||||
@@ -248,7 +246,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="group"/>
|
||||
<field name="condition"/>
|
||||
<field name="trigger_model"/>
|
||||
<field name="trigger_expr_id"/>
|
||||
<field name="trigger_ids"/>
|
||||
</tree>
|
||||
]]>
|
||||
</field>
|
||||
|
||||
Reference in New Issue
Block a user