Project

General

Profile

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

calebasse / calebasse / agenda / views.py @ 3e9b47e9

1
# -*- coding: utf-8 -*-
2

    
3
import datetime
4

    
5
from django.db.models import Q
6
from django.shortcuts import redirect
7
from django.http import HttpResponseRedirect, HttpResponse
8

    
9
from calebasse.cbv import TemplateView, CreateView, UpdateView
10
from calebasse.agenda.models import Event, EventType, EventWithAct
11
from calebasse.personnes.models import TimeTable, Holiday
12
from calebasse.agenda.appointments import get_daily_appointments, get_daily_usage
13
from calebasse.personnes.models import Worker
14
from calebasse.ressources.models import WorkerType, Room
15
from calebasse.actes.validation import (get_acts_of_the_day,
16
        get_days_with_acts_not_locked)
17
from calebasse.actes.validation_states import VALIDATION_STATES
18
from calebasse.actes.models import Act, ValidationMessage
19
from calebasse.actes.validation import (automated_validation, unlock_all_acts_of_the_day)
20
from calebasse import cbv
21

    
22
from forms import (NewAppointmentForm, NewEventForm,
23
        UpdateAppointmentForm, UpdateEventForm)
24

    
25

    
26
def redirect_today(request, service):
27
    '''If not date is given we redirect on the agenda for today'''
28
    return redirect('agenda', date=datetime.date.today().strftime('%Y-%m-%d'),
29
            service=service)
30

    
31

    
32
class AgendaHomepageView(TemplateView):
33
    template_name = 'agenda/index.html'
34

    
35
    def post(self, request, *args, **kwargs):
36
        acte_id = request.POST.get('event-id')
37
        try:
38
            event = EventWithAct.objects.get(id=acte_id)
39
            event = event.today_occurrence(self.date)
40
            act = event.act
41
            if not act.validation_locked:
42
                state_name = request.POST.get('act_state')
43
                act.save()
44
                act.set_state(state_name, request.user)
45
        except Act.DoesNotExist:
46
            pass
47
        return HttpResponseRedirect('#acte-frame-'+acte_id)
48

    
49
    def get_context_data(self, **kwargs):
50
        context = super(AgendaHomepageView, self).get_context_data(**kwargs)
51

    
52
        context['workers_types'] = []
53
        workers = Worker.objects.filter(enabled=True).select_related() \
54
                .prefetch_related('services')
55
        worker_by_type = {}
56
        for worker in workers:
57
            workers_for_type = worker_by_type.setdefault(worker.type, [])
58
            workers_for_type.append(worker)
59
        for worker_type, workers_for_type in worker_by_type.iteritems():
60
            context['workers_types'].append(
61
                    {'type': worker_type.name, 'workers': workers_for_type })
62
        context['workers'] = workers
63
        context['disponibility_start_times'] = range(8, 20)
64

    
65
        return context
66

    
67

    
68
class AgendaServiceActivityView(TemplateView):
69
    template_name = 'agenda/service-activity.html'
70

    
71
    def get_context_data(self, **kwargs):
72
        context = super(AgendaServiceActivityView, self).get_context_data(**kwargs)
73

    
74
        appointments_times = dict()
75
        events = Event.objects.for_today(self.date) \
76
                .exclude(event_type_id=1) \
77
                .filter(services=self.service) \
78
                .order_by('start_datetime') \
79
                .select_related() \
80
                .prefetch_related('participants', 'exceptions')
81
        eventswithact = EventWithAct.objects.for_today(self.date) \
82
                .filter(services=self.service) \
83
                .order_by('start_datetime') \
84
                .select_related() \
85
                .prefetch_related('participants', 'exceptions')
86
        events = [ e.today_occurrence(self.date) for e in events ] \
87
             + [ e.today_occurrence(self.date) for e in eventswithact ]
88
        for event in events:
89
            start_datetime = event.start_datetime.strftime("%H:%M")
90
            if not appointments_times.has_key(start_datetime):
91
                appointments_times[start_datetime] = dict()
92
                appointments_times[start_datetime]['row'] = 0
93
                appointments_times[start_datetime]['appointments'] = []
94
            appointment = dict()
95
            length = event.end_datetime - event.start_datetime
96
            if length.seconds:
97
                length = length.seconds / 60
98
                appointment['length'] = "%sm" % length
99
            if event.event_type_id == 1:
100
                appointment['type'] = 1
101
                appointment['label'] = event.patient.display_name
102
                appointment['act'] = event.act_type.name
103
                appointment['state'] = event.act.get_state()
104
                appointment['absent'] = event.act.is_absent()
105
            else:
106
                appointment['type'] = 2
107
                if event.event_type.label == 'Autre' and event.title:
108
                    appointment['label'] = event.title
109
                else:
110
                    appointment['label'] = '%s - %s' % (event.event_type.label,
111
                                                        event.title)
112
            appointment['participants'] = event.participants.all()
113
            appointments_times[start_datetime]['row'] += 1
114
            appointments_times[start_datetime]['appointments'].append(appointment)
115
        context['appointments_times'] = sorted(appointments_times.items())
116
        return context
117

    
118

    
119
class NewAppointmentView(cbv.ReturnToObjectMixin, cbv.ServiceFormMixin, CreateView):
120
    model = EventWithAct
121
    form_class = NewAppointmentForm
122
    template_name = 'agenda/new-appointment.html'
123
    success_url = '..'
124

    
125
    def get_initial(self):
126
        initial = super(NewAppointmentView, self).get_initial()
127
        initial['start_datetime'] = self.date
128
        initial['date'] = self.date
129
        initial['participants'] = self.request.GET.getlist('participants')
130
        initial['time'] = self.request.GET.get('time')
131
        initial['room'] = self.request.GET.get('room')
132
        return initial
133

    
134
    def get_form_kwargs(self):
135
        kwargs = super(NewAppointmentView, self).get_form_kwargs()
136
        kwargs['service'] = self.service
137
        return kwargs
138

    
139

    
140
class TodayOccurrenceMixin(object):
141
    def get_object(self, queryset=None):
142
        o = super(TodayOccurrenceMixin, self).get_object(queryset)
143
        return o.today_occurrence(self.date)
144

    
145

    
146
class BaseAppointmentView(UpdateView):
147
    model = EventWithAct
148
    form_class = UpdateAppointmentForm
149
    template_name = 'agenda/update-rdv.html'
150
    success_url = '..'
151

    
152
    def get_initial(self):
153
        initial = super(BaseAppointmentView, self).get_initial()
154
        initial['start_datetime'] = self.date
155
        initial['date'] = self.object.start_datetime.date()
156
        initial['time'] = self.object.start_datetime.time()
157
        time = self.object.end_datetime - self.object.start_datetime
158
        if time:
159
            time = time.seconds / 60
160
        else:
161
            time = 0
162
        initial['duration'] = time
163
        initial['participants'] = self.object.participants.values_list('id', flat=True)
164
        return initial
165

    
166
    def get_form_kwargs(self):
167
        kwargs = super(BaseAppointmentView, self).get_form_kwargs()
168
        kwargs['service'] = self.service
169
        return kwargs
170

    
171

    
172
class UpdateAppointmentView(TodayOccurrenceMixin, BaseAppointmentView):
173
    pass
174

    
175

    
176
class UpdatePeriodicAppointmentView(BaseAppointmentView):
177
    form_class = NewAppointmentForm
178
    template_name = 'agenda/new-appointment.html'
179

    
180

    
181
class NewEventView(CreateView):
182
    model = Event
183
    form_class = NewEventForm
184
    template_name = 'agenda/new-event.html'
185
    success_url = '..'
186

    
187
    def get_initial(self):
188
        initial = super(NewEventView, self).get_initial()
189
        initial['start_datetime'] = self.date
190
        initial['date'] = self.date
191
        initial['participants'] = self.request.GET.getlist('participants')
