diff --git a/.isort.cfg b/.isort.cfg index 5751c40d..a216b1b7 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -9,4 +9,4 @@ line_length=88 known_odoo=odoo known_odoo_addons=odoo.addons sections=FUTURE,STDLIB,THIRDPARTY,ODOO,ODOO_ADDONS,FIRSTPARTY,LOCALFOLDER -known_third_party= +known_third_party=psycopg2,pytz diff --git a/hr_attendance_report_theoretical_time/README.rst b/hr_attendance_report_theoretical_time/README.rst new file mode 100644 index 00000000..d52660a7 --- /dev/null +++ b/hr_attendance_report_theoretical_time/README.rst @@ -0,0 +1,168 @@ +===================================== +Theoretical vs Attended Time Analysis +===================================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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--attendance-lightgray.png?logo=github + :target: https://github.com/OCA/hr-attendance/tree/13.0/hr_attendance_report_theoretical_time + :alt: OCA/hr-attendance +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/hr-attendance-13-0/hr-attendance-13-0-hr_attendance_report_theoretical_time + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/288/13.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds a new report called "Theoretical vs Attended Time Analysis" +that compares worked time, measured through attendances records, with the +theoretical time, computed from employee's working calendar, public holidays +and employee specific leaves. Missing attendance days are generated on the fly +in the report with their corresponding theoretical hours. + +There is the possibility of counting as theoretical time some leave types if +specified in them. + +As an example, imagine a work week with 40 theoretical hours, and these +attendance situation: + +* Monday: Worked 10 hours +* Tuesday: Worked 10 hours +* Wednesday: Worked 10 hours +* Thursday: Worked 10 hours +* Friday: Ask for a compensation leave (said leave type), as already worked + 40 hours. + +On the report, whole week should put 40 theoretical hours - 8 per day - against +40 worked hours (although they were on previous days, and none on Friday). + +On contrary, if you want to take a holiday one of that days, you should ask for +a leave type without the check for counting as theoretical time, and then the +whole week will be 32 theoretical hours against the worked hours of that week +without the leave. + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +On installation time, this module computes the theoretical hours for the day of +the attendance check-in, so if you have a lot of records, this would be a bit +slow. + +Configuration +============= + +You need to be at least "Attendance / Manual Attendance" for being able to see +the attendances report. + +For including some leave types in the theoretical time, you have to: + +#. Go to *Leaves > Configuration > Leave Types*. +#. Select leave type you want to include. +#. Check the mark "Include in theoretical hours". + +When generating non worked days, this module uses a start date for beginning +the series generation, which is: + +* Manual start date set on the employee. +* If not set, the greatest of these 2 dates: + + * Employee creation date. + * Working calendar line start date. + +For configuring manual start date, you have to: + +#. Go to *Employees > Employees*. +#. Select an employee. +#. Go to "HR Settings" page. +#. Set the date in "Theoretical hours start date" field. + +The generation will stop on the end date of the working calendar line or today, +so don't forget to properly set start and end dates of the lines of the working +calendar for not leaving empty spaces between them. + +Usage +===== + +#. Go to *Attendances > Reporting > Theoretical vs Attended Time Analysis*. +#. Check pivot table or look at the graph view. + +Known issues / Roadmap +====================== + +* Employees with less than 1 week in the company will show full week + theoretical hours. +* Activate ORM cache for improving performance on computing theoretical hours, + but assuring that the cache is cleared when the conditions of the computation + changes. +* If you change employee's working time, theoretical hours for non attended + days will be computed according this new calendar. You have to define + start and end dates inside the calendar for avoiding this side effect. +* Theoretical hours of affected days when changing the leave type to be + included or not in theoretical time are not recomputed. + +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 smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Tecnativa + +Contributors +~~~~~~~~~~~~ + +* `Tecnativa `__: + + * Pedro M. Baeza. + * David Vidal +* Pedro Gonzalez + +Other credits +~~~~~~~~~~~~~ + +**Images** + +* Font Awesome: `Icon `_. + +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-attendance `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/hr_attendance_report_theoretical_time/__init__.py b/hr_attendance_report_theoretical_time/__init__.py new file mode 100644 index 00000000..ac2626d7 --- /dev/null +++ b/hr_attendance_report_theoretical_time/__init__.py @@ -0,0 +1,5 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import models +from . import reports +from . import wizards diff --git a/hr_attendance_report_theoretical_time/__manifest__.py b/hr_attendance_report_theoretical_time/__manifest__.py new file mode 100644 index 00000000..1e6a5dca --- /dev/null +++ b/hr_attendance_report_theoretical_time/__manifest__.py @@ -0,0 +1,22 @@ +# Copyright 2017-2019 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Theoretical vs Attended Time Analysis", + "version": "13.0.1.0.0", + "category": "Human Resources", + "website": "https://github.com/OCA/hr", + "author": "Tecnativa, " "Odoo Community Association (OCA)", + "license": "AGPL-3", + "installable": True, + "depends": ["hr_attendance", "hr_holidays_public"], + "data": [ + "security/ir.model.access.csv", + "security/hr_attendance_report_theoretical_time_security.xml", + "views/hr_attendance_views.xml", + "views/hr_leave_type_views.xml", + "views/hr_employee_views.xml", + "reports/hr_attendance_theoretical_time_report_views.xml", + "wizards/recompute_theoretical_attendance_views.xml", + "wizards/wizard_theoretical_time.xml", + ], +} diff --git a/hr_attendance_report_theoretical_time/i18n/de.po b/hr_attendance_report_theoretical_time/i18n/de.po new file mode 100644 index 00000000..2aceaba3 --- /dev/null +++ b/hr_attendance_report_theoretical_time/i18n/de.po @@ -0,0 +1,307 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_attendance_report_theoretical_time +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2019-10-11 10:36+0000\n" +"Last-Translator: Maria Sparenberg \n" +"Language-Team: none\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.8\n" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_theoretical_report +msgid "All Employees" +msgstr "Alle Angestellte" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_attendance +msgid "Attendance" +msgstr "Anwesenheit" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_report +msgid "Attendances Analysis" +msgstr "Anwesenheitsanalyse" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.recompute_theoretical_attendance_form +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Cancel" +msgstr "Abbrechen" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__create_uid +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__create_uid +msgid "Created by" +msgstr "Erstellt von" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__create_date +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__create_date +msgid "Created on" +msgstr "Erstellt am" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Current Month" +msgstr "Aktueller Monat" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Current Year" +msgstr "Aktuelles Jahr" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__date +msgid "Date" +msgstr "Datum" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__department_id +msgid "Department" +msgstr "Abteilung" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__difference +msgid "Difference" +msgstr "Unterschied" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__display_name +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__display_name +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__display_name +msgid "Display Name" +msgstr "Anzeigename" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_employee +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__employee_id +msgid "Employee" +msgstr "Angestellte(r)" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__employee_ids +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__employee_ids +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Employees" +msgstr "Angestellte" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_hr_employee__theoretical_hours_start_date +msgid "" +"Fill this field for setting a manual start date for computing the " +"theoretical hours independently from the attendances. If not filled, " +"employee creation date or the calendar start date will be used (the greatest " +"of both)." +msgstr "" +"Füllen Sie dieses Feld aus, um ein manuelles Startdatum zur Berechnung der " +"theoretischen Stundenzahl zu setzen, unabhängig von den tatsächlichen " +"Anwesenheiten. Ist das Feld nicht ausgefüllt, wird entweder das Erstelldatum " +"der/des Angestellte(n) oder das Kalender-Startdatum verwendet (das größere " +"von beiden)." + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_wizard_theoretical_time +msgid "Filtered Theoretical Time" +msgstr "Gefilterte theoretische Anwesenheitszeit" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Filters" +msgstr "Filter" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_from +msgid "From" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__id +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__id +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__id +msgid "ID" +msgstr "ID" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_hr_leave_type__include_in_theoretical +msgid "" +"If you check this mark, leaves in this category won't reduce the number of " +"theoretical hours in the attendance report." +msgstr "" +"Wenn der Haken gesetzt ist, wird Urlaub in dieser Kategorie die Anzahl der " +"theoretischen Stunden im Anwesenheitsbericht nicht reduzieren." + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_leave_type__include_in_theoretical +msgid "Include in theoretical hours" +msgstr "in theoretische Stunden einbeziehen" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report____last_update +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance____last_update +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time____last_update +msgid "Last Modified on" +msgstr "Zuletzt geändert am" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__write_uid +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__write_uid +msgid "Last Updated by" +msgstr "Zuletzt aktualisiert von" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__write_date +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__write_date +msgid "Last Updated on" +msgstr "Zuletzt aktualisiert am" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_leave +msgid "Leave" +msgstr "Urlaub" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_leave_type +msgid "Leave Type" +msgstr "Urlaubsart" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "My Attendances" +msgstr "Meine Anwesenheiten" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Populate" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Previous Month" +msgstr "Vorheriger Monat" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_holidays_public_line +msgid "Public Holidays Lines" +msgstr "Feiertagszeilen" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.recompute_theoretical_attendance_form +msgid "Recompute" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_recompute_theoretical_attendance +msgid "Recompute Employees Attendances" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.recompute_employee_theoretical_attendance +#, fuzzy +#| msgid "Report of theoretical time vs attendance time" +msgid "Recompute Theoretical Attendance" +msgstr "Bericht zu theoretischen und tatsächlichen Anwesenheitszeiten" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.act_wizard_recompute_theoretical_attendance +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_recompute_theoretical_attendance +#, fuzzy +#| msgid "Report of theoretical time vs attendance time" +msgid "Recompute Theoretical Attendances" +msgstr "Bericht zu theoretischen und tatsächlichen Anwesenheitszeiten" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_from +msgid "Recompute attendances from this date" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_to +msgid "Recompute attendances up to this date" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__employee_ids +msgid "Recompute these employees attendances" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_attendance_theoretical_time_report +msgid "Report of theoretical time vs attendance time" +msgstr "Bericht zu theoretischen und tatsächlichen Anwesenheitszeiten" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_theoretical_report_select +msgid "Select Employees" +msgstr "Angestellte wählen" + +#. module: hr_attendance_report_theoretical_time +#: code:addons/hr_attendance_report_theoretical_time/wizards/wizard_theoretical_time.py:43 +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.wizard_theoretical_time_act_window +#, python-format +msgid "Select Employees to Analyze Theoretical Time" +msgstr "" +"Angestellte wählen um die theoretische Zeit der Anwesenheit zu analysieren." + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__category_ids +msgid "Tag" +msgstr "Stichwort" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance__theoretical_hours +msgid "Theoretical Hours" +msgstr "Theoretische Stunden" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_employee__theoretical_hours_start_date +msgid "Theoretical Hours Start Date" +msgstr "Startdatum der theoretischen Stunden" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_theoretical_root +msgid "Theoretical vs Attended Time" +msgstr "Theoretische vs. tatsächliche Anwesenheitszeiten" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.hr_attendance_theoretical_action +msgid "Theoretical vs Attended Time Analysis" +msgstr "Analyse der theoretischen vs. tatsächlichen Anwesenheitszeiten" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__theoretical_hours +msgid "Theoric" +msgstr "Theoretisch" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_to +msgid "To" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Today" +msgstr "Heute" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "View Report" +msgstr "Bericht ansehen" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Wizard Theoretical Time" +msgstr "Assistent für theoretische Anwesenheitszeiten" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__worked_hours +msgid "Worked" +msgstr "Gearbeitet" diff --git a/hr_attendance_report_theoretical_time/i18n/es.po b/hr_attendance_report_theoretical_time/i18n/es.po new file mode 100644 index 00000000..212c52ea --- /dev/null +++ b/hr_attendance_report_theoretical_time/i18n/es.po @@ -0,0 +1,318 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_attendance_report_theoretical_time +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-11-14 13:18+0000\n" +"PO-Revision-Date: 2019-07-23 11:43+0000\n" +"Last-Translator: Jaime Arroyo \n" +"Language-Team: \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.7.1\n" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_theoretical_report +#, fuzzy +#| msgid "Employee" +msgid "All Employees" +msgstr "Empleado" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_attendance +msgid "Attendance" +msgstr "Asistencias" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_report +msgid "Attendances Analysis" +msgstr "Análisis de asistencias" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.recompute_theoretical_attendance_form +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Cancel" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__create_uid +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__create_uid +msgid "Created by" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__create_date +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__create_date +msgid "Created on" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Current Month" +msgstr "Mes actual" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Current Year" +msgstr "Año actual" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__date +msgid "Date" +msgstr "Fecha" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__department_id +msgid "Department" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__difference +msgid "Difference" +msgstr "Diferencia" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__display_name +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__display_name +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__display_name +msgid "Display Name" +msgstr "Nombre a mostrar" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_employee +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__employee_id +msgid "Employee" +msgstr "Empleado" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__employee_ids +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__employee_ids +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +#, fuzzy +#| msgid "Employee" +msgid "Employees" +msgstr "Empleado" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_hr_employee__theoretical_hours_start_date +msgid "" +"Fill this field for setting a manual start date for computing the " +"theoretical hours independently from the attendances. If not filled, " +"employee creation date or the calendar start date will be used (the greatest " +"of both)." +msgstr "" +"Rellene este campo para establecer una fecha manual para calcular las horas " +"teóricas independientemente de de las asistencias. Si no está rellenado, se " +"utilizará la fecha de creación del empleado o la fecha de comienzo del " +"calendario (la mayor de ambas)." + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_wizard_theoretical_time +#, fuzzy +#| msgid "Theoretical vs Attended Time" +msgid "Filtered Theoretical Time" +msgstr "Tiempo teórico vs trabajado" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Filters" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_from +msgid "From" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__id +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__id +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__id +msgid "ID" +msgstr "ID" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_hr_leave_type__include_in_theoretical +msgid "" +"If you check this mark, leaves in this category won't reduce the number of " +"theoretical hours in the attendance report." +msgstr "" +"Si marca esta casilla, las ausencias de este tipo no reduciran el número de " +"horas teóricas en el informe de asistencia." + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_leave_type__include_in_theoretical +msgid "Include in theoretical hours" +msgstr "Incluir en horas teóricas" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report____last_update +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance____last_update +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time____last_update +msgid "Last Modified on" +msgstr "Última modificación en" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__write_uid +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__write_date +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__write_date +#, fuzzy +#| msgid "Last Modified on" +msgid "Last Updated on" +msgstr "Última modificación en" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_leave +msgid "Leave" +msgstr "Ausencia" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_leave_type +msgid "Leave Type" +msgstr "Tipo de ausencia" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "My Attendances" +msgstr "Mis asistencias" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Populate" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Previous Month" +msgstr "Mes anterior" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_holidays_public_line +msgid "Public Holidays Lines" +msgstr "Líneas de vacaciones públicas" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.recompute_theoretical_attendance_form +msgid "Recompute" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_recompute_theoretical_attendance +msgid "Recompute Employees Attendances" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.recompute_employee_theoretical_attendance +#, fuzzy +#| msgid "Report of theoretical time vs attendance time" +msgid "Recompute Theoretical Attendance" +msgstr "Informe de tiempo teórico frente a tiempo trabajado" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.act_wizard_recompute_theoretical_attendance +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_recompute_theoretical_attendance +#, fuzzy +#| msgid "Report of theoretical time vs attendance time" +msgid "Recompute Theoretical Attendances" +msgstr "Informe de tiempo teórico frente a tiempo trabajado" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_from +msgid "Recompute attendances from this date" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_to +msgid "Recompute attendances up to this date" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__employee_ids +msgid "Recompute these employees attendances" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_attendance_theoretical_time_report +msgid "Report of theoretical time vs attendance time" +msgstr "Informe de tiempo teórico frente a tiempo trabajado" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_theoretical_report_select +#, fuzzy +#| msgid "Employee" +msgid "Select Employees" +msgstr "Empleado" + +#. module: hr_attendance_report_theoretical_time +#: code:addons/hr_attendance_report_theoretical_time/wizards/wizard_theoretical_time.py:43 +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.wizard_theoretical_time_act_window +#, python-format +msgid "Select Employees to Analyze Theoretical Time" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__category_ids +msgid "Tag" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance__theoretical_hours +msgid "Theoretical Hours" +msgstr "Horas teóricas" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_employee__theoretical_hours_start_date +msgid "Theoretical Hours Start Date" +msgstr "Fecha de inicio horas teóricas" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_theoretical_root +msgid "Theoretical vs Attended Time" +msgstr "Tiempo teórico vs trabajado" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.hr_attendance_theoretical_action +msgid "Theoretical vs Attended Time Analysis" +msgstr "Análisis de tiempo teórico vs trabajado" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__theoretical_hours +msgid "Theoric" +msgstr "Teórico" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_to +msgid "To" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Today" +msgstr "Hoy" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "View Report" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +#, fuzzy +#| msgid "Theoretical vs Attended Time" +msgid "Wizard Theoretical Time" +msgstr "Tiempo teórico vs trabajado" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__worked_hours +msgid "Worked" +msgstr "Trabajado" diff --git a/hr_attendance_report_theoretical_time/i18n/fr.po b/hr_attendance_report_theoretical_time/i18n/fr.po new file mode 100644 index 00000000..fbf70f06 --- /dev/null +++ b/hr_attendance_report_theoretical_time/i18n/fr.po @@ -0,0 +1,320 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_attendance_report_theoretical_time +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2019-05-24 14:19+0000\n" +"Last-Translator: Kévin Allard \n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.6.1\n" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_theoretical_report +#, fuzzy +#| msgid "Employee" +msgid "All Employees" +msgstr "Employé(e)" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_attendance +msgid "Attendance" +msgstr "Présence" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_report +msgid "Attendances Analysis" +msgstr "Analyse des présences" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.recompute_theoretical_attendance_form +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Cancel" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__create_uid +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__create_uid +msgid "Created by" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__create_date +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__create_date +msgid "Created on" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Current Month" +msgstr "Mois courant" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Current Year" +msgstr "Année courante" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__date +msgid "Date" +msgstr "Date" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__department_id +msgid "Department" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__difference +msgid "Difference" +msgstr "Différence" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__display_name +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__display_name +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__display_name +msgid "Display Name" +msgstr "Nom affiché" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_employee +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__employee_id +msgid "Employee" +msgstr "Employé(e)" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__employee_ids +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__employee_ids +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +#, fuzzy +#| msgid "Employee" +msgid "Employees" +msgstr "Employé(e)" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_hr_employee__theoretical_hours_start_date +#, fuzzy +msgid "" +"Fill this field for setting a manual start date for computing the " +"theoretical hours independently from the attendances. If not filled, " +"employee creation date or the calendar start date will be used (the greatest " +"of both)." +msgstr "" +"Remplissez ce champ pour définir une date de début manuelle pour le calcul " +"des heures théoriques indépendamment des heures de présence. Si non rempli, " +"la date de création de l'employé ou la date de début du calendrier sera " +"utilisée (la plus grande des deux)." + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_wizard_theoretical_time +#, fuzzy +#| msgid "Theoretical vs Attended Time" +msgid "Filtered Theoretical Time" +msgstr "Durée théorique / Durée réelle" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Filters" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_from +msgid "From" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__id +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__id +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__id +msgid "ID" +msgstr "ID" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_hr_leave_type__include_in_theoretical +#, fuzzy +msgid "" +"If you check this mark, leaves in this category won't reduce the number of " +"theoretical hours in the attendance report." +msgstr "" +"Si vous cochez cette case, les feuilles de cette catégorie ne réduiront pas " +"le nombre d'heures théoriques dans le rapport de présence." + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_leave_type__include_in_theoretical +msgid "Include in theoretical hours" +msgstr "Inclure dans les heures théoriques" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report____last_update +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance____last_update +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time____last_update +msgid "Last Modified on" +msgstr "Dernière modification le" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__write_uid +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__write_date +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__write_date +#, fuzzy +#| msgid "Last Modified on" +msgid "Last Updated on" +msgstr "Dernière modification le" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_leave +msgid "Leave" +msgstr "Congé" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_leave_type +msgid "Leave Type" +msgstr "Type de congé" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "My Attendances" +msgstr "Mes présences" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Populate" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Previous Month" +msgstr "Mois précédent" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_holidays_public_line +#, fuzzy +msgid "Public Holidays Lines" +msgstr "Lignes de jours fériés" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.recompute_theoretical_attendance_form +msgid "Recompute" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_recompute_theoretical_attendance +msgid "Recompute Employees Attendances" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.recompute_employee_theoretical_attendance +#, fuzzy +msgid "Recompute Theoretical Attendance" +msgstr "Rapport de durée théorique / durée de présence" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.act_wizard_recompute_theoretical_attendance +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_recompute_theoretical_attendance +#, fuzzy +msgid "Recompute Theoretical Attendances" +msgstr "Rapport de durée théorique / durée de présence" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_from +msgid "Recompute attendances from this date" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_to +msgid "Recompute attendances up to this date" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__employee_ids +msgid "Recompute these employees attendances" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_attendance_theoretical_time_report +#, fuzzy +msgid "Report of theoretical time vs attendance time" +msgstr "Rapport de durée théorique / durée de présence" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_theoretical_report_select +#, fuzzy +#| msgid "Employee" +msgid "Select Employees" +msgstr "Employé(e)" + +#. module: hr_attendance_report_theoretical_time +#: code:addons/hr_attendance_report_theoretical_time/wizards/wizard_theoretical_time.py:43 +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.wizard_theoretical_time_act_window +#, python-format +msgid "Select Employees to Analyze Theoretical Time" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__category_ids +msgid "Tag" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance__theoretical_hours +msgid "Theoretical Hours" +msgstr "Heures théoriques" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_employee__theoretical_hours_start_date +msgid "Theoretical Hours Start Date" +msgstr "Heure de début théorique" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_theoretical_root +msgid "Theoretical vs Attended Time" +msgstr "Durée théorique / Durée réelle" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.hr_attendance_theoretical_action +#, fuzzy +msgid "Theoretical vs Attended Time Analysis" +msgstr "Analyse de la durée réelle / Durée théorique" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__theoretical_hours +msgid "Theoric" +msgstr "Théorique" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_to +msgid "To" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Today" +msgstr "Aujourd'hui" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "View Report" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +#, fuzzy +#| msgid "Theoretical vs Attended Time" +msgid "Wizard Theoretical Time" +msgstr "Durée théorique / Durée réelle" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__worked_hours +msgid "Worked" +msgstr "Travaillé" diff --git a/hr_attendance_report_theoretical_time/i18n/hr_attendance_report_theoretical_time.pot b/hr_attendance_report_theoretical_time/i18n/hr_attendance_report_theoretical_time.pot new file mode 100644 index 00000000..6b25de7d --- /dev/null +++ b/hr_attendance_report_theoretical_time/i18n/hr_attendance_report_theoretical_time.pot @@ -0,0 +1,287 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_attendance_report_theoretical_time +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \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_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_theoretical_report +msgid "All Employees" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_attendance +msgid "Attendance" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_report +msgid "Attendances Analysis" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.recompute_theoretical_attendance_form +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Cancel" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__create_uid +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__create_uid +msgid "Created by" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__create_date +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__create_date +msgid "Created on" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Current Month" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Current Year" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__date +msgid "Date" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__department_id +msgid "Department" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__difference +msgid "Difference" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__display_name +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__display_name +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__display_name +msgid "Display Name" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_employee +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__employee_id +msgid "Employee" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__employee_ids +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__employee_ids +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Employees" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_hr_employee__theoretical_hours_start_date +msgid "Fill this field for setting a manual start date for computing the theoretical hours independently from the attendances. If not filled, employee creation date or the calendar start date will be used (the greatest of both)." +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_wizard_theoretical_time +msgid "Filtered Theoretical Time" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Filters" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_from +msgid "From" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__id +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__id +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__id +msgid "ID" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_hr_leave_type__include_in_theoretical +msgid "If you check this mark, leaves in this category won't reduce the number of theoretical hours in the attendance report." +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_leave_type__include_in_theoretical +msgid "Include in theoretical hours" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report____last_update +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance____last_update +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time____last_update +msgid "Last Modified on" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__write_uid +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__write_date +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__write_date +msgid "Last Updated on" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_leave +msgid "Leave" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_leave_type +msgid "Leave Type" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "My Attendances" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Populate" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Previous Month" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_holidays_public_line +msgid "Public Holidays Lines" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.recompute_theoretical_attendance_form +msgid "Recompute" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_recompute_theoretical_attendance +msgid "Recompute Employees Attendances" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.recompute_employee_theoretical_attendance +msgid "Recompute Theoretical Attendance" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.act_wizard_recompute_theoretical_attendance +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_recompute_theoretical_attendance +msgid "Recompute Theoretical Attendances" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_from +msgid "Recompute attendances from this date" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_to +msgid "Recompute attendances up to this date" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,help:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__employee_ids +msgid "Recompute these employees attendances" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model,name:hr_attendance_report_theoretical_time.model_hr_attendance_theoretical_time_report +msgid "Report of theoretical time vs attendance time" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_theoretical_report_select +msgid "Select Employees" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: code:addons/hr_attendance_report_theoretical_time/wizards/wizard_theoretical_time.py:43 +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.wizard_theoretical_time_act_window +#, python-format +msgid "Select Employees to Analyze Theoretical Time" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_wizard_theoretical_time__category_ids +msgid "Tag" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance__theoretical_hours +msgid "Theoretical Hours" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_employee__theoretical_hours_start_date +msgid "Theoretical Hours Start Date" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.ui.menu,name:hr_attendance_report_theoretical_time.menu_hr_attendance_theoretical_root +msgid "Theoretical vs Attended Time" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.actions.act_window,name:hr_attendance_report_theoretical_time.hr_attendance_theoretical_action +msgid "Theoretical vs Attended Time Analysis" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__theoretical_hours +msgid "Theoric" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_recompute_theoretical_attendance__date_to +msgid "To" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.hr_attendance_theoretical_view_filter +msgid "Today" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "View Report" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model_terms:ir.ui.view,arch_db:hr_attendance_report_theoretical_time.wizard_theoretical_time_form_view +msgid "Wizard Theoretical Time" +msgstr "" + +#. module: hr_attendance_report_theoretical_time +#: model:ir.model.fields,field_description:hr_attendance_report_theoretical_time.field_hr_attendance_theoretical_time_report__worked_hours +msgid "Worked" +msgstr "" + diff --git a/hr_attendance_report_theoretical_time/models/__init__.py b/hr_attendance_report_theoretical_time/models/__init__.py new file mode 100644 index 00000000..5819b6fd --- /dev/null +++ b/hr_attendance_report_theoretical_time/models/__init__.py @@ -0,0 +1,7 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import hr_attendance +from . import hr_employee +from . import hr_holidays_public +from . import hr_leave +from . import hr_leave_type diff --git a/hr_attendance_report_theoretical_time/models/hr_attendance.py b/hr_attendance_report_theoretical_time/models/hr_attendance.py new file mode 100644 index 00000000..8bdf9fb3 --- /dev/null +++ b/hr_attendance_report_theoretical_time/models/hr_attendance.py @@ -0,0 +1,20 @@ +# Copyright 2017-2019 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class HrAttendance(models.Model): + _inherit = "hr.attendance" + + theoretical_hours = fields.Float( + compute="_compute_theoretical_hours", store=True, compute_sudo=True + ) + + @api.depends("check_in", "employee_id") + def _compute_theoretical_hours(self): + obj = self.env["hr.attendance.theoretical.time.report"] + for record in self: + record.theoretical_hours = obj._theoretical_hours( + record.employee_id, record.check_in + ) diff --git a/hr_attendance_report_theoretical_time/models/hr_employee.py b/hr_attendance_report_theoretical_time/models/hr_employee.py new file mode 100644 index 00000000..07049ccf --- /dev/null +++ b/hr_attendance_report_theoretical_time/models/hr_employee.py @@ -0,0 +1,15 @@ +# Copyright 2018 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class HrEmployee(models.Model): + _inherit = "hr.employee" + + theoretical_hours_start_date = fields.Date( + help="Fill this field for setting a manual start date for computing " + "the theoretical hours independently from the attendances. If " + "not filled, employee creation date or the calendar start date " + "will be used (the greatest of both)." + ) diff --git a/hr_attendance_report_theoretical_time/models/hr_holidays_public.py b/hr_attendance_report_theoretical_time/models/hr_holidays_public.py new file mode 100644 index 00000000..7920eabd --- /dev/null +++ b/hr_attendance_report_theoretical_time/models/hr_holidays_public.py @@ -0,0 +1,52 @@ +# Copyright 2017-2019 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from datetime import datetime, time + +from odoo import api, fields, models + + +class HrHolidaysPublicLine(models.Model): + _inherit = "hr.holidays.public.line" + + @api.model + def _check_theoretical_hours(self, date): + """Recomputes all the theoretical hours that corresponds to the date + of the public holiday. + + :param: date: Date for recomputing attendances. + """ + if not date: + return + if isinstance(date, str): + date = fields.Date.from_string(date) + from_datetime = datetime.combine(date, time(0, 0, 0, 0)) + to_datetime = datetime.combine(date, time(23, 59, 59, 99999)) + records = self.env["hr.attendance"].search( + [ + ("check_in", ">=", fields.Datetime.to_string(from_datetime)), + ("check_in", "<=", fields.Datetime.to_string(to_datetime)), + ] + ) + records._compute_theoretical_hours() + + @api.model_create_multi + def create(self, vals_list): + """Trigger recomputation for the date of the new lines.""" + records = super(HrHolidaysPublicLine, self).create(vals_list) + for record in records: + self._check_theoretical_hours(record.date) + return records + + def write(self, vals): + """If the date of a line is changed, we first recompute hours of the + previous date, and then the theoretical hours of the current date. + """ + if "date" in vals: + dates = set(self.mapped("date")) + dates.add(vals["date"]) + res = super(HrHolidaysPublicLine, self).write(vals) + if "date" in vals: + for date in dates: + self._check_theoretical_hours(date=date) + return res diff --git a/hr_attendance_report_theoretical_time/models/hr_leave.py b/hr_attendance_report_theoretical_time/models/hr_leave.py new file mode 100644 index 00000000..092082be --- /dev/null +++ b/hr_attendance_report_theoretical_time/models/hr_leave.py @@ -0,0 +1,45 @@ +# Copyright 2017-2019 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import models + + +class HrLeave(models.Model): + _inherit = "hr.leave" + + def _create_resource_leave(self): + """On leave creation, trigger the recomputation of the involved + records.""" + res = super()._create_resource_leave() + self._check_theoretical_hours() + return res + + def _remove_resource_leave(self): + """On leave cancellation, trigger the recomputation of the involved + records.""" + res = super()._remove_resource_leave() + self._check_theoretical_hours() + return res + + def _check_theoretical_hours(self): + """Recomputes all the theoretical hours that corresponds to the + interval of dates and employee of the leaves. + + :param: self: Leave recordset. + """ + to_recompute = self.env["hr.attendance"] + for record in self.filtered(lambda x: x.date_from and x.date_to): + from_datetime = record.date_from.replace( + hour=0, minute=0, second=0, microsecond=0 + ) + to_datetime = record.date_to.replace( + hour=23, minute=59, second=59, microsecond=99999 + ) + to_recompute |= self.env["hr.attendance"].search( + [ + ("employee_id", "=", record.employee_id.id), + ("check_in", ">=", from_datetime), + ("check_in", "<=", to_datetime), + ] + ) + to_recompute._compute_theoretical_hours() diff --git a/hr_attendance_report_theoretical_time/models/hr_leave_type.py b/hr_attendance_report_theoretical_time/models/hr_leave_type.py new file mode 100644 index 00000000..7ef86062 --- /dev/null +++ b/hr_attendance_report_theoretical_time/models/hr_leave_type.py @@ -0,0 +1,14 @@ +# Copyright 2018-2019 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class HrLeaveType(models.Model): + _inherit = "hr.leave.type" + + include_in_theoretical = fields.Boolean( + string="Include in theoretical hours", + help="If you check this mark, leaves in this category won't reduce " + "the number of theoretical hours in the attendance report.", + ) diff --git a/hr_attendance_report_theoretical_time/readme/CONFIGURE.rst b/hr_attendance_report_theoretical_time/readme/CONFIGURE.rst new file mode 100644 index 00000000..04241274 --- /dev/null +++ b/hr_attendance_report_theoretical_time/readme/CONFIGURE.rst @@ -0,0 +1,28 @@ +You need to be at least "Attendance / Manual Attendance" for being able to see +the attendances report. + +For including some leave types in the theoretical time, you have to: + +#. Go to *Leaves > Configuration > Leave Types*. +#. Select leave type you want to include. +#. Check the mark "Include in theoretical hours". + +When generating non worked days, this module uses a start date for beginning +the series generation, which is: + +* Manual start date set on the employee. +* If not set, the greatest of these 2 dates: + + * Employee creation date. + * Working calendar line start date. + +For configuring manual start date, you have to: + +#. Go to *Employees > Employees*. +#. Select an employee. +#. Go to "HR Settings" page. +#. Set the date in "Theoretical hours start date" field. + +The generation will stop on the end date of the working calendar line or today, +so don't forget to properly set start and end dates of the lines of the working +calendar for not leaving empty spaces between them. diff --git a/hr_attendance_report_theoretical_time/readme/CONTRIBUTORS.rst b/hr_attendance_report_theoretical_time/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..7c0ea63c --- /dev/null +++ b/hr_attendance_report_theoretical_time/readme/CONTRIBUTORS.rst @@ -0,0 +1,5 @@ +* `Tecnativa `__: + + * Pedro M. Baeza. + * David Vidal +* Pedro Gonzalez diff --git a/hr_attendance_report_theoretical_time/readme/CREDITS.rst b/hr_attendance_report_theoretical_time/readme/CREDITS.rst new file mode 100644 index 00000000..c76e53ab --- /dev/null +++ b/hr_attendance_report_theoretical_time/readme/CREDITS.rst @@ -0,0 +1,3 @@ +**Images** + +* Font Awesome: `Icon `_. diff --git a/hr_attendance_report_theoretical_time/readme/DESCRIPTION.rst b/hr_attendance_report_theoretical_time/readme/DESCRIPTION.rst new file mode 100644 index 00000000..fb42d976 --- /dev/null +++ b/hr_attendance_report_theoretical_time/readme/DESCRIPTION.rst @@ -0,0 +1,26 @@ +This module adds a new report called "Theoretical vs Attended Time Analysis" +that compares worked time, measured through attendances records, with the +theoretical time, computed from employee's working calendar, public holidays +and employee specific leaves. Missing attendance days are generated on the fly +in the report with their corresponding theoretical hours. + +There is the possibility of counting as theoretical time some leave types if +specified in them. + +As an example, imagine a work week with 40 theoretical hours, and these +attendance situation: + +* Monday: Worked 10 hours +* Tuesday: Worked 10 hours +* Wednesday: Worked 10 hours +* Thursday: Worked 10 hours +* Friday: Ask for a compensation leave (said leave type), as already worked + 40 hours. + +On the report, whole week should put 40 theoretical hours - 8 per day - against +40 worked hours (although they were on previous days, and none on Friday). + +On contrary, if you want to take a holiday one of that days, you should ask for +a leave type without the check for counting as theoretical time, and then the +whole week will be 32 theoretical hours against the worked hours of that week +without the leave. diff --git a/hr_attendance_report_theoretical_time/readme/INSTALL.rst b/hr_attendance_report_theoretical_time/readme/INSTALL.rst new file mode 100644 index 00000000..47786637 --- /dev/null +++ b/hr_attendance_report_theoretical_time/readme/INSTALL.rst @@ -0,0 +1,3 @@ +On installation time, this module computes the theoretical hours for the day of +the attendance check-in, so if you have a lot of records, this would be a bit +slow. diff --git a/hr_attendance_report_theoretical_time/readme/ROADMAP.rst b/hr_attendance_report_theoretical_time/readme/ROADMAP.rst new file mode 100644 index 00000000..114c8109 --- /dev/null +++ b/hr_attendance_report_theoretical_time/readme/ROADMAP.rst @@ -0,0 +1,10 @@ +* Employees with less than 1 week in the company will show full week + theoretical hours. +* Activate ORM cache for improving performance on computing theoretical hours, + but assuring that the cache is cleared when the conditions of the computation + changes. +* If you change employee's working time, theoretical hours for non attended + days will be computed according this new calendar. You have to define + start and end dates inside the calendar for avoiding this side effect. +* Theoretical hours of affected days when changing the leave type to be + included or not in theoretical time are not recomputed. diff --git a/hr_attendance_report_theoretical_time/readme/USAGE.rst b/hr_attendance_report_theoretical_time/readme/USAGE.rst new file mode 100644 index 00000000..11b99246 --- /dev/null +++ b/hr_attendance_report_theoretical_time/readme/USAGE.rst @@ -0,0 +1,2 @@ +#. Go to *Attendances > Reporting > Theoretical vs Attended Time Analysis*. +#. Check pivot table or look at the graph view. diff --git a/hr_attendance_report_theoretical_time/reports/__init__.py b/hr_attendance_report_theoretical_time/reports/__init__.py new file mode 100644 index 00000000..ca76ed84 --- /dev/null +++ b/hr_attendance_report_theoretical_time/reports/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import hr_attendance_theoretical_time_report diff --git a/hr_attendance_report_theoretical_time/reports/hr_attendance_theoretical_time_report.py b/hr_attendance_report_theoretical_time/reports/hr_attendance_theoretical_time_report.py new file mode 100644 index 00000000..9223665c --- /dev/null +++ b/hr_attendance_report_theoretical_time/reports/hr_attendance_theoretical_time_report.py @@ -0,0 +1,236 @@ +# Copyright 2017-2019 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from datetime import datetime, time + +import pytz +from psycopg2.extensions import AsIs + +from odoo import api, fields, models, tools + + +class HrAttendanceTheoreticalTimeReport(models.Model): + _name = "hr.attendance.theoretical.time.report" + _description = "Report of theoretical time vs attendance time" + _auto = False + _rec_name = "date" + _order = "date,employee_id,theoretical_hours desc" + + employee_id = fields.Many2one( + comodel_name="hr.employee", string="Employee", readonly=True + ) + date = fields.Date(string="Date", readonly=True) + worked_hours = fields.Float(string="Worked", readonly=True) + theoretical_hours = fields.Float(string="Theoric", readonly=True) + difference = fields.Float(readonly=True) + + def _select(self): + # We put "max" aggregation function for theoretical hours because + # we will recompute for other detail levels different than day + # through recursivity by day results and will aggregate them manually + return """ + min(id) AS id, + employee_id, + date, + sum(worked_hours) AS worked_hours, + max(theoretical_hours) AS theoretical_hours, + sum(difference) AS difference + """ + + def _select_sub1(self): + # Unique ID is assured (mostly, as we lose some precission) through + # this MD5 hash converted to integer. See + # https://stackoverflow.com/a/9812029 for details. + return """ + ( + ('x'||substr(MD5('HA' || ha.id::text), 1, 8))::bit(32)::int + ) AS id, + ha.employee_id AS employee_id, + ha.check_in::date AS date, + ha.worked_hours AS worked_hours, + ha.theoretical_hours AS theoretical_hours, + 0.0 AS difference + """ + + def _from_sub1(self): + return """ + hr_attendance ha + """ + + def _where_sub1(self): + return "True" + + def _select_sub2(self): + # Same comment about ID uniqueness of sub1. + return """ + ( + ('x'||substr(MD5( + 'HE' || he.id::text || gs::text + ), 1, 8))::bit(32)::int + ) AS id, + he.id AS employee_id, + gs::date AS date, + 0 AS worked_hours, + -1 AS theoretical_hours, + 0.0 AS difference + """ + + def _from_sub2(self): + # We generate one record for each of the theoretical working days + # since the employee creation / working schedule beginning for not + # depending on the registered attendances. + return """ + hr_employee he + INNER JOIN + resource_resource rr ON he.resource_id = rr.id + LEFT JOIN + resource_calendar_attendance rca + ON rca.calendar_id = rr.calendar_id + CROSS JOIN + generate_series( + greatest( + COALESCE(he.theoretical_hours_start_date, + he.create_date::date), + COALESCE(rca.date_from, + he.theoretical_hours_start_date, + he.create_date::date) + ) + + (8 + rca.dayofweek::int - + extract(dow from greatest( + COALESCE(he.theoretical_hours_start_date, + he.create_date::date), + COALESCE(rca.date_from, + he.theoretical_hours_start_date, + he.create_date::date) + ))::int) % 7, + least( + COALESCE(rca.date_to, current_date), + current_date + ) + + (-6 + rca.dayofweek::int - + extract(dow from least( + COALESCE(rca.date_to, current_date), + current_date + ))::int) % 7, + '7 days' + ) AS gs + """ + + def _where_sub2(self): + return """ + rca.id IS NOT NULL + """ + + def _group_by(self): + return """ + employee_id, + date + """ + + def init(self): + tools.drop_view_if_exists(self.env.cr, self._table) + self.env.cr.execute( + """ +CREATE or REPLACE VIEW %s as ( + SELECT %s + FROM ( + ( + SELECT %s + FROM %s + WHERE %s + ) + UNION ( + SELECT %s + FROM %s + WHERE %s + ) + ) AS u + GROUP BY %s +) + """, + ( + AsIs(self._table), + AsIs(self._select()), + AsIs(self._select_sub1()), + AsIs(self._from_sub1()), + AsIs(self._where_sub1()), + AsIs(self._select_sub2()), + AsIs(self._from_sub2()), + AsIs(self._where_sub2()), + AsIs(self._group_by()), + ), + ) + + # TODO: To be activated for performance assuring cache clearing on changes + # @tools.ormcache('employee.id', 'date') + @api.model + def _theoretical_hours(self, employee, date): + """Get theoretical working hours for the day where the check-in is + done for that employee. + """ + if not employee.resource_id.calendar_id: + return 0 + tz = employee.resource_id.calendar_id.tz + return employee.with_context( + exclude_public_holidays=True, employee_id=employee.id + )._get_work_days_data( + datetime.combine(date, time(0, 0, 0, 0, tzinfo=pytz.timezone(tz))), + datetime.combine(date, time(23, 59, 59, 99999, tzinfo=pytz.timezone(tz))), + # Pass this domain for excluding leaves whose type is included in + # theoretical hours + domain=[ + "|", + ("holiday_id", "=", False), + ("holiday_id.holiday_status_id.include_in_theoretical", "=", False), + ], + )[ + "hours" + ] + + @api.model + def read_group( + self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True + ): + """Compute dynamically theoretical hours amount, computing on the fly + theoretical hours for non existing attendances with stored hours. + This technique has proven to be more efficient than trying to call + recursively `read_group` grouping by date and employee. + """ + res = super(HrAttendanceTheoreticalTimeReport, self).read_group( + domain, + fields, + groupby, + offset=offset, + limit=limit, + orderby=orderby, + lazy=lazy, + ) + + if "theoretical_hours:sum" not in fields: + return res + + full_fields = all( + x in fields + for x in {"theoretical_hours:sum", "worked_hours:sum", "difference:sum"} + ) + difference_field = "difference:sum" in fields + for line in res: + day_dict = {} + records = self.search(line.get("__domain", domain)) + for record in records: + key = (record.employee_id.id, record.date) + if key not in day_dict: + if record.theoretical_hours < 0: + day_dict[key] = self._theoretical_hours( + record.employee_id.sudo(), record.date + ) + else: + day_dict[key] = record.theoretical_hours + line["theoretical_hours"] = sum(day_dict.values()) + if full_fields: # compute difference + line["difference"] = (line["worked_hours"] or 0.0) - line[ + "theoretical_hours" + ] + elif difference_field: # Remove wrong 0 values + del line["difference"] + return res diff --git a/hr_attendance_report_theoretical_time/reports/hr_attendance_theoretical_time_report_views.xml b/hr_attendance_report_theoretical_time/reports/hr_attendance_theoretical_time_report_views.xml new file mode 100644 index 00000000..918d2ccf --- /dev/null +++ b/hr_attendance_report_theoretical_time/reports/hr_attendance_theoretical_time_report_views.xml @@ -0,0 +1,79 @@ + + + + + hr.attendance.theoretical.time.report + + + + + + + + + + + + + + + hr.attendance.theoretical.time.report + + + + + + + + + + + + + hr.attendance.theoretical.time.report + + + + + + + + + + + Theoretical vs Attended Time Analysis + hr.attendance.theoretical.time.report + {'search_default_previous_month': 1, 'search_default_current_month': 1, 'search_default_my': 1} + pivot,graph + + + + + + + + + + + + + diff --git a/hr_attendance_report_theoretical_time/security/hr_attendance_report_theoretical_time_security.xml b/hr_attendance_report_theoretical_time/security/hr_attendance_report_theoretical_time_security.xml new file mode 100644 index 00000000..ae6b5cc5 --- /dev/null +++ b/hr_attendance_report_theoretical_time/security/hr_attendance_report_theoretical_time_security.xml @@ -0,0 +1,20 @@ + + + + + + Theoretical vs worked hours: Own attendances + + + [['employee_id.user_id', '=', user.id]] + + + + Theoretical vs worked hours: All attendances + + + [[1, '=', 1]] + + + diff --git a/hr_attendance_report_theoretical_time/security/ir.model.access.csv b/hr_attendance_report_theoretical_time/security/ir.model.access.csv new file mode 100644 index 00000000..02550ad1 --- /dev/null +++ b/hr_attendance_report_theoretical_time/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_hr_attendance_theoretical_time_report,access_hr_attendance_theoretical_time_report,model_hr_attendance_theoretical_time_report,hr_attendance.group_hr_attendance,1,0,0,0 diff --git a/hr_attendance_report_theoretical_time/static/description/icon.png b/hr_attendance_report_theoretical_time/static/description/icon.png new file mode 100644 index 00000000..4d9d1027 Binary files /dev/null and b/hr_attendance_report_theoretical_time/static/description/icon.png differ diff --git a/hr_attendance_report_theoretical_time/static/description/icon.svg b/hr_attendance_report_theoretical_time/static/description/icon.svg new file mode 100644 index 00000000..cb0ff83a --- /dev/null +++ b/hr_attendance_report_theoretical_time/static/description/icon.svg @@ -0,0 +1,141 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hr_attendance_report_theoretical_time/static/description/index.html b/hr_attendance_report_theoretical_time/static/description/index.html new file mode 100644 index 00000000..e50522f3 --- /dev/null +++ b/hr_attendance_report_theoretical_time/static/description/index.html @@ -0,0 +1,517 @@ + + + + + + +Theoretical vs Attended Time Analysis + + + +
+

