Browse Source

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
parent
commit
32c3ef88eb
  1. 9
      mass_editing/ChangeLog.txt
  2. 109
      mass_editing/README.rst
  3. 24
      mass_editing/__init__.py
  4. 57
      mass_editing/__openerp__.py
  5. 12
      mass_editing/hooks.py
  6. 8
      mass_editing/i18n/de.po
  7. 8
      mass_editing/i18n/es.po
  8. 8
      mass_editing/i18n/fr.po
  9. 8
      mass_editing/i18n/fr_CA.po
  10. 8
      mass_editing/i18n/it.po
  11. 8
      mass_editing/i18n/mass_editing.pot
  12. 8
      mass_editing/i18n/pt_BR.po
  13. 8
      mass_editing/i18n/ru.po
  14. 8
      mass_editing/i18n/sl.po
  15. 22
      mass_editing/models/__init__.py
  16. 46
      mass_editing/models/ir_model_fields.py
  17. 174
      mass_editing/models/mass_object.py
  18. 0
      mass_editing/security/ir.model.access.csv
  19. BIN
      mass_editing/static/description/mass_editing-1.png
  20. BIN
      mass_editing/static/description/mass_editing-2.png
  21. BIN
      mass_editing/static/description/mass_editing-3.png
  22. BIN
      mass_editing/static/description/mass_editing-4.png
  23. BIN
      mass_editing/static/description/mass_editing-5.png
  24. 5
      mass_editing/tests/__init__.py
  25. 174
      mass_editing/tests/test_mass_editing.py
  26. 78
      mass_editing/views/mass_editing_view.xml
  27. 22
      mass_editing/wizard/__init__.py
  28. 279
      mass_editing/wizard/mass_editing_wizard.py

9
mass_editing/ChangeLog.txt

@ -1,6 +1,15 @@
=============================================================================== ===============================================================================
Version Change Log (mass_editing) 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 1.3 * March 11,2013 : Serpent Consulting Services
* Improved and optimized the code of mass_editing * Improved and optimized the code of mass_editing

109
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
<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.

24
mass_editing/__init__.py

@ -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

57
mass_editing/__openerp__.py

@ -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,
} }

12
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

8
mass_editing/i18n/de.po

@ -124,25 +124,25 @@ msgid "Remove the contextual action to use this template on related documents"
msgstr "" msgstr ""
#. module: mass_editing #. module: mass_editing
#: field:mass.object,ref_ir_act_window:0
#: field:mass.object,ref_ir_act_window_id:0
msgid "Sidebar Action" msgid "Sidebar Action"
msgstr "Sidebar-Aktion" msgstr "Sidebar-Aktion"
#. module: mass_editing #. module: mass_editing
#: view:mass.object:mass_editing.view_mass_object_form #: 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" msgid "Sidebar Button"
msgstr "Sidebar-Button" msgstr "Sidebar-Button"
#. module: mass_editing #. module: mass_editing
#: help:mass.object,ref_ir_act_window:0
#: help:mass.object,ref_ir_act_window_id:0
msgid "" msgid ""
"Sidebar action to make this template available on records " "Sidebar action to make this template available on records "
"of the related document model" "of the related document model"
msgstr "" msgstr ""
#. module: mass_editing #. 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" msgid "Sidebar button to open the sidebar action"
msgstr "Siebar-Button zum Öffnen einer Sidebar-Aktion" msgstr "Siebar-Button zum Öffnen einer Sidebar-Aktion"

8
mass_editing/i18n/es.po

