Project

General

Profile

Download (31.3 KB) Statistics
| Branch: | Tag: | Revision:

calebasse / calebasse / agenda / views.py @ 9ec8b7a2

1
# -*- coding: utf-8 -*-
2

    
3
import datetime
4
import logging
5
from itertools import chain
6

    
7
from django.contrib import messages
8
from django.db.models import Q
9
from django.shortcuts import redirect, get_object_or_404
10
from django.http import HttpResponseRedirect, HttpResponse
11
from django.conf import settings
12

    
13
from calebasse.cbv import TemplateView, CreateView, UpdateView
14
from calebasse.agenda.models import Event, EventType, EventWithAct
15
from calebasse.personnes.models import TimeTable, Holiday
16
from calebasse.agenda.appointments import get_daily_appointments, get_daily_usage
17
from calebasse.personnes.models import Worker
18
from calebasse.ressources.models import WorkerType, Room
19
from calebasse.actes.validation import (get_acts_of_the_day,
20
        get_days_with_acts_not_locked)
21
from calebasse.actes.validation_states import VALIDATION_STATES
22
from calebasse.actes.models import Act, ValidationMessage
23
from calebasse.actes.validation import (automated_validation, unlock_all_acts_of_the_day)
24
from calebasse import cbv
25

    
26
from calebasse.agenda.forms import (NewAppointmentForm, NewEventForm, UpdatePeriodicAppointmentForm,
27
        DisablePatientAppointmentForm, UpdateAppointmentForm, UpdatePeriodicEventForm, 
28
        UpdateEventForm, PeriodicEventsSearchForm)
29

    
30
logger = logging.getLogger(__name__)
31

    
32
def redirect_today(request, service):
33
    '''If not date is given we redirect on the agenda for today'''
34
    return redirect('agenda', date=datetime.date.today().strftime('%Y-%m-%d'),
35
            service=service)
36

    
37

    
38
class AgendaHomepageView(TemplateView):
39
    template_name = 'agenda/index.html'
40
    cookies_to_clear = []
41

    
42
    def post(self, request, *args, **kwargs):
43
        acte_id = request.POST.get('event-id')
44
        try:
45
            event = EventWithAct.objects.get(id=acte_id)
46
            event = event.today_occurrence(self.date)
47
            act = event.act
48
            if not act.validation_locked:
49
                state_name = request.POST.get('act_state')
50
                act.save()
51
                act.set_state(state_name, request.user)
52
        except Act.DoesNotExist:
53
            logger.warning('agenda homepage acte_id %d not found' % acte_id)
54
        return HttpResponseRedirect('#acte-frame-'+acte_id)
55

    
56
    def get_context_data(self, **kwargs):
57
        logger.info('AgendaHomepageView.get_context_data called')
58
        context = super(AgendaHomepageView, self).get_context_data(**kwargs)
59

    
60
        context['workers_types'] = []
61
        workers = Worker.objects.filter(enabled=True).select_related() \
62
                .prefetch_related('services')
63
        worker_by_type = {}
64
        for worker in workers:
65
            workers_for_type = worker_by_type.setdefault(worker.type, [])
66
            workers_for_type.append(worker)
67
        for worker_type, workers_for_type in worker_by_type.iteritems():
68
            context['workers_types'].append(
69
                    {'type': worker_type.name, 'workers': workers_for_type })
70
        context['workers'] = workers
71
        context['disponibility_start_times'] = range(8, 20)
72

    
73
        return context
74

    
75

    
76
class AgendaServiceActivityView(TemplateView, cbv.ServiceViewMixin):
77
    template_name = 'agenda/service-activity.html'
78
    cookies_to_clear = [('agenda-worker-tabs', ), ('agenda-ressource-tabs', )]
79

    
80
    def get_context_data(self, **kwargs):
81
        context = super(AgendaServiceActivityView, self).get_context_data(**kwargs)
82

    
83
        appointments_times = dict()
84
        events = Event.objects.for_today(self.date) \
85
                .exclude(event_type_id=1) \
86
                .filter(services=self.service) \
87
                .order_by('start_datetime', 'id') \
88
                .select_related() \
89
                .prefetch_related('participants', 'exceptions')
