diff --git a/.docker_files/main/__manifest__.py b/.docker_files/main/__manifest__.py index 082f168e..97e729ba 100644 --- a/.docker_files/main/__manifest__.py +++ b/.docker_files/main/__manifest__.py @@ -16,6 +16,7 @@ 'auditlog', 'base_extended_security', + 'base_xml_rename', 'disable_install_from_website', 'ir_attachment_access_token_portal', 'ir_attachment_name_autocomplete', @@ -24,12 +25,10 @@ 'mail_message_from_author', 'mail_notification_no_footer', 'mail_recipient_unchecked', - 'menu_item_rename', 'note_no_default_stage', 'private_data_group', 'queue_job_auto_requeue', 'super_calendar', - 'user_group_rename', 'web_email_field_new_tab', ], 'installable': True, diff --git a/Dockerfile b/Dockerfile index 939d56cf..471ba9c7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,6 +17,7 @@ USER odoo COPY auditlog /mnt/extra-addons/auditlog COPY base_extended_security /mnt/extra-addons/base_extended_security +COPY base_xml_rename /mnt/extra-addons/base_xml_rename COPY disable_install_from_website /mnt/extra-addons/disable_install_from_website COPY ir_attachment_access_token_portal /mnt/extra-addons/ir_attachment_access_token_portal COPY ir_attachment_name_autocomplete /mnt/extra-addons/ir_attachment_name_autocomplete @@ -25,13 +26,11 @@ COPY mail_follower_picker /mnt/extra-addons/mail_follower_picker COPY mail_message_from_author /mnt/extra-addons/mail_message_from_author COPY mail_notification_no_footer /mnt/extra-addons/mail_notification_no_footer COPY mail_recipient_unchecked /mnt/extra-addons/mail_recipient_unchecked -COPY menu_item_rename /mnt/extra-addons/menu_item_rename COPY note_no_default_stage /mnt/extra-addons/note_no_default_stage COPY private_data_group /mnt/extra-addons/private_data_group COPY queue_job_auto_requeue /mnt/extra-addons/queue_job_auto_requeue COPY super_calendar /mnt/extra-addons/super_calendar COPY test_http_request /mnt/extra-addons/test_http_request -COPY user_group_rename /mnt/extra-addons/user_group_rename COPY web_email_field_new_tab /mnt/extra-addons/web_email_field_new_tab COPY .docker_files/main /mnt/extra-addons/main diff --git a/base_xml_rename/README.rst b/base_xml_rename/README.rst new file mode 100644 index 00000000..81e5f7d1 --- /dev/null +++ b/base_xml_rename/README.rst @@ -0,0 +1,91 @@ +Base XML Rename +=============== +This module allows to rename UI elements using XML data files in modules. + +.. contents:: Table of Contents + +Context +------- +Renaming a menu in Odoo directly through the web interface is not a good idea. + +* We rapidly loose track of what was modified. +* The menu names are not changed in test environments (except with replication of the prod). +* The changes are lost if someone forces the override of translations. + +The same applies for renaming other objects such as user groups. + +Module Design +------------- +A mixin ``xml.rename.mixin`` is added. + +This mixin has a method ``rename`` which takes 3 mandatory parameters: + +* ``ref``: the xml reference of the record. +* ``lang``: the language of the term. +* ``value``: the new term. + +Optionaly, a ``field`` parameter can be supplied, in case the field is not ``name``. + +The mixin can be added to any model. + +For now, the module adds the mixin to ir.ui.menu and res.groups. + +Usage +----- +Here are 2 examples for renaming menu items and user groups. + +Renaming a Menu +~~~~~~~~~~~~~~~ +Inside an xml file: + +* Add a `function` node with model="ir.ui.menu". +* Inside the `function` node, you must set 3 `value` nodes. + + These nodes must have type="char" and respectively contain the following data: + + 1. The XML ID of the menu item + 2. The languge code + 3. The new label to set + +Here is an example to rename the `Settings` menu to `Administration`. + +.. code-block:: XML + + + base.menu_administration + en_US + Administration + + +Here is the result after loading the module containg the XML file. + +.. image:: static/description/admin_menu.png + +Renaming a User Group +~~~~~~~~~~~~~~~~~~~~~ +Here is an example of renaming a user group. This works the same way as renaming a menu item. + +.. code-block:: XML + + + account.group_account_user + fr_FR + Comptable + + +Before loading the XML, the group is named ``Montrer les fonctions de comptabilité complète`` in french. + +.. image:: static/description/group_before.png + +After loading the XML, the group is named ``Comptable``. + +.. image:: static/description/group_after.png + +Known Issues +~~~~~~~~~~~~ +If you reload translations with ``Overwrite Existing Terms`` checked, the terms loaded with XML +will not be reloaded automatically. You will need to update the modules containing these XML files). + +Contributors +------------ +* Numigi (tm) and all its contributors (https://bit.ly/numigiens) diff --git a/menu_item_rename/__init__.py b/base_xml_rename/__init__.py similarity index 100% rename from menu_item_rename/__init__.py rename to base_xml_rename/__init__.py diff --git a/menu_item_rename/__manifest__.py b/base_xml_rename/__manifest__.py similarity index 100% rename from menu_item_rename/__manifest__.py rename to base_xml_rename/__manifest__.py diff --git a/user_group_rename/__init__.py b/base_xml_rename/models/__init__.py similarity index 65% rename from user_group_rename/__init__.py rename to base_xml_rename/models/__init__.py index 6da4fa4e..edcf12ef 100644 --- a/user_group_rename/__init__.py +++ b/base_xml_rename/models/__init__.py @@ -1,4 +1,8 @@ # © 2019 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -from . import models +from . import ( + ir_ui_menu, + res_groups, + xml_rename_mixin, +) diff --git a/base_xml_rename/models/ir_ui_menu.py b/base_xml_rename/models/ir_ui_menu.py new file mode 100644 index 00000000..28d02a7e --- /dev/null +++ b/base_xml_rename/models/ir_ui_menu.py @@ -0,0 +1,23 @@ +# © 2019 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import api, models +from .xml_rename_mixin import is_lang_installed + + +class IrUiMenu(models.Model): + + _inherit = ('ir.ui.menu', 'xml.rename.mixin') + _name = 'ir.ui.menu' + + @api.model + def rename(self, ref, lang, value, field='name'): + super().rename(ref, lang, value, field) + + menu = self.env.ref(ref) + should_update_action_name = ( + is_lang_installed(self.env, lang) and + menu.action and field == 'name' + ) + if should_update_action_name: + menu.action.with_context(lang=lang).name = value diff --git a/user_group_rename/tests/__init__.py b/base_xml_rename/models/res_groups.py similarity index 50% rename from user_group_rename/tests/__init__.py rename to base_xml_rename/models/res_groups.py index 6ef2df91..54f65bd8 100644 --- a/user_group_rename/tests/__init__.py +++ b/base_xml_rename/models/res_groups.py @@ -1,2 +1,10 @@ # © 2019 Numigi (tm) and all its contributors (https://bit.ly/numigiens) # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import models + + +class ResGroups(models.Model): + + _inherit = ('res.groups', 'xml.rename.mixin') + _name = 'res.groups' diff --git a/base_xml_rename/models/xml_rename_mixin.py b/base_xml_rename/models/xml_rename_mixin.py new file mode 100644 index 00000000..706b5565 --- /dev/null +++ b/base_xml_rename/models/xml_rename_mixin.py @@ -0,0 +1,50 @@ +# © 2019 Numigi (tm) and all its contributors (https://bit.ly/numigiens) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +import logging +from odoo import api, models +from odoo.exceptions import ValidationError + + +_logger = logging.getLogger(__name__) + + +def is_lang_installed(env: 'Environment', lang: str): + return lang in dict(env['res.lang'].get_installed()) + + +class XMLRenameMixin(models.AbstractModel): + + _name = 'xml.rename.mixin' + _description = 'Mixin For Renaming Records Through XML' + + @api.model + def rename(self, ref, lang, value, field='name'): + """Rename the record to rename. + + :param ref: the XML ID of the record to rename + :param lang: the language of the term + :param value: the new name for the record + """ + if not is_lang_installed(self.env, lang): + _logger.debug( + 'Skip renaming the record {ref} for the language {lang}. ' + 'The language is not installed.' + .format(ref=ref, lang=lang) + ) + return + + _logger.info( + 'Renaming the record {ref} with the label `{value}` ' + 'for the language {lang}.' + .format(ref=ref, lang=lang, value=value) + ) + record = self.env.ref(ref) + if record._name != self._name: + raise ValidationError( + 'The XML ID {ref} does not reference a record of model {model}. ' + 'It references a record of model {record_model}' + .format(ref=ref, model=self._name, record_model=record._name) + ) + + record.with_context(lang=lang).write({field: value}) diff --git a/menu_item_rename/static/description/admin_menu.png b/base_xml_rename/static/description/admin_menu.png similarity index 100% rename from menu_item_rename/static/description/admin_menu.png rename to base_xml_rename/static/description/admin_menu.png diff --git a/user_group_rename/static/description/group_after.png b/base_xml_rename/static/description/group_after.png similarity index 100% rename from user_group_rename/static/description/group_after.png rename to base_xml_rename/static/description/group_after.png diff --git a/user_group_rename/static/description/group_before.png b/base_xml_rename/static/description/group_before.png similarity index 100% rename from user_group_rename/static/description/group_before.png rename to base_xml_rename/static/description/group_before.png diff --git a/menu_item_rename/static/description/icon.png b/base_xml_rename/static/description/icon.png similarity index 100% rename from menu_item_rename/static/description/icon.png rename to base_xml_rename/static/description/icon.png diff --git a/menu_item_rename/tests/__init__.py b/base_xml_rename/tests/__init__.py similarity index 100% rename from menu_item_rename/tests/__init__.py rename to base_xml_rename/tests/__init__.py diff --git a/menu_item_rename/tests/test_menu_item_rename.py b/base_xml_rename/tests/test_ir_ui_menu.py similarity index 93% rename from menu_item_rename/tests/test_menu_item_rename.py rename to base_xml_rename/tests/test_ir_ui_menu.py index 2cc8a8b8..3882e20a 100644 --- a/menu_item_rename/tests/test_menu_item_rename.py +++ b/base_xml_rename/tests/test_ir_ui_menu.py @@ -63,3 +63,8 @@ def test_after_rename_menu_with_en__action_fr_translation_unchanged(self): new_label = 'New label' self._rename_menu('en_US', new_label) assert self.action.with_context(lang='fr_FR').name == self.menu_name_fr + + def test_if_lang_not_active__term_ignored(self): + self.fr_lang.active = False + self._rename_menu('fr_FR', 'Nouveau libellé') + assert self.menu.name == self.menu_name_en diff --git a/user_group_rename/tests/test_group_rename.py b/base_xml_rename/tests/test_res_groups.py similarity index 89% rename from user_group_rename/tests/test_group_rename.py rename to base_xml_rename/tests/test_res_groups.py index 2857db83..cf0dee66 100644 --- a/user_group_rename/tests/test_group_rename.py +++ b/base_xml_rename/tests/test_res_groups.py @@ -41,3 +41,8 @@ def test_after_rename_group_with_en__fr_translation_unchanged(self): new_label = 'New label' self._rename_group('en_US', new_label) assert self.group.with_context(lang='fr_FR').name == self.group_name_fr + + def test_if_lang_not_active__term_ignored(self): + self.fr_lang.active = False + self._rename_group('fr_FR', 'Nouveau libellé') + assert self.group.name == self.group_name_en diff --git a/menu_item_rename/README.rst b/menu_item_rename/README.rst deleted file mode 100644 index 6c2c21bd..00000000 --- a/menu_item_rename/README.rst +++ /dev/null @@ -1,42 +0,0 @@ -Menu Item Rename -================ -This module allows to rename a menu item using XML data files in modules. - -Context -------- -Renaming a menu in Odoo directly through the web interface is not a good idea. - -* We rapidly loose track of what was modified. -* The menu names are not changed in test environments (except with replication of the prod). -* The changes are lost if someone forces the override of translations. - -Usage ------ -Inside an xml file: - -* Add a `function` node with model="ir.ui.menu". -* Inside the `function` node, you must set 3 `value` nodes. - - These nodes must have type="char" and respectively contain the following data: - - 1. The XML ID of the menu item - 2. The languge code - 3. The new label to set - -Here is an example to rename the `Settings` menu to `Administration`. - -.. code-block:: XML - - - base.menu_administration - en_US - Administration - - -Here is the result after loading the module containg the XML file. - -.. image:: static/description/admin_menu.png - -Contributors ------------- -* Numigi (tm) and all its contributors (https://bit.ly/numigiens) diff --git a/menu_item_rename/models.py b/menu_item_rename/models.py deleted file mode 100644 index 25623202..00000000 --- a/menu_item_rename/models.py +++ /dev/null @@ -1,39 +0,0 @@ -# © 2019 Numigi (tm) and all its contributors (https://bit.ly/numigiens) -# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). - -import logging -from odoo import api, models -from odoo.exceptions import ValidationError - - -_logger = logging.getLogger(__name__) - - -class MenuItem(models.Model): - - _inherit = 'ir.ui.menu' - - @api.model - def rename(self, menu_ref, lang, value): - """Rename the menu item. - - :param menu_ref: the XML ID of the menu item - :param lang: the language of the menu entry - :param value: the new name for the menu entry - """ - _logger.info( - 'Renaming menu item {menu_ref} with the label `{value}` ' - 'for the language {lang}.' - .format(menu_ref=menu_ref, lang=lang, value=value) - ) - menu = self.env.ref(menu_ref) - if menu._name != 'ir.ui.menu': - raise ValidationError( - 'The XML ID {} does not reference a menu item.' - .format(menu_ref) - ) - - menu.with_context(lang=lang).name = value - - if menu.action: - menu.action.with_context(lang=lang).name = value diff --git a/user_group_rename/README.rst b/user_group_rename/README.rst deleted file mode 100644 index 6d878106..00000000 --- a/user_group_rename/README.rst +++ /dev/null @@ -1,29 +0,0 @@ -User Group Rename -================= -This module allows to rename a user group using XML data files in modules. - -This module is the same as ``menu_item_rename`` but for user groups instead of menu items. - -Usage ------ -Here is an example of usage in an XML file. - -.. code-block:: XML - - - account.group_account_user - fr_FR - Comptable - - -Before loading the XML, the group is named ``Montrer les fonctions de comptabilité complète`` in french. - -.. image:: static/description/group_before.png - -After loading the XML, the group is named ``Comptable``. - -.. image:: static/description/group_after.png - -Contributors ------------- -* Numigi (tm) and all its contributors (https://bit.ly/numigiens) diff --git a/user_group_rename/__manifest__.py b/user_group_rename/__manifest__.py deleted file mode 100644 index fd21de24..00000000 --- a/user_group_rename/__manifest__.py +++ /dev/null @@ -1,14 +0,0 @@ -# © 2019 Numigi (tm) and all its contributors (https://bit.ly/numigiens) -# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). - -{ - 'name': 'User Group Rename', - 'version': '1.0.0', - 'author': 'Numigi', - 'maintainer': 'Numigi', - 'license': 'LGPL-3', - 'category': 'Other', - 'summary': 'Rename user groups using module xml.', - 'depends': ['base'], - 'installable': True, -} diff --git a/user_group_rename/models.py b/user_group_rename/models.py deleted file mode 100644 index 01e036b1..00000000 --- a/user_group_rename/models.py +++ /dev/null @@ -1,36 +0,0 @@ -# © 2019 Numigi (tm) and all its contributors (https://bit.ly/numigiens) -# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). - -import logging -from odoo import api, models -from odoo.exceptions import ValidationError - - -_logger = logging.getLogger(__name__) - - -class ResGroups(models.Model): - - _inherit = 'res.groups' - - @api.model - def rename(self, group_ref, lang, value): - """Rename the user group. - - :param group_ref: the XML ID of the group - :param lang: the language of the group - :param value: the new name for the group - """ - _logger.info( - 'Renaming the user group {group_ref} with the label `{value}` ' - 'for the language {lang}.' - .format(group_ref=group_ref, lang=lang, value=value) - ) - group = self.env.ref(group_ref) - if group._name != 'res.groups': - raise ValidationError( - 'The XML ID {} does not reference a group.' - .format(group_ref) - ) - - group.with_context(lang=lang).name = value diff --git a/user_group_rename/static/description/admin_menu.png b/user_group_rename/static/description/admin_menu.png deleted file mode 100644 index c25c4831..00000000 Binary files a/user_group_rename/static/description/admin_menu.png and /dev/null differ diff --git a/user_group_rename/static/description/icon.png b/user_group_rename/static/description/icon.png deleted file mode 100644 index 92a86b10..00000000 Binary files a/user_group_rename/static/description/icon.png and /dev/null differ