192
        initial['time'] = self.request.GET.get('time')
193
        initial['event_type'] = 2
194
        initial['room'] = self.request.GET.get('room')
195
        return initial
196

    
197
    def get_form_kwargs(self):
198
        kwargs = super(NewEventView, self).get_form_kwargs()
199
        kwargs['service'] = self.service
200
        return kwargs
201

    
202

    
203
class BaseEventView(UpdateView):
204
    model = Event
205
    form_class = UpdateEventForm
206
    template_name = 'agenda/update-event.html'
207
    success_url = '..'
208

    
209
    def get_initial(self):
210
        initial = super(BaseEventView, self).get_initial()
211
        initial['start_datetime'] = self.date
212
        initial['date'] = self.object.start_datetime.date()
213
        initial['time'] = self.object.start_datetime.time()
214
        time = self.object.end_datetime - self.object.start_datetime
215
        if time:
216
            time = time.seconds / 60
217
        else:
218
            time = 0
219
        initial['duration'] = time
220
        initial['participants'] = self.object.participants.values_list('id', flat=True)
221
        return initial
222

    
223
    def get_form_kwargs(self):
224
        kwargs = super(BaseEventView, self).get_form_kwargs()
225
        kwargs['service'] = self.service
226
        return kwargs
227

    
228

    
229
class UpdateEventView(TodayOccurrenceMixin, BaseEventView):
230
    pass
231

    
232

    
233
class UpdatePeriodicEventView(BaseEventView):
234
    form_class = NewEventForm
235
    template_name = 'agenda/new-event.html'
236

    
237

    
238
class DeleteEventView(TodayOccurrenceMixin, cbv.DeleteView):
239
    model = Event
240
    success_url = '..'
241

    
242
    def delete(self, request, *args, **kwargs):
243
        super(DeleteEventView, self).delete(request, *args, **kwargs)
244
        return HttpResponse(status=204)
245

    
246

    
247
class AgendaServiceActValidationView(TemplateView):
248
    template_name = 'agenda/act-validation.html'
249

    
250
    def acts_of_the_day(self):
251
        acts = [e.act for e in EventWithAct.objects.filter(patient__service=self.service)
252
                .today_occurrences(self.date)] + list(Act.objects.filter(date=self.date, parent_event__isnull=True))
253
        return sorted(acts, key=lambda a: a.time or datetime.time.min)
254

    
255
    def post(self, request, *args, **kwargs):
256
        if 'unlock-all' in request.POST:
257
            #TODO: check that the user is authorized
258
            unlock_all_acts_of_the_day(self.date, self.service)
259
            ValidationMessage(validation_date=self.date,
260
                who=request.user, what='Déverrouillage',
261
                service=self.service).save()
262
        else:
263
            acte_id = request.POST.get('acte-id')
264
            try:
265
                act = Act.objects.get(id=acte_id)
266
                if 'lock' in request.POST or 'unlock' in request.POST:
267
                    #TODO: check that the user is authorized
268
                    act.validation_locked = 'lock' in request.POST
269
                    act.save()
270
                else:
271
                    state_name = request.POST.get('act_state')
272
                    act.set_state(state_name, request.user)
273
            except Act.DoesNotExist:
274
                pass
275
            return HttpResponseRedirect('#acte-frame-'+acte_id)
276
        return HttpResponseRedirect('')
277

    
278
    def get_context_data(self, **kwargs):
279
        context = super(AgendaServiceActValidationView, self).get_context_data(**kwargs)
280
        authorized_lock = True # is_authorized_for_locking(get_request().user)
281
        validation_msg = ValidationMessage.objects.\
282
            filter(validation_date=self.date, service=self.service).\
283
            order_by('-when')[:3]
284
        acts_of_the_day = self.acts_of_the_day()
285
        actes = list()
286
        for act in acts_of_the_day:
287
            state = act.get_state()
288
            display_name = VALIDATION_STATES[state.state_name]
289
            if not state.previous_state and state.state_name == 'NON_VALIDE':
290
                state = None