90
        eventswithact = EventWithAct.objects.for_today(self.date) \
91
                .filter(services=self.service) \
92
                .order_by('start_datetime', 'id') \
93
                .select_related() \
94
                .prefetch_related('participants', 'exceptions')
95
        events = [ e.today_occurrence(self.date) for e in events ] \
96
             + [ e.today_occurrence(self.date) for e in eventswithact ]
97
        for event in events:
98
            start_datetime = event.start_datetime.strftime("%H:%M")
99
            if not appointments_times.has_key(start_datetime):
100
                appointments_times[start_datetime] = dict()
101
                appointments_times[start_datetime]['row'] = 0
102
                appointments_times[start_datetime]['appointments'] = []
103
            appointment = dict()
104
            length = event.end_datetime - event.start_datetime
105
            if length.seconds:
106
                length = length.seconds / 60
107
                appointment['length'] = "%sm" % length
108
            if event.event_type_id == 1:
109
                appointment['type'] = 1
110
                appointment['label'] = event.patient.display_name
111
                appointment['paper_id'] = event.patient.paper_id
112
                appointment['act'] = event.act_type.name
113
                appointment['state'] = event.act.get_state()
114
                appointment['absent'] = event.act.is_absent()
115
            else:
116
                appointment['type'] = 2
117
                if event.event_type.label == 'Autre' and event.title:
118
                    appointment['label'] = event.title
119
                else:
120
                    appointment['label'] = '%s - %s' % (event.event_type.label,
121
                                                        event.title)
122
            appointment['participants'] = event.participants.filter(worker__enabled=True)
123
            appointment['len_participants'] = len(appointment['participants'])
124
            appointment['workers_absent'] = event.get_missing_participants()
125
            appointments_times[start_datetime]['row'] += 1
126
            appointments_times[start_datetime]['appointments'].append(appointment)
127
        context['appointments_times'] = sorted(appointments_times.items())
128
        return context
129

    
130

    
131
class NewAppointmentView(cbv.ReturnToObjectMixin, cbv.ServiceFormMixin, CreateView):
132
    model = EventWithAct
133
    form_class = NewAppointmentForm
134
    template_name = 'agenda/new-appointment.html'
135
    success_msg = u'Rendez-vous enregistré avec succès.'
136
    cookies_to_clear = []
137

    
138
    def get_initial(self):
139
        initial = super(NewAppointmentView, self).get_initial()
140
        initial['start_datetime'] = self.date
141
        initial['date'] = self.date
142
        initial['participants'] = self.request.GET.getlist('participants')
143
        initial['time'] = self.request.GET.get('time')
144
        initial['room'] = self.request.GET.get('room')
145
        return initial
146

    
147
    def get_form_kwargs(self):
148
        kwargs = super(NewAppointmentView, self).get_form_kwargs()
149
        kwargs['service'] = self.service
150
        return kwargs
151

    
152
    def get_success_url(self):
153
        return self.request.META.get('HTTP_REFERER', '..')
154

    
155
    def form_valid(self, form):
156
        messages.add_message(self.request, messages.INFO, self.success_msg)
157
        return super(NewAppointmentView, self).form_valid(form)
158

    
159

    
160
class TodayOccurrenceMixin(object):
161
    def get_object(self, queryset=None):
162
        o = super(TodayOccurrenceMixin, self).get_object(queryset)
163
        return o.today_occurrence(self.date)
164

    
165

    
166
class BaseAppointmentView(UpdateView):
167
    model = EventWithAct
168
    form_class = UpdateAppointmentForm
169
    template_name = 'agenda/update-rdv.html'
170
    success_url = '..'
171
    cookies_to_clear = []
172

    
173
    def get_initial(self):
174
        initial = super(BaseAppointmentView, self).get_initial()
175
        initial['start_datetime'] = self.date
176
        initial['date'] = self.object.start_datetime.date()
177
        initial['time'] = self.object.start_datetime.time()
178
        time = self.object.end_datetime - self.object.start_datetime
179
        if time:
180
            time = time.seconds / 60
181
        else:
182
            time = 0
183
        initial['duration'] = time
184
        initial['participants'] = self.object.participants.values_list('id', flat=True)
185
        return initial
186

    
187
    def get_form_kwargs(self):
188
        kwargs = super(BaseAppointmentView, self).get_form_kwargs()
189
        kwargs['service'] = self.service
190
        return kwargs
191

    
192

    
193
class UpdateAppointmentView(TodayOccurrenceMixin, BaseAppointmentView):
194

    
195
    def get_form_class(self):
196
        if self.object.exception_to and not self.object.exception_to.canceled:
197
            return DisablePatientAppointmentForm
198
        else:
199
            return self.form_class
200

    
201

    
202
class UpdatePeriodicAppointmentView(BaseAppointmentView):
203
    form_class = UpdatePeriodicAppointmentForm
204
    template_name = 'agenda/new-appointment.html'
205

    
206

    
207
class NewEventView(CreateView):
208
    model = Event
209
    form_class = NewEventForm
210
    template_name = 'agenda/new-event.html'
211
    cookies_to_clear = []
212

    
213
    def get_initial(self):
214
        initial = super(NewEventView, self).get_initial()
215
        initial['start_datetime'] = self.date
216
        initial['date'] = self.date
217
        initial['participants'] = self.request.GET.getlist('participants')
218
        initial['time'] = self.request.GET.get('time')
219
        initial['event_type'] = 2
220
        initial['room'] = self.request.GET.get('room')
221
        if not initial.has_key('services'):
222
            initial['services'] = [self.service]
223
        return initial
224

    
225
    def get_form_kwargs(self):
226
        kwargs = super(NewEventView, self).get_form_kwargs()
227
        kwargs['service'] = self.service
228
        return kwargs
229

    
230
    def get_success_url(self):
231
        return self.request.META.get('HTTP_REFERER', '..')
232

    
233
    def form_valid(self, form):
234
        messages.add_message(self.request, messages.INFO, u'Evénement enregistré avec succès.')
235
        return super(NewEventView, self).form_valid(form)
236

    
237

    
238
class BaseEventView(UpdateView):
239
    model = Event
240
    form_class = UpdateEventForm
241
    template_name = 'agenda/update-event.html'
242
    success_url = '..'
243
    cookies_to_clear = []
244

    
245
    def get_initial(self):
246
        initial = super(BaseEventView, self).get_initial()
247
        initial['start_datetime'] = self.date
248
        initial['date'] = self.object.start_datetime.date()
249
        initial['time'] = self.object.start_datetime.time()
250
        time = self.object.end_datetime - self.object.start_datetime
251
        if time:
252
            time = time.seconds / 60
253
        else:
254
            time = 0
255
        initial['duration'] = time
256
        initial['participants'] = self.object.participants.values_list('id', flat=True)
257
        return initial
258

    
259
    def get_form_kwargs(self):
260
        kwargs = super(BaseEventView, self).get_form_kwargs()
261
        kwargs['service'] = self.service
262
        return kwargs
263

    
264

    
265
class UpdateEventView(TodayOccurrenceMixin, BaseEventView):
266
    pass
267

    
268

    
269
class UpdatePeriodicEventView(BaseEventView):
270
    form_class = UpdatePeriodicEventForm
271
    template_name = 'agenda/new-event.html'
272

    
273
def delete_eventwithact(event):
274
    assert event.event_type == 1
275
    if event.act.id \
276
            and not event.act.is_billed:
277
        event.act.delete()
278
    if not event.act.id or \
279
            not event.act.is_billed:
280
        event.delete()
281

    
282
class DeleteOccurrenceView(TodayOccurrenceMixin, cbv.DeleteView):
283
    model = Event
284
    success_url = '..'
285
    cookies_to_clear = []
286

    
287
    def delete(self, request, *args, **kwargs):
288
        self.object = self.get_object()
289
        if self.object.event_type == 1:
290
            delete_eventwithact(self.object)
291
        else:
292
            self.object.delete()
293

    
294
        return HttpResponse(status=204)
295

    
296
class DeleteEventView(cbv.DeleteView):
297
    model = Event
298
    success_url = '..'
299
    cookies_to_clear = []
300

    
301
    def delete(self, request, *args, **kwargs):
302
        self.object = self.get_object()
