Browse Source

Better partner_firstname. Merged rebase.

pull/104/head
Jairo Llopis 10 years ago
parent
commit
d9a7291ef0
  1. 55
      partner_firstname/README.rst
  2. 11
      partner_firstname/__init__.py
  3. 32
      partner_firstname/__openerp__.py
  4. 19
      partner_firstname/data/res_partner.yml
  5. 36
      partner_firstname/exceptions.py
  6. 52
      partner_firstname/i18n/es.po
  7. 33
      partner_firstname/i18n/partner_firstname.pot
  8. 92
      partner_firstname/models.py
  9. 131
      partner_firstname/partner.py
  10. 60
      partner_firstname/partner_view.xml
  11. 49
      partner_firstname/res_user.py
  12. 35
      partner_firstname/res_user_view.xml
  13. 229
      partner_firstname/tests/test_partner_firstname.py
  14. 113
      partner_firstname/views/res_partner.xml
  15. 49
      partner_firstname/views/res_user.xml

55
partner_firstname/README.rst

@ -0,0 +1,55 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3
Partner first name and last name
================================
This module was written to extend the functionality of contacts to support
having separate last name and first name.
Usage
=====
The field *name* becomes a stored function field concatenating the *last name*
and the *first name*. This avoids breaking compatibility with other modules.
Users should fulfill manually the separate fields for *last name* and *first
name*, but in case you edit just the *name* field in some unexpected module,
there is an inverse function that tries to split that automatically. It assumes
that you write the *name* in format *"Lastname Firstname"*, but it could lead to
wrong splitting (because it's just blindly trying to guess what you meant), so
you better specify it manually.
For the same reason, after installing, previous names for contacts will stay in
the *name* field, and the first time you edit any of them you will be asked to
supply the *last name* and *first name* (just once per contact).
For further information, please visit:
* https://www.odoo.com/forum/help-1
Credits
=======
Contributors
------------
* Nicolas Bessi <nicolas.bessi@camptocamp.com>
* Jonathan Nemry <jonathan.nemry@acsone.eu>
* Olivier Laurent <olivier.laurent@acsone.eu>
* Jairo Llopis <j.llopis@grupoesoc.es>
Maintainer
----------
.. image:: http://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: http://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.

11
partner_firstname/__init__.py

@ -1,7 +1,9 @@
# -*- 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
@ -15,8 +17,5 @@
#
# 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/>.
#
##############################################################################
from . import partner
from . import res_user
from . import models

32
partner_firstname/__openerp__.py

@ -1,7 +1,9 @@
# -*- 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
@ -15,35 +17,19 @@
#
# 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/>.
#
##############################################################################
{
'name': 'Partner first name, last name',
'description': """
This module splits first name and last name for non company partners
====================================================================
The field 'name' becomes a stored function field concatenating lastname and
firstname
Note: in version 7.0, installing this module invalidates a yaml test in the
'edi' module
Contributors
============
Jonathan Nemry <jonathan.nemry@acsone.eu>
Olivier Laurent <olivier.laurent@acsone.eu>
""",
'version': '1.2',
'name': 'Partner first name and last name',
'summary': "Split first name and last name for non company partners",
'version': '2.0',
'author': "Camptocamp,Odoo Community Association (OCA)",
'maintainer': 'Camptocamp, Acsone',
'category': 'Extra Tools',
'website': 'http://www.camptocamp.com, http://www.acsone.eu',
'depends': ['base'],
'data': [
'partner_view.xml',
'res_user_view.xml',
'views/res_partner.xml',
'views/res_user.xml',
],
'demo': [],
'test': [],

19
partner_firstname/data/res_partner.yml

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Copyright (C)
# 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/>.
- !function {model: res.partner, name: _firstname_install}

36
partner_firstname/exceptions.py

@ -0,0 +1,36 @@
# -*- 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/>.
from openerp import _, exceptions
class PartnerNameError(exceptions.ValidationError):
def __init__(self, record, value=None):
self.record = record
self._value = value
self.name = _("Error(s) with partner %d's name.") % record.id
@property
def value(self):
raise NotImplementedError()
class EmptyNames(PartnerNameError):
@property
def value(self):
return _("No name is set.")

52
partner_firstname/i18n/es.po

@ -6,48 +6,54 @@ msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-12-23 14:09+0000\n"
"PO-Revision-Date: 2014-12-23 14:09+0000\n"
"Last-Translator: <>\n"
"POT-Creation-Date: 2015-03-30 07:53+0000\n"
"PO-Revision-Date: 2015-03-30 10:01+0100\n"
"Last-Translator: Jairo Llopis <j.llopis@grupoesoc.es>\n"
"Language-Team: \n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: \n"
"X-Generator: Poedit 1.7.5\n"
#. module: partner_firstname
#: code:addons/partner_firstname/partner.py:81
#: code:addons/partner_firstname/res_user.py:35
#: code:addons/partner_firstname/tests/test_partner_firstname.py:56
#: code:addons/partner_firstname/tests/test_partner_firstname.py:57
#: code:addons/partner_firstname/tests/test_partner_firstname.py:71
#: code:addons/partner_firstname/tests/test_partner_firstname.py:72
#: code:addons/partner_firstname/exceptions.py:26
#, python-format
msgid "%s (copy)"
msgstr "%s (copia)"
#. module: partner_firstname
#: model:ir.model,name:partner_firstname.model_res_users
msgid "Users"
msgstr "Usuarios"
msgid "Error(s) with partner %d's name."
msgstr "Errores con el nombre de la empresa %d."
#. module: partner_firstname
#: field:res.partner,firstname:0
msgid "Firstname"
msgid "First name"
msgstr "Nombre"
#. module: partner_firstname
#: view:res.partner:partner_firstname.partner_form
msgid "Is a Company?"
msgstr "¿Es una empresa?"
#. module: partner_firstname
#: field:res.partner,lastname:0
msgid "Lastname"
msgstr "Apellidos"
msgid "Last name"
msgstr "Apellido"
#. module: partner_firstname
#: view:res.partner:0
msgid "Is a Company?"
msgstr "¿Es una empresa?"
#: code:addons/partner_firstname/exceptions.py:40
#, python-format
msgid "No name is set."
msgstr "No se ha establecido ningún nombre."
#. module: partner_firstname
#: model:ir.model,name:partner_firstname.model_res_partner
msgid "Partner"
msgstr "Empresa"
#~ msgid "True"
#~ msgstr "Verdadero"
#~ msgid "%s (copy)"
#~ msgstr "%s (copia)"
#~ msgid "Users"
#~ msgstr "Usuarios"

33
partner_firstname/i18n/partner_firstname.pot

@ -1,13 +1,13 @@
# Translation of OpenERP Server.
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * partner_firstname
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Project-Id-Version: Odoo Server 8.0-20150327\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-01-22 14:09+0000\n"
"PO-Revision-Date: 2014-01-22 14:09+0000\n"
"POT-Creation-Date: 2015-03-30 07:53+0000\n"
"PO-Revision-Date: 2015-03-30 07:53+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@ -16,38 +16,33 @@ msgstr ""
"Plural-Forms: \n"
#. module: partner_firstname
#: code:addons/partner_firstname/partner.py:81
#: code:addons/partner_firstname/res_user.py:35
#: code:addons/partner_firstname/tests/test_partner_firstname.py:56
#: code:addons/partner_firstname/tests/test_partner_firstname.py:57
#: code:addons/partner_firstname/tests/test_partner_firstname.py:71
#: code:addons/partner_firstname/tests/test_partner_firstname.py:72
#: code:addons/partner_firstname/exceptions.py:26
#, python-format
msgid "%s (copy)"
msgid "Error(s) with partner %d's name."
msgstr ""
#. module: partner_firstname
#: model:ir.model,name:partner_firstname.model_res_users
msgid "Users"
#: field:res.partner,firstname:0
msgid "First name"
msgstr ""
#. module: partner_firstname
#: field:res.partner,firstname:0
msgid "Firstname"
#: view:res.partner:partner_firstname.partner_form
msgid "Is a Company?"
msgstr ""
#. module: partner_firstname
#: field:res.partner,lastname:0
msgid "Lastname"
msgid "Last name"
msgstr ""
#. module: partner_firstname
#: view:res.partner:0
msgid "Is a Company?"
#: code:addons/partner_firstname/exceptions.py:40
#, python-format
msgid "No name is set."
msgstr ""
#. module: partner_firstname
#: model:ir.model,name:partner_firstname.model_res_partner
msgid "Partner"
msgstr ""

92
partner_firstname/models.py

@ -0,0 +1,92 @@
# -*- 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/>.
from openerp import api, fields, models
from . import exceptions
class ResPartner(models.Model):
"""Adds last name and first name; name becomes a stored function field."""
_inherit = 'res.partner'
firstname = fields.Char("First name")
lastname = fields.Char("Last name")
name = fields.Char(
compute="_name_compute",
inverse="_name_inverse",
required=False,
store=True)
@api.one
@api.depends("firstname", "lastname")
def _name_compute(self):
"""Write the 'name' field according to splitted data."""
self.name = " ".join((p for p in (self.lastname,
self.firstname) if p))
@api.one
def _name_inverse(self):
"""Try to reverse the effect of _compute_name_custom.
- If the partner is a company, save it in the first name.
- Otherwise, make a guess.
"""
# Remove unneeded whitespace
clean = " ".join(self.name.split(None))
# Clean name avoiding infinite recursion
if self.name != clean:
self.name = clean
# Save name in the real fields
else:
# Company name goes to the lastname
if self.is_company:
parts = [clean, False]
# Guess name splitting
else:
parts = clean.split(" ", 1)
while len(parts) < 2:
parts.append(False)
self.lastname, self.firstname = parts
@api.one
@api.constrains("firstname", "lastname")
def _check_name(self):
"""Ensure at least one name is set."""
if not (self.firstname or self.lastname):
raise exceptions.EmptyNames(self)
@api.model
def _firstname_install(self):
"""Save names correctly in the database.
Before installing the module, field ``name`` contains all full names.
When installing it, this method parses those names and saves them
correctly into the database. This can be called later too if needed.
"""
# Find records with empty firstname and lastname
records = self.search([("firstname", "=", False),
("lastname", "=", False)])
# Force calculations there
records._write_name()

131
partner_firstname/partner.py

@ -1,131 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi. Copyright Camptocamp SA
# Copyright (C) 2014 Agile Business Group (<http://www.agilebg.com>)
#
# 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/>.
#
##############################################################################
from openerp.osv import orm, fields
from openerp.tools.translate import _
import logging
_logger = logging.getLogger(__name__)
class ResPartner(orm.Model):
"""Adds lastname and firstname, name become a stored function field"""
_inherit = 'res.partner'
def _set_default_value_on_column(self, cr, column_name, context=None):
res = super(ResPartner, self)._set_default_value_on_column(
cr, column_name, context=context)
if column_name == 'lastname':
cr.execute('UPDATE res_partner SET lastname = name WHERE name '
'IS NOT NULL AND lastname IS NULL')
cr.execute('ALTER TABLE res_partner ALTER COLUMN lastname '
'SET NOT NULL')
_logger.info("NOT NULL constraint for "
"res_partner.lastname correctly set")
return res
def _prepare_name_custom(self, cursor, uid, partner, context=None):
"""
This function is designed to be inherited in a custom module
"""
names = (partner.lastname, partner.firstname)
fullname = " ".join([s for s in names if s])
return fullname
def _compute_name_custom(self, cursor, uid, ids, fname, arg, context=None):
res = {}
for partner in self.browse(cursor, uid, ids, context=context):
res[partner.id] = self._prepare_name_custom(
cursor, uid, partner, context=context)
return res
def _write_name(
self, cursor, uid, partner_id, field_name, field_value, arg,
context=None
):
"""
Try to reverse the effect of _compute_name_custom:
* if the partner is not a company and the firstname does not change in
the new name then firstname remains untouched and lastname is updated
accordingly
* otherwise lastname=new name and firstname=False
In addition an heuristic avoids to keep a firstname without a non-blank
lastname
"""
field_value = (
field_value and not field_value.isspace() and field_value or False)
vals = {'lastname': field_value, 'firstname': False}
if field_value:
flds = self.read(
cursor, uid, [partner_id], ['firstname', 'is_company'],
context=context)[0]
if not flds['is_company']:
to_check = ' %s' % flds['firstname']
if field_value.endswith(to_check):
ln = field_value[:-len(to_check)].strip()
if ln:
vals['lastname'] = ln
del(vals['firstname'])
else:
# If the lastname is deleted from the new name
# then the firstname becomes the lastname
vals['lastname'] = flds['firstname']
return self.write(cursor, uid, partner_id, vals, context=context)
def copy_data(self, cr, uid, id, default=None, context=None):
"""
Avoid to replicate the firstname into the name when duplicating a
partner
"""
default = default or {}
if not default.get('lastname'):
default = default.copy()
default['lastname'] = (
_('%s (copy)') % self.read(
cr, uid, [id], ['lastname'], context=context
)[0]['lastname']
)
if default.get('name'):
del(default['name'])
return super(ResPartner, self).copy_data(
cr, uid, id, default, context=context)
def create(self, cursor, uid, vals, context=None):
"""
To support data backward compatibility we have to keep this overwrite
even if we use fnct_inv: otherwise we can't create entry because
lastname is mandatory and module will not install if there is demo data
"""
corr_vals = vals.copy()
if corr_vals.get('name'):
corr_vals['lastname'] = corr_vals['name']
del(corr_vals['name'])
return super(ResPartner, self).create(
cursor, uid, corr_vals, context=context)
_columns = {'name': fields.function(_compute_name_custom, string="Name",
type="char", store=True,
select=True, readonly=True,
fnct_inv=_write_name),
'firstname': fields.char("Firstname"),
'lastname': fields.char("Lastname", required=True)}

60
partner_firstname/partner_view.xml

@ -1,60 +0,0 @@
<openerp>
<data>
<record id="view_partner_simple_form_firstname" model="ir.ui.view">
<field name="name">res.partner.simplified.form.firstname</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_simple_form"/>
<field name="arch" type="xml">
<field name="name" position="attributes">
<attribute name="attrs">{'readonly': [('is_company', '=', False)], 'required': [('is_company', '=', True)]}</attribute>
</field>
<field name="category_id" position="before">
<group attrs="{'invisible': [('is_company', '=', True)]}">
<field name="lastname" attrs="{'required': [('is_company', '=', False)]}"/>
<field name="firstname" />
</group>
</field>
</field>
</record>
<record id="view_partner_form_firstname" model="ir.ui.view">
<field name="name">res.partner.form.firstname</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<field name="name" position="attributes">
<attribute name="attrs">{'readonly': [('is_company', '=', False)], 'required': [('is_company', '=', True)]}</attribute>
</field>
<field name="category_id" position="before">
<group attrs="{'invisible': [('is_company', '=', True)]}">
<field name="lastname" attrs="{'required': [('is_company', '=', False)]}"/>
<field name="firstname"/>
</group>
</field>
<!-- Add firstname and last name in 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': [('is_company', '=', False)]}"/>
<field name="firstname"/>
</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">
<div class="oe_edit_only">
<field name="is_company"
on_change="onchange_type(is_company)"/>
<label for="is_company"
string="Is a Company?"/>
</div>
</xpath>
<xpath expr="//field[@name='child_ids']/form//field[@name='name']" position="attributes">
<attribute name="attrs">{'readonly': [('is_company', '=', False)], 'required': [('is_company', '=', True)]}</attribute>
</xpath>
</field>
</record>
</data>
</openerp>

49
partner_firstname/res_user.py

@ -1,49 +0,0 @@
# -*- coding: utf-8 -*-
"""Extend res.users to be compatible with split name in res.partner."""
##############################################################################
#
# Author: Nicolas Bessi. Copyright Camptocamp SA
#
# 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/>.
#
##############################################################################
from openerp import api, models
from openerp.tools.translate import _
class ResUsers(models.Model):
"""Extend res.users to be compatible with split name in res.partner."""
_inherit = 'res.users'
@api.onchange('firstname', 'lastname')
def change_name(self):
names = [name for name in [self.firstname, self.lastname] if name]
self.name = ' '.join(names)
def copy_data(self, cr, uid, _id, default=None, context=None):
"""
Avoid to replicate the firstname into the name when duplicating a user
"""
default = default or {}
if not default.get('lastname'):
default = default.copy()
default['lastname'] = (
_('%s (copy)') % self.read(
cr, uid, [_id], ['lastname'], context=context
)[0]['lastname']
)
if default.get('name'):
del(default['name'])
return super(ResUsers, self).copy_data(
cr, uid, _id, default, context=context)

35
partner_firstname/res_user_view.xml

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Replace name with first name and last name -->
<record id="view_users_form" model="ir.ui.view">
<field name="name">res.users.form.firstname</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<label for="name" position="attributes">
<attribute name="invisible">1</attribute>
</label>
<label for="name" position="after">
<label for="firstname" class="oe_edit_only"/>
</label>
<field name="name" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="name" position="after">
<field name="firstname"/>
</field>
<label for="login" position="before">
<label for="lastname" class="oe_edit_only"/>
<h1><field name="lastname"/></h1>
</label>
</field>
</record>
</data>
</openerp>

229
partner_firstname/tests/test_partner_firstname.py

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
#
#
# Authors: Nemry Jonathan
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
# All Rights Reserved
@ -25,129 +24,131 @@
# 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.
#
#
import openerp.tests.common as common
from openerp.tools.translate import _
from openerp.tests.common import TransactionCase
from .. import exceptions as ex
class test_partner_firstname(common.TransactionCase):
class PartnerFirstnameCase(TransactionCase):
def setUp(self):
super(test_partner_firstname, self).setUp()
super(PartnerFirstnameCase, self).setUp()
self.original = self.env["res.partner"].create({
"lastname": "lastname",
"firstname": "firstname"})
self.registry('ir.model').clear_caches()
self.registry('ir.model.data').clear_caches()
def test_copy_partner(self):
"""Copy the partner and compare the result."""
copy = self.original.with_context(lang="en_US").copy()
self.assertEqual(
copy.name,
"lastname firstname (copy)",
"Copy of the partner failed with wrong name")
self.assertEqual(
copy.lastname,
"lastname",
"Copy of the partner failed with wrong lastname")
self.assertEqual(
copy.firstname,
"firstname (copy)",
"Copy of the partner failed with wrong firstname")
self.user_model = self.registry("res.users")
self.partner_model = self.registry("res.partner")
self.fields_partner = {
'lastname': 'lastname', 'firstname': 'firstname'}
self.fields_user = {
'name': 'lastname', 'login': 'v5Ue4Tql0Pm67KX05g25A'}
def test_update_user_lastname(self):
"""Change lastname."""
self.original.name = "changed firstname"
self.context = self.user_model.context_get(self.cr, self.uid)
self.assertEqual(
self.original.name,
"changed firstname",
"Update of the partner lastname failed with wrong name")
self.assertEqual(
self.original.lastname,
"changed",
"Update of the partner lastname failed with wrong lastname")
self.assertEqual(
self.original.firstname,
"firstname",
"Update of the partner lastname failed with wrong firstname")
def test_copy_partner(self):
cr, uid, context = self.cr, self.uid, self.context
res_id = self.partner_model.create(
cr, uid, self.fields_partner, context=context)
res_id = self.partner_model.copy(
cr, uid, res_id, default={}, context=context)
vals = self.partner_model.read(cr, uid, [res_id], [
'name', 'lastname', 'firstname'], context=context)[0]
self.assertEqual(
vals['name'],
_('%s (copy)') % 'lastname' + " firstname",
'Copy of the partner failed with wrong name'
)
self.assertEqual(
vals['lastname'],
_('%s (copy)') % 'lastname',
'Copy of the partner failed with wrong lastname'
)
self.assertEqual(vals['firstname'], 'firstname',
'Copy of the partner failed with wrong firstname')
def test_update_user_firstname(self):
"""Change firstname."""
self.original.name = "lastname changed"
self.assertEqual(
self.original.name,
"lastname changed",
"Update of the partner lastname failed with wrong name")
self.assertEqual(
self.original.lastname,
"lastname",
"Update of the partner lastname failed with wrong lastname")
self.assertEqual(
self.original.firstname,
"changed",
"Update of the partner lastname failed with wrong firstname")
def test_no_names(self):
"""Test that you cannot set a partner without names."""
with self.assertRaises(ex.EmptyNames):
self.original.firstname = self.original.lastname = False
class UserFirstnameCase(TransactionCase):
def setUp(self):
super(UserFirstnameCase, self).setUp()
self.original = self.env["res.users"].create({
"name": "lastname firstname",
"login": "firstnametest@example.com"})
def test_copy_user(self):
cr, uid, context = self.cr, self.uid, self.context
# create a user
res_id = self.user_model.create(
cr, uid, self.fields_user, context=context)
# get the related partner id and add it a firstname
flds = self.user_model.read(
cr, uid, [res_id], ['partner_id'], context=context)[0]
self.partner_model.write(cr, uid, flds['partner_id'][
0], {'firstname': 'firstname'}, context=context)
# copy the user and compare result
res_id = self.user_model.copy(
cr, uid, res_id, default={}, context=context)
vals = self.user_model.read(
cr, uid, [res_id], ['name', 'lastname', 'firstname'],
context=context)[0]
self.assertEqual(
vals['name'],
_('%s (copy)') % 'lastname' + ' firstname',
'Copy of the user failed with wrong name'
)
self.assertEqual(
vals['lastname'], _('%s (copy)') %
'lastname', 'Copy of the user failed with wrong lastname')
self.assertEqual(vals['firstname'], 'firstname',
'Copy of the user failed with wrong firstname')
"""Copy the user and compare result."""
copy = self.original.with_context(lang="en_US").copy()
self.assertEqual(
copy.name,
"lastname firstname (copy)",
"Copy of the partner failed with wrong name")
self.assertEqual(
copy.lastname,
"lastname",
"Copy of the partner failed with wrong lastname")
self.assertEqual(
copy.firstname,
"firstname (copy)",
"Copy of the partner failed with wrong firstname")
def test_update_user_lastname(self):
cr, uid, context = self.cr, self.uid, self.context
# create a user
res_id = self.user_model.create(
cr, uid, self.fields_user, context=context)
# get the related partner id and add it a firstname
flds = self.user_model.read(
cr, uid, [res_id], ['partner_id'], context=context)[0]
self.partner_model.write(
cr, uid, flds['partner_id'][0], {'firstname': 'firstname'},
context=context)
self.user_model.write(
cr, uid, res_id, {'name': 'change firstname'}, context=context)
vals = self.user_model.read(
cr, uid, [res_id], ['name', 'lastname', 'firstname'],
context=context)[0]
self.assertEqual(vals['name'], 'change firstname',
'Update of the user lastname failed with wrong name')
self.assertEqual(
vals['lastname'], 'change',
'Update of the user lastname failed with wrong lastname')
self.assertEqual(
vals['firstname'], 'firstname',
'Update of the user lastname failed with wrong firstname')
"""Change lastname."""
self.original.name = "changed firstname"
self.assertEqual(
self.original.name,
"changed firstname",
"Update of the user lastname failed with wrong name")
self.assertEqual(
self.original.lastname,
"changed",
"Update of the user lastname failed with wrong lastname")
self.assertEqual(
self.original.firstname,
"firstname",
"Update of the user lastname failed with wrong firstname")
def test_update_user_firstname(self):
cr, uid, context = self.cr, self.uid, self.context
# create a user
res_id = self.user_model.create(
cr, uid, self.fields_user, context=context)
# get the related partner id and add it a firstname
flds = self.user_model.read(
cr, uid, [res_id], ['partner_id'], context=context)[0]
self.partner_model.write(
cr, uid, flds['partner_id'][0], {'firstname': 'firstname'},
context=context)
self.user_model.write(
cr, uid, res_id, {'name': 'lastname other'}, context=context)
vals = self.user_model.read(
cr, uid, [res_id], ['name', 'lastname', 'firstname'],
context=context)[0]
self.assertEqual(
vals['name'], 'lastname other',
'Update of the user firstname failed with wrong name')
self.assertEqual(
vals['lastname'], 'lastname other',
'Update of the user firstname failed with wrong lastname')
self.assertFalse(
vals['firstname'],
'Update of the user firstname failed with wrong firstname')
"""Change firstname."""
self.original.name = "lastname changed"
self.assertEqual(
self.original.name,
"lastname changed",
"Update of the user lastname failed with wrong name")
self.assertEqual(
self.original.lastname,
"lastname",
"Update of the user lastname failed with wrong lastname")
self.assertEqual(
self.original.firstname,
"changed",
"Update of the user lastname failed with wrong firstname")

113
partner_firstname/views/res_partner.xml

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Odoo, Open Source Management Solution
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/>.
-->
<openerp>
<data>
<record id="partner_simple_form" model="ir.ui.view">
<field name="name">Add firstname and lastname</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_simple_form"/>
<field name="arch" type="xml">
<data>
<xpath expr="//field[@name='name']" position="attributes">
<attribute name="attrs">{
'readonly': [('is_company', '=', False)],
'required': [('is_company', '=', True)]
}</attribute>
</xpath>
<xpath expr="//field[@name='category_id']" position="before">
<group attrs="{'invisible': [('is_company', '=', True)]}">
<field name="lastname"
attrs="{'required': [('firstname', '=', False)]}"/>
<field name="firstname"
attrs="{'required': [('lastname', '=', False)]}"/>
</group>
</xpath>
</data>
</field>
</record>
<record id="partner_form" model="ir.ui.view">
<field name="name">Add firstname and surnames</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<data>
<xpath expr="//field[@name='name']" position="attributes">
<attribute name="attrs">{
'readonly': [('is_company', '=', False)],
'required': [('is_company', '=', True)]
}</attribute>
</xpath>
<xpath expr="//field[@name='category_id']" position="before">
<group attrs="{'invisible': [('is_company', '=', True)]}">
<field name="lastname"
attrs="{'required': [('firstname', '=', False)]}"/>
<field name="firstname"
attrs="{'required': [('lastname', '=', 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)]}"/>
<field name="firstname"
attrs="{'required': [('lastname', '=', 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">
<div class="oe_edit_only">
<field name="is_company"
on_change="onchange_type(is_company)"/>
<label for="is_company"
string="Is a Company?"/>
</div>
</xpath>
<xpath expr="//field[@name='child_ids']/form//field[@name='name']"
position="attributes">
<attribute name="attrs">{
'readonly': [('is_company', '=', False)],
'required': [('is_company', '=', True)]
}</attribute>
</xpath>
</data>
</field>
</record>
</data>
</openerp>

49
partner_firstname/views/res_user.xml

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Odoo, Open Source Management Solution
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/>.
-->
<openerp>
<data>
<record id="users_form" model="ir.ui.view">
<field name="name">Add firstname and surnames</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<data>
<xpath expr="//field[@name='name']" position="attributes">
<attribute name="readonly">True</attribute>
</xpath>
<xpath expr="//field[@name='email']" position="after">
<group>
<field name="lastname"
attrs="{'required': [('firstname', '=', False)]}"/>
<field name="firstname"
attrs="{'required': [('lastname', '=', False)]}"/>
</group>
</xpath>
</data>
</field>
</record>
</data>
</openerp>
Loading…
Cancel
Save