Theoretical vs Attended Time Analysis

+ + +

Beta License: AGPL-3 OCA/hr-attendance Translate me on Weblate Try me on Runbot

+

This module adds a new report called “Theoretical vs Attended Time Analysis” +that compares worked time, measured through attendances records, with the +theoretical time, computed from employee’s working calendar, public holidays +and employee specific leaves. Missing attendance days are generated on the fly +in the report with their corresponding theoretical hours.

+

There is the possibility of counting as theoretical time some leave types if +specified in them.

+

As an example, imagine a work week with 40 theoretical hours, and these +attendance situation:

+
    +
  • Monday: Worked 10 hours
  • +
  • Tuesday: Worked 10 hours
  • +
  • Wednesday: Worked 10 hours
  • +
  • Thursday: Worked 10 hours
  • +
  • Friday: Ask for a compensation leave (said leave type), as already worked +40 hours.
  • +
+

On the report, whole week should put 40 theoretical hours - 8 per day - against +40 worked hours (although they were on previous days, and none on Friday).

+

On contrary, if you want to take a holiday one of that days, you should ask for +a leave type without the check for counting as theoretical time, and then the +whole week will be 32 theoretical hours against the worked hours of that week +without the leave.

+

Table of contents

+ +
+

Installation

+

On installation time, this module computes the theoretical hours for the day of +the attendance check-in, so if you have a lot of records, this would be a bit +slow.

