diff --git a/hr_timesheet_report/README.rst b/hr_timesheet_report/README.rst new file mode 100644 index 0000000000..1ef7a49f7a --- /dev/null +++ b/hr_timesheet_report/README.rst @@ -0,0 +1,124 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +========================== +Task Logs Timesheet Report +========================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:4e4a6b74c43b990d4b5ec0c9ecb577cdb297245f440406a4290977eb4fb75a7b + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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%2Ftimesheet-lightgray.png?logo=github + :target: https://github.com/OCA/timesheet/tree/19.0/hr_timesheet_report + :alt: OCA/timesheet +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/timesheet-19-0/timesheet-19-0-hr_timesheet_report + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/timesheet&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to generate configurable Timesheet Report from Task +Logs. + +Features: + + - Select reported fields + - Select and reorder report line grouping + - Configure time format (HH:MM, HH:MM:SS, or decimal) + - View in browser, export in PDF and XLSX formats + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To create report using Timesheet Report Wizard on a specific set of +Timesheet entries: + +1. Go to *Timesheets > My Timesheets* or *Timesheets > All timesheets*. +2. Select entries that should be used in the report +3. Press the *Action > Generate Timesheet Report* button +4. Configure the report and export it in one of the formats + +To create report using Timesheet Report Wizard on a generic set of +Timesheet entries: + +1. Go to *Timesheets > Reporting > Timesheet Report Wizard*. +2. Configure the report and export it in one of the formats + +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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* CorporateHub + +Contributors +------------ + +- Dhara Solanki +- `CorporateHub `__ + + - Alexey Pelykh + +- `Tecnativa `__: + + - Víctor Martínez + +- `Heliconia Solutions Pvt. Ltd. `__ + + - Bhavesh Heliconia + +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. + +.. |maintainer-alexey-pelykh| image:: https://github.com/alexey-pelykh.png?size=40px + :target: https://github.com/alexey-pelykh + :alt: alexey-pelykh + +Current `maintainer `__: + +|maintainer-alexey-pelykh| + +This module is part of the `OCA/timesheet `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/hr_timesheet_report/__init__.py b/hr_timesheet_report/__init__.py new file mode 100644 index 0000000000..8c4cde2890 --- /dev/null +++ b/hr_timesheet_report/__init__.py @@ -0,0 +1,5 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import models +from . import wizards +from . import report diff --git a/hr_timesheet_report/__manifest__.py b/hr_timesheet_report/__manifest__.py new file mode 100644 index 0000000000..3db55e3a16 --- /dev/null +++ b/hr_timesheet_report/__manifest__.py @@ -0,0 +1,26 @@ +# Copyright 2018-2020 Brainbean Apps (https://brainbeanapps.com) +# Copyright 2020 CorporateHub (https://corporatehub.eu) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +{ + "name": "Task Logs Timesheet Report", + "version": "19.0.1.0.0", + "category": "Human Resources", + "maintainers": ["alexey-pelykh"], + "website": "https://github.com/OCA/timesheet", + "author": "CorporateHub, Odoo Community Association (OCA)", + "license": "AGPL-3", + "installable": True, + "application": False, + "summary": "Generate Timesheet Report from Task Logs", + "depends": [ + "hr_timesheet", + "report_xlsx", + ], + "data": [ + "security/ir.model.access.csv", + "views/account_analytic_line.xml", + "report/hr_timesheet_report.xml", + "wizards/hr_timesheet_report_wizard.xml", + ], +} diff --git a/hr_timesheet_report/i18n/fr.po b/hr_timesheet_report/i18n/fr.po new file mode 100644 index 0000000000..d6c6d98141 --- /dev/null +++ b/hr_timesheet_report/i18n/fr.po @@ -0,0 +1,523 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_timesheet_report +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-09-05 17:07+0000\n" +"Last-Translator: Yves Le Doeuff \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 4.3.2\n" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "\"%s\" report type is not supported" +msgstr "\"%s\" n'est pas un type d'état supporté" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "\"%s\" report with \"%s\" type not found" +msgstr "L'état \"%s\" dont le type est \"%s\" est inconnu" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "%s not set" +msgstr "%s non paramétré" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Date Range:" +msgstr "Période:" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Timesheets Report" +msgstr "Etat des temps passés" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Subtotal" +msgstr "Sous-total" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__line_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__any_line_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__line_ids +msgid "Account Analytics Lines" +msgstr "Lignes d'analyse des comptes" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__aggregation +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__aggregation +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__aggregation +msgid "Aggregation" +msgstr "Agrégation" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_account_analytic_line +msgid "Analytic Line" +msgstr "Ligne analytique" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/wizards/hr_timesheet_report_wizard.py:0 +#, python-format +msgid "At least one Details field must be specified!" +msgstr "Au moins un champ Détails doit être spécifié !" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/wizards/hr_timesheet_report_wizard.py:0 +#, python-format +msgid "At least one field must be listed in Details Fields" +msgstr "Au moins un champ doit figurer dans la liste des champs détaillés" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "Cancel" +msgstr "Annuler" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__cell_classes +msgid "Cell classes" +msgstr "Classes de cellules" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__create_uid +msgid "Created by" +msgstr "Créé par" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__create_date +msgid "Created on" +msgstr "Créé le" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__department_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__department_ids +msgid "Departments" +msgstr "Départements" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Departments:" +msgstr "Départements:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__entry_field_ids +msgid "Details Fields" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_account_analytic_line__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_report_hr_timesheet_report_report__display_name +msgid "Display Name" +msgstr "Nom affiché" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__employee_category_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__employee_category_ids +msgid "Employee Tags" +msgstr "Etiquettes d'employé" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Employee Tags:" +msgstr "Etiquettes d'employé:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__employee_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__employee_ids +msgid "Employees" +msgstr "Employés" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Employees:" +msgstr "Employés:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__date_to +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__date_to +msgid "End Date" +msgstr "Date de fin" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__entry_ids +msgid "Entries" +msgstr "Entrées" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__entry_field_ids +msgid "Entry Fields" +msgstr "Champs de l'entrée" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "Export to PDF" +msgstr "Exporter en PDF" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "Export to XLSX" +msgstr "Exporter en XLSX" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__field_name +msgid "Field" +msgstr "Champ" + +#. module: hr_timesheet_report +#: model:ir.model.constraint,message:hr_timesheet_report.constraint_hr_timesheet_report_field_entry_field_name_uniq +#: model:ir.model.constraint,message:hr_timesheet_report.constraint_hr_timesheet_report_field_field_name_uniq +#: model:ir.model.constraint,message:hr_timesheet_report.constraint_hr_timesheet_report_field_groupby_field_name_uniq +msgid "Field can be reported only once!" +msgstr "Un champ ne peut figurer qu'une fois!" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__field_name +msgid "Field name" +msgstr "Nom du champ" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__field_title +msgid "Field title" +msgstr "Titre du champ" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__field_type +msgid "Field type" +msgstr "Type du champ" + +#. module: hr_timesheet_report +#: model:ir.actions.act_window,name:hr_timesheet_report.action_timesheet_report_wizard +#: model:ir.actions.server,name:hr_timesheet_report.action_timesheet_report_wizard_from_selection +msgid "Generate Timesheet Report" +msgstr "Générer l'état des feuilles de temps" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__group_id +msgid "Group" +msgstr "Groupe" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__groupby_field_ids +msgid "Group-By Fields" +msgstr "Champs de regroupement" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__groupby +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__groupby +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__groupby +msgid "Group-by expression" +msgstr "Expression de groupement" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__grouping_field_ids +msgid "Grouping Fields" +msgstr "Champs de regroupement" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__group_ids +msgid "Groups" +msgstr "Groupes" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report +msgid "HR Timesheet Report" +msgstr "Etat des feuilles de temps des RH" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard +msgid "HR Timesheet Report Wizard" +msgstr "Assistant de rapport de feuille de temps RH" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard_field +msgid "HR Timesheet Report Wizard field" +msgstr "Champ de l'assistant de rapport de feuille de temps RH" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard_field_details +msgid "HR Timesheet Report Wizard field (details)" +msgstr "Champ de l'assistant de rapport de feuille de temps RH (détails)" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard_field_grouping +msgid "HR Timesheet Report Wizard field (grouping)" +msgstr "Champ de l'assistant de rapport de feuille de temps RH (regroupement)" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_entry +msgid "HR Timesheet Report entry" +msgstr "HR Timesheet Report entry" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_field +msgid "HR Timesheet Report field" +msgstr "Champ du rapport de feuille de temps RH" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_field_entry +msgid "HR Timesheet Report field (entry)" +msgstr "Champ (entrée) du rapport de feuille de temps RH" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_field_groupby +msgid "HR Timesheet Report field (groupby)" +msgstr "Champ du rapport de feuille de temps RH (regroupement)" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_group +msgid "HR Timesheet Report group" +msgstr "Groupe de rapports sur les feuilles de temps RH" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__has_line_ids +msgid "Has lines (technical)" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_account_analytic_line__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_report_hr_timesheet_report_report__id +msgid "ID" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_account_analytic_line____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_report_hr_timesheet_report_report____last_update +msgid "Last Modified on" +msgstr "Dernière modification le" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__write_uid +msgid "Last Updated by" +msgstr "Dernière mise à jour par" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__write_date +msgid "Last Updated on" +msgstr "Dernière mise à jour le" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__name +msgid "Name" +msgstr "Nom" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__project_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__project_ids +msgid "Projects" +msgstr "Projets" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Projects:" +msgstr "Projets:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__report_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__report_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__report_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__report_id +msgid "Report" +msgstr "Rapport" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "Report %s" +msgstr "Rapport %s" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__scope +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__scope +msgid "Scope" +msgstr "Etendue" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__sequence +msgid "Sequence" +msgstr "Séquence" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__date_from +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__date_from +msgid "Start Date" +msgstr "Date de début" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__task_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__task_ids +msgid "Tasks" +msgstr "Tâches" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Tasks:" +msgstr "Tâches:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__time_format +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__time_format +msgid "Time format" +msgstr "Format horaire" + +#. module: hr_timesheet_report +#: model:ir.actions.report,name:hr_timesheet_report.action_report_qweb_html +#: model:ir.actions.report,name:hr_timesheet_report.action_report_qweb_pdf +#: model:ir.actions.report,name:hr_timesheet_report.action_report_xlsx +#: model:ir.model,name:hr_timesheet_report.model_report_hr_timesheet_report_report +msgid "Timesheet Report" +msgstr "Rapport sur les feuilles de temps" + +#. module: hr_timesheet_report +#: model:ir.ui.menu,name:hr_timesheet_report.menu_timesheet_report_wizard +msgid "Timesheet Report Wizard" +msgstr "Assistant de rapport de feuille de temps" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__field_title +msgid "Title" +msgstr "Titre" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "Total" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__total_unit_amount +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__total_unit_amount +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__total_unit_amount +msgid "Total Quantity" +msgstr "Qté Totale" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__field_type +msgid "Type" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "View" +msgstr "Vue" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__wizard_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__wizard_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__wizard_id +msgid "Wizard" +msgstr "Assistant" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "on" +msgstr "le" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "selected entries" +msgstr "entrées sélectionnées" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "since" +msgstr "depuis" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "until" +msgstr "jusqu'à" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "{l} » {r}" +msgstr "" diff --git a/hr_timesheet_report/i18n/hr_timesheet_report.pot b/hr_timesheet_report/i18n/hr_timesheet_report.pot new file mode 100644 index 0000000000..482a6233dc --- /dev/null +++ b/hr_timesheet_report/i18n/hr_timesheet_report.pot @@ -0,0 +1,496 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_timesheet_report +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.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_timesheet_report +#. odoo-python +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +msgid "\"%(report_name)s\" report with \"%(report_type)s\" type not found" +msgstr "" + +#. module: hr_timesheet_report +#. odoo-python +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +msgid "\"%(report_type)s\" report type is not supported" +msgstr "" + +#. module: hr_timesheet_report +#. odoo-python +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +msgid "%(field_title)s not set" +msgstr "" + +#. module: hr_timesheet_report +#. odoo-python +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +msgid "%(left)s » %(right)s" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Date Range:" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Timesheets Report" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Subtotal" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__line_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__any_line_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__line_ids +msgid "Account Analytics Lines" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__aggregation +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__aggregation +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__aggregation +msgid "Aggregation" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_account_analytic_line +msgid "Analytic Line" +msgstr "" + +#. module: hr_timesheet_report +#. odoo-python +#: code:addons/hr_timesheet_report/wizards/hr_timesheet_report_wizard.py:0 +msgid "At least one Details field must be specified!" +msgstr "" + +#. module: hr_timesheet_report +#. odoo-python +#: code:addons/hr_timesheet_report/wizards/hr_timesheet_report_wizard.py:0 +msgid "At least one field must be listed in Details Fields" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "Cancel" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__cell_classes +msgid "Cell classes" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__create_uid +msgid "Created by" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__create_date +msgid "Created on" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__department_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__department_ids +msgid "Departments" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Departments:" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__entry_field_ids +msgid "Details Fields" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__display_name +msgid "Display Name" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__employee_category_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__employee_category_ids +msgid "Employee Tags" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Employee Tags:" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__employee_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__employee_ids +msgid "Employees" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Employees:" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__date_to +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__date_to +msgid "End Date" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__entry_ids +msgid "Entries" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__entry_field_ids +msgid "Entry Fields" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "Export to PDF" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "Export to XLSX" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__field_name +msgid "Field" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.constraint,message:hr_timesheet_report.constraint_hr_timesheet_report_field_entry_field_name_uniq +#: model:ir.model.constraint,message:hr_timesheet_report.constraint_hr_timesheet_report_field_field_name_uniq +#: model:ir.model.constraint,message:hr_timesheet_report.constraint_hr_timesheet_report_field_groupby_field_name_uniq +msgid "Field can be reported only once!" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__field_name +msgid "Field name" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__field_title +msgid "Field title" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__field_type +msgid "Field type" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.actions.act_window,name:hr_timesheet_report.action_timesheet_report_wizard +#: model:ir.actions.server,name:hr_timesheet_report.action_timesheet_report_wizard_from_selection +msgid "Generate Timesheet Report" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__group_id +msgid "Group" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__groupby_field_ids +msgid "Group-By Fields" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__groupby +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__groupby +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__groupby +msgid "Group-by expression" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__grouping_field_ids +msgid "Grouping Fields" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__group_ids +msgid "Groups" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report +msgid "HR Timesheet Report" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard +msgid "HR Timesheet Report Wizard" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard_field +msgid "HR Timesheet Report Wizard field" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard_field_details +msgid "HR Timesheet Report Wizard field (details)" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard_field_grouping +msgid "HR Timesheet Report Wizard field (grouping)" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_entry +msgid "HR Timesheet Report entry" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_field +msgid "HR Timesheet Report field" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_field_entry +msgid "HR Timesheet Report field (entry)" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_field_groupby +msgid "HR Timesheet Report field (groupby)" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_group +msgid "HR Timesheet Report group" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__has_line_ids +msgid "Has lines (technical)" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__id +msgid "ID" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__write_date +msgid "Last Updated on" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__name +msgid "Name" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__project_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__project_ids +msgid "Projects" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Projects:" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__report_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__report_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__report_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__report_id +msgid "Report" +msgstr "" + +#. module: hr_timesheet_report +#. odoo-python +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +msgid "Report %(num)s" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__scope +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__scope +msgid "Scope" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__sequence +msgid "Sequence" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__date_from +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__date_from +msgid "Start Date" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__task_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__task_ids +msgid "Tasks" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Tasks:" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__time_format +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__time_format +msgid "Time format" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.actions.report,name:hr_timesheet_report.action_report_qweb_html +#: model:ir.actions.report,name:hr_timesheet_report.action_report_qweb_pdf +#: model:ir.actions.report,name:hr_timesheet_report.action_report_xlsx +#: model:ir.model,name:hr_timesheet_report.model_report_hr_timesheet_report_report +msgid "Timesheet Report" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.ui.menu,name:hr_timesheet_report.menu_timesheet_report_wizard +msgid "Timesheet Report Wizard" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__field_title +msgid "Title" +msgstr "" + +#. module: hr_timesheet_report +#. odoo-python +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +msgid "Total" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__total_unit_amount +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__total_unit_amount +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__total_unit_amount +msgid "Total Quantity" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__field_type +msgid "Type" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "View" +msgstr "" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__wizard_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__wizard_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__wizard_id +msgid "Wizard" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "on" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "selected entries" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "since" +msgstr "" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "until" +msgstr "" diff --git a/hr_timesheet_report/i18n/it.po b/hr_timesheet_report/i18n/it.po new file mode 100644 index 0000000000..3e40107d61 --- /dev/null +++ b/hr_timesheet_report/i18n/it.po @@ -0,0 +1,523 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_timesheet_report +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-12-31 20:35+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\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 4.17\n" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "\"%s\" report type is not supported" +msgstr "Tipo report \"%s\" non è supportato" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "\"%s\" report with \"%s\" type not found" +msgstr "Report \"%s\" con tipo \"%s\" non è stato trovato" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "%s not set" +msgstr "%s non impostato" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Date Range:" +msgstr "Periodo:" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Timesheets Report" +msgstr "Resoconto fogli ore" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Subtotal" +msgstr "Subtotale" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__line_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__any_line_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__line_ids +msgid "Account Analytics Lines" +msgstr "Righe conto analitico" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__aggregation +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__aggregation +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__aggregation +msgid "Aggregation" +msgstr "Aggregazione" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_account_analytic_line +msgid "Analytic Line" +msgstr "Riga analitica" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/wizards/hr_timesheet_report_wizard.py:0 +#, python-format +msgid "At least one Details field must be specified!" +msgstr "Almeno un campo Dettagli deve essere specificato!" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/wizards/hr_timesheet_report_wizard.py:0 +#, python-format +msgid "At least one field must be listed in Details Fields" +msgstr "Almeno un campo deve essere indicato in Campi Dettagli" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "Cancel" +msgstr "Annulla" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__cell_classes +msgid "Cell classes" +msgstr "Classi celle" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__department_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__department_ids +msgid "Departments" +msgstr "Dipartimenti" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Departments:" +msgstr "Dipartimenti:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__entry_field_ids +msgid "Details Fields" +msgstr "Campi Dettagli" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_account_analytic_line__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_report_hr_timesheet_report_report__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__employee_category_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__employee_category_ids +msgid "Employee Tags" +msgstr "Etichette dipendenti" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Employee Tags:" +msgstr "Etichette dipendenti:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__employee_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__employee_ids +msgid "Employees" +msgstr "Dipendenti" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Employees:" +msgstr "Dipendenti:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__date_to +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__date_to +msgid "End Date" +msgstr "Data fine" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__entry_ids +msgid "Entries" +msgstr "Voci" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__entry_field_ids +msgid "Entry Fields" +msgstr "Campi voci" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "Export to PDF" +msgstr "Esporta in PDF" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "Export to XLSX" +msgstr "Esporta in XLSX" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__field_name +msgid "Field" +msgstr "Campo" + +#. module: hr_timesheet_report +#: model:ir.model.constraint,message:hr_timesheet_report.constraint_hr_timesheet_report_field_entry_field_name_uniq +#: model:ir.model.constraint,message:hr_timesheet_report.constraint_hr_timesheet_report_field_field_name_uniq +#: model:ir.model.constraint,message:hr_timesheet_report.constraint_hr_timesheet_report_field_groupby_field_name_uniq +msgid "Field can be reported only once!" +msgstr "Un campo può essere indicato solo una volta!" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__field_name +msgid "Field name" +msgstr "Nome campo" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__field_title +msgid "Field title" +msgstr "Titolo campo" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__field_type +msgid "Field type" +msgstr "Tipo campo" + +#. module: hr_timesheet_report +#: model:ir.actions.act_window,name:hr_timesheet_report.action_timesheet_report_wizard +#: model:ir.actions.server,name:hr_timesheet_report.action_timesheet_report_wizard_from_selection +msgid "Generate Timesheet Report" +msgstr "Genera resoconto fogli ore" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__group_id +msgid "Group" +msgstr "Gruppo" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__groupby_field_ids +msgid "Group-By Fields" +msgstr "Campi Raggruppa per" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__groupby +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__groupby +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__groupby +msgid "Group-by expression" +msgstr "Espressione Raggruppa per" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__grouping_field_ids +msgid "Grouping Fields" +msgstr "Campi raggruppamento" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__group_ids +msgid "Groups" +msgstr "Gruppi" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report +msgid "HR Timesheet Report" +msgstr "Report fogli ore RU" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard +msgid "HR Timesheet Report Wizard" +msgstr "Procedura guidata foglio ore RU" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard_field +msgid "HR Timesheet Report Wizard field" +msgstr "Campo procedura guidata resoconto foglio ore RU" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard_field_details +msgid "HR Timesheet Report Wizard field (details)" +msgstr "Campo procedura guidata resoconto foglio ore RU (dettagli)" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard_field_grouping +msgid "HR Timesheet Report Wizard field (grouping)" +msgstr "Campo procedura guidata resoconto foglio ore RU (raggruppamento)" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_entry +msgid "HR Timesheet Report entry" +msgstr "Voce resoconto foglio ore RU" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_field +msgid "HR Timesheet Report field" +msgstr "Campo resoconto foglio ore RU" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_field_entry +msgid "HR Timesheet Report field (entry)" +msgstr "Campo resoconto foglio ore RU (voce)" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_field_groupby +msgid "HR Timesheet Report field (groupby)" +msgstr "Campo resoconto foglio ore RU (raggruppa per)" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_group +msgid "HR Timesheet Report group" +msgstr "Gruppo resoconto foglio ore RU" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__has_line_ids +msgid "Has lines (technical)" +msgstr "Ha delle righe (tecnico)" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_account_analytic_line__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_report_hr_timesheet_report_report__id +msgid "ID" +msgstr "ID" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_account_analytic_line____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_report_hr_timesheet_report_report____last_update +msgid "Last Modified on" +msgstr "Ultima modifica il" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__name +msgid "Name" +msgstr "Nome" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__project_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__project_ids +msgid "Projects" +msgstr "Progetti" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Projects:" +msgstr "Progetti:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__report_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__report_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__report_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__report_id +msgid "Report" +msgstr "Resoconto" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "Report %s" +msgstr "Resoconto %s" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__scope +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__scope +msgid "Scope" +msgstr "Scopo" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__sequence +msgid "Sequence" +msgstr "Sequenza" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__date_from +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__date_from +msgid "Start Date" +msgstr "Data inizio" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__task_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__task_ids +msgid "Tasks" +msgstr "Lavori" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Tasks:" +msgstr "Lavori:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__time_format +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__time_format +msgid "Time format" +msgstr "Formato ora" + +#. module: hr_timesheet_report +#: model:ir.actions.report,name:hr_timesheet_report.action_report_qweb_html +#: model:ir.actions.report,name:hr_timesheet_report.action_report_qweb_pdf +#: model:ir.actions.report,name:hr_timesheet_report.action_report_xlsx +#: model:ir.model,name:hr_timesheet_report.model_report_hr_timesheet_report_report +msgid "Timesheet Report" +msgstr "Report fogli ore" + +#. module: hr_timesheet_report +#: model:ir.ui.menu,name:hr_timesheet_report.menu_timesheet_report_wizard +msgid "Timesheet Report Wizard" +msgstr "Wizard report fogli ore" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__field_title +msgid "Title" +msgstr "Titolo" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "Total" +msgstr "Totale" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__total_unit_amount +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__total_unit_amount +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__total_unit_amount +msgid "Total Quantity" +msgstr "Quantità totale" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__field_type +msgid "Type" +msgstr "Tipo" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "View" +msgstr "Vista" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__wizard_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__wizard_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__wizard_id +msgid "Wizard" +msgstr "Procedura guidata" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "on" +msgstr "su" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "selected entries" +msgstr "voci selezionate" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "since" +msgstr "dal" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "until" +msgstr "al" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "{l} » {r}" +msgstr "{l} » {r}" diff --git a/hr_timesheet_report/i18n/pt.po b/hr_timesheet_report/i18n/pt.po new file mode 100644 index 0000000000..5316de68c9 --- /dev/null +++ b/hr_timesheet_report/i18n/pt.po @@ -0,0 +1,523 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_timesheet_report +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-08-19 18:07+0000\n" +"Last-Translator: Pedro Castro Silva \n" +"Language-Team: none\n" +"Language: pt\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 4.3.2\n" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "\"%s\" report type is not supported" +msgstr "o tipo de relatório \"%s\" não é suportado" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "\"%s\" report with \"%s\" type not found" +msgstr "relatório \"%s\" com o tipo \"%s\" não encontrado" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "%s not set" +msgstr "%s não definido" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Date Range:" +msgstr "Intervalo de datas:" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Timesheets Report" +msgstr "Relatório das Folhas de Horas" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Subtotal" +msgstr "Subtotal" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__line_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__any_line_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__line_ids +msgid "Account Analytics Lines" +msgstr "Linhas de Contas Analíticas" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__aggregation +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__aggregation +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__aggregation +msgid "Aggregation" +msgstr "Agregação" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_account_analytic_line +msgid "Analytic Line" +msgstr "Linha Analítica" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/wizards/hr_timesheet_report_wizard.py:0 +#, python-format +msgid "At least one Details field must be specified!" +msgstr "Pelo menos um campo de Detalhes deve ser especificado!" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/wizards/hr_timesheet_report_wizard.py:0 +#, python-format +msgid "At least one field must be listed in Details Fields" +msgstr "Pelo menos um campo deve ser listado em Campos de Detalhes" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "Cancel" +msgstr "Cancelar" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__cell_classes +msgid "Cell classes" +msgstr "Classes de células" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__create_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__create_uid +msgid "Created by" +msgstr "Criado por" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__create_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__create_date +msgid "Created on" +msgstr "Criado em" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__department_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__department_ids +msgid "Departments" +msgstr "Departamentos" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Departments:" +msgstr "Departamentos:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__entry_field_ids +msgid "Details Fields" +msgstr "Campos de Detalhes" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_account_analytic_line__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__display_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_report_hr_timesheet_report_report__display_name +msgid "Display Name" +msgstr "Nome a Apresentar" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__employee_category_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__employee_category_ids +msgid "Employee Tags" +msgstr "Etiquetas de Funcionários" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Employee Tags:" +msgstr "Etiquetas de Funcionários:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__employee_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__employee_ids +msgid "Employees" +msgstr "Funcionários" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Employees:" +msgstr "Empregados:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__date_to +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__date_to +msgid "End Date" +msgstr "Data Final" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__entry_ids +msgid "Entries" +msgstr "Entradas" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__entry_field_ids +msgid "Entry Fields" +msgstr "Campos de Entradas" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "Export to PDF" +msgstr "Exportação para PDF" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "Export to XLSX" +msgstr "Exportar para XLSX" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__field_name +msgid "Field" +msgstr "Campo" + +#. module: hr_timesheet_report +#: model:ir.model.constraint,message:hr_timesheet_report.constraint_hr_timesheet_report_field_entry_field_name_uniq +#: model:ir.model.constraint,message:hr_timesheet_report.constraint_hr_timesheet_report_field_field_name_uniq +#: model:ir.model.constraint,message:hr_timesheet_report.constraint_hr_timesheet_report_field_groupby_field_name_uniq +msgid "Field can be reported only once!" +msgstr "O campo só pode ser reportado uma vez!" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__field_name +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__field_name +msgid "Field name" +msgstr "Nome do campo" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__field_title +msgid "Field title" +msgstr "Título do campo" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__field_type +msgid "Field type" +msgstr "Tipo do campo" + +#. module: hr_timesheet_report +#: model:ir.actions.act_window,name:hr_timesheet_report.action_timesheet_report_wizard +#: model:ir.actions.server,name:hr_timesheet_report.action_timesheet_report_wizard_from_selection +msgid "Generate Timesheet Report" +msgstr "Gerar Relatório de Folha de Horas" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__group_id +msgid "Group" +msgstr "Grupo" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__groupby_field_ids +msgid "Group-By Fields" +msgstr "Campos de Agrupar Por" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__groupby +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__groupby +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__groupby +msgid "Group-by expression" +msgstr "Expressão de Agrupar Por" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__grouping_field_ids +msgid "Grouping Fields" +msgstr "Campos de Agrupamento" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__group_ids +msgid "Groups" +msgstr "Grupos" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report +msgid "HR Timesheet Report" +msgstr "Relatório de Folhas de Horas HR" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard +msgid "HR Timesheet Report Wizard" +msgstr "Assistente de Relatório de Folhas de Horas" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard_field +msgid "HR Timesheet Report Wizard field" +msgstr "Campo de Assistente de Relatório de Folhas de Horas" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard_field_details +msgid "HR Timesheet Report Wizard field (details)" +msgstr "Campo de Assistente de Relatório de Folhas de Horas (detalhes)" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_wizard_field_grouping +msgid "HR Timesheet Report Wizard field (grouping)" +msgstr "Campo de Assistente de Relatório de Folhas de Horas (agrupamento)" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_entry +msgid "HR Timesheet Report entry" +msgstr "Entrada do Relatório de Folhas de Horas" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_field +msgid "HR Timesheet Report field" +msgstr "Campo do Relatório de Folhas de Horas" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_field_entry +msgid "HR Timesheet Report field (entry)" +msgstr "Campo do Relatório de Folhas de Horas (entrada)" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_field_groupby +msgid "HR Timesheet Report field (groupby)" +msgstr "Campo do Relatório de Folhas de Horas (agrupar por)" + +#. module: hr_timesheet_report +#: model:ir.model,name:hr_timesheet_report.model_hr_timesheet_report_group +msgid "HR Timesheet Report group" +msgstr "Grupo do Relatório de Folhas de Horas" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__has_line_ids +msgid "Has lines (technical)" +msgstr "Tem linhas (técnicas)" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_account_analytic_line__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_report_hr_timesheet_report_report__id +msgid "ID" +msgstr "ID" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_account_analytic_line____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping____last_update +#: model:ir.model.fields,field_description:hr_timesheet_report.field_report_hr_timesheet_report_report____last_update +msgid "Last Modified on" +msgstr "Última Modificação em" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__write_uid +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__write_uid +msgid "Last Updated by" +msgstr "Última Actualização por" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__write_date +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__write_date +msgid "Last Updated on" +msgstr "Última Actualização em" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__name +msgid "Name" +msgstr "Nome" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__project_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__project_ids +msgid "Projects" +msgstr "Projetos" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Projects:" +msgstr "Projetos:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__report_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__report_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__report_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__report_id +msgid "Report" +msgstr "Relatório" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "Report %s" +msgstr "Relatório %s" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__scope +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__scope +msgid "Scope" +msgstr "Âmbito" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_entry__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_field_groupby__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__sequence +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__sequence +msgid "Sequence" +msgstr "Sequência" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__date_from +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__date_from +msgid "Start Date" +msgstr "Data de Início" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__task_ids +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__task_ids +msgid "Tasks" +msgstr "Tarefas" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "Tasks:" +msgstr "Tarefas:" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__time_format +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard__time_format +msgid "Time format" +msgstr "Formato da Hora" + +#. module: hr_timesheet_report +#: model:ir.actions.report,name:hr_timesheet_report.action_report_qweb_html +#: model:ir.actions.report,name:hr_timesheet_report.action_report_qweb_pdf +#: model:ir.actions.report,name:hr_timesheet_report.action_report_xlsx +#: model:ir.model,name:hr_timesheet_report.model_report_hr_timesheet_report_report +msgid "Timesheet Report" +msgstr "Relatório de Folhas de Horas" + +#. module: hr_timesheet_report +#: model:ir.ui.menu,name:hr_timesheet_report.menu_timesheet_report_wizard +msgid "Timesheet Report Wizard" +msgstr "Assistente de Relatório de Folhas de Horas" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__field_title +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__field_title +msgid "Title" +msgstr "Título" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "Total" +msgstr "Total" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report__total_unit_amount +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_entry__total_unit_amount +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_group__total_unit_amount +msgid "Total Quantity" +msgstr "Quantidade Total" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__field_type +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__field_type +msgid "Type" +msgstr "Tipo" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.hr_timesheet_report_wizard_form +msgid "View" +msgstr "Ver" + +#. module: hr_timesheet_report +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field__wizard_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_details__wizard_id +#: model:ir.model.fields,field_description:hr_timesheet_report.field_hr_timesheet_report_wizard_field_grouping__wizard_id +msgid "Wizard" +msgstr "Assistente" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "on" +msgstr "em" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "selected entries" +msgstr "entradas selecionadas" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "since" +msgstr "desde" + +#. module: hr_timesheet_report +#: model_terms:ir.ui.view,arch_db:hr_timesheet_report.report +msgid "until" +msgstr "até" + +#. module: hr_timesheet_report +#: code:addons/hr_timesheet_report/report/hr_timesheet_report.py:0 +#, python-format +msgid "{l} » {r}" +msgstr "" diff --git a/hr_timesheet_report/models/__init__.py b/hr_timesheet_report/models/__init__.py new file mode 100644 index 0000000000..9776396461 --- /dev/null +++ b/hr_timesheet_report/models/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import account_analytic_line diff --git a/hr_timesheet_report/models/account_analytic_line.py b/hr_timesheet_report/models/account_analytic_line.py new file mode 100644 index 0000000000..fd6b00f92f --- /dev/null +++ b/hr_timesheet_report/models/account_analytic_line.py @@ -0,0 +1,19 @@ +# Copyright 2018-2020 Brainbean Apps (https://brainbeanapps.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import Command, models + + +class AccountAnalyticLine(models.Model): + _inherit = "account.analytic.line" + + def action_timesheet_report_wizard(self): + return { + "type": "ir.actions.act_window", + "res_model": "hr.timesheet.report.wizard", + "views": [[False, "form"]], + "target": "new", + "context": { + "default_line_ids": [Command.set(self.ids)], + }, + } diff --git a/hr_timesheet_report/pyproject.toml b/hr_timesheet_report/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/hr_timesheet_report/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/hr_timesheet_report/readme/CONTRIBUTORS.md b/hr_timesheet_report/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..8e541e4e02 --- /dev/null +++ b/hr_timesheet_report/readme/CONTRIBUTORS.md @@ -0,0 +1,7 @@ +- Dhara Solanki \ +- [CorporateHub](https://corporatehub.eu/) + - Alexey Pelykh \ +- [Tecnativa](https://www.tecnativa.com): + - Víctor Martínez +- [Heliconia Solutions Pvt. Ltd.](https://www.heliconia.io) + - Bhavesh Heliconia diff --git a/hr_timesheet_report/readme/DESCRIPTION.md b/hr_timesheet_report/readme/DESCRIPTION.md new file mode 100644 index 0000000000..609d8034f7 --- /dev/null +++ b/hr_timesheet_report/readme/DESCRIPTION.md @@ -0,0 +1,9 @@ +This module allows to generate configurable Timesheet Report from Task +Logs. + +Features: + +> - Select reported fields +> - Select and reorder report line grouping +> - Configure time format (HH:MM, HH:MM:SS, or decimal) +> - View in browser, export in PDF and XLSX formats diff --git a/hr_timesheet_report/readme/USAGE.md b/hr_timesheet_report/readme/USAGE.md new file mode 100644 index 0000000000..df67780d20 --- /dev/null +++ b/hr_timesheet_report/readme/USAGE.md @@ -0,0 +1,14 @@ +To create report using Timesheet Report Wizard on a specific set of +Timesheet entries: + +1. Go to *Timesheets \> My Timesheets* or *Timesheets \> All + timesheets*. +2. Select entries that should be used in the report +3. Press the *Action \> Generate Timesheet Report* button +4. Configure the report and export it in one of the formats + +To create report using Timesheet Report Wizard on a generic set of +Timesheet entries: + +1. Go to *Timesheets \> Reporting \> Timesheet Report Wizard*. +2. Configure the report and export it in one of the formats diff --git a/hr_timesheet_report/report/__init__.py b/hr_timesheet_report/report/__init__.py new file mode 100644 index 0000000000..9200c14400 --- /dev/null +++ b/hr_timesheet_report/report/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import hr_timesheet_report diff --git a/hr_timesheet_report/report/hr_timesheet_report.py b/hr_timesheet_report/report/hr_timesheet_report.py new file mode 100644 index 0000000000..06a173a5c8 --- /dev/null +++ b/hr_timesheet_report/report/hr_timesheet_report.py @@ -0,0 +1,670 @@ +# Copyright 2018-2020 Brainbean Apps (https://brainbeanapps.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import html +from functools import reduce + +from xlsxwriter.utility import xl_rowcol_to_cell + +from odoo import Command, api, fields, models +from odoo.exceptions import UserError +from odoo.tools.safe_eval import safe_eval + + +class HrTimesheetReport(models.TransientModel): + _name = "hr.timesheet.report" + _description = "HR Timesheet Report" + + line_ids = fields.Many2many( + string="Account Analytics Lines", + comodel_name="account.analytic.line", + ) + date_from = fields.Date( + string="Start Date", + ) + date_to = fields.Date( + string="End Date", + ) + project_ids = fields.Many2many( + string="Projects", + comodel_name="project.project", + ) + task_ids = fields.Many2many( + string="Tasks", + comodel_name="project.task", + ) + employee_ids = fields.Many2many( + string="Employees", + comodel_name="hr.employee", + ) + employee_category_ids = fields.Many2many( + string="Employee Tags", + comodel_name="hr.employee.category", + ) + department_ids = fields.Many2many( + string="Departments", + comodel_name="hr.department", + ) + groupby_field_ids = fields.One2many( + string="Group-By Fields", + comodel_name="hr.timesheet.report.field.groupby", + inverse_name="report_id", + ) + entry_field_ids = fields.One2many( + string="Entry Fields", + comodel_name="hr.timesheet.report.field.entry", + inverse_name="report_id", + ) + time_format = fields.Selection( + string="Time format", + selection=lambda self: self._selection_time_format(), + required=True, + ) + group_ids = fields.One2many( + string="Groups", + comodel_name="hr.timesheet.report.group", + inverse_name="report_id", + compute="_compute_group_ids", + store=True, + ) + total_unit_amount = fields.Float( + string="Total Quantity", + compute="_compute_total_unit_amount", + store=True, + ) + + @api.model + def _selection_time_format(self): + return [ + ("hh_mm", "Hours, minutes"), + ("hh_mm_ss", "Hours, minutes, seconds"), + ("decimal", "Decimal"), + ] + + @api.model + def _supported_report_types(self): + return [ + "qweb-html", + "qweb-pdf", + "xlsx", + ] + + @api.depends( + "line_ids", + "date_from", + "date_to", + "project_ids", + "task_ids", + "employee_ids", + "employee_category_ids", + "department_ids", + "groupby_field_ids", + "entry_field_ids", + ) + def _compute_group_ids(self): + AccountAnalyticLine = self.env["account.analytic.line"] + + for report in self: + group_ids = [Command.clear()] + + if report.groupby_field_ids: + domain = report._get_domain() + grouped_lines = AccountAnalyticLine.formatted_read_group( + domain=domain, + groupby=report.groupby_field_ids.mapped("groupby"), + aggregates=["__count"], + order=", ".join( + report.groupby_field_ids.mapped("groupby"), + ), + ) + + for group_data in grouped_lines: + # Provide __domain for backward compatibility with _get_group_values + group_data["__domain"] = domain + group_data.get( + "__extra_domain", [] + ) + group_values = report._get_group_values(group_data) + if not group_values: + continue + + group_values.update( + { + "sequence": len(group_ids), + } + ) + group_ids.append(Command.create(group_values)) + else: + group_ids.append( + Command.create( + { + "sequence": len(group_ids), + "name": None, + "scope": str(report._get_domain()), + } + ) + ) + report.group_ids = group_ids + + def _get_group_values(self, grouped_lines): + self.ensure_one() + + name_parts = [] + for field in self.groupby_field_ids: + name_part = grouped_lines.get(field.field_name, None) + if not name_part: + name_part = self.env._( + "%(field_title)s not set", field_title=field.field_title + ) + else: + name_part = name_part[1] + name_parts.append(name_part) + + return { + "name": reduce( + lambda left, right: self.env._( + "%(left)s » %(right)s", + left=left, + right=right, + ), + name_parts, + ), + "scope": str(grouped_lines["__domain"]), + } + + @api.depends("group_ids.total_unit_amount") + def _compute_total_unit_amount(self): + for report in self: + report.total_unit_amount = sum(report.group_ids.mapped("total_unit_amount")) + + def _get_domain(self): + self.ensure_one() + + if self.line_ids: + return [("id", "in", self.line_ids.ids)] + + query = [("project_id", "!=", False)] + if self.date_from: + query.append(("date", ">=", fields.Date.to_string(self.date_from))) + if self.date_to: + query.append(("date", "<=", fields.Date.to_string(self.date_to))) + if self.project_ids: + query.append(("project_id", "in", self.project_ids.ids)) + if self.task_ids: + query.append(("task_id", "in", self.task_ids.ids)) + employee_ids = self.employee_ids | self.employee_category_ids.mapped( + "employee_ids" + ) + if employee_ids: + query.append(("employee_id", "in", employee_ids.ids)) + if self.department_ids: + query.append(("department_id", "in", self.department_ids.ids)) + return query + + def get_action(self, report_type="qweb-html"): + self.ensure_one() + + if report_type not in self._supported_report_types(): + raise UserError( + self.env._( + '"%(report_type)s" report type is not supported', + report_type=report_type, + ) + ) + + report_name = "hr_timesheet_report.report" + + action = self.env["ir.actions.report"].search( + [ + ("model", "=", self._name), + ("report_name", "=", report_name), + ("report_type", "=", report_type), + ], + limit=1, + ) + if not action: + raise UserError( + self.env._( + '"%(report_name)s" report with "%(report_type)s" type not found', + report_name=report_name, + report_type=report_type, + ) + ) + + context = dict(self.env.context) + return action.with_context(**context).report_action(self) + + +class HrTimesheetReportAbstractField(models.AbstractModel): + _name = "hr.timesheet.report.field" + _description = "HR Timesheet Report field" + _order = "sequence, id" + + report_id = fields.Many2one( + string="Report", + comodel_name="hr.timesheet.report", + required=True, + ondelete="cascade", + ) + sequence = fields.Integer( + required=True, + ) + field_name = fields.Char( + string="Field name", + required=True, + ) + field_title = fields.Char( + string="Field title", + required=True, + ) + field_type = fields.Char( + string="Field type", + required=True, + ) + aggregation = fields.Char() + groupby = fields.Char( + string="Group-by expression", + compute="_compute_groupby", + ) + + _field_name_uniq = models.Constraint( + "UNIQUE(report_id, field_name)", + "Field can be reported only once!", + ) + + @api.depends("field_name", "aggregation", "field_type") + def _compute_groupby(self): + for field in self: + if field.aggregation: + field.groupby = f"{field.field_name}:{field.aggregation}" + elif field.field_type in ("date", "datetime"): + field.groupby = f"{field.field_name}:day" + else: + field.groupby = field.field_name + + +class HrTimesheetReportGroupByField(models.TransientModel): + _name = "hr.timesheet.report.field.groupby" + _description = "HR Timesheet Report field (groupby)" + _inherit = "hr.timesheet.report.field" + + +class HrTimesheetReportEntryField(models.TransientModel): + _name = "hr.timesheet.report.field.entry" + _description = "HR Timesheet Report field (entry)" + _inherit = "hr.timesheet.report.field" + + cell_classes = fields.Char( + string="Cell classes", + compute="_compute_cell_classes", + ) + + @api.depends("field_type") + def _compute_cell_classes(self): + for field in self: + field.cell_classes = " ".join(field._get_cell_classes(field.field_type)) + + def _get_cell_classes(self, field_type): + self.ensure_one() + + return [] if field_type == "char" else ["text-nowrap"] + + +class HrTimesheetReportGroup(models.TransientModel): + _name = "hr.timesheet.report.group" + _description = "HR Timesheet Report group" + _order = "sequence, id" + + report_id = fields.Many2one( + string="Report", + comodel_name="hr.timesheet.report", + required=True, + ondelete="cascade", + ) + sequence = fields.Integer( + required=True, + ) + scope = fields.Char() + name = fields.Char() + entry_ids = fields.One2many( + string="Entries", + comodel_name="hr.timesheet.report.entry", + inverse_name="group_id", + compute="_compute_entry_ids", + store=True, + ) + total_unit_amount = fields.Float( + string="Total Quantity", + compute="_compute_total_unit_amount", + store=True, + ) + + @api.depends( + "scope", + "report_id.groupby_field_ids", + "report_id.entry_field_ids", + ) + def _compute_entry_ids(self): + AccountAnalyticLine = self.env["account.analytic.line"] + + for group in self: + domain = safe_eval(group.scope) if group.scope else [] + grouped_lines = AccountAnalyticLine.formatted_read_group( + domain=domain, + groupby=group.report_id.entry_field_ids.mapped("groupby"), + aggregates=["__count"], + order=", ".join( + group.report_id.entry_field_ids.mapped("groupby"), + ), + ) + + entry_ids = [Command.clear()] + for entry_data in grouped_lines: + entry_data["__domain"] = domain + entry_data.get("__extra_domain", []) + entry_values = group._get_entry_values(entry_data) + if not entry_values: + continue + + entry_values.update( + { + "sequence": len(entry_ids), + } + ) + entry_ids.append(Command.create(entry_values)) + group.entry_ids = entry_ids + + @api.depends("entry_ids.total_unit_amount") + def _compute_total_unit_amount(self): + for group in self: + group.total_unit_amount = sum(group.entry_ids.mapped("total_unit_amount")) + + def _get_entry_values(self, grouped_lines): + """Use the domain if it exists or the id (in case there is only one record).""" + self.ensure_one() + return { + "scope": ( + str(grouped_lines["__domain"]) + if "__domain" in grouped_lines + else [("id", "=", grouped_lines["id"])] + ) + } + + +class HrTimesheetReportEntry(models.TransientModel): + _name = "hr.timesheet.report.entry" + _description = "HR Timesheet Report entry" + _order = "sequence, id" + + group_id = fields.Many2one( + string="Group", + comodel_name="hr.timesheet.report.group", + required=True, + ondelete="cascade", + ) + sequence = fields.Integer( + required=True, + ) + scope = fields.Char() + any_line_id = fields.Many2one( + string="Account Analytics Lines", + comodel_name="account.analytic.line", + compute="_compute_any_line_id", + ) + total_unit_amount = fields.Float( + string="Total Quantity", + compute="_compute_total_unit_amount", + store=True, + ) + + @api.depends("scope") + def _compute_any_line_id(self): + AccountAnalyticLine = self.env["account.analytic.line"] + + for entry in self: + entry.any_line_id = AccountAnalyticLine.search( + safe_eval(entry.scope) if entry.scope else [], + limit=1, + ) + + @api.depends("scope") + def _compute_total_unit_amount(self): + AccountAnalyticLine = self.env["account.analytic.line"] + uom_hour = self.env.ref("uom.product_uom_hour") + + for entry in self: + total_unit_amount = 0.0 + line_ids = AccountAnalyticLine.search( + safe_eval(entry.scope) if entry.scope else [] + ) + for line_id in line_ids: + total_unit_amount += line_id.product_uom_id._compute_quantity( + line_id.unit_amount, uom_hour + ) + entry.total_unit_amount = total_unit_amount + + def render_value(self, field_name): + self.ensure_one() + + AccountAnalyticLine = self.env["account.analytic.line"] + + fields = AccountAnalyticLine.fields_get() + converter_model = "ir.qweb.field." + fields[field_name]["type"] + converter = self.env.get(converter_model, self.env["ir.qweb.field"]) + + return converter.record_to_html(self.any_line_id, field_name, {}) + + +class Report(models.AbstractModel): + _name = "report.hr_timesheet_report.report" + _inherit = "report.report_xlsx.abstract" + _description = "Timesheet Report" + + @api.model + def _get_report_values(self, docids, data=None): + docs = self.env["hr.timesheet.report"].browse(docids) + + return { + "doc_ids": docids, + "doc_model": "hr.timesheet.report", + "docs": docs, + } + + @api.model + def generate_xlsx_report(self, workbook, data, docs): + uom_hour = self.env.ref("uom.product_uom_hour") + + for report_index, report in enumerate(docs): + sheet = workbook.add_worksheet( + self.env._("Report %(num)s", num=report_index + 1) + ) + + formats = self._create_workbook_formats(report, workbook) + + amount_column_index = len(report.entry_field_ids) + + for column_index, entry_field in enumerate(report.entry_field_ids): + sheet.write( + 0, column_index, entry_field.field_title, formats["header_title"] + ) + sheet.write(0, amount_column_index, uom_hour.name, formats["header_title"]) + sheet.freeze_panes(1, 0) + rows_emitted = 1 + + section_row_indices = [] + for group in report.group_ids: + if group.name: + section_row_indices.append(rows_emitted) + + if amount_column_index > 1: + sheet.merge_range( + rows_emitted, + 0, + rows_emitted, + amount_column_index - 1, + group.name, + formats["section_title"], + ) + else: + sheet.write( + rows_emitted, 0, group.name, formats["section_title"] + ) + # ruff: noqa: E501 + sheet.write_formula( + rows_emitted, + amount_column_index, + f"=SUM(" + f"{xl_rowcol_to_cell(rows_emitted + 1, amount_column_index)}:" + f"{xl_rowcol_to_cell(rows_emitted + len(group.entry_ids), amount_column_index)}" + f")", + formats["section_total"], + self._convert_amount_num_format( + report, group.total_unit_amount + ), + ) + rows_emitted += 1 + + for entry in group.entry_ids: + for column_index, entry_field in enumerate(report.entry_field_ids): + self._render_value_cell( + rows_emitted, + column_index, + sheet, + formats, + entry, + entry_field, + ) + sheet.write_number( + rows_emitted, + amount_column_index, + self._convert_amount_num_format( + report, entry.total_unit_amount + ), + formats["entry_total"], + ) + + rows_emitted += 1 + + rows_emitted += 1 + + if amount_column_index > 1: + sheet.merge_range( + rows_emitted, + 0, + rows_emitted, + amount_column_index - 1, + self.env._("Total"), + formats["report_total_caption"], + ) + else: + sheet.write( + rows_emitted, + 0, + self.env._("Total"), + formats["report_total_caption"], + ) + if section_row_indices: + # ruff: noqa: E501 + sheet.write_formula( + rows_emitted, + amount_column_index, + f"=SUM({'+'.join(map(lambda x: xl_rowcol_to_cell(x, amount_column_index), section_row_indices))})", + formats["report_total_amount"], + self._convert_amount_num_format(report, report.total_unit_amount), + ) + else: + sheet.write_formula( + rows_emitted, + amount_column_index, + f"=SUM({xl_rowcol_to_cell(1, amount_column_index)}:" + f"{xl_rowcol_to_cell(rows_emitted - 2, amount_column_index)})", + formats["report_total_amount"], + self._convert_amount_num_format(report, report.total_unit_amount), + ) + + @api.model + def _create_workbook_formats(self, report, workbook): + amount_num_format = self._get_amount_num_format(report) + + return { + "header_title": workbook.add_format( + { + "bold": True, + "align": "center", + "valign": "vcenter", + } + ), + "section_title": workbook.add_format( + { + "italic": True, + } + ), + "section_total": workbook.add_format( + { + "num_format": amount_num_format, + "italic": True, + } + ), + "report_total_caption": workbook.add_format( + { + "bold": True, + "align": "right", + } + ), + "report_total_amount": workbook.add_format( + { + "num_format": amount_num_format, + "bold": True, + } + ), + "cell_generic": workbook.add_format( + { + "align": "left", + } + ), + "cell_date": workbook.add_format( + { + "num_format": "d mmm yyyy", + "align": "left", + } + ), + "cell_datetime": workbook.add_format( + { + "num_format": "d mmm yyyy hh:mm", + "align": "left", + } + ), + "entry_total": workbook.add_format( + { + "num_format": amount_num_format, + } + ), + } + + @api.model + def _get_amount_num_format(self, report): + if report.time_format == "decimal": + return "0.00" + elif report.time_format == "hh_mm": + return "[h]:mm" + elif report.time_format == "hh_mm_ss": + return "[h]:mm:ss" + + @api.model + def _convert_amount_num_format(self, report, amount): + if report.time_format in ["hh_mm", "hh_mm_ss"]: + return amount / 24.0 + return amount + + @api.model + def _render_value_cell(self, row, col, sheet, formats, entry, field): + raw_value = entry.any_line_id[field.field_name] + value = entry.render_value(field.field_name) + if field.field_type == "datetime": + sheet.write_datetime(row, col, raw_value, formats["cell_datetime"]) + elif field.field_type == "date": + sheet.write_datetime(row, col, raw_value, formats["cell_date"]) + elif field.field_type in ("monetary", "float", "integer"): + sheet.write_number(row, col, raw_value or 0, formats["cell_generic"]) + else: + if not isinstance(value, str): + value = str(value) if value or value == 0 else "" + sheet.write(row, col, html.unescape(value), formats["cell_generic"]) diff --git a/hr_timesheet_report/report/hr_timesheet_report.xml b/hr_timesheet_report/report/hr_timesheet_report.xml new file mode 100644 index 0000000000..38b69e41a6 --- /dev/null +++ b/hr_timesheet_report/report/hr_timesheet_report.xml @@ -0,0 +1,255 @@ + + + + + + + + Timesheet Report + hr.timesheet.report + qweb-pdf + hr_timesheet_report.report + Timesheet Report + + + + Timesheet Report + hr.timesheet.report + qweb-html + hr_timesheet_report.report + Timesheet Report + + + + Timesheet Report + hr.timesheet.report + xlsx + hr_timesheet_report.report + Timesheet Report + + diff --git a/hr_timesheet_report/security/ir.model.access.csv b/hr_timesheet_report/security/ir.model.access.csv new file mode 100644 index 0000000000..d9956f30f9 --- /dev/null +++ b/hr_timesheet_report/security/ir.model.access.csv @@ -0,0 +1,10 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_hr_timesheet_report_wizard_user,hr_timesheet_report_wizard.user,model_hr_timesheet_report_wizard,hr_timesheet.group_hr_timesheet_user,1,1,1,1 +access_hr_timesheet_report_field_user,hr_timesheet_report_field.user,model_hr_timesheet_report_field,hr_timesheet.group_hr_timesheet_user,1,1,1,1 +access_hr_timesheet_report_field_groupby_user,hr_timesheet_report_field_groupby.user,model_hr_timesheet_report_field_groupby,hr_timesheet.group_hr_timesheet_user,1,1,1,1 +access_hr_timesheet_report_field_entry_user,hr_timesheet_report_field_entry.user,model_hr_timesheet_report_field_entry,hr_timesheet.group_hr_timesheet_user,1,1,1,1 +access_hr_timesheet_report_group_user,hr_timesheet_report_group.user,model_hr_timesheet_report_group,hr_timesheet.group_hr_timesheet_user,1,1,1,1 +access_hr_timesheet_report_entry_user,hr_timesheet_report_entry.user,model_hr_timesheet_report_entry,hr_timesheet.group_hr_timesheet_user,1,1,1,1 +access_hr_timesheet_report_wizard_field_details_user,hr_timesheet_report_wizard_field_details.user,model_hr_timesheet_report_wizard_field_details,hr_timesheet.group_hr_timesheet_user,1,1,1,1 +access_hr_timesheet_report_user,hr_timesheet_report.user,model_hr_timesheet_report,hr_timesheet.group_hr_timesheet_user,1,1,1,1 +access_hr_timesheet_report_wizard_field_grouping_user,hr_timesheet_report_wizard_field_grouping.user,model_hr_timesheet_report_wizard_field_grouping,hr_timesheet.group_hr_timesheet_user,1,1,1,1 diff --git a/hr_timesheet_report/static/description/icon.png b/hr_timesheet_report/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/hr_timesheet_report/static/description/icon.png differ diff --git a/hr_timesheet_report/static/description/index.html b/hr_timesheet_report/static/description/index.html new file mode 100644 index 0000000000..4d44576251 --- /dev/null +++ b/hr_timesheet_report/static/description/index.html @@ -0,0 +1,471 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Task Logs Timesheet Report

