diff --git a/README.md b/README.md index d038b6a647..f7e87c5703 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Available addons ---------------- addon | version | maintainers | summary --- | --- | --- | --- +[portal_invitation_by_website](portal_invitation_by_website/) | 19.0.1.0.0 | | Restrict portal users to a specific website from the invitation wizard [website_conditional_visibility_user_group](website_conditional_visibility_user_group/) | 19.0.1.0.0 | | Only internal users will see the blocks you add this condition to [website_cookiefirst](website_cookiefirst/) | 19.0.1.0.0 | | Cookiefirst integration [website_form_require_legal](website_form_require_legal/) | 19.0.1.0.1 | | Add possibility to require confirm legal terms. diff --git a/portal_invitation_by_website/README.rst b/portal_invitation_by_website/README.rst new file mode 100644 index 0000000000..360bcdbee1 --- /dev/null +++ b/portal_invitation_by_website/README.rst @@ -0,0 +1,107 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +============================ +Portal Invitation by Website +============================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:0488fede852ebdbfad8cb4b98611ee4ba6ecf76e22cc28bd88c4e1614111ff3e + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fwebsite-lightgray.png?logo=github + :target: https://github.com/OCA/website/tree/19.0/portal_invitation_by_website + :alt: OCA/website +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/website-19-0/website-19-0-portal_invitation_by_website + :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/website&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module extends the portal invitation wizard to allow restricting +portal users to a specific website in multi-website environments. + +When inviting contacts as portal users from the backend, you can now +select a website at the wizard level (applied to all contacts) or +override it per-contact. The invitation email URL will automatically use +the selected website's domain, ensuring the signup link directs the user +to the correct site. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +1. Go to **Contacts** and select one or more contacts. +2. Open the action menu and click **Grant Portal Access**. +3. In the wizard, select a **Website** to restrict access to that site. + + - The website applies to all contacts in the list. + - You can override the website per contact using the **Website** + column. + +4. Click **Grant Access** for each contact or use the batch action. + +The invitation email will contain a signup URL pointing to the selected +website's domain. If the website has **Specific User Accounts** enabled +(``Website > Configuration > Settings``), the portal user will only be +able to log in from that website. + +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 +------- + +* Tecnativa + +Contributors +------------ + +- `Tecnativa `__: + + - Cristina Hidalgo + +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. + +This module is part of the `OCA/website `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/portal_invitation_by_website/__init__.py b/portal_invitation_by_website/__init__.py new file mode 100644 index 0000000000..9b4296142f --- /dev/null +++ b/portal_invitation_by_website/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizard diff --git a/portal_invitation_by_website/__manifest__.py b/portal_invitation_by_website/__manifest__.py new file mode 100644 index 0000000000..8d4c836039 --- /dev/null +++ b/portal_invitation_by_website/__manifest__.py @@ -0,0 +1,15 @@ +{ + "name": "Portal Invitation by Website", + "summary": "Restrict portal users to a specific website from the invitation wizard", + "version": "19.0.1.0.0", + "author": "Tecnativa, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/website", + "license": "AGPL-3", + "category": "Website", + "depends": ["portal", "website"], + "data": [ + "data/mail_template_portal_welcome.xml", + "views/portal_wizard_views.xml", + ], + "installable": True, +} diff --git a/portal_invitation_by_website/data/mail_template_portal_welcome.xml b/portal_invitation_by_website/data/mail_template_portal_welcome.xml new file mode 100644 index 0000000000..fdec487dd9 --- /dev/null +++ b/portal_invitation_by_website/data/mail_template_portal_welcome.xml @@ -0,0 +1,209 @@ + + + + Portal: User Invite (Website) + + {{ (object.company_id.email_formatted or user.email_formatted) }} + {{ object.email_formatted }} + Invitation email using website name instead of company name + {{ object.lang }} + + Your account at {{ object.website_id.name or object.company_id.name }} + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + +
+ Your Account +
+ Marc Demo +
+ +
+
+
+
+ + + + + + + +
+
+ Dear Marc Demo,

+ Welcome to YourCompany's Portal!

+ An account has been created for you with the following login: demo