+
+
+

Configuration

+

You need to be at least “Attendance / Manual Attendance” for being able to see +the attendances report.

+

For including some leave types in the theoretical time, you have to:

+
    +
  1. Go to Leaves > Configuration > Leave Types.
  2. +
  3. Select leave type you want to include.
  4. +
  5. Check the mark “Include in theoretical hours”.
  6. +
+

When generating non worked days, this module uses a start date for beginning +the series generation, which is:

+
    +
  • Manual start date set on the employee.
  • +
  • If not set, the greatest of these 2 dates:
      +
    • Employee creation date.
    • +
    • Working calendar line start date.
    • +
    +
  • +
+

For configuring manual start date, you have to:

+
    +
  1. Go to Employees > Employees.
  2. +
  3. Select an employee.
  4. +
  5. Go to “HR Settings” page.
  6. +
  7. Set the date in “Theoretical hours start date” field.
  8. +
+

The generation will stop on the end date of the working calendar line or today, +so don’t forget to properly set start and end dates of the lines of the working +calendar for not leaving empty spaces between them.

+
+
+

Usage

+
    +
  1. Go to Attendances > Reporting > Theoretical vs Attended Time Analysis.
  2. +
  3. Check pivot table or look at the graph view.
  4. +
+
+
+

Known issues / Roadmap

