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
14.0
Yannick Vaucher 9 years ago
committed by Luis Torres
parent
commit
617a2700a5
  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. 64
      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>
* 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>
* 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>
* Jairo Llopis <j.llopis@grupoesoc.es>
* 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
----------

21
partner_firstname/__init__.py

@ -1,21 +1,4 @@
# -*- 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

30
partner_firstname/__openerp__.py

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

18
partner_firstname/exceptions.py

@ -1,20 +1,6 @@
# -*- 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

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 -*-
# 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
from openerp import api, fields, models
from . import exceptions
from .. import exceptions
_logger = logging.getLogger(__name__)
@ -161,7 +146,8 @@ class ResPartner(models.Model):
@api.constrains("firstname", "lastname")
def _check_name(self):
"""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)
@api.one
@ -202,3 +188,11 @@ class ResPartner(models.Model):
# Force calculations there
records._inverse_name()
_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 -*-
##############################################################################
#
# 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 (
test_create,
@ -35,5 +8,6 @@ from . import (
test_delete,
test_empty,
test_name,
test_onchange
test_onchange,
test_user_onchange
)

27
partner_firstname/tests/base.py

@ -1,29 +1,6 @@
# -*- 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 .. import exceptions as ex

45
partner_firstname/tests/test_empty.py

@ -1,25 +1,11 @@
# -*- 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.
To have more accurate results, remove the ``mail`` module before testing.
"""
from openerp.tests.common import TransactionCase
from .base import MailInstalled
from .. import exceptions as ex
@ -33,8 +19,9 @@ class CompanyCase(TransactionCase):
def tearDown(self):
try:
data = {"name": self.name}
model = self.env[self.model].with_context(**self.context)
with self.assertRaises(ex.EmptyNamesError):
self.env[self.model].with_context(**self.context).create(data)
model.create(data)
finally:
super(CompanyCase, self).tearDown()
@ -49,7 +36,7 @@ class CompanyCase(TransactionCase):
class PersonCase(CompanyCase):
"""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):
@ -65,3 +52,23 @@ class UserCase(CompanyCase, MailInstalled):
else:
# Run tests
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 -*-
# © 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.
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()

64
partner_firstname/views/res_partner.xml

@ -15,7 +15,7 @@
}</attribute>
</xpath>
<xpath expr="//field[@name='category_id']" position="before">
<xpath expr="//h1//field[@name='name']/.." position="before">
<group attrs="{'invisible': [('is_company', '=', True)]}">
<field name="lastname" attrs=
"{'required': [('firstname', '=', False),
@ -42,47 +42,20 @@
}</attribute>
</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">
<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>
</xpath>
<!-- Modify inner contact form of child_ids -->
<xpath expr="//field[@name='child_ids']/form//field[@name='name']"
position="attributes">
<attribute name="attrs">{
@ -90,6 +63,21 @@
'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)]}">
<field name="lastname" attrs=
"{'required': [('firstname', '=', False),
('is_company', '=', False)]}"/>
<field name="firstname" attrs=
"{'required': [('lastname', '=', False),
('is_company', '=', False)]}"/>
</group>
</div>
</xpath>
</data>
</field>
</record>

5
partner_firstname/views/res_user.xml

@ -2,10 +2,6 @@
<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="view_users_form" model="ir.ui.view">
<field name="name">Add firstname and surnames</field>
<field name="model">res.users</field>
@ -14,6 +10,7 @@
<data>
<xpath expr="//field[@name='name']" position="attributes">
<attribute name="readonly">True</attribute>
<attribute name="required">False</attribute>
</xpath>
<xpath expr="//field[@name='email']" position="after">

Loading…
Cancel
Save