Files
odoo_source/addons/hr_presence/models/hr_employee.py
T
Martin Trigaux 604a47ead8 [IMP] *: remove global ACL
THese are rarely intended for all users but often intended only for
employees.

account:
account.incoterms: only used within internal business models
account.journal.group: same as account.journal, add sudo in computed field

account_edi: need access to accounting objects

base_address_extended:
res.city: only employees should access address data

board: only employees uses this (old) module

crm:
crm.stage: internal users business object

hr_recruitment: employees can read

im_livechat: apply same as for the steps

l10n_ar: used on partner, not only invoices
l10n_ec: accessed only through account.move
l10n_latam: accessed on res.partner

mail:
publisher.warrenty.contract: no data, only static models
mail.channel: group_user has already his own rule
mail.group: group_user has already his own rule
mail.message.subtype: group_user has already his own rule
mail.message.all: remove, already has a portal and employee rule

partner_autocomplete: no interaction with public

project:
project.tags: only needed for project sharing

sale_management:
sale.order.option: same as sale.order

utm: employee already has write access

web_editor: test models that have nothing to do here
web_tour: only employees uses tours

website_sale:
product.ribbon: add sudo for access

base:
ir.default: only employees uses set (could probably be converted to group_system)
ir.ui.view.custom: same as ir.ui.view, add sudo when needed
report.*: portal users don't configure reports
res.users.log: create in sudo, no access needed (adapt test to use another model)
res.lang: still needed for public

closes odoo/odoo#118701

Related: odoo/enterprise#41285
Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
2023-06-12 22:39:26 +02:00

186 lines
7.7 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from ast import literal_eval
from odoo import fields, models, _, api
from odoo.exceptions import UserError
from odoo.fields import Datetime
_logger = logging.getLogger(__name__)
class Employee(models.AbstractModel):
_inherit = 'hr.employee.base'
email_sent = fields.Boolean(default=False)
ip_connected = fields.Boolean(default=False)
manually_set_present = fields.Boolean(default=False)
# Stored field used in the presence kanban reporting view
# to allow group by state.
hr_presence_state_display = fields.Selection([
('to_define', 'To Define'),
('present', 'Present'),
('absent', 'Absent'),
])
@api.model
def _check_presence(self):
company = self.env.company
if not company.hr_presence_last_compute_date or \
company.hr_presence_last_compute_date.day != Datetime.now().day:
self.env['hr.employee'].search([
('company_id', '=', company.id)
]).write({
'email_sent': False,
'ip_connected': False,
'manually_set_present': False
})
employees = self.env['hr.employee'].search([('company_id', '=', company.id)])
all_employees = employees
# Check on IP
if literal_eval(self.env['ir.config_parameter'].sudo().get_param('hr_presence.hr_presence_control_ip', 'False')):
ip_list = company.hr_presence_control_ip_list
ip_list = ip_list.split(',') if ip_list else []
ip_employees = self.env['hr.employee']
for employee in employees:
employee_ips = self.env['res.users.log'].sudo().search([
('create_uid', '=', employee.user_id.id),
('ip', '!=', False),
('create_date', '>=', Datetime.to_string(Datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)))]
).mapped('ip')
if any(ip in ip_list for ip in employee_ips):
ip_employees |= employee
ip_employees.write({'ip_connected': True})
employees = employees - ip_employees
# Check on sent emails
if literal_eval(self.env['ir.config_parameter'].sudo().get_param('hr_presence.hr_presence_control_email', 'False')):
email_employees = self.env['hr.employee']
threshold = company.hr_presence_control_email_amount
for employee in employees:
sent_emails = self.env['mail.message'].search_count([
('author_id', '=', employee.user_id.partner_id.id),
('date', '>=', Datetime.to_string(Datetime.now().replace(hour=0, minute=0, second=0, microsecond=0))),
('date', '<=', Datetime.to_string(Datetime.now()))])
if sent_emails >= threshold:
email_employees |= employee
email_employees.write({'email_sent': True})
employees = employees - email_employees
company.sudo().hr_presence_last_compute_date = Datetime.now()
for employee in all_employees:
employee.hr_presence_state_display = employee.hr_presence_state
@api.model
def _action_open_presence_view(self):
# Compute the presence/absence for the employees on the same
# company than the HR/manager. Then opens the kanban view
# of the employees with an undefined presence/absence
_logger.info("Employees presence checked by: %s" % self.env.user.name)
self._check_presence()
return {
"type": "ir.actions.act_window",
"res_model": "hr.employee",
"views": [[self.env.ref('hr_presence.hr_employee_view_kanban').id, "kanban"], [False, "tree"], [False, "form"]],
'view_mode': 'kanban,tree,form',
"domain": [],
"name": _("Employee's Presence to Define"),
"search_view_id": [self.env.ref('hr_presence.hr_employee_view_presence_search').id, 'search'],
"context": {'search_default_group_hr_presence_state': 1,
'searchpanel_default_hr_presence_state_display': 'to_define'},
}
def _action_set_manual_presence(self, state):
if not self.env.user.has_group('hr.group_hr_manager'):
raise UserError(_("You don't have the right to do this. Please contact an Administrator."))
self.write({'manually_set_present': state})
def action_set_present(self):
self._action_set_manual_presence(True)
def action_set_absent(self):
self._action_set_manual_presence(False)
def write(self, vals):
if vals.get('hr_presence_state_display') == 'present':
vals['manually_set_present'] = True
return super().write(vals)
def action_open_leave_request(self):
self.ensure_one()
return {
"type": "ir.actions.act_window",
"res_model": "hr.leave",
"views": [[False, "form"]],
"view_mode": 'form',
"context": {'default_employee_id': self.id},
}
# --------------------------------------------------
# Messaging
# --------------------------------------------------
def action_send_sms(self):
self.ensure_one()
if not self.env.user.has_group('hr.group_hr_manager'):
raise UserError(_("You don't have the right to do this. Please contact an Administrator."))
if not self.mobile_phone:
raise UserError(_("There is no professional mobile for this employee."))
context = dict(self.env.context)
context.update(default_res_model='hr.employee', default_res_id=self.id, default_composition_mode='comment', default_number_field_name='mobile_phone')
template = self.env.ref('hr_presence.sms_template_presence', False)
if not template:
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.
Please, take appropriate measures in order to carry out this work absence.
Do not hesitate to contact your manager or the human resource department.""")
else:
context['default_template_id'] = template.id
return {
"type": "ir.actions.act_window",
"res_model": "sms.composer",
"view_mode": 'form',
"context": context,
"name": "Send SMS Text Message",
"target": "new",
}
def action_send_mail(self):
self.ensure_one()
if not self.env.user.has_group('hr.group_hr_manager'):
raise UserError(_("You don't have the right to do this. Please contact an Administrator."))
if not self.work_email:
raise UserError(_("There is no professional email address for this employee."))
template = self.env.ref('hr_presence.mail_template_presence', False)
compose_form = self.env.ref('mail.email_compose_message_wizard_form', False)
ctx = dict(
default_model="hr.employee",
default_res_ids=self.ids,
default_template_id=template.id,
default_composition_mode='comment',
default_email_layout_xmlid='mail.mail_notification_light',
default_subtype_id=self.env['ir.model.data']._xmlid_to_res_id('mail.mt_note'),
)
return {
'name': _('Compose Email'),
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'mail.compose.message',
'views': [(compose_form.id, 'form')],
'view_id': compose_form.id,
'target': 'new',
'context': ctx,
}