Projet

Général

Profil

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

calebasse / calebasse / agenda / views.py @ 055d68a5

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
from calebasse.utils import get_service_setting
26

    
27
from calebasse.agenda.forms import (NewAppointmentForm, NewEventForm, UpdatePeriodicAppointmentForm,
28
        DisablePatientAppointmentForm, UpdateAppointmentForm, UpdatePeriodicEventForm,
29
        UpdateEventForm, PeriodicEventsSearchForm)
30

    
31
logger = logging.getLogger(__name__)
32

    
33
def redirect_today(request, service):
34
    '''If not date is given we redirect on the agenda for today'''
35
    return redirect('agenda', date=datetime.date.today().strftime('%Y-%m-%d'),
36
            service=service)
37

    
38

    
39
class AgendaHomepageView(TemplateView):
40
    template_name = 'agenda/index.html'
41
    cookies_to_clear = []
42

    
43
    def post(self, request, *args, **kwargs):
44
        acte_id = request.POST.get('event-id')
45
        try:
46
            event = EventWithAct.objects.get(id=acte_id)
47
            event = event.today_occurrence(self.date)
48
            act = event.act
49
            if not act.validation_locked:
50
                state_name = request.POST.get('act_state')
51
                act.save()
52
                act.set_state(state_name, request.user)
53
        except Act.DoesNotExist:
54
            logger.warning('agenda homepage acte_id %d not found' % acte_id)
55
        return HttpResponseRedirect('#acte-frame-'+acte_id)
56

    
57
    def get_context_data(self, **kwargs):
58
        logger.info('AgendaHomepageView.get_context_data called')
59
        context = super(AgendaHomepageView, self).get_context_data(**kwargs)
60

    
61
        context['workers_types'] = []
62
        workers = Worker.objects.filter(enabled=True).select_related() \
63
                .prefetch_related('services')
64
        worker_by_type = {}
65
        for worker in workers:
66
            workers_for_type = worker_by_type.setdefault(worker.type, [])
67
            workers_for_type.append(worker)
68
        for worker_type, workers_for_type in worker_by_type.iteritems():
69
            context['workers_types'].append(
70
                    {'type': worker_type.name, 'workers': workers_for_type })
71
        context['workers'] = workers
72
        context['disponibility_start_times'] = range(8, 20)
73

    
74
        # ressources
75
        context['ressources_types'] = []
76
        data = {'type': Ressource._meta.verbose_name_plural,
77
                'ressources': Ressource.objects.all()}
78
        context['ressources_types'].append(data)
79

    
80
        return context
81

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

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

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

    
136

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

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

    
154
    def get_success_url(self):
155
        return self.request.META.get('HTTP_REFERER', '..')
156

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

    
162

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

    
171

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

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

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

    
198

    
199
class UpdateAppointmentView(TodayOccurrenceMixin, BaseAppointmentView):
200

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

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

    
211

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

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

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

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

    
239
    def form_valid(self, form):
240
        messages.add_message(self.request, messages.INFO, u'Evénement enregistré avec succès.')
241
        return super(NewEventView, self).form_valid(form)
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
class DeleteOccurrenceView(TodayOccurrenceMixin, cbv.DeleteView):
279
    model = Event
280
    success_url = '..'
281
    cookies_to_clear = []
282

    
283
    def delete(self, request, *args, **kwargs):
284
        self.object = self.get_object()
285
        # If the exception does not exist we need to create it before set it canceled
286
        self.object.save()
287
        self.object.delete()
288
        return HttpResponse(status=204)
289

    
290
class DeleteEventView(cbv.DeleteView):
291
    model = Event
292
    success_url = '..'
293
    cookies_to_clear = []
294

    
295
    def delete(self, request, *args, **kwargs):
296
        self.object = self.get_object()
297
        self.object.delete()
298
        return HttpResponse(status=204)
299

    
300
class AgendaServiceActValidationView(TemplateView):
301
    template_name = 'agenda/act-validation.html'
302
    cookies_to_clear = [('agenda-tabs', ), ('active-agenda', ), ('last-ressource', )]
303

    
304
    def acts_of_the_day(self):
305
        acts = list(Act.objects \
306
                .filter(date=self.date, patient__service=self.service) \
307
                .select_related() \
308
                .prefetch_related('doctors',
309
                        'patient__patientcontact',
310
                        'actvalidationstate_set__previous_state') \
311
                .order_by('time'))
312
        event_ids = [ a.parent_event_id for a in acts if a.parent_event_id ]
313
        events = EventWithAct.objects.for_today(self.date) \
314
                .filter(patient__service=self.service) \
315
                .exclude(id__in=event_ids)
