diff --git a/partner_firstname_portal/README.rst b/partner_firstname_portal/README.rst new file mode 100644 index 00000000000..89a44b44dff --- /dev/null +++ b/partner_firstname_portal/README.rst @@ -0,0 +1,91 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +========================================= +Partner First Name and Last Name - Portal +========================================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:f434fef408ff55e89859c340b56a64fd2a6bec074c832da8408ebec51beffcd4 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpartner--contact-lightgray.png?logo=github + :target: https://github.com/OCA/partner-contact/tree/19.0/partner_firstname_portal + :alt: OCA/partner-contact +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/partner-contact-19-0/partner-contact-19-0-partner_firstname_portal + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/partner-contact&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module is a glue module installed when OCA ``partner_firstname`` +module and Odoo ``portal`` module are installed. + +This allows the customer to edit their first and last names, once +logged. + +|signup| + +.. |signup| image:: https://raw.githubusercontent.com/OCA/partner-contact/19.0/partner_firstname_portal/static/description/my_account.png + +**Table of contents** + +.. contents:: + :local: + +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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* GRAP + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +.. |maintainer-legalsylvain| image:: https://github.com/legalsylvain.png?size=40px + :target: https://github.com/legalsylvain + :alt: legalsylvain + +Current `maintainer `__: + +|maintainer-legalsylvain| + +This module is part of the `OCA/partner-contact `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/partner_firstname_portal/__init__.py b/partner_firstname_portal/__init__.py new file mode 100644 index 00000000000..91c5580fed3 --- /dev/null +++ b/partner_firstname_portal/__init__.py @@ -0,0 +1,2 @@ +from . import controllers +from . import models diff --git a/partner_firstname_portal/__manifest__.py b/partner_firstname_portal/__manifest__.py new file mode 100644 index 00000000000..9c960afa020 --- /dev/null +++ b/partner_firstname_portal/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2025 Sylvain LE GAL (GRAP) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Partner First Name and Last Name - Portal", + "summary": "Glue module to make working portal and partner firstname module" + " together", + "version": "19.0.1.0.0", + "author": "GRAP, Odoo Community Association (OCA)", + "license": "AGPL-3", + "maintainers": ["legalsylvain"], + "category": "Extra Tools", + "website": "https://github.com/OCA/partner-contact", + "depends": ["partner_firstname", "portal"], + "data": [ + "views/portal_templates.xml", + ], + "auto_install": True, +} diff --git a/partner_firstname_portal/controllers/__init__.py b/partner_firstname_portal/controllers/__init__.py new file mode 100644 index 00000000000..8c3feb6f562 --- /dev/null +++ b/partner_firstname_portal/controllers/__init__.py @@ -0,0 +1 @@ +from . import portal diff --git a/partner_firstname_portal/controllers/portal.py b/partner_firstname_portal/controllers/portal.py new file mode 100644 index 00000000000..4025471c110 --- /dev/null +++ b/partner_firstname_portal/controllers/portal.py @@ -0,0 +1,81 @@ +# Copyright 2025 Sylvain LE GAL (GRAP) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.http import request + +from odoo.addons.portal.controllers.portal import CustomerPortal + + +def get_config_required(): + return ( + request.env["ir.config_parameter"] + .sudo() + .get_param("partner_firstname.required_fields") + ) + + +class PartnerFirstnameCustomerPortal(CustomerPortal): + def _create_or_update_address( + self, + partner_sudo, + address_type="billing", + use_delivery_as_billing=False, + callback="/my/addresses", + required_fields=False, + verify_address_values=True, + **form_data, + ): + if partner_sudo.is_company: + form_data.pop("firstname", None) + form_data.pop("lastname", None) + else: + partner_sudo = partner_sudo.with_context(name_field_pop_value=True) + return super()._create_or_update_address( + partner_sudo, + address_type, + use_delivery_as_billing, + callback, + required_fields, + verify_address_values, + **form_data, + ) + + def _validate_address_values( + self, address_values, partner_sudo, address_type, *args, **kwargs + ): + invalid_fields, missing_fields, error_messages = ( + super()._validate_address_values( + address_values, partner_sudo, address_type, *args, **kwargs + ) + ) + required_fields = get_config_required() + if "firstname" in required_fields and not kwargs.get("firstname"): + missing_fields.add("firstname") + error_messages.append(self.env._("Firstname is missing.")) + if "lastname" in required_fields and not kwargs.get("lastname"): + missing_fields.add("lastname") + error_messages.append(self.env._("Lastname is missing.")) + if ( + "no" == required_fields + and not kwargs.get("firstname") + and not kwargs.get("lastname") + and not partner_sudo.is_company + ): + error_messages.append( + self.env._("Please enter your firstname or your lastname.") + ) + missing_fields.add("firstname") + missing_fields.add("lastname") + return invalid_fields, missing_fields, error_messages + + def _handle_extra_form_data(self, extra_form_data, address_values): + res = super()._handle_extra_form_data(extra_form_data, address_values) + data = {} + if extra_form_data.get("firstname"): + data["firstname"] = extra_form_data["firstname"] + if extra_form_data.get("lastname"): + data["lastname"] = extra_form_data["lastname"] + if data: + partner = self.env.user.partner_id + partner.write(data) + return res diff --git a/partner_firstname_portal/i18n/fr.po b/partner_firstname_portal/i18n/fr.po new file mode 100644 index 00000000000..54475bec592 --- /dev/null +++ b/partner_firstname_portal/i18n/fr.po @@ -0,0 +1,48 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * partner_firstname_portal +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-09-01 14:41+0000\n" +"PO-Revision-Date: 2025-09-01 14:41+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: partner_firstname_portal +#: model_terms:ir.ui.view,arch_db:partner_firstname_portal.portal_my_details_fields +msgid "Company" +msgstr "Personne morale" + +#. module: partner_firstname_portal +#: model:ir.model,name:partner_firstname_portal.model_res_partner +msgid "Contact" +msgstr "" + +#. module: partner_firstname_portal +#: model_terms:ir.ui.view,arch_db:partner_firstname_portal.portal_my_details_fields +msgid "First Name" +msgstr "Prénom" + +#. module: partner_firstname_portal +#: model_terms:ir.ui.view,arch_db:partner_firstname_portal.portal_my_details_fields +msgid "Individual" +msgstr "Particulier" + +#. module: partner_firstname_portal +#: model_terms:ir.ui.view,arch_db:partner_firstname_portal.portal_my_details_fields +msgid "Last Name" +msgstr "Nom" + +#. module: partner_firstname_portal +#. odoo-python +#: code:addons/partner_firstname_portal/controllers/portal.py:0 +msgid "Please enter your firstname or your lastname." +msgstr "Veuillez saisir votre prénom ou votre nom." diff --git a/partner_firstname_portal/i18n/it.po b/partner_firstname_portal/i18n/it.po new file mode 100644 index 00000000000..7341cb89fb3 --- /dev/null +++ b/partner_firstname_portal/i18n/it.po @@ -0,0 +1,48 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * partner_firstname_portal +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2026-05-14 15:45+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.15.2\n" + +#. module: partner_firstname_portal +#: model_terms:ir.ui.view,arch_db:partner_firstname_portal.portal_my_details_fields +msgid "Company" +msgstr "Azienda" + +#. module: partner_firstname_portal +#: model:ir.model,name:partner_firstname_portal.model_res_partner +msgid "Contact" +msgstr "Contatto" + +#. module: partner_firstname_portal +#: model_terms:ir.ui.view,arch_db:partner_firstname_portal.portal_my_details_fields +msgid "First Name" +msgstr "Nome" + +#. module: partner_firstname_portal +#: model_terms:ir.ui.view,arch_db:partner_firstname_portal.portal_my_details_fields +msgid "Individual" +msgstr "Persona fisica" + +#. module: partner_firstname_portal +#: model_terms:ir.ui.view,arch_db:partner_firstname_portal.portal_my_details_fields +msgid "Last Name" +msgstr "Cognome" + +#. module: partner_firstname_portal +#. odoo-python +#: code:addons/partner_firstname_portal/controllers/portal.py:0 +msgid "Please enter your firstname or your lastname." +msgstr "Inserire nome e cognome." diff --git a/partner_firstname_portal/i18n/partner_firstname_portal.pot b/partner_firstname_portal/i18n/partner_firstname_portal.pot new file mode 100644 index 00000000000..06566366247 --- /dev/null +++ b/partner_firstname_portal/i18n/partner_firstname_portal.pot @@ -0,0 +1,45 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * partner_firstname_portal +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \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: partner_firstname_portal +#: model_terms:ir.ui.view,arch_db:partner_firstname_portal.portal_my_details_fields +msgid "Company" +msgstr "" + +#. module: partner_firstname_portal +#: model:ir.model,name:partner_firstname_portal.model_res_partner +msgid "Contact" +msgstr "" + +#. module: partner_firstname_portal +#: model_terms:ir.ui.view,arch_db:partner_firstname_portal.portal_my_details_fields +msgid "First Name" +msgstr "" + +#. module: partner_firstname_portal +#: model_terms:ir.ui.view,arch_db:partner_firstname_portal.portal_my_details_fields +msgid "Individual" +msgstr "" + +#. module: partner_firstname_portal +#: model_terms:ir.ui.view,arch_db:partner_firstname_portal.portal_my_details_fields +msgid "Last Name" +msgstr "" + +#. module: partner_firstname_portal +#. odoo-python +#: code:addons/partner_firstname_portal/controllers/portal.py:0 +msgid "Please enter your firstname or your lastname." +msgstr "" diff --git a/partner_firstname_portal/models/__init__.py b/partner_firstname_portal/models/__init__.py new file mode 100644 index 00000000000..91fed54d404 --- /dev/null +++ b/partner_firstname_portal/models/__init__.py @@ -0,0 +1 @@ +from . import res_partner diff --git a/partner_firstname_portal/models/res_partner.py b/partner_firstname_portal/models/res_partner.py new file mode 100644 index 00000000000..2feff2f7299 --- /dev/null +++ b/partner_firstname_portal/models/res_partner.py @@ -0,0 +1,26 @@ +# Copyright 2025 Sylvain LE GAL (GRAP) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + def _get_frontend_writable_fields(self): + res = super()._get_frontend_writable_fields() + required_fields = ( + self.env["ir.config_parameter"] + .sudo() + .get_param("partner_firstname.required_fields") + ) + if "firstname" in required_fields: + res.update({"firstname"}) + if "lastname" in required_fields: + res.update({"lastname"}) + return res + + def write(self, vals): + if self.env.context.get("name_field_pop_value"): + vals.pop("name", None) + return super().write(vals) diff --git a/partner_firstname_portal/pyproject.toml b/partner_firstname_portal/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/partner_firstname_portal/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/partner_firstname_portal/readme/DESCRIPTION.md b/partner_firstname_portal/readme/DESCRIPTION.md new file mode 100644 index 00000000000..d1ee44309ec --- /dev/null +++ b/partner_firstname_portal/readme/DESCRIPTION.md @@ -0,0 +1,6 @@ +This module is a glue module installed when OCA ``partner_firstname`` module +and Odoo ``portal`` module are installed. + +This allows the customer to edit their first and last names, once logged. + + ![signup](../static/description/my_account.png) diff --git a/partner_firstname_portal/static/description/icon.png b/partner_firstname_portal/static/description/icon.png new file mode 100644 index 00000000000..1dcc49c24f3 Binary files /dev/null and b/partner_firstname_portal/static/description/icon.png differ diff --git a/partner_firstname_portal/static/description/index.html b/partner_firstname_portal/static/description/index.html new file mode 100644 index 00000000000..d070c12f699 --- /dev/null +++ b/partner_firstname_portal/static/description/index.html @@ -0,0 +1,428 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Partner First Name and Last Name - Portal