303
        # If exceptions remove them only if act is not billed
304
        for exception in self.object.exceptions.all():
305
            exception.recurrence_periodicity = None
306
            exception.exception_to = None
307
            exception.save()
308
            if exception.event_type == 1:
309
                delete_eventwithact(exception)
310
            else:
311
                exception.delete()
312

    
313
        if self.object.event_type == 1:
314
            delete_eventwithact(self.object)
315
        else:
316
            self.object.delete()
317
        return HttpResponse(status=204)
318

    
319
class AgendaServiceActValidationView(TemplateView):
320
    template_name = 'agenda/act-validation.html'
321
    cookies_to_clear = [('agenda-worker-tabs', ), ('agenda-ressource-tabs', )]
322

    
323
    def acts_of_the_day(self):
324
        acts = list(Act.objects \
325
                .filter(date=self.date, patient__service=self.service) \
326
                .select_related() \
327
                .prefetch_related('doctors',
328
                        'patient__patientcontact',
329
                        'actvalidationstate_set__previous_state') \
330
                .order_by('time'))
331
        event_ids = [ a.parent_event_id for a in acts if a.parent_event_id ]
332
        events = EventWithAct.objects.for_today(self.date) \
333
                .filter(patient__service=self.service) \
334
                .exclude(id__in=event_ids)
335
        events = [ event.today_occurrence(self.date) for event in events ]
336
        acts += [ event.act for event in events if event ]
337
        return sorted(acts, key=lambda a: (a.time or datetime.time.min, a.id))
338

    
339
    def post(self, request, *args, **kwargs):
340
        if 'unlock-all' in request.POST:
341
            #TODO: check that the user is authorized
342
            unlock_all_acts_of_the_day(self.date, self.service)
343
            ValidationMessage(validation_date=self.date,
344
                who=request.user, what='Déverrouillage',
345
                service=self.service).save()
346
        else:
347
            acte_id = request.POST.get('acte-id')
348
            try:
349
                act = Act.objects.get(id=acte_id)
350
                if 'lock' in request.POST or 'unlock' in request.POST:
351
                    #TODO: check that the user is authorized
352
                    act.validation_locked = 'lock' in request.POST
353
                    act.save()
354
                else:
355
                    state_name = request.POST.get('act_state')
356
                    act.set_state(state_name, request.user)
357
            except Act.DoesNotExist:
358
                pass
359
            return HttpResponseRedirect('#acte-frame-'+acte_id)
360
        return HttpResponseRedirect('')
361

    
362
    def get_context_data(self, **kwargs):
363
        context = super(AgendaServiceActValidationView, self).get_context_data(**kwargs)
364
        authorized_lock = True # is_authorized_for_locking(get_request().user)
365
        validation_msg = ValidationMessage.objects.\
366
            filter(validation_date=self.date, service=self.service).\
367
            order_by('-when')[:3]
368
        acts_of_the_day = self.acts_of_the_day()
369
        actes = list()
370
        for act in acts_of_the_day:
371
            if not act.id:
372
                if act.date < datetime.date(2013, 1, 1):
373
                    continue
374
                else:
375
                    act.save()
376
            state = act.get_state()
377
            display_name = None
378
            if state :
379
                display_name = VALIDATION_STATES[state.state_name]
380
                if not state.previous_state_id and state.state_name == 'NON_VALIDE':
381
                    state = None
382
            actes.append((act, state, display_name))
383
        validation_states = dict(VALIDATION_STATES)
384
        if self.service.name != 'CMPP' and \
385
                'ACT_DOUBLE' in validation_states:
386
            validation_states.pop('ACT_DOUBLE')
387
        vs = [('VALIDE', 'Présent')]
388
        validation_states.pop('VALIDE')
389
        validation_states.pop('ACT_LOST')
390
        validation_states = vs + sorted(validation_states.items(), key=lambda tup: tup[0])
391
        context['validation_states'] = validation_states
392
        context['actes'] = actes
393
        context['validation_msg'] = validation_msg
394
        context['authorized_lock'] = authorized_lock
395
        return context
396

    
397

    
398
class AutomatedValidationView(TemplateView):
399
    template_name = 'agenda/automated-validation.html'
