diff --git a/hr_employee_firstname/models/hr_employee.py b/hr_employee_firstname/models/hr_employee.py index 1751794607e..e27b07d490d 100644 --- a/hr_employee_firstname/models/hr_employee.py +++ b/hr_employee_firstname/models/hr_employee.py @@ -72,11 +72,27 @@ def split_name(self, name): clean_name = " ".join(name.split(None)) if name else name return self.env['res.partner']._get_inverse_name(clean_name) + @api.model + def _get_names_order(self): + return self.env['res.partner']._get_names_order() + @api.multi def _inverse_name(self): """Try to revert the effect of :method:`._compute_name`.""" + order = self._get_names_order() for record in self: parts = self.env['res.partner']._get_inverse_name(record.name) + if len(parts) > 2: + keys = [item for item in parts.keys() if item not in [ + 'firstname', 'lastname']] + additional_parts = '' + if order == 'last_first': + field = 'lastname' + else: + field = 'firstname' + for key in keys: + additional_parts += ' ' + parts[key] if parts[key] else '' + parts[field] += additional_parts record.lastname = parts['lastname'] record.firstname = parts['firstname'] diff --git a/hr_employee_lastnames/README.rst b/hr_employee_lastnames/README.rst new file mode 100644 index 00000000000..0204e1e245a --- /dev/null +++ b/hr_employee_lastnames/README.rst @@ -0,0 +1,57 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +HR Employee First Name and Two Last Names +========================================= + +This module allows you to add firstname and lastnames (Father an Mother Last Name) in employee form, +and concatenate both in name field. + +Installation +============ + +To install this module, you need to: + +* clone the branch 10.0 of the repository https://github.com/OCA/hr +* add the path to this repository in your configuration (addons-path) +* update the module list +* search for "HR Employee First Name and Two Last Names" in your addons +* install the module + +Usage +===== + +On the employee form view you will have 3 separate fields, one for Firstname, +second for Lastname, both required and Mother's Last Name (optional). + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed feedback +`here `_. + +Credits +======= + +Contributors +------------ + +* Luis Escobar (Vauxoo) + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/hr_employee_lastnames/__init__.py b/hr_employee_lastnames/__init__.py new file mode 100644 index 00000000000..0e8e7ccacd6 --- /dev/null +++ b/hr_employee_lastnames/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +from . import models +from .hook import post_init_hook diff --git a/hr_employee_lastnames/__manifest__.py b/hr_employee_lastnames/__manifest__.py new file mode 100644 index 00000000000..cd8990df8c6 --- /dev/null +++ b/hr_employee_lastnames/__manifest__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + 'name': "HR Employee First Name and Two Last Names", + 'version': '10.0.1.0.1', + 'author': "Vauxoo, " + "Odoo Community Association (OCA)", + 'maintainer': 'Vauxoo', + 'website': 'https://github.com/OCA/hr/', + 'license': 'AGPL-3', + 'category': 'Human Resources', + 'summary': "Split Name in First Name, Father's Last Name and Mother's Last Name", + 'depends': [ + 'partner_second_lastname', + 'hr_employee_firstname', + ], + 'data': [ + 'views/hr_views.xml', + ], + 'post_init_hook': "post_init_hook", + 'demo': [], + 'test': [], + 'installable': True, +} diff --git a/hr_employee_lastnames/hook.py b/hr_employee_lastnames/hook.py new file mode 100644 index 00000000000..129c7c66e53 --- /dev/null +++ b/hr_employee_lastnames/hook.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +from odoo import SUPERUSER_ID +from odoo.api import Environment + + +def post_init_hook(cr, _): + # This SQL statement is necessary to call _install_employee_lastnames() and + # set name fields correctly. + # + # After the installation, previously the dependency hr_employee_firstname + # splitting the name into two parts: firstname and lastname, so for this + # module to be able to process the new field lastmane2 it is necessary to + # reset the values to empty to be able to correctly set the three fields + # (firstname, lastname and lastname2). + # + # For example: + # After install hr_employee_fisrtname and before install hr_employee_lastnames: + # name = 'John Peterson Clinton' + # firstname = 'John' + # lastname = 'Peterson Clinton' + # + # After install hr_employee_lastnames: + # name = 'John Peterson Clinton' + # firstname = 'John' + # lastname = 'Peterson' + # lastname2 = 'Clinton' + cr.execute('UPDATE hr_employee SET firstname = NULL, lastname = NULL') + env = Environment(cr, SUPERUSER_ID, {}) + env['hr.employee']._install_employee_lastnames() + env['ir.config_parameter'].sudo().set_param('partner_names_order', 'first_last') diff --git a/hr_employee_lastnames/i18n/es.po b/hr_employee_lastnames/i18n/es.po new file mode 100644 index 00000000000..e27f176ef68 --- /dev/null +++ b/hr_employee_lastnames/i18n/es.po @@ -0,0 +1,43 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_employee_lastnames +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-08-31 12:31+0000\n" +"PO-Revision-Date: 2020-08-31 12:31+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: hr_employee_lastnames +#: model:ir.model,name:hr_employee_lastnames.model_hr_employee +msgid "Employee" +msgstr "Empleado" + +#. module: hr_employee_lastnames +#: model:ir.model.fields,field_description:hr_employee_lastnames.field_hr_employee_firstname +msgid "First name" +msgstr "Nombre Propio" + +#. module: hr_employee_lastnames +#: model:ir.model.fields,field_description:hr_employee_lastnames.field_hr_employee_lastname +msgid "Last name" +msgstr "Primer Apellido" + +#. module: hr_employee_lastnames +#: code:addons/hr_employee_lastnames/models/hr_employee.py:32 +#: code:addons/hr_employee_lastnames/models/hr_employee.py:112 +#, python-format +msgid "No name set." +msgstr "Sin nombre establecido." + +#. module: hr_employee_lastnames +#: model:ir.model.fields,field_description:hr_employee_lastnames.field_hr_employee_lastname2 +msgid "Second last name" +msgstr "Segundo Apellido" diff --git a/hr_employee_lastnames/models/__init__.py b/hr_employee_lastnames/models/__init__.py new file mode 100644 index 00000000000..62e04307498 --- /dev/null +++ b/hr_employee_lastnames/models/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import hr_employee diff --git a/hr_employee_lastnames/models/hr_employee.py b/hr_employee_lastnames/models/hr_employee.py new file mode 100644 index 00000000000..1df76318b72 --- /dev/null +++ b/hr_employee_lastnames/models/hr_employee.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- +import logging + +from odoo import api, fields, models, _ +from odoo.exceptions import UserError +from odoo.addons.hr_employee_firstname.models.hr_employee import UPDATE_PARTNER_FIELDS + +_logger = logging.getLogger(__name__) + +UPDATE_PARTNER_FIELDS += ['lastname2'] + + +class HrEmployee(models.Model): + _inherit = 'hr.employee' + + firstname = fields.Char("First name") + lastname = fields.Char("Last name") + lastname2 = fields.Char("Second last name") + + @api.model + def _get_name_lastnames(self, lastname, firstname, lastname2=None): + return self.env['res.partner']._get_computed_name( + lastname, firstname, lastname2) + + def _prepare_vals_on_create_firstname_lastname(self, vals): + values = vals.copy() + res = super(HrEmployee, self)._prepare_vals_on_create_firstname_lastname(values) + if any([field in vals for field in 'firstname', 'lastname', 'lastname2']): + vals['name'] = self._get_name_lastnames( + vals.get('lastname'), vals.get('firstname'), vals.get('lastname2')) + elif vals.get('name'): + name_splitted = self.split_name(vals['name']) + vals['firstname'] = name_splitted['firstname'] + vals['lastname'] = name_splitted['lastname'] + vals['lastname2'] = name_splitted['lastname2'] + else: + raise UserError(_('No name set.')) + return res + + def _prepare_vals_on_write_firstname_lastname(self, vals): + values = vals.copy() + res = super(HrEmployee, self)._prepare_vals_on_write_firstname_lastname(values) + if any([field in vals for field in 'firstname', 'lastname', 'lastname2']): + if 'lastname' in vals: + lastname = vals['lastname'] + else: + lastname = self.lastname + if 'firstname' in vals: + firstname = vals['firstname'] + else: + firstname = self.firstname + if 'lastname2' in vals: + lastname2 = vals['lastname2'] + else: + lastname2 = self.lastname2 + vals['name'] = self._get_name_lastnames(lastname, firstname, lastname2) + elif vals.get('name'): + name_splitted = self.split_name(vals['name']) + vals['lastname'] = name_splitted['lastname'] + vals['firstname'] = name_splitted['firstname'] + vals['lastname2'] = name_splitted['lastname2'] + return res + + def _update_partner_firstname(self): + for employee in self: + partners = employee.mapped('user_id.partner_id') + partners |= employee.mapped('address_home_id') + partners.write({ + 'firstname': employee.firstname, + 'lastname': employee.lastname, + 'lastname2': employee.lastname2, + }) + return + + @api.multi + def _inverse_name(self): + """Try to revert the effect of :method:`._compute_name`.""" + for record in self: + parts = self.env['res.partner']._get_inverse_name(record.name) + record.write({ + 'lastname': parts['lastname'], + 'firstname': parts['firstname'], + 'lastname2': parts['lastname2'], + + }) + + @api.model + def _install_employee_lastnames(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 lastnames + records = self.search([("firstname", "=", False), + ("lastname", "=", False)]) + + # Force calculations there + records._inverse_name() + _logger.info("%d employees updated installing module.", len(records)) + + @api.onchange('firstname', 'lastname', 'lastname2') + def _onchange_firstname_lastname(self): + if self.firstname or self.lastname or self.lastname2: + self.name = self._get_name_lastnames( + self.lastname, self.firstname, self.lastname2) diff --git a/hr_employee_lastnames/readme/CONTRIBUTORS.rst b/hr_employee_lastnames/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..03ab0b41c7d --- /dev/null +++ b/hr_employee_lastnames/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Luis Escobar +* Hugo Adan diff --git a/hr_employee_lastnames/readme/DESCRIPTION.rst b/hr_employee_lastnames/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..ef50535cd9a --- /dev/null +++ b/hr_employee_lastnames/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +This module allows you to add firstname and lastnames (Father an Mother Last Name) in employee form, +and concatenate both in name field. diff --git a/hr_employee_lastnames/readme/USAGE.rst b/hr_employee_lastnames/readme/USAGE.rst new file mode 100644 index 00000000000..1c82d5662e4 --- /dev/null +++ b/hr_employee_lastnames/readme/USAGE.rst @@ -0,0 +1,2 @@ +#. Go to *Employees* +#. On the employee form view you will have 3 separate fields, one for Firstname, second for Lastname, both required and Mother's Last Name (optional). diff --git a/hr_employee_lastnames/static/description/icon.png b/hr_employee_lastnames/static/description/icon.png new file mode 100644 index 00000000000..297dc71c85c Binary files /dev/null and b/hr_employee_lastnames/static/description/icon.png differ diff --git a/hr_employee_lastnames/tests/__init__.py b/hr_employee_lastnames/tests/__init__.py new file mode 100644 index 00000000000..cfa44afe136 --- /dev/null +++ b/hr_employee_lastnames/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2014 Savoir-faire Linux. All Rights Reserved. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from . import test_hr_employee_lastnames diff --git a/hr_employee_lastnames/tests/test_hr_employee_lastnames.py b/hr_employee_lastnames/tests/test_hr_employee_lastnames.py new file mode 100644 index 00000000000..553b8451047 --- /dev/null +++ b/hr_employee_lastnames/tests/test_hr_employee_lastnames.py @@ -0,0 +1,117 @@ +# -*- coding: utf-8 -*- +from odoo.tests.common import TransactionCase + + +class TestEmployeeLastnames(TransactionCase): + def setUp(self): + super(TestEmployeeLastnames, self).setUp() + self.env['ir.config_parameter'].sudo().set_param( + 'partner_names_order', 'first_last') + self.employee_model = self.env['hr.employee'] + + # Create 3 employees to concatenate the firstname and lastnames + # in name_related + self.employee1_id = self.employee_model.create( + {'firstname': 'Manuel', 'lastname': 'Fernandez', 'lastname2': 'Gonzalez'}) + self.employee2_id = self.employee_model.create( + {'firstname': 'Jean-Pierre', 'lastname': 'Carnaud'}) + self.employee3_id = self.employee_model.create( + {'firstname': 'Jenssens', 'lastname': 'Famke'}) + + # Create 3 employees for split the name_related to + # firstname and lastnames + self.employee10_id = self.employee_model.create( + {'name': 'Manuel Fernandez Gonzalez'}) + self.employee20_id = self.employee_model.create( + {'name': 'Jean-Pierre Carnaud'}) + self.employee30_id = self.employee_model.create( + {'name': 'JenssensFamke'}) + + def test_get_name_lastnames(self): + """ Validate the _get_name_lastnames method is concatenating + the firstname and lastnames + """ + # Check for employee1 + self.assertEqual(self.employee1_id.name, 'Manuel Fernandez Gonzalez') + + # Check for employee2 + self.assertEqual(self.employee2_id.name, 'Jean-Pierre Carnaud') + + # Check for employee3 + self.assertEqual(self.employee3_id.name, 'Jenssens Famke') + + def test_onchange(self): + """ Validate the _get_name_lastnames method is not failing + """ + field_onchange = self.employee_model.new({})._onchange_spec() + self.assertEqual(field_onchange.get('firstname'), '1') + self.assertEqual(field_onchange.get('lastname'), '1') + values = {'firstname': 'Pedro', + 'lastname': 'Perez', + 'lastname2': 'Hernandez', + 'name': 'test employee'} + for field in self.employee_model._fields: + if field not in values: + values[field] = False + # we work on a temporary record + new_record = self.employee_model.new(values) + + updates = new_record.onchange( + values, ['firstname', 'lastname', 'lastname2'], field_onchange) + values.update(updates.get('value', {})) + self.assertEqual(values['name'], 'Pedro Perez Hernandez') + + def test_auto_init_name(self): + """ Validate the create method if the name is split + in firstname and lastnames + """ + # Check for employee10 + self.assertEqual(self.employee10_id.firstname, 'Manuel') + self.assertEqual(self.employee10_id.lastname, 'Fernandez') + self.assertEqual(self.employee10_id.lastname2, 'Gonzalez') + + # Check for employee20 + self.assertEqual(self.employee20_id.firstname, 'Jean-Pierre') + self.assertEqual(self.employee20_id.lastname, 'Carnaud') + self.assertEqual(self.employee20_id.lastname2, False) + + # Check for employee30 + self.assertEqual(self.employee30_id.firstname, False) + self.assertEqual(self.employee30_id.lastname, 'JenssensFamke') + self.assertEqual(self.employee30_id.lastname2, False) + + def test_change_name(self): + self.employee1_id.write({'name': 'Pedro Martinez Torres'}) + self.employee1_id.refresh() + + self.assertEqual(self.employee1_id.firstname, 'Pedro') + self.assertEqual(self.employee1_id.lastname, 'Martinez') + self.assertEqual(self.employee1_id.lastname2, 'Torres') + + def test_change_name_with_space(self): + self.employee1_id.write({'name': ' Jean-Pierre Carnaud-Eyck'}) + self.employee1_id.refresh() + + self.assertEqual(self.employee1_id.firstname, 'Jean-Pierre') + self.assertEqual(self.employee1_id.lastname, 'Carnaud-Eyck') + self.assertEqual(self.employee1_id.lastname2, False) + + def test_change_firstname(self): + self.employee1_id.write({'firstname': 'Pedro'}) + self.employee1_id.refresh() + + self.assertEqual(self.employee1_id.name, 'Pedro Fernandez Gonzalez') + + def test_change_lastname(self): + self.employee1_id.write({'lastname': 'Lopez'}) + self.employee1_id.refresh() + + self.assertEqual(self.employee1_id.name, 'Manuel Lopez Gonzalez') + + def test_change_firstname_and_lastnames(self): + self.employee1_id.write({ + 'firstname': 'Jean-Pierre', + 'lastname2': 'Carnaud'}) + self.employee1_id.refresh() + + self.assertEqual(self.employee1_id.name, 'Jean-Pierre Fernandez Carnaud') diff --git a/hr_employee_lastnames/views/hr_views.xml b/hr_employee_lastnames/views/hr_views.xml new file mode 100644 index 00000000000..09baa54c44d --- /dev/null +++ b/hr_employee_lastnames/views/hr_views.xml @@ -0,0 +1,15 @@ + + + + hr.employee.form.firstname.inherit + hr.employee + + + + + + + + + +