diff --git a/hr_timesheet_sheet/README.rst b/hr_timesheet_sheet/README.rst index 2e0a9896b4..cf79684164 100644 --- a/hr_timesheet_sheet/README.rst +++ b/hr_timesheet_sheet/README.rst @@ -1,7 +1,3 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - ================== HR Timesheet Sheet ================== @@ -17,7 +13,7 @@ HR Timesheet Sheet .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png +.. |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%2Ftimesheet-lightgray.png?logo=github @@ -71,6 +67,13 @@ accordingly. For adding more review policies, look at the *hr_timesheet_sheet_policy_xxx* extra modules. +To let a specific user review an employee's sheets in addition to the +users allowed by the review policy, go to *Configuration > Settings > +Timesheet Options* and set **Timesheet Approver Field** to an employee +field pointing to a user. For every sheet, the user found in that field +on the employee is allowed to review it. Leave the setting empty to rely +on the review policy only. + Usage ===== diff --git a/hr_timesheet_sheet/models/hr_timesheet_sheet.py b/hr_timesheet_sheet/models/hr_timesheet_sheet.py index 729753e71e..3b65921cba 100644 --- a/hr_timesheet_sheet/models/hr_timesheet_sheet.py +++ b/hr_timesheet_sheet/models/hr_timesheet_sheet.py @@ -183,7 +183,11 @@ def _compute_total_time(self): for sheet in self: sheet.total_time = sum(sheet.mapped("timesheet_ids.unit_amount")) - @api.depends("review_policy") + @api.depends( + "review_policy", + "employee_id", + "company_id.timesheet_sheet_approver_field_id", + ) def _compute_can_review(self): for sheet in self: sheet.can_review = self.env.user in sheet._get_possible_reviewers() @@ -329,8 +333,21 @@ def _get_possible_reviewers(self): res |= self.env.ref("hr.group_hr_manager").users elif self.review_policy == "timesheet_manager": res |= self.env.ref("hr_timesheet.group_hr_timesheet_approver").users + res |= self._get_employee_approver() return res + def _get_employee_approver(self): + """Return the user set in the employee field configured on the company. + + `sudo` is required because `ir.model.fields` is not readable by + `base.group_user`. + """ + self.ensure_one() + field = self.company_id.sudo().timesheet_sheet_approver_field_id + if not field or field.name not in self.employee_id._fields: + return self.env["res.users"] + return self.employee_id[field.name] + def _get_timesheet_sheet_company(self): self.ensure_one() employee = self.employee_id diff --git a/hr_timesheet_sheet/models/res_company.py b/hr_timesheet_sheet/models/res_company.py index b6582fbca8..51715a6449 100644 --- a/hr_timesheet_sheet/models/res_company.py +++ b/hr_timesheet_sheet/models/res_company.py @@ -37,3 +37,13 @@ class ResCompany(models.Model): default="hr", help="How Timesheet Sheets review is performed.", ) + timesheet_sheet_approver_field_id = fields.Many2one( + comodel_name="ir.model.fields", + string="Timesheet Approver Field", + domain="[('model', '=', 'hr.employee'), ('relation', '=', 'res.users'), " + "('ttype', '=', 'many2one')]", + ondelete="set null", + help="Employee field pointing to a user (res.users). The user found in " + "this field on the employee can review the employee's timesheet sheets, " + "in addition to the review policy.", + ) diff --git a/hr_timesheet_sheet/models/res_config.py b/hr_timesheet_sheet/models/res_config.py index 1e932b60c1..120290c00e 100644 --- a/hr_timesheet_sheet/models/res_config.py +++ b/hr_timesheet_sheet/models/res_config.py @@ -25,3 +25,10 @@ class ResConfig(models.TransientModel): timesheet_sheet_review_policy = fields.Selection( related="company_id.timesheet_sheet_review_policy", readonly=False ) + + timesheet_sheet_approver_field_id = fields.Many2one( + related="company_id.timesheet_sheet_approver_field_id", + readonly=False, + domain="[('model', '=', 'hr.employee'), ('relation', '=', 'res.users'), " + "('ttype', '=', 'many2one')]", + ) diff --git a/hr_timesheet_sheet/readme/CONFIGURE.md b/hr_timesheet_sheet/readme/CONFIGURE.md index 89ebdd4e99..51c5e08398 100644 --- a/hr_timesheet_sheet/readme/CONFIGURE.md +++ b/hr_timesheet_sheet/readme/CONFIGURE.md @@ -11,3 +11,10 @@ accordingly. For adding more review policies, look at the *hr_timesheet_sheet_policy_xxx* extra modules. + +To let a specific user review an employee's sheets in addition to the +users allowed by the review policy, go to *Configuration \> Settings \> +Timesheet Options* and set **Timesheet Approver Field** to an employee +field pointing to a user. For every sheet, the user found in that field +on the employee is allowed to review it. Leave the setting empty to rely +on the review policy only. diff --git a/hr_timesheet_sheet/static/description/index.html b/hr_timesheet_sheet/static/description/index.html index 49009b4855..c7eca4fe9d 100644 --- a/hr_timesheet_sheet/static/description/index.html +++ b/hr_timesheet_sheet/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +HR Timesheet Sheet -
+
+

