Improved module recorder to generate YAML
bzr revid: hda@tinyerp.com-20100310100254-z98732za4ph0ltmz
This commit is contained in:
parent
3b8faf7c1a
commit
8e87e1d3f3
|
@ -27,8 +27,8 @@ import pooler
|
|||
import string
|
||||
import tools
|
||||
|
||||
objects_proxy = netsvc.ExportService.getService('object').__class__
|
||||
class recording_objects_proxy(objects_proxy):
|
||||
#objects_proxy = netsvc.ExportService.getService('object').__class__
|
||||
class recording_objects_proxy(osv_pool):
|
||||
def execute(self, *args, **argv):
|
||||
if len(args) >= 6 and isinstance(args[5], dict):
|
||||
_old_args = args[5].copy()
|
||||
|
@ -38,7 +38,7 @@ class recording_objects_proxy(objects_proxy):
|
|||
pool = pooler.get_pool(args[0])
|
||||
mod = pool.get('ir.module.record')
|
||||
if mod and mod.recording:
|
||||
if args[4] in ('copy','write','unlink','create'):
|
||||
if args[3] not in ('default_get','read','fields_view_get','fields_get','search','search_count','name_search','name_get','get','request_get', 'get_sc', 'unlink'):
|
||||
if _old_args is not None:
|
||||
args[5].update(_old_args)
|
||||
if args[5]:
|
||||
|
@ -188,6 +188,71 @@ class base_module_record(osv.osv):
|
|||
|
||||
return record_list, noupdate
|
||||
|
||||
def _create_yaml_record(self, cr, uid, model, data, record_id):
|
||||
record={'model': model, 'id': str(record_id)}
|
||||
lids = self.pool.get('ir.model.data').search(cr, uid, [('model','=',model)])
|
||||
res = self.pool.get('ir.model.data').read(cr, uid, lids[:1], ['module'])
|
||||
attrs={}
|
||||
if res:
|
||||
self.depends[res[0]['module']]=True
|
||||
fields = self.pool.get(model).fields_get(cr, uid)
|
||||
defaults={}
|
||||
defaults[model] = self.pool.get(model).default_get(cr, uid, data)
|
||||
for key,val in data.items():
|
||||
if ((key in defaults[model]) and (val == defaults[model][key])) and not(fields[key].get('required',False)):
|
||||
continue
|
||||
if not (val or (fields[key]['type']=='boolean')):
|
||||
continue
|
||||
elif fields[key]['type'] in ('boolean',):
|
||||
if not val:
|
||||
continue
|
||||
attrs[key] = val
|
||||
elif fields[key]['type'] in ('integer','float'):
|
||||
attrs[key] = val
|
||||
elif fields[key]['type'] in ('many2one',):
|
||||
if type(val) in (type(''),type(u'')):
|
||||
id = val
|
||||
else:
|
||||
id,update = self._get_id(cr, uid, fields[key]['relation'], val)
|
||||
attrs[key] = str(id)
|
||||
elif fields[key]['type'] in ('one2many',):
|
||||
items=[[]]
|
||||
for valitem in (val or []):
|
||||
if valitem[0] in (0,1):
|
||||
if key in self.pool.get(model)._columns:
|
||||
fname = self.pool.get(model)._columns[key]._fields_id
|
||||
else:
|
||||
fname = self.pool.get(model)._inherit_fields[key][2]._fields_id
|
||||
valitem[2][fname] = record_id
|
||||
newid,update = self._get_id(cr, uid, fields[key]['relation'], valitem[1])
|
||||
if not newid:
|
||||
newid = self._create_id(cr, uid, fields[key]['relation'], valitem[2])
|
||||
self.ids[(fields[key]['relation'], valitem[1])] = newid
|
||||
childrecord = self._create_yaml_record(cr, uid, fields[key]['relation'],valitem[2], newid)
|
||||
items[0].append(childrecord['attrs'])
|
||||
attrs[key] = items
|
||||
elif fields[key]['type'] in ('many2many',):
|
||||
if (key in defaults[model]) and (val[0][2] == defaults[model][key]):
|
||||
continue
|
||||
res = []
|
||||
for valitem in (val or []):
|
||||
if valitem[0]==6:
|
||||
for id2 in valitem[2]:
|
||||
id,update = self._get_id(cr, uid, fields[key]['relation'], id2)
|
||||
self.ids[(fields[key]['relation'],id2)] = id
|
||||
res.append(str(id))
|
||||
m2m=[res]
|
||||
if m2m[0]:
|
||||
attrs[key] = m2m
|
||||
else:
|
||||
val=val.replace('"','\'')
|
||||
try:
|
||||
attrs[key]=str(val)
|
||||
except:
|
||||
attrs[key]=tools.ustr(val)
|
||||
record['attrs'] = attrs
|
||||
return record
|
||||
|
||||
def get_copy_data(self, cr, uid, model, id, result):
|
||||
res = []
|
||||
obj=self.pool.get(model)
|
||||
|
@ -215,7 +280,7 @@ class base_module_record(osv.osv):
|
|||
result[key]=data[key][0]
|
||||
|
||||
elif mod_fields[key]['type'] in ('one2many',):
|
||||
continue # due to this start stop recording will not record one2many field
|
||||
# continue # due to this start stop recording will not record one2many field
|
||||
rel = mod_fields[key]['relation']
|
||||
if len(data[key]):
|
||||
res1=[]
|
||||
|
@ -272,25 +337,41 @@ class base_module_record(osv.osv):
|
|||
noupdate = noupdate or update
|
||||
record_list += record
|
||||
|
||||
elif rec[4]=='create':
|
||||
id = self._create_id(cr, uid, rec[3],rec[5])
|
||||
record,noupdate = self._create_record(cr, uid, doc, rec[3], rec[5], id)
|
||||
elif rec[3]=='create':
|
||||
id = self._create_id(cr, uid, rec[2],rec[4])
|
||||
record,noupdate = self._create_record(cr, uid, doc, rec[2], rec[4], id)
|
||||
self.ids[(rec[3], result)] = id
|
||||
record_list += record
|
||||
|
||||
elif rec[4]=='copy':
|
||||
data=self.get_copy_data(cr,uid,rec[3],rec[5],rec[6])
|
||||
copy_rec=(rec[0],rec[1],rec[2],rec[3],rec[4],rec[5],data,rec[7])
|
||||
elif rec[3]=='copy':
|
||||
data=self.get_copy_data(cr,uid,rec[2],rec[4],rec[5])
|
||||
copy_rec=(rec[0],rec[1],rec[2],rec[3],rec[4],data,rec[5])
|
||||
rec=copy_rec
|
||||
rec_data=[(self.recording_data[0][0],rec,self.recording_data[0][2],self.recording_data[0][3])]
|
||||
self.recording_data=rec_data
|
||||
id = self._create_id(cr, uid, rec[3],rec[6])
|
||||
record,noupdate = self._create_record(cr, uid, doc, rec[3], rec[6], id)
|
||||
self.ids[(rec[3], result)] = id
|
||||
id = self._create_id(cr, uid, rec[2],rec[5])
|
||||
record,noupdate = self._create_record(cr, uid, doc, rec[2], rec[5], id)
|
||||
self.ids[(rec[2], result)] = id
|
||||
record_list += record
|
||||
|
||||
return record_list,noupdate
|
||||
|
||||
def _generate_object_yaml(self, cr, uid, rec, result=None):
|
||||
if self.mode=="create":
|
||||
id = self._create_id(cr, uid, rec[2],rec[4])
|
||||
self.ids[(rec[2], result)] = id
|
||||
record = self._create_yaml_record(cr, uid, rec[2], rec[4], id)
|
||||
return record
|
||||
data=self.get_copy_data(cr,uid,rec[2],rec[4],rec[5])
|
||||
copy_rec=(rec[0],rec[1],rec[2],rec[3],rec[4],data,rec[5])
|
||||
rec=copy_rec
|
||||
rec_data=[(self.recording_data[0][0],rec,self.recording_data[0][2],self.recording_data[0][3])]
|
||||
self.recording_data=rec_data
|
||||
id = self._create_id(cr, uid, rec[2],rec[5])
|
||||
record = self._create_yaml_record(cr, uid, str(rec[2]), rec[5], id)
|
||||
self.ids[(rec[2], result)] = id
|
||||
return record
|
||||
|
||||
def _generate_assert_xml(self, rec, doc):
|
||||
pass
|
||||
|
||||
|
@ -327,6 +408,78 @@ class base_module_record(osv.osv):
|
|||
elif rec[0]=='assert':
|
||||
pass
|
||||
return doc.toprettyxml(indent="\t").encode('utf-8')
|
||||
|
||||
def generate_yaml(self, cr, uid):
|
||||
self.ids = {}
|
||||
if len(self.recording_data):
|
||||
strg='''import yaml
|
||||
|
||||
class record(yaml.YAMLObject):
|
||||
yaml_tag = u'!record'
|
||||
def __init__(self, model, id=None, attrs={}):
|
||||
self.model = model
|
||||
self.id = id
|
||||
self.attrs=attrs
|
||||
def __repr__(self):
|
||||
return '!record {model: %s, id: %s}:' % (str(self.model,), str(self.id,))
|
||||
|
||||
class ref(yaml.YAMLObject):
|
||||
yaml_tag = u'!ref'
|
||||
def __init__(self, expr="False"):
|
||||
self.expr = expr
|
||||
def __repr__(self):
|
||||
return 'ref(%s)' % (str(self.expr,))
|
||||
|
||||
class eval(yaml.YAMLObject):
|
||||
yaml_tag = u'!eval'
|
||||
def __init__(self, expr="False"):
|
||||
self.expr = expr
|
||||
def __repr__(self):
|
||||
return 'eval(%s)' % (str(self.expr,))
|
||||
\n'''
|
||||
|
||||
for rec in self.recording_data:
|
||||
if rec[1][3] == 'create':
|
||||
self.mode="create"
|
||||
elif rec[1][3] == 'copy':
|
||||
self.mode="copy"
|
||||
else:
|
||||
continue
|
||||
record= self._generate_object_yaml(cr, uid, rec[1],rec[3])
|
||||
strg+="object=yaml.load(unicode('''\n !record %s \n''','iso-8859-1'))"%record
|
||||
strg+='''
|
||||
print object
|
||||
attrs=yaml.dump(object.attrs, default_flow_style=False)
|
||||
print attrs \n\n'''
|
||||
|
||||
import os
|
||||
py_path = os.path.join(os.getcwd(), 'records.py')
|
||||
txt_path = os.path.join(os.getcwd(), 'records.txt')
|
||||
f = open(py_path, 'w')
|
||||
f.write(strg)
|
||||
f.close()
|
||||
os.system('python %s > %s'%(py_path,txt_path))
|
||||
f = open(txt_path, 'r+')
|
||||
lines=f.readlines()
|
||||
f.seek(0)
|
||||
for line in lines:
|
||||
line=line.replace("''","'")
|
||||
if line.find('!record') == 0:
|
||||
line = "- \n" + " " + line
|
||||
elif line.find('- -') != -1:
|
||||
line=line.replace('- -',' -')
|
||||
line = " " + line
|
||||
else:
|
||||
line = " " + line
|
||||
f.write(line)
|
||||
f.close()
|
||||
f = open(txt_path, 'r')
|
||||
strg = ''.join(f.readlines())
|
||||
f.close()
|
||||
os.system('rm %s'%py_path)
|
||||
os.system('rm %s'%txt_path)
|
||||
return strg
|
||||
|
||||
base_module_record()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -37,14 +37,14 @@ intro_start_form = '''<?xml version="1.0"?>
|
|||
<field name="filter_cond"/>
|
||||
<separator string="Choose objects to record" colspan="4"/>
|
||||
<field name="objects" colspan="4" nolabel="1"/>
|
||||
|
||||
<group><field name="info_yaml"/></group>
|
||||
</form>'''
|
||||
|
||||
intro_start_fields = {
|
||||
'check_date': {'string':"Record from Date",'type':'datetime','required':True, 'default': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S')},
|
||||
'objects':{'string': 'Objects', 'type': 'many2many', 'relation': 'ir.model', 'help': 'List of objects to be recorded'},
|
||||
'filter_cond':{'string':'Records only', 'type':'selection','selection':[('created','Created'),('modified','Modified'),('created_modified','Created & Modified')], 'required':True, 'default': lambda *args:'created'},
|
||||
|
||||
'info_yaml': {'string':'YAML','type':'boolean'}
|
||||
}
|
||||
|
||||
exp_form = '''<?xml version="1.0"?>
|
||||
|
@ -98,16 +98,33 @@ def _record_objects(self, cr, uid, data, context):
|
|||
continue
|
||||
search_ids=obj_pool.search(cr,uid,search_condition)
|
||||
for s_id in search_ids:
|
||||
args=(cr.dbname,uid,user,obj_name,'copy',s_id,{},context)
|
||||
args=(cr.dbname,uid,obj_name,'copy',s_id,{},context)
|
||||
mod.recording_data.append(('query',args, {}, s_id))
|
||||
return {}
|
||||
|
||||
def _check(self, cr, uid, data, context):
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
mod = pool.get('ir.module.record')
|
||||
if len(mod.recording_data):
|
||||
if data['form']['info_yaml']:
|
||||
return 'save_yaml'
|
||||
else:
|
||||
return 'info'
|
||||
else:
|
||||
return 'end'
|
||||
|
||||
def _create_xml(self, cr, uid, data, context):
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
mod = pool.get('ir.module.record')
|
||||
res_xml = mod.generate_xml(cr, uid)
|
||||
return { 'res_text': res_xml }
|
||||
|
||||
def _create_yaml(self,cr,uid,data,context):
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
mod = pool.get('ir.module.record')
|
||||
res_xml = mod.generate_yaml(cr, uid)
|
||||
return { 'res_text': res_xml }
|
||||
|
||||
class base_module_record_objects(wizard.interface):
|
||||
states = {
|
||||
'init': {
|
||||
|
@ -122,11 +139,15 @@ class base_module_record_objects(wizard.interface):
|
|||
]
|
||||
}
|
||||
},
|
||||
'record': {
|
||||
'record': {
|
||||
'actions': [],
|
||||
'result': {'type':'action','action':_record_objects,'state':'intro'}
|
||||
'result': {'type':'action','action':_record_objects,'state':'check'}
|
||||
},
|
||||
'intro': {
|
||||
'check': {
|
||||
'actions': [],
|
||||
'result': {'type':'choice','next_state':_check}
|
||||
},
|
||||
'info': {
|
||||
'actions': [ _create_xml ],
|
||||
'result': {
|
||||
'type':'form',
|
||||
|
@ -136,7 +157,18 @@ class base_module_record_objects(wizard.interface):
|
|||
('end', 'End', 'gtk-cancel'),
|
||||
]
|
||||
},
|
||||
},
|
||||
'save_yaml': {
|
||||
'actions': [ _create_yaml ],
|
||||
'result': {
|
||||
'type':'form',
|
||||
'arch': exp_form,
|
||||
'fields':exp_fields,
|
||||
'state':[
|
||||
('end', 'End', 'gtk-cancel'),
|
||||
]
|
||||
},
|
||||
},
|
||||
'end': {
|
||||
'actions': [],
|
||||
'result': {'type':'form', 'arch':info, 'fields':{}, 'state':[('end','OK')]}
|
||||
|
|
|
@ -24,6 +24,7 @@ import osv
|
|||
import pooler
|
||||
import time
|
||||
import base_module_save
|
||||
|
||||
info = '''<?xml version="1.0"?>
|
||||
<form string="Module Recording">
|
||||
<label string="Thanks For using Module Recorder" colspan="4" align="0.0"/>
|
||||
|
@ -36,14 +37,14 @@ intro_start_form = '''<?xml version="1.0"?>
|
|||
<field name="filter_cond"/>
|
||||
<separator string="Choose objects to record" colspan="4"/>
|
||||
<field name="objects" colspan="4" nolabel="1"/>
|
||||
|
||||
<group><field name="info_yaml"/></group>
|
||||
</form>'''
|
||||
|
||||
intro_start_fields = {
|
||||
'check_date': {'string':"Record from Date",'type':'datetime','required':True, 'default': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S')},
|
||||
'objects':{'string': 'Objects', 'type': 'many2many', 'relation': 'ir.model', 'help': 'List of objects to be recorded'},
|
||||
'filter_cond':{'string':'Records only', 'type':'selection','selection':[('created','Created'),('modified','Modified'),('created_modified','Created & Modified')], 'required':True, 'default': lambda *args:'created'},
|
||||
|
||||
'info_yaml': {'string':'YAML','type':'boolean'}
|
||||
}
|
||||
|
||||
def _info_default(self, cr, uid, data, context):
|
||||
|
@ -87,7 +88,7 @@ def _record_objects(self, cr, uid, data, context):
|
|||
continue
|
||||
search_ids=obj_pool.search(cr,uid,search_condition)
|
||||
for s_id in search_ids:
|
||||
args=(cr.dbname,uid,user,obj_name,'copy',s_id,{},context)
|
||||
args=(cr.dbname,uid,obj_name,'copy',s_id,{},context)
|
||||
mod.recording_data.append(('query',args, {}, s_id))
|
||||
return {}
|
||||
|
||||
|
@ -95,6 +96,10 @@ def inter_call(self,cr,uid,data,context):
|
|||
res=base_module_save._create_module(self,cr, uid, data, context)
|
||||
return res
|
||||
|
||||
def _create_yaml(self,cr,uid,data,context):
|
||||
res=base_module_save._create_yaml(self,cr, uid, data, context)
|
||||
return res
|
||||
|
||||
class base_module_record_objects(wizard.interface):
|
||||
states = {
|
||||
'init': {
|
||||
|
@ -111,9 +116,13 @@ class base_module_record_objects(wizard.interface):
|
|||
},
|
||||
'record': {
|
||||
'actions': [],
|
||||
'result': {'type':'action','action':_record_objects,'state':'intro'}
|
||||
'result': {'type':'action','action':_record_objects,'state':'check'}
|
||||
},
|
||||
'intro': {
|
||||
'check': {
|
||||
'actions': [],
|
||||
'result': {'type':'choice','next_state':base_module_save._check}
|
||||
},
|
||||
'info': {
|
||||
'actions': [],
|
||||
'result': {
|
||||
'type':'form',
|
||||
|
@ -134,6 +143,17 @@ class base_module_record_objects(wizard.interface):
|
|||
'state':[('end', 'Close', 'gtk-ok'),]
|
||||
},
|
||||
},
|
||||
'save_yaml': {
|
||||
'actions': [_create_yaml],
|
||||
'result': {
|
||||
'type':'form',
|
||||
'arch':base_module_save.yaml_save_form,
|
||||
'fields': base_module_save.yaml_save_fields,
|
||||
'state':[
|
||||
('end', 'Close', 'gtk-ok'),
|
||||
]
|
||||
}
|
||||
},
|
||||
'end': {
|
||||
'actions': [],
|
||||
'result': {'type':'form', 'arch':info, 'fields':{}, 'state':[('end','OK')]}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
import wizard
|
||||
import osv
|
||||
import pooler
|
||||
from tools.translate import _
|
||||
|
||||
info = '''<?xml version="1.0"?>
|
||||
<form string="Module Recording">
|
||||
|
@ -33,11 +34,13 @@ info_start_form = '''<?xml version="1.0"?>
|
|||
<separator string="Recording Information" colspan="4"/>
|
||||
<field name="info_status"/>
|
||||
<field name="info_text" colspan="4" nolabel="1"/>
|
||||
<field name="info_yaml" colspan="4"/>
|
||||
</form>'''
|
||||
|
||||
info_start_fields = {
|
||||
'info_text': {'string':'Information', 'type':'text', 'readonly':True},
|
||||
'info_status': {'string':'Status','type':'selection', 'selection':[('no','Not Recording'),('record','Recording')], 'readonly':True}
|
||||
'info_status': {'string':'Status','type':'selection', 'selection':[('no','Not Recording'),('record','Recording')], 'readonly':True},
|
||||
'info_yaml': {'string':'YAML','type':'boolean'}
|
||||
}
|
||||
|
||||
|
||||
|
@ -74,7 +77,7 @@ intro_save_form = '''<?xml version="1.0"?>
|
|||
<newline/>
|
||||
<field name="module_file" filename="module_filename"/>
|
||||
<separator string="Information" colspan="4"/>
|
||||
<label string="If you think your module could interrest others people, we'd like you to publish it on OpenERP.com, in the 'Modules' section. You can do it through the website or using features of the 'base_module_publish' module." colspan="4" align="0.0"/>
|
||||
<label string="If you think your module could interest others people, we'd like you to publish it on OpenERP.com, in the 'Modules' section. You can do it through the website or using features of the 'base_module_publish' module." colspan="4" align="0.0"/>
|
||||
<label string="Thanks in advance for your contribution." colspan="4" align="0.0"/>
|
||||
</form>'''
|
||||
|
||||
|
@ -83,6 +86,17 @@ intro_save_fields = {
|
|||
'module_filename': {'string': 'Filename', 'type':'char', 'size': 64, 'readonly':True},
|
||||
}
|
||||
|
||||
yaml_save_form = '''<?xml version="1.0"?>
|
||||
<form string="Module Recording">
|
||||
<separator string="YAML file successfully created !" colspan="4"/>
|
||||
<newline/>
|
||||
<field name="yaml_file" filename="module_filename"/>
|
||||
</form>'''
|
||||
|
||||
yaml_save_fields = {
|
||||
'yaml_file': {'string': 'Module .zip File', 'type':'binary'},
|
||||
}
|
||||
|
||||
import zipfile
|
||||
import StringIO
|
||||
import base64
|
||||
|
@ -96,8 +110,8 @@ def _info_default(self, cr, uid, data, context):
|
|||
for line in mod.recording_data:
|
||||
result.setdefault(line[0],{})
|
||||
result[line[0]].setdefault(line[1][3], {})
|
||||
result[line[0]][line[1][3]].setdefault(line[1][4], 0)
|
||||
result[line[0]][line[1][3]][line[1][4]]+=1
|
||||
result[line[0]][line[1][3]].setdefault(line[1][3], 0)
|
||||
result[line[0]][line[1][3]][line[1][3]]+=1
|
||||
for key1,val1 in result.items():
|
||||
info+=key1+"\n"
|
||||
for key2,val2 in val1.items():
|
||||
|
@ -106,11 +120,22 @@ def _info_default(self, cr, uid, data, context):
|
|||
info+="\t\t"+key3+" : "+str(val3)+"\n"
|
||||
return {'info_text': info, 'info_status':mod.recording and 'record' or 'no'}
|
||||
|
||||
def _create_yaml(self, cr, uid, data, context):
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
mod = pool.get('ir.module.record')
|
||||
try:
|
||||
res_xml = mod.generate_yaml(cr, uid)
|
||||
except Exception, e:
|
||||
raise wizard.except_wizard(_('Error'),_(str(e)))
|
||||
return {
|
||||
'yaml_file': base64.encodestring(res_xml),
|
||||
}
|
||||
|
||||
def _create_module(self, cr, uid, data, context):
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
mod = pool.get('ir.module.record')
|
||||
res_xml = mod.generate_xml(cr, uid)
|
||||
|
||||
|
||||
s=StringIO.StringIO()
|
||||
zip = zipfile.ZipFile(s, 'w')
|
||||
dname = data['form']['directory_name']
|
||||
|
@ -155,7 +180,10 @@ def _check(self, cr, uid, data, context):
|
|||
pool = pooler.get_pool(cr.dbname)
|
||||
mod = pool.get('ir.module.record')
|
||||
if len(mod.recording_data):
|
||||
return 'info'
|
||||
if data['form']['info_yaml']:
|
||||
return 'save_yaml'
|
||||
else:
|
||||
return 'info'
|
||||
else:
|
||||
return 'end'
|
||||
|
||||
|
@ -200,6 +228,18 @@ class base_module_publish(wizard.interface):
|
|||
]
|
||||
}
|
||||
},
|
||||
'save_yaml': {
|
||||
'actions': [_create_yaml],
|
||||
'result': {
|
||||
'type':'form',
|
||||
'arch':yaml_save_form,
|
||||
'fields': yaml_save_fields,
|
||||
'state':[
|
||||
('end', 'Close', 'gtk-ok'),
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
'end': {
|
||||
'actions': [],
|
||||
'result': {'type':'form', 'arch':info, 'fields':{}, 'state':[('end','OK')]}
|
||||
|
|
Loading…
Reference in New Issue