316
        events = [ event.today_occurrence(self.date) for event in events ]
317
        acts += [ event.act for event in events if event ]
318
        return sorted(acts, key=lambda a: (a.time or datetime.time.min, a.id))
319

    
320
    def post(self, request, *args, **kwargs):
321
        if 'unlock-all' in request.POST:
322
            #TODO: check that the user is authorized
323
            unlock_all_acts_of_the_day(self.date, self.service)
324
            ValidationMessage(validation_date=self.date,
325
                who=request.user, what='Déverrouillage',
326
                service=self.service).save()
327
        else:
328
            acte_id = request.POST.get('acte-id')
329
            try:
330
                act = Act.objects.get(id=acte_id)
331
                if 'lock' in request.POST or 'unlock' in request.POST:
332
                    #TODO: check that the user is authorized
333
                    act.validation_locked = 'lock' in request.POST
334
                    act.save()
335
                else:
336
                    state_name = request.POST.get('act_state')
337
                    act.set_state(state_name, request.user)
338
                    messages.add_message(self.request, messages.INFO, u'Acte modifié avec succès')
339
            except Act.DoesNotExist:
340
                pass
341
            return HttpResponseRedirect('#acte-frame-'+acte_id)
342
        return HttpResponseRedirect('')
343

    
344
    def get_context_data(self, **kwargs):
345
        context = super(AgendaServiceActValidationView, self).get_context_data(**kwargs)
346
        authorized_lock = True # is_authorized_for_locking(get_request().user)
347
        validation_msg = ValidationMessage.objects.\
348
            filter(validation_date=self.date, service=self.service).\
349
            order_by('-when')[:3]
350
        acts_of_the_day = self.acts_of_the_day()
351
        actes = list()
352
        for act in acts_of_the_day:
353
            if not act.id:
354
                if act.date < datetime.date(2013, 1, 1):
355
                    continue
356
                else:
357
                    act.save()
358
            state = act.get_state()
359
            display_name = None
360
            if state :
361
                display_name = VALIDATION_STATES[state.state_name]
362
                if not state.previous_state_id and state.state_name == 'NON_VALIDE':
363
                    state = None
364
            actes.append((act, state, display_name))
365
        validation_states = dict(VALIDATION_STATES)
366
        if self.service.name != 'CMPP' and \
367
                'ACT_DOUBLE' in validation_states:
368
            validation_states.pop('ACT_DOUBLE')
369
        vs = [('VALIDE', 'Présent')]
370
        validation_states.pop('VALIDE')
371
        validation_states.pop('ACT_LOST')
372
        validation_states = vs + sorted(validation_states.items(), key=lambda tup: tup[0])
373
        context['validation_states'] = validation_states
374
        context['actes'] = actes
375
        context['validation_msg'] = validation_msg
376
        context['authorized_lock'] = authorized_lock
377
        return context
378

    
379

    
380
class AutomatedValidationView(TemplateView):
381
    template_name = 'agenda/automated-validation.html'
382

    
383
    def post(self, request, *args, **kwargs):
384
        automated_validation(self.date, self.service,
385
            request.user)
386
        ValidationMessage(validation_date=self.date,
387
            who=request.user, what='Validation automatique',
388
            service=self.service).save()
389
        return HttpResponseRedirect('..')
390

    
391
    def get_context_data(self, **kwargs):
392
        context = super(AutomatedValidationView, self).get_context_data(**kwargs)
393
        request = self.request
394
        (nb_acts_total, nb_acts_validated, nb_acts_double,
395
        nb_acts_abs_non_exc, nb_acts_abs_exc, nb_acts_abs_inter, nb_acts_annul_nous,
396
        nb_acts_annul_famille, nb_acts_reporte, nb_acts_abs_ess_pps,
397
        nb_acts_enf_hosp, nb_acts_losts) = \
398
            automated_validation(self.date, self.service,
399
                request.user, commit = False)
400

    
401
        nb_acts_not_validated = nb_acts_double + \
402
            nb_acts_abs_non_exc + \
403
            nb_acts_abs_exc + \
404
            nb_acts_abs_inter + \
405
            nb_acts_annul_nous + \
406
            nb_acts_annul_famille + \
407
            nb_acts_reporte + \
408
            nb_acts_abs_ess_pps + \
409
            nb_acts_enf_hosp + \
410
            nb_acts_losts
