Filling Many2many field (odoo 8) - python

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.

Related

Update one2many form view based on onchange

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

Automated Action assign spesific tag_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

How to add some new records to a One2many field in an onchange method in Odoo 10?

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

odoo one2many default not set

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, ...)

How to compute a databasefield with the field-id

Model:
db.define_table('orders',
Field('customer_id', db.customer)
Field('order_id', 'string')
)
I want to get a special order_id like XY-150012 where XY is part of the customer name, 15 is the year and 12 the id the actual record-id of orders. I tried in the model:
db.orders.order_id.compute = lambda r: "%s-%s00%s" % (db.customer(r['customer_id']).short, str(request.now.year)[2:], r['id'])
The id is never recognized, the computation ends up as None. If I remove r['id'] from the compute-line it works.
EDIT:
After adding an extra field field('running_number', 'integer') to the model I can access this fields content.
Is there a easy way to set this fields default=db.orders.id?
SOLUTION:
With Anthony´s Input, and reading about recursive selects I came up with this solution:
db.define_table('orders',
Field('customer_id', db.customer),
Field('order_id', 'string', default = None))
def get_order_id(id, short):
y = str(request.now.year)[2:]
return '%s-%s00%s' % (short, y, id)
def set_id_after_insert(fields,id):
fields.update(id=id)
def set_order_id_after_update(s,f):
row = s.select().first()
if row['order_id'] == None:
s.update_naive(order_id=get_order_id(row['id'], row['customer_id'].short)
else:
return
db.orders._after_insert.append(lambda f,id: set_id_after_insert(f,id))
db.orders._after_update.append(lambda s,f: set_order_id_after_update(s,f))
The problem is that the record ID is not known until after the record has been inserted in the database, as the id field is an auto-incrementing integer field whose value is generated by the database, not by web2py.
One option would be to define an _after_insert callback that updates the order_id field after the insert:
def order_after_insert(fields, id):
fields.update(id=id)
db(db.order.id == id).update(order_id=db.order.order_id.compute(fields))
db.order._after_insert.append(order_after_insert)
You might also want to create an _after_update callback, but in that case, be sure to use the update_naive argument in both callbacks when defining the Set (see above link for details).
Depending on how the order_id is used, another option might be a virtual field.

Categories

Resources