how to set domain with python in odoo - odoo

Is it possible to set domain on the python side without putting it in view?
I tried to set the domain in the customer field (sale order) based on branch in the Customer menu/template
I have tried this but why it doesn't work ?
#api.onchange('partner_id')
def _onchange_cust_domain(self):
for rec in self:
if self.branch_id.id:
cust_list = rec.partner_id.branch_id.id
return {'domain' : {'partner_id' : [('branch_id', '=', cust_list)]}}

To set the partner_id domain when the branch_id field value changes, use the following onchange function:
Example:
#api.onchange('branch_id')
def onchange_branch_id(self):
if self.branch_id:
return {'domain': {'partner_id': ['|', ('branch_id', '=', False), ('branch_id', '=', self.branch_id.id)]}}
Odoo sets by default the following domain from the python code:
['|', ('company_id', '=', False), ('company_id', '=', company_id)]

I think your problem is that you are making a domain for a field partner_id, but in the onchange method of the same field.
It makes no sense to me. So if you put a Customer with branch X, then you can only search customers of branch X for that sale_order (if that domain do the job).
I dont know what are you trying to do exactly, but i think than changing a domain in the same field you are changing the value it is no possible.
Your code would be correct if that domain applies to another field.
This is a working exaple. Notice that onchange field method and field to apply domain are diferent:
#api.onchange('operating_unit_id')
def _applicants_onchange(self):
if self.operating_unit_id:
return {'domain': {'applicant_id': [('default_operating_unit_id', '=', self.operating_unit_id.id)]}}
return {}

Returning a domain using onchange method has been deprecated in Odoo 14.
You can use the new way used by Odoo:
Returning a domain using onchange method has been deprecated in Odoo 14.
You can use this new way.

Related

Restrict write permissions for a field - Odoo 15

How can I restrict the write permissions for a field to a specific group ?
I want to check if a user is in a specific group with id 46. If the user is in this group, he should be allowed to write in this field. If he is not in this group, he should not be allowed to write.
The field is a custom field, editing the domain with the studio app I think I should avoid.
My field:
<field name="customer_codename" placeholder="Codename" attrs="{'invisible':['|',('customer_rank','=', 0),('is_company','=', False)]}"/>
I tried the following, but it did not work:
I created a new field using the studio app. Field type is boolean.
In the advanced properties I wanted to define the compute for the field. In dependencies I gave "user_id" and in the compute field I gave
for record in self:
user_id.has_group('__export__.res_groups_46_eff9dc52')
The boolean field should be set to true if the user is in a certain group.
Not sure if I can give you the best answer there is.
But for me, I'd personally create a Boolean field in the view's associated model, with its default field a lambda function checking if the user belongs to the groups you mentioned.
Assuming groups_id is the name of the user groups in model res.users, we have:
class ResUsers(models.Model):
_inherit = "res.users"
can_write_codename = fields.Boolean(default=lambda self: self.groups_id in ("model_name.group_name"))
Then in your xml file, you can include can_write_codename inside attrs, like this:
<field name="customer_codename" placeholder="Codename" attrs="{'invisible':['|',('customer_rank','=', 0),('is_company','=', False)], 'readonly': [('can_write_codename', '=', 'True')]}"}"/>

How to filter Many2one value depend another field?

please I have a custom module here is a capture :
then I go to Sales order and modify the module sale.order.line i add some fields in relation with my custom module
Now my request is in ligne contrat i want only lignes in the contrat
for example if i choose Contrat 01 only ligne in Contrat 01 like this
here is my code :
You can use a domain in the field definition in your XML:
<field name="contrat_name_id"/>
<field name="contrat_lignes_id" domain="[('ligne_ids', '=', contrat_name_id)]"/>
This will filter contrat_lignes_id to only show records where ligne_ids matches what you entered for contrat_name_id on that line.
What #djames did will work only in this form view if you want
to have this behavior in all your sale.order.line views use python
to do this job for you.
class bons_lines(model.Model):
_inherit = 'sale.order.line'
# your new fields
....
....
#api.onchange('contrat_name_id')
def onchange_contrat_name(self):
if self.contrat_name_id:
# add the domain
self.contrat_lignes_id = False # force the user to reselect the contrat_lignes_id if he changes the contrat name
return {'domain': {'contrat_lignes_id': [('ligne_ids', '=', self.contrat_name_id.id)]}}
else:
# remove the domain
return {'domain': {'contrat_lignes_id': []}}
This way you will not have to add the domain in every XML view you declare.

