Browse Source
Added Mass Editing v9 (#315)
Added Mass Editing v9 (#315)
* Added Mass Editing v9 * [IMP] Improved the coding standard as per API and PEP8. * [ADD] Added README and index file. * [IMP] Improved the indentation of the code as per travis test suggestion. * [IMP] Improved the README.rst * Update mass_object.py * Delete index.html * [ADD] Added unit test cases for MassEditing module. * Corrected as per @api.multi * Correction for the travis test * Correction for the travis test * [IMP] Improved the code as per review comments, improved copyrights, added test more cases and uninstall hook. * [ADD] Added Unit test case for m2m fields. * [ADD] Further added unit test case for unlink and multiple fields. * [ADD] Added unit test case for model_id onchange. * [IMP] Fixed the issue of eval in unit test case. * [ADD] Added unit test case for uninstall hook. * [ADD] Added unit test case for uninstall hook. * [ADD] Added unit test case for wizard's fields_view_get method. * [IMP] Improved the unit test case to cover more lines of code of fields view get. * [IMP] Improved the unit test case to cover more lines of code of fields view get.pull/5/head
Serpent Consulting Services Pvt Ltd
8 years ago
committed by
Pedro M. Baeza
28 changed files with 718 additions and 501 deletions
-
21mass_editing/ChangeLog.txt
-
109mass_editing/README.rst
-
24mass_editing/__init__.py
-
57mass_editing/__openerp__.py
-
12mass_editing/hooks.py
-
8mass_editing/i18n/de.po
-
8mass_editing/i18n/es.po
-
8mass_editing/i18n/fr.po
-
8mass_editing/i18n/fr_CA.po
-
8mass_editing/i18n/it.po
-
8mass_editing/i18n/mass_editing.pot
-
8mass_editing/i18n/pt_BR.po
-
8mass_editing/i18n/ru.po
-
8mass_editing/i18n/sl.po
-
22mass_editing/models/__init__.py
-
46mass_editing/models/ir_model_fields.py
-
196mass_editing/models/mass_object.py
-
0mass_editing/security/ir.model.access.csv
-
BINmass_editing/static/description/mass_editing-1.png
-
BINmass_editing/static/description/mass_editing-2.png
-
BINmass_editing/static/description/mass_editing-3.png
-
BINmass_editing/static/description/mass_editing-4.png
-
BINmass_editing/static/description/mass_editing-5.png
-
5mass_editing/tests/__init__.py
-
174mass_editing/tests/test_mass_editing.py
-
174mass_editing/views/mass_editing_view.xml
-
22mass_editing/wizard/__init__.py
-
285mass_editing/wizard/mass_editing_wizard.py
@ -1,11 +1,20 @@ |
|||||
=============================================================================== |
=============================================================================== |
||||
Version Change Log (mass_editing) |
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 |
@ -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 |
||||
|
<https://github.com/OCA/server-tools/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 |
||||
|
<https://github.com/OCA/ |
||||
|
server-tools/issues/new?body=module:%20 |
||||
|
server-tools%0Aversion:%20 |
||||
|
9.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Images |
||||
|
------ |
||||
|
|
||||
|
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_. |
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
|
||||
|
* Oihane Crucelaegui <oihanecrucelaegi@gmail.com> |
||||
|
* Serpent Consulting Services Pvt. Ltd. <support@serpentcs.com> |
||||
|
|
||||
|
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. |
||||
|
|
@ -1,24 +1,8 @@ |
|||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
############################################################################## |
|
||||
# |
|
||||
# This module uses OpenERP, Open Source Management Solution Framework. |
|
||||
# Copyright (C): |
|
||||
# 2012-Today Serpent Consulting Services (<http://www.serpentcs. |
|
||||
# |
|
||||
# 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 <http://www.gnu.org/licenses/> |
|
||||
# |
|
||||
############################################################################## |
|
||||
|
# © 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 models |
||||
from . import wizard |
from . import wizard |
||||
|
from . import tests |
||||
|
from .hooks import uninstall_hook |
@ -1,51 +1,26 @@ |
|||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
############################################################################## |
|
||||
# |
|
||||
# This module uses OpenERP, Open Source Management Solution Framework. |
|
||||
# Copyright (C): |
|
||||
# 2012-Today Serpent Consulting Services (<http://www.serpentcs.com>) |
|
||||
# |
|
||||
# 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 <http://www.gnu.org/licenses/> |
|
||||
# |
|
||||
############################################################################## |
|
||||
|
# © 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 <oihanecrucelaegi@gmail.com>", |
|
||||
|
'name': 'Mass Editing', |
||||
|
'version': '9.0.1.0.0', |
||||
|
'author': 'Serpent Consulting Services Pvt. Ltd., ' |
||||
|
'Odoo Community Association (OCA)', |
||||
|
'contributors': [ |
||||
|
'Oihane Crucelaegui <oihanecrucelaegi@gmail.com>', |
||||
|
'Serpent Consulting Services Pvt. Ltd. <support@serpentcs.com>', |
||||
], |
], |
||||
"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'], |
'depends': ['base'], |
||||
'data': [ |
'data': [ |
||||
"security/ir.model.access.csv", |
|
||||
|
'security/ir.model.access.csv', |
||||
'views/mass_editing_view.xml', |
'views/mass_editing_view.xml', |
||||
], |
], |
||||
'installable': True, |
'installable': True, |
||||
'application': True, |
|
||||
|
'application': False, |
||||
'auto_install': False, |
'auto_install': False, |
||||
} |
} |
@ -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 |
@ -1,24 +1,6 @@ |
|||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
############################################################################## |
|
||||
# |
|
||||
# This module uses OpenERP, Open Source Management Solution Framework. |
|
||||
# Copyright (C): |
|
||||
# 2012-Today Serpent Consulting Services (<http://www.serpentcs.com>) |
|
||||
# |
|
||||
# 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 <http://www.gnu.org/licenses/> |
|
||||
# |
|
||||
############################################################################## |
|
||||
|
# © 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 ir_model_fields |
||||
from . import mass_object |
from . import mass_object |
@ -1,45 +1,23 @@ |
|||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
############################################################################## |
|
||||
# |
|
||||
# This module uses OpenERP, Open Source Management Solution Framework. |
|
||||
# Copyright (C): |
|
||||
# 2012-Today Serpent Consulting Services (<http://www.serpentcs.com>) |
|
||||
# |
|
||||
# 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 <http://www.gnu.org/licenses/> |
|
||||
# |
|
||||
############################################################################## |
|
||||
|
# © 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' |
_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 = [] |
model_domain = [] |
||||
for domain in args: |
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)): |
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: |
else: |
||||
model_domain.append(domain) |
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) |
@ -1,138 +1,102 @@ |
|||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
############################################################################## |
|
||||
# |
|
||||
# This module uses OpenERP, Open Source Management Solution Framework. |
|
||||
# Copyright (C): |
|
||||
# 2012-Today Serpent Consulting Services (<http://www.serpentcs.com>) |
|
||||
# |
|
||||
# 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 <http://www.gnu.org/licenses/> |
|
||||
# |
|
||||
############################################################################## |
|
||||
|
# © 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" |
_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 = [ |
_sql_constraints = [ |
||||
('name_uniq', 'unique (name)', _('Name must be unique!')), |
('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 = {} |
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 |
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: |
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: |
except: |
||||
raise orm.except_orm( |
|
||||
_("Warning"), |
|
||||
_("Deletion of the action record failed.")) |
|
||||
|
raise UserError(_("Deletion of the action record failed.")) |
||||
return True |
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: |
if default is None: |
||||
default = {} |
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) |
After Width: 1366 | Height: 570 | Size: 66 KiB |
After Width: 1366 | Height: 518 | Size: 69 KiB |
After Width: 1366 | Height: 333 | Size: 70 KiB |
After Width: 1366 | Height: 340 | Size: 50 KiB |
After Width: 1366 | Height: 329 | Size: 57 KiB |
@ -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 |
@ -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.") |
@ -1,98 +1,96 @@ |
|||||
<?xml version="1.0" encoding="UTF-8"?> |
<?xml version="1.0" encoding="UTF-8"?> |
||||
<openerp> |
|
||||
<data> |
|
||||
|
<odoo> |
||||
|
|
||||
<record model="ir.ui.view" id="view_mass_object_form"> |
|
||||
<field name="name">mass.object.form</field> |
|
||||
<field name="model">mass.object</field> |
|
||||
<field name="arch" type="xml"> |
|
||||
<form string="Object"> |
|
||||
<sheet> |
|
||||
<div class="oe_title"> |
|
||||
<label for="name" class="oe_edit_only" /> |
|
||||
<h1> |
|
||||
<field name="name" required="1" /> |
|
||||
</h1> |
|
||||
|
<record model="ir.ui.view" id="view_mass_object_form"> |
||||
|
<field name="name">mass.object.form</field> |
||||
|
<field name="model">mass.object</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Object"> |
||||
|
<sheet> |
||||
|
<div class="oe_title"> |
||||
|
<label for="name" class="oe_edit_only"/> |
||||
|
<h1> |
||||
|
<field name="name" required="1"/> |
||||
|
</h1> |
||||
|
<group> |
||||
<group> |
<group> |
||||
<field name="model_id" required="1" |
|
||||
on_change="onchange_model_id(model_id)" /> |
|
||||
<field name="model_ids" invisible="1" /> |
|
||||
|
<field name="model_id" required="1" attrs="{'readonly':[('ref_ir_act_window_id','!=',False)]}"/> |
||||
</group> |
</group> |
||||
</div> |
|
||||
<div class="oe_right oe_button_box" name="buttons"> |
|
||||
<field name="ref_ir_act_window" |
|
||||
invisible="1" /> |
|
||||
<button class="oe_inline oe_stat_button" |
|
||||
name="create_action" type="object" |
|
||||
attrs="{'invisible':[('ref_ir_act_window','!=',False)]}" |
|
||||
icon="fa-plus" |
|
||||
help="Display a button in the sidebar of related documents to open a composition wizard"> |
|
||||
<div>Add<br />Sidebar Button</div> |
|
||||
</button> |
|
||||
<button name="unlink_action" type="object" |
|
||||
class="oe_stat_button" icon="fa-minus" |
|
||||
attrs="{'invisible':[('ref_ir_act_window','=',False)]}" |
|
||||
help="Remove the contextual action to use this template on related documents" |
|
||||
widget="statinfo"> |
|
||||
<div>Remove<br />Sidebar Button</div> |
|
||||
</button> |
|
||||
</div> |
|
||||
|
|
||||
<notebook colspan="4"> |
|
||||
<page string="Fields"> |
|
||||
<field name="field_ids" colspan="4" |
|
||||
nolabel="1" |
|
||||
domain="[('ttype', 'not in', ['reference', 'function']), ('model_id', 'in', model_ids[0][2])]" /> |
|
||||
</page> |
|
||||
<page string="Advanced" attrs="{'invisible':[('ref_ir_act_window','=',False)]}"> |
|
||||
<group colspan="2" col="2"> |
|
||||
<field name="ref_ir_act_window" /> |
|
||||
<field name="ref_ir_value" /> |
|
||||
</group> |
|
||||
</page> |
|
||||
</notebook> |
|
||||
</sheet> |
|
||||
</form> |
|
||||
</field> |
|
||||
</record> |
|
||||
|
<group> |
||||
|
<field name="model_list" invisible="1"/> |
||||
|
</group> |
||||
|
</group> |
||||
|
</div> |
||||
|
<div class="oe_right oe_button_box" name="buttons"> |
||||
|
<field name="ref_ir_act_window_id" invisible="1"/> |
||||
|
<button name="create_action" |
||||
|
type="object" |
||||
|
string="Add Sidebar Button" |
||||
|
class="oe_inline oe_stat_button" |
||||
|
attrs="{'invisible':[('ref_ir_act_window_id','!=',False)]}" |
||||
|
icon="fa-plus" |
||||
|
help="Display a button in the sidebar of related documents to open a composition wizard"/> |
||||
|
<button name="unlink_action" |
||||
|
type="object" |
||||
|
string="Remove Sidebar Button" |
||||
|
class="oe_stat_button" icon="fa-minus" |
||||
|
attrs="{'invisible':[('ref_ir_act_window_id','=',False)]}" |
||||
|
help="Remove the contextual action to use this template on related documents" |
||||
|
widget="statinfo"/> |
||||
|
</div> |
||||
|
<notebook colspan="4"> |
||||
|
<page string="Fields"> |
||||
|
<field name="field_ids" colspan="4" nolabel="1" |
||||
|
domain="[('ttype', 'not in', ['refenrence', 'function']), ('model_id', 'in', model_list)]"/> |
||||
|
</page> |
||||
|
<page string="Advanced" attrs="{'invisible':[('ref_ir_act_window_id','=',False)]}"> |
||||
|
<group colspan="2" col="2"> |
||||
|
<field name="ref_ir_act_window_id"/> |
||||
|
<field name="ref_ir_value_id"/> |
||||
|
</group> |
||||
|
</page> |
||||
|
</notebook> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
<record model="ir.ui.view" id="view_mass_object_tree"> |
|
||||
<field name="name">mass.object.tree</field> |
|
||||
<field name="model">mass.object</field> |
|
||||
<field name="arch" type="xml"> |
|
||||
<tree string="Object"> |
|
||||
<field name="name" /> |
|
||||
<field name="model_id" /> |
|
||||
</tree> |
|
||||
</field> |
|
||||
</record> |
|
||||
|
<record model="ir.ui.view" id="view_mass_object_tree"> |
||||
|
<field name="name">mass.object.tree</field> |
||||
|
<field name="model">mass.object</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Object"> |
||||
|
<field name="name"/> |
||||
|
<field name="model_id"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
<record model="ir.actions.act_window" id="action_mass_object_form"> |
|
||||
<field name="name">Mass Editing</field> |
|
||||
<field name="res_model">mass.object</field> |
|
||||
<field name="view_type">form</field> |
|
||||
<field name="view_mode">tree,form</field> |
|
||||
<field name="view_id" ref="view_mass_object_tree" /> |
|
||||
</record> |
|
||||
|
<record model="ir.actions.act_window" id="action_mass_object_form"> |
||||
|
<field name="name">Mass Editing</field> |
||||
|
<field name="res_model">mass.object</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
<field name="view_id" ref="view_mass_object_tree"/> |
||||
|
</record> |
||||
|
|
||||
<record id="action_mass_object_form_view1" model="ir.actions.act_window.view"> |
|
||||
<field eval="10" name="sequence" /> |
|
||||
<field name="view_mode">tree</field> |
|
||||
<field name="view_id" ref="view_mass_object_tree" /> |
|
||||
<field name="act_window_id" ref="action_mass_object_form" /> |
|
||||
</record> |
|
||||
<record id="action_mass_object_form_view2" model="ir.actions.act_window.view"> |
|
||||
<field eval="20" name="sequence" /> |
|
||||
<field name="view_mode">form</field> |
|
||||
<field name="view_id" ref="view_mass_object_form" /> |
|
||||
<field name="act_window_id" ref="action_mass_object_form" /> |
|
||||
</record> |
|
||||
|
<record id="action_mass_object_form_view1" model="ir.actions.act_window.view"> |
||||
|
<field eval="10" name="sequence"/> |
||||
|
<field name="view_mode">tree</field> |
||||
|
<field name="view_id" ref="view_mass_object_tree"/> |
||||
|
<field name="act_window_id" ref="action_mass_object_form"/> |
||||
|
</record> |
||||
|
<record id="action_mass_object_form_view2" model="ir.actions.act_window.view"> |
||||
|
<field eval="20" name="sequence"/> |
||||
|
<field name="view_mode">form</field> |
||||
|
<field name="view_id" ref="view_mass_object_form"/> |
||||
|
<field name="act_window_id" ref="action_mass_object_form"/> |
||||
|
</record> |
||||
|
|
||||
<menuitem id="menu_mass_editing" name="Mass Editing" |
|
||||
parent="base.menu_administration" sequence="6" /> |
|
||||
|
<menuitem id="menu_mass_editing" name="Mass Editing" |
||||
|
parent="base.menu_administration" sequence="6"/> |
||||
|
|
||||
<menuitem id="menu_mass_object_view" action="action_mass_object_form" |
|
||||
parent="menu_mass_editing" /> |
|
||||
|
<menuitem id="menu_mass_object_view" action="action_mass_object_form" |
||||
|
parent="menu_mass_editing"/> |
||||
|
|
||||
</data> |
|
||||
</openerp> |
|
||||
|
</odoo> |
@ -1,23 +1,5 @@ |
|||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
############################################################################## |
|
||||
# |
|
||||
# This module uses OpenERP, Open Source Management Solution Framework. |
|
||||
# Copyright (C): |
|
||||
# 2012-Today Serpent Consulting Services (<http://www.serpentcs. |
|
||||
# |
|
||||
# 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 <http://www.gnu.org/licenses/> |
|
||||
# |
|
||||
############################################################################## |
|
||||
|
# © 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 |
from . import mass_editing_wizard |
@ -1,213 +1,258 @@ |
|||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
############################################################################## |
|
||||
# |
|
||||
# This module uses OpenERP, Open Source Management Solution Framework. |
|
||||
# Copyright (C): |
|
||||
# 2012-Today Serpent Consulting Services (<http://www.serpentcs.com>) |
|
||||
# |
|
||||
# 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 <http://www.gnu.org/licenses/> |
|
||||
# |
|
||||
############################################################################## |
|
||||
|
# © 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 |
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' |
_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'): |
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 = {} |
all_fields = {} |
||||
xml_form = etree.Element('form', { |
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', { |
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: |
for field in editing_data.field_ids: |
||||
if field.ttype == "many2many": |
if field.ttype == "many2many": |
||||
all_fields[field.name] = field_info[field.name] |
all_fields[field.name] = field_info[field.name] |
||||
all_fields["selection__" + field.name] = { |
all_fields["selection__" + field.name] = { |
||||
'type': 'selection', |
'type': 'selection', |
||||
'string': field_info[field.name]['string'], |
'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', { |
xml_group = etree.SubElement(xml_group, 'group', { |
||||
'colspan': '4'}) |
|
||||
|
'colspan': '6', |
||||
|
'col': '6', |
||||
|
}) |
||||
etree.SubElement(xml_group, 'separator', { |
etree.SubElement(xml_group, 'separator', { |
||||
'string': field_info[field.name]['string'], |
'string': field_info[field.name]['string'], |
||||
'colspan': '2'}) |
|
||||
|
'colspan': '6', |
||||
|
}) |
||||
etree.SubElement(xml_group, 'field', { |
etree.SubElement(xml_group, 'field', { |
||||
'name': "selection__" + field.name, |
'name': "selection__" + field.name, |
||||
'colspan': '2', 'nolabel': '1'}) |
|
||||
|
'colspan': '6', |
||||
|
'nolabel': '1' |
||||
|
}) |
||||
etree.SubElement(xml_group, 'field', { |
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": |
elif field.ttype == "one2many": |
||||
all_fields["selection__" + field.name] = { |
all_fields["selection__" + field.name] = { |
||||
'type': 'selection', |
'type': 'selection', |
||||
'string': field_info[field.name]['string'], |
'string': field_info[field.name]['string'], |
||||
'selection': [('set', 'Set'), ('remove', 'Remove')]} |
|
||||
|
'selection': [('set', 'Set'), ('remove', 'Remove')], |
||||
|
} |
||||
all_fields[field.name] = { |
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', { |
etree.SubElement(xml_group, 'field', { |
||||
'name': "selection__" + field.name, 'colspan': '2'}) |
|
||||
|
'name': "selection__" + field.name, |
||||
|
'colspan': '4', |
||||
|
}) |
||||
etree.SubElement(xml_group, 'field', { |
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": |
elif field.ttype == "many2one": |
||||
all_fields["selection__" + field.name] = { |
all_fields["selection__" + field.name] = { |
||||
'type': 'selection', |
'type': 'selection', |
||||
'string': field_info[field.name]['string'], |
'string': field_info[field.name]['string'], |
||||
'selection': [('set', 'Set'), ('remove', 'Remove')]} |
|
||||
|
'selection': [('set', 'Set'), ('remove', 'Remove')], |
||||
|
} |
||||
all_fields[field.name] = { |
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', { |
etree.SubElement(xml_group, 'field', { |
||||
'name': "selection__" + field.name, 'colspan': '2'}) |
|
||||
|
'name': "selection__" + field.name, |
||||
|
'colspan': '2', |
||||
|
}) |
||||
etree.SubElement(xml_group, 'field', { |
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": |
elif field.ttype == "char": |
||||
all_fields["selection__" + field.name] = { |
all_fields["selection__" + field.name] = { |
||||
'type': 'selection', |
'type': 'selection', |
||||
'string': field_info[field.name]['string'], |
'string': field_info[field.name]['string'], |
||||
'selection': [('set', 'Set'), ('remove', 'Remove')]} |
|
||||
|
'selection': [('set', 'Set'), ('remove', 'Remove')], |
||||
|
} |
||||
all_fields[field.name] = { |
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', { |
etree.SubElement(xml_group, 'field', { |
||||
'name': "selection__" + field.name, |
'name': "selection__" + field.name, |
||||
'colspan': '2', |
'colspan': '2', |
||||
}) |
|
||||
|
}) |
||||
etree.SubElement(xml_group, 'field', { |
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': |
elif field.ttype == 'selection': |
||||
all_fields["selection__" + field.name] = { |
all_fields["selection__" + field.name] = { |
||||
'type': 'selection', |
'type': 'selection', |
||||
'string': field_info[field.name]['string'], |
'string': field_info[field.name]['string'], |
||||
'selection': [('set', 'Set'), ('remove', 'Remove')]} |
|
||||
|
'selection': [('set', 'Set'), ('remove', 'Remove')] |
||||
|
} |
||||
etree.SubElement(xml_group, 'field', { |
etree.SubElement(xml_group, 'field', { |
||||
'name': "selection__" + field.name, 'colspan': '2'}) |
|
||||
|
'name': "selection__" + field.name, |
||||
|
'colspan': '2', |
||||
|
}) |
||||
etree.SubElement(xml_group, 'field', { |
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] = { |
all_fields[field.name] = { |
||||
'type': field.ttype, |
'type': field.ttype, |
||||
'string': field.field_description, |
'string': field.field_description, |
||||
'selection': field_info[field.name]['selection']} |
|
||||
|
'selection': field_info[field.name]['selection'], |
||||
|
} |
||||
else: |
else: |
||||
all_fields[field.name] = { |
all_fields[field.name] = { |
||||
'type': field.ttype, 'string': field.field_description} |
|
||||
|
'type': field.ttype, |
||||
|
'string': field.field_description, |
||||
|
} |
||||
all_fields["selection__" + field.name] = { |
all_fields["selection__" + field.name] = { |
||||
'type': 'selection', |
'type': 'selection', |
||||
'string': field_info[field.name]['string'], |
'string': field_info[field.name]['string'], |
||||
'selection': [('set', 'Set'), ('remove', 'Remove')]} |
|
||||
|
'selection': [('set', 'Set'), ('remove', 'Remove')] |
||||
|
} |
||||
if field.ttype == 'text': |
if field.ttype == 'text': |
||||
xml_group = etree.SubElement(xml_group, 'group', { |
xml_group = etree.SubElement(xml_group, 'group', { |
||||
'colspan': '6'}) |
|
||||
|
'colspan': '6', |
||||
|
'col': '6', |
||||
|
}) |
||||
etree.SubElement(xml_group, 'separator', { |
etree.SubElement(xml_group, 'separator', { |
||||
'string': all_fields[field.name]['string'], |
'string': all_fields[field.name]['string'], |
||||
'colspan': '2'}) |
|
||||
|
'colspan': '6', |
||||
|
}) |
||||
etree.SubElement(xml_group, 'field', { |
etree.SubElement(xml_group, 'field', { |
||||
'name': "selection__" + field.name, |
'name': "selection__" + field.name, |
||||
'colspan': '2', 'nolabel': '1'}) |
|
||||
|
'colspan': '6', |
||||
|
'nolabel': '1', |
||||
|
}) |
||||
etree.SubElement(xml_group, 'field', { |
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: |
else: |
||||
all_fields["selection__" + field.name] = { |
all_fields["selection__" + field.name] = { |
||||
'type': 'selection', |
'type': 'selection', |
||||
'string': field_info[field.name]['string'], |
'string': field_info[field.name]['string'], |
||||
'selection': [( |
|
||||
'set', 'Set'), ('remove', 'Remove')]} |
|
||||
|
'selection': [('set', 'Set'), ('remove', 'Remove')] |
||||
|
} |
||||
etree.SubElement(xml_group, 'field', { |
etree.SubElement(xml_group, 'field', { |
||||
'name': "selection__" + field.name, |
'name': "selection__" + field.name, |
||||
'colspan': '2', }) |
|
||||
|
'colspan': '2', |
||||
|
}) |
||||
etree.SubElement(xml_group, 'field', { |
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', {}) |
xml_group3 = etree.SubElement(xml_form, 'footer', {}) |
||||
etree.SubElement(xml_group3, 'button', { |
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', { |
etree.SubElement(xml_group3, 'button', { |
||||
'string': 'Close', 'icon': "gtk-close", 'special': 'cancel'}) |
|
||||
|
'string': 'Close', |
||||
|
'class': 'btn-default', |
||||
|
'special': 'cancel', |
||||
|
}) |
||||
root = xml_form.getroottree() |
root = xml_form.getroottree() |
||||
result['arch'] = etree.tostring(root) |
result['arch'] = etree.tostring(root) |
||||
result['fields'] = all_fields |
result['fields'] = all_fields |
||||
return result |
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(): |
for key, val in vals.items(): |
||||
if key.startswith('selection__'): |
|
||||
|
if key.startswith('selection_'): |
||||
split_key = key.split('__', 1)[1] |
split_key = key.split('__', 1)[1] |
||||
if val == 'set': |
if val == 'set': |
||||
dict.update({split_key: vals.get(split_key, False)}) |
|
||||
|
values.update({split_key: vals.get(split_key, False)}) |
||||
elif val == 'remove': |
elif val == 'remove': |
||||
dict.update({split_key: False}) |
|
||||
|
values.update({split_key: False}) |
||||
elif val == 'remove_m2m': |
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': |
elif val == 'add': |
||||
m2m_list = [] |
m2m_list = [] |
||||
for m2m_id in vals.get(split_key, False)[0][2]: |
for m2m_id in vals.get(split_key, False)[0][2]: |
||||
m2m_list.append((4, m2m_id)) |
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'} |
return {'type': 'ir.actions.act_window_close'} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue