Project

General

Profile

Download (31.4 KB) Statistics
| Branch: | Tag: | Revision:

calebasse / calebasse / agenda / views.py @ 68a9fcc4

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

    
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
        context = super(AgendaHomepageView, self).get_context_data(**kwargs)
58

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

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

    
78
        return context
79

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

    
84
    def get_context_data(self, **kwargs):
85
        context = super(AgendaServiceActivityView, self).get_context_data(**kwargs)
86

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

    
134

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

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

    
151
    def get_success_url(self):
152
        return self.request.META.get('HTTP_REFERER', '..')
153

    
154
    def form_valid(self, form):
155
        obj = super(NewAppointmentView, self).form_valid(form)
156
        messages.add_message(self.request, messages.INFO, self.success_msg)
157
        return obj
158

    
159

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

    
168

    
169
class BaseAppointmentView(UpdateView):
170
    model = EventWithAct
171
    form_class = UpdateAppointmentForm
172
    template_name = 'agenda/update-rdv.html'
173
    success_url = '..'
174

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

    
189
    def get_form_kwargs(self):
190
        kwargs = super(BaseAppointmentView, self).get_form_kwargs()
191
        kwargs['service'] = self.service
192
        return kwargs
193

    
194

    
195
class UpdateAppointmentView(TodayOccurrenceMixin, BaseAppointmentView):
196

    
197
    def get_form_class(self):
198
        if self.object.exception_to and not self.object.exception_to.canceled:
199
            return DisablePatientAppointmentForm
200
        else:
201
            return self.form_class
202

    
203
class UpdatePeriodicAppointmentView(BaseAppointmentView):
204
    form_class = UpdatePeriodicAppointmentForm
205
    template_name = 'agenda/new-appointment.html'
206

    
207
class NewEventView(CreateView):
208
    model = Event
209
    form_class = NewEventForm
210
    template_name = 'agenda/new-event.html'
211

    
212
    def get_initial(self):
213
        initial = super(NewEventView, self).get_initial()
214
        initial['start_datetime'] = self.date
215
        initial['date'] = self.date
216
        initial['participants'] = self.request.GET.getlist('participants')
217
        initial['time'] = self.request.GET.get('time')
218
        initial['event_type'] = 2
219
        initial['ressource'] = self.request.GET.get('ressource')
220
        initial['duration'] = self.request.GET.get('duration')
221
        if not initial.has_key('services'):
222
            initial['services'] = [self.service]
223
        return initial
224

    
225
    def get_form_kwargs(self):
226
        kwargs = super(NewEventView, self).get_form_kwargs()
227
        kwargs['service'] = self.service
228
        return kwargs
229

    
230
    def get_success_url(self):
231
        return self.request.META.get('HTTP_REFERER', '..')
232

    
233
    def form_valid(self, form):
234
        messages.add_message(self.request, messages.INFO, u'Evénement enregistré avec succès.')
235
        return super(NewEventView, self).form_valid(form)
236

    
237
class BaseEventView(UpdateView):
238
    model = Event
239
    form_class = UpdateEventForm
240
    template_name = 'agenda/update-event.html'
241
    success_url = '..'
242

    
243
    def get_initial(self):
244
        initial = super(BaseEventView, self).get_initial()
245
        initial['start_datetime'] = self.date
246
        initial['date'] = self.object.start_datetime.date()
247
        initial['time'] = self.object.start_datetime.time()
248
        time = self.object.end_datetime - self.object.start_datetime
249
        if time:
250
            time = time.seconds / 60
251
        else:
252
            time = 0
253
        initial['duration'] = time
254
        initial['participants'] = self.object.participants.values_list('id', flat=True)
255
        return initial
256

    
257
    def get_form_kwargs(self):
258
        kwargs = super(BaseEventView, self).get_form_kwargs()
259
        kwargs['service'] = self.service
260
        return kwargs
261

    
262

    
263
class UpdateEventView(TodayOccurrenceMixin, BaseEventView):
264
    pass
265

    
266

    
267
class UpdatePeriodicEventView(BaseEventView):
268
    form_class = UpdatePeriodicEventForm
269
    template_name = 'agenda/new-event.html'
270

    
271
class DeleteOccurrenceView(TodayOccurrenceMixin, cbv.DeleteView):
272
    model = Event
273
    success_url = '..'
274

    
275
    def delete(self, request, *args, **kwargs):
276
        self.object = self.get_object()
277
        # If the exception does not exist we need to create it before set it canceled
278
        self.object.save()
279
        self.object.delete()
280
        return HttpResponse(status=204)
281

    
282
class DeleteEventView(cbv.DeleteView):
283
    model = Event
284
    success_url = '..'
285

    
286
    def delete(self, request, *args, **kwargs):
287
        self.object = self.get_object()
288
        self.object.delete()
289
        return HttpResponse(status=204)
290

    
291
class AgendaServiceActValidationView(TemplateView):
292
    template_name = 'agenda/act-validation.html'
293
    cookies_to_clear = [('agenda-tabs', ), ('active-agenda', ), ('last-ressource', )]
294

    
295
    def acts_of_the_day(self):
296
        acts = list(Act.objects \
297
                .filter(date=self.date, patient__service=self.service) \
298
                .select_related() \
299
                .prefetch_related('doctors',
300
                        'patient__patientcontact',
301
                        'actvalidationstate_set__previous_state') \
302
                .order_by('time'))
303
        event_ids = [ a.parent_event_id for a in acts if a.parent_event_id ]
304
        events = EventWithAct.objects.for_today(self.date) \
305
                .filter(patient__service=self.service) \
306
                .exclude(id__in=event_ids)
307
        events = [ event.today_occurrence(self.date) for event in events ]
308
        acts += [ event.act for event in events if event ]
309
        return sorted(acts, key=lambda a: (a.time or datetime.time.min, a.id))
310

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

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

    
370

    
371
class AutomatedValidationView(TemplateView):
372
    template_name = 'agenda/automated-validation.html'
373

    
374
    def post(self, request, *args, **kwargs):
375
        automated_validation(self.date, self.service,
376
            request.user)
377
        ValidationMessage(validation_date=self.date,
378
            who=request.user, what='Validation automatique',
379
            service=self.service).save()
380
        return HttpResponseRedirect('..')
381

    
382
    def get_context_data(self, **kwargs):
383
        context = super(AutomatedValidationView, self).get_context_data(**kwargs)
384
        request = self.request
385
        (nb_acts_total, nb_acts_validated, nb_acts_double,
386
        nb_acts_abs_non_exc, nb_acts_abs_exc, nb_acts_abs_inter, nb_acts_annul_nous,
387
        nb_acts_annul_famille, nb_acts_reporte, nb_acts_abs_ess_pps,
388
        nb_acts_enf_hosp, nb_acts_losts) = \
389
            automated_validation(self.date, self.service,
390
                request.user, commit = False)
391

    
392
        nb_acts_not_validated = nb_acts_double + \
393
            nb_acts_abs_non_exc + \
394
            nb_acts_abs_exc + \
395
            nb_acts_abs_inter + \
396
            nb_acts_annul_nous + \
397
            nb_acts_annul_famille + \
398
            nb_acts_reporte + \
399
            nb_acts_abs_ess_pps + \
400
            nb_acts_enf_hosp + \
401
            nb_acts_losts
402
        context.update({
403
            'nb_acts_total': nb_acts_total,
404
            'nb_acts_validated': nb_acts_validated,
405
            'nb_acts_not_validated': nb_acts_not_validated,
406
            'nb_acts_double': nb_acts_double,
407
            'nb_acts_abs_non_exc': nb_acts_abs_non_exc,
408
            'nb_acts_abs_exc': nb_acts_abs_exc,
409
            'nb_acts_abs_inter': nb_acts_abs_inter,
410
            'nb_acts_annul_nous': nb_acts_annul_nous,
411
            'nb_acts_annul_famille': nb_acts_annul_famille,
412
            'nb_acts_reporte': nb_acts_reporte,
413
            'nb_acts_abs_ess_pps': nb_acts_abs_ess_pps,
414
            'nb_acts_enf_hosp': nb_acts_enf_hosp,
415
            'nb_acts_losts': nb_acts_losts})
416
        return context
417

    
418
class UnlockAllView(CreateView):
419
    pass
420

    
421

    
422
class AgendasTherapeutesView(AgendaHomepageView):
423
    template_name = 'agenda/agendas-therapeutes.html'
424
    cookies_to_clear = [('agenda-tabs', ), ('active-agenda', ), ('last-ressource', )]
425

    
426
    def get_context_data(self, **kwargs):
427
        context = super(AgendasTherapeutesView, self).get_context_data(**kwargs)
428
        current_service_only = settings.CURRENT_SERVICE_EVENTS_ONLY
429

    
430
        time_tables = TimeTable.objects.select_related('worker'). \
431
                filter(services=self.service). \
432
                for_today(self.date). \
433
                order_by('start_date')
434
        holidays = Holiday.objects.select_related('worker') \
435
                .for_period(self.date, self.date) \
436
                .order_by('start_date') \
