hr_employee.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. # -*- coding: utf-8 -*-
  2. # Part of Odoo. See LICENSE file for full copyright and licensing details.
  3. import logging
  4. from ast import literal_eval
  5. from odoo import fields, models, _, api
  6. from odoo.exceptions import UserError
  7. from odoo.fields import Datetime
  8. _logger = logging.getLogger(__name__)
  9. class Employee(models.AbstractModel):
  10. _inherit = 'hr.employee.base'
  11. email_sent = fields.Boolean(default=False)
  12. ip_connected = fields.Boolean(default=False)
  13. manually_set_present = fields.Boolean(default=False)
  14. # Stored field used in the presence kanban reporting view
  15. # to allow group by state.
  16. hr_presence_state_display = fields.Selection([
  17. ('to_define', 'To Define'),
  18. ('present', 'Present'),
  19. ('absent', 'Absent'),
  20. ])
  21. def _compute_presence_state(self):
  22. super()._compute_presence_state()
  23. employees = self.filtered(lambda e: e.hr_presence_state != 'present' and not e.is_absent)
  24. company = self.env.company
  25. employee_to_check_working = employees.filtered(lambda e:
  26. not e.is_absent and
  27. (e.email_sent or e.ip_connected or e.manually_set_present))
  28. working_now_list = employee_to_check_working._get_employee_working_now()
  29. for employee in employees:
  30. if not employee.is_absent and company.hr_presence_last_compute_date and employee.id in working_now_list and \
  31. company.hr_presence_last_compute_date.day == Datetime.now().day and \
  32. (employee.email_sent or employee.ip_connected or employee.manually_set_present):
  33. employee.hr_presence_state = 'present'
  34. @api.model
  35. def _check_presence(self):
  36. company = self.env.company
  37. if not company.hr_presence_last_compute_date or \
  38. company.hr_presence_last_compute_date.day != Datetime.now().day:
  39. self.env['hr.employee'].search([
  40. ('company_id', '=', company.id)
  41. ]).write({
  42. 'email_sent': False,
  43. 'ip_connected': False,
  44. 'manually_set_present': False
  45. })
  46. employees = self.env['hr.employee'].search([('company_id', '=', company.id)])
  47. all_employees = employees
  48. # Check on IP
  49. if literal_eval(self.env['ir.config_parameter'].sudo().get_param('hr_presence.hr_presence_control_ip', 'False')):
  50. ip_list = company.hr_presence_control_ip_list
  51. ip_list = ip_list.split(',') if ip_list else []
  52. ip_employees = self.env['hr.employee']
  53. for employee in employees:
  54. employee_ips = self.env['res.users.log'].search([
  55. ('create_uid', '=', employee.user_id.id),
  56. ('ip', '!=', False),
  57. ('create_date', '>=', Datetime.to_string(Datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)))]
  58. ).mapped('ip')
  59. if any(ip in ip_list for ip in employee_ips):
  60. ip_employees |= employee
  61. ip_employees.write({'ip_connected': True})
  62. employees = employees - ip_employees
  63. # Check on sent emails
  64. if literal_eval(self.env['ir.config_parameter'].sudo().get_param('hr_presence.hr_presence_control_email', 'False')):
  65. email_employees = self.env['hr.employee']
  66. threshold = company.hr_presence_control_email_amount
  67. for employee in employees:
  68. sent_emails = self.env['mail.message'].search_count([
  69. ('author_id', '=', employee.user_id.partner_id.id),
  70. ('date', '>=', Datetime.to_string(Datetime.now().replace(hour=0, minute=0, second=0, microsecond=0))),
  71. ('date', '<=', Datetime.to_string(Datetime.now()))])
  72. if sent_emails >= threshold:
  73. email_employees |= employee
  74. email_employees.write({'email_sent': True})
  75. employees = employees - email_employees
  76. company.sudo().hr_presence_last_compute_date = Datetime.now()
  77. for employee in all_employees:
  78. employee.hr_presence_state_display = employee.hr_presence_state
  79. @api.model
  80. def _action_open_presence_view(self):
  81. # Compute the presence/absence for the employees on the same
  82. # company than the HR/manager. Then opens the kanban view
  83. # of the employees with an undefined presence/absence
  84. _logger.info("Employees presence checked by: %s" % self.env.user.name)
  85. self._check_presence()
  86. return {
  87. "type": "ir.actions.act_window",
  88. "res_model": "hr.employee",
  89. "views": [[self.env.ref('hr_presence.hr_employee_view_kanban').id, "kanban"], [False, "tree"], [False, "form"]],
  90. 'view_mode': 'kanban,tree,form',
  91. "domain": [],
  92. "name": _("Employee's Presence to Define"),
  93. "search_view_id": [self.env.ref('hr_presence.hr_employee_view_presence_search').id, 'search'],
  94. "context": {'search_default_group_hr_presence_state': 1,
  95. 'searchpanel_default_hr_presence_state_display': 'to_define'},
  96. }
  97. def _action_set_manual_presence(self, state):
  98. if not self.env.user.has_group('hr.group_hr_manager'):
  99. raise UserError(_("You don't have the right to do this. Please contact an Administrator."))
  100. self.write({'manually_set_present': state})
  101. def action_set_present(self):
  102. self._action_set_manual_presence(True)
  103. def action_set_absent(self):
  104. self._action_set_manual_presence(False)
  105. def write(self, vals):
  106. if vals.get('hr_presence_state_display') == 'present':
  107. vals['manually_set_present'] = True
  108. return super().write(vals)
  109. def action_open_leave_request(self):
  110. self.ensure_one()
  111. return {
  112. "type": "ir.actions.act_window",
  113. "res_model": "hr.leave",
  114. "views": [[False, "form"]],
  115. "view_mode": 'form',
  116. "context": {'default_employee_id': self.id},
  117. }
  118. # --------------------------------------------------
  119. # Messaging
  120. # --------------------------------------------------
  121. def action_send_sms(self):
  122. self.ensure_one()
  123. if not self.env.user.has_group('hr.group_hr_manager'):
  124. raise UserError(_("You don't have the right to do this. Please contact an Administrator."))
  125. if not self.mobile_phone:
  126. raise UserError(_("There is no professional mobile for this employee."))
  127. context = dict(self.env.context)
  128. context.update(default_res_model='hr.employee', default_res_id=self.id, default_composition_mode='comment', default_number_field_name='mobile_phone')
  129. template = self.env.ref('hr_presence.sms_template_presence', False)
  130. if not template:
  131. context['default_body'] = _("""Exception made if there was a mistake of ours, it seems that you are not at your office and there is not request of time off from you.
  132. Please, take appropriate measures in order to carry out this work absence.
  133. Do not hesitate to contact your manager or the human resource department.""")
  134. else:
  135. context['default_template_id'] = template.id
  136. return {
  137. "type": "ir.actions.act_window",
  138. "res_model": "sms.composer",
  139. "view_mode": 'form',
  140. "context": context,
  141. "name": "Send SMS Text Message",
  142. "target": "new",
  143. }
  144. def action_send_mail(self):
  145. self.ensure_one()
  146. if not self.env.user.has_group('hr.group_hr_manager'):
  147. raise UserError(_("You don't have the right to do this. Please contact an Administrator."))
  148. if not self.work_email:
  149. raise UserError(_("There is no professional email address for this employee."))
  150. template = self.env.ref('hr_presence.mail_template_presence', False)
  151. compose_form = self.env.ref('mail.email_compose_message_wizard_form', False)
  152. ctx = dict(
  153. default_model="hr.employee",
  154. default_res_id=self.id,
  155. default_use_template=bool(template),
  156. default_template_id=template.id,
  157. default_composition_mode='comment',
  158. default_is_log=True,
  159. default_email_layout_xmlid='mail.mail_notification_light',
  160. )
  161. return {
  162. 'name': _('Compose Email'),
  163. 'type': 'ir.actions.act_window',
  164. 'view_mode': 'form',
  165. 'res_model': 'mail.compose.message',
  166. 'views': [(compose_form.id, 'form')],
  167. 'view_id': compose_form.id,
  168. 'target': 'new',
  169. 'context': ctx,
  170. }