Merge lp:~serpentcs/server-env-tools/base_module_record into lp:~server-env-tools-core-editors/server-env-tools/7.0

Proposed by Serpent Consulting Services on 2013-11-25
Status: Needs review
Proposed branch: lp:~serpentcs/server-env-tools/base_module_record
Merge into: lp:~server-env-tools-core-editors/server-env-tools/7.0
Diff against target: 1437 lines (+1372/-0)
11 files modified
base_module_record/__init__.py (+25/-0)
base_module_record/__openerp__.py (+59/-0)
base_module_record/base_module_record.py (+505/-0)
base_module_record/security/ir.model.access.csv (+2/-0)
base_module_record/wizard/__init__.py (+26/-0)
base_module_record/wizard/base_module_record_data.py (+133/-0)
base_module_record/wizard/base_module_record_data_view.xml (+72/-0)
base_module_record/wizard/base_module_record_object_view.xml (+156/-0)
base_module_record/wizard/base_module_record_objects.py (+173/-0)
base_module_record/wizard/base_module_save.py (+170/-0)
base_module_record/wizard/base_module_save_view.xml (+51/-0)
To merge this branch: bzr merge lp:~serpentcs/server-env-tools/base_module_record
Reviewer Review Type Date Requested Status
Alexandre Fayolle - camptocamp code review, no tests Needs Fixing on 2014-06-23
Yannick Vaucher @ Camptocamp Abstain on 2014-03-14
Raphaël Valyi - http://www.akretion.com Abstain on 2014-01-23
Stefan Rijnhart (Opener) Needs Information on 2014-01-22
Pedro Manuel Baeza Disapprove on 2014-01-17
Joël Grand-Guillaume @ camptocamp code review, no tests 2013-11-25 Disapprove on 2014-01-17
Review via email: mp+196613@code.launchpad.net
To post a comment you must log in.

Hi,

Thanks for the work. I'm wondering why OpenERP SA dropped this module. Seems like, at least on my experience, it was producing a very randomized result and never really succeed to use it...

So, for my own opinion, I'm not in favor of taking it here under the community umbrella. But if other people want to, then say it and I may change my mind.

In the meanwhile I disapprove that MP.

Regards,

Joël

review: Disapprove (code review, no tests)
Pedro Manuel Baeza (pedro.baeza) wrote :

The problem with this module is IMHO that you need a very controlled environment to get results from it, and doesn't fulfill all the requirements that a "module creator" must have, so I also vote for having out from OCA repositories. If not, we can receive a lot of bugs reports for this or that thing from unexperienced users that believe that this module resolves all their problems.

Regards.

review: Disapprove

Sounds alright if community feels so.

Let this be out of server-env-tools, yet available for end users to use if they wish.

Thank you guys, appreciate your efforts and time on this.

Interesting. I would not have judged so hard on this module. Then again, I only ever used it to export data that was at that time easier for me to configure in the interface than in XML, such as email templates. I don't use it anymore, but I would not mind keeping it in a community repository where it has the chance to improve.

So I'm voting needs information, but to ask from other reviewers if anyone else thinks this one can be saved.

review: Needs Information

The Core and simple purpose of the module is to save your job of writing the simple yml n xml files.
OpenERP does not have a UI editor as of now, so this module does the job!

Hi,

