Browse Source

Merge pull request #238 from yvaucher/9.0-port-partner-firstname

[9.0] [PORT] partner_firstname
pull/231/merge
Pedro M. Baeza 9 years ago
parent
commit
3b65772832
  1. 17
      partner_firstname/README.rst
  2. 21
      partner_firstname/__init__.py
  3. 34
      partner_firstname/__openerp__.py
  4. 21
      partner_firstname/exceptions.py
  5. 5
      partner_firstname/models/__init__.py
  6. 107
      partner_firstname/models/res_partner.py
  7. 30
      partner_firstname/models/res_user.py
  8. 39
      partner_firstname/tests/__init__.py
  9. 30
      partner_firstname/tests/base.py
  10. 82
      partner_firstname/tests/test_create.py
  11. 65
      partner_firstname/tests/test_defaults.py
  12. 38
      partner_firstname/tests/test_delete.py
  13. 48
      partner_firstname/tests/test_empty.py
  14. 3
      partner_firstname/tests/test_onchange.py
  15. 64
      partner_firstname/views/res_partner.xml
  16. 4
      partner_firstname/views/res_user.xml

17
partner_firstname/README.rst

@ -39,11 +39,28 @@ Contributors
------------ ------------
* Nicolas Bessi <nicolas.bessi@camptocamp.com> * Nicolas Bessi <nicolas.bessi@camptocamp.com>
* Yannick Vaucher <yannick.vaucher@camptocamp.com>
* Vincent Renaville <vincent.renaville@camptocamp.com>
* Guewen Baconnier <guewen.baconnier@camptocamp.com>
* Holger Brunn <hbrunn@terp.nl>
* Jonathan Nemry <jonathan.nemry@acsone.eu> * Jonathan Nemry <jonathan.nemry@acsone.eu>
* Olivier Laurent <olivier.laurent@acsone.eu> * Olivier Laurent <olivier.laurent@acsone.eu>
* Sandy Carter <sandy.carter@savoirfairelinux.com>
* Alexis de Lattre <alexis.delattre@akretion.fr>
* Lorenzo Battistini <lorenzo.battistini@agilebg.com>
* Hans Henrik Gabelgaard <hhg@gabelgaard.org> * Hans Henrik Gabelgaard <hhg@gabelgaard.org>
* Jairo Llopis <j.llopis@grupoesoc.es> * Jairo Llopis <j.llopis@grupoesoc.es>
* Adrien Peiffer <adrien.peiffer@acsone.eu> * Adrien Peiffer <adrien.peiffer@acsone.eu>
* Ronald Portier <ronald@therp.nl>
* Sylvain Van Hoof
* Pedro Baeza <pedro.baeza@serviciosbaeza.com>
Translations
------------
* Danish: Hans Henrik Gabelgaard
* Italian: Leonardo Donelli
* Spanish: Antonio Espinosa
Maintainer Maintainer
---------- ----------

21
partner_firstname/__init__.py

@ -1,21 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Author: Nicolas Bessi. Copyright Camptocamp SA
# Copyright (C)
# 2014: Agile Business Group (<http://www.agilebg.com>)
# 2015: Grupo ESOC <www.grupoesoc.es>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# © 2013 Nicolas Bessi (Camptocamp SA)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import models from . import models

34
partner_firstname/__openerp__.py

@ -1,31 +1,21 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Author: Nicolas Bessi. Copyright Camptocamp SA
# Copyright (C)
# 2014: Agile Business Group (<http://www.agilebg.com>)
# 2015: Grupo ESOC <www.grupoesoc.es>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# © 2013 Nicolas Bessi (Camptocamp SA)
# © 2014 Agile Business Group (<http://www.agilebg.com>)
# © 2015 Grupo ESOC (<http://www.grupoesoc.es>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{ {
'name': 'Partner first name and last name', 'name': 'Partner first name and last name',
'summary': "Split first name and last name for non company partners", 'summary': "Split first name and last name for non company partners",
'version': '8.0.2.0.0',
'author': "Camptocamp,Odoo Community Association (OCA)",
'version': '9.0.1.0.0',
'author': "Camptocamp, "
"Grupo ESOC Ingeniería de Servicios, "
"Odoo Community Association (OCA)",
'license': "AGPL-3",
'maintainer': 'Camptocamp, Acsone', 'maintainer': 'Camptocamp, Acsone',
'category': 'Extra Tools', 'category': 'Extra Tools',
'website': 'http://www.camptocamp.com, http://www.acsone.eu',
'website':
'http://www.camptocamp.com, http://www.acsone.eu, http://grupoesoc.es',
'depends': ['base'], 'depends': ['base'],
'data': [ 'data': [
'views/res_partner.xml', 'views/res_partner.xml',
@ -35,6 +25,6 @@
'demo': [], 'demo': [],
'test': [], 'test': [],
'auto_install': False, 'auto_install': False,
'installable': False,
'installable': True,
'images': [] 'images': []
} }

