Projet

Général

Profil

Télécharger (76,2 ko) Statistiques
| Branche: | Tag: | Révision:

calebasse / calebasse / statistics / statistics.py @ 1f4ae3b3

1
# -*- coding: utf-8 -*-
2
import os
3
import tempfile
4
import csv
5

    
6
from collections import OrderedDict
7
from datetime import datetime, timedelta
8
from dateutil.relativedelta import relativedelta
9

    
10
from django.db import models
11
from django.db.models import Count
12
from django.utils import formats
13
from django.conf import settings
14
from django.db.models import Q
15

    
16
from calebasse.dossiers.models import PatientRecord, FileState
17
from calebasse.personnes.models import Worker
18
from calebasse.actes.models import Act
19
from calebasse.agenda.models import Event
20

    
21

    
22
STATISTICS = {
23
    'patients_per_worker_for_period' :
24
        {
25
        'display_name': 'Enfants suivis par intervenant sur une période',
26
        'category': 'Patients',
27
        'comment': """Liste et décompte des patients par intervenant pour les
28
            patients ayant eu au moins un acte proposé avec cet intervenant
29
            sur la plage de dates spécifiée. La date de début de la plage par
30
            défaut est le 1er janvier de l'année en cours. La date de fin de
31
            la plage par défaut est aujourd'hui. Si aucun patient ou
32
            intervenant n'est spécifié, tous les patients et les intervenants
33
            sont pris en compte. A l'inverse, si des patients ou des
34
            intervenants sont indiqués, seuls ceux-ci sont pris en compte.
35
            """
36
    },
37
    'active_patients_by_state_only' :
38
        {
39
        'display_name': "Dossiers actifs selon l'état du dossier à une date donnée",
40
        'category': 'Patients',
41
        'comment': """Listes des patients dont le dossier était actif à une date donnée.
42
            Rappel des états actifs des dossiers : CMPP : diagnostic
43
            ou traitement, CAMSP : suivi, SESSAD: Traitement.
44
            La date par défaut est aujourd'hui.
45
            """
46
    },
47
    'active_patients_with_act' :
48
        {
49
        'display_name': 'Listes des dossiers avec un acte validé, ou un acte '
50
            'proposé seulement, sur une période et triés par état du dossier '
51
            'en fin de période',
52
        'category': 'Patients',
53
        'comment': """Listes des dossiers avec un acte validé ou un acte
54
            proposé seulement sur une période et triés par état du dossier en
55
            fin de période.
56
            La date de début de la plage par
57
            défaut est le 1er janvier de l'année en cours. La date de fin de
58
            la plage par défaut est aujourd'hui.
59
            """
60
    },
61
    'closed_files' :
62
        {
63
        'display_name': 'Dossier clos sur une période et durée de la prise '
64
            'en charge',
65
        'category': 'Patients',
66
        'comment': """Liste des dossiers clos avec leur durée de la prise en
67
            charge sur la plage de dates spécifiée. Le nombre de dossier et la
68
            durée moyenne de la prise en charge est également donnée. La date
69
            de début de la plage par défaut est le 1er janvier de l'année en
70
            cours. La date de fin de la plage par défaut est aujourd'hui.
71
            """
72
    },
73
    'annual_activity' :
74
        {
75
        'display_name': "Activité annuelle",
76
        'category': 'Intervenants',
77
        'comment': """Tableaux de synthèse annuelle. La date saisie
78
            indique l'année à traiter. Si aucune date n'est spécifiée ce sera
79
            l'année en cours. Si aucun intervenant n'est spécifié, les
80
            tableaux de synthèse globaux sont retournés. Si des intervenants
81
            sont indiqués, les tableaux de synthèse pour chaque intervenant
82
            sont retournés.
83
            """
84
    },
85
    'patients_details' :
86
        {
87
        'display_name': "Synthèse par patient",
88
        'category': 'Patients',
89
        'comment': """Tableaux de synthèse par patient. Si aucun patient n'est
90
            indiqué, une synthèse pour chaque patient est retournée. La plage
91
            de date permet de selectionner les patients pour lesquels au
92
            moins au acte a été proposé durant cette période. Si un dossier a
93
            été clos durant cette période mais qu'aucun acte n'a été proposé
94
            durant cette période, il ne sera pas pris en compte. La date de
95
            début de la plage par défaut est le 1er janvier de l'année en
96
            cours. La date de fin de la plage par défaut est aujourd'hui. """
97
    },
98
    'patients_synthesis' :
99
        {
100
        'display_name': 'Synthèse sur les patients avec un acte valide sur '
101
            'la plage de date',
102
        'category': 'Patients',
103
        'comment': """Patients ayant eu au moins un acte validé
104
            sur la plage de dates spécifiée. La date de début de la plage par
105
            défaut est le 1er janvier de l'année en cours. La date de fin de
106
            la plage par défaut est aujourd'hui.
107
            """
108
    },
109
    'acts_synthesis' :
110
        {
111
        'display_name': 'Synthèse sur les actes',
112
        'category': 'Actes',
113
        'comment': """Synthèse sur les actes
114
            sur la plage de dates spécifiée. La date de début de la plage par
115
            défaut est le 1er janvier de l'année en cours. La date de fin de
116
            la plage par défaut est aujourd'hui.
117
            """
118
    },
119
    'acts_synthesis_cmpp' :
120
        {
121
        'display_name': 'Synthèse sur les dossiers facturés au CMPP',
122
        'category': 'Patients',
123
        'services': ['CMPP', ],
124
        'comment': """Synthèse sur les dossiers facturés au CMPP selon que ce
125
            soit en diagnostic, en traitement ou les deux,
126
            sur la plage de dates spécifiée. La date de début de la plage par
127
            défaut est le 1er janvier de l'année en cours. La date de fin de
128
            la plage par défaut est aujourd'hui.
129
            """
130
    },
131
    'mises' :
132
        {
133
        'display_name': 'Synthèse sur les pathologies MISES',
134
        'category': 'Patients',
135
        'comment': """Synthèse sur les pathologies
136
            sur la plage de dates spécifiée. La date de début de la plage par
137
            défaut est le 1er janvier de l'année en cours. La date de fin de
138
            la plage par défaut est aujourd'hui.
139
            """
140
    },
141
    'deficiencies' :
142
        {
143
        'display_name': 'Synthèse sur les déficiences',
144
        'category': 'Patients',
145
        'comment': """Synthèse sur les déficiences
146
            sur la plage de dates spécifiée. La date de début de la plage par
147
            défaut est le 1er janvier de l'année en cours. La date de fin de
148
            la plage par défaut est aujourd'hui.
149
            """
150
    },
151
    'patients_protection' :
152
        {
153
        'display_name': 'Synthèse sur les mesures de protection des patients '
154
            'à une date donnée',
155
        'category': 'Patients',
156
        'comment': """Synthèse sur les mesures de protection des patients.
157
            La date par défaut est aujourd'hui.
158
            """
159
    },
160
    'patients_contact' :
161
        {
162
        'display_name': 'Liste des patients en contact à une date donnée',
163
        'category': 'Patients',
164
        'comment': """Liste des patients en contact à une date donnée.
165
            La date par défaut est aujourd'hui.
166
            """
167
    },
168
}
169

    
170
ANNUAL_ACTIVITY_ROWS = ['total', 'pointe', 'non_pointe', 'absent', 'percent_abs', 'reporte', 'acts_present', 'abs_non_exc', 'abs_exc', 'abs_inter', 'annul_nous', 'annul_famille', 'abs_ess_pps', 'enf_hosp', 'non_facturables', 'facturables', 'perdus', 'doubles', 'really_facturables', 'factures', 'diag', 'trait', 'restants_a_fac', 'refac', 'nf', 'percent_nf', 'patients', 'intervenants', 'days', 'fact_per_day', 'moving_time', 'moving_time_per_intervene', 'moving_time_per_act']
171

    
172
ANNUAL_ACTIVITY_COLUMN_LABELS = ['Janv', 'Fév', 'Mar', 'T1', 'Avr', 'Mai', 'Jui', 'T2', 'Jui', 'Aoû', 'Sep', 'T3', 'Oct', 'Nov', 'Déc', 'T4', 'Total']
173

    
174
class AnnualActivityProcessingColumn():
175
    total = 0
176
    pointe = 0
177
    non_pointe = 0
178
    absent = 0
179
    percent_abs = 0
180
    reporte = 0
181
    acts_present = 0
182
    abs_non_exc = 0
183
    abs_exc = 0
184
    abs_inter = 0
185
    annul_nous = 0
186
    annul_famille = 0
187
    abs_ess_pps = 0
188
    enf_hosp = 0
189
    non_facturables = 0
190
    facturables = 0
191
    perdus = 0
192
    doubles = 0
193
    really_facturables = 0
194
    factures = 0
195
    diag = 0
196
    trait = 0
197
    restants_a_fac = 0
198
    refac = 0
199
    nf = 0
200
    percent_nf = 0
201
    patients = 0
202
    intervenants = 0
203
    days = 0
204
    fact_per_day = 0
205
    moving_time = timedelta()
206
    moving_time_per_intervene = timedelta()
207
    moving_time_per_act = timedelta()
208

    
209
def annual_activity_month_analysis(statistic, start_day, analyses, key, i, trim_cnt, participant=None):
210
    rd = relativedelta(months=1)
211
    sd = start_day + i * rd
212
    ed = sd + rd
213
    acts = None
214
    moving_events = None
215
    if participant:
216
        acts = Act.objects.filter(date__gte=sd.date(),
217
            date__lt=ed.date(), patient__service=statistic.in_service,
218
            doctors__in=[participant])
219
        moving_events = Event.objects.filter(event_type__label='Temps de trajet',
220
            canceled = False,
221
            start_datetime__gte=sd, end_datetime__lt=ed,
222
            services__in=[statistic.in_service],
223
            participants__in=[participant])
224
    else:
225
        acts = Act.objects.filter(date__gte=sd.date(),
226
            date__lt=ed.date(), patient__service=statistic.in_service)
227
        moving_events = Event.objects.filter(event_type__label='Temps de trajet',
228
            canceled = False,
229
            start_datetime__gte=sd, end_datetime__lt=ed,
230
            services__in=[statistic.in_service])
231
    analyses[key].append(AnnualActivityProcessingColumn())
232
    analyses[key][i+trim_cnt].patients = acts.aggregate(Count('patient', distinct=True))['patient__count']