411
        context.update({
412
            'nb_acts_total': nb_acts_total,
413
            'nb_acts_validated': nb_acts_validated,
414
            'nb_acts_not_validated': nb_acts_not_validated,
415
            'nb_acts_double': nb_acts_double,
416
            'nb_acts_abs_non_exc': nb_acts_abs_non_exc,
417
            'nb_acts_abs_exc': nb_acts_abs_exc,
418
            'nb_acts_abs_inter': nb_acts_abs_inter,
419
            'nb_acts_annul_nous': nb_acts_annul_nous,
420
            'nb_acts_annul_famille': nb_acts_annul_famille,
421
            'nb_acts_reporte': nb_acts_reporte,
422
            'nb_acts_abs_ess_pps': nb_acts_abs_ess_pps,
423
            'nb_acts_enf_hosp': nb_acts_enf_hosp,
424
            'nb_acts_losts': nb_acts_losts})
425
        return context
426

    
427
class UnlockAllView(CreateView):
428
    pass
429

    
430

    
431
class AgendasTherapeutesView(AgendaHomepageView):
432
    template_name = 'agenda/agendas-therapeutes.html'
433
    cookies_to_clear = [('agenda-tabs', ), ('active-agenda', ), ('last-ressource', )]
434

    
435
    def get_context_data(self, **kwargs):
436
        context = super(AgendasTherapeutesView, self).get_context_data(**kwargs)
437
        current_service_only = settings.CURRENT_SERVICE_EVENTS_ONLY
438

    
439
        time_tables = TimeTable.objects.select_related('worker'). \
440
                filter(services=self.service). \
441
                for_today(self.date). \
442
                order_by('start_date')
443
        holidays = Holiday.objects.select_related('worker') \
444
                .for_period(self.date, self.date) \
445
                .order_by('start_date') \
446
                .select_related()
447
        events = Event.objects.for_today(self.date) \
448
                .exclude(event_type_id=1) \
449
                .order_by('start_datetime') \
450
                .select_related() \
451
                .prefetch_related('services',
452
                        'exceptions',
453
                        'participants')
454
        eventswithact = EventWithAct.objects.for_today(self.date) \
455
                .order_by('start_datetime') \
456
                .select_related() \
457
                .prefetch_related(
458
                        'services',
459
                        'patient__service',
460
                        'act_set__actvalidationstate_set',
461
                        'exceptions', 'participants')
462

    
463
        if current_service_only:
464
            events = events.filter(services=self.service)
465
            eventswithact = eventswithact.filter(services=self.service)
466

    
467
        context['CURRENT_SERVICE_EVENTS_ONLY'] = current_service_only
468

    
469
        events = [ e.today_occurrence(self.date) for e in events ] \
470
             + [ e.today_occurrence(self.date) for e in eventswithact ]
471
        for e in events:
472
            e.workers_ids = set(p.id for p in e.participants.all())
473

    
474
        events_workers = {}
475
        time_tables_workers = {}
476
        holidays_workers = {}
477
        context['workers_agenda'] = []
478
        context['workers'] = context['workers'].filter(services=self.service)
479
        for worker in context['workers']:
480
            time_tables_worker = [tt for tt in time_tables if tt.worker.id == worker.id]
481
            events_worker = [o for o in events if worker.id in o.workers_ids ]
482
            holidays_worker = [h for h in holidays if h.worker_id in (None, worker.id)]
483
            events_workers[worker.id] = events_worker
484
            time_tables_workers[worker.id] = time_tables_worker
485
            holidays_workers[worker.id] = holidays_worker
486
            activity, daily_appointments = get_daily_appointments(context['date'], worker, self.service,
487
                        time_tables_worker, events_worker, holidays_worker)
488
            if all(map(lambda x: x.holiday, daily_appointments)):
489
                continue
490

    
491
            context['workers_agenda'].append({'worker': worker,
492
                    'appointments': daily_appointments,
493
                    'activity': activity,
494
                    'has_events': True if events_worker else False})
495

    
496
        for worker_agenda in context.get('workers_agenda', []):
497
            patient_appointments = [x for x in worker_agenda['appointments'] if x.patient_record_id]
498
            worker_agenda['summary'] = {
499
              'rdv': len(patient_appointments),
500
              'presence': len([x for x in patient_appointments if x.act_absence is None]),
501
              'absence': len([x for x in patient_appointments if x.act_absence is not None]),
502
              'doubles': len([x for x in patient_appointments if x.act_type == 'ACT_DOUBLE']),
503
              'valides': len([x for x in patient_appointments if x.act_type == 'ACT_VALIDE']),
504
            }
505

    
506
        return context
507

    
508
class JoursNonVerrouillesView(TemplateView):
509
    template_name = 'agenda/days-not-locked.html'
510

    
511
    def get_context_data(self, **kwargs):
512
        context = super(JoursNonVerrouillesView, self).get_context_data(**kwargs)
