portal_wizard_user_one2many
The Grant Access dialog is one of the few places in Odoo where a double click can send two invitation emails. portal_wizard_user_one2many is the twenty-line widget that stops it.
| Technical name | portal_wizard_user_one2many |
|---|---|
| Field types | one2many |
| Views | form, always with an inline list subview |
| Module | portal, installed by default with almost every Odoo app |
| Used in core | 1 occurrence, the Grant Portal Access wizard in portal |
| Versions | Odoo 20.0, Odoo 19.0, Odoo 18.0, Odoo 17.0, Odoo 16.0 |
| No-code setup | No. It is a view XML widget and only makes sense on a wizard that runs long server actions per row |
| Alternatives | one2many, many2many, list_activity |
What the portal wizard list field does
What this means for your team
Supported options in Odoo 19
| Option | Type | What it does |
|---|---|---|
editable | string (list attribute) | Set on the embedded <list> element, not on the widget. The core wizard uses bottom so the email column can be corrected inline. |
create | boolean (list attribute) | Set on the embedded <list> element. Core sets it to false: rows come from the contacts you selected, not from typing.(default: true) |
delete | boolean (list attribute) | Set on the embedded <list> element. Core sets it to false for the same reason.(default: true) |
Nothing here changes the guard. The re-entrancy protection and the blocked status icons are hardcoded in the controller subclass, so no XML option turns them off. If you need action_refresh_modal to actually run, it has to be renamed in the view or the controller has to be patched in JavaScript.
Working examples
Twenty lines, two hooks, one flag
Version compatibility
| Version | Status | Notes |
|---|---|---|
| Odoo 20.0 | In development | Not released. Byte-identical to Odoo 19 on the development branch. |
| Odoo 19.0 | Verified | Verified against the shipped source. Same controller and same guard. |
| Odoo 18.0 | Verified | Identical behavior. No XML change needed. |
| Odoo 17.0 | Verified | Identical behavior. This is where the registration became a descriptor object. |
| Odoo 16.0 | Verified | Same guard, but the component class was registered directly instead of a descriptor. |
Upgrade note. No XML change has ever been needed for this widget. Between Odoo 16 and Odoo 17 the registration switched from registering the component class directly to registering a descriptor object, which matters only to custom JavaScript that imported it. The controller itself has not changed since Odoo 16.
What is changing in Odoo 20
Common problems and fixes
| Symptom | Cause and fix |
|---|---|
| Clicking the green check or red cross does nothing | Intended. The controller blocks every button named action_refresh_modal. Treat them as status indicators. To refresh the state, edit the email in the row. |
| All buttons in the dialog stop responding | The in-flight flag was set and then a row save was rejected, so it was never cleared. Close and reopen the wizard. Fix the invalid row first, then run the action. |
| The email I typed was not saved | You clicked a status icon, which is aborted before the standard row save runs. Click elsewhere in the list, or press the real action button, which does save the row first. |
| Two invitations were sent anyway | The two clicks landed in different dialog sessions, or a custom view replaced the widget with a plain one2many. Confirm the field still carries widget="portal_wizard_user_one2many" in the inherited view. |
| Users can add rows to the list | An inherited view dropped create="false" from the embedded list. Restore create="false" and delete="false" on the <list> element. |
| Nothing happens on Grant Access for an internal user | Internal users are excluded; core renders a disabled button with an explanatory tooltip on those rows. Expected. Internal users already have portal-level access. |
Portal wizard list field vs the alternatives
| Widget | Best for | Key difference |
|---|---|---|
portal_wizard_user_one2many | Wizard lists whose row buttons run slow, irreversible server actions | Swaps the list controller to drop repeat clicks and to block the refresh-status button entirely |
| one2many | Any ordinary embedded list of child records | Standard controller, so nothing prevents a button from being clicked twice |
| many2many | Linking existing records rather than editing owned ones | Add and remove links instead of creating and deleting rows |
| list_activity | Showing the next action per row | Renders activity state in a column, unrelated to button safety |
Frequently asked questions
What does portal_wizard_user_one2many actually change?+
Why are the email status icons not clickable?+
Can I use this widget on my own wizard?+
Does it support any options?+
Will it change in Odoo 20?+
Do your wizards survive an impatient double click?
Row buttons that send mail, create users or call an external API are the quiet risk in most custom Odoo screens, and the default list controller does nothing to protect them. We review and harden that kind of workflow as part of Odoo customization work on 16 through 19.
Book a free consultation