Update value of field of another model from a create method of another model - odoo-14

I want to update value of field state from another model in odoo 14.Using the following code it is not working
_inherit = 'crm.lead'
lead_details_id = fields.Many2one('leads.details', string="Lead Id")
def create(self, vals):
if vals.get('lead_details_id'):
detail = self.env['leads.details'].search([('id', '=', vals.get('lead_details_id'))])
if detail:
detail.write({'state':'customer'})
return super(LeadDetailsInh, self).create(vals)

Related

Get value from a Many2one related model in model create function

I have two models, TextMessage and Device, that are related many TextMessages to one Device.
from odoo import models, fields, api
class Device(models.Model):
_name = 'device'
_description = 'A model for storing all devices'
name = fields.Char()
iden = fields.Char()
model_name = fields.Char()
manufacturer = fields.Char()
push_token = fields.Char()
app_version = fields.Integer()
icon = fields.Char()
has_sms = fields.Char()
text_message_ids = fields.One2many("text_message", "device_id", string="Text Messages")
from odoo import models, fields, api
class TextMessage(models.Model):
_name = 'text_message'
_description = 'Text Messages'
name = fields.Char()
message_text = fields.Text()
pb_response = fields.Text()
target_number = fields.Char()
device_id = fields.Many2one('device', 'Device', required=True)
#api.model
#api.depends("device_id")
def create(self, values):
print("values['device_id']",values["device_id"])
print("self.device_id",self.device_id.iden)
for rec in self.device_id:
print("Device ID",rec.iden)
values['pb_response'] = rec.device_id.iden
return super().create(values)
In the create method of TextMessage, I want to retrieve the value of the iden attribute of the Device model.
The print statements in TextMessage.create print:
values['device_id'] 1
self.device_id False
The print statement in the loop prints nothing.
You can't access self before creating the record so it will be false.
You can write the create method in two ways:
Create the record first and then get the iden value:
#api.model
def create(self, values):
res = super().create(values)
res.pb_response = res.device_id.iden
return res
Or you can get the device_id record from values as below:
#api.model
def create(self, values):
if 'device_id' in values and values.get('device_id',False):
device = self.env['device'].browse(values.get('device_id'))
if device:
values['pb_response'] = device.iden
return super().create(values)
If the pb_response field is the same of the iden field then you can create it as related field to device_id.iden and you will get the iden value automatically once the device-id assigned as below:
pb_response = fields.Char(related="device_id.iden")

Raise UserError only if none fields selected

I added my custom field to res.partner model and when I'm creating partner if branch_id is checked I want to that one of 3 fields should be selected. If some of the fields are not selected then I want to raise UserError.
But now it raises UserError even if I one of the fields is selected.
class ResPartner(models.Model):
_inherit = 'res.partner'
branch_id = fields.Many2one('branch.responsibility','Responsibility by branch')
drawer_id = fields.Many2one(
'furniture.parts.type', string='Drawer Type',
domain=[('type', '=', 'drawer')], )
flexible_id = fields.Many2one(
'furniture.parts.type', string='Flexible Type',
domain=[('type', '=', 'flexible')],)
runner_id = fields.Many2one(
'furniture.parts.type', string='Runner Type',
domain=[('type', '=', 'runner')], )
#api.model
def create(self, vals):
if vals.get('branch_id'):
if not vals['drawer_id'] or not vals['flexible_id'] or not vals['runner_id']:
raise UserError('You need to chose values from notebook raport data')
return super(ResPartner, self).create(vals)
UPDATE.
for write method, I tried this as CZoellner suggested for create but always get True True True for fields_to_check_in_vals
#api.multi
def write(self, vals):
if vals.get('branch_id') or vals.get('drawer_id') or vals.get('flexible_id') or vals.get('runner_id') or
vals.get('group_1_id') or vals.get('group_2_id')or
vals.get('group_3_id'):
fields_to_check = ['drawer_id', 'flexible_id', 'runner_id', 'group_1_id', 'group_2_id', 'group_3_id']
fields_to_check_in_vals = [f in self for f in fields_to_check]
if not any(fields_to_check_in_vals):
raise UserError('If branch is selected then you need to select one of the fields from data raport')
> return super(ResPartner, self).write(vals)
Your logic says, that all 3 fields have to be set. You could use any here:
if vals.get('branch_id'):
fields_to_check = ['drawer_id', 'flexible_id', 'runner_id']
fields_to_check_in_vals = [f in vals for f in fields_to_check]
if not any(fields_to_check_in_vals):
raise UserError()
Edit: the write method is a bit more tricky. Usually it is a multi record method, so a for each loop on self should be implemented. Then you'll need to use either getattr or just (it's suggested in the Odoo doc) treat the recordset like a dict. And then it could be, that the change happens right on the write call. So you have to check both the persisted and the new values:
for record in self:
if vals.get('branch_id'):
fields_to_check = ['drawer_id', 'flexible_id', 'runner_id']
fields_to_check_dict = {f:record[f] for f in fields_to_check}
fields_to_check_dict.update({f:f in vals for f in fields_to_check})
if not any(fields_to_check_dict.values()):
raise UserError()
That's a bit complicated. You could also first call super and just check after that. Raising an exception will rollback all changes, so nothing will happen.
res = super(MyModel, self).write(vals)
for record in self:
if vals.get('branch_id'):
fields_to_check = ['drawer_id', 'flexible_id', 'runner_id']
fields_to_check_in_record = [record[f] for f in fields_to_check]
if not any(fields_to_check_in_record):
raise UserError()
return res