I used this module some times in V7, like Stephen to export datas (demo or not) and only for that this module is very usefull. For exemple to write this file, that populate french departments, (http://bazaar.launchpad.net/~sylvain-legal/openerp-grap-shared/7.0/view/head:/l10n_fr_res_department/data/res_country_department_fr_data.yml), I earned an hour of work.

My PoV is : "better something than nothing", and even if this module receive a lot of bug reports, it doesn't really matter because it's a tools only for admin user.

My 2 cents.

review: Approve (module used, no code review)

Hello,

I let the other decide. Basically my PoV is that this is a shitty module that will remain a shitty module because it produces output that you should reprocess quite a lot manually. Now if some find it useful, why not.

review: Abstain

Never used that module

review: Abstain

Never used it, code looks shaggy, and there are not tests.

Are there known issues?

In it's current state, this module is not on par with the standards of OCA and it needs care and love.

If someone has use for this module and is volunteering to maintain it, I'm willing to perform a detailed review of the code and help that person to improve the module.

review: Needs Fixing (code review, no tests)

Unmerged revisions

54. By Serpent Consulting Services on 2013-11-25

Base_module_record v7 compatible
;

53. By Serpent Consulting Services on 2013-11-25

Merged with Parent

52. By Vacha Trivedi(SerpentCS) on 2013-11-07

[IMP] base_module_record : Improvments for v7 compatiblebase_module_record as av7 compatible module

51. By Serpent Consulting Services on 2013-11-03

[ADD] Added base_module_record as av7 compatible module

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'base_module_record'
2=== added file 'base_module_record/__init__.py'
3--- base_module_record/__init__.py 1970-01-01 00:00:00 +0000
4+++ base_module_record/__init__.py 2013-11-25 18:42:07 +0000
5@@ -0,0 +1,25 @@
6+# -*- coding: utf-8 -*-
7+##############################################################################
8+#
9+# OpenERP, Open Source Management Solution
10+# Copyright (C) 2012-Today Serpent Consulting Services Pvt. Ltd. (<http://www.serpentcs.com>)
11+#
12+# This program is free software: you can redistribute it and/or modify
13+# it under the terms of the GNU Affero General Public License as
14+# published by the Free Software Foundation, either version 3 of the
15+# License, or (at your option) any later version.
16+#
17+# This program is distributed in the hope that it will be useful,
18+# but WITHOUT ANY WARRANTY; without even the implied warranty of
19+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+# GNU Affero General Public License for more details.
21+#
22+# You should have received a copy of the GNU Affero General Public License
23+# along with this program. If not, see <http://www.gnu.org/licenses/>.
24+#
25+##############################################################################
26+
27+from . import base_module_record
28+from . import wizard
29+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
30+
31
32=== added file 'base_module_record/__openerp__.py'
33--- base_module_record/__openerp__.py 1970-01-01 00:00:00 +0000
34+++ base_module_record/__openerp__.py 2013-11-25 18:42:07 +0000
35@@ -0,0 +1,59 @@
36+# -*- coding: utf-8 -*-
37+##############################################################################
38+#
39+# OpenERP, Open Source Management Solution
40+# Copyright (C) 2012-Today Serpent Consulting Services Pvt. Ltd. (<http://www.serpentcs.com>)
41+#
42+# This program is free software: you can redistribute it and/or modify
43+# it under the terms of the GNU Affero General Public License as
44+# published by the Free Software Foundation, either version 3 of the
45+# License, or (at your option) any later version.
46+#
47+# This program is distributed in the hope that it will be useful,
48+# but WITHOUT ANY WARRANTY; without even the implied warranty of
49+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50+# GNU Affero General Public License for more details.
51+#
52+# You should have received a copy of the GNU Affero General Public License
53+# along with this program. If not, see <http://www.gnu.org/licenses/>.
54+#
55+##############################################################################
56+
57+
58+{
59+ 'name': 'Record and Create Modules',
60+ 'version': '1.0',
61+ 'category': 'Tools',
62+ 'description': """
63+This module allows you to create a new module without any development.
64+======================================================================
65+
66+It records all operations on objects during the recording session and
67+produce a .ZIP module. So you can create your own module directly from
68+the OpenERP client.
69+
70+This version works for creating and updating existing records. It recomputes
71+dependencies and links for all types of widgets (many2one, many2many, ...).
72+It also support workflows and demo/update data.
73+
74+This should help you to easily create reusable and publishable modules
75+for custom configurations and demo/testing data.
76+
77+How to use it:
78+Run Administration/Customization/Module Creation/Export Customizations As a Module wizard.
79+Select datetime criteria of recording and objects to be recorded and Record module.
80+ """,
81+ 'author': 'OpenERP SA, Serpent Consulting Services Pvt. Ltd.',
82+ 'website': 'http://www.openerp.com, http://www.serpentcs.com',
83+ 'depends': ['base'],
84+ 'data': [
85+ 'security/ir.model.access.csv',
86+ 'wizard/base_module_record_object_view.xml',
87+ 'wizard/base_module_record_data_view.xml',
88+ ],
89+ 'demo': [],
90+ 'installable': True,
91+ 'auto_install':False,
92+ 'images': ['images/base_module_record1.jpeg','images/base_module_record2.jpeg','images/base_module_record3.jpeg',]
93+}
94+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
95
96=== added file 'base_module_record/base_module_record.py'
97--- base_module_record/base_module_record.py 1970-01-01 00:00:00 +0000
98+++ base_module_record/base_module_record.py 2013-11-25 18:42:07 +0000
99@@ -0,0 +1,505 @@
100+# -*- coding: utf-8 -*-
101+##############################################################################
102+#
103+# OpenERP, Open Source Management Solution
104+# Copyright (C) 2012-Today Serpent Consulting Services Pvt. Ltd. (<http://www.serpentcs.com>)
105+#
106+# This program is free software: you can redistribute it and/or modify
107+# it under the terms of the GNU Affero General Public License as
108+# published by the Free Software Foundation, either version 3 of the
109+# License, or (at your option) any later version.
110+#
111+# This program is distributed in the hope that it will be useful,
112+# but WITHOUT ANY WARRANTY; without even the implied warranty of
113+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
114+# GNU Affero General Public License for more details.
115+#
116+# You should have received a copy of the GNU Affero General Public License
117+# along with this program. If not, see <http://www.gnu.org/licenses/>.
118+#
119+##############################################################################
120+
121+from xml.dom import minidom
122+from openerp.osv import fields,osv
123+from openerp import pooler
124+import string
125+from openerp import tools
126+
127+
128+class xElement(minidom.Element):
129+ """dom.Element with compact print
130+ The Element in minidom has a problem: if printed, adds whitespace
131+ around the text nodes. The standard will not ignore that whitespace.
132+ This class simply prints the contained nodes in their compact form, w/o
133+ added spaces.
134+ """
135+ def writexml(self, writer, indent="", addindent="", newl=""):
136+ writer.write(indent)
137+ minidom.Element.writexml(self, writer, indent='', addindent='', newl='')
138+ writer.write(newl)
139+
140+def doc_createXElement(xdoc, tagName):
141+ e = xElement(tagName)
142+ e.ownerDocument = xdoc
143+ return e
144+
145+import yaml
146+from openerp.tools import yaml_tag # This import is not unused! Do not remove!
147+# Please do not override yaml_tag here: modify it in server bin/tools/yaml_tag.py
148+
149+class base_module_record(osv.Model):
150+ _name = "ir.module.record"
151+ _columns = {
152+
153+ }
154+ def __init__(self, *args, **kwargs):
155+ self.recording = 0
156+ self.recording_data = []
157+ self.depends = {}
158+ super(base_module_record, self).__init__(*args, **kwargs)
159+
160+ # To Be Improved
161+ def _create_id(self, cr, uid, model, data):
162+ i = 0
163+ while True:
164+ try:
165+ name = filter(lambda x: x in string.letters, (data.get('name','') or '').lower())
166+ except:
167+ name=''
168+# name=data.get('name','') or ''.lower()
169+ val = model.replace('.','_')+'_'+ name + str(i)
170+ i+=1
171+ if val not in self.ids.values():
172+ break
173+ return val
174+
175+ def _get_id(self, cr, uid, model, id):
176+ if type(id)==type(()):
177+ id=id[0]
178+ if (model,id) in self.ids:
179+ res_id = self.ids[(model,id)]
180+ return res_id, False
181+ dt = self.pool.get('ir.model.data')
182+ dtids = dt.search(cr, uid, [('model','=',model), ('res_id','=',id)])
183+ if not dtids:
184+ return False, None
185+ obj = dt.browse(cr, uid, dtids[0])
186+ self.depends[obj.module] = True
187+ return obj.module+'.'+obj.name, obj.noupdate
188+
189+ def _create_record(self, cr, uid, doc, model, data, record_id, noupdate=False):
190+ data_pool = self.pool.get('ir.model.data')
191+ model_pool = self.pool.get(model)
192+
193+ record = doc.createElement('record')
194+ record.setAttribute("id", record_id)
195+ record.setAttribute("model", model)
196+ record_list = [record]
197+
198+ lids = data_pool.search(cr, uid, [('model','=',model)])
199+ res = data_pool.read(cr, uid, lids[:1], ['module'])
200+ if res:
201+ self.depends[res[0]['module']]=True
202+ fields = model_pool.fields_get(cr, uid)
203+ for key,val in data.items():
204+ if not (val or (fields[key]['type']=='boolean')):
205+ continue
206+ if (fields[key]['type'] in ('integer','float') or
207+ fields[key]['type'] == 'selection' and isinstance(val, int)):
208+ field = doc.createElement('field')
209+ field.setAttribute("name", key)
210+ field.setAttribute("eval", val and str(val) or 'False' )
211+ record.appendChild(field)
212+ elif fields[key]['type'] in ('boolean',):
213+ field = doc.createElement('field')
214+ field.setAttribute("name", key)
215+ field.setAttribute("eval", val and '1' or '0' )
216+ record.appendChild(field)
217+ elif fields[key]['type'] in ('many2one',):
218+ field = doc.createElement('field')
219+ field.setAttribute("name", key)
220+ if type(val) in (type(''),type(u'')):
221+ id = val
222+ else:
223+ id,update = self._get_id(cr, uid, fields[key]['relation'], val)
224+ noupdate = noupdate or update
225+ if not id:
226+ relation_pool = self.pool.get(fields[key]['relation'])
227+
228+ field.setAttribute("model", fields[key]['relation'])
229+ fld_nm = relation_pool._rec_name
230+ name = relation_pool.read(cr, uid, val,[fld_nm])[fld_nm] or False
231+ field.setAttribute("search", str([(str(fld_nm) ,'=', name)]))
232+ else:
233+ field.setAttribute("ref", id)
234+ record.appendChild(field)
235+ elif fields[key]['type'] in ('one2many',):
236+ for valitem in (val or []):
237+ if valitem[0] in (0,1):
238+ if key in model_pool._columns:
239+ model_pool._columns[key]._fields_id
240+ else:
241+ model_pool._inherit_fields[key][2]._fields_id
242+ if valitem[0] == 0:
243+ newid = self._create_id(cr, uid, fields[key]['relation'], valitem[2])
244+ valitem[1]=newid
245+ else:
246+ newid,update = self._get_id(cr, uid, fields[key]['relation'], valitem[1])
247+ if not newid:
248+ newid = self._create_id(cr, uid, fields[key]['relation'], valitem[2])
249+ valitem[1]=newid
250+ self.ids[(fields[key]['relation'], valitem[1])] = newid
251+
252+ childrecord, update = self._create_record(cr, uid, doc, fields[key]['relation'],valitem[2], newid)
253+ noupdate = noupdate or update
254+ record_list += childrecord
255+ else:
256+ pass
257+ elif fields[key]['type'] in ('many2many',):
258+ res = []
259+ for valitem in (val or []):
260+ if valitem[0]==6:
261+ for id2 in valitem[2]:
262+ id,update = self._get_id(cr, uid, fields[key]['relation'], id2)
263+ self.ids[(fields[key]['relation'],id2)] = id
264+ noupdate = noupdate or update
265+ res.append(id)
266+ field = doc.createElement('field')
267+ field.setAttribute("name", key)
268+ field.setAttribute("eval", "[(6,0,["+','.join(map(lambda x: "ref('%s')" % (x,), res))+'])]')
269+ record.appendChild(field)
270+ else:
271+ field = doc_createXElement(doc, 'field')
272+ field.setAttribute("name", key)
273+ field.appendChild(doc.createTextNode(val))
274+ record.appendChild(field)
275+
276+ return record_list, noupdate
277+
278+ def _create_yaml_record(self, cr, uid, model, data, record_id):
279+ record={'model': model, 'id': str(record_id)}
280+
281+ model_pool = self.pool.get(model)
282+ data_pool = self.pool.get('ir.model.data')
283+ lids = data_pool.search(cr, uid, [('model','=',model)])
284+
285+ res = data_pool.read(cr, uid, lids[:1], ['module'])
286+ attrs={}
287+ if res:
288+ self.depends[res[0]['module']]=True
289+ fields = model_pool.fields_get(cr, uid)
290+ defaults={}
291+ try:
292+ defaults[model] = model_pool.default_get(cr, uid, data)
293+ except:
294+ defaults[model]={}
295+ for key,val in data.items():
296+ if ((key in defaults[model]) and (val == defaults[model][key])) and not(fields[key].get('required',False)):
297+ continue
298+ if fields[key]['type'] in ('integer','float'):
299+ if not val:
300+ val=0.0
301+ attrs[key] = val
302+ elif not (val or (fields[key]['type']=='function')):
303+ continue
304+ elif fields[key]['type'] in ('boolean',):
305+ if not val:
306+ continue
307+ attrs[key] = val
308+ elif fields[key]['type'] in ('many2one',):
309+ if type(val) in (type(''), type(u'')):
310+ id = val
311+ else:
312+ id, update = self._get_id(cr, uid, fields[key]['relation'], val)
313+ attrs[key] = str(id)
314+ elif fields[key]['type'] in ('one2many',):
315+ items=[[]]
316+ for valitem in (val or []):
317+ if valitem[0] in (0,1):
318+ if key in model_pool._columns:
319+ fname = model_pool._columns[key]._fields_id
320+ else:
321+ fname = model_pool._inherit_fields[key][2]._fields_id
322+ del valitem[2][fname] #delete parent_field from child's fields list
323+
324+ childrecord = self._create_yaml_record(cr, uid, fields[key]['relation'],valitem[2], None)
325+ items[0].append(childrecord['attrs'])
326+ attrs[key] = items
327+ elif fields[key]['type'] in ('many2many',):
328+ if (key in defaults[model]) and (val[0][2] == defaults[model][key]):
329+ continue
330+ res = []
331+ for valitem in (val or []):
332+ if valitem[0]==6:
333+ for id2 in valitem[2]:
334+ id,update = self._get_id(cr, uid, fields[key]['relation'], id2)
335+ self.ids[(fields[key]['relation'],id2)] = id
336+ res.append(str(id))
337+ m2m=[res]
338+ if m2m[0]:
339+ attrs[key] = m2m
340+ else:
341+ try:
342+ attrs[key]=str(val)
343+ except:
344+ attrs[key]=tools.ustr(val)
345+ attrs[key]=attrs[key].replace('"','\'')
346+ record['attrs'] = attrs
347+ return record
348+
349+ def get_copy_data(self, cr, uid, model, id, result):
350+ res = []
351+ obj=self.pool.get(model)
352+ data=obj.read(cr, uid,[id])
353+ if type(data)==type([]):
354+ del data[0]['id']
355+ data=data[0]
356+ else:
357+ del data['id']
358+
359+ mod_fields = obj.fields_get(cr, uid)
360+ for f in filter(lambda a: isinstance(obj._columns[a], fields.function)\
361+ and (not obj._columns[a].store),obj._columns):
362+ del data[f]
363+
364+ for key,val in data.items():
365+ if result.has_key(key):
366+ continue
367+ if mod_fields[key]['type'] == 'many2one':
368+ if type(data[key])==type(True) or type(data[key])==type(1):
369+ result[key]=data[key]
370+ elif not data[key]:
371+ result[key] = False
372+ else:
373+ result[key]=data[key][0]
374+
375+ elif mod_fields[key]['type'] in ('one2many',):
376+# continue # due to this start stop recording will not record one2many field
377+ rel = mod_fields[key]['relation']
378+ if rel == 'mail.message':
379+ continue
380+ if len(data[key]):
381+ res1=[]
382+ for rel_id in data[key]:
383+ res=[0,0]
384+ res.append(self.get_copy_data(cr, uid,rel,rel_id,{}))
385+ res1.append(res)
386+ result[key]=res1
387+ else:
388+ result[key]=data[key]
389+
390+ elif mod_fields[key]['type'] == 'many2many':
391+ result[key]=[(6,0,data[key])]
392+
393+ else:
394+ result[key]=data[key]
395+ for k,v in obj._inherits.items():
396+ del result[v]
397+ return result
398+
399+ def _create_function(self, cr, uid, doc, model, name, record_id):
400+ record = doc.createElement('function')
401+ record.setAttribute("name", name)
402+ record.setAttribute("model", model)
403+ record_list = [record]
404+
405+ value = doc.createElement('value')
406+ value.setAttribute('eval', '[ref(\'%s\')]' % (record_id, ))
407+ value.setAttribute('model', model)
408+
409+ record.appendChild(value)
410+ return record_list, False
411+
412+ def _generate_object_xml(self, cr, uid, rec, recv, doc, result=None):
413+ record_list = []
414+ noupdate = False
415+ if rec[3]=='write':
416+ for id in rec[4]:
417+ id,update = self._get_id(cr, uid, rec[2], id)
418+ noupdate = noupdate or update
419+ if not id:
420+ continue
421+ record,update = self._create_record(cr, uid, doc, rec[2], rec[5], id)
422+ noupdate = noupdate or update
423+ record_list += record
424+
425+ elif rec[4] in ('menu_create',):
426+ for id in rec[5]:
427+ id,update = self._get_id(cr, uid, rec[3], id)
428+ noupdate = noupdate or update
429+ if not id:
430+ continue
431+ record,update = self._create_function(cr, uid, doc, rec[3], rec[4], id)
432+ noupdate = noupdate or update
433+ record_list += record
434+
435+ elif rec[3]=='create':
436+ id = self._create_id(cr, uid, rec[2],rec[4])
437+ record,noupdate = self._create_record(cr, uid, doc, rec[2], rec[4], id)
438+ self.ids[(rec[2], result)] = id
439+ record_list += record
440+
441+ elif rec[3]=='copy':
442+ data=self.get_copy_data(cr,uid,rec[2],rec[4],rec[5])
443+ copy_rec=(rec[0],rec[1],rec[2],rec[3],rec[4],data,rec[5])
444+ rec=copy_rec
445+ rec_data=[(self.recording_data[0][0],rec,self.recording_data[0][2],self.recording_data[0][3])]
446+ self.recording_data=rec_data
447+ id = self._create_id(cr, uid, rec[2],rec[5])
448+ record,noupdate = self._create_record(cr, uid, doc, rec[2], rec[5], id)
449+ self.ids[(rec[2], result)] = id
450+ record_list += record
451+
452+ return record_list,noupdate
453+
454+ def _generate_object_yaml(self, cr, uid, rec, result=None):
455+ if self.mode=="create":
456+ yml_id = self._create_id(cr, uid, rec[2],rec[4])
457+ self.ids[(rec[2], result)] = yml_id
458+ record = self._create_yaml_record(cr, uid, rec[2], rec[4], yml_id)
459+ return record
460+ if self.mode=="workflow":
461+ id,update = self._get_id(cr, uid, rec[2], rec[4])
462+ data = {}
463+ data['model'] = rec[2]
464+ data['action'] = rec[3]
465+ data['ref'] = id
466+ return data
467+ if self.mode=="write":
468+ id,update = self._get_id(cr, uid, rec[2],rec[4][0])
469+ record = self._create_yaml_record(cr, uid, rec[2], rec[5], id)
470+ return record
471+ data=self.get_copy_data(cr,uid,rec[2],rec[4],rec[5])
472+ copy_rec=(rec[0],rec[1],rec[2],rec[3],rec[4],data,rec[5])
473+ rec=copy_rec
474+ rec_data=[(self.recording_data[0][0],rec,self.recording_data[0][2],self.recording_data[0][3])]
475+ self.recording_data=rec_data
476+ id = self._create_id(cr, uid, rec[2],rec[5])
477+ record = self._create_yaml_record(cr, uid, str(rec[2]), rec[5], id)
478+ self.ids[(rec[2], result)] = id
479+ return record
480+
481+ def _generate_function_yaml(self, cr, uid, args):
482+ db, uid, model, action, ids, context = args
483+ temp_context = context.copy()
484+ active_id = temp_context['active_id']
485+ active_model = temp_context['active_model']
486+ active_id, update = self._get_id(cr, uid, active_model, active_id)
487+ if not active_id:
488+ active_id = 1
489+ rec_id, noupdate = self._get_id(cr, uid, model, ids[0])
490+ temp_context['active_id'] = "ref('%s')"%unicode(active_id)
491+ temp_context['active_ids'][0] = "ref('%s')"%str(active_id)
492+ function={}
493+ function['model'] = model
494+ function['action'] = action
495+ attrs = "self.%s(cr, uid, [ref('%s')], {" %(action, rec_id, )
496+ for k, v in temp_context.iteritems():
497+ if isinstance(v, str):
498+ f= "'"+k+"': "+"'%s'"%v + ", "
499+ else:
500+ v=str(v).replace('"', '')
501+ f= "'"+k+"': "+"%s"%v + ", "
502+ attrs = attrs + f
503+ attrs=str(attrs)+'})'
504+ function['attrs'] = attrs
505+ return function
506+
507+ def _generate_assert_xml(self, rec, doc):
508+ pass
509+
510+ def generate_xml(self, cr, uid):
511+ # Create the minidom document
512+ if len(self.recording_data):
513+ self.ids = {}
514+ doc = minidom.Document()
515+ terp = doc.createElement("openerp")
516+ doc.appendChild(terp)
517+ for rec in self.recording_data:
518+ if rec[0]=='workflow':
519+ rec_id,noupdate = self._get_id(cr, uid, rec[1][2], rec[1][4])
520+ if not rec_id:
521+ continue
522+ data = doc.createElement("data")
523+ terp.appendChild(data)
524+ wkf = doc.createElement('workflow')
525+ data.appendChild(wkf)
526+ wkf.setAttribute("model", rec[1][2])
527+ wkf.setAttribute("action", rec[1][3])
528+ if noupdate:
529+ data.setAttribute("noupdate", "1")
530+ wkf.setAttribute("ref", rec_id)
531+ if rec[0]=='query':
532+ res_list,noupdate = self._generate_object_xml(cr, uid, rec[1], rec[2], doc, rec[3])
533+ data = doc.createElement("data")
534+ if noupdate:
535+ data.setAttribute("noupdate", "1")
536+ if res_list:
537+ terp.appendChild(data)
538+ for res in res_list:
539+ data.appendChild(res)
540+ elif rec[0]=='assert':
541+ pass
542+ return doc.toprettyxml(indent="\t").encode('utf-8')
543+
544+ def generate_yaml(self, cr, uid):
545+ self.ids = {}
546+ if len(self.recording_data):
547+ yaml_file='''\n'''
548+
549+ for rec in self.recording_data:
550+ if rec[1][3] == 'create':
551+ self.mode="create"
552+ elif rec[1][3] == 'write':
553+ self.mode="write"
554+ elif rec[1][3] == 'copy':
555+ self.mode="copy"
556+ elif rec[0] == 'workflow':
557+ self.mode="workflow"
558+ elif rec[0] == 'osv_memory_action':
559+ self.mode='osv_memory_action'
560+ else:
561+ continue
562+ if self.mode == "workflow":
563+ record = self._generate_object_yaml(cr, uid, rec[1],rec[0])
564+ yaml_file += "!comment Performing a workflow action %s on module %s"%(record['action'], record['model']) + '''\n'''
565+ object = yaml.load(unicode('''\n !workflow %s \n'''%record,'iso-8859-1'))
566+ yaml_file += str(object) + '''\n\n'''
567+ elif self.mode == 'osv_memory_action':
568+ osv_action = self._generate_function_yaml(cr, uid, rec[1])
569+ yaml_file += "!comment Performing an osv_memory action %s on module %s"%(osv_action['action'], osv_action['model']) + '''\n'''
570+ osv_action = yaml.load(unicode('''\n !python %s \n'''%osv_action,'iso-8859-1'))
571+ yaml_file += str(osv_action) + '''\n'''
572+ attrs = yaml.dump(osv_action.attrs, default_flow_style=False)
573+ attrs = attrs.replace("''", '"')
574+ attrs = attrs.replace("'", '')
575+ yaml_file += attrs + '''\n\n'''
576+ else:
577+ record = self._generate_object_yaml(cr, uid, rec[1], rec[3])
578+ if self.mode == "create" or self.mode == "copy":
579+ yaml_file += "!comment Creating a %s record"%(record['model']) + '''\n'''
580+ else:
581+ yaml_file += "!comment Modifying a %s record"%(record['model']) + '''\n'''
582+ object = yaml.load(unicode('''\n !record %s \n'''%record,'iso-8859-1'))
583+ yaml_file += str(object) + '''\n'''
584+ attrs = yaml.dump(object.attrs, default_flow_style=False)
585+ yaml_file += attrs + '''\n\n'''
586+
587+ yaml_result=''''''
588+ for line in yaml_file.split('\n'):
589+ line=line.replace("''","'")
590+ if (line.find('!record') == 0) or (line.find('!workflow') == 0) or (line.find('!python') == 0):
591+ line = "- \n" + " " + line
592+ elif line.find('!comment') == 0:
593+ line=line.replace('!comment','- \n ')
594+ elif line.find('- -') != -1:
595+ line=line.replace('- -',' -')
596+ line = " " + line
597+ else:
598+ line = " " + line
599+ yaml_result += line + '''\n'''
600+ return yaml_result
601+
602+base_module_record()
603+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
604+
605
606=== added directory 'base_module_record/images'
607=== added file 'base_module_record/images/base_module_record1.jpeg'
608Binary files base_module_record/images/base_module_record1.jpeg 1970-01-01 00:00:00 +0000 and base_module_record/images/base_module_record1.jpeg 2013-11-25 18:42:07 +0000 differ
609=== added file 'base_module_record/images/base_module_record2.jpeg'
610Binary files base_module_record/images/base_module_record2.jpeg 1970-01-01 00:00:00 +0000 and base_module_record/images/base_module_record2.jpeg 2013-11-25 18:42:07 +0000 differ
611=== added file 'base_module_record/images/base_module_record3.jpeg'
612Binary files base_module_record/images/base_module_record3.jpeg 1970-01-01 00:00:00 +0000 and base_module_record/images/base_module_record3.jpeg 2013-11-25 18:42:07 +0000 differ
613=== added directory 'base_module_record/security'
614=== added file 'base_module_record/security/ir.model.access.csv'
615--- base_module_record/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
616+++ base_module_record/security/ir.model.access.csv 2013-11-25 18:42:07 +0000
617@@ -0,0 +1,2 @@
618+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
619+access_ir_module_record,ir.module.record,model_ir_module_record,base.group_system,1,1,1,1
620
621=== added directory 'base_module_record/wizard'
622=== added file 'base_module_record/wizard/__init__.py'
623--- base_module_record/wizard/__init__.py 1970-01-01 00:00:00 +0000
624+++ base_module_record/wizard/__init__.py 2013-11-25 18:42:07 +0000
625@@ -0,0 +1,26 @@
626+# -*- coding: utf-8 -*-
627+##############################################################################
628+#
629+# OpenERP, Open Source Management Solution
630+# Copyright (C) 2012-Today Serpent Consulting Services Pvt. Ltd. (<http://www.serpentcs.com>)
631+#
632+# This program is free software: you can redistribute it and/or modify
633+# it under the terms of the GNU Affero General Public License as
634+# published by the Free Software Foundation, either version 3 of the
635+# License, or (at your option) any later version.
636+#
637+# This program is distributed in the hope that it will be useful,
638+# but WITHOUT ANY WARRANTY; without even the implied warranty of
639+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
640+# GNU Affero General Public License for more details.
641+#
642+# You should have received a copy of the GNU Affero General Public License
643+# along with this program. If not, see <http://www.gnu.org/licenses/>.
644+#
645+##############################################################################
646+
647+from . import base_module_save
648+from . import base_module_record_objects
649+from . import base_module_record_data
650+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
651+
652
653=== added file 'base_module_record/wizard/base_module_record_data.py'
654--- base_module_record/wizard/base_module_record_data.py 1970-01-01 00:00:00 +0000
655+++ base_module_record/wizard/base_module_record_data.py 2013-11-25 18:42:07 +0000
656@@ -0,0 +1,133 @@
657+# -*- encoding: utf-8 -*-
658+##############################################################################
659+#
660+# OpenERP, Open Source Management Solution
661+# Copyright (C) 2012-Today Serpent Consulting Services Pvt. Ltd. (<http://www.serpentcs.com>)
662+#
663+# This program is free software: you can redistribute it and/or modify
664+# it under the terms of the GNU Affero General Public License as published by
665+# the Free Software Foundation, either version 3 of the License, or
666+# (at your option) any later version.
667+#
668+# This program is distributed in the hope that it will be useful,
669+# but WITHOUT ANY WARRANTY; without even the implied warranty of
670+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
671+# GNU Affero General Public License for more details.
672+#
673+# You should have received a copy of the GNU Affero General Public License
674+# along with this program. If not, see <http://www.gnu.org/licenses/>.
675+#
676+##############################################################################
677+
678+from openerp.osv import orm, fields, osv
679+from openerp import tools
680+from openerp.tools.translate import _
681+
682+import time
683+
684+class base_module_data(orm.TransientModel):
685+ _name = 'base.module.data'
686+ _description = "Base Module Data"
687+
688+ _columns = {
689+ 'check_date': fields.datetime('Record from Date', required=True),
690+ 'objects': fields.many2many('ir.model', 'base_module_record_model_rel', 'objects', 'model_id', 'Objects'),
691+ 'filter_cond': fields.selection([('created', 'Created'), ('modified', 'Modified'), ('created_modified', 'Created & Modified')], 'Records only', required=True),
692+ 'info_yaml': fields.boolean('YAML'),
693+ }
694+
695+ def _get_default_objects(self, cr, uid, context=None):
696+ names = ('ir.ui.view', 'ir.ui.menu', 'ir.model', 'ir.model.fields', 'ir.model.access',
697+ 'res.partner', 'res.partner.category', 'workflow',
698+ 'workflow.activity', 'workflow.transition', 'ir.actions.server', 'ir.server.object.lines')
699+ return self.pool.get('ir.model').search(cr, uid, [('model', 'in', names)])
700+
701+ _defaults = {
702+ 'check_date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
703+ 'objects': _get_default_objects,
704+ 'filter_cond': 'created',
705+ }
706+
707+ def _create_xml(self, cr, uid, data, context=None):
708+ mod = self.pool.get('ir.module.record')
709+ res_xml = mod.generate_xml(cr, uid)
710+ return {'res_text': res_xml }
711+
712+ def _create_yaml(self, cr, uid, data, context=None):
713+ mod = self.pool.get('ir.module.record')
714+ res_xml = mod.generate_yaml(cr, uid)
715+ return { 'res_text': res_xml }
716+
717+ def record_objects(self, cr, uid, ids, context=None):
718+ data = self.read(cr, uid, ids, [], context=context)[0]
719+ check_date = data['check_date']
720+ filter = data['filter_cond']
721+ user = (self.pool.get('res.users').browse(cr, uid, uid)).login
722+ mod = self.pool.get('ir.module.record')
723+ mod_obj = self.pool.get('ir.model')
724+ mod.recording_data = []
725+ for id in data['objects']:
726+ obj_name=(mod_obj.browse(cr, uid, id)).model
727+ obj_pool=self.pool.get(obj_name)
728+ if filter =='created':
729+ search_condition =[('create_date','>',check_date)]
730+ elif filter =='modified':
731+ search_condition =[('write_date','>',check_date)]
732+ elif filter =='created_modified':
733+ search_condition =['|',('create_date','>',check_date),('write_date','>',check_date)]
734+ if '_log_access' in dir(obj_pool):
735+ if not (obj_pool._log_access):
736+ search_condition=[]
737+ if '_auto' in dir(obj_pool):
738+ if not obj_pool._auto:
739+ continue
740+ search_ids=obj_pool.search(cr,uid,search_condition)
741+ for s_id in search_ids:
742+ args=(cr.dbname,uid,obj_name,'copy', s_id,{}, context)
743+ mod.recording_data.append(('query', args, {}, s_id))
744+
745+ mod_obj = self.pool.get('ir.model.data')
746+ if len(mod.recording_data):
747+ if data['info_yaml']:
748+ res=self._create_yaml(cr, uid, data, context)
749+ else:
750+ res=self._create_xml(cr, uid, data, context)
751+ model_data_ids = mod_obj.search(cr, uid, [('model', '=', 'ir.ui.view'), ('name', '=', 'module_create_xml_view')], context=context)
752+ resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
753+ return {
754+ 'name': _('Data Recording'),
755+ 'context': {'default_res_text': tools.ustr(res['res_text'])},
756+ 'view_type': 'form',
757+ 'view_mode': 'form',
758+ 'res_model': 'base.module.record.data',
759+ 'views': [(resource_id, 'form')],
760+ 'type': 'ir.actions.act_window',
761+ 'target': 'new',
762+ }
763+
764+ model_data_ids = mod_obj.search(cr, uid,[('model', '=', 'ir.ui.view'), ('name', '=', 'module_recording_message_view')], context=context)
765+ resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
766+ return {
767+ 'name': _('Module Recording'),
768+ 'context': context,
769+ 'view_type': 'form',
770+ 'view_mode': 'form',
771+ 'res_model': 'base.module.record.objects',
772+ 'views': [(resource_id, 'form')],
773+ 'type': 'ir.actions.act_window',
774+ 'target': 'new',
775+ }
776+
777+base_module_data()
778+
779+class base_module_record_data(orm.TransientModel):
780+ _name = 'base.module.record.data'
781+ _description = "Base Module Record Data"
782+
783+ _columns = {
784+ 'res_text': fields.text('Result'),
785+ }
786+
787+base_module_record_data()
788+
789+#vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
790
791=== added file 'base_module_record/wizard/base_module_record_data_view.xml'
792--- base_module_record/wizard/base_module_record_data_view.xml 1970-01-01 00:00:00 +0000
793+++ base_module_record/wizard/base_module_record_data_view.xml 2013-11-25 18:42:07 +0000
794@@ -0,0 +1,72 @@
795+<?xml version="1.0" encoding="utf-8"?>
796+<openerp>
797+ <data>
798+
799+ <record id="base_module_record_data_view" model="ir.ui.view">
800+ <field name="name">base_module_record_data</field>
801+ <field name="model">base.module.data</field>
802+ <field name="arch" type="xml">
803+ <form string="Data Recording" version="7.0">
804+ <sheet>
805+ <group>
806+ <field name="check_date"/>
807+ <newline/>
808+ <field name="filter_cond"/>
809+ <separator string="Choose objects to record" colspan="4"/>
810+ <field name="objects" colspan="4" nolabel="1"/>
811+ </group>
812+ <group><field name="info_yaml"/></group>
813+ <footer>
814+ <button icon="gtk-cancel" string="Cancel" special="cancel"/>
815+ <button name="record_objects" icon="gtk-ok" string="Record" type="object"/>
816+ </footer>
817+ </sheet>
818+ </form>
819+ </field>
820+ </record>
821+
822+ <record model="ir.actions.act_window" id="action_base_module_record_data">
823+ <field name="name">Export Customizations as Data</field>
824+ <field name="res_model">base.module.data</field>
825+ <field name="view_type">form</field>
826+ <field name="view_mode">form</field>
827+ <field name="target">new</field>
828+ <field name="view_id" ref="base_module_record_data_view"/>
829+ </record>
830+
831+
832+ <menuitem
833+ parent="menu_wizard_base_mod_rec"
834+ name="Export Customizations As Data file"
835+ action="action_base_module_record_data"
836+ id="menu_wizard_base_module_record_data"/>
837+
838+ <act_window
839+ id="act_base_module_record_data"
840+ name="Export Customizations As Data File"
841+ res_model="base.module.data"
842+ src_model="ir.module.module"
843+ view_mode="form"
844+ target="new"
845+ multi="True"
846+ key2="client_action_multi"/>
847+
848+ <record id="module_create_xml_view" model="ir.ui.view">
849+ <field name="name">module.create.xml.form</field>
850+ <field name="model">base.module.record.data</field>
851+ <field name="arch" type="xml">
852+ <form string="Data Recording" version="7.0">
853+ <sheet>
854+ <group>
855+ <separator string="Result, paste this to your module's xml" colspan="4"/>
856+ <field name="res_text" nolabel="1" colspan="4"/>
857+ </group>
858+ <footer>
859+ <button icon="gtk-close" string="Close" special="cancel"/>
860+ </footer>
861+ </sheet>
862+ </form>
863+ </field>
864+ </record>
865+ </data>
866+</openerp>
867
868=== added file 'base_module_record/wizard/base_module_record_object_view.xml'
869--- base_module_record/wizard/base_module_record_object_view.xml 1970-01-01 00:00:00 +0000
870+++ base_module_record/wizard/base_module_record_object_view.xml 2013-11-25 18:42:07 +0000
871@@ -0,0 +1,156 @@
872+<?xml version="1.0" encoding="utf-8"?>
873+<openerp>
874+ <data>
875+
876+ <record id="base_module_record_objects_view" model="ir.ui.view">
877+ <field name="name">base_module_record_objects</field>
878+ <field name="model">base.module.record</field>
879+ <field name="arch" type="xml">
880+ <form string="Objects Recording" version="7.0">
881+ <sheet>
882+ <group>
883+ <field name="check_date"/>
884+ <newline/>
885+ <field name="filter_cond"/>
886+ <separator string="Choose objects to record" colspan="4"/>
887+ <field name="objects" colspan="4" nolabel="1"/>
888+ </group>
889+ <group><field name="info_yaml"/></group>
890+ <separator colspan="4"/>
891+ <footer>
892+ <button icon="gtk-cancel" string="Cancel" special="cancel"/>
893+ <button name="record_objects" icon="gtk-ok" string="Record" type="object"/>
894+ </footer>
895+ </sheet>
896+ </form>
897+ </field>
898+ </record>
899+
900+ <record model="ir.actions.act_window" id="action_base_module_record_objects">
901+ <field name="name">Export Customizations as a Module</field>
902+ <field name="res_model">base.module.record</field>
903+ <field name="view_type">form</field>
904+ <field name="view_mode">form</field>
905+ <field name="target">new</field>
906+ <field name="view_id" ref="base_module_record_objects_view"/>
907+ </record>
908+
909+ <menuitem
910+ parent="base.menu_custom"
911+ name="Module Creation"
912+ id="menu_wizard_base_mod_rec"/>
913+<!-- groups="base.group_extended"/> -->
914+
915+ <menuitem
916+ parent="menu_wizard_base_mod_rec"
917+ name="Export Customizations As a Module"
918+ action="action_base_module_record_objects"
919+ id="menu_wizard_base_module_record_objects"/>
920+
921+ <act_window
922+ id="act_base_module_record_objects"
923+ name="Export Customizations As a Module"
924+ res_model="base.module.record"
925+ src_model="ir.module.module"
926+ view_mode="form"
927+ target="new"
928+ multi="True"
929+ key2="client_action_multi"/>
930+
931+ <record id="module_create_form_view" model="ir.ui.view">
932+ <field name="name">module.create.form</field>
933+ <field name="model">base.module.record.objects</field>
934+ <field name="arch" type="xml">
935+ <form string="Module Recording" version="7.0">
936+ <sheet>
937+ <group>
938+ <separator string="Module successfully created !" colspan="4"/>
939+ <field name="module_filename"/>
940+ <newline/>
941+ <field name="module_file"/>
942+ </group>
943+ <separator string="Information" colspan="4"/>
944+ <label string="If you think your module could interest other people, we'd like you to publish it on http://www.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"/>
945+ <label string="Thanks in advance for your contribution." colspan="4" align="0.0"/>
946+ <separator colspan="4"/>
947+ <footer>
948+ <button icon="gtk-close" string="Close" special="cancel"/>
949+ </footer>
950+ </sheet>
951+ </form>
952+ </field>
953+ </record>
954+
955+ <record model="ir.actions.act_window" id="action_module_created">
956+ <field name="name">Module Recording</field>
957+ <field name="res_model">base.module.record.objects</field>
958+ <field name="view_type">form</field>
959+ <field name="view_mode">form</field>
960+ <field name="target">new</field>
961+ <field name="view_id" ref="module_create_form_view"/>
962+ </record>
963+
964+ <record id="info_start_form_view" model="ir.ui.view">
965+ <field name="name">info.start.form.view</field>
966+ <field name="model">base.module.record.objects</field>
967+ <field name="arch" type="xml">
968+ <form string="Module Recording" version="7.0">
969+ <sheet>
970+ <group>
971+ <separator string="Module Information" colspan="4"/>
972+ <field name="name"/>
973+ <field name="directory_name"/>
974+ <field name="version"/>
975+ <field name="author"/>
976+ <field name="website"/>
977+ <field name="category"/>
978+ <field name="data_kind"/>
979+ <newline/>
980+ <field name="description"/>
981+ <separator colspan="4"/>
982+ <footer>
983+ <button icon="gtk-cancel" string="Cancel" special="cancel"/>
984+ <button string="Continue" name="inter_call" type="object" icon="gtk-ok"/>
985+ </footer>
986+ </group>
987+ </sheet>
988+ </form>
989+ </field>
990+ </record>
991+
992+ <record id="module_recording_message_view" model="ir.ui.view">
993+ <field name="name">module_recording_message</field>
994+ <field name="model">base.module.record.objects</field>
995+ <field name="arch" type="xml">
996+ <form string="Module Recording" version="7.0">
997+ <sheet>
998+ <label string="Thanks For using Module Recorder" colspan="4" align="0.0"/>
999+ <separator string="" colspan="4"/>
1000+ <footer>
1001+ <button icon="gtk-ok" string="OK" special="cancel"/>
1002+ </footer>
1003+ </sheet>
1004+ </form>
1005+ </field>
1006+ </record>
1007+
1008+ <record id="yml_save_form_view" model="ir.ui.view">
1009+ <field name="name">yml.save.form</field>
1010+ <field name="model">base.module.record.objects</field>
1011+ <field name="arch" type="xml">
1012+ <form string="Module Recording" version="7.0">
1013+ <sheet>
1014+ <separator string="YAML file successfully created !" colspan="4"/>
1015+ <newline/>
1016+ <field name="yaml_file" filename="module_filename"/>
1017+ <separator colspan="4"/>
1018+ <footer>
1019+ <button icon="gtk-close" string="Close" special="cancel"/>
1020+ </footer>
1021+ </sheet>
1022+ </form>
1023+ </field>
1024+ </record>
1025+
1026+ </data>
1027+</openerp>
1028
1029=== added file 'base_module_record/wizard/base_module_record_objects.py'
1030--- base_module_record/wizard/base_module_record_objects.py 1970-01-01 00:00:00 +0000
1031+++ base_module_record/wizard/base_module_record_objects.py 2013-11-25 18:42:07 +0000
1032@@ -0,0 +1,173 @@
1033+# -*- coding: utf-8 -*-
1034+##############################################################################
1035+#
1036+# OpenERP, Open Source Management Solution
1037+# Copyright (C) 2012-Today Serpent Consulting Services Pvt. Ltd. (<http://www.serpentcs.com>)
1038+#
1039+# This program is free software: you can redistribute it and/or modify
1040+# it under the terms of the GNU Affero General Public License as
1041+# published by the Free Software Foundation, either version 3 of the
1042+# License, or (at your option) any later version.
1043+#
1044+# This program is distributed in the hope that it will be useful,
1045+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1046+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1047+# GNU Affero General Public License for more details.
1048+#
1049+# You should have received a copy of the GNU Affero General Public License
1050+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1051+#
1052+##############################################################################
1053+
1054+from openerp.osv import orm, fields, osv
1055+from openerp import tools
1056+from openerp.tools.translate import _
1057+from . import base_module_save
1058+
1059+import time
1060+
1061+class base_module_record(orm.TransientModel):
1062+ _name = 'base.module.record'
1063+ _description = "Base Module Record"
1064+
1065+ _columns = {
1066+ 'check_date': fields.datetime('Record from Date', required=True),
1067+ 'objects': fields.many2many('ir.model', 'base_module_record_object_rel', 'objects', 'model_id', 'Objects'),
1068+ 'filter_cond': fields.selection([('created', 'Created'), ('modified', 'Modified'), ('created_modified', 'Created & Modified')], 'Records only', required=True),
1069+ 'info_yaml': fields.boolean('YAML'),
1070+ }
1071+
1072+ def _get_default_objects(self, cr, uid, context=None):
1073+ names = ('ir.ui.view', 'ir.ui.menu', 'ir.model', 'ir.model.fields', 'ir.model.access',
1074+ 'res.partner', 'res.partner.address', 'res.partner.category', 'workflow',
1075+ 'workflow.activity', 'workflow.transition', 'ir.actions.server', 'ir.server.object.lines')
1076+ return self.pool.get('ir.model').search(cr, uid, [('model', 'in', names)])
1077+
1078+ _defaults = {
1079+ 'check_date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
1080+ 'objects': _get_default_objects,
1081+ 'filter_cond': 'created',
1082+ }
1083+
1084+ def record_objects(self, cr, uid, ids, context=None):
1085+ data = self.read(cr, uid, ids, [], context=context)[0]
1086+ check_date=data['check_date']
1087+ filter=data['filter_cond']
1088+ user=(self.pool.get('res.users').browse(cr,uid,uid)).login
1089+ mod = self.pool.get('ir.module.record')
1090+ mod_obj = self.pool.get('ir.model')
1091+ mod.recording_data = []
1092+ for id in data['objects']:
1093+ obj_name=(mod_obj.browse(cr,uid,id)).model
1094+ obj_pool=self.pool.get(obj_name)
1095+ if filter =='created':
1096+ search_condition =[('create_date', '>', check_date)]
1097+ elif filter =='modified':
1098+ search_condition =[('write_date', '>', check_date)]
1099+ elif filter =='created_modified':
1100+ search_condition =['|',('create_date', '>', check_date), ('write_date', '>', check_date)]
1101+ if '_log_access' in dir(obj_pool):
1102+ if not (obj_pool._log_access):
1103+ search_condition=[]
1104+ if '_auto' in dir(obj_pool):
1105+ if not obj_pool._auto:
1106+ continue
1107+ search_ids = obj_pool.search(cr,uid,search_condition)
1108+ for s_id in search_ids:
1109+ args=(cr.dbname, uid,obj_name, 'copy', s_id,{},context)
1110+ mod.recording_data.append(('query', args, {}, s_id))
1111+
1112+ mod_obj = self.pool.get('ir.model.data')
1113+ if len(mod.recording_data):
1114+ if data['info_yaml']:
1115+ mod = self.pool.get('ir.module.record')
1116+ res=base_module_save._create_yaml(self, cr, uid, data, context)
1117+ model_data_ids = mod_obj.search(cr, uid,[('model', '=', 'ir.ui.view'), ('name', '=', 'yml_save_form_view')], context=context)
1118+ resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
1119+ return {
1120+ 'name': _('Message'),
1121+ 'context': {'default_yaml_file': tools.ustr(res['yaml_file'])},
1122+ 'view_type': 'form',
1123+ 'view_mode': 'form',
1124+ 'res_model': 'base.module.record.objects',
1125+ 'views': [(resource_id, 'form')],
1126+ 'type': 'ir.actions.act_window',
1127+ 'target': 'new',
1128+ }
1129+ else:
1130+ model_data_ids = mod_obj.search(cr, uid, [('model', '=', 'ir.ui.view'), ('name', '=', 'info_start_form_view')], context=context)
1131+ resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
1132+ return {
1133+ 'name': _('Message'),
1134+ 'context': context,
1135+ 'view_type': 'form',
1136+ 'view_mode': 'form',
1137+ 'res_model': 'base.module.record.objects',
1138+ 'views': [(resource_id, 'form')],
1139+ 'type': 'ir.actions.act_window',
1140+ 'target': 'new',
1141+ }
1142+
1143+ model_data_ids = mod_obj.search(cr, uid, [('model', '=', 'ir.ui.view'), ('name', '=', 'module_recording_message_view')], context=context)
1144+ resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
1145+ return {
1146+ 'name': _('Message'),
1147+ 'context': context,
1148+ 'view_type': 'form',
1149+ 'view_mode': 'form',
1150+ 'res_model': 'base.module.record.objects',
1151+ 'views': [(resource_id, 'form')],
1152+ 'type': 'ir.actions.act_window',
1153+ 'target': 'new',
1154+ }
1155+
1156+base_module_record()
1157+
1158+class base_module_record_objects(orm.TransientModel):
1159+ _name = 'base.module.record.objects'
1160+ _description = "Base Module Record Objects"
1161+
1162+ def inter_call(self,cr,uid,data,context=None):
1163+ res=base_module_save._create_module(self, cr, uid, data, context)
1164+ mod_obj = self.pool.get('ir.model.data')
1165+ model_data_ids = mod_obj.search(cr, uid,[('model', '=', 'ir.ui.view'), ('name', '=', 'module_create_form_view')], context=context)
1166+ resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
1167+ context.update(res)
1168+
1169+ return {
1170+ 'name': _('Message'),
1171+ 'context': {
1172+ 'default_module_filename': tools.ustr(res['module_filename']),
1173+ 'default_module_file': tools.ustr(res['module_file']),
1174+ },
1175+ 'view_type': 'form',
1176+ 'view_mode': 'form',
1177+ 'res_model': 'base.module.record.objects',
1178+ 'views': [(resource_id, 'form')],
1179+ 'type': 'ir.actions.act_window',
1180+ 'target': 'new',
1181+ }
1182+
1183+ _columns = {
1184+ 'name': fields.char('Module Name', size=64, required=True),
1185+ 'directory_name': fields.char('Directory Name', size=32, required=True),
1186+ 'version': fields.char('Version', size=16, required=True),
1187+ 'author': fields.char('Author', size=64, required=True),
1188+ 'category': fields.char('Category', size=64, required=True),
1189+ 'website': fields.char('Documentation URL', size=64, required=True),
1190+ 'description': fields.text('Full Description', required=True),
1191+ 'data_kind': fields.selection([('demo', 'Demo Data'), ('update', 'Normal Data')], 'Type of Data', required=True),
1192+ 'module_file': fields.binary('Module .zip File', filename="module_filename"),
1193+ 'module_filename': fields.char('Filename', size=64),
1194+ 'yaml_file': fields.binary('Module .zip File'),
1195+ }
1196+ _defaults = {
1197+ 'author': 'OpenERP SA',
1198+ 'category': 'Vertical Modules/Parametrization',
1199+ 'website': 'http://www.openerp.com',
1200+ 'data_kind': 'update',
1201+ }
1202+
1203+base_module_record_objects()
1204+
1205+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1206
1207=== added file 'base_module_record/wizard/base_module_save.py'
1208--- base_module_record/wizard/base_module_save.py 1970-01-01 00:00:00 +0000
1209+++ base_module_record/wizard/base_module_save.py 2013-11-25 18:42:07 +0000
1210@@ -0,0 +1,170 @@
1211+# -*- coding: utf-8 -*-
1212+##############################################################################
1213+#
1214+# OpenERP, Open Source Management Solution
1215+# Copyright (C) 2012-Today Serpent Consulting Services Pvt. Ltd. (<http://www.serpentcs.com>)
1216+#
1217+# This program is free software: you can redistribute it and/or modify
1218+# it under the terms of the GNU Affero General Public License as
1219+# published by the Free Software Foundation, either version 3 of the
1220+# License, or (at your option) any later version.
1221+#
1222+# This program is distributed in the hope that it will be useful,
1223+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1224+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1225+# GNU Affero General Public License for more details.
1226+#
1227+# You should have received a copy of the GNU Affero General Public License
1228+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1229+#
1230+##############################################################################
1231+
1232+import zipfile
1233+import StringIO
1234+import base64
1235+
1236+from openerp import tools
1237+from openerp.tools.translate import _
1238+from openerp.osv import orm, fields, osv
1239+
1240+
1241+def _create_yaml(self, cr, uid, data, context=None):
1242+ mod = self.pool.get('ir.module.record')
1243+ try:
1244+ res_xml = mod.generate_yaml(cr, uid)
1245+ except Exception, e:
1246+ raise osv.except_osv(_('Error'),_(str(e)))
1247+ return {
1248+ 'yaml_file': base64.encodestring(res_xml),
1249+}
1250+
1251+def _create_module(self, cr, uid, ids, context=None):
1252+ mod = self.pool.get('ir.module.record')
1253+ res_xml = mod.generate_xml(cr, uid)
1254+ data = self.read(cr, uid, ids, [], context=context)[0]
1255+ s = StringIO.StringIO()
1256+ zip = zipfile.ZipFile(s, 'w')
1257+ dname = data['directory_name']
1258+ data['update_name'] = ''
1259+ data['demo_name'] = ''
1260+ if ['data_kind'] =='demo':
1261+ data['demo_name'] = '"%(directory_name)s_data.xml"' % data
1262+ else:
1263+ data['update_name'] = '"%(directory_name)s_data.xml"' % data
1264+ data['depends'] = ','.join(map(lambda x: '"'+x+'"', mod.depends.keys()))
1265+ _terp = """{
1266+ "name" : "%(name)s",
1267+ "version" : "%(version)s",
1268+ "author" : "%(author)s",
1269+ "website" : "%(website)s",
1270+ "category" : "%(category)s",
1271+ "description": \"\"\"%(description)s\"\"\",
1272+ "depends" : [%(depends)s],
1273+ "init_xml" : [ ],
1274+ "demo_xml" : [ %(demo_name)s],
1275+ "update_xml" : [%(update_name)s],
1276+ "installable": True
1277+} """ % data
1278+ filewrite = {
1279+ '__init__.py':'#\n# Generated by the OpenERP module recorder !\n#\n',
1280+ '__openerp__.py':_terp,
1281+ dname+'_data.xml': res_xml
1282+ }
1283+ for name,datastr in filewrite.items():
1284+ info = zipfile.ZipInfo(dname+'/'+name)
1285+ info.compress_type = zipfile.ZIP_DEFLATED
1286+ info.external_attr = 2175008768
1287+ if not datastr:
1288+ datastr = ''
1289+ zip.writestr(info, datastr)
1290+ zip.close()
1291+ return {
1292+ 'module_file': base64.encodestring(s.getvalue()),
1293+ 'module_filename': data['directory_name']+'-'+data['version']+'.zip'
1294+ }
1295+
1296+class base_module_save(orm.TransientModel):
1297+ _name = 'base.module.save'
1298+ _description = "Base Module Save"
1299+
1300+ def default_get(self, cr, uid, fields, context=None):
1301+ mod = self.pool.get('ir.module.record')
1302+ result = {}
1303+ info = "Details of "+str(len(mod.recording_data))+" Operation(s):\n\n"
1304+ res = super(base_module_save, self).default_get(cr, uid, fields, context=context)
1305+ for line in mod.recording_data:
1306+ result.setdefault(line[0],{})
1307+ result[line[0]].setdefault(line[1][3], {})
1308+ result[line[0]][line[1][3]].setdefault(line[1][3], 0)
1309+ result[line[0]][line[1][3]][line[1][3]]+=1
1310+ for key1,val1 in result.items():
1311+ info+=key1+"\n"
1312+ for key2,val2 in val1.items():
1313+ info+="\t"+key2+"\n"
1314+ for key3,val3 in val2.items():
1315+ info+="\t\t"+key3+" : "+str(val3)+"\n"
1316+ if 'info_text' in fields:
1317+ res.update({'info_text': info})
1318+ if 'info_status' in fields:
1319+ info_status = mod.recording and 'record' or 'no'
1320+ res.update({'info_status': info_status})
1321+ return res
1322+
1323+ _columns = {
1324+ 'info_text': fields.text('Information', readonly=True),
1325+ 'info_status': fields.selection([('no', 'Not Recording'),('record', 'Recording')], 'Status', readonly=True),
1326+ 'info_yaml': fields.boolean('YAML'),
1327+ }
1328+
1329+ def record_save(self, cr, uid, ids, context=None):
1330+ data = self.read(cr, uid, ids, [], context=context)[0]
1331+ mod = self.pool.get('ir.module.record')
1332+ mod_obj = self.pool.get('ir.model.data')
1333+ if len(mod.recording_data):
1334+ if data['info_yaml']:
1335+ mod = self.pool.get('ir.module.record')
1336+ res=_create_yaml(self, cr, uid, data, context)
1337+ model_data_ids = mod_obj.search(cr, uid,[('model', '=', 'ir.ui.view'), ('name', '=', 'yml_save_form_view')], context=context)
1338+ resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
1339+ return {
1340+ 'name': _('Message'),
1341+ 'context': {
1342+ 'default_yaml_file': tools.ustr(res['yaml_file']),
1343+ },
1344+ 'view_type': 'form',
1345+ 'view_mode': 'form',
1346+ 'res_model': 'base.module.record.objects',
1347+ 'views': [(resource_id, 'form')],
1348+ 'type': 'ir.actions.act_window',
1349+ 'target': 'new',
1350+ }
1351+ else:
1352+ model_data_ids = mod_obj.search(cr, uid,[('model', '=', 'ir.ui.view'), ('name', '=', 'info_start_form_view')], context=context)
1353+ resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
1354+ return {
1355+ 'name': _('Message'),
1356+ 'context': context,
1357+ 'view_type': 'form',
1358+ 'view_mode': 'form',
1359+ 'res_model': 'base.module.record.objects',
1360+ 'views': [(resource_id, 'form')],
1361+ 'type': 'ir.actions.act_window',
1362+ 'target': 'new',
1363+ }
1364+ model_data_ids = mod_obj.search(cr, uid,[('model', '=', 'ir.ui.view'), ('name', '=', 'module_recording_message_view')], context=context)
1365+ resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
1366+
1367+ return {
1368+ 'name': _('Message'),
1369+ 'context': context,
1370+ 'view_type': 'form',
1371+ 'view_mode': 'form',
1372+ 'res_model': 'base.module.record.objects',
1373+ 'views': [(resource_id, 'form')],
1374+ 'type': 'ir.actions.act_window',
1375+ 'target': 'new',
1376+ }
1377+
1378+base_module_save()
1379+
1380+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1381\ No newline at end of file
1382
1383=== added file 'base_module_record/wizard/base_module_save_view.xml'
1384--- base_module_record/wizard/base_module_save_view.xml 1970-01-01 00:00:00 +0000
1385+++ base_module_record/wizard/base_module_save_view.xml 2013-11-25 18:42:07 +0000
1386@@ -0,0 +1,51 @@
1387+<?xml version="1.0" encoding="utf-8"?>
1388+<openerp>
1389+ <data>
1390+
1391+ <record id="base_module_save_view" model="ir.ui.view">
1392+ <field name="name">base_module_save</field>
1393+ <field name="model">base.module.save</field>
1394+ <field name="arch" type="xml">
1395+ <form string="Module Recording" version="7.0">
1396+ <sheet>
1397+ <separator string="Recording Information" colspan="4"/>
1398+ <field name="info_status"/>
1399+ <field name="info_text" colspan="4" nolabel="1"/>
1400+ <field name="info_yaml" colspan="4"/>
1401+ <separator colspan="4"/>
1402+ <group colspan="4" col="2">
1403+ <button icon="gtk-cancel" string="Cancel" special="cancel"/>
1404+ <button name="record_save" icon="gtk-ok" string="Continue" type="object"/>
1405+ </group>
1406+ </sheet>
1407+ </form>
1408+ </field>
1409+ </record>
1410+
1411+ <record model="ir.actions.act_window" id="action_base_module_save">
1412+ <field name="name">Publish as module</field>
1413+ <field name="res_model">base.module.save</field>
1414+ <field name="view_type">form</field>
1415+ <field name="view_mode">form</field>
1416+ <field name="target">new</field>
1417+ <field name="view_id" ref="base_module_save_view"/>
1418+ </record>
1419+
1420+ <menuitem
1421+ parent="menu_wizard_base_mod_rec"
1422+ name="Publish as Module"
1423+ action="action_base_module_save"
1424+ id="menu_wizard_base_module_save"/>
1425+
1426+ <act_window
1427+ id="act_base_module_save"
1428+ name="Publish as Module"
1429+ res_model="base.module.save"
1430+ src_model="ir.module.module"
1431+ view_mode="form"
1432+ target="new"
1433+ multi="True"
1434+ key2="client_action_multi"/>
1435+
1436+ </data>
1437+</openerp>