Projet

Général

Profil

Télécharger (31,8 ko) Statistiques
| Branche: | Tag: | Révision:

calebasse / calebasse / agenda / views.py @ ae79c334

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, Http404
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, Ressource
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
        # ressources
74
        context['ressources_types'] = []
75
        data = {'type': Ressource._meta.verbose_name_plural,
76
                'ressources': Ressource.objects.all()}
77
        context['ressources_types'].append(data)
78

    
79
        return context
80

    
81
class AgendaServiceActivityView(TemplateView, cbv.ServiceViewMixin):
82
    template_name = 'agenda/service-activity.html'
83
    cookies_to_clear = [('agenda-tabs', ), ('active-agenda', ), ('last-ressource', )]
84

    
85
    def get_context_data(self, **kwargs):
86
        context = super(AgendaServiceActivityView, self).get_context_data(**kwargs)
87

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

    
135

    
136
class NewAppointmentView(cbv.ReturnToObjectMixin, cbv.ServiceFormMixin, CreateView):
137
    model = EventWithAct
138
    form_class = NewAppointmentForm
139
    template_name = 'agenda/new-appointment.html'
140
    success_msg = u'Rendez-vous enregistré avec succès.'
141
    cookies_to_clear = []
142

    
143
    def get_initial(self):
144
        initial = super(NewAppointmentView, self).get_initial()
145
        initial['start_datetime'] = self.date
146
        initial['date'] = self.date
147
        initial['participants'] = self.request.GET.getlist('participants')
148
        initial['time'] = self.request.GET.get('time')
149
        initial['ressource'] = self.request.GET.get('ressource')
150
        initial['duration'] = self.request.GET.get('duration')
151
        return initial
152

    
153
    def get_form_kwargs(self):
154
        kwargs = super(NewAppointmentView, self).get_form_kwargs()
155
        kwargs['service'] = self.service
156
        return kwargs
157

    
158
    def get_success_url(self):
159
        return self.request.META.get('HTTP_REFERER', '..')
160

    
161
    def form_valid(self, form):
162
        messages.add_message(self.request, messages.INFO, self.success_msg)
163
        return super(NewAppointmentView, self).form_valid(form)
164

    
165

    
166
class TodayOccurrenceMixin(object):
167
    def get_object(self, queryset=None):
168
        o = super(TodayOccurrenceMixin, self).get_object(queryset)
169
        obj = o.today_occurrence(self.date)
170
        if obj:
171
            return obj
172
        raise Http404
173

    
174

    
175
class BaseAppointmentView(UpdateView):
176
    model = EventWithAct
177
    form_class = UpdateAppointmentForm
178
    template_name = 'agenda/update-rdv.html'
179
    success_url = '..'
180
    cookies_to_clear = []
181

    
182
    def get_initial(self):
183
        initial = super(BaseAppointmentView, self).get_initial()
184
        initial['start_datetime'] = self.date
185
        initial['date'] = self.object.start_datetime.date()
186
        initial['time'] = self.object.start_datetime.time()
187
        time = self.object.end_datetime - self.object.start_datetime
188
        if time:
189
            time = time.seconds / 60
190
        else:
191
            time = 0
192
        initial['duration'] = time
193
        initial['participants'] = self.object.participants.values_list('id', flat=True)
194
        return initial
195

    
196
    def get_form_kwargs(self):
197
        kwargs = super(BaseAppointmentView, self).get_form_kwargs()
198
        kwargs['service'] = self.service
199
        return kwargs
200

    
201

    
202
class UpdateAppointmentView(TodayOccurrenceMixin, BaseAppointmentView):
203

    
204
    def get_form_class(self):
205
        if self.object.exception_to and not self.object.exception_to.canceled:
206
            return DisablePatientAppointmentForm
207
        else:
208
            return self.form_class
209

    
210
class UpdatePeriodicAppointmentView(BaseAppointmentView):
211
    form_class = UpdatePeriodicAppointmentForm
212
    template_name = 'agenda/new-appointment.html'
213

    
214

    
215
class NewEventView(CreateView):
216
    model = Event
217
    form_class = NewEventForm
218
    template_name = 'agenda/new-event.html'
219
    cookies_to_clear = []
220

    
221
    def get_initial(self):
222
        initial = super(NewEventView, self).get_initial()
223
        initial['start_datetime'] = self.date
224
        initial['date'] = self.date
225
        initial['participants'] = self.request.GET.getlist('participants')
