This question has been flagged
3 Replies
5851 Views

Hi All,

I am trying to write a custom module that allows products to only be purchased by a specific customer. I added a customer field to the Products form, but I don't know how to compare that to the customer field in a Sales Order. I assume that it is going to be modifying the search() function in product.product but I don't know how to compare the two fields. Can anyone help? Thanks!

 

prakash - this is what my .xml file contains now, is this correct?

 

    <record id="view_res_sale_line_form1" model="ir.ui.view">

      <field name="model">sale.order</field>

      <field name="name">sale.order.line.form.inherit</field>

      <field name="inherit_id" ref="sale.view_order_form"/>

      <field name="arch" type="xml">

        <xpath expr="//field[@name='product_id']" position="replace">

           <field name="product_id" domain="[('id','in',parent.custproduct_id)]"/>

        </xpath>

        <xpath expr="//tree/field[@name='product_id']" position="after">

             <field name="custproduct_id" invisible="1"/>

        </xpath>

      </field>

    </record>

 

    <record id="view_res_sale_cust_domain" model="ir.ui.view">

      <field name="name">res.sale.cust.domain</field>

      <field name="inherit_id" ref="sale.view_order_line_tree"/>

      <field name="model">sale.order.line</field>

      <field name="arch" type="xml">

         <xpath expr="//tree/field[@name='name']">

             <field name="product_id" domain="[('id','in',parent.custproduct_id)]" />

        <xpath expr="//tree//field[@name='product_id']" position="after">

             <field name="custproduct_id" invisible="1"/>

        </xpath>

 

        </xpath>

      </field>

    </record>

Avatar
Discard
Best Answer

Assumption here: You are making a many2one field from the product.product to your res.partner object? If so, on the sale order you will need to reach a level up.

When creating new sale order lines, the domain on the product field should have something to do with the order_id.partner_id on the line itself. The line is connected to the order by means of an order_id. 

If that id is unavailable to you at the time of creating, you can always check the on_change method for the product on sale.order.line. This will give you a clue as to how the order line will get the right price (calculating in the pricelist on the sale order). 

 

If this does not help you, please post your code thus far and we will see what can be done.

Avatar
Discard
Author

Hi Ludo, thanks for the help. I posted some code below that may help us figure this out.

Best Answer

In Sale Order added field  customer product ID dyamically based on onchange customer.

class sale_order(osv.osv):
    _inherit = "sale.order"
    
    _columns = {        
        'custproduct_id': fields.char('Customer Product', size=64),
    }
    
    def onchange_partner_id(self, cr, uid, ids, part, context=None):
        res = super(sale_order, self).onchange_partner_id(cr, uid, ids, part, context=context)
        if part:
            product_obj = self.pool.get('product.product')
            matching_cust_ids = product_obj.search(cr, uid, [('x_cust_name','=',part)])            
            res['value'].update({'custproduct_id': matching_cust_ids})            
        return res
        
sale_order()

In Sale order line Form/Tree view inherit to add domain

 <field name="product_id" domain="[('id','in',parent.custproduct_id)]"/>

Avatar
Discard
Author

Hi prakash, I read that link and attempted to write some code to fix mine, but it didn't work. I edited my answer with the new code, if you could take a second to check it out I would really appreciate it.

Hi Alex, I updated code please check the same. sale order new field created and stored customer product ID dynamically. And sale order line domain conditions added.

Author

Hi prakash, thanks for your help, as always. I added the code as above, but am confused as to where to add the domain tag, since there are lots of potential fields in the Sales Order module. Do I need to xpath to it? I put it under "sale.view_order_form" and under "sale.view_order_line_tree", but to no avail. Put my code under Edit 2 above if you get a chance to look at it. Thanks again!

yes using xpath and replace tag to add the domain custom module. After replace tag copy the original product_id field with onchange and context additional add the domain. In another way for testing purpose Activate the developer Mode and Edit the form view and add domain.

Author

Unfortunately I am still struggling to get this working. I keep getting "Error: KeyError: 'custproduct_id'". I have a few questions: 1) Does adding the on change_partner_id() function as above override the existing one in sale/sale.py? Or do they both get run? Should I copy/paste the contents of the function in sale.py, or just enter it exactly as you did? 2) When using xpath to overwrite the "product_id" field, should I be replacing the existing product_id? As <xpath expr="//field[@name='product_id']" position="replace">? Also, is that the correct xpath? I can't find a good explanation of how those paths work. Thanks again for you help, I feel like I am so close to figuring this out.

Hi Alex, Add sale order form using xpath and after tag field name="custproduct_id" invisible="1" to fix KeyError.

Author

Hi prakash, I tried to do as you said, but am still getting KeyErrors when I add the domain lines to 'Edit FormView' from Developer Mode. I put my .xml code in the original question if you could take a look at it I'd appreciate it. Also do you have any resources for learning how xpath works? The documentation doesn't appear to have much.

Hi Alex, Document to override xml file https://doc.odoo.com/v6.0/developer/2_6_views_events/views/view_inheritence/

Hi Alex, please see the link https://www.odoo.com/forum/help-1/question/onchange-return-domain-for-one2many-product-id-field-60654 I posted new question based on this topic.

Author Best Answer

EDIT: Added my own code written after prakash's comment.

Here is the code I used to put the customer name on the product form, like you said, it's a many2one on product.product:

class ec_products(osv.Model):

    _inherit = 'product.product'

    _columns = {

       'x_cust_name': fields.many2one('res.partner', 'Customer')

       }

 

I added the entirety of product_id_change() from sale.order.line to my custom module, and added these lines of code:

        matching_cust_ids = product_obj.search(cr, uid, ['x_cust_name','=', partner_id])

        domain = {

        'product_id':[('id', 'in', matching_cust_ids)]

        }

 

From what I can tell this would scan all the product objects and pick the ones whose 'x_cust_name' field is the same as partner_id, which is passed to the on_change function. Now I am getting an error when I try to add any sales order lines:

File "/usr/lib/pymodules/python2.7/openerp/osv/orm.py", line 4680, in _where_calc if not any(item[0] == 'active' for item in domain): File "/usr/lib/pymodules/python2.7/openerp/osv/orm.py", line 4680, in <genexpr> if not any(item[0] == 'active' for item in domain): TypeError: 'int' object has no attribute '__getitem__'

 

I know there is something wrong with my code, but I can't figure out what it is. Does self.pool.get('product.product') return a list of all products? I think there is something big I am missing here. Thanks!

 

Edit 2 - This is where I am adding the domain... is this right?

 

    <record id="view_res_sale_cust_domain" model="ir.ui.view">

      <field name="name">res.sale.cust.domain</field>

      <field name="inherit_id" ref="sale.view_order_line_tree"/>

      <field name="model">sale.order.line</field>

      <field name="arch" type="xml">

         <field name="product_id" domain="[('id','in',parent.custproduct_id)]"/>

      </field>

    </record>

Avatar
Discard