513
        acts = Act.objects.filter(is_billed=False,
514
            patient__service=self.service).order_by('date')
515
        days = set(acts.values_list('date', flat=True))
516
        if days:
517
            max_day, min_day = max(days), min(days)
518
            today = datetime.datetime.today().date()
519
            if max_day > today:
520
                max_day = today
521
            days &= set(get_days_with_acts_not_locked(min_day, max_day, self.service))
522
        context['days_not_locked'] = sorted(days)
523
        return context
524

    
525
class AjaxWorkerTabView(TemplateView):
526

    
527
    template_name = 'agenda/ajax-worker-tab.html'
528
    cookies_to_clear = []
529

    
530
    def get_context_data(self, worker_id, **kwargs):
531
        context = super(AjaxWorkerTabView, self).get_context_data(**kwargs)
532
        worker = Worker.objects.get(id=worker_id)
533

    
534
        time_tables_worker = TimeTable.objects.select_related('worker'). \
535
                filter(worker=worker) \
536
                .for_today(self.date) \
537
                .order_by('start_date') \
538
                .select_related()
539

    
540
        holidays_worker = Holiday.objects.for_worker(worker) \
541
                .for_period(self.date, self.date) \
542
                .order_by('start_date') \
543
                .select_related()
544
        events = Event.objects.for_today(self.date) \
545
                .exclude(event_type_id=1) \
546
                .filter(participants=worker) \
547
                .order_by('start_datetime') \
548
                .select_related() \
549
                .prefetch_related('services',
550
                        'exceptions',
551
                        'participants')
552
        eventswithact = EventWithAct.objects.for_today(self.date) \
553
                .filter(participants=worker) \
554
                .order_by('start_datetime') \
555
                .select_related() \
556
                .prefetch_related('patient__addresses',
557
                        'patient__addresses__patientcontact_set',
558
                        'services',
559
                        'patient__service',
560
                        'act_set__actvalidationstate_set',
561
                        'exceptions', 'participants')
562
        events = [ e.today_occurrence(self.date) for e in events ] \
563
             + [ e.today_occurrence(self.date) for e in eventswithact ]
564
        activity, appointments = get_daily_appointments(context['date'], worker,
565
                                                        self.service, time_tables_worker,
566
                                                        events, holidays_worker)
567

    
568
        context['worker_agenda'] = {'worker': worker,
569
                                    'appointments': appointments}
570

    
571
        if settings.RTF_TEMPLATES_DIRECTORY:
572
            context['mail'] = True
573
        return context
574

    
575
class AjaxRessourceTabView(TemplateView):
576
    template_name = 'agenda/ajax-ressource-tab.html'
577
    cookies_to_clear = []
578

    
579
    def get_context_data(self, ressource_id, **kwargs):
580
        context = super(AjaxRessourceTabView, self).get_context_data(**kwargs)
581
        ressource = Ressource.objects.get(pk=ressource_id)
582
        plain_events = Event.objects.for_today(self.date) \
583
                                    .order_by('start_datetime').select_subclasses()
584
        events = [ e.today_occurrence(self.date) for e in plain_events ]
585
        events_ressource = [e for e in events if ressource == e.ressource]
586
        context['ressource_agenda'] = {'appointments': get_daily_usage(context['date'],
587
                                                                       ressource,
588
                                                                       self.service,
589
                                                                       events_ressource)
590
        }
591
        return context
592

    
593
class AjaxDisponibilityColumnView(TemplateView):
594

    
595
    template_name = 'agenda/ajax-disponibility-column.html'
596
    cookies_to_clear = []
597

    
598
    def get_ressource_context_data(self, ressource_id, context):
599
        ressource = Ressource.objects.get(pk = ressource_id)
600
        context['initials'] = ressource.name[:3]
601
        disponibility = dict()
602
        start_datetime = datetime.datetime(self.date.year,
603
                                           self.date.month,
604
                                           self.date.day, 8, 0)
605
        end_datetime = datetime.datetime(self.date.year, self.date.month,
606
                                         self.date.day, 8, 15)
607
        events = Event.objects.filter(ressource__id=ressource_id).today_occurrences(self.date)
608

    
609
        while (start_datetime.hour <= 19):
610
            if start_datetime.hour not in disponibility:
611
                disponibility[start_datetime.hour] = [[], [], [], []]
612
                quarter = 0
613
            dispo = 'free'
614
            mins = quarter * 15
615

    
616
            if events:
617
                for event in events:
618
                    if get_service_setting('show_overlapping_appointments'):
619
                        overlap_events = Event.objects.overlap_occurences(start_datetime, events)
620
                    else:
621
                        overlap_events = []
622
                    if len(overlap_events) > 1:
623
                        dispo = 'overlap'
624
                    elif event.start_datetime <= start_datetime and event.end_datetime >= end_datetime:
625
                        dispo = 'busy'
626
            disponibility[start_datetime.hour][quarter].append((mins, {'id': ressource_id, 'dispo': dispo}))
627
            quarter += 1
628
            start_datetime += datetime.timedelta(minutes=15)
629
            end_datetime += datetime.timedelta(minutes=15)
630

    
631
        context['disponibility'] = disponibility
632
        return context
633

    
634

    
635
    def get_worker_context_data(self, worker_id, context):
636
        worker = Worker.objects.get(pk=worker_id)
637

    
638
        time_tables = TimeTable.objects.select_related('worker'). \
639
                filter(services=self.service, worker=worker). \
640
                for_today(self.date). \
641
                order_by('start_date')
642
        holidays = Holiday.objects.for_worker(worker). \
643
                for_period(self.date, self.date). \
644
                order_by('start_date')
645
        events = Event.objects.for_today(self.date) \
646
                .exclude(event_type_id=1) \
647
                .filter(participants=worker) \
648
                .order_by('start_datetime') \
649
                .select_related() \
650
                .prefetch_related('participants', 'exceptions')
651
        eventswithact = EventWithAct.objects.for_today(self.date) \
652
                .filter(participants=worker) \
653
                .order_by('start_datetime') \
654
                .select_related() \
655
                .prefetch_related('participants', 'exceptions',
656
                        'act_set__actvalidationstate_set')
657

    
658
        events = list(events) + list(eventswithact)
659
        events = [ e.today_occurrence(self.date) for e in events ]
660
        time_tables_workers = {worker.id: time_tables}
661
        events_workers = {worker.id: events}
662
        holidays_workers = {worker.id: holidays}
663

    
664
        context['initials'] = worker.initials
665
        context['disponibility'] = Event.objects.daily_disponibilities(self.date,
666
                events, worker, time_tables, holidays)
667
        return context
668

    
669
    def get_context_data(self, ressource_type, ressource_id, **kwargs):
670
        context = super(AjaxDisponibilityColumnView, self).get_context_data(**kwargs)
671
        if ressource_type in ('worker', 'ressource',):
672
            context['ressource_type'] = ressource_type
673
            context['ressource_id'] = ressource_id
674
            getattr(self, 'get_%s_context_data' % ressource_type)(ressource_id, context)
675
        return context
676

    
677
class PeriodicEventsView(cbv.ListView):
678
    model = EventWithAct
679
    template_name = 'agenda/periodic-events.html'
680
    cookies_to_clear = [('agenda-tabs', ), ('active-agenda', ), ('last-ressource', )]
681

    
682
    def dispatch(self, request, *args, **kwargs):
683
        if 'worker_id' in kwargs:
684
            self.worker = get_object_or_404(Worker, id=kwargs['worker_id'])
685
        else:
686
            self.worker = None
687
        return super(PeriodicEventsView, self).dispatch(request, *args, **kwargs)
688

    
689
    def get_form(self):
690
        kwargs = {
691
                'initial': {
692
                    'start_date': self.date,
693
                }
694
        }
695
        if self.request.GET:
696
            kwargs['data'] = self.request.GET
697
        self.form = PeriodicEventsSearchForm(prefix='periodic-events-search-form', **kwargs)
698
        return self.form
699

    
700
    def get_queryset(self):
701
        qs1 = Event.objects.exclude(event_type_id=1)
702
        qs2 = EventWithAct.objects.all()
703
        form = self.get_form()
704
        if not self.request.GET:
705
            return ()
706
        qs1 = self.filter_queryset(form, qs1)
707
        qs2 = self.filter_queryset(form, qs2)
708
        if form.is_valid():
709
            patient = form.cleaned_data.get('patient')
710
            if patient is not None:
711
                qs1 = qs1.none()
712
                qs2 = qs2.filter(patient=patient)
713
            worker = form.cleaned_data.get('worker')
714
            if worker is not None:
715
                qs1 = qs1.filter(participants=worker)
716
                qs2 = qs2.filter(participants=worker)
717
        return sorted(chain(qs1, qs2),
718
                key=lambda x: (x.start_datetime, x.recurrence_end_date or datetime.date(9999,12,31)))
719

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

    
750
    def get_context_data(self, **kwargs):
751
        ctx = super(PeriodicEventsView, self).get_context_data(**kwargs)
752
        ctx['search_form'] = self.form
753
        ctx['worker'] = self.worker
754
        return ctx
(10-10/10)