Merge lp:~openerp-community/server-env-tools/6.1-mass_editing into lp:~server-env-tools-core-editors/server-env-tools/6.1
- 6.1-mass_editing
- Merge into 6.1
Status: | Merged |
---|---|
Approved by: | Sandy Carter (http://www.savoirfairelinux.com) |
Approved revision: | 53 |
Merged at revision: | 45 |
Proposed branch: | lp:~openerp-community/server-env-tools/6.1-mass_editing |
Merge into: | lp:~server-env-tools-core-editors/server-env-tools/6.1 |
Diff against target: |
570 lines (+526/-0) 8 files modified
mass_editing/__init__.py (+27/-0) mass_editing/__openerp__.py (+47/-0) mass_editing/i18n/mass_editing.pot (+118/-0) mass_editing/mass_editing.py (+105/-0) mass_editing/mass_editing_view.xml (+73/-0) mass_editing/security/ir.model.access.csv (+2/-0) mass_editing/wizard/__init__.py (+25/-0) mass_editing/wizard/mass_editing_wizard.py (+129/-0) |
To merge this branch: | bzr merge lp:~openerp-community/server-env-tools/6.1-mass_editing |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Stefan Rijnhart (Opener) | Approve | ||
Sandy Carter (http://www.savoirfairelinux.com) | Approve | ||
Joël Grand-Guillaume @ camptocamp | code review, no test | Approve | |
Review via email: mp+161619@code.launchpad.net |
Commit message
Description of the change
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : | # |
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
Please stop merging so fast.
If this is a submit of the current state of affairs on 7.0, there were all kinds of problems with it. See my review there. Serpent never addressed my comments directly but updated the branch periodically. I believe it has improved in certain aspects, but it was never resubmitted.
This version needs to be audited against my objections. I was going to do it myself today or tomorrow but now I was not given the chance. Please uncommit.
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) wrote : | # |
Merge uncommited and MP reopened.
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
My review is a bit compact but feel free to discuss anything that you disagree about.
l. 128 e.a. Please replace the whole stringified ID list thing by a regular many2many field. Adapt onchange_model to return just a list of ids. Replace the eval'ed string clause in the domain by model_ids[0][2], because you will find the representation of the many2many field in the regular [(6, 0, [1,2,3])] notation.
l.131 In the onchange method, clear the list of selected fields if the model really changes (or make the model unchangeable after saving for the first time), just to prevent mixing fields from several unrelated models.
l. 150: do not loop but deal with first ID. Line 171 is not robust against handling multiple resources anyway (or put the write in the loop of course!)
l. 213 spelling error 'refenrence' -> 'reference'
l. 215 spelling error 'Advance' -> 'Advanced'
l. 227 Please allow only read access to every users and CRUD only to an administrator group
l. 368 and all other occurences: take this line out of the loop, call fields_get only once with a list of all relevant fields as its argument as it gets called in all code paths inside the loop and sometimes even twice (l.389/391)
l. 369 and other assignments of all_fields[
l. 370 and further: the use of the prefix 'selection_' can lead to a namespace clash relatively easily. Use one or two leading underscores to avoid that. Maybe use a constant in case it needs changing again.
l. 377 remove this condition if it looks as random to you as it does to me
l. 350 This module actually displays the Serpent company logo in every wizard. As we agreed for community projects that module names should not contain company names, I feel that this should not be accepted either, or I want my logo in their too given the time that I spent reviewing this module by now.
l. 431 Dataloss issue with many2many fields. You think you select a single item for removal but you clear the whole field. The 7.0 version of this branch seems to have fixed this one at least.
All the regular style conventions and deprecated API stuff applies but I think the above is more important.
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) wrote : | # |
@Jay
Do you want me to fix it or you fix it yourself ?
Thanks.
Serpent Consulting Services (serpent-consulting-services) wrote : | # |
If I am not wrong, only 2 or 3 points remain to be fixed. You can take a look at our v7 merge proposal.
You can use the latest code from that branch.
I dont want you to waste time on fixing the thigs we alrready fixed. Rather I want you to suggest things we can improve, or you yourself can do the necessary improvements.
With all respect towards you,
Serpent Consulting Services.
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) wrote : | # |
Then we will wait for the merge in v7 to backport it to 6.1.
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
To be honest, I was hoping to speed up the process if someone else started to work on it. The V7 of this branch only fixes the data loss issue and the typos, so the majority of the issues still stand.
Virgil Dupras (hsoft) wrote : | # |
I began tackling Stephan's list of issues, starting with the first one (using a m2m field instead of a serialized ID list). It's in commit #40 which I have just pushed.
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
Hi Virgil,
that change is very welcome. However, you may want to discard this proposal and start out with a backport of the version 7 of this module (just need to remove a little bit of 7.0 specific view stuff I think). It has evolved rather well recently. https:/
Virgil Dupras (hsoft) wrote : | # |
Two similar MPs in parallel like that creates a somewhat complicated situation (in the 7.0 MP, mass_object.
So I guessing that the best way to proceed would be to work on getting the 7.0 branch approved, and only then backport it.
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
Good idea, and thanks again for picking this up!
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) wrote : | # |
Hello,
I understand it is now time to backport what has been merged in 7.0 branch.
Can someone confirm ?
thanks
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
Hi Maxime,
first of all, the branch is borked and cannot be merged with the 6.1 series of the project without the conflict mentioned at the top of this page. You could try crafting a new branch with the module directory from this one. As a result, I cannot refer to line numbers in the (incomplete) diff.
About the module in 7.0: I was pretty happy with how it looked at merge time. I compared its code with the code in this branch. Changes from it that you should probably include here:
7.0 removes its act window and ir value upon unlinking. The code is present in 6.1 but it is not called.
6.1 still contains the typo 'refenrence'. In the same line, it still excludes field type 'one2many'. The 7.0 does not exclude it anymore (although I am still a bit dubious about that but I haven't tested).
6.1 still contains typo 'Advance' in the page view element. Change to Advanced
6.1: permissions on mass.object for group_users are too wide. Set to readonly (1,0,0,0)
6.1 still contains the Serpent logo. 7.0 does not
6.1 still contains the bug causing data loss in the case of attempting to remove a *selection* of m2m items
Changes not to include:
The 7.0 still contains the (by now unnecessary) unguided override of ir.model.
- 43. By Maxime Chambreuil (http://www.savoirfairelinux.com)
-
[IMP] Backporting v7 fixes
- 44. By Maxime Chambreuil (http://www.savoirfairelinux.com)
-
[ADD] Translation file
- 45. By Maxime Chambreuil (http://www.savoirfairelinux.com)
-
[MRG] Solving conflicts
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) wrote : | # |
Hi Stefan,
Thanks for the review.
unlink_action is used in the view (l345).
Typo fixed. 'one2many' removed from the exclude list.
Typo fixed.
Permissions fixed.
Logo removed from the wizard.
Data loss bug not fixed yet.
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
Hi Maxime,
Thanks. Don't you need to call unlink_action in the model's unlink() method to prevent dangling act_windows? The dataloss is easy to fix, just apply the (3, id) directive to remove specific items.
- 46. By Maxime Chambreuil (http://www.savoirfairelinux.com)
-
[FIX] Call unlink_action in the model's unlink() method
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
I received a resubmit in my mail, meaning that you put the status of this MP to 'Needs review', but the dataloss issue has not yet been resolved.
- 47. By Stefan Rijnhart (Opener)
-
[FIX] Data loss - removing a set of m2m actually removes all
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
I'm proposing the long awaited change (AFAIK) to this branch here: https:/
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
or rather: AFAIC
Sandy Carter (http://www.savoirfairelinux.com) (sandy-carter) wrote : | # |
@Stefan, could you please explain the dataloss issue in this frame, I don't quite understand.
How does the branch you propose come into play here?
- 48. By Stefan Rijnhart (Opener)
-
[IMP] Don't use a reserved word for a variable name
- 49. By Stefan Rijnhart (Opener)
-
[IMP] Use a more descriptive variable name for the model field name
- 50. By Stefan Rijnhart (Opener)
-
[FIX] Don't allow for iterating over False
- 51. By Stefan Rijnhart (Opener)
-
[RFR] Don't update() dictionaries with only a single key
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
l.550: when the user makes a selection of m2m values to remove, the code executes a [(5, 0, [])]. This removes all values. My branch executes a [(3, value) for each value].
- 52. By Stefan Rijnhart (Opener)
-
[FIX] Pep8 in the affected code
- 53. By Stefan Rijnhart (Opener)
-
[RFR] Remove redundant get()
Sandy Carter (http://www.savoirfairelinux.com) (sandy-carter) : | # |
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
Thanks for taking my suggestions!
debaetsr (rubendebaets) wrote : | # |
Hello,
I've found a lot of interesting stuff that you might like, just take a look <http://
Very truly yours, ruben
Preview Diff
1 | === added directory 'mass_editing' |
2 | === added file 'mass_editing/__init__.py' |
3 | --- mass_editing/__init__.py 1970-01-01 00:00:00 +0000 |
4 | +++ mass_editing/__init__.py 2014-03-19 13:59:44 +0000 |
5 | @@ -0,0 +1,27 @@ |
6 | +# -*- coding: utf-8 -*- |
7 | +############################################################################## |
8 | +# |
9 | +# OpenERP, Open Source Management Solution |
10 | +# Copyright (C) 2012 Serpent Consulting Services (<http://www.serpentcs.com>) |
11 | +# Copyright (C) 2010-Today OpenERP SA (<http://www.openerp.com>) |
12 | +# |
13 | +# This program is free software: you can redistribute it and/or modify |
14 | +# it under the terms of the GNU General Public License as published by |
15 | +# the Free Software Foundation, either version 3 of the License, or |
16 | +# (at your option) any later version. |
17 | +# |
18 | +# This program is distributed in the hope that it will be useful, |
19 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | +# GNU General Public License for more details. |
22 | +# |
23 | +# You should have received a copy of the GNU General Public License |
24 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
25 | +# |
26 | +############################################################################## |
27 | + |
28 | +import mass_editing |
29 | +import wizard |
30 | + |
31 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
32 | + |
33 | |
34 | === added file 'mass_editing/__openerp__.py' |
35 | --- mass_editing/__openerp__.py 1970-01-01 00:00:00 +0000 |
36 | +++ mass_editing/__openerp__.py 2014-03-19 13:59:44 +0000 |
37 | @@ -0,0 +1,47 @@ |
38 | +# -*- coding: utf-8 -*- |
39 | +############################################################################## |
40 | +# |
41 | +# OpenERP, Open Source Management Solution |
42 | +# Copyright (C) 2012 Serpent Consulting Services (<http://www.serpentcs.com>) |
43 | +# Copyright (C) 2010-Today OpenERP SA (<http://www.openerp.com>) |
44 | +# |
45 | +# This program is free software: you can redistribute it and/or modify |
46 | +# it under the terms of the GNU General Public License as published by |
47 | +# the Free Software Foundation, either version 3 of the License, or |
48 | +# (at your option) any later version. |
49 | +# |
50 | +# This program is distributed in the hope that it will be useful, |
51 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
52 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
53 | +# GNU General Public License for more details. |
54 | +# |
55 | +# You should have received a copy of the GNU General Public License |
56 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
57 | +# |
58 | +############################################################################## |
59 | + |
60 | + |
61 | +{ |
62 | + "name" : "Mass Editing", |
63 | + "version" : "1.1", |
64 | + "author" : "Serpent Consulting Services", |
65 | + "category" : "Tools", |
66 | + "website" : "http://www.serpentcs.com", |
67 | + "description": """This module provides the functionality to add, update or remove the values of more than one records on the fly at the same time. |
68 | + You can configure mass editing for any OpenERP model. |
69 | + The video explaining the feature is available at http://t.co/wukYMx1A |
70 | + The menu is now Under Settings/Configuration. |
71 | + For more details/customization/feedback contact us on contact@serpentcs.com. |
72 | + """, |
73 | + 'depends': ['base'], |
74 | + 'init_xml': [], |
75 | + 'update_xml': [ |
76 | + "security/ir.model.access.csv", |
77 | + 'mass_editing_view.xml', |
78 | + ], |
79 | + 'installable': True, |
80 | + 'application': True, |
81 | + 'auto_install': False, |
82 | +} |
83 | + |
84 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
85 | |
86 | === added directory 'mass_editing/i18n' |
87 | === added file 'mass_editing/i18n/mass_editing.pot' |
88 | --- mass_editing/i18n/mass_editing.pot 1970-01-01 00:00:00 +0000 |
89 | +++ mass_editing/i18n/mass_editing.pot 2014-03-19 13:59:44 +0000 |
90 | @@ -0,0 +1,118 @@ |
91 | +# Translation of OpenERP Server. |
92 | +# This file contains the translation of the following modules: |
93 | +# * mass_editing |
94 | +# |
95 | +msgid "" |
96 | +msgstr "" |
97 | +"Project-Id-Version: OpenERP Server 6.1\n" |
98 | +"Report-Msgid-Bugs-To: \n" |
99 | +"POT-Creation-Date: 2013-08-20 03:41+0000\n" |
100 | +"PO-Revision-Date: 2013-08-20 03:41+0000\n" |
101 | +"Last-Translator: <>\n" |
102 | +"Language-Team: \n" |
103 | +"MIME-Version: 1.0\n" |
104 | +"Content-Type: text/plain; charset=UTF-8\n" |
105 | +"Content-Transfer-Encoding: \n" |
106 | +"Plural-Forms: \n" |
107 | + |
108 | +#. module: mass_editing |
109 | +#: model:ir.actions.act_window,name:mass_editing.action_mass_object_form |
110 | +#: model:ir.ui.menu,name:mass_editing.menu_mass_editing |
111 | +#: model:ir.ui.menu,name:mass_editing.menu_mass_object_view |
112 | +msgid "Mass Editing" |
113 | +msgstr "" |
114 | + |
115 | +#. module: mass_editing |
116 | +#: view:mass.object:0 |
117 | +msgid "Display a button in the sidebar of related documents to open a composition wizard" |
118 | +msgstr "" |
119 | + |
120 | +#. module: mass_editing |
121 | +#: model:ir.model,name:mass_editing.model_mass_editing_wizard |
122 | +msgid "mass.editing.wizard" |
123 | +msgstr "" |
124 | + |
125 | +#. module: mass_editing |
126 | +#: field:mass.object,name:0 |
127 | +msgid "Name" |
128 | +msgstr "" |
129 | + |
130 | +#. module: mass_editing |
131 | +#: code:addons/mass_editing/mass_editing.py:96 |
132 | +#, python-format |
133 | +msgid "Deletion of the action record failed." |
134 | +msgstr "" |
135 | + |
136 | +#. module: mass_editing |
137 | +#: view:mass.object:0 |
138 | +#: field:mass.object,field_ids:0 |
139 | +msgid "Fields" |
140 | +msgstr "" |
141 | + |
142 | +#. module: mass_editing |
143 | +#: code:addons/mass_editing/mass_editing.py:62 |
144 | +#, python-format |
145 | +msgid "Mass Editing (%s)" |
146 | +msgstr "" |
147 | + |
148 | +#. module: mass_editing |
149 | +#: view:mass.object:0 |
150 | +msgid "Object" |
151 | +msgstr "" |
152 | + |
153 | +#. module: mass_editing |
154 | +#: help:mass.object,ref_ir_act_window:0 |
155 | +msgid "Sidebar action to make this template available on records of the related document model" |
156 | +msgstr "" |
157 | + |
158 | +#. module: mass_editing |
159 | +#: model:ir.model,name:mass_editing.model_mass_object |
160 | +msgid "mass.object" |
161 | +msgstr "" |
162 | + |
163 | +#. module: mass_editing |
164 | +#: field:mass.object,model_ids:0 |
165 | +msgid "Model List" |
166 | +msgstr "" |
167 | + |
168 | +#. module: mass_editing |
169 | +#: code:addons/mass_editing/mass_editing.py:96 |
170 | +#, python-format |
171 | +msgid "Warning" |
172 | +msgstr "" |
173 | + |
174 | +#. module: mass_editing |
175 | +#: field:mass.object,ref_ir_act_window:0 |
176 | +msgid "Sidebar action" |
177 | +msgstr "" |
178 | + |
179 | +#. module: mass_editing |
180 | +#: view:mass.object:0 |
181 | +msgid "Remove sidebar button" |
182 | +msgstr "" |
183 | + |
184 | +#. module: mass_editing |
185 | +#: field:mass.object,ref_ir_value:0 |
186 | +msgid "Sidebar button" |
187 | +msgstr "" |
188 | + |
189 | +#. module: mass_editing |
190 | +#: field:mass.object,model_id:0 |
191 | +msgid "Model" |
192 | +msgstr "" |
193 | + |
194 | +#. module: mass_editing |
195 | +#: view:mass.object:0 |
196 | +msgid "Add sidebar button" |
197 | +msgstr "" |
198 | + |
199 | +#. module: mass_editing |
200 | +#: view:mass.object:0 |
201 | +msgid "Advanced" |
202 | +msgstr "" |
203 | + |
204 | +#. module: mass_editing |
205 | +#: help:mass.object,ref_ir_value:0 |
206 | +msgid "Sidebar button to open the sidebar action" |
207 | +msgstr "" |
208 | + |
209 | |
210 | === added file 'mass_editing/mass_editing.py' |
211 | --- mass_editing/mass_editing.py 1970-01-01 00:00:00 +0000 |
212 | +++ mass_editing/mass_editing.py 2014-03-19 13:59:44 +0000 |
213 | @@ -0,0 +1,105 @@ |
214 | +# -*- coding: utf-8 -*- |
215 | +############################################################################## |
216 | +# |
217 | +# OpenERP, Open Source Management Solution |
218 | +# Copyright (C) 2012 Serpent Consulting Services (<http://www.serpentcs.com>) |
219 | +# Copyright (C) 2010-Today OpenERP SA (<http://www.openerp.com>) |
220 | +# |
221 | +# This program is free software: you can redistribute it and/or modify |
222 | +# it under the terms of the GNU General Public License as published by |
223 | +# the Free Software Foundation, either version 3 of the License, or |
224 | +# (at your option) any later version. |
225 | +# |
226 | +# This program is distributed in the hope that it will be useful, |
227 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
228 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
229 | +# GNU General Public License for more details. |
230 | +# |
231 | +# You should have received a copy of the GNU General Public License |
232 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
233 | +# |
234 | +############################################################################## |
235 | + |
236 | + |
237 | +from osv import fields, osv |
238 | +from tools.translate import _ |
239 | + |
240 | +class mass_object(osv.osv): |
241 | + _name = "mass.object" |
242 | + |
243 | + _columns = { |
244 | + 'name' : fields.char("Name", size=64, required=True, select=1), |
245 | + 'model_id' : fields.many2one('ir.model', 'Model', required=True, select=1), |
246 | + 'field_ids' : fields.many2many('ir.model.fields', 'mass_field_rel', 'mass_id', 'field_id', 'Fields'), |
247 | + 'ref_ir_act_window':fields.many2one('ir.actions.act_window', 'Sidebar action', readonly=True, |
248 | + help="Sidebar action to make this template available on records " |
249 | + "of the related document model"), |
250 | + 'ref_ir_value':fields.many2one('ir.values', 'Sidebar button', readonly=True, |
251 | + help="Sidebar button to open the sidebar action"), |
252 | + 'model_ids': fields.many2many('ir.model', string='Model List') |
253 | + } |
254 | + |
255 | + def onchange_model(self, cr, uid, ids, model_id): |
256 | + model_ids = [] |
257 | + if model_id: |
258 | + model_obj = self.pool.get('ir.model') |
259 | + model_data = model_obj.browse(cr, uid, model_id) |
260 | + model_ids = [model_id] |
261 | + active_model_obj = self.pool.get(model_data.model) |
262 | + if active_model_obj._inherits: |
263 | + for key, val in active_model_obj._inherits.items(): |
264 | + found_model_ids = model_obj.search(cr, uid, [('model', '=', key)]) |
265 | + if found_model_ids: |
266 | + model_ids.append(found_model_ids[0]) |
267 | + return {'value': {'model_ids': [(6, 0, model_ids)]}} |
268 | + |
269 | + def create_action(self, cr, uid, ids, context=None): |
270 | + vals = {} |
271 | + action_obj = self.pool.get('ir.actions.act_window') |
272 | + data_obj = self.pool.get('ir.model.data') |
273 | + for data in self.browse(cr, uid, ids, context=context): |
274 | + src_obj = data.model_id.model |
275 | + button_name = _('Mass Editing (%s)') % data.name |
276 | + vals['ref_ir_act_window'] = action_obj.create(cr, uid, { |
277 | + 'name': button_name, |
278 | + 'type': 'ir.actions.act_window', |
279 | + 'res_model': 'mass.editing.wizard', |
280 | + 'src_model': src_obj, |
281 | + 'view_type': 'form', |
282 | + 'context': "{'mass_editing_object' : %d}" % (data.id), |
283 | + 'view_mode':'form,tree', |
284 | + 'target': 'new', |
285 | + 'auto_refresh':1 |
286 | + }, context) |
287 | + vals['ref_ir_value'] = self.pool.get('ir.values').create(cr, uid, { |
288 | + 'name': button_name, |
289 | + 'model': src_obj, |
290 | + 'key2': 'client_action_multi', |
291 | + 'value': "ir.actions.act_window," + str(vals['ref_ir_act_window']), |
292 | + 'object': True, |
293 | + }, context) |
294 | + self.write(cr, uid, ids, { |
295 | + 'ref_ir_act_window': vals.get('ref_ir_act_window',False), |
296 | + 'ref_ir_value': vals.get('ref_ir_value',False), |
297 | + }, context) |
298 | + return True |
299 | + |
300 | + def unlink_action(self, cr, uid, ids, context=None): |
301 | + for template in self.browse(cr, uid, ids, context=context): |
302 | + try: |
303 | + if template.ref_ir_act_window: |
304 | + self.pool.get('ir.actions.act_window').unlink(cr, uid, template.ref_ir_act_window.id, context) |
305 | + if template.ref_ir_value: |
306 | + ir_values_obj = self.pool.get('ir.values') |
307 | + ir_values_obj.unlink(cr, uid, template.ref_ir_value.id, context) |
308 | + except: |
309 | + raise osv.except_osv(_("Warning"), _("Deletion of the action record failed.")) |
310 | + return True |
311 | + |
312 | + def unlink(self, cr, uid, ids, context=None): |
313 | + self.unlink_action(cr, uid, ids, context) |
314 | + return super(mass_object, self).unlink(cr, uid, ids, context) |
315 | + |
316 | +mass_object() |
317 | + |
318 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
319 | |
320 | === added file 'mass_editing/mass_editing_view.xml' |
321 | --- mass_editing/mass_editing_view.xml 1970-01-01 00:00:00 +0000 |
322 | +++ mass_editing/mass_editing_view.xml 2014-03-19 13:59:44 +0000 |
323 | @@ -0,0 +1,73 @@ |
324 | +<?xml version="1.0" encoding="UTF-8"?> |
325 | +<openerp> |
326 | + <data> |
327 | + |
328 | + <record model="ir.ui.view" id="view_mass_object_form"> |
329 | + <field name="name">mass.object.form</field> |
330 | + <field name="model">mass.object</field> |
331 | + <field name="type">form</field> |
332 | + <field name="arch" type="xml"> |
333 | + <form string="Object"> |
334 | + <field name="name"/> |
335 | + <field name="model_id" on_change="onchange_model(model_id)"/> |
336 | + <field name="model_ids" invisible="1"/> |
337 | + <notebook colspan="4"> |
338 | + <page string="Fields"> |
339 | + <field name="field_ids" colspan="4" nolabel="1" |
340 | + domain="[('ttype', 'not in', ['reference','function']), ('model_id', 'in', model_ids[0][2])]"/> |
341 | + </page> |
342 | + <page string="Advanced"> |
343 | + <group colspan="2" col="2"> |
344 | + <button name="create_action" string="Add sidebar button" type="object" icon="gtk-execute" |
345 | + colspan="2" attrs="{'invisible':[('ref_ir_act_window','!=',False)]}" |
346 | + help="Display a button in the sidebar of related documents to open a composition wizard"/> |
347 | + <field name="ref_ir_act_window" attrs="{'invisible':[('ref_ir_act_window','=',False)]}"/> |
348 | + <field name="ref_ir_value" attrs="{'invisible':[('ref_ir_act_window','=',False)]}"/> |
349 | + <button name="unlink_action" string="Remove sidebar button" type="object" icon="gtk-delete" |
350 | + attrs="{'invisible':[('ref_ir_act_window','=',False)]}" colspan="2" /> |
351 | + </group> |
352 | + </page> |
353 | + </notebook> |
354 | + </form> |
355 | + </field> |
356 | + </record> |
357 | + |
358 | + <record model="ir.ui.view" id="view_mass_object_tree"> |
359 | + <field name="name">mass.object.tree</field> |
360 | + <field name="model">mass.object</field> |
361 | + <field name="type">form</field> |
362 | + <field name="arch" type="xml"> |
363 | + <tree string="Object"> |
364 | + <field name="name"/> |
365 | + <field name="model_id"/> |
366 | + </tree> |
367 | + </field> |
368 | + </record> |
369 | + |
370 | + <record model="ir.actions.act_window" id="action_mass_object_form"> |
371 | + <field name="name">Mass Editing</field> |
372 | + <field name="res_model">mass.object</field> |
373 | + <field name="view_type">form</field> |
374 | + <field name="view_mode">tree,form</field> |
375 | + <field name="view_id" ref="view_mass_object_tree" /> |
376 | + </record> |
377 | + |
378 | + <record id="action_mass_object_form_view1" model="ir.actions.act_window.view"> |
379 | + <field eval="10" name="sequence"/> |
380 | + <field name="view_mode">tree</field> |
381 | + <field name="view_id" ref="view_mass_object_tree"/> |
382 | + <field name="act_window_id" ref="action_mass_object_form"/> |
383 | + </record> |
384 | + <record id="action_mass_object_form_view2" model="ir.actions.act_window.view"> |
385 | + <field eval="20" name="sequence"/> |
386 | + <field name="view_mode">form</field> |
387 | + <field name="view_id" ref="view_mass_object_form"/> |
388 | + <field name="act_window_id" ref="action_mass_object_form"/> |
389 | + </record> |
390 | + |
391 | + <menuitem id="menu_mass_editing" name="Mass Editing" parent="base.menu_config" sequence="6"/> |
392 | + |
393 | + <menuitem id="menu_mass_object_view" action="action_mass_object_form" parent="menu_mass_editing"/> |
394 | + |
395 | + </data> |
396 | +</openerp> |
397 | |
398 | === added directory 'mass_editing/security' |
399 | === added file 'mass_editing/security/ir.model.access.csv' |
400 | --- mass_editing/security/ir.model.access.csv 1970-01-01 00:00:00 +0000 |
401 | +++ mass_editing/security/ir.model.access.csv 2014-03-19 13:59:44 +0000 |
402 | @@ -0,0 +1,2 @@ |
403 | +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" |
404 | +"access_mass_editing_normal_user","mass.editing.normal.user","model_mass_object","base.group_user",1,0,0,0 |
405 | |
406 | === added directory 'mass_editing/wizard' |
407 | === added file 'mass_editing/wizard/__init__.py' |
408 | --- mass_editing/wizard/__init__.py 1970-01-01 00:00:00 +0000 |
409 | +++ mass_editing/wizard/__init__.py 2014-03-19 13:59:44 +0000 |
410 | @@ -0,0 +1,25 @@ |
411 | +# -*- coding: utf-8 -*- |
412 | +############################################################################## |
413 | +# |
414 | +# OpenERP, Open Source Management Solution |
415 | +# Copyright (C) 2012 Serpent Consulting Services (<http://www.serpentcs.com>) |
416 | +# Copyright (C) 2010-Today OpenERP SA (<http://www.openerp.com>) |
417 | +# |
418 | +# This program is free software: you can redistribute it and/or modify |
419 | +# it under the terms of the GNU General Public License as published by |
420 | +# the Free Software Foundation, either version 3 of the License, or |
421 | +# (at your option) any later version. |
422 | +# |
423 | +# This program is distributed in the hope that it will be useful, |
424 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
425 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
426 | +# GNU General Public License for more details. |
427 | +# |
428 | +# You should have received a copy of the GNU General Public License |
429 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
430 | +# |
431 | +############################################################################## |
432 | + |
433 | +import mass_editing_wizard |
434 | + |
435 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
436 | \ No newline at end of file |
437 | |
438 | === added file 'mass_editing/wizard/mass_editing_wizard.py' |
439 | --- mass_editing/wizard/mass_editing_wizard.py 1970-01-01 00:00:00 +0000 |
440 | +++ mass_editing/wizard/mass_editing_wizard.py 2014-03-19 13:59:44 +0000 |
441 | @@ -0,0 +1,129 @@ |
442 | +# -*- coding: utf-8 -*- |
443 | +############################################################################## |
444 | +# |
445 | +# OpenERP, Open Source Management Solution |
446 | +# Copyright (C) 2012 Serpent Consulting Services (<http://www.serpentcs.com>) |
447 | +# Copyright (C) 2010-Today OpenERP SA (<http://www.openerp.com>) |
448 | +# |
449 | +# This program is free software: you can redistribute it and/or modify |
450 | +# it under the terms of the GNU General Public License as published by |
451 | +# the Free Software Foundation, either version 3 of the License, or |
452 | +# (at your option) any later version. |
453 | +# |
454 | +# This program is distributed in the hope that it will be useful, |
455 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
456 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
457 | +# GNU General Public License for more details. |
458 | +# |
459 | +# You should have received a copy of the GNU General Public License |
460 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
461 | +# |
462 | +############################################################################## |
463 | + |
464 | +from osv import osv |
465 | +from osv import fields |
466 | +from lxml import etree |
467 | +import tools |
468 | + |
469 | +class mass_editing_wizard(osv.osv_memory): |
470 | + _name = 'mass.editing.wizard' |
471 | + |
472 | + _columns = { |
473 | + } |
474 | + |
475 | + def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): |
476 | + result = super(mass_editing_wizard, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar,submenu) |
477 | + if context.get('mass_editing_object'): |
478 | + mass_object = self.pool.get('mass.object') |
479 | + editing_data = mass_object.browse(cr, uid, context.get('mass_editing_object'), context) |
480 | + all_fields = {} |
481 | + xml_form = etree.Element('form', {'string': tools.ustr(editing_data.name)}) |
482 | + xml_group = etree.SubElement(xml_form, 'group', {'colspan': '4'}) |
483 | + etree.SubElement(xml_group, 'label', {'string': '','colspan': '2'}) |
484 | + xml_group = etree.SubElement(xml_form, 'group', {'colspan': '4'}) |
485 | + model_obj = self.pool.get(context.get('active_model')) |
486 | + for field in editing_data.field_ids: |
487 | + if field.ttype == "many2many": |
488 | + field_info = model_obj.fields_get(cr, uid, [field.name], context) |
489 | + all_fields[field.name] = field_info[field.name] |
490 | + all_fields["selection_"+field.name] = {'type':'selection', 'string': field_info[field.name]['string'],'selection':[('set','Set'),('remove_m2m','Remove'),('add','Add')]} |
491 | + xml_group = etree.SubElement(xml_group, 'group', {'colspan': '4'}) |
492 | + etree.SubElement(xml_group, 'separator', {'string': field_info[field.name]['string'],'colspan': '2'}) |
493 | + etree.SubElement(xml_group, 'field', {'name': "selection_"+field.name,'colspan': '2','nolabel':'1'}) |
494 | + etree.SubElement(xml_group, 'field', {'name': field.name, 'colspan':'4', 'nolabel':'1', 'attrs':"{'invisible':[('selection_"+field.name+"','=','remove_m2m')]}"}) |
495 | + elif field.ttype == "many2one": |
496 | + field_info = model_obj.fields_get(cr, uid, [field.name], context) |
497 | + if field_info: |
498 | + all_fields["selection_"+field.name] = {'type':'selection', 'string': field_info[field.name]['string'],'selection':[('set','Set'),('remove','Remove')]} |
499 | + all_fields[field.name] = {'type':field.ttype, 'string': field.field_description, 'relation': field.relation} |
500 | + etree.SubElement(xml_group, 'field', {'name': "selection_"+field.name, 'colspan':'2'}) |
501 | + etree.SubElement(xml_group, 'field', {'name': field.name,'nolabel':'1','colspan':'2', 'attrs':"{'invisible':[('selection_"+field.name+"','=','remove')]}"}) |
502 | + elif field.ttype == "char": |
503 | + field_info = model_obj.fields_get(cr, uid, [field.name], context) |
504 | + all_fields["selection_"+field.name] = {'type':'selection', 'string': field_info[field.name]['string'],'selection':[('set','Set'),('remove','Remove')]} |
505 | + all_fields[field.name] = {'type':field.ttype, 'string': field.field_description, 'size': field.size or 256} |
506 | + etree.SubElement(xml_group, 'field', {'name': "selection_"+field.name,'colspan':'2', 'colspan':'2'}) |
507 | + etree.SubElement(xml_group, 'field', {'name': field.name,'nolabel':'1', 'attrs':"{'invisible':[('selection_"+field.name+"','=','remove')]}", 'colspan':'2'}) |
508 | + elif field.ttype == 'selection': |
509 | + field_info = model_obj.fields_get(cr, uid, [field.name], context) |
510 | + all_fields["selection_"+field.name] = {'type':'selection', 'string': field_info[field.name]['string'],'selection':[('set','Set'),('remove','Remove')]} |
511 | + field_info = model_obj.fields_get(cr, uid, [field.name], context) |
512 | + etree.SubElement(xml_group, 'field', {'name': "selection_"+field.name, 'colspan':'2'}) |
513 | + etree.SubElement(xml_group, 'field', {'name': field.name,'nolabel':'1','colspan':'2', 'attrs':"{'invisible':[('selection_"+field.name+"','=','remove')]}"}) |
514 | + all_fields[field.name] = {'type':field.ttype, 'string': field.field_description, 'selection': field_info[field.name]['selection']} |
515 | + else: |
516 | + field_info = model_obj.fields_get(cr, uid, [field.name], context) |
517 | + all_fields[field.name] = {'type':field.ttype, 'string': field.field_description} |
518 | + all_fields["selection_"+field.name] = {'type':'selection', 'string': field_info[field.name]['string'],'selection':[('set','Set'),('remove','Remove')]} |
519 | + if field.ttype == 'text': |
520 | + xml_group = etree.SubElement(xml_group, 'group', {'colspan': '6'}) |
521 | + etree.SubElement(xml_group, 'separator', {'string': all_fields[field.name]['string'],'colspan': '2'}) |
522 | + etree.SubElement(xml_group, 'field', {'name': "selection_"+field.name,'colspan': '2','nolabel':'1'}) |
523 | + etree.SubElement(xml_group, 'field', {'name': field.name, 'colspan':'4', 'nolabel':'1', 'attrs':"{'invisible':[('selection_"+field.name+"','=','remove')]}"}) |
524 | + else: |
525 | + all_fields["selection_"+field.name] = {'type':'selection', 'string': field_info[field.name]['string'],'selection':[('set','Set'),('remove','Remove')]} |
526 | + etree.SubElement(xml_group, 'field', {'name': "selection_"+field.name, 'colspan': '2',}) |
527 | + etree.SubElement(xml_group, 'field', {'name': field.name,'nolabel':'1', 'attrs':"{'invisible':[('selection_"+field.name+"','=','remove')]}",'colspan': '2',}) |
528 | + |
529 | + etree.SubElement(xml_form, 'separator', {'string' : '','colspan': '6'}) |
530 | + xml_group3 = etree.SubElement(xml_form, 'group', {'col': '2', 'colspan': '4'}) |
531 | + etree.SubElement(xml_group3, 'button', {'string' :'Close','icon': "gtk-close", 'special' :'cancel'}) |
532 | + etree.SubElement(xml_group3, 'button', {'string' :'Apply','icon': "gtk-execute", 'type' :'object','name':"action_apply"}) |
533 | + |
534 | + root = xml_form.getroottree() |
535 | + result['arch'] = etree.tostring(root) |
536 | + result['fields'] = all_fields |
537 | + return result |
538 | + |
539 | + def create(self, cr, uid, vals, context=None): |
540 | + if context.get('active_model') and context.get('active_ids'): |
541 | + model_obj = self.pool.get(context.get('active_model')) |
542 | + model_vals = {} |
543 | + for key, val in vals.items(): |
544 | + if key.startswith('selection_'): |
545 | + model_field = key.split('_', 1)[1] |
546 | + if val == 'set': |
547 | + model_vals[model_field] = vals[model_field] |
548 | + elif val == 'remove': |
549 | + model_vals[model_field] = False |
550 | + elif val == 'remove_m2m': |
551 | + m2m_list = [] |
552 | + for m2m_id in vals[model_field][0][2] or []: |
553 | + m2m_list.append((3, m2m_id)) |
554 | + model_vals[model_field] = m2m_list |
555 | + elif val == 'add': |
556 | + m2m_list = [] |
557 | + for m2m_id in vals[model_field][0][2] or []: |
558 | + m2m_list.append((4, m2m_id)) |
559 | + model_vals[model_field] = m2m_list |
560 | + if model_vals: |
561 | + model_obj.write(cr, uid, context['active_ids'], model_vals, context) |
562 | + result = super(mass_editing_wizard, self).create(cr, uid, {}, context) |
563 | + return result |
564 | + |
565 | + def action_apply(self, cr, uid, ids, context=None): |
566 | + return {'type': 'ir.actions.act_window_close'} |
567 | + |
568 | +mass_editing_wizard() |
569 | + |
570 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
Hi,
Thanks for this contribs ! It look good to me. Only remark, as Stefan said for v7.0, we may want to restrict the security a bit more... Giving access to "base.group_user" may be dangerous at some point, but otherwise ok.
Regards,
Joël