+ +

Beta License: AGPL-3 OCA/partner-contact Translate me on Weblate Try me on Runboat

+

This module is a glue module installed when OCA partner_firstname +module and Odoo portal module are installed.

+

This allows the customer to edit their first and last names, once +logged.

+

signup

+

Table of contents

+ +
+

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 to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • GRAP
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

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.

+

Current maintainer:

+

legalsylvain

+

This module is part of the OCA/partner-contact project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+
+ + diff --git a/partner_firstname_portal/static/description/my_account.png b/partner_firstname_portal/static/description/my_account.png new file mode 100644 index 00000000000..f2336ed8e97 Binary files /dev/null and b/partner_firstname_portal/static/description/my_account.png differ diff --git a/partner_firstname_portal/tests/__init__.py b/partner_firstname_portal/tests/__init__.py new file mode 100644 index 00000000000..d2e8c712809 --- /dev/null +++ b/partner_firstname_portal/tests/__init__.py @@ -0,0 +1 @@ +from . import test_partner_firstname_portal diff --git a/partner_firstname_portal/tests/test_partner_firstname_portal.py b/partner_firstname_portal/tests/test_partner_firstname_portal.py new file mode 100644 index 00000000000..e78645b89c6 --- /dev/null +++ b/partner_firstname_portal/tests/test_partner_firstname_portal.py @@ -0,0 +1,109 @@ +# Copyright 2025 Sylvain LE GAL (GRAP) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +from odoo import http +from odoo.fields import Command +from odoo.tests.common import HttpCase + + +class TestPartnerFirstnamePortal(HttpCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + # Generated with https://www.fakenamegenerator.com + cls.partner_portal = cls.env["res.partner"].create( + { + "name": "Théodule Bernier", + "email": "theodule_bernier@jourrapide.com", + "country_id": cls.env.ref("base.be").id, + "phone": "0487 49 15 23", + "street": "Hooivelden 198", + "zip": "4720", + "city": "La calamine", + } + ) + cls.user_portal = cls.env["res.users"].create( + { + "login": "portal", + "password": "portal", + "partner_id": cls.partner_portal.id, + "group_ids": [Command.set([cls.env.ref("base.group_portal").id])], + } + ) + cls.base_data = { + "name": cls.user_portal.partner_id.name, + "partner_id": cls.user_portal.partner_id.id, + "country_id": cls.user_portal.country_id.id, + "email": cls.user_portal.email, + "phone": cls.user_portal.phone, + "street": cls.user_portal.street, + "city": cls.user_portal.city, + "zip": cls.user_portal.zip, + } + + def _set_required_field(self, value): + self.env["ir.config_parameter"].set_param( + "partner_firstname.required_fields", value + ) + + def _post_account_details(self, **data): + self.authenticate(self.user_portal.login, "admin") + data["csrf_token"] = http.Request.csrf_token(self) + return self.url_open("/my/address/submit", data=data) + + def test_edition_individual_missing_firstname(self): + self._set_required_field("firstname") + self._post_account_details( + **self.base_data, + lastname="MY LAST NAME portal", + ) + self.assertEqual( + self.user_portal.name, + "Théodule Bernier", + "Should not change name, if required firstname is missing", + ) + + def test_edition_individual_missing_lastname(self): + self._set_required_field("lastname") + self._post_account_details( + **self.base_data, + firstname="My First Name portal", + ) + self.assertEqual( + self.user_portal.partner_id.name, + "Théodule Bernier", + "Should not change name, if required lastname is missing", + ) + + def test_edition_individual_missing_lastname_and_firstname(self): + self._set_required_field("no") + self._post_account_details( + **self.base_data, + ) + self.assertEqual( + self.user_portal.partner_id.name, + "Théodule Bernier", + "Should not change name, if lastname and firstname is missing", + ) + + def test_edition_individual_with_new_firstname_and_lastname(self): + self._post_account_details( + **self.base_data, + firstname="My First Name portal", + lastname="MY LAST NAME portal", + ) + self.assertEqual( + self.user_portal.partner_id.name, "My First Name portal MY LAST NAME portal" + ) + + def test_edition_company_missing_new_name(self): + self.user_portal.partner_id.company_type = "company" + self._post_account_details(**self.base_data) + self.assertEqual(self.user_portal.partner_id.name, "Théodule Bernier") + + def test_edition_company_with_new_name(self): + self.user_portal.partner_id.is_company = True + self.base_data["name"] = "My New Company Name" + self._post_account_details(**self.base_data) + self.assertEqual(self.user_portal.partner_id.name, "My New Company Name") diff --git a/partner_firstname_portal/views/portal_templates.xml b/partner_firstname_portal/views/portal_templates.xml new file mode 100644 index 00000000000..47d6e3a592b --- /dev/null +++ b/partner_firstname_portal/views/portal_templates.xml @@ -0,0 +1,93 @@ + + + + +