diff --git a/mass_editing/ChangeLog.txt b/mass_editing/ChangeLog.txt old mode 100755 new mode 100644 index 143abf1..3891613 --- a/mass_editing/ChangeLog.txt +++ b/mass_editing/ChangeLog.txt @@ -1,11 +1,20 @@ =============================================================================== Version Change Log (mass_editing) =============================================================================== -1.3 * March 11,2013 : Serpent Consulting Services - * Improved and optimized the code of mass_editing +1.6 * June 01,2016 : Serpent Consulting Services + * Added Unit Test Cases -1.2 * Feb 14,2013 : Serpent Consulting Services - * Corrected code as per the review by Community +1.5 * March 23,2016 : Serpent Consulting Services + * Added README and index.html file. -1.1 * Feb 12,2013 : Serpent Consulting Services - * Added the module +1.4 * March 19,2016 : Serpent Consulting Services + * Improved and migrated the code as per API and OCA standards. + +1.3 * March 11,2013 : Serpent Consulting Services + * Improved and optimized the code of mass_editing + +1.2 * Feb 14,2013 : Serpent Consulting Services + * Corrected code as per the review by Community + +1.1 * Feb 12,2013 : Serpent Consulting Services + * Added the module diff --git a/mass_editing/README.rst b/mass_editing/README.rst new file mode 100644 index 0000000..f498e34 --- /dev/null +++ b/mass_editing/README.rst @@ -0,0 +1,109 @@ +.. image:: https://img.shields.io/badge/license-LGPLv3-blue.svg + :target: https://www.gnu.org/licenses/lgpl.html + :alt: License: LGPL-3 + +============ +Mass Editing +============ + +This module provides the following features: + +* You can add, update or remove the values of more than one records on the fly at the same time. + +* You can configure mass editing for any Odoo model. + +* The video explaining the features and how-to for OpenERP Version 6 is here http://t.co/wukYMx1A + +* The video explaining the features and how-to for OpenERP Version 7 is here : http://www.youtube.com/watch?v=9BH0o74A748&feature=youtu.be + +* For more details/customization/feedback contact us on contact@serpentcs.com + +Installation +============ + +No external library is used. + +Configuration +============= + +To configure this module, you need to: + +* Go to *Settings / Mass Editing / Mass Editing* and configure the object and fields for Mass Editing. + +Usage +===== + +This module allows to add, update or remove the values of more than one records on the fly at the same time. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/149/9.0 + +As shown in figure you have to configure the object and fields for mass editing. + +* Select the object and add the fields of that object on which you want to apply mass editing. + +.. image:: /mass_editing/static/description/mass_editing-1.png + :width: 70% + +* *Add Action*: As shown in figure click on *Add Sidebar Button* to add mass editing option in *Action* option in action. + +.. image:: /mass_editing/static/description/mass_editing-2.png + :width: 70% + +* *Go for Mass Editing*: As shown in figure, select the records which you want to modify and click on *Action* to open mass editing popup. + +.. image:: /mass_editing/static/description/mass_editing-3.png + :width: 70% + +* Select *Set / Remove* action and write down the value to set or remove the value for the given field. + +.. image:: /mass_editing/static/description/mass_editing-4.png + :width: 70% + +* This way you can set / remove the values of the fields. + +.. image:: /mass_editing/static/description/mass_editing-5.png + :width: 70% + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed `feedback +`_. + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Oihane Crucelaegui +* Serpent Consulting Services Pvt. Ltd. + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: http://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit http://odoo-community.org. + diff --git a/mass_editing/__init__.py b/mass_editing/__init__.py index 686e4a8..f232425 100644 --- a/mass_editing/__init__.py +++ b/mass_editing/__init__.py @@ -1,24 +1,8 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# This module uses OpenERP, Open Source Management Solution Framework. -# Copyright (C): -# 2012-Today Serpent Consulting Services ( -# -############################################################################## +# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import models from . import wizard +from . import tests +from .hooks import uninstall_hook diff --git a/mass_editing/__openerp__.py b/mass_editing/__openerp__.py index 7e01b31..2567679 100644 --- a/mass_editing/__openerp__.py +++ b/mass_editing/__openerp__.py @@ -1,51 +1,26 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# This module uses OpenERP, Open Source Management Solution Framework. -# Copyright (C): -# 2012-Today Serpent Consulting Services () -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see -# -############################################################################## +# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - "name": "Mass Editing", - "version": "8.0.1.3.0", - "author": "Serpent Consulting Services,Odoo Community Association (OCA)", - "contributors": [ - "Oihane Crucelaegui ", + 'name': 'Mass Editing', + 'version': '9.0.1.0.0', + 'author': 'Serpent Consulting Services Pvt. Ltd., ' + 'Odoo Community Association (OCA)', + 'contributors': [ + 'Oihane Crucelaegui ', + 'Serpent Consulting Services Pvt. Ltd. ', ], - "category": "Tools", - "website": "http://www.serpentcs.com", - "license": "GPL-3 or any later version", - "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. - You can configure mass editing for any OpenERP model. - The video explaining the features and how-to for OpenERP Version 6 - is here http://t.co/wukYMx1A - The video explaining the features and how-to for OpenERP Version 7 is - here : http://www.youtube.com/watch?v=9BH0o74A748&feature=youtu.be - For more details/customization/feedback contact us on - contact@serpentcs.com. - """, + 'category': 'Tools', + 'website': 'http://www.serpentcs.com', + 'license': 'GPL-3 or any later version', + 'summary': 'Mass Editing', + 'uninstall_hook': 'uninstall_hook', 'depends': ['base'], 'data': [ - "security/ir.model.access.csv", + 'security/ir.model.access.csv', 'views/mass_editing_view.xml', ], 'installable': True, - 'application': True, + 'application': False, 'auto_install': False, } diff --git a/mass_editing/hooks.py b/mass_editing/hooks.py new file mode 100644 index 0000000..708c4e4 --- /dev/null +++ b/mass_editing/hooks.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +def uninstall_hook(cr, registry): + cr.execute("""SELECT id FROM ir_act_window + WHERE res_model = 'mass.editing.wizard'""") + for res in cr.dictfetchall(): + value = 'ir.actions.act_window,%s' % res.get('id') + cr.execute("DELETE FROM ir_values WHERE value = '%s'" % value) + return True diff --git a/mass_editing/i18n/de.po b/mass_editing/i18n/de.po index 6da7f26..2f9331a 100644 --- a/mass_editing/i18n/de.po +++ b/mass_editing/i18n/de.po @@ -124,25 +124,25 @@ msgid "Remove the contextual action to use this template on related documents" msgstr "" #. module: mass_editing -#: field:mass.object,ref_ir_act_window:0 +#: field:mass.object,ref_ir_act_window_id:0 msgid "Sidebar Action" msgstr "Sidebar-Aktion" #. module: mass_editing #: view:mass.object:mass_editing.view_mass_object_form -#: field:mass.object,ref_ir_value:0 +#: field:mass.object,ref_ir_value_id:0 msgid "Sidebar Button" msgstr "Sidebar-Button" #. module: mass_editing -#: help:mass.object,ref_ir_act_window:0 +#: help:mass.object,ref_ir_act_window_id:0 msgid "" "Sidebar action to make this template available on records " "of the related document model" msgstr "" #. module: mass_editing -#: help:mass.object,ref_ir_value:0 +#: help:mass.object,ref_ir_value_id:0 msgid "Sidebar button to open the sidebar action" msgstr "Siebar-Button zum Öffnen einer Sidebar-Aktion" diff --git a/mass_editing/i18n/es.po b/mass_editing/i18n/es.po index 8b4ee66..734ed20 100644 --- a/mass_editing/i18n/es.po +++ b/mass_editing/i18n/es.po @@ -124,25 +124,25 @@ msgid "Remove the contextual action to use this template on related documents" msgstr "" #. module: mass_editing -#: field:mass.object,ref_ir_act_window:0 +#: field:mass.object,ref_ir_act_window_id:0 msgid "Sidebar Action" msgstr "Acción del menú contextual" #. module: mass_editing #: view:mass.object:mass_editing.view_mass_object_form -#: field:mass.object,ref_ir_value:0 +#: field:mass.object,ref_ir_value_id:0 msgid "Sidebar Button" msgstr "Botón del menú contextual" #. module: mass_editing -#: help:mass.object,ref_ir_act_window:0 +#: help:mass.object,ref_ir_act_window_id:0 msgid "" "Sidebar action to make this template available on records " "of the related document model" msgstr "" #. module: mass_editing -#: help:mass.object,ref_ir_value:0 +#: help:mass.object,ref_ir_value_id:0 msgid "Sidebar button to open the sidebar action" msgstr "Botón del menú contextual para abrir la acción del menú contextual" diff --git a/mass_editing/i18n/fr.po b/mass_editing/i18n/fr.po index e006ad2..1213d9f 100644 --- a/mass_editing/i18n/fr.po +++ b/mass_editing/i18n/fr.po @@ -125,25 +125,25 @@ msgid "Remove the contextual action to use this template on related documents" msgstr "" #. module: mass_editing -#: field:mass.object,ref_ir_act_window:0 +#: field:mass.object,ref_ir_act_window_id:0 msgid "Sidebar Action" msgstr "" #. module: mass_editing #: view:mass.object:mass_editing.view_mass_object_form -#: field:mass.object,ref_ir_value:0 +#: field:mass.object,ref_ir_value_id:0 msgid "Sidebar Button" msgstr "" #. module: mass_editing -#: help:mass.object,ref_ir_act_window:0 +#: help:mass.object,ref_ir_act_window_id:0 msgid "" "Sidebar action to make this template available on records " "of the related document model" msgstr "" #. module: mass_editing -#: help:mass.object,ref_ir_value:0 +#: help:mass.object,ref_ir_value_id:0 msgid "Sidebar button to open the sidebar action" msgstr "" diff --git a/mass_editing/i18n/fr_CA.po b/mass_editing/i18n/fr_CA.po index 2192c1d..e92ddc9 100644 --- a/mass_editing/i18n/fr_CA.po +++ b/mass_editing/i18n/fr_CA.po @@ -125,25 +125,25 @@ msgid "Remove the contextual action to use this template on related documents" msgstr "" #. module: mass_editing -#: field:mass.object,ref_ir_act_window:0 +#: field:mass.object,ref_ir_act_window_id:0 msgid "Sidebar Action" msgstr "Action du menu latéral" #. module: mass_editing #: view:mass.object:mass_editing.view_mass_object_form -#: field:mass.object,ref_ir_value:0 +#: field:mass.object,ref_ir_value_id:0 msgid "Sidebar Button" msgstr "Bouton du menu latéral" #. module: mass_editing -#: help:mass.object,ref_ir_act_window:0 +#: help:mass.object,ref_ir_act_window_id:0 msgid "" "Sidebar action to make this template available on records " "of the related document model" msgstr "" #. module: mass_editing -#: help:mass.object,ref_ir_value:0 +#: help:mass.object,ref_ir_value_id:0 msgid "Sidebar button to open the sidebar action" msgstr "" diff --git a/mass_editing/i18n/it.po b/mass_editing/i18n/it.po index e63f6fa..483d29e 100644 --- a/mass_editing/i18n/it.po +++ b/mass_editing/i18n/it.po @@ -124,25 +124,25 @@ msgid "Remove the contextual action to use this template on related documents" msgstr "" #. module: mass_editing -#: field:mass.object,ref_ir_act_window:0 +#: field:mass.object,ref_ir_act_window_id:0 msgid "Sidebar Action" msgstr "" #. module: mass_editing #: view:mass.object:mass_editing.view_mass_object_form -#: field:mass.object,ref_ir_value:0 +#: field:mass.object,ref_ir_value_id:0 msgid "Sidebar Button" msgstr "" #. module: mass_editing -#: help:mass.object,ref_ir_act_window:0 +#: help:mass.object,ref_ir_act_window_id:0 msgid "" "Sidebar action to make this template available on records " "of the related document model" msgstr "" #. module: mass_editing -#: help:mass.object,ref_ir_value:0 +#: help:mass.object,ref_ir_value_id:0 msgid "Sidebar button to open the sidebar action" msgstr "" diff --git a/mass_editing/i18n/mass_editing.pot b/mass_editing/i18n/mass_editing.pot index 3085b14..7e1e2e7 100644 --- a/mass_editing/i18n/mass_editing.pot +++ b/mass_editing/i18n/mass_editing.pot @@ -82,7 +82,7 @@ msgid "Name must be unique!" msgstr "" #. module: mass_editing -#: field:mass.object,ref_ir_act_window:0 +#: field:mass.object,ref_ir_act_window_id:0 msgid "Sidebar Action" msgstr "" @@ -92,7 +92,7 @@ msgid "Remove sidebar button" msgstr "" #. module: mass_editing -#: field:mass.object,ref_ir_value:0 +#: field:mass.object,ref_ir_value_id:0 msgid "Sidebar Button" msgstr "" @@ -108,7 +108,7 @@ msgid "Warning" msgstr "" #. module: mass_editing -#: help:mass.object,ref_ir_act_window:0 +#: help:mass.object,ref_ir_act_window_id:0 msgid "Sidebar action to make this template available on records of the related document model" msgstr "" @@ -123,7 +123,7 @@ msgid "Advanced" msgstr "" #. module: mass_editing -#: help:mass.object,ref_ir_value:0 +#: help:mass.object,ref_ir_value_id:0 msgid "Sidebar button to open the sidebar action" msgstr "" diff --git a/mass_editing/i18n/pt_BR.po b/mass_editing/i18n/pt_BR.po index 9ab1eb1..1f83c39 100644 --- a/mass_editing/i18n/pt_BR.po +++ b/mass_editing/i18n/pt_BR.po @@ -125,25 +125,25 @@ msgid "Remove the contextual action to use this template on related documents" msgstr "Remover a ação contextual para usar este modelo nos documentos relacionados" #. module: mass_editing -#: field:mass.object,ref_ir_act_window:0 +#: field:mass.object,ref_ir_act_window_id:0 msgid "Sidebar Action" msgstr "Ação da Barra Lateral" #. module: mass_editing #: view:mass.object:mass_editing.view_mass_object_form -#: field:mass.object,ref_ir_value:0 +#: field:mass.object,ref_ir_value_id:0 msgid "Sidebar Button" msgstr "Botão da Barra Lateral" #. module: mass_editing -#: help:mass.object,ref_ir_act_window:0 +#: help:mass.object,ref_ir_act_window_id:0 msgid "" "Sidebar action to make this template available on records " "of the related document model" msgstr "Ação da Barra Lateral para fazer este modelo disponível nos registros dos modelos de documento relacionados" #. module: mass_editing -#: help:mass.object,ref_ir_value:0 +#: help:mass.object,ref_ir_value_id:0 msgid "Sidebar button to open the sidebar action" msgstr "Botão da Barra Lateral para abrir ação na Barra Lateral" diff --git a/mass_editing/i18n/ru.po b/mass_editing/i18n/ru.po index 49740d7..4e3f4ce 100644 --- a/mass_editing/i18n/ru.po +++ b/mass_editing/i18n/ru.po @@ -124,25 +124,25 @@ msgid "Remove the contextual action to use this template on related documents" msgstr "" #. module: mass_editing -#: field:mass.object,ref_ir_act_window:0 +#: field:mass.object,ref_ir_act_window_id:0 msgid "Sidebar Action" msgstr "" #. module: mass_editing #: view:mass.object:mass_editing.view_mass_object_form -#: field:mass.object,ref_ir_value:0 +#: field:mass.object,ref_ir_value_id:0 msgid "Sidebar Button" msgstr "" #. module: mass_editing -#: help:mass.object,ref_ir_act_window:0 +#: help:mass.object,ref_ir_act_window_id:0 msgid "" "Sidebar action to make this template available on records " "of the related document model" msgstr "" #. module: mass_editing -#: help:mass.object,ref_ir_value:0 +#: help:mass.object,ref_ir_value_id:0 msgid "Sidebar button to open the sidebar action" msgstr "" diff --git a/mass_editing/i18n/sl.po b/mass_editing/i18n/sl.po index e4dee47..a48dbf7 100644 --- a/mass_editing/i18n/sl.po +++ b/mass_editing/i18n/sl.po @@ -125,25 +125,25 @@ msgid "Remove the contextual action to use this template on related documents" msgstr "Odstrani kontekstno dejanje za uporabo te predloge na povezanih dokumentih" #. module: mass_editing -#: field:mass.object,ref_ir_act_window:0 +#: field:mass.object,ref_ir_act_window_id:0 msgid "Sidebar Action" msgstr "Dejanje stranske vrstice" #. module: mass_editing #: view:mass.object:mass_editing.view_mass_object_form -#: field:mass.object,ref_ir_value:0 +#: field:mass.object,ref_ir_value_id:0 msgid "Sidebar Button" msgstr "Gumb stranske vrstice" #. module: mass_editing -#: help:mass.object,ref_ir_act_window:0 +#: help:mass.object,ref_ir_act_window_id:0 msgid "" "Sidebar action to make this template available on records " "of the related document model" msgstr "Dejanje stranske vrstice, da ta predloga postane razpoložljiva na zapisih povezanih modelov dokumentov" #. module: mass_editing -#: help:mass.object,ref_ir_value:0 +#: help:mass.object,ref_ir_value_id:0 msgid "Sidebar button to open the sidebar action" msgstr "Gumb stranske vrstice za zagon dejanja stranske vrstice" diff --git a/mass_editing/models/__init__.py b/mass_editing/models/__init__.py index 64fd501..28f986c 100644 --- a/mass_editing/models/__init__.py +++ b/mass_editing/models/__init__.py @@ -1,24 +1,6 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# This module uses OpenERP, Open Source Management Solution Framework. -# Copyright (C): -# 2012-Today Serpent Consulting Services () -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see -# -############################################################################## +# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import ir_model_fields from . import mass_object diff --git a/mass_editing/models/ir_model_fields.py b/mass_editing/models/ir_model_fields.py index b1413fe..fd4f1f2 100644 --- a/mass_editing/models/ir_model_fields.py +++ b/mass_editing/models/ir_model_fields.py @@ -1,45 +1,23 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# This module uses OpenERP, Open Source Management Solution Framework. -# Copyright (C): -# 2012-Today Serpent Consulting Services () -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see -# -############################################################################## +# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from openerp.osv import orm +from openerp import api, models -class IrModelFields(orm.Model): +class IrModelFields(models.Model): _inherit = 'ir.model.fields' - def search( - self, cr, uid, args, offset=0, limit=0, order=None, context=None, - count=False): + @api.model + def search(self, args, offset=0, limit=0, order=None, count=False): model_domain = [] for domain in args: - if (len(domain) > 2 and - domain[0] == 'model_id' and + if (len(domain) > 2 and domain[0] == 'model_id' and isinstance(domain[2], basestring)): - model_domain += [ - ('model_id', 'in', map(int, domain[2][1:-1].split(','))) - ] + model_domain += [('model_id', 'in', + map(int, domain[2][1:-1].split(',')))] else: model_domain.append(domain) - return super(IrModelFields, self).search( - cr, uid, model_domain, offset=offset, limit=limit, order=order, - context=context, count=count - ) + return super(IrModelFields, self).search(model_domain, offset=offset, + limit=limit, order=order, + count=count) diff --git a/mass_editing/models/mass_object.py b/mass_editing/models/mass_object.py index d859ea7..880702b 100644 --- a/mass_editing/models/mass_object.py +++ b/mass_editing/models/mass_object.py @@ -1,138 +1,102 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# This module uses OpenERP, Open Source Management Solution Framework. -# Copyright (C): -# 2012-Today Serpent Consulting Services () -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see -# -############################################################################## +# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from openerp import SUPERUSER_ID -from openerp.osv import orm, fields -from openerp.tools.translate import _ +from openerp.exceptions import UserError +from openerp import api, fields, models, _ -class MassObject(orm.Model): +class MassObject(models.Model): _name = "mass.object" + _description = "Mass Editing Object" - _columns = { - 'name': fields.char("Name", size=64, required=True, select=1), - 'model_id': fields.many2one( - 'ir.model', 'Model', required=True, select=1), - 'field_ids': fields.many2many( - 'ir.model.fields', 'mass_field_rel', 'mass_id', 'field_id', - 'Fields'), - 'ref_ir_act_window': fields.many2one( - 'ir.actions.act_window', 'Sidebar Action', readonly=True, - help="Sidebar action to make this template available on records \ - of the related document model"), - 'ref_ir_value': fields.many2one( - 'ir.values', 'Sidebar Button', readonly=True, - help="Sidebar button to open the sidebar action"), - 'model_ids': fields.many2many('ir.model', string='Model List') - } + name = fields.Char('Name', required=True, select=1) + model_id = fields.Many2one('ir.model', 'Model', required=True, + help="Model is used for Selecting Fields. " + "This is editable until Sidebar menu " + "is not created.") + field_ids = fields.Many2many('ir.model.fields', 'mass_field_rel', + 'mass_id', 'field_id', 'Fields') + ref_ir_act_window_id = fields.Many2one('ir.actions.act_window', + 'Sidebar action', + readonly=True, + help="Sidebar action to make this " + "template available on " + "records of the related " + "document model.") + ref_ir_value_id = fields.Many2one('ir.values', 'Sidebar button', + readonly=True, + help="Sidebar button to open " + "the sidebar action.") + model_list = fields.Char('Model List') _sql_constraints = [ ('name_uniq', 'unique (name)', _('Name must be unique!')), ] - def onchange_model_id(self, cr, uid, ids, model_id, context=None): - if context is None: - context = {} - if not model_id: - return {'value': {'model_ids': [(6, 0, [])]}} - model_ids = [model_id] - model_obj = self.pool['ir.model'] - active_model_obj = self.pool.get(model_obj.browse( - cr, uid, model_id).model) - if active_model_obj._inherits: - for key, val in active_model_obj._inherits.items(): - found_model_ids = model_obj.search( - cr, uid, [('model', '=', key)], context=context) - model_ids += found_model_ids - return {'value': {'model_ids': [(6, 0, model_ids)]}} + @api.onchange('model_id') + def _onchange_model_id(self): + self.field_ids = [(6, 0, [])] + model_list = [] + if self.model_id: + model_obj = self.env['ir.model'] + model_list = [self.model_id.id] + active_model_obj = self.env[self.model_id.model] + if active_model_obj._inherits: + keys = active_model_obj._inherits.keys() + inherits_model_list = model_obj.search([('model', 'in', keys)]) + model_list.extend((inherits_model_list and + inherits_model_list.ids or [])) + self.model_list = model_list - def create_action(self, cr, uid, ids, context=None): + @api.multi + def create_action(self): + self.ensure_one() vals = {} - action_obj = self.pool['ir.actions.act_window'] - ir_values_obj = self.pool['ir.values'] - for data in self.browse(cr, uid, ids, context=context): - src_obj = data.model_id.model - button_name = _('Mass Editing (%s)') % data.name - vals['ref_ir_act_window'] = action_obj.create( - cr, SUPERUSER_ID, - { - 'name': button_name, - 'type': 'ir.actions.act_window', - 'res_model': 'mass.editing.wizard', - 'src_model': src_obj, - 'view_type': 'form', - 'context': "{'mass_editing_object' : %d}" % (data.id), - 'view_mode': 'form,tree', - 'target': 'new', - 'auto_refresh': 1, - }, - context) - vals['ref_ir_value'] = ir_values_obj.create( - cr, SUPERUSER_ID, - { - 'name': button_name, - 'model': src_obj, - 'key2': 'client_action_multi', - 'value': ( - "ir.actions.act_window," + - str(vals['ref_ir_act_window'])), - 'object': True, - }, - context) - self.write( - cr, uid, ids, - { - 'ref_ir_act_window': vals.get('ref_ir_act_window', False), - 'ref_ir_value': vals.get('ref_ir_value', False), - }, - context) + action_obj = self.env['ir.actions.act_window'] + src_obj = self.model_id.model + button_name = _('Mass Editing (%s)') % self.name + vals['ref_ir_act_window_id'] = action_obj.create({ + 'name': button_name, + 'type': 'ir.actions.act_window', + 'res_model': 'mass.editing.wizard', + 'src_model': src_obj, + 'view_type': 'form', + 'context': "{'mass_editing_object' : %d}" % (self.id), + 'view_mode': 'form, tree', + 'target': 'new', + 'auto_refresh': 1, + }).id + vals['ref_ir_value_id'] = self.env['ir.values'].create({ + 'name': button_name, + 'model': src_obj, + 'key2': 'client_action_multi', + 'value': "ir.actions.act_window," + + str(vals['ref_ir_act_window_id']), + }).id + self.write(vals) return True - def unlink_action(self, cr, uid, ids, context=None): - for template in self.browse(cr, uid, ids, context=context): + @api.multi + def unlink_action(self): + for mass in self: try: - if template.ref_ir_act_window: - act_window_obj = self.pool['ir.actions.act_window'] - act_window_obj.unlink( - cr, SUPERUSER_ID, [template.ref_ir_act_window.id], - context=context) - if template.ref_ir_value: - ir_values_obj = self.pool['ir.values'] - ir_values_obj.unlink( - cr, SUPERUSER_ID, template.ref_ir_value.id, - context=context) + if mass.ref_ir_act_window_id: + mass.ref_ir_act_window_id.unlink() + if mass.ref_ir_value_id: + mass.ref_ir_value_id.unlink() except: - raise orm.except_orm( - _("Warning"), - _("Deletion of the action record failed.")) + raise UserError(_("Deletion of the action record failed.")) return True - def unlink(self, cr, uid, ids, context=None): - self.unlink_action(cr, uid, ids, context=context) - return super(MassObject, self).unlink(cr, uid, ids, context=context) + @api.multi + def unlink(self): + self.unlink_action() + return super(MassObject, self).unlink() - def copy(self, cr, uid, record_id, default=None, context=None): + @api.returns('self', lambda value: value.id) + def copy(self, default=None): if default is None: default = {} - default.update({'name': '', 'field_ids': []}) - return super(MassObject, self).copy( - cr, uid, record_id, default, context=context) + default.update({'name': _("%s (copy)" % self.name), 'field_ids': []}) + return super(MassObject, self).copy(default) diff --git a/mass_editing/security/ir.model.access.csv b/mass_editing/security/ir.model.access.csv old mode 100755 new mode 100644 diff --git a/mass_editing/static/description/mass_editing-1.png b/mass_editing/static/description/mass_editing-1.png new file mode 100644 index 0000000..445c7e5 Binary files /dev/null and b/mass_editing/static/description/mass_editing-1.png differ diff --git a/mass_editing/static/description/mass_editing-2.png b/mass_editing/static/description/mass_editing-2.png new file mode 100644 index 0000000..830b5b7 Binary files /dev/null and b/mass_editing/static/description/mass_editing-2.png differ diff --git a/mass_editing/static/description/mass_editing-3.png b/mass_editing/static/description/mass_editing-3.png new file mode 100644 index 0000000..e8374d3 Binary files /dev/null and b/mass_editing/static/description/mass_editing-3.png differ diff --git a/mass_editing/static/description/mass_editing-4.png b/mass_editing/static/description/mass_editing-4.png new file mode 100644 index 0000000..95d74b2 Binary files /dev/null and b/mass_editing/static/description/mass_editing-4.png differ diff --git a/mass_editing/static/description/mass_editing-5.png b/mass_editing/static/description/mass_editing-5.png new file mode 100644 index 0000000..3c8e9e3 Binary files /dev/null and b/mass_editing/static/description/mass_editing-5.png differ diff --git a/mass_editing/tests/__init__.py b/mass_editing/tests/__init__.py new file mode 100644 index 0000000..15099e1 --- /dev/null +++ b/mass_editing/tests/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import test_mass_editing diff --git a/mass_editing/tests/test_mass_editing.py b/mass_editing/tests/test_mass_editing.py new file mode 100644 index 0000000..518d6e2 --- /dev/null +++ b/mass_editing/tests/test_mass_editing.py @@ -0,0 +1,174 @@ +# -*- coding: utf-8 -*- +# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import ast + +from openerp.tests import common +from openerp.modules import registry +from openerp.addons.mass_editing.hooks import uninstall_hook + + +class TestMassEditing(common.TransactionCase): + + def setUp(self): + super(TestMassEditing, self).setUp() + model_obj = self.env['ir.model'] + self.mass_wiz_obj = self.env['mass.editing.wizard'] + self.mass_object_model = self.env['mass.object'] + self.res_partner_model = self.env['res.partner'] + self.partner = self._create_partner() + self.partner_model = model_obj.\ + search([('model', '=', 'res.partner')]) + self.user_model = model_obj.search([('model', '=', 'res.users')]) + self.fields_model = self.env['ir.model.fields'].\ + search([('model_id', '=', self.partner_model.id), + ('name', 'in', ['email', 'phone', 'category_id', 'comment', + 'country_id', 'customer', 'child_ids', + 'title'])]) + self.mass = self._create_mass_editing(self.partner_model, + self.fields_model) + self.copy_mass = self.mass.copy() + self.user = self._create_user() + + def _create_partner(self): + """Create a Partner.""" + categ_ids = self.env['res.partner.category'].search([]).ids + return self.res_partner_model.create({ + 'name': 'Test Partner', + 'email': 'example@yourcompany.com', + 'phone': 123456, + 'category_id': [(6, 0, categ_ids)], + }) + + def _create_user(self): + return self.env['res.users'].create({ + 'name': 'Test User', + 'login': 'test_login', + 'email': 'test@test.com', + }) + + def _create_mass_editing(self, model, fields): + """Create a Mass Editing with Partner as model and + email field of partner.""" + mass = self.mass_object_model.create({ + 'name': 'Mass Editing for Partner', + 'model_id': model.id, + 'field_ids': [(6, 0, fields.ids)] + }) + mass.create_action() + return mass + + def _apply_action(self, partner, vals): + """Create Wizard object to perform mass editing to + REMOVE field's value.""" + ctx = { + 'active_id': partner.id, + 'active_ids': partner.ids, + 'active_model': 'res.partner', + } + return self.mass_wiz_obj.with_context(ctx).create(vals) + + def test_wiz_fields_view_get(self): + """Test whether fields_view_get method returns arch or not.""" + ctx = { + 'mass_editing_object': self.mass.id, + 'active_id': self.partner.id, + 'active_ids': self.partner.ids, + 'active_model': 'res.partner', + } + result = self.mass_wiz_obj.with_context(ctx).fields_view_get() + self.assertTrue(result.get('arch'), + 'Fields view get must return architecture.') + + def test_onchange_model(self): + """Test whether onchange model_id returns model_id in list""" + new_mass = self.mass_object_model.new({'model_id': self.user_model.id}) + new_mass._onchange_model_id() + model_list = ast.literal_eval(new_mass.model_list) + self.assertTrue(self.user_model.id in model_list, + 'Onchange model list must contains model_id.') + + def test_mass_edit_email(self): + """Test Case for MASS EDITING which will remove and after add + Partner's email and will assert the same.""" + # Remove email address + vals = { + 'selection__email': 'remove', + 'selection__phone': 'remove', + } + self._apply_action(self.partner, vals) + self.assertEqual(self.partner.email, False, + 'Partner\'s Email should be removed.') + # Set email address + vals = { + 'selection__email': 'set', + 'email': 'sample@mycompany.com', + } + self._apply_action(self.partner, vals) + self.assertNotEqual(self.partner.email, False, + 'Partner\'s Email should be set.') + + def test_mass_edit_m2m_categ(self): + """Test Case for MASS EDITING which will remove and add + Partner's category m2m.""" + # Remove m2m categories + vals = { + 'selection__category_id': 'remove_m2m', + } + self._apply_action(self.partner, vals) + self.assertNotEqual(self.partner.category_id, False, + 'Partner\'s category should be removed.') + # Add m2m categories + dist_categ_id = self.env.ref('base.res_partner_category_13').id + vals = { + 'selection__category_id': 'add', + 'category_id': [[6, 0, [dist_categ_id]]], + } + wiz_action = self._apply_action(self.partner, vals) + self.assertTrue(dist_categ_id in self.partner.category_id.ids, + 'Partner\'s category should be added.') + # Check window close action + res = wiz_action.action_apply() + self.assertTrue(res['type'] == 'ir.actions.act_window_close', + 'IR Action must be window close.') + + def test_mass_edit_copy(self): + """Test if fields one2many field gets blank when mass editing record + is copied. + """ + self.assertEqual(self.copy_mass.field_ids.ids, [], + 'Fields must be blank.') + + def test_sidebar_action(self): + """Test if Sidebar Action is added / removed to / from give object.""" + action = self.mass.ref_ir_act_window_id and self.mass.ref_ir_value_id + self.assertTrue(action, 'Sidebar action must be exists.') + # Remove the sidebar actions + self.mass.unlink_action() + action = self.mass.ref_ir_act_window_id and self.mass.ref_ir_value_id + self.assertFalse(action, 'Sidebar action must be removed.') + + def test_unlink_mass(self): + """Test if related actions are removed when mass editing + record is unlinked.""" + mass_action_id = "ir.actions.act_window," + str(self.mass.id) + self.mass.unlink() + value_cnt = self.env['ir.values'].search([('value', '=', + mass_action_id)], + count=True) + self.assertTrue(value_cnt == 0, + "Sidebar action must be removed when mass" + " editing is unlinked.") + + def test_uninstall_hook(self): + """Test if related actions are removed when mass editing + record is uninstalled.""" + uninstall_hook(self.cr, registry) + mass_action_id = "ir.actions.act_window," + str(self.mass.id) + value_cnt = self.env['ir.values'].search([('value', '=', + mass_action_id)], + count=True) + self.assertTrue(value_cnt == 0, + "Sidebar action must be removed when mass" + " editing module is uninstalled.") diff --git a/mass_editing/views/mass_editing_view.xml b/mass_editing/views/mass_editing_view.xml index 1ab945f..119ca5a 100644 --- a/mass_editing/views/mass_editing_view.xml +++ b/mass_editing/views/mass_editing_view.xml @@ -1,98 +1,96 @@ - - + - - mass.object.form - mass.object - -
- -
-
+
+ +
+ + + + + + + + + + + +
+ +
+
- - mass.object.tree - mass.object - - - - - - - + + mass.object.tree + mass.object + + + + + + + - - Mass Editing - mass.object - form - tree,form - - + + Mass Editing + mass.object + form + tree,form + + - - - tree - - - - - - form - - - + + + tree + + + + + + form + + + - + - + -
-
+ diff --git a/mass_editing/wizard/__init__.py b/mass_editing/wizard/__init__.py index 4f383dd..ecfaa57 100644 --- a/mass_editing/wizard/__init__.py +++ b/mass_editing/wizard/__init__.py @@ -1,23 +1,5 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# This module uses OpenERP, Open Source Management Solution Framework. -# Copyright (C): -# 2012-Today Serpent Consulting Services ( -# -############################################################################## +# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from . import mass_editing_wizard diff --git a/mass_editing/wizard/mass_editing_wizard.py b/mass_editing/wizard/mass_editing_wizard.py index b266d34..8456307 100644 --- a/mass_editing/wizard/mass_editing_wizard.py +++ b/mass_editing/wizard/mass_editing_wizard.py @@ -1,213 +1,258 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# This module uses OpenERP, Open Source Management Solution Framework. -# Copyright (C): -# 2012-Today Serpent Consulting Services () -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see -# -############################################################################## +# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from openerp.osv import orm -import openerp.tools as tools from lxml import etree +import openerp.tools as tools +from openerp import api, models + -class MassEditingWizard(orm.TransientModel): +class MassEditingWizard(models.TransientModel): _name = 'mass.editing.wizard' - def fields_view_get( - self, cr, uid, view_id=None, view_type='form', context=None, - toolbar=False, submenu=False): - result = super(MassEditingWizard, self).fields_view_get( - cr, uid, view_id, view_type, context, toolbar, submenu) + @api.model + def fields_view_get(self, view_id=None, view_type='form', toolbar=False, + submenu=False): + result =\ + super(MassEditingWizard, self).fields_view_get(view_id=view_id, + view_type=view_type, + toolbar=toolbar, + submenu=submenu) + context = self._context if context.get('mass_editing_object'): - mass_object = self.pool['mass.object'] - editing_data = mass_object.browse( - cr, uid, context.get('mass_editing_object'), context) + mass_obj = self.env['mass.object'] + editing_data = mass_obj.browse(context.get('mass_editing_object')) all_fields = {} xml_form = etree.Element('form', { - 'string': tools.ustr(editing_data.name), 'version': '7.0'}) - xml_group = etree.SubElement(xml_form, 'group', {'colspan': '4'}) + 'string': tools.ustr(editing_data.name) + }) + xml_group = etree.SubElement(xml_form, 'group', { + 'colspan': '6', + 'col': '6', + }) etree.SubElement(xml_group, 'label', { - 'string': '', 'colspan': '2'}) - xml_group = etree.SubElement(xml_form, 'group', {'colspan': '4', - 'col': '4'}) - model_obj = self.pool[context.get('active_model')] - field_info = model_obj.fields_get(cr, uid, [], context) + 'string': '', + 'colspan': '2', + }) + xml_group = etree.SubElement(xml_form, 'group', { + 'colspan': '6', + 'col': '6', + }) + model_obj = self.env[context.get('active_model')] + field_info = model_obj.fields_get() for field in editing_data.field_ids: if field.ttype == "many2many": all_fields[field.name] = field_info[field.name] all_fields["selection__" + field.name] = { 'type': 'selection', 'string': field_info[field.name]['string'], - 'selection': [ - ('set', 'Set'), ('remove_m2m', 'Remove'), - ('add', 'Add')]} + 'selection': [('set', 'Set'), + ('remove_m2m', 'Remove'), + ('add', 'Add')] + } xml_group = etree.SubElement(xml_group, 'group', { - 'colspan': '4'}) + 'colspan': '6', + 'col': '6', + }) etree.SubElement(xml_group, 'separator', { 'string': field_info[field.name]['string'], - 'colspan': '2'}) + 'colspan': '6', + }) etree.SubElement(xml_group, 'field', { 'name': "selection__" + field.name, - 'colspan': '2', 'nolabel': '1'}) + 'colspan': '6', + 'nolabel': '1' + }) etree.SubElement(xml_group, 'field', { - 'name': field.name, 'colspan': '4', 'nolabel': '1', - 'attrs': ( - "{'invisible':[('selection__" + - field.name + "','=','remove_m2m')]}")}) + 'name': field.name, + 'colspan': '6', + 'nolabel': '1', + 'attrs': ("{'invisible': [('selection__" + + field.name + "', '=', 'remove_m2m')]}"), + }) elif field.ttype == "one2many": all_fields["selection__" + field.name] = { 'type': 'selection', 'string': field_info[field.name]['string'], - 'selection': [('set', 'Set'), ('remove', 'Remove')]} + 'selection': [('set', 'Set'), ('remove', 'Remove')], + } all_fields[field.name] = { - 'type': field.ttype, 'string': field.field_description, - 'relation': field.relation} + 'type': field.ttype, + 'string': field.field_description, + 'relation': field.relation, + } etree.SubElement(xml_group, 'field', { - 'name': "selection__" + field.name, 'colspan': '2'}) + 'name': "selection__" + field.name, + 'colspan': '4', + }) etree.SubElement(xml_group, 'field', { - 'name': field.name, 'colspan': '4', 'nolabel': '1', - 'attrs': ( - "{'invisible':[('selection__" + - field.name + "','=','remove_o2m')]}")}) + 'name': field.name, + 'colspan': '6', + 'nolabel': '1', + 'attrs': ("{'invisible':[('selection__" + + field.name + "', '=', 'remove_o2m')]}"), + }) elif field.ttype == "many2one": all_fields["selection__" + field.name] = { 'type': 'selection', 'string': field_info[field.name]['string'], - 'selection': [('set', 'Set'), ('remove', 'Remove')]} + 'selection': [('set', 'Set'), ('remove', 'Remove')], + } all_fields[field.name] = { - 'type': field.ttype, 'string': field.field_description, - 'relation': field.relation} + 'type': field.ttype, + 'string': field.field_description, + 'relation': field.relation, + } etree.SubElement(xml_group, 'field', { - 'name': "selection__" + field.name, 'colspan': '2'}) + 'name': "selection__" + field.name, + 'colspan': '2', + }) etree.SubElement(xml_group, 'field', { - 'name': field.name, 'nolabel': '1', 'colspan': '2', - 'attrs': ( - "{'invisible':[('selection__" + - field.name + "','=','remove')]}")}) + 'name': field.name, + 'nolabel': '1', + 'colspan': '4', + 'attrs': ("{'invisible':[('selection__" + + field.name + "', '=', 'remove')]}"), + }) elif field.ttype == "char": all_fields["selection__" + field.name] = { 'type': 'selection', 'string': field_info[field.name]['string'], - 'selection': [('set', 'Set'), ('remove', 'Remove')]} + 'selection': [('set', 'Set'), ('remove', 'Remove')], + } all_fields[field.name] = { - 'type': field.ttype, 'string': field.field_description, - 'size': field.size or 256} + 'type': field.ttype, + 'string': field.field_description, + 'size': field.size or 256, + } etree.SubElement(xml_group, 'field', { 'name': "selection__" + field.name, 'colspan': '2', - }) + }) etree.SubElement(xml_group, 'field', { - 'name': field.name, 'nolabel': '1', - 'attrs': ( - "{'invisible':[('selection__" + - field.name + "','=','remove')]}"), - 'colspan': '2'}) + 'name': field.name, + 'nolabel': '1', + 'attrs': ("{'invisible':[('selection__" + + field.name + "','=','remove')]}"), + 'colspan': '4', + }) elif field.ttype == 'selection': all_fields["selection__" + field.name] = { 'type': 'selection', 'string': field_info[field.name]['string'], - 'selection': [('set', 'Set'), ('remove', 'Remove')]} + 'selection': [('set', 'Set'), ('remove', 'Remove')] + } etree.SubElement(xml_group, 'field', { - 'name': "selection__" + field.name, 'colspan': '2'}) + 'name': "selection__" + field.name, + 'colspan': '2', + }) etree.SubElement(xml_group, 'field', { - 'name': field.name, 'nolabel': '1', 'colspan': '2', - 'attrs': ( - "{'invisible':[('selection__" + - field.name + "','=','remove')]}")}) + 'name': field.name, + 'nolabel': '1', + 'colspan': '4', + 'attrs': ("{'invisible':[('selection__" + + field.name + "', '=', 'remove')]}"), + }) all_fields[field.name] = { 'type': field.ttype, 'string': field.field_description, - 'selection': field_info[field.name]['selection']} + 'selection': field_info[field.name]['selection'], + } else: all_fields[field.name] = { - 'type': field.ttype, 'string': field.field_description} + 'type': field.ttype, + 'string': field.field_description, + } all_fields["selection__" + field.name] = { 'type': 'selection', 'string': field_info[field.name]['string'], - 'selection': [('set', 'Set'), ('remove', 'Remove')]} + 'selection': [('set', 'Set'), ('remove', 'Remove')] + } if field.ttype == 'text': xml_group = etree.SubElement(xml_group, 'group', { - 'colspan': '6'}) + 'colspan': '6', + 'col': '6', + }) etree.SubElement(xml_group, 'separator', { 'string': all_fields[field.name]['string'], - 'colspan': '2'}) + 'colspan': '6', + }) etree.SubElement(xml_group, 'field', { 'name': "selection__" + field.name, - 'colspan': '2', 'nolabel': '1'}) + 'colspan': '6', + 'nolabel': '1', + }) etree.SubElement(xml_group, 'field', { - 'name': field.name, 'colspan': '4', 'nolabel': '1', - 'attrs': ( - "{'invisible':[('selection__" + - field.name + "','=','remove')]}")}) + 'name': field.name, + 'colspan': '6', + 'nolabel': '1', + 'attrs': ("{'invisible':[('selection__" + + field.name + "','=','remove')]}"), + }) else: all_fields["selection__" + field.name] = { 'type': 'selection', 'string': field_info[field.name]['string'], - 'selection': [( - 'set', 'Set'), ('remove', 'Remove')]} + 'selection': [('set', 'Set'), ('remove', 'Remove')] + } etree.SubElement(xml_group, 'field', { 'name': "selection__" + field.name, - 'colspan': '2', }) + 'colspan': '2', + }) etree.SubElement(xml_group, 'field', { - 'name': field.name, 'nolabel': '1', - 'attrs': ( - "{'invisible':[('selection__" + - field.name + "','=','remove')]}"), - 'colspan': '2', }) - etree.SubElement( - xml_form, 'separator', {'string': '', 'colspan': '4'}) + 'name': field.name, + 'nolabel': '1', + 'attrs': ("{'invisible':[('selection__" + + field.name + "','=','remove')]}"), + 'colspan': '4', + }) + etree.SubElement(xml_form, 'separator', { + 'string': '', + 'colspan': '6', + 'col': '6', + }) xml_group3 = etree.SubElement(xml_form, 'footer', {}) etree.SubElement(xml_group3, 'button', { - 'string': 'Apply', 'icon': "gtk-execute", - 'type': 'object', 'name': "action_apply", - 'class': "oe_highlight"}) + 'string': 'Apply', + 'class': 'btn-primary', + 'type': 'object', + 'name': 'action_apply', + }) etree.SubElement(xml_group3, 'button', { - 'string': 'Close', 'icon': "gtk-close", 'special': 'cancel'}) + 'string': 'Close', + 'class': 'btn-default', + 'special': 'cancel', + }) root = xml_form.getroottree() result['arch'] = etree.tostring(root) result['fields'] = all_fields return result - def create(self, cr, uid, vals, context=None): - if context.get('active_model') and context.get('active_ids'): - model_obj = self.pool.get(context.get('active_model')) - dict = {} + @api.model + def create(self, vals): + if (self._context.get('active_model') and + self._context.get('active_ids')): + model_obj = self.env[self._context.get('active_model')] + values = {} for key, val in vals.items(): - if key.startswith('selection__'): + if key.startswith('selection_'): split_key = key.split('__', 1)[1] if val == 'set': - dict.update({split_key: vals.get(split_key, False)}) + values.update({split_key: vals.get(split_key, False)}) elif val == 'remove': - dict.update({split_key: False}) + values.update({split_key: False}) elif val == 'remove_m2m': - dict.update({split_key: [ - (3, id) for id in vals.get( - split_key, False)[0][2]]}) + values.update({split_key: [(5, 0, [])]}) elif val == 'add': m2m_list = [] for m2m_id in vals.get(split_key, False)[0][2]: m2m_list.append((4, m2m_id)) - dict.update({split_key: m2m_list}) - if dict: - model_obj.write( - cr, uid, context.get('active_ids'), dict, context) - result = super(MassEditingWizard, self).create(cr, uid, {}, context) - return result + values.update({split_key: m2m_list}) + if values: + model_obj.browse(self._context.get('active_ids')).write(values) + return super(MassEditingWizard, self).create({}) - def action_apply(self, cr, uid, ids, context=None): + @api.multi + def action_apply(self): return {'type': 'ir.actions.act_window_close'}