437
                .select_related()
438
        events = Event.objects.for_today(self.date) \
439
                .exclude(event_type_id=1) \
440
                .order_by('start_datetime') \
441
                .select_related() \
442
                .prefetch_related('services',
443
                        'exceptions',
444
                        'participants')
445
        eventswithact = EventWithAct.objects.for_today(self.date) \
446
                .order_by('start_datetime') \
447
                .select_related() \
448
                .prefetch_related(
449
                        'services',
450
                        'patient__service',
451
                        'act_set__actvalidationstate_set',
452
                        'exceptions', 'participants')
453

    
454
        if current_service_only:
455
            events = events.filter(services=self.service)
456
            eventswithact = eventswithact.filter(services=self.service)
457

    
458
        context['CURRENT_SERVICE_EVENTS_ONLY'] = current_service_only
459

    
460
        events = [ e.today_occurrence(self.date) for e in events ] \
461
             + [ e.today_occurrence(self.date) for e in eventswithact ]
462
        for e in events:
463
            e.workers_ids = set(p.id for p in e.participants.all())
464

    
465
        events_workers = {}
466
        time_tables_workers = {}
467
        holidays_workers = {}
468
        context['workers_agenda'] = []
469
        context['workers'] = context['workers'].filter(services=self.service)
470
        for worker in context['workers']:
471
            time_tables_worker = [tt for tt in time_tables if tt.worker.id == worker.id]
472
            events_worker = [o for o in events if worker.id in o.workers_ids ]
473
            holidays_worker = [h for h in holidays if h.worker_id in (None, worker.id)]
474
            events_workers[worker.id] = events_worker
475
            time_tables_workers[worker.id] = time_tables_worker
476
            holidays_workers[worker.id] = holidays_worker
477
            activity, daily_appointments = get_daily_appointments(context['date'], worker, self.service,
478
                        time_tables_worker, events_worker, holidays_worker)
479
            if all(map(lambda x: x.holiday, daily_appointments)):
480
                continue
481

    
482
            context['workers_agenda'].append({'worker': worker,
483
                    'appointments': daily_appointments,
484
                    'activity': activity,
485
                    'has_events': True if events_worker else False})
486

    
487
        for worker_agenda in context.get('workers_agenda', []):
488
            patient_appointments = [x for x in worker_agenda['appointments'] if x.patient_record_id]
489
            worker_agenda['summary'] = {
490
              'rdv': len(patient_appointments),
491
              'presence': len([x for x in patient_appointments if x.act_absence is None]),
492
              'absence': len([x for x in patient_appointments if x.act_absence is not None]),
493
              'doubles': len([x for x in patient_appointments if x.act_type == 'ACT_DOUBLE']),
494
              'valides': len([x for x in patient_appointments if x.act_type == 'ACT_VALIDE']),
495
            }
496

    
497
        return context
498

    
499
class JoursNonVerrouillesView(TemplateView):
500
    template_name = 'agenda/days-not-locked.html'
501

    
502
    def get_context_data(self, **kwargs):
503
        context = super(JoursNonVerrouillesView, self).get_context_data(**kwargs)
504
        acts = Act.objects.filter(is_billed=False,
505
            patient__service=self.service).order_by('date')
506
        days = set(acts.values_list('date', flat=True))
507
        if days:
508
            max_day, min_day = max(days), min(days)
509
            today = datetime.datetime.today().date()
510
            if max_day > today:
511
                max_day = today
512
            days &= set(get_days_with_acts_not_locked(min_day, max_day, self.service))
513
        context['days_not_locked'] = sorted(days)
514
        return context
515

    
516
class AjaxWorkerTabView(TemplateView):
517

    
518
    template_name = 'agenda/ajax-worker-tab.html'
519

    
520
    def get_context_data(self, worker_id, **kwargs):
521
        context = super(AjaxWorkerTabView, self).get_context_data(**kwargs)
522
        worker = Worker.objects.get(id=worker_id)
523

    
524
        time_tables_worker = TimeTable.objects.select_related('worker'). \
525
                filter(worker=worker) \
526
                .for_today(self.date) \
527
                .order_by('start_date') \
528
                .select_related()
529

    
530
        holidays_worker = Holiday.objects.for_worker(worker) \
531
                .for_period(self.date, self.date) \
532
                .order_by('start_date') \
533
                .select_related()
534
        events = Event.objects.for_today(self.date) \
535
                .exclude(event_type_id=1) \
536
                .filter(participants=worker) \
537
                .order_by('start_datetime') \
538
                .select_related() \
539
                .prefetch_related('services',
540
                        'exceptions',
541
                        'participants')
