# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import api, models, fields, _ from odoo.exceptions import AccessError class User(models.Model): _inherit = ['res.users'] # note: a user can only be linked to one employee per company (see sql constraint in ´hr.employee´) employee_ids = fields.One2many('hr.employee', 'user_id', string='Related employee') employee_id = fields.Many2one('hr.employee', string="Company employee", compute='_compute_company_employee', store=True) job_title = fields.Char(related='employee_id.job_title', readonly=False) work_phone = fields.Char(related='employee_id.work_phone', readonly=False) mobile_phone = fields.Char(related='employee_id.mobile_phone', readonly=False) phone = fields.Char(related='employee_id.phone', readonly=False, related_sudo=False) work_email = fields.Char(related='employee_id.work_email', readonly=False, related_sudo=False) category_ids = fields.Many2many(related='employee_id.category_ids', string="Employee Tags", readonly=False, related_sudo=False) department_id = fields.Many2one(related='employee_id.department_id', readonly=False, related_sudo=False) address_id = fields.Many2one(related='employee_id.address_id', readonly=False, related_sudo=False) work_location = fields.Char(related='employee_id.work_location', readonly=False, related_sudo=False) parent_id = fields.Many2one(related='employee_id.parent_id', related_sudo=False) coach_id = fields.Many2one(related='employee_id.coach_id', readonly=False, related_sudo=False) address_home_id = fields.Many2one(related='employee_id.address_home_id', readonly=False, related_sudo=False) is_address_home_a_company = fields.Boolean(related='employee_id.is_address_home_a_company', readonly=False, related_sudo=False) km_home_work = fields.Integer(related='employee_id.km_home_work', readonly=False, related_sudo=False) # res.users already have a field bank_account_id and country_id from the res.partner inheritance: don't redefine them employee_bank_account_id = fields.Many2one(related='employee_id.bank_account_id', string="Employee's Bank Account Number", related_sudo=False, readonly=False) employee_country_id = fields.Many2one(related='employee_id.country_id', string="Employee's Country", readonly=False, related_sudo=False) identification_id = fields.Char(related='employee_id.identification_id', readonly=False, related_sudo=False) passport_id = fields.Char(related='employee_id.passport_id', readonly=False, related_sudo=False) gender = fields.Selection(related='employee_id.gender', readonly=False, related_sudo=False) birthday = fields.Date(related='employee_id.birthday', readonly=False, related_sudo=False) place_of_birth = fields.Char(related='employee_id.place_of_birth', readonly=False, related_sudo=False) country_of_birth = fields.Many2one(related='employee_id.country_of_birth', readonly=False, related_sudo=False) marital = fields.Selection(related='employee_id.marital', readonly=False, related_sudo=False) spouse_complete_name = fields.Char(related='employee_id.spouse_complete_name', readonly=False, related_sudo=False) spouse_birthdate = fields.Date(related='employee_id.spouse_birthdate', readonly=False, related_sudo=False) children = fields.Integer(related='employee_id.children', readonly=False, related_sudo=False) emergency_contact = fields.Char(related='employee_id.emergency_contact', readonly=False, related_sudo=False) emergency_phone = fields.Char(related='employee_id.emergency_phone', readonly=False, related_sudo=False) visa_no = fields.Char(related='employee_id.visa_no', readonly=False, related_sudo=False) permit_no = fields.Char(related='employee_id.permit_no', readonly=False, related_sudo=False) visa_expire = fields.Date(related='employee_id.visa_expire', readonly=False, related_sudo=False) google_drive_link = fields.Char(related='employee_id.google_drive_link', readonly=False, related_sudo=False) additional_note = fields.Text(related='employee_id.additional_note', readonly=False, related_sudo=False) barcode = fields.Char(related='employee_id.barcode', readonly=False, related_sudo=False) pin = fields.Char(related='employee_id.pin', readonly=False, related_sudo=False) employee_warning = fields.Char("Missing employee warning", compute='_compute_employee_warning') @api.depends('groups_id', 'employee_ids', 'active') def _compute_employee_warning(self): """ Fill warning only for active internal user (employee) not linked to hr.employee """ for user in self: if not user.employee_ids and not user.share and user.active: user.employee_warning = _("Don't forget to create the linked employee.") else: user.employee_warning = False def __init__(self, pool, cr): """ Override of __init__ to add access rights. Access rights are disabled by default, but allowed on some specific fields defined in self.SELF_{READ/WRITE}ABLE_FIELDS. """ hr_readable_fields = [ 'active', 'child_ids', 'employee_id', 'employee_ids', 'parent_id', ] hr_writable_fields = [ 'additional_note', 'address_home_id', 'address_id', 'barcode', 'birthday', 'category_ids', 'children', 'coach_id', 'country_of_birth', 'department_id', 'display_name', 'emergency_contact', 'emergency_phone', 'employee_bank_account_id', 'employee_country_id', 'gender', 'google_drive_link', 'identification_id', 'is_address_home_a_company', 'job_title', 'km_home_work', 'marital', 'mobile_phone', 'notes', 'parent_id', 'passport_id', 'permit_no', 'phone', 'pin', 'place_of_birth', 'spouse_birthdate', 'spouse_complete_name', 'visa_expire', 'visa_no', 'work_email', 'work_location', 'work_phone' ] init_res = super(User, self).__init__(pool, cr) # duplicate list to avoid modifying the original reference type(self).SELF_READABLE_FIELDS = type(self).SELF_READABLE_FIELDS + hr_readable_fields + hr_writable_fields type(self).SELF_WRITEABLE_FIELDS = type(self).SELF_WRITEABLE_FIELDS + hr_writable_fields return init_res @api.model def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): # When the front-end loads the views it gets the list of available fields # for the user (according to its access rights). Later, when the front-end wants to # populate the view with data, it only asks to read those available fields. # However, in this case, we want the user to be able to read/write its own data, # even if they are protected by groups. # We make the front-end aware of those fields by sending all field definitions. # Note: limit the `sudo` to the only action of "editing own profile" action in order to # avoid breaking `groups` mecanism on res.users form view. context_params = self._context.get('params', {}) if view_type == 'form' and context_params.get('id') == self.env.user.id and not self.env.user.share: action_id = self.env['ir.model.data'].xmlid_to_res_id('hr.res_users_action_my', raise_if_not_found=False) if action_id and context_params.get('action') == action_id: self = self.sudo() return super(User, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu) @api.multi def write(self, vals): """ Synchronize user and its related employee and check access rights if employees are not allowed to update their own data (otherwise sudo is applied for self data). """ hr_fields = { field for field_name, field in self._fields.items() if field.related_field and field.related_field.model_name == 'hr.employee' and field_name in vals } can_edit_self = self.env['ir.config_parameter'].sudo().get_param('hr.hr_employee_self_edit') or self.env.user.has_group('hr.group_hr_user') if hr_fields and not can_edit_self: # Raise meaningful error message raise AccessError(_("You are only allowed to update your preferences. Please contact a HR officer to update other informations.")) result = super(User, self).write(vals) employee_values = {} for fname in [f for f in ['name', 'email', 'image', 'tz'] if f in vals]: employee_values[fname] = vals[fname] if employee_values: if 'email' in employee_values: employee_values['work_email'] = employee_values.pop('email') self.env['hr.employee'].sudo().search([('user_id', 'in', self.ids)]).write(employee_values) return result @api.model def action_get(self): if self.env.user.employee_id: return self.sudo().env.ref('hr.res_users_action_my').read()[0] return super(User, self).action_get() @api.depends('company_id', 'employee_ids') def _compute_company_employee(self): for user in self: user.employee_id = self.env['hr.employee'].search([('id', 'in', user.employee_ids.ids), ('company_id', '=', user.company_id.id)], limit=1) @api.multi def action_create_employee(self): self.ensure_one() form_view = self.env.ref('hr.view_employee_form') return { 'name': _('Create Employee'), 'type': 'ir.actions.act_window', 'res_model': 'hr.employee', 'views': [(form_view.id, 'form')], 'target': 'new', 'context': {'default_user_id': self.id} }