+ +

Beta License: AGPL-3 OCA/timesheet Translate me on Weblate Try me on Runboat

+

This module allows to generate configurable Timesheet Report from Task +Logs.

+

Features:

+
+
    +
  • Select reported fields
  • +
  • Select and reorder report line grouping
  • +
  • Configure time format (HH:MM, HH:MM:SS, or decimal)
  • +
  • View in browser, export in PDF and XLSX formats
  • +
+
+

Table of contents

+ +
+

Usage

+

To create report using Timesheet Report Wizard on a specific set of +Timesheet entries:

+
    +
  1. Go to Timesheets > My Timesheets or Timesheets > All timesheets.
  2. +
  3. Select entries that should be used in the report
  4. +
  5. Press the Action > Generate Timesheet Report button
  6. +
  7. Configure the report and export it in one of the formats
  8. +
+

To create report using Timesheet Report Wizard on a generic set of +Timesheet entries:

+
    +
  1. Go to Timesheets > Reporting > Timesheet Report Wizard.
  2. +
  3. Configure the report and export it in one of the formats
  4. +
+
+
+

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

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • CorporateHub
  • +
+
+
+

Contributors

+ +
+
+

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.

+

Current maintainer:

+

alexey-pelykh

+

This module is part of the OCA/timesheet project on GitHub.

