Odoo: dynamically set field which not getting stored - python

I have a field "qty_av" which i set dynamically via an onchange method depending on field "branch_product_ids" value, the "qty_av" is successfully set as long as i haven't saved the record yet
But once the record is saved "qty_av" is turned into null
Before:
After:
My code
branch_product_ids = fields.Many2one(comodel_name="custom.product", string="Product",
domain="[('branch_line.branch_id.user_lines.user_id','=', user_id)]")
user_id = fields.Many2one('res.users', 'Current User', default=lambda self: self.env.user.id)
branch_id = fields.Many2one('custom.branch', string="Branch", required=False, compute="_get_branch", store=True)
qty_av = fields.Integer('Av Qty', readonly=True, store=True)
#api.onchange('branch_product_ids')
def onchange_product(self):
selected_lines = []
if self.branch_product_ids:
for rec in self:
selected_lines = rec.env['custom.branch.line'].search(
['&', ('product_id', '=', rec.branch_product_ids.id), ('branch_id', '=', rec.branch_id.id)]).mapped(
'qty')
if not selected_lines:
raise ValidationError(
_('Current branch has ZERO stock on this product, Please select an available Product'))
else:
rec.qty_av = selected_lines[0]

Because you are making it read-only that is why.
To store read-only field try this.
In Python:
qty_av = fields.Integer('Av Qty')
In XML:
<field name="qty_av" readonly="1" force_save="1"/>

Related

Get records from odoo relational table

I have two models in my odoo project. Employee and equipment, as shown bellow.
Equipment/model.py
from openerp import models, fields, api
import datetime
class equipment(models.Model):
_name = 'equipment.equipment'
name = fields.Char(string='Name', )
date_of_purchase = fields.Date(string='Date Of Purchase', default=fields.Date.today(), )
write_off_days = fields.Integer(string="Days To Write-off", required=True, )
write_off_date = fields.Date(string="Write-off Date", compute="_get_write_off_date", )
price = fields.Float(string="Price '$'", required=True, )
description = fields.Char(string="Description", required=False, )
employee_id = fields.Char(string="Owner", compute="_get_owner", )
#api.one
#api.depends('employee_id')
def _get_owner(self):
//result = self.env.['res.equipment_table'].
//get id from relation database <-------------
#api.one
#api.depends('write_off_days', 'date_of_purchase')
def _get_write_off_date(self):
date = datetime.datetime.strptime(self.date_of_purchase, "%Y-%m-%d")
self.write_off_date = date + datetime.timedelta(days=self.write_off_days)
employee/model.py
from openerp import models, fields, api
class employee(models.Model):
_name = 'employee.employee'
name = fields.Char(string='First Name')
last_name = fields.Char(string='Last Name')
birth_date = fields.Date(string='Birth Date', default=fields.Date.today(), )
equipment_ids = fields.Many2many(string="Equipment", comodel_name="equipment.equipment", relation="equipment_table", )
total_equipment_price = fields.Float(string="Total Equipment Price '$'", compute="_get_total_equipment_price", )
#api.one
#api.depends('equipment_ids')
def _get_total_equipment_price(self):
total = 0
for equipment in self.equipment_ids:
total += equipment.price
self.total_equipment_price = total
I have many2many field, which holds all equipment that employee owns. I need to update the equipment owner every time the field is changed. The reason for this is.. when a user adds new equipment to the employee, there should be shown only unowned equipment. That is why I need to check and update the owner.
I already made a domain to check if equipment already has an owner, which will be shown below. Just need to update that employee_id field somehow.
<notebook>
<page string="Equipment">
<group>
<field name="equipment_ids" domain="[('employee_id', '=', False)]"/>
</group>
</page>
</notebook>
Change the type of employee_id to Many2one:
employee_id = fields.Many2one('employee.employee', string="Owner")
Override create and write methods to set employee_id each time new equipment is added to the list:
class Employee(models.Model):
_name = 'employee.employee'
#api.model
def create(self, values):
res = super(Employee, self).create(values)
if res.equipment_ids:
res.equipment_ids.write({'employee_id': res.id})
return res
#api.multi
def write(self, values):
res = super(Employee, self).write(values)
for r in self:
equipment_ids = r.equipment_ids.filtered(lambda s: not s.employee_id)
if equipment_ids:
equipment_ids.write({'employee_id': r.id})
return res
Because an equipment can set to one owner, I suggest you to change the type of equipment_ids to One2many to be able to set a list of equipments by employee and the employee_id field value will be set automatically for you when you add equipment to the list.
If you change the value of employee_id the equipment will be automatically visible in the list of equipments of the new employee.
equipment_ids = fields.One2many("equipment.equipment", 'employee_id', string="Equipments")
Reset owner
#api.multi
def write(self, values):
removed_ids = set()
old_ids = {r.id: r.equipment_ids.ids for r in self}
res = super(Employee, self).write(values)
for r in self:
equipment_ids = r.equipment_ids.filtered(lambda s: not s.employee_id)
if equipment_ids:
equipment_ids.write({'employee_id': r.id})
removed_ids |= set(old_ids[r.id]) - set(r.equipment_ids.ids)
self.equipment_ids.browse(removed_ids).write({'employee_id': False})
return res

