Project

General

Profile

Download (17.7 KB) Statistics
| Branch: | Tag: | Revision:
1097fd0a Benjamin Dauvergne
# -*- coding: utf-8 -*-

1eab6c73 Frédéric Péters
from datetime import datetime, date, time as datetime_time
7a0a30d7 Benjamin Dauvergne
1097fd0a Benjamin Dauvergne
from django.db import models
f7d9fa12 Benjamin Dauvergne
from django.db.models import query
1097fd0a Benjamin Dauvergne
from django.contrib.auth.models import User
706c6be7 Benjamin Dauvergne
from django.template.defaultfilters import date as date_filter
f8f903c3 Benjamin Dauvergne
from django import forms
1097fd0a Benjamin Dauvergne
37093bfa Benjamin Dauvergne
from model_utils.managers import InheritanceManager
366eb65a Benjamin Dauvergne
ee47faa1 Jérôme Schneider
from calebasse.models import PhoneNumberField
aceeeca7 Mikaël Ates
from calebasse.ressources.models import Service, NamedAbstractModel
688c7fbe Mikaël Ates
from calebasse.models import (BaseModelMixin, WeekRankField,
PhoneNumberField, ZipCodeField)
f8f903c3 Benjamin Dauvergne
from calebasse.utils import weeks_since_epoch, weekday_ranks
7a0a30d7 Benjamin Dauvergne
from interval import Interval
1097fd0a Benjamin Dauvergne
1a43d77a Benjamin Dauvergne
from model_utils import Choices
f7d9fa12 Benjamin Dauvergne
from model_utils.managers import PassThroughManager

a01d85be Serghei MIHAI
from ..middleware.request import get_request

aceeeca7 Mikaël Ates
class Role(NamedAbstractModel):
users = models.ManyToManyField(User,
verbose_name=u'Utilisateurs', blank=True)

9e738c5d Benjamin Dauvergne
class People(BaseModelMixin, models.Model):
8e6fe119 Jérôme Schneider
GENDERS = Choices(
b8b97c77 Mikaël Ates
(1, 'Masculin'),
(2, 'Féminin'),
f8f903c3 Benjamin Dauvergne
)
8e6fe119 Jérôme Schneider
37093bfa Benjamin Dauvergne
objects = InheritanceManager()
f10536ea Jérôme Schneider
last_name = models.CharField(max_length=128, verbose_name=u'Nom',
db_index=True)
1178f357 Mikaël Ates
first_name = models.CharField(max_length=128, verbose_name=u'Prénom(s)',
cd8a83dc Jérôme Schneider
blank=True, null=True)
9e738c5d Benjamin Dauvergne
display_name = models.CharField(max_length=256,
08a6bedd Benjamin Dauvergne
verbose_name=u'Nom complet', editable=False, db_index=True)
1a43d77a Benjamin Dauvergne
gender = models.IntegerField(verbose_name=u"Genre", choices=GENDERS,
1a9b2fe9 Jérôme Schneider
max_length=1, blank=True, null=True)
ee47faa1 Jérôme Schneider
email = models.EmailField(blank=True, null=True)
phone = PhoneNumberField(verbose_name=u"Téléphone", blank=True, null=True)
1097fd0a Benjamin Dauvergne
e39efb4a Jérôme Schneider
def save(self, **kwargs):
1178f357 Mikaël Ates
if self.first_name:
self.display_name = self.first_name + ' ' + self.last_name.upper()
else:
self.display_name = self.last_name.upper()
e39efb4a Jérôme Schneider
super(People, self).save(**kwargs)
1097fd0a Benjamin Dauvergne
9e738c5d Benjamin Dauvergne
def __unicode__(self):
return self.display_name

b60abafc Frédéric Péters
def get_initials(self):
initials = []
if self.first_name:
43a788f8 Mikaël Ates
initials = [name[0].upper() for name in ' '.join(self.first_name.split('-')).split()]
initials += [name[0].upper() for name in ' '.join(self.last_name.split('-')).split()]
b60abafc Frédéric Péters
return ''.join(initials)

