249 lines
7.8 KiB
Python
249 lines
7.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from odoo import api, fields, models, _
|
|
from datetime import datetime, timedelta
|
|
|
|
class PlanningModification(models.Model):
|
|
"""Modèle pour suivre les modifications de créneaux de planning via le portail."""
|
|
_name = 'portal.planning.modification'
|
|
_description = 'Modification de Planning via Portail'
|
|
_rec_name = 'slot_id'
|
|
_order = 'date desc'
|
|
_inherit = ['mail.thread', 'mail.activity.mixin']
|
|
|
|
slot_id = fields.Many2one(
|
|
'planning.slot',
|
|
string='Créneau de planning',
|
|
required=True,
|
|
ondelete='cascade',
|
|
tracking=True
|
|
)
|
|
user_id = fields.Many2one(
|
|
'res.users',
|
|
string='Demandé par',
|
|
required=True,
|
|
default=lambda self: self.env.user.id,
|
|
tracking=True
|
|
)
|
|
employee_id = fields.Many2one(
|
|
'hr.employee',
|
|
string='Employé',
|
|
related='slot_id.employee_id',
|
|
store=True,
|
|
readonly=True
|
|
)
|
|
date = fields.Datetime(
|
|
string='Date de demande',
|
|
required=True,
|
|
default=fields.Datetime.now,
|
|
tracking=True
|
|
)
|
|
|
|
# Valeurs originales
|
|
old_start = fields.Datetime(
|
|
string='Début original',
|
|
required=True,
|
|
tracking=True
|
|
)
|
|
old_end = fields.Datetime(
|
|
string='Fin originale',
|
|
required=True,
|
|
tracking=True
|
|
)
|
|
old_role_id = fields.Many2one(
|
|
'planning.role',
|
|
string='Rôle original',
|
|
tracking=True
|
|
)
|
|
|
|
# Nouvelles valeurs
|
|
new_start = fields.Datetime(
|
|
string='Nouveau début',
|
|
required=True,
|
|
tracking=True
|
|
)
|
|
new_end = fields.Datetime(
|
|
string='Nouvelle fin',
|
|
required=True,
|
|
tracking=True
|
|
)
|
|
new_role_id = fields.Many2one(
|
|
'planning.role',
|
|
string='Nouveau rôle',
|
|
tracking=True
|
|
)
|
|
|
|
# Suivi de la demande
|
|
state = fields.Selection([
|
|
('pending', 'En attente'),
|
|
('approved', 'Approuvé'),
|
|
('rejected', 'Refusé'),
|
|
('cancelled', 'Annulé')
|
|
], string='État', default='pending', tracking=True, copy=False)
|
|
approver_id = fields.Many2one(
|
|
'res.users',
|
|
string='Approuvé/Refusé par',
|
|
copy=False,
|
|
tracking=True
|
|
)
|
|
approval_date = fields.Datetime(
|
|
string='Date d\'approbation/refus',
|
|
copy=False,
|
|
tracking=True
|
|
)
|
|
notes = fields.Text(
|
|
string='Notes',
|
|
tracking=True
|
|
)
|
|
company_id = fields.Many2one(
|
|
'res.company',
|
|
string='Société',
|
|
default=lambda self: self.env.company
|
|
)
|
|
|
|
# Champs calculés
|
|
allocated_hours = fields.Float(
|
|
string='Heures allouées',
|
|
compute='_compute_allocated_hours',
|
|
store=True,
|
|
readonly=True
|
|
)
|
|
can_approve = fields.Boolean(
|
|
compute='_compute_can_approve',
|
|
string='Peut approuver',
|
|
help="Indique si l'utilisateur actuel peut approuver cette demande"
|
|
)
|
|
can_reject = fields.Boolean(
|
|
compute='_compute_can_reject',
|
|
string='Peut refuser',
|
|
help="Indique si l'utilisateur actuel peut refuser cette demande"
|
|
)
|
|
can_cancel = fields.Boolean(
|
|
compute='_compute_can_cancel',
|
|
string='Peut annuler',
|
|
help="Indique si l'utilisateur actuel peut annuler cette demande"
|
|
)
|
|
|
|
@api.depends('new_start', 'new_end')
|
|
def _compute_allocated_hours(self):
|
|
"""Calcule le nombre d'heures allouées pour la modification."""
|
|
for modification in self:
|
|
if modification.new_start and modification.new_end:
|
|
delta = modification.new_end - modification.new_start
|
|
modification.allocated_hours = delta.total_seconds() / 3600
|
|
else:
|
|
modification.allocated_hours = 0
|
|
|
|
@api.depends('state')
|
|
def _compute_can_approve(self):
|
|
"""Détermine si l'utilisateur actuel peut approuver cette demande."""
|
|
is_manager = self.env.user.has_group('planning.group_planning_manager')
|
|
for modification in self:
|
|
modification.can_approve = modification.state == 'pending' and is_manager
|
|
|
|
@api.depends('state')
|
|
def _compute_can_reject(self):
|
|
"""Détermine si l'utilisateur actuel peut refuser cette demande."""
|
|
is_manager = self.env.user.has_group('planning.group_planning_manager')
|
|
for modification in self:
|
|
modification.can_reject = modification.state == 'pending' and is_manager
|
|
|
|
@api.depends('state', 'user_id')
|
|
def _compute_can_cancel(self):
|
|
"""Détermine si l'utilisateur actuel peut annuler cette demande."""
|
|
is_manager = self.env.user.has_group('planning.group_planning_manager')
|
|
for modification in self:
|
|
modification.can_cancel = (
|
|
modification.state == 'pending' and
|
|
(modification.user_id.id == self.env.user.id or is_manager)
|
|
)
|
|
|
|
def action_approve(self):
|
|
"""Approuve la demande de modification."""
|
|
self.ensure_one()
|
|
if not self.can_approve:
|
|
return False
|
|
|
|
# Mettre à jour le créneau de planning
|
|
self.slot_id.write({
|
|
'start_datetime': self.new_start,
|
|
'end_datetime': self.new_end,
|
|
'allocated_hours': self.allocated_hours,
|
|
'role_id': self.new_role_id.id if self.new_role_id else self.slot_id.role_id.id,
|
|
'portal_modification_approved': 'approved',
|
|
'portal_confirmed': False, # Nécessite une nouvelle confirmation
|
|
})
|
|
|
|
# Mettre à jour la demande
|
|
self.write({
|
|
'state': 'approved',
|
|
'approver_id': self.env.user.id,
|
|
'approval_date': fields.Datetime.now()
|
|
})
|
|
|
|
# Envoyer une notification à l'employé
|
|
self.message_post(
|
|
body=_('Demande de modification approuvée par %s') % self.env.user.name,
|
|
message_type='notification',
|
|
subtype_xmlid='mail.mt_comment',
|
|
partner_ids=[self.user_id.partner_id.id]
|
|
)
|
|
|
|
return True
|
|
|
|
def action_reject(self):
|
|
"""Refuse la demande de modification."""
|
|
self.ensure_one()
|
|
if not self.can_reject:
|
|
return False
|
|
|
|
# Mettre à jour le créneau de planning
|
|
self.slot_id.write({
|
|
'portal_modification_approved': 'rejected'
|
|
})
|
|
|
|
# Mettre à jour la demande
|
|
self.write({
|
|
'state': 'rejected',
|
|
'approver_id': self.env.user.id,
|
|
'approval_date': fields.Datetime.now()
|
|
})
|
|
|
|
# Envoyer une notification à l'employé
|
|
self.message_post(
|
|
body=_('Demande de modification refusée par %s') % self.env.user.name,
|
|
message_type='notification',
|
|
subtype_xmlid='mail.mt_comment',
|
|
partner_ids=[self.user_id.partner_id.id]
|
|
)
|
|
|
|
return True
|
|
|
|
def action_cancel(self):
|
|
"""Annule la demande de modification."""
|
|
self.ensure_one()
|
|
if not self.can_cancel:
|
|
return False
|
|
|
|
# Mettre à jour le créneau de planning si c'est l'employé qui annule
|
|
if self.user_id.id == self.env.user.id:
|
|
self.slot_id.write({
|
|
'portal_modification_approved': False,
|
|
'portal_modified': False
|
|
})
|
|
|
|
# Mettre à jour la demande
|
|
self.write({
|
|
'state': 'cancelled',
|
|
'approver_id': self.env.user.id,
|
|
'approval_date': fields.Datetime.now()
|
|
})
|
|
|
|
# Envoyer une notification
|
|
self.message_post(
|
|
body=_('Demande de modification annulée par %s') % self.env.user.name,
|
|
message_type='notification',
|
|
subtype_xmlid='mail.mt_comment'
|
|
)
|
|
|
|
return True
|