226
        initial['time'] = self.request.GET.get('time')
227
        initial['event_type'] = 2
228
        initial['ressource'] = self.request.GET.get('ressource')
229
        initial['duration'] = self.request.GET.get('duration')
230
        if not initial.has_key('services'):
231
            initial['services'] = [self.service]
232
        return initial
233

    
234
    def get_form_kwargs(self):
235
        kwargs = super(NewEventView, self).get_form_kwargs()
236
        kwargs['service'] = self.service
237
        return kwargs
238

    
239
    def get_success_url(self):
240
        return self.request.META.get('HTTP_REFERER', '..')
241

    
242
    def form_valid(self, form):
243
        messages.add_message(self.request, messages.INFO, u'Evénement enregistré avec succès.')
244
        return super(NewEventView, self).form_valid(form)
245

    
246

    
247
class BaseEventView(UpdateView):
248
    model = Event
249
    form_class = UpdateEventForm
250
    template_name = 'agenda/update-event.html'
251
    success_url = '..'
252
    cookies_to_clear = []
253

    
254
    def get_initial(self):
255
        initial = super(BaseEventView, self).get_initial()
256
        initial['start_datetime'] = self.date
257
        initial['date'] = self.object.start_datetime.date()
258
        initial['time'] = self.object.start_datetime.time()
259
        time = self.object.end_datetime - self.object.start_datetime
260
        if time:
261
            time = time.seconds / 60
262
        else:
263
            time = 0
264
        initial['duration'] = time
265
        initial['participants'] = self.object.participants.values_list('id', flat=True)
266
        return initial
267

    
268
    def get_form_kwargs(self):
269
        kwargs = super(BaseEventView, self).get_form_kwargs()
270
        kwargs['service'] = self.service
271
        return kwargs
272

    
273

    
274
class UpdateEventView(TodayOccurrenceMixin, BaseEventView):
275
    pass
276

    
277

    
278
class UpdatePeriodicEventView(BaseEventView):
279
    form_class = UpdatePeriodicEventForm
280
    template_name = 'agenda/new-event.html'
281

    
282
def delete_eventwithact(event):
283
    assert event.event_type == 1
284
    if event.act.id \
285
            and not event.act.is_billed:
286
        event.act.delete()
287
    if not event.act.id or \
288
            not event.act.is_billed:
289
        event.delete()
290

    
291
class DeleteOccurrenceView(TodayOccurrenceMixin, cbv.DeleteView):
292
    model = Event
293
    success_url = '..'
294
    cookies_to_clear = []
295

    
296
    def delete(self, request, *args, **kwargs):
297
        self.object = self.get_object()
298
        if self.object.event_type == 1:
299
            delete_eventwithact(self.object)
300
        else:
301
            self.object.delete()
302

    
303
        return HttpResponse(status=204)
304

    
305
class DeleteEventView(cbv.DeleteView):
306
    model = Event
307
    success_url = '..'
308
    cookies_to_clear = []
309

    
310
    def delete(self, request, *args, **kwargs):
311
        self.object = self.get_object()
312
        # If exceptions remove them only if act is not billed
313
        for exception in self.object.exceptions.all():
314
            exception.recurrence_periodicity = None
315
            exception.exception_to = None
316
            exception.save()
317
            if exception.event_type == 1:
318
                delete_eventwithact(exception)
319
            else:
320
                exception.delete()
321

    
322
        if self.object.event_type == 1:
323
            delete_eventwithact(self.object)
324
        else:
325
            self.object.delete()
326
        return HttpResponse(status=204)
327

    
328
class AgendaServiceActValidationView(TemplateView):
329
    template_name = 'agenda/act-validation.html'
330
    cookies_to_clear = [('agenda-tabs', ), ('active-agenda', ), ('last-ressource', )]
331

    
332
    def acts_of_the_day(self):
333
        acts = list(Act.objects \
334
                .filter(date=self.date, patient__service=self.service) \
335
                .select_related() \
336
                .prefetch_related('doctors',
337
                        'patient__patientcontact',
338
                        'actvalidationstate_set__previous_state') \
339
                .order_by('time'))
340
        event_ids = [ a.parent_event_id for a in acts if a.parent_event_id ]
341
        events = EventWithAct.objects.for_today(self.date) \
342
                .filter(patient__service=self.service) \
343
                .exclude(id__in=event_ids)
