Browse Source

[MRG]

For Partner:

1) Create always the SQL constraint on 'lastname'
2) Better implementation of "_write_name" allowing more intuitive update of the partner name when processing from another model (ex: res_user), i.e., try to keep the firstname if unchanged
3) When duplicating a partner, avoid to repeat the firstname in the name
4) Beautify the inner form for children contacts (placing fields as in the main form)
5) Allow edition of the field name in the inner form if child is a company

For User:

1) Reintegrate the name as "required"
2) When duplicating a user, avoid to repeat the firstname in the related partner name
pull/2/head
Jonathan Nemry 11 years ago
committed by Maxime Chambreuil
parent
commit
be2de23ee3
  1. 20
      partner_firstname/__openerp__.py
  2. 27
      partner_firstname/i18n/de.po
  3. 28
      partner_firstname/i18n/en.po
  4. 27
      partner_firstname/i18n/fr.po
  5. 27
      partner_firstname/i18n/nl.po
  6. 25
      partner_firstname/i18n/partner_firstname.pot
  7. 51
      partner_firstname/partner.py
  8. 19
      partner_firstname/partner_view.xml
  9. 18
      partner_firstname/res_user.py
  10. 1
      partner_firstname/res_user_view.xml
  11. 37
      partner_firstname/tests/__init__.py
  12. 103
      partner_firstname/tests/test_partner_firstname.py

20
partner_firstname/__openerp__.py

