Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions portal_ux/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
.. |company| replace:: ADHOC SA

.. |company_logo| image:: https://raw.githubusercontent.com/ingadhoc/maintainer-tools/master/resources/adhoc-logo.png
:alt: ADHOC SA
:target: https://www.adhoc.com.ar

.. |icon| image:: https://raw.githubusercontent.com/ingadhoc/maintainer-tools/master/resources/adhoc-icon.png

.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png
:target: https://www.gnu.org/licenses/agpl
:alt: License: AGPL-3

=========
Portal UX
=========

Usability improvements for the portal access wizard.

* Adds a **"Grant Access to All"** button to the portal access wizard
(``portal.wizard``), granting portal access to every contact loaded in the
wizard in a single pass.
* Applies only to contacts with a valid email (``email_state == 'ok'``) that
don't already have portal access and are not internal users
(``is_portal`` / ``is_internal``); the rest are skipped without raising an
error.
* Reuses the native per-row logic (``action_grant_access``) of
``portal.wizard.user``, so any override of that method added by other
modules keeps applying.


Installation
============

Only install the module.

Configuration
=============

There is nothing to configure.

Usage
=====

#. Go to **Contacts**, select one or more contacts and run the **"Grant
portal access"** action (``portal.wizard``).
#. In the wizard, click **"Grant Access to All"**.
#. Every listed contact with a valid, unused email gets portal access in a
single operation.

.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: http://runbot.adhoc.com.ar/

Bug Tracker
===========

Bugs are tracked on `GitHub Issues
<https://github.com/ingadhoc/miscellaneous/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.

Credits
=======

Images
------

* |company| |icon|

Contributors
------------

Maintainer
----------

|company_logo|

This module is maintained by the |company|.

To contribute to this module, please visit https://www.adhoc.com.ar.
5 changes: 5 additions & 0 deletions portal_ux/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from . import wizards
41 changes: 41 additions & 0 deletions portal_ux/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
##############################################################################
#
# Copyright (C) 2026 ADHOC SA (http://www.adhoc.com.ar)
# All Rights Reserved.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
"name": "Portal UX",
"version": "19.0.1.0.0",
"category": "Tools",
"sequence": 14,
"summary": "",
"author": "ADHOC SA",
"website": "www.adhoc.com.ar",
"license": "AGPL-3",
"images": [],
"depends": [
"portal",
],
"data": [
"wizards/portal_wizard_views.xml",
],
"demo": [],
"test": [],
"installable": True,
"auto_install": False,
"application": False,
}
5 changes: 5 additions & 0 deletions portal_ux/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from . import test_portal_wizard
46 changes: 46 additions & 0 deletions portal_ux/tests/test_portal_wizard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from odoo.tests import TransactionCase, tagged


@tagged("-at_install", "post_install")
class TestPortalWizard(TransactionCase):
def test_action_grant_access_all(self):
partner_model = self.env["res.partner"].sudo()
valid_partner_1 = partner_model.create({"name": "Valid Contact 1", "email": "valid1@test.example.com"})
valid_partner_2 = partner_model.create({"name": "Valid Contact 2", "email": "valid2@test.example.com"})
invalid_partner = partner_model.create({"name": "Invalid Contact", "email": "not-an-email"})

partners = valid_partner_1 + valid_partner_2 + invalid_partner
wizard = self.env["portal.wizard"].with_context(active_ids=partners.ids).create({})
self.assertEqual(len(wizard.user_ids), 3)

wizard.action_grant_access_all()

group_portal = self.env.ref("base.group_portal")
for partner in (valid_partner_1, valid_partner_2):
self.assertTrue(partner.user_ids, "A portal user should have been created")
self.assertIn(group_portal, partner.user_ids.group_ids)

self.assertFalse(
invalid_partner.user_ids,
"No user should be created for a contact with an invalid email",
)

def test_action_grant_access_all_skips_existing_portal_user(self):
partner_model = self.env["res.partner"].sudo()
already_portal_partner = partner_model.create(
{"name": "Already Portal Contact", "email": "already@test.example.com"}
)
wizard = self.env["portal.wizard"].with_context(active_ids=already_portal_partner.ids).create({})
wizard.user_ids.action_grant_access()
user = already_portal_partner.user_ids
self.assertTrue(user, "Precondition: partner should already have a portal user")

# Re-open the wizard: the existing portal user must be skipped, not re-processed.
wizard_2 = self.env["portal.wizard"].with_context(active_ids=already_portal_partner.ids).create({})
wizard_2.action_grant_access_all()

self.assertEqual(already_portal_partner.user_ids, user)
5 changes: 5 additions & 0 deletions portal_ux/wizards/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from . import portal_wizard
15 changes: 15 additions & 0 deletions portal_ux/wizards/portal_wizard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from odoo import models


class PortalWizard(models.TransientModel):
_inherit = "portal.wizard"

def action_grant_access_all(self):
for wizard_user in self.user_ids:
if not wizard_user.is_portal and not wizard_user.is_internal and wizard_user.email_state == "ok":
wizard_user.action_grant_access()
return self._action_open_modal()
14 changes: 14 additions & 0 deletions portal_ux/wizards/portal_wizard_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<odoo>
<record id="wizard_view" model="ir.ui.view">
<field name="name">portal.wizard.form (in portal_ux)</field>
<field name="model">portal.wizard</field>
<field name="inherit_id" ref="portal.wizard_view"/>
<field name="arch" type="xml">
<field name="welcome_message" position="after">
<button string="Grant Access to All" name="action_grant_access_all"
type="object" class="btn-secondary"
help="This button will grant access to all contacts with a valid email address."/>
</field>
</field>
</record>
</odoo>
Loading