diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/hr/models/hr_employee_base.py | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/hr/models/hr_employee_base.py')
| -rw-r--r-- | addons/hr/models/hr_employee_base.py | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/addons/hr/models/hr_employee_base.py b/addons/hr/models/hr_employee_base.py new file mode 100644 index 00000000..9732f6da --- /dev/null +++ b/addons/hr/models/hr_employee_base.py @@ -0,0 +1,179 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from ast import literal_eval + +from odoo import api, fields, models +from pytz import timezone, UTC, utc +from datetime import timedelta + +from odoo.tools import format_time + + +class HrEmployeeBase(models.AbstractModel): + _name = "hr.employee.base" + _description = "Basic Employee" + _order = 'name' + + name = fields.Char() + active = fields.Boolean("Active") + color = fields.Integer('Color Index', default=0) + department_id = fields.Many2one('hr.department', 'Department', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]") + job_id = fields.Many2one('hr.job', 'Job Position', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]") + job_title = fields.Char("Job Title", compute="_compute_job_title", store=True, readonly=False) + company_id = fields.Many2one('res.company', 'Company') + address_id = fields.Many2one('res.partner', 'Work Address', compute="_compute_address_id", store=True, readonly=False, + domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]") + work_phone = fields.Char('Work Phone', compute="_compute_phones", store=True, readonly=False) + mobile_phone = fields.Char('Work Mobile') + work_email = fields.Char('Work Email') + work_location = fields.Char('Work Location') + user_id = fields.Many2one('res.users') + resource_id = fields.Many2one('resource.resource') + resource_calendar_id = fields.Many2one('resource.calendar', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]") + parent_id = fields.Many2one('hr.employee', 'Manager', compute="_compute_parent_id", store=True, readonly=False, + domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]") + coach_id = fields.Many2one( + 'hr.employee', 'Coach', compute='_compute_coach', store=True, readonly=False, + domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", + help='Select the "Employee" who is the coach of this employee.\n' + 'The "Coach" has no specific rights or responsibilities by default.') + tz = fields.Selection( + string='Timezone', related='resource_id.tz', readonly=False, + help="This field is used in order to define in which timezone the resources will work.") + hr_presence_state = fields.Selection([ + ('present', 'Present'), + ('absent', 'Absent'), + ('to_define', 'To Define')], compute='_compute_presence_state', default='to_define') + last_activity = fields.Date(compute="_compute_last_activity") + last_activity_time = fields.Char(compute="_compute_last_activity") + hr_icon_display = fields.Selection([ + ('presence_present', 'Present'), + ('presence_absent_active', 'Present but not active'), + ('presence_absent', 'Absent'), + ('presence_to_define', 'To define'), + ('presence_undetermined', 'Undetermined')], compute='_compute_presence_icon') + + @api.depends('user_id.im_status') + def _compute_presence_state(self): + """ + This method is overritten in several other modules which add additional + presence criterions. e.g. hr_attendance, hr_holidays + """ + # Check on login + check_login = literal_eval(self.env['ir.config_parameter'].sudo().get_param('hr.hr_presence_control_login', 'False')) + employee_to_check_working = self.filtered(lambda e: e.user_id.im_status == 'offline') + working_now_list = employee_to_check_working._get_employee_working_now() + for employee in self: + state = 'to_define' + if check_login: + if employee.user_id.im_status == 'online' or employee.last_activity: + state = 'present' + elif employee.user_id.im_status == 'offline' and employee.id not in working_now_list: + state = 'absent' + employee.hr_presence_state = state + + @api.depends('user_id') + def _compute_last_activity(self): + presences = self.env['bus.presence'].search_read([('user_id', 'in', self.mapped('user_id').ids)], ['user_id', 'last_presence']) + # transform the result to a dict with this format {user.id: last_presence} + presences = {p['user_id'][0]: p['last_presence'] for p in presences} + + for employee in self: + tz = employee.tz + last_presence = presences.get(employee.user_id.id, False) + if last_presence: + last_activity_datetime = last_presence.replace(tzinfo=UTC).astimezone(timezone(tz)).replace(tzinfo=None) + employee.last_activity = last_activity_datetime.date() + if employee.last_activity == fields.Date.today(): + employee.last_activity_time = format_time(self.env, last_activity_datetime, time_format='short') + else: + employee.last_activity_time = False + else: + employee.last_activity = False + employee.last_activity_time = False + + @api.depends('parent_id') + def _compute_coach(self): + for employee in self: + manager = employee.parent_id + previous_manager = employee._origin.parent_id + if manager and (employee.coach_id == previous_manager or not employee.coach_id): + employee.coach_id = manager + elif not employee.coach_id: + employee.coach_id = False + + @api.depends('job_id') + def _compute_job_title(self): + for employee in self.filtered('job_id'): + employee.job_title = employee.job_id.name + + @api.depends('address_id') + def _compute_phones(self): + for employee in self: + if employee.address_id and employee.address_id.phone: + employee.work_phone = employee.address_id.phone + else: + employee.work_phone = False + + @api.depends('company_id') + def _compute_address_id(self): + for employee in self: + address = employee.company_id.partner_id.address_get(['default']) + employee.address_id = address['default'] if address else False + + @api.depends('department_id') + def _compute_parent_id(self): + for employee in self.filtered('department_id.manager_id'): + employee.parent_id = employee.department_id.manager_id + + @api.depends('resource_calendar_id', 'hr_presence_state') + def _compute_presence_icon(self): + """ + This method compute the state defining the display icon in the kanban view. + It can be overriden to add other possibilities, like time off or attendances recordings. + """ + working_now_list = self.filtered(lambda e: e.hr_presence_state == 'present')._get_employee_working_now() + for employee in self: + if employee.hr_presence_state == 'present': + if employee.id in working_now_list: + icon = 'presence_present' + else: + icon = 'presence_absent_active' + elif employee.hr_presence_state == 'absent': + # employee is not in the working_now_list and he has a user_id + icon = 'presence_absent' + else: + # without attendance, default employee state is 'to_define' without confirmed presence/absence + # we need to check why they are not there + if employee.user_id: + # Display an orange icon on internal users. + icon = 'presence_to_define' + else: + # We don't want non-user employee to have icon. + icon = 'presence_undetermined' + employee.hr_icon_display = icon + + @api.model + def _get_employee_working_now(self): + working_now = [] + # We loop over all the employee tz and the resource calendar_id to detect working hours in batch. + all_employee_tz = set(self.mapped('tz')) + for tz in all_employee_tz: + employee_ids = self.filtered(lambda e: e.tz == tz) + resource_calendar_ids = employee_ids.mapped('resource_calendar_id') + for calendar_id in resource_calendar_ids: + res_employee_ids = employee_ids.filtered(lambda e: e.resource_calendar_id.id == calendar_id.id) + start_dt = fields.Datetime.now() + stop_dt = start_dt + timedelta(hours=1) + from_datetime = utc.localize(start_dt).astimezone(timezone(tz or 'UTC')) + to_datetime = utc.localize(stop_dt).astimezone(timezone(tz or 'UTC')) + # Getting work interval of the first is working. Functions called on resource_calendar_id + # are waiting for singleton + work_interval = res_employee_ids[0].resource_calendar_id._work_intervals(from_datetime, to_datetime) + # Employee that is not supposed to work have empty items. + if len(work_interval._items) > 0: + # The employees should be working now according to their work schedule + working_now += res_employee_ids.ids + return working_now + |