233
    analyses[key][i+trim_cnt].intervenants = acts.aggregate(Count('doctors', distinct=True))['doctors__count']
234
    analyses[key][i+trim_cnt].days = acts.aggregate(Count('date', distinct=True))['date__count']
235
    for me in moving_events:
236
        analyses[key][i+trim_cnt].moving_time += me.timedelta()
237
    for a in acts:
238
        if a.is_new():
239
            analyses[key][i+trim_cnt].non_pointe += 1
240
        elif a.is_absent():
241
            state = a.get_state()
242
            if state.state_name == 'REPORTE':
243
                analyses[key][i+trim_cnt].reporte += 1
244
            else:
245
                analyses[key][i+trim_cnt].absent += 1
246
                if state.state_name == 'ABS_NON_EXC':
247
                    analyses[key][i+trim_cnt].abs_non_exc += 1
248
                elif state.state_name == 'ABS_EXC':
249
                    analyses[key][i+trim_cnt].abs_exc += 1
250
                elif state.state_name == 'ABS_INTER':
251
                    analyses[key][i+trim_cnt].abs_inter += 1
252
                elif state.state_name == 'ANNUL_NOUS':
253
                    analyses[key][i+trim_cnt].annul_nous += 1
254
                elif state.state_name == 'ANNUL_FAMILLE':
255
                    analyses[key][i+trim_cnt].annul_famille += 1
256
                elif state.state_name == 'ABS_ESS_PPS':
257
                    analyses[key][i+trim_cnt].abs_ess_pps += 1
258
                elif state.state_name == 'ENF_HOSP':
259
                    analyses[key][i+trim_cnt].enf_hosp += 1
260
        else:
261
            analyses[key][i+trim_cnt].acts_present += 1
262
            if statistic.in_service.name == 'CMPP':
263
                if not a.is_billable():
264
                    analyses[key][i+trim_cnt].non_facturables += 1
265
                elif a.is_lost:
266
                    analyses[key][i+trim_cnt].perdus += 1
267
                elif a.get_state().state_name == 'ACT_DOUBLE':
268
                    analyses[key][i+trim_cnt].doubles += 1
269
                elif a.is_billed:
270
                    analyses[key][i+trim_cnt].factures += 1
271
                    if a.invoice_set.latest('created').first_tag[0] == 'D':
272
                        analyses[key][i+trim_cnt].diag += 1
273
                    else:
274
                        analyses[key][i+trim_cnt].trait += 1
275
                else:
276
                    analyses[key][i+trim_cnt].restants_a_fac += 1
277
                    if a.invoice_set.all():
278
                        analyses[key][i+trim_cnt].refac += 1
279

    
280
    analyses[key][i+trim_cnt].total = analyses[key][i+trim_cnt].non_pointe + analyses[key][i+trim_cnt].reporte + analyses[key][i+trim_cnt].absent + analyses[key][i+trim_cnt].acts_present
281
    analyses[key][i+trim_cnt].pointe = analyses[key][i+trim_cnt].total - analyses[key][i+trim_cnt].non_pointe
282
    percent_abs = 100
283
    if not analyses[key][i+trim_cnt].pointe or not analyses[key][i+trim_cnt].absent:
284
        percent_abs = 0
285
    elif analyses[key][i+trim_cnt].absent:
286
        percent_abs = (analyses[key][i+trim_cnt].absent/float(analyses[key][i+trim_cnt].pointe))*100
287
    analyses[key][i+trim_cnt].percent_abs = "%.2f" % percent_abs
288

    
289
    if statistic.in_service.name == 'CMPP':
290
        analyses[key][i+trim_cnt].facturables = analyses[key][i+trim_cnt].acts_present - analyses[key][i+trim_cnt].non_facturables
291
        analyses[key][i+trim_cnt].really_facturables = analyses[key][i+trim_cnt].facturables - analyses[key][i+trim_cnt].perdus - analyses[key][i+trim_cnt].doubles
292
        analyses[key][i+trim_cnt].nf = analyses[key][i+trim_cnt].perdus + analyses[key][i+trim_cnt].doubles + analyses[key][i+trim_cnt].non_facturables # + analyses[key][i+trim_cnt].reporte
293
        percent_nf = 100
294
        if not analyses[key][i+trim_cnt].pointe or not analyses[key][i+trim_cnt].nf:
295
            percent_nf = 0
296
        elif analyses[key][i+trim_cnt].nf:
297
            percent_nf = (analyses[key][i+trim_cnt].nf/float(analyses[key][i+trim_cnt].pointe))*100
298
        analyses[key][i+trim_cnt].percent_nf = "%.2f" % percent_nf
299
        if analyses[key][i+trim_cnt].days:
300
            analyses[key][i+trim_cnt].fact_per_day = "%.2f" % (analyses[key][i+trim_cnt].really_facturables / float(analyses[key][i+trim_cnt].days))
301

    
302
    if analyses[key][i+trim_cnt].moving_time and analyses[key][i+trim_cnt].intervenants:
303
        analyses[key][i+trim_cnt].moving_time_per_intervene = analyses[key][i+trim_cnt].moving_time / analyses[key][i+trim_cnt].intervenants
304
    if analyses[key][i+trim_cnt].moving_time and analyses[key][i+trim_cnt].acts_present:
305
        analyses[key][i+trim_cnt].moving_time_per_act = analyses[key][i+trim_cnt].moving_time / analyses[key][i+trim_cnt].acts_present
306

    
307

    
308
def annual_activity_trimester_analysis(statistic, start_day, analyses, key, i, trim_cnt, participant=None):
309
    analyses[key].append(AnnualActivityProcessingColumn())
310
    rd = relativedelta(months=1)
311
    sd = start_day + i * rd
312
    start = start_day + (i-2) * rd
313
    end = sd + rd
314
    acts = None
315
    if participant:
316
        acts = Act.objects.filter(date__gte=start.date(),
317
            date__lt=end.date(), patient__service=statistic.in_service,
318
            doctors__in=[participant])
319
    else:
320
        acts = Act.objects.filter(date__gte=start.date(),
321
            date__lt=end.date(), patient__service=statistic.in_service)
322
    for row in ANNUAL_ACTIVITY_ROWS:
323
        if row == 'percent_abs':
324
            pointe = analyses[key][i+trim_cnt-1].pointe + analyses[key][i-2+trim_cnt].pointe + analyses[key][i-3+trim_cnt].pointe
325
            tot_abs = analyses[key][i+trim_cnt-1].absent + analyses[key][i-2+trim_cnt].absent + analyses[key][i-3+trim_cnt].absent
326
            percent_abs = 100
327
            if not pointe or not tot_abs:
328
                percent_abs = 0
329
            elif tot_abs:
330
                percent_abs = (tot_abs/float(pointe))*100
331
            analyses[key][i+trim_cnt].percent_abs = "%.2f" % percent_abs
332
        elif row == 'percent_nf':
333
            pointe = analyses[key][i+trim_cnt-1].pointe + analyses[key][i-2+trim_cnt].pointe + analyses[key][i-3+trim_cnt].pointe
334
            tot_nf = analyses[key][i+trim_cnt-1].nf + analyses[key][i-2+trim_cnt].nf + analyses[key][i-3+trim_cnt].nf
335
            percent_nf = 100
336
            if not pointe or not tot_nf:
337
                percent_nf = 0
338
            elif tot_nf:
339
                percent_nf = (tot_nf/float(pointe))*100
340
            analyses[key][i+trim_cnt].percent_nf = "%.2f" % percent_nf
341
        elif row == 'patients':
342
            analyses[key][i+trim_cnt].patients = acts.aggregate(Count('patient', distinct=True))['patient__count']
343
        elif row == 'intervenants':
344
            analyses[key][i+trim_cnt].intervenants = acts.aggregate(Count('doctors', distinct=True))['doctors__count']
345
        elif row == 'fact_per_day':
346
            if analyses[key][i+trim_cnt].days:
347
                analyses[key][i+trim_cnt].fact_per_day = "%.2f" % (analyses[key][i+trim_cnt].really_facturables / float(analyses[key][i+trim_cnt].days))
348
        elif row == 'moving_time_per_intervene':
349
            if analyses[key][i+trim_cnt].moving_time and analyses[key][i+trim_cnt].intervenants:
350
                analyses[key][i+trim_cnt].moving_time_per_intervene = analyses[key][i+trim_cnt].moving_time / analyses[key][i+trim_cnt].intervenants
351
        elif row == 'moving_time_per_act':
352
            if analyses[key][i+trim_cnt].moving_time and analyses[key][i+trim_cnt].acts_present:
353
                analyses[key][i+trim_cnt].moving_time_per_act = analyses[key][i+trim_cnt].moving_time / analyses[key][i+trim_cnt].acts_present
354
        else:
355
            setattr(analyses[key][i+trim_cnt], row, getattr(analyses[key][i+trim_cnt-1], row) + getattr(analyses[key][i-2+trim_cnt], row) + getattr(analyses[key][i-3+trim_cnt], row))
356

    
357
def annual_activity_synthesis_analysis(statistic, start_day, end_day, analyses, key, participant=None):
358
    analyses[key].append(AnnualActivityProcessingColumn())
359
    acts = None
360
    if participant:
361
        acts = Act.objects.filter(date__gte=start_day.date(),
362
            date__lt=end_day.date(), patient__service=statistic.in_service,
363
            doctors__in=[participant])
364
    else:
365
        acts = Act.objects.filter(date__gte=start_day.date(),
366
            date__lt=end_day.date(), patient__service=statistic.in_service)
367
    for row in ANNUAL_ACTIVITY_ROWS:
368
        if row == 'percent_abs':
369
            tot_abs = 0
370
            pointe = 0
371
            for i in (3, 7, 11, 15):
372
                pointe += analyses[key][i].pointe
373
                tot_abs += analyses[key][i].absent
374
            percent_abs = 100
375
            if not pointe or not tot_abs:
376
                percent_abs = 0
377
            elif tot_abs:
378
                percent_abs = (tot_abs/float(pointe))*100
379
            analyses[key][16].percent_abs = "%.2f" % percent_abs
380
        elif row == 'percent_nf':
381
            tot_nf= 0
382
            pointe = 0
383
            for i in (3, 7, 11, 15):
384
                pointe += analyses[key][i].pointe
385
                tot_nf += analyses[key][i].nf
386
            percent_nf = 100
387
            if not pointe or not tot_nf:
388
                percent_nf = 0
389
            elif tot_nf:
390
                percent_nf = (tot_nf/float(pointe))*100
391
            analyses[key][16].percent_nf = "%.2f" % percent_nf
392
        elif row == 'patients':
393
            analyses[key][16].patients = acts.aggregate(Count('patient', distinct=True))['patient__count']
394
        elif row == 'intervenants':
395
            analyses[key][16].intervenants = acts.aggregate(Count('doctors', distinct=True))['doctors__count']
396
        elif row == 'fact_per_day':
397
            if analyses[key][16].days:
398
                analyses[key][16].fact_per_day = "%.2f" % (analyses[key][16].really_facturables / float(analyses[key][16].days))
399
        elif row == 'moving_time_per_intervene':
400
            if analyses[key][16].moving_time and analyses[key][16].intervenants:
401
                analyses[key][16].moving_time_per_intervene = analyses[key][16].moving_time / analyses[key][16].intervenants
402
        elif row == 'moving_time_per_act':
403
            if analyses[key][16].moving_time and analyses[key][16].acts_present:
404
                analyses[key][16].moving_time_per_act = analyses[key][16].moving_time / analyses[key][16].acts_present
405
        else:
406
            val = 0
407
            if row == 'moving_time':
408
                val = timedelta()
409
            for i in (3, 7, 11, 15):
410
                val += getattr(analyses[key][i], row)
411
            setattr(analyses[key][16], row, val)
412

    
413
def strfdelta(tdelta):
414
    s = ''
415
    if tdelta.days:
416
        s += "%dj " % tdelta.days
417
    hours, rem = divmod(tdelta.seconds, 3600)
418
    if hours:
419
        s += "%dh " % hours
420
    minutes, seconds = divmod(rem, 60)
421
    if minutes:
422
        s += "%d" % minutes
423
    return s or "0"
424

    
425
def annual_activity_build_tables(statistic, analyses, key, label, data_tables):
426
    table_1 = []
427
    table_1_label = label + ' - général'
428
    table_1.append([table_1_label] + ANNUAL_ACTIVITY_COLUMN_LABELS)
429
    rows = []
430
    row = ['Proposés']
431
    for column in analyses[key]:
432
        row.append(column.total)
433
    rows.append(row)
434
    row = ['Non pointés']
435
    for column in analyses[key]:
436
        row.append(column.non_pointe)
437
    rows.append(row)
438
    row = ['Absences']
439
    for column in analyses[key]:
440
        row.append(column.absent)
441
    rows.append(row)
442
    row = ['Reportés']
443
    for column in analyses[key]:
444
        row.append(column.reporte)
445
    rows.append(row)
446
    row = ['Présents']
447
    for column in analyses[key]:
448
        row.append(column.acts_present)
449
    rows.append(row)
450
    if statistic.in_service.name == 'CMPP':
451
        row = ['Facturables']
452
        for column in analyses[key]:
453
            row.append(column.really_facturables)
454
        rows.append(row)
455
        row = ['Facturés']
456
        for column in analyses[key]:
457
            row.append(column.factures)
458
        rows.append(row)
459
        row = ['Diagnostics']
460
        for column in analyses[key]:
461
            row.append(column.diag)
462
        rows.append(row)
463
        row = ['Traitements']
464
        for column in analyses[key]:
465
            row.append(column.trait)
466
        rows.append(row)
467
        row = ['Restants à facturer']
468
        for column in analyses[key]:
469
            row.append(column.restants_a_fac)
470
        rows.append(row)
471
        row = ['Dont en refact.']
472
        for column in analyses[key]:
473
            row.append(column.refac)
474
        rows.append(row)
475
    row = ['Patients']
476
    for column in analyses[key]:
477
        row.append(column.patients)
478
    rows.append(row)
479
    row = ['Intervenants']
480
    for column in analyses[key]:
481
        row.append(column.intervenants)
482
    rows.append(row)
483
    row = ['Jours']
484
    for column in analyses[key]:
485
        row.append(column.days)
486
    rows.append(row)
487
    if statistic.in_service.name == 'CMPP':
488
        row = ['Facturables / jour']
489
        for column in analyses[key]:
490
            row.append(column.fact_per_day)
491
        rows.append(row)
492
    row = ['Temps de déplacement']
493
    for column in analyses[key]:
494
        row.append(strfdelta(column.moving_time))
495
    rows.append(row)
496
    row = ['Temps de déplacement par intervenant']
497
    for column in analyses[key]:
498
        row.append(strfdelta(column.moving_time_per_intervene))
499
    rows.append(row)
500
    row = ['Temps de déplacement par acte']
501
    for column in analyses[key]:
502
        row.append(strfdelta(column.moving_time_per_act))
503
    rows.append(row)
504
    table_1.append(rows)
505
    data_tables.append(table_1)
506

    
507
    table_2 = []
508
    table_2_label = label + ' - absences'
509
    table_2.append([table_2_label] + ANNUAL_ACTIVITY_COLUMN_LABELS)
510
    rows = []
511
    row = ['Pointés']
512
    for column in analyses[key]:
513
        row.append(column.pointe)
514
    rows.append(row)
515
    row = ['Absences']
516
    for column in analyses[key]:
517
        row.append(column.absent)
518
    rows.append(row)
519
    row = ['% absences / pointés']
520
    for column in analyses[key]:
521
        row.append(column.percent_abs)
522
    rows.append(row)
523
    row = ['Excusées']
524
    for column in analyses[key]:
525
        row.append(column.abs_exc)
526
    rows.append(row)
527
    row = ['Non excusées']
528
    for column in analyses[key]:
529
        row.append(column.abs_non_exc)
530
    rows.append(row)
531
    row = ["De l'intervenant"]
532
    for column in analyses[key]:
533
        row.append(column.abs_inter)
534
    rows.append(row)
535
    row = ["Annulés par nous"]
536
    for column in analyses[key]:
537
        row.append(column.annul_nous)
538
    rows.append(row)
539
    row = ['Annulés par la famille']
540
    for column in analyses[key]:
541
        row.append(column.annul_famille)
542
    rows.append(row)
543
    row = ['ESS PPS']
544
    for column in analyses[key]:
545
        row.append(column.abs_ess_pps)
546
    rows.append(row)
547
    row = ['Hospitalisations']
548
    for column in analyses[key]:
549
        row.append(column.enf_hosp)
550
    rows.append(row)
551
    table_2.append(rows)
552
    data_tables.append(table_2)
553

    
554
    if statistic.in_service.name == 'CMPP':
555
        table_3 = []
556
        table_3_label = label + ' - non fact.'
557
        table_3.append([table_3_label] + ANNUAL_ACTIVITY_COLUMN_LABELS)
558
        rows = []
559
        row = ['Pointés']
560
        for column in analyses[key]:
561
            row.append(column.pointe)
562
        rows.append(row)
563
        row = ['Présents']
564
        for column in analyses[key]:
565
            row.append(column.acts_present)
566
        rows.append(row)
567
        row = ['De type non fact.']
568
        for column in analyses[key]:
569
            row.append(column.non_facturables)
570
        rows.append(row)
571
        row = ['De type fact.']
572
        for column in analyses[key]:
573
            row.append(column.facturables)
574
        rows.append(row)
575
        row = ['Perdus']
576
        for column in analyses[key]:
577
            row.append(column.perdus)
578
        rows.append(row)
579
        row = ['En doubles']
580
        for column in analyses[key]:
581
            row.append(column.doubles)
582
        rows.append(row)
583
        row = ['Non facturables']
584
        for column in analyses[key]:
585
            row.append(column.nf)
586
        rows.append(row)
587
        row = ['% NF / pointés']
588
        for column in analyses[key]:
589
            row.append(column.percent_nf)
590
        rows.append(row)
591
        table_3.append(rows)
592
        data_tables.append(table_3)
593

    
594
def run_annual_activity(statistic, start_day, analyses, key, label, data_tables, participant=None):
595
    analyses[key] = list()
596
    trim_cnt = 0
597
    for i in range(0, 12):
598
        annual_activity_month_analysis(statistic, start_day, analyses, key, i, trim_cnt, participant)
599
        if not (i + 1) % 3:
600
            trim_cnt += 1
601
            annual_activity_trimester_analysis(statistic, start_day, analyses, key, i, trim_cnt, participant)
602
    end_day = datetime(start_day.year+1, 1, 1)
603
    annual_activity_synthesis_analysis(statistic, start_day, end_day, analyses, key, participant)
604
    annual_activity_build_tables(statistic, analyses, key, label, data_tables)
605

    
606
def annual_activity(statistic):
607
    if not statistic.in_service:
608
        return None
609
    start_day = datetime(datetime.today().year, 1, 1)
610
    if statistic.in_year:
611
        start_day = datetime(statistic.in_year, 1, 1)
612
    data_tables = list()
613
    analyses = dict()
614
    if not statistic.in_participants:
615
        run_annual_activity(statistic, start_day, analyses, 'global', str(statistic.in_year) + ' - Tous', data_tables, participant=None)
616
    else:
617
        for participant in statistic.in_participants:
618
            run_annual_activity(statistic, start_day, analyses, participant.id, str(statistic.in_year) + ' - ' + str(participant), data_tables, participant=participant)
619
    return [data_tables]
620

    
621
def patients_per_worker_for_period(statistic):
622
    if not statistic.in_service:
623
        return None
624
    data_tables = []
625
    data = []
626
    data.append(['Intervenants', 'Nombre', 'Patients'])
627
    values = []
628
    if not statistic.in_end_date:
629
        statistic.in_end_date = datetime.today()
630
    if not statistic.in_start_date:
631
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
632
    acts = None
633
    if statistic.in_patients:
634
        acts = Act.objects.filter(date__gte=statistic.in_start_date,
635
            date__lte=statistic.in_end_date,
636
            patient__service=statistic.in_service,
637
            patient__in=statistic.in_patients)
638
    else:
639
        acts = Act.objects.filter(date__gte=statistic.in_start_date,
640
            date__lte=statistic.in_end_date,
641
            patient__service=statistic.in_service)
642
    if statistic.no_synthesis:
643
        synthesis_q = Q(act_type__name__icontains="SYNTHÈSE") | \
644
                Q(act_type__name__icontains="SYNTHESE") | \
645
                Q(act_type__name__icontains="SYNTHÉSE")
646
        acts = acts.exclude(synthesis_q)
647
    analyse = dict()
648
    for act in acts:
649
        for intervene in act.doctors.all():
650
            if statistic.in_participants:
651
                if intervene in statistic.in_participants:
652
                    analyse.setdefault(intervene, []).append(str(act.patient))
653
            else:
654
                analyse.setdefault(intervene, []).append(str(act.patient))
655
    for intervene, patients in sorted(analyse.items(),
656
            key=lambda t: (t[0].last_name, t[0].first_name)):
657
        lst = list(set(patients))
658
        values.append([str(intervene), len(lst), lst])
659
    data.append(values)
660
    data_tables.append(data)
661
    return [data_tables]
662

    
663
def active_patients_by_state_only(statistic):
664
    if not statistic.in_service:
665
        return None
666
    if not statistic.in_start_date:
667
        statistic.in_start_date = datetime.today()
668
    active_states = None
669
    if statistic.in_service.name == 'CMPP':
670
        active_states = ('TRAITEMENT', 'DIAGNOSTIC')
671
    elif statistic.in_service.name == 'CAMSP':
672
        active_states = ('SUIVI', )
673
    else:
674
        active_states = ('TRAITEMENT', )
675
    patients = [(p.last_name, p.first_name, p.paper_id, p.pk) \
676
        for p in PatientRecord.objects.filter(service=statistic.in_service) \
677
            if p.get_state_at_day(statistic.in_start_date) and \
678
                p.get_state_at_day(statistic.in_start_date).status.type in active_states]