400

    
401
    def post(self, request, *args, **kwargs):
402
        automated_validation(self.date, self.service,
403
            request.user)
404
        ValidationMessage(validation_date=self.date,
405
            who=request.user, what='Validation automatique',
406
            service=self.service).save()
407
        return HttpResponseRedirect('..')
408

    
409
    def get_context_data(self, **kwargs):
410
        context = super(AutomatedValidationView, self).get_context_data(**kwargs)
411
        request = self.request
412
        (nb_acts_total, nb_acts_validated, nb_acts_double,
413
        nb_acts_abs_non_exc, nb_acts_abs_exc, nb_acts_abs_inter, nb_acts_annul_nous,
414
        nb_acts_annul_famille, nb_acts_reporte, nb_acts_abs_ess_pps,
415
        nb_acts_enf_hosp, nb_acts_losts) = \
416
            automated_validation(self.date, self.service,
417
                request.user, commit = False)
418

    
419
        nb_acts_not_validated = nb_acts_double + \
420
            nb_acts_abs_non_exc + \
421
            nb_acts_abs_exc + \
422
            nb_acts_abs_inter + \
423
            nb_acts_annul_nous + \
424
            nb_acts_annul_famille + \
425
            nb_acts_reporte + \
426
            nb_acts_abs_ess_pps + \
427
            nb_acts_enf_hosp + \
428
            nb_acts_losts
429
        context.update({
430
            'nb_acts_total': nb_acts_total,
431
            'nb_acts_validated': nb_acts_validated,
432
            'nb_acts_not_validated': nb_acts_not_validated,
433
            'nb_acts_double': nb_acts_double,
434
            'nb_acts_abs_non_exc': nb_acts_abs_non_exc,
435
            'nb_acts_abs_exc': nb_acts_abs_exc,
436
            'nb_acts_abs_inter': nb_acts_abs_inter,
437
            'nb_acts_annul_nous': nb_acts_annul_nous,
438
            'nb_acts_annul_famille': nb_acts_annul_famille,
439
            'nb_acts_reporte': nb_acts_reporte,
440
            'nb_acts_abs_ess_pps': nb_acts_abs_ess_pps,
441
            'nb_acts_enf_hosp': nb_acts_enf_hosp,
442
            'nb_acts_losts': nb_acts_losts})
443
        return context
444

    
445
class UnlockAllView(CreateView):
446
    pass
447

    
448

    
449
class AgendasTherapeutesView(AgendaHomepageView):
450
    template_name = 'agenda/agendas-therapeutes.html'
451
    cookies_to_clear = [('agenda-worker-tabs', ), ('agenda-ressource-tabs', )]
452

    
453
    def get_context_data(self, **kwargs):
454
        context = super(AgendasTherapeutesView, self).get_context_data(**kwargs)
455

    
456
        time_tables = TimeTable.objects.select_related('worker'). \
457
                filter(services=self.service). \
458
                for_today(self.date). \
459
                order_by('start_date')
460
        holidays = Holiday.objects.select_related('worker') \
461
                .for_period(self.date, self.date) \
462
                .order_by('start_date') \
463
                .select_related()
464
        events = Event.objects.for_today(self.date) \
465
                .exclude(event_type_id=1) \
466
                .filter(services=self.service) \
467
                .order_by('start_datetime') \
468
                .select_related() \
469
                .prefetch_related('services',
470
                        'exceptions',
471
                        'participants')
472
        eventswithact = EventWithAct.objects.for_today(self.date) \
473
                .filter(services=self.service) \
474
                .order_by('start_datetime') \
475
                .select_related() \
476
                .prefetch_related(
477
                        'services',
478
                        'patient__service',
479
                        'act_set__actvalidationstate_set',
480
                        'exceptions', 'participants')
481
        events = [ e.today_occurrence(self.date) for e in events ] \
482
             + [ e.today_occurrence(self.date) for e in eventswithact ]
483
        for e in events:
484
            e.workers_ids = set(p.id for p in e.participants.all())
485

    
486
        events_workers = {}
487
        time_tables_workers = {}
488
        holidays_workers = {}
489
        context['workers_agenda'] = []
