Ahmed Abd El Latif
Ahmed Abd El Latif

Reputation: 233

Odoo: How to set a dynamic domain to a many2many field

I want to change the retrieved set of values of a many2many field according to a many2one field onchange function, it worked well with another many2one field, but doesn't seem to filter the outcome on a many2many field my code is as follows

class CustomPurchase(models.Model):
    _name = 'custom.purchase'
    _description = 'Purchase Record'

    supplier_id = fields.Many2one('custom.supplier', string='Supplier', required=True)
    product_ids = fields.Many2many('custom.supply.line', string='Purchase Lines', required=True)

    @api.onchange('supplier_id')
    def onchange_supplier(self):
        selected_lines = []
        if self.supplier_id:
            for rec in self:
                selected_lines = rec.env['custom.supply.line'].search([('supplier_id', '=', rec.supplier_id.id)])
                domain = {'product_ids': [('id', '=', selected_lines.id)]}
            return {'domain': domain, 'value': {'selected_lines': []}}

Expected behavior is to have just the items related to the supplier_id many2one field

Produced behavior is all the items are retrieved

Edit: I've noticed that i when i remove widget="section_and_note_one2many" the domain works perfectly, yet the tree view can't be edited within the same form, even with editable="bottom"

Upvotes: 3

Views: 4718

Answers (2)

Ahrimann Steiner
Ahrimann Steiner

Reputation: 1314

For more complex cases, to ensure that the domain is correctly set onLoad (even without any onChange event): it's better to use a Field.Binary with a def_compute to get the allowed ids: for instance in the module account: to restrict the domain of tags on countries coming from different models:

In the file account_tax.py:

class AccountTaxRepartitionLine(models.Model):
    _name = "account.tax.repartition.line"

    tag_ids = fields.Many2many(string="Tax Grids", comodel_name='account.account.tag', domain=[('applicability', '=', 'taxes')], copy=True, ondelete='restrict')
    tag_ids_domain = fields.Binary(string="tag domain", help="Dynamic domain used for the tag that can be set on tax", compute="_compute_tag_ids_domain")

    @api.depends('company_id.multi_vat_foreign_country_ids', 'company_id.account_fiscal_country_id')
    def _compute_tag_ids_domain(self):
        for rep_line in self:
            allowed_country_ids = (False, rep_line.company_id.account_fiscal_country_id.id, *rep_line.company_id.multi_vat_foreign_country_ids.ids,)
            rep_line.tag_ids_domain = [('applicability', '=', 'taxes'), ('country_id', 'in', allowed_country_ids)]


In the file account_tax_views.xml:

<record id="tax_repartition_line_tree" model="ir.ui.view">
            <field name="name">account.tax.repartition.line.tree</field>
            <field name="model">account.tax.repartition.line</field>
            <field name="arch" type="xml">
                <tree editable="bottom" create="1" delete="1">
                    <!-- ... -->
                    <field name="tag_ids"
                           widget="many2many_tags"
                           options="{'no_create': True}"
                           domain="tag_ids_domain"/>
                    
                    <field name="tag_ids_domain" invisible="1"/>
                </tree>
            </field>
        </record>



Upvotes: 0

Uncle Dev
Uncle Dev

Reputation: 11

You can add check using supplier field directly inside domain.

Code:

    @api.onchange('supplier_id')
    def onchange_supplier(self):
        domain = {'product_ids': []}
        for rec in self:
            if rec.supplier_id:
                domain = {'product_ids': [('supplier_id', '=', rec.supplier_id.id)]}
        return {'domain': domain}

UPDATE: Try to implement this as same as in /addons/mrp/models/mrp_bom.py on attribute_value_ids. [Version:12]

Upvotes: 1

Related Questions