21
partner_firstname/exceptions.py

@ -1,21 +1,6 @@
# -*- encoding: utf-8 -*-
# Odoo, Open Source Management Solution
# Copyright (C) 2014-2015 Grupo ESOC <www.grupoesoc.es>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
# © 2014-2015 Grupo ESOC (<http://www.grupoesoc.es>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import _, exceptions from openerp import _, exceptions

5
partner_firstname/models/__init__.py

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# © 2013 Nicolas Bessi (Camptocamp SA)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import res_partner
from . import res_user

107
partner_firstname/models.py → partner_firstname/models/res_partner.py

@ -1,26 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Author: Nicolas Bessi. Copyright Camptocamp SA
# Copyright (C)
# 2014: Agile Business Group (<http://www.agilebg.com>)
# 2015: Grupo ESOC <www.grupoesoc.es>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# © 2013 Nicolas Bessi (Camptocamp SA)
# © 2014 Agile Business Group (<http://www.agilebg.com>)
# © 2015 Grupo ESOC (<http://www.grupoesoc.es>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import logging import logging
from openerp import api, fields, models from openerp import api, fields, models
from . import exceptions
from .. import exceptions
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -38,6 +23,56 @@ class ResPartner(models.Model):
required=False, required=False,
store=True) store=True)
@api.model
def create(self, vals):
"""Add inverted names at creation if unavailable."""
context = dict(self.env.context)
name = vals.get("name", context.get("default_name"))
if name is not None:
# Calculate the splitted fields
inverted = self._get_inverse_name(
self._get_whitespace_cleaned_name(name),
vals.get("is_company",
self.default_get(["is_company"])["is_company"]))
for key, value in inverted.iteritems():
if not vals.get(key) or context.get("copy"):
vals[key] = value
# Remove the combined fields
if "name" in vals:
del vals["name"]
if "default_name" in context:
del context["default_name"]
return super(ResPartner, self.with_context(context)).create(vals)
@api.multi
def copy(self, default=None):
"""Ensure partners are copied right.
Odoo adds ``(copy)`` to the end of :attr:`~.name`, but that would get
ignored in :meth:`~.create` because it also copies explicitly firstname
and lastname fields.
"""
return super(ResPartner, self.with_context(copy=True)).copy(default)
@api.model
def default_get(self, fields_list):
"""Invert name when getting default values."""
result = super(ResPartner, self).default_get(fields_list)
inverted = self._get_inverse_name(
self._get_whitespace_cleaned_name(result.get("name", "")),
result.get("is_company", False))
for field in inverted.keys():
if field in fields_list:
result[field] = inverted.get(field)
return result
@api.model @api.model
def _get_computed_name(self, lastname, firstname): def _get_computed_name(self, lastname, firstname):
"""Compute the 'name' field according to splitted data. """Compute the 'name' field according to splitted data.
@ -55,13 +90,11 @@ class ResPartner(models.Model):
def _inverse_name_after_cleaning_whitespace(self): def _inverse_name_after_cleaning_whitespace(self):
"""Clean whitespace in :attr:`~.name` and split it. """Clean whitespace in :attr:`~.name` and split it.
Removes leading, trailing and duplicated whitespace.
The splitting logic is stored separately in :meth:`~._inverse_name`, so The splitting logic is stored separately in :meth:`~._inverse_name`, so
submodules can extend that method and get whitespace cleaning for free. submodules can extend that method and get whitespace cleaning for free.
""" """
# Remove unneeded whitespace # Remove unneeded whitespace
clean = u" ".join(self.name.split(None)) if self.name else self.name
clean = self._get_whitespace_cleaned_name(self.name)
# Clean name avoiding infinite recursion # Clean name avoiding infinite recursion
if self.name != clean: if self.name != clean:
@ -71,9 +104,17 @@ class ResPartner(models.Model):
else: else:
self._inverse_name() self._inverse_name()
@api.model
def _get_whitespace_cleaned_name(self, name):
"""Remove redundant whitespace from :param:`name`.
Removes leading, trailing and duplicated whitespace.
"""
return u" ".join(name.split(None)) if name else name
@api.model @api.model
def _get_inverse_name(self, name, is_company=False): def _get_inverse_name(self, name, is_company=False):
"""Try to revert the effect of :meth:`._compute_name`.
"""Compute the inverted name.
- If the partner is a company, save it in the lastname. - If the partner is a company, save it in the lastname.
- Otherwise, make a guess. - Otherwise, make a guess.
@ -90,21 +131,23 @@ class ResPartner(models.Model):
parts = [name or False, False] parts = [name or False, False]
# Guess name splitting # Guess name splitting
else: else:
parts = name.split(" ", 1)
parts = name.strip().split(" ", 1)
while len(parts) < 2: while len(parts) < 2:
parts.append(False) parts.append(False)
return parts
return {"lastname": parts[0], "firstname": parts[1]}
@api.one @api.one
def _inverse_name(self): def _inverse_name(self):
"""Try to revert the effect of :meth:`._compute_name`."""
parts = self._get_inverse_name(self.name, self.is_company) parts = self._get_inverse_name(self.name, self.is_company)
self.lastname, self.firstname = parts
self.lastname, self.firstname = parts["lastname"], parts["firstname"]
@api.one @api.one
@api.constrains("firstname", "lastname") @api.constrains("firstname", "lastname")
def _check_name(self): def _check_name(self):
"""Ensure at least one name is set.""" """Ensure at least one name is set."""
if not (self.firstname or self.lastname):
if ((self.type == 'contact' or self.is_company) and
not (self.firstname or self.lastname)):
raise exceptions.EmptyNamesError(self) raise exceptions.EmptyNamesError(self)
@api.one @api.one
@ -145,3 +188,11 @@ class ResPartner(models.Model):
# Force calculations there # Force calculations there
records._inverse_name() records._inverse_name()
_logger.info("%d partners updated installing module.", len(records)) _logger.info("%d partners updated installing module.", len(records))
# Disabling SQL constraint givint a more explicit error using a Python
# contstraint
_sql_constraints = [(
'check_name',
"CHECK( 1=1 )",
'Contacts require a name.'
)]

