diff --git a/hr_employee_calendar_planning/README.rst b/hr_employee_calendar_planning/README.rst new file mode 100644 index 00000000000..1c9fec23858 --- /dev/null +++ b/hr_employee_calendar_planning/README.rst @@ -0,0 +1,137 @@ +========================== +Employee Calendar Planning +========================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fhr-lightgray.png?logo=github + :target: https://github.com/OCA/hr/tree/15.0/hr_employee_calendar_planning + :alt: OCA/hr +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/hr-15-0/hr-15-0-hr_employee_calendar_planning + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/116/15.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to manage employee working time with profiles by date +intervals. + +The profiles are regular working time calendars, but they are treated as +master ones here, allowing you to compose complexes working times by dates. + +Under the hook, a unique working time is created for each employee with the +proper composition for not affecting the rest of the functionality linked to +this model. + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +During the installation of the module, current working times are split by +start/end dates for having consistent data, and the potential new composed +calendar planning is saved instead on the employee. + +Configuration +============= + +#. Go to *Employees > Employees*. +#. Open or create a new one. +#. On the "Work Information" tab, fill the section "Working Hours" with: + + * Starting date (optional). + * Ending date (optional). + * Working time to apply during that date interval. + +Known issues / Roadmap +====================== + + +* Add a wizard for generating next year calendar planning based on current one + in batch. +* Add constraint for avoiding planning lines overlapping. +* Avoid the regeneration of whole private calendars each time a change is + detected. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Tecnativa + +Contributors +~~~~~~~~~~~~ + +* `Tecnativa `_: + + * Pedro M. Baeza + * Víctor Martínez + +* `Creu Blanca `_: + + * Jaime Arroyo + +* `ForgeFlow `_: + + * Jordi Ballester Alomar (jordi.ballester@forgeflow.com) + + * Nattapong W. + +* `Pesol `__: + + * Pedro Evaristo Gonzalez Sanchez + +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-victoralmau| image:: https://github.com/victoralmau.png?size=40px + :target: https://github.com/victoralmau + :alt: victoralmau +.. |maintainer-pedrobaeza| image:: https://github.com/pedrobaeza.png?size=40px + :target: https://github.com/pedrobaeza + :alt: pedrobaeza + +Current `maintainers `__: + +|maintainer-victoralmau| |maintainer-pedrobaeza| + +This module is part of the `OCA/hr `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/hr_employee_calendar_planning/__init__.py b/hr_employee_calendar_planning/__init__.py new file mode 100644 index 00000000000..c0d9f3d12f7 --- /dev/null +++ b/hr_employee_calendar_planning/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import models +from .hooks import post_init_hook diff --git a/hr_employee_calendar_planning/__manifest__.py b/hr_employee_calendar_planning/__manifest__.py new file mode 100644 index 00000000000..69b6b3c612f --- /dev/null +++ b/hr_employee_calendar_planning/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright 2019 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Employee Calendar Planning", + "version": "16.0.1.1.6", + "category": "Human Resources", + "website": "https://github.com/OCA/hr", + "author": "Tecnativa,Odoo Community Association (OCA)", + "license": "AGPL-3", + "installable": True, + "depends": ["hr"], + "data": ["security/ir.model.access.csv", "views/hr_employee_views.xml"], + "post_init_hook": "post_init_hook", + "maintainers": ["victoralmau", "pedrobaeza"], +} diff --git a/hr_employee_calendar_planning/hooks.py b/hr_employee_calendar_planning/hooks.py new file mode 100644 index 00000000000..4aa879a2862 --- /dev/null +++ b/hr_employee_calendar_planning/hooks.py @@ -0,0 +1,71 @@ +# Copyright 2019 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from collections import defaultdict + +from odoo import SUPERUSER_ID, api + + +def post_init_hook(cr, registry, employees=None): + """Split current calendars by date ranges and assign new ones for + having proper initial data. + """ + env = api.Environment(cr, SUPERUSER_ID, {}) + if not employees: + employees = env["hr.employee"].search([]) + calendars = employees.mapped("resource_calendar_id") + calendar_obj = env["resource.calendar"] + line_obj = env["resource.calendar.attendance"] + groups = line_obj.read_group( + [("calendar_id", "in", calendars.ids)], + ["calendar_id", "date_from", "date_to"], + ["calendar_id", "date_from:day", "date_to:day"], + lazy=False, + ) + calendar_mapping = defaultdict(list) + for group in groups: + calendar = calendar_obj.browse(group["calendar_id"][0]) + lines = line_obj.search(group["__domain"]) + if len(calendar.attendance_ids) == len(lines): + # Don't alter calendar, as it's the same + new_calendar = calendar + else: + name = calendar.name + " {}-{}".format( + lines[0].date_from, + lines[0].date_to, + ) + attendances = [] + for line in lines: + data = line.copy_data({"date_from": False, "date_to": False})[0] + data.pop("calendar_id") + attendances.append((0, 0, data)) + new_calendar = calendar_obj.create( + {"name": name, "attendance_ids": attendances} + ) + calendar_mapping[calendar].append( + (lines[0].date_from, lines[0].date_to, new_calendar), + ) + for employee in employees.filtered("resource_calendar_id"): + calendar_lines = [] + for data in calendar_mapping[employee.resource_calendar_id]: + calendar_lines.append( + ( + 0, + 0, + { + "date_start": data[0], + "date_end": data[1], + "calendar_id": data[2].id, + }, + ) + ) + # Extract employee's existing leaves so they are passed to the new + # automatic calendar. + leaves = employee.resource_calendar_id.leave_ids.filtered( + lambda x: x.resource_id == employee.resource_id + ) + employee.calendar_ids = calendar_lines + employee.resource_calendar_id.active = False + # Now the automatic calendar has been created, so we link the + # leaves to that one so they count correctly. + leaves.write({"calendar_id": employee.resource_calendar_id.id}) diff --git a/hr_employee_calendar_planning/i18n/ca.po b/hr_employee_calendar_planning/i18n/ca.po new file mode 100644 index 00000000000..d0f43a4d2a2 --- /dev/null +++ b/hr_employee_calendar_planning/i18n/ca.po @@ -0,0 +1,147 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_employee_calendar_planning +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-03-21 14:17+0000\n" +"Last-Translator: Noel estudillo \n" +"Language-Team: none\n" +"Language: ca\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_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "%s is used in %s employee(s) related to another company." +msgstr "%s s'utilitza en %s empleats relacionats amb una altra empresa." + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "%s is used in %s employee(s). You should change them first." +msgstr "%s s'utilitza en %s empleat(s). Primer els hauries de canviar." + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__active +msgid "Active" +msgstr "Actiu" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__auto_generate +msgid "Auto Generate" +msgstr "Generació automàtica" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "Auto generated calendar for employee" +msgstr "Horari autogenerat per a l'empleat" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__calendar_ids +msgid "Calendar planning" +msgstr "Pla d'horari" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__company_id +msgid "Company" +msgstr "Companyia" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_uid +msgid "Created by" +msgstr "Creat per" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_date +msgid "Created on" +msgstr "Creat el" + +#. module: hr_employee_calendar_planning +#: model:ir.model.constraint,message:hr_employee_calendar_planning.constraint_hr_employee_calendar_date_consistency +msgid "Date end should be higher than date start" +msgstr "La data de fi ha de ser més gran que la d'inici" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__display_name +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__display_name +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__display_name +msgid "Display Name" +msgstr "Nom a mostrar" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__employee_id +msgid "Employee" +msgstr "Empleat" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee_calendar +msgid "Employee Calendar" +msgstr "Horari de l'empleat" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_end +msgid "End Date" +msgstr "Data de finalització" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__id +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__id +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__id +msgid "ID" +msgstr "ID" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,help:hr_employee_calendar_planning.field_resource_calendar__active +msgid "" +"If the active field is set to false, it will allow you to hide the Working " +"Time without removing it." +msgstr "" +"Si el camp actiu està definit com a fals, us permetrà ocultar el temps de " +"treball sense eliminar-lo." + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee____last_update +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar____last_update +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar____last_update +msgid "Last Modified on" +msgstr "Darrera modificació el" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_uid +msgid "Last Updated by" +msgstr "Darrera modificació per" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_date +msgid "Last Updated on" +msgstr "Darrera modificació el" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_resource_calendar +msgid "Resource Working Time" +msgstr "Temps de treball" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_start +msgid "Start Date" +msgstr "Data d'Inici" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__calendar_id +msgid "Working Time" +msgstr "Temps de treball" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "You can not create employees without any calendar." +msgstr "" diff --git a/hr_employee_calendar_planning/i18n/ca_ES.po b/hr_employee_calendar_planning/i18n/ca_ES.po new file mode 100644 index 00000000000..c29aac1b1e7 --- /dev/null +++ b/hr_employee_calendar_planning/i18n/ca_ES.po @@ -0,0 +1,143 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_employee_calendar_planning +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: ca_ES\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "%s is used in %s employee(s) related to another company." +msgstr "" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "%s is used in %s employee(s). You should change them first." +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__active +msgid "Active" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__auto_generate +msgid "Auto Generate" +msgstr "" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "Auto generated calendar for employee" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__calendar_ids +msgid "Calendar planning" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__company_id +msgid "Company" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_uid +msgid "Created by" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_date +msgid "Created on" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.constraint,message:hr_employee_calendar_planning.constraint_hr_employee_calendar_date_consistency +msgid "Date end should be higher than date start" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__display_name +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__display_name +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__display_name +msgid "Display Name" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__employee_id +msgid "Employee" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee_calendar +msgid "Employee Calendar" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_end +msgid "End Date" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__id +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__id +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__id +msgid "ID" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,help:hr_employee_calendar_planning.field_resource_calendar__active +msgid "" +"If the active field is set to false, it will allow you to hide the Working " +"Time without removing it." +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee____last_update +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar____last_update +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar____last_update +msgid "Last Modified on" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_date +msgid "Last Updated on" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_resource_calendar +msgid "Resource Working Time" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_start +msgid "Start Date" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__calendar_id +msgid "Working Time" +msgstr "" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "You can not create employees without any calendar." +msgstr "" diff --git a/hr_employee_calendar_planning/i18n/de.po b/hr_employee_calendar_planning/i18n/de.po new file mode 100644 index 00000000000..5dd8ce6321b --- /dev/null +++ b/hr_employee_calendar_planning/i18n/de.po @@ -0,0 +1,143 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_employee_calendar_planning +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "%s is used in %s employee(s) related to another company." +msgstr "" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "%s is used in %s employee(s). You should change them first." +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__active +msgid "Active" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__auto_generate +msgid "Auto Generate" +msgstr "" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "Auto generated calendar for employee" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__calendar_ids +msgid "Calendar planning" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__company_id +msgid "Company" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_uid +msgid "Created by" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_date +msgid "Created on" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.constraint,message:hr_employee_calendar_planning.constraint_hr_employee_calendar_date_consistency +msgid "Date end should be higher than date start" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__display_name +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__display_name +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__display_name +msgid "Display Name" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__employee_id +msgid "Employee" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee_calendar +msgid "Employee Calendar" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_end +msgid "End Date" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__id +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__id +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__id +msgid "ID" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,help:hr_employee_calendar_planning.field_resource_calendar__active +msgid "" +"If the active field is set to false, it will allow you to hide the Working " +"Time without removing it." +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee____last_update +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar____last_update +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar____last_update +msgid "Last Modified on" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_date +msgid "Last Updated on" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_resource_calendar +msgid "Resource Working Time" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_start +msgid "Start Date" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__calendar_id +msgid "Working Time" +msgstr "" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "You can not create employees without any calendar." +msgstr "" diff --git a/hr_employee_calendar_planning/i18n/es.po b/hr_employee_calendar_planning/i18n/es.po new file mode 100644 index 00000000000..1be5893a139 --- /dev/null +++ b/hr_employee_calendar_planning/i18n/es.po @@ -0,0 +1,150 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_employee_calendar_planning +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-08-29 06:53+0000\n" +"PO-Revision-Date: 2022-08-29 08:55+0200\n" +"Last-Translator: Carles Antoli \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Poedit 3.0.1\n" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "" +"%(item_name)s is used in %(total_items)s employee(s) related to another " +"company." +msgstr "" +"%(item_name)s está usado en %(total_items)s empleado/a(s) relacionado/a(s) con " +"otra compañía." + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "" +"%(item_name)s is used in %(total_items)s employee(s).You should change them " +"first." +msgstr "" +"%(item_name)s está usado en %(total_items)s empleado(s). Debería cambiarlo " +"primero." + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__active +msgid "Active" +msgstr "Activo" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__auto_generate +msgid "Auto Generate" +msgstr "" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "Auto generated calendar for employee" +msgstr "Horario autogenerado para el empleado" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__calendar_ids +msgid "Calendar planning" +msgstr "Plan de Horario" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__company_id +msgid "Company" +msgstr "Compañía" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: hr_employee_calendar_planning +#: model:ir.model.constraint,message:hr_employee_calendar_planning.constraint_hr_employee_calendar_date_consistency +msgid "Date end should be higher than date start" +msgstr "La fecha de fin debe ser mayor que la de inicio" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__display_name +msgid "Display Name" +msgstr "Nombre a mostrar" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__employee_id +msgid "Employee" +msgstr "Empleado" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee_calendar +msgid "Employee Calendar" +msgstr "Horario del Empleado" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_end +msgid "End Date" +msgstr "Fecha de finalización" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__id +msgid "ID" +msgstr "ID" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,help:hr_employee_calendar_planning.field_resource_calendar__active +msgid "" +"If the active field is set to false, it will allow you to hide the Working " +"Time without removing it." +msgstr "" +"Si el campo activo se establece en falso, le permitirá ocultar el tiempo de " +"trabajo sin eliminarlo." + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar____last_update +msgid "Last Modified on" +msgstr "Última modificación el" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_uid +msgid "Last Updated by" +msgstr "Última modificación por" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_date +msgid "Last Updated on" +msgstr "Última modificación el" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_resource_calendar +msgid "Resource Working Time" +msgstr "Tiempo de trabajo" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_start +msgid "Start Date" +msgstr "Fecha de Inicio" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__calendar_id +msgid "Working Time" +msgstr "Tiempo de Trabajo" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "You can not create employees without any calendar." +msgstr "No puede crear empleados sin ningún calendario." diff --git a/hr_employee_calendar_planning/i18n/es_AR.po b/hr_employee_calendar_planning/i18n/es_AR.po new file mode 100644 index 00000000000..8dee5949eb4 --- /dev/null +++ b/hr_employee_calendar_planning/i18n/es_AR.po @@ -0,0 +1,146 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_employee_calendar_planning +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-08-05 01:07+0000\n" +"Last-Translator: Nicolas Rodriguez Sande \n" +"Language-Team: none\n" +"Language: es_AR\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_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "%s is used in %s employee(s) related to another company." +msgstr "%s está siendo usada en %s empleados(s) relacionados con otra compañía." + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "%s is used in %s employee(s). You should change them first." +msgstr "%s está siendo usado en los empleados %s. Debes cambiarlo primero." + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__active +msgid "Active" +msgstr "Activo" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__auto_generate +msgid "Auto Generate" +msgstr "Autogenerar" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "Auto generated calendar for employee" +msgstr "Calendario autogenerado para el empleado" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__calendar_ids +msgid "Calendar planning" +msgstr "Planeamiento de calendario" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__company_id +msgid "Company" +msgstr "Empresa" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_date +msgid "Created on" +msgstr "Creado en" + +#. module: hr_employee_calendar_planning +#: model:ir.model.constraint,message:hr_employee_calendar_planning.constraint_hr_employee_calendar_date_consistency +msgid "Date end should be higher than date start" +msgstr "Fecha final debe ser posterior a la fecha inicial" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__display_name +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__display_name +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__display_name +msgid "Display Name" +msgstr "Nombre para mostrar" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__employee_id +msgid "Employee" +msgstr "Empleado" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee_calendar +msgid "Employee Calendar" +msgstr "Calendario del empleado" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_end +msgid "End Date" +msgstr "Fecha hasta" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__id +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__id +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__id +msgid "ID" +msgstr "ID" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,help:hr_employee_calendar_planning.field_resource_calendar__active +msgid "" +"If the active field is set to false, it will allow you to hide the Working " +"Time without removing it." +msgstr "" +"Si el campo activo es falso, te permite ocultar este registro sin removerlo." + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee____last_update +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar____last_update +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar____last_update +msgid "Last Modified on" +msgstr "Última modificación en" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_uid +msgid "Last Updated by" +msgstr "Última actualización por" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_date +msgid "Last Updated on" +msgstr "Última actualización en" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_resource_calendar +msgid "Resource Working Time" +msgstr "Tiempo de trabajo del recurso" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_start +msgid "Start Date" +msgstr "Fecha inicio" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__calendar_id +msgid "Working Time" +msgstr "Tiempo de trabajo" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "You can not create employees without any calendar." +msgstr "No puedes crear empleados sin asignarles ningún calendario." diff --git a/hr_employee_calendar_planning/i18n/fr.po b/hr_employee_calendar_planning/i18n/fr.po new file mode 100644 index 00000000000..29d1d864a47 --- /dev/null +++ b/hr_employee_calendar_planning/i18n/fr.po @@ -0,0 +1,147 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_employee_calendar_planning +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-05-14 17:47+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_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "%s is used in %s employee(s) related to another company." +msgstr "" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "%s is used in %s employee(s). You should change them first." +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__active +msgid "Active" +msgstr "Actif" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__auto_generate +msgid "Auto Generate" +msgstr "" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "Auto generated calendar for employee" +msgstr "Calendrier généré automatiquement pour les employés" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__calendar_ids +msgid "Calendar planning" +msgstr "Calendrier planning" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__company_id +msgid "Company" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_uid +msgid "Created by" +msgstr "Créé par" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_date +msgid "Created on" +msgstr "Créé le" + +#. module: hr_employee_calendar_planning +#: model:ir.model.constraint,message:hr_employee_calendar_planning.constraint_hr_employee_calendar_date_consistency +msgid "Date end should be higher than date start" +msgstr "La date de fin doit être postérieure à la date de début" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__display_name +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__display_name +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__display_name +msgid "Display Name" +msgstr "Nom affiché" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__employee_id +msgid "Employee" +msgstr "Employé" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee_calendar +msgid "Employee Calendar" +msgstr "Calendrier de l'employé" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_end +msgid "End Date" +msgstr "Date de fin" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__id +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__id +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__id +msgid "ID" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,help:hr_employee_calendar_planning.field_resource_calendar__active +msgid "" +"If the active field is set to false, it will allow you to hide the Working " +"Time without removing it." +msgstr "" +"Si le champ actif est défini sur Faux, il vous permettra de masquer la durée " +"de travail sans la supprimer." + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee____last_update +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar____last_update +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar____last_update +msgid "Last Modified on" +msgstr "Dernière modification le" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_uid +msgid "Last Updated by" +msgstr "Dernière mise à jour par" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_date +msgid "Last Updated on" +msgstr "Dernière mise à jour le" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_resource_calendar +msgid "Resource Working Time" +msgstr "Horaire de travail de la ressource" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_start +msgid "Start Date" +msgstr "Date de début" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__calendar_id +msgid "Working Time" +msgstr "Horaire de travail" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "You can not create employees without any calendar." +msgstr "" diff --git a/hr_employee_calendar_planning/i18n/hr_employee_calendar_planning.pot b/hr_employee_calendar_planning/i18n/hr_employee_calendar_planning.pot new file mode 100644 index 00000000000..ac7ce91eacf --- /dev/null +++ b/hr_employee_calendar_planning/i18n/hr_employee_calendar_planning.pot @@ -0,0 +1,140 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_employee_calendar_planning +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.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_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "" +"%(item_name)s is used in %(total_items)s employee(s) related to another " +"company." +msgstr "" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "" +"%(item_name)s is used in %(total_items)s employee(s).You should change them " +"first." +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__active +msgid "Active" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__auto_generate +msgid "Auto Generate" +msgstr "" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "Auto generated calendar for employee" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__calendar_ids +msgid "Calendar planning" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__company_id +msgid "Company" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_uid +msgid "Created by" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_date +msgid "Created on" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.constraint,message:hr_employee_calendar_planning.constraint_hr_employee_calendar_date_consistency +msgid "Date end should be higher than date start" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__display_name +msgid "Display Name" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__employee_id +msgid "Employee" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee_calendar +msgid "Employee Calendar" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_end +msgid "End Date" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__id +msgid "ID" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,help:hr_employee_calendar_planning.field_resource_calendar__active +msgid "" +"If the active field is set to false, it will allow you to hide the Working " +"Time without removing it." +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar____last_update +msgid "Last Modified on" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_date +msgid "Last Updated on" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_resource_calendar +msgid "Resource Working Time" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_start +msgid "Start Date" +msgstr "" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__calendar_id +msgid "Working Time" +msgstr "" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "You can not create employees without any calendar." +msgstr "" diff --git a/hr_employee_calendar_planning/i18n/it.po b/hr_employee_calendar_planning/i18n/it.po new file mode 100644 index 00000000000..7602539ba7e --- /dev/null +++ b/hr_employee_calendar_planning/i18n/it.po @@ -0,0 +1,149 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_employee_calendar_planning +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-05-30 09:10+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_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "" +"%(item_name)s is used in %(total_items)s employee(s) related to another " +"company." +msgstr "" +"L'elemento %(item_name)s è utilizzato in %(total_items)s dipendenti relativo " +"ad un'altra azienda." + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/resource_calendar.py:0 +#, python-format +msgid "" +"%(item_name)s is used in %(total_items)s employee(s).You should change them " +"first." +msgstr "" +"L'elemento %(item_name)s è utilizzato in %(total_items)s dipendenti. Bisogna " +"prima modificarli." + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__active +msgid "Active" +msgstr "Attiva" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_resource_calendar__auto_generate +msgid "Auto Generate" +msgstr "Autogenerata" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "Auto generated calendar for employee" +msgstr "Calendario autogenerato per dipendente" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee__calendar_ids +msgid "Calendar planning" +msgstr "Pianificazione calendario" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__company_id +msgid "Company" +msgstr "Azienda" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: hr_employee_calendar_planning +#: model:ir.model.constraint,message:hr_employee_calendar_planning.constraint_hr_employee_calendar_date_consistency +msgid "Date end should be higher than date start" +msgstr "La data fine deve essere successiva alla data inizio" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__employee_id +msgid "Employee" +msgstr "Dipendente" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_hr_employee_calendar +msgid "Employee Calendar" +msgstr "Calendario dipendente" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_end +msgid "End Date" +msgstr "Data fine" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__id +msgid "ID" +msgstr "ID" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,help:hr_employee_calendar_planning.field_resource_calendar__active +msgid "" +"If the active field is set to false, it will allow you to hide the Working " +"Time without removing it." +msgstr "" +"Se il campo attivo è impostato a falso, consente di nascondere il tempo " +"lavorato senza eliminarlo." + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar____last_update +msgid "Last Modified on" +msgstr "Ultima modifica il" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: hr_employee_calendar_planning +#: model:ir.model,name:hr_employee_calendar_planning.model_resource_calendar +msgid "Resource Working Time" +msgstr "Orario lavoro risorsa" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__date_start +msgid "Start Date" +msgstr "Data inizio" + +#. module: hr_employee_calendar_planning +#: model:ir.model.fields,field_description:hr_employee_calendar_planning.field_hr_employee_calendar__calendar_id +msgid "Working Time" +msgstr "Orario lavoro" + +#. module: hr_employee_calendar_planning +#: code:addons/hr_employee_calendar_planning/models/hr_employee.py:0 +#, python-format +msgid "You can not create employees without any calendar." +msgstr "Non è possibile creare un dipendente senza un calendario." diff --git a/hr_employee_calendar_planning/models/__init__.py b/hr_employee_calendar_planning/models/__init__.py new file mode 100644 index 00000000000..c90fb8413f2 --- /dev/null +++ b/hr_employee_calendar_planning/models/__init__.py @@ -0,0 +1,2 @@ +from . import hr_employee +from . import resource_calendar diff --git a/hr_employee_calendar_planning/models/hr_employee.py b/hr_employee_calendar_planning/models/hr_employee.py new file mode 100644 index 00000000000..b66def4a3a4 --- /dev/null +++ b/hr_employee_calendar_planning/models/hr_employee.py @@ -0,0 +1,236 @@ +# Copyright 2019 Tecnativa - Pedro M. Baeza +# Copyright 2022-2023 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import UserError +from odoo.tools import config + +SECTION_LINES = [ + ( + 0, + 0, + { + "name": "Even week", + "dayofweek": "0", + "sequence": "0", + "hour_from": 0, + "day_period": "morning", + "week_type": "0", + "hour_to": 0, + "display_type": "line_section", + }, + ), + ( + 0, + 0, + { + "name": "Odd week", + "dayofweek": "0", + "sequence": "25", + "hour_from": 0, + "day_period": "morning", + "week_type": "1", + "hour_to": 0, + "display_type": "line_section", + }, + ), +] + + +class HrEmployee(models.Model): + _inherit = "hr.employee" + + calendar_ids = fields.One2many( + comodel_name="hr.employee.calendar", + inverse_name="employee_id", + string="Calendar planning", + copy=True, + ) + + def _regenerate_calendar(self): + self.ensure_one() + vals_list = [] + two_weeks = bool( + self.calendar_ids.mapped("calendar_id").filtered("two_weeks_calendar") + ) + if self.resource_id.calendar_id.auto_generate: + self.resource_calendar_id.attendance_ids.unlink() + self.resource_calendar_id.two_weeks_calendar = two_weeks + seq = 0 + for week in ["0", "1"] if two_weeks else ["0"]: + if two_weeks: + section_vals = SECTION_LINES[int(week)] + section_vals[2]["sequence"] = seq + vals_list.append(section_vals) + seq += 1 + for line in self.calendar_ids: + if line.calendar_id.two_weeks_calendar: + attendances = line.calendar_id.attendance_ids.filtered( + lambda x: x.week_type == week + ) + else: + attendances = line.calendar_id.attendance_ids + for attendance_line in attendances: + if attendance_line.display_type == "line_section": + continue + data = attendance_line.copy_data( + { + "calendar_id": self.resource_calendar_id.id, + "date_from": line.date_start, + "date_to": line.date_end, + "week_type": week if two_weeks else False, + "sequence": seq, + } + )[0] + seq += 1 + vals_list.append((0, 0, data)) + # Autogenerate + if not self.resource_id.calendar_id.auto_generate: + self.resource_id.calendar_id = ( + self.env["resource.calendar"] + .create( + { + "active": False, + "company_id": self.company_id.id, + "auto_generate": True, + "name": _("Auto generated calendar for employee") + + " %s" % self.name, + "attendance_ids": vals_list, + "two_weeks_calendar": two_weeks, + "tz": self.tz, # take employee timezone as default + } + ) + .id + ) + else: + self.resource_calendar_id.attendance_ids = vals_list + # Set the hours per day to the last (top date end) calendar line to apply + if self.calendar_ids: + self.resource_id.calendar_id.hours_per_day = self.calendar_ids[ + 0 + ].calendar_id.hours_per_day + # set global leaves + self.resource_id.calendar_id.global_leave_ids = [ + ( + 6, + 0, + self.copy_global_leaves(), + ) + ] + + def copy_global_leaves(self): + self.ensure_one() + leave_ids = [] + for calendar in self.calendar_ids: + global_leaves = calendar.calendar_id.global_leave_ids + if calendar.date_start: + global_leaves = global_leaves.filtered( + lambda x: x.date_from.date() >= calendar.date_start + ) + if calendar.date_end: + global_leaves = global_leaves.filtered( + lambda x: x.date_to.date() <= calendar.date_end + ) + leave_ids += global_leaves.ids + vals = [ + leave.copy_data({})[0] + for leave in self.env["resource.calendar.leaves"].browse(leave_ids) + ] + return self.env["resource.calendar.leaves"].create(vals).ids + + def regenerate_calendar(self): + for item in self: + item._regenerate_calendar() + + def copy(self, default=None): + self.ensure_one() + new = super().copy(default) + # Define a good main calendar for being able to regenerate it later + new.resource_id.calendar_id = fields.first(new.calendar_ids).calendar_id + new.filtered("calendar_ids").regenerate_calendar() + return new + + def _sync_user(self, user, employee_has_image=False): + res = super()._sync_user(user=user, employee_has_image=employee_has_image) + # set calendar_ids from Create employee button from user + if not self.calendar_ids: + res.update( + { + "calendar_ids": [ + ( + 0, + 0, + { + "calendar_id": user.company_id.resource_calendar_id.id, + }, + ), + ] + } + ) + return res + + @api.model_create_multi + def create(self, vals_list): + res = super().create(vals_list) + if ( + not self.env.context.get("skip_employee_calendars_required") + and not config["test_enable"] + and not self.env.context.get("install_mode") + and res.filtered(lambda x: not x.calendar_ids) + ): + raise UserError(_("You can not create employees without any calendar.")) + res.filtered("calendar_ids").regenerate_calendar() + return res + + +class HrEmployeeCalendar(models.Model): + _name = "hr.employee.calendar" + _description = "Employee Calendar" + _order = "date_end desc" + + date_start = fields.Date( + string="Start Date", + ) + date_end = fields.Date( + string="End Date", + ) + employee_id = fields.Many2one( + comodel_name="hr.employee", + string="Employee", + required=True, + ) + company_id = fields.Many2one(related="employee_id.company_id") + calendar_id = fields.Many2one( + comodel_name="resource.calendar", + string="Working Time", + required=True, + check_company=True, + ) + + _sql_constraints = [ + ( + "date_consistency", + "CHECK(date_start <= date_end)", + "Date end should be higher than date start", + ), + ] + + @api.model_create_multi + def create(self, vals): + record = super(HrEmployeeCalendar, self).create(vals) + record.employee_id._regenerate_calendar() + return record + + def write(self, vals): + res = super(HrEmployeeCalendar, self).write(vals) + for employee in self.mapped("employee_id"): + employee._regenerate_calendar() + return res + + def unlink(self): + employees = self.mapped("employee_id") + res = super(HrEmployeeCalendar, self).unlink() + for employee in employees: + employee._regenerate_calendar() + return res diff --git a/hr_employee_calendar_planning/models/resource_calendar.py b/hr_employee_calendar_planning/models/resource_calendar.py new file mode 100644 index 00000000000..4e8ae193515 --- /dev/null +++ b/hr_employee_calendar_planning/models/resource_calendar.py @@ -0,0 +1,60 @@ +# Copyright 2019 Tecnativa - Pedro M. Baeza +# Copyright 2021 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class ResourceCalendar(models.Model): + _inherit = "resource.calendar" + + active = fields.Boolean(default=True) + auto_generate = fields.Boolean() + + @api.constrains("active") + def _check_active(self): + for item in self: + total_items = self.env["hr.employee.calendar"].search_count( + [("calendar_id", "=", item.id)] + ) + if total_items: + raise ValidationError( + _( + "%(item_name)s is used in %(total_items)s employee(s)." + "You should change them first.", + item_name=item.name, + total_items=total_items, + ) + ) + + @api.constrains("company_id") + def _check_company_id(self): + for item in self.filtered("company_id"): + total_items = self.env["hr.employee.calendar"].search_count( + [ + ("calendar_id.company_id", "=", item.company_id.id), + ("employee_id.company_id", "!=", item.company_id.id), + ("employee_id.company_id", "!=", False), + ] + ) + if total_items: + raise ValidationError( + _( + "%(item_name)s is used in %(total_items)s employee(s)" + " related to another company.", + item_name=item.name, + total_items=total_items, + ) + ) + + def write(self, vals): + res = super(ResourceCalendar, self).write(vals) + if "attendance_ids" in vals or "global_leave_ids" in vals: + for record in self.filtered(lambda x: not x.auto_generate): + calendars = self.env["hr.employee.calendar"].search( + [("calendar_id", "=", record.id)] + ) + for employee in calendars.mapped("employee_id"): + employee._regenerate_calendar() + return res diff --git a/hr_employee_calendar_planning/readme/CONFIGURE.rst b/hr_employee_calendar_planning/readme/CONFIGURE.rst new file mode 100644 index 00000000000..8668fcbb774 --- /dev/null +++ b/hr_employee_calendar_planning/readme/CONFIGURE.rst @@ -0,0 +1,7 @@ +#. Go to *Employees > Employees*. +#. Open or create a new one. +#. On the "Work Information" tab, fill the section "Working Hours" with: + + * Starting date (optional). + * Ending date (optional). + * Working time to apply during that date interval. diff --git a/hr_employee_calendar_planning/readme/CONTRIBUTORS.rst b/hr_employee_calendar_planning/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..f58a7bfe7e8 --- /dev/null +++ b/hr_employee_calendar_planning/readme/CONTRIBUTORS.rst @@ -0,0 +1,18 @@ +* `Tecnativa `_: + + * Pedro M. Baeza + * Víctor Martínez + +* `Creu Blanca `_: + + * Jaime Arroyo + +* `ForgeFlow `_: + + * Jordi Ballester Alomar (jordi.ballester@forgeflow.com) + + * Nattapong W. + +* `Pesol `__: + + * Pedro Evaristo Gonzalez Sanchez diff --git a/hr_employee_calendar_planning/readme/DESCRIPTION.rst b/hr_employee_calendar_planning/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..ecbbf38b29f --- /dev/null +++ b/hr_employee_calendar_planning/readme/DESCRIPTION.rst @@ -0,0 +1,9 @@ +This module allows to manage employee working time with profiles by date +intervals. + +The profiles are regular working time calendars, but they are treated as +master ones here, allowing you to compose complexes working times by dates. + +Under the hook, a unique working time is created for each employee with the +proper composition for not affecting the rest of the functionality linked to +this model. diff --git a/hr_employee_calendar_planning/readme/INSTALL.rst b/hr_employee_calendar_planning/readme/INSTALL.rst new file mode 100644 index 00000000000..33232227e63 --- /dev/null +++ b/hr_employee_calendar_planning/readme/INSTALL.rst @@ -0,0 +1,3 @@ +During the installation of the module, current working times are split by +start/end dates for having consistent data, and the potential new composed +calendar planning is saved instead on the employee. diff --git a/hr_employee_calendar_planning/readme/ROADMAP.rst b/hr_employee_calendar_planning/readme/ROADMAP.rst new file mode 100644 index 00000000000..5f673b02ba6 --- /dev/null +++ b/hr_employee_calendar_planning/readme/ROADMAP.rst @@ -0,0 +1,6 @@ + +* Add a wizard for generating next year calendar planning based on current one + in batch. +* Add constraint for avoiding planning lines overlapping. +* Avoid the regeneration of whole private calendars each time a change is + detected. diff --git a/hr_employee_calendar_planning/security/ir.model.access.csv b/hr_employee_calendar_planning/security/ir.model.access.csv new file mode 100644 index 00000000000..c2f0fd1f3dd --- /dev/null +++ b/hr_employee_calendar_planning/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_hr_employee_calendar_planning_user,access_hr_employee_calendar,model_hr_employee_calendar,base.group_user,1,0,0,0 +access_hr_employee_calendar_planning_manager,access_hr_employee_calendar,model_hr_employee_calendar,hr.group_hr_user,1,1,1,1 diff --git a/hr_employee_calendar_planning/static/description/icon.png b/hr_employee_calendar_planning/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/hr_employee_calendar_planning/static/description/icon.png differ diff --git a/hr_employee_calendar_planning/static/description/index.html b/hr_employee_calendar_planning/static/description/index.html new file mode 100644 index 00000000000..e93ae1e3594 --- /dev/null +++ b/hr_employee_calendar_planning/static/description/index.html @@ -0,0 +1,476 @@ + + + + + + +Employee Calendar Planning + + + +
+

