From 8fdc75a622bf17febbc911b8173344565ba0e125 Mon Sep 17 00:00:00 2001 From: "Laurent Mignon (ACSONE)" Date: Thu, 7 Nov 2019 17:29:07 +0100 Subject: [PATCH] [MIG] partner_fistname: Migration to 13.0 Remove kack on context and pseudo onchange methods and takes benefit on compute method with readonly=False --- partner_firstname/exceptions.py | 3 +- partner_firstname/models/res_partner.py | 31 +----- partner_firstname/readme/CONTRIBUTORS.rst | 1 + partner_firstname/tests/__init__.py | 4 +- partner_firstname/tests/base.py | 12 +- partner_firstname/tests/test_name.py | 2 +- partner_firstname/tests/test_onchange.py | 104 ------------------ partner_firstname/tests/test_partner_form.py | 103 +++++++++++++++++ partner_firstname/tests/test_user_form.py | 59 ++++++++++ partner_firstname/tests/test_user_onchange.py | 51 --------- partner_firstname/views/base_config_view.xml | 4 +- 11 files changed, 174 insertions(+), 200 deletions(-) delete mode 100644 partner_firstname/tests/test_onchange.py create mode 100644 partner_firstname/tests/test_partner_form.py create mode 100644 partner_firstname/tests/test_user_form.py delete mode 100644 partner_firstname/tests/test_user_onchange.py diff --git a/partner_firstname/exceptions.py b/partner_firstname/exceptions.py index 882ad7a42..00c0ce495 100644 --- a/partner_firstname/exceptions.py +++ b/partner_firstname/exceptions.py @@ -4,7 +4,8 @@ from odoo import _, exceptions class EmptyNamesError(exceptions.ValidationError): - def __init__(self, record, value=_("No name is set.")): + def __init__(self, record, value=None): + value = value or _("No name is set.") self.record = record self._value = value self.name = _("Error(s) with partner %d's name.") % record.id diff --git a/partner_firstname/models/res_partner.py b/partner_firstname/models/res_partner.py index e89b6418c..db677410d 100644 --- a/partner_firstname/models/res_partner.py +++ b/partner_firstname/models/res_partner.py @@ -23,6 +23,7 @@ class ResPartner(models.Model): inverse="_inverse_name_after_cleaning_whitespace", required=False, store=True, + readonly=False, ) @api.model @@ -117,14 +118,8 @@ class ResPartner(models.Model): for record in self: # Remove unneeded whitespace clean = record._get_whitespace_cleaned_name(record.name) - - # Clean name avoiding infinite recursion - if record.name != clean: - record.name = clean - - # Save name in the real fields - else: - record._inverse_name() + record.name = clean + record._inverse_name() @api.model def _get_whitespace_cleaned_name(self, name, comma=False): @@ -202,26 +197,6 @@ class ResPartner(models.Model): ): raise exceptions.EmptyNamesError(record) - @api.onchange("firstname", "lastname") - def _onchange_subnames(self): - """Avoid recursion when the user changes one of these fields. - - This forces to skip the :attr:`~.name` inversion when the user is - setting it in a not-inverted way. - """ - # Modify self's context without creating a new Environment. - # See https://github.com/odoo/odoo/issues/7472#issuecomment-119503916. - self.env.context = self.with_context(skip_onchange=True).env.context - - @api.onchange("name") - def _onchange_name(self): - """Ensure :attr:`~.name` is inverted in the UI.""" - if self.env.context.get("skip_onchange"): - # Do not skip next onchange - self.env.context = self.with_context(skip_onchange=False).env.context - else: - self._inverse_name_after_cleaning_whitespace() - @api.model def _install_partner_firstname(self): """Save names correctly in the database. diff --git a/partner_firstname/readme/CONTRIBUTORS.rst b/partner_firstname/readme/CONTRIBUTORS.rst index 09ee264df..cbf534710 100644 --- a/partner_firstname/readme/CONTRIBUTORS.rst +++ b/partner_firstname/readme/CONTRIBUTORS.rst @@ -16,3 +16,4 @@ * Pedro Baeza * Dave Lasley * Graeme Gellatly +* Laurent Mignon diff --git a/partner_firstname/tests/__init__.py b/partner_firstname/tests/__init__.py index 56bf8465d..bb102a3ac 100644 --- a/partner_firstname/tests/__init__.py +++ b/partner_firstname/tests/__init__.py @@ -4,8 +4,8 @@ from . import ( test_delete, test_empty, test_name, - test_onchange, - test_user_onchange, + test_partner_form, + test_user_form, test_order, test_copy, ) diff --git a/partner_firstname/tests/base.py b/partner_firstname/tests/base.py index 720dea7cc..29dc7e205 100644 --- a/partner_firstname/tests/base.py +++ b/partner_firstname/tests/base.py @@ -40,7 +40,7 @@ class BaseCase(TransactionCase, MailInstalled): for field in ("name", "lastname", "firstname"): self.assertEqual( - getattr(self.changed, field), + self.changed[field], getattr(self, field), "Test failed with wrong %s" % field, ) @@ -63,13 +63,3 @@ class BaseCase(TransactionCase, MailInstalled): self.check_fields = False with self.assertRaises(ex.EmptyNamesError): self.original.firstname = self.original.lastname = False - - -class OnChangeCase(TransactionCase): - is_company = False - - def new_partner(self): - """Create an empty partner. Ensure it is (or not) a company.""" - new = self.env["res.partner"].new() - new.is_company = self.is_company - return new diff --git a/partner_firstname/tests/test_name.py b/partner_firstname/tests/test_name.py index 1bf89335d..613dc17de 100644 --- a/partner_firstname/tests/test_name.py +++ b/partner_firstname/tests/test_name.py @@ -48,7 +48,7 @@ class PartnerContactCase(BaseCase): self.original.name = " newfïrstname newlästname " # Need this to refresh the ``name`` field - self.original.invalidate_cache() + self.original.invalidate_cache(["name"]) class PartnerCompanyCase(BaseCase): diff --git a/partner_firstname/tests/test_onchange.py b/partner_firstname/tests/test_onchange.py deleted file mode 100644 index 10a4bd54f..000000000 --- a/partner_firstname/tests/test_onchange.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2015 Grupo ESOC -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -"""These tests try to mimic the behavior of the UI form. - -The form operates in onchange mode, with its limitations. -""" - -from .base import OnChangeCase - - -class PartnerCompanyCase(OnChangeCase): - is_company = True - - def test_create_from_form(self): - """A user creates a company from the form.""" - name = "Sôme company" - with self.env.do_in_onchange(): - # User presses ``new`` - partner = self.new_partner() - - # User sets a name, which triggers onchanges - partner.name = name - partner._onchange_name() - - self.assertEqual(partner.name, name) - self.assertEqual(partner.firstname, False) - self.assertEqual(partner.lastname, name) - - def test_empty_name_and_subnames(self): - """If the user empties ``name``, subnames must be ``False``. - - Otherwise, the ``required`` attr will not work as expected. - """ - with self.env.do_in_onchange(): - # User presses ``new`` - partner = self.new_partner() - - # User sets a name, which triggers onchanges - partner.name = "Foó" - partner._onchange_name() - - # User unsets name, which triggers onchanges - partner.name = "" - partner._onchange_name() - - self.assertEqual(partner.firstname, False) - self.assertEqual(partner.lastname, False) - - -class PartnerContactCase(OnChangeCase): - def test_create_from_form_only_firstname(self): - """A user creates a contact with only the firstname from the form.""" - firstname = "Fïrst" - with self.env.do_in_onchange(): - # User presses ``new`` - partner = self.new_partner() - - # Changes firstname, which triggers onchanges - partner.firstname = firstname - partner._onchange_subnames() - partner._onchange_name() - - self.assertEqual(partner.lastname, False) - self.assertEqual(partner.firstname, firstname) - self.assertEqual(partner.name, firstname) - - def test_create_from_form_only_lastname(self): - """A user creates a contact with only the lastname from the form.""" - lastname = "Läst" - with self.env.do_in_onchange(): - # User presses ``new`` - partner = self.new_partner() - - # Changes lastname, which triggers onchanges - partner.lastname = lastname - partner._onchange_subnames() - partner._onchange_name() - - self.assertEqual(partner.firstname, False) - self.assertEqual(partner.lastname, lastname) - self.assertEqual(partner.name, lastname) - - def test_create_from_form_all(self): - """A user creates a contact with all names from the form.""" - firstname = "Fïrst" - lastname = "Läst" - with self.env.do_in_onchange(): - # User presses ``new`` - partner = self.new_partner() - - # Changes firstname, which triggers onchanges - partner.firstname = firstname - partner._onchange_subnames() - partner._onchange_name() - - # Changes lastname, which triggers onchanges - partner.lastname = lastname - partner._onchange_subnames() - partner._onchange_name() - - self.assertEqual(partner.lastname, lastname) - self.assertEqual(partner.firstname, firstname) - self.assertEqual(partner.name, " ".join((firstname, lastname))) diff --git a/partner_firstname/tests/test_partner_form.py b/partner_firstname/tests/test_partner_form.py new file mode 100644 index 000000000..4de60f0e2 --- /dev/null +++ b/partner_firstname/tests/test_partner_form.py @@ -0,0 +1,103 @@ +# Copyright 2015 Grupo ESOC +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +"""These tests try to mimic the behavior of the UI form. + +The form operates in onchange mode, with its limitations. +""" + +from odoo.tests.common import Form, TransactionCase + +from ..exceptions import EmptyNamesError + + +class PartnerCompanyCase(TransactionCase): + is_company = True + + def test_create_from_form(self): + name = "Sôme company" + with Form(self.env["res.partner"]) as partner_form: + partner_form.is_company = self.is_company + partner_form.name = name + + self.assertEqual(partner_form.name, name) + self.assertEqual(partner_form.firstname, False) + self.assertEqual(partner_form.lastname, name) + + def test_empty_name(self): + """If we empty the name and save the form, EmptyNamesError must + be raised (firstname and lastname are reset...) + """ + with Form( + self.env["res.partner"], view="base.view_partner_simple_form" + ) as partner_form: + partner_form.is_company = self.is_company + + name = "Foó" + # User sets a name + partner_form.name = name + # call save to trigger the inverse + partner_form.save() + self.assertEqual(partner_form.name, name) + self.assertEqual(partner_form.firstname, False) + self.assertEqual(partner_form.lastname, name) + + # User unsets name + partner_form.name = "" + # call save to trigger the inverse and therefore raise an exception + with self.assertRaises(EmptyNamesError), self.env.cr.savepoint(): + partner_form.save() + + name += " bis" + partner_form.name = name + partner_form.save() + self.assertEqual(partner_form.name, name) + self.assertEqual(partner_form.firstname, False) + self.assertEqual(partner_form.lastname, name) + + +class PartnerContactCase(TransactionCase): + is_company = False + + def test_create_from_form_only_firstname(self): + """A user creates a contact with only the firstname from the form.""" + firstname = "Fïrst" + with Form(self.env["res.partner"]) as partner_form: + partner_form.is_company = self.is_company + + # Changes firstname, which triggers compute + partner_form.firstname = firstname + + self.assertEqual(partner_form.lastname, False) + self.assertEqual(partner_form.firstname, firstname) + self.assertEqual(partner_form.name, firstname) + + def test_create_from_form_only_lastname(self): + """A user creates a contact with only the lastname from the form.""" + lastname = "Läst" + with Form(self.env["res.partner"]) as partner_form: + partner_form.is_company = self.is_company + + # Changes lastname, which triggers compute + partner_form.lastname = lastname + + self.assertEqual(partner_form.firstname, False) + self.assertEqual(partner_form.lastname, lastname) + self.assertEqual(partner_form.name, lastname) + + def test_create_from_form_all(self): + """A user creates a contact with all names from the form.""" + firstname = "Fïrst" + lastname = "Läst" + with Form(self.env["res.partner"]) as partner_form: + partner_form.is_company = self.is_company + + # Changes firstname, which triggers compute + partner_form.firstname = firstname + + # Changes lastname, which triggers compute + partner_form.lastname = lastname + + self.assertEqual(partner_form.lastname, lastname) + self.assertEqual(partner_form.firstname, firstname) + self.assertEqual(partner_form.name, " ".join((firstname, lastname))) diff --git a/partner_firstname/tests/test_user_form.py b/partner_firstname/tests/test_user_form.py new file mode 100644 index 000000000..e3d250565 --- /dev/null +++ b/partner_firstname/tests/test_user_form.py @@ -0,0 +1,59 @@ +# Copyright 2016 Yannick Vaucher (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import Form, TransactionCase + + +class UserOnchangeCase(TransactionCase): + def test_create_from_form_only_firstname(self): + """In a new users form, a user set only the firstname.""" + login = "Zoë" + firstname = "Zoë" + with Form( + self.env["res.users"], view="partner_firstname.view_users_form" + ) as user_form: + user_form.login = login + # Changes firstname, which triggers onchanges + user_form.firstname = firstname + + self.assertEqual(user_form.lastname, False) + self.assertEqual(user_form.firstname, firstname) + self.assertEqual(user_form.name, firstname) + + def test_create_from_form_only_lastname(self): + """In a new user form, a user set only the lastname.""" + login = "Żywioł" + lastname = "Żywioł" + with Form( + self.env["res.users"], view="partner_firstname.view_users_form" + ) as user_form: + user_form.login = login + # Changes lastname, which triggers onchanges + user_form.lastname = lastname + + self.assertEqual(user_form.firstname, False) + self.assertEqual(user_form.lastname, lastname) + self.assertEqual(user_form.name, lastname) + + def test_create_from_form_all(self): + """In a new user form, a user set all names.""" + login = "Zoë.Żywioł" + firstname = "Zoë" + lastname = "Żywioł" + with Form( + self.env["res.users"], view="partner_firstname.view_users_form" + ) as user_form: + user_form.login = login + # Changes firstname, which triggers onchanges + user_form.firstname = firstname + + # Changes lastname, which triggers onchanges + user_form.lastname = lastname + + self.assertEqual(user_form.lastname, lastname) + self.assertEqual(user_form.firstname, firstname) + self.assertEqual(user_form.name, " ".join((firstname, lastname))) + + def setUp(self): + super(UserOnchangeCase, self).setUp() + self.user = self.env["res.users"].new() diff --git a/partner_firstname/tests/test_user_onchange.py b/partner_firstname/tests/test_user_onchange.py deleted file mode 100644 index d378b85e2..000000000 --- a/partner_firstname/tests/test_user_onchange.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2016 Yannick Vaucher (Camptocamp SA) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo.tests.common import TransactionCase - - -class UserOnchangeCase(TransactionCase): - def test_create_from_form_only_firstname(self): - """In a new users form, a user set only the firstname.""" - firstname = "Zoë" - with self.env.do_in_onchange(): - # Changes firstname, which triggers onchanges - self.user.firstname = firstname - self.user._compute_name() - - self.assertEqual(self.user.lastname, False) - self.assertEqual(self.user.firstname, firstname) - self.assertEqual(self.user.name, firstname) - - def test_create_from_form_only_lastname(self): - """In a new user form, a user set only the lastname.""" - lastname = "Żywioł" - with self.env.do_in_onchange(): - # Changes lastname, which triggers onchanges - self.user.lastname = lastname - self.user._compute_name() - - self.assertEqual(self.user.firstname, False) - self.assertEqual(self.user.lastname, lastname) - self.assertEqual(self.user.name, lastname) - - def test_create_from_form_all(self): - """In a new user form, a user set all names.""" - firstname = "Zoë" - lastname = "Żywioł" - with self.env.do_in_onchange(): - # Changes firstname, which triggers onchanges - self.user.firstname = firstname - self.user._compute_name() - - # Changes lastname, which triggers onchanges - self.user.lastname = lastname - self.user._compute_name() - - self.assertEqual(self.user.lastname, lastname) - self.assertEqual(self.user.firstname, firstname) - self.assertEqual(self.user.name, " ".join((firstname, lastname))) - - def setUp(self): - super(UserOnchangeCase, self).setUp() - self.user = self.env["res.users"].new() diff --git a/partner_firstname/views/base_config_view.xml b/partner_firstname/views/base_config_view.xml index 5b968567d..488328e37 100644 --- a/partner_firstname/views/base_config_view.xml +++ b/partner_firstname/views/base_config_view.xml @@ -3,13 +3,13 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). --> - + Add partner_names_order config parameter res.config.settings - +

Partner Names Order