+ Click on the button below to pick a password and activate your account. + + Welcome to our company's portal. +
+
+
+
+
+ + + + + + + +
+ YourCompany +
+ +1 650-123-4567 + + | info@yourcompany.com + + + | http://www.example.com + +
+
+
+ + + + +
+ Powered by Odoo +
+
+
+
+
diff --git a/portal_invitation_by_website/i18n/es.po b/portal_invitation_by_website/i18n/es.po new file mode 100644 index 0000000000..0906aaf19c --- /dev/null +++ b/portal_invitation_by_website/i18n/es.po @@ -0,0 +1,324 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * portal_invitation_by_website +# +# Translators: +# Cristina Hidalgo , 2026 +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2026-05-20 09:56+0000\n" +"PO-Revision-Date: 2026-05-20 11:57+0200\n" +"Last-Translator: Cristina Hidalgo \n" +"Language-Team: Spanish (https://www.transifex.com/odoo/teams/41243/es/)\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.9\n" + +#. module: portal_invitation_by_website +#: model:mail.template,body_html:portal_invitation_by_website.mail_template_portal_welcome_website +msgid "" +"\n" +"\n" +"\n" +"
\n" +"\n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +" Your Account
\n" +" Marc Demo\n" +"
\n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +"
\n" +" Dear Marc " +"Demo,

\n" +" Welcome to YourCompany's Portal!

\n" +" An account has been created for you with the " +"following login: demo

\n" +" Click on the button below to pick a password and " +"activate your account.\n" +" \n" +" Welcome to our company's portal.\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +" YourCompany\n" +"
\n" +" +1 " +"650-123-4567\n" +" \n" +" | info@yourcompany.com\n" +" \n" +" \n" +" | http://www.example.com\n" +" \n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +"
\n" +" Powered by Odoo\n" +"
\n" +"
\n" +" " +msgstr "" +"\n" +"\n" +"\n" +"
\n" +"\n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +" Tu cuenta
\n" +" Marc Demo\n" +"
\n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +"
\n" +" Estimado/a Marc Demo,

\n" +" ¡Bienvenido/a al portal de YourCompany!

\n" +" Se ha creado una cuenta para ti con el siguiente " +"inicio de sesión: demo

\n" +" Haz clic en el siguiente botón para elegir una " +"contraseña y activar tu cuenta.\n" +" \n" +" Bienvenido/a al portal de nuestra empresa.\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +" YourCompany\n" +"
\n" +" +1 " +"650-123-4567\n" +" \n" +" | info@yourcompany.com\n" +" \n" +" \n" +" | http://www.example.com\n" +" \n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +"
\n" +" Con tecnología de Odoo\n" +"
\n" +"
\n" +" " + +#. module: portal_invitation_by_website +#: model_terms:ir.ui.view,arch_db:portal_invitation_by_website.portal_wizard_view_website +msgid "Apply Website" +msgstr "Aplicar sitio web" + +#. module: portal_invitation_by_website +#: model:ir.model.fields,help:portal_invitation_by_website.field_portal_wizard__website_id +msgid "" +"Apply this website to all the contacts below. The invitation email URL will " +"match this website's domain. Leave empty to keep each contact's current " +"website." +msgstr "" +"Aplica este sitio web a todos los contactos de abajo. La URL del correo de " +"invitación usará el dominio de este sitio web. Déjalo vacío para mantener el " +"sitio web actual de cada contacto." + +#. module: portal_invitation_by_website +#: model:ir.model,name:portal_invitation_by_website.model_portal_wizard +msgid "Grant Portal Access" +msgstr "Conceder acceso al portal" + +#. module: portal_invitation_by_website +#: model:mail.template,description:portal_invitation_by_website.mail_template_portal_welcome_website +msgid "Invitation email using website name instead of company name" +msgstr "" +"Correo de invitación en el que se utiliza el nombre del sitio web en lugar " +"del nombre de la empresa" + +#. module: portal_invitation_by_website +#: model:ir.model,name:portal_invitation_by_website.model_ir_model_data +msgid "Model Data" +msgstr "Datos del modelo" + +#. module: portal_invitation_by_website +#: model:ir.model,name:portal_invitation_by_website.model_portal_wizard_user +msgid "Portal User Config" +msgstr "Configuración de usuario del portal" + +#. module: portal_invitation_by_website +#: model:mail.template,name:portal_invitation_by_website.mail_template_portal_welcome_website +msgid "Portal: User Invite (Website)" +msgstr "Portal: Invitación de usuario (Sitio web)" + +#. module: portal_invitation_by_website +#: model:ir.model,name:portal_invitation_by_website.model_res_users +msgid "User" +msgstr "" + +#. module: portal_invitation_by_website +#: model:ir.model.fields,field_description:portal_invitation_by_website.field_portal_wizard__website_id +#: model:ir.model.fields,field_description:portal_invitation_by_website.field_portal_wizard_user__website_id +msgid "Website" +msgstr "Sitio web" + +#. module: portal_invitation_by_website +#: model:mail.template,subject:portal_invitation_by_website.mail_template_portal_welcome_website +msgid "" +"Your account at {{ object.website_id.name or " +"object.user_id.company_id.name }}" +msgstr "" +"Tu cuenta en {{ object.website_id.name or object.user_id.company_id.name }}" diff --git a/portal_invitation_by_website/i18n/it.po b/portal_invitation_by_website/i18n/it.po new file mode 100644 index 0000000000..953b263cd6 --- /dev/null +++ b/portal_invitation_by_website/i18n/it.po @@ -0,0 +1,560 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * portal_invitation_by_website +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2026-06-10 15:46+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: portal_invitation_by_website +#: model:mail.template,body_html:portal_invitation_by_website.mail_template_portal_welcome_website +msgid "" +"\n" +"\n" +"\n" +"
\n" +"\n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +" Your Account
\n" +" Marc Demo\n" +"
\n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +"
\n" +" Dear Marc " +"Demo,

