# Copyright 2018 ForgeFlow, S.L. # Copyright 2018-2019 Brainbean Apps (https://brainbeanapps.com) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from odoo import api, fields, models from odoo.exceptions import UserError, ValidationError class AccountAnalyticLine(models.Model): _inherit = "account.analytic.line" sheet_id = fields.Many2one(comodel_name="hr_timesheet.sheet", string="Sheet") sheet_state = fields.Selection(string="Sheet State", related="sheet_id.state") def _get_sheet_domain(self): """Hook for extensions""" self.ensure_one() return [ ("date_end", ">=", self.date), ("date_start", "<=", self.date), ("employee_id", "=", self.employee_id.id), ("company_id", "in", [self.company_id.id, False]), ("state", "in", ["new", "draft"]), ] def _determine_sheet(self): """Hook for extensions""" self.ensure_one() return self.env["hr_timesheet.sheet"].search(self._get_sheet_domain(), limit=1) def _compute_sheet(self): """Links the timesheet line to the corresponding sheet""" for timesheet in self.filtered("project_id"): sheet = timesheet._determine_sheet() if timesheet.sheet_id != sheet: timesheet.sheet_id = sheet @api.constrains("company_id", "sheet_id") def _check_company_id_sheet_id(self): for aal in self.sudo(): if ( aal.company_id and aal.sheet_id.company_id and aal.company_id != aal.sheet_id.company_id ): raise ValidationError( aal.env._( "You cannot create a timesheet of a different company " "than the one of the timesheet sheet:" "\n - %(sheet_name)s of %(sheet_company)s" "\n - %(name)s of %(company)s", sheet_name=aal.sheet_id.complete_name, sheet_company=aal.sheet_id.company_id.name, name=aal.name, company=aal.company_id.name, ) ) @api.model_create_multi def create(self, vals_list): for vals in vals_list: if not self.env.context.get("sheet_create") and "sheet_id" in vals: del vals["sheet_id"] records = super().create(vals_list) records._compute_sheet() return records @api.model def _sheet_create(self, values): return self.with_context(sheet_create=True).create(values) def write(self, values): self._check_state_on_write(values) res = super().write(values) if self._timesheet_should_compute_sheet(values): self._compute_sheet() return res def unlink(self): self._check_state() return super().unlink() def _check_state_on_write(self, values): """Hook for extensions""" if self._timesheet_should_check_write(values): self._check_state() @api.model def _timesheet_should_check_write(self, values): """Hook for extensions""" return bool(set(self._get_timesheet_protected_fields()) & set(values.keys())) @api.model def _timesheet_should_compute_sheet(self, values): """Hook for extensions""" return any(f in self._get_sheet_affecting_fields() for f in values) @api.model def _get_timesheet_protected_fields(self): """Hook for extensions""" return [ "name", "date", "unit_amount", "user_id", "employee_id", "department_id", "company_id", "task_id", "project_id", "sheet_id", ] @api.model def _get_sheet_affecting_fields(self): """Hook for extensions""" return ["date", "employee_id", "project_id", "company_id"] def _check_state(self): if self.env.context.get("skip_check_state"): return for line in self.exists().filtered("sheet_id"): if line.sheet_id.state not in ["new", "draft"]: raise UserError( line.env._( "You cannot modify an entry in a confirmed timesheet sheet" ": %(names)s", names=line.sheet_id.complete_name, ) ) def merge_timesheets(self): unit_amount = sum(t.unit_amount for t in self) amount = sum(t.amount for t in self) self[0].write({"unit_amount": unit_amount, "amount": amount}) self[1:].unlink() return self[0] def _check_can_write(self, values): is_installed = ( self.env["ir.module.module"] .sudo() .search( [ ("name", "=", "project_timesheet_holidays"), ("state", "=", "installed"), ] ) ) if is_installed: if not self.env.su: if ( hasattr(self, "holiday_id") and self.holiday_id and values.get("sheet_id", False) ): # Dont raise error during create return True if hasattr(self, "holiday_id") and self.holiday_id and self.sheet_id: raise UserError( self.env._( """You cannot modify timesheets that are linked to \ time off requests. Please use the Time Off application to modify your time off requests instead.""" ) ) return super()._check_can_write(values)