30
partner_firstname/models/res_user.py

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# © 2013 Nicolas Bessi (Camptocamp SA)
# © 2014 Agile Business Group (<http://www.agilebg.com>)
# © 2015 Grupo ESOC (<http://www.grupoesoc.es>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import logging
from openerp import api, models
_logger = logging.getLogger(__name__)
class ResUser(models.Model):
_inherit = 'res.users'
@api.model
def default_get(self, fields_list):
"""Invert name when getting default values."""
result = super(ResUser, self).default_get(fields_list)
partner_model = self.env['res.partner']
inverted = partner_model._get_inverse_name(
partner_model._get_whitespace_cleaned_name(result.get("name", "")),
result.get("is_company", False))
for field in inverted.keys():
if field in fields_list:
result[field] = inverted.get(field)
return result

39
partner_firstname/tests/__init__.py

@ -1,31 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
##############################################################################
#
# Authors: Nemry Jonathan
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
# All Rights Reserved
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs.
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contact a Free Software
# Service Company.
#
# 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 2
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
# © 2014 Nemry Jonathan (Acsone SA/NV) (http://www.acsone.eu)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import test_empty, test_name, test_onchange
from . import (
test_create,
test_defaults,
test_delete,
test_empty,
test_name,
test_onchange
)

30
partner_firstname/tests/base.py

