diff --git a/hr_attendance_resume/README.rst b/hr_attendance_resume/README.rst new file mode 100644 index 00000000..78be10d8 --- /dev/null +++ b/hr_attendance_resume/README.rst @@ -0,0 +1,30 @@ +.. 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 +==================== + +* New object "Hours imputations resume". The new menu option for this object is + found in Attendances - Manage attendances - Imputations resume. To see this + new menu option, the user must be in the group "Attendance-Manager". +* In attendances new wizard for impute then in assistances resume. + +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/__init__.py b/hr_attendance_resume/__init__.py new file mode 100644 index 00000000..b6237f60 --- /dev/null +++ b/hr_attendance_resume/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2019 Alfredo de la Fuente - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +from . import models +from . import wizard diff --git a/hr_attendance_resume/__manifest__.py b/hr_attendance_resume/__manifest__.py new file mode 100644 index 00000000..4edb5180 --- /dev/null +++ b/hr_attendance_resume/__manifest__.py @@ -0,0 +1,26 @@ +# Copyright 2019 Alfredo de la Fuente - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +{ + "name": "Hr Attendance Resume", + "version": "12.0.1.0.0", + "license": "AGPL-3", + "depends": [ + "hr_attendance", + "resource_time", + "resource_rest_time", + "resource_bonus", + "hr_employee_calendar_planning" + ], + "author": "AvanzOSC", + "website": "http://www.avanzosc.es", + "category": "Human Resources", + "data": [ + "security/ir.model.access.csv", + "views/hr_attendance_view.xml", + "views/hr_attendance_resume_view.xml", + "views/hr_employee_view.xml", + "wizard/wiz_hr_attendance_resume_view.xml", + "wizard/wiz_hr_attendance_uncheck_treaties_view.xml", + ], + "installable": True, +} diff --git a/hr_attendance_resume/_common.py b/hr_attendance_resume/_common.py new file mode 100644 index 00000000..3d4b7a87 --- /dev/null +++ b/hr_attendance_resume/_common.py @@ -0,0 +1,64 @@ +# 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_to_utc_date(date, time=0.0, tz=u'UTC'): + if not date: + return False + if not tz: + tz = u'UTC' + date = date2str(date) if isinstance(date, datetype) else date + date = str2datetime(date) if isinstance(date, str) else date + date += relativedelta(hours=float(time)) + local = timezone(tz) + local_date = local.localize(date, is_dst=None) + utc_date = local_date.astimezone(utc).replace(tzinfo=None) + return utc_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) + + +def _catch_dayofweek(date): + day = str(date.weekday()) + if day == '0': + return _('Monday') + if day == '1': + return _('Tuesday') + if day == '2': + return _('Wednesday') + if day == '3': + return _('Thursday') + if day == '4': + return _('Friday') + if day == '5': + return _('Saturday') + if day == '6': + return _('Sunday') diff --git a/hr_attendance_resume/i18n/es.po b/hr_attendance_resume/i18n/es.po new file mode 100644 index 00000000..c138eb2c --- /dev/null +++ b/hr_attendance_resume/i18n/es.po @@ -0,0 +1,351 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_attendance_resume +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-11-18 08:52+0000\n" +"PO-Revision-Date: 2019-11-18 08:52+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 +#: model:ir.model,name:hr_attendance_resume.model_hr_attendance +msgid "Attendance" +msgstr "Asistencia" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__hr_attendance_ids +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.hr_attendance_resume_view_form +msgid "Attendances" +msgstr "Asistencias" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_employee__count_attendances_resumes +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.view_employee_form_inherit_hr_attendance +msgid "Attendances resume" +msgstr "Resumen asistencias" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__bonus_hours +msgid "Bonus hours" +msgstr "Horas bonificadas" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_resume_view_form +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_uncheck_treaties_view_form +msgid "Cancel" +msgstr "Cancelar" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance__check_in_without_hour +msgid "Check in without hour" +msgstr "Entrada sin salida" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__create_uid +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_resume__create_uid +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_uncheck_treaties__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__create_date +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_resume__create_date +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_uncheck_treaties__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__date +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.hr_attendance_resume_view_search +msgid "Date" +msgstr "Fecha" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__day_week +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__day_week_literal +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.hr_attendance_resume_view_search +msgid "Day week" +msgstr "Día semana" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__difference_hours +msgid "Difference hours" +msgstr "Diferencia horas" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__difference_minutes +msgid "Difference minutes" +msgstr "Diferencia minutos" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__display_name +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_resume__display_name +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_uncheck_treaties__display_name +msgid "Display Name" +msgstr "Nombre mostrado" + +#. module: hr_attendance_resume +#: model:ir.model,name:hr_attendance_resume.model_hr_employee +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__employee_id +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.hr_attendance_resume_view_search +msgid "Employee" +msgstr "Empleado" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/_common.py:60 +#, python-format +msgid "Friday" +msgstr "Viernes" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.hr_attendance_resume_view_search +msgid "Group By" +msgstr "Agrupar por" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance__hour_gap +msgid "Hour gap" +msgstr "Margen hora" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance__attendance_resume_id +msgid "Hours imputations resume" +msgstr "Resumen imputaciones horas" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__id +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_resume__id +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_uncheck_treaties__id +msgid "ID" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__imputable_time +msgid "Imputable time" +msgstr "Tiempo imputable" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance__imputation_date +msgid "Imputation date" +msgstr "Fecha imputación" + +#. module: hr_attendance_resume +#: model:ir.actions.act_window,name:hr_attendance_resume.action_hr_attendance_resume +#: model:ir.ui.menu,name:hr_attendance_resume.hr_attendance_resume_group_view +msgid "Imputations resume" +msgstr "Resumen imputaciones" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_employee__attendance_resume_ids +msgid "Imputations resumes" +msgstr "Resumenes imputaciones" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_resume_view_form +msgid "Impute" +msgstr "Imputar" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_resume_view_form +msgid "Impute assistances in resume" +msgstr "Imputar asistencias en resumen" + +#. module: hr_attendance_resume +#: model:ir.actions.act_window,name:hr_attendance_resume.action_wiz_hr_attendance_anomaly +msgid "Impute in resume" +msgstr "Imputar en resumen" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume____last_update +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_resume____last_update +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_uncheck_treaties____last_update +msgid "Last Modified on" +msgstr "Última modificación en" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__write_uid +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_resume__write_uid +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_uncheck_treaties__write_uid +msgid "Last Updated by" +msgstr "Última actualización por" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__write_date +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_resume__write_date +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_uncheck_treaties__write_date +msgid "Last Updated on" +msgstr "Última actualización el" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__markings +msgid "Markings (E=Entrance, O=Output)" +msgstr "Fichajes (E=Entrada, S=Salida)" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/_common.py:52 +#, python-format +msgid "Monday" +msgstr "Lunes" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.hr_attendance_view_filter +msgid "No treated" +msgstr "No tratado" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance__notes +msgid "Notes" +msgstr "Notas" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__planned_rest +msgid "Planned rest" +msgstr "Descanso planificado" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__presence_time +msgid "Presence time" +msgstr "Tiempo presencia" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__rest_exceeded +msgid "Rest exceeded" +msgstr "Descanso excedido" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__rest_number +msgid "Rest number" +msgstr "Núm. Descansos" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance__rest_time +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__rest_time +msgid "Rest time" +msgstr "Tiempo descanso" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/_common.py:62 +#, python-format +msgid "Saturday" +msgstr "Sábado" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/_common.py:64 +#, python-format +msgid "Sunday" +msgstr "Domingo" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__theoretical_time +msgid "Theoretical time" +msgstr "Tiempo teorico" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/_common.py:58 +#, python-format +msgid "Thursday" +msgstr "Jueves" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance__treated +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.hr_attendance_view_filter +msgid "Treated" +msgstr "Tratado" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/_common.py:54 +#, python-format +msgid "Tuesday" +msgstr "Martes" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_uncheck_treaties_view_form +msgid "Uncheck" +msgstr "Desmarcar" + +#. module: hr_attendance_resume +#: model:ir.actions.act_window,name:hr_attendance_resume.action_wiz_hr_attendance_uncheck_treaties +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_uncheck_treaties_view_form +msgid "Uncheck treaties" +msgstr "Desmarcar tratados" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/_common.py:56 +#, python-format +msgid "Wednesday" +msgstr "Miércoles" + +#. module: hr_attendance_resume +#: model:ir.model,name:hr_attendance_resume.model_wiz_hr_attendance_uncheck_treaties +msgid "Wizard for uncheck attendances treaties" +msgstr "Asistente para desmarcar asistencias tratadas" + +#. module: hr_attendance_resume +#: model:ir.model,name:hr_attendance_resume.model_wiz_hr_attendance_resume +msgid "Wizard to impute assistances resume" +msgstr "Asistente para imputar en resumen de asistencias" + +#. module: hr_attendance_resume +#: model:ir.model,name:hr_attendance_resume.model_resource_calendar_attendance +msgid "Work Detail" +msgstr "Detalle del trabajo" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__work_time +#: model:ir.model.fields,field_description:hr_attendance_resume.field_resource_calendar_attendance__work_time +msgid "Work time" +msgstr "Tiempo trabajo" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_resume_view_form +msgid "You are going to impute in assistances resume" +msgstr "Usted va a imputar en resumen de asistencias" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_uncheck_treaties_view_form +msgid "You are going to uncheck treaties" +msgstr "Usted va a desmarcar los tratados" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/models/hr_attendance.py:95 +#, python-format +msgid "You cannot delete the hours imputations resume with date {}, of the employee {}, because he has assigned an allocation" +msgstr "No puede borrar resumen de imputaciones con fecha {}, del empleado {}, porque tiene asignado/a una asignación de ausencia." + +#. module: hr_attendance_resume +#: model:ir.model,name:hr_attendance_resume.model_hr_attendance_resume +msgid "hr.attendance.resume" +msgstr "" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/models/hr_attendance.py:213 +#, python-format +msgid "{} (Bonus {}%)" +msgstr "{} (Bonificado {}%)" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/models/hr_attendance.py:241 +#, python-format +msgid "{}/{}:{}E{}:{}O" +msgstr "{}/{}:{}E{}:{}S" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/models/hr_attendance.py:229 +#, python-format +msgid "{}:{}E{}:{}O" +msgstr "{}:{}E{}:{}S" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/models/hr_attendance.py:235 +#, python-format +msgid "{}{}:{}E{}:{}O" +msgstr "{}{}:{}E{}:{}S" + diff --git a/hr_attendance_resume/i18n/hr_attendance_resume.pot b/hr_attendance_resume/i18n/hr_attendance_resume.pot new file mode 100644 index 00000000..a0f20db3 --- /dev/null +++ b/hr_attendance_resume/i18n/hr_attendance_resume.pot @@ -0,0 +1,351 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_attendance_resume +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-11-18 08:51+0000\n" +"PO-Revision-Date: 2019-11-18 08:51+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 +#: model:ir.model,name:hr_attendance_resume.model_hr_attendance +msgid "Attendance" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__hr_attendance_ids +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.hr_attendance_resume_view_form +msgid "Attendances" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_employee__count_attendances_resumes +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.view_employee_form_inherit_hr_attendance +msgid "Attendances resume" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__bonus_hours +msgid "Bonus hours" +msgstr "" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_resume_view_form +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_uncheck_treaties_view_form +msgid "Cancel" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance__check_in_without_hour +msgid "Check in without hour" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__create_uid +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_resume__create_uid +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_uncheck_treaties__create_uid +msgid "Created by" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__create_date +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_resume__create_date +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_uncheck_treaties__create_date +msgid "Created on" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__date +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.hr_attendance_resume_view_search +msgid "Date" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__day_week +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__day_week_literal +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.hr_attendance_resume_view_search +msgid "Day week" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__difference_hours +msgid "Difference hours" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__difference_minutes +msgid "Difference minutes" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__display_name +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_resume__display_name +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_uncheck_treaties__display_name +msgid "Display Name" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model,name:hr_attendance_resume.model_hr_employee +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__employee_id +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.hr_attendance_resume_view_search +msgid "Employee" +msgstr "" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/_common.py:60 +#, python-format +msgid "Friday" +msgstr "" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.hr_attendance_resume_view_search +msgid "Group By" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance__hour_gap +msgid "Hour gap" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance__attendance_resume_id +msgid "Hours imputations resume" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__id +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_resume__id +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_uncheck_treaties__id +msgid "ID" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__imputable_time +msgid "Imputable time" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance__imputation_date +msgid "Imputation date" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.actions.act_window,name:hr_attendance_resume.action_hr_attendance_resume +#: model:ir.ui.menu,name:hr_attendance_resume.hr_attendance_resume_group_view +msgid "Imputations resume" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_employee__attendance_resume_ids +msgid "Imputations resumes" +msgstr "" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_resume_view_form +msgid "Impute" +msgstr "" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_resume_view_form +msgid "Impute assistances in resume" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.actions.act_window,name:hr_attendance_resume.action_wiz_hr_attendance_anomaly +msgid "Impute in resume" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume____last_update +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_resume____last_update +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_uncheck_treaties____last_update +msgid "Last Modified on" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__write_uid +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_resume__write_uid +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_uncheck_treaties__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__write_date +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_resume__write_date +#: model:ir.model.fields,field_description:hr_attendance_resume.field_wiz_hr_attendance_uncheck_treaties__write_date +msgid "Last Updated on" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__markings +msgid "Markings (E=Entrance, O=Output)" +msgstr "" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/_common.py:52 +#, python-format +msgid "Monday" +msgstr "" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.hr_attendance_view_filter +msgid "No treated" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance__notes +msgid "Notes" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__planned_rest +msgid "Planned rest" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__presence_time +msgid "Presence time" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__rest_exceeded +msgid "Rest exceeded" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__rest_number +msgid "Rest number" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance__rest_time +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__rest_time +msgid "Rest time" +msgstr "" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/_common.py:62 +#, python-format +msgid "Saturday" +msgstr "" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/_common.py:64 +#, python-format +msgid "Sunday" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__theoretical_time +msgid "Theoretical time" +msgstr "" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/_common.py:58 +#, python-format +msgid "Thursday" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance__treated +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.hr_attendance_view_filter +msgid "Treated" +msgstr "" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/_common.py:54 +#, python-format +msgid "Tuesday" +msgstr "" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_uncheck_treaties_view_form +msgid "Uncheck" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.actions.act_window,name:hr_attendance_resume.action_wiz_hr_attendance_uncheck_treaties +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_uncheck_treaties_view_form +msgid "Uncheck treaties" +msgstr "" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/_common.py:56 +#, python-format +msgid "Wednesday" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model,name:hr_attendance_resume.model_wiz_hr_attendance_uncheck_treaties +msgid "Wizard for uncheck attendances treaties" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model,name:hr_attendance_resume.model_wiz_hr_attendance_resume +msgid "Wizard to impute assistances resume" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model,name:hr_attendance_resume.model_resource_calendar_attendance +msgid "Work Detail" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model.fields,field_description:hr_attendance_resume.field_hr_attendance_resume__work_time +#: model:ir.model.fields,field_description:hr_attendance_resume.field_resource_calendar_attendance__work_time +msgid "Work time" +msgstr "" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_resume_view_form +msgid "You are going to impute in assistances resume" +msgstr "" + +#. module: hr_attendance_resume +#: model_terms:ir.ui.view,arch_db:hr_attendance_resume.wiz_hr_attendance_uncheck_treaties_view_form +msgid "You are going to uncheck treaties" +msgstr "" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/models/hr_attendance.py:95 +#, python-format +msgid "You cannot delete the hours imputations resume with date {}, of the employee {}, because he has assigned an allocation" +msgstr "" + +#. module: hr_attendance_resume +#: model:ir.model,name:hr_attendance_resume.model_hr_attendance_resume +msgid "hr.attendance.resume" +msgstr "" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/models/hr_attendance.py:213 +#, python-format +msgid "{} (Bonus {}%)" +msgstr "" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/models/hr_attendance.py:241 +#, python-format +msgid "{}/{}:{}E{}:{}O" +msgstr "" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/models/hr_attendance.py:229 +#, python-format +msgid "{}:{}E{}:{}O" +msgstr "" + +#. module: hr_attendance_resume +#: code:addons/hr_attendance_resume/models/hr_attendance.py:235 +#, python-format +msgid "{}{}:{}E{}:{}O" +msgstr "" + diff --git a/hr_attendance_resume/models/__init__.py b/hr_attendance_resume/models/__init__.py new file mode 100644 index 00000000..ed4ed6ac --- /dev/null +++ b/hr_attendance_resume/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 resource_calendar_attendance +from . import hr_attendance +from . import hr_employee diff --git a/hr_attendance_resume/models/hr_attendance.py b/hr_attendance_resume/models/hr_attendance.py new file mode 100644 index 00000000..e978575c --- /dev/null +++ b/hr_attendance_resume/models/hr_attendance.py @@ -0,0 +1,356 @@ +# 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, exceptions, _ +from dateutil.relativedelta import relativedelta +from .._common import _convert_to_local_date, _convert_to_utc_date +from .._common import _catch_dayofweek + + +class HrAttendance(models.Model): + _inherit = 'hr.attendance' + + treated = fields.Boolean(string='Treated', default=False) + imputation_date = fields.Date( + string='Imputation date', compute='_compute_imputation_date_hour', + store=True) + rest_time = fields.Float( + string='Rest time', compute='_compute_imputation_date_hour', + store=True) + hour_gap = fields.Float( + string='Hour gap', compute='_compute_imputation_date_hour', + store=True) + notes = fields.Text(string='Notes') + attendance_resume_id = fields.Many2one( + string='Hours imputations resume', + comodel_name='hr.attendance.resume') + check_in_without_hour = fields.Date( + string='Check in without hour', store=True, + compute='_compute_check_in_without_hour') + + @api.depends('check_in') + def _compute_check_in_without_hour(self): + for record in self.filtered( + lambda c: c.employee_id.resource_calendar_id and c.check_in): + date = _convert_to_local_date( + record.check_in, record.employee_id.resource_calendar_id.tz) + record.check_in_without_hour = date.date() + + @api.depends( + 'check_in', 'check_out', 'employee_id', + 'employee_id.resource_calendar_id', + 'employee_id.resource_calendar_id.attendance_ids', + 'employee_id.resource_calendar_id.attendance_ids.delay_hour_from', + 'employee_id.resource_calendar_id.attendance_ids.delay_hour_to', + 'employee_id.resource_calendar_id.attendance_ids.rest_time', + 'employee_id.resource_calendar_id.attendance_ids.night_shift', + 'employee_id.calendar_ids', 'employee_id.calendar_ids.date_start', + 'employee_id.calendar_ids.date_end', + 'employee_id.calendar_ids.calendar_id', + 'employee_id.resource_calendar_id.tz') + def _compute_imputation_date_hour(self): + for record in self.filtered( + lambda c: c.employee_id.resource_calendar_id and c.check_out): + date = _convert_to_local_date( + record.check_in, record.employee_id.resource_calendar_id.tz) + calendar = record.employee_id._get_employee_calendar( + date=date.date()) + days = calendar.mapped('attendance_ids').filtered( + lambda x: x.dayofweek == str(date.date().weekday())) + imputation_date = date.date() + if not days: + imputation_date = (date.date() + relativedelta(days=-1)) + calendar2 = record.employee_id._get_employee_calendar( + date=imputation_date) + days = calendar2.mapped('attendance_ids').filtered( + lambda x: x.dayofweek == str(imputation_date.weekday())) + for day in days: + fec_des = _convert_to_utc_date( + imputation_date, time=day.delay_hour_from, tz=u'UTC') + hours = day.delay_hour_to + my_date = fec_des.date() + if hours > 24.0: + hours -= 24 + my_date = (fec_des.date() + relativedelta(days=+1)) + fec_has = _convert_to_utc_date( + my_date, time=hours, tz=u'UTC') + if date >= fec_des and date <= fec_has: + record.imputation_date = imputation_date + if (date >= fec_des and date <= fec_has and not + day.night_shift): + record.rest_time = sum(days.mapped('rest_time')) + record.hour_gap = sum(days.mapped('work_time')) + break + if date >= fec_des and date <= fec_has and day.night_shift: + calendar2 = False + days2 = False + if day.hour_from == 0.0: + record.imputation_date = ( + imputation_date + relativedelta(days=-1)) + if day.hour_from == 0.0 and day.rest_time == 0.0: + date2 = imputation_date + relativedelta(days=-1) + calendar2 = record.employee_id._get_employee_calendar( + date=date2) + if (day.hour_from == 0.0 and day.rest_time == 0.0 and + calendar2): + days2 = calendar2.mapped('attendance_ids').filtered( + lambda x: x.hour_to == 23.9833333333333 and + x.dayofweek == str(date2.weekday())) + if (day.hour_from == 0.0 and day.rest_time == 0.0 and + calendar2 and days2): + record.rest_time = ( + day.rest_time if day.rest_time else + days2.rest_time) + record.hour_gap = day.work_time + days2.work_time + if day.hour_to == 23.9833333333333: + date2 = imputation_date + relativedelta(days=+1) + calendar2 = record.employee_id._get_employee_calendar( + date=date2) + if day.hour_to == 23.9833333333333 and calendar2: + days2 = calendar2.mapped('attendance_ids').filtered( + lambda x: x.hour_from == 0 and + x.dayofweek == str(date2.weekday())) + if (day.hour_to == 23.9833333333333 and calendar2 and + days2): + record.rest_time = ( + day.rest_time if day.rest_time else + days2.rest_time) + record.hour_gap = day.work_time + days2.work_time + break + + @api.multi + def unlink(self): + for attendance in self: + date = attendance.imputation_date + resume = self._search_employee_attendance_resume( + attendance.employee_id, date) + if resume and resume.hr_leave_allocation_id: + error = _(u'You cannot delete the hours imputations resume ' + 'with date {}, of the employee {}, because he has ' + 'assigned an allocation').format( + resume.date, resume.employee_id.name) + raise exceptions.Warning(error) + return super(HrAttendance, self).unlink() + + @api.multi + def write(self, vals): + if 'treated' in vals and not vals.get('treated', False): + for attendance in self: + date = attendance.imputation_date + resume = self._search_employee_attendance_resume( + attendance.employee_id, date) + if resume: + resume.unlink() + return super(HrAttendance, self).write(vals) + + def _impute_in_attendance_resume(self): + cond = [('id', 'in', self.mapped('employee_id').ids), + ('resource_calendar_id', '!=', False)] + employees = self.env['hr.employee'].search(cond) + for employee in employees: + emp_attendances = self.filtered( + lambda c: c.employee_id.id == employee.id and + c.check_out and not c.treated) + emp_attendances._impute_employee_attendances() + + def _impute_employee_attendances(self): + self._delete_employee_attendance_resumes() + imputations = self.filtered(lambda c: c.imputation_date) + dates = set(imputations.mapped('imputation_date')) + for date in dates: + if date: + attendances = self.filtered( + lambda c: c.imputation_date == date) + attendances._impute_employee_attendances_day() + + def _delete_employee_attendance_resumes(self): + resume_obj = self.env['hr.attendance.resume'] + min_fec, max_fec = self._catch_employee_min_max_dates() + cond = [('employee_id', '=', self[0].employee_id.id), + ('date', '>=', min_fec), + ('date', '<=', max_fec)] + resumes = resume_obj.search(cond) + if resumes: + resumes.unlink() + + def _catch_employee_min_max_dates(self): + with_calendar = self.filtered(lambda c: c.imputation_date) + min_fec = False + max_fec = False + if with_calendar: + min_fec = min(with_calendar, key=lambda x: x.imputation_date) + min_fec = min_fec.imputation_date + max_fec = max(with_calendar, key=lambda x: x.imputation_date) + max_fec = max_fec.imputation_date + without_calendar = self.filtered(lambda c: not c.imputation_date) + if without_calendar: + max_fec2 = max( + without_calendar, key=lambda x: x.check_in_without_hour) + if not max_fec or max_fec2.check_in_without_hour > max_fec: + max_fec = max_fec2.check_in_without_hour + min_fec2 = min( + without_calendar, key=lambda x: x.check_in_without_hour) + if not min_fec or min_fec2.check_in_without_hour < min_fec: + min_fec = min_fec2.check_in_without_hour + return min_fec, max_fec + + def _impute_employee_attendances_day(self): + resume_obj = self.env['hr.attendance.resume'] + resume = resume_obj.create(self._catch_values_for_create_resume()) + self.update({'treated': True, + 'attendance_resume_id': resume.id}) + return resume + + def _search_employee_attendance_resume(self, employee, date): + cond = [('employee_id', '=', employee.id), + ('date', '=', date)] + return self.env['hr.attendance.resume'].search(cond, limit=1) + + def _catch_values_for_create_resume(self): + min_fec = min(self, key=lambda x: x.check_in) + max_fec = max(self, key=lambda x: x.check_in) + date = (min_fec.imputation_date if min_fec.imputation_date else + min_fec.check_in_without_hour) + check_in = _convert_to_local_date( + min_fec.check_in, + min_fec.employee_id.resource_calendar_id.tz) + check_out = _convert_to_local_date( + max_fec.check_out, + max_fec.employee_id.resource_calendar_id.tz) + fout = fields.Datetime.from_string('{} {}:{}:00'.format( + check_out.date(), check_out.hour, check_out.minute)) + fini = fields.Datetime.from_string('{} {}:{}:00'.format( + check_in.date(), check_in.hour, check_in.minute)) + delta = fout - fini + presence_time = delta.total_seconds() / 3600.0 + work_time = sum(self.mapped('worked_hours')) + theoretical_time = min_fec.hour_gap + calendar = min_fec.employee_id._get_employee_calendar( + date=min_fec.check_in.date()) + bonus_hours = 0.0 + bonus_day = calendar.mapped('bonus_ids').filtered( + lambda x: x.dayofweek == str(date.weekday())) + if bonus_day: + bonus_hours = (work_time * bonus_day.bonus_percentage) / 100 + rest_number = int(len(self)) + if rest_number >= 1: + rest_number -= 1 + vals = { + 'employee_id': min_fec.employee_id.id, + 'date': date, + 'planned_rest': min_fec.rest_time, + 'presence_time': presence_time, + 'work_time': work_time, + 'bonus_hours': bonus_hours, + 'theoretical_time': theoretical_time, + 'rest_number': rest_number} + date_to = ( + _convert_to_local_date(max_fec.check_out, calendar.tz)).date() + date_dayofweek = _catch_dayofweek(date) + date_to_dayofweek = _catch_dayofweek(date_to) + day_week_literal = date_dayofweek + if date_dayofweek != date_to_dayofweek: + day_week_literal = u"{}-{}".format( + day_week_literal, date_to_dayofweek) + if bonus_day: + day_week_literal = _(u'{} (Bonus {}%)').format( + day_week_literal, bonus_day.bonus_percentage) + vals['day_week_literal'] = day_week_literal + markings = '' + dates = sorted(set(self.mapped('check_in'))) + count = 0 + for date in dates: + imputation = self.filtered( + lambda x: x.check_in == date) + check_in = ( + _convert_to_local_date(imputation.check_in, calendar.tz)) + check_out = ( + _convert_to_local_date(imputation.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 + vals['markings'] = markings + return vals + + +class HrAttendanceResume(models.Model): + _name = 'hr.attendance.resume' + _description = "Hours imputations resume" + + employee_id = fields.Many2one( + string='Employee', comodel_name='hr.employee') + date = fields.Date(string='Date') + day_week = fields.Char( + string='Day week', compute='_compute_day_week', store=True) + day_week_literal = fields.Char(string='Day week') + markings = fields.Char( + string='Markings (E=Entrance, O=Output)') + planned_rest = fields.Float(string='Planned rest', default=0.0) + presence_time = fields.Float(string='Presence time', default=0.0) + rest_number = fields.Integer( + string='Rest number', default=0) + rest_time = fields.Float( + string='Rest time', compute='_compute_rest_exceeded_time', store=True) + rest_exceeded = fields.Float( + string='Rest exceeded', store=True, + compute='_compute_rest_exceeded_time') + work_time = fields.Float(string='Work time', default=0.0) + bonus_hours = fields.Float(string='Bonus hours', default=0.0) + imputable_time = fields.Float( + string='Imputable time', compute='_compute_imputable_diference', + store=True) + theoretical_time = fields.Float(string='Theoretical time', default=0.0) + difference_hours = fields.Float( + string='Difference hours', store=True, + compute='_compute_imputable_diference') + difference_minutes = fields.Integer( + string='Difference minutes', store=True, + compute='_compute_imputable_diference') + hr_attendance_ids = fields.One2many( + comodel_name='hr.attendance', inverse_name='attendance_resume_id', + string='Attendances') + + @api.depends('date') + def _compute_day_week(self): + for record in self.filtered(lambda c: c.date): + record.day_week = _catch_dayofweek(record.date) + + @api.depends('presence_time', 'work_time', 'planned_rest') + def _compute_rest_exceeded_time(self): + for record in self.filtered(lambda c: c.presence_time and c.work_time): + record.rest_time = record.presence_time - record.work_time + if ((record.rest_time - record.planned_rest) <= 0): + record.rest_exceeded = 0 + else: + record.rest_exceeded = record.rest_time - record.planned_rest + + @api.depends('theoretical_time', 'presence_time', 'bonus_hours', + 'rest_exceeded', 'planned_rest') + def _compute_imputable_diference(self): + for record in self.filtered(lambda c: c.theoretical_time): + record.imputable_time = ( + record.presence_time + record.bonus_hours - + record.rest_exceeded) + difference_hours = record.imputable_time - record.theoretical_time + if difference_hours != 0: + record.difference_hours = difference_hours + record.difference_minutes = round(difference_hours * 60) diff --git a/hr_attendance_resume/models/hr_employee.py b/hr_attendance_resume/models/hr_employee.py new file mode 100644 index 00000000..114a3dd4 --- /dev/null +++ b/hr_attendance_resume/models/hr_employee.py @@ -0,0 +1,57 @@ +# 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 odoo.models import expression +from odoo.tools.safe_eval import safe_eval + + +class HrEmployee(models.Model): + _inherit = 'hr.employee' + + attendance_resume_ids = fields.One2many( + comodel_name='hr.attendance.resume', + inverse_name='employee_id', string='Imputations resumes') + count_attendances_resumes = fields.Integer( + string='Attendances resume', store=True, + compute='_compute_count_attendances_resumes') + + @api.multi + @api.depends('attendance_resume_ids') + def _compute_count_attendances_resumes(self): + for employee in self: + employee.count_attendances_resumes = ( + len(employee.attendance_resume_ids)) + + def _get_employee_calendar(self, date): + calendar = self.resource_calendar_id + if self.calendar_ids: + esp_calendar = self.calendar_ids.filtered( + lambda c: (not c.date_start or + (c.date_start and c.date_start <= date)) and + (not c.date_end or (c.date_end and c.date_end >= date))) + if esp_calendar and len(esp_calendar) == 1: + calendar = esp_calendar.calendar_id + return calendar + + def _regenerate_calendar(self): + self.ensure_one() + return True + + @api.multi + def button_show_attendance_resumes(self): + self.ensure_one() + self = self.with_context( + search_default_employee_id=self.id, default_employee_id=self.id) + action = self.env.ref( + 'hr_attendance_resume.action_hr_attendance_resume') + action_dict = action.read()[0] if action else {} + action_dict['context'] = safe_eval( + action_dict.get('context', '{}')) + action_dict['context'].update( + {'search_default_employee_id': self.id, + 'default_employee_id': self.id}) + domain = expression.AND([ + [('employee_id', '=', self.id)], + safe_eval(action.domain or '[]')]) + action_dict.update({'domain': domain}) + return action_dict diff --git a/hr_attendance_resume/models/resource_calendar_attendance.py b/hr_attendance_resume/models/resource_calendar_attendance.py new file mode 100644 index 00000000..ab5ae316 --- /dev/null +++ b/hr_attendance_resume/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' + + @api.depends('hour_from', 'hour_to') + def _compute_work_time(self): + for record in self: + hours = record.hour_to - record.hour_from + if record.hour_to == 23.9833333333333: + hours += 0.0166666666666667 + record.work_time = hours + + work_time = fields.Float( + string='Work time', compute='_compute_work_time', store=True) diff --git a/hr_attendance_resume/security/ir.model.access.csv b/hr_attendance_resume/security/ir.model.access.csv new file mode 100644 index 00000000..74fbcd7c --- /dev/null +++ b/hr_attendance_resume/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_hr_attendance_resume_manager,hr.attendance.resume,model_hr_attendance_resume,hr_attendance.group_hr_attendance_manager,1,1,1,1 +access_hr_attendance_resume_user,hr.attendance.resume,model_hr_attendance_resume,hr_attendance.group_hr_attendance_user,1,,, diff --git a/hr_attendance_resume/views/hr_attendance_resume_view.xml b/hr_attendance_resume/views/hr_attendance_resume_view.xml new file mode 100644 index 00000000..f0f3d45b --- /dev/null +++ b/hr_attendance_resume/views/hr_attendance_resume_view.xml @@ -0,0 +1,91 @@ + + + + hr.attendance.resume + + + + + + + + + + + + + + + + + + + + + + hr.attendance.resume + + + + + + + + + + + + + + + hr.attendance.resume + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + Imputations resume + hr.attendance.resume + form + form,tree + + + +
diff --git a/hr_attendance_resume/views/hr_attendance_view.xml b/hr_attendance_resume/views/hr_attendance_view.xml new file mode 100644 index 00000000..880fd2f5 --- /dev/null +++ b/hr_attendance_resume/views/hr_attendance_view.xml @@ -0,0 +1,45 @@ + + + + hr.attendance + + + + + + + + + + hr.attendance + + + + + + + + + + + + + hr.attendance + + + + + + + + {'readonly': [('treated', '=', True)]} + + + {'readonly': [('treated', '=', True)]} + + + {'readonly': [('treated', '=', True)]} + + + + diff --git a/hr_attendance_resume/views/hr_employee_view.xml b/hr_attendance_resume/views/hr_employee_view.xml new file mode 100644 index 00000000..6a67f866 --- /dev/null +++ b/hr_attendance_resume/views/hr_employee_view.xml @@ -0,0 +1,25 @@ + + + + hr.employee + + + + 0 + + + + + hr.employee + + + + + + + + diff --git a/hr_attendance_resume/wizard/__init__.py b/hr_attendance_resume/wizard/__init__.py new file mode 100644 index 00000000..d8ea65b1 --- /dev/null +++ b/hr_attendance_resume/wizard/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2019 Alfredo de la fuente - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +from . import wiz_hr_attendance_resume +from . import wiz_hr_attendance_uncheck_treaties diff --git a/hr_attendance_resume/wizard/wiz_hr_attendance_resume.py b/hr_attendance_resume/wizard/wiz_hr_attendance_resume.py new file mode 100644 index 00000000..35d689cc --- /dev/null +++ b/hr_attendance_resume/wizard/wiz_hr_attendance_resume.py @@ -0,0 +1,19 @@ +# Copyright 2019 Alfredo de la fuente - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +from odoo import models, api + + +class WizHrAttendanceResume(models.TransientModel): + _name = "wiz.hr.attendance.resume" + _description = "Wizard to impute assistances resume" + + @api.multi + def button_impute(self): + context = dict(self._context or {}) + active_ids = context.get('active_ids', []) or [] + attendances = self.env['hr.attendance'].browse(active_ids) + if attendances: + attendances = attendances.filtered(lambda c: not c.treated) + if attendances: + attendances._impute_in_attendance_resume() + return {'type': 'ir.actions.act_window_close'} diff --git a/hr_attendance_resume/wizard/wiz_hr_attendance_resume_view.xml b/hr_attendance_resume/wizard/wiz_hr_attendance_resume_view.xml new file mode 100644 index 00000000..e260eff4 --- /dev/null +++ b/hr_attendance_resume/wizard/wiz_hr_attendance_resume_view.xml @@ -0,0 +1,23 @@ + + + + wiz.hr.attendance.resume + +
+

