Copy last value in new tree view row odoo 9 - odoo

When click on Add an Item in tree view, I want in new row copy value from last inserted row.
Eg. if field name = 'Text' in new row I need in field name string 'Text'
Any simple solution?

If you want to load default value from a database then follow this method.
You can achieve it by overriding default_get method and in that, you need to write your logic.
#api.model
def default_get(self,fields):
res = super(class_name, self).default_get(fields)
last_rec = self.search([], order='id desc', limit=1)
if last_rec:
res.update({'your_field_name':last_rec.field_value})
return res
While you click on add an item it will fill the new record with its default value and in default value we have written last record's value it it's there.
If you want to load default value from list view (last added value in a list) then it's a bit tricky work, for that you can do something like as follow.
Add one field in the parent form.
last_added_value = fields.Char("Last Added Value")
Create onchange method for that field.
#api.onchange('field_name')
def onchange_fieldname(self):
# there must be many2one field of parent model, use it here.
self.parent_model_field.last_added_value = self.field_name
And in xml field, you need to write like this.
<field name="one2many_field" context="{'default_field_name' : parent.last_added_value}">
<tree string="Title" editable="bottom">
<field name="field_name"/>
</tree>
</field>
You also need to write default_get method.
#api.model
def default_get(self,fields):
res = super(class_name, self).default_get(fields)
last_rec = self.search([('parent_field_id','=',self.parent_field_id.id)], order='id desc', limit=1)
if last_rec:
res.update({'your_field_name':last_rec.field_value})
return res

Related

How to update a field in Model B using onchange in the field of model A ? Odoo 12

What i'm trying to achieve is ,When updating a field in model A ,i needs to update a field in model B using onchange method
_name = 'Model_A'
health_profile = fields.Many2one('health.profile', domain="[('partner_id', '=', partner_id)]", string="Health Profile")
#api.onchange('health_profile')
def get_health_profile_specialist(self):
ctx = self.health_profile.id
res = self.env['model_B'].browse(ctx)
return res.update({'specialist_name': self.specialist_name})
From what I understand there is no need to modify the field with an onchange. You can directly check the value in the model A field, you could directly use a related field
health_profile = fields.Many2one('health.profile', domain="[('partner_id', '=', partner_id)]", string="Health Profile")
specialist_id = fields.Many2one('<yourmodel>', related='health_profile.specialist_id')
Maybe you should explain yourself better.

Is it possible to change the value of a selection field dynamically in Odoo 10?

I would like to have my selections depend on the value of a Char field, for instance, a Char field defined as such:
my_char = fields.Char("Enter Something", readonly = False)
so I suppose the selection field should call a function, something like "_get_value"
my_selection = fields.Selection(selection = ' _get_value')
#api.model
def _get_value(self):
my_list = [('key1','value1')]
#no idea how to assign the value of my_char to value1
return my_list
Eventually, I would like to have the selections in the drop down list vary as the user input different strings in my_char.
Is this achievable in Odoo? Because if it's not, I should better start reorganizing my structure. Thanks a lot.
As far is i know, it isn't possible with field type Selection. But you can use a Many2one field for such a behaviour.
class MySelectionModel(model.Models):
_name = "my.selection.model"
name = fields.Char()
class MyModel(models.Model):
_name = "my.model"
my_char = fields.Char()
my_selection_id = fields.Many2one(
comodel_name="my.selection.model", string="My Selection")
#api.onchange("my_char")
def onchange_my_char(self):
return {'domain': {'my_selection_id': [('name', 'ilike', self.my_char)]}}
Or without a onchange method:
my_selection_id = fields.Many2one(
comodel_name="my.selection.model", string="My Selection",
domain="[('name', 'ilike', my_char)]")
To let the Many2one field look like a selection, add the widget="selection" on that field in the form view.
How the domain should look like, should be decided by you. Here it is just an example.
No need to write method here. Just declare the dictionary to a variable and call it in selection field.
VAR_LIST = [('a','ABC'),
('p','PQR'),
('x','XYZ')]
my_selection = fields.Selection(string="Field Name",VAR_LIST)

Not getting records which created in One2many field on onchange in transient model