291
            actes.append((act, state, display_name))
292
            if not act.id:
293
                act.save()
294
        validation_states = dict(VALIDATION_STATES)
295
        if self.service.name != 'CMPP' and \
296
                'ACT_DOUBLE' in validation_states:
297
            validation_states.pop('ACT_DOUBLE')
298
        vs = [('VALIDE', 'Présent')]
299
        validation_states.pop('VALIDE')
300
        validation_states = vs + sorted(validation_states.items(), key=lambda tup: tup[0])
301
        context['validation_states'] = validation_states
302
        context['actes'] = actes
303
        context['validation_msg'] = validation_msg
304
        context['authorized_lock'] = authorized_lock
305
        return context
306

    
307

    
308
class AutomatedValidationView(TemplateView):
309
    template_name = 'agenda/automated-validation.html'
310

    
311
    def post(self, request, *args, **kwargs):
312
        automated_validation(self.date, self.service,
313
            request.user)
314
        ValidationMessage(validation_date=self.date,
315
            who=request.user, what='Validation automatique',
316
            service=self.service).save()
317
        return HttpResponseRedirect('..')
318

    
319
    def get_context_data(self, **kwargs):
320
        context = super(AutomatedValidationView, self).get_context_data(**kwargs)
321
        request = self.request
322
        (nb_acts_total, nb_acts_validated, nb_acts_double,
323
        nb_acts_abs_non_exc, nb_acts_abs_exc, nb_acts_abs_inter, nb_acts_annul_nous,
324
        nb_acts_annul_famille, nb_acts_reporte, nb_acts_abs_ess_pps,
325
        nb_acts_enf_hosp, nb_acts_losts) = \
326
            automated_validation(self.date, self.service,
327
                request.user, commit = False)
328

    
329
        nb_acts_not_validated = nb_acts_double + \
330
            nb_acts_abs_non_exc + \
331
            nb_acts_abs_exc + \
332
            nb_acts_abs_inter + \
333
            nb_acts_annul_nous + \
334
            nb_acts_annul_famille + \
335
            nb_acts_reporte + \
336
            nb_acts_abs_ess_pps + \
337
            nb_acts_enf_hosp + \
338
            nb_acts_losts
339
        context.update({
340
            'nb_acts_total': nb_acts_total,
341
            'nb_acts_validated': nb_acts_validated,
342
            'nb_acts_not_validated': nb_acts_not_validated,
343
            'nb_acts_double': nb_acts_double,
344
            'nb_acts_abs_non_exc': nb_acts_abs_non_exc,
345
            'nb_acts_abs_exc': nb_acts_abs_exc,
346
            'nb_acts_abs_inter': nb_acts_abs_inter,
347
            'nb_acts_annul_nous': nb_acts_annul_nous,
348
            'nb_acts_annul_famille': nb_acts_annul_famille,
349
            'nb_acts_reporte': nb_acts_reporte,
350
            'nb_acts_abs_ess_pps': nb_acts_abs_ess_pps,
351
            'nb_acts_enf_hosp': nb_acts_enf_hosp,
352
            'nb_acts_losts': nb_acts_losts})
353
        return context
354

    
355
class UnlockAllView(CreateView):
356
    pass
357

    
358

    
359
class AgendasTherapeutesView(AgendaHomepageView):
360
    template_name = 'agenda/agendas-therapeutes.html'
361

    
362
    def get_context_data(self, **kwargs):
363
        context = super(AgendasTherapeutesView, self).get_context_data(**kwargs)
364

    
365
        time_tables = TimeTable.objects.select_related('worker'). \
366
                filter(services=self.service). \
367
                for_today(self.date). \
368
                order_by('start_date')
369
        holidays = Holiday.objects.select_related('worker') \
370
                .for_period(self.date, self.date) \
371
                .order_by('start_date') \
372
                .select_related()
373
        events = Event.objects.for_today(self.date) \
374
                .exclude(event_type_id=1) \
375
                .filter(services=self.service) \
376
                .order_by('start_datetime') \
