Domain on Many2one field - odoo

I need applay domain on field product_id in purchase.order.line model, after call onchange method in purchase.order model.
Example:
_inherit = "purchase.order"
custom_id = fields.Many2one('custom.model', string='Custom')
#api.onchange('custom_id')
def change_product(self):
lst = [1,2,3]
return {'domain': {'order_id.product_id': [('id', 'in', lst)]}}
This is original field where I want add my domain
product_id = fields.Many2one('product.product', string='Product',domain=[('purchase_ok', '=', True)], change_default=True, required=True)
I don't get any error but in product_id field show all data from database, not product where id 1,2,3 from above example.

write onchange function for product_id, instead of custom_id and return domain.
#api.onchange('product_id')
def change_product(self):
lst = [1,2,3]
return {'domain': {'product_id': [('id', 'in', lst)]}}
inside the onchange function consider the custom_id.

You have a little problem here: you can't set a domain for child relations IIRC.
What you can do is to create a related field on the child relation (here purchase.order.line and trigger the onchange on that.
class PurchaseOrder(models.Model):
_inherit = "purchase.order"
custom_id = fields.Many2one(
comodel_name='custom.model', string='Custom')
class PurchaseOrderLine(models.Model):
_inherit = "purchase.order.line"
custom_id = fields.Many2one(
comodel_name="custom.model", related="order_id.custom_id")
#api.onchange('custom_id')
def onchange_custom_id(self):
lst = [1,2,3]
return {'domain': {'product_id': [('id', 'in', lst)]}}
And some more information. Let me presume you have set custom_id on product variants (a) or on product categories (b). Just change the domain of product_id and use the domain operator '=?'. You won't need an onchange method for this solution, but you have to define custom_id in the view (invisible is possible, this is also a must have for the complete first solution)!
(a)
class PurchaseOrderLine(models.Model):
_inherit = "purchase.order.line"
custom_id = fields.Many2one(
comodel_name="custom.model", related="order_id.custom_id")
product_id = fields.Many2one(
domain="[('purchase_ok', '=', True), ('custom_id', '=?', custom_id)]")
(b)
class PurchaseOrderLine(models.Model):
_inherit = "purchase.order.line"
custom_id = fields.Many2one(
comodel_name="custom.model", related="order_id.custom_id")
product_id = fields.Many2one(
domain="[('purchase_ok', '=', True), ('categ_id.custom_id', '=?', custom_id)]")
If no custom_id is set the domain will read: product has to be purchasable AND True.

Related

Odoo domain for Many2Many relation

Here is code:
class Car(models.Model):
_name = 'car'
parking_id = fields.Many2one('cars')
class Parking(models.Model):
_name = 'parking'
cars_ids = fields.One2many('cars', 'parking_id')
class Group(models.Model):
_name = 'group'
parking_id = fields.Many2one('parking')
cars_ids = fields.Many2many('cars', lambda self: [('parking_id', '=', self.parking_id)])
What i want is to limit records of cars when i picking it in group form by parking on that cars are.
But my code does not work. What the mistake ?
If you define the domain in python code it will not be changed after the user
select the parking_id you need to update the domain every time the user
changes the parking_id:
class Group(models.Model):
_name = 'group'
parking_id = fields.Many2one('parking')
# it's always better to define m2m field with full properties
# cars_ids = fields.Many2many('cars','group_cars_rel', 'group_id', 'car_id', 'List of cars' )
cars_ids = fields.Many2many('cars')
#api.onchange('parking_id')
def onchange_parking(self):
"""change the domain when user change parking_id"""
# you may need to empty the many2many field if the user change the parking
# if not just remove this line
self.cars_ids = [(5, 0, 0)] # remove all record from many2many
if self.parking_id:
return {'domain': {'cars_ids': [('parking_id', '=', self.parking_id.id)]}}
else:
# remove domain
return {'domain': {'cars_ids': []}}
It seems your syntax is wrong for domain, change as below:
class Group(models.Model):
_name = 'group'
parking_id = fields.Many2one('parking')
cars_ids = fields.Many2many('cars', domain=[('parking_id', '=', parking_id)])

Inherited model many2one picking a wrong field value

I am trying to reference form_serial_no field of formdownload model in my inherited model(plot.allocate). Instead of the dropdown to show the computed value of form_serial_no which is company_short_code padded with sequence e.g CCK0000006, it's showing "CCK" which is the value of company_short_code excluding the sequence. In actual fact, it's referencing company_short_code of companyname model instead of the computed value of form_serial_no of formdownload model. And in the database, form_serial_no field is showing the right record which is something like these......ABC0000008, CDG0000003 and so on. This is my question, is there any reason why form_serial_no_id Many2one field of plot.allocate model is not picking the value of form_serial_no Char field of formdownload, instead, it's picking the company_short_code Char field of companyname model?
Secondly, how can i change the status field default value of companyname model record to true when a value is picked in form_serial_no_id Many2one field of plot.allocate model?
Kindly help me look into these.
Below are my code snippet
# -*- coding: utf-8 -*-
from openerp import models, fields, api
class CompanyName(models.Model):
_name = 'companyname'
_rec_name = 'company_short_code'
company_name = fields.Char(string="Company Name", required=True)
company_short_code = fields.Char(string="Company short code", required=True)
class FormDownload(models.Model):
_name = 'formdownload'
_rec_name = 'form_serial_no'
name = fields.Many2one('companyname', string="Company Name", ondelete='cascade',
required=True)
form_serial_no = fields.Char(string="Form Serial No", readonly=True)
status = fields.Boolean(string="Status", default=False)
#api.model
def create(self, vals):
serial_no = self.env['ir.sequence'].get('formdownload.form_serial_no')
code = self.env['companyname'].browse(vals['name']).company_short_code
# capitalize company short code values
code = code.upper()
# merge code and serial number
vals['form_serial_no'] = code + serial_no
return super(FormDownload, self).create(vals)
class PlotAllocation(models.Model):
_inherit = 'plot.allocate'
form_serial_no_id = fields.Many2one('formdownload',
domain=[('status', '=', False)],
ondelete='cascade', string="Form Serial No")
#api.model
def create(self, vals):
record = self.env['formdownload'].search([('name', 'like', vals.get('name', False))]).form_serial_no
status = self.env['companyname'].search([('name', 'like', vals.get('name', False))]).status
if vals.get('form_serial_no_id') == record.id:
self.env['companyname'].write({status : True})
return super(PlotAllocation, self).create(vals)
in the view the many2one is always showing the value of the field specified in the Model class by _rec_name :
by default _rec_name = 'name'
so in reality your model is like this :
class FormDownload(models.Model):
_name = 'formdownload'
_rec_name = 'name'
so he will retreive the value of field name name is also a many2one so the value retrieved is the _rec_name of model companyname with is company_short_code:
so i you want to change the value of many2one you have to choice:
if one field is enough than specify the _rec_name = 'form_serial_no'
if you want to combined value like first && last name then override name_get method
#api.multi
def name_get(self):
"""
change the displayed value on m2o
"""
result = []
for record in self:
result.append((record.id, _(" %s %s") % (record.first_name, record.last_name)))
return result
EDITS
in create method is easy just remove all the code in create method and put this two line
rec_id = super(PlotAllocation, self).create(vals)
# create return a record you can acces it's value
rec_id.form_serial_no_id.name.status = True
return rec_id # you need to return the record

How overwrite default function of a field in odoo new api

I have a field that call a function to get default value (in module project_forecast):
def default_user_id(self):
return self.env.user if ("default_user_id" not in self.env.context) else self.env.context["default_user_id"]
user_id = fields.Many2one('res.users', string="User", required=True,
default=default_user_id)
I create another module to inherit it and change default value of field user_id but it's not working without any error in log, how can I resolve this ?
def default_user_id(self):
return False
You're linking a method directly on field definition. So overriding the method isn't enough anymore. Just define the field user_id again with default as the only parameter and ofc your new method:
The original model:
class MyModel(models.Model):
_name = "my.model"
def default_user_id(self):
return self.env.context.get("default_user_id", self.env.user)
user_id = fields.Many2one(
comodel_name='res.users', string="User", required=True,
default=default_user_id)
The inherited model:
class MyModelInherit(models.Model):
_inherit = "my.model"
def default_user_id(self):
return self.env['res.users']
user_id = fields.Many2one(default=default_user_id)
Please check this
user_id = fields.Many2one('res.users', string='User',readonly=True, default=lambda self: self.env.user)

How to modify many to many field in wizard?

I have model contains many to many assign_to_id, I want to modify that field in wizard form through escalte_to method when user trigger escalate button
Model:
class Incident(models.Model):
_name = 'itmangement.incident'
assigned_to_id = fields.Many2one('hr.employee', string="Assigned To",domain="[('department_id', '=', dep_id)]",required=True)
Wizard model
class Escalate(models.TransientModel):
escalated_to = fields.Many2one('hr.employee', string="Escalated To", required=True)
#api.one
def escalate(self):
incident_obj = self.env['itmangement.incident']
record = incident_obj.browse(self._context.get('active_ids'))
record.write({'state': 'escalated'})
class Escalate(models.TransientModel):
escalated_to = fields.Many2one('hr.employee', string="Escalated To", required=True)
#api.one
def escalate(self):
object_id = self.env.context.get('active_id')
for object in self.env['itmangement.incident'].browse(object_id) and self.escalated_to:
object.assigned_to_id = self.escalated_to.id

how can I inherit of inherited model and view in odoo/openerp

I need help to set default value of purchase_ok field at product_template class in purchase module
thanks
You can simply set the default attribute like this:
class ProductTemplate(models.Model):
_inherit = 'product.template'
purchase_ok = fields.Boolean(
string='Selectable on purchase operations',
default=True,
)
Or you can use a lambda function like this:
class ProductTemplate(models.Model):
_inherit = 'product.template'
purchase_ok = fields.Boolean(
string='Selectable on purchase operations',
default=lambda self: self._get_default_purchase_ok(),
)
#api.model
def _get_default_purchase_ok(self):
value = True
# some operations
return value