@ -124,25 +124,25 @@ msgid "Remove the contextual action to use this template on related documents"
msgstr "" msgstr ""
#. module: mass_editing #. module: mass_editing
#: field:mass.object,ref_ir_act_window:0
#: field:mass.object,ref_ir_act_window_id:0
msgid "Sidebar Action" msgid "Sidebar Action"
msgstr "Acción del menú contextual" msgstr "Acción del menú contextual"
#. module: mass_editing #. module: mass_editing
#: view:mass.object:mass_editing.view_mass_object_form #: 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" msgid "Sidebar Button"
msgstr "Botón del menú contextual" msgstr "Botón del menú contextual"
#. module: mass_editing #. module: mass_editing
#: help:mass.object,ref_ir_act_window:0
#: help:mass.object,ref_ir_act_window_id:0
msgid "" msgid ""
"Sidebar action to make this template available on records " "Sidebar action to make this template available on records "
"of the related document model" "of the related document model"
msgstr "" msgstr ""
#. module: mass_editing #. 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" msgid "Sidebar button to open the sidebar action"
msgstr "Botón del menú contextual para abrir la acción del menú contextual" msgstr "Botón del menú contextual para abrir la acción del menú contextual"

8
mass_editing/i18n/fr.po

@ -125,25 +125,25 @@ msgid "Remove the contextual action to use this template on related documents"
msgstr "" msgstr ""
#. module: mass_editing #. module: mass_editing
#: field:mass.object,ref_ir_act_window:0
#: field:mass.object,ref_ir_act_window_id:0
msgid "Sidebar Action" msgid "Sidebar Action"
msgstr "" msgstr ""
#. module: mass_editing #. module: mass_editing
#: view:mass.object:mass_editing.view_mass_object_form #: 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" msgid "Sidebar Button"
msgstr "" msgstr ""
#. module: mass_editing #. module: mass_editing
#: help:mass.object,ref_ir_act_window:0
#: help:mass.object,ref_ir_act_window_id:0
msgid "" msgid ""
"Sidebar action to make this template available on records " "Sidebar action to make this template available on records "
"of the related document model" "of the related document model"
msgstr "" msgstr ""
#. module: mass_editing #. 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" msgid "Sidebar button to open the sidebar action"
msgstr "" msgstr ""

8
mass_editing/i18n/fr_CA.po

@ -125,25 +125,25 @@ msgid "Remove the contextual action to use this template on related documents"
msgstr "" msgstr ""
#. module: mass_editing #. module: mass_editing
#: field:mass.object,ref_ir_act_window:0
#: field:mass.object,ref_ir_act_window_id:0
msgid "Sidebar Action" msgid "Sidebar Action"
msgstr "Action du menu latéral" msgstr "Action du menu latéral"
#. module: mass_editing #. module: mass_editing
#: view:mass.object:mass_editing.view_mass_object_form #: 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" msgid "Sidebar Button"
msgstr "Bouton du menu latéral" msgstr "Bouton du menu latéral"
#. module: mass_editing #. module: mass_editing
#: help:mass.object,ref_ir_act_window:0
#: help:mass.object,ref_ir_act_window_id:0
msgid "" msgid ""
"Sidebar action to make this template available on records " "Sidebar action to make this template available on records "
"of the related document model" "of the related document model"
msgstr "" msgstr ""
#. module: mass_editing #. 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" msgid "Sidebar button to open the sidebar action"
msgstr "" msgstr ""

8
mass_editing/i18n/it.po

@ -124,25 +124,25 @@ msgid "Remove the contextual action to use this template on related documents"
msgstr "" msgstr ""
#. module: mass_editing #. module: mass_editing
#: field:mass.object,ref_ir_act_window:0
#: field:mass.object,ref_ir_act_window_id:0
msgid "Sidebar Action" msgid "Sidebar Action"
msgstr "" msgstr ""
#. module: mass_editing #. module: mass_editing
#: view:mass.object:mass_editing.view_mass_object_form #: 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" msgid "Sidebar Button"
msgstr "" msgstr ""
#. module: mass_editing #. module: mass_editing
#: help:mass.object,ref_ir_act_window:0
#: help:mass.object,ref_ir_act_window_id:0
msgid "" msgid ""
"Sidebar action to make this template available on records " "Sidebar action to make this template available on records "
"of the related document model" "of the related document model"
msgstr "" msgstr ""
#. module: mass_editing #. 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" msgid "Sidebar button to open the sidebar action"
msgstr "" msgstr ""

8
mass_editing/i18n/mass_editing.pot

@ -82,7 +82,7 @@ msgid "Name must be unique!"
msgstr "" msgstr ""
#. module: mass_editing #. module: mass_editing
#: field:mass.object,ref_ir_act_window:0
#: field:mass.object,ref_ir_act_window_id:0
msgid "Sidebar Action" msgid "Sidebar Action"
msgstr "" msgstr ""
@ -92,7 +92,7 @@ msgid "Remove sidebar button"
msgstr "" msgstr ""
#. module: mass_editing #. module: mass_editing
#: field:mass.object,ref_ir_value:0
#: field:mass.object,ref_ir_value_id:0
msgid "Sidebar Button" msgid "Sidebar Button"
msgstr "" msgstr ""
@ -108,7 +108,7 @@ msgid "Warning"
msgstr "" msgstr ""
#. module: mass_editing #. 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" msgid "Sidebar action to make this template available on records of the related document model"
msgstr "" msgstr ""
@ -123,7 +123,7 @@ msgid "Advanced"
msgstr "" msgstr ""
#. module: mass_editing #. 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" msgid "Sidebar button to open the sidebar action"
msgstr "" msgstr ""

8
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" msgstr "Remover a ação contextual para usar este modelo nos documentos relacionados"
#. module: mass_editing #. module: mass_editing
#: field:mass.object,ref_ir_act_window:0
#: field:mass.object,ref_ir_act_window_id:0
msgid "Sidebar Action" msgid "Sidebar Action"
msgstr "Ação da Barra Lateral" msgstr "Ação da Barra Lateral"
#. module: mass_editing #. module: mass_editing
#: view:mass.object:mass_editing.view_mass_object_form #: 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" msgid "Sidebar Button"
msgstr "Botão da Barra Lateral" msgstr "Botão da Barra Lateral"
#. module: mass_editing #. module: mass_editing
#: help:mass.object,ref_ir_act_window:0
#: help:mass.object,ref_ir_act_window_id:0
msgid "" msgid ""
"Sidebar action to make this template available on records " "Sidebar action to make this template available on records "
"of the related document model" "of the related document model"
msgstr "Ação da Barra Lateral para fazer este modelo disponível nos registros dos modelos de documento relacionados" msgstr "Ação da Barra Lateral para fazer este modelo disponível nos registros dos modelos de documento relacionados"
#. module: mass_editing #. 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" msgid "Sidebar button to open the sidebar action"
msgstr "Botão da Barra Lateral para abrir ação na Barra Lateral" msgstr "Botão da Barra Lateral para abrir ação na Barra Lateral"

8
mass_editing/i18n/ru.po

@ -124,25 +124,25 @@ msgid "Remove the contextual action to use this template on related documents"
msgstr "" msgstr ""
#. module: mass_editing #. module: mass_editing
#: field:mass.object,ref_ir_act_window:0
#: field:mass.object,ref_ir_act_window_id:0
msgid "Sidebar Action" msgid "Sidebar Action"
msgstr "" msgstr ""
#. module: mass_editing #. module: mass_editing
#: view:mass.object:mass_editing.view_mass_object_form #: 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" msgid "Sidebar Button"
msgstr "" msgstr ""
#. module: mass_editing #. module: mass_editing
#: help:mass.object,ref_ir_act_window:0
#: help:mass.object,ref_ir_act_window_id:0
msgid "" msgid ""
"Sidebar action to make this template available on records " "Sidebar action to make this template available on records "
"of the related document model" "of the related document model"
msgstr "" msgstr ""
#. module: mass_editing #. 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" msgid "Sidebar button to open the sidebar action"
msgstr "" msgstr ""