I am trying to create records in one2many field in one of my transient model on onchange of boolean field.
Eg.
Models
class test_model(models.TransientModel):
_name ="test.model"
is_okay = fields.Boolean("Okay?")
lines = fields.One2many("opposite.model","test_id",string="Lines")
#api.onchange('is_okay')
def onchnage_is_okay(self):
ids = []
for l in range(5):
record = self.env['opposite.model'].create({'name':str(l),'test_id':self.id})
ids.append(record.id)
self.lines = [(6,0,ids)]
class opposite_model(models.TransientModel):
_name ="opposite.model"
name = fields.Char("Name")
test_id = fields.Many2one("test.model",string="Test Model")
View
<record id="view_form" model="ir.ui.view">
<field name="name">view.form</field>
<field name="model">test.model</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Test Model">
<field name="is_okay" />
<field name="lines" />
<footer>
<button name ="click_okay" string="Okay" type="object"/>
</footer>
</form>
</field>
</record>
Now, problem is that when in check or uncheck the is_okay field it fills the records in the One2many field.
That is working fine.
But in my above view i have button which calls the method click_okay().
Eg.
#api.one
def click_okay(self):
print self.lines
So, print statement gives me blank recordset. But, i can see the 5 records in the view when i am changing is_okay field.
I am not getting any idea how to get those lines in method?
Any response would be appreciated?
It should work. That's wired behavior.
You may try with following alternative way using self.update()
#api.onchange('is_okay')
def onchnage_is_okay(self):
ids = []
for l in range(5):
record = self.env['opposite.model'].create({'name':str(l),'test_id':self.id})
ids.append(record.id)
self.update({
'lines' : [(6,0,ids)]
)}
No matter what odoo keep doing the same thing:
the problem is that odoo always passes this records to create method with command 1 but in odoo we cannot use this command in create method and this
why you lose this records in the call of method.
(1, id, values)
updates an existing record of id id with the values in values. Can not be used in create().
i don't know why you are creating this record in onchange event because this not recomanded if the user hit close instead of ok the record all ready created in database and every time he check the button will recreate this record again and again.
if you don't need to create this records in the onchange event what you should do is:
#api.onchange('is_okay')
def onchnage_is_okay(self):
ids = []
for l in range(5):
record = self.env['opposite.model'].new({'name': str(l)})
ids.append(record.id)
self.lines = ids
one thing here onchange will return the dictionnary to the form, the tree of the one2field must have all field that are passed in that dictionary in this case the tree must have field name if oppisite.model have for example another field like test_field if we pass {'name': value, 'test_field': value_2} if the tree have only name field value of test_field will be lost in create method.
but if you need like you are doing, you should work arround odoo and change the command to 4 in create a method:
#api.model
def create(self, vals):
"""
"""
lines = vals.get('lines', False)
if lines:
for line in lines:
line[0] = 4
line[2] = False
vals.update({'lines': lines})
return super(test_model, self).create(vals)

Concatenate fields on Odoo v9

