Project

General

Profile

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

calebasse / calebasse / statistics / statistics.py @ fdb98b89

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

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

    
20

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

    
160
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']
161

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

    
164
class AnnualActivityProcessingColumn():
165
    total = 0
166
    pointe = 0
167
    non_pointe = 0
168
    absent = 0
169
    percent_abs = 0
170
    reporte = 0
171
    acts_present = 0
172
    abs_non_exc = 0
173
    abs_exc = 0
174
    abs_inter = 0
175
    annul_nous = 0
176
    annul_famille = 0
177
    abs_ess_pps = 0
178
    enf_hosp = 0
179
    non_facturables = 0
180
    facturables = 0
181
    perdus = 0
182
    doubles = 0
183
    really_facturables = 0
184
    factures = 0
185
    diag = 0
186
    trait = 0
187
    restants_a_fac = 0
188
    refac = 0
189
    nf = 0
190
    percent_nf = 0
191
    patients = 0
192
    intervenants = 0
193
    days = 0
194
    fact_per_day = 0
195
    moving_time = timedelta()
196
    moving_time_per_intervene = timedelta()
197
    moving_time_per_act = timedelta()
198

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

    
268
    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
269
    analyses[key][i+trim_cnt].pointe = analyses[key][i+trim_cnt].total - analyses[key][i+trim_cnt].non_pointe
270
    percent_abs = 100
271
    if not analyses[key][i+trim_cnt].pointe or not analyses[key][i+trim_cnt].absent:
272
        percent_abs = 0
273
    elif analyses[key][i+trim_cnt].absent:
274
        percent_abs = (analyses[key][i+trim_cnt].absent/float(analyses[key][i+trim_cnt].pointe))*100
275
    analyses[key][i+trim_cnt].percent_abs = "%.2f" % percent_abs
276

    
277
    if statistic.in_service.name == 'CMPP':
278
        analyses[key][i+trim_cnt].facturables = analyses[key][i+trim_cnt].acts_present - analyses[key][i+trim_cnt].non_facturables
279
        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
280
        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
281
        percent_nf = 100
282
        if not analyses[key][i+trim_cnt].pointe or not analyses[key][i+trim_cnt].nf:
283
            percent_nf = 0
284
        elif analyses[key][i+trim_cnt].nf:
285
            percent_nf = (analyses[key][i+trim_cnt].nf/float(analyses[key][i+trim_cnt].pointe))*100
286
        analyses[key][i+trim_cnt].percent_nf = "%.2f" % percent_nf
287
        if analyses[key][i+trim_cnt].days:
288
            analyses[key][i+trim_cnt].fact_per_day = "%.2f" % (analyses[key][i+trim_cnt].really_facturables / float(analyses[key][i+trim_cnt].days))
289

    
290
    if analyses[key][i+trim_cnt].moving_time and analyses[key][i+trim_cnt].intervenants:
291
        analyses[key][i+trim_cnt].moving_time_per_intervene = analyses[key][i+trim_cnt].moving_time / analyses[key][i+trim_cnt].intervenants
292
    if analyses[key][i+trim_cnt].moving_time and analyses[key][i+trim_cnt].acts_present:
293
        analyses[key][i+trim_cnt].moving_time_per_act = analyses[key][i+trim_cnt].moving_time / analyses[key][i+trim_cnt].acts_present
294

    
295

    
296
def annual_activity_trimester_analysis(statistic, start_day, analyses, key, i, trim_cnt, participant=None):
297
    analyses[key].append(AnnualActivityProcessingColumn())
298
    rd = relativedelta(months=1)
299
    sd = start_day + i * rd
300
    start = start_day + (i-2) * rd
301
    end = sd + rd
302
    acts = None
303
    if participant:
304
        acts = Act.objects.filter(date__gte=start.date(),
305
            date__lt=end.date(), patient__service=statistic.in_service,
306
            doctors__in=[participant])
307
    else:
308
        acts = Act.objects.filter(date__gte=start.date(),
309
            date__lt=end.date(), patient__service=statistic.in_service)
310
    for row in ANNUAL_ACTIVITY_ROWS:
311
        if row == 'percent_abs':
312
            pointe = analyses[key][i+trim_cnt-1].pointe + analyses[key][i-2+trim_cnt].pointe + analyses[key][i-3+trim_cnt].pointe
313
            tot_abs = analyses[key][i+trim_cnt-1].absent + analyses[key][i-2+trim_cnt].absent + analyses[key][i-3+trim_cnt].absent
314
            percent_abs = 100
315
            if not pointe or not tot_abs:
316
                percent_abs = 0
317
            elif tot_abs:
318
                percent_abs = (tot_abs/float(pointe))*100
319
            analyses[key][i+trim_cnt].percent_abs = "%.2f" % percent_abs
320
        elif row == 'percent_nf':
321
            pointe = analyses[key][i+trim_cnt-1].pointe + analyses[key][i-2+trim_cnt].pointe + analyses[key][i-3+trim_cnt].pointe
322
            tot_nf = analyses[key][i+trim_cnt-1].nf + analyses[key][i-2+trim_cnt].nf + analyses[key][i-3+trim_cnt].nf
323
            percent_nf = 100
324
            if not pointe or not tot_nf:
325
                percent_nf = 0
326
            elif tot_nf:
327
                percent_nf = (tot_nf/float(pointe))*100
328
            analyses[key][i+trim_cnt].percent_nf = "%.2f" % percent_nf
329
        elif row == 'patients':
330
            analyses[key][i+trim_cnt].patients = acts.aggregate(Count('patient', distinct=True))['patient__count']
331
        elif row == 'intervenants':
332
            analyses[key][i+trim_cnt].intervenants = acts.aggregate(Count('doctors', distinct=True))['doctors__count']
333
        elif row == 'fact_per_day':
334
            if analyses[key][i+trim_cnt].days:
335
                analyses[key][i+trim_cnt].fact_per_day = "%.2f" % (analyses[key][i+trim_cnt].really_facturables / float(analyses[key][i+trim_cnt].days))
336
        elif row == 'moving_time_per_intervene':
337
            if analyses[key][i+trim_cnt].moving_time and analyses[key][i+trim_cnt].intervenants:
338
                analyses[key][i+trim_cnt].moving_time_per_intervene = analyses[key][i+trim_cnt].moving_time / analyses[key][i+trim_cnt].intervenants
339
        elif row == 'moving_time_per_act':
340
            if analyses[key][i+trim_cnt].moving_time and analyses[key][i+trim_cnt].acts_present:
341
                analyses[key][i+trim_cnt].moving_time_per_act = analyses[key][i+trim_cnt].moving_time / analyses[key][i+trim_cnt].acts_present
342
        else:
343
            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))