8
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" msgstr "Odstrani kontekstno dejanje za uporabo te predloge na povezanih dokumentih"
#. module: mass_editing #. module: mass_editing
#: field:mass.object,ref_ir_act_window:0
#: field:mass.object,ref_ir_act_window_id:0
msgid "Sidebar Action" msgid "Sidebar Action"
msgstr "Dejanje stranske vrstice" msgstr "Dejanje stranske vrstice"
#. module: mass_editing #. module: mass_editing
#: view:mass.object:mass_editing.view_mass_object_form #: 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" msgid "Sidebar Button"
msgstr "Gumb stranske vrstice" msgstr "Gumb stranske vrstice"
#. module: mass_editing #. module: mass_editing
#: help:mass.object,ref_ir_act_window:0
#: help:mass.object,ref_ir_act_window_id:0
msgid "" msgid ""
"Sidebar action to make this template available on records " "Sidebar action to make this template available on records "
"of the related document model" "of the related document model"
msgstr "Dejanje stranske vrstice, da ta predloga postane razpoložljiva na zapisih povezanih modelov dokumentov" msgstr "Dejanje stranske vrstice, da ta predloga postane razpoložljiva na zapisih povezanih modelov dokumentov"
#. module: mass_editing #. 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" msgid "Sidebar button to open the sidebar action"
msgstr "Gumb stranske vrstice za zagon dejanja stranske vrstice" msgstr "Gumb stranske vrstice za zagon dejanja stranske vrstice"

22
mass_editing/models/__init__.py

@ -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

46
mass_editing/models/ir_model_fields.py

@ -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)

174
mass_editing/models/mass_object.py