542
        eventswithact = EventWithAct.objects.for_today(self.date) \
543
                .filter(participants=worker) \
544
                .order_by('start_datetime') \
545
                .select_related() \
546
                .prefetch_related('patient__addresses',
547
                        'patient__addresses__patientcontact_set',
548
                        'services',
549
                        'patient__service',
550
                        'act_set__actvalidationstate_set',
551
                        'exceptions', 'participants')
552
        events = [ e.today_occurrence(self.date) for e in events ] \
553
             + [ e.today_occurrence(self.date) for e in eventswithact ]
554
        activity, appointments = get_daily_appointments(context['date'], worker,
555
                                                        self.service, time_tables_worker,
556
                                                        events, holidays_worker)
557

    
558
        context['worker_agenda'] = {'worker': worker,
559
                                    'appointments': appointments}
560

    
561
        if settings.RTF_TEMPLATES_DIRECTORY:
562
            context['mail'] = True
563
        return context
564

    
565
class AjaxRessourceTabView(TemplateView):
566
    template_name = 'agenda/ajax-ressource-tab.html'
567

    
568
    def get_context_data(self, ressource_id, **kwargs):
569
        context = super(AjaxRessourceTabView, self).get_context_data(**kwargs)
570
        ressource = Ressource.objects.get(pk=ressource_id)
571
        plain_events = Event.objects.for_today(self.date) \
572
                                    .order_by('start_datetime').select_subclasses()
573
        events = [ e.today_occurrence(self.date) for e in plain_events ]
574
        events_ressource = [e for e in events if ressource == e.ressource]
575
        context['ressource_agenda'] = {'appointments': get_daily_usage(context['date'],
576
                                                                       ressource,
577
                                                                       self.service,
578
                                                                       events_ressource)
579
        }
580
        return context
581

    
582
class AjaxDisponibilityColumnView(TemplateView):
583

    
584
    template_name = 'agenda/ajax-disponibility-column.html'
585

    
586
    def get_ressource_context_data(self, ressource_id, context):
587
        ressource = Ressource.objects.get(pk = ressource_id)
588
        context['initials'] = ressource.name[:3]
589
        disponibility = dict()
590
        start_datetime = datetime.datetime(self.date.year,
591
                                           self.date.month,
592
                                           self.date.day, 8, 0)
593
        end_datetime = datetime.datetime(self.date.year, self.date.month,
594
                                         self.date.day, 8, 15)
595
        events = Event.objects.filter(ressource__id=ressource_id).today_occurrences(self.date)
596

    
597
        while (start_datetime.hour <= 19):
598
            if start_datetime.hour not in disponibility:
599
                disponibility[start_datetime.hour] = [[], [], [], []]
600
                quarter = 0
601
            dispo = 'free'
602
            mins = quarter * 15
603

    
604
            if events:
605
                for event in events:
606
                    if get_service_setting('show_overlapping_appointments'):
607
                        overlap_events = Event.objects.overlap_occurences(start_datetime, events)
608
                    else:
609
                        overlap_events = []
610
                    if len(overlap_events) > 1:
611
                        dispo = 'overlap'
612
                    elif event.start_datetime <= start_datetime and event.end_datetime >= end_datetime:
613
                        dispo = 'busy'
614
            disponibility[start_datetime.hour][quarter].append((mins, {'id': ressource_id, 'dispo': dispo}))
615
            quarter += 1
616
            start_datetime += datetime.timedelta(minutes=15)
617
            end_datetime += datetime.timedelta(minutes=15)
618

    
619
        context['disponibility'] = disponibility
620
        return context
621

    
622

    
623
    def get_worker_context_data(self, worker_id, context):
624
        worker = Worker.objects.get(pk=worker_id)
625

    
626
        time_tables = TimeTable.objects.select_related('worker'). \
627
                filter(services=self.service, worker=worker). \
628
                for_today(self.date). \
629
                order_by('start_date')
630
        holidays = Holiday.objects.for_worker(worker). \
631
                for_period(self.date, self.date). \
632
                order_by('start_date')
633
        events = Event.objects.for_today(self.date) \
634
                .exclude(event_type_id=1) \
635
                .filter(participants=worker) \
636
                .order_by('start_datetime') \
637
                .select_related() \
638
                .prefetch_related('participants', 'exceptions')
639
        eventswithact = EventWithAct.objects.for_today(self.date) \
640
                .filter(participants=worker) \
641
                .order_by('start_datetime') \
642
                .select_related() \
643
                .prefetch_related('participants', 'exceptions',
644
                        'act_set__actvalidationstate_set')
