Projet

Général

Profil

Télécharger (32,3 ko) Statistiques
| Branche: | Tag: | Révision:

calebasse / calebasse / agenda / views.py @ ce41c769

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
class BaseEventView(UpdateView):
243
    model = Event
244
    form_class = UpdateEventForm
245
    template_name = 'agenda/update-event.html'
246
    success_url = '..'
247
    cookies_to_clear = []
248

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

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

    
268

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

    
272

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

    
277
def delete_eventwithact(event):
278
    assert event.event_type_id == 1
279

    
280
    # in case of "event" is an instance of "Event" model and not "EventWithAct"
281
    # and so doesn't have 'act' attribute
282
    try:
283
        if event.act.id \
284
           and not event.act.is_billed:
285
            event.act.delete()
286

    
287
        if not event.act.id or \
288
           not event.act.is_billed:
289
            event.delete()
290
    except AttributeError:
291
        event.delete()
292

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

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

    
305
        return HttpResponse(status=204)
306

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

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

    
324
        if self.object.event_type_id == 1:
325
            delete_eventwithact(self.object)
326
        else:
327
            self.object.delete()
328
        return HttpResponse(status=204)
329

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

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

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

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

    
409

    
410
class AutomatedValidationView(TemplateView):
411
    template_name = 'agenda/automated-validation.html'
412

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

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

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

    
457
class UnlockAllView(CreateView):
458
    pass
459

    
460

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

    
465
    def get_context_data(self, **kwargs):
466
        context = super(AgendasTherapeutesView, self).get_context_data(**kwargs)
467

    
468
        time_tables = TimeTable.objects.select_related('worker'). \
469
                filter(services=self.service). \
470
                for_today(self.date). \
471
                order_by('start_date')
472
        holidays = Holiday.objects.select_related('worker') \
473
                .for_period(self.date, self.date) \
474
                .order_by('start_date') \
475
                .select_related()
476
        events = Event.objects.for_today(self.date) \
477
                .exclude(event_type_id=1) \
478
                .filter(services=self.service) \
479
                .order_by('start_datetime') \
480
                .select_related() \
481
                .prefetch_related('services',
482
                        'exceptions',
483
                        'participants')
484
        eventswithact = EventWithAct.objects.for_today(self.date) \
485
                .filter(services=self.service) \
486
                .order_by('start_datetime') \
487
                .select_related() \
488
                .prefetch_related(
489
                        'services',
490
                        'patient__service',
491
                        'act_set__actvalidationstate_set',
492
                        'exceptions', 'participants')
493

    
494
        context['CURRENT_SERVICE_EVENTS_ONLY'] = settings.CURRENT_SERVICE_EVENTS_ONLY
495

    
496
        events = [ e.today_occurrence(self.date) for e in events ] \
497
             + [ e.today_occurrence(self.date) for e in eventswithact ]
498
        for e in events:
499
            e.workers_ids = set(p.id for p in e.participants.all())
500

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

    
518
            context['workers_agenda'].append({'worker': worker,
519
                    'appointments': daily_appointments,
520
                    'activity': activity,
521
                    'has_events': True if events_worker else False})
522

    
523
        for worker_agenda in context.get('workers_agenda', []):
524
            patient_appointments = [x for x in worker_agenda['appointments'] if x.patient_record_id]
525
            worker_agenda['summary'] = {
526
              'rdv': len(patient_appointments),
527
              'presence': len([x for x in patient_appointments if x.act_absence is None]),
528
              'absence': len([x for x in patient_appointments if x.act_absence is not None]),
529
              'doubles': len([x for x in patient_appointments if x.act_type == 'ACT_DOUBLE']),
530
              'valides': len([x for x in patient_appointments if x.act_type == 'ACT_VALIDE']),
531
            }
532

    
533
        return context
534

    
535
class JoursNonVerrouillesView(TemplateView):
536
    template_name = 'agenda/days-not-locked.html'
537

    
538
    def get_context_data(self, **kwargs):
539
        context = super(JoursNonVerrouillesView, self).get_context_data(**kwargs)
540
        acts = Act.objects.filter(is_billed=False,
541
            patient__service=self.service).order_by('date')
542
        days = set(acts.values_list('date', flat=True))
543
        if days:
544
            max_day, min_day = max(days), min(days)
545
            today = datetime.datetime.today().date()
546
            if max_day > today:
547
                max_day = today
548
            days &= set(get_days_with_acts_not_locked(min_day, max_day, self.service))
549
        context['days_not_locked'] = sorted(days)
550
        return context
551

    
552
class AjaxWorkerTabView(TemplateView):
553

    
554
    template_name = 'agenda/ajax-worker-tab.html'
555
    cookies_to_clear = []
556

    
557
    def get_context_data(self, worker_id, **kwargs):
558
        context = super(AjaxWorkerTabView, self).get_context_data(**kwargs)
559
        worker = Worker.objects.get(id=worker_id)
