From 3ca8609d769fefecc484f6bc0f71a0ec437477aa Mon Sep 17 00:00:00 2001 From: Thor Date: Thu, 26 Dec 2019 16:30:11 +0100 Subject: [PATCH] [ADD] hr_attendance_resume_of: New menu "Imputations resume R". --- hr_attendance_resume_of/README.rst | 27 +++++ hr_attendance_resume_of/__init__.py | 3 + hr_attendance_resume_of/__manifest__.py | 18 +++ hr_attendance_resume_of/_common.py | 32 +++++ hr_attendance_resume_of/i18n/es.po | 82 +++++++++++++ .../i18n/hr_attendance_resume_of.pot | 82 +++++++++++++ hr_attendance_resume_of/models/__init__.py | 5 + .../models/hr_attendance_resume.py | 109 ++++++++++++++++++ hr_attendance_resume_of/models/hr_employee.py | 32 +++++ .../models/resource_calendar_attendance.py | 18 +++ .../views/hr_attendance_resume_view.xml | 85 ++++++++++++++ 11 files changed, 493 insertions(+) create mode 100644 hr_attendance_resume_of/README.rst create mode 100644 hr_attendance_resume_of/__init__.py create mode 100644 hr_attendance_resume_of/__manifest__.py create mode 100644 hr_attendance_resume_of/_common.py create mode 100644 hr_attendance_resume_of/i18n/es.po create mode 100644 hr_attendance_resume_of/i18n/hr_attendance_resume_of.pot create mode 100644 hr_attendance_resume_of/models/__init__.py create mode 100644 hr_attendance_resume_of/models/hr_attendance_resume.py create mode 100644 hr_attendance_resume_of/models/hr_employee.py create mode 100644 hr_attendance_resume_of/models/resource_calendar_attendance.py create mode 100644 hr_attendance_resume_of/views/hr_attendance_resume_view.xml diff --git a/hr_attendance_resume_of/README.rst b/hr_attendance_resume_of/README.rst new file mode 100644 index 00000000..cd70758f --- /dev/null +++ b/hr_attendance_resume_of/README.rst @@ -0,0 +1,27 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +======================= +Hr attendance resume of +======================= + +* New menu "Imputations resume R". + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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 +------------ +* Ana Juaristi +* Alfredo de la Fuente + +Do not contact contributors directly about support or help with technical issues. diff --git a/hr_attendance_resume_of/__init__.py b/hr_attendance_resume_of/__init__.py new file mode 100644 index 00000000..1fd704ff --- /dev/null +++ b/hr_attendance_resume_of/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2019 Alfredo de la Fuente - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +from . import models diff --git a/hr_attendance_resume_of/__manifest__.py b/hr_attendance_resume_of/__manifest__.py new file mode 100644 index 00000000..5ab67d39 --- /dev/null +++ b/hr_attendance_resume_of/__manifest__.py @@ -0,0 +1,18 @@ +# Copyright 2019 Alfredo de la Fuente - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +{ + "name": "Hr Attendance Resume OF", + "version": "12.0.1.0.0", + "license": "AGPL-3", + "depends": [ + "hr_attendance_resume", + "resource_gesalaga", + ], + "author": "AvanzOSC", + "website": "http://www.avanzosc.es", + "category": "Human Resources", + "data": [ + "views/hr_attendance_resume_view.xml", + ], + "installable": True, +} diff --git a/hr_attendance_resume_of/_common.py b/hr_attendance_resume_of/_common.py new file mode 100644 index 00000000..5f67493a --- /dev/null +++ b/hr_attendance_resume_of/_common.py @@ -0,0 +1,32 @@ +# Copyright 2019 Alfredo de la Fuente - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +from datetime import date as datetype +from dateutil.relativedelta import relativedelta +from pytz import timezone, utc +from odoo import fields, _ + +str2datetime = fields.Datetime.from_string +date2str = fields.Date.to_string + + +def _convert_to_local_date(date, tz=u'UTC'): + if not date: + return False + if not tz: + tz = u'UTC' + new_date = str2datetime(date) if isinstance(date, str) else date + new_date = new_date.replace(tzinfo=utc) + local_date = new_date.astimezone(timezone(tz)).replace(tzinfo=None) + return local_date + + +def _convert_time_to_float(date, tz=u'UTC'): + if not date: + return False + if not tz: + tz = u'UTC' + local_time = _convert_to_local_date(date, tz=tz) + hour = float(local_time.hour) + minutes = float(local_time.minute) / 60 + seconds = float(local_time.second) / 360 + return (hour + minutes + seconds) diff --git a/hr_attendance_resume_of/i18n/es.po b/hr_attendance_resume_of/i18n/es.po new file mode 100644 index 00000000..1a2a3c1a --- /dev/null +++ b/hr_attendance_resume_of/i18n/es.po @@ -0,0 +1,82 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_attendance_resume_of +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-12-26 15:13+0000\n" +"PO-Revision-Date: 2019-12-26 15:13+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_attendance_resume_of +#: model:ir.model,name:hr_attendance_resume_of.model_hr_employee +msgid "Employee" +msgstr "Empleado" + +#. module: hr_attendance_resume_of +#: model:ir.model,name:hr_attendance_resume_of.model_hr_attendance_resume +msgid "Hours imputations resume" +msgstr "Resumen horas imputaciones" + +#. module: hr_attendance_resume_of +#: model:ir.model.fields,field_description:hr_attendance_resume_of.field_hr_attendance_resume__imputable_time_of +msgid "Imputable time of" +msgstr "Tiempo imputable" + +#. module: hr_attendance_resume_of +#: model:ir.actions.act_window,name:hr_attendance_resume_of.action_hr_attendance_resume_of +#: model:ir.ui.menu,name:hr_attendance_resume_of.hr_attendance_resume_of_group_view +msgid "Imputations resume R" +msgstr "Resumen imputaciones R" + +#. module: hr_attendance_resume_of +#: model:ir.model.fields,field_description:hr_attendance_resume_of.field_hr_attendance_resume__markings_of +msgid "Markings of (E=Entrance, O=Output)" +msgstr "Fichajes (E=Entrada, S=Salida)" + +#. module: hr_attendance_resume_of +#: model:ir.model.fields,field_description:hr_attendance_resume_of.field_hr_attendance_resume__presence_time_of +msgid "Presence time of" +msgstr "Tiempo presencia" + +#. module: hr_attendance_resume_of +#: model:ir.model.fields,field_description:hr_attendance_resume_of.field_hr_attendance_resume__theoretical_time_of +msgid "Theoretical time of" +msgstr "Tiempo teorico" + +#. module: hr_attendance_resume_of +#: model:ir.model,name:hr_attendance_resume_of.model_resource_calendar_attendance +msgid "Work Detail" +msgstr "Detalle del trabajo" + +#. module: hr_attendance_resume_of +#: model:ir.model.fields,field_description:hr_attendance_resume_of.field_hr_attendance_resume__work_time_of +#: model:ir.model.fields,field_description:hr_attendance_resume_of.field_resource_calendar_attendance__work_time_of +msgid "Work time of" +msgstr "Tiempo trabajo" + +#. module: hr_attendance_resume_of +#: code:addons/hr_attendance_resume_of/models/hr_attendance_resume.py:101 +#, python-format +msgid "{}/{}:{}E{}:{}O" +msgstr "{}/{}:{}E{}:{}S" + +#. module: hr_attendance_resume_of +#: code:addons/hr_attendance_resume_of/models/hr_attendance_resume.py:89 +#, python-format +msgid "{}:{}E{}:{}O" +msgstr "{}:{}E{}:{}S" + +#. module: hr_attendance_resume_of +#: code:addons/hr_attendance_resume_of/models/hr_attendance_resume.py:95 +#, python-format +msgid "{}{}:{}E{}:{}O" +msgstr "{}{}:{}E{}:{}S" + diff --git a/hr_attendance_resume_of/i18n/hr_attendance_resume_of.pot b/hr_attendance_resume_of/i18n/hr_attendance_resume_of.pot new file mode 100644 index 00000000..44a8dd58 --- /dev/null +++ b/hr_attendance_resume_of/i18n/hr_attendance_resume_of.pot @@ -0,0 +1,82 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_attendance_resume_of +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-12-26 15:12+0000\n" +"PO-Revision-Date: 2019-12-26 15:12+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_attendance_resume_of +#: model:ir.model,name:hr_attendance_resume_of.model_hr_employee +msgid "Employee" +msgstr "" + +#. module: hr_attendance_resume_of +#: model:ir.model,name:hr_attendance_resume_of.model_hr_attendance_resume +msgid "Hours imputations resume" +msgstr "" + +#. module: hr_attendance_resume_of +#: model:ir.model.fields,field_description:hr_attendance_resume_of.field_hr_attendance_resume__imputable_time_of +msgid "Imputable time of" +msgstr "" + +#. module: hr_attendance_resume_of +#: model:ir.actions.act_window,name:hr_attendance_resume_of.action_hr_attendance_resume_of +#: model:ir.ui.menu,name:hr_attendance_resume_of.hr_attendance_resume_of_group_view +msgid "Imputations resume R" +msgstr "" + +#. module: hr_attendance_resume_of +#: model:ir.model.fields,field_description:hr_attendance_resume_of.field_hr_attendance_resume__markings_of +msgid "Markings of (E=Entrance, O=Output)" +msgstr "" + +#. module: hr_attendance_resume_of +#: model:ir.model.fields,field_description:hr_attendance_resume_of.field_hr_attendance_resume__presence_time_of +msgid "Presence time of" +msgstr "" + +#. module: hr_attendance_resume_of +#: model:ir.model.fields,field_description:hr_attendance_resume_of.field_hr_attendance_resume__theoretical_time_of +msgid "Theoretical time of" +msgstr "" + +#. module: hr_attendance_resume_of +#: model:ir.model,name:hr_attendance_resume_of.model_resource_calendar_attendance +msgid "Work Detail" +msgstr "" + +#. module: hr_attendance_resume_of +#: model:ir.model.fields,field_description:hr_attendance_resume_of.field_hr_attendance_resume__work_time_of +#: model:ir.model.fields,field_description:hr_attendance_resume_of.field_resource_calendar_attendance__work_time_of +msgid "Work time of" +msgstr "" + +#. module: hr_attendance_resume_of +#: code:addons/hr_attendance_resume_of/models/hr_attendance_resume.py:101 +#, python-format +msgid "{}/{}:{}E{}:{}O" +msgstr "" + +#. module: hr_attendance_resume_of +#: code:addons/hr_attendance_resume_of/models/hr_attendance_resume.py:89 +#, python-format +msgid "{}:{}E{}:{}O" +msgstr "" + +#. module: hr_attendance_resume_of +#: code:addons/hr_attendance_resume_of/models/hr_attendance_resume.py:95 +#, python-format +msgid "{}{}:{}E{}:{}O" +msgstr "" + diff --git a/hr_attendance_resume_of/models/__init__.py b/hr_attendance_resume_of/models/__init__.py new file mode 100644 index 00000000..5c01f882 --- /dev/null +++ b/hr_attendance_resume_of/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2019 Alfredo de la Fuente - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +from . import hr_attendance_resume +from . import hr_employee +from . import resource_calendar_attendance diff --git a/hr_attendance_resume_of/models/hr_attendance_resume.py b/hr_attendance_resume_of/models/hr_attendance_resume.py new file mode 100644 index 00000000..93eeb404 --- /dev/null +++ b/hr_attendance_resume_of/models/hr_attendance_resume.py @@ -0,0 +1,109 @@ +# Copyright 2019 Alfredo de la fuente - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +from odoo import models, fields, api, _ +from dateutil.relativedelta import relativedelta +from .._common import _convert_to_local_date + + +class HrAttendanceResume(models.Model): + _inherit = 'hr.attendance.resume' + + presence_time_of = fields.Float( + string='Presence time of', compute='_compute_of_times', store=True) + work_time_of = fields.Float( + string='Work time of', compute='_compute_of_times', store=True) + imputable_time_of = fields.Float( + string='Imputable time of', compute='_compute_of_times', store=True) + theoretical_time_of = fields.Float( + string='Theoretical time of', compute='_compute_of_times', store=True) + markings_of = fields.Char( + string='Markings of (E=Entrance, O=Output)', store=True, + compute='_compute_markings_of') + + @api.depends('presence_time', 'work_time', 'imputable_time', + 'theoretical_time') + def _compute_of_times(self): + for record in self: + emp = record.employee_id + calendar = emp._get_employee_calendar(record.date) + if calendar: + work_time_of, hour_from, hour_to = emp._get_day_work_time_of( + calendar, record.date) + work_time, hour_from, hour_to = emp._get_day_work_time( + calendar, record.date) + dif = work_time - work_time_of + record.presence_time_of = record.presence_time - dif + record.work_time_of = record.work_time - dif + record.imputable_time_of = record.imputable_time - dif + record.theoretical_time_of = record.theoretical_time - dif + + @api.depends('markings', 'hr_attendance_ids') + def _compute_markings_of(self): + for record in self: + record.markings_of = record._calculate_markings_of() + + def _calculate_markings_of(self): + employee = self.employee_id + calendar = employee._get_employee_calendar(self.date) + if not calendar: + return self.markings + work_time_of, hour_from, hour_to = employee._get_day_work_time_of( + calendar, self.date) + if work_time_of == 0.0: + return self.markings + work_time, hour_from, hour_to = employee._get_day_work_time( + calendar, self.date) + if work_time_of == work_time: + return self.markings + dif = work_time - work_time_of + hours = {} + dates = sorted(set(self.hr_attendance_ids.mapped('check_in'))) + count = 0 + for my_date in dates: + imputation = self.hr_attendance_ids.filtered( + lambda x: x.check_in == my_date) + count += 1 + key = str(count) + if key not in hours: + check_in = imputation.check_in + if count == 1: + check_in += relativedelta(hours=float(dif / 2)) + check_out = imputation.check_out + if count == len(dates): + check_out -= relativedelta(hours=float(dif / 2)) + vals = {'check_in': check_in, + 'check_out': check_out} + hours[key] = vals + markings = '' + count = 0 + for key in hours.keys(): + check_in = ( + _convert_to_local_date( + hours.get(key).get('check_in'), calendar.tz)) + check_out = ( + _convert_to_local_date( + hours.get(key).get('check_out'), calendar.tz)) + count += 1 + if count == 1: + if not markings: + markings = _(u'{}:{}E{}:{}O').format( + str(check_in.hour).zfill(2), + str(check_in.minute).zfill(2), + str(check_out.hour).zfill(2), + str(check_out.minute).zfill(2)) + else: + markings = _(u'{}{}:{}E{}:{}O').format( + markings, str(check_in.hour).zfill(2), + str(check_in.minute).zfill(2), + str(check_out.hour).zfill(2), + str(check_out.minute).zfill(2)) + else: + markings = _(u'{}/{}:{}E{}:{}O').format( + markings, str(check_in.hour).zfill(2), + str(check_in.minute).zfill(2), + str(check_out.hour).zfill(2), + str(check_out.minute).zfill(2)) + if count == 2: + markings += '\n' + count = 0 + return markings diff --git a/hr_attendance_resume_of/models/hr_employee.py b/hr_attendance_resume_of/models/hr_employee.py new file mode 100644 index 00000000..ebd065c9 --- /dev/null +++ b/hr_attendance_resume_of/models/hr_employee.py @@ -0,0 +1,32 @@ +# Copyright 2019 Alfredo de la fuente - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +from odoo import models +from dateutil.relativedelta import relativedelta + + +class HrEmployee(models.Model): + _inherit = 'hr.employee' + + def _get_day_work_time_of(self, calendar, date): + days = calendar.mapped('attendance_ids').filtered( + lambda x: x.dayofweek == str(date.weekday())) + if not days: + return 0.0, 0.0, 0.0 + if len(days) == 1: + return days.work_time_of, days.real_hour_from, days.real_hour_to + if not any(p.hour_to == 23.9833333333333 for p in days): + min_hour = min(days, key=lambda x: x.real_hour_from) + max_hour = max(days, key=lambda x: x.real_hour_to) + hours = sum(days.mapped('work_time_of')) + return hours, min_hour.real_hour_from, max_hour.real_hour_to + day = days.filtered(lambda x: x.real_hour_to == 23.9833333333333) + work_time = day.work_time_of + date += relativedelta(days=1) + days2 = calendar.mapped('attendance_ids').filtered( + lambda x: x.dayofweek == str(date.weekday())) + hour_to = 0.0 + if days2: + day2 = min(days2, key=lambda x: x.real_hour_from) + hour_to = day2.real_hour_to + work_time += day2.work_time_of + return work_time, day.real_hour_from, hour_to diff --git a/hr_attendance_resume_of/models/resource_calendar_attendance.py b/hr_attendance_resume_of/models/resource_calendar_attendance.py new file mode 100644 index 00000000..71325854 --- /dev/null +++ b/hr_attendance_resume_of/models/resource_calendar_attendance.py @@ -0,0 +1,18 @@ +# Copyright 2019 Alfredo de la fuente - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +from odoo import models, fields, api + + +class ResourceCalendarAttendance(models.Model): + _inherit = 'resource.calendar.attendance' + + work_time_of = fields.Float( + string='Work time of', compute='_compute_work_time_of', store=True) + + @api.depends('real_hour_from', 'real_hour_to') + def _compute_work_time_of(self): + for record in self: + hours = record.real_hour_to - record.real_hour_from + if record.real_hour_to == 23.9833333333333: + hours += 0.0166666666666667 + record.work_time_of = hours diff --git a/hr_attendance_resume_of/views/hr_attendance_resume_view.xml b/hr_attendance_resume_of/views/hr_attendance_resume_view.xml new file mode 100644 index 00000000..2a75b830 --- /dev/null +++ b/hr_attendance_resume_of/views/hr_attendance_resume_view.xml @@ -0,0 +1,85 @@ + + + + hr.attendance.resume + + + + + + + + + + + + + + + + + + + + + + + hr.attendance.resume + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + Imputations resume R + hr.attendance.resume + form + form,tree + + + + + tree + + + + + + + form + + + + +