377
                .select_related() \
378
                .prefetch_related('services',
379
                        'exceptions',
380
                        'participants')
381
        eventswithact = EventWithAct.objects.for_today(self.date) \
382
                .filter(services=self.service) \
383
                .order_by('start_datetime') \
384
                .select_related() \
385
                .prefetch_related(
386
                        'services',
387
                        'patient__service',
388
                        'act_set__actvalidationstate_set',
389
                        'exceptions', 'participants')
390
        events = [ e.today_occurrence(self.date) for e in events ] \
391
             + [ e.today_occurrence(self.date) for e in eventswithact ]
392
        for e in events:
393
            e.workers_ids = set(p.id for p in e.participants.all())
394

    
395
        events_workers = {}
396
        time_tables_workers = {}
397
        holidays_workers = {}
398
        context['workers_agenda'] = []
399
        context['workers'] = context['workers'].filter(services=self.service)
400
        for worker in context['workers']:
401
            time_tables_worker = [tt for tt in time_tables if tt.worker.id == worker.id]
402
            events_worker = [o for o in events if worker.id in o.workers_ids ]
403
            holidays_worker = [h for h in holidays if h.worker_id in (None, worker.id)]
404
            events_workers[worker.id] = events_worker
405
            time_tables_workers[worker.id] = time_tables_worker
406
            holidays_workers[worker.id] = holidays_worker
407
            daily_appointments = get_daily_appointments(context['date'], worker, self.service,
408
                        time_tables_worker, events_worker, holidays_worker)
409
            if all(map(lambda x: x.holiday, daily_appointments)):
410
                continue
411
            context['workers_agenda'].append({'worker': worker,
412
                    'appointments': daily_appointments})
413

    
414
        for worker_agenda in context.get('workers_agenda', []):
415
            patient_appointments = [x for x in worker_agenda['appointments'] if x.patient_record_id]
416
            worker_agenda['summary'] = {
417
              'rdv': len(patient_appointments),
418
              'presence': len([x for x in patient_appointments if x.act_absence is None]),
419
              'absence': len([x for x in patient_appointments if x.act_absence is not None]),
420
              'doubles': len([x for x in patient_appointments if x.act_type == 'ACT_DOUBLE']),
421
              'valides': len([x for x in patient_appointments if x.act_type == 'ACT_VALIDE']),
422
            }
423

    
424
        return context
425

    
426
class JoursNonVerrouillesView(TemplateView):
427
    template_name = 'agenda/days-not-locked.html'
428

    
429
    def get_context_data(self, **kwargs):
430
        context = super(JoursNonVerrouillesView, self).get_context_data(**kwargs)
431
        acts = Act.objects.filter(is_billed=False,
432
            patient__service=self.service).order_by('date')
433
        days = set(acts.values_list('date', flat=True))
434
        if days:
435
            max_day, min_day = max(days), min(days)
436
            today = datetime.datetime.today().date()
437
            if max_day > today:
438
                max_day = today
439
            days &= set(get_days_with_acts_not_locked(min_day, max_day, self.service))
440
        context['days_not_locked'] = sorted(days)
441
        return context
442

    
443
class RessourcesView(TemplateView):
444

    
445
    template_name = 'agenda/ressources.html'
446

    
447
    def get_context_data(self, **kwargs):
448
        context = super(RessourcesView, self).get_context_data(**kwargs)
449

    
450
        plain_events = Event.objects.for_today(self.date) \
451
                .order_by('start_datetime').select_subclasses()
452
        events = [ e.today_occurrence(self.date) for e in plain_events ]
453

    
454
        context['ressources_types'] = []
455
        context['ressources_agenda'] = []
456
        context['disponibility'] = {}
457
        ressources = []
458
        data = {'type': Room._meta.verbose_name_plural, 'ressources': Room.objects.all() }
459
        context['ressources_types'].append(data)
460
        ressources.extend(data['ressources'])
461

    
462
        events_ressources = {}
463
        for ressource in ressources:
464
            events_ressource = [e for e in events if ressource == e.room]
465
            events_ressources[ressource.id] = events_ressource
466
            context['ressources_agenda'].append({'ressource': ressource,
467
                    'appointments': get_daily_usage(context['date'], ressource,
468
                        self.service, events_ressource)})
469

    
470
        return context
471

    
472
class AjaxWorkerTabView(TemplateView):
473

    
474
    template_name = 'agenda/ajax-worker-tab.html'
475

    
476
    def get_context_data(self, worker_id, **kwargs):
477
        context = super(AjaxWorkerTabView, self).get_context_data(**kwargs)
478
        worker = Worker.objects.get(id=worker_id)
479

    
480
        time_tables_worker = TimeTable.objects.select_related('worker'). \
481
                filter(services=self.service, worker=worker) \
482
                .for_today(self.date) \
483
                .order_by('start_date') \
484
                .select_related()
485
        holidays_worker = Holiday.objects.for_worker(worker) \
486
                .for_period(self.date, self.date) \
487
                .order_by('start_date') \
488
                .select_related()
489
        events = Event.objects.for_today(self.date) \
490
                .exclude(event_type_id=1) \
491
                .filter(participants=worker) \
492
                .order_by('start_datetime') \
493
                .select_related() \
494
                .prefetch_related('services',
495
                        'exceptions',
496
                        'participants')
497
        eventswithact = EventWithAct.objects.for_today(self.date) \
498
                .filter(participants=worker) \
499
                .order_by('start_datetime') \
500
                .select_related() \
501
                .prefetch_related('patient__addresses',
502
                        'patient__addresses__patientcontact_set',
503
                        'services',
504
                        'patient__service',
505
                        'act_set__actvalidationstate_set',
506
                        'exceptions', 'participants')
507
        events = [ e.today_occurrence(self.date) for e in events ] \
508
             + [ e.today_occurrence(self.date) for e in eventswithact ]
509

    
510
        context['worker_agenda'] = {'worker': worker,
511
                    'appointments': get_daily_appointments(context['date'], worker, self.service,
512
                        time_tables_worker, events, holidays_worker)}
513
        return context
514

    
515
class AjaxWorkerDisponibilityColumnView(TemplateView):
516

    
517
    template_name = 'agenda/ajax-worker-disponibility-column.html'
518

    
519
    def get_context_data(self, worker_id, **kwargs):
520
        context = super(AjaxWorkerDisponibilityColumnView, self).get_context_data(**kwargs)
521
        worker = Worker.objects.get(pk=worker_id)
522

    
523
        time_tables_worker = TimeTable.objects.select_related('worker'). \
524
                filter(services=self.service, worker=worker). \
525
                for_today(self.date). \
526
                order_by('start_date')
527
        holidays_worker = Holiday.objects.for_worker(worker). \
528
                for_period(self.date, self.date). \
529
                order_by('start_date')
530
        events = Event.objects.for_today(self.date) \
531
                .exclude(event_type_id=1) \
532
                .filter(participants=worker) \
533
                .order_by('start_datetime') \
534
                .select_related() \
535
                .prefetch_related('participants', 'exceptions')
536
        eventswithact = EventWithAct.objects.for_today(self.date) \
537
                .filter(participants=worker) \
538
                .order_by('start_datetime') \
539
                .select_related() \
540
                .prefetch_related('participants', 'exceptions',
541
                        'act_set__actvalidationstate_set')
542

    
543
        events = list(events) + list(eventswithact)
544
        events = [ e.today_occurrence(self.date) for e in events ]
545
        time_tables_workers = {worker.id: time_tables_worker}
546
        events_workers = {worker.id: events}
547
        holidays_workers = {worker.id: holidays_worker}
548

    
549
        context['initials'] = worker.get_initials()
550
        context['worker_id'] = worker.id
551
        context['disponibility'] = Event.objects.daily_disponibilities(self.date,
552
                events_workers, [worker], time_tables_workers, holidays_workers)
553
        return context
(10-10/10)