# © 2019 Le Filament (<http://www.le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from datetime import datetime, time from odoo import _, api, fields, models from odoo.exceptions import UserError, ValidationError class ScopHrTimesheet(models.Model): _inherit = "account.analytic.line" def _default_ur(self): return self.env["res.company"]._ur_default_get() # Inherited fields name = fields.Char(required=False) partner_id = fields.Many2one(required=True) # New fields cgscop_timesheet_code_id = fields.Many2one( related="project_id.cgscop_timesheet_code_id", string="Code Activité National", store=True, ) ur_financial_system_id = fields.Many2one( comodel_name="ur.financial.system", string="Dispositif Financier" ) ur_regional_convention_id = fields.Many2one( comodel_name="ur.regional.convention", string="Convention Régionale" ) ur_id = fields.Many2one( "union.regionale", string="Union Régionale", index=True, ondelete="restrict", default=_default_ur, ) sheet_id = fields.Many2one( comodel_name="cgscop.timesheet.sheet", string="Feuille de temps", readonly=True, copy=False, ) state = fields.Selection( [ ("to_report", "A rapporter"), ("draft", "Brouillon"), ("submit", "Soumis"), ("valid", "Validé"), ], compute="_compute_state", string="Statut", copy=False, index=True, readonly=True, store=True, ) ur_financial_system_nb = fields.Integer( string="Nb Dispositifs Financiers", compute="_compute_ur_system_nb" ) ur_regional_convention_nb = fields.Integer( string="Nb conventions régionales", compute="_compute_ur_system_nb" ) is_present = fields.Boolean("Présentiel") location = fields.Selection( [ ("R", "Rendez-vous"), ("D", "Déplacement"), ("B", "Bureau"), ], string="Lieu", ) justificatifs = fields.Char(string="Justificatifs", required=False) is_overtime = fields.Boolean( string="Heures supplémentaires", default=False, ) is_overtime_allowed = fields.Boolean( string="Heures supplémentaires autorisées", compute="_compute_overtime_allowed", ) travel_time = fields.Float( string="Temps déplacement", ) is_travel_time_allowed = fields.Boolean( string="Temps de déplacement autorisé", compute="_compute_travel_time_allowed", ) calendar_l1 = fields.Char( string="Ligne 1 calendrier", compute="_compute_calendar_l1", ) calendar_l2 = fields.Char( string="Ligne 2 calendrier", compute="_compute_calendar_l2", ) # ------------------------------------------------------ # Compute Functions # ------------------------------------------------------ @api.depends("ur_id") def _compute_overtime_allowed(self): for rec in self: rec.is_overtime_allowed = self.env.company.overtime_working @api.depends("ur_id") def _compute_travel_time_allowed(self): for rec in self: rec.is_travel_time_allowed = self.env.company.use_travel_time @api.depends("ur_id") def _compute_ur_system_nb(self): for timesheet in self: # Calcul nombre de dispositifs financiers financial_system = timesheet.env["ur.financial.system"].search( [("ur_id", "=", timesheet.ur_id.id)] ) timesheet.ur_financial_system_nb = len(financial_system) # Calcul nombre de conventions regional_convention = timesheet.env["ur.regional.convention"].search( [("ur_id", "=", timesheet.ur_id.id)] ) timesheet.ur_regional_convention_nb = len(regional_convention) @api.depends("sheet_id", "sheet_id.state") def _compute_state(self): for timesheet in self: if not timesheet.sheet_id: timesheet.state = "to_report" else: timesheet.state = timesheet.sheet_id.state @api.depends("project_id", "partner_id") def _compute_calendar_l1(self): for ts in self: ts.calendar_l1 = "" if ts.project_id: ts.calendar_l1 += ts.project_id.name + ", " if ts.partner_id: ts.calendar_l1 += ts.partner_id.name @api.depends("unit_amount") def _compute_calendar_l2(self): for ts in self: ts.calendar_l2 = "Durée : " + str(ts.unit_amount) + " heure(s)" # ------------------------------------------------------ # Override le _rec_name # ------------------------------------------------------ @api.depends("project_id", "partner_id") def name_get(self): result = [] for ts in self: name = ts.calendar_l1 result.append((ts.id, name)) return result # ------------------------------------------------------ # OnChange Functions # ------------------------------------------------------ @api.onchange("project_id") def onchange_project_id(self): self.partner_id = self.project_id.partner_id @api.onchange("partner_id") def onchange_partner_id(self): # affiche le Dispositif Financier par défaut sur la LdT # si il n'y a pas de date limite du dispositif # ou si la date de la Ldt est inférieure à la date limite du dispositif if ( not self.partner_id.ur_financial_system_date or self.date <= self.partner_id.ur_financial_system_date ): self.ur_financial_system_id = self.partner_id.ur_financial_system_id # affiche la Convention par défaut sur la LdT # si il n'y a pas de date limite de la convention # ou si la date de la LdT est inférieure à la date limite de la convention if ( not self.partner_id.ur_regional_convention_date or self.date <= self.partner_id.ur_regional_convention_date ): self.ur_regional_convention_id = self.partner_id.ur_regional_convention_id # ------------------------------------------------------ # Contrains # ------------------------------------------------------ @api.constrains("unit_amount", "date") def _check_hours(self): for record in self: if record.project_id: lines = self.search( [ ("date", "=", record.date), ("employee_id", "=", record.employee_id.id), ] ) total = sum(lines.mapped("unit_amount")) if ( not self.env.company.day_working and total > self.env.company.day_duration ): raise ValidationError( _( "Vous ne pouvez imputer plus de %sh sur la même journée.\n" "Journée du %s" ) % ( self.env.company.day_duration, record.date.strftime("%d/%m/%Y"), ) ) @api.constrains("date") def _check_weekday(self): if self.env.company.weekend_working: return for line in self: dt = datetime.combine(line.date, time(12, 00)) holiday = self.env["resource.calendar.leaves"].search( [ "|", ("company_id", "=", False), ("company_id", "=", self.env.company.id), ("date_from", "<=", dt), ("date_to", ">=", dt), ("resource_id", "=", False), ] ) if not line.holiday_id and (line.date.weekday() in (5, 6) or holiday): raise ValidationError( _( "Vous ne pouvez imputer du temps sur un weekend " "ou un jour férié." ) ) # ------------------------------------------------------ # Override ORM # ------------------------------------------------------ def unlink(self): for timesheet in self: if timesheet.state in ["submit", "valid"]: raise UserError( _( "Vous ne pouvez pas supprimer une " "ligne de temps soumise ou validée" ) ) super(ScopHrTimesheet, self).unlink() # ------------------------------------------------------ # Actions # ------------------------------------------------------ def action_submit_timesheet_lines(self): """ Crée une feuille de temps avec les lignes sélectionnées """ if any(time.state != "to_report" or time.sheet_id for time in self): raise UserError(_("Vous ne pouvez pas insérer 2 fois la même ligne !")) if len(self.mapped("employee_id")) != 1: raise UserError( _( "Il ne peut y avoir plusieurs employés dans une " "même feuille de temps." ) ) return { "name": "New Expense Report", "type": "ir.actions.act_window", "view_mode": "form", "res_model": "cgscop.timesheet.sheet", "target": "current", "context": { "default_timesheet_line_ids": self.ids, "default_employee_id": self[0].employee_id.id, "default_name": self[0].name if len(self) == 1 else "", }, } # ------------------------------------------------------ # Modification du context pour cacher les colonnes # ------------------------------------------------------ @api.model def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): custom_context = self.env.context.copy() current_ur_id = self.env.context['current_ur_id'] nbfs = self.env["ur.financial.system"].search([("ur_id", "=", current_ur_id)]) if len(nbfs) == 0: custom_context['hide_financial_system'] = True nbrc = self.env["ur.regional.convention"].search([("ur_id", "=", current_ur_id)]) if len(nbrc) == 0: custom_context['hide_regional_convention'] = True overtime_allowed = self.env.company.overtime_working if not overtime_allowed: custom_context['hide_overtime'] = True travel_time_allowed = self.env.company.use_travel_time if not travel_time_allowed: custom_context['hide_travel_time'] = True res = super(ScopHrTimesheet, self.with_context(custom_context)).fields_view_get( view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu) return res