Projet

Général

Profil

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

calebasse / calebasse / agenda / views.py @ 75f679a3

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

    
284
    if not event.act.id or \
285
            not event.act.is_billed:
286
        event.delete()
287

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

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

    
300
        return HttpResponse(status=204)
301

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

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

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

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

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

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

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

    
403

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

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

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

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

    
451
class UnlockAllView(CreateView):
452
    pass
453

    
454

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

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

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

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

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

    
522
        return context
523

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

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

    
541
class AjaxWorkerTabView(TemplateView):
542

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

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

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

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

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

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

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

    
606
class AjaxDisponibilityColumnView(TemplateView):
607

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

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

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

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

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

    
644

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

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

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

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

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

    
687
class PeriodicEventsView(cbv.ListView):
688
    model = EventWithAct
689
    template_name = 'agenda/periodic-events.html'
690
    cookies_to_clear = [('agenda-tabs', ), ('active-agenda', ), ('last-ressource', )]
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)