Employee Calendar Planning

+ + +

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

+

This module allows to manage employee working time with profiles by date +intervals.

+

The profiles are regular working time calendars, but they are treated as +master ones here, allowing you to compose complexes working times by dates.

+

Under the hook, a unique working time is created for each employee with the +proper composition for not affecting the rest of the functionality linked to +this model.

+

Table of contents

+ +
+

Installation

+

During the installation of the module, current working times are split by +start/end dates for having consistent data, and the potential new composed +calendar planning is saved instead on the employee.

+
+
+

Configuration

+
    +
  1. Go to Employees > Employees.
  2. +
  3. Open or create a new one.
  4. +
  5. On the “Work Information” tab, fill the section “Working Hours” with:
      +
    • Starting date (optional).
    • +
    • Ending date (optional).
    • +
    • Working time to apply during that date interval.
    • +
    +
  6. +
+
+
+

Known issues / Roadmap

+
    +
  • Add a wizard for generating next year calendar planning based on current one +in batch.
  • +
  • Add constraint for avoiding planning lines overlapping.
  • +
  • Avoid the regeneration of whole private calendars each time a change is +detected.
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+ +
+
+

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 maintainers:

+

victoralmau pedrobaeza

+

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

+

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

+
+
+
+ + diff --git a/hr_employee_calendar_planning/tests/__init__.py b/hr_employee_calendar_planning/tests/__init__.py new file mode 100644 index 00000000000..56b3f3e4712 --- /dev/null +++ b/hr_employee_calendar_planning/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import test_hr_employee_calendar_planning diff --git a/hr_employee_calendar_planning/tests/test_hr_employee_calendar_planning.py b/hr_employee_calendar_planning/tests/test_hr_employee_calendar_planning.py new file mode 100644 index 00000000000..1bec1c81f2d --- /dev/null +++ b/hr_employee_calendar_planning/tests/test_hr_employee_calendar_planning.py @@ -0,0 +1,450 @@ +# Copyright 2019 Tecnativa - Pedro M. Baeza +# Copyright 2021-2023 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import exceptions, fields +from odoo.tests import common, new_test_user + +from ..hooks import post_init_hook + + +class TestHrEmployeeCalendarPlanning(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env( + context=dict( + cls.env.context, + mail_create_nolog=True, + mail_create_nosubscribe=True, + mail_notrack=True, + no_reset_password=True, + ) + ) + resource_calendar = cls.env["resource.calendar"] + cls.calendar1 = resource_calendar.create( + {"name": "Test calendar 1", "attendance_ids": []} + ) + cls.calendar2 = resource_calendar.create( + {"name": "Test calendar 2", "attendance_ids": []} + ) + for day in range(5): # From monday to friday + cls.calendar1.attendance_ids = [ + ( + 0, + 0, + { + "name": "Attendance", + "dayofweek": str(day), + "hour_from": "08", + "hour_to": "12", + }, + ), + ( + 0, + 0, + { + "name": "Attendance", + "dayofweek": str(day), + "hour_from": "13", + "hour_to": "17", + }, + ), + ] + cls.calendar2.attendance_ids = [ + ( + 0, + 0, + { + "name": "Attendance", + "dayofweek": str(day), + "hour_from": "07", + "hour_to": "14", + }, + ), + ] + cls.employee = cls.env["hr.employee"].create({"name": "Test employee"}) + cls.leave1 = cls.env["resource.calendar.leaves"].create( + { + "name": "Test leave", + "calendar_id": cls.calendar1.id, + "resource_id": cls.employee.resource_id.id, + "date_from": "2019-06-01", + "date_to": "2019-06-10", + } + ) + cls.global_leave1 = cls.env["resource.calendar.leaves"].create( + { + "name": "Global Leave 1", + "date_from": "2019-03-01", + "date_to": "2019-03-02", + } + ) + cls.global_leave2 = cls.env["resource.calendar.leaves"].create( + { + "name": "Global Leave 2", + "date_from": "2020-03-12", + "date_to": "2020-03-13", + } + ) + cls.global_leave3 = cls.env["resource.calendar.leaves"].create( + { + "name": "Global Leave 3", + "date_from": "2020-03-09", + "date_to": "2020-03-10", + } + ) + cls.calendar1.global_leave_ids = [ + (6, 0, [cls.global_leave1.id, cls.global_leave2.id]) + ] + cls.calendar2.global_leave_ids = [(6, 0, [cls.global_leave3.id])] + + def test_calendar_planning(self): + self.employee.calendar_ids = [ + (0, 0, {"date_end": "2019-12-31", "calendar_id": self.calendar1.id}), + (0, 0, {"date_start": "2020-01-01", "calendar_id": self.calendar2.id}), + ] + self.assertTrue(self.employee.resource_calendar_id) + calendar = self.employee.resource_calendar_id + self.assertEqual(len(calendar.attendance_ids), 15) + self.assertEqual( + len( + calendar.attendance_ids.filtered( + lambda x: x.date_from == fields.Date.to_date("2020-01-01") + ) + ), + 5, + ) + self.assertEqual( + len( + calendar.attendance_ids.filtered( + lambda x: x.date_to == fields.Date.to_date("2019-12-31") + ) + ), + 10, + ) + + # Change one line + calendar_line = self.employee.calendar_ids[0] + calendar_line.date_end = "2019-12-30" + calendar = self.employee.resource_calendar_id + self.assertEqual( + len( + calendar.attendance_ids.filtered( + lambda x: x.date_to == fields.Date.to_date("2019-12-30") + ) + ), + 10, + ) + calendar_line.unlink() + self.assertEqual( + len( + calendar.attendance_ids.filtered( + lambda x: x.date_to == fields.Date.to_date("2019-12-30") + ) + ), + 0, + ) + self.assertEqual(len(calendar.attendance_ids), 5) + self.calendar2.write( + { + "attendance_ids": [ + ( + 0, + 0, + { + "name": "Attendance", + "dayofweek": "6", + "hour_from": "08", + "hour_to": "12", + }, + ) + ], + } + ) + self.assertEqual(len(calendar.attendance_ids), 6) + + # 2 week calendars + self.employee.calendar_ids = [ + (0, 0, {"date_end": "2019-12-31", "calendar_id": self.calendar1.id}) + ] + self.calendar1.switch_calendar_type() + + self.assertTrue(self.employee.resource_calendar_id.two_weeks_calendar) + + # Calendar 1 has 20 lines + Calendar 2 has 6 lines that are duplicated + # in the odd and even week + even week label + odd week label + self.assertEqual( + len(self.employee.resource_calendar_id.attendance_ids), 20 + 6 * 2 + 2 + ) + + def test_calendar_planning_two_weeks(self): + self.calendar1.switch_calendar_type() + self.employee.calendar_ids = [ + (0, 0, {"date_end": "2019-12-31", "calendar_id": self.calendar1.id}), + (0, 0, {"date_start": "2020-01-01", "calendar_id": self.calendar2.id}), + ] + self.assertEqual( + len(self.employee.resource_calendar_id.attendance_ids), 20 + 5 * 2 + 2 + ) + items = self.employee.resource_calendar_id.attendance_ids + items_with_sections = items.filtered(lambda x: x.display_type) + self.assertEqual(len(items_with_sections), 2) + items_date_to = items.filtered( + lambda x: x.date_to == fields.Date.to_date("2019-12-31") + ) + self.assertEqual(len(items_date_to), 20) + self.assertEqual(len(items_date_to.filtered(lambda x: x.week_type == "0")), 10) + self.assertEqual(len(items_date_to.filtered(lambda x: x.week_type == "1")), 10) + items_date_from = items.filtered( + lambda x: x.date_from == fields.Date.to_date("2020-01-01") + ) + self.assertEqual(len(items_date_from), 10) + self.assertEqual(len(items_date_from.filtered(lambda x: x.week_type == "0")), 5) + self.assertEqual(len(items_date_from.filtered(lambda x: x.week_type == "1")), 5) + items_without_sections = items - items_with_sections + self.assertEqual( + len(items_without_sections.filtered(lambda x: x.week_type == "0")), 10 + 5 + ) + self.assertEqual( + len(items_without_sections.filtered(lambda x: x.week_type == "1")), 10 + 5 + ) + self.calendar2.switch_calendar_type() + items = self.employee.resource_calendar_id.attendance_ids + items_with_sections = items.filtered(lambda x: x.display_type) + items_without_sections = items - items_with_sections + self.assertEqual(len(items), 20 + 20 + 2) + self.assertEqual(len(items_with_sections), 2) + items_date_to = items.filtered( + lambda x: x.date_to == fields.Date.to_date("2019-12-31") + ) + self.assertEqual(len(items_date_to), 20) + items_date_from = items.filtered( + lambda x: x.date_from == fields.Date.to_date("2020-01-01") + ) + self.assertEqual(len(items_date_from), 20) + items_week_0 = items_without_sections.filtered(lambda x: x.week_type == "0") + self.assertEqual(len(items_week_0), 10 + 10) + self.assertEqual( + len( + items_week_0.filtered( + lambda x: x.date_to == fields.Date.to_date("2019-12-31") + ) + ), + 5 + 5, + ) + self.assertEqual( + len( + items_week_0.filtered( + lambda x: x.date_from == fields.Date.to_date("2020-01-01") + ) + ), + 5 + 5, + ) + items_week_1 = items_without_sections.filtered(lambda x: x.week_type == "1") + self.assertEqual(len(items_week_1), 10 + 10) + self.assertEqual( + len( + items_week_1.filtered( + lambda x: x.date_to == fields.Date.to_date("2019-12-31") + ) + ), + 5 + 5, + ) + self.assertEqual( + len( + items_week_1.filtered( + lambda x: x.date_from == fields.Date.to_date("2020-01-01") + ) + ), + 5 + 5, + ) + + def test_calendar_planning_two_weeks_multi(self): + self.calendar1.switch_calendar_type() + self.calendar2.switch_calendar_type() + self.employee.calendar_ids = [ + (0, 0, {"date_end": "2019-12-31", "calendar_id": self.calendar1.id}), + ( + 0, + 0, + { + "date_start": "2020-01-01", + "date_end": "2020-01-31", + "calendar_id": self.calendar2.id, + }, + ), + ( + 0, + 0, + { + "date_start": "2020-02-01", + "date_end": "2020-02-02", + "calendar_id": self.calendar1.id, + }, + ), + (0, 0, {"date_start": "2020-01-03", "calendar_id": self.calendar2.id}), + ] + items = self.employee.resource_calendar_id.attendance_ids + items_with_sections = items.filtered(lambda x: x.display_type) + items_without_sections = items - items_with_sections + self.assertEqual(len(items), (20 * 2) + (20 * 2) + 2) + self.assertEqual(len(items_with_sections), 2) + items_week_0 = items_without_sections.filtered(lambda x: x.week_type == "0") + self.assertEqual( + len( + items_week_0.filtered( + lambda x: x.date_to == fields.Date.to_date("2019-12-31") + ) + ), + 10, + ) + self.assertEqual( + len( + items_week_0.filtered( + lambda x: x.date_to == fields.Date.to_date("2020-01-31") + ) + ), + 10, + ) + self.assertEqual( + len( + items_week_0.filtered( + lambda x: x.date_to == fields.Date.to_date("2020-02-02") + ) + ), + 10, + ) + self.assertEqual( + len( + items_week_0.filtered( + lambda x: x.date_from == fields.Date.to_date("2020-01-03") + ) + ), + 10, + ) + self.assertEqual(len(items_week_0), 20 + 20) + items_week_1 = items_without_sections.filtered(lambda x: x.week_type == "1") + self.assertEqual(len(items_week_0), len(items_week_1)) + + def test_post_install_hook(self): + self.employee.resource_calendar_id = self.calendar1.id + post_init_hook(self.env.cr, self.env.registry, self.employee) + self.assertNotEqual(self.employee.resource_calendar_id, self.calendar1) + # Check that no change is done on original calendar + self.assertEqual(len(self.calendar1.attendance_ids), 10) + self.assertEqual(len(self.employee.calendar_ids), 1) + self.assertFalse(self.employee.calendar_ids.date_start) + self.assertFalse(self.employee.calendar_ids.date_end) + # Check that the employee leaves are transferred to the new calendar + # And that global leaves remain untouched + self.assertEqual( + self.calendar1.leave_ids, self.global_leave1 + self.global_leave2 + ) + self.assertTrue( + self.leave1.id in self.employee.resource_calendar_id.leave_ids.ids + ) + # Test that global leaves are copied to the autogenerated calendar on post install hook + self.assertEqual( + { + global_leave.name + for global_leave in self.employee.resource_calendar_id.global_leave_ids + }, + {"Global Leave 1", "Global Leave 2"}, + ) + + def test_post_install_hook_several_calendaries(self): + self.calendar1.attendance_ids[0].date_from = "2019-01-01" + self.calendar1.attendance_ids[1].date_from = "2019-01-01" + self.employee.resource_calendar_id = self.calendar1.id + post_init_hook(self.env.cr, self.env.registry, self.employee) + self.assertNotEqual(self.employee.resource_calendar_id, self.calendar1) + # Check that no change is done on original calendar + self.assertEqual(len(self.calendar1.attendance_ids), 10) + self.assertEqual(len(self.employee.calendar_ids), 2) + self.assertEqual( + len(self.employee.calendar_ids[0].calendar_id.attendance_ids), + 2, + ) + self.assertEqual( + len(self.employee.calendar_ids[1].calendar_id.attendance_ids), + 8, + ) + + def test_resource_calendar_constraint(self): + self.employee.calendar_ids = [ + (0, 0, {"date_end": "2019-12-31", "calendar_id": self.calendar1.id}) + ] + with self.assertRaises(exceptions.ValidationError): + self.calendar1.write({"active": False}) + self.employee.write({"calendar_ids": [(2, self.employee.calendar_ids.id)]}) + self.calendar1.write({"active": False}) + self.assertFalse(self.calendar1.active) + + def test_resource_calendar_constraint_company_id(self): + main_company = self.env.ref("base.main_company") + self.calendar1.company_id = main_company + self.employee.company_id = main_company + self.employee.calendar_ids = [ + (0, 0, {"date_end": "2019-12-31", "calendar_id": self.calendar1.id}) + ] + company2 = self.env["res.company"].create({"name": "Test company"}) + with self.assertRaises(exceptions.ValidationError): + self.calendar1.company_id = company2 + + def test_employee_with_calendar_ids(self): + employee = self.env["hr.employee"].create( + { + "name": "Test employee", + "calendar_ids": [ + ( + 0, + 0, + {"date_start": "2020-01-01", "calendar_id": self.calendar2.id}, + ), + ], + } + ) + self.assertTrue(employee.resource_calendar_id.auto_generate) + + def test_copy_global_leaves(self): + # test that global leaves are combined from calendar_ids + global_leave_ids_cal1 = self.calendar1.global_leave_ids.ids + # self.employee.calendar_ids.unlink() + self.employee.calendar_ids = [ + (0, 0, {"date_end": "2020-03-03", "calendar_id": self.calendar1.id}), + (0, 0, {"date_start": "2020-03-03", "calendar_id": self.calendar2.id}), + ] + self.assertEqual( + { + global_leave.name + for global_leave in self.employee.resource_calendar_id.global_leave_ids + }, + {"Global Leave 1", "Global Leave 3"}, + ) + # test that global leaves on original calendar are not changed + self.assertEqual(global_leave_ids_cal1, self.calendar1.global_leave_ids.ids) + + def test_employee_copy(self): + self.employee.calendar_ids = [ + (0, 0, {"date_end": "2019-12-31", "calendar_id": self.calendar1.id}), + (0, 0, {"date_start": "2020-01-01", "calendar_id": self.calendar2.id}), + ] + self.assertTrue(self.employee.resource_calendar_id) + self.assertTrue(self.employee.resource_calendar_id.auto_generate) + employee2 = self.employee.copy() + self.assertIn(self.calendar1, employee2.mapped("calendar_ids.calendar_id")) + self.assertIn(self.calendar2, employee2.mapped("calendar_ids.calendar_id")) + self.assertTrue(employee2.resource_calendar_id) + self.assertTrue(employee2.resource_calendar_id.auto_generate) + self.assertNotEqual( + self.employee.resource_calendar_id, employee2.resource_calendar_id + ) + + def test_user_action_create_employee(self): + user = new_test_user(self.env, login="test-user") + user.action_create_employee() + self.assertIn( + user.company_id.resource_calendar_id, + user.employee_id.mapped("calendar_ids.calendar_id"), + ) diff --git a/hr_employee_calendar_planning/views/hr_employee_views.xml b/hr_employee_calendar_planning/views/hr_employee_views.xml new file mode 100644 index 00000000000..8ca77d0a85d --- /dev/null +++ b/hr_employee_calendar_planning/views/hr_employee_views.xml @@ -0,0 +1,37 @@ + + + + + hr.employee + + + + 1 + + + + + + + + + + + + + + + hr.employee.public.form + hr.employee.public + + + + 1 + + + + diff --git a/setup/hr_employee_calendar_planning/odoo/addons/hr_employee_calendar_planning b/setup/hr_employee_calendar_planning/odoo/addons/hr_employee_calendar_planning new file mode 120000 index 00000000000..0148314c13b --- /dev/null +++ b/setup/hr_employee_calendar_planning/odoo/addons/hr_employee_calendar_planning @@ -0,0 +1 @@ +../../../../hr_employee_calendar_planning \ No newline at end of file diff --git a/setup/hr_employee_calendar_planning/setup.py b/setup/hr_employee_calendar_planning/setup.py new file mode 100644 index 00000000000..28c57bb6403 --- /dev/null +++ b/setup/hr_employee_calendar_planning/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)