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': 'Dossiers actifs et inactifs avec un acte validé ou non sur une période',
|
49
|
'category': 'Patients',
|
50
|
'comment': """Listes des patients ayant eu au moins un acte proposé
|
51
|
durant la période indiquée. Les patients sont scindés en quatre
|
52
|
tableaux.
|
53
|
Les patients dont au moins un acte a été
|
54
|
validé ET dont le dossier est dans un état "actif".
|
55
|
Les patients dont au moins un acte a été
|
56
|
validé ET dont le dossier N'est PAS dans un état "actif".
|
57
|
Les patients sans aucun acte validé ET dont le dossier est dans
|
58
|
un état "actif".
|
59
|
Les patients sans aucun acte validé ET dont le dossier N'est PAS
|
60
|
dans un état "actif".
|
61
|
Rappel des états actifs des dossiers : CMPP : diagnostic
|
62
|
ou traitement, CAMSP : suivi, SESSAD: Traitement.
|
63
|
La date de début de la plage par
|
64
|
défaut est le 1er janvier de l'année en cours. La date de fin de
|
65
|
la plage par défaut est aujourd'hui.
|
66
|
"""
|
67
|
},
|
68
|
'closed_files' :
|
69
|
{
|
70
|
'display_name': 'Dossier clos sur une période et durée de la prise '
|
71
|
'en charge',
|
72
|
'category': 'Patients',
|
73
|
'comment': """Liste des dossiers clos avec leur durée de la prise en
|
74
|
charge sur la plage de dates spécifiée. Le nombre de dossier et la
|
75
|
durée moyenne de la prise en charge est également donnée. La date
|
76
|
de début de la plage par défaut est le 1er janvier de l'année en
|
77
|
cours. La date de fin de la plage par défaut est aujourd'hui.
|
78
|
"""
|
79
|
},
|
80
|
'annual_activity' :
|
81
|
{
|
82
|
'display_name': "Activité annuelle",
|
83
|
'category': 'Intervenants',
|
84
|
'comment': """Tableaux de synthèse annuelle. La date saisie
|
85
|
indique l'année à traiter. Si aucune date n'est spécifiée ce sera
|
86
|
l'année en cours. Si aucun intervenant n'est spécifié, les
|
87
|
tableaux de synthèse globaux sont retournés. Si des intervenants
|
88
|
sont indiqués, les tableaux de synthèse pour chaque intervenant
|
89
|
sont retournés.
|
90
|
"""
|
91
|
},
|
92
|
'patients_details' :
|
93
|
{
|
94
|
'display_name': "Synthèse par patient",
|
95
|
'category': 'Patients',
|
96
|
'comment': """Tableaux de synthèse par patient. Si aucun patient n'est
|
97
|
indiqué, une synthèse pour chaque patient est retournée. La plage
|
98
|
de date permet de selectionner les patients pour lesquels au
|
99
|
moins au acte a été proposé durant cette période. Si un dossier a
|
100
|
été clos durant cette période mais qu'aucun acte n'a été proposé
|
101
|
durant cette période, il ne sera pas pris en compte. La date de
|
102
|
début de la plage par défaut est le 1er janvier de l'année en
|
103
|
cours. La date de fin de la plage par défaut est aujourd'hui. """
|
104
|
},
|
105
|
'patients_synthesis' :
|
106
|
{
|
107
|
'display_name': 'Synthèse sur les patients avec un acte valide sur '
|
108
|
'la plage de date',
|
109
|
'category': 'Patients',
|
110
|
'comment': """Patients ayant eu au moins un acte validé
|
111
|
sur la plage de dates spécifiée. La date de début de la plage par
|
112
|
défaut est le 1er janvier de l'année en cours. La date de fin de
|
113
|
la plage par défaut est aujourd'hui.
|
114
|
"""
|
115
|
},
|
116
|
'acts_synthesis' :
|
117
|
{
|
118
|
'display_name': 'Synthèse sur les actes',
|
119
|
'category': 'Actes',
|
120
|
'comment': """Synthèse sur les actes
|
121
|
sur la plage de dates spécifiée. La date de début de la plage par
|
122
|
défaut est le 1er janvier de l'année en cours. La date de fin de
|
123
|
la plage par défaut est aujourd'hui.
|
124
|
"""
|
125
|
},
|
126
|
'acts_synthesis_cmpp' :
|
127
|
{
|
128
|
'display_name': 'Synthèse sur les dossiers facturés au CMPP',
|
129
|
'category': 'Patients',
|
130
|
'services': ['CMPP', ],
|
131
|
'comment': """Synthèse sur les dossiers facturés au CMPP selon que ce
|
132
|
soit en diagnostic, en traitement ou les deux,
|
133
|
sur la plage de dates spécifiée. La date de début de la plage par
|
134
|
défaut est le 1er janvier de l'année en cours. La date de fin de
|
135
|
la plage par défaut est aujourd'hui.
|
136
|
"""
|
137
|
},
|
138
|
'mises' :
|
139
|
{
|
140
|
'display_name': 'Synthèse sur les pathologies MISES',
|
141
|
'category': 'Patients',
|
142
|
'comment': """Synthèse sur les pathologies
|
143
|
sur la plage de dates spécifiée. La date de début de la plage par
|
144
|
défaut est le 1er janvier de l'année en cours. La date de fin de
|
145
|
la plage par défaut est aujourd'hui.
|
146
|
"""
|
147
|
},
|
148
|
'deficiencies' :
|
149
|
{
|
150
|
'display_name': 'Synthèse sur les déficiences',
|
151
|
'category': 'Patients',
|
152
|
'comment': """Synthèse sur les déficiences
|
153
|
sur la plage de dates spécifiée. La date de début de la plage par
|
154
|
défaut est le 1er janvier de l'année en cours. La date de fin de
|
155
|
la plage par défaut est aujourd'hui.
|
156
|
"""
|
157
|
},
|
158
|
'patients_protection' :
|
159
|
{
|
160
|
'display_name': 'Synthèse sur les mesures de protection des patients '
|
161
|
'à une date donnée',
|
162
|
'category': 'Patients',
|
163
|
'comment': """La date par défaut est aujourd'hui.
|
164
|
"""
|
165
|
},
|
166
|
}
|
167
|
|
168
|
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']
|
169
|
|
170
|
ANNUAL_ACTIVITY_COLUMN_LABELS = ['Janv', 'Fév', 'Mar', 'T1', 'Avr', 'Mai', 'Jui', 'T2', 'Jui', 'Aoû', 'Sep', 'T3', 'Oct', 'Nov', 'Déc', 'T4', 'Total']
|
171
|
|
172
|
class AnnualActivityProcessingColumn():
|
173
|
total = 0
|
174
|
pointe = 0
|
175
|
non_pointe = 0
|
176
|
absent = 0
|
177
|
percent_abs = 0
|
178
|
reporte = 0
|
179
|
acts_present = 0
|
180
|
abs_non_exc = 0
|
181
|
abs_exc = 0
|
182
|
abs_inter = 0
|
183
|
annul_nous = 0
|
184
|
annul_famille = 0
|
185
|
abs_ess_pps = 0
|
186
|
enf_hosp = 0
|
187
|
non_facturables = 0
|
188
|
facturables = 0
|
189
|
perdus = 0
|
190
|
doubles = 0
|
191
|
really_facturables = 0
|
192
|
factures = 0
|
193
|
diag = 0
|
194
|
trait = 0
|
195
|
restants_a_fac = 0
|
196
|
refac = 0
|
197
|
nf = 0
|
198
|
percent_nf = 0
|
199
|
patients = 0
|
200
|
intervenants = 0
|
201
|
days = 0
|
202
|
fact_per_day = 0
|
203
|
moving_time = timedelta()
|
204
|
moving_time_per_intervene = timedelta()
|
205
|
moving_time_per_act = timedelta()
|
206
|
|
207
|
def annual_activity_month_analysis(statistic, start_day, analyses, key, i, trim_cnt, participant=None):
|
208
|
rd = relativedelta(months=1)
|
209
|
sd = start_day + i * rd
|
210
|
ed = sd + rd
|
211
|
acts = None
|
212
|
moving_events = None
|
213
|
if participant:
|
214
|
acts = Act.objects.filter(date__gte=sd.date(),
|
215
|
date__lt=ed.date(), patient__service=statistic.in_service,
|
216
|
doctors__in=[participant])
|
217
|
moving_events = Event.objects.filter(event_type__label='Temps de trajet',
|
218
|
start_datetime__gte=sd, end_datetime__lt=ed,
|
219
|
services__in=[statistic.in_service],
|
220
|
participants__in=[participant])
|
221
|
else:
|
222
|
acts = Act.objects.filter(date__gte=sd.date(),
|
223
|
date__lt=ed.date(), patient__service=statistic.in_service)
|
224
|
moving_events = Event.objects.filter(event_type__label='Temps de trajet',
|
225
|
start_datetime__gte=sd, end_datetime__lt=ed,
|
226
|
services__in=[statistic.in_service])
|
227
|
analyses[key].append(AnnualActivityProcessingColumn())
|
228
|
analyses[key][i+trim_cnt].patients = acts.aggregate(Count('patient', distinct=True))['patient__count']
|
229
|
analyses[key][i+trim_cnt].intervenants = acts.aggregate(Count('doctors', distinct=True))['doctors__count']
|
230
|
analyses[key][i+trim_cnt].days = acts.aggregate(Count('date', distinct=True))['date__count']
|
231
|
for me in moving_events:
|
232
|
analyses[key][i+trim_cnt].moving_time += me.timedelta()
|
233
|
for a in acts:
|
234
|
if a.is_new():
|
235
|
analyses[key][i+trim_cnt].non_pointe += 1
|
236
|
elif a.is_absent():
|
237
|
state = a.get_state()
|
238
|
if state.state_name == 'REPORTE':
|
239
|
analyses[key][i+trim_cnt].reporte += 1
|
240
|
else:
|
241
|
analyses[key][i+trim_cnt].absent += 1
|
242
|
if state.state_name == 'ABS_NON_EXC':
|
243
|
analyses[key][i+trim_cnt].abs_non_exc += 1
|
244
|
elif state.state_name == 'ABS_EXC':
|
245
|
analyses[key][i+trim_cnt].abs_exc += 1
|
246
|
elif state.state_name == 'ABS_INTER':
|
247
|
analyses[key][i+trim_cnt].abs_inter += 1
|
248
|
elif state.state_name == 'ANNUL_NOUS':
|
249
|
analyses[key][i+trim_cnt].annul_nous += 1
|
250
|
elif state.state_name == 'ANNUL_FAMILLE':
|
251
|
analyses[key][i+trim_cnt].annul_famille += 1
|
252
|
elif state.state_name == 'ABS_ESS_PPS':
|
253
|
analyses[key][i+trim_cnt].abs_ess_pps += 1
|
254
|
elif state.state_name == 'ENF_HOSP':
|
255
|
analyses[key][i+trim_cnt].enf_hosp += 1
|
256
|
else:
|
257
|
analyses[key][i+trim_cnt].acts_present += 1
|
258
|
if statistic.in_service.name == 'CMPP':
|
259
|
if not a.is_billable():
|
260
|
analyses[key][i+trim_cnt].non_facturables += 1
|
261
|
elif a.is_lost:
|
262
|
analyses[key][i+trim_cnt].perdus += 1
|
263
|
elif a.get_state().state_name == 'ACT_DOUBLE':
|
264
|
analyses[key][i+trim_cnt].doubles += 1
|
265
|
elif a.is_billed:
|
266
|
analyses[key][i+trim_cnt].factures += 1
|
267
|
if a.invoice_set.latest('created').first_tag[0] == 'D':
|
268
|
analyses[key][i+trim_cnt].diag += 1
|
269
|
else:
|
270
|
analyses[key][i+trim_cnt].trait += 1
|
271
|
else:
|
272
|
analyses[key][i+trim_cnt].restants_a_fac += 1
|
273
|
if a.invoice_set.all():
|
274
|
analyses[key][i+trim_cnt].refac += 1
|
275
|
|
276
|
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
|
277
|
analyses[key][i+trim_cnt].pointe = analyses[key][i+trim_cnt].total - analyses[key][i+trim_cnt].non_pointe
|
278
|
percent_abs = 100
|
279
|
if not analyses[key][i+trim_cnt].pointe or not analyses[key][i+trim_cnt].absent:
|
280
|
percent_abs = 0
|
281
|
elif analyses[key][i+trim_cnt].absent:
|
282
|
percent_abs = (analyses[key][i+trim_cnt].absent/float(analyses[key][i+trim_cnt].pointe))*100
|
283
|
analyses[key][i+trim_cnt].percent_abs = "%.2f" % percent_abs
|
284
|
|
285
|
if statistic.in_service.name == 'CMPP':
|
286
|
analyses[key][i+trim_cnt].facturables = analyses[key][i+trim_cnt].acts_present - analyses[key][i+trim_cnt].non_facturables
|
287
|
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
|
288
|
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
|
289
|
percent_nf = 100
|
290
|
if not analyses[key][i+trim_cnt].pointe or not analyses[key][i+trim_cnt].nf:
|
291
|
percent_nf = 0
|
292
|
elif analyses[key][i+trim_cnt].nf:
|
293
|
percent_nf = (analyses[key][i+trim_cnt].nf/float(analyses[key][i+trim_cnt].pointe))*100
|
294
|
analyses[key][i+trim_cnt].percent_nf = "%.2f" % percent_nf
|
295
|
if analyses[key][i+trim_cnt].days:
|
296
|
analyses[key][i+trim_cnt].fact_per_day = "%.2f" % (analyses[key][i+trim_cnt].really_facturables / float(analyses[key][i+trim_cnt].days))
|
297
|
|
298
|
if analyses[key][i+trim_cnt].moving_time and analyses[key][i+trim_cnt].intervenants:
|
299
|
analyses[key][i+trim_cnt].moving_time_per_intervene = analyses[key][i+trim_cnt].moving_time / analyses[key][i+trim_cnt].intervenants
|
300
|
if analyses[key][i+trim_cnt].moving_time and analyses[key][i+trim_cnt].acts_present:
|
301
|
analyses[key][i+trim_cnt].moving_time_per_act = analyses[key][i+trim_cnt].moving_time / analyses[key][i+trim_cnt].acts_present
|
302
|
|
303
|
|
304
|
def annual_activity_trimester_analysis(statistic, start_day, analyses, key, i, trim_cnt, participant=None):
|
305
|
analyses[key].append(AnnualActivityProcessingColumn())
|
306
|
rd = relativedelta(months=1)
|
307
|
sd = start_day + i * rd
|
308
|
start = start_day + (i-2) * rd
|
309
|
end = sd + rd
|
310
|
acts = None
|
311
|
if participant:
|
312
|
acts = Act.objects.filter(date__gte=start.date(),
|
313
|
date__lt=end.date(), patient__service=statistic.in_service,
|
314
|
doctors__in=[participant])
|
315
|
else:
|
316
|
acts = Act.objects.filter(date__gte=start.date(),
|
317
|
date__lt=end.date(), patient__service=statistic.in_service)
|
318
|
for row in ANNUAL_ACTIVITY_ROWS:
|
319
|
if row == 'percent_abs':
|
320
|
pointe = analyses[key][i+trim_cnt-1].pointe + analyses[key][i-2+trim_cnt].pointe + analyses[key][i-3+trim_cnt].pointe
|
321
|
tot_abs = analyses[key][i+trim_cnt-1].absent + analyses[key][i-2+trim_cnt].absent + analyses[key][i-3+trim_cnt].absent
|
322
|
percent_abs = 100
|
323
|
if not pointe or not tot_abs:
|
324
|
percent_abs = 0
|
325
|
elif tot_abs:
|
326
|
percent_abs = (tot_abs/float(pointe))*100
|
327
|
analyses[key][i+trim_cnt].percent_abs = "%.2f" % percent_abs
|
328
|
elif row == 'percent_nf':
|
329
|
pointe = analyses[key][i+trim_cnt-1].pointe + analyses[key][i-2+trim_cnt].pointe + analyses[key][i-3+trim_cnt].pointe
|
330
|
tot_nf = analyses[key][i+trim_cnt-1].nf + analyses[key][i-2+trim_cnt].nf + analyses[key][i-3+trim_cnt].nf
|
331
|
percent_nf = 100
|
332
|
if not pointe or not tot_nf:
|
333
|
percent_nf = 0
|
334
|
elif tot_nf:
|
335
|
percent_nf = (tot_nf/float(pointe))*100
|
336
|
analyses[key][i+trim_cnt].percent_nf = "%.2f" % percent_nf
|
337
|
elif row == 'patients':
|
338
|
analyses[key][i+trim_cnt].patients = acts.aggregate(Count('patient', distinct=True))['patient__count']
|
339
|
elif row == 'intervenants':
|
340
|
analyses[key][i+trim_cnt].intervenants = acts.aggregate(Count('doctors', distinct=True))['doctors__count']
|
341
|
elif row == 'fact_per_day':
|
342
|
if analyses[key][i+trim_cnt].days:
|
343
|
analyses[key][i+trim_cnt].fact_per_day = "%.2f" % (analyses[key][i+trim_cnt].really_facturables / float(analyses[key][i+trim_cnt].days))
|
344
|
elif row == 'moving_time_per_intervene':
|
345
|
if analyses[key][i+trim_cnt].moving_time and analyses[key][i+trim_cnt].intervenants:
|
346
|
analyses[key][i+trim_cnt].moving_time_per_intervene = analyses[key][i+trim_cnt].moving_time / analyses[key][i+trim_cnt].intervenants
|
347
|
elif row == 'moving_time_per_act':
|
348
|
if analyses[key][i+trim_cnt].moving_time and analyses[key][i+trim_cnt].acts_present:
|
349
|
analyses[key][i+trim_cnt].moving_time_per_act = analyses[key][i+trim_cnt].moving_time / analyses[key][i+trim_cnt].acts_present
|
350
|
else:
|
351
|
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))
|
352
|
|
353
|
def annual_activity_synthesis_analysis(statistic, start_day, end_day, analyses, key, participant=None):
|
354
|
analyses[key].append(AnnualActivityProcessingColumn())
|
355
|
acts = None
|
356
|
if participant:
|
357
|
acts = Act.objects.filter(date__gte=start_day.date(),
|
358
|
date__lt=end_day.date(), patient__service=statistic.in_service,
|
359
|
doctors__in=[participant])
|
360
|
else:
|
361
|
acts = Act.objects.filter(date__gte=start_day.date(),
|
362
|
date__lt=end_day.date(), patient__service=statistic.in_service)
|
363
|
for row in ANNUAL_ACTIVITY_ROWS:
|
364
|
if row == 'percent_abs':
|
365
|
tot_abs = 0
|
366
|
pointe = 0
|
367
|
for i in (3, 7, 11, 15):
|
368
|
pointe += analyses[key][i].pointe
|
369
|
tot_abs += analyses[key][i].absent
|
370
|
percent_abs = 100
|
371
|
if not pointe or not tot_abs:
|
372
|
percent_abs = 0
|
373
|
elif tot_abs:
|
374
|
percent_abs = (tot_abs/float(pointe))*100
|
375
|
analyses[key][16].percent_abs = "%.2f" % percent_abs
|
376
|
elif row == 'percent_nf':
|
377
|
tot_nf= 0
|
378
|
pointe = 0
|
379
|
for i in (3, 7, 11, 15):
|
380
|
pointe += analyses[key][i].pointe
|
381
|
tot_nf += analyses[key][i].nf
|
382
|
percent_nf = 100
|
383
|
if not pointe or not tot_nf:
|
384
|
percent_nf = 0
|
385
|
elif tot_nf:
|
386
|
percent_nf = (tot_nf/float(pointe))*100
|
387
|
analyses[key][16].percent_nf = "%.2f" % percent_nf
|
388
|
elif row == 'patients':
|
389
|
analyses[key][16].patients = acts.aggregate(Count('patient', distinct=True))['patient__count']
|
390
|
elif row == 'intervenants':
|
391
|
analyses[key][16].intervenants = acts.aggregate(Count('doctors', distinct=True))['doctors__count']
|
392
|
elif row == 'fact_per_day':
|
393
|
if analyses[key][16].days:
|
394
|
analyses[key][16].fact_per_day = "%.2f" % (analyses[key][16].really_facturables / float(analyses[key][16].days))
|
395
|
elif row == 'moving_time_per_intervene':
|
396
|
if analyses[key][16].moving_time and analyses[key][16].intervenants:
|
397
|
analyses[key][16].moving_time_per_intervene = analyses[key][16].moving_time / analyses[key][16].intervenants
|
398
|
elif row == 'moving_time_per_act':
|
399
|
if analyses[key][16].moving_time and analyses[key][16].acts_present:
|
400
|
analyses[key][16].moving_time_per_act = analyses[key][16].moving_time / analyses[key][16].acts_present
|
401
|
else:
|
402
|
val = 0
|
403
|
if row == 'moving_time':
|
404
|
val = timedelta()
|
405
|
for i in (3, 7, 11, 15):
|
406
|
val += getattr(analyses[key][i], row)
|
407
|
setattr(analyses[key][16], row, val)
|
408
|
|
409
|
def strfdelta(tdelta, fmt):
|
410
|
if not tdelta:
|
411
|
return '0'
|
412
|
d = {"days": tdelta.days}
|
413
|
d["hours"], rem = divmod(tdelta.seconds, 3600)
|
414
|
d["minutes"], d["seconds"] = divmod(rem, 60)
|
415
|
return fmt.format(**d)
|
416
|
|
417
|
def annual_activity_build_tables(statistic, analyses, key, label, data_tables):
|
418
|
table_1 = []
|
419
|
table_1_label = label + ' - général'
|
420
|
table_1.append([table_1_label] + ANNUAL_ACTIVITY_COLUMN_LABELS)
|
421
|
rows = []
|
422
|
row = ['Proposés']
|
423
|
for column in analyses[key]:
|
424
|
row.append(column.total)
|
425
|
rows.append(row)
|
426
|
row = ['Non pointés']
|
427
|
for column in analyses[key]:
|
428
|
row.append(column.non_pointe)
|
429
|
rows.append(row)
|
430
|
row = ['Absences']
|
431
|
for column in analyses[key]:
|
432
|
row.append(column.absent)
|
433
|
rows.append(row)
|
434
|
row = ['Reportés']
|
435
|
for column in analyses[key]:
|
436
|
row.append(column.reporte)
|
437
|
rows.append(row)
|
438
|
row = ['Présents']
|
439
|
for column in analyses[key]:
|
440
|
row.append(column.acts_present)
|
441
|
rows.append(row)
|
442
|
if statistic.in_service.name == 'CMPP':
|
443
|
row = ['Facturables']
|
444
|
for column in analyses[key]:
|
445
|
row.append(column.really_facturables)
|
446
|
rows.append(row)
|
447
|
row = ['Facturés']
|
448
|
for column in analyses[key]:
|
449
|
row.append(column.factures)
|
450
|
rows.append(row)
|
451
|
row = ['Diagnostics']
|
452
|
for column in analyses[key]:
|
453
|
row.append(column.diag)
|
454
|
rows.append(row)
|
455
|
row = ['Traitements']
|
456
|
for column in analyses[key]:
|
457
|
row.append(column.trait)
|
458
|
rows.append(row)
|
459
|
row = ['Restants à facturer']
|
460
|
for column in analyses[key]:
|
461
|
row.append(column.restants_a_fac)
|
462
|
rows.append(row)
|
463
|
row = ['Dont en refact.']
|
464
|
for column in analyses[key]:
|
465
|
row.append(column.refac)
|
466
|
rows.append(row)
|
467
|
row = ['Patients']
|
468
|
for column in analyses[key]:
|
469
|
row.append(column.patients)
|
470
|
rows.append(row)
|
471
|
row = ['Intervenants']
|
472
|
for column in analyses[key]:
|
473
|
row.append(column.intervenants)
|
474
|
rows.append(row)
|
475
|
row = ['Jours']
|
476
|
for column in analyses[key]:
|
477
|
row.append(column.days)
|
478
|
rows.append(row)
|
479
|
if statistic.in_service.name == 'CMPP':
|
480
|
row = ['Facturables / jour']
|
481
|
for column in analyses[key]:
|
482
|
row.append(column.fact_per_day)
|
483
|
rows.append(row)
|
484
|
row = ['Temps de déplacement']
|
485
|
for column in analyses[key]:
|
486
|
row.append(strfdelta(column.moving_time, "{hours}h {minutes}m"))
|
487
|
if column.moving_time.days:
|
488
|
row.append(strfdelta(column.moving_time, "{days}j {hours}h {minutes}m"))
|
489
|
rows.append(row)
|
490
|
row = ['Temps de déplacement par intervenant']
|
491
|
for column in analyses[key]:
|
492
|
row.append(strfdelta(column.moving_time_per_intervene, "{hours}h {minutes}m"))
|
493
|
if column.moving_time_per_intervene.days:
|
494
|
row.append(strfdelta(column.moving_time_per_intervene, "{days}j {hours}h {minutes}m"))
|
495
|
rows.append(row)
|
496
|
row = ['Temps de déplacement par acte']
|
497
|
for column in analyses[key]:
|
498
|
row.append(strfdelta(column.moving_time_per_act, "{hours}h {minutes}m"))
|
499
|
if column.moving_time_per_act.days:
|
500
|
row.append(strfdelta(column.moving_time_per_act, "{days}j {hours}h {minutes}m"))
|
501
|
rows.append(row)
|
502
|
table_1.append(rows)
|
503
|
data_tables.append(table_1)
|
504
|
|
505
|
table_2 = []
|
506
|
table_2_label = label + ' - absences'
|
507
|
table_2.append([table_2_label] + ANNUAL_ACTIVITY_COLUMN_LABELS)
|
508
|
rows = []
|
509
|
row = ['Pointés']
|
510
|
for column in analyses[key]:
|
511
|
row.append(column.pointe)
|
512
|
rows.append(row)
|
513
|
row = ['Absences']
|
514
|
for column in analyses[key]:
|
515
|
row.append(column.absent)
|
516
|
rows.append(row)
|
517
|
row = ['% absences / pointés']
|
518
|
for column in analyses[key]:
|
519
|
row.append(column.percent_abs)
|
520
|
rows.append(row)
|
521
|
row = ['Excusées']
|
522
|
for column in analyses[key]:
|
523
|
row.append(column.abs_exc)
|
524
|
rows.append(row)
|
525
|
row = ['Non excusées']
|
526
|
for column in analyses[key]:
|
527
|
row.append(column.abs_non_exc)
|
528
|
rows.append(row)
|
529
|
row = ["De l'intervenant"]
|
530
|
for column in analyses[key]:
|
531
|
row.append(column.abs_inter)
|
532
|
rows.append(row)
|
533
|
row = ["Annulés par nous"]
|
534
|
for column in analyses[key]:
|
535
|
row.append(column.annul_nous)
|
536
|
rows.append(row)
|
537
|
row = ['Annulés par la famille']
|
538
|
for column in analyses[key]:
|
539
|
row.append(column.annul_famille)
|
540
|
rows.append(row)
|
541
|
row = ['ESS PPS']
|
542
|
for column in analyses[key]:
|
543
|
row.append(column.abs_ess_pps)
|
544
|
rows.append(row)
|
545
|
row = ['Hospitalisations']
|
546
|
for column in analyses[key]:
|
547
|
row.append(column.enf_hosp)
|
548
|
rows.append(row)
|
549
|
table_2.append(rows)
|
550
|
data_tables.append(table_2)
|
551
|
|
552
|
if statistic.in_service.name == 'CMPP':
|
553
|
table_3 = []
|
554
|
table_3_label = label + ' - non fact.'
|
555
|
table_3.append([table_3_label] + ANNUAL_ACTIVITY_COLUMN_LABELS)
|
556
|
rows = []
|
557
|
row = ['Pointés']
|
558
|
for column in analyses[key]:
|
559
|
row.append(column.pointe)
|
560
|
rows.append(row)
|
561
|
row = ['Présents']
|
562
|
for column in analyses[key]:
|
563
|
row.append(column.acts_present)
|
564
|
rows.append(row)
|
565
|
row = ['De type non fact.']
|
566
|
for column in analyses[key]:
|
567
|
row.append(column.non_facturables)
|
568
|
rows.append(row)
|
569
|
row = ['De type fact.']
|
570
|
for column in analyses[key]:
|
571
|
row.append(column.facturables)
|
572
|
rows.append(row)
|
573
|
row = ['Perdus']
|
574
|
for column in analyses[key]:
|
575
|
row.append(column.perdus)
|
576
|
rows.append(row)
|
577
|
row = ['En doubles']
|
578
|
for column in analyses[key]:
|
579
|
row.append(column.doubles)
|
580
|
rows.append(row)
|
581
|
row = ['Non facturables']
|
582
|
for column in analyses[key]:
|
583
|
row.append(column.nf)
|
584
|
rows.append(row)
|
585
|
row = ['% NF / pointés']
|
586
|
for column in analyses[key]:
|
587
|
row.append(column.percent_nf)
|
588
|
rows.append(row)
|
589
|
table_3.append(rows)
|
590
|
data_tables.append(table_3)
|
591
|
|
592
|
def run_annual_activity(statistic, start_day, analyses, key, label, data_tables, participant=None):
|
593
|
analyses[key] = list()
|
594
|
trim_cnt = 0
|
595
|
for i in range(0, 12):
|
596
|
annual_activity_month_analysis(statistic, start_day, analyses, key, i, trim_cnt, participant)
|
597
|
if not (i + 1) % 3:
|
598
|
trim_cnt += 1
|
599
|
annual_activity_trimester_analysis(statistic, start_day, analyses, key, i, trim_cnt, participant)
|
600
|
end_day = datetime(start_day.year+1, 1, 1)
|
601
|
annual_activity_synthesis_analysis(statistic, start_day, end_day, analyses, key, participant)
|
602
|
annual_activity_build_tables(statistic, analyses, key, label, data_tables)
|
603
|
|
604
|
def annual_activity(statistic):
|
605
|
if not statistic.in_service:
|
606
|
return None
|
607
|
start_day = datetime(datetime.today().year, 1, 1)
|
608
|
if statistic.in_year:
|
609
|
start_day = datetime(statistic.in_year, 1, 1)
|
610
|
data_tables = list()
|
611
|
analyses = dict()
|
612
|
if not statistic.in_participants:
|
613
|
run_annual_activity(statistic, start_day, analyses, 'global', str(statistic.in_year) + ' - Tous', data_tables, participant=None)
|
614
|
else:
|
615
|
for participant in statistic.in_participants:
|
616
|
run_annual_activity(statistic, start_day, analyses, participant.id, str(statistic.in_year) + ' - ' + str(participant), data_tables, participant=participant)
|
617
|
return [data_tables]
|
618
|
|
619
|
def patients_per_worker_for_period(statistic):
|
620
|
if not statistic.in_service:
|
621
|
return None
|
622
|
data_tables = []
|
623
|
data = []
|
624
|
data.append(['Intervenants', 'Nombre', 'Patients'])
|
625
|
values = []
|
626
|
if not statistic.in_end_date:
|
627
|
statistic.in_end_date = datetime.today()
|
628
|
if not statistic.in_start_date:
|
629
|
statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
|
630
|
acts = None
|
631
|
if statistic.in_patients:
|
632
|
acts = Act.objects.filter(date__gte=statistic.in_start_date,
|
633
|
date__lte=statistic.in_end_date,
|
634
|
patient__service=statistic.in_service,
|
635
|
patient__in=statistic.in_patients)
|
636
|
else:
|
637
|
acts = Act.objects.filter(date__gte=statistic.in_start_date,
|
638
|
date__lte=statistic.in_end_date,
|
639
|
patient__service=statistic.in_service)
|
640
|
analyse = dict()
|
641
|
for act in acts:
|
642
|
for intervene in act.doctors.all():
|
643
|
if statistic.in_participants:
|
644
|
if intervene in statistic.in_participants:
|
645
|
analyse.setdefault(intervene, []).append(str(act.patient))
|
646
|
else:
|
647
|
analyse.setdefault(intervene, []).append(str(act.patient))
|
648
|
o_analyse = OrderedDict(sorted(analyse.items(), key=lambda t: t[0]))
|
649
|
for intervene, patients in o_analyse.iteritems():
|
650
|
lst = list(set(patients))
|
651
|
values.append([str(intervene), len(lst), lst])
|
652
|
data.append(values)
|
653
|
data_tables.append(data)
|
654
|
return [data_tables]
|
655
|
|
656
|
def active_patients_by_state_only(statistic):
|
657
|
if not statistic.in_service:
|
658
|
return None
|
659
|
if not statistic.in_start_date:
|
660
|
statistic.in_start_date = datetime.today()
|
661
|
active_states = None
|
662
|
if statistic.in_service.name == 'CMPP':
|
663
|
active_states = ('TRAITEMENT', 'DIAGNOSTIC')
|
664
|
elif statistic.in_service.name == 'CAMSP':
|
665
|
active_states = ('SUIVI', )
|
666
|
else:
|
667
|
active_states = ('TRAITEMENT', )
|
668
|
patients = [(p.last_name, p.first_name, p.paper_id) \
|
669
|
for p in PatientRecord.objects.filter(service=statistic.in_service) \
|
670
|
if p.get_state_at_day(
|
671
|
statistic.in_start_date).status.type in active_states]
|
672
|
data_tables_set=[[[['En date du :', formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"), len(patients)]]]]
|
673
|
data = []
|
674
|
data.append(['Nom', 'Prénom', 'N° Dossier'])
|
675
|
p_list = []
|
676
|
for ln, fn, pid in patients:
|
677
|
ln = ln or ''
|
678
|
if len(ln) > 1:
|
679
|
ln = ln[0].upper() + ln[1:].lower()
|
680
|
fn = fn or ''
|
681
|
if len(fn) > 1:
|
682
|
fn = fn[0].upper() + fn[1:].lower()
|
683
|
p_list.append((ln, fn, str(pid or '')))
|
684
|
data.append(sorted(p_list,
|
685
|
key=lambda k: k[0]+k[1]))
|
686
|
data_tables_set[0].append(data)
|
687
|
return data_tables_set
|
688
|
|
689
|
def patients_protection(statistic):
|
690
|
if not statistic.in_service:
|
691
|
return None
|
692
|
if not statistic.in_start_date:
|
693
|
statistic.in_start_date = datetime.today()
|
694
|
patients = PatientRecord.objects.filter(protectionstate__isnull=False).distinct()
|
695
|
protection_states = [p.get_protection_state_at_date(
|
696
|
statistic.in_start_date) for p in patients
|
697
|
if p.get_protection_state_at_date(statistic.in_start_date)]
|
698
|
analyse = {}
|
699
|
for state in protection_states:
|
700
|
analyse.setdefault(state.status.name, 0)
|
701
|
analyse[state.status.name] += 1
|
702
|
data_tables_set=[[[['En date du :', formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"), len(protection_states)]]]]
|
703
|
data = []
|
704
|
data.append(['Mesure de protection', 'Nombre de dossiers'])
|
705
|
data.append(analyse.items())
|
706
|
data_tables_set[0].append(data)
|
707
|
return data_tables_set
|
708
|
|
709
|
def active_patients_with_act(statistic):
|
710
|
def process(patients_list, title):
|
711
|
data_tables = []
|
712
|
data = []
|
713
|
data.append([title, len(patients_list), '', ''])
|
714
|
data_tables.append(data)
|
715
|
data = []
|
716
|
data.append(['Nom', 'Prénom', 'N° Dossier'])
|
717
|
patients_values = patients_list.\
|
718
|
values_list('last_name', 'first_name', 'paper_id')
|
719
|
p_list = []
|
720
|
for ln, fn, pid in patients_values:
|
721
|
ln = ln or ''
|
722
|
if len(ln) > 1:
|
723
|
ln = ln[0].upper() + ln[1:].lower()
|
724
|
fn = fn or ''
|
725
|
if len(fn) > 1:
|
726
|
fn = fn[0].upper() + fn[1:].lower()
|
727
|
p_list.append((ln, fn, str(pid or '')))
|
728
|
data.append(sorted(p_list,
|
729
|
key=lambda k: k[0]+k[1]))
|
730
|
data_tables.append(data)
|
731
|
return data_tables
|
732
|
if not statistic.in_service:
|
733
|
return None
|
734
|
if not statistic.in_end_date:
|
735
|
statistic.in_end_date = datetime.today()
|
736
|
if not statistic.in_start_date:
|
737
|
statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
|
738
|
active_states = None
|
739
|
if statistic.in_service.name == 'CMPP':
|
740
|
active_states = ('TRAITEMENT', 'DIAGNOSTIC')
|
741
|
elif statistic.in_service.name == 'CAMSP':
|
742
|
active_states = ('SUIVI', )
|
743
|
else:
|
744
|
active_states = ('TRAITEMENT', )
|
745
|
|
746
|
data_tables_set = []
|
747
|
data_tables = []
|
748
|
data = []
|
749
|
data.append(['Période', 'Jours'])
|
750
|
data.append([("%s - %s"
|
751
|
% (formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
|
752
|
formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT")),
|
753
|
(statistic.in_end_date-statistic.in_start_date).days+1)])
|
754
|
data_tables.append(data)
|
755
|
data_tables_set.append(data_tables)
|
756
|
|
757
|
acts_base = Act.objects.filter(
|
758
|
date__gte=statistic.in_start_date,
|
759
|
date__lte=statistic.in_end_date,
|
760
|
patient__service=statistic.in_service)
|
761
|
acts_valide = acts_base.filter(valide=True)
|
762
|
acts_valide_patients_ids = acts_valide.order_by('patient').\
|
763
|
distinct('patient').values_list('patient')
|
764
|
acts_valide_patients = PatientRecord.objects.filter(
|
765
|
id__in=[patient[0] for patient in acts_valide_patients_ids])
|
766
|
all_patients_ids = acts_base.order_by('patient').distinct('patient').\
|
767
|
values_list('patient')
|
768
|
acts_not_valide_patients = PatientRecord.objects.filter(
|
769
|
id__in=[patient[0] for patient in all_patients_ids
|
770
|
if not patient in acts_valide_patients_ids])
|
771
|
|
772
|
|
773
|
patients_1 = acts_valide_patients.filter(
|
774
|
last_state__status__type__in=active_states)
|
775
|
patients_2 = acts_valide_patients.exclude(
|
776
|
last_state__status__type__in=active_states)
|
777
|
patients_3 = acts_not_valide_patients.filter(
|
778
|
last_state__status__type__in=active_states)
|
779
|
patients_4 = acts_not_valide_patients.exclude(
|
780
|
last_state__status__type__in=active_states)
|
781
|
|
782
|
data_tables_set.append(process(patients_1, 'Patients avec un acte validé et dans un état actif'))
|
783
|
data_tables_set.append(process(patients_2, 'Patients avec un acte validé et dans un état non actif'))
|
784
|
data_tables_set.append(process(patients_3, 'Patients sans acte validé et dans un état actif'))
|
785
|
data_tables_set.append(process(patients_4, 'Patients sans acte validé et dans un état non actif'))
|
786
|
|
787
|
return data_tables_set
|
788
|
|
789
|
def closed_files(statistic):
|
790
|
if not statistic.in_service:
|
791
|
return None
|
792
|
data_tables = []
|
793
|
data1 = []
|
794
|
data1.append(['Période', 'Jours',
|
795
|
'Nombre de dossiers clos durant la période', 'PEC totale', 'PEC moyenne', "Dossiers qui ne sont plus clos"])
|
796
|
data2 = []
|
797
|
data2.append(['Nom', 'Prénom', 'N° Dossier', 'Date de clôture', 'Durée de la PEC', "N'est plus clos"])
|
798
|
if not statistic.in_end_date:
|
799
|
statistic.in_end_date = datetime.today()
|
800
|
if not statistic.in_start_date:
|
801
|
statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
|
802
|
closed_records = FileState.objects.filter(status__type='CLOS',
|
803
|
date_selected__gte=statistic.in_start_date,
|
804
|
date_selected__lte=statistic.in_end_date). \
|
805
|
order_by('patient').distinct('patient').\
|
806
|
values_list('patient')
|
807
|
closed_records = PatientRecord.objects.filter(service=statistic.in_service, id__in=[patient[0]
|
808
|
for patient in closed_records])
|
809
|
total_pec = 0
|
810
|
p_list = []
|
811
|
not_closed_now = 0
|
812
|
for record in closed_records:
|
813
|
ln = record.last_name or ''
|
814
|
if len(ln) > 1:
|
815
|
ln = ln[0].upper() + ln[1:].lower()
|
816
|
fn = record.first_name or ''
|
817
|
if len(fn) > 1:
|
818
|
fn = fn[0].upper() + fn[1:].lower()
|
819
|
current_state = ''
|
820
|
close_date = record.last_state.date_selected.date()
|
821
|
if record.get_current_state().status.type != 'CLOS':
|
822
|
not_closed_now += 1
|
823
|
current_state = record.get_current_state().status.name + \
|
824
|
' le ' + formats.date_format(record.get_current_state(). \
|
825
|
date_selected, "SHORT_DATE_FORMAT")
|
826
|
close_date = FileState.objects.filter(status__type='CLOS',
|
827
|
patient=record).order_by('-date_selected')[0].date_selected.date()
|
828
|
p_list.append((ln, fn, str(record.paper_id or ''),
|
829
|
close_date,
|
830
|
record.care_duration_since_last_contact_or_first_act,
|
831
|
current_state))
|
832
|
total_pec += record.care_duration_since_last_contact_or_first_act
|
833
|
data2.append(sorted(p_list,
|
834
|
key=lambda k: k[0]+k[1]))
|
835
|
avg_pec = 0
|
836
|
if closed_records.count() and total_pec:
|
837
|
avg_pec = total_pec/closed_records.count()
|
838
|
data1.append([("%s - %s"
|
839
|
% (formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
|
840
|
formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT")),
|
841
|
(statistic.in_end_date-statistic.in_start_date).days+1,
|
842
|
closed_records.count(), total_pec, avg_pec, not_closed_now)])
|
843
|
data_tables.append(data1)
|
844
|
data_tables.append(data2)
|
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
|
TS = ('TRAITEMENT', 'DIAGNOSTIC', 'SUIVI')
|
1009
|
inscriptions = []
|
1010
|
for patient in patients:
|
1011
|
# Select patient if she has been in treament between the selected dates
|
1012
|
traitement_states_tmp = FileState.objects.filter(patient=patient, status__type__in=TS, date_selected__lte=statistic.in_end_date).order_by('date_selected')
|
1013
|
traitement_states = []
|
1014
|
for ts in traitement_states_tmp:
|
1015
|
if not ts.get_next_state() or ts.get_next_state().date_selected >= statistic.in_start_date:
|
1016
|
traitement_states.append(ts)
|
1017
|
|
1018
|
# Patient has been in treatment
|
1019
|
# We look for all the treament periods during the selected dates
|
1020
|
# A treament period ends if during the period the file has left treament state
|
1021
|
openings = []
|
1022
|
opening = []
|
1023
|
start = False
|
1024
|
for ts in traitement_states:
|
1025
|
if start:
|
1026
|
openings.append(opening)
|
1027
|
opening = []
|
1028
|
start = False
|
1029
|
if ts.get_next_state() and not ts.get_next_state().status.type in TS and ts.get_next_state().get_next_state() and ts.get_next_state().get_next_state().status.type in TS:
|
1030
|
start = True
|
1031
|
opening.append(ts)
|
1032
|
openings.append(opening)
|
1033
|
|
1034
|
# The first treatment state is the first one of each period matching the dates selected.
|
1035
|
# But there could be other treatment state before, like diag before treatment.
|
1036
|
# so We have to look for the very first treament state to look at the first act after
|
1037
|
first_tss = []
|
1038
|
for opening in openings:
|
1039
|
if len(opening) >= 1:
|
1040
|
first_ts = opening[0]
|
1041
|
while first_ts.previous_state and first_ts.previous_state.status.type in TS:
|
1042
|
first_ts = first_ts.previous_state
|
1043
|
contact = None
|
1044
|
if first_ts.previous_state and first_ts.previous_state.status.type=='ACCUEIL':
|
1045
|
contact = first_ts.previous_state.date_selected.date()
|
1046
|
first_tss.append((contact, first_ts))
|
1047
|
|
1048
|
# We look to the first act after the datebeginning
|
1049
|
for contact, first_ts in first_tss:
|
1050
|
acts_tmp = Act.objects.filter(valide=True,
|
1051
|
date__gte=first_ts.date_selected,
|
1052
|
patient=patient).order_by('date')
|
1053
|
if acts_tmp and acts_tmp[0].date >= statistic.in_start_date.date() and acts_tmp[0].date <= statistic.in_end_date.date():
|
1054
|
waiting_duration = 0
|
1055
|
if contact:
|
1056
|
waiting_duration = (acts_tmp[0].date - contact).days
|
1057
|
inscriptions.append((patient, contact, first_ts.date_selected.date(), acts_tmp[0].date, waiting_duration))
|
1058
|
|
1059
|
if statistic.inscriptions:
|
1060
|
patients = PatientRecord.objects.filter(id__in=[p.id for p, _, _, _, _ in inscriptions])
|
1061
|
acts = acts.filter(patient__in=patients)
|
1062
|
|
1063
|
nb_patients = patients.count()
|
1064
|
|
1065
|
data.append([("%s - %s"
|
1066
|
% (formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
|
1067
|
formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT")),
|
1068
|
(statistic.in_end_date-statistic.in_start_date).days+1,
|
1069
|
nb_patients, acts.count())])
|
1070
|
data_tables.append(data)
|
1071
|
data = []
|
1072
|
data.append(['Féminin', 'Masculin'])
|
1073
|
data.append([(patients.filter(gender='2').count(),
|
1074
|
patients.filter(gender='1').count())])
|
1075
|
data_tables.append(data)
|
1076
|
data = []
|
1077
|
data.append(['Durée totale de la PEC',
|
1078
|
'Durée moyenne de la PEC par patient'])
|
1079
|
pec_total = sum([p.care_duration_since_last_contact_or_first_act for p in patients])
|
1080
|
data.append([(pec_total, pec_total/nb_patients)])
|
1081
|
data_tables.append(data)
|
1082
|
|
1083
|
data = []
|
1084
|
data.append(["Etat du dossier à ce jour (%s)" % formats.date_format(datetime.today(), "SHORT_DATE_FORMAT"), 'Nombre de patients'])
|
1085
|
states = dict()
|
1086
|
for patient in patients:
|
1087
|
states.setdefault(patient.get_current_state().status, []).append(patient)
|
1088
|
values = []
|
1089
|
for state, ps in states.iteritems():
|
1090
|
values.append((state.name, len(ps)))
|
1091
|
data.append(values)
|
1092
|
data_tables.append(data)
|
1093
|
|
1094
|
data = []
|
1095
|
data.append(["Etat du dossier en date de fin (%s)" % formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT"), 'Nombre de patients'])
|
1096
|
states = dict()
|
1097
|
for patient in patients:
|
1098
|
states.setdefault(patient.get_state_at_day(statistic.in_end_date).status, []).append(patient)
|
1099
|
values = []
|
1100
|
for state, ps in states.iteritems():
|
1101
|
values.append((state.name, len(ps)))
|
1102
|
data.append(values)
|
1103
|
data_tables.append(data)
|
1104
|
|
1105
|
data = []
|
1106
|
data.append(["Inscriptions (premier acte suivant le début d'une phase de traitement dans la période)", "Durée moyenne de l'attente"])
|
1107
|
data.append([(len(inscriptions), sum([wd for _, _, _, _, wd in inscriptions])/len(inscriptions) if len(inscriptions) else 0)])
|
1108
|
data_tables.append(data)
|
1109
|
|
1110
|
if inscriptions:
|
1111
|
data = []
|
1112
|
data.append(['Nom', 'Prénom', "Numéro papier", "Date premier acte", "Date passage en traitement", "Date de contact", "Attente"])
|
1113
|
values = []
|
1114
|
for patient, contact, first_ts, first_act, waiting_duration in sorted(inscriptions, key=lambda p: (p[0].last_name, p[0].first_name)):
|
1115
|
values.append((patient.last_name, patient.first_name, patient.paper_id, first_act, first_ts, contact, waiting_duration))
|
1116
|
data.append(values)
|
1117
|
data_tables.append(data)
|
1118
|
|
1119
|
closed_records = FileState.objects.filter(status__type='CLOS',
|
1120
|
date_selected__gte=statistic.in_start_date,
|
1121
|
date_selected__lte=statistic.in_end_date, patient__in=patients). \
|
1122
|
order_by('patient').distinct('patient').\
|
1123
|
values_list('patient')
|
1124
|
closed_records = PatientRecord.objects.filter(service=statistic.in_service, id__in=[patient[0]
|
1125
|
for patient in closed_records])
|
1126
|
total_pec = 0
|
1127
|
not_closed_now = 0
|
1128
|
for record in closed_records:
|
1129
|
if record.get_current_state().status.type != 'CLOS':
|
1130
|
not_closed_now += 1
|
1131
|
total_pec += record.care_duration_since_last_contact_or_first_act
|
1132
|
avg_pec = 0
|
1133
|
if closed_records.count() and total_pec:
|
1134
|
avg_pec = total_pec/closed_records.count()
|
1135
|
if closed_records.count():
|
1136
|
data = []
|
1137
|
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"])
|
1138
|
data.append([(closed_records.count(), total_pec, avg_pec, not_closed_now)])
|
1139
|
data_tables.append(data)
|
1140
|
|
1141
|
mdph_requests = 0
|
1142
|
mdph_requests_before = 0
|
1143
|
for patient in patients:
|
1144
|
if patient.mdph_requests.exists():
|
1145
|
mdph_requests += 1
|
1146
|
# We only look to the last one
|
1147
|
if patient.mdph_requests.order_by('-start_date')[0].start_date < statistic.in_start_date.date():
|
1148
|
mdph_requests_before +=1
|
1149
|
data = []
|
1150
|
data.append(['Dossier avec une demande MDPH', "Dont la dernière demande a été faite avant la période"])
|
1151
|
data.append([(mdph_requests, mdph_requests_before)])
|
1152
|
data_tables.append(data)
|
1153
|
|
1154
|
birth_years = dict()
|
1155
|
patients_without_birthyear = []
|
1156
|
for patient in patients:
|
1157
|
try:
|
1158
|
birth_years.setdefault(patient.birthdate.year, []).append(patient)
|
1159
|
except:
|
1160
|
patients_without_birthyear.append(patient)
|
1161
|
data = []
|
1162
|
data.append(['Année de naissance', "Nombre de dossiers", "%"])
|
1163
|
values = []
|
1164
|
for birth_year, pts in birth_years.iteritems():
|
1165
|
values.append((birth_year, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
|
1166
|
values.append(('Non renseignée', len(patients_without_birthyear), "%.2f" % (len(patients_without_birthyear) / float(len(patients)) * 100)))
|
1167
|
data.append(values)
|
1168
|
data_tables.append(data)
|
1169
|
|
1170
|
if patients_without_birthyear:
|
1171
|
data = []
|
1172
|
data.append(["Patients sans date de naissance"])
|
1173
|
values = [[patients_without_birthyear]]
|
1174
|
data.append(values)
|
1175
|
data_tables.append(data)
|
1176
|
|
1177
|
|
1178
|
lower_bounds = [0, 3, 5, 7, 11, 16, 20, 25, 30, 35, 40, 45, 50, 55, 60, 75, 85, 96]
|
1179
|
anap_code = 198
|
1180
|
data = []
|
1181
|
data.append(["Code ANAP", "Tranche d'âge (au %s)" \
|
1182
|
% formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT"),
|
1183
|
"Nombre de dossiers", "%"])
|
1184
|
values = []
|
1185
|
for i in range(len(lower_bounds)):
|
1186
|
lower_bound = lower_bounds[i]
|
1187
|
if i == len(lower_bounds) - 1:
|
1188
|
values.append([anap_code, "De %d ans et plus" % lower_bound, 0, None])
|
1189
|
else:
|
1190
|
values.append([anap_code, "De %d à %d ans" % (lower_bound, lower_bounds[i + 1] - 1), 0, None])
|
1191
|
anap_code += 1
|
1192
|
unknown = 0
|
1193
|
for patient in patients:
|
1194
|
try:
|
1195
|
age = statistic.in_end_date.date() - patient.birthdate
|
1196
|
age = age.days / 365
|
1197
|
i = 0
|
1198
|
while age >= lower_bounds[i+1]:
|
1199
|
i += 1
|
1200
|
if i == len(lower_bounds) - 1:
|
1201
|
break
|
1202
|
values[i][2] += 1
|
1203
|
except:
|
1204
|
unknown += 1
|
1205
|
for value in values:
|
1206
|
value[3] = "%.2f" % (value[2] / float(len(patients)) * 100)
|
1207
|
values.append(['', "Non renseignée", unknown, "%.2f" % (unknown / float(len(patients)) * 100)])
|
1208
|
data.append(values)
|
1209
|
data_tables.append(data)
|
1210
|
|
1211
|
jobs = dict()
|
1212
|
no_job = 0
|
1213
|
for patient in patients:
|
1214
|
job = False
|
1215
|
if patient.job_mother:
|
1216
|
jobs.setdefault(patient.job_mother, []).append(patient)
|
1217
|
job = True
|
1218
|
else:
|
1219
|
for contact in patient.contacts.all():
|
1220
|
if contact.parente and contact.parente.name == 'Mère':
|
1221
|
if contact.job:
|
1222
|
jobs.setdefault(contact.job, []).append(patient)
|
1223
|
job = True
|
1224
|
break
|
1225
|
if not job:
|
1226
|
no_job += 1
|
1227
|
data = []
|
1228
|
data.append(["Profession de la mère", "Nombre de dossiers", "%"])
|
1229
|
values = []
|
1230
|
for job, pts in jobs.iteritems():
|
1231
|
values.append((job, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
|
1232
|
values.append(("Non renseignée", no_job, "%.2f" % (no_job / float(len(patients)) * 100)))
|
1233
|
data.append(values)
|
1234
|
data_tables.append(data)
|
1235
|
|
1236
|
jobs = dict()
|
1237
|
no_job = 0
|
1238
|
for patient in patients:
|
1239
|
job = False
|
1240
|
if patient.job_father:
|
1241
|
jobs.setdefault(patient.job_father, []).append(patient)
|
1242
|
job = True
|
1243
|
else:
|
1244
|
for contact in patient.contacts.all():
|
1245
|
if contact.parente and contact.parente.name == 'Père':
|
1246
|
if contact.job:
|
1247
|
jobs.setdefault(contact.job, []).append(patient)
|
1248
|
job = True
|
1249
|
break
|
1250
|
if not job:
|
1251
|
no_job += 1
|
1252
|
data = []
|
1253
|
data.append(["Profession du père", "Nombre de dossiers", "%"])
|
1254
|
values = []
|
1255
|
for job, pts in jobs.iteritems():
|
1256
|
values.append((job, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
|
1257
|
values.append(("Non renseignée", no_job, "%.2f" % (no_job / float(len(patients)) * 100)))
|
1258
|
data.append(values)
|
1259
|
data_tables.append(data)
|
1260
|
|
1261
|
provenances = dict()
|
1262
|
unknown = 0
|
1263
|
for patient in patients:
|
1264
|
if patient.provenance:
|
1265
|
provenances.setdefault(patient.provenance, []).append(patient)
|
1266
|
else:
|
1267
|
unknown += 1
|
1268
|
data = []
|
1269
|
data.append(["Provenances", "Nombre de dossiers", "%"])
|
1270
|
values = []
|
1271
|
for provenance, pts in provenances.iteritems():
|
1272
|
values.append((provenance, len(pts), "%.2f" % (len(pts) / float(len(patients)) * 100)))
|
1273
|
values.append(('Non renseignée', unknown, "%.2f" % (unknown / float(len(patients)) * 100)))
|
1274
|
data.append(values)
|
1275
|
data_tables.append(data)
|
1276
|
|
1277
|
outmotives = dict()
|
1278
|
unknown = 0
|
1279
|
for patient in patients:
|
1280
|
if patient.outmotive:
|
1281
|
outmotives.setdefault(patient.outmotive, []).append(patient)
|
1282
|
else:
|
1283
|
unknown += 1
|
1284
|
data = []
|
1285
|
data.append(["Motifs de sortie", "Nombre de dossiers", "%"])
|
1286
|
values = []
|
1287
|
for outmotive, pts in outmotives.iteritems():
|
1288
|
values.append((outmotive, len(pts)))
|
1289
|
values.append(('Non renseigné', unknown, "%.2f" % (unknown / float(len(patients)) * 100)))
|
1290
|
data.append(values)
|
1291
|
data_tables.append(data)
|
1292
|
|
1293
|
outtos = dict()
|
1294
|
unknown = 0
|
1295
|
for patient in patients:
|
1296
|
if patient.outto:
|
1297
|
outtos.setdefault(patient.outto, []).append(patient)
|
1298
|
else:
|
1299
|
unknown += 1
|
1300
|
data = []
|
1301
|
data.append(["Orientations", "Nombre de dossiers", "%"])
|
1302
|
values = []
|
1303
|
for outto, pts in outtos.iteritems():
|
1304
|
values.append((outto, len(pts)))
|
1305
|
values.append(('Non renseigné', unknown, "%.2f" % (unknown / float(len(patients)) * 100)))
|
1306
|
data.append(values)
|
1307
|
data_tables.append(data)
|
1308
|
|
1309
|
provenance_places = dict()
|
1310
|
unknown = 0
|
1311
|
for patient in patients:
|
1312
|
if patient.provenanceplace:
|
1313
|
provenance_places.setdefault(patient.provenanceplace, []).append(patient)
|
1314
|
else:
|
1315
|
unknown += 1
|
1316
|
data = []
|
1317
|
data.append(["Lieux de provenance", "Nombre de dossiers", "%"])
|
1318
|
values = []
|
1319
|
for provenance_place, pts in provenance_places.iteritems():
|
1320
|
values.append((provenance_place, len(pts)))
|
1321
|
values.append(('Non renseigné', unknown, "%.2f" % (unknown / float(len(patients)) * 100)))
|
1322
|
data.append(values)
|
1323
|
data_tables.append(data)
|
1324
|
|
1325
|
return [data_tables]
|
1326
|
|
1327
|
def acts_synthesis(statistic):
|
1328
|
if not statistic.in_service:
|
1329
|
return None
|
1330
|
if not statistic.in_end_date:
|
1331
|
statistic.in_end_date = datetime.today()
|
1332
|
if not statistic.in_start_date:
|
1333
|
statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
|
1334
|
data_tables_set = []
|
1335
|
data_tables = []
|
1336
|
data = []
|
1337
|
data.append(['Période', 'Jours',
|
1338
|
"Nombre d'actes proposés sur la période",
|
1339
|
"Dossiers concernés",
|
1340
|
"Nombre d'actes réalisés sur la période",
|
1341
|
"Dossiers concernés"])
|
1342
|
acts = Act.objects.filter(date__gte=statistic.in_start_date,
|
1343
|
date__lte=statistic.in_end_date,
|
1344
|
patient__service=statistic.in_service)
|
1345
|
len_patients = len(set([a.patient.id for a in acts]))
|
1346
|
acts_present = [a for a in acts if a.is_present()]
|
1347
|
len_patients_present = len(set([a.patient.id for a in acts_present]))
|
1348
|
len_acts_present = len(acts_present)
|
1349
|
data.append([("%s - %s"
|
1350
|
% (formats.date_format(statistic.in_start_date, "SHORT_DATE_FORMAT"),
|
1351
|
formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT")),
|
1352
|
(statistic.in_end_date-statistic.in_start_date).days+1,
|
1353
|
acts.count(), len_patients, len_acts_present, len_patients_present)])
|
1354
|
data_tables.append(data)
|
1355
|
data_tables_set.append(data_tables)
|
1356
|
|
1357
|
data_tables=[]
|
1358
|
acts_types = dict()
|
1359
|
for act in acts:
|
1360
|
acts_types.setdefault(act.act_type, []).append(act)
|
1361
|
data = []
|
1362
|
data.append(["Types des actes", "Nombre d'actes proposés", "Nombre de dossiers", "Nombre d'actes réalisés", "Nombre de dossiers"])
|
1363
|
values = []
|
1364
|
for act_type, acts in acts_types.iteritems():
|
1365
|
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()]))))
|
1366
|
data.append(values)
|
1367
|
data_tables.append(data)
|
1368
|
data_tables_set.append(data_tables)
|
1369
|
|
1370
|
data_tables=[]
|
1371
|
acts_count_participants = dict()
|
1372
|
for act in acts_present:
|
1373
|
acts_count_participants.setdefault(act.doctors.count(), []).append(act)
|
1374
|
data = []
|
1375
|
data.append(["Nombre d'intervenants des actes réalisés", "Nombre d'actes", "Nombre de dossiers concernés"])
|
1376
|
values = []
|
1377
|
for number, acts_counted in acts_count_participants.iteritems():
|
1378
|
values.append((number, len(acts_counted), len(set([a.patient.id for a in acts_counted]))))
|
1379
|
data.append(values)
|
1380
|
data_tables.append(data)
|
1381
|
data_tables_set.append(data_tables)
|
1382
|
|
1383
|
for act_type, acts in acts_types.iteritems():
|
1384
|
data_tables=[]
|
1385
|
analysis = {'Non pointés': 0,
|
1386
|
'Reportés': 0, 'Absents': 0, 'Présents': 0}
|
1387
|
for a in acts:
|
1388
|
if a.is_new():
|
1389
|
analysis['Non pointés'] += 1
|
1390
|
elif a.is_absent():
|
1391
|
state = a.get_state()
|
1392
|
if state.state_name == 'REPORTE':
|
1393
|
analysis['Reportés'] += 1
|
1394
|
else:
|
1395
|
analysis['Absents'] += 1
|
1396
|
else:
|
1397
|
analysis['Présents'] += 1
|
1398
|
data = []
|
1399
|
data.append(["Type d'acte", act_type])
|
1400
|
values = []
|
1401
|
for status, number in analysis.iteritems():
|
1402
|
values.append((status, number))
|
1403
|
data.append(values)
|
1404
|
data_tables.append(data)
|
1405
|
acts_type_patients = {}
|
1406
|
for act in acts:
|
1407
|
acts_type_patients.setdefault(act.patient, []).append(act)
|
1408
|
data = []
|
1409
|
data.append(["Patient", "Actes proposés", "Actes réalisés"])
|
1410
|
values = []
|
1411
|
for patient, acts_type in acts_type_patients.iteritems():
|
1412
|
values.append((patient, len(acts_type), len([a for a in acts_type if a.is_present()])))
|
1413
|
data.append(values)
|
1414
|
data_tables.append(data)
|
1415
|
data_tables_set.append(data_tables)
|
1416
|
|
1417
|
return data_tables_set
|
1418
|
|
1419
|
def acts_synthesis_cmpp(statistic):
|
1420
|
data_tables_set = []
|
1421
|
if not statistic.in_service:
|
1422
|
return None
|
1423
|
if not statistic.in_end_date:
|
1424
|
statistic.in_end_date = datetime.today()
|
1425
|
if not statistic.in_start_date:
|
1426
|
statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
|
1427
|
acts = Act.objects.filter(date__gte=statistic.in_start_date,
|
1428
|
date__lte=statistic.in_end_date,
|
1429
|
patient__service=statistic.in_service)
|
1430
|
acts_billed = acts.filter(is_billed=True)
|
1431
|
patients_billed = dict()
|
1432
|
for act in acts_billed:
|
1433
|
patients_billed.setdefault(act.patient, [False, False])
|
1434
|
if act.get_hc_tag() and act.get_hc_tag()[0] == 'D':
|
1435
|
patients_billed[act.patient][0] = True
|
1436
|
elif act.get_hc_tag() and act.get_hc_tag()[0] == 'T':
|
1437
|
patients_billed[act.patient][1] = True
|
1438
|
values1, values2, values3 = [], [], []
|
1439
|
for patient, vals in patients_billed.iteritems():
|
1440
|
pfields = [patient.last_name, patient.first_name, patient.paper_id]
|
1441
|
if vals == [True, False]:
|
1442
|
values1.append(pfields)
|
1443
|
elif vals == [False, True]:
|
1444
|
values2.append(pfields)
|
1445
|
elif vals == [True, True]:
|
1446
|
values3.append(pfields)
|
1447
|
cols = ['Nom', 'Prénom', 'Numéro de dossier']
|
1448
|
data_tables_set.append([[['Seulement facturé en diagnostic'], [[len(values1)]]], [cols, sorted(values1, key=lambda t: t[0])]])
|
1449
|
data_tables_set.append([[['Seulement facturé en traitement'], [[len(values2)]]], [cols, sorted(values2, key=lambda t: t[0])]])
|
1450
|
data_tables_set.append([[['Facturé en diagnostic et en traitement'], [[len(values3)]]], [cols, sorted(values3, key=lambda t: t[0])]])
|
1451
|
return data_tables_set
|
1452
|
|
1453
|
def mises(statistic):
|
1454
|
if not statistic.in_service:
|
1455
|
return None
|
1456
|
if not statistic.in_end_date:
|
1457
|
statistic.in_end_date = datetime.today()
|
1458
|
if not statistic.in_start_date:
|
1459
|
statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
|
1460
|
acts = Act.objects.filter(valide='True',
|
1461
|
date__gte=statistic.in_start_date,
|
1462
|
date__lte=statistic.in_end_date,
|
1463
|
patient__service=statistic.in_service)
|
1464
|
patients = acts.order_by('patient').distinct('patient').\
|
1465
|
values_list('patient')
|
1466
|
patients = PatientRecord.objects.filter(id__in=[patient[0]
|
1467
|
for patient in patients])
|
1468
|
pathologies = dict()
|
1469
|
for patient in patients:
|
1470
|
for pathology in patient.mises_1.all():
|
1471
|
pathologies.setdefault(pathology, 0)
|
1472
|
pathologies[pathology] += 1
|
1473
|
for pathology in patient.mises_2.all():
|
1474
|
pathologies.setdefault(pathology, 0)
|
1475
|
pathologies[pathology] += 1
|
1476
|
for pathology in patient.mises_3.all():
|
1477
|
pathologies.setdefault(pathology, 0)
|
1478
|
pathologies[pathology] += 1
|
1479
|
data = [['Pathologies MISES', 'Nombre de patients concernés']]
|
1480
|
data.append(OrderedDict(sorted(pathologies.items(), key=lambda t: t[0].ordering_code)).items())
|
1481
|
return [[data]]
|
1482
|
|
1483
|
def deficiencies(statistic):
|
1484
|
if not statistic.in_service:
|
1485
|
return None
|
1486
|
if not statistic.in_end_date:
|
1487
|
statistic.in_end_date = datetime.today()
|
1488
|
if not statistic.in_start_date:
|
1489
|
statistic.in_start_date = datetime(statistic.in_end_date.year, 1, 1)
|
1490
|
acts = Act.objects.filter(valide='True',
|
1491
|
date__gte=statistic.in_start_date,
|
1492
|
date__lte=statistic.in_end_date,
|
1493
|
patient__service=statistic.in_service)
|
1494
|
patients = acts.order_by('patient').distinct('patient').\
|
1495
|
values_list('patient')
|
1496
|
patients = PatientRecord.objects.filter(id__in=[patient[0]
|
1497
|
for patient in patients])
|
1498
|
deficiencies_three = ('deficiency_intellectual',
|
1499
|
'deficiency_autism_and_other_ted',
|
1500
|
'deficiency_mental_disorder', 'deficiency_learning_disorder',
|
1501
|
'deficiency_auditory', 'deficiency_visual', 'deficiency_motor',
|
1502
|
'deficiency_metabolic_disorder', 'deficiency_brain_damage',
|
1503
|
'deficiency_behavioral_disorder', 'deficiency_other_disorder')
|
1504
|
data = [['Déficiences', 'Nombre de patients concernés'], []]
|
1505
|
for deficiency in deficiencies_three:
|
1506
|
name = PatientRecord._meta.get_field_by_name(deficiency)[0].verbose_name
|
1507
|
filter_dict = {deficiency: 1}
|
1508
|
data[1].append((name + ' à titre principal', patients.filter(**filter_dict).count()))
|
1509
|
filter_dict = {deficiency: 2}
|
1510
|
data[1].append((name + ' à titre associé', patients.filter(**filter_dict).count()))
|
1511
|
name = PatientRecord._meta.get_field_by_name('deficiency_polyhandicap')[0].verbose_name
|
1512
|
data[1].append((name, patients.filter(deficiency_polyhandicap=True).count()))
|
1513
|
name = PatientRecord._meta.get_field_by_name('deficiency_in_diagnostic')[0].verbose_name
|
1514
|
data[1].append((name, patients.filter(deficiency_in_diagnostic=True).count()))
|
1515
|
return [[data]]
|
1516
|
|
1517
|
class Statistic(models.Model):
|
1518
|
patients = models.ManyToManyField('dossiers.PatientRecord',
|
1519
|
null=True, blank=True, default=None)
|
1520
|
participants = models.ManyToManyField('personnes.People',
|
1521
|
null=True, blank=True, default=None)
|
1522
|
in_start_date = None
|
1523
|
in_end_date = None
|
1524
|
in_service = None
|
1525
|
in_participants = None
|
1526
|
in_patients = None
|
1527
|
in_year = None
|
1528
|
inscriptions = False
|
1529
|
|
1530
|
def __init__(self, name=None, inputs=dict()):
|
1531
|
self.name = name
|
1532
|
params = STATISTICS.get(name, {})
|
1533
|
self.display_name = params['display_name']
|
1534
|
self.category = params['category']
|
1535
|
self.inputs = inputs
|
1536
|
self.in_participants = list()
|
1537
|
participants = inputs.get('participants')
|
1538
|
if participants:
|
1539
|
p_str_ids = [p for p in participants.split('|') if p]
|
1540
|
for str_id in p_str_ids:
|
1541
|
try:
|
1542
|
self.in_participants.append(Worker.objects.get(pk=int(str_id)))
|
1543
|
except:
|
1544
|
pass
|
1545
|
self.in_patients = list()
|
1546
|
patients = inputs.get('patients')
|
1547
|
if patients:
|
1548
|
p_str_ids = [p for p in patients.split('|') if p]
|
1549
|
for str_id in p_str_ids:
|
1550
|
try:
|
1551
|
self.in_patients.append(PatientRecord.objects.get(pk=int(str_id)))
|
1552
|
except:
|
1553
|
pass
|
1554
|
self.in_service = inputs.get('service')
|
1555
|
self.in_start_date = None
|
1556
|
try:
|
1557
|
self.in_start_date = datetime.strptime(inputs.get('start_date'),
|
1558
|
"%d/%m/%Y")
|
1559
|
self.in_year = self.in_start_date.year
|
1560
|
except:
|
1561
|
pass
|
1562
|
self.in_end_date = None
|
1563
|
try:
|
1564
|
self.in_end_date = datetime.strptime(inputs.get('end_date'),
|
1565
|
"%d/%m/%Y")
|
1566
|
except:
|
1567
|
pass
|
1568
|
self.inscriptions = inputs.get('inscriptions')
|
1569
|
|
1570
|
def get_data(self):
|
1571
|
func = globals()[self.name]
|
1572
|
data = func(self)
|
1573
|
self.data = [[[["Date du jour", "Service", "Nom statistique"],
|
1574
|
[[formats.date_format(datetime.today(), "SHORT_DATE_FORMAT"),
|
1575
|
self.in_service, STATISTICS[self.name]['display_name']]]]]] + data
|
1576
|
return self.data
|
1577
|
|
1578
|
def render_to_csv(self):
|
1579
|
_delimiter = ';'
|
1580
|
_quotechar = '|'
|
1581
|
_doublequote = True
|
1582
|
_skipinitialspace = False
|
1583
|
_lineterminator = '\r\n'
|
1584
|
_quoting = csv.QUOTE_MINIMAL
|
1585
|
if getattr(settings, 'CSVPROFILE', None):
|
1586
|
csv_profile = settings.CSVPROFILE
|
1587
|
_delimiter = csv_profile.get('delimiter', ';')
|
1588
|
_quotechar = csv_profile.get('quotechar', '|')
|
1589
|
_doublequote = csv_profile.get('doublequote', True)
|
1590
|
_skipinitialspace = csv_profile.get('skipinitialspace', False)
|
1591
|
_lineterminator = csv_profile.get('lineterminator', '\r\n')
|
1592
|
_quoting = csv_profile.get('quoting', csv.QUOTE_MINIMAL)
|
1593
|
class CSVProfile(csv.Dialect):
|
1594
|
delimiter = _delimiter
|
1595
|
quotechar = _quotechar
|
1596
|
doublequote = _doublequote
|
1597
|
skipinitialspace = _skipinitialspace
|
1598
|
lineterminator = _lineterminator
|
1599
|
quoting = _quoting
|
1600
|
csv.register_dialect('csv_profile', CSVProfile())
|
1601
|
encoding = getattr(settings, 'CSV_ENCODING', 'utf-8')
|
1602
|
# Python 3: , encoding=encoding
|
1603
|
# with tempfile.NamedTemporaryFile(delete=False) as temp_out_csv:
|
1604
|
# try:
|
1605
|
# writer = csv.writer(temp_out_csv, dialect='csv_profile')
|
1606
|
# for data_set in self.data:
|
1607
|
# for data in data_set:
|
1608
|
# writer.writerow(data[0])
|
1609
|
# if len(data) > 1:
|
1610
|
# for d in data[1]:
|
1611
|
# writer.writerow(d)
|
1612
|
# writer.writerow([])
|
1613
|
# writer.writerow([])
|
1614
|
# return temp_out_csv.name
|
1615
|
# except Exception, e:
|
1616
|
# print e
|
1617
|
# try:
|
1618
|
# os.unlink(temp_out_pdf.name)
|
1619
|
# except:
|
1620
|
# pass
|
1621
|
|
1622
|
import codecs
|
1623
|
filename = None
|
1624
|
with tempfile.NamedTemporaryFile(delete=False) as temp_out_csv:
|
1625
|
filename = temp_out_csv.name
|
1626
|
temp_out_csv.close()
|
1627
|
with codecs.open(filename, 'w+b', encoding=encoding) as encoded_f:
|
1628
|
try:
|
1629
|
writer = csv.writer(encoded_f, dialect='csv_profile')
|
1630
|
for data_set in self.data:
|
1631
|
for data in data_set:
|
1632
|
writer.writerow(data[0])
|
1633
|
if len(data) > 1:
|
1634
|
for d in data[1]:
|
1635
|
writer.writerow(d)
|
1636
|
writer.writerow([])
|
1637
|
writer.writerow([])
|
1638
|
return filename
|
1639
|
except:
|
1640
|
try:
|
1641
|
os.unlink(temp_out_pdf.name)
|
1642
|
except:
|
1643
|
pass
|
1644
|
|
1645
|
def get_file(self):
|
1646
|
self.get_data()
|
1647
|
return self.render_to_csv()
|