In Odoo9 I need a dynamic domain that depends on many2one
field on a wizard.
Using various examples I made it work, but the filtered values are always valid for previous option. Or they are valid if I choose an (invalid) option from the filtered domain.
Details:
At the end of opportunity workflow a salesman is supposed to evaluate opportunity where s/he chooses the probability of success. There were several levels to be chosen in special wizard ("100% sure", "not sure", "maybe" etc). I used fields.Selection
for this. Then I introduced a new opportunity type (retention) where only 100% and 0% should be available. So I created a new model evaluation_option
, replaced fields.Selection
with fields.Many2one
and out of these values I filter out allowed options (with retention=True
).
This is my wizard model:
class evaluation_wizard(models.TransientModel):
_name = 'evaluation.wizard'
_description = 'Wizard to evaluate opportunity'
lead_id = fields.Many2one('crm.lead')
evaluation_option_id = fields.Many2one('evaluation.option')
def get_object(self, model, fieldname):
ids = self._context.get(fieldname)
if ids is None:
ids = self._context.get('default_' + fieldname)
return self.env[model].browse(ids)
@api.onchange('lead_id')
def _onchange_lead_id(self):
# I check the context to get lead_id
lead_id = self.lead_id if self else self.get_object('crm.lead', 'lead_id')
dom = [('retention', '=', True)] if lead_id.retention else []
return {'domain': {'evaluation_option_id': dom}}
and this is actual wizard
<record id="evaluation_wizard_view" model="ir.ui.view">
<field name="name">evaluation.wizard.view</field>
<field name="model">evaluation.wizard</field>
<field name="arch" type="xml">
<form string="Evaluate opportunity">
<sheet class="row">
<group>
<group>
<field name="lead_id" invisible="False"/>
<field name="evaluation_option_id" required="True"
create="False" edit="False" widget="radio"
/>
</group>
</group>
<footer>
<button name="evaluate"
type="object"
string="Confirm"
class="oe_highlight"
context="{'lead_id': default_lead_id,
'active_id': default_lead_id,
'evaluation_option_id': evaluation_option_id}"/>
</footer>
</sheet>
</form>
</field>
</record>
I made an onchange method for dynamic changing of the domain, shown above. I tried also to compute domain like this: evaluation_option_id = fields.Many2one('evaluation.option', domain=_compute_domain)
where compute_domain
was the same method as for onchange but decorated with api.depends
. None of the methods worked as expected.
I use transient model with values (e.g. lead_id
) prefilled with default values (default_lead_id
) via context on button.
Whatever I try, when I make domain actually work it filters out the values, but always valid for previous selection. It means if I choose a retention opportunity I get all the options, if I then choose normal opportunity I get the retention options. If the next one is regular opportunity, the options are correct. However, if I choose retention opportunity (and invalid options are shown) and then I pick an invalid option, the invalid options would filter out suddenly. I am not sure, but it seems to me that the same problem is referred here: domain filter for many2one fields in odoo? in the last comment of accepted answer.
Can you see an obvious mistake or do you know another way how to dynamically change domain?
-- Edit:
I eventually managed to make it work. I do not remember what exactly I have done a year ago but the comparison between the old version and current version of code shows this:
1) I updated get_object method to get lead_id directly from the form and then if not successful, try dig it from the context.
def get_object(self, model, fieldname):
value = getattr(self, fieldname, None)
if value is not None:
return value
ids = self._context.get(fieldname, None)
if ids is None:
ids = self._context.get('default_' + fieldname)
ids = [] if ids is None else ids
return self.env[model].browse(ids)
@api.onchange('lead_id')
def _onchange_lead_id(self):
lead_id = self.get_object('crm.lead', 'lead_id')
dom = [('retention', '=', True)] if lead_id.is_retention_opp else []
return {'domain': {'evaluation_option_id': dom}}
2) the other change is in xml - readonly lead_id
(so that it is only called once when rendering the wizard) and removed radio widget from evaluation_option_id
:
<group>
<field name="lead_id" invisible="True" readonly="True"/>
<field name="evaluation_option_id" required="True"
options="{'no_create': True}"/>
</group>
Hopefully this might help someone.