summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLucas Lefèvre <lul@odoo.com>2019-06-24 07:28:44 +0000
committerYannick Tivisse <yti@odoo.com>2019-07-17 09:11:18 +0000
commitf6fdde96bddfedf8764cd8a73089e44340d476ae (patch)
treec7acd4cccf2286e7ba333f5da501e674ec643227
parent008634730adb0e834e759d5f356b8978e083395a (diff)
[IMP] hr_*: Improve employee presence state
Purpose ======= There are currently multiple ways to determine if an employee is presence or absent: - login state (user status on chat) - checkin/checkout from the Attendance app - leave - hr_presence (email, ip) Those states are displayed in several different places and can be inconsitent. e.g. Logged in -> green in the chat Not checked in -> red on the employee kanban view. The multiple ways to determine employee presence described above should be aggregated together to have a better consistency. Specification ============= There are 3 presence states (previously defined in module `hr_presence`), namely `present`, `absent`, `to_define`. They are now defined as soon as `hr` module is installed. The state computation can have several behaviors according to which apps are installed: 1. `hr` is installed Check employee presence based on login by default (only for employees with a user). Kanban state (private and public): should be green when logged in, red when logged out and orange when the user is away. Private employee form: Display a stat button "Connected" on the form view when the user is logged in or "Last Activity xx/xx/xxx" otherwise. 2. `hr_attendance` is installed: when the user is logged out, the state is determined from the checked in/out state. But when the user is logged in, consider the user as present (even if he checked out). Kanban state: green for checked in, red for checked out Private form view: attendance stat button. 3. `hr_holidays` is installed: Has the highest priority if the employee is on leave. Kanban state: red if employee is on leave. Private form view: stat button "Absent Until xx/xx/xxxx" if employee is on leave. 4. `hr_presence` is installed: Two additionnal presence checking option: emails sent and IP address connected. Once a user sent an email or the IP address was connected, he is considered present for the entire day. There should be at most one stat button on the employee form view, with the relevent information. Task id: 2024482 closes odoo/odoo#34933 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
-rw-r--r--addons/hr/data/hr_data.xml5
-rw-r--r--addons/hr/models/__init__.py1
-rw-r--r--addons/hr/models/hr_employee_base.py28
-rw-r--r--addons/hr/models/res_company.py11
-rw-r--r--addons/hr/models/res_config_settings.py9
-rw-r--r--addons/hr/models/res_users.py4
-rw-r--r--addons/hr/views/hr_employee_public_views.xml10
-rw-r--r--addons/hr/views/hr_employee_views.xml41
-rw-r--r--addons/hr/views/res_config_settings_views.xml44
-rw-r--r--addons/hr/views/res_users.xml22
-rw-r--r--addons/hr_attendance/models/hr_employee.py14
-rw-r--r--addons/hr_attendance/views/hr_employee_view.xml51
-rw-r--r--addons/hr_attendance_presence/__init__.py1
-rw-r--r--addons/hr_attendance_presence/__manifest__.py19
-rw-r--r--addons/hr_attendance_presence/models/__init__.py2
-rw-r--r--addons/hr_attendance_presence/models/hr_employee.py32
-rw-r--r--addons/hr_attendance_presence/models/res_config_settings.py9
-rw-r--r--addons/hr_attendance_presence/views/hr_employee.xml21
-rw-r--r--addons/hr_attendance_presence/views/res_config_settings_views.xml17
-rw-r--r--addons/hr_holidays/models/hr_employee.py5
-rw-r--r--addons/hr_holidays/models/hr_leave.py1
-rw-r--r--addons/hr_holidays/views/hr_views.xml17
-rw-r--r--addons/hr_holidays_attendance/__init__.py0
-rw-r--r--addons/hr_holidays_attendance/__manifest__.py15
-rw-r--r--addons/hr_holidays_attendance/views/hr_employee_views.xml64
-rw-r--r--addons/hr_presence/__manifest__.py1
-rw-r--r--addons/hr_presence/models/__init__.py1
-rw-r--r--addons/hr_presence/models/hr_employee.py77
-rw-r--r--addons/hr_presence/models/res_company.py3
-rw-r--r--addons/hr_presence/models/res_config_settings.py13
-rw-r--r--addons/hr_presence/views/hr_employee_views.xml62
-rw-r--r--addons/hr_presence/views/res_config_settings_views.xml44
32 files changed, 341 insertions, 303 deletions
diff --git a/addons/hr/data/hr_data.xml b/addons/hr/data/hr_data.xml
index ab7165fee25..8c70cef3e68 100644
--- a/addons/hr/data/hr_data.xml
+++ b/addons/hr/data/hr_data.xml
@@ -99,5 +99,10 @@
<field name="user_signature" eval="False"/>
</record>
+ <record model="ir.config_parameter" id="hr_presence_control_login" forcecreate="False">
+ <field name="key">hr.hr_presence_control_login</field>
+ <field name="value">True</field>
+ </record>
+
</data>
</odoo>
diff --git a/addons/hr/models/__init__.py b/addons/hr/models/__init__.py
index efe3c1d702c..43857d3d83e 100644
--- a/addons/hr/models/__init__.py
+++ b/addons/hr/models/__init__.py
@@ -13,3 +13,4 @@ from . import mail_channel
from . import res_config_settings
from . import res_partner
from . import res_users
+from . import res_company
diff --git a/addons/hr/models/hr_employee_base.py b/addons/hr/models/hr_employee_base.py
index fec003ccfc6..191a5cb926d 100644
--- a/addons/hr/models/hr_employee_base.py
+++ b/addons/hr/models/hr_employee_base.py
@@ -23,3 +23,31 @@ class HrEmployeeBase(models.AbstractModel):
user_id = fields.Many2one('res.users')
resource_id = fields.Many2one('resource.resource')
resource_calendar_id = fields.Many2one('resource.calendar')
+ 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")
+
+ 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 = self.env['ir.config_parameter'].sudo().get_param('hr.hr_presence_control_login')
+ for employee in self:
+ state = 'to_define'
+ if check_login:
+ if employee.user_id.im_status == 'online':
+ state = 'present'
+ elif employee.user_id.im_status == 'offline':
+ state = 'absent'
+ employee.hr_presence_state = state
+
+ def _compute_last_activity(self):
+ employees = self.filtered(lambda e: e.user_id)
+ presences = self.env['bus.presence'].search([('user_id', 'in', employees.mapped('user_id.id'))])
+
+ for presence in presences:
+ presence.user_id.employee_ids.last_activity = presence.last_presence.date()
diff --git a/addons/hr/models/res_company.py b/addons/hr/models/res_company.py
new file mode 100644
index 00000000000..cd1937d639e
--- /dev/null
+++ b/addons/hr/models/res_company.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import fields, models
+
+
+class Company(models.Model):
+ _inherit = 'res.company'
+
+ hr_presence_control_email_amount = fields.Integer(string="# emails to send")
+ hr_presence_control_ip_list = fields.Char(string="Valid IP addresses")
diff --git a/addons/hr/models/res_config_settings.py b/addons/hr/models/res_config_settings.py
index 14494a6318e..a75564bc122 100644
--- a/addons/hr/models/res_config_settings.py
+++ b/addons/hr/models/res_config_settings.py
@@ -10,9 +10,12 @@ class ResConfigSettings(models.TransientModel):
'resource.calendar', 'Company Working Hours',
related='company_id.resource_calendar_id', readonly=False)
module_hr_org_chart = fields.Boolean(string="Show Organizational Chart")
- module_hr_presence = fields.Boolean(string="Control presence of employees")
+ module_hr_presence = fields.Boolean(string="Advanced control presence of employees")
module_hr_skills = fields.Boolean(string="Employee Skills and Resumé")
hr_presence_control_login = fields.Boolean(string="According to the system login (User status on chat)", config_parameter='hr.hr_presence_control_login')
- hr_presence_control_email = fields.Boolean(string="According to the amount of sent emails", config_parameter='hr.hr_presence_control_email')
- hr_presence_control_ip = fields.Boolean(string="According to the IP address", config_parameter='hr.hr_presence_control_ip')
+ hr_presence_control_email = fields.Boolean(string="According to the amount of sent emails", config_parameter='hr_presence.hr_presence_control_email')
+ hr_presence_control_ip = fields.Boolean(string="According to the IP address", config_parameter='hr_presence.hr_presence_control_ip')
+ module_hr_attendance = fields.Boolean(string="According to the Attendance module.")
+ hr_presence_control_email_amount = fields.Integer(related="company_id.hr_presence_control_email_amount", readonly=False)
+ hr_presence_control_ip_list = fields.Char(related="company_id.hr_presence_control_ip_list", readonly=False)
hr_employee_self_edit = fields.Boolean(string="Employee Edition", config_parameter='hr.hr_employee_self_edit')
diff --git a/addons/hr/models/res_users.py b/addons/hr/models/res_users.py
index 0e663a8d62b..c64f678070a 100644
--- a/addons/hr/models/res_users.py
+++ b/addons/hr/models/res_users.py
@@ -52,6 +52,8 @@ class User(models.Model):
study_field = fields.Char(related='employee_id.study_field', readonly=False, related_sudo=False)
study_school = fields.Char(related='employee_id.study_school', readonly=False, related_sudo=False)
employee_count = fields.Integer(compute='_compute_employee_count')
+ hr_presence_state = fields.Selection(related='employee_id.hr_presence_state')
+ last_activity = fields.Date(related='employee_id.last_activity')
@api.depends('employee_ids')
def _compute_employee_count(self):
@@ -69,6 +71,8 @@ class User(models.Model):
'employee_id',
'employee_ids',
'employee_parent_id',
+ 'hr_presence_state',
+ 'last_activity',
]
hr_writable_fields = [
diff --git a/addons/hr/views/hr_employee_public_views.xml b/addons/hr/views/hr_employee_public_views.xml
index fa8582f3015..95b277b30f0 100644
--- a/addons/hr/views/hr_employee_public_views.xml
+++ b/addons/hr/views/hr_employee_public_views.xml
@@ -95,6 +95,7 @@
<field name="arch" type="xml">
<kanban class="o_hr_employee_kanban">
<field name="id"/>
+ <field name="hr_presence_state"/>
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_global_click o_kanban_record_has_image_fill o_hr_kanban_record">
@@ -107,6 +108,15 @@
<div class="o_kanban_record_top">
<div class="o_kanban_record_headings">
<strong class="o_kanban_record_title">
+ <div class="float-right" t-if="record.hr_presence_state.raw_value == 'present'">
+ <span class="fa fa-circle text-success" role="img" aria-label="Present" title="Present" name="presence_present"></span>
+ </div>
+ <div class="float-right" t-if="record.hr_presence_state.raw_value == 'absent'">
+ <span class="fa fa-circle text-danger" role="img" aria-label="Absent" title="Absent" name="presence_absent"></span>
+ </div>
+ <div class="float-right" t-if="record.hr_presence_state.raw_value == 'to_define'">
+ <span class="fa fa-circle text-warning" role="img" aria-label="To define" title="To define" name="presence_to_define"></span>
+ </div>
<field name="name"/>
</strong>
<span t-if="record.job_id.raw_value" class="o_kanban_record_subtitle"><field name="job_id"/></span>
diff --git a/addons/hr/views/hr_employee_views.xml b/addons/hr/views/hr_employee_views.xml
index d7e52389246..56a96215194 100644
--- a/addons/hr/views/hr_employee_views.xml
+++ b/addons/hr/views/hr_employee_views.xml
@@ -40,14 +40,37 @@
<form string="Employee" js_class="hr_employee_form">
<field name="active" invisible="1"/>
<field name="user_partner_id" invisible="1"/>
+ <field name="hr_presence_state" invisible="1"/>
<header>
<button string="Chat" class="btn btn-primary o_employee_chat_btn" attrs="{'invisible': [('user_id','=', False)]}"/>
<button name="%(plan_wizard_action)d" string="Launch Plan" type="action" groups="hr.group_hr_manager"/>
</header>
<sheet>
- <widget name="web_ribbon" text="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
- <div name="button_box" class="oe_button_box"/>
- <field name="image" widget='image' class="oe_avatar" options='{"zoom": true, "preview_image":"image_medium"}'/>
+ <widget name="web_ribbon" text="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
+ <div name="button_box" class="oe_button_box">
+ <button
+ id="hr_presence_button"
+ class="oe_stat_button"
+ disabled="1"
+ attrs="{'invisible': ['|', ('last_activity', '=', False), ('user_id', '=', False)]}">
+ <div role="img" class="fa fa-fw fa-circle text-success o_button_icon" attrs="{'invisible': [('hr_presence_state', '!=', 'present')]}" aria-label="Available" title="Available"/>
+ <div role="img" class="fa fa-fw fa-circle text-warning o_button_icon" attrs="{'invisible': [('hr_presence_state', '!=', 'to_define')]}" aria-label="Away" title="Away"/>
+ <div role="img" class="fa fa-fw fa-circle text-danger o_button_icon" attrs="{'invisible': [('hr_presence_state', '!=', 'absent')]}" aria-label="Not available" title="Not available"/>
+
+ <div class="o_stat_info" attrs="{'invisible': [('hr_presence_state', '=', 'present')]}">
+ <span class="o_stat_value">
+ <field name="last_activity"/>
+ </span>
+ <span class="o_stat_text">
+ Last Activity
+ </span>
+ </div>
+ <div class="o_stat_info" attrs="{'invisible': [('hr_presence_state', '!=', 'present')]}">
+ <span class="o_stat_text">Connected</span>
+ </div>
+ </button>
+ </div>
+ <field name="image" widget='image' class="oe_avatar" options='{"zoom": true, "preview_image":"image_medium"}'/>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1>
@@ -204,6 +227,7 @@
<field name="arch" type="xml">
<kanban class="o_hr_employee_kanban">
<field name="id"/>
+ <field name="hr_presence_state"/>
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_global_click o_kanban_record_has_image_fill o_hr_kanban_record">
@@ -216,7 +240,16 @@
<div class="o_kanban_record_top">
<div class="o_kanban_record_headings">
<strong class="o_kanban_record_title">
- <field name="name"/>
+ <div class="float-right" t-if="record.hr_presence_state.raw_value == 'present'">
+ <span class="fa fa-circle text-success" role="img" aria-label="Present" title="Present" name="presence_present"></span>
+ </div>
+ <div class="float-right" t-if="record.hr_presence_state.raw_value == 'absent'">
+ <span class="fa fa-circle text-danger" role="img" aria-label="Absent" title="Absent" name="presence_absent"></span>
+ </div>
+ <div class="float-right" t-if="record.hr_presence_state.raw_value == 'to_define'">
+ <span class="fa fa-circle text-warning" role="img" aria-label="To define" title="To define" name="presence_to_define"></span>
+ </div>
+ <field name="name" placeholder="Employee's Name"/>
</strong>
<span t-if="record.job_id.raw_value" class="o_kanban_record_subtitle"><field name="job_id"/></span>
</div>
diff --git a/addons/hr/views/res_config_settings_views.xml b/addons/hr/views/res_config_settings_views.xml
index 5cdcf6f679a..62d4f4179f6 100644
--- a/addons/hr/views/res_config_settings_views.xml
+++ b/addons/hr/views/res_config_settings_views.xml
@@ -20,6 +20,50 @@
</div>
</div>
</div>
+ <div class="col-12 col-lg-6 o_setting_box" title="Presence of employees">
+
+ <div class="o_setting_right_pane">
+ <span class="o_form_label">Control presence of employees</span>
+ <div class="content-group" name="hr_presence_options">
+ <div class="row">
+ <field name="module_hr_attendance" class="col-lg-1 ml16"/>
+ <label for="module_hr_attendance" class="col-lg-10 o_light_label"/>
+ </div>
+ <div class="row">
+ <field name="hr_presence_control_login" class="col-lg-1 ml16"/>
+ <label for="hr_presence_control_login" class="col-lg-10 o_light_label"/>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-12 col-lg-6 o_setting_box" title="Advanced presence of employees">
+ <div class="o_setting_left_pane">
+ <field name="module_hr_presence"/>
+ </div>
+ <div class="o_setting_right_pane">
+ <label for="module_hr_presence"/>
+ <div class="text-muted" name="hr_presence_options_advanced">
+ Presence reporting screen, email and IP address control.
+ </div>
+ <div class="row mt-1" attrs="{'invisible': [('module_hr_presence', '=', False)]}">
+ <field name="hr_presence_control_email" class="col-lg-1 ml16"/>
+ <label for="hr_presence_control_email" class="col-lg-10 o_light_label"/>
+ </div>
+ <div class="row ml-4" attrs="{'invisible': ['|', ('module_hr_presence', '=', False), ('hr_presence_control_email', '=', False)]}">
+ <span class="mr-2">At least </span>
+ <field name="hr_presence_control_email_amount"/>
+ <span> sent emails</span>
+ </div>
+ <div class="row" attrs="{'invisible': [('module_hr_presence', '=', False)]}">
+ <field name="hr_presence_control_ip" class="col-lg-1 ml16"/>
+ <label for="hr_presence_control_ip" class="col-lg-10 o_light_label"/>
+ </div>
+ <div class="row ml-4" attrs="{'invisible': ['|', ('module_hr_presence', '=', False), ('hr_presence_control_ip', '=', False)]}">
+ <span class="mr-2">IP List (comma separated):</span>
+ <field name="hr_presence_control_ip_list"/>
+ </div>
+ </div>
+ </div>
</div>
<h2>Work Organization</h2>
<div class="row mt16 o_settings_container">
diff --git a/addons/hr/views/res_users.xml b/addons/hr/views/res_users.xml
index d417b93341b..1eb980c20f3 100644
--- a/addons/hr/views/res_users.xml
+++ b/addons/hr/views/res_users.xml
@@ -36,9 +36,31 @@
<field name="arch" type="xml">
<form position="replace">
<form>
+ <field name="hr_presence_state" invisible="1"/>
<header></header> <!-- Used by other modules to add buttons -->
<sheet>
<div class="oe_button_box" name="button_box">
+ <button
+ id="hr_presence_button"
+ class="oe_stat_button"
+ disabled="1"
+ attrs="{'invisible': [('hr_presence_state', '=', 'absent')]}">
+ <div role="img" class="fa fa-fw fa-circle text-success o_button_icon" attrs="{'invisible': [('hr_presence_state', '!=', 'present')]}" aria-label="Available" title="Available"/>
+ <div role="img" class="fa fa-fw fa-circle text-warning o_button_icon" attrs="{'invisible': [('hr_presence_state', '!=', 'to_define')]}" aria-label="Away" title="Away"/>
+ <div role="img" class="fa fa-fw fa-circle text-danger o_button_icon" attrs="{'invisible': [('hr_presence_state', '!=', 'absent')]}" aria-label="Not available" title="Not available"/>
+
+ <div class="o_stat_info" attrs="{'invisible': [('hr_presence_state', '=', 'present')]}">
+ <span class="o_stat_value">
+ <field name="last_activity"/>
+ </span>
+ <span class="o_stat_text">
+ Last Activity
+ </span>
+ </div>
+ <div class="o_stat_info" attrs="{'invisible': [('hr_presence_state', '!=', 'present')]}">
+ <span class="o_stat_text">Connected</span>
+ </div>
+ </button>
</div>
<field name="image" widget='image' class="oe_avatar" options='{"zoom": true, "preview_image":"image_medium"}'/>
<div class="oe_title">
diff --git a/addons/hr_attendance/models/hr_employee.py b/addons/hr_attendance/models/hr_employee.py
index 62b7def6d2c..fa5d788c210 100644
--- a/addons/hr_attendance/models/hr_employee.py
+++ b/addons/hr_attendance/models/hr_employee.py
@@ -17,6 +17,20 @@ class HrEmployeeBase(models.AbstractModel):
hours_last_month = fields.Float(compute='_compute_hours_last_month')
hours_today = fields.Float(compute='_compute_hours_today')
+ def _compute_presence_state(self):
+ """
+ Override to include checkin/checkout in the presence state
+ Attendance has the second highest priority after login
+ """
+ super()._compute_presence_state()
+ employees = self.filtered(lambda employee: employee.hr_presence_state != 'present')
+ for employee in employees:
+ if employee.attendance_state == 'checked_out' and employee.hr_presence_state == 'to_define':
+ employee.hr_presence_state = 'absent'
+ for employee in employees:
+ if employee.attendance_state == 'checked_in':
+ employee.hr_presence_state = 'present'
+
def _compute_hours_last_month(self):
for employee in self:
now = datetime.now()
diff --git a/addons/hr_attendance/views/hr_employee_view.xml b/addons/hr_attendance/views/hr_employee_view.xml
index f03fddc1730..ad1d073dd60 100644
--- a/addons/hr_attendance/views/hr_employee_view.xml
+++ b/addons/hr_attendance/views/hr_employee_view.xml
@@ -4,14 +4,24 @@
<field name="name">hr.employee</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr.view_employee_form"/>
- <field name="priority">10</field>
+ <field name="priority">20</field>
<field name="groups_id" eval="[(4,ref('hr_attendance.group_hr_attendance_user'))]"/>
<field name="arch" type="xml">
- <div name="button_box" position="inside">
+ <xpath expr="//button[@id='hr_presence_button']" position="attributes">
+ <attribute name="attrs">
+ {'invisible': ['|', '|', ('user_id', '=', False), ('hr_presence_state', '=', 'absent'), ('attendance_state', '=', 'checked_in')]}
+ </attribute>
+ </xpath>
+ <xpath expr="//div[@name='button_box']" position="inside">
<field name="attendance_state" invisible="1"/>
<button name="%(hr_attendance_action_employee)d"
+ id="hr_attendance_button"
class="oe_stat_button"
- type="action" attrs="{'invisible': [('attendance_state', '=', False)]}">
+ type="action" attrs="{'invisible': [
+ '|', ('attendance_state', '=', False),
+ '&amp;',
+ ('hr_presence_state', '=', 'present'),
+ ('attendance_state', '=', 'checked_out')]}">
<div role="img" id="oe_hr_attendance_status" class="fa fa-fw fa-circle o_button_icon oe_hr_attendance_status_green" attrs="{'invisible': [('attendance_state', '=', 'checked_out')]}" aria-label="Available" title="Available"/>
<div role="img" id="oe_hr_attendance_status" class="fa fa-fw fa-circle o_button_icon oe_hr_attendance_status_red" attrs="{'invisible': [('attendance_state', '=', 'checked_in')]}" aria-label="Not available" title="Not available"/>
<div class="o_stat_info">
@@ -34,7 +44,7 @@
</span>
</div>
</button>
- </div>
+ </xpath>
</field>
</record>
@@ -43,11 +53,17 @@
<field name="model">res.users</field>
<field name="inherit_id" ref="hr.res_users_view_form_profile"/>
<field name="arch" type="xml">
+ <xpath expr="//button[@id='hr_presence_button']" position="attributes">
+ <attribute name="attrs">
+ {'invisible': ['|', '|', ('hr_presence_state', '=', 'absent'), ('attendance_state', '=', 'checked_in')]}
+ </attribute>
+ </xpath>
<xpath expr="//div[@name='button_box']" position="inside">
<field name="attendance_state" invisible="1"/>
<button name="%(hr_attendance_action_my_attendances)d"
+ id="hr_attendance_button"
class="oe_stat_button"
- type="action" attrs="{'invisible': [('attendance_state', '=', False)]}">
+ type="action" attrs="{'invisible': ['|', ('attendance_state', '=', False), '&amp;', ('hr_presence_state', '=', 'present'), ('attendance_state', '=', 'checked_out')]}">
<div role="img" id="oe_hr_attendance_status" class="fa fa-fw fa-circle o_button_icon oe_hr_attendance_status_green" attrs="{'invisible': [('attendance_state', '=', 'checked_out')]}" aria-label="Available" title="Available"/>
<div role="img" id="oe_hr_attendance_status" class="fa fa-fw fa-circle o_button_icon oe_hr_attendance_status_red" attrs="{'invisible': [('attendance_state', '=', 'checked_in')]}" aria-label="Not available" title="Not available"/>
<div class="o_stat_info">
@@ -131,31 +147,6 @@
</field>
</record>
- <record id="view_employee_kanban_inherit_hr_attendance" model="ir.ui.view">
- <field name="name">hr.employee</field>
- <field name="model">hr.employee</field>
- <field name="inherit_id" ref="hr.hr_kanban_view_employees"/>
- <field name="priority">1</field>
- <field name="arch" type="xml">
- <templates position="before">
- <field name="attendance_state"/>
- </templates>
- <field name="name" position="replace">
- <div>
- <div class="float-right" t-if="record.attendance_state.raw_value == 'checked_in'">
- <span id="oe_hr_attendance_status" class="fa fa-circle oe_hr_attendance_status_green" role="img" aria-label="Available" title="Available"></span>
- </div>
- <div class="float-right" t-if="record.attendance_state.raw_value == 'checked_out'">
- <span id="oe_hr_attendance_status" class="fa fa-circle oe_hr_attendance_status_red" role="img" aria-label="Not available" title="Not available"></span>
- </div>
- <strong>
- <field name="name" placeholder="Employee's Name"/>
- </strong>
- </div>
- </field>
- </field>
- </record>
-
<record id="hr_employee_attendance_action_kanban" model="ir.actions.act_window">
<field name="name">Employees</field>
<field name="res_model">hr.employee</field>
diff --git a/addons/hr_attendance_presence/__init__.py b/addons/hr_attendance_presence/__init__.py
deleted file mode 100644
index 0650744f6bc..00000000000
--- a/addons/hr_attendance_presence/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from . import models
diff --git a/addons/hr_attendance_presence/__manifest__.py b/addons/hr_attendance_presence/__manifest__.py
deleted file mode 100644
index da31006ddb7..00000000000
--- a/addons/hr_attendance_presence/__manifest__.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# -*- coding: utf-8 -*-
-# Part of Odoo. See LICENSE file for full copyright and licensing details.
-
-{
- 'name': 'Attendance Presence',
- 'version': '1.0',
- 'category': 'Human Resources',
- 'sequence': 85,
- 'summary': 'Bridge Attendance module and Presence module',
- 'description': "",
- 'website': 'https://www.odoo.com/page/employees',
- 'depends': ['hr_attendance', 'hr_presence'],
- 'installable': True,
- 'auto_install': True,
- 'data': [
- 'views/res_config_settings_views.xml',
- 'views/hr_employee.xml',
- ],
-}
diff --git a/addons/hr_attendance_presence/models/__init__.py b/addons/hr_attendance_presence/models/__init__.py
deleted file mode 100644
index 5d68338dfc7..00000000000
--- a/addons/hr_attendance_presence/models/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from . import hr_employee
-from . import res_config_settings
diff --git a/addons/hr_attendance_presence/models/hr_employee.py b/addons/hr_attendance_presence/models/hr_employee.py
deleted file mode 100644
index c1dc644cac7..00000000000
--- a/addons/hr_attendance_presence/models/hr_employee.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# -*- coding: utf-8 -*-
-# Part of Odoo. See LICENSE file for full copyright and licensing details.
-
-import logging
-
-from odoo import models
-
-_logger = logging.getLogger(__name__)
-
-
-class Employee(models.Model):
- _inherit = 'hr.employee'
-
- def _action_open_presence_view(self):
- action = super(Employee, self)._action_open_presence_view()
-
- if self.env['ir.config_parameter'].sudo().get_param('hr_presence.hr_presence_control_attendance'):
- company = self.env.company
- employees = self.env['hr.employee'].search([
- ('department_id.company_id', '=', company.id),
- ('user_id', '!=', False),
- ])
-
- employees.filtered(
- lambda e: e.attendance_state == 'checked_in'
- ).write({'hr_presence_state': 'present'})
-
- employees.filtered(
- lambda e: e.attendance_state == 'checked_out'
- ).write({'hr_presence_state': 'absent'})
-
- return action
diff --git a/addons/hr_attendance_presence/models/res_config_settings.py b/addons/hr_attendance_presence/models/res_config_settings.py
deleted file mode 100644
index a9bbd8f64b3..00000000000
--- a/addons/hr_attendance_presence/models/res_config_settings.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import fields, models
-
-
-class ResConfigSettings(models.TransientModel):
- _inherit = 'res.config.settings'
-
- hr_presence_control_attendance = fields.Boolean(string="According to the Attendance module", config_parameter='hr_presence.hr_presence_control_attendance')
diff --git a/addons/hr_attendance_presence/views/hr_employee.xml b/addons/hr_attendance_presence/views/hr_employee.xml
deleted file mode 100644
index a645e594b20..00000000000
--- a/addons/hr_attendance_presence/views/hr_employee.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<odoo>
-
- <record id="hr_employee_view_kanban" model="ir.ui.view">
- <field name="name">hr.employee</field>
- <field name="model">hr.employee</field>
- <field name="inherit_id" ref="hr_presence.hr_employee_view_kanban_inherit"/>
- <field name="priority">20</field>
- <field name="arch" type="xml">
- <xpath expr="//span[@name='presence_absent']" position="attributes">
- <attribute name="invisible">1</attribute>
- </xpath>
- <xpath expr="//span[@name='presence_present']" position="attributes">
- <attribute name="invisible">1</attribute>
- </xpath>
- <xpath expr="//span[@name='presence_to_define']" position="attributes">
- <attribute name="invisible">1</attribute>
- </xpath>
- </field>
- </record>
-</odoo>
diff --git a/addons/hr_attendance_presence/views/res_config_settings_views.xml b/addons/hr_attendance_presence/views/res_config_settings_views.xml
deleted file mode 100644
index ef6ab9142e6..00000000000
--- a/addons/hr_attendance_presence/views/res_config_settings_views.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<odoo>
- <record id="res_config_settings_view_form" model="ir.ui.view">
- <field name="name">res.config.settings.view.form.inherit.presence.hr</field>
- <field name="model">res.config.settings</field>
- <field name="priority" eval="70"/>
- <field name="inherit_id" ref="hr.res_config_settings_view_form"/>
- <field name="arch" type="xml">
- <xpath expr="//div[@name='hr_presence_options']" position="inside">
- <div class="row">
- <field name="hr_presence_control_attendance" class="col-lg-1 ml16"/>
- <label for="hr_presence_control_attendance" class="col-lg-10 o_light_label"/>
- </div>
- </xpath>
- </field>
- </record>
-</odoo>
diff --git a/addons/hr_holidays/models/hr_employee.py b/addons/hr_holidays/models/hr_employee.py
index c0a47809e04..a79ad7eb307 100644
--- a/addons/hr_holidays/models/hr_employee.py
+++ b/addons/hr_holidays/models/hr_employee.py
@@ -93,6 +93,11 @@ class HrEmployeeBase(models.AbstractModel):
for employee in self:
employee.allocation_used_count = employee.allocation_count - employee.remaining_leaves
+ def _compute_presence_state(self):
+ super()._compute_presence_state()
+ employees = self.filtered(lambda employee: employee.hr_presence_state != 'present' and employee.is_absent)
+ employees.update({'hr_presence_state': 'absent'})
+
@api.multi
def _compute_leave_status(self):
# Used SUPERUSER_ID to forcefully get status of other user's leave, to bypass record rule
diff --git a/addons/hr_holidays/models/hr_leave.py b/addons/hr_holidays/models/hr_leave.py
index 4685e543a0c..8deda82c3f4 100644
--- a/addons/hr_holidays/models/hr_leave.py
+++ b/addons/hr_holidays/models/hr_leave.py
@@ -793,7 +793,6 @@ class HolidaysRequest(models.Model):
# FIXME RLi: This does not make sense, only the parent should be in validation_type both
if leaves and leaves[0].validation_type == 'both':
leaves.action_validate()
-
employee_requests = self.filtered(lambda hol: hol.holiday_type == 'employee')
employee_requests._validate_leave_request()
if not self.env.context.get('leave_fast_create'):
diff --git a/addons/hr_holidays/views/hr_views.xml b/addons/hr_holidays/views/hr_views.xml
index c7da3c7eea1..48f28f883b8 100644
--- a/addons/hr_holidays/views/hr_views.xml
+++ b/addons/hr_holidays/views/hr_views.xml
@@ -135,6 +135,11 @@
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr.view_employee_form"/>
<field name="arch" type="xml">
+ <xpath expr="//button[@id='hr_presence_button']" position="attributes">
+ <attribute name="attrs">
+ {'invisible': ['|', '|', '|', ('last_activity', '=', False), ('is_absent', '=', True), ('user_id', '=', False), ('id', '=', False)]}
+ </attribute>
+ </xpath>
<xpath expr="//group[@name='managers']" position="inside">
<field name="leave_manager_id"/>
</xpath>
@@ -142,10 +147,11 @@
<field name="current_leave_id" invisible="1"/>
<field name="show_leaves" invisible="1"/>
<field name="is_absent" invisible="1"/>
- <button name="%(hr_leave_action_new_request)d" type="action"
+ <button disabled="1"
class="oe_stat_button"
+ context="{'search_default_employee_id': active_id}"
attrs="{'invisible': [('is_absent', '=', False)]}">
- <div role="img" class="fa fa-fw fa-circle o_button_icon text-danger" aria-label="Absent Until" title="Absent Until"/>
+ <div role="img" class="fa fa-fw fa-plane o_button_icon text-danger" aria-label="Absent Until" title="Absent Until"/>
<div class="o_field_widget o_stat_info">
<span class="o_stat_value">
<field name="leave_date_to"/>
@@ -160,6 +166,7 @@
class="oe_stat_button"
icon="fa-calendar"
attrs="{'invisible': [('show_leaves','=', False)]}"
+ context="{'search_default_employee_id': active_id}"
groups="base.group_user"
help="Remaining leaves">
<div class="o_field_widget o_stat_info">
@@ -188,10 +195,10 @@
<field name="current_leave_id" invisible="1"/>
<field name="show_leaves" invisible="1"/>
<field name="is_absent" invisible="1"/>
- <button name="%(hr_leave_action_new_request)d" type="action"
+ <button disabled="1"
class="oe_stat_button"
attrs="{'invisible': [('is_absent', '=', False)]}">
- <div role="img" class="fa fa-fw fa-circle o_button_icon text-danger" aria-label="Absent Until" title="Absent Until"/>
+ <div role="img" class="fa fa-fw fa-plane o_button_icon text-danger" aria-label="Absent Until" title="Absent Until"/>
<div class="o_field_widget o_stat_info">
<span class="o_stat_value">
<field name="leave_date_to"/>
@@ -232,7 +239,7 @@
<button name="%(hr_leave_action_new_request)d" type="action"
class="oe_stat_button"
attrs="{'invisible': [('is_absent', '=', False)]}">
- <div role="img" class="fa fa-fw fa-circle o_button_icon text-danger" aria-label="Absent Until" title="Absent Until"/>
+ <div role="img" class="fa fa-fw fa-plane o_button_icon text-danger" aria-label="Absent Until" title="Absent Until"/>
<div class="o_field_widget o_stat_info">
<span class="o_stat_value">
<field name="leave_date_to"/>
diff --git a/addons/hr_holidays_attendance/__init__.py b/addons/hr_holidays_attendance/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/addons/hr_holidays_attendance/__init__.py
diff --git a/addons/hr_holidays_attendance/__manifest__.py b/addons/hr_holidays_attendance/__manifest__.py
new file mode 100644
index 00000000000..b20f356c401
--- /dev/null
+++ b/addons/hr_holidays_attendance/__manifest__.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+{
+ 'name': "HR Attendance Holidays",
+ 'summary': """""",
+ 'category': 'HR',
+ 'description': """
+ Hides attendance presence stat button when an employee is on leave.
+ """,
+ 'version': '1.0',
+ 'depends': ['hr_attendance', 'hr_holidays'],
+ 'auto_install': True,
+ 'data': [
+ 'views/hr_employee_views.xml',
+ ],
+}
diff --git a/addons/hr_holidays_attendance/views/hr_employee_views.xml b/addons/hr_holidays_attendance/views/hr_employee_views.xml
new file mode 100644
index 00000000000..53cc6d53e90
--- /dev/null
+++ b/addons/hr_holidays_attendance/views/hr_employee_views.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<odoo>
+
+ <record id="hr_user_view_form" model="ir.ui.view">
+ <field name="name">hr.user.preferences.view.form.attendance.inherit</field>
+ <field name="model">res.users</field>
+ <field name="inherit_id" ref="hr_attendance.hr_user_view_form"/>
+ <field name="arch" type="xml">
+ <!-- Hide Attendance button -->
+ <xpath expr="//button[@id='hr_attendance_button']" position="attributes">
+ <attribute name="attrs">
+ {'invisible': ['|', '|', '&amp;',
+ ('hr_presence_state', '=', 'present'),
+ ('attendance_state', '=', 'checked_out'),
+ ('is_absent', '=', True),
+ ('id', '=', False),
+ ]}
+ </attribute>
+ </xpath>
+ <!-- Merge invisible attr of both module -->
+ <xpath expr="//button[@id='hr_presence_button']" position="attributes">
+ <attribute name="attrs">
+ {'invisible': ['|', '|', '|',
+ ('is_absent', '=', True),
+ ('hr_presence_state', '=', 'absent'),
+ ('attendance_state', '=', 'checked_in'),
+ ('id', '=', False),
+ ]}
+ </attribute>
+ </xpath>
+ </field>
+ </record>
+
+ <record id="hr_employee_view_form" model="ir.ui.view">
+ <field name="name">hr.employee.holidays.attendance.inherit</field>
+ <field name="model">hr.employee</field>
+ <field name="inherit_id" ref="hr_attendance.view_employee_form_inherit_hr_attendance"/>
+ <field name="arch" type="xml">
+ <!-- Hide Attendance button -->
+ <xpath expr="//button[@id='hr_attendance_button']" position="attributes">
+ <attribute name="attrs">
+ {'invisible': ['|', '|', '&amp;',
+ ('hr_presence_state', '=', 'present'),
+ ('attendance_state', '=', 'checked_out'),
+ ('is_absent', '=', True),
+ ('id', '=', False),
+ ]}
+ </attribute>
+ </xpath>
+ <!-- Merge invisible attr of both module -->
+ <xpath expr="//button[@id='hr_presence_button']" position="attributes">
+ <attribute name="attrs">
+ {'invisible': ['|', '|', '|',
+ ('is_absent', '=', True),
+ ('hr_presence_state', '=', 'absent'),
+ ('attendance_state', '=', 'checked_in'),
+ ('id', '=', False),
+ ]}
+ </attribute>
+ </xpath>
+ </field>
+ </record>
+
+</odoo>
diff --git a/addons/hr_presence/__manifest__.py b/addons/hr_presence/__manifest__.py
index d0fdba48fff..05b27fca5ca 100644
--- a/addons/hr_presence/__manifest__.py
+++ b/addons/hr_presence/__manifest__.py
@@ -18,7 +18,6 @@ Allows to contact directly the employee in case of unjustified absence.
""",
'depends': ['hr', 'hr_holidays', 'sms'],
'data': [
- 'views/res_config_settings_views.xml',
'data/ir_actions_server.xml',
'views/hr_employee_views.xml',
'data/sms_data.xml',
diff --git a/addons/hr_presence/models/__init__.py b/addons/hr_presence/models/__init__.py
index 996b19c0a45..76aa02054b2 100644
--- a/addons/hr_presence/models/__init__.py
+++ b/addons/hr_presence/models/__init__.py
@@ -3,5 +3,4 @@
from . import hr_employee
from . import res_company
-from . import res_config_settings
from . import res_users_log
diff --git a/addons/hr_presence/models/hr_employee.py b/addons/hr_presence/models/hr_employee.py
index 2f0c55a9571..9860fa0ec1b 100644
--- a/addons/hr_presence/models/hr_employee.py
+++ b/addons/hr_presence/models/hr_employee.py
@@ -10,21 +10,28 @@ from odoo.fields import Datetime
_logger = logging.getLogger(__name__)
-class ResCompany(models.Model):
- _inherit = 'hr.employee'
+class Employee(models.AbstractModel):
+ _inherit = 'hr.employee.base'
- hr_presence_state = fields.Selection([
+ 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([
('present', 'Present'),
('absent', 'Absent'),
- ('to_define', 'To Define')], groups="hr.group_hr_user", default='to_define')
- last_activity = fields.Date(compute="_compute_last_activity")
-
- def _compute_last_activity(self):
- employees = self.filtered(lambda e: e.user_id)
- presences = self.env['bus.presence'].search([('user_id', 'in', employees.mapped('user_id.id'))])
+ ('to_define', 'To Define')])
- for presence in presences:
- presence.user_id.employee_ids.last_activity = presence.last_presence.date()
+ def _compute_presence_state(self):
+ super()._compute_presence_state()
+ employees = self.filtered(lambda employee: employee.hr_presence_state != 'present' and not employee.is_absent)
+ company = self.env.company
+ for employee in employees:
+ if not employee.is_absent and company.hr_presence_last_compute_date and company.hr_presence_last_compute_date.day == Datetime.now().day and \
+ (employee.email_sent or employee.ip_connected or employee.manually_set_present):
+ employee.hr_presence_state = 'present'
@api.model
def _check_presence(self):
@@ -32,28 +39,16 @@ class ResCompany(models.Model):
if not company.hr_presence_last_compute_date or \
company.hr_presence_last_compute_date.day != Datetime.now().day:
self.env['hr.employee'].search([
- ('department_id.company_id', '=', company.id)
- ]).write({'hr_presence_state': 'to_define'})
-
- employees = self.env['hr.employee'].search([
- ('department_id.company_id', '=', company.id),
- ('user_id', '!=', False),
- ('hr_presence_state', '=', 'to_define')])
-
- # Remove employees on holidays
- leaves = self.env['hr.leave'].search([
- ('state', '=', 'validate'),
- ('date_from', '<=', Datetime.to_string(Datetime.now())),
- ('date_to', '>=', Datetime.to_string(Datetime.now()))])
- employees_on_holiday = leaves.mapped('employee_id')
- employees_on_holiday.write({'hr_presence_state': 'absent'})
- employees = employees - employees_on_holiday
-
- # Check on system login
- if self.env['ir.config_parameter'].sudo().get_param('hr_presence.hr_presence_control_login'):
- online_employees = employees.filtered(lambda employee: employee.user_id.im_status in ['away', 'online'])
- online_employees.write({'hr_presence_state': 'present'})
- employees = employees - online_employees
+ ('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 self.env['ir.config_parameter'].sudo().get_param('hr_presence.hr_presence_control_ip'):
@@ -68,7 +63,7 @@ class ResCompany(models.Model):
).mapped('ip')
if any([ip in ip_list for ip in employee_ips]):
ip_employees |= employee
- ip_employees.write({'hr_presence_state': 'present'})
+ ip_employees.write({'ip_connected': True})
employees = employees - ip_employees
# Check on sent emails
@@ -82,10 +77,13 @@ class ResCompany(models.Model):
('date', '<=', Datetime.to_string(Datetime.now()))])
if sent_emails >= threshold:
email_employees |= employee
- email_employees.write({'hr_presence_state': 'present'})
+ email_employees.write({'email_sent': True})
employees = employees - email_employees
- company.hr_presence_last_compute_date = Datetime.now()
+ 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):
@@ -110,7 +108,12 @@ class ResCompany(models.Model):
def action_set_present(self):
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({'hr_presence_state': 'present'})
+ self.write({'manually_set_present': True})
+
+ 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()
diff --git a/addons/hr_presence/models/res_company.py b/addons/hr_presence/models/res_company.py
index 7de70604a92..834fd26cf21 100644
--- a/addons/hr_presence/models/res_company.py
+++ b/addons/hr_presence/models/res_company.py
@@ -7,7 +7,4 @@ from odoo import fields, models
class ResCompany(models.Model):
_inherit = 'res.company'
-
- hr_presence_control_email_amount = fields.Integer(string="# emails to send")
- hr_presence_control_ip_list = fields.Char(string="Valid IP addresses")
hr_presence_last_compute_date = fields.Datetime()
diff --git a/addons/hr_presence/models/res_config_settings.py b/addons/hr_presence/models/res_config_settings.py
deleted file mode 100644
index e831d7506bb..00000000000
--- a/addons/hr_presence/models/res_config_settings.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from odoo import fields, models
-
-
-class ResConfigSettings(models.TransientModel):
- _inherit = 'res.config.settings'
-
- hr_presence_control_login = fields.Boolean(string="According to the system login (User status on chat)", config_parameter='hr_presence.hr_presence_control_login')
- hr_presence_control_email = fields.Boolean(string="According to the amount of sent emails", config_parameter='hr_presence.hr_presence_control_email')
- hr_presence_control_ip = fields.Boolean(string="According to the IP address", config_parameter='hr_presence.hr_presence_control_ip')
- hr_presence_control_email_amount = fields.Integer(related="company_id.hr_presence_control_email_amount", readonly=False)
- hr_presence_control_ip_list = fields.Char(related="company_id.hr_presence_control_ip_list", readonly=False)
diff --git a/addons/hr_presence/views/hr_employee_views.xml b/addons/hr_presence/views/hr_employee_views.xml
index 6f226b3dc71..61cb26184f8 100644
--- a/addons/hr_presence/views/hr_employee_views.xml
+++ b/addons/hr_presence/views/hr_employee_views.xml
@@ -7,42 +7,11 @@
<field name="groups_id" eval="[(4, ref('hr.group_hr_manager'))]"/>
<field name="arch" type="xml">
<filter name="group_manager" position="after">
- <filter name="group_hr_presence_state" string="Presence" domain="[]" context="{'group_by':'hr_presence_state'}"/>
+ <filter name="group_hr_presence_state" string="Presence" domain="[]" context="{'group_by':'hr_presence_state_display'}"/>
</filter>
</field>
</record>
- <record id="hr_employee_view_form" model="ir.ui.view">
- <field name="name">hr.employee.presence.form.inherit</field>
- <field name="model">hr.employee</field>
- <field name="inherit_id" ref="hr.view_employee_form"/>
- <field name="groups_id" eval="[(4, ref('hr.group_hr_manager'))]"/>
- <field name="arch" type="xml">
- <div name="button_box" position="inside">
- <field name="hr_presence_state" invisible="1"/>
- <button name="%(ir_actions_server_action_open_presence_view)d"
- class="oe_stat_button"
- type="action"
- attrs="{'invisible': ['|', ('hr_presence_state', '=', 'absent'), ('user_id', '=', False)]}">
- <div role="img" class="fa fa-fw fa-circle text-success o_button_icon" attrs="{'invisible': [('hr_presence_state', '!=', 'present')]}" aria-label="Available" title="Available"/>
- <div role="img" class="fa fa-fw fa-circle text-warning o_button_icon" attrs="{'invisible': [('hr_presence_state', '!=', 'to_define')]}" aria-label="Not available" title="Not available"/>
-
- <div class="o_stat_info" attrs="{'invisible': [('hr_presence_state', '!=', 'to_define')]}">
- <span class="o_stat_value">
- <field name="last_activity"/>
- </span>
- <span class="o_stat_text">
- Last Activity
- </span>
- </div>
- <div class="o_stat_info" attrs="{'invisible': [('hr_presence_state', '!=', 'present')]}">
- <span class="o_stat_text">Connected</span>
- </div>
- </button>
- </div>
- </field>
- </record>
-
<record id="hr_employee_view_kanban" model="ir.ui.view">
<field name="name">hr.employee.view.kanban</field>
<field name="model">hr.employee</field>
@@ -54,7 +23,7 @@
<div class="o_kanban_record_bottom">
<div class="oe_kanban_bottom_left">
<field name="hr_presence_state" invisible="1"/>
- <button name="action_set_present" type="object" class="btn btn-primary btn-sm mt8 fa fa-check" title="Set as present" attrs="{'invisible': [('hr_presence_state', '!=', 'to_define')]}"> </button>
+ <button name="action_set_present" type="object" class="btn btn-primary btn-sm mt8 fa fa-check" title="Set as present" attrs="{'invisible': [('hr_presence_state', '=', 'present')]}"> </button>
<button name="action_open_leave_request" type="object" class="btn btn-primary btn-sm mt8">Time Off</button>
<button name="action_send_sms" type="object" class="btn btn-primary btn-sm mt8">SMS</button>
<button name="action_send_mail" type="object" class="btn btn-primary btn-sm mt8">Mail</button>
@@ -64,31 +33,4 @@
</field>
</record>
- <record id="hr_employee_view_kanban_inherit" model="ir.ui.view">
- <field name="name">hr.employee</field>
- <field name="model">hr.employee</field>
- <field name="inherit_id" ref="hr.hr_kanban_view_employees"/>
- <field name="priority">1</field>
- <field name="arch" type="xml">
- <templates position="before">
- <field name="hr_presence_state"/>
- </templates>
- <field name="name" position="replace">
- <div>
- <div class="float-right" t-if="record.hr_presence_state.raw_value == 'present'">
- <span class="fa fa-circle text-success" role="img" aria-label="Present" title="Present" name="presence_present"></span>
- </div>
- <div class="float-right" t-if="record.hr_presence_state.raw_value == 'absent'">
- <span class="fa fa-circle text-danger" role="img" aria-label="Absent" title="Absent" name="presence_absent"></span>
- </div>
- <div class="float-right" t-if="record.hr_presence_state.raw_value == 'to_define'">
- <span class="fa fa-circle text-warning" role="img" aria-label="To define" title="To define" name="presence_to_define"></span>
- </div>
- <strong>
- <field name="name" placeholder="Employee's Name"/>
- </strong>
- </div>
- </field>
- </field>
- </record>
</odoo>
diff --git a/addons/hr_presence/views/res_config_settings_views.xml b/addons/hr_presence/views/res_config_settings_views.xml
deleted file mode 100644
index 9f447753925..00000000000
--- a/addons/hr_presence/views/res_config_settings_views.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<odoo>
- <record id="res_config_settings_view_form" model="ir.ui.view">
- <field name="name">res.config.settings.view.form.inherit.hr</field>
- <field name="model">res.config.settings</field>
- <field name="priority" eval="70"/>
- <field name="inherit_id" ref="hr.res_config_settings_view_form"/>
- <field name="arch" type="xml">
- <xpath expr="//div[@data-key='hr']//div[hasclass('o_settings_container')]" position="inside">
- <div class="col-12 col-lg-6 o_setting_box" title="Control presence of employees">
- <div class="o_setting_left_pane">
- <field name="module_hr_presence"/>
- </div>
- <div class="o_setting_right_pane">
- <label for="module_hr_presence"/>
- <div class="content-group" name="hr_presence_options">
- <div class="row">
- <field name="hr_presence_control_login" class="col-lg-1 ml16"/>
- <label for="hr_presence_control_login" class="col-lg-10 o_light_label"/>
- </div>
- <div class="row">
- <field name="hr_presence_control_email" class="col-lg-1 ml16"/>
- <label for="hr_presence_control_email" class="col-lg-10 o_light_label"/>
- </div>
- <div attrs="{'invisible': [('hr_presence_control_email', '=', False)]}">
- <span>At least </span>
- <field name="hr_presence_control_email_amount"/>
- <span> sent emails</span>
- </div>
- <div class="row">
- <field name="hr_presence_control_ip" class="col-lg-1 ml16"/>
- <label for="hr_presence_control_ip" class="col-lg-10 o_light_label"/>
- </div>
- <div attrs="{'invisible': [('hr_presence_control_ip', '=', False)]}">
- <span>IP List (comma separated):</span>
- <field name="hr_presence_control_ip_list"/>
- </div>
- </div>
- </div>
- </div>
- </xpath>
- </field>
- </record>
-</odoo>