+

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

+
+
+
+
+ + diff --git a/hr_timesheet_report/tests/__init__.py b/hr_timesheet_report/tests/__init__.py new file mode 100644 index 0000000000..bd6526d74d --- /dev/null +++ b/hr_timesheet_report/tests/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import test_hr_timesheet_report +from . import test_hr_timesheet_report_wizard diff --git a/hr_timesheet_report/tests/test_hr_timesheet_report.py b/hr_timesheet_report/tests/test_hr_timesheet_report.py new file mode 100644 index 0000000000..19146e075e --- /dev/null +++ b/hr_timesheet_report/tests/test_hr_timesheet_report.py @@ -0,0 +1,467 @@ +# Copyright 2018-2020 Brainbean Apps (https://brainbeanapps.com) +# Copyright 2024 Tecnativa - Victor Martínez +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from unittest.mock import MagicMock, patch + +from psycopg2 import IntegrityError + +from odoo import Command, fields +from odoo.exceptions import UserError +from odoo.tests import Form +from odoo.tools import mute_logger + +from odoo.addons.base.tests.common import BaseCommon + + +class TestHrTimesheetReportBase(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.today = fields.Date.today() + cls.IrActionReport = cls.env["ir.actions.report"] + cls.Wizard = cls.env["hr.timesheet.report.wizard"] + cls.project = cls.env["project.project"].create({"name": "Project"}) + cls.employee = cls.env["hr.employee"].create({"name": "Employee"}) + cls.timesheet_1 = cls.env["account.analytic.line"].create( + { + "project_id": cls.project.id, + "name": "Time Entry", + "employee_id": cls.employee.id, + "date": cls.today, + "unit_amount": 1, + } + ) + + def _create_report_from_wizard(self, wizard): + return self.env["hr.timesheet.report"].create(wizard._collect_report_values()) + + +class TestHrTimesheetReport(TestHrTimesheetReportBase): + @mute_logger("odoo.models.unlink") + def test_html_export(self): + wizard_form = Form(self.Wizard) + wizard_form.employee_ids.add(self.employee) + wizard = wizard_form.save() + self.assertTrue(wizard.grouping_field_ids) + self.assertTrue(wizard.entry_field_ids) + wizard.action_export_html() + report = self._create_report_from_wizard(wizard) + self.IrActionReport._render_qweb_html("hr_timesheet_report.report", report.ids) + + @mute_logger("odoo.models.unlink") + def test_pdf_export(self): + wizard_form = Form(self.Wizard) + wizard_form.employee_ids.add(self.employee) + wizard = wizard_form.save() + self.assertTrue(wizard.grouping_field_ids) + self.assertTrue(wizard.entry_field_ids) + wizard.action_export_pdf() + report = self._create_report_from_wizard(wizard) + self.IrActionReport._render_qweb_html("hr_timesheet_report.report", report.ids) + + @mute_logger("odoo.models.unlink") + def test_xlsx_export(self): + wizard_form = Form(self.Wizard) + wizard_form.employee_ids.add(self.employee) + wizard = wizard_form.save() + self.assertTrue(wizard.grouping_field_ids) + self.assertTrue(wizard.entry_field_ids) + report = self._create_report_from_wizard(wizard) + self.IrActionReport._render_xlsx("hr_timesheet_report.report", report.ids, None) + + @mute_logger("odoo.models.unlink") + def test_no_grouping(self): + wizard_form = Form( + self.Wizard.with_context(default_grouping_field_ids=[Command.clear()]) + ) + wizard_form.date_from = self.today + wizard_form.date_to = self.today + wizard_form.employee_ids.add(self.employee) + wizard = wizard_form.save() + self.assertFalse(wizard.grouping_field_ids) + self.assertTrue(wizard.entry_field_ids) + report = self._create_report_from_wizard(wizard) + self.assertEqual(len(report.group_ids), 1) + self.assertEqual(report.total_unit_amount, 1) + + +class TestHrTimesheetReportMultiProject(TestHrTimesheetReportBase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.extra_project = cls.env["project.project"].create({"name": "Extra Project"}) + cls.timesheet_2 = cls.env["account.analytic.line"].create( + { + "project_id": cls.extra_project.id, + "name": "Time Entry 2", + "employee_id": cls.employee.id, + "date": cls.today, + "unit_amount": 2, + } + ) + + @mute_logger("odoo.models.unlink") + def test_multi_project_01(self): + entries = self.timesheet_1 + self.timesheet_2 + res = entries.action_timesheet_report_wizard() + wizard_form = Form(self.env[res["res_model"]].with_context(**res["context"])) + wizard = wizard_form.save() + self.assertTrue(wizard.grouping_field_ids) + self.assertTrue(wizard.entry_field_ids) + report = self._create_report_from_wizard(wizard) + self.assertEqual(len(report.group_ids), 2) + self.assertEqual(len(report.line_ids), 2) + self.assertIn(self.timesheet_1, report.line_ids) + self.assertIn(self.timesheet_2, report.line_ids) + self.assertEqual(report.total_unit_amount, 3) + + @mute_logger("odoo.models.unlink") + def test_multi_project_02(self): + wizard_form = Form(self.Wizard) + wizard_form.date_from = self.today + wizard_form.date_to = self.today + wizard_form.employee_ids.add(self.employee) + wizard = wizard_form.save() + self.assertTrue(wizard.grouping_field_ids) + self.assertTrue(wizard.entry_field_ids) + report = self._create_report_from_wizard(wizard) + self.assertEqual(len(report.group_ids), 2) + self.assertEqual(report.total_unit_amount, 3) + + +class TestAccountAnalyticLineTimesheetWizardAction(TestHrTimesheetReportMultiProject): + @mute_logger("odoo.models.unlink") + def test_action_timesheet_report_wizard_action_dict(self): + # Single entry + res = self.timesheet_1.action_timesheet_report_wizard() + self.assertEqual(res["type"], "ir.actions.act_window") + self.assertEqual(res["res_model"], "hr.timesheet.report.wizard") + self.assertEqual(res["views"], [[False, "form"]]) + self.assertEqual(res["target"], "new") + self.assertEqual( + res["context"].get("default_line_ids"), + [Command.set([self.timesheet_1.id])], + ) + wizard_form = Form(self.env[res["res_model"]].with_context(**res["context"])) + wizard = wizard_form.save() + self.assertEqual(wizard.line_ids, self.timesheet_1) + + # Multiple entries + entries = self.timesheet_1 + self.timesheet_2 + res = entries.action_timesheet_report_wizard() + self.assertEqual(res["type"], "ir.actions.act_window") + self.assertEqual(res["res_model"], "hr.timesheet.report.wizard") + self.assertEqual(res["views"], [[False, "form"]]) + self.assertEqual(res["target"], "new") + default_line_ids = res["context"].get("default_line_ids") + self.assertTrue(default_line_ids) + self.assertEqual(default_line_ids[0][0], 6) + self.assertEqual(default_line_ids[0][1], False) + self.assertEqual(set(default_line_ids[0][2]), set(entries.ids)) + wizard_form = Form(self.env[res["res_model"]].with_context(**res["context"])) + wizard = wizard_form.save() + self.assertEqual(set(wizard.line_ids.ids), set(entries.ids)) + + +class TestHrTimesheetReportExtraCoverage(TestHrTimesheetReportBase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.Report = cls.env["hr.timesheet.report"] + cls.GroupByField = cls.env["hr.timesheet.report.field.groupby"] + cls.EntryField = cls.env["hr.timesheet.report.field.entry"] + cls.Group = cls.env["hr.timesheet.report.group"] + cls.Entry = cls.env["hr.timesheet.report.entry"] + cls.ReportXlsx = cls.env["report.hr_timesheet_report.report"] + + def _create_min_report(self, **vals): + vals.setdefault("time_format", "decimal") + return self.Report.create(vals) + + @mute_logger("odoo.models.unlink") + def test_supported_report_types_and_time_format_selection(self): + report = self._create_min_report() + self.assertIn("qweb-html", report._supported_report_types()) + self.assertIn("xlsx", report._supported_report_types()) + selection = report._selection_time_format() + self.assertIn(("decimal", "Decimal"), selection) + + @mute_logger("odoo.models.unlink") + def test_get_domain_line_ids_priority(self): + report = self._create_min_report(line_ids=[Command.set([self.timesheet_1.id])]) + self.assertEqual(report._get_domain(), [("id", "in", [self.timesheet_1.id])]) + + @mute_logger("odoo.models.unlink") + def test_get_action_unsupported_type_raises(self): + report = self._create_min_report(line_ids=[Command.set([self.timesheet_1.id])]) + with self.assertRaises(UserError): + report.get_action("nope") + + @mute_logger("odoo.models.unlink") + def test_get_action_report_not_found_raises(self): + report = self._create_min_report(line_ids=[Command.set([self.timesheet_1.id])]) + IrActionsReportModel = type(self.env["ir.actions.report"]) + + def _fake_search(self, domain, limit=None, **kwargs): + # return empty recordset => triggers "not found" + return self.browse() + + with patch.object(IrActionsReportModel, "search", _fake_search): + with self.assertRaises(UserError): + report.get_action("qweb-html") + + @mute_logger("odoo.models.unlink") + def test_get_group_values_not_set_and_separator(self): + report = self._create_min_report(line_ids=[Command.set([self.timesheet_1.id])]) + self.GroupByField.create( + { + "report_id": report.id, + "sequence": 10, + "field_name": "project_id", + "field_title": "Project", + "field_type": "many2one", + } + ) + self.GroupByField.create( + { + "report_id": report.id, + "sequence": 20, + "field_name": "employee_id", + "field_title": "Employee", + "field_type": "many2one", + } + ) + vals = report._get_group_values( + { + "project_id": False, + "employee_id": False, + "__domain": [("id", "in", [self.timesheet_1.id])], + } + ) + self.assertIn("not set", vals["name"]) + self.assertIn("»", vals["name"]) + self.assertTrue(vals["scope"]) + + @mute_logger("odoo.models.unlink") + def test_field_groupby_compute_with_and_without_aggregation(self): + report = self._create_min_report(line_ids=[Command.set([self.timesheet_1.id])]) + f1 = self.EntryField.create( + { + "report_id": report.id, + "sequence": 10, + "field_name": "unit_amount", + "field_title": "Qty", + "field_type": "float", + "aggregation": "sum", + } + ) + self.assertEqual(f1.groupby, "unit_amount:sum") + f2 = self.EntryField.create( + { + "report_id": report.id, + "sequence": 20, + "field_name": "name", + "field_title": "Name", + "field_type": "char", + } + ) + self.assertEqual(f2.groupby, "name") + + @mute_logger("odoo.models.unlink") + def test_field_name_unique_sql_constraint(self): + report = self._create_min_report(line_ids=[Command.set([self.timesheet_1.id])]) + self.EntryField.create( + { + "report_id": report.id, + "sequence": 10, + "field_name": "name", + "field_title": "Name", + "field_type": "char", + } + ) + with mute_logger("odoo.sql_db"): + with self.assertRaises(IntegrityError): + self.EntryField.create( + { + "report_id": report.id, + "sequence": 20, + "field_name": "name", # duplicate in same report + "field_title": "Name 2", + "field_type": "char", + } + ) + + @mute_logger("odoo.models.unlink") + def test_entry_field_cell_classes(self): + report = self._create_min_report(line_ids=[Command.set([self.timesheet_1.id])]) + char_f = self.EntryField.create( + { + "report_id": report.id, + "sequence": 10, + "field_name": "name", + "field_title": "Desc", + "field_type": "char", + } + ) + self.assertEqual(char_f.cell_classes, "") + non_char_f = self.EntryField.create( + { + "report_id": report.id, + "sequence": 20, + "field_name": "unit_amount", + "field_title": "Qty", + "field_type": "float", + } + ) + self.assertEqual(non_char_f.cell_classes, "text-nowrap") + + @mute_logger("odoo.models.unlink") + def test_group_get_entry_values_domain_vs_id(self): + report = self._create_min_report(line_ids=[Command.set([self.timesheet_1.id])]) + group = self.Group.create( + { + "report_id": report.id, + "sequence": 10, + "name": "G", + "scope": str([("id", "in", [self.timesheet_1.id])]), + } + ) + vals = group._get_entry_values({"__domain": [("id", "=", self.timesheet_1.id)]}) + self.assertEqual(vals["scope"], str([("id", "=", self.timesheet_1.id)])) + vals = group._get_entry_values({"id": self.timesheet_1.id}) + self.assertEqual(vals["scope"], [("id", "=", self.timesheet_1.id)]) + + @mute_logger("odoo.models.unlink") + def test_xlsx_amount_num_format_and_convert(self): + report = self._create_min_report(time_format="decimal") + self.assertEqual(self.ReportXlsx._get_amount_num_format(report), "0.00") + self.assertEqual(self.ReportXlsx._convert_amount_num_format(report, 2.5), 2.5) + report.time_format = "hh_mm" + self.assertEqual(self.ReportXlsx._get_amount_num_format(report), "[h]:mm") + self.assertEqual(self.ReportXlsx._convert_amount_num_format(report, 24.0), 1.0) + report.time_format = "hh_mm_ss" + self.assertEqual(self.ReportXlsx._get_amount_num_format(report), "[h]:mm:ss") + self.assertEqual(self.ReportXlsx._convert_amount_num_format(report, 48.0), 2.0) + + +class TestHrTimesheetReportExtraBranches(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.today = fields.Date.today() + cls.Report = cls.env["hr.timesheet.report"] + cls.GroupByField = cls.env["hr.timesheet.report.field.groupby"] + cls.EntryField = cls.env["hr.timesheet.report.field.entry"] + cls.ReportXlsx = cls.env["report.hr_timesheet_report.report"] + cls.project = cls.env["project.project"].create({"name": "P"}) + cls.employee = cls.env["hr.employee"].create({"name": "E"}) + cls.department = cls.env["hr.department"].create({"name": "D"}) + cls.employee.department_id = cls.department + cls.task = cls.env["project.task"].create( + {"name": "T", "project_id": cls.project.id} + ) + cls.employee_tag = cls.env["hr.employee.category"].create({"name": "Tag"}) + cls.employee.category_ids = [Command.link(cls.employee_tag.id)] + cls.timesheet = cls.env["account.analytic.line"].create( + { + "project_id": cls.project.id, + "task_id": cls.task.id, + "name": "Time Entry", + "employee_id": cls.employee.id, + "date": cls.today, + "unit_amount": 1, + } + ) + + def _entry_field_cmd(self): + return [ + Command.create( + { + "sequence": 10, + "field_name": "name", + "field_title": "Name", + "field_type": "char", + }, + ) + ] + + @mute_logger("odoo.models.unlink") + def test_compute_group_ids_skips_empty_group_values(self): + report = self.Report.create( + { + "time_format": "decimal", + "line_ids": [Command.set([self.timesheet.id])], + "entry_field_ids": self._entry_field_cmd(), + "groupby_field_ids": [ + Command.create( + { + "sequence": 10, + "field_name": "project_id", + "field_title": "Project", + "field_type": "many2one", + }, + ) + ], + } + ) + ReportModel = type(self.env["hr.timesheet.report"]) + with patch.object(ReportModel, "_get_group_values", return_value={}): + report._compute_group_ids() + self.assertFalse(report.group_ids) + + @mute_logger("odoo.models.unlink") + def test_get_domain_includes_project_task_employee_department(self): + report = self.Report.create( + { + "time_format": "decimal", + "date_from": self.today, + "date_to": self.today, + "project_ids": [Command.set([self.project.id])], + "task_ids": [Command.set([self.task.id])], + "employee_category_ids": [Command.set([self.employee_tag.id])], + "department_ids": [Command.set([self.department.id])], + "entry_field_ids": self._entry_field_cmd(), + } + ) + domain = report._get_domain() + self.assertIn(("project_id", "in", [self.project.id]), domain) + self.assertIn(("task_id", "in", [self.task.id]), domain) + self.assertIn(("employee_id", "in", [self.employee.id]), domain) + self.assertIn(("department_id", "in", [self.department.id]), domain) + + @mute_logger("odoo.models.unlink") + def test_generate_xlsx_report_total_without_sections(self): + report = self.Report.create( + { + "time_format": "decimal", + "line_ids": [Command.set([self.timesheet.id])], + "groupby_field_ids": [ + Command.clear() + ], # no grouping => group.name == None + # len == 1 => amount_column_index == 1 + "entry_field_ids": self._entry_field_cmd(), + } + ) + _ = report.group_ids + for g in report.group_ids: + _ = g.entry_ids + workbook = MagicMock() + sheet = MagicMock() + workbook.add_worksheet.return_value = sheet + workbook.add_format.return_value = object() + self.ReportXlsx.generate_xlsx_report(workbook, None, report) + + # 1) "Total" written via sheet.write (because amount_column_index == 1) + total_calls = [ + c + for c in sheet.write.call_args_list + if len(c.args) >= 3 and c.args[2] == "Total" + ] + self.assertTrue(total_calls) + + # 2) else branch formula with ":" range + formula_calls = [ + c for c in sheet.write_formula.call_args_list if ":" in str(c.args[2]) + ] + self.assertTrue(formula_calls) diff --git a/hr_timesheet_report/tests/test_hr_timesheet_report_wizard.py b/hr_timesheet_report/tests/test_hr_timesheet_report_wizard.py new file mode 100644 index 0000000000..f685c94df1 --- /dev/null +++ b/hr_timesheet_report/tests/test_hr_timesheet_report_wizard.py @@ -0,0 +1,82 @@ +from odoo import Command +from odoo.exceptions import UserError, ValidationError +from odoo.tools import mute_logger + +from odoo.addons.base.tests.common import BaseCommon + + +class TestHrTimesheetReportWizardExtra(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.Wizard = cls.env["hr.timesheet.report.wizard"] + + def _entry_field_cmd(self): + return [ + Command.create( + { + "sequence": 10, + "field_name": "name", + "field_title": "Name", + "field_type": "char", + } + ) + ] + + @mute_logger("odoo.models.unlink") + def test_create_sets_empty_grouping_if_missing(self): + wizard = self.Wizard.create( + { + "entry_field_ids": self._entry_field_cmd(), + } + ) + self.assertFalse(wizard.grouping_field_ids) + self.assertEqual(len(wizard.entry_field_ids), 1) + + @mute_logger("odoo.models.unlink") + def test_create_without_entry_fields_raises_usererror(self): + with self.assertRaises(UserError): + self.Wizard.create({}) + + @mute_logger("odoo.models.unlink") + def test_constrains_entry_field_ids_empty_raises_validationerror(self): + with self.assertRaises(ValidationError): + self.Wizard.create( + { + "grouping_field_ids": [Command.clear()], + "entry_field_ids": [ + Command.clear() + ], # key exists, but empty => constraint + } + ) + + @mute_logger("odoo.models.unlink") + def test_action_export_html_target_main_when_no_lines(self): + wizard = self.Wizard.create( + { + "grouping_field_ids": [Command.clear()], + "entry_field_ids": [ + Command.create( + { + "sequence": 10, + "field_name": "name", + "field_title": "Name", + "field_type": "char", + } + ) + ], + } + ) + action = wizard.action_export_html() + self.assertEqual(action.get("target"), "main") + + @mute_logger("odoo.models.unlink") + def test_action_export_xlsx_calls_generate_report(self): + wizard = self.Wizard.create( + { + "grouping_field_ids": [Command.clear()], + "entry_field_ids": self._entry_field_cmd(), + } + ) + action = wizard.action_export_xlsx() + self.assertIsInstance(action, dict) diff --git a/hr_timesheet_report/views/account_analytic_line.xml b/hr_timesheet_report/views/account_analytic_line.xml new file mode 100644 index 0000000000..1fcc6dc8f0 --- /dev/null +++ b/hr_timesheet_report/views/account_analytic_line.xml @@ -0,0 +1,22 @@ + + + + + + Generate Timesheet Report + ir.actions.server + + + code + + if records: + action = records.action_timesheet_report_wizard() + + + diff --git a/hr_timesheet_report/wizards/__init__.py b/hr_timesheet_report/wizards/__init__.py new file mode 100644 index 0000000000..3b412c86c4 --- /dev/null +++ b/hr_timesheet_report/wizards/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import hr_timesheet_report_wizard diff --git a/hr_timesheet_report/wizards/hr_timesheet_report_wizard.py b/hr_timesheet_report/wizards/hr_timesheet_report_wizard.py new file mode 100644 index 0000000000..cb414c61f7 --- /dev/null +++ b/hr_timesheet_report/wizards/hr_timesheet_report_wizard.py @@ -0,0 +1,260 @@ +# Copyright 2018-2020 Brainbean Apps (https://brainbeanapps.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import Command, api, fields, models +from odoo.exceptions import UserError, ValidationError + + +class HrTimesheetReportWizard(models.TransientModel): + _name = "hr.timesheet.report.wizard" + _description = "HR Timesheet Report Wizard" + + line_ids = fields.Many2many( + string="Account Analytics Lines", + comodel_name="account.analytic.line", + ) + has_line_ids = fields.Boolean( + string="Has lines (technical)", + compute="_compute_has_line_ids", + ) + date_from = fields.Date( + string="Start Date", + ) + date_to = fields.Date( + string="End Date", + ) + project_ids = fields.Many2many( + string="Projects", + comodel_name="project.project", + ) + task_ids = fields.Many2many( + string="Tasks", + comodel_name="project.task", + ) + employee_ids = fields.Many2many( + string="Employees", + comodel_name="hr.employee", + ) + employee_category_ids = fields.Many2many( + string="Employee Tags", + comodel_name="hr.employee.category", + ) + department_ids = fields.Many2many( + string="Departments", + comodel_name="hr.department", + ) + grouping_field_ids = fields.One2many( + string="Grouping Fields", + comodel_name="hr.timesheet.report.wizard.field.grouping", + inverse_name="wizard_id", + default=lambda self: self._default_grouping_field_ids(), + ) + entry_field_ids = fields.One2many( + string="Details Fields", + comodel_name="hr.timesheet.report.wizard.field.details", + inverse_name="wizard_id", + default=lambda self: self._default_entry_field_ids(), + ) + time_format = fields.Selection( + string="Time format", + selection=lambda self: self._selection_time_format(), + required=True, + default=lambda self: self._selection_time_format()[0][0], + ) + + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + if "grouping_field_ids" not in vals: + # In order to avoid empty set being replaced with default value: + vals.update( + { + "grouping_field_ids": [Command.clear()], + } + ) + if "entry_field_ids" not in vals: + raise UserError( + self.env._("At least one Details field must be specified!") + ) + return super().create(vals_list) + + @api.model + def _default_grouping_field_ids(self): + return list(map(Command.create, self._get_default_grouping_fields())) + + @api.model + def _get_default_grouping_fields(self): + return [ + { + "sequence": 10, + "field_name": "project_id", + }, + { + "sequence": 20, + "field_name": "task_id", + }, + { + "sequence": 30, + "field_name": "employee_id", + }, + ] + + @api.model + def _default_entry_field_ids(self): + return list(map(Command.create, self._get_default_entry_fields())) + + @api.model + def _get_default_entry_fields(self): + return [ + { + "sequence": 10, + "field_name": "date", + }, + { + "sequence": 20, + "field_name": "name", + }, + ] + + @api.model + def _selection_time_format(self): + Report = self.env["hr.timesheet.report"] + return Report._selection_time_format() + + @api.constrains("entry_field_ids") + def _check_entry_field_ids(self): + for wizard in self: + if len(wizard.entry_field_ids) < 1: + raise ValidationError( + self.env._("At least one field must be listed in Details Fields") + ) + + @api.depends("line_ids") + def _compute_has_line_ids(self): + for wizard in self: + wizard.has_line_ids = len(wizard.line_ids) > 0 + + def action_export_html(self): + self.ensure_one() + + action = self._generate_report("qweb-html") + if not self.has_line_ids: + action.update( + { + "target": "main", + } + ) + + return action + + def action_export_pdf(self): + self.ensure_one() + return self._generate_report("qweb-pdf") + + def action_export_xlsx(self): + self.ensure_one() + return self._generate_report("xlsx") + + def _generate_report(self, report_type): + self.ensure_one() + report = self.env["hr.timesheet.report"].create(self._collect_report_values()) + return report.get_action(report_type) + + def _collect_report_values(self): + self.ensure_one() + return { + "line_ids": [Command.set(self.line_ids.ids)], + "date_from": self.date_from, + "date_to": self.date_to, + "project_ids": [Command.set(self.project_ids.ids)], + "task_ids": [Command.set(self.task_ids.ids)], + "employee_ids": [Command.set(self.employee_ids.ids)], + "employee_category_ids": [Command.set(self.employee_category_ids.ids)], + "department_ids": [Command.set(self.department_ids.ids)], + "groupby_field_ids": list( + map( + lambda x: Command.create(x._collect_report_values()), + self.grouping_field_ids, + ) + ), + "entry_field_ids": list( + map( + lambda x: Command.create(x._collect_report_values()), + self.entry_field_ids, + ) + ), + "time_format": self.time_format, + } + + +class HrTimesheetReportWizardField(models.AbstractModel): + _name = "hr.timesheet.report.wizard.field" + _description = "HR Timesheet Report Wizard field" + _order = "sequence, id" + + wizard_id = fields.Many2one( + string="Wizard", + comodel_name="hr.timesheet.report.wizard", + required=True, + ondelete="cascade", + ) + sequence = fields.Integer( + required=True, + default=10, + ) + field_name = fields.Selection( + string="Field", + selection="_selection_field_name", + required=True, + ) + field_title = fields.Char( + string="Title", + compute="_compute_field_title", + ) + field_type = fields.Char( + string="Type", + compute="_compute_field_type", + ) + + @api.model + def _selection_field_name(self): + fields = self.env["account.analytic.line"].fields_get().items() + return [(f, d.get("string")) for f, d in fields if self._field_selectable(f, d)] + + @api.model + def _field_selectable(self, field, definition): + return definition.get("store", True) + + @api.depends("field_name") + def _compute_field_title(self): + fields = self.env["account.analytic.line"].fields_get() + for field in self: + field.field_title = fields[field.field_name]["string"] + + @api.depends("field_name") + def _compute_field_type(self): + fields = self.env["account.analytic.line"].fields_get() + for field in self: + field.field_type = fields[field.field_name]["type"] + + def _collect_report_values(self): + self.ensure_one() + return { + "sequence": self.sequence, + "field_name": self.field_name, + "field_title": self.field_title, + "field_type": self.field_type, + "aggregation": ("day" if self.field_type in ["datetime", "date"] else None), + } + + +class HrTimesheetReportWizardGroupingField(models.TransientModel): + _name = "hr.timesheet.report.wizard.field.grouping" + _description = "HR Timesheet Report Wizard field (grouping)" + _inherit = "hr.timesheet.report.wizard.field" + + +class HrTimesheetReportWizardDetailsField(models.TransientModel): + _name = "hr.timesheet.report.wizard.field.details" + _description = "HR Timesheet Report Wizard field (details)" + _inherit = "hr.timesheet.report.wizard.field" diff --git a/hr_timesheet_report/wizards/hr_timesheet_report_wizard.xml b/hr_timesheet_report/wizards/hr_timesheet_report_wizard.xml new file mode 100644 index 0000000000..80b9903a62 --- /dev/null +++ b/hr_timesheet_report/wizards/hr_timesheet_report_wizard.xml @@ -0,0 +1,89 @@ + + + + + hr.timesheet.report.wizard.form + hr.timesheet.report.wizard + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + Generate Timesheet Report + ir.actions.act_window + hr.timesheet.report.wizard + form + new + + + +