2
votes

I want to search records of one2many field that depends on another fields.
here my code,

Parent class:

class SaleOrder(models.Model):
    _inherit = 'sale.order'

    customer_product_ids = fields.One2many('product.product',
                           compute='_get_partner_products')
    order_line = fields.One2many('sale.order.line', 'order_id')

Child class:

class SaleOrderLine(models.Model):
    _inherit = 'sale.order.line'

    order_id = fields.Many2one('sale.order')
    product_id = fields.Many2one('product.product')

View

 <record id="view_ata_sale_order_form_inherit" model="ir.ui.view">
        <field name="name">view.ata.sale.order.form.inherit</field>
        <field name="model">sale.order</field>
        <field name="inherit_id" ref="sale.view_order_form"/>
        <field name="arch" type="xml">
            <field name="partner_id" position="after">
                <field name="partner_channel_id" invisible="1"/>
                <field name="customer_product_ids"/>
            </field>
            <xpath expr="//tree/field[@name='product_id']" position="attributes">
                <attribute name="domain">[('id', 'in', [rec.id for rec in parent.customer_product_ids])]</attribute>
            </xpath>
        </field>
    </record>

By default, a customer can see all the products defined.
In my case, I need to filter the products depends on customer selected.
Each customer can have different list products or if they didn't categorize they can see all the products.

I tried the code above but got error:

Uncaught Error: Expected "]", got "(name)"

I guess the error come from this code:

<attribute name="domain">[('id', 'in', [rec.id for rec in parent.partner_product_ids])]</attribute>

my question,
is it possible to do python loop comprehension like the code above (within view)?

Thank you.

3

3 Answers

5
votes

In your case you need to use onchange and return dynamic domain to your one2many field

you should have some thing like this:

@api.onchange('partner')
def onchange_partner(self):
    ids=search for products that have this partner
    then return some thing like this {'domain': {'Many2one or One2many': [('id', 'in', ids)}}

i will not write the code for you,so you must search for the onchange and apply it.You can find some info here .

1
votes

You can't put such code in there. I'd do it in a different way:

Change the product model adding its customer

class Product(models.Model):
    _inherit = 'product.product'

    parent_id = fields.Many2one('res.partner')

then the view can be changed much easier:

<attribute name="domain">[('partner_id', '=', partner_id)]</attribute>

or

<attribute name="domain">[('partner_id', '=', parent.partner_id)]</attribute>

(depending on where is your product_id field...

1
votes

Hello Mostafa and Alessandro Ruffolo

Thank very much to answering my question :) (# sorry for the late response)

I've tried the solution from Mostafa Mohamed, but it's not affected the products list (they keep displaying all the products).
What should onchange methods do and return?

Here my code,

@api.multi
def onchange_partner_id(self, part):
    res = super(SaleOrder, self).onchange_partner_id(part)
    domain = [('active', '=', True), ('sale_ok', '=', True)]
    if part:
        partner = self.env['res.partner'].browse(part)
        if partner and partner.sales_channel_id:
            domain.append(('sales_channel_ids', '=',
                           partner.sales_channel_id.id))
    product_ids = self.env['product.product'].search(domain)
    res.update(domain={
        'order_line.product_id': ['id', 'in', [rec.id for rec in product_ids]]
    })
    return res  

I've tried another solution, so I override search_name and search method within product.product model and it's works.

here my code,
1) inherit sale_view.xml

<xpath expr="//tree/field[@name='product_id']" position="attributes">
    <attribute name="domain">[
        ('sales_channel_ids', '=', parent.partner_channel_id),
        ('sale_ok', '=', True),
        ('active', '=', True)
    ]</attribute>
    <attribute name="context">{
        'partner_channel_id': parent.partner_channel_id,
        'partner_id': parent.partner_id,
        'quantity': product_uom_qty,
        'pricelist': parent.pricelist_id,
        'uom': product_uom,
        'company_id': parent.company_id
    }</attribute>
 </xpath>   

and the override method
2) search_name method:

@api.model
def name_search(self, name, args=None, operator='ilike', limit=100):
    if 'partner_channel_id' in self._context:
        target_domain = findDomain(args, 'sales_channel_ids')
        if len(target_domain) == 1:
            idx = target_domain.keys()[0]
            domain = target_domain.values()[0]
            if False in domain:
                args.pop(idx)
    return super(ProductProduct, self).name_search(name=name,
                                               args=args,
                                               operator=operator,
                                               limit=limit)   

3) search method:

@api.model
def search(self, args, offset=0, limit=None, order=None, count=False):
    if 'partner_channel_id' in self._context:
        target_domain = findDomain(args, 'sales_channel_ids')
        if len(target_domain) == 1:
            idx = target_domain.keys()[0]
            domain = target_domain.values()[0]
            if False in domain:
                args.pop(idx)
    return super(ProductProduct, self).search(args=args,
                                          offset=offset,
                                          limit=limit,
                                          order=order,
                                          count=count)

What I try to do here is when they detected 'partner_channel_id' in context and domain like this ['sales_channel_ids', '=', False], I removed that domain and keep the rest (customer doesn't have channel can see all the products, no filtering products from them).