Jairo Llopis
10 years ago
committed by
Nikul-Chaudhary
11 changed files with 869 additions and 0 deletions
-
72partner_second_lastname/README.rst
-
5partner_second_lastname/__init__.py
-
21partner_second_lastname/__openerp__.py
-
68partner_second_lastname/i18n/es.po
-
63partner_second_lastname/i18n/partner_second_lastname.pot
-
97partner_second_lastname/models.py
-
6partner_second_lastname/tests/__init__.py
-
177partner_second_lastname/tests/test_name.py
-
213partner_second_lastname/tests/test_onchange.py
-
105partner_second_lastname/views/res_partner.xml
-
42partner_second_lastname/views/res_user.xml
@ -0,0 +1,72 @@ |
|||||
|
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
||||
|
:alt: License: AGPL-3 |
||||
|
|
||||
|
Partner second lastname |
||||
|
======================= |
||||
|
|
||||
|
This module was written to extend the functionality of ``partner_firstname`` to |
||||
|
support having a second lastname for contact partners. |
||||
|
|
||||
|
In some countries, it's important to have a second last name for contacts. |
||||
|
|
||||
|
Contact partners will need to fulfill at least one of the name fields |
||||
|
(*First name*, *First last name* or *Second last name*). |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
To use this module, you need to: |
||||
|
|
||||
|
* Edit any partner's form. |
||||
|
* Make sure the partner is not a company. |
||||
|
* Enter firstname and lastnames. |
||||
|
|
||||
|
If you directly enter the full name instead of entering the other fields |
||||
|
separately (maybe from other form), this module will try to guess the best |
||||
|
match for your input and split it between firstname, lastname and second |
||||
|
lastname. |
||||
|
|
||||
|
If the name you enter is in the form *Firstname Lastname1 Lastname2*, it will |
||||
|
be split as such. If you use a comma, it will understand it as *Lastname1 |
||||
|
Lastname2, Firstname*. |
||||
|
|
||||
|
If you can, always enter it manually please. Automatic guessing could fail for |
||||
|
you easily in some corner cases. |
||||
|
|
||||
|
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas |
||||
|
:alt: Try me on Runbot |
||||
|
:target: https://runbot.odoo-community.org/runbot/134/8.0 |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
|
||||
|
Bugs are tracked on `GitHub Issues |
||||
|
<https://github.com/OCA/partner-contact/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 `here |
||||
|
<https://github.com/OCA/partner-contact/issues/new?body=module:%20partner_second_lastname%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. |
||||
|
|
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
|
||||
|
* `Grupo ESOC <http://grupoesoc.es>`_: |
||||
|
* `Jairo Llopis <mailto:j.llopis@grupoesoc.es>`_. |
||||
|
|
||||
|
Maintainer |
||||
|
---------- |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://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. |
@ -0,0 +1,5 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
# © 2015 Grupo ESOC Ingeniería de Servicios, S.L.U. |
||||
|
|
||||
|
from . import models |
@ -0,0 +1,21 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
# © 2015 Grupo ESOC Ingeniería de Servicios, S.L.U. |
||||
|
|
||||
|
{ |
||||
|
"name": "Partner second last name", |
||||
|
"version": "8.0.4.0.0", |
||||
|
"author": "Grupo ESOC, Odoo Community Association (OCA)", |
||||
|
"license": "AGPL-3", |
||||
|
"maintainer": "Odoo Community Association (OCA)", |
||||
|
"category": "Extra Tools", |
||||
|
"website": "http://www.grupoesoc.es", |
||||
|
"depends": [ |
||||
|
"partner_firstname" |
||||
|
], |
||||
|
"data": [ |
||||
|
"views/res_partner.xml", |
||||
|
"views/res_user.xml", |
||||
|
], |
||||
|
"installable": True, |
||||
|
} |
@ -0,0 +1,68 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * partner_lastname2 |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 8.0-20150327\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2015-08-13 11:16+0100\n" |
||||
|
"PO-Revision-Date: 2015-08-13 11:16+0100\n" |
||||
|
"Last-Translator: Jairo Llopis <j.llopis@grupoesoc.es>\n" |
||||
|
"Language-Team: \n" |
||||
|
"Language: es_ES\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: 8bit\n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
"X-Generator: Poedit 1.8.1\n" |
||||
|
|
||||
|
#. module: partner_second_lastname |
||||
|
#: model:ir.model,name:partner_second_lastname.model_res_partner |
||||
|
msgid "Partner" |
||||
|
msgstr "Empresa" |
||||
|
|
||||
|
#. module: partner_second_lastname |
||||
|
#: field:res.partner,lastname2:0 |
||||
|
msgid "Second last name" |
||||
|
msgstr "Segundo apellido" |
||||
|
|
||||
|
#. module: partner_second_lastname |
||||
|
#: view:res.partner:partner_second_lastname.partner_form |
||||
|
#: view:res.partner:partner_second_lastname.partner_simple_form |
||||
|
msgid "" |
||||
|
"{\n" |
||||
|
" 'required': [('firstname', '=', False),\n" |
||||
|
" ('lastname2', '=', False),\n" |
||||
|
" ('is_company', '=', False)]\n" |
||||
|
" }" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_second_lastname |
||||
|
#: view:res.users:partner_second_lastname.users_form |
||||
|
msgid "" |
||||
|
"{\n" |
||||
|
" 'required': [('firstname', '=', False),\n" |
||||
|
" ('lastname2', '=', False)]\n" |
||||
|
" }" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_second_lastname |
||||
|
#: view:res.partner:partner_second_lastname.partner_form |
||||
|
#: view:res.partner:partner_second_lastname.partner_simple_form |
||||
|
msgid "" |
||||
|
"{\n" |
||||
|
" 'required': [('lastname', '=', False),\n" |
||||
|
" ('lastname2', '=', False),\n" |
||||
|
" ('is_company', '=', False)]\n" |
||||
|
" }" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_second_lastname |
||||
|
#: view:res.users:partner_second_lastname.users_form |
||||
|
msgid "" |
||||
|
"{\n" |
||||
|
" 'required': [('lastname', '=', False),\n" |
||||
|
" ('lastname2', '=', False)]\n" |
||||
|
" }" |
||||
|
msgstr "" |
@ -0,0 +1,63 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * partner_second_lastname |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 8.0-20150811\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2015-08-13 09:15+0000\n" |
||||
|
"PO-Revision-Date: 2015-08-13 09:15+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: \n" |
||||
|
|
||||
|
#. module: partner_second_lastname |
||||
|
#: model:ir.model,name:partner_second_lastname.model_res_partner |
||||
|
msgid "Partner" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_second_lastname |
||||
|
#: field:res.partner,lastname2:0 |
||||
|
msgid "Second last name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_second_lastname |
||||
|
#: view:res.partner:partner_second_lastname.partner_form |
||||
|
#: view:res.partner:partner_second_lastname.partner_simple_form |
||||
|
msgid "{\n" |
||||
|
" 'required': [('firstname', '=', False),\n" |
||||
|
" ('lastname2', '=', False),\n" |
||||
|
" ('is_company', '=', False)]\n" |
||||
|
" }" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_second_lastname |
||||
|
#: view:res.users:partner_second_lastname.users_form |
||||
|
msgid "{\n" |
||||
|
" 'required': [('firstname', '=', False),\n" |
||||
|
" ('lastname2', '=', False)]\n" |
||||
|
" }" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_second_lastname |
||||
|
#: view:res.partner:partner_second_lastname.partner_form |
||||
|
#: view:res.partner:partner_second_lastname.partner_simple_form |
||||
|
msgid "{\n" |
||||
|
" 'required': [('lastname', '=', False),\n" |
||||
|
" ('lastname2', '=', False),\n" |
||||
|
" ('is_company', '=', False)]\n" |
||||
|
" }" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_second_lastname |
||||
|
#: view:res.users:partner_second_lastname.users_form |
||||
|
msgid "{\n" |
||||
|
" 'required': [('lastname', '=', False),\n" |
||||
|
" ('lastname2', '=', False)]\n" |
||||
|
" }" |
||||
|
msgstr "" |
||||
|
|
@ -0,0 +1,97 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
# © 2015 Grupo ESOC Ingeniería de Servicios, S.L.U. |
||||
|
|
||||
|
from openerp import api, fields, models |
||||
|
from openerp.addons.partner_firstname import exceptions |
||||
|
|
||||
|
|
||||
|
class ResPartner(models.Model): |
||||
|
"""Adds a second last name.""" |
||||
|
|
||||
|
_inherit = "res.partner" |
||||
|
|
||||
|
lastname2 = fields.Char("Second last name") |
||||
|
|
||||
|
@api.model |
||||
|
def _get_computed_name(self, lastname, firstname, lastname2=None): |
||||
|
"""Compute the name combined with the second lastname too. |
||||
|
|
||||
|
We have 2 lastnames, so lastnames and firstname will be separated by a |
||||
|
comma. |
||||
|
""" |
||||
|
names = list() |
||||
|
|
||||
|
if lastname: |
||||
|
names.append(lastname) |
||||
|
if lastname2: |
||||
|
names.append(lastname2) |
||||
|
if names and firstname: |
||||
|
names[-1] = names[-1] + "," |
||||
|
if firstname: |
||||
|
names.append(firstname) |
||||
|
|
||||
|
return u" ".join(names) |
||||
|
|
||||
|
@api.one |
||||
|
@api.depends("firstname", "lastname", "lastname2") |
||||
|
def _compute_name(self): |
||||
|
"""Write :attr:`~.name` according to splitted data.""" |
||||
|
self.name = self._get_computed_name(self.lastname, |
||||
|
self.firstname, |
||||
|
self.lastname2) |
||||
|
|
||||
|
@api.one |
||||
|
def _inverse_name(self): |
||||
|
"""Try to revert the effect of :meth:`._compute_name`.""" |
||||
|
parts = self._get_inverse_name(self.name, self.is_company) |
||||
|
|
||||
|
# Avoid to hit :meth:`~._check_name` with all 3 fields being ``False`` |
||||
|
before, after = dict(), dict() |
||||
|
for key, value in parts.iteritems(): |
||||
|
(before if value else after)[key] = value |
||||
|
self.update(before) |
||||
|
self.update(after) |
||||
|
|
||||
|
@api.model |
||||
|
def _get_inverse_name(self, name, is_company=False): |
||||
|
"""Compute the inverted name. |
||||
|
|
||||
|
- If the partner is a company, save it in the lastname. |
||||
|
- Otherwise, make a guess. |
||||
|
""" |
||||
|
# Company name goes to the lastname |
||||
|
if is_company or not name: |
||||
|
parts = [False, name or False, False] |
||||
|
|
||||
|
# The comma separates the firstname |
||||
|
elif "," in name: |
||||
|
lastnames, firstname = name.split(",", 1) |
||||
|
parts = [firstname.strip()] + lastnames.split(" ", 1) |
||||
|
|
||||
|
# Without comma, the user wrote the firstname first |
||||
|
else: |
||||
|
parts = name.split(" ", 2) |
||||
|
|
||||
|
while len(parts) < 3: |
||||
|
parts.append(False) |
||||
|
|
||||
|
return {"firstname": parts[0], |
||||
|
"lastname": parts[1], |
||||
|
"lastname2": parts[2]} |
||||
|
|
||||
|
@api.one |
||||
|
@api.constrains("firstname", "lastname", "lastname2") |
||||
|
def _check_name(self): |
||||
|
"""Ensure at least one name is set.""" |
||||
|
try: |
||||
|
super(ResPartner, self)._check_name() |
||||
|
except exceptions.EmptyNamesError as error: |
||||
|
if not self.lastname2: |
||||
|
raise error |
||||
|
|
||||
|
@api.one |
||||
|
@api.onchange("firstname", "lastname", "lastname2") |
||||
|
def _onchange_subnames(self): |
||||
|
"""Trigger onchange with :attr:`~.lastname2` too.""" |
||||
|
super(ResPartner, self)._onchange_subnames() |
@ -0,0 +1,6 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
# © 2015 Grupo ESOC Ingeniería de Servicios, S.L.U. |
||||
|
|
||||
|
from . import test_name, test_onchange |
||||
|
from openerp.addons.partner_firstname.tests import test_empty |
@ -0,0 +1,177 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
# © 2015 Grupo ESOC Ingeniería de Servicios, S.L.U. |
||||
|
|
||||
|
from openerp.tests.common import TransactionCase |
||||
|
from openerp.addons.partner_firstname.tests.base import MailInstalled |
||||
|
|
||||
|
|
||||
|
class CompanyCase(TransactionCase): |
||||
|
"""Test ``res.partner`` when it is a company.""" |
||||
|
def tearDown(self): |
||||
|
try: |
||||
|
new = self.env["res.partner"].create({ |
||||
|
"is_company": True, |
||||
|
"name": self.name, |
||||
|
}) |
||||
|
|
||||
|
# Name should be cleaned of unneeded whitespace |
||||
|
clean_name = u" ".join(self.name.split(None)) |
||||
|
|
||||
|
# Check it's saved OK |
||||
|
self.assertEqual( |
||||
|
new.name, |
||||
|
clean_name, |
||||
|
"Saved company name is wrong.") |
||||
|
|
||||
|
# Check it's saved in the lastname |
||||
|
self.assertEqual( |
||||
|
new.lastname, |
||||
|
clean_name, |
||||
|
"Company name should be saved in the lastname field.") |
||||
|
|
||||
|
# Check that other fields are empty |
||||
|
self.assertEqual( |
||||
|
new.firstname, |
||||
|
False, |
||||
|
"Company first name must always be empty.") |
||||
|
self.assertEqual( |
||||
|
new.lastname2, |
||||
|
False, |
||||
|
"Company last name 2 must always be empty.") |
||||
|
|
||||
|
finally: |
||||
|
super(CompanyCase, self).tearDown() |
||||
|
|
||||
|
def test_long_name(self): |
||||
|
"""Create a company with a long name.""" |
||||
|
self.name = u"Söme very lóng nâme" |
||||
|
|
||||
|
def test_short_name(self): |
||||
|
"""Create a company with a short name.""" |
||||
|
self.name = u"Shoŕt" |
||||
|
|
||||
|
def test_whitespace_before(self): |
||||
|
"""Create a company with name prefixed with whitespace.""" |
||||
|
self.name = u" Wĥitespace befòre" |
||||
|
|
||||
|
def test_whitespace_after(self): |
||||
|
"""Create a company with name suffixed with whitespace.""" |
||||
|
self.name = u"Whitespâce aftér " |
||||
|
|
||||
|
def test_whitespace_inside(self): |
||||
|
"""Create a company with whitespace inside the name.""" |
||||
|
self.name = u"Whitespacé ïnside" |
||||
|
|
||||
|
def test_whitespace_everywhere(self): |
||||
|
"""Create a company with whitespace everywhere in the name.""" |
||||
|
self.name = u" A lot öf whitespace " |
||||
|
|
||||
|
|
||||
|
class PersonCase(TransactionCase): |
||||
|
"""Test ``res.partner`` when it is a person.""" |
||||
|
model = "res.partner" |
||||
|
context = dict() |
||||
|
|
||||
|
def setUp(self): |
||||
|
super(PersonCase, self).setUp() |
||||
|
|
||||
|
self.firstname = u"Fírstname" |
||||
|
self.lastname = u"Làstname1" |
||||
|
self.lastname2 = u"Lâstname2" |
||||
|
self.template = u"%(last1)s %(last2)s, %(first)s" |
||||
|
|
||||
|
def tearDown(self): |
||||
|
try: |
||||
|
new = (self.env[self.model].with_context(self.context) |
||||
|
.create(self.params)) |
||||
|
|
||||
|
# Check that each individual field matches |
||||
|
self.assertEqual( |
||||
|
self.firstname, |
||||
|
new.firstname, |
||||
|
"First name saved badly.") |
||||
|
self.assertEqual( |
||||
|
self.lastname, |
||||
|
new.lastname, |
||||
|
"Last name 1 saved badly.") |
||||
|
self.assertEqual( |
||||
|
self.lastname2, |
||||
|
new.lastname2, |
||||
|
"Last name 2 saved badly.") |
||||
|
|
||||
|
# Check that name gets saved fine |
||||
|
self.assertEqual( |
||||
|
self.template % ({"last1": self.lastname, |
||||
|
"last2": self.lastname2, |
||||
|
"first": self.firstname}), |
||||
|
new.name, |
||||
|
"Name saved badly.") |
||||
|
|
||||
|
finally: |
||||
|
super(PersonCase, self).tearDown() |
||||
|
|
||||
|
def test_firstname_first(self): |
||||
|
"""Create a person setting his first name first.""" |
||||
|
self.params = { |
||||
|
"is_company": False, |
||||
|
"name": "%s %s %s" % (self.firstname, |
||||
|
self.lastname, |
||||
|
self.lastname2), |
||||
|
} |
||||
|
|
||||
|
def test_firstname_last(self): |
||||
|
"""Create a persong setting his first name last.""" |
||||
|
self.params = { |
||||
|
"is_company": False, |
||||
|
"name": "%s %s, %s" % (self.lastname, |
||||
|
self.lastname2, |
||||
|
self.firstname), |
||||
|
} |
||||
|
|
||||
|
def test_firstname_only(self): |
||||
|
"""Create a persong setting his first name only.""" |
||||
|
self.lastname = self.lastname2 = False |
||||
|
self.template = "%(first)s" |
||||
|
self.params = { |
||||
|
"is_company": False, |
||||
|
"name": self.firstname, |
||||
|
} |
||||
|
|
||||
|
def test_firstname_lastname_only(self): |
||||
|
"""Create a persong setting his first name and last name 1 only.""" |
||||
|
self.lastname2 = False |
||||
|
self.template = "%(last1)s, %(first)s" |
||||
|
self.params = { |
||||
|
"is_company": False, |
||||
|
"name": "%s %s" % (self.firstname, self.lastname), |
||||
|
} |
||||
|
|
||||
|
def test_lastname_firstname_only(self): |
||||
|
"""Create a persong setting his last name 1 and first name only.""" |
||||
|
self.lastname2 = False |
||||
|
self.template = "%(last1)s, %(first)s" |
||||
|
self.params = { |
||||
|
"is_company": False, |
||||
|
"name": "%s, %s" % (self.lastname, self.firstname), |
||||
|
} |
||||
|
|
||||
|
def test_separately(self): |
||||
|
"""Create a person setting separately all fields.""" |
||||
|
self.params = { |
||||
|
"is_company": False, |
||||
|
"firstname": self.firstname, |
||||
|
"lastname": self.lastname, |
||||
|
"lastname2": self.lastname2, |
||||
|
} |
||||
|
|
||||
|
|
||||
|
class UserCase(PersonCase, MailInstalled): |
||||
|
"""Test ``res.users``.""" |
||||
|
model = "res.users" |
||||
|
context = {"default_login": "user@example.com"} |
||||
|
|
||||
|
def tearDown(self): |
||||
|
# Skip if ``mail`` is installed |
||||
|
if not self.mail_installed(): |
||||
|
super(UserCase, self).tearDown() |
@ -0,0 +1,213 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
# © 2015 Grupo ESOC Ingeniería de Servicios, S.L.U. |
||||
|
"""These tests try to mimic the behavior of the UI form. |
||||
|
|
||||
|
The form operates in onchange mode, with its limitations. |
||||
|
""" |
||||
|
|
||||
|
from openerp.tests.common import TransactionCase |
||||
|
|
||||
|
|
||||
|
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 |
||||
|
|
||||
|
|
||||
|
class PartnerCompanyCase(OnChangeCase): |
||||
|
is_company = True |
||||
|
|
||||
|
def tearDown(self): |
||||
|
"""Companies never have ``firstname`` nor ``lastname2``.""" |
||||
|
self.assertEqual(self.partner.firstname, False) |
||||
|
self.assertEqual(self.partner.lastname2, False) |
||||
|
|
||||
|
def set_name(self, value): |
||||
|
self.partner.name = value |
||||
|
|
||||
|
# It triggers onchange |
||||
|
self.partner._onchange_name() |
||||
|
|
||||
|
# Ensure it's properly set |
||||
|
self.assertEqual(self.partner.name, value) |
||||
|
|
||||
|
def test_create_from_form(self): |
||||
|
"""A user creates a company from the form.""" |
||||
|
name = u"Sôme company" |
||||
|
with self.env.do_in_onchange(): |
||||
|
# User presses ``new`` |
||||
|
self.partner = self.new_partner() |
||||
|
|
||||
|
# User changes fields |
||||
|
self.set_name(name) |
||||
|
|
||||
|
self.assertEqual(self.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`` |
||||
|
self.partner = self.new_partner() |
||||
|
|
||||
|
# User changes fields |
||||
|
self.set_name(u"Fóo") |
||||
|
self.set_name(u"") |
||||
|
|
||||
|
self.assertEqual(self.partner.lastname, False) |
||||
|
|
||||
|
|
||||
|
class PartnerContactCase(OnChangeCase): |
||||
|
def set_field(self, field, value): |
||||
|
# Changes the field |
||||
|
setattr(self.partner, field, value) |
||||
|
|
||||
|
if field in ("firstname", "lastname", "lastname2"): |
||||
|
# Trigger onchanges |
||||
|
self.partner._onchange_subnames() |
||||
|
self.partner._onchange_name() |
||||
|
|
||||
|
# Check it's set OK |
||||
|
self.assertEqual(getattr(self.partner, field), value) |
||||
|
|
||||
|
def test_create_from_form_empty(self): |
||||
|
"""A user creates a contact from the form. |
||||
|
|
||||
|
All subfields must be false, or the ``required`` attr will not work as |
||||
|
expected. |
||||
|
""" |
||||
|
with self.env.do_in_onchange(): |
||||
|
# User presses ``new`` |
||||
|
self.partner = self.new_partner() |
||||
|
|
||||
|
# Odoo tries to compute the name |
||||
|
self.partner._compute_name() |
||||
|
|
||||
|
# This is then triggered |
||||
|
self.partner._onchange_name() |
||||
|
|
||||
|
# Subnames must start as False to make the UI work fine |
||||
|
self.assertEqual(self.partner.firstname, False) |
||||
|
self.assertEqual(self.partner.lastname, False) |
||||
|
self.assertEqual(self.partner.lastname2, False) |
||||
|
|
||||
|
# ``name`` cannot be False, or upstream Odoo will fail |
||||
|
self.assertEqual(self.partner.name, u"") |
||||
|
|
||||
|
def test_create_from_form_only_firstname(self): |
||||
|
"""A user creates a contact with only the firstname from the form.""" |
||||
|
firstname = u"Fïrst" |
||||
|
with self.env.do_in_onchange(): |
||||
|
# User presses ``new`` |
||||
|
self.partner = self.new_partner() |
||||
|
|
||||
|
# User changes fields |
||||
|
self.set_field("firstname", firstname) |
||||
|
|
||||
|
self.assertEqual(self.partner.lastname, False) |
||||
|
self.assertEqual(self.partner.lastname2, False) |
||||
|
self.assertEqual(self.partner.name, firstname) |
||||
|
|
||||
|
def test_create_from_form_only_lastname(self): |
||||
|
"""A user creates a contact with only the lastname from the form.""" |
||||
|
lastname = u"Läst" |
||||
|
with self.env.do_in_onchange(): |
||||
|
# User presses ``new`` |
||||
|
self.partner = self.new_partner() |
||||
|
|
||||
|
# User changes fields |
||||
|
self.set_field("lastname", lastname) |
||||
|
|
||||
|
self.assertEqual(self.partner.firstname, False) |
||||
|
self.assertEqual(self.partner.lastname2, False) |
||||
|
self.assertEqual(self.partner.name, lastname) |
||||
|
|
||||
|
def test_create_from_form_only_lastname2(self): |
||||
|
"""A user creates a contact with only the lastname2 from the form.""" |
||||
|
lastname2 = u"Läst2" |
||||
|
with self.env.do_in_onchange(): |
||||
|
# User presses ``new`` |
||||
|
self.partner = self.new_partner() |
||||
|
|
||||
|
# User changes fields |
||||
|
self.set_field("lastname2", lastname2) |
||||
|
|
||||
|
self.assertEqual(self.partner.firstname, False) |
||||
|
self.assertEqual(self.partner.lastname, False) |
||||
|
self.assertEqual(self.partner.name, lastname2) |
||||
|
|
||||
|
def test_create_from_without_firstname(self): |
||||
|
"""A user creates a contact without firstname from the form.""" |
||||
|
lastname = u"Läst" |
||||
|
lastname2 = u"Läst2" |
||||
|
with self.env.do_in_onchange(): |
||||
|
# User presses ``new`` |
||||
|
self.partner = self.new_partner() |
||||
|
|
||||
|
# User changes fields |
||||
|
self.set_field("lastname", lastname) |
||||
|
self.set_field("lastname2", lastname2) |
||||
|
|
||||
|
self.assertEqual(self.partner.firstname, False) |
||||
|
self.assertEqual( |
||||
|
self.partner.name, |
||||
|
u"%s %s" % (lastname, lastname2)) |
||||
|
|
||||
|
def test_create_from_without_lastname(self): |
||||
|
"""A user creates a contact without lastname from the form.""" |
||||
|
firstname = u"Fïrst" |
||||
|
lastname2 = u"Läst2" |
||||
|
with self.env.do_in_onchange(): |
||||
|
# User presses ``new`` |
||||
|
self.partner = self.new_partner() |
||||
|
|
||||
|
# User changes fields |
||||
|
self.set_field("firstname", firstname) |
||||
|
self.set_field("lastname2", lastname2) |
||||
|
|
||||
|
self.assertEqual(self.partner.lastname, False) |
||||
|
self.assertEqual( |
||||
|
self.partner.name, |
||||
|
u"%s, %s" % (lastname2, firstname)) |
||||
|
|
||||
|
def test_create_from_without_lastname2(self): |
||||
|
"""A user creates a contact without lastname2 from the form.""" |
||||
|
firstname = u"Fïrst" |
||||
|
lastname = u"Läst" |
||||
|
with self.env.do_in_onchange(): |
||||
|
# User presses ``new`` |
||||
|
self.partner = self.new_partner() |
||||
|
|
||||
|
# User changes fields |
||||
|
self.set_field("firstname", firstname) |
||||
|
self.set_field("lastname", lastname) |
||||
|
|
||||
|
self.assertEqual(self.partner.lastname2, False) |
||||
|
self.assertEqual( |
||||
|
self.partner.name, |
||||
|
u"%s, %s" % (lastname, firstname)) |
||||
|
|
||||
|
def test_create_from_form_all(self): |
||||
|
"""A user creates a contact with all names from the form.""" |
||||
|
firstname = u"Fïrst" |
||||
|
lastname = u"Läst" |
||||
|
lastname2 = u"Läst2" |
||||
|
with self.env.do_in_onchange(): |
||||
|
# User presses ``new`` |
||||
|
self.partner = self.new_partner() |
||||
|
|
||||
|
# User changes fields |
||||
|
self.set_field("firstname", firstname) |
||||
|
self.set_field("lastname", lastname) |
||||
|
self.set_field("lastname2", lastname2) |
||||
|
|
||||
|
self.assertEqual( |
||||
|
self.partner.name, |
||||
|
u"%s %s, %s" % (lastname, lastname2, firstname)) |
@ -0,0 +1,105 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
© 2015 Grupo ESOC Ingeniería de Servicios, S.L.U. --> |
||||
|
|
||||
|
<openerp> |
||||
|
<data> |
||||
|
<record id="partner_simple_form" model="ir.ui.view"> |
||||
|
<field name="name">Add second last name</field> |
||||
|
<field name="model">res.partner</field> |
||||
|
<field name="inherit_id" |
||||
|
ref="partner_firstname.view_partner_simple_form_firstname"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<data> |
||||
|
<xpath expr="//field[@name='firstname']" position="attributes"> |
||||
|
<attribute name="attrs">{ |
||||
|
'required': [('lastname', '=', False), |
||||
|
('lastname2', '=', False), |
||||
|
('is_company', '=', False)] |
||||
|
}</attribute> |
||||
|
</xpath> |
||||
|
|
||||
|
<xpath expr="//field[@name='lastname']" position="attributes"> |
||||
|
<attribute name="attrs">{ |
||||
|
'required': [('firstname', '=', False), |
||||
|
('lastname2', '=', False), |
||||
|
('is_company', '=', False)] |
||||
|
}</attribute> |
||||
|
</xpath> |
||||
|
|
||||
|
<xpath expr="//field[@name='lastname']" position="after"> |
||||
|
<field name="lastname2" |
||||
|
attrs="{'required': [('firstname', '=', False), |
||||
|
('lastname', '=', False), |
||||
|
('is_company', '=', False)]}"/> |
||||
|
</xpath> |
||||
|
</data> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="partner_form" model="ir.ui.view"> |
||||
|
<field name="name">Add second last name</field> |
||||
|
<field name="model">res.partner</field> |
||||
|
<field name="inherit_id" |
||||
|
ref="partner_firstname.view_partner_form_firstname"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<data> |
||||
|
<!-- Main form --> |
||||
|
<xpath expr="//field[@name='firstname']" position="attributes"> |
||||
|
<attribute name="attrs">{ |
||||
|
'required': [('lastname', '=', False), |
||||
|
('lastname2', '=', False), |
||||
|
('is_company', '=', False)] |
||||
|
}</attribute> |
||||
|
</xpath> |
||||
|
|
||||
|
<xpath expr="//field[@name='lastname']" position="attributes"> |
||||
|
<attribute name="attrs">{ |
||||
|
'required': [('firstname', '=', False), |
||||
|
('lastname2', '=', False), |
||||
|
('is_company', '=', False)] |
||||
|
}</attribute> |
||||
|
</xpath> |
||||
|
|
||||
|
<xpath expr="//field[@name='lastname']" position="after"> |
||||
|
<field name="lastname2" |
||||
|
attrs="{'required': [('firstname', '=', False), |
||||
|
('lastname', '=', False), |
||||
|
('is_company', '=', False)]}"/> |
||||
|
</xpath> |
||||
|
|
||||
|
<!-- Inner contact form of child_ids --> |
||||
|
<xpath expr="//field[@name='child_ids']/form |
||||
|
//field[@name='firstname']" |
||||
|
position="attributes"> |
||||
|
<attribute name="attrs">{ |
||||
|
'required': [('lastname', '=', False), |
||||
|
('lastname2', '=', False), |
||||
|
('is_company', '=', False)] |
||||
|
}</attribute> |
||||
|
</xpath> |
||||
|
|
||||
|
<xpath expr="//field[@name='child_ids']/form |
||||
|
//field[@name='lastname']" |
||||
|
position="attributes"> |
||||
|
<attribute name="attrs">{ |
||||
|
'required': [('firstname', '=', False), |
||||
|
('lastname2', '=', False), |
||||
|
('is_company', '=', False)] |
||||
|
}</attribute> |
||||
|
</xpath> |
||||
|
|
||||
|
<xpath expr="//field[@name='child_ids']/form |
||||
|
//field[@name='lastname']" |
||||
|
position="after"> |
||||
|
<field name="lastname2" |
||||
|
attrs="{'required': [('firstname', '=', False), |
||||
|
('lastname', '=', False), |
||||
|
('is_company', '=', False)]}"/> |
||||
|
</xpath> |
||||
|
</data> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,42 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
© 2015 Grupo ESOC Ingeniería de Servicios, S.L.U. --> |
||||
|
|
||||
|
<openerp> |
||||
|
<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="users_form" model="ir.ui.view"> |
||||
|
<field name="name">Add second last name</field> |
||||
|
<field name="model">res.users</field> |
||||
|
<field name="inherit_id" ref="partner_firstname.view_users_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<data> |
||||
|
<xpath expr="//field[@name='firstname']" position="attributes"> |
||||
|
<attribute name="attrs">{ |
||||
|
'required': [('lastname', '=', False), |
||||
|
('lastname2', '=', False)] |
||||
|
}</attribute> |
||||
|
</xpath> |
||||
|
|
||||
|
<xpath expr="//field[@name='lastname']" position="attributes"> |
||||
|
<attribute name="attrs">{ |
||||
|
'required': [('firstname', '=', False), |
||||
|
('lastname2', '=', False)] |
||||
|
}</attribute> |
||||
|
</xpath> |
||||
|
|
||||
|
<xpath expr="//field[@name='lastname']" position="after"> |
||||
|
<field name="lastname2" |
||||
|
attrs="{'required': [('firstname', '=', False), |
||||
|
('lastname', '=', False)]}"/> |
||||
|
</xpath> |
||||
|
</data> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
</data> |
||||
|
</openerp> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue