Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

16.0 hr kanban attendance key figures #7

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions hr_attendance_kanban/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ HR Kanban Attendance
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:da8f298b12a35459d46da47157c9e26e70bc0ae50cfe53fc246e0094cf4f382c
!! source digest: sha256:bb5e4e353e16db9f446b1bc3c8357da4043163595c495916286cf835943c1a88
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
Expand Down Expand Up @@ -38,10 +38,14 @@ such as:
* 🏠 Home-Office
* 🚋 Travelling

On the right side of the kanban board, you can see certain key figures for the employee
such as overtime hours and remaining vacation time.

This module also adds the ability for employees to go on a break by using the kanban board.
Upon returning, they can end the break which will add the spent time to their attendance as
"break time". Once the employee checks out, they will be able to modify the total break time
if needed.
Upon returning, they can end the break which will **end** the current attendance at the
start time of the break and it will **start** a new attendance from the end time of the break.
This will result in the employee having multiple attendance records for the day and the time
spent on break is the delta between these attendances.

**Table of contents**

Expand All @@ -51,10 +55,20 @@ if needed.
Usage
=====

Setting up the attendance kanban configuration:

#. Go to *Attendances > Configuration > Attendance Types*
#. Adjust the attendance types to your needs
#. The employees can use *Attendances > Employees Kanban*

Using the attendance kanban:

#. Go to *Attendances > Employees Kanban*
#. Check in by dragging and dropping the employee card to the desired attendance type
#. Start a break by pressing the pause icon on the employee card
#. End a break by pressing the play icon on the employee card
#. Check out by dragging and dropping the employee card to the absent attendance type

Bug Tracker
===========

Expand Down
5 changes: 3 additions & 2 deletions hr_attendance_kanban/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

{
"name": "HR Kanban Attendance",
"version": "16.0.2.0.0",
"version": "16.0.4.0.0",
"category": "Human Resources",
"website": "https://github.com/OCA/hr-attendance",
"author": "Sozialinfo, Odoo Community Association (OCA), Miika Nissi",
"maintainers": ["miikanissi"],
"license": "LGPL-3",
"installable": True,
"depends": ["hr_attendance"],
"depends": ["hr_attendance", "hr_holidays"],
"data": [
"data/hr_attendance_type_data.xml",
"views/hr_employee_view.xml",
Expand All @@ -25,6 +25,7 @@
"web.assets_backend": [
"hr_attendance_kanban/static/src/views/**/*.js",
"hr_attendance_kanban/static/src/views/**/*.xml",
"hr_attendance_kanban/static/src/views/**/*.scss",
"hr_attendance_kanban/static/src/scss/hr_attendance_kanban.scss",
]
},
Expand Down
86 changes: 44 additions & 42 deletions hr_attendance_kanban/models/hr_attendance.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,57 +17,59 @@ class HrAttendance(models.Model):
)
comment = fields.Char(help="Optional comment for attendance")