344

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

    
401
def strfdelta(tdelta, fmt):
402
    if not tdelta:
403
        return '0'
404
    d = {"days": tdelta.days}
405
    d["hours"], rem = divmod(tdelta.seconds, 3600)
406
    d["minutes"], d["seconds"] = divmod(rem, 60)
407
    return fmt.format(**d)
408

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

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

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

    
584
def run_annual_activity(statistic, start_day, analyses, key, label, data_tables, participant=None):
585
    analyses[key] = list()
586
    trim_cnt = 0
587
    for i in range(0, 12):
588
        annual_activity_month_analysis(statistic, start_day, analyses, key, i, trim_cnt, participant)
589
        if not (i + 1) % 3:
590
            trim_cnt += 1
591
            annual_activity_trimester_analysis(statistic, start_day, analyses, key, i, trim_cnt, participant)
592
    end_day = datetime(start_day.year+1, 1, 1)
593
    annual_activity_synthesis_analysis(statistic, start_day, end_day, analyses, key, participant)
594
    annual_activity_build_tables(statistic, analyses, key, label, data_tables)
595

    
596
def annual_activity(statistic):
597
    if not statistic.in_service:
598
        return None
599
    start_day = datetime(datetime.today().year, 1, 1)
600
    if statistic.in_year:
601
        start_day = datetime(statistic.in_year, 1, 1)
602
    data_tables = list()
603
    analyses = dict()
604
    if not statistic.in_participants:
605
        run_annual_activity(statistic, start_day, analyses, 'global', str(statistic.in_year) + ' - Tous', data_tables, participant=None)
606
    else:
607
        for participant in statistic.in_participants:
608
            run_annual_activity(statistic, start_day, analyses, participant.id, str(statistic.in_year) + ' - ' + str(participant), data_tables, participant=participant)
609
    return [data_tables]
610

    
611
def patients_per_worker_for_period(statistic):
612
    if not statistic.in_service:
613
        return None
614
    data_tables = []
615
    data = []
616
    data.append(['Intervenants', 'Nombre', 'Patients'])
617
    values = []
618
    if not statistic.in_end_date:
619
        statistic.in_end_date = datetime.today()
620
    if not statistic.in_start_date:
621
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
622
    acts = None
623
    if statistic.in_patients:
624
        acts = Act.objects.filter(date__gte=statistic.in_start_date,
625
            date__lte=statistic.in_end_date,
626
            patient__service=statistic.in_service,
627
            patient__in=statistic.in_patients)
628
    else:
629
        acts = Act.objects.filter(date__gte=statistic.in_start_date,
630
            date__lte=statistic.in_end_date,
631
            patient__service=statistic.in_service)
632
    analyse = dict()
633
    for act in acts:
634
        for intervene in act.doctors.all():
635
            if statistic.in_participants:
636
                if intervene in statistic.in_participants:
637
                    analyse.setdefault(intervene, []).append(str(act.patient))
638
            else:
639
                analyse.setdefault(intervene, []).append(str(act.patient))
640
    o_analyse = OrderedDict(sorted(analyse.items(), key=lambda t: t[0]))
641
    for intervene, patients in o_analyse.iteritems():
642
        lst = list(set(patients))
643
        values.append([str(intervene), len(lst), lst])
644
    data.append(values)
645
    data_tables.append(data)
646
    return [data_tables]
647

    
648
def active_patients_by_state_only(statistic):
649
    if not statistic.in_service:
650
        return None
651
    if not statistic.in_start_date:
652
        statistic.in_start_date = datetime.today()
653
    active_states = None
654
    if statistic.in_service.name == 'CMPP':
655
        active_states = ('TRAITEMENT', 'DIAGNOSTIC')
656
    elif statistic.in_service.name == 'CAMSP':
657
        active_states = ('SUIVI', )
658
    else:
659
        active_states = ('TRAITEMENT', )
660
    patients = [(p.last_name, p.first_name, p.paper_id) \
661
        for p in PatientRecord.objects.filter(service=statistic.in_service) \
662
            if p.get_state_at_day(
663
                statistic.in_start_date).status.type in active_states]
