I'm working on Odoo 18 Enterprise and I'm struggling to filter the analytic accounts displayed in the analytic_distribution widget on purchase order lines.
Context
We have a custom model called global.budget that manages the global budget of a project. It has a one2many field forecast_budget_ids referencing another model forecast.budget, which contains:
- analytic_account_id: the analytic account
- budget_amount: the budgeted amount (monetary)
On the purchase.order model, we added a Many2one field overall_budget_id pointing to global.budget.
Goal
When a user opens the analytic distribution wizard on a purchase order line, in the "Analytic Account" column, we want to display only the analytic accounts that have a budget_amount > 0 in the linked global budget.
What we tried
1-Computed field on purchase.order to get allowed analytic account IDs:
allowed_analytic_account_ids = fields.Many2many(
'account.analytic.account',
compute='_compute_allowed_analytic_account_ids'
)
@api.depends(
'overall_budget_id',
'overall_budget_id.forecast_budget_ids',
'overall_budget_id.forecast_budget_ids.analytic_account_id',
'overall_budget_id.forecast_budget_ids.budget_amount',
)
def _compute_allowed_analytic_account_ids(self):
for order in self:
if order.overall_budget_id:
lines = order.overall_budget_id.forecast_budget_ids.filtered(
lambda l: l.budget_amount > 0 and l.analytic_account_id
)
order.allowed_analytic_account_ids = lines.mapped('analytic_account_id')
else:
order.allowed_analytic_account_ids = False
- Related field on purchase.order to expose the allowed IDs on the line level:
allowed_analytic_account_ids = fields.Many2many(
'account.analytic.account',
related='order_id.allowed_analytic_account_ids',
store=False,
)
- Injecting context in the XML view on the analytic_distribution field:
{
'allowed_analytic_account_ids': parent.allowed_analytic_account_ids
}
- Overriding name_search and search on account.analytic.account to apply the filter from context:
@api.model
def search(self, domain, offset=0, limit=None, order=None):
allowed_ids = self.env.context.get('allowed_analytic_account_ids')
if allowed_ids:
domain = [('id', 'in', allowed_ids)] + list(domain)
print("Search domain:", domain)
return super().search(domain, offset=offset, limit=limit, order=order)
@api.model
def name_search(self, name='', args=None, operator='ilike', limit=100):
args = args or []
allowed_ids = self.env.context.get('allowed_analytic_account_ids')
if allowed_ids:
args = [('id', 'in', allowed_ids)] + args
print(args)
return super().name_search(
name=name, args=args, operator=operator, limit=limit
)
Problem
We verified that the computed field allowed_analytic_account_ids on the purchase order is correctly populated , thanks to the odoo shell — it does contain the expected analytic account IDs (only those with budget_amount > 0). So the data side is working fine. However, the print statements inside search and name_search are never printed when we open the analytic distribution wizard. This tells us two things: The widget is not going through these Python methods at all, OR The context we set in the XML view (allowed_analytic_account_ids) is not being forwarded to the internal RPC calls made by the widget. In other words, the IDs are computed correctly on the purchase order, but they never seem to reach the analytic_distribution widget. The analytic accounts are therefore not filtered as expected.
Questions
- Which Python method does the analytic_distribution widget actually call in Odoo 18 Enterprise to load the analytic accounts in each column of the wizard?
- Is the context from the XML field properly forwarded to the widget's internal RPC calls?
- What is the correct way to inject a domain filter on analytic accounts inside this widget?
Any help or pointer to the right method/hook to override would be greatly appreciated!
Thanks in advance.