Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions hr_timesheet_sheet/README.rst
Original file line number Diff line number Diff line change
@@ -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
==================
Expand All @@ -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
Expand Down Expand Up @@ -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
=====

Expand Down
19 changes: 18 additions & 1 deletion hr_timesheet_sheet/models/hr_timesheet_sheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions hr_timesheet_sheet/models/res_company.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
)
7 changes: 7 additions & 0 deletions hr_timesheet_sheet/models/res_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')]",
)
7 changes: 7 additions & 0 deletions hr_timesheet_sheet/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
38 changes: 19 additions & 19 deletions hr_timesheet_sheet/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>README.rst</title>
<title>HR Timesheet Sheet</title>
<style type="text/css">

/*
Expand Down Expand Up @@ -360,21 +360,16 @@
</style>
</head>
<body>
<div class="document">
<div class="document" id="hr-timesheet-sheet">
<h1 class="title">HR Timesheet Sheet</h1>


<a class="reference external image-reference" href="https://odoo-community.org/get-involved?utm_source=readme">
<img alt="Odoo Community Association" src="https://odoo-community.org/readme-banner-image" />
</a>
<div class="section" id="hr-timesheet-sheet">
<h1>HR Timesheet Sheet</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:93b65554582c0e5fb4eb757777a1f6cc35a751d26aa72ea64c691513915ab3bd
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/timesheet/tree/18.0/hr_timesheet_sheet"><img alt="OCA/timesheet" src="https://img.shields.io/badge/github-OCA%2Ftimesheet-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/timesheet-18-0/timesheet-18-0-hr_timesheet_sheet"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/timesheet&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/timesheet/tree/18.0/hr_timesheet_sheet"><img alt="OCA/timesheet" src="https://img.shields.io/badge/github-OCA%2Ftimesheet-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/timesheet-18-0/timesheet-18-0-hr_timesheet_sheet"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/timesheet&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>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
Expand All @@ -399,7 +394,7 @@ <h1>HR Timesheet Sheet</h1>
</ul>
</div>
<div class="section" id="installation">
<h2><a class="toc-backref" href="#toc-entry-1">Installation</a></h2>
<h1><a class="toc-backref" href="#toc-entry-1">Installation</a></h1>
<p>This module relies on:</p>
<ul class="simple">
<li>The OCA module ‘2D matrix for x2many fields’, and can be downloaded
Expand All @@ -408,7 +403,7 @@ <h2><a class="toc-backref" href="#toc-entry-1">Installation</a></h2>
</ul>
</div>
<div class="section" id="configuration">
<h2><a class="toc-backref" href="#toc-entry-2">Configuration</a></h2>
<h1><a class="toc-backref" href="#toc-entry-2">Configuration</a></h1>
<p>If you want other default ranges different from weekly, you need to go:</p>
<ul class="simple">
<li>In the menu Configuration -&gt; Settings -&gt; <strong>Timesheet Options</strong>, and
Expand All @@ -421,9 +416,15 @@ <h2><a class="toc-backref" href="#toc-entry-2">Configuration</a></h2>
accordingly.</p>
<p>For adding more review policies, look at the
<em>hr_timesheet_sheet_policy_xxx</em> extra modules.</p>
<p>To let a specific user review an employee’s sheets in addition to the
users allowed by the review policy, go to <em>Configuration &gt; Settings &gt;
Timesheet Options</em> and set <strong>Timesheet Approver Field</strong> 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.</p>
</div>
<div class="section" id="usage">
<h2><a class="toc-backref" href="#toc-entry-3">Usage</a></h2>
<h1><a class="toc-backref" href="#toc-entry-3">Usage</a></h1>
<p>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.</p>
Expand All @@ -432,7 +433,7 @@ <h2><a class="toc-backref" href="#toc-entry-3">Usage</a></h2>
the Details tab, please save before.</p>
</div>
<div class="section" id="known-issues-roadmap">
<h2><a class="toc-backref" href="#toc-entry-4">Known issues / Roadmap</a></h2>
<h1><a class="toc-backref" href="#toc-entry-4">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>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
Expand All @@ -442,25 +443,25 @@ <h2><a class="toc-backref" href="#toc-entry-4">Known issues / Roadmap</a></h2>
</ul>
</div>
<div class="section" id="bug-tracker">
<h2><a class="toc-backref" href="#toc-entry-5">Bug Tracker</a></h2>
<h1><a class="toc-backref" href="#toc-entry-5">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/timesheet/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/timesheet/issues/new?body=module:%20hr_timesheet_sheet%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h2><a class="toc-backref" href="#toc-entry-6">Credits</a></h2>
<h1><a class="toc-backref" href="#toc-entry-6">Credits</a></h1>
<div class="section" id="authors">
<h3><a class="toc-backref" href="#toc-entry-7">Authors</a></h3>
<h2><a class="toc-backref" href="#toc-entry-7">Authors</a></h2>
<ul class="simple">
<li>ForgeFlow</li>
<li>Onestein</li>
<li>CorporateHub</li>
</ul>
</div>
<div class="section" id="contributors">
<h3><a class="toc-backref" href="#toc-entry-8">Contributors</a></h3>
<h2><a class="toc-backref" href="#toc-entry-8">Contributors</a></h2>
<ul class="simple">
<li>Miquel Raïch &lt;<a class="reference external" href="mailto:miquel.raich&#64;forgeflow.com">miquel.raich&#64;forgeflow.com</a>&gt;</li>
<li>Andrea Stirpe &lt;<a class="reference external" href="mailto:a.stirpe&#64;onestein.nl">a.stirpe&#64;onestein.nl</a>&gt;</li>
Expand All @@ -479,7 +480,7 @@ <h3><a class="toc-backref" href="#toc-entry-8">Contributors</a></h3>
</ul>
</div>
<div class="section" id="maintainers">
<h3><a class="toc-backref" href="#toc-entry-9">Maintainers</a></h3>
<h2><a class="toc-backref" href="#toc-entry-9">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
Expand All @@ -492,6 +493,5 @@ <h3><a class="toc-backref" href="#toc-entry-9">Maintainers</a></h3>
</div>
</div>
</div>
</div>
</body>
</html>
19 changes: 19 additions & 0 deletions hr_timesheet_sheet/tests/test_hr_timesheet_sheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions hr_timesheet_sheet/views/res_config_settings_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@
required="1"
/>
</setting>
<setting
help="Choose an employee field pointing to a user. That user can review the employee's timesheet sheets."
company_dependent="1"
>
<field name="timesheet_sheet_approver_field_id" />
</setting>
</block>
</xpath>
</field>
Expand Down
Loading