490
        context['workers'] = context['workers'].filter(services=self.service)
491
        for worker in context['workers']:
492
            time_tables_worker = [tt for tt in time_tables if tt.worker.id == worker.id]
493
            events_worker = [o for o in events if worker.id in o.workers_ids ]
494
            holidays_worker = [h for h in holidays if h.worker_id in (None, worker.id)]
495
            events_workers[worker.id] = events_worker
496
            time_tables_workers[worker.id] = time_tables_worker
497
            holidays_workers[worker.id] = holidays_worker
498
            daily_appointments = get_daily_appointments(context['date'], worker, self.service,
499
                        time_tables_worker, events_worker, holidays_worker)
500
            if all(map(lambda x: x.holiday, daily_appointments)):
501
                continue
502
            context['workers_agenda'].append({'worker': worker,
503
                    'appointments': daily_appointments})
504

    
505
        for worker_agenda in context.get('workers_agenda', []):
506
            patient_appointments = [x for x in worker_agenda['appointments'] if x.patient_record_id]
507
            worker_agenda['summary'] = {
508
              'rdv': len(patient_appointments),
509
              'presence': len([x for x in patient_appointments if x.act_absence is None]),
510
              'absence': len([x for x in patient_appointments if x.act_absence is not None]),
511
              'doubles': len([x for x in patient_appointments if x.act_type == 'ACT_DOUBLE']),
512
              'valides': len([x for x in patient_appointments if x.act_type == 'ACT_VALIDE']),
513
            }
514

    
515
        return context
516

    
517
class JoursNonVerrouillesView(TemplateView):
518
    template_name = 'agenda/days-not-locked.html'
519

    
520
    def get_context_data(self, **kwargs):
521
        context = super(JoursNonVerrouillesView, self).get_context_data(**kwargs)
522
        acts = Act.objects.filter(is_billed=False,
523
            patient__service=self.service).order_by('date')
524
        days = set(acts.values_list('date', flat=True))
525
        if days:
526
            max_day, min_day = max(days), min(days)
527
            today = datetime.datetime.today().date()
528
            if max_day > today:
529
                max_day = today
530
            days &= set(get_days_with_acts_not_locked(min_day, max_day, self.service))
531
        context['days_not_locked'] = sorted(days)
532
        return context
533

    
534
class RessourcesView(TemplateView):
535

    
536
    template_name = 'agenda/ressources.html'
537
    cookies_to_clear = []
538

    
539
    def get_context_data(self, **kwargs):
540
        context = super(RessourcesView, self).get_context_data(**kwargs)
541

    
542
        plain_events = Event.objects.for_today(self.date) \
543
                .order_by('start_datetime').select_subclasses()
544
        events = [ e.today_occurrence(self.date) for e in plain_events ]
545

    
546
        context['ressources_types'] = []
547
        context['ressources_agenda'] = []
548
        context['disponibility'] = {}
549
        ressources = []
550
        data = {'type': Room._meta.verbose_name_plural, 'ressources': Room.objects.all() }
551
        context['ressources_types'].append(data)
552
        ressources.extend(data['ressources'])
553
        context['disponibility_start_times'] = range(8, 20)
554

    
555
        events_ressources = {}
556
        for ressource in ressources:
557
            events_ressource = [e for e in events if ressource == e.room]
558
            events_ressources[ressource.id] = events_ressource
559
            context['ressources_agenda'].append({'ressource': ressource,
560
                    'appointments': get_daily_usage(context['date'], ressource,
561
                        self.service, events_ressource)})
562

    
563
        return context
564

    
565
class AjaxWorkerTabView(TemplateView):
566

    
567
    template_name = 'agenda/ajax-worker-tab.html'
568
    cookies_to_clear = []
569

    
570
    def get_context_data(self, worker_id, **kwargs):
571
        context = super(AjaxWorkerTabView, self).get_context_data(**kwargs)
572
        worker = Worker.objects.get(id=worker_id)
573

    
574
        time_tables_worker = TimeTable.objects.select_related('worker'). \
575
                filter(services=self.service, worker=worker) \
576
                .for_today(self.date) \
577
                .order_by('start_date') \
578
                .select_related()