@ -1,29 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Authors: Nemry Jonathan
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
# All Rights Reserved
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs.
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contact a Free Software
# Service Company.
#
# 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 2
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# © 2014 Nemry Jonathan (Acsone SA/NV) (http://www.acsone.eu)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp.tests.common import TransactionCase from openerp.tests.common import TransactionCase
from .. import exceptions as ex from .. import exceptions as ex
@ -71,7 +48,8 @@ class BaseCase(TransactionCase, MailInstalled):
def test_copy(self): def test_copy(self):
"""Copy the partner and compare the result.""" """Copy the partner and compare the result."""
self.expect(self.lastname, u"%s (copy)" % self.firstname) self.expect(self.lastname, u"%s (copy)" % self.firstname)
self.changed = self.original.with_context(lang="en_US").copy()
self.changed = (self.original.with_context(copy=True, lang="en_US")
.copy())
def test_one_name(self): def test_one_name(self):
"""Test what happens when only one name is given.""" """Test what happens when only one name is given."""

82
partner_firstname/tests/test_create.py

@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
# © 2015 Grupo ESOC Ingeniería de Servicios, S.L. - Jairo Llopis.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
"""Test default values for models."""
from openerp.tests.common import TransactionCase
from .base import MailInstalled
class PersonCase(TransactionCase):
"""Test ``res.partner`` when it is a person."""
context = {"default_is_company": False}
model = "res.partner"
def setUp(self):
super(PersonCase, self).setUp()
self.good_values = {
"firstname": u"Núñez",
"lastname": u"Fernán",
}
self.good_values["name"] = "%s %s" % (self.good_values["lastname"],
self.good_values["firstname"])
if "default_is_company" in self.context:
self.good_values["is_company"] = self.context["default_is_company"]
self.values = self.good_values.copy()
def tearDown(self):
self.record = (self.env[self.model]
.with_context(self.context)
.create(self.values))
for key, value in self.good_values.iteritems():
self.assertEqual(
self.record[key],
value,
"Checking key %s" % key)
super(PersonCase, self).tearDown()
def test_no_name(self):
"""Name is calculated."""
del self.values["name"]
def test_wrong_name_value(self):
"""Wrong name value is ignored, name is calculated."""
self.values["name"] = u"BÄD"
def test_wrong_name_context(self):
"""Wrong name context is ignored, name is calculated."""
del self.values["name"]
self.context["default_name"] = u"BÄD"
def test_wrong_name_value_and_context(self):
"""Wrong name value and context is ignored, name is calculated."""
self.values["name"] = u"BÄD1"
self.context["default_name"] = u"BÄD2"
class CompanyCase(PersonCase):
"""Test ``res.partner`` when it is a company."""
context = {"default_is_company": True}
def setUp(self):
super(CompanyCase, self).setUp()
self.good_values.update(lastname=self.values["name"], firstname=False)
self.values = self.good_values.copy()
class UserCase(PersonCase, MailInstalled):
"""Test ``res.users``."""
model = "res.users"
context = {"default_login": "user@example.com"}
def tearDown(self):
# Cannot create users if ``mail`` is installed
if self.mail_installed():
# Skip tests
super(PersonCase, self).tearDown()
else:
# Run tests
super(UserCase, self).tearDown()

65
partner_firstname/tests/test_defaults.py

@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
# © 2015 Grupo ESOC Ingeniería de Servicios, S.L. - Jairo Llopis.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
"""Test default values for models."""
from openerp.tests.common import TransactionCase
from .base import MailInstalled
class PersonCase(TransactionCase):
"""Test ``res.partner`` when it is a person."""
context = {"default_is_company": False}
model = "res.partner"
def setUp(self):
super(PersonCase, self).setUp()
self.values = {
"firstname": u"Núñez",
"lastname": u"Fernán",
}
self.values["name"] = "%s %s" % (self.values["lastname"],
self.values["firstname"])
if "default_is_company" in self.context:
self.values["is_company"] = self.context["default_is_company"]
def tearDown(self):
for key, value in self.values.iteritems():
self.assertEqual(
self.defaults.get(key),
value,
"Checking key %s" % key)
return super(PersonCase, self).tearDown()
def test_default_get(self):
"""Getting default values for fields includes new fields."""
self.defaults = (self.env[self.model]
.with_context(self.context,
default_name=self.values["name"])
.default_get(self.values.keys()))
class CompanyCase(PersonCase):
"""Test ``res.partner`` when it is a company."""
context = {"default_is_company": True}
def tearDown(self):
self.values.update(lastname=self.values["name"], firstname=False)
return super(CompanyCase, self).tearDown()
class UserCase(PersonCase, MailInstalled):
"""Test ``res.users``."""
model = "res.users"
context = {"default_login": "user@example.com"}
def tearDown(self):
# Cannot create users if ``mail`` is installed
if self.mail_installed():
# Skip tests
super(PersonCase, self).tearDown()
else:
# Run tests
super(UserCase, self).tearDown()