645

    
646
        events = list(events) + list(eventswithact)
647
        events = [ e.today_occurrence(self.date) for e in events ]
648
        time_tables_workers = {worker.id: time_tables}
649
        events_workers = {worker.id: events}
650
        holidays_workers = {worker.id: holidays}
651

    
652
        context['initials'] = worker.initials
653
        context['disponibility'] = Event.objects.daily_disponibilities(self.date,
654
                events, worker, time_tables, holidays)
655
        return context
656

    
657
    def get_context_data(self, ressource_type, ressource_id, **kwargs):
658
        context = super(AjaxDisponibilityColumnView, self).get_context_data(**kwargs)
659
        if ressource_type in ('worker', 'ressource',):
660
            context['ressource_type'] = ressource_type
661
            context['ressource_id'] = ressource_id
662
            getattr(self, 'get_%s_context_data' % ressource_type)(ressource_id, context)
663
        return context
664

    
665
class PeriodicEventsView(cbv.ListView):
666
    model = EventWithAct
667
    template_name = 'agenda/periodic-events.html'
668
    cookies_to_clear = [('agenda-tabs', ), ('active-agenda', ), ('last-ressource', )]
669

    
670
    def dispatch(self, request, *args, **kwargs):
671
        if 'worker_id' in kwargs:
672
            self.worker = get_object_or_404(Worker, id=kwargs['worker_id'])
673
        else:
674
            self.worker = None
675
        return super(PeriodicEventsView, self).dispatch(request, *args, **kwargs)
676

    
677
    def get_form(self):
678
        kwargs = {
679
                'initial': {
680
                    'start_date': self.date,
681
                }
682
        }
683
        if self.request.GET:
684
            kwargs['data'] = self.request.GET
685
        self.form = PeriodicEventsSearchForm(prefix='periodic-events-search-form', **kwargs)
686
        return self.form
687

    
688
    def get_queryset(self):
689
        qs1 = Event.objects.exclude(event_type_id=1)
690
        qs2 = EventWithAct.objects.all()
691
        form = self.get_form()
692
        if not self.request.GET:
693
            return ()
694
        qs1 = self.filter_queryset(form, qs1)
695
        qs2 = self.filter_queryset(form, qs2)
696
        if form.is_valid():
697
            patient = form.cleaned_data.get('patient')
698
            if patient is not None:
699
                qs1 = qs1.none()
700
                qs2 = qs2.filter(patient=patient)
701
            worker = form.cleaned_data.get('worker')
702
            if worker is not None:
703
                qs1 = qs1.filter(participants=worker)
704
                qs2 = qs2.filter(participants=worker)
705
        return sorted(chain(qs1, qs2),
706
                key=lambda x: (x.start_datetime, x.recurrence_end_date or datetime.date(9999,12,31)))
707

    
708
    def filter_queryset(self, form, qs):
709
        if self.worker is not None:
710
            qs = qs.filter(participants=self.worker)
711
        start_date = datetime.date.today()
712
        end_date = start_date+datetime.timedelta(days=90)
713
        if form.is_valid():
714
            if form.cleaned_data.get('start_date'):
715
                start_date = form.cleaned_data['start_date']
716
            if form.cleaned_data.get('end_date'):
717
                end_date = form.cleaned_data['end_date']
718
            else:
719
                end_date = start_date+datetime.timedelta(days=90)
720
            if len(form.cleaned_data.get('event_type')) != 2:
721
                if '0' in form.cleaned_data.get('event_type'):
722
                    qs = qs.filter(event_type_id=1)
723
                else:
724
                    qs = qs.exclude(event_type_id=1)
725
            if form.cleaned_data.get('no_end_date'):
726
                qs = qs.filter(recurrence_end_date__isnull=True)
727
        qs = qs.filter(canceled=False)
728
        qs = qs.filter(services=self.service)
729
        qs = qs.filter(recurrence_periodicity__isnull=False)
730
        qs = qs.filter(start_datetime__lt=end_date)
731
        qs = qs.filter(Q(recurrence_end_date__isnull=True)
732
                | Q(recurrence_end_date__gte=start_date))
733
        qs = qs.order_by('start_datetime', 'recurrence_end_date')
734
        qs = qs.select_related()
735
        qs = qs.prefetch_related('participants', 'services')
736
        return qs
737

    
738
    def get_context_data(self, **kwargs):
739
        ctx = super(PeriodicEventsView, self).get_context_data(**kwargs)
740
        ctx['search_form'] = self.form
741
        ctx['worker'] = self.worker
742
        return ctx
(10-10/10)