Projet

Général

Profil

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

calebasse / calebasse / agenda / views.py @ 9e8be8ad

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
        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
class DeleteOccurrenceView(TodayOccurrenceMixin, cbv.DeleteView):
278
    model = Event
279
    success_url = '..'
280
    cookies_to_clear = []
281

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

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

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

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

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

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

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

    
378

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

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

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

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

    
426
class UnlockAllView(CreateView):
427
    pass
428

    
429

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

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

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

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

    
466
        context['CURRENT_SERVICE_EVENTS_ONLY'] = current_service_only
467

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

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

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

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

    
505
        return context
506

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

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

    
524
class AjaxWorkerTabView(TemplateView):
525

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

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

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

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

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

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

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

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

    
592
class AjaxDisponibilityColumnView(TemplateView):
593

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

    
597
    def get_ressource_context_data(self, ressource_id, context):
598
        ressource = Ressource.objects.get(pk = ressource_id)
599
        context['initials'] = ressource.name[:3]
600
        disponibility = dict()
601
        start_datetime = datetime.datetime(self.date.year,
602
                                           self.date.month,
603
                                           self.date.day, 8, 0)
604
        end_datetime = datetime.datetime(self.date.year, self.date.month,
605
                                         self.date.day, 8, 15)
606
        events = Event.objects.filter(ressource__id=ressource_id,
607
                                      services=self.service).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(services=self.service, 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(services=self.service, 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)