579
        holidays_worker = Holiday.objects.for_worker(worker) \
580
                .for_period(self.date, self.date) \
581
                .order_by('start_date') \
582
                .select_related()
583
        events = Event.objects.for_today(self.date) \
584
                .exclude(event_type_id=1) \
585
                .filter(participants=worker) \
586
                .order_by('start_datetime') \
587
                .select_related() \
588
                .prefetch_related('services',
589
                        'exceptions',
590
                        'participants')
591
        eventswithact = EventWithAct.objects.for_today(self.date) \
592
                .filter(participants=worker) \
593
                .order_by('start_datetime') \
594
                .select_related() \
595
                .prefetch_related('patient__addresses',
596
                        'patient__addresses__patientcontact_set',
597
                        'services',
598
                        'patient__service',
599
                        'act_set__actvalidationstate_set',
600
                        'exceptions', 'participants')
601
        events = [ e.today_occurrence(self.date) for e in events ] \
602
             + [ e.today_occurrence(self.date) for e in eventswithact ]
603

    
604
        context['worker_agenda'] = {'worker': worker,
605
                    'appointments': get_daily_appointments(context['date'], worker, self.service,
606
                        time_tables_worker, events, holidays_worker)}
607

    
608
        if settings.RTF_TEMPLATES_DIRECTORY:
609
            context['mail'] = True
610
        return context
611

    
612
class AjaxWorkerDisponibilityColumnView(TemplateView):
613

    
614
    template_name = 'agenda/ajax-ressource-disponibility-column.html'
615
    cookies_to_clear = []
616

    
617
    def get_context_data(self, worker_id, **kwargs):
618
        context = super(AjaxWorkerDisponibilityColumnView, self).get_context_data(**kwargs)
619
        worker = Worker.objects.get(pk=worker_id)
620

    
621
        time_tables_worker = TimeTable.objects.select_related('worker'). \
622
                filter(services=self.service, worker=worker). \
623
                for_today(self.date). \
624
                order_by('start_date')
625
        holidays_worker = Holiday.objects.for_worker(worker). \
626
                for_period(self.date, self.date). \
627
                order_by('start_date')
628
        events = Event.objects.for_today(self.date) \
629
                .exclude(event_type_id=1) \
630
                .filter(participants=worker) \
631
                .order_by('start_datetime') \
632
                .select_related() \
633
                .prefetch_related('participants', 'exceptions')
634
        eventswithact = EventWithAct.objects.for_today(self.date) \
635
                .filter(participants=worker) \
636
                .order_by('start_datetime') \
637
                .select_related() \
638
                .prefetch_related('participants', 'exceptions',
639
                        'act_set__actvalidationstate_set')
640

    
641
        events = list(events) + list(eventswithact)
642
        events = [ e.today_occurrence(self.date) for e in events ]
643
        time_tables_workers = {worker.id: time_tables_worker}
644
        events_workers = {worker.id: events}
645
        holidays_workers = {worker.id: holidays_worker}
646

    
647
        context['initials'] = worker.initials
648
        context['ressource_id'] = worker.id
649
        context['disponibility'] = Event.objects.daily_disponibilities(self.date,
650
                events_workers, [worker], time_tables_workers, holidays_workers)
651
        return context
652

    
653
class AjaxRessourceDisponibilityColumnView(AjaxWorkerDisponibilityColumnView):
654

    
655
    def get_context_data(self, ressource_id, **kwargs):
656
        context = {}
657
        ressource = Room.objects.get(pk = ressource_id)
658
        context = {'initials': ressource.name[:3], 'ressource_id': ressource.id}
659
        disponibility = dict()
660
        start_datetime = datetime.datetime(self.date.year,
661
                                           self.date.month,
662
                                           self.date.day, 8, 0)
663
        end_datetime = datetime.datetime(self.date.year, self.date.month,
664
                                         self.date.day, 8, 15)
665
        events = Event.objects.filter(room__id=ressource_id).today_occurrences(self.date)
666

    
667
        while (start_datetime.hour <= 19):
668
            if start_datetime.hour not in disponibility:
669
                disponibility[start_datetime.hour] = [[], [], [], []]
670
                quarter = 0
671
            dispo = 'free'