HR Timesheet Sheet

- - -Odoo Community Association - -
-

HR Timesheet Sheet

-

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

+

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

This module supplies a new screen enabling you to manage your work encoding (timesheet) by period. Timesheet entries are made by employees each day. At the end of the defined period, employees submit their @@ -399,7 +394,7 @@

HR Timesheet Sheet

-

Installation

+

Installation

This module relies on:

  • The OCA module ‘2D matrix for x2many fields’, and can be downloaded @@ -408,7 +403,7 @@

    Installation

-

Configuration

+

Configuration

If you want other default ranges different from weekly, you need to go:

  • In the menu Configuration -> Settings -> Timesheet Options, and @@ -421,9 +416,15 @@

    Configuration

    accordingly.

    For adding more review policies, look at the hr_timesheet_sheet_policy_xxx extra modules.

    +

    To let a specific user review an employee’s sheets in addition to the +users allowed by the review policy, go to Configuration > Settings > +Timesheet Options and set Timesheet Approver Field to an employee +field pointing to a user. For every sheet, the user found in that field +on the employee is allowed to review it. Leave the setting empty to rely +on the review policy only.

-

Usage

+

Usage

If you modify the Details tab, automatically the Summary tab is updated. But if you modify the Summary tab, you need to save in order to have the Details tab updated.

@@ -432,7 +433,7 @@

Usage

the Details tab, please save before.

-

Known issues / Roadmap

+

Known issues / Roadmap

  • The timesheet grid is limited to display a max. of 1M cells, due to a limitation of the tree view limit parameter not being able to @@ -442,7 +443,7 @@

    Known issues / Roadmap

-

Bug Tracker

+

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 @@ -450,9 +451,9 @@

Bug Tracker

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

-

Credits

+

Credits

-

Authors

+

Authors

  • ForgeFlow
  • Onestein
  • @@ -460,7 +461,7 @@

    Authors

-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -492,6 +493,5 @@

Maintainers

-
diff --git a/hr_timesheet_sheet/tests/test_hr_timesheet_sheet.py b/hr_timesheet_sheet/tests/test_hr_timesheet_sheet.py index d0cb7ca760..f2627540d9 100644 --- a/hr_timesheet_sheet/tests/test_hr_timesheet_sheet.py +++ b/hr_timesheet_sheet/tests/test_hr_timesheet_sheet.py @@ -1003,6 +1003,25 @@ def test_review_policy_default(self): sheet.unlink() self.assertFalse(sheet.exists()) + @mute_logger("odoo.models.unlink") + def test_approver_from_configured_field(self): + # `user_3` is not an HR Officer, so the "hr" review policy alone does + # not allow them to review the sheet. + sheet = Form(self.sheet_model.with_user(self.user_3)).save() + self.assertEqual(sheet.employee_id, self.department_manager) + self.assertEqual(sheet.review_policy, "hr") + self.assertNotIn(self.user_3, sheet._get_possible_reviewers()) + self.assertFalse(sheet.with_user(self.user_3).can_review) + # Designating an employee field as the approver field grants review + # rights to the user it points to, on top of the review policy. + self.company.timesheet_sheet_approver_field_id = self.env[ + "ir.model.fields" + ]._get("hr.employee", "user_id") + self.assertIn(self.user_3, sheet._get_possible_reviewers()) + self.assertTrue(sheet.with_user(self.user_3).can_review) + sheet.unlink() + self.assertFalse(sheet.exists()) + def test_same_week_different_years(self): sheet_form = Form(self.sheet_model.with_user(self.user)) sheet_form.date_start = date(2019, 12, 30) diff --git a/hr_timesheet_sheet/views/res_config_settings_views.xml b/hr_timesheet_sheet/views/res_config_settings_views.xml index 3dcaeb4ec1..98dcdf7877 100644 --- a/hr_timesheet_sheet/views/res_config_settings_views.xml +++ b/hr_timesheet_sheet/views/res_config_settings_views.xml @@ -38,6 +38,12 @@ required="1" /> + + +