Merge lp:~serpentcs/server-env-tools/base_module_record into lp:~server-env-tools-core-editors/server-env-tools/7.0
- base_module_record
- Merge into 7.0
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexandre Fayolle - camptocamp | code review, no tests | Needs Fixing | |
Yannick Vaucher @ Camptocamp | Abstain | ||
Raphaël Valyi - http://www.akretion.com | Abstain | ||
Sylvain LE GAL (GRAP) (community) | module used, no code review | Approve | |
Stefan Rijnhart (Opener) | Needs Information | ||
Pedro Manuel Baeza | Disapprove | ||
Joël Grand-Guillaume @ camptocamp | code review, no tests | Disapprove | |
Review via email: mp+196613@code.launchpad.net |
Commit message
Description of the change
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : | # |
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.
Serpent Consulting Services (serpent-consulting-services) wrote : | # |
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.
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
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.
Serpent Consulting Services (serpent-consulting-services) wrote : | # |
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!
Sylvain LE GAL (GRAP) (sylvain-legal) wrote : | # |
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://
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.
Raphaël Valyi - http://www.akretion.com (rvalyi) wrote : | # |
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.
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote : | # |
Never used that module
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
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.
Unmerged revisions
- 54. By Serpent Consulting Services
-
Base_module_record v7 compatible
; - 53. By Serpent Consulting Services
-
Merged with Parent
- 52. By Vacha Trivedi(SerpentCS)
-
[IMP] base_module_record : Improvments for v7 compatiblebase_
module_ record as av7 compatible module - 51. By Serpent Consulting Services
-
[ADD] Added base_module_record as av7 compatible module
Preview Diff
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' |
608 | Binary 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' |
610 | Binary 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' |
612 | Binary 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> |
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