@ -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)
@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: 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)]}}
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,
{
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, 'name': button_name,
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
'res_model': 'mass.editing.wizard', 'res_model': 'mass.editing.wizard',
'src_model': src_obj, 'src_model': src_obj,
'view_type': 'form', 'view_type': 'form',
'context': "{'mass_editing_object' : %d}" % (data.id),
'view_mode': 'form,tree',
'context': "{'mass_editing_object' : %d}" % (self.id),
'view_mode': 'form, tree',
'target': 'new', 'target': 'new',
'auto_refresh': 1, 'auto_refresh': 1,
},
context)
vals['ref_ir_value'] = ir_values_obj.create(
cr, SUPERUSER_ID,
{
}).id
vals['ref_ir_value_id'] = self.env['ir.values'].create({
'name': button_name, 'name': button_name,
'model': src_obj, 'model': src_obj,
'key2': 'client_action_multi', '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)
'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)

0
mass_editing/security/ir.model.access.csv

BIN
mass_editing/static/description/mass_editing-1.png

After

Width: 1366  |  Height: 570  |  Size: 66 KiB

BIN
mass_editing/static/description/mass_editing-2.png

After

Width: 1366  |  Height: 518  |  Size: 69 KiB

BIN
mass_editing/static/description/mass_editing-3.png

After

Width: 1366  |  Height: 333  |  Size: 70 KiB

BIN
mass_editing/static/description/mass_editing-4.png

After

Width: 1366  |  Height: 340  |  Size: 50 KiB

BIN
mass_editing/static/description/mass_editing-5.png

After

Width: 1366  |  Height: 329  |  Size: 57 KiB

5
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

174
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.")

78
mass_editing/views/mass_editing_view.xml

@ -1,6 +1,5 @@
<?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"> <record model="ir.ui.view" id="view_mass_object_form">
<field name="name">mass.object.form</field> <field name="name">mass.object.form</field>
@ -9,45 +8,45 @@
<form string="Object"> <form string="Object">
<sheet> <sheet>
<div class="oe_title"> <div class="oe_title">
<label for="name" class="oe_edit_only" />
<label for="name" class="oe_edit_only"/>
<h1> <h1>
<field name="name" required="1" />
<field name="name" required="1"/>
</h1> </h1>
<group> <group>
<field name="model_id" required="1"
on_change="onchange_model_id(model_id)" />
<field name="model_ids" invisible="1" />
<group>
<field name="model_id" required="1" attrs="{'readonly':[('ref_ir_act_window_id','!=',False)]}"/>
</group>
<group>
<field name="model_list" invisible="1"/>
</group>
</group> </group>
</div> </div>
<div class="oe_right oe_button_box" name="buttons"> <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)]}"
<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" 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"
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" class="oe_stat_button" icon="fa-minus"
attrs="{'invisible':[('ref_ir_act_window','=',False)]}"
attrs="{'invisible':[('ref_ir_act_window_id','=',False)]}"
help="Remove the contextual action to use this template on related documents" help="Remove the contextual action to use this template on related documents"
widget="statinfo">
<div>Remove<br />Sidebar Button</div>
</button>
widget="statinfo"/>
</div> </div>
<notebook colspan="4"> <notebook colspan="4">
<page string="Fields"> <page string="Fields">
<field name="field_ids" colspan="4"
nolabel="1"
domain="[('ttype', 'not in', ['reference', 'function']), ('model_id', 'in', model_ids[0][2])]" />
<field name="field_ids" colspan="4" nolabel="1"
domain="[('ttype', 'not in', ['refenrence', 'function']), ('model_id', 'in', model_list)]"/>
</page> </page>
<page string="Advanced" attrs="{'invisible':[('ref_ir_act_window','=',False)]}">
<page string="Advanced" attrs="{'invisible':[('ref_ir_act_window_id','=',False)]}">
<group colspan="2" col="2"> <group colspan="2" col="2">
<field name="ref_ir_act_window" />
<field name="ref_ir_value" />
<field name="ref_ir_act_window_id"/>
<field name="ref_ir_value_id"/>
</group> </group>
</page> </page>
</notebook> </notebook>
@ -61,8 +60,8 @@
<field name="model">mass.object</field> <field name="model">mass.object</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Object"> <tree string="Object">
<field name="name" />
<field name="model_id" />
<field name="name"/>
<field name="model_id"/>
</tree> </tree>
</field> </field>
</record> </record>
@ -72,27 +71,26 @@
<field name="res_model">mass.object</field> <field name="res_model">mass.object</field>
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
<field name="view_id" ref="view_mass_object_tree" />
<field name="view_id" ref="view_mass_object_tree"/>
</record> </record>
<record id="action_mass_object_form_view1" model="ir.actions.act_window.view"> <record id="action_mass_object_form_view1" model="ir.actions.act_window.view">
<field eval="10" name="sequence" />
<field eval="10" name="sequence"/>
<field name="view_mode">tree</field> <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" />
<field name="view_id" ref="view_mass_object_tree"/>
<field name="act_window_id" ref="action_mass_object_form"/>
</record> </record>
<record id="action_mass_object_form_view2" model="ir.actions.act_window.view"> <record id="action_mass_object_form_view2" model="ir.actions.act_window.view">
<field eval="20" name="sequence" />
<field eval="20" name="sequence"/>
<field name="view_mode">form</field> <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" />
<field name="view_id" ref="view_mass_object_form"/>
<field name="act_window_id" ref="action_mass_object_form"/>
</record> </record>
<menuitem id="menu_mass_editing" name="Mass Editing" <menuitem id="menu_mass_editing" name="Mass Editing"
parent="base.menu_administration" sequence="6" />
parent="base.menu_administration" sequence="6"/>
<menuitem id="menu_mass_object_view" action="action_mass_object_form" <menuitem id="menu_mass_object_view" action="action_mass_object_form"
parent="menu_mass_editing" />
parent="menu_mass_editing"/>
</data>
</openerp>
</odoo>

22
mass_editing/wizard/__init__.py

@ -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

279
mass_editing/wizard/mass_editing_wizard.py

@ -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__" +
'name': field.name,
'nolabel': '1',
'attrs': ("{'invisible':[('selection__" +
field.name + "','=','remove')]}"), field.name + "','=','remove')]}"),
'colspan': '2'})
'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__" +
'name': field.name,
'nolabel': '1',
'attrs': ("{'invisible':[('selection__" +
field.name + "','=','remove')]}"), field.name + "','=','remove')]}"),
'colspan': '2', })
etree.SubElement(
xml_form, 'separator', {'string': '', 'colspan': '4'})
'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'}
Loading…
Cancel
Save