\n" +" Welcome to YourCompany's Portal!

\n" +" An account has been created for you with the " +"following login: demo

\n" +" Click on the button below to pick a password and " +"activate your account.\n" +" \n" +" Welcome to our company's portal.\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +" YourCompany\n" +"
\n" +" +1 " +"650-123-4567\n" +" \n" +" | info@yourcompany.com\n" +" \n" +" \n" +" | http://www.example.com\n" +" \n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +"
\n" +" Powered by Odoo\n" +"
\n" +"
\n" +" " +msgstr "" +"\n" +"\n" +"\n" +"
\n" +"\n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +" Il tuo account" +"
\n" +" Marc Demo\n" +"
\n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +"
\n" +" Egregio Marc " +"Demo,

\n" +" benvenuto al portale " +"YourCompany!

\n" +" È stato creato un account per te con il seguente " +"accesso: demo

\n" +" Cliccare il pulsante sottostante per generare una " +"passworde attivare l'account.\n" +" \n" +" " +"Benvenuto nel portale della nostra azienda.\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +" YourCompany\n" +"
\n" +" +1 " +"650-123-4567\n" +" \n" +" | " +"info@yourcompany.com\n" +" \n" +" \n" +" | http://www.example.com\n" +" \n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +"
\n" +" Powered by Odoo\n" +"
\n" +"
\n" +" " + +#. module: portal_invitation_by_website +#: model_terms:ir.ui.view,arch_db:portal_invitation_by_website.portal_wizard_view_website +msgid "Apply Website" +msgstr "Applica sito web" + +#. module: portal_invitation_by_website +#: model:ir.model.fields,help:portal_invitation_by_website.field_portal_wizard__website_id +msgid "" +"Apply this website to all the contacts below. The invitation email URL will " +"match this website's domain. Leave empty to keep each contact's current " +"website." +msgstr "" +"Applicare questo sito web a tutti i contatti qui sotto. L'URL dell'email di " +"invito corrisponderà al dominio di questo sito web. Lasciare vuoto per " +"mantenere il sito web attuale di ciascun contatto." + +#. module: portal_invitation_by_website +#: model:ir.model,name:portal_invitation_by_website.model_portal_wizard +msgid "Grant Portal Access" +msgstr "Concedi accesso portale" + +#. module: portal_invitation_by_website +#: model:mail.template,description:portal_invitation_by_website.mail_template_portal_welcome_website +msgid "Invitation email using website name instead of company name" +msgstr "" +"E-mail di invito utilizzando il nome del sito web al posto del nome aziendale" + +#. module: portal_invitation_by_website +#: model:ir.model,name:portal_invitation_by_website.model_ir_model_data +msgid "Model Data" +msgstr "Dati modello" + +#. module: portal_invitation_by_website +#: model:ir.model,name:portal_invitation_by_website.model_portal_wizard_user +msgid "Portal User Config" +msgstr "Configurazione utente portale" + +#. module: portal_invitation_by_website +#: model:mail.template,name:portal_invitation_by_website.mail_template_portal_welcome_website +msgid "Portal: User Invite (Website)" +msgstr "Portale: invito utente (sito web)" + +#. module: portal_invitation_by_website +#: model:ir.model,name:portal_invitation_by_website.model_res_users +msgid "User" +msgstr "Utente" + +#. module: portal_invitation_by_website +#: model:ir.model.fields,field_description:portal_invitation_by_website.field_portal_wizard__website_id +#: model:ir.model.fields,field_description:portal_invitation_by_website.field_portal_wizard_user__website_id +msgid "Website" +msgstr "Sito web" + +#. module: portal_invitation_by_website +#: model:mail.template,subject:portal_invitation_by_website.mail_template_portal_welcome_website +msgid "" +"Your account at {{ object.website_id.name or " +"object.user_id.company_id.name }}" +msgstr "" +"Il tuo account a {{ object.website_id.name or " +"object.user_id.company_id.name }}" + +#~ msgid "" +#~ "\n" +#~ "\n" +#~ "\n" +#~ "
\n" +#~ "\n" +#~ "\n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ "\n" +#~ "
\n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ "
\n" +#~ " Your Account
\n" +#~ " Marc Demo\n" +#~ "
\n" +#~ " \n" +#~ "
\n" +#~ "
\n" +#~ "
\n" +#~ "
\n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ "
\n" +#~ "
\n" +#~ " Dear Marc " +#~ "Demo,

