add hr_timesheet_sheet_no_review, hr_timesheet_sheet_holidays, hr_timesheet_sheet_delete_cascade
This commit is contained in:
parent
b07082f70d
commit
8b0d0bb6cc
53 changed files with 3953 additions and 0 deletions
|
|
@ -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()
|
||||
Loading…
Add table
Add a link
Reference in a new issue