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,62 @@
# Copyright 2026 Criptomart
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, models
# The context of an RPC call is controlled by the client: odoo.api.call_kw
# rebuilds the environment with whatever dictionary arrives in the request, so
# a flag carrying a JSON value could be forged by any authenticated user and
# the cascade would delete a sheet without the confirmation wizard. This
# sentinel is compared by identity and cannot be produced by a deserializer,
# so it only ever reaches the consumer from inside this process.
_SHEET_DELETE_CASCADE = object()
class AccountAnalyticLine(models.Model):
_inherit = "account.analytic.line"
def _sheet_delete_cascade_token(self):
"""Hook for extensions"""
return _SHEET_DELETE_CASCADE
def _in_sheet_delete_cascade(self):
return (
self.env.context.get("sheet_delete_cascade")
is self._sheet_delete_cascade_token()
)
def _sheet_leave_policy(self):
"""Hook for extensions"""
companies = self.sheet_id.company_id or self.company_id or self.env.company
policies = companies.mapped("timesheet_sheet_delete_leave_policy")
return "cancel" if "cancel" in policies else "detach"
def _in_deliberate_delete_cascade(self):
"""Hook for extensions
The sentinel alone is not enough: the elevated privileges that only the
cancellation branch of the sheet grants are required as a second
barrier, so an in-process caller that merely carries the cascade
context cannot delete a time off entry on its way.
"""
return self._in_sheet_delete_cascade() and self.env.su
def _detach_leave_lines_on_unlink(self):
if self._in_deliberate_delete_cascade():
return self._sheet_leave_policy() != "cancel"
return super()._detach_leave_lines_on_unlink()
@api.ondelete(at_uninstall=False)
def _unlink_except_linked_leave(self):
# Defence in depth. The cancellation branch of the cascade never gets
# here with a time off entry: project_timesheet_holidays clears
# holiday_id before unlinking the entries of a refused request
# (models/hr_holidays.py:127-134), so by then they are ordinary lines.
# This keeps the contract true for any other caller that unlinks a time
# off entry from inside a deliberate cascade.
if (
self._in_deliberate_delete_cascade()
and self._sheet_leave_policy() == "cancel"
):
return
return super()._unlink_except_linked_leave()