560

    
561
        time_tables_worker = TimeTable.objects.select_related('worker'). \
562
                filter(worker=worker) \
563
                .for_today(self.date) \
564
                .order_by('start_date') \
565
                .select_related()
566

    
567
        holidays_worker = Holiday.objects.for_worker(worker) \
568
                .for_period(self.date, self.date) \
569
                .order_by('start_date') \
570
                .select_related()
571
        events = Event.objects.for_today(self.date) \
572
                .exclude(event_type_id=1) \
573
                .filter(participants=worker) \
574
                .order_by('start_datetime') \
575
                .select_related() \
576
                .prefetch_related('services',
577
                        'exceptions',
578
                        'participants')
579
        eventswithact = EventWithAct.objects.for_today(self.date) \
580
                .filter(participants=worker) \
581
                .order_by('start_datetime') \
582
                .select_related() \
583
                .prefetch_related('patient__addresses',
584
                        'patient__addresses__patientcontact_set',
585
                        'services',
586
                        'patient__service',
587
                        'act_set__actvalidationstate_set',
588
                        'exceptions', 'participants')
589
        events = [ e.today_occurrence(self.date) for e in events ] \
590
             + [ e.today_occurrence(self.date) for e in eventswithact ]
591
        activity, appointments = get_daily_appointments(context['date'], worker,
592
                                                        self.service, time_tables_worker,
593
                                                        events, holidays_worker)
594

    
595
        context['worker_agenda'] = {'worker': worker,
596
                                    'appointments': appointments}
597

    
598
        if settings.RTF_TEMPLATES_DIRECTORY:
599
            context['mail'] = True
600
        return context
601

    
602
class AjaxRessourceTabView(TemplateView):
603
    template_name = 'agenda/ajax-ressource-tab.html'
604
    cookies_to_clear = []
605

    
606
    def get_context_data(self, ressource_id, **kwargs):
607
        context = super(AjaxRessourceTabView, self).get_context_data(**kwargs)
608
        ressource = Ressource.objects.get(pk=ressource_id)
609
        plain_events = Event.objects.for_today(self.date) \
610
                                    .order_by('start_datetime').select_subclasses()
611
        events = [ e.today_occurrence(self.date) for e in plain_events ]
612
        events_ressource = [e for e in events if ressource == e.ressource]
613
        context['ressource_agenda'] = {'appointments': get_daily_usage(context['date'],
614
                                                                       ressource,
615
                                                                       self.service,
616
                                                                       events_ressource)
617
        }
618
        return context
619

    
620
class AjaxDisponibilityColumnView(TemplateView):
621

    
622
    template_name = 'agenda/ajax-disponibility-column.html'
623
    cookies_to_clear = []
624

    
625
    def get_ressource_context_data(self, ressource_id, context):
626
        ressource = Ressource.objects.get(pk = ressource_id)
627
        context['initials'] = ressource.name[:3]
628
        disponibility = dict()
629
        start_datetime = datetime.datetime(self.date.year,
630
                                           self.date.month,
631
                                           self.date.day, 8, 0)
632
        end_datetime = datetime.datetime(self.date.year, self.date.month,
633
                                         self.date.day, 8, 15)
634
        events = Event.objects.filter(ressource__id=ressource_id).today_occurrences(self.date)
635

    
636
        while (start_datetime.hour <= 19):
637
            if start_datetime.hour not in disponibility:
638
                disponibility[start_datetime.hour] = [[], [], [], []]
639
                quarter = 0
640
            dispo = 'free'
641
            mins = quarter * 15
642

    
643
            if events:
644
                for event in events:
645
                    overlap_events = Event.objects.overlap_occurences(start_datetime, events)
646
                    if len(overlap_events) > 1:
647
                        dispo = 'overlap'
648
                    elif event.start_datetime <= start_datetime and event.end_datetime >= end_datetime:
649
                        dispo = 'busy'
650
            disponibility[start_datetime.hour][quarter].append((mins, {'id': ressource_id, 'dispo': dispo}))
651
            quarter += 1
652
            start_datetime += datetime.timedelta(minutes=15)
653
            end_datetime += datetime.timedelta(minutes=15)
654

    
655
        context['disponibility'] = disponibility
656
        return context
657

    
658

    
659
    def get_worker_context_data(self, worker_id, context):
660
        worker = Worker.objects.get(pk=worker_id)
661

    
662
        time_tables = TimeTable.objects.select_related('worker'). \
663
                filter(services=self.service, worker=worker). \
664
                for_today(self.date). \
665
                order_by('start_date')
666
        holidays = Holiday.objects.for_worker(worker). \
667
                for_period(self.date, self.date). \
668
                order_by('start_date')
669
        events = Event.objects.for_today(self.date) \
670
                .exclude(event_type_id=1) \
671
                .filter(participants=worker) \
672
                .order_by('start_datetime') \
673
                .select_related() \