+ You are going to impute in assistances resume +

+
+
+
+
+
+ +
+
diff --git a/hr_attendance_resume/wizard/wiz_hr_attendance_uncheck_treaties.py b/hr_attendance_resume/wizard/wiz_hr_attendance_uncheck_treaties.py new file mode 100644 index 00000000..e39fdd5d --- /dev/null +++ b/hr_attendance_resume/wizard/wiz_hr_attendance_uncheck_treaties.py @@ -0,0 +1,29 @@ +# Copyright 2019 Alfredo de la fuente - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +from odoo import models, api + + +class WizHrAttendanceUncheckTreaties(models.TransientModel): + _name = "wiz.hr.attendance.uncheck.treaties" + _description = "Wizard for uncheck attendances treaties" + + @api.multi + def button_uncheck(self): + context = dict(self._context or {}) + active_ids = context.get('active_ids', []) or [] + attendances = self.env['hr.attendance'].browse(active_ids) + if attendances: + attendances.write({'treated': False}) + self._delete_employees_resumes(attendances) + return {'type': 'ir.actions.act_window_close'} + + def _delete_employees_resumes(self, attendances): + cond = [('id', 'in', attendances.mapped('employee_id').ids), + ('resource_calendar_id', '!=', False)] + employees = self.env['hr.employee'].search(cond) + for employee in employees: + emp_attendances = attendances.filtered( + lambda c: c.employee_id.id == employee.id and + c.check_out and not c.treated) + if emp_attendances: + emp_attendances._delete_employee_attendance_resumes() diff --git a/hr_attendance_resume/wizard/wiz_hr_attendance_uncheck_treaties_view.xml b/hr_attendance_resume/wizard/wiz_hr_attendance_uncheck_treaties_view.xml new file mode 100644 index 00000000..7f31e210 --- /dev/null +++ b/hr_attendance_resume/wizard/wiz_hr_attendance_uncheck_treaties_view.xml @@ -0,0 +1,23 @@ + + + + wiz.hr.attendance.uncheck.treaties + +
+

+ You are going to uncheck treaties +

+
+
+
+
+
+ +
+