74 lines
2.8 KiB
Python
74 lines
2.8 KiB
Python
# Copyright 2026 Criptomart
|
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
|
|
|
from odoo import _, models
|
|
from odoo.exceptions import UserError
|
|
from odoo.tools.misc import format_date
|
|
|
|
# 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. These
|
|
# sentinels are compared by identity and cannot be produced by a deserializer,
|
|
# so they only ever reach the consumer from inside this process.
|
|
_SHEET_LINK_WRITE = object()
|
|
_SHEET_RECOMPUTE = object()
|
|
|
|
|
|
class AccountAnalyticLine(models.Model):
|
|
_inherit = "account.analytic.line"
|
|
|
|
def _sheet_neutral_fields(self):
|
|
"""Hook for extensions"""
|
|
return {"sheet_id"}
|
|
|
|
def _sheet_link_write_token(self):
|
|
"""Hook for extensions"""
|
|
return _SHEET_LINK_WRITE
|
|
|
|
def _sheet_recompute_token(self):
|
|
"""Hook for extensions"""
|
|
return _SHEET_RECOMPUTE
|
|
|
|
def _in_sheet_link_write(self):
|
|
return (
|
|
self.env.context.get("sheet_link_write") is self._sheet_link_write_token()
|
|
)
|
|
|
|
def _detach_leave_lines_on_unlink(self):
|
|
"""Hook for extensions"""
|
|
return self.env.context.get("sheet_recompute") is self._sheet_recompute_token()
|
|
|
|
def _check_can_update_timesheet(self):
|
|
if self._in_sheet_link_write():
|
|
return True
|
|
if not self.env.su and self.filtered("holiday_id"):
|
|
return False
|
|
return super()._check_can_update_timesheet()
|
|
|
|
def write(self, vals):
|
|
if vals and self.filtered("holiday_id"):
|
|
if set(vals) <= self._sheet_neutral_fields():
|
|
linking = self.with_context(
|
|
sheet_link_write=self._sheet_link_write_token()
|
|
)
|
|
return super(AccountAnalyticLine, linking).write(vals)
|
|
if not self._check_can_update_timesheet():
|
|
line = self.filtered("holiday_id")[:1]
|
|
raise UserError(
|
|
_(
|
|
"Time off hours are managed from the Time Off application"
|
|
" and cannot be changed from a timesheet sheet.\n"
|
|
"Sheet: %(sheet)s\n"
|
|
"Day: %(day)s",
|
|
sheet=line.sheet_id.complete_name or "-",
|
|
day=format_date(self.env, line.date),
|
|
)
|
|
)
|
|
return super().write(vals)
|
|
|
|
def unlink(self):
|
|
leave_lines = self.filtered("holiday_id")
|
|
if leave_lines and leave_lines._detach_leave_lines_on_unlink():
|
|
leave_lines.write({"sheet_id": False})
|
|
return super(AccountAnalyticLine, self - leave_lines).unlink()
|
|
return super().unlink()
|