Odoo: How to set a dynamic domain to a many2many field

I want to change the retrieved set of values of a many2many field according to a many2one field onchange function, it worked well with another many2one field, but doesn't seem to filter the outcome on a many2many field
my code is as follows
class CustomPurchase(models.Model):
_name = 'custom.purchase'
_description = 'Purchase Record'
supplier_id = fields.Many2one('custom.supplier', string='Supplier', required=True)
product_ids = fields.Many2many('custom.supply.line', string='Purchase Lines', required=True)
#api.onchange('supplier_id')
def onchange_supplier(self):
selected_lines = []
if self.supplier_id:
for rec in self:
selected_lines = rec.env['custom.supply.line'].search([('supplier_id', '=', rec.supplier_id.id)])
domain = {'product_ids': [('id', '=', selected_lines.id)]}
return {'domain': domain, 'value': {'selected_lines': []}}
Expected behavior is to have just the items related to the supplier_id many2one field
Produced behavior is all the items are retrieved
Edit:
I've noticed that i when i remove widget="section_and_note_one2many" the domain works perfectly, yet the tree view can't be edited within the same form, even with editable="bottom"
You can add check using supplier field directly inside domain.
Code:
#api.onchange('supplier_id')
def onchange_supplier(self):
domain = {'product_ids': []}
for rec in self:
if rec.supplier_id:
domain = {'product_ids': [('supplier_id', '=', rec.supplier_id.id)]}
return {'domain': domain}
UPDATE:
Try to implement this as same as in /addons/mrp/models/mrp_bom.py on attribute_value_ids. [Version:12]

How to get the value of a dynamic many2many field in create() function