\n" +#~ " Welcome to YourCompany's Portal!

\n" +#~ " An account has been created for you with the " +#~ "following login: demo

\n" +#~ " Click on the button below to pick a password and " +#~ "activate your account.\n" +#~ " \n" +#~ " Welcome to our company's portal.\n" +#~ "
\n" +#~ "
\n" +#~ "
\n" +#~ "
\n" +#~ "
\n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ "
\n" +#~ " YourCompany\n" +#~ "
\n" +#~ " +1 " +#~ "650-123-4567\n" +#~ " \n" +#~ " | info@yourcompany.com\n" +#~ " \n" +#~ " \n" +#~ " | http://www.example.com\n" +#~ " \n" +#~ "
\n" +#~ "
\n" +#~ "
\n" +#~ " \n" +#~ " \n" +#~ "
\n" +#~ " Powered by Odoo\n" +#~ "
\n" +#~ "
\n" +#~ " " +#~ msgstr "" +#~ "\n" +#~ "\n" +#~ "\n" +#~ "
\n" +#~ "\n" +#~ "\n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ "\n" +#~ "
\n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ "
\n" +#~ " Il tuo account
\n" +#~ " Marc Demo\n" +#~ "
\n" +#~ " \n" +#~ "
\n" +#~ "
\n" +#~ "
\n" +#~ "
\n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ "
\n" +#~ "
\n" +#~ " Egregio Marc Demo,

\n" +#~ " benvenuto al portale YourCompany!

\n" +#~ " È stato creato un account per te con il seguente " +#~ "accesso: demo

\n" +#~ " Cliccare il pulsante sottostante per generare una " +#~ "passworde attivare l'account.\n" +#~ " \n" +#~ " Benvenuto nel portale della nostra azienda.\n" +#~ "
\n" +#~ "
\n" +#~ "
\n" +#~ "
\n" +#~ "
\n" +#~ " \n" +#~ " \n" +#~ " \n" +#~ "
\n" +#~ " YourCompany\n" +#~ "
\n" +#~ " +1 " +#~ "650-123-4567\n" +#~ " \n" +#~ " | info@yourcompany.com\n" +#~ " \n" +#~ " \n" +#~ " | http://www.example.com\n" +#~ " \n" +#~ "
\n" +#~ "
\n" +#~ "
\n" +#~ " \n" +#~ " \n" +#~ "
\n" +#~ " Powered by Odoo\n" +#~ "
\n" +#~ "
\n" +#~ " " diff --git a/portal_invitation_by_website/i18n/portal_invitation_by_website.pot b/portal_invitation_by_website/i18n/portal_invitation_by_website.pot new file mode 100644 index 0000000000..2bda7451f5 --- /dev/null +++ b/portal_invitation_by_website/i18n/portal_invitation_by_website.pot @@ -0,0 +1,185 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * portal_invitation_by_website +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 19.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: portal_invitation_by_website +#: model:mail.template,body_html:portal_invitation_by_website.mail_template_portal_welcome_website +msgid "" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" Your Account\n" +"
\n" +" Marc Demo\n" +"
\n" +" \n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"
\n" +" Dear Marc Demo,

