Newer
Older
# © 2019 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

Benjamin - Le Filament
committed
from datetime import datetime, time
from odoo import _, api, fields, models

Benjamin - Le Filament
committed
from odoo.exceptions import UserError, ValidationError
class ScopHrTimesheet(models.Model):
_inherit = "account.analytic.line"
return self.env["res.company"]._ur_default_get()
partner_id = fields.Many2one(required=True)
related="project_id.cgscop_timesheet_code_id",
string="Code Activité National",
store=True,
)
comodel_name="ur.financial.system", string="Dispositif Financier"
)

Benjamin - Le Filament
committed
ur_regional_convention_id = fields.Many2one(
comodel_name="ur.regional.convention", string="Convention Régionale"
)
"union.regionale",
string="Union Régionale",
ondelete="restrict",
default=_default_ur,
)

Benjamin - Le Filament
committed
sheet_id = fields.Many2one(
comodel_name="cgscop.timesheet.sheet",

Benjamin - Le Filament
committed
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",

Benjamin - Le Filament
committed
copy=False,
index=True,
readonly=True,

Benjamin - Le Filament
committed
ur_financial_system_nb = fields.Integer(
string="Nb Dispositifs Financiers", compute="_compute_ur_system_nb"
)

Benjamin - Le Filament
committed
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",
)

Benjamin - Le Filament
committed
# ------------------------------------------------------
# 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")

Benjamin - Le Filament
committed
def _compute_ur_system_nb(self):

Benjamin - Le Filament
committed
for timesheet in self:

Benjamin - Le Filament
committed
# 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)

Benjamin - Le Filament
committed
# 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)

Benjamin - Le Filament
committed
@api.depends("sheet_id", "sheet_id.state")

Benjamin - Le Filament
committed
def _compute_state(self):
for timesheet in self:
if not timesheet.sheet_id:
timesheet.state = "to_report"

Benjamin - Le Filament
committed
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

Benjamin - Le Filament
committed
@api.onchange("partner_id")

Benjamin - Le Filament
committed
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
):

Benjamin - Le Filament
committed
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

Benjamin - Le Filament
committed

Benjamin - Le Filament
committed
# ------------------------------------------------------
# Contrains
# ------------------------------------------------------
@api.constrains("unit_amount", "date")

Benjamin - Le Filament
committed
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"),
)
)

Benjamin - Le Filament
committed
@api.constrains("date")

Benjamin - Le Filament
committed
def _check_weekday(self):

Hervé Silvant - CGScop
committed
if self.env.company.weekend_working:
return

Benjamin - Le Filament
committed
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):

Benjamin - Le Filament
committed
raise ValidationError(
_(
"Vous ne pouvez imputer du temps sur un weekend "
"ou un jour férié."
)

Benjamin - Le Filament
committed

Benjamin - Le Filament
committed
# ------------------------------------------------------
# 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"
)

Benjamin - Le Filament
committed
super(ScopHrTimesheet, self).unlink()

Benjamin - Le Filament
committed
# ------------------------------------------------------
# Actions
# ------------------------------------------------------
def action_submit_timesheet_lines(self):

Benjamin - Le Filament
committed
"""
Crée une feuille de temps avec les lignes sélectionnées

Benjamin - Le Filament
committed
"""
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:

Benjamin - Le Filament
committed
raise UserError(
_(
"Il ne peut y avoir plusieurs employés dans une "
"même feuille de temps."
)

Benjamin - Le Filament
committed
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 "",
},

Benjamin - Le Filament
committed
}

Hervé Silvant - CGScop
committed
# ------------------------------------------------------
# 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

Hervé Silvant - CGScop
committed
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