diff --git a/hr_work_entry_timesheet/README.rst b/hr_work_entry_timesheet/README.rst new file mode 100644 index 00000000000..35009544c80 --- /dev/null +++ b/hr_work_entry_timesheet/README.rst @@ -0,0 +1,136 @@ +========================== +Work Entry with timesheets +========================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:96eb505415cddcb1b2c8c641f493ff97424f3420d941266623c9a92dddda19c1 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |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/18.0/hr_work_entry_timesheet + :alt: OCA/hr +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/hr-18-0/hr-18-0-hr_work_entry_timesheet + :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/hr&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module extends the functionality of hr_work_entry_contract in order +to display corresponding timesheet duration on work entries. + +Also a check is made for discrepancy and the work entries are displayed +hatched on calendar view in case : + +1. no timesheet has been recorded on some day (assuming that leaves also + create timesheets with native Odoo module project_timesheet_holidays) +2. more hours have been recorded than duration of the work entry + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +Use Cases / Context +=================== + +In France, when your employes have a contract with a specific number of +days worked per year, you need to have every month the count of days +worked per employee. hr_work_entry_contract module from Odoo can be used +to cover this need. + +However, the above native Odoo module shows you the work entry per type, +depending on contract and leaves. + +From time to time, leaves are not up to date (somebody worked a few +hours one day on which he should be on leave for instance). Based on +timesheets, this module proposes to retrieve existing timesheets and +display those on work entries. + +Usage +===== + +- Go to *Employees* + +- On an "Employee" form view, click on smart-button "Work entries" + +- In the calendar view for work entries, you get : + + - hatched entries when discrepancy are found + - timesheet duration on card view (when clicking on an entry) + +- Timesheet duration has also been added on Work entries form, tree and + pivot views. + +Known issues / Roadmap +====================== + +- In case resource calendar is using half-day attendances you get 2 + work entries per day, when timesheets are per day, so we do not know + on which work entry the timesheets should be attributed. So far they + are divided by number of work entries for the day. + +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 +------- + +* Le Filament + +Contributors +------------ + +- Rémi remi-filament (https://le-filament.com) + +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-remi-filament| image:: https://github.com/remi-filament.png?size=40px + :target: https://github.com/remi-filament + :alt: remi-filament + +Current `maintainer `__: + +|maintainer-remi-filament| + +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_work_entry_timesheet/__init__.py b/hr_work_entry_timesheet/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/hr_work_entry_timesheet/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/hr_work_entry_timesheet/__manifest__.py b/hr_work_entry_timesheet/__manifest__.py new file mode 100644 index 00000000000..d06586495b0 --- /dev/null +++ b/hr_work_entry_timesheet/__manifest__.py @@ -0,0 +1,20 @@ +{ + "name": "Work Entry with timesheets", + "version": "18.0.1.0.0", + "development_status": "Alpha", + "category": "Human Resources/Employees", + "website": "https://github.com/OCA/hr", + "author": "Le Filament, Odoo Community Association (OCA)", + "maintainers": ["remi-filament"], + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": [ + "hr_timesheet", + "hr_work_entry_contract", + "project_timesheet_holidays", + ], + "data": [ + "views/hr_work_entry_view.xml", + ], +} diff --git a/hr_work_entry_timesheet/i18n/fr.po b/hr_work_entry_timesheet/i18n/fr.po new file mode 100644 index 00000000000..e2571f92976 --- /dev/null +++ b/hr_work_entry_timesheet/i18n/fr.po @@ -0,0 +1,36 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_work_entry_timesheet +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-05-27 09:58+0000\n" +"PO-Revision-Date: 2025-05-27 09:58+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: hr_work_entry_timesheet +#: model:ir.model,name:hr_work_entry_timesheet.model_account_analytic_line +msgid "Analytic Line" +msgstr "Ligne analytique" + +#. module: hr_work_entry_timesheet +#: model:ir.model,name:hr_work_entry_timesheet.model_hr_work_entry +msgid "HR Work Entry" +msgstr "Prestation RH" + +#. module: hr_work_entry_timesheet +#: model:ir.model.fields,field_description:hr_work_entry_timesheet.field_hr_work_entry__is_hatched +msgid "Timesheet Conflict" +msgstr "Conflit de feuille de temps" + +#. module: hr_work_entry_timesheet +#: model:ir.model.fields,field_description:hr_work_entry_timesheet.field_hr_work_entry__timesheet_duration +msgid "Timesheet Duration" +msgstr "Durée de feuilles de temps" diff --git a/hr_work_entry_timesheet/i18n/hr_work_entry_timesheet.pot b/hr_work_entry_timesheet/i18n/hr_work_entry_timesheet.pot new file mode 100644 index 00000000000..a3ae66b95c8 --- /dev/null +++ b/hr_work_entry_timesheet/i18n/hr_work_entry_timesheet.pot @@ -0,0 +1,36 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_work_entry_timesheet +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-05-27 09:53+0000\n" +"PO-Revision-Date: 2025-05-27 09:53+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: hr_work_entry_timesheet +#: model:ir.model,name:hr_work_entry_timesheet.model_account_analytic_line +msgid "Analytic Line" +msgstr "" + +#. module: hr_work_entry_timesheet +#: model:ir.model,name:hr_work_entry_timesheet.model_hr_work_entry +msgid "HR Work Entry" +msgstr "" + +#. module: hr_work_entry_timesheet +#: model:ir.model.fields,field_description:hr_work_entry_timesheet.field_hr_work_entry__is_hatched +msgid "Timesheet Conflict" +msgstr "" + +#. module: hr_work_entry_timesheet +#: model:ir.model.fields,field_description:hr_work_entry_timesheet.field_hr_work_entry__timesheet_duration +msgid "Timesheet Duration" +msgstr "" diff --git a/hr_work_entry_timesheet/models/__init__.py b/hr_work_entry_timesheet/models/__init__.py new file mode 100644 index 00000000000..8d40a264f6c --- /dev/null +++ b/hr_work_entry_timesheet/models/__init__.py @@ -0,0 +1,2 @@ +from . import hr_work_entry +from . import hr_timesheet diff --git a/hr_work_entry_timesheet/models/hr_timesheet.py b/hr_work_entry_timesheet/models/hr_timesheet.py new file mode 100644 index 00000000000..4f7d113d3a3 --- /dev/null +++ b/hr_work_entry_timesheet/models/hr_timesheet.py @@ -0,0 +1,52 @@ +# Copyright 2025- Le Filament (https://le-filament.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from dateutil.relativedelta import relativedelta + +from odoo import api, models + + +class AccountAnalyticLine(models.Model): + _inherit = "account.analytic.line" + + def _get_work_entry(self): + work_entries = self.env["hr.work.entry"] + for timesheet in self.filtered( + lambda line: line.project_id and line.employee_id + ): + work_entries += work_entries.search( + [ + ("employee_id", "=", timesheet.employee_id.id), + ("date_start", ">=", timesheet.date), + ("date_start", "<", timesheet.date + relativedelta(days=1)), + ] + ) + return work_entries + + @api.model_create_multi + def create(self, vals_list): + res = super().create(vals_list) + timesheets = res.filtered("project_id") + if not timesheets: + return res + work_entries = timesheets._get_work_entry() + if work_entries: + work_entries._compute_timesheet_duration() + return res + + def write(self, vals): + res = super().write(vals) + if ("unit_amount" in vals or "employee_id" in vals or "date" in vals) and ( + self.filtered("project_id") or "project_id" in vals + ): + self._get_work_entry()._compute_timesheet_duration() + return res + + def unlink(self): + work_entries = self.env["hr.work.entry"] + timesheets = self.filtered("project_id") + if timesheets: + work_entries = timesheets._get_work_entry() + res = super().unlink() + if timesheets: + work_entries._compute_timesheet_duration() + return res diff --git a/hr_work_entry_timesheet/models/hr_work_entry.py b/hr_work_entry_timesheet/models/hr_work_entry.py new file mode 100644 index 00000000000..322525953ce --- /dev/null +++ b/hr_work_entry_timesheet/models/hr_work_entry.py @@ -0,0 +1,104 @@ +# Copyright 2025- Le Filament (https://le-filament.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import pytz + +from odoo import api, fields, models + + +class HrWorkEntry(models.Model): + _inherit = "hr.work.entry" + + timesheet_duration = fields.Float(compute="_compute_timesheet_duration", store=True) + is_hatched = fields.Boolean( + compute="_compute_timesheet_conflict", + string="Timesheet Conflict", + store=True, + readonly=False, + ) + + @api.depends("date_start", "employee_id") + def _compute_timesheet_duration(self): + if not self: + return + min_datetime = min(self.mapped("date_start")) + max_datetime = max(self.mapped("date_stop")) + dates = self.mapped( + lambda work_entry: pytz.UTC.localize(work_entry.date_start) + .astimezone(pytz.timezone(work_entry.employee_id.tz)) + .replace(tzinfo=None) + .date() + ) + min_date = min(dates) + max_date = max(dates) + employee_ids = self.mapped("employee_id").ids + timesheets = ( + self.env["account.analytic.line"] + .with_context(tz="UTC") + .read_group( + domain=[ + ("project_id", "!=", False), + ("employee_id", "in", employee_ids), + ("date", ">=", min_date), + ("date", "<=", max_date), + ], + fields=["unit_amount"], + groupby=["employee_id", "date:day"], + lazy=False, + ) + ) + timesheet_dict = {eid: {} for eid in employee_ids} + for line in timesheets: + date = fields.Date().from_string(line["__range"]["date:day"]["from"]) + timesheet_dict[line["employee_id"][0]][date] = line["unit_amount"] + work_entries_dict = {eid: {} for eid in employee_ids} + for employee_id in employee_ids: + employee = self.env["hr.employee"].browse(employee_id) + work_entries = ( + self.env["hr.work.entry"] + .with_context(tz=employee.tz) + .read_group( + domain=[ + ("employee_id", "=", employee_id), + ("date_start", ">=", min_datetime), + ("date_stop", "<=", max_datetime), + ], + fields=[], + groupby=["date_start:day"], + ) + ) + work_entries_dict[employee_id] = { + pytz.UTC.localize( + fields.Datetime().from_string( + line["__range"]["date_start:day"]["from"] + ) + ) + .astimezone(pytz.timezone(employee.tz)) + .replace(tzinfo=None) + .date(): line["date_start_count"] + for line in work_entries + } + for work_entry in self: + date_start = ( + pytz.UTC.localize(work_entry.date_start) + .astimezone(pytz.timezone(work_entry.employee_id.tz)) + .replace(tzinfo=None) + .date() + ) + timesheet_duration = timesheet_dict[work_entry.employee_id.id].get( + date_start, 0.0 + ) + work_entry_count = work_entries_dict[work_entry.employee_id.id].get( + date_start, 0 + ) + work_entry.timesheet_duration = ( + timesheet_duration / work_entry_count if work_entry_count else 0.0 + ) + + @api.depends("duration", "timesheet_duration") + def _compute_timesheet_conflict(self): + for entry in self: + entry.is_hatched = entry.duration > 0.0 and ( + entry.timesheet_duration == 0.0 + or entry.timesheet_duration > entry.duration + ) diff --git a/hr_work_entry_timesheet/pyproject.toml b/hr_work_entry_timesheet/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/hr_work_entry_timesheet/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/hr_work_entry_timesheet/readme/CONTEXT.md b/hr_work_entry_timesheet/readme/CONTEXT.md new file mode 100644 index 00000000000..7e169a04b41 --- /dev/null +++ b/hr_work_entry_timesheet/readme/CONTEXT.md @@ -0,0 +1,7 @@ +In France, when your employes have a contract with a specific number of days worked per year, you need to have every month the count of days worked per employee. +hr_work_entry_contract module from Odoo can be used to cover this need. + +However, the above native Odoo module shows you the work entry per type, depending on contract and leaves. + +From time to time, leaves are not up to date (somebody worked a few hours one day on which he should be on leave for instance). +Based on timesheets, this module proposes to retrieve existing timesheets and display those on work entries. diff --git a/hr_work_entry_timesheet/readme/CONTRIBUTORS.md b/hr_work_entry_timesheet/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..53f884c65b5 --- /dev/null +++ b/hr_work_entry_timesheet/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Rémi remi-filament (https://le-filament.com) diff --git a/hr_work_entry_timesheet/readme/DESCRIPTION.md b/hr_work_entry_timesheet/readme/DESCRIPTION.md new file mode 100644 index 00000000000..65673060597 --- /dev/null +++ b/hr_work_entry_timesheet/readme/DESCRIPTION.md @@ -0,0 +1,5 @@ +This module extends the functionality of hr_work_entry_contract in order to display corresponding timesheet duration on work entries. + +Also a check is made for discrepancy and the work entries are displayed hatched on calendar view in case : +1. no timesheet has been recorded on some day (assuming that leaves also create timesheets with native Odoo module project_timesheet_holidays) +1. more hours have been recorded than duration of the work entry diff --git a/hr_work_entry_timesheet/readme/ROADMAP.md b/hr_work_entry_timesheet/readme/ROADMAP.md new file mode 100644 index 00000000000..d6669644224 --- /dev/null +++ b/hr_work_entry_timesheet/readme/ROADMAP.md @@ -0,0 +1 @@ +- In case resource calendar is using half-day attendances you get 2 work entries per day, when timesheets are per day, so we do not know on which work entry the timesheets should be attributed. So far they are divided by number of work entries for the day. diff --git a/hr_work_entry_timesheet/readme/USAGE.md b/hr_work_entry_timesheet/readme/USAGE.md new file mode 100644 index 00000000000..7c4d5385ed3 --- /dev/null +++ b/hr_work_entry_timesheet/readme/USAGE.md @@ -0,0 +1,9 @@ +- Go to *Employees* + +- On an "Employee" form view, click on smart-button "Work entries" + +- In the calendar view for work entries, you get : + - hatched entries when discrepancy are found + - timesheet duration on card view (when clicking on an entry) + +- Timesheet duration has also been added on Work entries form, tree and pivot views. diff --git a/hr_work_entry_timesheet/static/description/icon.png b/hr_work_entry_timesheet/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/hr_work_entry_timesheet/static/description/icon.png differ diff --git a/hr_work_entry_timesheet/static/description/icon.svg b/hr_work_entry_timesheet/static/description/icon.svg new file mode 100644 index 00000000000..a7a26d0932a --- /dev/null +++ b/hr_work_entry_timesheet/static/description/icon.svg @@ -0,0 +1,79 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/hr_work_entry_timesheet/static/description/index.html b/hr_work_entry_timesheet/static/description/index.html new file mode 100644 index 00000000000..f92d18ab8d6 --- /dev/null +++ b/hr_work_entry_timesheet/static/description/index.html @@ -0,0 +1,124 @@ +
+
+
+

Module name

+

This module was written to extend the functionality of ... to support ... and allow you to ...

+
+
+
+ +
+
+
+

Installation

+
+
+

To install this module, you need to: +

    +
  • ...
  • +
+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Configuration

+
+
+

To configure this module, you need to: +

    +
  • ...
  • +
+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Usage

+
+
+

To use this module, you need to: +

    +
  • ...
  • +
+

+

For further information, please visit: +

+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Known issues / Roadmap

+
+
+

+

    +
  • ...
  • +
+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Credits

+
+
+

Contributors

+ +
+
+

Maintainer

+

+ This module is maintained by the OCA.
+ 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.
+ To contribute to this module, please visit http://odoo-community.org.
+ +

+
+
+
diff --git a/hr_work_entry_timesheet/views/hr_work_entry_view.xml b/hr_work_entry_timesheet/views/hr_work_entry_view.xml new file mode 100644 index 00000000000..f70b9ff0e9f --- /dev/null +++ b/hr_work_entry_timesheet/views/hr_work_entry_view.xml @@ -0,0 +1,50 @@ + + + + + hr.work.entry.calendar.with_timesheet + hr.work.entry + + + + + + + + + + + + hr.work.entry.form.with_timesheet + hr.work.entry + + + + + + + + + + hr.work.entry.tree.with_timesheet + hr.work.entry + + + + + + + + + + hr.work.entry.pivot.with_timesheet + hr.work.entry + + + + + + + + diff --git a/hr_work_entry_timesheet_validate/README.rst b/hr_work_entry_timesheet_validate/README.rst new file mode 100644 index 00000000000..ad38f4c5f5e --- /dev/null +++ b/hr_work_entry_timesheet_validate/README.rst @@ -0,0 +1,104 @@ +========================================= +Work Entry with timesheets and validation +========================================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:96eb505415cddcb1b2c8c641f493ff97424f3420d941266623c9a92dddda19c1 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |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/18.0/hr_work_entry_timesheet_validate + :alt: OCA/hr +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/hr-18-0/hr-18-0-hr_work_entry_timesheet_validate + :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/hr&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module is a glue module between hr_work_entry_timesheet and +hr_work_entry_validate, allowing to show timesheet on new views created +for simple employees. + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +- Go to *Employees* / *My Work Entries* + +- In the calendar view for work entries, you get : + + - hatched entries when discrepancy are found + - timesheet duration on card view (when clicking on an entry) + +- Timesheet duration has also been added on Work entries form, tree and + pivot views. + +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 +------- + +* Le Filament + +Contributors +------------ + +- Rémi remi-filament (https://le-filament.com) + +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-remi-filament| image:: https://github.com/remi-filament.png?size=40px + :target: https://github.com/remi-filament + :alt: remi-filament + +Current `maintainer `__: + +|maintainer-remi-filament| + +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_work_entry_timesheet_validate/__init__.py b/hr_work_entry_timesheet_validate/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/hr_work_entry_timesheet_validate/__manifest__.py b/hr_work_entry_timesheet_validate/__manifest__.py new file mode 100644 index 00000000000..7eb138a2987 --- /dev/null +++ b/hr_work_entry_timesheet_validate/__manifest__.py @@ -0,0 +1,19 @@ +{ + "name": "Work Entry with timesheets and validation", + "version": "18.0.1.0.0", + "development_status": "Alpha", + "category": "Human Resources/Employees", + "website": "https://github.com/OCA/hr", + "author": "Le Filament, Odoo Community Association (OCA)", + "maintainers": ["remi-filament"], + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": [ + "hr_work_entry_timesheet", + "hr_work_entry_validate", + ], + "data": [ + "views/hr_work_entry_view.xml", + ], +} diff --git a/hr_work_entry_timesheet_validate/pyproject.toml b/hr_work_entry_timesheet_validate/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/hr_work_entry_timesheet_validate/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/hr_work_entry_timesheet_validate/readme/CONTRIBUTORS.md b/hr_work_entry_timesheet_validate/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..53f884c65b5 --- /dev/null +++ b/hr_work_entry_timesheet_validate/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Rémi remi-filament (https://le-filament.com) diff --git a/hr_work_entry_timesheet_validate/readme/DESCRIPTION.md b/hr_work_entry_timesheet_validate/readme/DESCRIPTION.md new file mode 100644 index 00000000000..9193ec57c26 --- /dev/null +++ b/hr_work_entry_timesheet_validate/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This module is a glue module between hr_work_entry_timesheet and hr_work_entry_validate, allowing to show timesheet on new views created for simple employees. diff --git a/hr_work_entry_timesheet_validate/readme/USAGE.md b/hr_work_entry_timesheet_validate/readme/USAGE.md new file mode 100644 index 00000000000..291d0d2b492 --- /dev/null +++ b/hr_work_entry_timesheet_validate/readme/USAGE.md @@ -0,0 +1,7 @@ +- Go to *Employees* / *My Work Entries* + +- In the calendar view for work entries, you get : + - hatched entries when discrepancy are found + - timesheet duration on card view (when clicking on an entry) + +- Timesheet duration has also been added on Work entries form, tree and pivot views. diff --git a/hr_work_entry_timesheet_validate/static/description/icon.png b/hr_work_entry_timesheet_validate/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/hr_work_entry_timesheet_validate/static/description/icon.png differ diff --git a/hr_work_entry_timesheet_validate/static/description/icon.svg b/hr_work_entry_timesheet_validate/static/description/icon.svg new file mode 100644 index 00000000000..a7a26d0932a --- /dev/null +++ b/hr_work_entry_timesheet_validate/static/description/icon.svg @@ -0,0 +1,79 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/hr_work_entry_timesheet_validate/static/description/index.html b/hr_work_entry_timesheet_validate/static/description/index.html new file mode 100644 index 00000000000..f92d18ab8d6 --- /dev/null +++ b/hr_work_entry_timesheet_validate/static/description/index.html @@ -0,0 +1,124 @@ +
+
+
+

Module name

+

This module was written to extend the functionality of ... to support ... and allow you to ...

+
+
+
+ +
+
+
+

Installation

+
+
+

To install this module, you need to: +

    +
  • ...
  • +
+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Configuration

+
+
+

To configure this module, you need to: +

    +
  • ...
  • +
+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Usage

+
+
+

To use this module, you need to: +

    +
  • ...
  • +
+

+

For further information, please visit: +

+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Known issues / Roadmap

+
+
+

+

    +
  • ...
  • +
+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Credits

+
+
+

Contributors

+ +
+
+

Maintainer

+

+ This module is maintained by the OCA.
+ 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.
+ To contribute to this module, please visit http://odoo-community.org.
+ +

+
+
+
diff --git a/hr_work_entry_timesheet_validate/views/hr_work_entry_view.xml b/hr_work_entry_timesheet_validate/views/hr_work_entry_view.xml new file mode 100644 index 00000000000..1314dc350fa --- /dev/null +++ b/hr_work_entry_timesheet_validate/views/hr_work_entry_view.xml @@ -0,0 +1,56 @@ + + + + + hr.work.entry.calendar.with_timesheet_validate + hr.work.entry + + + + + + + + + + + + hr.work.entry.form.with_timesheet_validate + hr.work.entry + + + + + + + + + + hr.work.entry.tree.with_timesheet_validate + hr.work.entry + + + + + + + + + + hr.work.entry.pivot.with_timesheet_validate + hr.work.entry + + + + + + + + diff --git a/hr_work_entry_timesheet_weekend/README.rst b/hr_work_entry_timesheet_weekend/README.rst new file mode 100644 index 00000000000..2bad8ccd06f --- /dev/null +++ b/hr_work_entry_timesheet_weekend/README.rst @@ -0,0 +1,109 @@ +======================================= +Work Entry with timesheets for weekends +======================================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:52d01e811327de69384ccdf81729cd163c1672e4aaa4294745010610215f61d5 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |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/18.0/hr_work_entry_timesheet_weekend + :alt: OCA/hr +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/hr-18-0/hr-18-0-hr_work_entry_timesheet_weekend + :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/hr&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Native Odoo module hr_work_entry_contract, by default does not create +work entries on week-ends. This module extends the functionality of +hr_work_entry_timesheet from this same OCA repo to generate work entries +on week-ends in case you have timesheet registered on these days. + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module, you need to: + +- Go to *Employees* + +- On an "Employee" form view, click on smart-button "Work entries" + +- On "Work entries" calendar view, click on "Regenerate work entries" + and select dates + +- If you have timesheets on week-ends (meaning on days which are not + listed in calendar resource attendance), you will get an + hr_work_entry for that day, using "Not working day" type added by + this module. + +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 +------- + +* Le Filament + +Contributors +------------ + +- Rémi remi-filament (https://le-filament.com) + +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-remi-filament| image:: https://github.com/remi-filament.png?size=40px + :target: https://github.com/remi-filament + :alt: remi-filament + +Current `maintainer `__: + +|maintainer-remi-filament| + +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_work_entry_timesheet_weekend/__init__.py b/hr_work_entry_timesheet_weekend/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/hr_work_entry_timesheet_weekend/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/hr_work_entry_timesheet_weekend/__manifest__.py b/hr_work_entry_timesheet_weekend/__manifest__.py new file mode 100644 index 00000000000..104d89fc43a --- /dev/null +++ b/hr_work_entry_timesheet_weekend/__manifest__.py @@ -0,0 +1,18 @@ +{ + "name": "Work Entry with timesheets for weekends", + "version": "18.0.1.0.0", + "development_status": "Alpha", + "category": "Human Resources/Employees", + "website": "https://github.com/OCA/hr", + "author": "Le Filament, Odoo Community Association (OCA)", + "maintainers": ["remi-filament"], + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": [ + "hr_work_entry_timesheet", + ], + "data": [ + "data/hr_work_entry_type_data.xml", + ], +} diff --git a/hr_work_entry_timesheet_weekend/data/hr_work_entry_type_data.xml b/hr_work_entry_timesheet_weekend/data/hr_work_entry_type_data.xml new file mode 100644 index 00000000000..f8b59a2ffbd --- /dev/null +++ b/hr_work_entry_timesheet_weekend/data/hr_work_entry_type_data.xml @@ -0,0 +1,9 @@ + + + + Not working day + NOTWORK + 3 + False + + diff --git a/hr_work_entry_timesheet_weekend/i18n/fr.po b/hr_work_entry_timesheet_weekend/i18n/fr.po new file mode 100644 index 00000000000..c25839f1549 --- /dev/null +++ b/hr_work_entry_timesheet_weekend/i18n/fr.po @@ -0,0 +1,26 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_work_entry_timesheet_weekend +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-05-27 09:59+0000\n" +"PO-Revision-Date: 2025-05-27 09:59+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: hr_work_entry_timesheet_weekend +#: model:ir.model,name:hr_work_entry_timesheet_weekend.model_hr_contract +msgid "Employee Contract" +msgstr "Contrat de l'employé" + +#. module: hr_work_entry_timesheet_weekend +#: model:hr.work.entry.type,name:hr_work_entry_timesheet_weekend.work_entry_type_leave +msgid "Not working day" +msgstr "Jour non ouvré" diff --git a/hr_work_entry_timesheet_weekend/i18n/hr_work_entry_timesheet_weekend.pot b/hr_work_entry_timesheet_weekend/i18n/hr_work_entry_timesheet_weekend.pot new file mode 100644 index 00000000000..f15e6f10613 --- /dev/null +++ b/hr_work_entry_timesheet_weekend/i18n/hr_work_entry_timesheet_weekend.pot @@ -0,0 +1,26 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_work_entry_timesheet_weekend +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-05-27 09:54+0000\n" +"PO-Revision-Date: 2025-05-27 09:54+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: hr_work_entry_timesheet_weekend +#: model:ir.model,name:hr_work_entry_timesheet_weekend.model_hr_contract +msgid "Employee Contract" +msgstr "" + +#. module: hr_work_entry_timesheet_weekend +#: model:hr.work.entry.type,name:hr_work_entry_timesheet_weekend.work_entry_type_leave +msgid "Not working day" +msgstr "" diff --git a/hr_work_entry_timesheet_weekend/models/__init__.py b/hr_work_entry_timesheet_weekend/models/__init__.py new file mode 100644 index 00000000000..b07b7896843 --- /dev/null +++ b/hr_work_entry_timesheet_weekend/models/__init__.py @@ -0,0 +1 @@ +from . import hr_contract diff --git a/hr_work_entry_timesheet_weekend/models/hr_contract.py b/hr_work_entry_timesheet_weekend/models/hr_contract.py new file mode 100644 index 00000000000..050c8b95210 --- /dev/null +++ b/hr_work_entry_timesheet_weekend/models/hr_contract.py @@ -0,0 +1,77 @@ +# Copyright 2025- Le Filament (https://le-filament.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import pytz +from dateutil.relativedelta import relativedelta + +from odoo import fields, models + + +class HrContract(models.Model): + _inherit = "hr.contract" + + def _get_contract_work_entries_values(self, date_start, date_stop): + contract_vals = super()._get_contract_work_entries_values(date_start, date_stop) + + start_dt = ( + pytz.utc.localize(date_start) if not date_start.tzinfo else date_start + ) + end_dt = pytz.utc.localize(date_stop) if not date_stop.tzinfo else date_stop + result = dict() + for calendar in self.mapped("resource_calendar_id"): + result.update(calendar._get_unusual_days(start_dt, end_dt)) + weekends = [] + for we_date in result: + if result[we_date]: + weekends.append(we_date) + + timesheets = self.env["account.analytic.line"].search( + [ + ("date", "in", weekends), + ("project_id", "!=", False), + ("holiday_id", "=", False), + ("global_leave_id", "=", False), + ] + ) + + for contract in self: + new_work_entry_dates = [] + for timesheet in timesheets.filtered( + lambda aal: aal.employee_id == contract.employee_id # noqa: B023 + ): + if ( + not timesheet._get_work_entry() + and timesheet.date not in new_work_entry_dates + ): + new_work_entry_dates.append(timesheet.date) + leave_entry_type = self.env.ref( + "hr_work_entry_timesheet_weekend.work_entry_type_leave" + ) + date_start = ( + pytz.timezone(contract.resource_calendar_id.tz) + .localize(fields.Datetime().to_datetime(timesheet.date)) + .astimezone(pytz.UTC) + .replace(tzinfo=None) + ) + if leave_entry_type: + contract_name = f"{leave_entry_type.name}: " + else: + contract_name = "" + contract_vals += [ + dict( + [ + ( + "name", + f"{contract_name}{contract.employee_id.name}", + ), + ("date_start", date_start), + ("date_stop", date_start + relativedelta(minutes=1)), + ("work_entry_type_id", leave_entry_type.id), + ("employee_id", contract.employee_id.id), + ("company_id", contract.company_id.id), + ("state", "draft"), + ("contract_id", contract.id), + ] + ) + ] + return contract_vals diff --git a/hr_work_entry_timesheet_weekend/pyproject.toml b/hr_work_entry_timesheet_weekend/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/hr_work_entry_timesheet_weekend/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/hr_work_entry_timesheet_weekend/readme/CONTRIBUTORS.md b/hr_work_entry_timesheet_weekend/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..53f884c65b5 --- /dev/null +++ b/hr_work_entry_timesheet_weekend/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Rémi remi-filament (https://le-filament.com) diff --git a/hr_work_entry_timesheet_weekend/readme/DESCRIPTION.md b/hr_work_entry_timesheet_weekend/readme/DESCRIPTION.md new file mode 100644 index 00000000000..cd9bfd454d6 --- /dev/null +++ b/hr_work_entry_timesheet_weekend/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +Native Odoo module hr_work_entry_contract, by default does not create work entries on week-ends. +This module extends the functionality of hr_work_entry_timesheet from this same OCA repo to generate work entries on week-ends in case you have timesheet registered on these days. diff --git a/hr_work_entry_timesheet_weekend/readme/USAGE.md b/hr_work_entry_timesheet_weekend/readme/USAGE.md new file mode 100644 index 00000000000..1e990aabf08 --- /dev/null +++ b/hr_work_entry_timesheet_weekend/readme/USAGE.md @@ -0,0 +1,9 @@ +To use this module, you need to: + +- Go to *Employees* + +- On an "Employee" form view, click on smart-button "Work entries" + +- On "Work entries" calendar view, click on "Regenerate work entries" and select dates + +- If you have timesheets on week-ends (meaning on days which are not listed in calendar resource attendance), you will get an hr_work_entry for that day, using "Not working day" type added by this module. diff --git a/hr_work_entry_timesheet_weekend/static/description/icon.png b/hr_work_entry_timesheet_weekend/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/hr_work_entry_timesheet_weekend/static/description/icon.png differ diff --git a/hr_work_entry_timesheet_weekend/static/description/icon.svg b/hr_work_entry_timesheet_weekend/static/description/icon.svg new file mode 100644 index 00000000000..a7a26d0932a --- /dev/null +++ b/hr_work_entry_timesheet_weekend/static/description/icon.svg @@ -0,0 +1,79 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/hr_work_entry_timesheet_weekend/static/description/index.html b/hr_work_entry_timesheet_weekend/static/description/index.html new file mode 100644 index 00000000000..f92d18ab8d6 --- /dev/null +++ b/hr_work_entry_timesheet_weekend/static/description/index.html @@ -0,0 +1,124 @@ +
+
+
+

Module name

+

This module was written to extend the functionality of ... to support ... and allow you to ...

+
+
+
+ +
+
+
+

Installation

+
+
+

To install this module, you need to: +

    +
  • ...
  • +
+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Configuration

+
+
+

To configure this module, you need to: +

    +
  • ...
  • +
+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Usage

+
+
+

To use this module, you need to: +

    +
  • ...
  • +
+

+

For further information, please visit: +

+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Known issues / Roadmap

+
+
+

+

    +
  • ...
  • +
+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Credits

+
+
+

Contributors

+ +
+
+

Maintainer

+

+ This module is maintained by the OCA.
+ 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.
+ To contribute to this module, please visit http://odoo-community.org.
+ +

+
+
+
diff --git a/hr_work_entry_validate/README.rst b/hr_work_entry_validate/README.rst new file mode 100644 index 00000000000..9a88e03dd25 --- /dev/null +++ b/hr_work_entry_validate/README.rst @@ -0,0 +1,118 @@ +=================== +Validate Work Entry +=================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:96eb505415cddcb1b2c8c641f493ff97424f3420d941266623c9a92dddda19c1 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |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/18.0/hr_work_entry_validate + :alt: OCA/hr +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/hr-18-0/hr-18-0-hr_work_entry_validate + :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/hr&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module extends the functionality of hr_work_entry_contract in order +to allow users to validate their work entries. + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +Use Cases / Context +=================== + +In France, when your employees have a contract with a specific number of +days worked per year, they need to validate every month the count of +days worked for the past month. + +Function to validate already exists in native hr_work_entry module but +is not accessible on the interface. + +Usage +===== + +To use this module, you need to: + +- Go to *Employees* / *My Work Entries* + +- Switch to list view, select a number of entries and click on "Action" + > "Validate work entries" + +- On form view, you can also click on "Action" > "Validate work + entries" + +Known issues / Roadmap +====================== + +- Add an action on calendar view to validate displayed work entries. + +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 +------- + +* Le Filament + +Contributors +------------ + +- Rémi remi-filament (https://le-filament.com) + +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-remi-filament| image:: https://github.com/remi-filament.png?size=40px + :target: https://github.com/remi-filament + :alt: remi-filament + +Current `maintainer `__: + +|maintainer-remi-filament| + +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_work_entry_validate/__init__.py b/hr_work_entry_validate/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/hr_work_entry_validate/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/hr_work_entry_validate/__manifest__.py b/hr_work_entry_validate/__manifest__.py new file mode 100644 index 00000000000..8fbf543a36e --- /dev/null +++ b/hr_work_entry_validate/__manifest__.py @@ -0,0 +1,27 @@ +{ + "name": "Validate Work Entry", + "version": "18.0.1.0.0", + "development_status": "Alpha", + "category": "Human Resources/Employees", + "website": "https://github.com/OCA/hr", + "author": "Le Filament, Odoo Community Association (OCA)", + "maintainers": ["remi-filament"], + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": [ + "hr_work_entry_contract", + ], + "data": [ + "security/ir.model.access.csv", + "security/hr_work_entry_security.xml", + "data/ir_actions_server_data.xml", + "views/hr_work_entry_views.xml", + ], + "assets": { + "web.assets_backend": [ + "hr_work_entry_validate/static/src/views/**/*.js", + "hr_work_entry_validate/static/src/views/**/*.xml", + ], + }, +} diff --git a/hr_work_entry_validate/data/ir_actions_server_data.xml b/hr_work_entry_validate/data/ir_actions_server_data.xml new file mode 100644 index 00000000000..c023b2528de --- /dev/null +++ b/hr_work_entry_validate/data/ir_actions_server_data.xml @@ -0,0 +1,16 @@ + + + + + Validate work entries + + + + code + records.action_validate_with_error() + + diff --git a/hr_work_entry_validate/i18n/fr.po b/hr_work_entry_validate/i18n/fr.po new file mode 100644 index 00000000000..835d290ec72 --- /dev/null +++ b/hr_work_entry_validate/i18n/fr.po @@ -0,0 +1,153 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_work_entry_validate +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-11-04 14:09+0000\n" +"PO-Revision-Date: 2025-11-04 14:09+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: hr_work_entry_validate +#. odoo-javascript +#: code:addons/hr_work_entry_validate/static/src/views/calendar/calendar_controller.esm.js:0 +msgid "%s work entries validated" +msgstr "%s entrées validées" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_form +msgid "Hours" +msgstr "Heures" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_search +msgid "Archived" +msgstr "Archivé" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_tree +msgid "Beginning" +msgstr "Début" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_search +msgid "Conflicting" +msgstr "En conflit" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_search +msgid "Current Month" +msgstr "Mois courant" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_search +msgid "Date" +msgstr "Date" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_form +msgid "Description" +msgstr "Description" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_tree +msgid "End" +msgstr "Fin" + +#. module: hr_work_entry_validate +#. odoo-javascript +#: code:addons/hr_work_entry_validate/static/src/views/calendar/calendar_controller.esm.js:0 +msgid "Error" +msgstr "Erreur" + +#. module: hr_work_entry_validate +#: model:ir.model,name:hr_work_entry_validate.model_hr_work_entry +msgid "HR Work Entry" +msgstr "Prestation RH" + +#. module: hr_work_entry_validate +#: model:ir.ui.menu,name:hr_work_entry_validate.menu_my_work_entry +msgid "My Work Entries" +msgstr "Mes prestations" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_form +msgid "Note: Validated work entries cannot be modified." +msgstr "Note : Les prestations validées ne peuvent être modifiées" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_search +msgid "Search Work Entry" +msgstr "Recherche de prestation" + +#. module: hr_work_entry_validate +#. odoo-python +#: code:addons/hr_work_entry_validate/models/hr_work_entry.py:0 +msgid "" +"Some entries are in conflict and cannot be validated, please solve conflicts" +" first." +msgstr "" +"Certaines entrées sont en conflit et ne peuvent être validées, merci de résoudre les" +" confilts avant de valider." + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_search +msgid "Start Date" +msgstr "Date de début" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_form +msgid "This work entry cannot be validated. The work entry type is undefined." +msgstr "Cette prestation ne peut pas être validée. Son type est inconnu." + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_search +msgid "Type" +msgstr "" + +#. module: hr_work_entry_validate +#. odoo-javascript +#: code:addons/hr_work_entry_validate/static/src/views/calendar/calendar_controller.xml:0 +msgid "Validate period" +msgstr "Valider la période" + +#. module: hr_work_entry_validate +#. odoo-javascript +#: code:addons/hr_work_entry_validate/static/src/views/calendar/calendar_controller.xml:0 +msgid "Validate period work entries" +msgstr "Valider les entrées de la période en cours" + +#. module: hr_work_entry_validate +#: model:ir.actions.server,name:hr_work_entry_validate.action_validate_work_entries +msgid "Validate work entries" +msgstr "Valider les prestations" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_pivot +msgid "Work Entries" +msgstr "Prestations" + +#. module: hr_work_entry_validate +#: model:ir.actions.act_window,name:hr_work_entry_validate.hr_work_entry_action +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_calendar +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_form +msgid "Work Entry" +msgstr "Prestation" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_form +msgid "Work Entry Name" +msgstr "Nom de la prestation" + +#. module: hr_work_entry_validate +#. odoo-javascript +#: code:addons/hr_work_entry_validate/static/src/views/calendar/calendar_controller.esm.js:0 +msgid "Work entries could not be validated." +msgstr "Les entrées n'ont pas pu être validées." diff --git a/hr_work_entry_validate/i18n/hr_work_entry_validate.pot b/hr_work_entry_validate/i18n/hr_work_entry_validate.pot new file mode 100644 index 00000000000..b99e9e4d207 --- /dev/null +++ b/hr_work_entry_validate/i18n/hr_work_entry_validate.pot @@ -0,0 +1,135 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_work_entry_validate +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-05-27 09:54+0000\n" +"PO-Revision-Date: 2025-05-27 09:54+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_form +msgid "Hours" +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_search +msgid "Archived" +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_tree +msgid "Beginning" +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_search +msgid "Conflicting" +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_search +msgid "Current Month" +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_search +msgid "Date" +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_form +msgid "Description" +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_tree +msgid "End" +msgstr "" + +#. module: hr_work_entry_validate +#: model:ir.model,name:hr_work_entry_validate.model_hr_work_entry +msgid "HR Work Entry" +msgstr "" + +#. module: hr_work_entry_validate +#: model:ir.ui.menu,name:hr_work_entry_validate.menu_my_work_entry +msgid "My Work Entries" +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.actions.act_window,help:hr_work_entry_validate.hr_work_entry_action +msgid "No data to display" +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_form +msgid "Note: Validated work entries cannot be modified." +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_search +msgid "Search Work Entry" +msgstr "" + +#. module: hr_work_entry_validate +#. odoo-python +#: code:addons/hr_work_entry_validate/models/hr_work_entry.py:0 +#: code:addons/hr_work_entry_validate/models/hr_work_entry.py:0 +#, python-format +msgid "" +"Some entries are in conflict and cannot be validated, please solve conflicts" +" first." +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_search +msgid "Start Date" +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_form +msgid "This work entry cannot be validated. The work entry type is undefined." +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.actions.act_window,help:hr_work_entry_validate.hr_work_entry_action +msgid "" +"Try to add some records, or make sure that there is no active filter in the " +"search bar." +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_search +msgid "Type" +msgstr "" + +#. module: hr_work_entry_validate +#: model:ir.actions.server,name:hr_work_entry_validate.action_validate_work_entries +msgid "Validate work entries" +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_pivot +msgid "Work Entries" +msgstr "" + +#. module: hr_work_entry_validate +#: model:ir.actions.act_window,name:hr_work_entry_validate.hr_work_entry_action +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_calendar +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_form +msgid "Work Entry" +msgstr "" + +#. module: hr_work_entry_validate +#: model_terms:ir.ui.view,arch_db:hr_work_entry_validate.hr_work_entry_view_form +msgid "Work Entry Name" +msgstr "" diff --git a/hr_work_entry_validate/models/__init__.py b/hr_work_entry_validate/models/__init__.py new file mode 100644 index 00000000000..32b8578582d --- /dev/null +++ b/hr_work_entry_validate/models/__init__.py @@ -0,0 +1 @@ +from . import hr_work_entry diff --git a/hr_work_entry_validate/models/hr_work_entry.py b/hr_work_entry_validate/models/hr_work_entry.py new file mode 100644 index 00000000000..7fd4bfb48ae --- /dev/null +++ b/hr_work_entry_validate/models/hr_work_entry.py @@ -0,0 +1,36 @@ +# Copyright 2025- Le Filament (https://le-filament.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from datetime import datetime, time + +from odoo import _, fields, models +from odoo.exceptions import ValidationError + + +class HrWorkEntry(models.Model): + _inherit = "hr.work.entry" + + def action_validate_with_error(self): + res = self.action_validate() + if not res: + raise ValidationError( + _( + "Some entries are in conflict and cannot be validated, " + "please solve conflicts first." + ) + ) + return res + + def validate_work_entries(self, employee_id, date_start, date_stop): + date_start = datetime.combine(fields.Date().from_string(date_start), time.min) + date_stop = date_start = datetime.combine( + fields.Date().from_string(date_stop), time.max + ) + work_entries = self.search( + [ + ("employee_id", "=", int(employee_id)), + ("date_start", ">=", date_start), + ("date_stop", "<=", date_stop), + ] + ) + return work_entries.action_validate() diff --git a/hr_work_entry_validate/pyproject.toml b/hr_work_entry_validate/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/hr_work_entry_validate/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/hr_work_entry_validate/readme/CONTEXT.md b/hr_work_entry_validate/readme/CONTEXT.md new file mode 100644 index 00000000000..b66e63c0774 --- /dev/null +++ b/hr_work_entry_validate/readme/CONTEXT.md @@ -0,0 +1,3 @@ +In France, when your employees have a contract with a specific number of days worked per year, they need to validate every month the count of days worked for the past month. + +Function to validate already exists in native hr_work_entry module but is not accessible on the interface. diff --git a/hr_work_entry_validate/readme/CONTRIBUTORS.md b/hr_work_entry_validate/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..53f884c65b5 --- /dev/null +++ b/hr_work_entry_validate/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Rémi remi-filament (https://le-filament.com) diff --git a/hr_work_entry_validate/readme/DESCRIPTION.md b/hr_work_entry_validate/readme/DESCRIPTION.md new file mode 100644 index 00000000000..24b2a53bea3 --- /dev/null +++ b/hr_work_entry_validate/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This module extends the functionality of hr_work_entry_contract in order to allow users to validate their work entries. diff --git a/hr_work_entry_validate/readme/ROADMAP.md b/hr_work_entry_validate/readme/ROADMAP.md new file mode 100644 index 00000000000..7be93d7a938 --- /dev/null +++ b/hr_work_entry_validate/readme/ROADMAP.md @@ -0,0 +1 @@ +- Add an action on calendar view to validate displayed work entries. diff --git a/hr_work_entry_validate/readme/USAGE.md b/hr_work_entry_validate/readme/USAGE.md new file mode 100644 index 00000000000..8f93031e10a --- /dev/null +++ b/hr_work_entry_validate/readme/USAGE.md @@ -0,0 +1,7 @@ +To use this module, you need to: + +- Go to *Employees* / *My Work Entries* + +- Switch to list view, select a number of entries and click on "Action" > "Validate work entries" + +- On form view, you can also click on "Action" > "Validate work entries" diff --git a/hr_work_entry_validate/security/hr_work_entry_security.xml b/hr_work_entry_validate/security/hr_work_entry_security.xml new file mode 100644 index 00000000000..51fdb96781b --- /dev/null +++ b/hr_work_entry_validate/security/hr_work_entry_security.xml @@ -0,0 +1,31 @@ + + + + Work entries/Employee : only self + + [('employee_id.user_id', '=', user.id)] + + + + + + + + + Work entries/HR officer : all work entries + + [(1, '=', 1)] + + + + + + + + + HR Contract: Employee + + + [('employee_id.user_id', '=', user.id)] + + diff --git a/hr_work_entry_validate/security/ir.model.access.csv b/hr_work_entry_validate/security/ir.model.access.csv new file mode 100644 index 00000000000..3c9bcb30277 --- /dev/null +++ b/hr_work_entry_validate/security/ir.model.access.csv @@ -0,0 +1,4 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_hr_work_entry_user,access_hr_work_entry_user,hr_work_entry.model_hr_work_entry,base.group_user,1,1,0,0 +access_hr_work_entry_type_user,access_hr_work_entry_type_user,hr_work_entry.model_hr_work_entry_type,base.group_user,1,0,0,0 +access_hr_contract_user,hr.contract.user,hr_contract.model_hr_contract,base.group_user,1,0,0,0 diff --git a/hr_work_entry_validate/static/description/icon.png b/hr_work_entry_validate/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/hr_work_entry_validate/static/description/icon.png differ diff --git a/hr_work_entry_validate/static/description/icon.svg b/hr_work_entry_validate/static/description/icon.svg new file mode 100644 index 00000000000..a7a26d0932a --- /dev/null +++ b/hr_work_entry_validate/static/description/icon.svg @@ -0,0 +1,79 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/hr_work_entry_validate/static/description/index.html b/hr_work_entry_validate/static/description/index.html new file mode 100644 index 00000000000..f92d18ab8d6 --- /dev/null +++ b/hr_work_entry_validate/static/description/index.html @@ -0,0 +1,124 @@ +
+
+
+

Module name

+

This module was written to extend the functionality of ... to support ... and allow you to ...

+
+
+
+ +
+
+
+

Installation

+
+
+

To install this module, you need to: +

    +
  • ...
  • +
+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Configuration

+
+
+

To configure this module, you need to: +

    +
  • ...
  • +
+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Usage

+
+
+

To use this module, you need to: +

    +
  • ...
  • +
+

+

For further information, please visit: +

+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Known issues / Roadmap

+
+
+

+

    +
  • ...
  • +
+

+
+
+
+ + + +
+
+
+
+ +
+
+
+

Credits

+
+
+

Contributors

+ +
+
+

Maintainer

+

+ This module is maintained by the OCA.
+ 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.
+ To contribute to this module, please visit http://odoo-community.org.
+ +

+
+
+
diff --git a/hr_work_entry_validate/static/src/views/calendar/calendar_controller.esm.js b/hr_work_entry_validate/static/src/views/calendar/calendar_controller.esm.js new file mode 100644 index 00000000000..cb5cd40f4fe --- /dev/null +++ b/hr_work_entry_validate/static/src/views/calendar/calendar_controller.esm.js @@ -0,0 +1,70 @@ +import {_t} from "@web/core/l10n/translation"; +import {onWillStart} from "@odoo/owl"; +import {patch} from "@web/core/utils/patch"; +import {user} from "@web/core/user"; +import {useService} from "@web/core/utils/hooks"; +import {WorkEntryCalendarController} from "@hr_work_entry_contract/views/work_entry_calendar/work_entry_calendar_controller"; + +patch(WorkEntryCalendarController.prototype, { + setup() { + super.setup(...arguments); + this.notification = useService("notification"); + this.isHrUser = false; + // Console.log(this); + + onWillStart(async () => { + this.isHrUser = await user.hasGroup("hr.group_hr_user"); + }); + }, + + // Only display button if month or week + get displayValidateButton() { + return this.model.meta.scale === "week" || this.model.meta.scale === "month"; + }, + + // Tell if any record is still draft + get anyDraft() { + return this.filteredRecords.length !== 0; + }, + + // Get current draft records + get filteredRecords() { + return this.filterRecords(this.model.data.records, "draft"); + }, + + // Filter records based on current month / week and state + filterRecords(records, state) { + const {start, end} = this.model.computeRange(); + // Filter records + return Object.values(records).filter( + (record) => + record.start > start && + record.end < end && + record.rawRecord.state === state + ); + }, + + // Call action_validate on current records + async validate() { + const record_ids = this.filteredRecords.map((r) => r.id); + // Console.log("Validating records", record_ids); + const success = await this.orm.call("hr.work.entry", "action_validate", [ + record_ids, + ]); + if (success) { + // Refresh + this.model.env.searchModel.search(); + // Notify success + this.notification.add(_t("%s work entries validated", record_ids.length), { + title: "Ok", + type: "success", + }); + } else { + // Notify failure + this.notification.add(_t("Work entries could not be validated."), { + title: _t("Error"), + type: "danger", + }); + } + }, +}); diff --git a/hr_work_entry_validate/static/src/views/calendar/calendar_controller.xml b/hr_work_entry_validate/static/src/views/calendar/calendar_controller.xml new file mode 100644 index 00000000000..7393c41bb63 --- /dev/null +++ b/hr_work_entry_validate/static/src/views/calendar/calendar_controller.xml @@ -0,0 +1,22 @@ + + + + + isHrUser + + + + + + + diff --git a/hr_work_entry_validate/views/hr_work_entry_views.xml b/hr_work_entry_validate/views/hr_work_entry_views.xml new file mode 100644 index 00000000000..d8232d1ebb8 --- /dev/null +++ b/hr_work_entry_validate/views/hr_work_entry_views.xml @@ -0,0 +1,206 @@ + + + + hr.work.entry.calendar + hr.work.entry + + + + + + + + + hr.work.entry.form + hr.work.entry + +
+
+ +
+ +
+ +
+ + + + + + + + + + + + +
+
+
+ + + hr.work.entry.list + hr.work.entry + + + + + + + + + + + + + + + + hr.work.entry.pivot + hr.work.entry + + + + + + + + + + hr.work.entry.filter + hr.work.entry + + + + + + + + + + + + + + + + + + + Work Entry + hr.work.entry + calendar,list,form,pivot + [('employee_id.user_id', '=', uid)] + {} + + + + + + calendar + + + + + + list + + + + + + pivot + + + + + + form + + + + +
diff --git a/setup/hr_work_entry_timesheet/odoo/addons/hr_work_entry_timesheet b/setup/hr_work_entry_timesheet/odoo/addons/hr_work_entry_timesheet new file mode 120000 index 00000000000..0f08f0632ab --- /dev/null +++ b/setup/hr_work_entry_timesheet/odoo/addons/hr_work_entry_timesheet @@ -0,0 +1 @@ +../../../../hr_work_entry_timesheet \ No newline at end of file diff --git a/setup/hr_work_entry_timesheet/setup.py b/setup/hr_work_entry_timesheet/setup.py new file mode 100644 index 00000000000..28c57bb6403 --- /dev/null +++ b/setup/hr_work_entry_timesheet/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/hr_work_entry_timesheet_weekend/odoo/addons/hr_work_entry_timesheet_weekend b/setup/hr_work_entry_timesheet_weekend/odoo/addons/hr_work_entry_timesheet_weekend new file mode 120000 index 00000000000..f07558b5463 --- /dev/null +++ b/setup/hr_work_entry_timesheet_weekend/odoo/addons/hr_work_entry_timesheet_weekend @@ -0,0 +1 @@ +../../../../hr_work_entry_timesheet_weekend \ No newline at end of file diff --git a/setup/hr_work_entry_timesheet_weekend/setup.py b/setup/hr_work_entry_timesheet_weekend/setup.py new file mode 100644 index 00000000000..28c57bb6403 --- /dev/null +++ b/setup/hr_work_entry_timesheet_weekend/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/hr_work_entry_validate/odoo/addons/hr_work_entry_validate b/setup/hr_work_entry_validate/odoo/addons/hr_work_entry_validate new file mode 120000 index 00000000000..b93bf311fa7 --- /dev/null +++ b/setup/hr_work_entry_validate/odoo/addons/hr_work_entry_validate @@ -0,0 +1 @@ +../../../../hr_work_entry_validate \ No newline at end of file diff --git a/setup/hr_work_entry_validate/setup.py b/setup/hr_work_entry_validate/setup.py new file mode 100644 index 00000000000..28c57bb6403 --- /dev/null +++ b/setup/hr_work_entry_validate/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)