\n" +" Welcome to YourCompany's Portal!

\n" +" An account has been created for you with the following login: demo

\n" +" Click on the button below to pick a password and activate your account.\n" +" \n" +" Welcome to our company's portal.\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" YourCompany\n" +"
\n" +" +1 650-123-4567\n" +" \n" +" | info@yourcompany.com\n" +" \n" +" \n" +" | http://www.example.com\n" +" \n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" Powered by Odoo\n" +"
\n" +"
\n" +" " +msgstr "" + +#. module: portal_invitation_by_website +#: model_terms:ir.ui.view,arch_db:portal_invitation_by_website.portal_wizard_view_website +msgid "Apply Website" +msgstr "" + +#. module: portal_invitation_by_website +#: model:ir.model.fields,help:portal_invitation_by_website.field_portal_wizard__website_id +msgid "" +"Apply this website to all the contacts below. The invitation email URL will " +"match this website's domain. Leave empty to keep each contact's current " +"website." +msgstr "" + +#. module: portal_invitation_by_website +#: model:ir.model.fields,field_description:portal_invitation_by_website.field_ir_model_data__display_name +#: model:ir.model.fields,field_description:portal_invitation_by_website.field_portal_wizard__display_name +#: model:ir.model.fields,field_description:portal_invitation_by_website.field_portal_wizard_user__display_name +#: model:ir.model.fields,field_description:portal_invitation_by_website.field_res_users__display_name +msgid "Display Name" +msgstr "" + +#. module: portal_invitation_by_website +#: model:ir.model,name:portal_invitation_by_website.model_portal_wizard +msgid "Grant Portal Access" +msgstr "" + +#. module: portal_invitation_by_website +#: model:ir.model.fields,field_description:portal_invitation_by_website.field_ir_model_data__id +#: model:ir.model.fields,field_description:portal_invitation_by_website.field_portal_wizard__id +#: model:ir.model.fields,field_description:portal_invitation_by_website.field_portal_wizard_user__id +#: model:ir.model.fields,field_description:portal_invitation_by_website.field_res_users__id +msgid "ID" +msgstr "" + +#. module: portal_invitation_by_website +#: model:mail.template,description:portal_invitation_by_website.mail_template_portal_welcome_website +msgid "Invitation email using website name instead of company name" +msgstr "" + +#. module: portal_invitation_by_website +#: model:ir.model,name:portal_invitation_by_website.model_ir_model_data +msgid "Model Data" +msgstr "" + +#. module: portal_invitation_by_website +#: model:ir.model,name:portal_invitation_by_website.model_portal_wizard_user +msgid "Portal User Config" +msgstr "" + +#. module: portal_invitation_by_website +#: model:mail.template,name:portal_invitation_by_website.mail_template_portal_welcome_website +msgid "Portal: User Invite (Website)" +msgstr "" + +#. module: portal_invitation_by_website +#: model:ir.model,name:portal_invitation_by_website.model_res_users +msgid "User" +msgstr "" + +#. module: portal_invitation_by_website +#: model:ir.model.fields,field_description:portal_invitation_by_website.field_portal_wizard__website_id +#: model:ir.model.fields,field_description:portal_invitation_by_website.field_portal_wizard_user__website_id +msgid "Website" +msgstr "" + +#. module: portal_invitation_by_website +#: model:mail.template,subject:portal_invitation_by_website.mail_template_portal_welcome_website +msgid "Your account at {{ object.website_id.name or object.company_id.name }}" +msgstr "" diff --git a/portal_invitation_by_website/models/__init__.py b/portal_invitation_by_website/models/__init__.py new file mode 100644 index 0000000000..409f85f8ec --- /dev/null +++ b/portal_invitation_by_website/models/__init__.py @@ -0,0 +1 @@ +from . import ir_model_data, res_users diff --git a/portal_invitation_by_website/models/ir_model_data.py b/portal_invitation_by_website/models/ir_model_data.py new file mode 100644 index 0000000000..1c9052921f --- /dev/null +++ b/portal_invitation_by_website/models/ir_model_data.py @@ -0,0 +1,18 @@ +from odoo import api, models + +PORTAL_WELCOME_XMLID = "auth_signup.portal_set_password_email" +WEBSITE_WELCOME_XMLID = ( + "portal_invitation_by_website.mail_template_portal_welcome_website" +) + + +class IrModelData(models.Model): + _inherit = "ir.model.data" + + @api.model + def _xmlid_to_res_model_res_id(self, xmlid, raise_if_not_found=False): + if xmlid == PORTAL_WELCOME_XMLID and self.env.context.get( + "portal_invitation_website_id" + ): + xmlid = WEBSITE_WELCOME_XMLID + return super()._xmlid_to_res_model_res_id(xmlid, raise_if_not_found) diff --git a/portal_invitation_by_website/models/res_users.py b/portal_invitation_by_website/models/res_users.py new file mode 100644 index 0000000000..43cf90a087 --- /dev/null +++ b/portal_invitation_by_website/models/res_users.py @@ -0,0 +1,11 @@ +from odoo import models + + +class ResUsers(models.Model): + _inherit = "res.users" + + def _create_user_from_template(self, values): + website_id = self.env.context.get("portal_invitation_website_id") + if website_id: + values["website_id"] = website_id + return super()._create_user_from_template(values) diff --git a/portal_invitation_by_website/pyproject.toml b/portal_invitation_by_website/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/portal_invitation_by_website/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/portal_invitation_by_website/readme/CONTRIBUTORS.md b/portal_invitation_by_website/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..689a1cdc4c --- /dev/null +++ b/portal_invitation_by_website/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- [Tecnativa](https://www.tecnativa.com): + - Cristina Hidalgo diff --git a/portal_invitation_by_website/readme/DESCRIPTION.md b/portal_invitation_by_website/readme/DESCRIPTION.md new file mode 100644 index 0000000000..b3478aca29 --- /dev/null +++ b/portal_invitation_by_website/readme/DESCRIPTION.md @@ -0,0 +1,7 @@ +This module extends the portal invitation wizard to allow restricting portal +users to a specific website in multi-website environments. + +When inviting contacts as portal users from the backend, you can now select a +website at the wizard level (applied to all contacts) or override it +per-contact. The invitation email URL will automatically use the selected +website's domain, ensuring the signup link directs the user to the correct site. diff --git a/portal_invitation_by_website/readme/USAGE.md b/portal_invitation_by_website/readme/USAGE.md new file mode 100644 index 0000000000..7548761456 --- /dev/null +++ b/portal_invitation_by_website/readme/USAGE.md @@ -0,0 +1,11 @@ +1. Go to **Contacts** and select one or more contacts. +2. Open the action menu and click **Grant Portal Access**. +3. In the wizard, select a **Website** to restrict access to that site. + - The website applies to all contacts in the list. + - You can override the website per contact using the **Website** column. +4. Click **Grant Access** for each contact or use the batch action. + +The invitation email will contain a signup URL pointing to the selected +website's domain. If the website has **Specific User Accounts** enabled +(`Website > Configuration > Settings`), the portal user will only be able to +log in from that website. diff --git a/portal_invitation_by_website/static/description/icon.png b/portal_invitation_by_website/static/description/icon.png new file mode 100644 index 0000000000..1dcc49c24f Binary files /dev/null and b/portal_invitation_by_website/static/description/icon.png differ diff --git a/portal_invitation_by_website/static/description/index.html b/portal_invitation_by_website/static/description/index.html new file mode 100644 index 0000000000..7c6ef18c09 --- /dev/null +++ b/portal_invitation_by_website/static/description/index.html @@ -0,0 +1,457 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Portal Invitation by Website