344
        events = [ event.today_occurrence(self.date) for event in events ]
345
        acts += [ event.act for event in events if event ]
346
        return sorted(acts, key=lambda a: (a.time or datetime.time.min, a.id))
347

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

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

    
406

    
407
class AutomatedValidationView(TemplateView):
408
    template_name = 'agenda/automated-validation.html'
409

    
410
    def post(self, request, *args, **kwargs):
411
        automated_validation(self.date, self.service,
412
            request.user)
413
        ValidationMessage(validation_date=self.date,
414
            who=request.user, what='Validation automatique',
415
            service=self.service).save()
416
        return HttpResponseRedirect('..')
417

    
418
    def get_context_data(self, **kwargs):
419
        context = super(AutomatedValidationView, self).get_context_data(**kwargs)
420
        request = self.request
421
        (nb_acts_total, nb_acts_validated, nb_acts_double,
422
        nb_acts_abs_non_exc, nb_acts_abs_exc, nb_acts_abs_inter, nb_acts_annul_nous,
423
        nb_acts_annul_famille, nb_acts_reporte, nb_acts_abs_ess_pps,
424
        nb_acts_enf_hosp, nb_acts_losts) = \
425
            automated_validation(self.date, self.service,
426
                request.user, commit = False)
427

    
428
        nb_acts_not_validated = nb_acts_double + \
429
            nb_acts_abs_non_exc + \
430
            nb_acts_abs_exc + \
431
            nb_acts_abs_inter + \
432
            nb_acts_annul_nous + \
433
            nb_acts_annul_famille + \
434
            nb_acts_reporte + \
435
            nb_acts_abs_ess_pps + \
436
            nb_acts_enf_hosp + \
437
            nb_acts_losts
438
        context.update({
439
            'nb_acts_total': nb_acts_total,
440
            'nb_acts_validated': nb_acts_validated,
441
            'nb_acts_not_validated': nb_acts_not_validated,
442
            'nb_acts_double': nb_acts_double,
443
            'nb_acts_abs_non_exc': nb_acts_abs_non_exc,
444
            'nb_acts_abs_exc': nb_acts_abs_exc,
445
            'nb_acts_abs_inter': nb_acts_abs_inter,
446
            'nb_acts_annul_nous': nb_acts_annul_nous,
447
            'nb_acts_annul_famille': nb_acts_annul_famille,
448
            'nb_acts_reporte': nb_acts_reporte,
449
            'nb_acts_abs_ess_pps': nb_acts_abs_ess_pps,
450
            'nb_acts_enf_hosp': nb_acts_enf_hosp,
451
            'nb_acts_losts': nb_acts_losts})
452
        return context
453

    
454
class UnlockAllView(CreateView):
455
    pass
456

    
457

    
458
class AgendasTherapeutesView(AgendaHomepageView):
459
    template_name = 'agenda/agendas-therapeutes.html'
460
    cookies_to_clear = [('agenda-tabs', ), ('active-agenda', ), ('last-ressource', )]
461

    
462
    def get_context_data(self, **kwargs):
463
        context = super(AgendasTherapeutesView, self).get_context_data(**kwargs)
464

    
465
        time_tables = TimeTable.objects.select_related('worker'). \
466
                filter(services=self.service). \
467
                for_today(self.date). \
468
                order_by('start_date')
469
        holidays = Holiday.objects.select_related('worker') \
470
                .for_period(self.date, self.date) \
471
                .order_by('start_date') \
472
                .select_related()
473
        events = Event.objects.for_today(self.date) \
474
                .exclude(event_type_id=1) \
475
                .filter(services=self.service) \
476
                .order_by('start_datetime') \
477
                .select_related() \
478
                .prefetch_related('services',
479
                        'exceptions',
480
                        'participants')
481
        eventswithact = EventWithAct.objects.for_today(self.date) \
482
                .filter(services=self.service) \
483
                .order_by('start_datetime') \
484
                .select_related() \
485
                .prefetch_related(
486
                        'services',
487
                        'patient__service',
488
                        'act_set__actvalidationstate_set',
489
                        'exceptions', 'participants')
490
        events = [ e.today_occurrence(self.date) for e in events ] \
491
             + [ e.today_occurrence(self.date) for e in eventswithact ]
492
        for e in events:
493
            e.workers_ids = set(p.id for p in e.participants.all())
494

    
495
        events_workers = {}
496
        time_tables_workers = {}
497
        holidays_workers = {}
