diff --git a/mass_editing/ChangeLog.txt b/mass_editing/ChangeLog.txt deleted file mode 100644 index 3891613..0000000 --- a/mass_editing/ChangeLog.txt +++ /dev/null @@ -1,20 +0,0 @@ -=============================================================================== - Version Change Log (mass_editing) -=============================================================================== -1.6 * June 01,2016 : Serpent Consulting Services - * Added Unit Test Cases - -1.5 * March 23,2016 : Serpent Consulting Services - * Added README and index.html file. - -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 index 8e66086..7770de5 100644 --- a/mass_editing/README.rst +++ b/mass_editing/README.rst @@ -1,6 +1,6 @@ -.. image:: https://img.shields.io/badge/license-LGPLv3-blue.svg - :target: https://www.gnu.org/licenses/lgpl.html - :alt: License: LGPL-3 +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 ============ Mass Editing @@ -12,12 +12,6 @@ This module provides the following features: * 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 ============ @@ -37,7 +31,7 @@ This module allows to add, update or remove the values of more than one records .. 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 + :target: https://runbot.odoo-community.org/runbot/149/11.0 As shown in figure you have to configure the object and fields for mass editing. @@ -70,13 +64,13 @@ Bug Tracker =========== Bugs are tracked on `GitHub Issues -`_. In case of trouble, please +`_. 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 `_. +server-ux/issues/new?body=module:%20 +server-ux%0Aversion:%20 +11.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. Credits ======= @@ -91,14 +85,16 @@ Contributors * Oihane Crucelaegui * Serpent Consulting Services Pvt. Ltd. +* Jay Vora * Jairo Llopis +* Juan Negrete Maintainer ---------- .. image:: https://odoo-community.org/logo.png :alt: Odoo Community Association - :target: http://odoo-community.org + :target: https://odoo-community.org This module is maintained by the OCA. @@ -106,5 +102,4 @@ 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. - +To contribute to this module, please visit https://odoo-community.org. diff --git a/mass_editing/__init__.py b/mass_editing/__init__.py index f232425..cae1047 100644 --- a/mass_editing/__init__.py +++ b/mass_editing/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/mass_editing/__manifest__.py b/mass_editing/__manifest__.py index 949e127..70e1a71 100644 --- a/mass_editing/__manifest__.py +++ b/mass_editing/__manifest__.py @@ -1,20 +1,14 @@ -# -*- coding: utf-8 -*- # © 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': '10.0.1.1.0', + 'version': '11.0.1.0.0', 'author': 'Serpent Consulting Services Pvt. Ltd., ' 'Tecnativa, ' 'Odoo Community Association (OCA)', - 'contributors': [ - 'Oihane Crucelaegui ', - 'Serpent Consulting Services Pvt. Ltd. ', - 'Jay Vora ' - ], 'category': 'Tools', 'website': 'http://www.serpentcs.com', - 'license': 'GPL-3 or any later version', + 'license': 'AGPL-3', 'summary': 'Mass Editing', 'uninstall_hook': 'uninstall_hook', 'depends': ['base'], diff --git a/mass_editing/hooks.py b/mass_editing/hooks.py index 0b81f68..7ee3f89 100644 --- a/mass_editing/hooks.py +++ b/mass_editing/hooks.py @@ -1,12 +1,10 @@ -# -*- 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, )) + """Delete the actions that were created with mass_editing when + the module is uninstalled""" + cr.execute("""DELETE FROM ir_act_window + WHERE res_model = 'mass.editing.wizard'""") return True diff --git a/mass_editing/i18n/mass_editing.pot b/mass_editing/i18n/mass_editing.pot deleted file mode 100644 index 7e1e2e7..0000000 --- a/mass_editing/i18n/mass_editing.pot +++ /dev/null @@ -1,129 +0,0 @@ -# Translation of OpenERP Server. -# This file contains the translation of the following modules: -# * mass_editing -# -msgid "" -msgstr "" -"Project-Id-Version: OpenERP Server 7.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-03-14 17:40+0000\n" -"PO-Revision-Date: 2014-03-14 17:40+0000\n" -"Last-Translator: <>\n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: \n" - -#. module: mass_editing -#: model:ir.actions.act_window,name:mass_editing.action_mass_object_form -#: model:ir.ui.menu,name:mass_editing.menu_mass_editing -#: model:ir.ui.menu,name:mass_editing.menu_mass_object_view -msgid "Mass Editing" -msgstr "" - -#. module: mass_editing -#: view:mass.object:0 -msgid "Display a button in the sidebar of related documents to open a composition wizard" -msgstr "" - -#. module: mass_editing -#: model:_description:0 -#: model:ir.model,name:mass_editing.model_mass_editing_wizard -msgid "mass.editing.wizard" -msgstr "" - -#. module: mass_editing -#: field:mass.object,name:0 -msgid "Name" -msgstr "" - -#. module: mass_editing -#: code:addons/mass_editing/mass_editing.py:114 -#, python-format -msgid "Deletion of the action record failed." -msgstr "" - -#. module: mass_editing -#: model:_description:0 -#: model:ir.model,name:mass_editing.model_ir_model_fields -#: view:mass.object:0 -#: field:mass.object,field_ids:0 -msgid "Fields" -msgstr "" - -#. module: mass_editing -#: code:addons/mass_editing/mass_editing.py:80 -#, python-format -msgid "Mass Editing (%s)" -msgstr "" - -#. module: mass_editing -#: view:mass.object:0 -msgid "Object" -msgstr "" - -#. module: mass_editing -#: model:_description:0 -#: model:ir.model,name:mass_editing.model_mass_object -msgid "mass.object" -msgstr "" - -#. module: mass_editing -#: field:mass.object,model_ids:0 -msgid "Model List" -msgstr "" - -#. module: mass_editing -#: code:addons/mass_editing/mass_editing.py:57 -#: sql_constraint:mass.object:0 -#, python-format -msgid "Name must be unique!" -msgstr "" - -#. module: mass_editing -#: field:mass.object,ref_ir_act_window_id:0 -msgid "Sidebar Action" -msgstr "" - -#. module: mass_editing -#: view:mass.object:0 -msgid "Remove sidebar button" -msgstr "" - -#. module: mass_editing -#: field:mass.object,ref_ir_value_id:0 -msgid "Sidebar Button" -msgstr "" - -#. module: mass_editing -#: field:mass.object,model_id:0 -msgid "Model" -msgstr "" - -#. module: mass_editing -#: code:addons/mass_editing/mass_editing.py:114 -#, python-format -msgid "Warning" -msgstr "" - -#. module: mass_editing -#: 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 -#: view:mass.object:0 -msgid "Add sidebar button" -msgstr "" - -#. module: mass_editing -#: view:mass.object:0 -msgid "Advanced" -msgstr "" - -#. module: mass_editing -#: help:mass.object,ref_ir_value_id:0 -msgid "Sidebar button to open the sidebar action" -msgstr "" - diff --git a/mass_editing/models/__init__.py b/mass_editing/models/__init__.py index 28f986c..d867b13 100644 --- a/mass_editing/models/__init__.py +++ b/mass_editing/models/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/mass_editing/models/ir_model_fields.py b/mass_editing/models/ir_model_fields.py index d22867e..235d3d9 100644 --- a/mass_editing/models/ir_model_fields.py +++ b/mass_editing/models/ir_model_fields.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). @@ -12,11 +11,11 @@ class IrModelFields(models.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 - isinstance(domain[2], basestring) and + if (len(domain) > 2 and domain[0] == 'mass_editing_domain' and + isinstance(domain[2], str) and list(domain[2][1:-1])): model_domain += [('model_id', 'in', - map(int, domain[2][1:-1].split(',')))] + list(map(int, domain[2][1:-1].split(','))))] else: model_domain.append(domain) return super(IrModelFields, self).search(model_domain, offset=offset, diff --git a/mass_editing/models/mass_object.py b/mass_editing/models/mass_object.py index ddeba4d..3bae49f 100644 --- a/mass_editing/models/mass_object.py +++ b/mass_editing/models/mass_object.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). @@ -24,14 +23,10 @@ class MassObject(models.Model): "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!')), + ('name_uniq', 'unique (name)', 'Name must be unique!'), ] @api.onchange('model_id') @@ -43,7 +38,7 @@ class MassObject(models.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() + keys = list(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 [])) @@ -65,25 +60,16 @@ class MassObject(models.Model): 'context': "{'mass_editing_object' : %d}" % (self.id), 'view_mode': 'form, tree', 'target': 'new', - }).id - # We make sudo as any user with rights in this model should be able - # to create the action, not only admin - vals['ref_ir_value_id'] = self.env['ir.values'].sudo().create({ - 'name': button_name, - 'model': src_obj, - 'key2': 'client_action_multi', - 'value': "ir.actions.act_window," + - str(vals['ref_ir_act_window_id']), + 'binding_model_id': self.model_id.id, + 'binding_type': 'action', + 'multi': True, }).id self.write(vals) return True @api.multi def unlink_action(self): - # We make sudo as any user with rights in this model should be able - # to delete the action, not only admin - self.mapped('ref_ir_act_window_id').sudo().unlink() - self.mapped('ref_ir_value_id').sudo().unlink() + self.mapped('ref_ir_act_window_id').unlink() return True @api.multi diff --git a/mass_editing/tests/__init__.py b/mass_editing/tests/__init__.py index 15099e1..c1f46a4 100644 --- a/mass_editing/tests/__init__.py +++ b/mass_editing/tests/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/mass_editing/tests/test_mass_editing.py b/mass_editing/tests/test_mass_editing.py index 7ec719a..66f64d4 100644 --- a/mass_editing/tests/test_mass_editing.py +++ b/mass_editing/tests/test_mass_editing.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). @@ -89,6 +88,27 @@ class TestMassEditing(common.TransactionCase): self.assertTrue(self.user_model.id in model_list, 'Onchange model list must contains model_id.') + def test_wiz_read_fields(self): + """Test whether read method returns all fields or not.""" + ctx = { + 'mass_editing_object': self.mass.id, + 'active_id': self.partner.id, + 'active_ids': self.partner.ids, + 'active_model': 'res.partner', + } + fields_view = self.mass_wiz_obj.with_context(ctx).fields_view_get() + fields = list(fields_view['fields'].keys()) + # add a real field + fields.append('display_name') + vals = { + 'selection__email': 'remove', + 'selection__phone': 'remove', + } + mass_wiz_obj = self._apply_action(self.partner, vals) + result = mass_wiz_obj.read(fields)[0] + self.assertTrue(all([field in result for field in fields]), + 'Read must return all fields.') + 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.""" @@ -121,13 +141,23 @@ class TestMassEditing(common.TransactionCase): 'Partner\'s category should be removed.') # Add m2m categories dist_categ_id = self.env.ref('base.res_partner_category_13').id + vend_categ_id = self.env.ref('base.res_partner_category_1').id vals = { 'selection__category_id': 'add', - 'category_id': [[6, 0, [dist_categ_id]]], + 'category_id': [[6, 0, [dist_categ_id, vend_categ_id]]], } wiz_action = self._apply_action(self.partner, vals) - self.assertTrue(dist_categ_id in self.partner.category_id.ids, + self.assertTrue(all(item in self.partner.category_id.ids + for item in [dist_categ_id, vend_categ_id]), 'Partner\'s category should be added.') + # Remove one m2m category + vals = { + 'selection__category_id': 'remove_m2m', + 'category_id': [[6, 0, [vend_categ_id]]], + } + wiz_action = self._apply_action(self.partner, vals) + self.assertTrue([dist_categ_id] == self.partner.category_id.ids, + 'Partner\'s category should be removed.') # Check window close action res = wiz_action.action_apply() self.assertTrue(res['type'] == 'ir.actions.act_window_close', @@ -142,21 +172,23 @@ class TestMassEditing(common.TransactionCase): 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 + action = self.mass.ref_ir_act_window_id\ + and self.mass.ref_ir_act_window_id.binding_model_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 + action = self.mass.ref_ir_act_window_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) + mass_action_id = self.mass.ref_ir_act_window_id.id + mass_object_id = self.mass.id + mass_id = self.env['mass.object'].browse(mass_object_id) + mass_id.unlink() + value_cnt = self.env['ir.actions.act_window'].search([ + ('id', '=', mass_action_id)], count=True) self.assertTrue(value_cnt == 0, "Sidebar action must be removed when mass" " editing is unlinked.") @@ -165,10 +197,9 @@ class TestMassEditing(common.TransactionCase): """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) + mass_action_id = self.mass.ref_ir_act_window_id.id + value_cnt = len(self.env['ir.actions.act_window'].browse( + mass_action_id)) 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 5e5c381..cf0c9a8 100644 --- a/mass_editing/views/mass_editing_view.xml +++ b/mass_editing/views/mass_editing_view.xml @@ -41,12 +41,11 @@ + domain="[('ttype', 'not in', ['reference', 'function']), ('mass_editing_domain', 'in', model_list)]"/> - diff --git a/mass_editing/wizard/mass_editing_wizard.py b/mass_editing/wizard/mass_editing_wizard.py index bee0ab2..7b95c39 100644 --- a/mass_editing/wizard/mass_editing_wizard.py +++ b/mass_editing/wizard/mass_editing_wizard.py @@ -246,7 +246,14 @@ class MassEditingWizard(models.TransientModel): elif val == 'remove': values.update({split_key: False}) elif val == 'remove_m2m': - values.update({split_key: [(5, 0, [])]}) + m2m_list = [] + if vals.get(split_key): + for m2m_id in vals.get(split_key)[0][2]: + m2m_list.append((3, m2m_id)) + if m2m_list: + values.update({split_key: m2m_list}) + else: + values.update({split_key: [(5, 0, [])]}) elif val == 'add': m2m_list = [] for m2m_id in vals.get(split_key, False)[0][2]: @@ -271,4 +278,7 @@ class MassEditingWizard(models.TransientModel): if fields: # We remove fields which are not in _fields real_fields = [x for x in fields if x in self._fields] - return super(MassEditingWizard, self).read(real_fields, load=load) + result = super(MassEditingWizard, self).read(real_fields, load=load) + # adding fields to result + [result[0].update({x: False}) for x in fields if x not in real_fields] + return result