Projet

Général

Profil

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

calebasse / calebasse / agenda / views.py @ 8a5069a6

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

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

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

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

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

    
306
        return HttpResponse(status=204)
307

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

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

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

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

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

    
351
    def post(self, request, *args, **kwargs):
352
        if 'unlock-all' in request.POST:
353
            #TODO: check that the user is authorized
354
            unlock_all_acts_of_the_day(self.date, self.service)
355
            ValidationMessage(validation_date=self.date,
356
                who=request.user, what='Déverrouillage',
357
                service=self.service).save()
358
        else:
359
            acte_id = request.POST.get('acte-id')
360
            try:
361
                act = Act.objects.get(id=acte_id)
362
                if 'lock' in request.POST or 'unlock' in request.POST:
363
                    #TODO: check that the user is authorized
364
                    act.validation_locked = 'lock' in request.POST
365
                    act.save()
366
                else:
367
                    state_name = request.POST.get('act_state')
368
                    act.set_state(state_name, request.user)
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
        events = [ e.today_occurrence(self.date) for e in events ] \
494
             + [ e.today_occurrence(self.date) for e in eventswithact ]
495
        for e in events:
496
            e.workers_ids = set(p.id for p in e.participants.all())
497

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

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

    
528
        return context
529

    
530
class JoursNonVerrouillesView(TemplateView):
531
    template_name = 'agenda/days-not-locked.html'
532

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

    
547
class AjaxWorkerTabView(TemplateView):
548

    
549
    template_name = 'agenda/ajax-worker-tab.html'
550
    cookies_to_clear = []
551

    
552
    def get_context_data(self, worker_id, **kwargs):
553
        context = super(AjaxWorkerTabView, self).get_context_data(**kwargs)
554
        worker = Worker.objects.get(id=worker_id)
555

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

    
586
        context['worker_agenda'] = {'worker': worker,
587
                    'appointments': get_daily_appointments(context['date'], worker, self.service,
588
                        time_tables_worker, events, holidays_worker)}
589

    
590
        if settings.RTF_TEMPLATES_DIRECTORY:
591
            context['mail'] = True
592
        return context
593

    
594
class AjaxRessourceTabView(TemplateView):
595
    template_name = 'agenda/ajax-ressource-tab.html'
596
    cookies_to_clear = []
597

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

    
612
class AjaxDisponibilityColumnView(TemplateView):
613

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

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

    
628
        while (start_datetime.hour <= 19):
629
            if start_datetime.hour not in disponibility:
630
                disponibility[start_datetime.hour] = [[], [], [], []]
631
                quarter = 0
632
            dispo = 'free'
633
            mins = quarter * 15
634

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

    
647
        context['disponibility'] = disponibility
648
        return context
649

    
650

    
651
    def get_worker_context_data(self, worker_id, context):
652
        worker = Worker.objects.get(pk=worker_id)
653

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

    
674
        events = list(events) + list(eventswithact)
675
        events = [ e.today_occurrence(self.date) for e in events ]
676
        time_tables_workers = {worker.id: time_tables}
677
        events_workers = {worker.id: events}
678
        holidays_workers = {worker.id: holidays}
679

    
680
        context['initials'] = worker.initials
681
        context['disponibility'] = Event.objects.daily_disponibilities(self.date,
682
                events, worker, time_tables, holidays)
683
        return context
684

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

    
693
class PeriodicEventsView(cbv.ListView):
694
    model = EventWithAct
695
    template_name = 'agenda/periodic-events.html'
696
    cookies_to_clear = [('agenda-tabs', ), ('active-agenda', ), ('last-ressource', )]
697

    
698
    def dispatch(self, request, *args, **kwargs):
699
        if 'worker_id' in kwargs:
700
            self.worker = get_object_or_404(Worker, id=kwargs['worker_id'])
701
        else:
702
            self.worker = None
703
        return super(PeriodicEventsView, self).dispatch(request, *args, **kwargs)
704

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

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

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

    
766
    def get_context_data(self, **kwargs):
767
        ctx = super(PeriodicEventsView, self).get_context_data(**kwargs)
768
        ctx['search_form'] = self.form
769
        ctx['worker'] = self.worker
770
        return ctx
(10-10/10)