498
        context['workers_agenda'] = []
499
        context['workers'] = context['workers'].filter(services=self.service)
500
        for worker in context['workers']:
501
            time_tables_worker = [tt for tt in time_tables if tt.worker.id == worker.id]
502
            events_worker = [o for o in events if worker.id in o.workers_ids ]
503
            holidays_worker = [h for h in holidays if h.worker_id in (None, worker.id)]
504
            events_workers[worker.id] = events_worker
505
            time_tables_workers[worker.id] = time_tables_worker
506
            holidays_workers[worker.id] = holidays_worker
507
            daily_appointments = get_daily_appointments(context['date'], worker, self.service,
508
                        time_tables_worker, events_worker, holidays_worker)
509
            if all(map(lambda x: x.holiday, daily_appointments)):
510
                continue
511
            context['workers_agenda'].append({'worker': worker,
512
                    'appointments': daily_appointments})
513

    
514
        for worker_agenda in context.get('workers_agenda', []):
515
            patient_appointments = [x for x in worker_agenda['appointments'] if x.patient_record_id]
516
            worker_agenda['summary'] = {
517
              'rdv': len(patient_appointments),
518
              'presence': len([x for x in patient_appointments if x.act_absence is None]),
519
              'absence': len([x for x in patient_appointments if x.act_absence is not None]),
520
              'doubles': len([x for x in patient_appointments if x.act_type == 'ACT_DOUBLE']),
521
              'valides': len([x for x in patient_appointments if x.act_type == 'ACT_VALIDE']),
522
            }
523

    
524
        return context
525

    
526
class JoursNonVerrouillesView(TemplateView):
527
    template_name = 'agenda/days-not-locked.html'
528

    
529
    def get_context_data(self, **kwargs):
530
        context = super(JoursNonVerrouillesView, self).get_context_data(**kwargs)
531
        acts = Act.objects.filter(is_billed=False,
532
            patient__service=self.service).order_by('date')
533
        days = set(acts.values_list('date', flat=True))
534
        if days:
535
            max_day, min_day = max(days), min(days)
536
            today = datetime.datetime.today().date()
537
            if max_day > today:
538
                max_day = today
539
            days &= set(get_days_with_acts_not_locked(min_day, max_day, self.service))
540
        context['days_not_locked'] = sorted(days)
541
        return context
542

    
543
class AjaxWorkerTabView(TemplateView):
544

    
545
    template_name = 'agenda/ajax-worker-tab.html'
546
    cookies_to_clear = []
547

    
548
    def get_context_data(self, worker_id, **kwargs):
549
        context = super(AjaxWorkerTabView, self).get_context_data(**kwargs)
550
        worker = Worker.objects.get(id=worker_id)
551

    
552
        time_tables_worker = TimeTable.objects.select_related('worker'). \
553
                filter(services=self.service, worker=worker) \
554
                .for_today(self.date) \
555
                .order_by('start_date') \
556
                .select_related()
557
        holidays_worker = Holiday.objects.for_worker(worker) \
558
                .for_period(self.date, self.date) \
559
                .order_by('start_date') \
560
                .select_related()
561
        events = Event.objects.for_today(self.date) \
562
                .exclude(event_type_id=1) \
563
                .filter(participants=worker) \
564
                .order_by('start_datetime') \
565
                .select_related() \
566
                .prefetch_related('services',
567
                        'exceptions',
568
                        'participants')
569
        eventswithact = EventWithAct.objects.for_today(self.date) \
570
                .filter(participants=worker) \
571
                .order_by('start_datetime') \
572
                .select_related() \
573
                .prefetch_related('patient__addresses',
574
                        'patient__addresses__patientcontact_set',
575
                        'services',
576
                        'patient__service',
577
                        'act_set__actvalidationstate_set',
578
                        'exceptions', 'participants')
579
        events = [ e.today_occurrence(self.date) for e in events ] \
580
             + [ e.today_occurrence(self.date) for e in eventswithact ]
581

    
582
        context['worker_agenda'] = {'worker': worker,
583
                    'appointments': get_daily_appointments(context['date'], worker, self.service,
584
                        time_tables_worker, events, holidays_worker)}
585

    
586
        if settings.RTF_TEMPLATES_DIRECTORY:
587
            context['mail'] = True
588
        return context
589

    
590
class AjaxRessourceTabView(TemplateView):
591
    template_name = 'agenda/ajax-ressource-tab.html'
