116 lines
5.2 KiB
Python
116 lines
5.2 KiB
Python
from django.conf import settings
|
||
from django.db import models
|
||
|
||
|
||
class PlanningState(models.Model):
|
||
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
||
revision = models.PositiveIntegerField(default=0)
|
||
|
||
|
||
class WorkSchedule(models.Model):
|
||
class Mode(models.TextChoices):
|
||
PRECISE = 'precise', 'Horaires précis'
|
||
DAILY_HOURS = 'daily_hours', 'Nombre d’heures par jour'
|
||
WEEKLY_HOURS = 'weekly_hours', 'Nombre d’heures par semaine'
|
||
|
||
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='work_schedules')
|
||
valid_from = models.DateField()
|
||
cycle_weeks = models.PositiveSmallIntegerField(default=1)
|
||
mode = models.CharField(max_length=16, choices=Mode.choices, default=Mode.PRECISE)
|
||
day_targets = models.JSONField(default=list, blank=True)
|
||
week_targets = models.JSONField(default=list, blank=True)
|
||
valid_to = models.DateField(null=True, blank=True)
|
||
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL, related_name='+')
|
||
updated_at = models.DateTimeField(auto_now=True)
|
||
|
||
class Meta:
|
||
ordering = ['-valid_from', '-pk']
|
||
constraints = [models.UniqueConstraint(fields=['user', 'valid_from'], name='schedule_user_start_unique')]
|
||
|
||
|
||
class WorkScheduleSlot(models.Model):
|
||
schedule = models.ForeignKey(WorkSchedule, on_delete=models.CASCADE, related_name='slots')
|
||
weekday = models.PositiveSmallIntegerField() # lundi = 0
|
||
week_index = models.PositiveSmallIntegerField(default=0)
|
||
start_time = models.TimeField()
|
||
end_time = models.TimeField()
|
||
end_day_offset = models.PositiveSmallIntegerField(default=0)
|
||
|
||
class Meta:
|
||
ordering = ['week_index', 'weekday', 'start_time']
|
||
|
||
|
||
class ScheduleException(models.Model):
|
||
class Mode(models.TextChoices):
|
||
PRECISE = 'precise', 'Horaires précis'
|
||
DAILY_HOURS = 'daily_hours', 'Nombre d’heures à effectuer'
|
||
|
||
class Kind(models.TextChoices):
|
||
WORK = 'work', 'Horaires exceptionnels'
|
||
REST = 'rest', 'Repos'
|
||
ABSENCE = 'absence', 'Congé / absence'
|
||
|
||
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='schedule_exceptions')
|
||
label = models.CharField(max_length=160, blank=True)
|
||
kind = models.CharField(max_length=8, choices=Kind.choices, default=Kind.WORK)
|
||
mode = models.CharField(max_length=16, choices=Mode.choices, default=Mode.PRECISE)
|
||
target_minutes = models.PositiveSmallIntegerField(null=True, blank=True)
|
||
start_date = models.DateField()
|
||
end_date = models.DateField(null=True, blank=True)
|
||
recurring = models.BooleanField(default=False)
|
||
weekdays = models.JSONField(default=list)
|
||
every_weeks = models.PositiveSmallIntegerField(default=1)
|
||
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL, related_name='+')
|
||
request = models.ForeignKey('DayChangeRequest', null=True, blank=True, on_delete=models.SET_NULL, related_name='applied_exceptions')
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
updated_at = models.DateTimeField(auto_now=True)
|
||
|
||
class Meta:
|
||
ordering = ['-pk']
|
||
indexes = [models.Index(fields=['user', 'start_date'], name='exception_user_date_idx')]
|
||
|
||
|
||
class ExceptionSlot(models.Model):
|
||
exception = models.ForeignKey(ScheduleException, on_delete=models.CASCADE, related_name='slots')
|
||
start_time = models.TimeField()
|
||
end_time = models.TimeField()
|
||
end_day_offset = models.PositiveSmallIntegerField(default=0)
|
||
|
||
class Meta:
|
||
ordering = ['start_time']
|
||
|
||
|
||
class DayChangeRequest(models.Model):
|
||
class Kind(models.TextChoices):
|
||
LEAVE = 'leave', 'Congé / absence'
|
||
HOURS = 'hours', 'Modification d’horaires'
|
||
MOVE = 'move', 'Déplacement de journée'
|
||
SWAP = 'swap', 'Échange de journée'
|
||
|
||
class Status(models.TextChoices):
|
||
PENDING = 'pending', 'En attente'
|
||
APPROVED = 'approved', 'Acceptée'
|
||
REJECTED = 'rejected', 'Refusée'
|
||
CANCELLED = 'cancelled', 'Annulée'
|
||
|
||
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='day_requests')
|
||
kind = models.CharField(max_length=8, choices=Kind.choices)
|
||
start_date = models.DateField()
|
||
end_date = models.DateField()
|
||
target_date = models.DateField(null=True, blank=True)
|
||
target_user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL, related_name='received_swaps')
|
||
reason = models.TextField(blank=True, max_length=2000)
|
||
proposed_slots = models.JSONField(default=list)
|
||
before = models.JSONField(default=list)
|
||
after = models.JSONField(default=list)
|
||
status = models.CharField(max_length=10, choices=Status.choices, default=Status.PENDING)
|
||
reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL, related_name='+')
|
||
reviewed_at = models.DateTimeField(null=True, blank=True)
|
||
response = models.TextField(blank=True, max_length=2000)
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
updated_at = models.DateTimeField(auto_now=True)
|
||
|
||
class Meta:
|
||
ordering = ['-created_at', '-pk']
|
||
indexes = [models.Index(fields=['status', 'user'], name='request_status_user_idx')]
|