Skip to content

Commit 4dca13a

Browse files
committed
[IMP] hr_timesheet_sheet: configurable approver field
Add a company setting that points to a res.users field on hr.employee. The user set in that field for an employee can review the employee's timesheet sheets, in addition to the users granted by the review policy. The field is referenced dynamically by name, so fields added by other modules can be used without depending on them. task-6883
1 parent 8910c51 commit 4dca13a

6 files changed

Lines changed: 57 additions & 1 deletion

File tree

hr_timesheet_sheet/models/hr_timesheet_sheet.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@ def _default_department_id(self):
149149
compute="_compute_available_task_ids",
150150
)
151151
total_time = fields.Float(compute="_compute_total_time", store=True)
152+
approver_id = fields.Many2one(
153+
comodel_name="res.users",
154+
string="Approver",
155+
compute="_compute_approver_id",
156+
help="User able to review this sheet, in addition to the users allowed "
157+
"by the review policy. It is read from the employee field configured "
158+
"as the approver field on the company.",
159+
)
152160
can_review = fields.Boolean(
153161
compute="_compute_can_review", search="_search_can_review"
154162
)
@@ -183,7 +191,18 @@ def _compute_total_time(self):
183191
for sheet in self:
184192
sheet.total_time = sum(sheet.mapped("timesheet_ids.unit_amount"))
185193

186-
@api.depends("review_policy")
194+
@api.depends("employee_id", "company_id.timesheet_sheet_approver_field_id")
195+
def _compute_approver_id(self):
196+
for sheet in self:
197+
company = sheet.company_id or self.env.company
198+
field = company.sudo().timesheet_sheet_approver_field_id
199+
approver = self.env["res.users"]
200+
employee = sheet.employee_id
201+
if field and employee and field.name in employee._fields:
202+
approver = employee[field.name]
203+
sheet.approver_id = approver
204+
205+
@api.depends("review_policy", "approver_id")
187206
def _compute_can_review(self):
188207
for sheet in self:
189208
sheet.can_review = self.env.user in sheet._get_possible_reviewers()
@@ -329,6 +348,8 @@ def _get_possible_reviewers(self):
329348
res |= self.env.ref("hr.group_hr_manager").users
330349
elif self.review_policy == "timesheet_manager":
331350
res |= self.env.ref("hr_timesheet.group_hr_timesheet_approver").users
351+
if self.approver_id:
352+
res |= self.approver_id
332353
return res
333354

334355
def _get_timesheet_sheet_company(self):

hr_timesheet_sheet/models/res_company.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,12 @@ class ResCompany(models.Model):
3737
default="hr",
3838
help="How Timesheet Sheets review is performed.",
3939
)
40+
timesheet_sheet_approver_field_id = fields.Many2one(
41+
comodel_name="ir.model.fields",
42+
string="Timesheet Approver Field",
43+
domain="[('model', '=', 'hr.employee'), ('relation', '=', 'res.users')]",
44+
ondelete="set null",
45+
help="Employee field pointing to a user (res.users). The user found in "
46+
"this field on the employee can review the employee's timesheet sheets, "
47+
"in addition to the review policy.",
48+
)

hr_timesheet_sheet/models/res_config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,7 @@ class ResConfig(models.TransientModel):
2525
timesheet_sheet_review_policy = fields.Selection(
2626
related="company_id.timesheet_sheet_review_policy", readonly=False
2727
)
28+
29+
timesheet_sheet_approver_field_id = fields.Many2one(
30+
related="company_id.timesheet_sheet_approver_field_id", readonly=False
31+
)

hr_timesheet_sheet/tests/test_hr_timesheet_sheet.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,21 @@ def test_review_policy_default(self):
10031003
sheet.unlink()
10041004
self.assertFalse(sheet.exists())
10051005

1006+
@mute_logger("odoo.models.unlink")
1007+
def test_approver_from_configured_field(self):
1008+
sheet = Form(self.sheet_model.with_user(self.user)).save()
1009+
# No approver field configured yet, so there is no approver.
1010+
self.assertFalse(sheet.approver_id)
1011+
# Configure which employee field designates the approver. The user set
1012+
# in that field on the employee becomes the approver of the sheet and
1013+
# can review it.
1014+
self.company.timesheet_sheet_approver_field_id = self.env[
1015+
"ir.model.fields"
1016+
]._get("hr.employee", "user_id")
1017+
sheet.invalidate_recordset(["approver_id"])
1018+
self.assertEqual(sheet.approver_id, self.employee.user_id)
1019+
self.assertIn(self.employee.user_id, sheet._get_possible_reviewers())
1020+
10061021
def test_same_week_different_years(self):
10071022
sheet_form = Form(self.sheet_model.with_user(self.user))
10081023
sheet_form.date_start = date(2019, 12, 30)

hr_timesheet_sheet/views/hr_timesheet_sheet_views.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
<group name="details">
109109
<field name="company_id" force_save="1" readonly="1" />
110110
<field name="department_id" invisible="1" />
111+
<field name="approver_id" invisible="not approver_id" />
111112
</group>
112113
</group>
113114
<field name="new_line_ids" invisible="1" />

hr_timesheet_sheet/views/res_config_settings_views.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@
3838
required="1"
3939
/>
4040
</setting>
41+
<setting
42+
help="Choose an employee field pointing to a user. That user can review the employee's timesheet sheets."
43+
company_dependent="1"
44+
>
45+
<field name="timesheet_sheet_approver_field_id" />
46+
</setting>
4147
</block>
4248
</xpath>
4349
</field>

0 commit comments

Comments
 (0)