Search code examples
odoo

ValueError: Expected singleton: daily.attendance.line(123,124,125


@api.model
def create(self, vals):
    curr = datetime.now()
    new_date = datetime.strftime(curr, '%Y-%m-%d')
    cal_obj = self.env['daily.attendance'].search([])

@api.constrains('date')
def _date_test_unique(self):
     for rec in self:
        if self.search_count([('date', '=', rec.date)]) > 1:
            raise ValidationError(_('Current Date Attendance Already Existed!'))
          
@api.onchange('user_id')
def onchange_department(self):
    if self.user_id == True:
        emps = self.env['hr.employee'].search([])
        emp_attd = []
        from datetime import datetime

        now = datetime.now() # current date and time
        check_in = now.strftime('%Y-%m-%d %H:%M:%S')
        check_in_from = now.strftime('%Y-%m-%d 05:30')
        check_out = now.strftime('%Y-%m-%d %H:%M:%S')
        check_out_from = now.strftime('%Y-%m-%d 14:30')
        for emp in emps:
            vals = {
                'employe_id':emp.id,
                'check_in': check_in_from,
                'check_out': check_out_from,
                'is_present': True
            }
            emp_attd.append([0, 0, vals])
        self.update({
            'employee_ids': emp_attd,
        })
    else:
        self.employee_ids = False
    return {
        'type': 'ir.actions.client',
        'tag': 'reload',
    }      

Solution

  • The error happens when Odoo tries to get employee_ids value from a record set but it expects a record.

    for emp in self.employee_ids:
    

    You need to loop over self then access employee_ids field value for each record:

    Example:

    def attendance_validate(self):
        for rec in self:
            for emp in rec.employee_ids:
    

    You should move the following code outside the for loop

    self.write({'state': 'validate', })
    

    Example:

    hr_attendance = self.env['hr.attendance']
    for rec in self:
        for emp in rec.employee_ids:
            if emp.is_present == True:
                attd_crete_id = hr_attendance .create({'employee_id': emp.employe_id.id,
                                             'check_in': emp.check_in,
                                             'check_out': emp.check_out,
                                             })
        rec.write({
            'state': 'validate',
        })
        ...
    

    Probably you need to call write state to validate when the attendance_validate method succeed (at the end)

    improvement:

    • The following expression

        if emp.is_present == True:
      

      can be simplified to:

        if emp.is_present:
      
    • You are using two fields is_present and is_absent, you can simply use is_present and when its value is False (not set) the employee is absent.

    • You need to remove the second if statement, which is useless

      elif emp.is_absent == True:
          if emp.is_absent == True:
      
    • Avoid raising a validation error in the create method because it will break the workflow, instead you can define a constraint on date field:

        @api.constrains('date')
        def _date_test_unique(self):
            for rec in self:
                if self.search_count([('date', '=', rec.date)]) > 1:
                    raise ValidationError(_('Current Date Attendance Already Existed!'))
      

    Update:

    The create method should return the newly created record:

    @api.model
    def create(self, vals):
        res = super(CLASS_NAME, self).create(vals)
        # Your code
        return res