674
                .prefetch_related('participants', 'exceptions')
675
        eventswithact = EventWithAct.objects.for_today(self.date) \
676
                .filter(participants=worker) \
677
                .order_by('start_datetime') \
678
                .select_related() \
679
                .prefetch_related('participants', 'exceptions',
680
                        'act_set__actvalidationstate_set')
681

    
682
        events = list(events) + list(eventswithact)
683
        events = [ e.today_occurrence(self.date) for e in events ]
684
        time_tables_workers = {worker.id: time_tables}
685
        events_workers = {worker.id: events}
686
        holidays_workers = {worker.id: holidays}
687

    
688
        context['initials'] = worker.initials
689
        context['disponibility'] = Event.objects.daily_disponibilities(self.date,
690
                events, worker, time_tables, holidays)
691
        return context
692

    
693
    def get_context_data(self, ressource_type, ressource_id, **kwargs):
694
        context = super(AjaxDisponibilityColumnView, self).get_context_data(**kwargs)
695
        if ressource_type in ('worker', 'ressource',):
696
            context['ressource_type'] = ressource_type
697
            context['ressource_id'] = ressource_id
698
            getattr(self, 'get_%s_context_data' % ressource_type)(ressource_id, context)
699
        return context
700

    
701
class PeriodicEventsView(cbv.ListView):
702
    model = EventWithAct
703
    template_name = 'agenda/periodic-events.html'
704
    cookies_to_clear = [('agenda-tabs', ), ('active-agenda', ), ('last-ressource', )]
705

    
706
    def dispatch(self, request, *args, **kwargs):
707
        if 'worker_id' in kwargs:
708
            self.worker = get_object_or_404(Worker, id=kwargs['worker_id'])
709
        else:
710
            self.worker = None
711
        return super(PeriodicEventsView, self).dispatch(request, *args, **kwargs)
712

    
713
    def get_form(self):
714
        kwargs = {
715
                'initial': {
716
                    'start_date': self.date,
717
                }
718
        }
719
        if self.request.GET:
720
            kwargs['data'] = self.request.GET
721
        self.form = PeriodicEventsSearchForm(prefix='periodic-events-search-form', **kwargs)
722
        return self.form
723

    
724
    def get_queryset(self):
725
        qs1 = Event.objects.exclude(event_type_id=1)
726
        qs2 = EventWithAct.objects.all()
727
        form = self.get_form()
728
        if not self.request.GET:
729
            return ()
730
        qs1 = self.filter_queryset(form, qs1)
731
        qs2 = self.filter_queryset(form, qs2)
732
        if form.is_valid():
733
            patient = form.cleaned_data.get('patient')
734
            if patient is not None:
735
                qs1 = qs1.none()
736
                qs2 = qs2.filter(patient=patient)
737
            worker = form.cleaned_data.get('worker')
738
            if worker is not None:
739
                qs1 = qs1.filter(participants=worker)
740
                qs2 = qs2.filter(participants=worker)
741
        return sorted(chain(qs1, qs2),
742
                key=lambda x: (x.start_datetime, x.recurrence_end_date or datetime.date(9999,12,31)))
743

    
744
    def filter_queryset(self, form, qs):
745
        if self.worker is not None:
746
            qs = qs.filter(participants=self.worker)
747
        start_date = datetime.date.today()
748
        end_date = start_date+datetime.timedelta(days=90)
749
        if form.is_valid():
750
            if form.cleaned_data.get('start_date'):
751
                start_date = form.cleaned_data['start_date']
752
            if form.cleaned_data.get('end_date'):
753
                end_date = form.cleaned_data['end_date']
754
            else:
755
                end_date = start_date+datetime.timedelta(days=90)
756
            if len(form.cleaned_data.get('event_type')) != 2:
757
                if '0' in form.cleaned_data.get('event_type'):
758
                    qs = qs.filter(event_type_id=1)
759
                else:
760
                    qs = qs.exclude(event_type_id=1)
761
            if form.cleaned_data.get('no_end_date'):
762
                qs = qs.filter(recurrence_end_date__isnull=True)
763
        qs = qs.filter(canceled=False)
764
        qs = qs.filter(services=self.service)
765
        qs = qs.filter(recurrence_periodicity__isnull=False)
766
        qs = qs.filter(start_datetime__lt=end_date)
767
        qs = qs.filter(Q(recurrence_end_date__isnull=True)
768
                | Q(recurrence_end_date__gte=start_date))
769
        qs = qs.order_by('start_datetime', 'recurrence_end_date')
770
        qs = qs.select_related()
771
        qs = qs.prefetch_related('participants', 'services')
772
        return qs
773

    
774
    def get_context_data(self, **kwargs):
775
        ctx = super(PeriodicEventsView, self).get_context_data(**kwargs)
776
        ctx['search_form'] = self.form
777
        ctx['worker'] = self.worker
778
        return ctx
(10-10/10)