add hr_timesheet_sheet_no_review, hr_timesheet_sheet_holidays, hr_timesheet_sheet_delete_cascade

This commit is contained in:
Luis 2026-09-22 10:58:36 +02:00
parent b07082f70d
commit 8b0d0bb6cc
53 changed files with 3953 additions and 0 deletions

View file

@ -0,0 +1,24 @@
Two things are not resolved by installing the module and have to be reviewed
by hand.
**The record rules change existing permissions.** Before this module, every
internal user could write and delete the timesheet sheet of any other
employee. The module restricts writing and deleting to the owner of the sheet
for every internal user (``base.group_user``), and lifts the restriction for
the members of *Timesheets / Administrator*
(``hr_timesheet.group_timesheet_manager``), who keep access to every sheet.
The restrictive rule is set on ``base.group_user`` on purpose: a rule set on a
timesheet group would leave any internal user outside that group with the
unrestricted access the ACL grants and no rule at all. Reading is left open so
that the *All Timesheet Sheets* menu and the reports keep working. Check with
the customer whether any flow relies on a colleague editing somebody else's
sheet before installing.
**The time off policy has a conservative default.** In
*Settings / Timesheets / Timesheet Options*, the field *Time Off Policy On
Sheet Deletion* is per company and defaults to *Keep the time off, detach its
lines*: deleting a sheet never touches a time off request nor an employee
balance. An installation that expects the deletion of a sheet to cancel the
time off it contains has to set *Cancel the time off and restore the balance*
on purpose. That value is irreversible and cancels the whole request, even the
days that fall in other weeks.

View file

@ -0,0 +1,3 @@
* Criptomart
* Luis Martínez <luis@criptomart.net>

View file

@ -0,0 +1,19 @@
In ``hr_timesheet_sheet``, deleting a timesheet sheet does not delete the
timesheet entries it contains: they are left behind with an empty ``Sheet``
field, invisible from any sheet and hard to find again.
This module makes the deletion of a sheet cascade to its timesheet entries,
behind a confirmation wizard that states beforehand how many entries and how
many hours are about to disappear. Invoiced entries are never deleted: a sheet
that contains one cannot be deleted at all.
Because a sheet also contains the entries generated by approved time off, the
module makes that case an explicit company policy: either the time off request
is kept untouched and only its entries are detached from the sheet (the
default), or the request is cancelled and the days are restored to the
employee balance.
Turning a harmless ``unlink()`` into a destructive one is only safe if the
record rules are in place first, so the module also adds the record rules that
``hr_timesheet.sheet`` is missing: without them any internal user can delete
the sheet of any other employee.

View file

@ -0,0 +1,16 @@
* Public holidays generate timesheet entries carrying ``global_leave_id``
instead of ``holiday_id``. Neither policy applies to them: they do not belong
to a single employee and there is no balance to restore. They are deleted
with the sheet like any other entry, and they are removed on their own when
the public holiday itself is deleted, through the ``ondelete='cascade'`` of
the field.
* The ``cancel`` policy refuses, resets and deletes the time off request. An
installation that wants to keep a history of the cancelled requests would
stop at the refusal, which is already where the days are restored to the
balance. It is a known variant and it is not implemented.
* The confirmation wizard reads the time off requests in ``sudo`` under the
``cancel`` policy, because a timesheet manager entitled to delete the sheet
of another employee is not necessarily entitled to read that employee's time
off.

View file

@ -0,0 +1,26 @@
The native trash bin is removed from the sheet form, list and kanban views.
Sheets are deleted from the **Delete Sheet** button in the header of the sheet
form, or from the **Action** menu of the list view for several sheets at once.
Both open a confirmation wizard that lists the sheets, the number of timesheet
entries and the total number of hours that will be deleted, and a time off
section that depends on the configured policy. Nothing is deleted until
**Delete permanently** is pressed, and the button is hidden when something
blocks the deletion.
A plain ``sheet.unlink()`` from a script or a server action raises a
``UserError`` that points to the button, so the confirmation step cannot be
skipped by accident. Code that really means to delete does
``sheet._with_delete_cascade().unlink()``.
The cascade is armed by a sentinel object rather than by a plain value in the
context, and ``_with_delete_cascade()`` is the only way to obtain it. The
context of an RPC call is controlled by the caller, so a context flag holding
a JSON value could be forged by any authenticated user and would delete a
sheet without ever showing the confirmation; a sentinel compared by identity
cannot be produced by a deserializer, and a method whose name starts with an
underscore cannot be reached remotely.
With the ``Cancel the time off`` policy, cancelling a time off request posts a
message in its chatter telling the employee that the request has been refused.
The wording talks about a refusal, not about a deleted timesheet sheet.