957da834 Benjamin Dauvergne
class Meta:
ordering = ['last_name', 'first_name']

f7d9fa12 Benjamin Dauvergne
class WorkerQuerySet(query.QuerySet):
0f0cacbb Jérôme Schneider
def for_service(self, service, type=None):
if type:
c0f82cd1 Frédéric Péters
return self.filter(enabled=True, services__in=[service], type=type)
0f0cacbb Jérôme Schneider
else:
c0f82cd1 Frédéric Péters
return self.filter(enabled=True, services__in=[service])
0f0cacbb Jérôme Schneider
6e58dbc4 Mikaël Ates
96f613c6 Benjamin Dauvergne
class Worker(People):
f7d9fa12 Benjamin Dauvergne
objects = PassThroughManager.for_queryset_class(WorkerQuerySet)()
97bee351 Jérôme Schneider
7967cb73 Jérôme Schneider
initials = models.CharField(max_length=5, verbose_name=u'Initiales', default='', blank=True)
9e738c5d Benjamin Dauvergne
type = models.ForeignKey('ressources.WorkerType',
verbose_name=u'Type de personnel')
38d1b4f8 Mikaël Ates
services = models.ManyToManyField('ressources.Service', blank=True, null=True)
6e58dbc4 Mikaël Ates
enabled = models.BooleanField(verbose_name=u'Actif',
default=True)
old_camsp_id = models.CharField(max_length=256,
verbose_name=u'Ancien ID au CAMSP', blank=True, null=True)
old_cmpp_id = models.CharField(max_length=256,
verbose_name=u'Ancien ID au CMPP', blank=True, null=True)
old_sessad_dys_id = models.CharField(max_length=256,
verbose_name=u'Ancien ID au SESSAD TED', blank=True, null=True)
old_sessad_ted_id = models.CharField(max_length=256,
verbose_name=u'Ancien ID au SESSAD DYS', blank=True, null=True)

97bee351 Jérôme Schneider
def save(self, **kwargs):
if not self.initials:
self.initials = self.get_initials()
super(Worker, self).save(**kwargs)

6e58dbc4 Mikaël Ates
def is_active(self):
return self.enabled
9e738c5d Benjamin Dauvergne
957da834 Benjamin Dauvergne
def is_away(self):
f8f903c3 Benjamin Dauvergne
if self.timetable_set.filter(weekday=date.today().weekday()).exists():
957da834 Benjamin Dauvergne
return False
return True

b478e27e Benjamin Dauvergne
@models.permalink
def get_absolute_url(self):
return ('worker_update', (), {
'service': self.services.all()[0].name.lower(),
'pk': self.pk })

96f613c6 Benjamin Dauvergne
class Meta:
verbose_name = u'Personnel'
verbose_name_plural = u'Personnels'
1097fd0a Benjamin Dauvergne
688c7fbe Mikaël Ates
class ExternalWorker(People):
description = models.TextField(blank=True, null=True, default=None)
address = models.CharField(max_length=120,
verbose_name=u"Adresse", blank=True, null=True, default=None)
address_complement = models.CharField(max_length=120,
blank=True,
null=True,
default=None,
verbose_name=u"Complément d'adresse")
zip_code = ZipCodeField(verbose_name=u"Code postal",
blank=True, null=True, default=None)
city = models.CharField(max_length=80, verbose_name=u"Ville",
blank=True, null=True, default=None)
phone_work = PhoneNumberField(verbose_name=u"Téléphone du travail",
blank=True, null=True, default=None)
fax = models.CharField(max_length=30,
blank=True, null=True, default=None)
type = models.ForeignKey('ressources.WorkerType',
26a5dbc0 Jérôme Schneider
verbose_name=u'Spécialité', default=18)
688c7fbe Mikaël Ates
old_id = models.CharField(max_length=256,
verbose_name=u'Ancien ID', blank=True, null=True)
old_service = models.CharField(max_length=256,
verbose_name=u'Ancien Service', blank=True, null=True)
class Meta:
verbose_name = u'Intervenant extérieur'
verbose_name_plural = u'Intervenants extérieurs'

