Browse Source

[PORT] partner_firstname to 9.0

- add missing authors
- use reduced license header
- move models in models directory
- adapt views
- show firstname, lastname only in edit mode
- use company_type in views instead of is_company
- adapt constraint on contacts

[PORT][9.0] partner_firstname - remove hack to be able to edit user view. Fixed in odoo/odoo#cf63d4d277ef1ba02ff4ebcdae8583332a1775b1

[PORT][9.0] partner_firstname - Format of string in __openerp__.py

[PORT][9.0] Adapt tests to take new constraint raising IntegrityError

partner_firstname: Name is not mandatory if partner is an address

[FIX] Ensure default values are computed for res.users

Add test for shipping address with empty name

partner_firstname: fix user creation
User name field is required what is stoping to create a new user

Fix user form with firstname and lastname asking for a mandatory name
pull/663/head
Yannick Vaucher 9 years ago
committed by Jairo Llopis
parent
commit
280ef066b9
  1. 17
      partner_firstname/README.rst
  2. 21
      partner_firstname/__init__.py
  3. 30
      partner_firstname/__openerp__.py
  4. 18
      partner_firstname/exceptions.py
  5. 5
      partner_firstname/models/__init__.py
  6. 36
      partner_firstname/models/res_partner.py
  7. 37
      partner_firstname/models/res_user.py
  8. 34
      partner_firstname/tests/__init__.py
  9. 27
      partner_firstname/tests/base.py
  10. 45
      partner_firstname/tests/test_empty.py
  11. 3
      partner_firstname/tests/test_onchange.py
  12. 53
      partner_firstname/tests/test_user_onchange.py
  13. 44
      partner_firstname/views/res_partner.xml
  14. 5
      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

30
partner_firstname/__openerp__.py

@ -1,31 +1,17 @@
# -*- 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.1.0',
"author": "Camptocamp, "
'version': '9.0.1.0.0',
'author': "Camptocamp, "
"Grupo ESOC Ingeniería de Servicios, " "Grupo ESOC Ingeniería de Servicios, "
"Odoo Community Association (OCA)", "Odoo Community Association (OCA)",
"license": "AGPL-3",
'license': "AGPL-3",
'maintainer': 'Camptocamp, Acsone', 'maintainer': 'Camptocamp, Acsone',
'category': 'Extra Tools', 'category': 'Extra Tools',
'website': 'website':
@ -39,6 +25,6 @@
'demo': [], 'demo': [],
'test': [], 'test': [],
'auto_install': False, 'auto_install': False,
'installable': False,
'installable': True,
'images': [] 'images': []
} }

18
partner_firstname/exceptions.py

@ -1,20 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: 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/>.
# © 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

36
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__)
@ -161,7 +146,8 @@ class ResPartner(models.Model):
@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
@ -202,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.'
)]

37
partner_firstname/models/res_user.py

@ -0,0 +1,37 @@
# -*- 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
@api.onchange("firstname", "lastname")
def _compute_name(self):
"""Write the 'name' field according to splitted data."""
for rec in self:
rec.name = rec.partner_id._get_computed_name(
rec.lastname, rec.firstname)

34
partner_firstname/tests/__init__.py

@ -1,33 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
##############################################################################
#
# Authors: Nemry Jonathan
# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
# 2015: Grupo ESOC <www.grupoesoc.es>
# 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 ( from . import (
test_create, test_create,
@ -35,5 +8,6 @@ from . import (
test_delete, test_delete,
test_empty, test_empty,
test_name, test_name,
test_onchange
test_onchange,
test_user_onchange
) )

27
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

45
partner_firstname/tests/test_empty.py

@ -1,25 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: 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/>.
# © 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
@ -33,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()
@ -49,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):
@ -65,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.

53
partner_firstname/tests/test_user_onchange.py

@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
# © 2016 Yannick Vaucher (Camptocamp SA)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp.tests.common import TransactionCase
class UserOnchangeCase(TransactionCase):
def test_create_from_form_only_firstname(self):
"""In a new users form, a user set only the firstname."""
firstname = u"Zoë"
with self.env.do_in_onchange():
# Changes firstname, which triggers onchanges
self.user.firstname = firstname
self.user._compute_name()
self.assertEqual(self.user.lastname, False)
self.assertEqual(self.user.firstname, firstname)
self.assertEqual(self.user.name, firstname)
def test_create_from_form_only_lastname(self):
"""In a new user form, a user set only the lastname."""
lastname = u"Żywioł"
with self.env.do_in_onchange():
# Changes lastname, which triggers onchanges
self.user.lastname = lastname
self.user._compute_name()
self.assertEqual(self.user.firstname, False)
self.assertEqual(self.user.lastname, lastname)
self.assertEqual(self.user.name, lastname)
def test_create_from_form_all(self):
"""In a new user form, a user set all names."""
firstname = u"Zoë"
lastname = u"Żywioł"
with self.env.do_in_onchange():
# Changes firstname, which triggers onchanges
self.user.firstname = firstname
self.user._compute_name()
# Changes lastname, which triggers onchanges
self.user.lastname = lastname
self.user._compute_name()
self.assertEqual(self.user.lastname, lastname)
self.assertEqual(self.user.firstname, firstname)
self.assertEqual(self.user.name, u" ".join((lastname, firstname)))
def setUp(self):
super(UserOnchangeCase, self).setUp()
self.user = self.env["res.users"].new()

44
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,7 +42,8 @@
}</attribute> }</attribute>
</xpath> </xpath>
<xpath expr="//field[@name='category_id']" position="before">
<xpath expr="//h1//field[@name='name']/.." position="after">
<div class="oe_edit_only">
<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),
@ -51,12 +52,22 @@
"{'required': [('lastname', '=', False), "{'required': [('lastname', '=', False),
('is_company', '=', False)]}"/> ('is_company', '=', False)]}"/>
</group> </group>
</div>
</xpath> </xpath>
<!-- Modify inner contact form of child_ids --> <!-- Modify inner contact form of child_ids -->
<xpath expr="//field[@name='child_ids']/form
//field[@name='category_id']"
position="before">
<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>
<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)]}"> <group attrs="{'invisible': [('is_company', '=', True)]}">
<field name="lastname" attrs= <field name="lastname" attrs=
"{'required': [('firstname', '=', False), "{'required': [('firstname', '=', False),
@ -65,31 +76,8 @@
"{'required': [('lastname', '=', False), "{'required': [('lastname', '=', False),
('is_company', '=', False)]}"/> ('is_company', '=', False)]}"/>
</group> </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> </div>
</xpath> </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> </data>
</field> </field>
</record> </record>

5
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>
@ -14,6 +10,7 @@
<data> <data>
<xpath expr="//field[@name='name']" position="attributes"> <xpath expr="//field[@name='name']" position="attributes">
<attribute name="readonly">True</attribute> <attribute name="readonly">True</attribute>
<attribute name="required">False</attribute>
</xpath> </xpath>
<xpath expr="//field[@name='email']" position="after"> <xpath expr="//field[@name='email']" position="after">

Loading…
Cancel
Save