Update fields with different number of values

In res.partner model I have a field
property_product_pricelist = fields.Many2many('product.pricelist')
and in sale.order
alternative_pricelist_ids = fields.Many2many(
'product.pricelist')
Partner can have more than one price list so my goal is to add the first pricelist to the pricelist_id field and other pricelists to alternative_pricelist_ids. The things are that how I wrote code is not really good, as you can see I will get an error if there are more than 4 pricelists. So how can I avoid it and write it another way?
#api.multi
#api.onchange('partner_id')
def onchange_partner_id(self):
super(SaleOrder,self).onchange_partner_id()
values = { 'pricelist_id': self.partner_id.property_product_pricelist[0] and self.partner_id.property_product_pricelist.id[0] or False,
'alternative_pricelist_ids': self.partner_id.property_product_pricelist[1] and self.partner_id.property_product_pricelist[2] and self.partner_id.property_product_pricelist[3] or False,
}
self.update(values)
Try this :
#api.multi
#api.onchange('partner_id')
def onchange_partner_id(self):
super(SaleOrder, self).onchange_partner_()
for record in self:
pricelist_id = False
alternative_ids = []
for pricelist in record.partner_id.property_product_pricelist:
if not pricelist_id:
pricelist_id = pricelist.id
else:
alternative_ids.append(pricelist.id)
record.pricelist_id = pricelist_id
record.alternative_pricelist_ids = [(6, 0, alternative_ids)]

How can I change the value of a selection field on create function?

I wanna change the value of status once I click save. status is a selection field [('ok', 'Ok'),('tobe', 'Not Ok')]
status = fields.Selection(
readonly=False,
default='tobe',
related= 'name.status'
)
#api.model
def create(self, values):
self.status= 'ok'
line = super(MyClass, self).create(values)
return line
Status is a related field so after creating change the status of you many2one field.
#api.model
def create(self, values):
rec = super(YouClassName, self).create(values)
# here change the status.
rec.name.status = 'ok'
return rec
The error is in your selection field declaration. It should be like this:
status = fields.Selection([('ok', "OK"),('not ok', "Not OK"),],default='tobe')
#api.multi
def write(self, vals):
vals['status'] = 'ok'
ret = super(Your-Class-Name-here, self).write(vals)
By default, readonly on every field is false, so no need specifying it inside the selection field.
Please, notify me if this solve your challenge.
Thanks
On the time, when the method create is called, your instance isn't created. So self doesn't have any instance. self.status = 'ok' will change the value of status of nothing.
You can set the value in values like that:
#api.model
def create(self, values):
values['status'] = 'ok'
line = super(MyClass, self).create(values)
return line
Or change the value after create instance:
#api.model
def create(self, values):
line = super(MyClass, self).create(values)
line.status = 'ok'
return line
But the method create is called, only when a new instance is created. There is the case, that someone want to save the instance. Then you must override the method write:
#api.multi
def write(self, vals):
vals['status'] = 'ok'
ret = super(FrameworkAgreement, self).write(vals)

what should I add to display the value of fields correctly?

what should I add to display user_id and cat correctly
#api.model
def create(self, vals):
record=super(test, self).create(vals)
if vals['total'] > 0:
vals['date'] = fields.Datetime.now()
self.env['journal'].create({
'user_id': record.patient_id,
'cat': record.cat,})
....
.....
on the tree view (journal):
user_id is displayed as test.user(6,)
cat is displayed as cat1
EDITS:
class test(models.Model):
_name = 'test'
cat = fields.Selection(
required=True,
related='test_type_cat.name',
store=True,
)
user_id = fields.Many2one('res.users', string='user', readonly=True,)
.....
#api.model
def create(self, vals):
record=super(test, self).create(vals)
if vals['total'] > 0:
vals['date'] = fields.Datetime.now()
self.env['journal'].create({
'patient_id': record.patient_id.name,
'cat': record.cat,
'user_id': record.user_id.name,
})
record.total = 0
return record
why does it work with .name and not .id ?
for m2o field should I pass the integer value ? if it is the case why does it work here with .name ? and what about m2m and o2m?
this worked for you because you are creating a record in model: journal not in test model.
and if you go to journal model you will find that patient_id is Char field not a many2one field.
so if you pass: record.patient_id you are passing an object and it's converted to char this is why you get test(1,). because pateint_id is a many2one field in test model witch mean is an object.
Hope this clear thing little bit for you.