664
    data_tables_set=[[[['En date du :', formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"), len(patients)]]]]
665
    data = []
666
    data.append(['Nom', 'Prénom', 'N° Dossier'])
667
    p_list = []
668
    for ln, fn, pid in patients:
669
        ln = ln or ''
670
        if len(ln) > 1:
671
            ln = ln[0].upper() + ln[1:].lower()
672
        fn = fn or ''
673
        if len(fn) > 1:
674
            fn = fn[0].upper() + fn[1:].lower()
675
        p_list.append((ln, fn, str(pid or '')))
676
    data.append(sorted(p_list,
677
        key=lambda k: k[0]+k[1]))
678
    data_tables_set[0].append(data)
679
    return data_tables_set
680

    
681
def patients_protection(statistic):
682
    if not statistic.in_service:
683
        return None
684
    if not statistic.in_start_date:
685
        statistic.in_start_date = datetime.today()
686
    patients = PatientRecord.objects.filter(protectionstate__isnull=False).distinct()
687
    protection_states = [p.get_protection_state_at_date(
688
            statistic.in_start_date) for p in patients
689
            if p.get_protection_state_at_date(statistic.in_start_date)]
690
    analyse = {}
691
    for state in protection_states:
692
        analyse.setdefault(state.status.name, 0)
693
        analyse[state.status.name] += 1
694
    data_tables_set=[[[['En date du :', formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"), len(protection_states)]]]]
695
    data = []
696
    data.append(['Mesure de protection', 'Nombre de dossiers'])
697
    data.append(analyse.items())
698
    data_tables_set[0].append(data)
699
    return data_tables_set
700

    
701
def active_patients_with_act(statistic):
702
    def process(patients_list, title):
703
        data_tables = []
704
        data = []
705
        data.append([title, len(patients_list), '', ''])
706
        data_tables.append(data)
707
        data = []
708
        data.append(['Nom', 'Prénom', 'N° Dossier'])
709
        p_list = []
710
        for p in patients_list:
711
            ln, fn, pid = p.last_name, p.first_name, p.paper_id
712
            ln = ln or ''
713
            if len(ln) > 1:
714
                ln = ln[0].upper() + ln[1:].lower()
715
            fn = fn or ''
716
            if len(fn) > 1:
717
                fn = fn[0].upper() + fn[1:].lower()
718
            p_list.append((ln, fn, str(pid or '')))
719
        data.append(sorted(p_list,
720
            key=lambda k: k[0]+k[1]))
721
        data_tables.append(data)
722
        return data_tables
723
    if not statistic.in_service:
724
        return None
725
    if not statistic.in_end_date:
726
        statistic.in_end_date = datetime.today()
727
    if not statistic.in_start_date:
728
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
729
    active_states = None
730
    if statistic.in_service.name == 'CMPP':
731
        active_states = ('TRAITEMENT', 'DIAGNOSTIC')
732
    elif statistic.in_service.name == 'CAMSP':
733
        active_states = ('SUIVI', )
734
    else:
735
        active_states = ('TRAITEMENT', )
736

    
737
    data_tables_set = []
738
    data_tables = []
739
    data = []
740
    data.append(['Période', 'Jours'])
741
    data.append([("%s - %s"
742
        % (formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
743
        formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT")),
744
        (statistic.in_end_date-statistic.in_start_date).days+1)])
745
    data_tables.append(data)
746
    data_tables_set.append(data_tables)
747

    
748
    acts_base = Act.objects.filter(
749
        date__gte=statistic.in_start_date,
750
        date__lte=statistic.in_end_date,
751
        patient__service=statistic.in_service)
752
    acts_valide = acts_base.filter(valide=True)
753
    acts_valide_patients_ids = acts_valide.order_by('patient').\
754
        distinct('patient').values_list('patient')
755
    acts_valide_patients = PatientRecord.objects.filter(
756
        id__in=[patient[0] for patient in acts_valide_patients_ids])
757
    all_patients_ids = acts_base.order_by('patient').distinct('patient').\
758
        values_list('patient')
759
    acts_not_valide_patients = PatientRecord.objects.filter(
760
        id__in=[patient[0] for patient in all_patients_ids
761
            if not patient in acts_valide_patients_ids])
762

    
763
    p_val = dict()
764
    for p in acts_valide_patients:
765
        p_val.setdefault(p.get_state_at_day(statistic.in_end_date).status, []).append(p)
766
    for k, v in p_val.items():
767
        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"))))
768
    p_val = dict()
769
    for p in acts_not_valide_patients:
770
        p_val.setdefault(p.get_state_at_day(statistic.in_end_date).status, []).append(p)
771
    for k, v in p_val.items():
772
        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"))))
773

    
774
    return data_tables_set
775

    
776
def closed_files(statistic):
777
    if not statistic.in_service:
778
        return None
779
    data_tables = []
780
    data1 = []
781
    data1.append(['Période', 'Jours',
782
        'Nombre de dossiers clos durant la période', 'PEC totale', 'PEC moyenne', "Dossiers qui ne sont plus clos"])
783
    data2 = []
784
    data2.append(['Nom', 'Prénom', 'N° Dossier', 'Date de clôture', 'Durée de la PEC', "N'est plus clos"])
785
    if not statistic.in_end_date:
786
        statistic.in_end_date = datetime.today()
787
    if not statistic.in_start_date:
788
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
789
    closed_records = FileState.objects.filter(status__type='CLOS',
790
        date_selected__gte=statistic.in_start_date,
791
        date_selected__lte=statistic.in_end_date). \
792
        order_by('patient').distinct('patient').\
793
        values_list('patient')
794
    closed_records = PatientRecord.objects.filter(service=statistic.in_service, id__in=[patient[0]
795
        for patient in closed_records])
796
    total_pec = 0
797
    p_list = []
798
    not_closed_now = 0
799
    for record in closed_records:
800
        ln = record.last_name or ''
801
        if len(ln) > 1:
802
            ln = ln[0].upper() + ln[1:].lower()
803
        fn = record.first_name or ''
804
        if len(fn) > 1:
805
            fn = fn[0].upper() + fn[1:].lower()
806
        current_state = ''
807
        close_date = record.last_state.date_selected.date()
808
        if record.get_current_state().status.type != 'CLOS':
809
            not_closed_now += 1
810
            current_state = record.get_current_state().status.name + \
811
                ' le ' + formats.date_format(record.get_current_state(). \
812
                date_selected, "SHORT_DATE_FORMAT")
813
            close_date = FileState.objects.filter(status__type='CLOS',
814
                patient=record).order_by('-date_selected')[0].date_selected.date()
815
        p_list.append((ln, fn, str(record.paper_id or ''),
816
            close_date,
817
            record.care_duration_since_last_contact_or_first_act,
818
            current_state))
819
        total_pec += record.care_duration_since_last_contact_or_first_act
820
    data2.append(sorted(p_list,
821
        key=lambda k: k[0]+k[1]))
822
    avg_pec = 0
823
    if closed_records.count() and total_pec:
824
        avg_pec = total_pec/closed_records.count()
825
    data1.append([("%s - %s"
826
        % (formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
827
        formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT")),
828
        (statistic.in_end_date-statistic.in_start_date).days+1,
829
        closed_records.count(), total_pec, avg_pec, not_closed_now)])
830
    data_tables.append(data1)
831
    data_tables.append(data2)
832

    
833
    days_states = {}
834
    for record in closed_records:
835
        for state, duration in record.get_states_history_with_duration():
836
            days_states.setdefault(state.status, 0)
837
            days_states[state.status] += duration.days
838
    data = []
839
    data.append(["Etat des dossiers", "Nombre de jours total", "Nombre de jours moyen par dossier"])
840
    values = []
841
    for status, duration in days_states.iteritems():
842
        values.append((status.name, duration, duration/closed_records.count()))
843
    data.append(values)
844
    data_tables.append(data)
845
    return [data_tables]
846

    
847
def patients_details(statistic):
848
    if not statistic.in_service:
849
        return None
850
    data_tables_set = []
851
    if not statistic.in_end_date:
852
        statistic.in_end_date = datetime.today()
853
    if not statistic.in_start_date:
854
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
855
    acts = None
856
    if statistic.in_patients:
857
        acts = Act.objects.filter(date__gte=statistic.in_start_date,
858
            date__lte=statistic.in_end_date,
859
            patient__service=statistic.in_service,
860
            patient__in=statistic.in_patients)
861
    else:
862
        acts = Act.objects.filter(date__gte=statistic.in_start_date,
863
            date__lte=statistic.in_end_date,
864
            patient__service=statistic.in_service)
865
    analyse = dict()
866
    for act in acts:
867
        analyse.setdefault(act.patient, []).append(act)
868
    o_analyse = OrderedDict(sorted(analyse.items(),
869
        key=lambda t: t[0].last_name))
870
    data = []
871
    data.append(['Période', 'Jours',
872
        'Nombre de dossiers'])
873
    data.append([("%s - %s"
874
        % (formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
875
        formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT")),
876
        (statistic.in_end_date-statistic.in_start_date).days+1,
877
        len(o_analyse))])
878
    data_tables_set.append([data])
879
    for patient, acts in o_analyse.iteritems():
880
        data_tables = list()
881
        data_tables.append([["%s %s" % (str(patient), str(patient.paper_id))]])
882
        data_tables.append([["Durée de la prise en charge (depuis le premier acte)"], [[patient.care_duration_since_last_contact_or_first_act]]])
883
        data = []
884
        data.append(["Statut de l'acte", 'Nombre'])
885
        values = []
886
        values.append(('Proposés', len(acts)))
887
        np, absent = 0, 0
888
        act_types = dict()
889
        for a in acts:
890
            if a.is_new():
891
                np += 1
892
            elif a.is_absent():
893
                absent += 1
894
            act_types.setdefault(a.act_type, []).append(a)
895
        values.append(('Non pointés', np))
896
        values.append(('Présents', len(acts) - np - absent))
897
        values.append(('Absents', absent))
898
        data.append(values)
899
        data_tables.append(data)
900

    
901
        data = []
902
        data.append(["Types d'acte", "Nombre d'actes proposés", "Nombre d'actes réalisés"])
903
        values = []
904
        for act_type, acts in act_types.iteritems():
905
            values.append((act_type, len(acts), len([a for a in acts if a.is_present()])))
906
        data.append(values)
907
        data_tables.append(data)
908

    
909
        data = []
910
        data.append(["Historique", "Nombre de jours par état"])
911
        values = []
912
        for state, duration in patient.get_states_history_with_duration():
913
            values.append(("%s (%s)" % (state.status.name,
914
                formats.date_format(state.date_selected,
915
                "SHORT_DATE_FORMAT")), duration.days))
916
        data.append(values)
917
        data_tables.append(data)
918

    
919
        contacts = FileState.objects.filter(patient=patient, status__type='ACCUEIL').order_by('date_selected')
920
        recontact = 'Non'
921
        last_contact = None
922
        first_acts_after_contact = None
923
        if len(contacts) == 1:
924
            last_contact = contacts[0]
925
        elif len(contacts) > 1:
926
            recontact = 'Oui'
927
            last_contact = contacts[len(contacts)-1]
928
        if last_contact:
929
            # inscription act
930
            first_acts_after_contact = Act.objects.filter(patient=patient, date__gte=last_contact.date_selected).order_by('date')
931
            if first_acts_after_contact:
932
                first_act_after_contact = first_acts_after_contact[0]
933
                if first_act_after_contact.date <= statistic.in_end_date.date() and first_act_after_contact.date >= statistic.in_start_date.date():
934
                    # inscription during the selected date range.
935
                    waiting_duration = first_act_after_contact.date - last_contact.date_selected.date()
936
                    data = []
937
                    data.append(["Date inscription", "Date accueil", 'Attente', 'Réinscription'])
938
                    values = []
939
                    values.append((first_act_after_contact.date, last_contact.date_selected.date(), waiting_duration.days, recontact))
940
                    data.append(values)
941
                    data_tables.append(data)
942

    
943
        closed_during_range_date = None
944
        try:
945
            closed_during_range_date = FileState.objects.filter(patient=patient, status__type='CLOS',
946
                date_selected__gte=statistic.in_start_date,
947
                date_selected__lte=statistic.in_end_date).latest('date_selected')
948
        except:
949
            pass
950
        care_duration = patient.care_duration_since_last_contact_or_first_act
951
        closure_date = ''
952
        if closed_during_range_date:
953
            closure_date = closed_during_range_date.date_selected.date
954
        reopen = ''
955
        if closed_during_range_date and not patient.exit_date:
956
            reopen = 'Oui'
957
        data = []
958
        data.append(["Durée de la prise en charge", "Clos pendant la période", "Actes suivants la clôture"])
959
        values = []
960
        values.append((patient.care_duration_since_last_contact_or_first_act, closure_date, reopen))
961
        data.append(values)
962
        data_tables.append(data)
963

    
964
        if patient.mdph_requests.exists():
965
            data = []
966
            data.append(["Demande(s) MDPH pendant la période", "Date de la demande", "Demande antérieure à la date de début saisie"])
967
            values = []
968
            for request in patient.mdph_requests.order_by('start_date'):
969
                before = 'Non'
970
                if request.start_date < statistic.in_start_date.date():
971
                    before = 'Oui'
972
                values.append(('MDPH : ' + request.mdph.department, request.start_date, before))
973
            data.append(values)
974
            data_tables.append(data)
975
        if patient.mdph_responses.exists():
976
            data = []
977
            data.append(["Réponse(s) MDPH pendant la période", "Date de début", "Date de fin"])
978
            values = []
979
            for response in patient.mdph_responses.order_by('start_date'):
980
                values.append(('MDPH : ' + response.mdph.department, response.start_date, response.end_date))
981
            data.append(values)
982
            data_tables.append(data)
983
        data_tables_set.append(data_tables)
984

    
985
    return data_tables_set
986

    
987
def patients_synthesis(statistic):
988
    if not statistic.in_service:
989
        return None
990
    data_tables = []
991
    data = []
992
    data.append(['Période', 'Jours',
993
        'Nombre de dossiers avec un acte validé sur la période',
994
        "Nombre d'actes validés sur la période"])
995
    if not statistic.in_end_date:
996
        statistic.in_end_date = datetime.today()
997
    if not statistic.in_start_date:
998
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
999
    acts = Act.objects.filter(valide=True,
1000
        date__gte=statistic.in_start_date,
1001
        date__lte=statistic.in_end_date,
1002
        patient__service=statistic.in_service)
1003
    patients = acts.order_by('patient').distinct('patient').\
1004
        values_list('patient')
1005
    patients = PatientRecord.objects.filter(id__in=[patient[0]
1006
        for patient in patients])
1007

    
1008
    active_states = None
1009
    if statistic.in_service.name == 'CMPP':
1010
        active_states = ('TRAITEMENT', 'DIAGNOSTIC', )
1011
    elif statistic.in_service.name == 'CAMSP':
1012
        active_states = ('SUIVI', 'BILAN', 'SURVEILLANCE', 'CLOS', )
1013
    else:
1014
        active_states = ('TRAITEMENT', )
1015

    
1016
    inscriptions = []
1017
    for patient in patients:
1018
        # Select patient if she has been in treament between the selected dates
1019
        traitement_states_tmp = FileState.objects.filter(patient=patient, status__type__in=active_states, date_selected__lte=statistic.in_end_date).order_by('date_selected')
1020
        traitement_states = []
1021
        for ts in traitement_states_tmp:
1022
            if not ts.get_next_state() or ts.get_next_state().date_selected >= statistic.in_start_date:
1023
                traitement_states.append(ts)
1024

    
1025
        # Patient has been in treatment
1026
        # We look for all the treament periods during the selected dates
1027
        # A treament period ends if during the period the file has left treament state
1028
        openings = []
1029
        opening = []
1030
        start = False
1031
        for ts in traitement_states:
1032
            if start:
1033
                openings.append(opening)
1034
                opening = []
1035
                start = False
1036
            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:
1037
                start = True
1038
            opening.append(ts)
1039
        openings.append(opening)
1040

    
1041
        # The first treatment state is the first one of each period matching the dates selected.
1042
        # But there could be other treatment state before, like diag before treatment.
1043
        # so We have to look for the very first treament state to look at the first act after
1044
        first_tss = []
1045
        for opening in openings:
1046
            if len(opening) >= 1:
1047
                first_ts = opening[0]
1048
                while first_ts.previous_state and first_ts.previous_state.status.type in active_states:
1049
                    first_ts = first_ts.previous_state
1050
                contact = None
1051
                if first_ts.previous_state and first_ts.previous_state.status.type=='ACCUEIL':
1052
                    contact = first_ts.previous_state.date_selected.date()
1053
                first_tss.append((contact, first_ts))
1054

    
1055
        # We look to the first act after the datebeginning
1056
        for contact, first_ts in first_tss:
1057
            acts_tmp = Act.objects.filter(valide=True,
1058
                date__gte=first_ts.date_selected,
1059
                patient=patient).order_by('date')
1060
            if acts_tmp and acts_tmp[0].date >= statistic.in_start_date.date() and acts_tmp[0].date <= statistic.in_end_date.date():
1061
                waiting_duration = 0
1062
                if contact:
1063
                    waiting_duration = (acts_tmp[0].date - contact).days
1064
                inscriptions.append((patient, contact, first_ts.date_selected.date(), acts_tmp[0].date, waiting_duration))
1065

    
1066
    if statistic.inscriptions:
1067
        patients = PatientRecord.objects.filter(id__in=[p.id for p, _, _, _, _ in inscriptions])
1068
        acts = acts.filter(patient__in=patients)
1069

    
1070
    nb_patients = patients.count()
1071

    
1072
    data.append([("%s - %s"
1073
        % (formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
1074
        formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT")),
1075
        (statistic.in_end_date-statistic.in_start_date).days+1,
1076
        nb_patients, acts.count())])
1077
    data_tables.append(data)
1078
    data = []
1079
    data.append(['Féminin', 'Masculin'])
1080
    data.append([(patients.filter(gender='2').count(),
1081
        patients.filter(gender='1').count())])
1082
    data_tables.append(data)
1083
    data = []
1084
    data.append(['Durée totale de la PEC',
1085
        'Durée moyenne de la PEC par patient'])
1086
    pec_total = sum([p.care_duration_since_last_contact_or_first_act for p in patients])
1087
    data.append([(pec_total, pec_total/nb_patients)])
1088
    data_tables.append(data)
1089

    
1090
    data = []
1091
    data.append(["Etat du dossier à ce jour (%s)" % formats.date_format(datetime.today(), "SHORT_DATE_FORMAT"), 'Nombre de patients'])
1092
    states = dict()
1093
    for patient in patients:
1094
        states.setdefault(patient.get_current_state().status, []).append(patient)
1095
    values = []
1096
    for state, ps in states.iteritems():
1097
        values.append((state.name, len(ps)))
1098
    data.append(values)
1099
    data_tables.append(data)
1100

    
1101
    data = []
1102
    data.append(["Etat du dossier en date de fin (%s)" % formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT"), 'Nombre de patients'])
1103
    states = dict()
1104
    for patient in patients:
1105
        states.setdefault(patient.get_state_at_day(statistic.in_end_date).status, []).append(patient)
1106
    values = []
1107
    for state, ps in states.iteritems():
1108
        values.append((state.name, len(ps)))
1109
    data.append(values)
1110
    data_tables.append(data)
1111

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

    
1117
    if inscriptions:
1118
        data = []
1119
        data.append(['Nom', 'Prénom', "Numéro papier", "Date premier acte", "Date passage en traitement", "Date de contact", "Attente"])
1120
        values = []
1121
        for patient, contact, first_ts, first_act, waiting_duration in sorted(inscriptions, key=lambda p: (p[0].last_name, p[0].first_name)):
1122
            values.append((patient.last_name, patient.first_name, patient.paper_id, first_act, first_ts, contact, waiting_duration))
1123
        data.append(values)
1124
        data_tables.append(data)
1125

    
1126
    closed_records = FileState.objects.filter(status__type='CLOS',
1127
        date_selected__gte=statistic.in_start_date,
1128
        date_selected__lte=statistic.in_end_date, patient__in=patients). \
1129
        order_by('patient').distinct('patient').\
1130
        values_list('patient')
1131
    closed_records = PatientRecord.objects.filter(service=statistic.in_service, id__in=[patient[0]
1132
        for patient in closed_records])
1133
    total_pec = 0
1134
    not_closed_now = 0
1135
    for record in closed_records:
1136
        if record.get_current_state().status.type != 'CLOS':
1137
            not_closed_now += 1
1138
        total_pec += record.care_duration_since_last_contact_or_first_act
1139
    avg_pec = 0
1140
    if closed_records.count() and total_pec:
1141
        avg_pec = total_pec/closed_records.count()
1142
    if closed_records.count():
1143
        data = []
1144
        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"])
1145
        data.append([(closed_records.count(), total_pec, avg_pec, not_closed_now)])
1146
        data_tables.append(data)
1147

    
1148
    mdph_requests = 0
1149
    mdph_requests_before = 0
1150
    for patient in patients:
1151
        if patient.mdph_requests.exists():
1152
            mdph_requests += 1
1153
            # We only look to the last one
1154
            if patient.mdph_requests.order_by('-start_date')[0].start_date < statistic.in_start_date.date():
1155
                mdph_requests_before +=1
1156
    data = []
1157
    data.append(['Dossier avec une demande MDPH', "Dont la dernière demande a été faite avant la période"])
1158
    data.append([(mdph_requests, mdph_requests_before)])
1159
    data_tables.append(data)
1160

    
1161
    birth_years = dict()
1162
    patients_without_birthyear = []
1163
    for patient in patients:
1164
        try:
1165
            birth_years.setdefault(patient.birthdate.year, []).append(patient)
1166
        except:
1167
            patients_without_birthyear.append(patient)
1168
    data = []
1169
    data.append(['Année de naissance', "Nombre de dossiers", "%"])
1170
    values = []
1171
    for birth_year, pts in birth_years.iteritems():
1172
        values.append((birth_year, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
1173
    values.append(('Non renseignée',  len(patients_without_birthyear), "%.2f" % (len(patients_without_birthyear) / float(len(patients)) * 100)))
1174
    data.append(values)
1175
    data_tables.append(data)
1176

    
1177
    if patients_without_birthyear:
1178
        data = []
1179
        data.append(["Patients sans date de naissance"])
1180
        values = [[patients_without_birthyear]]
1181
        data.append(values)
1182
        data_tables.append(data)
1183

    
1184

    
1185
    lower_bounds = [0, 3, 5, 7, 11, 16, 20, 25, 30, 35, 40, 45, 50, 55, 60, 75, 85, 96]
1186
    anap_code = 198
1187
    data = []
1188
    data.append(["Code ANAP", "Tranche d'âge (au %s)" \
1189
        % formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT"),
1190
        "Nombre de dossiers", "%"])
1191
    values = []
1192
    for i in range(len(lower_bounds)):
1193
        lower_bound = lower_bounds[i]
1194
        if i == len(lower_bounds) - 1:
1195
            values.append([anap_code, "De %d ans et plus" % lower_bound, 0, None])
1196
        else:
1197
            values.append([anap_code, "De %d à %d ans" % (lower_bound, lower_bounds[i + 1] - 1), 0, None])
1198
        anap_code += 1
1199
    unknown = 0
1200
    for patient in patients:
1201
        try:
1202
            age = statistic.in_end_date.date() - patient.birthdate
1203
            age = age.days / 365
1204
            i = 0
1205
            while age >= lower_bounds[i+1]:
1206
                i += 1
1207
                if i == len(lower_bounds) - 1:
1208
                    break
1209
            values[i][2] += 1
1210
        except:
1211
            unknown += 1
1212
    for value in values:
1213
        value[3] = "%.2f" % (value[2] / float(len(patients)) * 100)
1214
    values.append(['', "Non renseignée", unknown, "%.2f" % (unknown / float(len(patients)) * 100)])
1215
    data.append(values)
1216
    data_tables.append(data)
1217

    
1218
    jobs = dict()
1219
    no_job = 0
1220
    for patient in patients:
1221
        job = False
1222
        if patient.job_mother:
1223
            jobs.setdefault(patient.job_mother, []).append(patient)
1224
            job = True
1225
        else:
1226
            for contact in patient.contacts.all():
1227
                if contact.parente and contact.parente.name == 'Mère':
1228
                    if contact.job:
1229
                        jobs.setdefault(contact.job, []).append(patient)
1230
                        job = True
1231
                    break
1232
        if not job:
1233
            no_job += 1
1234
    data = []
1235
    data.append(["Profession de la mère", "Nombre de dossiers", "%"])
1236
    values = []
1237
    for job, pts in jobs.iteritems():
1238
        values.append((job, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
1239
    values.append(("Non renseignée", no_job, "%.2f" % (no_job / float(len(patients)) * 100)))
1240
    data.append(values)
1241
    data_tables.append(data)
1242

    
1243
    jobs = dict()
1244
    no_job = 0
1245
    for patient in patients:
1246
        job = False
1247
        if patient.job_father:
1248
            jobs.setdefault(patient.job_father, []).append(patient)
1249
            job = True
1250
        else:
1251
            for contact in patient.contacts.all():
1252
                if contact.parente and contact.parente.name == 'Père':
1253
                    if contact.job:
1254
                        jobs.setdefault(contact.job, []).append(patient)
1255
                        job = True
1256
                    break
1257
        if not job:
1258
            no_job += 1
1259
    data = []
1260
    data.append(["Profession du père", "Nombre de dossiers", "%"])
1261
    values = []
1262
    for job, pts in jobs.iteritems():
1263
        values.append((job, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
1264
    values.append(("Non renseignée", no_job, "%.2f" % (no_job / float(len(patients)) * 100)))
1265
    data.append(values)
1266
    data_tables.append(data)
1267

    
1268
    provenances = dict()
1269
    unknown = 0
1270
    for patient in patients:
1271
        if patient.provenance:
1272
            provenances.setdefault(patient.provenance, []).append(patient)
1273
        else:
1274
            unknown += 1
1275
    data = []
1276
    data.append(["Provenances", "Nombre de dossiers", "%"])
1277
    values = []
1278
    for provenance, pts in provenances.iteritems():
1279
        values.append((provenance, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
1280
    values.append(('Non renseignée', unknown, "%.2f" % (unknown / float(len(patients)) * 100)))
1281
    data.append(values)
1282
    data_tables.append(data)
1283

    
1284
    outmotives = dict()
1285
    unknown = 0
1286
    for patient in patients:
1287
        if patient.outmotive:
1288
            outmotives.setdefault(patient.outmotive, []).append(patient)
1289
        else:
1290
            unknown += 1
1291
    data = []
1292
    data.append(["Motifs de sortie", "Nombre de dossiers", "%"])
1293
    values = []
1294
    for outmotive, pts in outmotives.iteritems():
1295
        values.append((outmotive, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
1296
    values.append(('Non renseigné', unknown, "%.2f" % (unknown / float(len(patients)) * 100)))
1297
    data.append(values)
1298
    data_tables.append(data)
1299

    
1300
    outtos = dict()
1301
    unknown = 0
1302
    for patient in patients:
1303
        if patient.outto:
1304
            outtos.setdefault(patient.outto, []).append(patient)
1305
        else:
1306
            unknown += 1
1307
    data = []
1308
    data.append(["Orientations", "Nombre de dossiers", "%"])
1309
    values = []
1310
    for outto, pts in outtos.iteritems():
1311
        values.append((outto, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
1312
    values.append(('Non renseigné', unknown, "%.2f" % (unknown / float(len(patients)) * 100)))
1313
    data.append(values)
1314
    data_tables.append(data)
1315

    
1316
    provenance_places = dict()
1317
    unknown = 0
1318
    for patient in patients:
1319
        if patient.provenanceplace:
1320
            provenance_places.setdefault(patient.provenanceplace, []).append(patient)
1321
        else:
1322
            unknown += 1
1323
    data = []
1324
    data.append(["Lieux de provenance", "Nombre de dossiers", "%"])
1325
    values = []
1326
    for provenance_place, pts in provenance_places.iteritems():
1327
        values.append((provenance_place, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
1328
    values.append(('Non renseigné', unknown, "%.2f" % (unknown / float(len(patients)) * 100)))
1329
    data.append(values)
1330
    data_tables.append(data)
1331

    
1332
    return [data_tables]
1333

    
1334
def acts_synthesis(statistic):
1335
    if not statistic.in_service:
1336
        return None
1337
    if not statistic.in_end_date:
1338
        statistic.in_end_date = datetime.today()
1339
    if not statistic.in_start_date:
1340
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
1341

    
1342
    data_tables_set = []
1343
    data_tables = []
1344
    data = []
1345
    data.append(['Période', 'Jours',
1346
        "Nombre d'actes proposés sur la période",
1347
        "Dossiers concernés",
1348
        "Nombre d'actes réalisés sur la période",
1349
        "Dossiers concernés"])
1350
    acts = Act.objects.filter(date__gte=statistic.in_start_date,
1351
        date__lte=statistic.in_end_date,
1352
        patient__service=statistic.in_service)
1353
    len_patients = len(set([a.patient.id for a in acts]))
1354
    acts_present = [a for a in acts if a.is_present()]
1355
    len_patients_present = len(set([a.patient.id for a in acts_present]))
1356
    len_acts_present = len(acts_present)
1357
    data.append([("%s - %s"
1358
        % (formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
1359
        formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT")),
1360
        (statistic.in_end_date-statistic.in_start_date).days+1,
1361
        acts.count(), len_patients, len_acts_present, len_patients_present)])
1362
    data_tables.append(data)
1363
    data_tables_set.append(data_tables)
1364

    
1365
    data_tables=[]
1366
    acts_types = dict()
1367
    for act in acts:
1368
        acts_types.setdefault(act.act_type, []).append(act)
1369
    data = []
1370
    data.append(["Types des actes", "Nombre d'actes proposés", "Nombre de dossiers", "Nombre d'actes réalisés", "Nombre de dossiers"])
1371
    values = []
1372
    for act_type, acts in sorted(acts_types.items(), key=lambda t: t[0].name):
1373
        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()]))))
1374
    data.append(values)
1375
    data_tables.append(data)
1376
    data_tables_set.append(data_tables)
1377

    
1378
    data_tables=[]
1379
    acts_count_participants = dict()
1380
    for act in acts_present:
1381
        acts_count_participants.setdefault(act.doctors.count(), []).append(act)
1382
    data = []
1383
    data.append(["Nombre d'intervenants des actes réalisés", "Nombre d'actes", "Nombre de dossiers concernés"])
1384
    values = []
1385
    for number, acts_counted in acts_count_participants.iteritems():
1386
        values.append((number, len(acts_counted), len(set([a.patient.id for a in acts_counted]))))
1387
    data.append(values)
1388
    data_tables.append(data)
1389
    data_tables_set.append(data_tables)
1390

    
1391
    for act_type, acts in sorted(acts_types.items(), key=lambda t: t[0].name):
1392
        data_tables=[]
1393
        analysis = {'Non pointés': 0,
1394
            'Reportés': 0, 'Absents': 0, 'Présents': 0}
1395
        for a in acts:
1396
            if a.is_new():
1397
                analysis['Non pointés'] += 1
1398
            elif a.is_absent():
1399
                state = a.get_state()
1400
                if state.state_name == 'REPORTE':
1401
                    analysis['Reportés'] += 1
1402
                else:
1403
                    analysis['Absents'] += 1
1404
            else:
1405
                analysis['Présents'] += 1
1406
        data = []
1407
        data.append(["Type d'acte", act_type])
1408
        values = []
1409
        for status, number in analysis.iteritems():
1410
            values.append((status, number))
1411
        data.append(values)
1412
        data_tables.append(data)
1413
        acts_type_patients = {}
1414
        for act in acts:
1415
            acts_type_patients.setdefault(act.patient, []).append(act)
1416
        data = []
1417
        data.append(["Patient", "Actes proposés", "Actes réalisés"])
1418
        values = []
1419
        for patient, acts_type in acts_type_patients.iteritems():
1420
            values.append((patient, len(acts_type), len([a for a in acts_type if a.is_present()])))
1421
        data.append(values)
1422
        data_tables.append(data)
1423
        data_tables_set.append(data_tables)
1424

    
1425
    return data_tables_set
1426

    
1427
def acts_synthesis_cmpp(statistic):
1428
    data_tables_set = []
1429
    if not statistic.in_service:
1430
        return None
1431
    if not statistic.in_end_date:
1432
        statistic.in_end_date = datetime.today()
1433
    if not statistic.in_start_date:
1434
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
1435
    acts = Act.objects.filter(date__gte=statistic.in_start_date,
1436
        date__lte=statistic.in_end_date,
1437
        patient__service=statistic.in_service)
1438
    acts_billed = acts.filter(is_billed=True)
1439
    patients_billed = dict()
1440
    for act in acts_billed:
1441
        patients_billed.setdefault(act.patient, [False, False])
1442
        if act.get_hc_tag() and act.get_hc_tag()[0] == 'D':
1443
            patients_billed[act.patient][0] = True
1444
        elif act.get_hc_tag() and act.get_hc_tag()[0] == 'T':
1445
            patients_billed[act.patient][1] = True
1446
    values1, values2, values3 = [], [], []
1447
    for patient, vals in patients_billed.iteritems():
1448
        pfields = [patient.last_name, patient.first_name, patient.paper_id]
1449
        if vals == [True, False]:
1450
            values1.append(pfields)
1451
        elif vals == [False, True]:
1452
            values2.append(pfields)
1453
        elif vals == [True, True]:
1454
            values3.append(pfields)
1455
    cols = ['Nom', 'Prénom', 'Numéro de dossier']
1456
    data_tables_set.append([[['Seulement facturé en diagnostic'], [[len(values1)]]], [cols, sorted(values1, key=lambda t: t[0])]])
1457
    data_tables_set.append([[['Seulement facturé en traitement'], [[len(values2)]]], [cols, sorted(values2, key=lambda t: t[0])]])
1458
    data_tables_set.append([[['Facturé en diagnostic et en traitement'], [[len(values3)]]], [cols, sorted(values3, key=lambda t: t[0])]])
1459
    return data_tables_set
1460

    
1461
def mises(statistic):
1462
    if not statistic.in_service:
1463
        return None
1464
    if not statistic.in_end_date:
1465
        statistic.in_end_date = datetime.today()
1466
    if not statistic.in_start_date:
1467
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
1468
    acts = Act.objects.filter(valide='True',
1469
        date__gte=statistic.in_start_date,
1470
        date__lte=statistic.in_end_date,
1471
        patient__service=statistic.in_service)
1472
    patients = acts.order_by('patient').distinct('patient').\
1473
        values_list('patient')
1474
    patients = PatientRecord.objects.filter(id__in=[patient[0]
1475
        for patient in patients])
1476
    pathologies = dict()
1477
    for patient in patients:
1478
        for pathology in patient.mises_1.all():
1479
            pathologies.setdefault(pathology, 0)
1480
            pathologies[pathology] += 1
1481
        for pathology in patient.mises_2.all():
1482
            pathologies.setdefault(pathology, 0)
1483
            pathologies[pathology] += 1
1484
        for pathology in patient.mises_3.all():
1485
            pathologies.setdefault(pathology, 0)
1486
            pathologies[pathology] += 1
1487
    data = [['Pathologies MISES', 'Nombre de patients concernés']]
1488
    data.append(OrderedDict(sorted(pathologies.items(), key=lambda t: t[0].ordering_code)).items())
1489
    return [[data]]
1490

    
1491
def deficiencies(statistic):
1492
    if not statistic.in_service:
1493
        return None
1494
    if not statistic.in_end_date:
1495
        statistic.in_end_date = datetime.today()
1496
    if not statistic.in_start_date:
1497
        statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
1498
    acts = Act.objects.filter(valide='True',
1499
        date__gte=statistic.in_start_date,
1500
        date__lte=statistic.in_end_date,
1501
        patient__service=statistic.in_service)
1502
    patients = acts.order_by('patient').distinct('patient').\
1503
        values_list('patient')
1504
    patients = PatientRecord.objects.filter(id__in=[patient[0]
1505
        for patient in patients])
1506
    deficiencies_three = ('deficiency_intellectual',
1507
            'deficiency_autism_and_other_ted',
1508
            'deficiency_mental_disorder', 'deficiency_learning_disorder',
1509
            'deficiency_auditory', 'deficiency_visual', 'deficiency_motor',
1510
            'deficiency_metabolic_disorder', 'deficiency_brain_damage',
1511
            'deficiency_behavioral_disorder', 'deficiency_other_disorder')
1512
    data = [['Déficiences', 'Nombre de patients concernés'], []]
1513
    for deficiency in deficiencies_three:
1514
        name = PatientRecord._meta.get_field_by_name(deficiency)[0].verbose_name
1515
        filter_dict = {deficiency: 1}
1516
        data[1].append((name + ' à titre principal', patients.filter(**filter_dict).count()))
1517
        filter_dict = {deficiency: 2}
1518
        data[1].append((name + ' à titre associé', patients.filter(**filter_dict).count()))
1519
    name = PatientRecord._meta.get_field_by_name('deficiency_polyhandicap')[0].verbose_name
1520
    data[1].append((name, patients.filter(deficiency_polyhandicap=True).count()))
1521
    name = PatientRecord._meta.get_field_by_name('deficiency_in_diagnostic')[0].verbose_name
1522
    data[1].append((name, patients.filter(deficiency_in_diagnostic=True).count()))
1523
    return [[data]]
1524

    
1525
class Statistic(object):
1526
    in_start_date = None
1527
    in_end_date = None
1528
    in_service = None
1529
    in_participants = None
1530
    in_patients = None
1531
    in_year = None
1532
    inscriptions = False
1533

    
1534
    def __init__(self, name=None, inputs=dict()):
1535
        self.name = name
1536
        params = STATISTICS.get(name, {})
1537
        self.display_name = params['display_name']
1538
        self.category = params['category']
1539
        self.inputs = inputs
1540
        self.in_participants = list()
1541
        participants = inputs.get('participants')
1542
        if participants:
1543
            p_str_ids = [p for p in participants.split('|') if p]
1544
            for str_id in p_str_ids:
1545
                try:
1546
                    self.in_participants.append(Worker.objects.get(pk=int(str_id)))
1547
                except:
1548
                    pass
1549
        self.in_patients = list()
1550
        patients = inputs.get('patients')
1551
        if patients:
1552
            p_str_ids = [p for p in patients.split('|') if p]
1553
            for str_id in p_str_ids:
1554
                try:
1555
                    self.in_patients.append(PatientRecord.objects.get(pk=int(str_id)))
1556
                except:
1557
                    pass
1558
        self.in_service = inputs.get('service')
1559
        self.in_start_date = None
1560
        try:
1561
            self.in_start_date = datetime.strptime(inputs.get('start_date'),
1562
                "%d/%m/%Y")
1563
            self.in_year = self.in_start_date.year
1564
        except:
1565
            pass
1566
        self.in_end_date = None
1567
        try:
1568
            self.in_end_date = datetime.strptime(inputs.get('end_date'),
1569
                "%d/%m/%Y")
1570
        except:
1571
            pass
1572
        self.inscriptions = inputs.get('inscriptions')
1573

    
1574
    def get_data(self):
1575
        func = globals()[self.name]
1576
        data = func(self)
1577
        self.data = [[[["Date du jour", "Service", "Nom statistique"],
1578
            [[formats.date_format(datetime.today(), "SHORT_DATE_FORMAT"),
1579
            self.in_service, STATISTICS[self.name]['display_name']]]]]] + data
1580
        return self.data
1581

    
1582
    def render_to_csv(self):
1583
        _delimiter = ';'
1584
        _quotechar = '|'
1585
        _doublequote = True
1586
        _skipinitialspace = False
1587
        _lineterminator = '\r\n'
1588
        _quoting = csv.QUOTE_MINIMAL
1589
        if getattr(settings, 'CSVPROFILE', None):
1590
            csv_profile = settings.CSVPROFILE
1591
            _delimiter = csv_profile.get('delimiter', ';')
1592
            _quotechar = csv_profile.get('quotechar', '|')
1593
            _doublequote = csv_profile.get('doublequote', True)
1594
            _skipinitialspace = csv_profile.get('skipinitialspace', False)
1595
            _lineterminator = csv_profile.get('lineterminator', '\r\n')
1596
            _quoting = csv_profile.get('quoting', csv.QUOTE_MINIMAL)
1597
        class CSVProfile(csv.Dialect):
1598
            delimiter = _delimiter
1599
            quotechar = _quotechar
1600
            doublequote = _doublequote
1601
            skipinitialspace = _skipinitialspace
1602
            lineterminator = _lineterminator
1603
            quoting = _quoting
1604
        csv.register_dialect('csv_profile', CSVProfile())
1605
        encoding = getattr(settings, 'CSV_ENCODING', 'utf-8')
1606

    
1607
        import codecs
1608
        filename = None
1609
        with tempfile.NamedTemporaryFile(delete=False) as temp_out_csv:
1610
            filename = temp_out_csv.name
1611
            temp_out_csv.close()
1612
        with codecs.open(filename, 'w+b', encoding=encoding) as encoded_f:
1613
            try:
1614
                writer = csv.writer(encoded_f, dialect='csv_profile')
1615
                for data_set in self.data:
1616
                    for data in data_set:
1617
                        writer.writerow(data[0])
1618
                        if len(data) > 1:
1619
                            for d in data[1]:
1620
                                writer.writerow(d)
1621
                        writer.writerow([])
1622
                    writer.writerow([])
1623
                return filename
1624
            except:
1625
                try:
1626
                    os.unlink(temp_out_pdf.name)
1627
                except:
1628
                    pass
1629

    
1630
    def get_file(self):
1631
        self.get_data()
1632
        return self.render_to_csv()
(5-5/8)