@ -19,14 +19,24 @@
############################################################################## ##############################################################################
{'name': 'Partner first name, last name', {'name': 'Partner first name, last name',
'description': """Split first name and last name on res.partner.
'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>
The field 'name' becomes a stored function field concatenating lastname, firstname
""", """,
'version': '1.0.1',
'version': '1.1',
'author': 'Camptocamp', 'author': 'Camptocamp',
'category': 'MISC',
'website': 'http://www.camptocamp.com',
'maintainer': 'Camptocamp, Acsone',
'category': 'Extra Tools',
'website': 'http://www.camptocamp.com, http://www.acsone.eu',
'depends': ['base'], 'depends': ['base'],
'data': [ 'data': [
'partner_view.xml', 'partner_view.xml',

27
partner_firstname/i18n/de.po

@ -16,15 +16,36 @@ msgstr ""
"Plural-Forms: \n" "Plural-Forms: \n"
#. module: partner_firstname #. module: partner_firstname
#: field:res.partner,lastname:0
msgid "Lastname"
msgstr "Name"
#: 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
#, python-format
msgid "%s (copy)"
msgstr "%s (kopie)"
#. module: partner_firstname
#: model:ir.model,name:partner_firstname.model_res_users
msgid "Users"
msgstr "Benutzer"
#. module: partner_firstname #. module: partner_firstname
#: field:res.partner,firstname:0 #: field:res.partner,firstname:0
msgid "Firstname" msgid "Firstname"
msgstr "Vorname" msgstr "Vorname"
#. module: partner_firstname
#: field:res.partner,lastname:0
msgid "Lastname"
msgstr "Name"
#. module: partner_firstname
#: view:res.partner:0
msgid "Is a Company?"
msgstr "Ist ein Unternehmen?"
#. module: partner_firstname #. module: partner_firstname
#: model:ir.model,name:partner_firstname.model_res_partner #: model:ir.model,name:partner_firstname.model_res_partner
msgid "Partner" msgid "Partner"

28
partner_firstname/i18n/en.po

@ -16,17 +16,37 @@ msgstr ""
"Plural-Forms: \n" "Plural-Forms: \n"
#. module: partner_firstname #. module: partner_firstname
#: field:res.partner,lastname:0
msgid "Lastname"
msgstr "Lastname"
#: 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
#, python-format
msgid "%s (copy)"
msgstr "%s (copy)"
#. module: partner_firstname
#: model:ir.model,name:partner_firstname.model_res_users
msgid "Users"
msgstr "Users"
#. module: partner_firstname #. module: partner_firstname
#: field:res.partner,firstname:0 #: field:res.partner,firstname:0
msgid "Firstname" msgid "Firstname"
msgstr "Firstname" msgstr "Firstname"
#. module: partner_firstname
#: field:res.partner,lastname:0
msgid "Lastname"
msgstr "Lastname"
#. module: partner_firstname
#: view:res.partner:0
msgid "Is a Company?"
msgstr "Is a Company?"
#. module: partner_firstname #. module: partner_firstname
#: model:ir.model,name:partner_firstname.model_res_partner #: model:ir.model,name:partner_firstname.model_res_partner
msgid "Partner" msgid "Partner"
msgstr "Partner" msgstr "Partner"

27
partner_firstname/i18n/fr.po

@ -16,15 +16,36 @@ msgstr ""
"Plural-Forms: \n" "Plural-Forms: \n"
#. module: partner_firstname #. module: partner_firstname
#: field:res.partner,lastname:0
msgid "Lastname"
msgstr "Nom"
#: 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
#, python-format
msgid "%s (copy)"
msgstr "%s (copie)"
#. module: partner_firstname
#: model:ir.model,name:partner_firstname.model_res_users
msgid "Users"
msgstr "Utilisateur"
#. module: partner_firstname #. module: partner_firstname
#: field:res.partner,firstname:0 #: field:res.partner,firstname:0
msgid "Firstname" msgid "Firstname"
msgstr "Prénom" msgstr "Prénom"
#. module: partner_firstname
#: field:res.partner,lastname:0
msgid "Lastname"
msgstr "Nom de famille"
#. module: partner_firstname
#: view:res.partner:0
msgid "Is a Company?"
msgstr "Est une société?"
#. module: partner_firstname #. module: partner_firstname
#: model:ir.model,name:partner_firstname.model_res_partner #: model:ir.model,name:partner_firstname.model_res_partner
msgid "Partner" msgid "Partner"

27
partner_firstname/i18n/nl.po

@ -16,15 +16,36 @@ msgstr ""
"Plural-Forms: \n" "Plural-Forms: \n"
#. module: partner_firstname #. module: partner_firstname
#: field:res.partner,lastname:0
msgid "Lastname"
msgstr "Achternaam"
#: 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
#, python-format
msgid "%s (copy)"
msgstr "%s (kopie)"
#. module: partner_firstname
#: model:ir.model,name:partner_firstname.model_res_users
msgid "Users"
msgstr "Gebruikers"
#. module: partner_firstname #. module: partner_firstname
#: field:res.partner,firstname:0 #: field:res.partner,firstname:0
msgid "Firstname" msgid "Firstname"
msgstr "Voornaam" msgstr "Voornaam"
#. module: partner_firstname
#: field:res.partner,lastname:0
msgid "Lastname"
msgstr "Achternaam"
#. module: partner_firstname
#: view:res.partner:0
msgid "Is a Company?"
msgstr "Is een bedrijf?"
#. module: partner_firstname #. module: partner_firstname
#: model:ir.model,name:partner_firstname.model_res_partner #: model:ir.model,name:partner_firstname.model_res_partner
msgid "Partner" msgid "Partner"

25
partner_firstname/i18n/partner_firstname.pot

@ -6,8 +6,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n" "Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-10-03 16:09+0000\n"
"PO-Revision-Date: 2013-10-03 16:09+0000\n"
"POT-Creation-Date: 2014-01-22 14:09+0000\n"
"PO-Revision-Date: 2014-01-22 14:09+0000\n"
"Last-Translator: <>\n" "Last-Translator: <>\n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -15,6 +15,22 @@ msgstr ""
"Content-Transfer-Encoding: \n" "Content-Transfer-Encoding: \n"
"Plural-Forms: \n" "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
#, python-format
msgid "%s (copy)"
msgstr ""
#. module: partner_firstname
#: model:ir.model,name:partner_firstname.model_res_users
msgid "Users"
msgstr ""
#. module: partner_firstname #. module: partner_firstname
#: field:res.partner,firstname:0 #: field:res.partner,firstname:0
msgid "Firstname" msgid "Firstname"
@ -25,6 +41,11 @@ msgstr ""
msgid "Lastname" msgid "Lastname"
msgstr "" msgstr ""
#. module: partner_firstname
#: view:res.partner:0
msgid "Is a Company?"
msgstr ""
#. module: partner_firstname #. module: partner_firstname
#: model:ir.model,name:partner_firstname.model_res_partner #: model:ir.model,name:partner_firstname.model_res_partner
msgid "Partner" msgid "Partner"

51
partner_firstname/partner.py

@ -18,6 +18,7 @@
# #
############################################################################## ##############################################################################
from openerp.osv.orm import Model, fields from openerp.osv.orm import Model, fields
from openerp.tools.translate import _
class ResPartner(Model): class ResPartner(Model):
@ -29,6 +30,10 @@ class ResPartner(Model):
cursor.execute('SELECT id FROM res_partner WHERE lastname IS NOT NULL Limit 1') cursor.execute('SELECT id FROM res_partner WHERE lastname IS NOT NULL Limit 1')
if not cursor.fetchone(): if not cursor.fetchone():
cursor.execute('UPDATE res_partner set lastname = name WHERE name IS NOT NULL') cursor.execute('UPDATE res_partner set lastname = name WHERE name IS NOT NULL')
# Create Sql constraint if table is not empty
cursor.execute('SELECT id FROM res_partner Limit 1')
if cursor.fetchone():
cursor.execute('ALTER TABLE res_partner ALTER COLUMN lastname SET NOT NULL')
def _compute_name_custom(self, cursor, uid, ids, fname, arg, context=None): def _compute_name_custom(self, cursor, uid, ids, fname, arg, context=None):
res = {} res = {}
@ -41,15 +46,51 @@ class ResPartner(Model):
return res return res
def _write_name(self, cursor, uid, partner_id, field_name, field_value, arg, context=None): def _write_name(self, cursor, uid, partner_id, field_name, field_value, arg, context=None):
return self.write(cursor, uid, partner_id,
{'lastname': field_value}, context=context)
"""
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): def create(self, cursor, uid, vals, context=None):
"""To support data backward compatibility we have to keep this overwrite even if we
"""
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 use fnct_inv: otherwise we can't create entry because lastname is mandatory and module
will not install if there is demo data"""
will not install if there is demo data
"""
to_use = vals to_use = vals
if vals.get('name'):
if 'name' in vals:
corr_vals = vals.copy() corr_vals = vals.copy()
corr_vals['lastname'] = corr_vals['name'] corr_vals['lastname'] = corr_vals['name']
del(corr_vals['name']) del(corr_vals['name'])

19
partner_firstname/partner_view.xml

@ -32,15 +32,26 @@
</group> </group>
</field> </field>
<!-- Add firstname and last name in inner contact form of child_ids --> <!-- Add firstname and last name in inner contact form of child_ids -->
<xpath expr="//form[@string='Contact']/sheet/div" position="after">
<xpath expr="//form[@string='Contact']/sheet//field[@name='category_id']" position="before">
<group attrs="{'invisible': [('is_company', '=', True)]}"> <group attrs="{'invisible': [('is_company', '=', True)]}">
<field name="lastname" attrs="{'required': [('is_company', '=', False)]}"/> <field name="lastname" attrs="{'required': [('is_company', '=', False)]}"/>
<field name="firstname"/> <field name="firstname"/>
</group> </group>
</xpath> </xpath>
<xpath expr="//form[@string='Contact']/sheet/div/h1" position="after">
<field name="is_company" on_change="onchange_type(is_company)" class="oe_inline"/>
<label for="is_company" string="Is a Company?"/>)
<xpath expr="//form[@string='Contact']/sheet//field[@name='category_id']" position="attributes">
<attribute name="style"/>
</xpath>
<xpath expr="//form[@string='Contact']/sheet/div/label" position="replace">
<div class="oe_edit_only">
<label for="name"/> (
<field name="is_company" on_change="onchange_type(is_company)" class="oe_inline"/>
<label for="is_company" string="Is a Company?"/>)
</div>
</xpath>
<xpath expr="//form[@string='Contact']/sheet/div/h1/field[@name='name']" position="attributes">
<div class="oe_edit_only">
<attribute name="attrs">{'readonly': [('is_company', '=', False)], 'required': [('is_company', '=', True)]}</attribute>
</div>
</xpath> </xpath>