class ExternalTherapist(People):
description = models.TextField(blank=True, null=True, default=None)
address = models.CharField(max_length=120,
verbose_name=u"Adresse", blank=True, null=True, default=None)
address_complement = models.CharField(max_length=120,
blank=True,
null=True,
default=None,
verbose_name=u"Complément d'adresse")
zip_code = ZipCodeField(verbose_name=u"Code postal",
blank=True, null=True, default=None)
city = models.CharField(max_length=80, verbose_name=u"Ville",
blank=True, null=True, default=None)
phone_work = PhoneNumberField(verbose_name=u"Téléphone du travail",
blank=True, null=True, default=None)
fax = models.CharField(max_length=30,
blank=True, null=True, default=None)
type = models.ForeignKey('ressources.WorkerType',
26a5dbc0 Jérôme Schneider
verbose_name=u'Spécialité', default=18)
688c7fbe Mikaël Ates
old_id = models.CharField(max_length=256,
verbose_name=u'Ancien ID', blank=True, null=True)
old_service = models.CharField(max_length=256,
verbose_name=u'Ancien Service', blank=True, null=True)
old_id = models.CharField(max_length=256,
verbose_name=u'Ancien ID', blank=True, null=True)
old_service = models.CharField(max_length=256,
verbose_name=u'Ancien Service', blank=True, null=True)
class Meta:
verbose_name = u'Médecin extérieur'
verbose_name_plural = u'Médecins extérieurs'

65141e8b Benjamin Dauvergne
class UserWorker(BaseModelMixin, models.Model):
user = models.OneToOneField('auth.User')
9e738c5d Benjamin Dauvergne
worker = models.ForeignKey('Worker',
verbose_name=u'Personnel')
96f613c6 Benjamin Dauvergne
9e738c5d Benjamin Dauvergne
def __unicode__(self):
65141e8b Benjamin Dauvergne
return u'Lien entre la personne {0} et l\'utilisateur {1}'.format(
self.worker, self.user)
1097fd0a Benjamin Dauvergne
96f613c6 Benjamin Dauvergne
class SchoolTeacher(People):
schools = models.ManyToManyField('ressources.School')
1cba0446 Benjamin Dauvergne
role = models.ForeignKey('ressources.SchoolTeacherRole')
1097fd0a Benjamin Dauvergne
f7d9fa12 Benjamin Dauvergne
class TimeTableQuerySet(query.QuerySet):
f8f903c3 Benjamin Dauvergne
def current(self, today=None):
if today is None:
today = date.today()
33e71e35 Benjamin Dauvergne
return self.filter(models.Q(start_date__lte=today) | models.Q(start_date__isnull=True)) \
.filter(models.Q(end_date__gte=today) | models.Q(end_date__isnull=True))
04022fee Benjamin Dauvergne
f8f903c3 Benjamin Dauvergne
def for_today(self, today=None):
if today is None:
today = date.today()
qs = self.current(today)
3fae7dcc Benjamin Dauvergne
qs = qs.filter(weekday=today.weekday())
f8f903c3 Benjamin Dauvergne
filters = []
# week periods
for week_period in range(1,5):
filters.append(models.Q(week_period=week_period,
week_offset=weeks_since_epoch(today) % week_period))
# week parity
797b7721 Benjamin Dauvergne
parity = today.isocalendar()[1] % 2
f8f903c3 Benjamin Dauvergne
filters.append(models.Q(week_parity=parity))
# week ranks
filters.append(models.Q(week_rank__in=weekday_ranks(today)))
qs = qs.filter(reduce(models.Q.__or__, filters))
return qs

eeb26fe2 Mikaël Ates
PERIODICITIES = (
(1, u'Toutes les semaines'),
(2, u'Une semaine sur deux'),
(3, u'Une semaine sur trois'),
(4, u'Une semaine sur quatre'),
(5, u'Une semaine sur cinq'),
(6, u'La première semaine du mois'),
(7, u'La deuxième semaine du mois'),
(8, u'La troisième semaine du mois'),
(9, u'La quatrième semaine du mois'),
(10, u'La dernière semaine du mois'),
(11, u'Les semaines paires'),
(12, u'Les semaines impaires')
)