679
    data_tables_set=[[[['En date du :', formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"), len(patients)]]]]
680
    data = []
681
    data.append(['Nom', 'Prénom', 'N° Dossier', 'N° dossier informatique'])
682
    p_list = []
683
    for ln, fn, paper_id, pid in patients:
684
        ln = ln or ''
685
        if len(ln) > 1:
686
            ln = ln[0].upper() + ln[1:].lower()
687
        fn = fn or ''
688
        if len(fn) > 1:
689
            fn = fn[0].upper() + fn[1:].lower()
690
        p_list.append((ln, fn, str(paper_id or ''), {'data': pid, 'style': 'lightgray'}))
691
    data.append(sorted(p_list,
692
        key=lambda k: k[0]+k[1]))
693
    data_tables_set[0].append(data)
694
    return data_tables_set
695

    
696
def patients_protection(statistic):
697
    if not statistic.in_service:
698
        return None
699
    if not statistic.in_start_date:
700
        statistic.in_start_date = datetime.today()
701
    patients = PatientRecord.objects.filter(protectionstate__isnull=False).distinct()
702
    protection_states = [p.get_protection_state_at_date(
703
            statistic.in_start_date) for p in patients
704
            if p.get_protection_state_at_date(statistic.in_start_date)]
705
    analyse = {}
706
    for state in protection_states:
707
        analyse.setdefault(state.status.name, 0)
708
        analyse[state.status.name] += 1
709
    data_tables_set=[[[['En date du :', formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"), len(protection_states)]]]]
710
    data = []
711
    data.append(['Mesure de protection', 'Nombre de dossiers'])
712
    data.append(analyse.items())
713
    data_tables_set[0].append(data)
714
    return data_tables_set
715

    
716
def patients_contact(statistic):
717
    if not statistic.in_service:
718
        return None
719
    if not statistic.in_start_date:
720
        statistic.in_start_date = datetime.today()
721
    patients = [p for p in PatientRecord.objects.filter(service=statistic.in_service) \
722
            if p.was_in_state_at_day(statistic.in_start_date, 'ACCUEIL') ]
723

    
724
    all_patients = []
725
    patients_acts = []
726
    patients_no_acts = []
727

    
728
    for p in patients:
729
        values = [p.last_name, p.first_name, p.paper_id or "",
730
            formats.date_format(p.get_state_at_day(
731
            statistic.in_start_date).date_selected,
732
            "SHORT_DATE_FORMAT")]
733
        all_patients.append(values)
734
        acts = Act.objects.filter(patient=p, valide=True,
735
                date__lte=statistic.in_start_date).order_by("-date")
736
        if acts:
737
            v = list(values)
738
            v.append(acts[0].date)
739
            v.append(acts[0].act_type)
740
            patients_acts.append(v)
741
        else:
742
            patients_no_acts.append(values)
743

    
744
    data_tables_set = []
745

    
746
    data_tables_set.append([[['Dossiers en contact en date du %s' % \
747
            formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
748
            len(all_patients)]]])
749
    data = []
750
    data.append(['Nom', 'Prénom', 'N° dossier', 'Contact'])
751
    data.append(sorted(all_patients, key=lambda k: k[0]+k[1]))
752
    data_tables_set[0].append(data)
753

    
754
    data_tables_set.append([[["Dossiers n'ayant jamais eu d'actes validé avant cette date",
755
            len(patients_no_acts)]]])
756
    data = []
757
    data.append(['Nom', 'Prénom', 'N° dossier', 'Contact'])
758
    data.append(sorted(patients_no_acts, key=lambda k: k[0]+k[1]))
759
    data_tables_set[1].append(data)
760

    
761
    data_tables_set.append([[["Dossiers ayant déjà eu au moins un acte validé avant cette date",
762
            len(patients_acts)]]])
763
    data = []
764
    data.append(['Nom', 'Prénom', 'N° dossier', 'Contact', 'Dernier acte', "Type de l'acte"])
765
    data.append(sorted(patients_acts, key=lambda k: k[0]+k[1]))
766
    data_tables_set[2].append(data)
767

    
768
    return data_tables_set
769

    
770
def active_patients_with_act(statistic):
771
    def process(patients_list, title):
772
        data_tables = []
773
        data = []
774
        data.append([title, len(patients_list), '', ''])
775
        data_tables.append(data)
776
        data = []
777
        data.append(['Nom', 'Prénom', 'N° Dossier'])
778
        p_list = []
779
        for p in patients_list:
780
            ln, fn, pid = p.last_name, p.first_name, p.paper_id
781
            ln = ln or ''
782
            if len(ln) > 1:
783
                ln = ln[0].upper() + ln[1:].lower()
784
            fn = fn or ''
785
            if len(fn) > 1:
786
                fn = fn[0].upper() + fn[1:].lower()
787
            p_list.append((ln, fn, str(pid or '')))
788
        data.append(sorted(p_list,
789
            key=lambda k: k[0]+k[1]))
790
        data_tables.append(data)
791
        return data_tables
792
    if not statistic.in_service:
793
        return None
794
    if not statistic.in_end_date:
795
        statistic.in_end_date = datetime.today()
796
    if not statistic.in_start_date:
797
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
798
    active_states = None
799
    if statistic.in_service.name == 'CMPP':
800
        active_states = ('TRAITEMENT', 'DIAGNOSTIC')
801
    elif statistic.in_service.name == 'CAMSP':
802
        active_states = ('SUIVI', )
803
    else:
804
        active_states = ('TRAITEMENT', )
805

    
806
    data_tables_set = []
807
    data_tables = []
808
    data = []
809
    data.append(['Période', 'Jours'])
810
    data.append([("%s - %s"
811
        % (formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
812
        formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT")),
813
        (statistic.in_end_date-statistic.in_start_date).days+1)])
814
    data_tables.append(data)
815
    data_tables_set.append(data_tables)
816

    
817
    acts_base = Act.objects.filter(
818
        date__gte=statistic.in_start_date,
819
        date__lte=statistic.in_end_date,
820
        patient__service=statistic.in_service)
821
    acts_valide = acts_base.filter(valide=True)
822
    acts_valide_patients_ids = acts_valide.order_by('patient').\
823
        distinct('patient').values_list('patient')
824
    acts_valide_patients = PatientRecord.objects.filter(
825
        id__in=[patient[0] for patient in acts_valide_patients_ids])
826
    all_patients_ids = acts_base.order_by('patient').distinct('patient').\
827
        values_list('patient')
828
    acts_not_valide_patients = PatientRecord.objects.filter(
829
        id__in=[patient[0] for patient in all_patients_ids
830
            if not patient in acts_valide_patients_ids])
831

    
832
    data_tables_set.append(process(acts_valide_patients, "Patients avec un acte validé sur la période"))
833
    p_val = dict()
834
    for p in acts_valide_patients:
835
        s = "Indéfini"
836
        if p.get_state_at_day(statistic.in_end_date):
837
            s = p.get_state_at_day(statistic.in_end_date).status
838
        p_val.setdefault(s, []).append(p)
839
    for k, v in p_val.items():
840
        data_tables_set.append(process(v, "Patients avec un acte validé et dans l'état '%s' en date du %s" % (k, formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT"))))
841
    p_val = dict()
842
    data_tables_set.append(process(acts_not_valide_patients, "Patients avec un acte proposé seulement sur la période"))
843
    for p in acts_not_valide_patients:
844
        s = "Indéfini"
845
        if p.get_state_at_day(statistic.in_end_date):
846
            s = p.get_state_at_day(statistic.in_end_date).status
847
        p_val.setdefault(s, []).append(p)
848
    for k, v in p_val.items():
849
        data_tables_set.append(process(v, "Patients avec sans acte validé et dans l'état '%s' en date du %s" % (k, formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT"))))
850

    
851
    return data_tables_set
852

    
853
def closed_files(statistic):
854
    if not statistic.in_service:
855
        return None
856
    data_tables = []
857
    data1 = []
858
    data1.append(['Période', 'Jours',
859
        'Nombre de dossiers clos durant la période', 'PEC totale', 'PEC moyenne', "Dossiers qui ne sont plus clos"])
860
    data2 = []
861
    data2.append(['Nom', 'Prénom', 'N° Dossier', 'Date de clôture', 'Durée de la PEC', "N'est plus clos", "Dernier acte validé avant clôture", "Type de cet acte", "Etat précédent la clôture"])
862
    if not statistic.in_end_date:
863
        statistic.in_end_date = datetime.today()
864
    if not statistic.in_start_date:
865
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
866
    closed_records = FileState.objects.filter(status__type='CLOS',
867
        date_selected__gte=statistic.in_start_date,
868
        date_selected__lte=statistic.in_end_date). \
869
        order_by('patient').distinct('patient').\
870
        values_list('patient')
871
    closed_records = PatientRecord.objects.filter(service=statistic.in_service, id__in=[patient[0]
872
        for patient in closed_records])
873
    total_pec = 0
874
    p_list = []
875
    not_closed_now = 0
876
    closure_states = []
877
    for record in closed_records:
878
        ln = record.last_name or ''
879
        if len(ln) > 1:
880
            ln = ln[0].upper() + ln[1:].lower()
881
        fn = record.first_name or ''
882
        if len(fn) > 1:
883
            fn = fn[0].upper() + fn[1:].lower()
884
        current_state = ''
885
        closure_state = record.last_state
886
        if record.get_current_state().status.type != 'CLOS':
887
            not_closed_now += 1
888
            current_state = record.get_current_state().status.name + \
889
                ' le ' + formats.date_format(record.get_current_state(). \
890
                date_selected, "SHORT_DATE_FORMAT")
891
            closure_state = FileState.objects.filter(status__type='CLOS',
892
                patient=record).order_by('-date_selected')[0]
893
        closure_states.append(closure_state)
894
        close_date = closure_state.date_selected.date()
895
        last_act_date = ""
896
        last_act_type = ""
897
        try:
898
            last_act = Act.objects.filter(valide=True, patient=record, date__lte=close_date).order_by("-date")[0]
899
            last_act_date = formats.date_format(last_act.date, "SHORT_DATE_FORMAT")
900
            last_act_type = last_act.act_type
901
        except:
902
            pass
903
        status = "Indéfini"
904
        try:
905
            status = closure_state.previous_state.status
906
        except:
907
            pass
908
        close_date = formats.date_format(close_date, "SHORT_DATE_FORMAT")
909
        p_list.append((ln, fn, str(record.paper_id or ''),
910
            close_date,
911
            record.care_duration_before_close_state(closure_state.date_selected),
912
            current_state, last_act_date, last_act_type,
913
            status))
914
        total_pec += record.care_duration_before_close_state(closure_state.date_selected)
915
    data2.append(sorted(p_list,
916
        key=lambda k: k[0]+k[1]))
917
    avg_pec = 0
918
    if closed_records.count() and total_pec:
919
        avg_pec = total_pec/closed_records.count()
920
    data1.append([("%s - %s"
921
        % (formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
922
        formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT")),
923
        (statistic.in_end_date-statistic.in_start_date).days+1,
924
        closed_records.count(), total_pec, avg_pec, not_closed_now)])
925
    data_tables.append(data1)
926
    data_tables.append(data2)
927

    
928
    days_states = {}
929
    for record in closed_records:
930
        for state, duration in record.get_states_history_with_duration():
931
            days_states.setdefault(state.status, 0)
932
            days_states[state.status] += duration.days
933
    data = []
934
    data.append(["Etat des dossiers", "Nombre de jours total", "Nombre de jours moyen par dossier"])
935
    values = []
936
    for status, duration in days_states.iteritems():
937
        values.append((status.name, duration, duration/closed_records.count()))
938
    data.append(values)
939
    data_tables.append(data)
940

    
941
    states_before_closure = {}
942
    for closure_state in closure_states:
943
        status = "Indéfini"
944
        try:
945
            status = closure_state.previous_state.status.name
946
        except:
947
            pass
948
        states_before_closure.setdefault(status, []).append(closure_state)
949
    data = []
950
    data.append(["Etat du dossier avant clôture", "Nombre de dossiers", "Nombre de jours total de la PEC", "Nombre de jours moyen de la PEC"])
951
    values = []
952
    for k, v in states_before_closure.items():
953
        if v:
954
            total_pec = 0
955
            for closure_state in v:
956
                total_pec += closure_state.patient.care_duration_before_close_state(closure_state.date_selected)
957
            values.append((k, len(v), total_pec, total_pec/len(v)))
958
    data.append(values)
959
    data_tables.append(data)
960

    
961
    return [data_tables]
962

    
963
def patients_details(statistic):
964
    if not statistic.in_service:
965
        return None
966
    data_tables_set = []
967
    if not statistic.in_end_date:
968
        statistic.in_end_date = datetime.today()
969
    if not statistic.in_start_date:
970
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
971
    acts = None
972
    if statistic.in_patients:
973
        acts = Act.objects.filter(date__gte=statistic.in_start_date,
974
            date__lte=statistic.in_end_date,
975
            patient__service=statistic.in_service,
976
            patient__in=statistic.in_patients)
977
    else:
978
        acts = Act.objects.filter(date__gte=statistic.in_start_date,
979
            date__lte=statistic.in_end_date,
980
            patient__service=statistic.in_service)
981
    analyse = dict()
982
    for act in acts:
983
        analyse.setdefault(act.patient, []).append(act)
984
    o_analyse = OrderedDict(sorted(analyse.items(),
985
        key=lambda t: t[0].last_name))
986
    data = []
987
    data.append(['Période', 'Jours',
988
        'Nombre de dossiers'])
989
    data.append([("%s - %s"
990
        % (formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
991
        formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT")),
992
        (statistic.in_end_date-statistic.in_start_date).days+1,
993
        len(o_analyse))])
994
    data_tables_set.append([data])
995
    for patient, acts in o_analyse.iteritems():
996
        closed_during_range_date = None
997
        try:
998
            closed_during_range_date = FileState.objects.filter(patient=patient, status__type='CLOS',
999
                date_selected__gte=statistic.in_start_date,
1000
                date_selected__lte=statistic.in_end_date).latest('date_selected')
1001
        except:
1002
            pass
1003
        closure_date = ''
1004
        if closed_during_range_date:
1005
            closure_date = closed_during_range_date.date_selected.date
1006
        reopen = ''
1007
        if closed_during_range_date and not patient.exit_date:
1008
            reopen = 'Oui'
1009
        if closed_during_range_date and not reopen:
1010
            end_date = closed_during_range_date.date_selected
1011
        else:
1012
            end_date = statistic.in_end_date
1013
        pec = patient.care_duration_before_close_state(end_date=end_date)
1014
        data_tables = list()
1015
        data_tables.append([["%s %s" % (str(patient), str(patient.paper_id))]])
1016
        data_tables.append([["Durée de la prise en charge"], [[pec]]])
1017
        data = []
1018
        data.append(["Statut de l'acte", 'Nombre'])
1019
        values = []
1020
        values.append(('Proposés', len(acts)))
1021
        np, absent = 0, 0
1022
        act_types = dict()
1023
        for a in acts:
1024
            if a.is_new():
1025
                np += 1
1026
            elif a.is_absent():
1027
                absent += 1
1028
            act_types.setdefault(a.act_type, []).append(a)
1029
        values.append(('Non pointés', np))
1030
        values.append(('Présents', len(acts) - np - absent))
1031
        values.append(('Absents', absent))
1032
        data.append(values)
1033
        data_tables.append(data)
1034

    
1035
        data = []
1036
        data.append(["Types d'acte", "Nombre d'actes proposés", "Nombre d'actes réalisés"])
1037
        values = []
1038
        for act_type, acts in act_types.iteritems():
1039
            values.append((act_type, len(acts), len([a for a in acts if a.is_present()])))
1040
        data.append(values)
1041
        data_tables.append(data)
1042

    
1043
        data = []
1044
        data.append(["Historique", "Nombre de jours par état"])
1045
        values = []
1046
        for state, duration in patient.get_states_history_with_duration():
1047
            values.append(("%s (%s)" % (state.status.name,
1048
                formats.date_format(state.date_selected,
1049
                "SHORT_DATE_FORMAT")), duration.days))
1050
        data.append(values)
1051
        data_tables.append(data)
1052

    
1053
        contacts = FileState.objects.filter(patient=patient, status__type='ACCUEIL').order_by('date_selected')
1054
        recontact = 'Non'
1055
        last_contact = None
1056
        first_acts_after_contact = None
1057
        if len(contacts) == 1:
1058
            last_contact = contacts[0]
1059
        elif len(contacts) > 1:
1060
            recontact = 'Oui'
1061
            last_contact = contacts[len(contacts)-1]
1062
        if last_contact:
1063
            # inscription act
1064
            first_acts_after_contact = Act.objects.filter(patient=patient, date__gte=last_contact.date_selected).order_by('date')
1065
            if first_acts_after_contact:
1066
                first_act_after_contact = first_acts_after_contact[0]
1067
                if first_act_after_contact.date <= statistic.in_end_date.date() and first_act_after_contact.date >= statistic.in_start_date.date():
1068
                    # inscription during the selected date range.
1069
                    waiting_duration = first_act_after_contact.date - last_contact.date_selected.date()
1070
                    data = []
1071
                    data.append(["Date inscription", "Date accueil", 'Attente', 'Réinscription'])
1072
                    values = []
1073
                    values.append((first_act_after_contact.date, last_contact.date_selected.date(), waiting_duration.days, recontact))
1074
                    data.append(values)
1075
                    data_tables.append(data)
1076

    
1077
        data = []
1078
        data.append(["Durée de la prise en charge", "Clos pendant la période", "Réouvert"])
1079
        values = []
1080
        values.append((pec, closure_date, reopen))
1081
        data.append(values)
1082
        data_tables.append(data)
1083

    
1084
        if patient.mdph_requests.exists():
1085
            data = []
1086
            data.append(["Demande(s) MDPH pendant la période", "Date de la demande", "Demande antérieure à la date de début saisie"])
1087
            values = []
1088
            for request in patient.mdph_requests.order_by('start_date'):
1089
                before = 'Non'
1090
                if request.start_date < statistic.in_start_date.date():
1091
                    before = 'Oui'
1092
                values.append(('MDPH : ' + request.mdph.department, request.start_date, before))
1093
            data.append(values)
1094
            data_tables.append(data)
1095
        if patient.mdph_responses.exists():
1096
            data = []
1097
            data.append(["Réponse(s) MDPH pendant la période", "Date de début", "Date de fin"])
1098
            values = []
1099
            for response in patient.mdph_responses.order_by('start_date'):
1100
                values.append(('MDPH : ' + response.mdph.department, response.start_date, response.end_date))
1101
            data.append(values)
1102
            data_tables.append(data)
1103
        data_tables_set.append(data_tables)
1104

    
1105
    return data_tables_set
1106

    
1107
def patients_synthesis(statistic):
1108
    if not statistic.in_service:
1109
        return None
1110
    data_tables = []
1111
    data = []
1112
    data.append(['Période', 'Jours',
1113
        'Nombre de dossiers avec un acte validé sur la période',
1114
        "Nombre d'actes validés sur la période"])
1115
    if not statistic.in_end_date:
1116
        statistic.in_end_date = datetime.today()
1117
    if not statistic.in_start_date:
1118
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
1119
    acts = Act.objects.filter(valide=True,
1120
        date__gte=statistic.in_start_date,
1121
        date__lte=statistic.in_end_date,
1122
        patient__service=statistic.in_service)
1123
    patients = acts.order_by('patient').distinct('patient').\
1124
        values_list('patient')
1125
    patients = PatientRecord.objects.filter(id__in=[patient[0]
1126
        for patient in patients])
1127

    
1128
    active_states = None
1129
    if statistic.in_service.name == 'CMPP':
1130
        active_states = ('TRAITEMENT', 'DIAGNOSTIC', )
1131
    elif statistic.in_service.name == 'CAMSP':
1132
        active_states = ('SUIVI', 'BILAN', 'SURVEILLANCE', 'CLOS', )
1133
    else:
1134
        active_states = ('TRAITEMENT', )
1135

    
1136
    pec_total = 0
1137
    inscriptions = []
1138
    for patient in patients:
1139
        # Select patient if she has been in treament between the selected dates
1140
        traitement_states_tmp = FileState.objects.filter(patient=patient, status__type__in=active_states, date_selected__lte=statistic.in_end_date).order_by('date_selected')
1141
        traitement_states = []
1142
        for ts in traitement_states_tmp:
1143
            if not ts.get_next_state() or ts.get_next_state().date_selected >= statistic.in_start_date:
1144
                traitement_states.append(ts)
1145

    
1146
        # Patient has been in treatment
1147
        # We look for all the treament periods during the selected dates
1148
        # A treament period ends if during the period the file has left treament state
1149
        openings = []
1150
        opening = []
1151
        start = False
1152
        for ts in traitement_states:
1153
            if start:
1154
                openings.append(opening)
1155
                opening = []
1156
                start = False
1157
            if ts.get_next_state() and not ts.get_next_state().status.type in active_states and ts.get_next_state().get_next_state() and ts.get_next_state().get_next_state().status.type in active_states:
1158
                start = True
1159
            opening.append(ts)
1160
        openings.append(opening)
1161

    
1162
        # The first treatment state is the first one of each period matching the dates selected.
1163
        # But there could be other treatment state before, like diag before treatment.
1164
        # so We have to look for the very first treament state to look at the first act after
1165
        first_tss = []
1166
        for opening in openings:
1167
            if len(opening) >= 1:
1168
                first_ts = opening[0]
1169
                while first_ts.previous_state and first_ts.previous_state.status.type in active_states:
1170
                    first_ts = first_ts.previous_state
1171
                contact = None
1172
                if first_ts.previous_state and first_ts.previous_state.status.type=='ACCUEIL':
1173
                    contact = first_ts.previous_state.date_selected.date()
1174
                first_tss.append((contact, first_ts))
1175

    
1176
        # We look to the first act after the datebeginning
1177
        for contact, first_ts in first_tss:
1178
            acts_tmp = Act.objects.filter(valide=True,
1179
                date__gte=first_ts.date_selected,
1180
                patient=patient).order_by('date')
1181
            if acts_tmp and acts_tmp[0].date >= statistic.in_start_date.date() and acts_tmp[0].date <= statistic.in_end_date.date():
1182
                waiting_duration = 0
1183
                if contact:
1184
                    waiting_duration = (acts_tmp[0].date - contact).days
1185
                inscriptions.append((patient, contact, first_ts.date_selected.date(), acts_tmp[0].date, waiting_duration))
1186

    
1187
        closed_during_range_date = None
1188
        try:
1189
            closed_during_range_date = FileState.objects.filter(patient=patient, status__type='CLOS',
1190
                date_selected__gte=statistic.in_start_date,
1191
                date_selected__lte=statistic.in_end_date).latest('date_selected')
1192
        except:
1193
            pass
1194
        if closed_during_range_date and not patient.exit_date:
1195
            end_date = closed_during_range_date.date_selected
1196
        else:
1197
            end_date = statistic.in_end_date
1198
        pec_total += patient.care_duration_before_close_state(end_date=end_date)
1199

    
1200

    
1201
    if statistic.inscriptions:
1202
        patients = PatientRecord.objects.filter(id__in=[p.id for p, _, _, _, _ in inscriptions])
1203
        acts = acts.filter(patient__in=patients)
1204

    
1205
    nb_patients = patients.count()
1206
    if not nb_patients:
1207
        return []
1208

    
1209
    data.append([("%s - %s"
1210
        % (formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
1211
        formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT")),
1212
        (statistic.in_end_date-statistic.in_start_date).days+1,
1213
        nb_patients, acts.count())])
1214
    data_tables.append(data)
1215
    data = []
1216
    data.append(['Filles', 'Garçons'])
1217
    data.append([(patients.filter(gender='2').count(),
1218
        patients.filter(gender='1').count())])
1219
    data_tables.append(data)
1220
    data = []
1221
    data.append(['Durée totale de la PEC',
1222
        'Durée moyenne de la PEC par patient'])
1223
    data.append([(pec_total, pec_total/nb_patients)])
1224
    data_tables.append(data)
1225

    
1226
    data = []
1227
    data.append(["Etat du dossier à ce jour (%s)" % formats.date_format(datetime.today(), "SHORT_DATE_FORMAT"), 'Nombre de patients'])
1228
    states = dict()
1229
    for patient in patients:
1230
        current_state = patient.get_current_state()
1231
        state = "Indéfini"
1232
        if current_state:
1233
            state = current_state.status.name
1234
        states.setdefault(state, []).append(patient)
1235
    values = []
1236
    for state, ps in states.iteritems():
1237
        values.append((state, len(ps)))
1238
    data.append(values)
1239
    data_tables.append(data)
1240

    
1241
    data = []
1242
    data.append(["Etat du dossier en date de fin (%s)" % formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT"), 'Nombre de patients'])
1243
    states = dict()
1244
    for patient in patients:
1245
        s = "Indéfini"
1246
        if patient.get_state_at_day(statistic.in_end_date):
1247
            s = patient.get_state_at_day(statistic.in_end_date).status.name
1248
        states.setdefault(s, []).append(patient)
1249
    values = []
1250
    for state, ps in states.iteritems():
1251
        values.append((state, len(ps)))
1252
    data.append(values)
1253
    data_tables.append(data)
1254

    
1255
    data = []
1256
    data.append(["Inscriptions (premier acte suivant le début d'une phase de traitement dans la période)", "Durée moyenne de l'attente"])
1257
    data.append([(len(inscriptions), sum([wd for _, _, _, _, wd in inscriptions])/len(inscriptions) if len(inscriptions) else 0)])
1258
    data_tables.append(data)
1259

    
1260
    if inscriptions:
1261
        data = []
1262
        data.append(['Nom', 'Prénom', "Numéro papier", "Date premier acte", "Date passage en traitement", "Date de contact", "Attente"])
1263
        values = []
1264
        for patient, contact, first_ts, first_act, waiting_duration in sorted(inscriptions, key=lambda p: (p[0].last_name, p[0].first_name)):
1265
            values.append((patient.last_name, patient.first_name, patient.paper_id, first_act, first_ts, contact, waiting_duration))
1266
        data.append(values)
1267
        data_tables.append(data)
1268

    
1269
    closed_records = FileState.objects.filter(status__type='CLOS',
1270
        date_selected__gte=statistic.in_start_date,
1271
        date_selected__lte=statistic.in_end_date, patient__in=patients). \
1272
        order_by('patient').distinct('patient').\
1273
        values_list('patient')
1274
    closed_records = PatientRecord.objects.filter(service=statistic.in_service, id__in=[patient[0]
1275
        for patient in closed_records])
1276
    total_pec = 0
1277
    not_closed_now = 0
1278
    for record in closed_records:
1279
        if record.get_current_state().status.type != 'CLOS':
1280
            not_closed_now += 1
1281
        closed_during_range_date = None
1282
        try:
1283
            closed_during_range_date = FileState.objects.filter(patient=record, status__type='CLOS',
1284
                date_selected__gte=statistic.in_start_date,
1285
                date_selected__lte=statistic.in_end_date).latest('date_selected')
1286
        except:
1287
            pass
1288
        if closed_during_range_date and not record.exit_date:
1289
            end_date = closed_during_range_date.date_selected
1290
        else:
1291
            end_date = statistic.in_end_date
1292
        total_pec += record.care_duration_before_close_state(end_date=end_date)
1293

    
1294
    avg_pec = 0
1295
    if closed_records.count() and total_pec:
1296
        avg_pec = total_pec/closed_records.count()
1297
    if closed_records.count():
1298
        data = []
1299
        data.append(['Clos dans la période', 'Durée totale de la PEC', 'Durée moyenne de la PEC', "Qui ne sont plus clos à ce jour"])
1300
        data.append([(closed_records.count(), total_pec, avg_pec, not_closed_now)])
1301
        data_tables.append(data)
1302

    
1303
    mdph_requests = 0
1304
    mdph_requests_before = 0
1305
    for patient in patients:
1306
        if patient.mdph_requests.exists():
1307
            mdph_requests += 1
1308
            # We only look to the last one
1309
            if patient.mdph_requests.order_by('-start_date')[0].start_date < statistic.in_start_date.date():
1310
                mdph_requests_before +=1
1311
    data = []
1312
    data.append(['Dossier avec une demande MDPH', "Dont la dernière demande a été faite avant la période"])
1313
    data.append([(mdph_requests, mdph_requests_before)])
1314
    data_tables.append(data)
1315

    
1316
    birth_years = dict()
1317
    patients_without_birthyear = []
1318
    for patient in patients:
1319
        try:
1320
            birth_years.setdefault(patient.birthdate.year, []).append(patient)
1321
        except:
1322
            patients_without_birthyear.append(patient)
1323
    data = []
1324
    data.append(['Année de naissance', "Nombre de dossiers", "%"])
1325
    values = []
1326
    for birth_year, pts in birth_years.iteritems():
1327
        values.append((birth_year, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
1328
    values.append(('Non renseignée',  len(patients_without_birthyear), "%.2f" % (len(patients_without_birthyear) / float(len(patients)) * 100)))
1329
    data.append(values)
1330
    data_tables.append(data)
1331

    
1332
    if patients_without_birthyear:
1333
        data = []
1334
        data.append(["Patients sans date de naissance"])
1335
        values = [[patients_without_birthyear]]
1336
        data.append(values)
1337
        data_tables.append(data)
1338

    
1339

    
1340
    lower_bounds = [0, 3, 5, 7, 11, 16, 20, 25, 30, 35, 40, 45, 50, 55, 60, 75, 85, 96]
1341
    anap_code = 198
1342
    data = []
1343
    data.append(["Code ANAP", "Tranche d'âge (au %s)" \
1344
        % formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT"),
1345
        "Nombre de dossiers", "%", "Filles", "%", "Garçons", "%"])
1346
    values = []
1347
    for i in range(len(lower_bounds)):
1348
        lower_bound = lower_bounds[i]
1349
        if i == len(lower_bounds) - 1:
1350
            values.append([anap_code, "De %d ans et plus" % lower_bound, 0, 0, 0, 0, 0, 0])
1351
        else:
1352
            values.append([anap_code, "De %d à %d ans" % (lower_bound, lower_bounds[i + 1] - 1), 0, 0, 0, 0, 0, 0])
1353
        anap_code += 1
1354
    patients_sorted = {}
1355
    unknowns = [0, 0]
1356
    for patient in patients:
1357
        try:
1358
            age = statistic.in_end_date.date() - patient.birthdate
1359
            age = age.days / 365
1360
            i = 0
1361
            while age >= lower_bounds[i+1]:
1362
                i += 1
1363
                if i == len(lower_bounds) - 1:
1364
                    break
1365
            patients_sorted.setdefault(i, [0, 0])
1366
            if patient.gender == 1:
1367
                patients_sorted[i][0] += 1
1368
            else:
1369
                patients_sorted[i][1] += 1
1370
        except:
1371
            if patient.gender == 1:
1372
                unknowns[0] += 1
1373
            else:
1374
                unknowns[1] += 1
1375

    
1376
    for k, v in patients_sorted.items():
1377
        values[k][2] = v[0] + v[1]
1378
        values[k][3] = "%.2f" % (values[k][2] / float(len(patients)) * 100)
1379
        values[k][4] = v[1]
1380
        values[k][5] = "%.2f" % (v[1] / float(values[k][2]) * 100)
1381
        values[k][6] = v[0]
1382
        values[k][7] = "%.2f" % (v[0] / float(values[k][2]) * 100)
1383
    l_ukn = unknowns[0] + unknowns[1]
1384
    if l_ukn:
1385
        values.append(['', "Non renseigné", l_ukn, "%.2f" % (l_ukn / float(len(patients)) * 100),
1386
            unknowns[1], "%.2f" % (unknowns[1] / float(l_ukn) * 100),
1387
            unknowns[0], "%.2f" % (unknowns[0] / float(l_ukn) * 100)])
1388
    data.append(values)
1389
    data_tables.append(data)
1390

    
1391
    jobs = dict()
1392
    no_job = 0
1393
    for patient in patients:
1394
        job = False
1395
        if patient.job_mother:
1396
            jobs.setdefault(patient.job_mother, []).append(patient)
1397
            job = True
1398
        else:
1399
            for contact in patient.contacts.all():
1400
                if contact.parente and contact.parente.name == 'Mère':
1401
                    if contact.job:
1402
                        jobs.setdefault(contact.job, []).append(patient)
1403
                        job = True
1404
                    break
1405
        if not job:
1406
            no_job += 1
1407
    data = []
1408
    data.append(["Profession de la mère", "Nombre de dossiers", "%"])
1409
    values = []
1410
    for job, pts in jobs.iteritems():
1411
        values.append((job, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
1412
    values.append(("Non renseignée", no_job, "%.2f" % (no_job / float(len(patients)) * 100)))
1413
    data.append(values)
1414
    data_tables.append(data)
1415

    
1416
    jobs = dict()
1417
    no_job = 0
1418
    for patient in patients:
1419
        job = False
1420
        if patient.job_father:
1421
            jobs.setdefault(patient.job_father, []).append(patient)
1422
            job = True
1423
        else:
1424
            for contact in patient.contacts.all():
1425
                if contact.parente and contact.parente.name == 'Père':
1426
                    if contact.job:
1427
                        jobs.setdefault(contact.job, []).append(patient)
1428
                        job = True
1429
                    break
1430
        if not job:
1431
            no_job += 1
1432
    data = []
1433
    data.append(["Profession du père", "Nombre de dossiers", "%"])
1434
    values = []
1435
    for job, pts in jobs.iteritems():
1436
        values.append((job, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
1437
    values.append(("Non renseignée", no_job, "%.2f" % (no_job / float(len(patients)) * 100)))
1438
    data.append(values)
1439
    data_tables.append(data)
1440

    
1441
    provenances = dict()
1442
    unknown = 0
1443
    for patient in patients:
1444
        if patient.provenance:
1445
            provenances.setdefault(patient.provenance, []).append(patient)
1446
        else:
1447
            unknown += 1
1448
    data = []
1449
    data.append(["Provenances", "Nombre de dossiers", "%"])
1450
    values = []
1451
    for provenance, pts in provenances.iteritems():
1452
        values.append((provenance, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
1453
    values.append(('Non renseignée', unknown, "%.2f" % (unknown / float(len(patients)) * 100)))
1454
    data.append(values)
1455
    data_tables.append(data)
1456

    
1457
    outmotives = dict()
1458
    unknown = 0
1459
    for patient in patients:
1460
        if patient.outmotive:
1461
            outmotives.setdefault(patient.outmotive, []).append(patient)
1462
        else:
1463
            unknown += 1
1464
    data = []
1465
    data.append(["Motifs de sortie", "Nombre de dossiers", "%"])
1466
    values = []
1467
    for outmotive, pts in outmotives.iteritems():
1468
        values.append((outmotive, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
1469
    values.append(('Non renseigné', unknown, "%.2f" % (unknown / float(len(patients)) * 100)))
1470
    data.append(values)
1471
    data_tables.append(data)
1472

    
1473
    outtos = dict()
1474
    unknown = 0
1475
    for patient in patients:
1476
        if patient.outto:
1477
            outtos.setdefault(patient.outto, []).append(patient)
1478
        else:
1479
            unknown += 1
1480
    data = []
1481
    data.append(["Orientations", "Nombre de dossiers", "%"])
1482
    values = []
1483
    for outto, pts in outtos.iteritems():
1484
        values.append((outto, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
1485
    values.append(('Non renseigné', unknown, "%.2f" % (unknown / float(len(patients)) * 100)))
1486
    data.append(values)
1487
    data_tables.append(data)
1488

    
1489
    provenance_places = dict()
1490
    unknown = 0
1491
    for patient in patients:
1492
        if patient.provenanceplace:
1493
            provenance_places.setdefault(patient.provenanceplace, []).append(patient)
1494
        else:
1495
            unknown += 1
1496
    data = []
1497
    data.append(["Lieux de provenance", "Nombre de dossiers", "%"])
1498
    values = []
1499
    for provenance_place, pts in provenance_places.iteritems():
1500
        values.append((provenance_place, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
1501
    values.append(('Non renseigné', unknown, "%.2f" % (unknown / float(len(patients)) * 100)))
1502
    data.append(values)
1503
    data_tables.append(data)
1504

    
1505
    return [data_tables]
1506

    
1507
def acts_synthesis(statistic):
1508
    if not statistic.in_service:
1509
        return None
1510
    if not statistic.in_end_date:
1511
        statistic.in_end_date = datetime.today()
1512
    if not statistic.in_start_date:
1513
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
1514

    
1515
    data_tables_set = []
1516
    data_tables = []
1517
    data = []
1518
    data.append(['Période', 'Jours',
1519
        "Nombre d'actes proposés sur la période",
1520
        "Dossiers concernés",
1521
        "Nombre d'actes réalisés sur la période",
1522
        "Dossiers concernés"])
1523
    acts = Act.objects.filter(date__gte=statistic.in_start_date,
1524
        date__lte=statistic.in_end_date,
1525
        patient__service=statistic.in_service)
1526
    len_patients = len(set([a.patient.id for a in acts]))
1527
    acts_present = [a for a in acts if a.is_present()]
1528
    len_patients_present = len(set([a.patient.id for a in acts_present]))
1529
    len_acts_present = len(acts_present)
1530
    data.append([("%s - %s"
1531
        % (formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
1532
        formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT")),
1533
        (statistic.in_end_date-statistic.in_start_date).days+1,
1534
        acts.count(), len_patients, len_acts_present, len_patients_present)])
1535
    data_tables.append(data)
1536
    data_tables_set.append(data_tables)
1537

    
1538
    data_tables=[]
1539
    acts_types = dict()
1540
    for act in acts:
1541
        acts_types.setdefault(act.act_type, []).append(act)
1542
    data = []
1543
    data.append(["Types des actes", "Nombre d'actes proposés", "Nombre de dossiers", "Nombre d'actes réalisés", "Nombre de dossiers"])
1544
    values = []
1545
    for act_type, acts in sorted(acts_types.items(), key=lambda t: t[0].name):
1546
        values.append((act_type, len(acts), len(set([a.patient.id for a in acts])), len([a for a in acts if a.is_present()]), len(set([a.patient.id for a in acts if a.is_present()]))))
1547
    data.append(values)
1548
    data_tables.append(data)
1549
    data_tables_set.append(data_tables)
1550

    
1551
    data_tables=[]
1552
    acts_count_participants = dict()
1553
    for act in acts_present:
1554
        acts_count_participants.setdefault(act.doctors.count(), []).append(act)
1555
    data = []
1556
    data.append(["Nombre d'intervenants des actes réalisés", "Nombre d'actes", "Nombre de dossiers concernés"])
1557
    values = []
1558
    for number, acts_counted in acts_count_participants.iteritems():
1559
        values.append((number, len(acts_counted), len(set([a.patient.id for a in acts_counted]))))
1560
    data.append(values)
1561
    data_tables.append(data)
1562
    data_tables_set.append(data_tables)
1563

    
1564
    for act_type, acts in sorted(acts_types.items(), key=lambda t: t[0].name):
1565
        data_tables=[]
1566
        analysis = {'Non pointés': 0,
1567
            'Reportés': 0, 'Absents': 0, 'Présents': 0}
1568
        for a in acts:
1569
            if a.is_new():
1570
                analysis['Non pointés'] += 1
1571
            elif a.is_absent():
1572
                state = a.get_state()
1573
                if state.state_name == 'REPORTE':
1574
                    analysis['Reportés'] += 1
1575
                else:
1576
                    analysis['Absents'] += 1
1577
            else:
1578
                analysis['Présents'] += 1
1579
        data = []
1580
        data.append(["Type d'acte", act_type])
1581
        values = []
1582
        for status, number in analysis.iteritems():
1583
            values.append((status, number))
1584
        data.append(values)
1585
        data_tables.append(data)
1586
        acts_type_patients = {}
1587
        for act in acts:
1588
            acts_type_patients.setdefault(act.patient, []).append(act)
1589
        data = []
1590
        data.append(["Patient", "Actes proposés", "Actes réalisés"])
1591
        values = []
1592
        for patient, acts_type in acts_type_patients.iteritems():
1593
            values.append((patient, len(acts_type), len([a for a in acts_type if a.is_present()])))
1594
        data.append(values)
1595
        data_tables.append(data)
1596
        data_tables_set.append(data_tables)
1597

    
1598
    return data_tables_set
1599

    
1600
def acts_synthesis_cmpp(statistic):
1601
    data_tables_set = []
1602
    if not statistic.in_service:
1603
        return None
1604
    if not statistic.in_end_date:
1605
        statistic.in_end_date = datetime.today()
1606
    if not statistic.in_start_date:
1607
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
1608
    acts = Act.objects.filter(date__gte=statistic.in_start_date,
1609
        date__lte=statistic.in_end_date,
1610
        patient__service=statistic.in_service)
1611
    acts_billed = acts.filter(is_billed=True)
1612
    patients_billed = dict()
1613
    for act in acts_billed:
1614
        patients_billed.setdefault(act.patient, [False, False])
1615
        if act.get_hc_tag() and act.get_hc_tag()[0] == 'D':
1616
            patients_billed[act.patient][0] = True
1617
        elif act.get_hc_tag() and act.get_hc_tag()[0] == 'T':
1618
            patients_billed[act.patient][1] = True
1619
    values1, values2, values3 = [], [], []
1620
    for patient, vals in patients_billed.iteritems():
1621
        pfields = [patient.last_name, patient.first_name, patient.paper_id]
1622
        if vals == [True, False]:
1623
            values1.append(pfields)
1624
        elif vals == [False, True]:
1625
            values2.append(pfields)
1626
        elif vals == [True, True]:
1627
            values3.append(pfields)
1628
    cols = ['Nom', 'Prénom', 'Numéro de dossier']
1629
    data_tables_set.append([[['Seulement facturé en diagnostic'], [[len(values1)]]], [cols, sorted(values1, key=lambda t: t[0])]])
1630
    data_tables_set.append([[['Seulement facturé en traitement'], [[len(values2)]]], [cols, sorted(values2, key=lambda t: t[0])]])
1631
    data_tables_set.append([[['Facturé en diagnostic et en traitement'], [[len(values3)]]], [cols, sorted(values3, key=lambda t: t[0])]])
1632
    return data_tables_set
1633

    
1634
def mises(statistic):
1635
    if not statistic.in_service:
1636
        return None
1637
    if not statistic.in_end_date:
1638
        statistic.in_end_date = datetime.today()
1639
    if not statistic.in_start_date:
1640
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
1641
    acts = Act.objects.filter(valide='True',
1642
        date__gte=statistic.in_start_date,
1643
        date__lte=statistic.in_end_date,
1644
        patient__service=statistic.in_service)
1645
    patients = acts.order_by('patient').distinct('patient').\
1646
        values_list('patient')
1647
    patients = PatientRecord.objects.filter(id__in=[patient[0]
1648
        for patient in patients])
1649
    pathologies = dict()
1650
    for patient in patients:
1651
        for pathology in patient.mises_1.all():
1652
            pathologies.setdefault(pathology, 0)
1653
            pathologies[pathology] += 1
1654
        for pathology in patient.mises_2.all():
1655
            pathologies.setdefault(pathology, 0)
1656
            pathologies[pathology] += 1
1657
        for pathology in patient.mises_3.all():
1658
            pathologies.setdefault(pathology, 0)
1659
            pathologies[pathology] += 1
1660
    data = [['Pathologies MISES', 'Nombre de patients concernés']]
1661
    data.append(OrderedDict(sorted(pathologies.items(), key=lambda t: t[0].ordering_code)).items())
1662
    return [[data]]
1663

    
1664
def deficiencies(statistic):
1665
    if not statistic.in_service:
1666
        return None
1667
    if not statistic.in_end_date:
1668
        statistic.in_end_date = datetime.today()
1669
    if not statistic.in_start_date:
1670
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
1671
    acts = Act.objects.filter(valide='True',
1672
        date__gte=statistic.in_start_date,
1673
        date__lte=statistic.in_end_date,
1674
        patient__service=statistic.in_service)
1675
    patients = acts.order_by('patient').distinct('patient').\
1676
        values_list('patient')
1677
    patients = PatientRecord.objects.filter(id__in=[patient[0]
1678
        for patient in patients])
1679
    deficiencies_three = ('deficiency_intellectual',
1680
            'deficiency_autism_and_other_ted',
1681
            'deficiency_mental_disorder', 'deficiency_learning_disorder',
1682
            'deficiency_auditory', 'deficiency_visual', 'deficiency_motor',
1683
            'deficiency_metabolic_disorder', 'deficiency_brain_damage',
1684
            'deficiency_behavioral_disorder', 'deficiency_other_disorder')
1685
    data = [['Déficiences', 'Nombre de patients concernés'], []]
1686
    for deficiency in deficiencies_three:
1687
        name = PatientRecord._meta.get_field_by_name(deficiency)[0].verbose_name
1688
        filter_dict = {deficiency: 1}
1689
        data[1].append((name + ' à titre principal', patients.filter(**filter_dict).count()))
1690
        filter_dict = {deficiency: 2}
1691
        data[1].append((name + ' à titre associé', patients.filter(**filter_dict).count()))
1692
    name = PatientRecord._meta.get_field_by_name('deficiency_polyhandicap')[0].verbose_name
1693
    data[1].append((name, patients.filter(deficiency_polyhandicap=True).count()))
1694
    name = PatientRecord._meta.get_field_by_name('deficiency_in_diagnostic')[0].verbose_name
1695
    data[1].append((name, patients.filter(deficiency_in_diagnostic=True).count()))
1696
    return [[data]]
1697

    
1698
class Statistic(object):
1699
    in_start_date = None
1700
    in_end_date = None
1701
    in_service = None
1702
    in_participants = None
1703
    in_patients = None
1704
    in_year = None
1705
    inscriptions = False
1706

    
1707
    def __init__(self, name=None, inputs=dict()):
1708
        self.name = name
1709
        params = STATISTICS.get(name, {})
1710
        self.display_name = params['display_name']
1711
        self.category = params['category']
1712
        self.inputs = inputs
1713
        self.in_participants = list()
1714
        participants = inputs.get('participants')
1715
        if participants:
1716
            p_str_ids = [p for p in participants.split('|') if p]
1717
            for str_id in p_str_ids:
1718
                try:
1719
                    self.in_participants.append(Worker.objects.get(pk=int(str_id)))
1720
                except:
1721
                    pass
1722
        self.in_patients = list()
1723
        patients = inputs.get('patients')
1724
        if patients:
1725
            p_str_ids = [p for p in patients.split('|') if p]
1726
            for str_id in p_str_ids:
1727
                try:
1728
                    self.in_patients.append(PatientRecord.objects.get(pk=int(str_id)))
1729
                except:
1730
                    pass
1731
        self.in_service = inputs.get('service')
1732
        self.in_start_date = None
1733
        try:
1734
            self.in_start_date = datetime.strptime(inputs.get('start_date'),
1735
                "%d/%m/%Y")
1736
            self.in_year = self.in_start_date.year
1737
        except:
1738
            pass
1739
        self.in_end_date = None
1740
        try:
1741
            self.in_end_date = datetime.strptime(inputs.get('end_date'),
1742
                "%d/%m/%Y")
1743
        except:
1744
            pass
1745
        self.inscriptions = inputs.get('inscriptions')
1746
        self.no_synthesis = inputs.get('no_synthesis')
1747

    
1748
    def get_data(self):
1749
        print self.name
1750
        func = globals()[self.name]
1751
        data = func(self)
1752
        self.data = [[[["Date du jour", "Service", "Nom statistique"],
1753
            [[formats.date_format(datetime.today(), "SHORT_DATE_FORMAT"),
1754
            self.in_service, STATISTICS[self.name]['display_name']]]]]] + data
1755
        return self.data
1756

    
1757
    def render_to_csv(self):
1758
        _delimiter = ';'
1759
        _quotechar = '|'
1760
        _doublequote = True
1761
        _skipinitialspace = False
1762
        _lineterminator = '\r\n'
1763
        _quoting = csv.QUOTE_MINIMAL
1764
        if getattr(settings, 'CSVPROFILE', None):
1765
            csv_profile = settings.CSVPROFILE
1766
            _delimiter = csv_profile.get('delimiter', ';')
1767
            _quotechar = csv_profile.get('quotechar', '|')
1768
            _doublequote = csv_profile.get('doublequote', True)
1769
            _skipinitialspace = csv_profile.get('skipinitialspace', False)
1770
            _lineterminator = csv_profile.get('lineterminator', '\r\n')
1771
            _quoting = csv_profile.get('quoting', csv.QUOTE_MINIMAL)
1772
        class CSVProfile(csv.Dialect):
1773
            delimiter = _delimiter
1774
            quotechar = _quotechar
1775
            doublequote = _doublequote
1776
            skipinitialspace = _skipinitialspace
1777
            lineterminator = _lineterminator
1778
            quoting = _quoting
1779
        csv.register_dialect('csv_profile', CSVProfile())
1780
        encoding = getattr(settings, 'CSV_ENCODING', 'utf-8')
1781

    
1782
        import codecs
1783
        filename = None
1784
        with tempfile.NamedTemporaryFile(delete=False) as temp_out_csv:
1785
            filename = temp_out_csv.name
1786
            temp_out_csv.close()
1787
        with codecs.open(filename, 'w+b', encoding=encoding) as encoded_f:
1788
            try:
1789
                writer = csv.writer(encoded_f, dialect='csv_profile')
1790
                for data_set in self.data:
1791
                    for data in data_set:
1792
                        writer.writerow(data[0])
1793
                        if len(data) > 1:
1794
                            for d in data[1]:
1795
                                writer.writerow(d)
1796
                        writer.writerow([])
1797
                    writer.writerow([])
1798
                return filename
1799
            except:
1800
                try:
1801
                    os.unlink(temp_out_pdf.name)
1802
                except:
1803
                    pass
1804

    
1805
    def get_file(self):
1806
        self.get_data()
1807
        return self.render_to_csv()
(5-5/8)