18
partner_firstname/res_user.py

@ -18,15 +18,21 @@
# #
############################################################################## ##############################################################################
from openerp.osv import orm from openerp.osv import orm
from openerp.tools.translate import _
class ResUsers(orm.Model): class ResUsers(orm.Model):
"""Allows user creation from user form as
name is not in form"""
_inherit = 'res.users' _inherit = 'res.users'
def create(self, cursor, uid, vals, context=None):
if not vals.get('name'):
vals['name'] = vals['login']
return super(ResUsers, self).create(cursor, uid, 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 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)

1
partner_firstname/res_user_view.xml

@ -8,6 +8,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="name" position="attributes"> <field name="name" position="attributes">
<attribute name="readonly">False</attribute> <attribute name="readonly">False</attribute>
<attribute name="required">True</attribute>
</field> </field>
</field> </field>
</record> </record>

37
partner_firstname/tests/__init__.py

@ -0,0 +1,37 @@
# -*- 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.
#
##############################################################################
import test_partner_firstname
checks = [
test_partner_firstname
]
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

103
partner_firstname/tests/test_partner_firstname.py

@ -0,0 +1,103 @@
# -*- 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.
#
##############################################################################
import openerp.tests.common as common
from openerp.tools.translate import _
class test_partner_firstname(common.TransactionCase):
def setUp(self):
super(test_partner_firstname, self).setUp()
self.registry('ir.model').clear_caches()
self.registry('ir.model.data').clear_caches()
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'}
self.context = self.user_model.context_get(self.cr, self.uid)
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_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')
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')
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')
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
Loading…
Cancel
Save