f8f903c3 Benjamin Dauvergne
9e738c5d Benjamin Dauvergne
class TimeTable(BaseModelMixin, models.Model):
f7d9fa12 Benjamin Dauvergne
objects = PassThroughManager.for_queryset_class(TimeTableQuerySet)()
9e738c5d Benjamin Dauvergne
worker = models.ForeignKey(Worker,
verbose_name=u'Intervenant')
52d3b722 Benjamin Dauvergne
services = models.ManyToManyField('ressources.Service')
f8f903c3 Benjamin Dauvergne
WEEKDAYS = Choices(*enumerate(('lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi',
'samedi', 'dimanche')))
aceeeca7 Mikaël Ates
f8f903c3 Benjamin Dauvergne
weekday = models.PositiveIntegerField(
verbose_name=u"Jour de la semaine",
choices=WEEKDAYS)
9e738c5d Benjamin Dauvergne
start_time = models.TimeField(
verbose_name=u'Heure de début')
end_time = models.TimeField(
verbose_name=u'Heure de fin')
start_date = models.DateField(
3f7c000d Benjamin Dauvergne
verbose_name=u'Début',
help_text=u'format: jj/mm/aaaa')
9e738c5d Benjamin Dauvergne
end_date = models.DateField(
3f7c000d Benjamin Dauvergne
verbose_name=u'Fin', blank=True, null=True,
help_text=u'format: jj/mm/aaaa')
1097fd0a Benjamin Dauvergne
eaf1d7af Mikaël Ates
periodicity = models.PositiveIntegerField(
choices=PERIODICITIES,
verbose_name=u"Périodicité",
default=1,
blank=True,
null=True)

f8f903c3 Benjamin Dauvergne
PERIODS = (
(1, u'Toutes les semaines'),
(2, u'Une semaine sur deux'),
(3, u'Une semaine sur trois'),
eaf1d7af Mikaël Ates
(4, u'Une semaine sur quatre'),
(5, u'Une semaine sur cinq')
f8f903c3 Benjamin Dauvergne
)
OFFSET = range(0,4)
week_offset = models.PositiveIntegerField(
choices=zip(OFFSET, OFFSET),
aceeeca7 Mikaël Ates
verbose_name=u"Décalage en semaines par rapport au 1/1/1970 pour le calcul de période",
f8f903c3 Benjamin Dauvergne
default=0)
week_period = models.PositiveIntegerField(
choices=PERIODS,
aceeeca7 Mikaël Ates
verbose_name=u"Période en semaines",
eeb26fe2 Mikaël Ates
blank=True, null=True)
f8f903c3 Benjamin Dauvergne
PARITIES = (
eaf1d7af Mikaël Ates
(0, u'Les semaines paires'),
(1, u'Les semaines impaires')
f8f903c3 Benjamin Dauvergne
)
week_parity = models.PositiveIntegerField(
choices=PARITIES,
verbose_name=u"Parité des semaines",
blank=True, null=True)

WEEK_RANKS = (
(0, u'La première semaine du mois'),
(1, u'La deuxième semaine du mois'),
(2, u'La troisième semaine du mois'),
(3, u'La quatrième semaine du mois'),
(4, u'La dernière semaine du mois')
)

eeb26fe2 Mikaël Ates
week_rank = models.PositiveIntegerField(
f8f903c3 Benjamin Dauvergne
verbose_name=u"Rang de la semaine dans le mois",
choices=WEEK_RANKS,
eeb26fe2 Mikaël Ates
blank=True, null=True)
f8f903c3 Benjamin Dauvergne
def clean(self):
if (self.week_period is None) + (self.week_parity is None) + \
(self.week_rank is None) != 2:
eeb26fe2 Mikaël Ates
raise forms.ValidationError('Only one periodicity criteria can be used')
f8f903c3 Benjamin Dauvergne
if self.week_period and self.start_date:
self.week_offset = weeks_since_epoch(self.start_date) % self.week_period

