# © 2020 Le Filament (<http://www.le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import _, api, fields, models from odoo.exceptions import UserError, ValidationError class ScopHrTimesheetSheet(models.Model): _name = "cgscop.timesheet.sheet" _inherit = ["mail.thread", "mail.activity.mixin"] _description = "Timesheet Report" _order = "create_date desc, validation_date desc, id desc" def _default_ur(self): return self.env["res.company"]._ur_default_get() name = fields.Char("Nom", required=True) timesheet_line_ids = fields.One2many( comodel_name="account.analytic.line", inverse_name="sheet_id", string="Lignes de temps", states={"valid": [("readonly", True)]}, copy=False, ) state = fields.Selection( [("draft", "Brouillon"), ("submit", "Soumis"), ("valid", "Validé")], string="Statut", index=True, tracking=True, copy=False, default="draft", required=True, ) employee_id = fields.Many2one( comodel_name="hr.employee", string="Employé", required=True, readonly=True, states={"draft": [("readonly", False)]}, default=lambda self: self.env["hr.employee"].search( [("user_id", "=", self.env.uid)], limit=1 ), ) total_hour = fields.Float(string="Total", compute="_compute_hour", store=True) company_id = fields.Many2one( comodel_name="res.company", string="Company", readonly=True, states={"draft": [("readonly", False)]}, default=lambda self: self.env.company, ) validation_date = fields.Date("Date de validation") submit_date = fields.Date("Soumis le") ur_id = fields.Many2one( "union.regionale", string="Union Régionale", index=True, ondelete="restrict", default=_default_ur, ) can_edit = fields.Boolean("Can Reset", compute="_compute_can_reset") # ------------------------------------------------------ # Compute Functions # ------------------------------------------------------ @api.depends("timesheet_line_ids", "timesheet_line_ids.unit_amount") def _compute_hour(self): for sheet in self: sheet.total_hour = sum(sheet.timesheet_line_ids.mapped("unit_amount")) def _compute_can_reset(self): is_timesheet_user = self.user_has_groups("hr_timesheet.group_timesheet_manager") for sheet in self: if sheet.state == "draft" or is_timesheet_user: sheet.can_edit = True else: sheet.can_edit = False # ------------------------------------------------------ # Constain Functions # ------------------------------------------------------ @api.constrains("timesheet_line_ids", "employee_id") def _check_employee(self): for sheet in self: employee_ids = sheet.timesheet_line_ids.mapped("employee_id") if len(employee_ids) > 1 or ( len(employee_ids) == 1 and employee_ids != sheet.employee_id ): raise ValidationError( _( "Vous ne pouvez pas ajouter les lignes" " de temps de plusieurs employés." ) ) # ------------------------------------------------------ # Override ORM # ------------------------------------------------------ def unlink(self): for timesheet in self: if timesheet.state in ["submit", "valid"]: raise UserError( _( "Vous ne pouvez pas supprimer une " "feuille de temps soumise ou validée" ) ) super(ScopHrTimesheetSheet, self).unlink() # ------------------------------------------------------ # Action button # ------------------------------------------------------ def action_submit_timesheet(self): self.write({"state": "submit", "submit_date": fields.Date.today()}) def approve_timesheet_sheets(self): self.write({"state": "valid", "validation_date": fields.Date.today()}) def reset_timesheet_sheets(self): self.write({"state": "draft", "submit_date": False, "validation_date": False}) def print_timesheet(self): return self.env.ref( "cgscop_timesheet.cgscop_timesheet_sheet_report" ).report_action(self) # ------------------------------------------------------ # Retourne les lignes de la Fdt avec les totaux par projet # ------------------------------------------------------ def _to_duration(self, infloat): return '{0:02.0f}:{1:02.0f}'.format(*divmod(infloat * 60, 60)) def _get_timesheet_line_act(self): for sheet in self: lines = sheet.timesheet_line_ids.sorted(key=lambda b: (b.project_id.name, b.date)) rows = [] last_project = False tot_project = 0 for line in lines: # On insère un total intermédiaire if last_project != line.project_id.name and tot_project != 0: rows.append({ 'total': 1, 'name': False, 'partner': False, 'project': False, 'date': False, 'ur_financial_system': 'Total ' + last_project + ' : ' + self._to_duration(tot_project), 'unit_amount': False, }) tot_project = 0 # On insère la ligne lue rows.append({ 'total': 0, 'name': line.name, 'partner': line.partner_id.name, 'project': line.project_id.name, 'date': line.date, 'ur_financial_system': line.ur_financial_system_id.name, 'unit_amount': self._to_duration(line.unit_amount), }) last_project = line.project_id.name tot_project = tot_project + line.unit_amount # On insère le dernier total rows.append({ 'total': 1, 'name': False, 'partner': False, 'project': False, 'date': False, 'ur_financial_system': 'Total ' + last_project + ' : ' + self._to_duration(tot_project), 'unit_amount': False, }) return rows