How to return a domain from Odoo server action

I am trying to create a server action via the Odoo UI that will alter the domain of another field in the view. This seems to be a pretty common use-case when dealing with the Odoo source code as you can see in the following documentation:
https://www.odoo.com/documentation/10.0/reference/orm.html#odoo.api.onchange
In those docs, they indicate that if I were in the source code of the model, I can define an onchange method and return a domain, for example, the behavior I'm trying to accomplish in the sale.order.line model would be:
#api.onchange('product_id')
def _onchange_product(self):
return {
'domain': {'route_id': [('id', 'in', x_all_route_ids.ids)]}
}
In other words, when the product of an sales order line changes, update the available options in the route_id field.
Is there any way to accomplish this same thing via a server action created through the UI? I am having trouble figuring out how to return a domain from the Python code.
The notes in the code section say:
# Available variables:
# - time, datetime, dateutil, timezone: Python libraries
# - env: Odoo Environement
# - model: Model of the record on which the action is triggered
# - record: Record on which the action is triggered if there is one, otherwise None
# - records: Records on which the action is triggered if there is one, otherwise None
# - log : log(message), function to log debug information in logging table
# - Warning: Warning Exception to use with raise
# To return an action, assign: action = {...}
I don't see how I can use this to return a domain. Does anybody have any idea?
I have tried setting the python code field to simply:
domain = {'route_id': [('id', 'in', record.x_all_route_ids)]}
But that doesn't work. The route_id list is unchanged.
I got some insight from Odoo technical support and it turns out this is possible. Anything assigned to the action variable will be treated as the return value for the server action.
So you can simply do:
action = {
'domain': {
'route_id': [('id', 'in', record.x_all_route_ids.ids)]
}
}
It is not possible. Only these special on-change methods return values will be evaluated correctly.

How to pass an external id to a domain filter

I have a Many2One field accepting a product in my model, but I want to limit this field to a specific product template, using the said template external id (The XML id).
I've try this without success:
#This piece of code doesn't work
the_product = fields.Many2one('product.product',
domain = [('product_tmpl_id','=', "ref('the_package.the_external_id')")])
How can I do this?
The solution to this problem is to use a function that returns the filters parameters. That way, we have access to the self variable in the body of the function, and therefore, we can use it to search specific external ids.
#api.model
def _get_domain(self):
# We have access to self.env in this context.
ids = self.env.ref('the_package.the_external_id').ids
return [('product_tmpl_id','=', ids)]
the_field = fields.Many2one('product.product',
required=False,
domain = _get_picking_product_domain)
The above solution does does not work.
Error :
ProgrammingError: can't adapt type 'model_name'
But try this:
You don't have to insert domain in your field :
#api.onchange('field_a')
def fiel_change(self):
dom['field_a'] = [(*)] #* type your domain
return {'domain':dom}

OpenERP one2many issue

I have the following:
shipment_obj = self.pool.get('stock.picking.in').browse(cr, uid, context.get('active_id'))
This returns correct object, I can access properties, but when I access the O2m field "move_lines", it returns None object and cannot iterate.
Do I need special way to access the products for the specific incoming shipment?
This is in existing OpenERP:
'move_lines': fields.one2many('stock.move', 'picking_id', 'Internal Moves', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}),
'product_id': fields.related('move_lines', 'product_id', type='many2one', relation='product.product', string='Product'),
stock.picking.in , stock.picking.out and stock.picking are actually the same table stock_picking and stock.picking is considered as the base of both stock.picking.in and stock.picking.out. I think this functionality still have some issues and it is solved in openerp v8.So when you need to browse the object, use the stock.picking whether you are browsing for stock.picking.in nor stock.picking.out
when using
shipment_obj = self.pool.get('stock.picking.in').browse(cr, uid, context.get('active_id'))
here you will get a list of browse records, you can access the one2many field move_lines like
for shipment_id in shipment_obj:
move_lines = shipment_id.move_lines
here you will get the move_lines of each records of the list...
Needed to add this which solves the problem:
if context is not None and context.get('active_id'):
it is the way I thought the method was called that didn't need to check context and active_id since there would always be a context and active_id, I was wrong.