[MIG] hr_effective_attendance_period: migrate to 18.0
This commit is contained in:
67
hr_effective_attendance_period/README.rst
Normal file
67
hr_effective_attendance_period/README.rst
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
==============================
|
||||||
|
hr_effective_attendance_period
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Provide indication that attendance periods are effectively worked or not.
|
||||||
|
|
||||||
|
Description
|
||||||
|
===========
|
||||||
|
|
||||||
|
This module adds a boolean field on working time attendance lines to mark
|
||||||
|
which periods are effectively worked by employees. It provides utility methods
|
||||||
|
on the resource calendar to determine:
|
||||||
|
|
||||||
|
- Whether a day is a working day
|
||||||
|
- Whether a day is a full working day (both morning and afternoon)
|
||||||
|
- Whether all attendances of a day are effectively worked (no leaves)
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
Use Odoo normal module installation procedure to install
|
||||||
|
``hr_effective_attendance_period``.
|
||||||
|
|
||||||
|
This module depends on:
|
||||||
|
|
||||||
|
* ``base`` (Odoo core)
|
||||||
|
* ``resource`` (Odoo core)
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
=============
|
||||||
|
|
||||||
|
Go to ``Configuration > Technical > Resource > Working Times`` and create
|
||||||
|
Working Times for your company. For each attendance line, check
|
||||||
|
``Effective Attendance Period`` to indicate which periods are effectively
|
||||||
|
attended by employees.
|
||||||
|
|
||||||
|
Known issues / Roadmap
|
||||||
|
======================
|
||||||
|
|
||||||
|
None yet.
|
||||||
|
|
||||||
|
Bug Tracker
|
||||||
|
===========
|
||||||
|
|
||||||
|
Bugs are tracked on `our issues website <https://github.com/elabore-coop/hr-tools/issues>`_.
|
||||||
|
In case of trouble, please check there if your issue has already been reported.
|
||||||
|
If you spotted it first, help us smash it by providing detailed and welcomed feedback.
|
||||||
|
|
||||||
|
Credits
|
||||||
|
=======
|
||||||
|
|
||||||
|
Contributors
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Stéphan Sainléger
|
||||||
|
|
||||||
|
Funders
|
||||||
|
-------
|
||||||
|
|
||||||
|
The development of this module has been financially supported by:
|
||||||
|
|
||||||
|
* Elabore (https://elabore.coop)
|
||||||
|
|
||||||
|
Maintainer
|
||||||
|
----------
|
||||||
|
|
||||||
|
This module is maintained by Elabore.
|
||||||
1
hr_effective_attendance_period/__init__.py
Normal file
1
hr_effective_attendance_period/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import models
|
||||||
24
hr_effective_attendance_period/__manifest__.py
Normal file
24
hr_effective_attendance_period/__manifest__.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Copyright 2023 Stéphan Sainléger (Elabore)
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "hr_effective_attendance_period",
|
||||||
|
"version": "18.0.1.0.0",
|
||||||
|
"author": "Elabore",
|
||||||
|
"website": "https://git.elabore.coop/elabore/hr-tools",
|
||||||
|
"maintainer": "Stéphan Sainléger",
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"category": "Tools",
|
||||||
|
"summary": "Indicate whether attendance periods are effectively worked",
|
||||||
|
# any module necessary for this one to work correctly
|
||||||
|
"depends": [
|
||||||
|
"base",
|
||||||
|
"resource",
|
||||||
|
],
|
||||||
|
"data": [
|
||||||
|
"views/resource_views.xml",
|
||||||
|
],
|
||||||
|
"installable": True,
|
||||||
|
"auto_install": False,
|
||||||
|
"application": False,
|
||||||
|
}
|
||||||
1
hr_effective_attendance_period/i18n/README
Normal file
1
hr_effective_attendance_period/i18n/README
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This directory should contain the *.po for Odoo translation.
|
||||||
49
hr_effective_attendance_period/i18n/fr.po
Normal file
49
hr_effective_attendance_period/i18n/fr.po
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * hr_effective_attendance_period
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 14.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2023-01-24 21:50+0000\n"
|
||||||
|
"PO-Revision-Date: 2023-01-24 21:50+0000\n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
|
#. module: hr_effective_attendance_period
|
||||||
|
#: model:ir.model.fields,field_description:hr_effective_attendance_period.field_resource_calendar__display_name
|
||||||
|
#: model:ir.model.fields,field_description:hr_effective_attendance_period.field_resource_calendar_attendance__display_name
|
||||||
|
msgid "Display Name"
|
||||||
|
msgstr "Nom affiché"
|
||||||
|
|
||||||
|
#. module: hr_effective_attendance_period
|
||||||
|
#: model:ir.model.fields,field_description:hr_effective_attendance_period.field_resource_calendar_attendance__effective_attendance_period
|
||||||
|
msgid "Effective Attendance Period"
|
||||||
|
msgstr "Présence effective"
|
||||||
|
|
||||||
|
#. module: hr_effective_attendance_period
|
||||||
|
#: model:ir.model.fields,field_description:hr_effective_attendance_period.field_resource_calendar__id
|
||||||
|
#: model:ir.model.fields,field_description:hr_effective_attendance_period.field_resource_calendar_attendance__id
|
||||||
|
msgid "ID"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: hr_effective_attendance_period
|
||||||
|
#: model:ir.model.fields,field_description:hr_effective_attendance_period.field_resource_calendar____last_update
|
||||||
|
#: model:ir.model.fields,field_description:hr_effective_attendance_period.field_resource_calendar_attendance____last_update
|
||||||
|
msgid "Last Modified on"
|
||||||
|
msgstr "Dernière modification le"
|
||||||
|
|
||||||
|
#. module: hr_effective_attendance_period
|
||||||
|
#: model:ir.model,name:hr_effective_attendance_period.model_resource_calendar
|
||||||
|
msgid "Resource Working Time"
|
||||||
|
msgstr "Temps de travail de la ressource"
|
||||||
|
|
||||||
|
#. module: hr_effective_attendance_period
|
||||||
|
#: model:ir.model,name:hr_effective_attendance_period.model_resource_calendar_attendance
|
||||||
|
msgid "Work Detail"
|
||||||
|
msgstr "Détail du travail"
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * hr_effective_attendance_period
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 14.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2023-01-24 21:49+0000\n"
|
||||||
|
"PO-Revision-Date: 2023-01-24 21:49+0000\n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
|
#. module: hr_effective_attendance_period
|
||||||
|
#: model:ir.model.fields,field_description:hr_effective_attendance_period.field_resource_calendar__display_name
|
||||||
|
#: model:ir.model.fields,field_description:hr_effective_attendance_period.field_resource_calendar_attendance__display_name
|
||||||
|
msgid "Display Name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: hr_effective_attendance_period
|
||||||
|
#: model:ir.model.fields,field_description:hr_effective_attendance_period.field_resource_calendar_attendance__effective_attendance_period
|
||||||
|
msgid "Effective Attendance Period"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: hr_effective_attendance_period
|
||||||
|
#: model:ir.model.fields,field_description:hr_effective_attendance_period.field_resource_calendar__id
|
||||||
|
#: model:ir.model.fields,field_description:hr_effective_attendance_period.field_resource_calendar_attendance__id
|
||||||
|
msgid "ID"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: hr_effective_attendance_period
|
||||||
|
#: model:ir.model.fields,field_description:hr_effective_attendance_period.field_resource_calendar____last_update
|
||||||
|
#: model:ir.model.fields,field_description:hr_effective_attendance_period.field_resource_calendar_attendance____last_update
|
||||||
|
msgid "Last Modified on"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: hr_effective_attendance_period
|
||||||
|
#: model:ir.model,name:hr_effective_attendance_period.model_resource_calendar
|
||||||
|
msgid "Resource Working Time"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: hr_effective_attendance_period
|
||||||
|
#: model:ir.model,name:hr_effective_attendance_period.model_resource_calendar_attendance
|
||||||
|
msgid "Work Detail"
|
||||||
|
msgstr ""
|
||||||
1
hr_effective_attendance_period/models/__init__.py
Normal file
1
hr_effective_attendance_period/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import resource
|
||||||
97
hr_effective_attendance_period/models/resource.py
Normal file
97
hr_effective_attendance_period/models/resource.py
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import math
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
from odoo import fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceCalendarAttendance(models.Model):
|
||||||
|
_inherit = "resource.calendar.attendance"
|
||||||
|
|
||||||
|
effective_attendance_period = fields.Boolean(store=True)
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceCalendar(models.Model):
|
||||||
|
_inherit = "resource.calendar"
|
||||||
|
|
||||||
|
def _retrieve_day_matching_attendances(self, day):
|
||||||
|
domain = [
|
||||||
|
("calendar_id", "=", self.id),
|
||||||
|
("dayofweek", "=", day.weekday()),
|
||||||
|
("effective_attendance_period", "=", True),
|
||||||
|
]
|
||||||
|
if self.two_weeks_calendar:
|
||||||
|
# Employee has Even/Odd weekly calendar
|
||||||
|
week_type = 1 if int(math.floor((day.toordinal() - 1) / 7) % 2) else 0
|
||||||
|
domain.append(("week_type", "=", week_type))
|
||||||
|
result = self.env["resource.calendar.attendance"].search(domain)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def is_working_day(self, day):
|
||||||
|
day_attendances = self._retrieve_day_matching_attendances(day)
|
||||||
|
if len(day_attendances) == 0:
|
||||||
|
# This day of the week is not supposed to be a working day
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
# This day of the week is supposed to be a working day
|
||||||
|
return True
|
||||||
|
|
||||||
|
def is_full_working_day(self, day):
|
||||||
|
day_attendances = self._retrieve_day_matching_attendances(day)
|
||||||
|
morning_worked = (
|
||||||
|
len(day_attendances.filtered(lambda x: x.day_period == "morning")) > 0
|
||||||
|
)
|
||||||
|
afternoon_worked = (
|
||||||
|
len(day_attendances.filtered(lambda x: x.day_period == "afternoon")) > 0
|
||||||
|
)
|
||||||
|
return morning_worked and afternoon_worked
|
||||||
|
|
||||||
|
def _compute_datetime_in_utc_tz(self, date):
|
||||||
|
user_tz = pytz.timezone(self.env.context.get("tz", "utc") or "utc")
|
||||||
|
return user_tz.localize(date).astimezone(pytz.utc)
|
||||||
|
|
||||||
|
def _is_worked_attendance(self, resource, day, attendance):
|
||||||
|
attendance_start = fields.Datetime.to_datetime(day.date()) + timedelta(
|
||||||
|
hours=attendance.hour_from
|
||||||
|
)
|
||||||
|
attendance_end = fields.Datetime.to_datetime(day.date()) + timedelta(
|
||||||
|
hours=attendance.hour_to
|
||||||
|
)
|
||||||
|
utc_start = self._compute_datetime_in_utc_tz(attendance_start)
|
||||||
|
utc_end = self._compute_datetime_in_utc_tz(attendance_end)
|
||||||
|
resource_leaves = (
|
||||||
|
self.env["resource.calendar.leaves"]
|
||||||
|
.sudo()
|
||||||
|
.search(
|
||||||
|
[
|
||||||
|
("company_id", "=", resource.company_id.id),
|
||||||
|
("date_from", "<=", utc_start),
|
||||||
|
("date_to", ">=", utc_end),
|
||||||
|
"|",
|
||||||
|
("resource_id", "=", resource.id),
|
||||||
|
("resource_id", "=", None),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if resource_leaves:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
# a part or the whole attendance is worked
|
||||||
|
return True
|
||||||
|
|
||||||
|
def is_worked_day(self, resource, day):
|
||||||
|
day_attendances = self._retrieve_day_matching_attendances(day)
|
||||||
|
# If at least one attendance is worked, return True
|
||||||
|
for attendance in day_attendances:
|
||||||
|
if self._is_worked_attendance(resource, day, attendance):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def all_attendances_worked(self, resource, day):
|
||||||
|
day_attendances = self._retrieve_day_matching_attendances(day)
|
||||||
|
# If at least one attendance is not worked, return False
|
||||||
|
for attendance in day_attendances:
|
||||||
|
if not self._is_worked_attendance(resource, day, attendance):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
36
hr_effective_attendance_period/views/resource_views.xml
Normal file
36
hr_effective_attendance_period/views/resource_views.xml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<odoo>
|
||||||
|
<record
|
||||||
|
id="view_resource_calendar_attendance_tree_inherit_effective_attendance"
|
||||||
|
model="ir.ui.view"
|
||||||
|
>
|
||||||
|
<field name="name">resource.calendar.attendance.view.list.inherit</field>
|
||||||
|
<field name="model">resource.calendar.attendance</field>
|
||||||
|
<field
|
||||||
|
name="inherit_id"
|
||||||
|
ref="resource.view_resource_calendar_attendance_tree"
|
||||||
|
/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//field[@name='week_type']" position="after">
|
||||||
|
<field name="effective_attendance_period" />
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record
|
||||||
|
id="view_resource_calendar_attendance_form_inherit_effective_attendance"
|
||||||
|
model="ir.ui.view"
|
||||||
|
>
|
||||||
|
<field name="name">resource.calendar.attendance.view.list.inherit</field>
|
||||||
|
<field name="model">resource.calendar.attendance</field>
|
||||||
|
<field
|
||||||
|
name="inherit_id"
|
||||||
|
ref="resource.view_resource_calendar_attendance_form"
|
||||||
|
/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//field[@name='day_period']" position="after">
|
||||||
|
<field name="effective_attendance_period" />
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
Reference in New Issue
Block a user