+ +

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

+

This module extends the portal invitation wizard to allow restricting +portal users to a specific website in multi-website environments.

+

When inviting contacts as portal users from the backend, you can now +select a website at the wizard level (applied to all contacts) or +override it per-contact. The invitation email URL will automatically use +the selected website’s domain, ensuring the signup link directs the user +to the correct site.

+

Table of contents

+ +
+

Usage

+
    +
  1. Go to Contacts and select one or more contacts.
  2. +
  3. Open the action menu and click Grant Portal Access.
  4. +
  5. In the wizard, select a Website to restrict access to that site.
      +
    • The website applies to all contacts in the list.
    • +
    • You can override the website per contact using the Website +column.
    • +
    +
  6. +
  7. Click Grant Access for each contact or use the batch action.
  8. +
+

The invitation email will contain a signup URL pointing to the selected +website’s domain. If the website has Specific User Accounts enabled +(Website > Configuration > Settings), the portal user will only be +able to log in from that website.

+
+
+

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

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+ +
+
+

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.

+

This module is part of the OCA/website project on GitHub.

+

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

+
+
+
+
+ + diff --git a/portal_invitation_by_website/tests/__init__.py b/portal_invitation_by_website/tests/__init__.py new file mode 100644 index 0000000000..c121601f09 --- /dev/null +++ b/portal_invitation_by_website/tests/__init__.py @@ -0,0 +1 @@ +from . import test_portal_wizard diff --git a/portal_invitation_by_website/tests/test_portal_wizard.py b/portal_invitation_by_website/tests/test_portal_wizard.py new file mode 100644 index 0000000000..c4c7706302 --- /dev/null +++ b/portal_invitation_by_website/tests/test_portal_wizard.py @@ -0,0 +1,90 @@ +from unittest.mock import patch + +from odoo.tests.common import TransactionCase, users + +from odoo.addons.mail.tests.common import mail_new_test_user + + +class TestPortalWizardWebsite(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.website_1 = cls.env.ref("website.default_website") + cls.website_2 = cls.env["website"].create( + { + "name": "Website 2", + "domain": "https://www.website2.example.com", + "specific_user_account": True, + } + ) + cls.partner = cls.env["res.partner"].create( + { + "name": "Portal Test Partner", + "email": "portal_test@example.com", + } + ) + cls.partner_with_website = cls.env["res.partner"].create( + { + "name": "Partner With Website", + "email": "partner_website@example.com", + "website_id": cls.website_1.id, + } + ) + + def _open_wizard(self, partners): + return ( + self.env["portal.wizard"].with_context(active_ids=partners.ids).create({}) + ) + + @users("admin") + def test_website_id_propagates_from_wizard(self): + """website_id set at wizard level flows to all portal.wizard.user lines.""" + wizard = self._open_wizard(self.partner) + wizard.website_id = self.website_2 + self.assertEqual(wizard.user_ids.website_id, self.website_2) + + @users("admin") + def test_website_id_defaults_from_partner(self): + """When wizard has no website_id, each line defaults to its partner's.""" + wizard = self._open_wizard(self.partner_with_website) + self.assertEqual(wizard.user_ids.website_id, self.website_1) + + @users("admin") + def test_grant_access_sets_partner_website(self): + """Granting portal access propagates website_id to the partner.""" + wizard = self._open_wizard(self.partner) + wizard.website_id = self.website_2 + wizard_user = wizard.user_ids + with patch.object(type(wizard_user), "_send_email", return_value=True): + wizard_user.action_grant_access() + self.assertEqual(self.partner.website_id, self.website_2) + + @users("admin") + def test_grant_access_user_website_id(self): + """Created portal user inherits website_id via partner's related field.""" + wizard = self._open_wizard(self.partner) + wizard.website_id = self.website_2 + wizard_user = wizard.user_ids + with patch.object(type(wizard_user), "_send_email", return_value=True): + wizard_user.action_grant_access() + portal_user = self.partner.with_context(active_test=False).user_ids + self.assertTrue(portal_user) + self.assertEqual(portal_user.website_id, self.website_2) + + @users("admin") + def test_invite_again_updates_website(self): + """Re-inviting an existing portal user updates its website_id.""" + portal_user = mail_new_test_user( + self.env, + name="Existing Portal", + login="existing_portal@example.com", + email="existing_portal@example.com", + groups="base.group_portal", + ) + wizard = self._open_wizard(portal_user.partner_id) + wizard.website_id = self.website_2 + wizard_user = wizard.user_ids + with patch.object(type(wizard_user), "_send_email", return_value=True): + wizard_user.action_invite_again() + self.assertEqual(portal_user.partner_id.website_id, self.website_2) + self.assertEqual(portal_user.website_id, self.website_2) diff --git a/portal_invitation_by_website/views/portal_wizard_views.xml b/portal_invitation_by_website/views/portal_wizard_views.xml new file mode 100644 index 0000000000..e3c640ab88 --- /dev/null +++ b/portal_invitation_by_website/views/portal_wizard_views.xml @@ -0,0 +1,37 @@ + + + + portal.wizard.website + portal.wizard + + + + + + + + + + + + + + +