I wrote a wizard which form view should show a one2many field with rows taken from context['active_ids'].
I set the one2many default correctly, but when the form opens, no rows are showed.
Did I miss anything? (I apologize for code bad indentation)
class delivery_wizard(models.TransientModel):
_name = 'as.delivery.wizard'
address = fields.Many2one('res.partner')
details = fields.One2many('as.delivery.detail.wizard', 'delivery')
carrier = fields.Many2one('delivery.carrier')
#api.model
def default_get(self, fields_list):
res = models.TransientModel.default_get(self, fields_list)
ids = self.env.context.get('active_ids', [])
details = self.env['as.delivery.detail'].browse(ids)
dwz = self.env['as.delivery.detail.wizard']
dws = []
for detail in details:
dw = dwz.create({
'production': detail.production_id.id,
'quantity': detail.quantity,
'actual_quantity': detail.quantity,
'enabled': detail.production_id.state == 'done',
'delivery': self.id,
})
dws.append(dw.id)
res['details'] = [(6, False, dws)]
res['address'] = details[0].delivery_id.address_id.id
return res
class delivery_detail_wizard(models.TransientModel):
_name = 'as.delivery.detail.wizard'
production = fields.Many2one('as.production')
quantity = fields.Float()
actual_quantity = fields.Float()
force = fields.Boolean()
enabled = fields.Boolean()
delivery = fields.Many2one('as.delivery.wizard')
The problem may be there :
res['details'] = **[(6, False, dws)]**
Your details field is a One2many field, [(6,0, [IDS])] are for Many2many.
In your case, you don't need to assign anything to the details fields ; it's a One2many, so it's automatic as you already created the corresponding Many2one record (dw).
Little reminder from the doc :
For Many2many
For a many2many field, a list of tuples is expected. Here is the list
of tuple that are accepted, with the corresponding semantics
(0, 0, { values }) link to a new record that needs to be created
with the given values dictionary
(1, ID, { values }) update the linked record with id = ID (write
values on it)
(2, ID) remove and delete the linked record with id =
ID (calls unlink on ID, that will delete the object completely, and
the link to it as well)
(3, ID) cut the link to the linked record with id = ID
(delete the relationship between the two objects but does not delete
the target object itself)
(4, ID) link to existing record with id = ID (adds a
relationship)
(5) unlink all (like using (3,ID) for all linked
records)
(6, 0, [IDs]) replace the list of linked IDs (like using (5)
then (4,ID) for each ID in the list of IDs)
Example: [(6, 0, [8, 5, 6, 4])] sets the many2many to ids [8, 5, 6,
4]
And One2many :
(0, 0, { values }) link to a new record that needs to be created
with the given values dictionary
(1, ID, { values }) update the linked record with id = ID (write
values on it)
(2, ID) remove and delete the linked record with id =
ID (calls unlink on ID, that will delete the object completely, and
the link to it as well)
Example: [(0, 0, {'field_name':field_value_record1, ...}), (0, 0,
{'field_name':field_value_record2, ...})]
Also, try to follow odoo guidelines for Many2One/One2many fields if you want your code to be easily understandable by other people :
One2Many and Many2Many fields should always have _ids as suffix (example: sale_order_line_ids)
Many2One fields should have _id as suffix (example : partner_id, user_id, ...)
Related
I assign for each project many tasks into task view form by using many2one field related project model. Then i create one2many field into project model to retrieve tasks directly into project View form, and into the code i'm looping from all the one2many fields for all tasks and append value into the one one2many field for displaying all tasks,the project_id_for_project is many2one field inside project model used to give the abaility of when i select one project it give all the attached tasks i hope you get my idea so i created the two model like below:
class project(models.Model):
_name = 'project.project'
_description = 'project.project'
project_id_for_project = fields.Many2one('project.project' )
Project_task_aff = fields.One2many('tasks.tasks','task_aff')
#api.onchange('project_id_for_project')
def getone2manyproject(self):
for rec in self:
lines = []
for line in rec.project_id_for_project.Project_task_aff :
val = {
# 'task_aff' : line.id ,
'task_actor' : line.task_actor,
'name' : line.name,
'DATE_tsk' : line.DATE_tsk,
'Description' : line.Description,
}
lines.append((0,0, val))
rec.Project_task_aff = lines
and the task model :
class tasks(models.Model):
_name = 'tasks.tasks'
_description = 'tasks.tasks'
_inherit = ['mail.thread', 'mail.activity.mixin']
task_actor = fields.Many2one('res.users', string='Chauffeur')
task_aff = fields.Many2one('project.project')
name = fields.Char()
DATE_tsk = fields.Date()
Description = fields.Char()
project_id = fields.Many2one('project.project')
the code give update the one2many field Project_task_aff but it dont give all the taks from task module: it mean that when i go into task model view, and create 5 entries related to a project, but when the onchange methode based of project_id_for_project field didn't give the 5 stored task but append just whose are stored into the onetomany field into the project view ?
You need to apply the relational field rules to update the value.
Rules:
(0, 0, { values }) link to a new record that needs to be created with the given values dictionary
(1, ID, { values }) update the linked record with id = ID (write values on it)
(2, ID) remove and delete the linked record with id = ID (calls unlink on ID, that will delete the object completely, and the link to it as well)
(3, ID) cut the link to the linked record with id = ID (delete the relationship between the two objects but does not delete the target object itself)
(4, ID) link to existing record with id = ID (adds a relationship)
(5) unlink all (like using (3,ID) for all linked records)
(6, 0, [IDs]) replace the list of linked IDs (like using (5) then (4,ID) for each ID in the list of IDs)
rec.Project_task_aff = [(6, 0, lines)]
I think this URL help with this problem and debugging.
https://raise360.odoocommunity.net/slides/slide/how-to-update-one2many-field-from-onchange-of-field-124
Try this way.
#api.onchange('project_id_for_project')
def getone2manyproject(self):
for rec in self:
tasks = self.env['tasks.tasks'].search([('task_aff', '=', rec.id)])
rec.Project_task_aff = [(6, 0, tasks.ids)]
Edit:
What is the purpose of project_id_for_project field in project's model for child parent relationship?
May be this will help, I just retrieve the first line browse loop self, and replace the tuple (0, 0, val) with (6, 0, val) in last line
#api.onchange('project_id_for_project')
def getone2manyproject(self):
lines = []
for line in self.project_id_for_project.Project_task_aff :
val = {
# 'task_aff' : line.id ,
'task_actor' : line.task_actor.id,
'name' : line.name,
'DATE_tsk' : line.DATE_tsk,
'Description' : line.Description,
}
lines.append((6, 0, val))
self.Project_task_aff = lines
i am stuck since a couple of days in some many2many and one2many field i am trying to add value to through code. The idea is to consume a web service to get some data from a third party website and re-use these same data in my odoo 12 modules. I was able to parse the JSON request and create entities using model.Models. However, for fields using one2many or many2many i was unable to add their values and link them to my models. Here is my python code. What i want to achieve is after the creation of a record "book.db" i want to also create its category in the same time and link it to the current record. However everytime i run the code only the "book.db" model is created. The category model is never made nor linked. Can someone point me to the right direction or correct my code if possible. Thanks alot.
from odoo import models, fields, api
from . import prestashopproduct
import requests
import json
class Book(models.Model):
_name = "book.db"
prestashop_id = fields.Integer('Prestashop ID')
title = fields.Char(string="book title")
ean13_code = fields.Char(string="EAN13")
author = fields.Char(string="book author")
released = fields.Date(string="Date de publication")
type = fields.Selection([('Numérique', 'Numérique'), ('Papier', 'Papier')], string="type")
catalog = fields.Char(string="catalogue")
collection = fields.Char(string="collection")
isbn = fields.Char(string="Numero ISBN")
description = fields.Html("Description")
distributeur = fields.Char(string="Distribiteur")
code_distribiture = fields.Char(string="Code distribiteur")
code_collection = fields.Char(string="Code collection")
code_dispo = fields.Char(string="Code dispo")
code_tva1 = fields.Integer("Code tva1")
code_tva2 = fields.Integer("Code tva2")
presentation = fields.Html("Presentation")
type_produit = fields.Char(string="Type de produit")
theme_edilectre = fields.Char(string="Type de produit")
categorie = fields.Html("categorie")
poid = fields.Float("Poid en Gramme")
prix = fields.Float("Prix")
largeur = fields.Float("Largeur en MM")
epaisseur = fields.Float("Epaisseur en MM")
hauteur = fields.Float("Hauteur en MM")
image = fields.One2many('product.images', 'product_id', string='Imags du produit')
cate = fields.Many2many('product.cetegorie', 'product_id', string='Imags du produit')
image_product = fields.Char("Image")
#api.one
def get_books(self):
jso = prestashopproduct.Product.get_full_stock(self=prestashopproduct.Product())
for j in jso['products']:
if self.check_unicity(j['id']):
book = [{'title': j['name'][1]['value'],
'ean13_code': j['ean13'],
'isbn': j['isbn'],
'epaisseur': j['width'],
'largeur': j['depth'],
'hauteur': j['height'],
'poid': j['weight'],
'prestashop_id': j['id'],
'description': j['description'][1]['value'],
'presentation': j['description_short'][1]['value'],
'categorie': j['description_short'][1]['value']}]
record = self.create(book)
print (self.id)
record.cate.create({'cate': [{'product_id': record.id, 'name': 'absc'}]})
def check_unicity(self, id):
if self.search_count([('prestashop_id', '=', id)]) > 0:
return False
else:
return True
class Image(models.Model):
_name = 'product.images'
product_id = fields.Many2many('book.db', string='Prestashop ID')
product_image = fields.Binary('Image du produit')
product_image_url = fields.Char("product_image")
def donload_product_image(self, product_id, image_id):
image = prestashopproduct.Product.get_product_image(prestashopproduct.Product(), id_product=product_id,
id_image=image_id)
return image
class Categories(models.Model):
_name = 'product.cetegorie'
product_id = fields.Many2many('book.db', string="Categories")
nb_products_recursive = fields.Integer("nb_products_recursive")
name = fields.Char("Descriptif")
#api.one
def new_record(self, product_id):
self.create([{'product_id': product_id, 'name': 'a'}])
#api.model
def _repare_cate_list(self, cates=[]):
post_cates = []
existing_add = []
for cate_name in cates:
cate_ids = self.env['product.cetegorie'].search([('name', '=', cate_name)])
if cate_ids:
existing_add.append(int(cate_ids[0]))
else:
post_cates.append((0, 0, {'name': cate_name}))
post_cates.insert(0, [6, 0, existing_add])
return post_cates
#api.one
def get_books(self):
jso = prestashopproduct.Product.get_full_stock(self=prestashopproduct.Product())
for j in jso['products']:
if self.check_unicity(j['id']):
cate_vals = self._repare_cate_list(['absc'])
book = [{'title': j['name'][1]['value'],
'ean13_code': j['ean13'],
'isbn': j['isbn'],
'epaisseur': j['width'],
'largeur': j['depth'],
'hauteur': j['height'],
'poid': j['weight'],
'prestashop_id': j['id'],
'description': j['description'][1]['value'],
'presentation': j['description_short'][1]['value'],
'categorie': j['description_short'][1]['value'],
'cate':cate_vals
}]
record = self.create(book)
Also remove line product_id = fields.Many2many('book.db', string="Categories") from the 'product.cetegorie' model its not needed. As Many to many is using separate table to link categories to save them.
Whenever you want to edit, update or delete One2many or Many2many field(s) please refer below lines.
(0, 0, {values}) link to a new record that needs to be created with
the given values dictionary
(1, ID, {values}) update the linked record with id = ID (write values
on it)
(2, ID) remove and delete the linked record with id = ID (calls unlink
on ID, that will delete the object completely, and the link to it as
well)
(3, ID) cut the link to the linked record with id = ID (delete the
relationship between the two objects but does not delete the target
object itself)
(4, ID) link to existing record with id = ID (adds a relationship)
(5) unlink all (like using (3, ID) for all linked records)
(6, 0, [IDs]) replace the list of linked IDs (like using (5) then (4,
ID) for each ID in the list of IDs)
I wanna add specific tag on tag_ids on ir.attachment with an Automated Action:
Code:
if record:
if record.res_name and record.res_model_name == 'Task':
key,name = record.res_name.split(" - ")
rec = env['project.task'].search([('key','=',key)])
name_of_task = rec.key +" - " +rec.name
if rec.x_studio_parent_project.x_assign_folder:
if rec.x_studio_level == "IMPLEMENTER":
record._cr.execute("UPDATE ir_attachment SET folder_id = %s WHERE res_name= %s and res_model_name = 'Task'""",(rec.x_studio_parent_project.x_assign_folder.id, name_of_task))
elif rec.x_studio_level == "SUPERVISOR":
record._cr.execute("UPDATE ir_attachment SET folder_id = %s WHERE res_name= %s and res_model_name = 'Task'""",(rec.x_studio_parent_project.x_assign_folder.id, name_of_task))
if rec.project_id.x_assign_folder:
if rec.x_studio_level == "INTERNAL CUSTOMER":
record._cr.execute("UPDATE ir_attachment SET folder_id = %s WHERE res_name= %s and res_model_name = 'Task'""",(rec.project_id.x_assign_folder.id, name_of_task))
The code above is working but i wanna also change the tag id with specific document.facet id.
Tags = tag_ids: Many2many field
I tried:
record.write({'tag_ids':[66]})
record.write({'tag_ids':[(66)]})
record.tag_ids = [(66)]
record.tag_ids = [66]
record.tag_ids = 66
But none of them working any solution? Thanks in advance
For a many2many field, a list of tuples is expected. Following are the list of how to pass tuples.
(0, 0, { values }) link to a new record that needs to be created with
the given values dictionary
(1, ID, { values }) update the linked record with id = ID (write
values on it)
(2, ID) remove and delete the linked record with id = ID (calls unlink
on ID, that will delete the object completely, and the link to it as
well)
(3, ID) cut the link to the linked record with id = ID (delete the
relationship between the two objects but does not delete the target
object itself)
(4, ID) link to existing record with id = ID (adds a relationship)
(5) unlink all (like using (3,ID) for all linked records)
(6, 0, [IDs]) replace the list of linked IDs (like using (5) then
(4,ID) for each ID in the list of IDs)
On Many2many field, you can do like this,
record.write({'tag_ids':[(6, 0, [ID])]})
Thanks
I am trying to modify an One2many field through an onchange method. What I need is to add some records but preserve some of the existing ones before the onchange computation.
To be more accurate, I have a field named tax_line_ids. This field stores taxes. Taxes have a field named manual, a Boolean.
So each time the field my_field changes, I need to add new taxes to the One2many field tax_line_ids, but I need to preserve the old ones which have manual set to True.
Attempt A
#api.onchange('my_field')
def onchange_my_field(self):
new_tax_lines = []
tax_line_ids = self.tax_line_ids.filtered(
lambda r: r.manual).ids
# get_taxes_values returns a list of dictionaries with values
tax_grouped = self.get_taxes_values()
for tax in tax_grouped.values():
new_tax = self.env['account.invoice.tax'].create(tax)
tax_line_ids.append(new_tax.id)
self.tax_line_ids = [(6, 0, tax_line_ids)]
Problem
The onchange method works fine, but when I click on Save button, the tax_line_ids records introduced by my onchange method disappear (tax_line_ids is not a readonly field).
Attempt B
#api.onchange('my_field')
def onchange_my_field(self):
new_tax_lines = []
manual_tax_lines = self.tax_line_ids.filtered(
lambda r: r.manual)
for manual_tax_line in manual_tax_lines:
new_tax_lines.append(manual_tax_line.sudo().read()[0])
tax_grouped = self.get_taxes_values()
for tax in tax_grouped.values():
new_tax_lines.append((0, 0, tax))
self.tax_line_ids = new_tax_lines
Problem
The onchange method works fine the first time, even if I click on Save button (records does not dissapear), but if I modify my_field a second time before saving, I got a security access error (I am working with the admin):
(Document type: account.invoice.tax, Operación: read)
This is the reason why I added sudo() before the read(), just in case, but the error still remains.
Conclusion
So, in my onchange method, how can I add new records to the One2many field preserving some of the existing ones?
#api.onchange('my_field')
def onchange_my_field(self):
tax_line_ids = self.tax_line_ids.filtered(
lambda r: r.manual).ids
# get_taxes_values returns a list of dictionaries with values
tax_grouped = self.get_taxes_values()
new_tax_datas = []
for tax in tax_grouped.values():
new_tax_datas.append(tax)
self.tax_line_ids = [
(4, tl_id) for tl_id in tax_line_ids,
(0, 0, td) for td in new_tax_datas]
OR
#api.onchange('my_field')
def onchange_my_field(self):
new_tax_lines = []
tax_lines = self.tax_line_ids.filtered(
lambda r: r.manual)
# get_taxes_values returns a list of dictionaries with values
tax_grouped = self.get_taxes_values()
for tax in tax_grouped.values():
new_tax = self.env['account.invoice.tax'].create(tax)
tax_lines += new_tax
self.tax_line_ids = [(6, 0, tax_lines.ids)]
try to do like this
#api.onchange('my_field')
def onchange_my_field(self):
account_invoice_tax = self.env['account.invoice.tax']
for invoice in self:
invoice._cr.execute("DELETE FROM account_invoice_tax WHERE invoice_id=%s AND manual is False", (invoice.id,))
if invoice._cr.rowcount:
invoice.invalidate_cache()
tax_grouped = invoice.get_taxes_values()
# Create new tax lines
for tax in tax_grouped.values():
account_invoice_tax.create(tax)
I just tried existing method.
forvas
Try to do this,
return {'value': {'your_one2many_field' : list_of_ids}}
Thanks
What I've done:
I have a module with
myfield = fields.Many2one('res.partner', string="Graduate", domain=[('is_graduated', '=', True)])
Then I have another class with
_inherit = 'res.partner'
is_graduated = fields.Boolean("Graduated before?", default=False)
graduations = fields.Many2many('my_module.courses', string="Graduation courses")
What I get:
The myfield works good, but the graduations field is empty. If you edit user 1 profile you can add entries to graduation field using Add item, but I need it to be filled automaticaly.
What I expect:
I expect that every record where myfield is set to lets say user 1, will be visible in field graduations when you open user 1 profile. When I create record and set myfield value to lets say user 1, that record must to be visible in user 1 profile in the field graduations. How to achieve that?
user_rel_ids = fields.Many2many(comodel_name='course',
relation='user_course_rel',
column1='user_id',
column2='course_id')
Or
user_rel_id = fields.Many2many('course')
For Filling Data (for add new relation)
user_rel_id = [(4,course_id)]
According to http://odoo4u.blogspot.com/2014/10/orm-methods.html, It says:
A full list of options is in the documentation for the class.
This same thing will apply for one2many
For a many2many and one2many field, a list of tuples is
expected. Here is the list of the tuple that is accepted, with the
corresponding semantics:
(0, 0, { values }) link to a new record that needs to be
created with the given values dictionary
(1, ID, { values }) update the linked record with id = ID (write
values on it)
(2, ID) remove and delete the linked record with id = ID (calls
unlink on ID, that will delete the object completely, and the link to
it as well)
(3, ID) cut the link to the linked record with id = ID (delete the
relationship between the two objects but does not delete the target
object itself)
(4, ID) link to existing record with id = ID (adds a
relationship)
(5) unlink all (like using (3, ID) for all linked records)
(6, 0, [IDs]) replace the list of linked IDs (like using (5)
then (4,ID) for each ID in the list of IDs)
You need to use an onchange method for myfield, then inside it you need to fill the graduations field, something like this:
#api.onchange('myfield'):
def _onchange_myfield(self):
#fill graduations field here...
...
_inherit = 'crm.phonecall'
alarm_ids = fields.Many2many('calendar.alarm',string="Reminders")
set the alarm_ids of calendar.event model in create method of crm phonecall...
alarm_ids = [(6,0,self.alarm_ids.ids)]
_inherit = 'calendar.event'
alarm_ids = fields.Many2many('calendar.alarm',string="Reminders")
You can achieve like these.
For example:
#api.one
#api.depends(
#here you may define your depend field name
)
def _set_graduations(self):
#here comes your logic which will collect ids
#and than return it with self.field_name like
self.graduations = [list_of_ids]
graduations = fields.Many2many('my_module.courses', string='Payments',
compute='_set_graduations')
If you don't want to use #api.depends than you may use #api.multi. For reference you may check out account module with account_invoice.py file.