I want to get the value from of a dynamically populated many2many field in create() function, but i get this outcome [[6, False, [98]]], 98 is actually the expected outcome though
this is my code below
class CustomTransRequest(models.Model):
_name = 'custom.trans.request'
_description = 'Transfer Request'
branch_from_id = fields.Many2one('custom.branch', string="From", required=True)
branch_to_id = fields.Many2one('custom.branch', string="To", required=True)
line_id = fields.Many2one('custom.branch.line', string="Products", required=True)
product_id = fields.Many2many('custom.product', required=False, )
qty = fields.Integer(string="Qty", required=True)
#api.onchange('line_id')
def onchange_line(self):
if self.line_id:
for rec in self:
selected_products = rec.env['custom.branch.line'].search(
[('id', '=', rec.line_id.id)]).mapped('product_id')
self.product_id = [(6, 0, selected_products.ids)]
#api.model
def create(self, vals):
print("Create Function ")
print("SELECT id FROM custom_branch_line WHERE (branch_id = %s) AND (product_id = %s)" % (
vals.get('branch_to_id'), vals['product_id']))
result = super(CustomTransRequest, self).create(vals)
return result
This how Odoo Handles X2many fields, by convention they are called command (or list of command) most of the time in the create method, the command that will be passed for your m2m fields will be:
# only one command 6 which tell Odoo replace all record with the selected ids
[(6, 0, [list_of_selected_record_ids)]
So in order to retrieve them just do: vals['product_id'][0][2]
No I don't know if you are just trying to show select query or you want to use, if you are just printing it:
# replace vals['product_id'] with
'({})'.format(','.join(vals['product_id'][0][2]))
If you will execute it, use query params:
self.cr.execute("SELECT id FROM custom_branch_line WHERE (branch_id = %s) AND (product_id = %s)", (vals['branch_to_id'], vals['product_id'][0][2]))
for more information about X2many command check this:
One2many and Many2many use a special "commands"
Note: I assumed that this field will not be empty if not you need to check if the fields are not empty first.

Domain in Many2one Odoo 11

I have three models
class ZohoTags(models.Model):
_name = 'zoho.tags'
name = fields.Char(string="Tags")
tag_id = fields.Char(string="Tag Id")
class TagsLine(models.Model):
_name = 'zoho.tags.line'
x_zoho_tags = fields.Many2one('zoho.tags', string='Tags')
x_tags_option = fields.Many2one('zoho.tag.option', string='Tags Option', domain="[('tag_ids', '=', x_zoho_tags.tag_id)]")
rules_id = fields.Many2one('hr.salary.rule')
class TagOptions(models.Model):
_name = 'zoho.tag.option'
name = fields.Char(string="tag option name")
option_tag_id = fields.Char(string="tag option id")
tag_ids = fields.Char(string="tag_id")
In the zoho.tags model, I have a field called tag_id and in the zoho.tag.option, I have tag_ids and both are having the same values.
In the zoho.tags.line model, I have a Many2one field called x_zoho_tags, which shows a list of tags like: division, state, etc. and x_tags_option, which shows options for each tag, such as:
Tag (division) has options (A,B,C) and these options are having the same tag_ids stored for (division) tag
I want to add a domain to x_tags_option in order to filter x_tag_option
to show only options that are having the same tag_id.
So when I select division from x_zoho_tags, then x_tags_option should show only A, B and C.
I have tried to add this line below, but it does not work
domain="[('tag_ids', '=', x_zoho_tags.tag_id)]
I have figure it out. This is how I have done it:
In python:
#api.onchange('x_zoho_tags')
def onchange_tags(self):
res = {}
if self.x_zoho_tags:
res['domain'] = {'x_tags_option': [('tag_ids', '=', self.x_zoho_tags.tag_id)]}
return res
In XML:
<field name="x_zoho_tags"/>
<field name="x_tags_option" onchange="onchange_tags(x_zoho_tags)"/>

api.constrain for give condition if one of field is empty

I tried to use api.constrain in odoo. The case is, I want to give condition to odoo if user missing one field, odoo will give some warning like alert, and user have to give some input to the previous field. This is my code :
class Provinc(models.Model):
_name = 'provinsi.model'
_rec_name ='prov'
prov = fields.Char(
string='Provinsi',
)
res_partner_ids = fields.One2many(
'res.partner',
'provinsi'
city_id = fields.One2many(
'city.model',
'provinsi_id'
)
class city(models.Model):
_name = 'kota.model'
_rec_name ='city'
city = fields.Char(
string='City',
)
res_partner_city = fields.One2many(
'res.partner',
'city'
)
provinsi_id = fields.Many2one(
'provinsi.model',
string='provinsi',
)
class Master_data(models.Model):
_inherit = 'res.partner'
provinsi = fields.Many2one(
'provinsi.model',
'provinsi',
)
city = fields.Many2one(
'city.model',
'city',
)
#api.onchange('provinsi')
def show_provinsi(self):
return {'domain': {'city': [('provinsi_id', '=', self.provinsi.id)]}}
#api.constrains('provinsi')
#api.onchange('city')
def show_kota(self):
for record in self:
if record.provinsi == False:
raise ValidationError("is gonna be error")
I have tried 2 ways. First, I put the api.constrain insode class City, and it's doesn't work,second ways I tried put the api.constrain like the code inside class master, and the result remains the same.
you only need onchang not any constrains to display warning!
#api.onchange('city')
def show_kota(self):
if self.city and not self.provinsi:
raise ValidationError("is gonna be error")
now if you select value in city field and provinsi missing value then it will display error msg
guessing field "city" and "provinsi" is in 'res.partner' form view!
If you want to check a field value is empty or not, just use required ="1" like:
<field name="provinsi" required="1"/>

Categories

Resources