38
partner_firstname/tests/test_delete.py

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
# © 2015 Grupo ESOC
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp.tests.common import TransactionCase
from .base import MailInstalled
class CompanyCase(TransactionCase):
model = "res.partner"
context = {"default_is_company": True}
def test_computing_after_unlink(self):
"""Test what happens if recomputed after unlinking.
This test might seem useless, but really this happens when module
``partner_relations`` is installed.
See https://github.com/OCA/partner-contact/issues/154.
"""
data = {"name": u"Söme name"}
record = self.env[self.model].with_context(**self.context).create(data)
record.unlink()
record.recompute()
class PersonCase(CompanyCase):
context = {"default_is_company": False}
class UserCase(CompanyCase, MailInstalled):
model = "res.users"
context = {"default_login": "user@example.com"}
def test_computing_after_unlink(self):
# Cannot create users if ``mail`` is installed
if not self.mail_installed():
super(UserCase, self).test_computing_after_unlink()

48
partner_firstname/tests/test_empty.py

@ -1,26 +1,11 @@
# -*- encoding: utf-8 -*-
# Odoo, Open Source Management Solution
# Copyright (C) 2014-2015 Grupo ESOC <www.grupoesoc.es>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
# © 2014-2015 Grupo ESOC <www.grupoesoc.es>
# © 2016 Yannick Vaucher (Camptocamp)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
"""Test situations where names are empty. """Test situations where names are empty.
To have more accurate results, remove the ``mail`` module before testing. To have more accurate results, remove the ``mail`` module before testing.
""" """
from openerp.tests.common import TransactionCase from openerp.tests.common import TransactionCase
from .base import MailInstalled from .base import MailInstalled
from .. import exceptions as ex from .. import exceptions as ex
@ -34,8 +19,9 @@ class CompanyCase(TransactionCase):
def tearDown(self): def tearDown(self):
try: try:
data = {"name": self.name} data = {"name": self.name}
model = self.env[self.model].with_context(**self.context)
with self.assertRaises(ex.EmptyNamesError): with self.assertRaises(ex.EmptyNamesError):
self.env[self.model].with_context(**self.context).create(data)
model.create(data)
finally: finally:
super(CompanyCase, self).tearDown() super(CompanyCase, self).tearDown()
@ -50,7 +36,7 @@ class CompanyCase(TransactionCase):
class PersonCase(CompanyCase): class PersonCase(CompanyCase):
"""Test ``res.partner`` when it is a person.""" """Test ``res.partner`` when it is a person."""
context = {"default_is_company": False}
context = {"default_is_company": False, "default_type": 'contact'}
class UserCase(CompanyCase, MailInstalled): class UserCase(CompanyCase, MailInstalled):
@ -66,3 +52,23 @@ class UserCase(CompanyCase, MailInstalled):
else: else:
# Run tests # Run tests
super(UserCase, self).tearDown() super(UserCase, self).tearDown()
class AddressCase(TransactionCase):
"""Test ``res.partner`` when it is a address."""
def test_new_empty_invoice_address(self):
"""Create an invoice patner without name."""
self.original = self.env["res.partner"].create({
"is_company": False,
"type": 'invoice',
"lastname": "",
"firstname": ""})
def test_new_empty_shipping_address(self):
"""Create an shipping patner without name."""
self.original = self.env["res.partner"].create({
"is_company": False,
"type": 'delivery',
"lastname": "",
"firstname": ""})

3
partner_firstname/tests/test_onchange.py