9e738c5d Benjamin Dauvergne
def __unicode__(self):
52d3b722 Benjamin Dauvergne
s = u'%s pour au %s le %s de %s à %s' % \
(self.worker, ', '.join(map(unicode, self.services.all())), self.weekday, self.start_time,
9e738c5d Benjamin Dauvergne
self.end_time)
if self.end_time:
s += u' à partir du %s' % self.start_date
else:
s += u' du %s au %s' % (self.start_data, self.end_date)
return s
1097fd0a Benjamin Dauvergne
9e738c5d Benjamin Dauvergne
class Meta:
verbose_name = u'Emploi du temps'
verbose_name_plural = u'Emplois du temps'
7a0a30d7 Benjamin Dauvergne
def to_interval(self, date):
return Interval(datetime.combine(date, self.start_time),
datetime.combine(date, self.end_time))
04022fee Benjamin Dauvergne
f7d9fa12 Benjamin Dauvergne
class HolidayQuerySet(query.QuerySet):
61fd471b Mikaël Ates
# To grab group holidays:
# No worker AND
# Either the holiday has no service, that means for all
# Or the user must be in the service of the holiday
04022fee Benjamin Dauvergne
def for_worker(self, worker):
f7d9fa12 Benjamin Dauvergne
filter_query = models.Q(worker=worker) \
04022fee Benjamin Dauvergne
| models.Q(worker__isnull=True,
5b90c12e Serghei MIHAI
services = None) \
61fd471b Mikaël Ates
| models.Q(worker__isnull=True,
5b90c12e Serghei MIHAI
services__in = worker.services.all())
f16d675e Serghei MIHAI
return self.filter(filter_query).distinct()
04022fee Benjamin Dauvergne
61fd471b Mikaël Ates
def for_worker_id(self, worker_id):
worker = None
try:
worker = Worker.objects.get(pk=worker_id)
except:
return None
filter_query = models.Q(worker=worker) \
| models.Q(worker__isnull=True,
5b90c12e Serghei MIHAI
services = None) \
61fd471b Mikaël Ates
| models.Q(worker__isnull=True,
5b90c12e Serghei MIHAI
services__in = worker.services.all())
61fd471b Mikaël Ates
return self.filter(filter_query)

def for_type(self, holiday_type):
5b90c12e Serghei MIHAI
return self.filter(holiday_type = holiday_type)
61fd471b Mikaël Ates
04022fee Benjamin Dauvergne
def for_service(self, service):
5b90c12e Serghei MIHAI
return self.filter(worker__isnull = True) \
.filter(models.Q(services = service)
|models.Q(services__isnull = True))
04022fee Benjamin Dauvergne
1dba86d1 Benjamin Dauvergne
def for_service_workers(self, service):
5b90c12e Serghei MIHAI
return self.filter(models.Q(worker__services = [service])
|models.Q(services__in = [service])
|models.Q(worker__isnull=True, services__isnull = True))
a5bdc8ec Benjamin Dauvergne
def future(self):
return self.filter(end_date__gte=date.today())

bcb35e14 Benjamin Dauvergne
def today(self, today=None):
today = today or date.today()
a5bdc8ec Benjamin Dauvergne
return self.filter(start_date__lte=today,
end_date__gte=today)

