Hi everyone,
I'm developing a custom app in Odoo 18 that opens a client-side frontend (ir.actions.client) after user authentication. The app has its own menu root and submenus.
Here’s how it works:
- If the user has a valid token → directly open the app
- If not → open a login wizard
- After successful login → call _action_open_documents_list() which returns an ir.actions.client
The issue:
When the user is already logged in, clicking the menu opens the app correctly, and all menu items remain visible.
But when opening via the login wizard (i.e., first-time login), the app opens successfully, but all Odoo menu items disappear from the top bar (only the app switcher and user menu remain).
This seems to be related to the `app...
Minimal reproducible code
XML – menus & server actions
<odoo>
<menuitem id="didox_menu_root" name="Didox" sequence="10"
web_icon="didox,static/description/didox-logo.png"/>
<!-- server actions that call the backend method -->
<record id="action_didox_incoming_server" model="ir.actions.server">
<field name="name">Incoming</field>
<field name="model_id" ref="base.model_res_users"/>
<field name="state">code</field>
<field name="code">
action = env["didox.backend"].sudo().action_open_app(owner=0)
</field>
</record>
<!-- … other server actions (Outgoing, Draft, …) … -->
<menuitem id="didox_menu_documents" name="Documents"
parent="didox_menu_root" sequence="1"/>
<menuitem id="didox_menu_incoming" name="Incoming"
parent="didox_menu_documents" action="action_didox_incoming_server" sequence="1"/>
<!-- … other sub-menus … -->
</odoo>
Python – backend helper
from datetime import datetime, timedelta, timezone
from odoo import fields, models, _
class DidoxBackend(models.Model):
_name = "didox.backend"
_description = "Didox backend helpers"
def action_open_app(self, owner: int = 0, status: int = None):
user = self.env.user
now = datetime.now(timezone.utc)
if user.didox_user_token and user.didox_user_token_exp:
exp = fields.Datetime.from_string(user.didox_user_token_exp).replace(tzinfo=timezone.utc)
if exp > now:
return self._action_open_documents_list(owner=owner, status=status)
# no valid token → open login wizard
return {
"type": "ir.actions.act_window",
"name": _("Login to Didox"),
"res_model": "didox.login.wizard",
"view_mode": "form",
"target": "new",
}
def _action_open_documents_list(self, owner: int, status: int = None):
return {
"type": "ir.actions.client",
"tag": "didox_client_page",
"target": "current",
"params": {"owner": owner, "status": status},
}
Wizard – login action (called after successful login)
def action_login(self):
self.ensure_one()
# … login logic, token saved on res.users …
self.env.user.write({
"didox_user_token": token,
"didox_user_token_exp": fields.Datetime.to_string(
datetime.now(timezone.utc) + timedelta(minutes=360)
),
})
return {
"type": "ir.actions.client",
"tag": "didox_client_page",
"target": "current",
"params": {"owner": 0},
}
Your example source is missing way to many details to have it run as an example. I.e. what's didox_client_page?