ValueError Expected singleton, Odoo8
I am working on a module in Odoo8 on Ubuntu 14.04. I came up with a weird problem when saving a form record based on some One2many fields. The error says
ValueError
Expected singleton: hr.employee.pay.change(84, 85)
My Python code is below
class hr_employee_pay_change(models.Model):
_name='hr.employee.pay.change'
hr_payroll_change_ids = fields.Many2one("employee.salary.change", "Employee", ondelete="cascade")
@api.onchange('emp_basic', 'emp_allowance')
@api.depends('emp_basic', 'emp_allowance')
def _current_total(self):
self.emp_current_total = self.emp_basic + self.emp_allowance
@api.onchange('emp_propose_allowance', 'emp_propose_basic')
@api.depends('emp_propose_allowance', 'emp_propose_basic')
def _proposed_total(self):
data_val={}
self.emp_propose_total = self.emp_propose_basic + self.emp_propose_allowance
cr=self._cr
uid=self._uid
ids=self._ids
val=int(self.employee_name)
if val:
cr.execute("select max_salary,min_salary from hr_job where id in (select job_id from hr_employee where id='"+str(val)+"')")
res=cr.fetchall()
for data_val in res:
max_sal=data_val[0]
min_sal=data_val[1]
if not min_sal < self.emp_propose_total < max_sal:
self.emp_propose_basic = 0.0
self.emp_propose_allowance = 0.0
return {'warning':{'title':'warning','message':'Out of Range, Proposed Total must be in between "'+str(max_sal)+'"to"'+str(min_sal)+'"'}}
else:
cr.execute("select wage from hr_contract where employee_id=0")
@api.onchange('employee_name')
@api.depends('employee_name')
def get_data(self):
data={}
cr=self._cr
uid=self._uid
ids=self._ids
value=int(self.employee_name)
if(self.employee_name):
cr.execute("select wage,allowance from hr_contract where employee_id ='"+str(value)+"'")
res=cr.fetchall()
for data in res:
self.emp_basic=data[0]
self.emp_allowance = data[1]
else:
cr.execute("select wage,allowance from hr_contract where employee_id=0")
employee_name = fields.Many2one('hr.employee', 'Employee Name', required=True )
zeo_number = fields.Char(related='employee_name.zeo_number', string='ZEO Number', readonly=True )
emp_basic = fields.Float('Basic Salary', compute='get_data',readonly=True, store=True )
emp_allowance = fields.Float('Allowance', compute='get_data',readonly=True, store=True )
emp_current_total = fields.Float('Totals', compute='_current_total', store=True, track_visibility='always')
emp_propose_basic = fields.Float('Proposed Basic')
emp_propose_allowance = fields.Float('Proposed Allowance')
emp_propose_total = fields.Float('Proposed Totals', compute='_proposed_total', store=True, track_visibility='always')
I cannot get this problem. I tried removing the "readonly = True" property of this field and the problem is fixed, but I need to have them as read-only. Offer hopes
source to share
Expected singleton:
Class methods require one caller (single reachable record) to invoke the method and suppose it will invoke multiple callers (Browsable Recordsets) then the method won't be able to determine which object it should be processed for, so it will throw Expected error singleton .
The new API decorator is used to define a method call pattern when methods allow only one object or multiple objects to call that method.
@ api.one
This decorator will automatically loop over the RecordSet for you. Self is overridden as the current record
Note: Attention: the return value is placed in the list. This is not always supported by the web client for example. button action methods. In this case, you should use @ api.multi to decorate your method and possibly call self.ensure_one () in the method definition.
@ api.multi
Self will be the current RecordSet without iteration. This is the default behavior (multiple objects available for viewing). Methods returning non-transitive data (list, dictionary, function) should be decorated with @ api.multi
@ api.model
This decorator will convert old API calls to a decorated function into a new API signature. This allows you to be polite when the migration code. Self does not contain entries / entries in methods decorated with this decorator.
So just call it
self.env ['model_name']. Method_name (arguments)
You should try
class hr_employee_pay_change(models.Model):
_name='hr.employee.pay.change'
hr_payroll_change_ids = fields.Many2one("employee.salary.change", "Employee", ondelete="cascade")
@api.onchange('emp_basic', 'emp_allowance')
@api.depends('emp_basic', 'emp_allowance')
def _current_total(self):
for rec in self:
rec.emp_current_total = rec.emp_basic + rec.emp_allowance
@api.onchange('emp_propose_allowance', 'emp_propose_basic')
@api.depends('emp_propose_allowance', 'emp_propose_basic')
def _proposed_total(self):
for rec in self:
data_val={}
rec.emp_propose_total = rec.emp_propose_basic + rec.emp_propose_allowance
cr=self._cr
uid=self._uid
ids=self._ids
val=int(rec.employee_name)
if val:
cr.execute("select max_salary,min_salary from hr_job where id in (select job_id from hr_employee where id='"+str(val)+"')")
res=cr.fetchall()
for data_val in res:
max_sal=data_val[0]
min_sal=data_val[1]
if not min_sal < self.emp_propose_total < max_sal:
self.emp_propose_basic = 0.0
self.emp_propose_allowance = 0.0
return {'warning':{'title':'warning','message':'Out of Range, Proposed Total must be in between "'+str(max_sal)+'"to"'+str(min_sal)+'"'}}
else:
cr.execute("select wage from hr_contract where employee_id=0")
@api.onchange('employee_name')
@api.depends('employee_name')
def get_data(self):
for rec in self:
data={}
cr=self._cr
uid=rec._uid
ids=rec._ids
value=int(rec.employee_name)
if(rec.employee_name):
cr.execute("select wage,allowance from hr_contract where employee_id ='"+str(value)+"'")
res=cr.fetchall()
for data in res:
rec.emp_basic=data[0]
rec.emp_allowance = data[1]
else:
cr.execute("select wage,allowance from hr_contract where employee_id=0")
source to share