@ -1,4 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2015 Grupo ESOC <www.grupoesoc.es>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
"""These tests try to mimic the behavior of the UI form. """These tests try to mimic the behavior of the UI form.
The form operates in onchange mode, with its limitations. The form operates in onchange mode, with its limitations.

64
partner_firstname/views/res_partner.xml

@ -15,7 +15,7 @@
}</attribute> }</attribute>
</xpath> </xpath>
<xpath expr="//field[@name='category_id']" position="before">
<xpath expr="//h1//field[@name='name']/.." position="before">
<group attrs="{'invisible': [('is_company', '=', True)]}"> <group attrs="{'invisible': [('is_company', '=', True)]}">
<field name="lastname" attrs= <field name="lastname" attrs=
"{'required': [('firstname', '=', False), "{'required': [('firstname', '=', False),
@ -42,47 +42,20 @@
}</attribute> }</attribute>
</xpath> </xpath>
<xpath expr="//field[@name='category_id']" position="before">
<group attrs="{'invisible': [('is_company', '=', True)]}">
<field name="lastname" attrs=
"{'required': [('firstname', '=', False),
('is_company', '=', False)]}"/>
<field name="firstname" attrs=
"{'required': [('lastname', '=', False),
('is_company', '=', False)]}"/>
</group>
</xpath>
<!-- Modify inner contact form of child_ids -->
<xpath expr="//field[@name='child_ids']/form
//field[@name='category_id']"
position="before">
<group attrs="{'invisible': [('is_company', '=', True)]}">
<field name="lastname" attrs=
"{'required': [('firstname', '=', False),
('is_company', '=', False)]}"/>
<field name="firstname" attrs=
"{'required': [('lastname', '=', False),
('is_company', '=', False)]}"/>
</group>
</xpath>
<xpath expr="//field[@name='child_ids']/form
//field[@name='category_id']"
position="attributes">
<attribute name="style"/>
</xpath>
<xpath expr="//field[@name='child_ids']/form//label[@for='name']"
position="before">
<xpath expr="//h1//field[@name='name']/.." position="after">
<div class="oe_edit_only"> <div class="oe_edit_only">
<field name="is_company"
on_change="onchange_type(is_company)"/>
<label for="is_company"
string="Is a Company?"/>
<group attrs="{'invisible': [('is_company', '=', True)]}">
<field name="lastname" attrs=
"{'required': [('firstname', '=', False),
('is_company', '=', False)]}"/>
<field name="firstname" attrs=
"{'required': [('lastname', '=', False),
('is_company', '=', False)]}"/>
</group>
</div> </div>
</xpath> </xpath>
<!-- Modify inner contact form of child_ids -->
<xpath expr="//field[@name='child_ids']/form//field[@name='name']" <xpath expr="//field[@name='child_ids']/form//field[@name='name']"
position="attributes"> position="attributes">
<attribute name="attrs">{ <attribute name="attrs">{
@ -90,6 +63,21 @@
'required': [('is_company', '=', True)] 'required': [('is_company', '=', True)]
}</attribute> }</attribute>
</xpath> </xpath>
<xpath expr="//field[@name='child_ids']/form//field[@name='name']"
position="after">
<div class="oe_edit_only" colspan="2">
<field name="is_company" invisible="True"/>
<group attrs="{'invisible': [('is_company', '=', True)]}">
<field name="lastname" attrs=
"{'required': [('firstname', '=', False),
('is_company', '=', False)]}"/>
<field name="firstname" attrs=
"{'required': [('lastname', '=', False),
('is_company', '=', False)]}"/>
</group>
</div>
</xpath>
</data> </data>
</field> </field>
</record> </record>

4
partner_firstname/views/res_user.xml

@ -2,10 +2,6 @@
<openerp> <openerp>
<data> <data>
<!-- Required before modifying `base.vew_users_form`.
https://github.com/odoo/odoo/issues/6324#issuecomment-93534579 -->
<function model="res.groups" name="update_user_groups_view" />
<record id="view_users_form" model="ir.ui.view"> <record id="view_users_form" model="ir.ui.view">
<field name="name">Add firstname and surnames</field> <field name="name">Add firstname and surnames</field>
<field name="model">res.users</field> <field name="model">res.users</field>

Loading…
Cancel
Save