Odoo Help
Odoo is the world's easiest all-in-one management software. It includes hundreds of business apps:
CRM | e-Commerce | Accounting | Inventory | PoS | Project management | MRP | etc.
How to filter field on a one2many?
Hello everyone, kindda lost for my odoo adventure and i need a help. I have a class named "planned.bom", some of it's columns are product_id (many2one on product), project_id (many2one on project). This is where i stuck, in my purchase requisition, when i add purchase requisition lines, i want to show only those products which are under planned.bom and base on project.
Here is the image i want to tell:
Any help is much appreciated.
-------------------------------------------------------------------------
In purchase.requisition i add fields.function;
'product_ids_to_chose_from' : fields.function(_get_assigned_bom, type='many2many', method=True,store=False, multi='compute_assigned_bomproduct', string='Assigned BOM product')
and the functions looks lik this:
def _get_assigned_bom(self,cr,uid,ids,context=None):
vals = {}
pr_id = None
for rec in self.browse(cr, uid, ids, context=context):
pr_id = self.pool.get('project.project').search(cr,uid,[('id','=',rec.project_id.id)])
for project in self.pool.get('project.project').browse(cr,uid,pr_id,context=context):
p_bom_ids = self.pool.get('planned.bom').search(cr,uid,[('project_id','=',project.id)])
for bom in self.pool.get('planned.bom').browse(cr,uid,p_bom_ids,context=context):
pr_id = bom.product_id.id
vals[rec.id] = {'product_ids_to_chose_from':pr_id}
return vals
on purchase.requisition.line i add this one:
'product_ids_to_chose_from': fields.related('requisition_id', 'product_ids_to_chose_from', type='many2many', string='Assigned BOM product'),
and on my form here how create the domain:
<page string="Products" attrs="{'invisible':[('state','=','new')]}">
<field name="line_ids" context="{'requisition_id': active_id}" attrs="{'readonly':[('state','not in','add_product')]}">
<tree string="Products" editable="bottom">
<field name="product_id" required="True"
on_change="onchange_product_id_limit(product_id,product_uom_id,product_qty,context)"
domain="[('is_bom','=',True),('ids','in',product_ids_to_chose_from[0][2])]" />
upon clicking on a product i recieve this client error:
Uncaught Error: NameError: name 'product_ids_to_chose_from' is not defined
i don't know what it cause.
****************** EDIT
def _get_assigned_bom(self, cr, uid, ids, name, arg, context=None):
vals = {}
pr_id = []
for rec in self.browse(cr, uid, ids, context=context):
id = rec.id
vals[id] = []
if rec.project_id:
p_bom_ids = self.pool.get('planned.bom').search(cr,uid,[('project_id','=',rec.project_id.id)])
for bom in self.pool.get('planned.bom').browse(cr,uid,p_bom_ids,context=context):
pr_id = bom.product_id
vals[id] = [(6, 0, [x.id for x in pr_id])]
return vals
I presume that the purchase.requisition (PR) is somehow linked to the planned.bom. So, here is a trick that I usually used:
- Create a function many2many field in the PR (or you can alternatively populate this column during create / write).
- The many2many field need to be populated with all the product.product that is linked to the planned.bom.
- In your purchase.requisiton.line model, extend (using related field in v7 or compute argument in v8) to reflect the new many2many field of the related PR. Say, it is named product_ids_to_chose_from
- Use that field to domain your product_id: domain="[('ids', 'in', product_ids_to_chose_from[0][2])]"
Thank you sir for your response, actually purchase.requisition has no direct link with planned.bom other than that it has many2one on project.project and with all due respect sir, do you mean in 'create a function' i need to create fields.function on my PR?
It's OK if the link is not direct as long as it has link. Because it is needed for the step in the 2nd point. And yes, you need to create fields.function (I presume that you are developing in v7 then, cause in v8 it is implemented differently).
Sir i updated my question above, i am not sure if i correctly followed your suggestion and that's why i got an error.
The domain need to be implemented in the view XML not from the field definition. Reason: product_ids_to_chose_from can only have value when a record is selected. The domain in field definition can only use something that is not depending on the record value.
One more note: the first 3 lines in the first for loop in _get_assigned_bom can be collapsed. There are 3 lines that I'm referring to: pr_id = self.pool.get('project.project').search(cr,uid,[('id','=',rec.project_id.id)]); for project in self.pool.get('project.project').browse(cr,uid,pr_id,context=context):; p_bom_ids = self.pool.get('planned.bom').search(cr,uid,[('project_id','=',project.id)]). Can be collapsed to p_bom_ids = self.pool.get('planned.bom').search(cr,uid,[('project_id','=',res.project_id.id)]). You might want to put a check before to see if res.project_id is empty or not.
Sir, i guess i recieved a client error because my fields product_ids_to_chose_from is not srored in my database, I am not sure though. Yeah the domain: "domain="[('is_bom','=',True),('ids','in',product_ids_to_chose_from[0][2])]" is in my view form. I tried to make product_ids_to_chose_from as store=True but it also produce an error.
Sorry forgot to mention that you need to put the field product_ids_to_chose_from in the view. Don't store, unless if you are sure that the list of products will only change if the purchase.requisition is saved (i.e. there is no way that the list of products may change because there is new planned.bom added to the project.)
Sir, after adding the field on the view, my using vals[rec.id] = {'product_ids_to_chose_from':pr_id} produce no output, when i click the tree view of my purchase requisition it says: "Uncaught TypeError: undefined is not a function" and using vals[rec.id] = pr_id it says: "AttributeError: 'int' object has no attribute 'iteritems'"
Return of _get_assigned_bom should be in the form or [(6, 0, [XXXX])]. Where [XXXX] is the list of product ids that you have collected. I see that you assign just one id to pr_id. Why so? Also, pr_id variable is reused, you may end up in the situation where self.pool.get('planned.bom').browse(cr,uid,p_bom_ids,context=context) and your pr_id is the one returned from self.pool.get('project.project').search(cr,uid,[('id','=',rec.project_id.id)]).
Do you mean sir, pr_id = bom.product_id.id must be changed to pr_id = bom.product_id and then loop for this items? Or my head is already spinning and that's why i can't spot it.
Sir I have updated my function replacing vals[rec.id] into vals[id] = [(6, 0, [x.id for x in pr_id])] and terminal says, NotImplementedError: Iteration is not allowed on browse_record(product.product, 4)
Because you are still using pr_id which is assigned in this line: pr_id = bom.product_id. And thus pr_id is a single browser_record and cannot be interated. You should collect all bom.product_id in a list, like so: pr_id = [bom.product.id if bom.product else False for bom in self.pool.get('planned.bom').browse(cr,uid,p_bom_ids,context=context)]
Oh oh, kindda nose bleed for the code structure. Can you explain it to me sir, if it's okay with you.
Sir, using vals[id] = [(6, 0, [x.id for x in pr_id])] produce an error, it says AttributeError: 'int' object has no attribute 'id'. When i tried, vals[id] = {'product_ids_to_chose_from':pr_id} it works but on my purchase.requisition.line field "product_ids_to_chose_from" is empty while field "product_ids_to_chose_from" on purchase.requisition has item on it. When i check product_ids_to_chose_from on purchase.requisition.line it is related to product_ids_to_chose_from on purchase.requisition.
Sorry, I did make the pr_id to be a list of Database IDs instead of list of browse_objects. You can change the vals[id] line to be: vals[id] = [(6, 0, pr_id)] OR change the pr_id line to be: pr_id = [bom.product for bom in self.pool.get('planned.bom').browse(cr,uid,p_bom_ids,context=context)]
And if you have difficulty in reading the code, I suggest that you familiarise yourself with list comprehension:,,
I have tried it sir, using vals[id] = [(6, 0, pr_id)] and it says AttributeError: 'list' object has no attribute 'iteritems'.
Not sure what causes the AttributeError. But from code I think vals has been defined as list instead of dictionary as it should. The code that you have posted in the question defined it as dictionary.
but everytime i tried vals[id] = {'product_ids_to_chose_from':pr_id} it works but on the purchase.requisition only, on purchase.requisition.line the field product_ids_to_chose_from is empty.
but everytime i tried vals[id] = {'product_ids_to_chose_from':pr_id} it works but on the purchase.requisition only, on purchase.requisition.line the field product_ids_to_chose_from is empty.
It is from a different method. Your definition of vals does not carry over different methods.
even if it is fields.related sir?
After changing vals = {} into vals = [] and assigning vals[id] = [(6, 0, pr_id)], now the compiler says: "IndexError: list assignment index out of range" for my vals assignment.
Sir,can i ask one more question. Now in my purchase requisition form it does not completely shows my BOM (i.g if project A, have 4 BOM only three is bieng displayed on my form. I tried to show it on my terminal but it all print planned.bom under that project). What's the possible cause of this one?
Sorry I did not caught your earlier messages. I'm not sure what you mean by your question about fields.related. The vals need to be a dictionary {} not list []. The error "IndexError: list assignment index out of range" is due to you using a list. On the subject of 4 BOMs showing only 3, I would suggest that you check: 1. Are there really 4 planned.bom that are connected to that project (whose project_id is the project's database ID)? 2. Do you have any Record Rules or any domain applied to the view/column/model?
In my purchase.requisition.line i have product_ids_to_chose_from w/c is of fields.related on product_ids_to_chose_from from purchase.requisition. For number one, yes there exist a four planned bom under same project. For number 2, yes there is a domain on product_ids_to_chose_from in my view.
Actually sir, it works properly on my purchase.requisition.line, it shows all products whose planned bom is under project selected by the user from purchase.requisition. I am just wondering, why all planned bom are not shown on purchase.requisition view.
If it shows in the purchase.requisition.line but not in the purhcase.requisition, my suspect will be a domain that prevents the record to be shown in the view definition.
Copy, perhaps i just have to make it invisible. What is the important is it filter the product. By the way thanks a lot sir for your patient especially for