def for_period(self, start_date, end_date):
return self.filter(start_date__lte=end_date, end_date__gte=start_date)
04022fee Benjamin Dauvergne
e6b125bd Mikaël Ates
def for_timed_period(self, date, start_time, end_time):
filter_query = models.Q(start_date__lt=date, end_date__gt=date) \
| models.Q(start_date=date, start_time__isnull=True, end_date__gt=date) \
| models.Q(start_date=date, start_time__lt=end_time, end_date__gt=date) \
| models.Q(start_date__lt=date, end_date=date, end_time__isnull=True) \
| models.Q(start_date__lt=date, end_date=date, end_time__gt=start_time) \
| models.Q(start_date=date, end_date=date, start_time__isnull=True, end_time__isnull=True) \
| models.Q(start_date=date, end_date=date, start_time__isnull=True, end_time__gt=start_time) \
| models.Q(start_date=date, end_date=date, start_time__lt=end_time, end_time__isnull=True) \
| models.Q(start_date=date, end_date=date, start_time__lte=start_time, end_time__gt=start_time) \
fb7b45d2 Serghei MIHAI
| models.Q(start_date=date, end_date=date, start_time__lt=end_time, end_time__gte=end_time)
e6b125bd Mikaël Ates
return self.filter(filter_query)

706c6be7 Benjamin Dauvergne
def time2french(time):
if time.minute:
return '{0}h{1}'.format(time.hour, time.minute)
return '{0}h'.format(time.hour)

04022fee Benjamin Dauvergne
class Holiday(BaseModelMixin, models.Model):
f7d9fa12 Benjamin Dauvergne
objects = PassThroughManager().for_queryset_class(HolidayQuerySet)()
04022fee Benjamin Dauvergne
61fd471b Mikaël Ates
holiday_type = models.ForeignKey('ressources.HolidayType',
verbose_name=u'Type de congé')
04022fee Benjamin Dauvergne
worker = models.ForeignKey(Worker, blank=True, null=True,
verbose_name=u"Personnel")
fc35a6fd Serghei MIHAI
services = models.ManyToManyField(Service, blank = False, null = False,
verbose_name = u'Services')
3f7c000d Benjamin Dauvergne
start_date = models.DateField(verbose_name=u"Date de début",
help_text=u'format: jj/mm/aaaa')
end_date = models.DateField(verbose_name=u"Date de fin",
help_text=u'format: jj/mm/aaaa')
d5122c5e Benjamin Dauvergne
start_time = models.TimeField(verbose_name=u"Horaire de début", blank=True,
null=True)
end_time = models.TimeField(verbose_name=u"Horaire de fin", blank=True,
null=True)
a39c35ec Benjamin Dauvergne
comment = models.TextField(verbose_name=u'Commentaire', blank=True)
04022fee Benjamin Dauvergne
class Meta:
verbose_name = u'Congé'
verbose_name_plural = u'Congés'
5d69a81c Benjamin Dauvergne
ordering = ('start_date', 'start_time')
04022fee Benjamin Dauvergne
def is_current(self):
return self.start_date <= date.today() <= self.end_date

5b90c12e Serghei MIHAI
def for_all_services(self):
return self.services.count() == Service.objects.count()

706c6be7 Benjamin Dauvergne
def __unicode__(self):
ret = ''
if self.start_date == self.end_date:
ret = u'le {0}'.format(date_filter(self.start_date, 'j F Y'))
61fd471b Mikaël Ates
if self.start_time:
ret += u', à partir de {0}'.format(time2french(self.start_time))
if self.end_time:
ret += u", jusqu'à {0}".format(time2french(self.end_time))
706c6be7 Benjamin Dauvergne
else:
61fd471b Mikaël Ates
ret = u'du {0}'.format(date_filter(self.start_date, 'j F Y'))
if self.start_time:
ret += u' (à partir de {0})'.format(time2french(self.start_time))
ret += u' au {0}'.format(date_filter(self.end_date, 'j F Y'))
if self.end_time:
ret += u" (jusqu'à {0})".format(time2french(self.end_time))
706c6be7 Benjamin Dauvergne
return ret
428081e0 Jérôme Schneider
84614733 Benjamin Dauvergne
def to_interval(self, date=None):
1eab6c73 Frédéric Péters
if date == self.start_date:
start_time = self.start_time or datetime_time(8, 0)
else:
start_time = datetime_time(8, 0)
if date == self.end_date:
end_time = self.end_time or datetime_time(20, 0)
else:
end_time = datetime_time(20, 0)
return Interval(datetime.combine(self.start_date, start_time),
datetime.combine(self.end_date, end_time))