break_time = fields.Float(help="Duration of the break in hours", default=0.0)
on_break = fields.Datetime(
break_start_time = fields.Datetime(
help=(
"Start time of the break. This is a technical field used to calculate break"
" time."
" time and determine if an attendance is on break."
),
readonly=True,
)

_sql_constraints = [
(
"check_break_time_positive",
"CHECK(break_time >= 0.0)",
"The break time cannot be negative.",
),
]

@api.model
def _read_group_attendance_type_ids(self, stages, domain, order):
return self.env["hr.attendance.type"].search([])

@api.depends("check_in", "check_out", "break_time")
def _compute_worked_hours(self):
attendance_with_break = self.filtered(lambda a: a.break_time > 0)
for attendance in attendance_with_break:
if attendance.check_out and attendance.check_in:
delta = attendance.check_out - attendance.check_in
worked_hours = (delta.total_seconds() / 3600.0) - attendance.break_time
attendance.worked_hours = max(0.0, worked_hours)
else:
attendance.worked_hours = False
return super(HrAttendance, self - attendance_with_break)._compute_worked_hours()
@api.constrains("check_out", "check_in", "break_start_time")
def _check_break_time(self):
for attendance in self.filtered("break_start_time"):
if attendance.check_out:
raise UserError(_("Employee cannot start a break while checked out."))
elif (
attendance.check_in
and attendance.check_in >= attendance.break_start_time
):
raise UserError(_("Employee cannot start a break before checking in."))

def _action_start_break(self, start_time):
self.write({"on_break": start_time})

def _action_end_break(self, start_time=None, end_time=None):
if not end_time:
self.write({"on_break": False})
return
for attendance in self:
if not attendance.on_break:
raise UserError(_("Employee is not on break."))
if not start_time:
start_time = attendance.on_break
attendance.write(
{
"break_time": (
attendance.break_time
+ (end_time - start_time).total_seconds() / 3600
),
"on_break": False,
}
def write(self, vals):
res = super().write(vals)
# Ensure that the break is ended when checking out
if vals.get("check_out"):
self.filtered(lambda x: x.break_start_time).write(
{"break_start_time": False}
)
return res

def _action_start_break(self, start_time=None):
"""
Starts a break for the employee by setting the break_start_time.

:param start_time: Optional datetime to set as the break_start_time. \
If not provided, the current datetime is used.
"""
self.write({"break_start_time": start_time or fields.Datetime.now()})

def _action_check_out(self, end_time=None):
"""
Checks out the employee by setting the check_out time resetting the \
break_start_time.

:param end_time: Optional datetime to set as the check_out time.
:raises UserError: If the employee is already checked out.
"""
self.ensure_one()
if self.check_out:
raise UserError(_("Employee is already checked out."))

self.write(
{"check_out": end_time or fields.Datetime.now(), "break_start_time": False}
)
4 changes: 2 additions & 2 deletions hr_attendance_kanban/models/hr_employee.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ class HrEmployee(models.Model):
store=True,
groups="hr_attendance.group_hr_attendance_user,hr.group_hr_user",
)
on_break = fields.Datetime(
related="last_attendance_id.on_break",
break_start_time = fields.Datetime(
related="last_attendance_id.break_start_time",
store=True,
groups="hr_attendance.group_hr_attendance_user,hr.group_hr_user",
)
Expand Down
4 changes: 2 additions & 2 deletions hr_attendance_kanban/models/hr_employee_public.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ class HrEmployeePublic(models.Model):
help="Technical field to see if the current user is the user of the record.",
)

on_break = fields.Datetime(
related="employee_id.on_break",
break_start_time = fields.Datetime(
related="employee_id.break_start_time",
readonly=True,
groups="hr_attendance.group_hr_attendance,hr.group_hr_user",
)
Expand Down
10 changes: 7 additions & 3 deletions hr_attendance_kanban/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ such as:
* 🏠 Home-Office
* 🚋 Travelling

On the right side of the kanban board, you can see certain key figures for the employee
such as overtime hours and remaining vacation time.

This module also adds the ability for employees to go on a break by using the kanban board.
Upon returning, they can end the break which will add the spent time to their attendance as
"break time". Once the employee checks out, they will be able to modify the total break time
if needed.
Upon returning, they can end the break which will **end** the current attendance at the
start time of the break and it will **start** a new attendance from the end time of the break.
This will result in the employee having multiple attendance records for the day and the time
spent on break is the delta between these attendances.
10 changes: 10 additions & 0 deletions hr_attendance_kanban/readme/USAGE.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
Setting up the attendance kanban configuration:

#. Go to *Attendances > Configuration > Attendance Types*
#. Adjust the attendance types to your needs
#. The employees can use *Attendances > Employees Kanban*

Using the attendance kanban:

#. Go to *Attendances > Employees Kanban*
#. Check in by dragging and dropping the employee card to the desired attendance type
#. Start a break by pressing the pause icon on the employee card
#. End a break by pressing the play icon on the employee card
#. Check out by dragging and dropping the employee card to the absent attendance type
20 changes: 16 additions & 4 deletions hr_attendance_kanban/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ <h1 class="title">HR Kanban Attendance</h1>
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:da8f298b12a35459d46da47157c9e26e70bc0ae50cfe53fc246e0094cf4f382c
!! source digest: sha256:bb5e4e353e16db9f446b1bc3c8357da4043163595c495916286cf835943c1a88
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/hr-attendance/tree/16.0/hr_attendance_kanban"><img alt="OCA/hr-attendance" src="https://img.shields.io/badge/github-OCA%2Fhr--attendance-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/hr-attendance-16-0/hr-attendance-16-0-hr_attendance_kanban"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/hr-attendance&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module allows employees to check-in or check-out by moving their avatar on a kanban board.</p>
Expand All @@ -380,10 +380,13 @@ <h1 class="title">HR Kanban Attendance</h1>
<li>🏠 Home-Office</li>
<li>🚋 Travelling</li>
</ul>
<p>On the right side of the kanban board, you can see certain key figures for the employee
such as overtime hours and remaining vacation time.</p>
<p>This module also adds the ability for employees to go on a break by using the kanban board.
Upon returning, they can end the break which will add the spent time to their attendance as
“break time”. Once the employee checks out, they will be able to modify the total break time
if needed.</p>
Upon returning, they can end the break which will <strong>end</strong> the current attendance at the
start time of the break and it will <strong>start</strong> a new attendance from the end time of the break.
This will result in the employee having multiple attendance records for the day and the time
spent on break is the delta between these attendances.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
Expand All @@ -399,11 +402,20 @@ <h1 class="title">HR Kanban Attendance</h1>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<p>Setting up the attendance kanban configuration:</p>
<ol class="arabic simple">
<li>Go to <em>Attendances &gt; Configuration &gt; Attendance Types</em></li>
<li>Adjust the attendance types to your needs</li>
<li>The employees can use <em>Attendances &gt; Employees Kanban</em></li>
</ol>
<p>Using the attendance kanban:</p>
<ol class="arabic simple">
<li>Go to <em>Attendances &gt; Employees Kanban</em></li>
<li>Check in by dragging and dropping the employee card to the desired attendance type</li>
<li>Start a break by pressing the pause icon on the employee card</li>
<li>End a break by pressing the play icon on the employee card</li>
<li>Check out by dragging and dropping the employee card to the absent attendance type</li>
</ol>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/** @odoo-module **/

import {EmployeeInspector} from "../inspector/employee_inspector.esm";
import {KanbanRenderer} from "@web/views/kanban/kanban_renderer";

const {useRef} = owl;

export class HrEmployeeAttendanceKanbanRenderer extends KanbanRenderer {
setup() {
super.setup();
this.root = useRef("root");
}

getEmployeeInspectorProps() {
// Modify any props here
return {
selection: this.props.list.selection,
};
}
}

HrEmployeeAttendanceKanbanRenderer.template =
"hr_attendance_kanban.HrEmployeeAttendanceKanbanRenderer";
HrEmployeeAttendanceKanbanRenderer.components = Object.assign(
{},
KanbanRenderer.components,
{
EmployeeInspector,
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates>
<t
t-name="hr_attendance_kanban.HrEmployeeAttendanceKanbanRenderer"
t-inherit="web.KanbanRenderer"
t-inherit-mode="primary"
owl="1"
>
<xpath expr="//div[hasclass('o_kanban_renderer')]" position="attributes">
<attribute name="class" add="o_attendance_kanban_view" separator=" " />
</xpath>
<xpath expr="//div[hasclass('o_kanban_renderer')]" position="after">
<EmployeeInspector t-props="getEmployeeInspectorProps()" />
</xpath>
</t>
</templates>
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import {HrEmployeeAttendanceKanbanController} from "@hr_attendance_kanban/views/hr_employee_attendance_kanban/hr_employee_attendance_kanban_controller.esm";
import {HrEmployeeAttendanceKanbanModel} from "@hr_attendance_kanban/views/hr_employee_attendance_kanban/hr_employee_attendance_kanban_model.esm";
import {HrEmployeeAttendanceKanbanRenderer} from "@hr_attendance_kanban/views/hr_employee_attendance_kanban/hr_employee_attendance_kanban_renderer.esm";
import {kanbanView} from "@web/views/kanban/kanban_view";
import {registry} from "@web/core/registry";

export const hrEmployeeAttendanceKanbanView = {
...kanbanView,
Controller: HrEmployeeAttendanceKanbanController,
Model: HrEmployeeAttendanceKanbanModel,
Renderer: HrEmployeeAttendanceKanbanRenderer,
buttonTemplate: "hr_attendance_kanban.HrEmployeeAttendanceKanbanController.Buttons",
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/** @odoo-module **/

import fieldUtils from "web.field_utils";
import {session} from "@web/session";
import {TimeOffCard} from "@hr_holidays/dashboard/time_off_card";
import {useService} from "@web/core/utils/hooks";

const {Component, useState, onWillStart} = owl;

export class EmployeeInspector extends Component {
setup() {
this.orm = useService("orm");
this.state = useState({
employee: {},
holidays: [],
});
onWillStart(async () => {
await this.getEmployeeDays();
});
}

async getEmployeeDays() {
const context = {};

const publicEmployee = await this.orm.searchRead(
"hr.employee.public",
[["user_id", "=", session.uid]],
["id", "name", "total_overtime"],
{limit: 1}
);
if (publicEmployee.length === 0) {
return;
}

this.state.employee = publicEmployee[0];
context.employee_id = this.state.employee.id;

this.state.holidays = await this.orm.call(
"hr.leave.type",
"get_days_all_request",
[],
{
context: context,
}
);
}

formatFloatTime(value) {
return fieldUtils.format.float_time(value);
}
}

EmployeeInspector.components = {TimeOffCard};
EmployeeInspector.template = "hr_attendance_kanban.EmployeeInspector";
Loading