592
    cookies_to_clear = []
593

    
594
    def get_context_data(self, ressource_id, **kwargs):
595
        context = super(AjaxRessourceTabView, self).get_context_data(**kwargs)
596
        ressource = Ressource.objects.get(pk=ressource_id)
597
        plain_events = Event.objects.for_today(self.date) \
598
                                    .order_by('start_datetime').select_subclasses()
599
        events = [ e.today_occurrence(self.date) for e in plain_events ]
600
        events_ressource = [e for e in events if ressource == e.ressource]
601
        context['ressource_agenda'] = {'appointments': get_daily_usage(context['date'],
602
                                                                       ressource,
603
                                                                       self.service,
604
                                                                       events_ressource)
605
        }
606
        return context
607

    
608
class AjaxDisponibilityColumnView(TemplateView):
609

    
610
    template_name = 'agenda/ajax-disponibility-column.html'
611
    cookies_to_clear = []
612

    
613
    def get_ressource_context_data(self, ressource_id, context):
614
        ressource = Ressource.objects.get(pk = ressource_id)
615
        context['initials'] = ressource.name[:3]
616
        disponibility = dict()
617
        start_datetime = datetime.datetime(self.date.year,
618
                                           self.date.month,
619
                                           self.date.day, 8, 0)
620
        end_datetime = datetime.datetime(self.date.year, self.date.month,
621
                                         self.date.day, 8, 15)
622
        events = Event.objects.filter(ressource__id=ressource_id).today_occurrences(self.date)
623

    
624
        while (start_datetime.hour <= 19):
625
            if start_datetime.hour not in disponibility:
626
                disponibility[start_datetime.hour] = [[], [], [], []]
627
                quarter = 0
628
            dispo = 'free'
629
            mins = quarter * 15
630

    
631
            if events:
632
                for event in events:
633
                    overlap_events = Event.objects.overlap_occurences(start_datetime, events)
634
                    if len(overlap_events) > 1:
635
                        dispo = 'overlap'
636
                    elif event.start_datetime <= start_datetime and event.end_datetime >= end_datetime:
637
                        dispo = 'busy'
638
                disponibility[start_datetime.hour][quarter].append((mins, {'id': ressource_id, 'dispo': dispo}))
639
            quarter += 1
640
            start_datetime += datetime.timedelta(minutes=15)
641
            end_datetime += datetime.timedelta(minutes=15)
642

    
643
        context['disponibility'] = disponibility
644
        return context
645

    
646

    
647
    def get_worker_context_data(self, worker_id, context):
648
        worker = Worker.objects.get(pk=worker_id)
649

    
650
        time_tables = TimeTable.objects.select_related('worker'). \
651
                filter(services=self.service, worker=worker). \
652
                for_today(self.date). \
653
                order_by('start_date')
654
        holidays = Holiday.objects.for_worker(worker). \
655
                for_period(self.date, self.date). \
656
                order_by('start_date')
657
        events = Event.objects.for_today(self.date) \
658
                .exclude(event_type_id=1) \
659
                .filter(participants=worker) \
660
                .order_by('start_datetime') \
661
                .select_related() \
662
                .prefetch_related('participants', 'exceptions')
663
        eventswithact = EventWithAct.objects.for_today(self.date) \
664
                .filter(participants=worker) \
665
                .order_by('start_datetime') \
666
                .select_related() \
667
                .prefetch_related('participants', 'exceptions',
668
                        'act_set__actvalidationstate_set')
669

    
670
        events = list(events) + list(eventswithact)
671
        events = [ e.today_occurrence(self.date) for e in events ]
672
        time_tables_workers = {worker.id: time_tables}
673
        events_workers = {worker.id: events}
674
        holidays_workers = {worker.id: holidays}
675

    
676
        context['initials'] = worker.initials
677
        context['disponibility'] = Event.objects.daily_disponibilities(self.date,
678
                events, worker, time_tables, holidays)
679
        return context
680

    
681
    def get_context_data(self, ressource_type, ressource_id, **kwargs):
682
        context = super(AjaxDisponibilityColumnView, self).get_context_data(**kwargs)
683
        if ressource_type in ('worker', 'ressource',):
684
            context['ressource_type'] = ressource_type
685
            context['ressource_id'] = ressource_id
686
            getattr(self, 'get_%s_context_data' % ressource_type)(ressource_id, context)
687
        return context
688

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

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

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

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

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

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