I'm trying to concatenate 3 fields to form a internal code and display it in the views:
I have 3 models:
Category (size=2)
Product (size=4)
Serie (size=3)
And I want to display it in the form like this
Product Code: CAT-PROD-001
I don't know if i have to use a computed field or if exist anoter way to do this, because I was doing test with computed fields but can't reach the desired output.
Edit:
Now I'm trying to use a computed field with a onchange function to generate the value on the field
MODEL
# -*- coding:utf-8 -*-
from openerp import models,fields,api
class exec_modl(models.Model):
_name = "exec.modl"
_rec_name = "exec_desc"
exec_code = fields.Char('Identificador',required=True,size=3)
exec_desc = fields.Char('DescripciĆ³n',required=True)
cour_exec = fields.Many2one('cour.modl')
proc_exec = fields.Many2one('enro.modl')
inte_code = fields.Char(compute='_onchange_proc')
FUNCTION
#api.onchange('proc_exec')
def _onchange_proc(self):
cate = "XX"
cour = "XXXX"
exet = "XXX"
output = cate+"-"+cour+"-"+exet
return output
I'm just trying with plain values just to know how to send it to the field.
EDIT 2:
Using the answer from #Charif I can print the static strings on the form, but the next milestome I'm trying to reach is getting the codes (external models fields) to crate that inte_code
ex: From the model cour.modl I want to get the value from the field cour_code(internal_id for course) corresponding to the cour_exec field on the first model (the cour_exec field have the description of the course from cour.modl model)
#api.depends('proc_exec')
def _onchange_proc(self):
cate = "XX"
cour = self.env['cour.modl'].search([['cour_desc','=',self.cour_exec]])
exet = "XXX"
output = cate+"-"+cour+"-"+exet
self.inte_code = output
E #api.depends('inte_code')
def _onchange_proc(self):
cate = "XX"
# first domain use tuple not list
cour_result = self.env['cour.modl'].search([('id','=',exec_modl.cour_exec)]).cour_code
cour = "" # empty string because you cannot contcatenate None or False with a string value
#if cour_result :
# cour = ",".join(crse_code for crse_code in cour_result.ids)
#else :
# print "result of search is empty check you domain"
exet = "XXX"
output = cate+"-"+cour+"-"+exet+"-"+cour_result
self.inte_code = output
EDIT 3
I've been trying to usse the search mode calling other model values but I have the console output :
Can't adapt type 'Many2One' , seems im trying to compare 2 different type of fields, the types can be parsed on odoo ? or I'm using a wrong syntax for search method?
#api.depends('inte_code')
def _onchange_proc(self):
cate = "XX"
# first domain use tuple not list
cour_result = self.env['cour.modl'].search([('id','=',exec_modl.cour_exec)]).cour_code
exet = "XXX"
output = cate+"-"+cour+"-"+exet+"-"+cour_result
self.inte_code = output
EDIT 4 : ANSWER
Finally I've reach the desired output! using the following code:
#api.depends('inte_code')
def _onchange_proc(self):
cate_result = self.cate_exec
proc_result = self.env['enro.modl'].search([('id','=',str(self.proc_exec.id))]).enro_code
cour_result = self.env['cour.modl'].search([('id','=',str(self.cour_exec.id))]).cour_code
output = str(proc_result)+"-"+str(cate_result)+"-"+str(cour_result)+"-"+self.exec_code
self.inte_code = output
Additionaly I've added a related field for add the course category to the final output.
cate_exec = fields.Char(related='cour_exec.cour_cate.cate_code')
Now the output have this structure:
INTERNAL_PROC_ID-CAT_COURSE-COURSE-EXECUTION_CODE
EX: xxxxxxxx-xx-xxxx-xxx
First in compute field use api.depends not onchange :
Second the compute function don't return anything but it passes the record on the self variable so all you have to do is assign the value to the computed field.
#api.depends('proc_exec')
def _onchange_proc(self):
# compute the value
# ...
# Than assign it to the field
self.computed_field = computed_value
one of the thing that i recommand to do is to loop the self because it's recordSet so if the self contains more than one record this previous code will raise signlton error
so you can do this :
# compute the value here if it's the same for every record in self
for rec in self :
# compute the value here it depends on the value of the record
rec.compute_field = computeValue
or use api.one with api.depends
#api.one
#api.depends('field1', 'field2', ...)
EDITS:
#api.depends('proc_exec')
def _onchange_proc(self):
cate = "XX"
# first domain use tuple not list
cour_result = self.env['cour.modl'].search([('cour_desc','=',self.cour_exec)])
cour = "" # empty string because you cannot contcatenate None or False with a string value
if cour_result :
cour = ",".join(id for id in cour_result.ids)
else :
print "result of search is empty check you domain"
exet = "XXX"
output = cate+"-"+cour+"-"+exet
self.inte_code = output
try this code i think the result of search is a recordSet so you can get the list of ids by name_of_record_set.ids than create a string from the list of ids to concatenate it try and let me know if there is an error because i'm using work PC i don't have odoo on my hand ^^
You can create new wizard.
From wizard you can generate Internal Reference.
class create_internal_reference(models.TransientModel):
_name="create.internal.reference"
#api.multi
def create_internal_reference(self):
product_obj=self.env['product.product']
active_ids=self._context.get('active_ids')
if active_ids:
products=product_obj.browse(active_ids)
products.generate_new_internal_reference()
return True
Create View & act_window
<record model="ir.ui.view" id="create_internal_reference_1">
<field name="name">Create Internal Reference</field>
<field name="model">create.internal.reference</field>
<field name="arch" type="xml">
<form string="Create Internal Reference">
<footer>
<button name="create_internal_reference" string="Generate Internal Reference" type="object" class="oe_highlight"/>
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
<act_window name="Generate Internal Reference" res_model="create.internal.reference"
src_model="product.product" view_mode="form" view_type="form"
target="new" multi="True" key2="client_action_multi"
id="action_create_internal_reference"
view_id="create_internal_reference_1"/>
class product_product(models.Model):
_inherit='product.product'
#api.multi
def generate_new_internal_reference(self):
for product in self:
if not product.internal_reference:
product.internal_reference='%s-%s-%s'%(str(product.categ_id.name)[:2],str(product.name)[:4],third_field[:3])
From product.product under more button you can access this wizard and generate internal reference.
This may help you.

how to get value of a field in fields_view_get?

I want to get a value of a field in fields_view_get method in openerp 7.0.
I tried the following:
1- send the value of the field in the context attribute as following:
< field name="employee_id" context="{'employee_id':employee_id}" />
and in the fields_view_get I get it as following:
print "employee_id in the context value is %s"%(context.get('employee_id', False))
but it always the the context.get(...) returns False. so I tried the following:
2- on the onchange method of the field I send the value of the field in the context as following:
def onchange_employee_id(self, cr, uid, ids, employee_id):
return {'context': {'employee_id': employee_id}}
and in the fields_view_get I get it as following:
print "employee_id in the context value is %s"%(context.get('employee_id', False))
but also the same thing always the context.get(..) returns False.
How can I get the value of a field in fields_view_get function ?
Maybe this answer is too late for you, but perhaps someone will find it useful.
If you need the dynamic view just on form view, you should write a tree view and you can put the selected record id to the context...so with the context id, you can read the fields.
But fields_view_get is not too easy. Dont forget about update the return dictionary (the two very important keys: fields, arch).
If you want to use invisible or readonly tag, you should use modifiers tag like attrs.
Example:
def fields_view_get(self, cr, uid, view_id=False, view_type='tree', context=None, toolbar=False, submenu=False):
fields = self.read(cr, uid, context['working_id'], [])
actualView = super(ModelName, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
# you can write default view in xml and dynamic complete with some field in this method
actualView['fields'].update({'field_name':{'type': 'text', 'string': 'Name'}})
arch = minidom.parseString(actualView['arch'])
#for example: triggered to <newline/> field
newlineField = arch.getElementByTagName('newline').item(0)
element = arch.createElement('field_name')
element.setAttribute('name', 'Name')
newlineField.insertBefore(element, 0)
actualView['arch'] = arch.toxml("utf-8")
return actualView