Project

General

Profile

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

calebasse / calebasse / agenda / views.py @ 1e0ec553

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.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_success_url(self):
154
        return self.request.META.get('HTTP_REFERER', '..')
155

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

    
161

    
162
class TodayOccurrenceMixin(object):
163
    def get_object(self, queryset=None):
164
        o = super(TodayOccurrenceMixin, self).get_object(queryset)
165
        obj = o.today_occurrence(self.date)
166
        if obj:
167
            return obj
168
        raise Http404
169

    
170

    
171
class BaseAppointmentView(UpdateView):
172
    model = EventWithAct
173
    form_class = UpdateAppointmentForm
174
    template_name = 'agenda/update-rdv.html'
175
    success_url = '..'
176
    cookies_to_clear = []
177

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

    
192
    def get_form_kwargs(self):
193
        kwargs = super(BaseAppointmentView, self).get_form_kwargs()
194
        kwargs['service'] = self.service
195
        return kwargs
196

    
197

    
198
class UpdateAppointmentView(TodayOccurrenceMixin, BaseAppointmentView):
199

    
200
    def get_form_class(self):
201
        if self.object.exception_to and not self.object.exception_to.canceled:
202
            return DisablePatientAppointmentForm
203
        else:
204
            return self.form_class
205

    
206
class UpdatePeriodicAppointmentView(BaseAppointmentView):
207
    form_class = UpdatePeriodicAppointmentForm
208
    template_name = 'agenda/new-appointment.html'
209

    
210

    
211
class NewEventView(CreateView):
212
    model = Event
213
    form_class = NewEventForm
214
    template_name = 'agenda/new-event.html'
215
    cookies_to_clear = []
216

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

    
230
    def get_form_kwargs(self):
231
        kwargs = super(NewEventView, self).get_form_kwargs()
232
        kwargs['service'] = self.service
233
        return kwargs
234

    
235
    def get_success_url(self):
236
        return self.request.META.get('HTTP_REFERER', '..')
237

    
238
    def form_valid(self, form):
239
        messages.add_message(self.request, messages.INFO, u'Evénement enregistré avec succès.')
240
        return super(NewEventView, self).form_valid(form)
241

    
242

    
243
class BaseEventView(UpdateView):
244
    model = Event
245
    form_class = UpdateEventForm
246
    template_name = 'agenda/update-event.html'
247
    success_url = '..'
248
    cookies_to_clear = []
249

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

    
264
    def get_form_kwargs(self):
265
        kwargs = super(BaseEventView, self).get_form_kwargs()
266
        kwargs['service'] = self.service
267
        return kwargs
268

    
269

    
270
class UpdateEventView(TodayOccurrenceMixin, BaseEventView):
271
    pass
272

    
273

    
274
class UpdatePeriodicEventView(BaseEventView):
275
    form_class = UpdatePeriodicEventForm
276
    template_name = 'agenda/new-event.html'
277

    
278
def delete_eventwithact(event):
279
    assert event.event_type.id == 1
280
    if event.act.id \
281
            and not event.act.is_billed:
282
        event.act.delete()
283
    if not event.act.id or \
284
            not event.act.is_billed:
285
        event.delete()
286

    
287
class DeleteOccurrenceView(TodayOccurrenceMixin, cbv.DeleteView):
288
    model = Event
289
    success_url = '..'
290
    cookies_to_clear = []
291

    
292
    def delete(self, request, *args, **kwargs):
293
        self.object = self.get_object()
294
        if self.object.event_type.id == 1:
295
            delete_eventwithact(self.object)
296
        else:
297
            self.object.delete()
298

    
299
        return HttpResponse(status=204)
300

    
301
class DeleteEventView(cbv.DeleteView):
302
    model = Event
303
    success_url = '..'
304
    cookies_to_clear = []
305

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

    
318
        if self.object.event_type.id == 1:
319
            delete_eventwithact(self.object)
320
        else:
321
            self.object.delete()
322
        return HttpResponse(status=204)
323

    
324
class AgendaServiceActValidationView(TemplateView):
325
    template_name = 'agenda/act-validation.html'
326
    cookies_to_clear = [('agenda-tabs', ), ('active-agenda', ), ('last-ressource', )]
327

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

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

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

    
402

    
403
class AutomatedValidationView(TemplateView):
404
    template_name = 'agenda/automated-validation.html'
405

    
406
    def post(self, request, *args, **kwargs):
407
        automated_validation(self.date, self.service,
408
            request.user)
409
        ValidationMessage(validation_date=self.date,
410
            who=request.user, what='Validation automatique',
411
            service=self.service).save()
412
        return HttpResponseRedirect('..')
413

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

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

    
450
class UnlockAllView(CreateView):
451
    pass
452

    
453

    
454
class AgendasTherapeutesView(AgendaHomepageView):
455
    template_name = 'agenda/agendas-therapeutes.html'
456
    cookies_to_clear = [('agenda-tabs', ), ('active-agenda', ), ('last-ressource', )]
457

    
458
    def get_context_data(self, **kwargs):
459
        context = super(AgendasTherapeutesView, self).get_context_data(**kwargs)
460

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

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

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

    
521
        return context
522

    
523
class JoursNonVerrouillesView(TemplateView):
524
    template_name = 'agenda/days-not-locked.html'
525

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

    
540
class AjaxWorkerTabView(TemplateView):
541

    
542
    template_name = 'agenda/ajax-worker-tab.html'
543
    cookies_to_clear = []
544

    
545
    def get_context_data(self, worker_id, **kwargs):
546
        context = super(AjaxWorkerTabView, self).get_context_data(**kwargs)
547
        worker = Worker.objects.get(id=worker_id)
548

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

    
579
        context['worker_agenda'] = {'worker': worker,
580
                    'appointments': get_daily_appointments(context['date'], worker, self.service,
581
                        time_tables_worker, events, holidays_worker)}
582

    
583
        if settings.RTF_TEMPLATES_DIRECTORY:
584
            context['mail'] = True
585
        return context
586

    
587
class AjaxRessourceTabView(TemplateView):
588
    template_name = 'agenda/ajax-ressource-tab.html'
589
    cookies_to_clear = []
590

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

    
605
class AjaxDisponibilityColumnView(TemplateView):
606

    
607
    template_name = 'agenda/ajax-disponibility-column.html'
608
    cookies_to_clear = []
609

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

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

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

    
640
        context['disponibility'] = disponibility
641
        return context
642

    
643

    
644
    def get_worker_context_data(self, worker_id, context):
645
        worker = Worker.objects.get(pk=worker_id)
646

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

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

    
673
        context['initials'] = worker.initials
674
        context['disponibility'] = Event.objects.daily_disponibilities(self.date,
675
                events, worker, time_tables, holidays)
676
        return context
677

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

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

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

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

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

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

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