-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by dreispt
- Loading branch information
Showing
28 changed files
with
1,931 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
=================== | ||
HR Attendance Sheet | ||
=================== | ||
|
||
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
!! This file is generated by oca-gen-addon-readme !! | ||
!! changes will be overwritten. !! | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png | ||
:target: https://odoo-community.org/page/development-status | ||
:alt: Beta | ||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png | ||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html | ||
:alt: License: AGPL-3 | ||
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fhr-lightgray.png?logo=github | ||
:target: https://github.com/OCA/hr/tree/12.0/hr_attendance_rfid | ||
:alt: OCA/hr | ||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png | ||
:target: https://translation.odoo-community.org/projects/hr-12-0/hr-12-0-hr_attendance_rfid | ||
:alt: Translate me on Weblate | ||
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png | ||
:target: https://runbot.odoo-community.org/runbot/116/12.0 | ||
:alt: Try me on Runbot | ||
|
||
|badge1| |badge2| |badge3| |badge4| |badge5| | ||
|
||
This module extends attendance and adds sheets and other features. | ||
Feature List: | ||
|
||
* Attendance sheets, generated Daily, Weekly, Bi-Weekly or Monthly | ||
* Auto lunch calculation in the duration if attendance duration surpasses time. | ||
* Split attendance at midnight is attendance crosses to the next day. | ||
* Approval process for 'HR', 'Manger' and 'Manager or HR' | ||
|
||
**Table of contents** | ||
|
||
.. contents:: | ||
:local: | ||
|
||
Configuration | ||
============= | ||
|
||
Attendance Sheet Configuration: | ||
#. Go to *Attendances -> Configuration*. | ||
#. Set the Attendance Sheet Range to be used to calculate start/end dates | ||
on the sheet when they are created. | ||
#. Set the Attendance Sheet Review Policy for who cab review sheets. | ||
#. Choose Split Overnight Attendance if you want attendances that cross | ||
overnight to be split into two attendances at midnight. | ||
#. Choose Auto Lunch if you want a lunch calculated automatically. Duration is | ||
maximum hours where a lunch would be calculated with the lunch duration. | ||
For example, duration set to 5hrs, lunch set to .5hrs, if attendance is 6hours | ||
then the duration on the attendance would show 5.5hrs due to the auto lunch. | ||
|
||
Employee Configuration: | ||
#. Go to *Attendances -> Manage Attendances -> Employees*. | ||
#. Open the Employee and then HR Settings | ||
#. Check Manual Attendance to give them access to the attendance app. | ||
#. Check Attendance Sheets if they will be having sheets created for them. | ||
#. Set Hours to Work which is the expected work time during the sheet period, | ||
this is used to calculates overtime values on the sheet. | ||
#. If manager's are set to review, make sure a manager is set on the employee. | ||
|
||
Usage | ||
===== | ||
|
||
#. Sheets will be auto created by a scheduled action for employees that have | ||
the attendance sheet checked on their employee record. | ||
#. Sheets will have a start/end time based on the period set in settings. | ||
#. Attendances that have dates between the sheet start/end time will | ||
automatically be put into the sheet. | ||
#. Split overnight attendance (if enabled) is used if attendances shouldn't | ||
cross overnight and will generate another attendance for the next day, split | ||
at midnight of the timezone that is set on the employee record. A banner will | ||
show on the attendance stating that a split has been applied. | ||
#. Auto lunch (if enabled) will be calculated in the attendance duration if the | ||
duration exceeds the auto lunch setting. A banner will show on the attendance | ||
stating that an auto lunch has been applied. | ||
#. After sheet period ends, Employee submits sheet to reviewer. Reviewer makes | ||
changes if necessary and approves sheet. | ||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/hr/issues>`_. | ||
In case of trouble, please check there if your issue has already been reported. | ||
If you spotted it first, help us smashing it by providing a detailed and welcomed | ||
`feedback <https://github.com/OCA/hr/issues/new?body=module:%20hr_attendance_rfid%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. | ||
|
||
Do not contact contributors directly about support or help with technical issues. | ||
|
||
Credits | ||
======= | ||
|
||
Authors | ||
~~~~~~~ | ||
|
||
* Pavlov Media | ||
|
||
Contributors | ||
~~~~~~~~~~~~ | ||
|
||
* Patrick Wilson <pwilson@pavlovmedia.com> | ||
|
||
Maintainers | ||
~~~~~~~~~~~ | ||
|
||
This module is maintained by the OCA. | ||
|
||
.. image:: https://odoo-community.org/logo.png | ||
:alt: Odoo Community Association | ||
:target: https://odoo-community.org | ||
|
||
OCA, or the Odoo Community Association, is a nonprofit organization whose | ||
mission is to support the collaborative development of Odoo features and | ||
promote its widespread use. | ||
|
||
This module is part of the `OCA/hr <https://github.com/OCA/hr/tree/12.0/hr_attendance_sheet>`_ project on GitHub. | ||
|
||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Copyright 2017 Odoo S.A. | ||
# Copyright 2020 Pavlov Media | ||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html | ||
|
||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Copyright 2020 Pavlov Media | ||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html | ||
|
||
{ | ||
"name": "HR Attendance Sheet", | ||
"version": "12.0.1.0.0", | ||
"category": "Human Resources", | ||
"summary": "Group attendances into attendance sheets.", | ||
"website": "https://github.com/OCA/hr", | ||
"author": "Odoo S.A., Odoo Community Association (OCA)", | ||
"license": "AGPL-3", | ||
"installable": True, | ||
"depends": [ | ||
"hr_attendance", | ||
], | ||
"data": [ | ||
"security/ir.model.access.csv", | ||
"security/security_groups.xml", | ||
"data/cron.xml", | ||
"data/mail_data.xml", | ||
"report/hr_attendance_sheet_report.xml", | ||
"views/hr_attendance_sheet.xml", | ||
"views/hr_attendance_view.xml", | ||
"views/hr_department.xml", | ||
"views/hr_employee.xml", | ||
"views/res_config_settings_views.xml", | ||
"views/res_company.xml", | ||
], | ||
"development_status": "Beta", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<odoo> | ||
<record id="ir_cron_attendance_sheet_creation" model="ir.cron"> | ||
<field name="name">Attendance Sheets: Create Sheets</field> | ||
<field name="interval_number">4</field> | ||
<field name="interval_type">hours</field> | ||
<field name="numbercall">-1</field> | ||
<field name="doall" eval="False"/> | ||
<field name="model_id" ref="model_hr_attendance_sheet"/> | ||
<field name="code">model._create_sheet_id()</field> | ||
<field name="state">code</field> | ||
</record> | ||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<odoo noupdate="1"> | ||
<!-- Leave specific activities --> | ||
<record id="mail_act_attendance_sheet_approval" model="mail.activity.type"> | ||
<field name="name">Attendance Sheet Approval</field> | ||
<field name="icon">fa-sun-o</field> | ||
<field name="res_model_id" ref="hr_attendance_sheet.model_hr_attendance_sheet"/> | ||
</record> | ||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Copyright 2020 Pavlov Media | ||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html | ||
|
||
from . import hr_attendance | ||
from . import hr_attendance_sheet | ||
from . import hr_department | ||
from . import hr_employee | ||
from . import res_company | ||
from . import res_config |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
# Copyright 2020 Pavlov Media | ||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html | ||
|
||
from odoo import api, fields, models, _ | ||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT | ||
from odoo.exceptions import UserError | ||
|
||
import pytz | ||
from datetime import datetime | ||
|
||
|
||
class HrAttendance(models.Model): | ||
_inherit = "hr.attendance" | ||
|
||
attendance_sheet_id = fields.Many2one( | ||
"hr.attendance.sheet", | ||
string="Sheet", | ||
compute="_compute_attendance_sheet_id", | ||
store=True, | ||
) | ||
duration = fields.Float( | ||
string="Duration (Hrs)", | ||
compute="_compute_duration", | ||
) | ||
auto_lunch = fields.Boolean( | ||
string="Auto Lunch Applied", | ||
help="If Auto Lunch is enabled and applied on this attendance.", | ||
) | ||
company_id = fields.Many2one( | ||
"res.company", string="Company", related="attendance_sheet_id.company_id" | ||
) | ||
auto_lunch_enabled = fields.Boolean( | ||
string="Auto Lunch Enabled", related="company_id.auto_lunch" | ||
) | ||
override_auto_lunch = fields.Boolean( | ||
string="Override Auto Lunch", | ||
help="Enable if you don't want the auto lunch to calculate.", | ||
) | ||
override_reason = fields.Text( | ||
string="Override Reason", | ||
help="State the reason you are overriding the auto lunch.", | ||
) | ||
attendance_admin = fields.Many2one( | ||
"hr.employee", | ||
string="Attendance Admin", | ||
help="""In addition to the employees manager, this person can | ||
administer attendances for all employees in the department. This field | ||
is set on the department.""", | ||
related="department_id.attendance_admin", | ||
) | ||
|
||
# Get Methods | ||
def _get_attendance_employee_tz(self, date=None): | ||
"""Convert date according to timezone of user""" | ||
tz = False | ||
if self.employee_id: | ||
tz = self.employee_id.tz | ||
if not date: | ||
return False | ||
time_zone = pytz.timezone(tz or "UTC") | ||
attendance_dt = datetime.strptime(str(date), DEFAULT_SERVER_DATETIME_FORMAT) | ||
attendance_tz_dt = pytz.UTC.localize(attendance_dt) | ||
attendance_tz_dt = attendance_tz_dt.astimezone(time_zone) | ||
attendance_tz_date_str = datetime.strftime( | ||
attendance_tz_dt, DEFAULT_SERVER_DATE_FORMAT | ||
) | ||
return attendance_tz_date_str | ||
|
||
def _get_attendance_state(self): | ||
"""Check and raise error if related sheet is not in 'draft' state""" | ||
if self.attendance_sheet_id and self.attendance_sheet_id.state == "locked": | ||
raise UserError(_("You cannot modify an entry in a locked sheet.")) | ||
elif ( | ||
self.attendance_sheet_id.state == "done" | ||
and self.env.user not in self.attendance_sheet_id._get_possible_reviewers() | ||
): | ||
raise UserError(_("You cannot modify an entry in a approved sheet")) | ||
return True | ||
|
||
# Compute Methods | ||
@api.depends("employee_id", "check_in", "check_out") | ||
def _compute_attendance_sheet_id(self): | ||
"""Find and set current sheet in current attendance record""" | ||
for attendance in self: | ||
sheet_obj = self.env["hr.attendance.sheet"] | ||
check_in = False | ||
if attendance.check_in: | ||
check_in = attendance._get_attendance_employee_tz( | ||
date=attendance.check_in | ||
) | ||
domain = [("employee_id", "=", attendance.employee_id.id)] | ||
if check_in: | ||
domain += [ | ||
("date_start", "<=", check_in), | ||
("date_end", ">=", check_in), | ||
] | ||
attendance_sheet_ids = sheet_obj.search(domain, limit=1) | ||
if attendance_sheet_ids.state not in ("locked", "done"): | ||
attendance.attendance_sheet_id = attendance_sheet_ids or False | ||
|
||
@api.multi | ||
def _compute_duration(self): | ||
for rec in self: | ||
if rec.check_in and rec.check_out: | ||
delta = rec.check_out - rec.check_in | ||
rec.duration = delta.total_seconds() / 3600 | ||
|
||
# If auto lunch is enabled for the company and time between | ||
# other attendances < lunch period, then adjust the duration | ||
# calculation for the first attendance. | ||
if ( | ||
rec.company_id.auto_lunch | ||
and rec.duration > rec.company_id.auto_lunch_duration != 0.0 | ||
and not rec.override_auto_lunch | ||
): | ||
day_start = rec.check_in.replace( | ||
hour=0, minute=0, second=0, microsecond=0 | ||
) | ||
day_end = rec.check_out.replace( | ||
hour=23, minute=59, second=59, microsecond=59 | ||
) | ||
first_attendance = self.env["hr.attendance"].search( | ||
[ | ||
("check_in", ">=", day_start), | ||
("check_in", "<=", day_end), | ||
("employee_id", "=", rec.employee_id.id), | ||
], | ||
order="check_in asc", | ||
limit=1, | ||
) | ||
today_attendances = self.env["hr.attendance"].search( | ||
[ | ||
("check_in", ">=", day_start), | ||
("check_in", "<=", day_end), | ||
("employee_id", "=", rec.employee_id.id), | ||
] | ||
) | ||
time_between_attendances = 0.0 | ||
if first_attendance and first_attendance.id == rec.id: | ||
if len(today_attendances) > 1: | ||
for attendance in today_attendances: | ||
if attendance.id != first_attendance.id: | ||
delta2 = ( | ||
attendance.check_in - first_attendance.check_out | ||
) | ||
time_between_attendances = ( | ||
delta2.total_seconds() / 3600 | ||
) | ||
rec.write({"auto_lunch": False}) | ||
if ( | ||
time_between_attendances | ||
< rec.company_id.auto_lunch_hours | ||
): | ||
rec.duration = ( | ||
delta.total_seconds() / 3600 | ||
) - rec.company_id.auto_lunch_hours | ||
rec.write({"auto_lunch": True}) | ||
else: | ||
rec.duration = ( | ||
delta.total_seconds() / 3600 | ||
) - rec.company_id.auto_lunch_hours | ||
rec.write({"auto_lunch": True}) | ||
else: | ||
rec.write({"auto_lunch": False}) | ||
elif rec.company_id.auto_lunch and rec.auto_lunch: | ||
rec.write({"auto_lunch": False}) | ||
|
||
# Unlink/Write/Create Methods | ||
@api.multi | ||
def unlink(self): | ||
"""Restrict to delete attendance from confirmed/locked sheet""" | ||
for attendance in self: | ||
attendance._get_attendance_state() | ||
return super(HrAttendance, self).unlink() | ||
|
||
@api.multi | ||
def write(self, vals): | ||
"""Restrict to write attendance from confirmed/locked sheet.""" | ||
protected_fields = ["employee_id", "check_in", "check_out"] | ||
for attendance in self: | ||
if attendance.attendance_sheet_id.state in ("locked", "done") and any( | ||
f in vals.keys() for f in protected_fields | ||
): | ||
attendance._get_attendance_state() | ||
return super(HrAttendance, self).write(vals) |
Oops, something went wrong.