672

    
673
            if events:
674
                event = events[0]
675

    
676
                if event.start_datetime <= start_datetime and event.end_datetime >= end_datetime:
677
                    dispo = 'busy'
678

    
679
            disponibility[start_datetime.hour][quarter].append({'id': ressource_id, 'dispo': dispo})
680
            quarter += 1
681
            start_datetime += datetime.timedelta(minutes=15)
682
            end_datetime += datetime.timedelta(minutes=15)
683
        context['disponibility'] = disponibility
684
        return context
685

    
686

    
687
class PeriodicEventsView(cbv.ListView):
688
    model = EventWithAct
689
    template_name = 'agenda/periodic-events.html'
690
    cookies_to_clear = [('agenda-worker-tabs', ), ('agenda-ressource-tabs', )]
691

    
692
    def dispatch(self, request, *args, **kwargs):
693
        if 'worker_id' in kwargs:
694
            self.worker = get_object_or_404(Worker, id=kwargs['worker_id'])
695
        else:
696
            self.worker = None
697
        return super(PeriodicEventsView, self).dispatch(request, *args, **kwargs)
698

    
699
    def get_form(self):
700
        kwargs = {
701
                'initial': {
702
                    'start_date': self.date,
703
                }
704
        }
705
        if self.request.GET:
706
            kwargs['data'] = self.request.GET
707
        self.form = PeriodicEventsSearchForm(prefix='periodic-events-search-form', **kwargs)
708
        return self.form
709

    
710
    def get_queryset(self):
711
        qs1 = Event.objects.exclude(event_type_id=1)
712
        qs2 = EventWithAct.objects.all()
713
        form = self.get_form()
714
        if not self.request.GET:
715
            return ()
716
        qs1 = self.filter_queryset(form, qs1)
717
        qs2 = self.filter_queryset(form, qs2)
718
        if form.is_valid():
719
            patient = form.cleaned_data.get('patient')
720
            if patient is not None:
721
                qs1 = qs1.none()
722
                qs2 = qs2.filter(patient=patient)
723
            worker = form.cleaned_data.get('worker')
724
            if worker is not None:
725
                qs1 = qs1.filter(participants=worker)
726
                qs2 = qs2.filter(participants=worker)
727
        return sorted(chain(qs1, qs2),
728
                key=lambda x: (x.start_datetime, x.recurrence_end_date or datetime.date(9999,12,31)))
729

    
730
    def filter_queryset(self, form, qs):
731
        if self.worker is not None:
732
            qs = qs.filter(participants=self.worker)
733
        start_date = datetime.date.today()
734
        end_date = start_date+datetime.timedelta(days=90)
735
        if form.is_valid():
736
            if form.cleaned_data.get('start_date'):
737
                start_date = form.cleaned_data['start_date']
738
            if form.cleaned_data.get('end_date'):
739
                end_date = form.cleaned_data['end_date']
740
            else:
741
                end_date = start_date+datetime.timedelta(days=90)
742
            if len(form.cleaned_data.get('event_type')) != 2:
743
                if '0' in form.cleaned_data.get('event_type'):
744
                    qs = qs.filter(event_type_id=1)
745
                else:
746
                    qs = qs.exclude(event_type_id=1)
747
            if form.cleaned_data.get('no_end_date'):
748
                qs = qs.filter(recurrence_end_date__isnull=True)
749
        qs = qs.filter(canceled=False)
750
        qs = qs.filter(services=self.service)
751
        qs = qs.filter(recurrence_periodicity__isnull=False)
752
        qs = qs.filter(start_datetime__lt=end_date)
753
        qs = qs.filter(Q(recurrence_end_date__isnull=True)
754
                | Q(recurrence_end_date__gte=start_date))
755
        qs = qs.order_by('start_datetime', 'recurrence_end_date')
756
        qs = qs.select_related()
757
        qs = qs.prefetch_related('participants', 'services')
758
        return qs
759

    
760
    def get_context_data(self, **kwargs):
761
        ctx = super(PeriodicEventsView, self).get_context_data(**kwargs)
762
        ctx['search_form'] = self.form
763
        ctx['worker'] = self.worker
764
        return ctx
(10-10/10)