+
    +
  • Employees with less than 1 week in the company will show full week +theoretical hours.
  • +
  • Activate ORM cache for improving performance on computing theoretical hours, +but assuring that the cache is cleared when the conditions of the computation +changes.
  • +
  • If you change employee’s working time, theoretical hours for non attended +days will be computed according this new calendar. You have to define +start and end dates inside the calendar for avoiding this side effect.
  • +
  • Theoretical hours of affected days when changing the leave type to be +included or not in theoretical time are not recomputed.
  • +
+
+
+

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 smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+ +
+
+

Other credits

+

Images

+
    +
  • Font Awesome: Icon.
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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-attendance project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/hr_attendance_report_theoretical_time/tests/__init__.py b/hr_attendance_report_theoretical_time/tests/__init__.py new file mode 100644 index 00000000..2c657caf --- /dev/null +++ b/hr_attendance_report_theoretical_time/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import test_hr_attendance_report_theoretical_time diff --git a/hr_attendance_report_theoretical_time/tests/test_hr_attendance_report_theoretical_time.py b/hr_attendance_report_theoretical_time/tests/test_hr_attendance_report_theoretical_time.py new file mode 100644 index 00000000..d0a3bc32 --- /dev/null +++ b/hr_attendance_report_theoretical_time/tests/test_hr_attendance_report_theoretical_time.py @@ -0,0 +1,268 @@ +# Copyright 2017-2019 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.tests import common + + +class TestHrAttendanceReportTheoreticalTime(common.SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.HrLeave = cls.env["hr.leave"] + cls.HrHolidaysPublic = cls.env["hr.holidays.public"] + cls.HrLeaveType = cls.env["hr.leave.type"] + cls.calendar = cls.env["resource.calendar"].create( + {"name": "Test Calendar", "attendance_ids": False, "tz": "UTC"} + ) + for day in range(5): # From monday to friday + cls.calendar.attendance_ids = [ + ( + 0, + 0, + { + "name": "Attendance", + "dayofweek": str(day), + "hour_from": "08", + "hour_to": "12", + }, + ), + ( + 0, + 0, + { + "name": "Attendance", + "dayofweek": str(day), + "hour_from": "14", + "hour_to": "18", + }, + ), + ] + cls.address_1 = cls.env["res.partner"].create( + {"name": "Address 1", "country_id": cls.env.ref("base.uk").id} + ) + cls.address_2 = cls.env["res.partner"].create( + { + "name": "Address 1", + "country_id": cls.env.ref("base.es").id, + "state_id": cls.env.ref("base.state_es_cr").id, + } + ) + cls.employee_1 = cls.env["hr.employee"].create( + { + "name": "Employee 1", + "resource_calendar_id": cls.calendar.id, + "address_id": cls.address_1.id, + } + ) + cls.employee_2 = cls.env["hr.employee"].create( + { + "name": "Employee 2", + "resource_calendar_id": cls.calendar.id, + "address_id": cls.address_2.id, + } + ) + # Use a very old year for avoiding to collapse with current data + cls.public_holiday_global = cls.HrHolidaysPublic.create( + { + "year": 1946, + "line_ids": [(0, 0, {"name": "Christmas", "date": "1946-12-25"})], + } + ) + cls.public_holiday_country = cls.HrHolidaysPublic.create( + { + "year": 1946, + "country_id": cls.address_2.country_id.id, + "line_ids": [ + (0, 0, {"name": "Before Christmas", "date": "1946-12-24"}), + ( + 0, + 0, + { + "name": "Even More Before Christmas", + "date": "1946-12-23", + "state_ids": [(6, 0, cls.address_2.state_id.ids)], + }, + ), + ], + } + ) + cls.leave_type = cls.HrLeaveType.create( + { + "name": "Leave Type Test", + "exclude_public_holidays": True, + "allocation_type": "no", + "validity_start": False, + } + ) + # Remove timezone for controlling data better + cls.env.user.tz = False + # Force employee create_date for having auto-generated report entries + cls.env.cr.execute( + "UPDATE hr_employee SET create_date = %s " "WHERE id in %s", + ("1946-12-23 12:00:00", (cls.employee_1.id, cls.employee_2.id)), + ) + # Leave for employee 1 + cls.leave = cls.HrLeave.create( + { + "date_from": "1946-12-26 00:00:00", + "date_to": "1946-12-26 23:59:59", + "request_date_from": "1946-12-26", + "request_date_to": "1946-12-26", + "employee_id": cls.employee_1.id, + "holiday_status_id": cls.leave_type.id, + } + ) + cls.leave._onchange_request_parameters() + cls.leave.action_validate() + cls.attendances = [] + for employee in (cls.employee_1, cls.employee_2): + for day in range(23, 27): + cls.attendances.append( + cls.env["hr.attendance"].create( + { + "employee_id": employee.id, + "check_in": "1946-12-%s 08:00:00" % day, + "check_out": "1946-12-%s 12:00:00" % day, + } + ) + ) + cls.attendances.append( + cls.env["hr.attendance"].create( + { + "employee_id": employee.id, + "check_in": "1946-12-%s 14:00:00" % day, + "check_out": "1946-12-%s 18:00:00" % day, + } + ) + ) + + def test_theoretical_hours(self): + # EMPLOYEE 1 + # 1946-12-23 + self.assertEqual(self.attendances[0].theoretical_hours, 8) + self.assertEqual(self.attendances[1].theoretical_hours, 8) + # 1946-12-24 + self.assertEqual(self.attendances[2].theoretical_hours, 8) + self.assertEqual(self.attendances[3].theoretical_hours, 8) + # 1946-12-25 - Global public holiday + self.assertEqual(self.attendances[4].theoretical_hours, 0) + self.assertEqual(self.attendances[5].theoretical_hours, 0) + # 1946-12-26 - Employee on Holidays + self.assertEqual(self.attendances[6].theoretical_hours, 0) + self.assertEqual(self.attendances[7].theoretical_hours, 0) + # EMPLOYEE 2 + # 1946-12-23 - Public holidays for state of employee 2 + self.assertEqual(self.attendances[8].theoretical_hours, 0) + self.assertEqual(self.attendances[9].theoretical_hours, 0) + # 1946-12-24 - Public holiday for country of employee 2 + self.assertEqual(self.attendances[10].theoretical_hours, 0) + self.assertEqual(self.attendances[11].theoretical_hours, 0) + # 1946-12-25 - Global public holiday + self.assertEqual(self.attendances[12].theoretical_hours, 0) + self.assertEqual(self.attendances[13].theoretical_hours, 0) + # 1946-12-26 - Employee 2 leave + self.assertEqual(self.attendances[14].theoretical_hours, 8) + self.assertEqual(self.attendances[15].theoretical_hours, 8) + + def test_theoretical_hours_recompute(self): + """Change calendar, and then recompute with the wizard""" + # Get rid of 4 hours per day so the theoretical should be 4. + self.calendar.attendance_ids.filtered(lambda x: x.hour_from == 14.0).unlink() + # The attendances theoretical hours remain at 8 if not recomputed + self.assertEqual(self.attendances[0].theoretical_hours, 8) + self.assertEqual(self.attendances[1].theoretical_hours, 8) + # Then we run the wizard just for day 23 + wizard = self.env["recompute.theoretical.attendance"].create( + { + "employee_ids": [(4, self.employee_1.id)], + "date_from": "1946-12-23 00:00:00", + "date_to": "1946-12-23 23:59:59", + } + ) + wizard.action_recompute() + # Attendances for day 23 are recomputed + self.assertEqual(self.attendances[0].theoretical_hours, 4) + self.assertEqual(self.attendances[1].theoretical_hours, 4) + # Attendances for day 24 remaine as they were + self.assertEqual(self.attendances[2].theoretical_hours, 8) + self.assertEqual(self.attendances[3].theoretical_hours, 8) + + def test_hr_attendance_read_group(self): + # TODO: Test when having theoretical_hours_start_date set + # Group by employee + res = self.env["hr.attendance.theoretical.time.report"].read_group( + [ + ("date", ">=", "1946-12-23"), + ("date", "<", "1946-12-31"), + ("employee_id", "in", (self.employee_1.id, self.employee_2.id)), + ], + [ + "employee_id", + "theoretical_hours:sum", + "worked_hours:sum", + "difference:sum", + ], + ["employee_id"], + ) + # It should include 4 working days (25 is holiday and 26 is leave) + self.assertEqual(res[0]["theoretical_hours"], 32) + self.assertEqual(res[0]["worked_hours"], 32) + self.assertEqual(res[0]["difference"], 0) + # It should include 5 working days (25 is holiday) + self.assertEqual(res[1]["theoretical_hours"], 24) + self.assertEqual(res[1]["worked_hours"], 32) + self.assertEqual(res[1]["difference"], 8) + # Group by day + res = self.env["hr.attendance.theoretical.time.report"].read_group( + [ + ("date", ">=", "1946-12-23"), + ("date", "<", "1946-12-31"), + ("employee_id", "=", self.employee_1.id), + ], + ["employee_id", "theoretical_hours:sum", "date"], + ["date:day"], + ) + self.assertEqual(res[0]["theoretical_hours"], 8) # 1946-12-23 + self.assertEqual(res[1]["theoretical_hours"], 8) # 1946-12-24 + self.assertEqual(res[2]["theoretical_hours"], 0) # 1946-12-25 + self.assertEqual(res[3]["theoretical_hours"], 0) # 1946-12-26 + self.assertEqual(res[4]["theoretical_hours"], 8) # 1946-12-27(virtual) + self.assertEqual(res[5]["theoretical_hours"], 8) # 1946-12-30(virtual) + + def test_change_hr_holidays_public(self): + self.public_holiday_global.line_ids[0].write({"date": "1946-12-23"}) + # 1946-12-23 + self.assertEqual(self.attendances[0].theoretical_hours, 0) + self.assertEqual(self.attendances[8].theoretical_hours, 0) + # 1946-12-25 + self.assertEqual(self.attendances[4].theoretical_hours, 8) + self.assertEqual(self.attendances[12].theoretical_hours, 8) + + def test_change_hr_holidays(self): + self.leave.action_refuse() + # 1946-12-26 - Employee 2 + self.assertEqual(self.attendances[14].theoretical_hours, 8) + + def test_hr_holidays_status_include_in_theoretical(self): + obj = self.env["hr.attendance.theoretical.time.report"] + self.leave.holiday_status_id.include_in_theoretical = True + # 1946-12-26 - Employee 1 + a = self.attendances[6] + self.assertEqual(obj._theoretical_hours(a.employee_id, a.check_in), 8) + + def test_wizard_theoretical_time(self): + department = self.env["hr.department"].create({"name": "Department"}) + tag = self.env["hr.employee.category"].create({"name": "Tag"}) + self.employee_1.write( + {"department_id": department.id, "category_ids": [(4, tag.id)]} + ) + wizard = self.env["wizard.theoretical.time"].create( + {"department_id": department.id, "category_ids": [(4, tag.id)]} + ) + wizard.populate() + report = wizard.view_report() + self.assertTrue(wizard.employee_ids) + self.assertEqual(wizard.employee_ids[0].name, self.employee_1.name) + self.assertEqual( + report["domain"], [("employee_id", "in", [self.employee_1.id])] + ) diff --git a/hr_attendance_report_theoretical_time/views/hr_attendance_views.xml b/hr_attendance_report_theoretical_time/views/hr_attendance_views.xml new file mode 100644 index 00000000..a3feace4 --- /dev/null +++ b/hr_attendance_report_theoretical_time/views/hr_attendance_views.xml @@ -0,0 +1,15 @@ + + + + + hr.attendance.pivot - Don't show "Theoretical hours" measure + hr.attendance + + + + + + + + diff --git a/hr_attendance_report_theoretical_time/views/hr_employee_views.xml b/hr_attendance_report_theoretical_time/views/hr_employee_views.xml new file mode 100644 index 00000000..131e7eed --- /dev/null +++ b/hr_attendance_report_theoretical_time/views/hr_employee_views.xml @@ -0,0 +1,23 @@ + + + + + + hr.employee + + + + + + + + diff --git a/hr_attendance_report_theoretical_time/views/hr_leave_type_views.xml b/hr_attendance_report_theoretical_time/views/hr_leave_type_views.xml new file mode 100644 index 00000000..eddbed41 --- /dev/null +++ b/hr_attendance_report_theoretical_time/views/hr_leave_type_views.xml @@ -0,0 +1,12 @@ + + + + hr.leave.type + + + + + + + + diff --git a/hr_attendance_report_theoretical_time/wizards/__init__.py b/hr_attendance_report_theoretical_time/wizards/__init__.py new file mode 100644 index 00000000..84e8ebd9 --- /dev/null +++ b/hr_attendance_report_theoretical_time/wizards/__init__.py @@ -0,0 +1,2 @@ +from . import wizard_theoretical_time +from . import recompute_theoretical_attendance diff --git a/hr_attendance_report_theoretical_time/wizards/recompute_theoretical_attendance.py b/hr_attendance_report_theoretical_time/wizards/recompute_theoretical_attendance.py new file mode 100644 index 00000000..56e888f9 --- /dev/null +++ b/hr_attendance_report_theoretical_time/wizards/recompute_theoretical_attendance.py @@ -0,0 +1,33 @@ +# Copyright 2019 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class RecomputeTheoreticalAttendance(models.TransientModel): + _name = "recompute.theoretical.attendance" + _description = "Recompute Employees Attendances" + + employee_ids = fields.Many2many( + comodel_name="hr.employee", + required=True, + string="Employees", + help="Recompute these employees attendances", + ) + date_from = fields.Datetime( + string="From", required=True, help="Recompute attendances from this date" + ) + date_to = fields.Datetime( + string="To", required=True, help="Recompute attendances up to this date" + ) + + def action_recompute(self): + self.ensure_one() + attendances = self.env["hr.attendance"].search( + [ + ("employee_id", "in", self.employee_ids.ids), + ("check_in", ">=", self.date_from), + ("check_out", "<=", self.date_to), + ] + ) + attendances._compute_theoretical_hours() + return {"type": "ir.actions.act_window_close"} diff --git a/hr_attendance_report_theoretical_time/wizards/recompute_theoretical_attendance_views.xml b/hr_attendance_report_theoretical_time/wizards/recompute_theoretical_attendance_views.xml new file mode 100644 index 00000000..fb267905 --- /dev/null +++ b/hr_attendance_report_theoretical_time/wizards/recompute_theoretical_attendance_views.xml @@ -0,0 +1,40 @@ + + + + + Recompute Theoretical Attendances + recompute.theoretical.attendance + form + new + + + + recompute.theoretical.attendance + +
+ + + + + + + +
+
+
+
+
+ + + +
diff --git a/hr_attendance_report_theoretical_time/wizards/wizard_theoretical_time.py b/hr_attendance_report_theoretical_time/wizards/wizard_theoretical_time.py new file mode 100644 index 00000000..8ad67eae --- /dev/null +++ b/hr_attendance_report_theoretical_time/wizards/wizard_theoretical_time.py @@ -0,0 +1,55 @@ +# Copyright 2019 Creu Blanca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models + + +class WizardTheoreticalTime(models.TransientModel): + + _name = "wizard.theoretical.time" + _description = "Filtered Theoretical Time" + + employee_ids = fields.Many2many("hr.employee", string="Employees") + + department_id = fields.Many2one("hr.department", string="Department") + category_ids = fields.Many2many("hr.employee.category", string="Tag") + + @api.model + def default_get(self, fields): + res = super().default_get(fields) + if self.env.user.employee_ids: + res["department_id"] = self.env.user.employee_ids[0].department_id.id + return res + + def _prepare_employee_domain(self): + res = [] + if self.category_ids: + res.append(("category_ids", "in", self.category_ids.ids)) + if self.department_id: + res.append(("department_id", "child_of", self.department_id.id)) + return res + + def populate(self): + domain = self._prepare_employee_domain() + self.employee_ids = self.env["hr.employee"].search(domain) + action = { + "name": _("Select Employees to Analyze Theoretical Time"), + "type": "ir.actions.act_window", + "res_model": "wizard.theoretical.time", + "view_mode": "form", + "target": "new", + "res_id": self.id, + "context": self._context, + } + return action + + def view_report(self): + self.ensure_one() + action = { + "type": "ir.actions.act_window", + "name": "Theoretical vs Attended Time Analysis", + "res_model": "hr.attendance.theoretical.time.report", + "domain": [("employee_id", "in", self.employee_ids.ids)], + "view_mode": "pivot,graph", + } + return action diff --git a/hr_attendance_report_theoretical_time/wizards/wizard_theoretical_time.xml b/hr_attendance_report_theoretical_time/wizards/wizard_theoretical_time.xml new file mode 100644 index 00000000..2f7bc752 --- /dev/null +++ b/hr_attendance_report_theoretical_time/wizards/wizard_theoretical_time.xml @@ -0,0 +1,59 @@ + + + + + + + wizard.theoretical.time.form (in hr_attendance_report_theoretical_time) + wizard.theoretical.time + +
+ + + + + + + + +
+
+ + + + + + + + + + + + +
+
+
+
+
+ + + Select Employees to Analyze Theoretical Time + wizard.theoretical.time + form + {} + new + + + + +
diff --git a/oca_dependencies.txt b/oca_dependencies.txt new file mode 100644 index 00000000..573d7ab3 --- /dev/null +++ b/oca_dependencies.txt @@ -0,0 +1 @@ +hr-holidays