Revision 1c2fd868
Added by Benjamin Dauvergne almost 12 years ago
scripts/import_rs2.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
#!/usr/bin/env python |
|
3 |
|
|
4 |
import os |
|
5 |
import csv |
|
6 |
|
|
7 |
from datetime import datetime, date |
|
8 |
|
|
9 |
import calebasse.settings |
|
10 |
import django.core.management |
|
11 |
|
|
12 |
django.core.management.setup_environ(calebasse.settings) |
|
13 |
|
|
14 |
from django.db import transaction |
|
15 |
from calebasse.agenda.models import EventWithAct |
|
16 |
from calebasse.dossiers.models import PatientRecord |
|
17 |
from calebasse.personnes.models import Worker |
|
18 |
from calebasse.ressources.models import Service |
|
19 |
from calebasse.ressources.models import ActType |
|
20 |
from calebasse.actes.models import Act, ActValidationState |
|
21 |
|
|
22 |
from import_dossiers import map_cs |
|
23 |
|
|
24 |
# Configuration |
|
25 |
db_path = "./scripts/20130104-213225" |
|
26 |
|
|
27 |
dbs = ["F_ST_ETIENNE_SESSAD_TED", "F_ST_ETIENNE_CMPP", "F_ST_ETIENNE_CAMSP", "F_ST_ETIENNE_SESSAD"] |
|
28 |
# dbs = ["F_ST_ETIENNE_SESSAD_TED"] |
|
29 |
|
|
30 |
def _to_datetime(str_date): |
|
31 |
if not str_date: |
|
32 |
return None |
|
33 |
return datetime.strptime(str_date[:19], "%Y-%m-%d %H:%M:%S") |
|
34 |
|
|
35 |
def _to_date(str_date): |
|
36 |
dt = _to_datetime(str_date) |
|
37 |
return dt and dt.date() |
|
38 |
|
|
39 |
def _to_time(str_date): |
|
40 |
dt = _to_datetime(str_date) |
|
41 |
return dt and dt.time() |
|
42 |
|
|
43 |
def _to_duration(str_date): |
|
44 |
dt = _to_datetime(str_date) |
|
45 |
if dt is None: |
|
46 |
return None |
|
47 |
return dt - datetime(1900, 01, 01, 0, 0) |
|
48 |
|
|
49 |
def _to_int(str_int): |
|
50 |
if not str_int: |
|
51 |
return None |
|
52 |
return int(str_int) |
|
53 |
|
|
54 |
def _get_dict(cols, line): |
|
55 |
"""""" |
|
56 |
res = {} |
|
57 |
for i, data in enumerate(line): |
|
58 |
res[cols[i]] = data.decode('utf-8') |
|
59 |
return res |
|
60 |
|
|
61 |
def batch_delete(qs, limit): |
|
62 |
count = qs.count() |
|
63 |
i = 0 |
|
64 |
while i < count: |
|
65 |
ids = qs[i:i+limit].values_list('pk', flat=True) |
|
66 |
qs.filter(pk__in=ids).delete() |
|
67 |
i += limit |
|
68 |
|
|
69 |
|
|
70 |
PERIOD_FAURE_NOUS = {1 : 1, |
|
71 |
2 : 2, |
|
72 |
3 : 3, |
|
73 |
4 : 4, |
|
74 |
5: 6, |
|
75 |
6: 7, |
|
76 |
7: 8, |
|
77 |
8: 9, |
|
78 |
9: None, |
|
79 |
10: 10, |
|
80 |
12: 11, |
|
81 |
13: 12, |
|
82 |
} |
|
83 |
|
|
84 |
JOURS = {1: 'lundi', |
|
85 |
2: 'mardi', |
|
86 |
3: 'mercredi', |
|
87 |
4: 'jeudi', |
|
88 |
5: 'vendredi' |
|
89 |
} |
|
90 |
|
|
91 |
dic_worker = {} |
|
92 |
|
|
93 |
def load_csv(db, name, offset=0, limit=9999999, id_column=0, year=None): |
|
94 |
records = [] |
|
95 |
idx = {} |
|
96 |
|
|
97 |
csvfile = open(os.path.join(db_path, db, name + '.csv'), 'rb') |
|
98 |
csvlines = csv.reader(csvfile, delimiter=';', quotechar='|') |
|
99 |
cols = csvlines.next() |
|
100 |
i = 0 |
|
101 |
for line in csvlines: |
|
102 |
if not (offset <= int(line[id_column]) < offset+limit): |
|
103 |
continue |
|
104 |
data = _get_dict(cols, line) |
|
105 |
if year and not (('date_rdv' in data and data['date_rdv'].startswith(str(year))) \ |
|
106 |
or ('date_debut' in data and data['date_debut'].startswith(str(year)))): |
|
107 |
continue |
|
108 |
records.append(data) |
|
109 |
idx[data['id']] = i |
|
110 |
i += 1 |
|
111 |
csvfile.close() |
|
112 |
return records, idx, cols |
|
113 |
|
|
114 |
def add_invalid(d, reason): |
|
115 |
d.setdefault('invalid', '') |
|
116 |
if d['invalid']: |
|
117 |
d['invalid'] += ', ' |
|
118 |
d['invalid'] += reason |
|
119 |
|
|
120 |
@transaction.commit_on_success |
|
121 |
def main(): |
|
122 |
""" """ |
|
123 |
|
|
124 |
workers = Worker.objects.all() |
|
125 |
for db in dbs: |
|
126 |
workers_idx = {} |
|
127 |
act_types_idx = {} |
|
128 |
if "F_ST_ETIENNE_CMPP" == db: |
|
129 |
service = Service.objects.get(name="CMPP") |
|
130 |
elif "F_ST_ETIENNE_CAMSP" == db: |
|
131 |
service = Service.objects.get(name="CAMSP") |
|
132 |
elif "F_ST_ETIENNE_SESSAD_TED" == db: |
|
133 |
service = Service.objects.get(name="SESSAD TED") |
|
134 |
elif "F_ST_ETIENNE_SESSAD" == db: |
|
135 |
service = Service.objects.get(name="SESSAD DYS") |
|
136 |
|
|
137 |
print '===', service.name, '===' |
|
138 |
print datetime.now() |
|
139 |
|
|
140 |
for i, worker in enumerate(workers): |
|
141 |
if service.name == 'CMPP': |
|
142 |
j = worker.old_cmpp_id |
|
143 |
elif service.name == 'CAMSP': |
|
144 |
j = worker.old_camsp_id |
|
145 |
elif service.name == 'SESSAD DYS': |
|
146 |
j = worker.old_sessad_dys_id |
|
147 |
elif service.name == 'SESSAD TED': |
|
148 |
j = worker.old_sessad_ted_id |
|
149 |
else: |
|
150 |
print "service inconnu!!!" |
|
151 |
exit(0) |
|
152 |
if j: |
|
153 |
workers_idx[j] = worker |
|
154 |
|
|
155 |
act_types = ActType.objects.for_service(service) |
|
156 |
act_type_id_not_found = set() |
|
157 |
for i, act_type in enumerate(act_types): |
|
158 |
j = act_type.old_id |
|
159 |
if j: |
|
160 |
act_types_idx[j] = act_type |
|
161 |
else: |
|
162 |
act_type_id_not_found.add(act_type) |
|
163 |
print "%s - Nombre de types d'actes : %d" % (service.name, len(act_types)) |
|
164 |
print "%s - Liste des types d'actes sans id : %s" % (service.name, str(act_type_id_not_found)) |
|
165 |
|
|
166 |
invalid_rs = set() |
|
167 |
invalid_rr = set() |
|
168 |
new_rs = [] |
|
169 |
new_rr = [] |
|
170 |
invalid_rs_csv = open('./scripts/invalid_rs_%s.csv' % (service.name, ), 'wb+') |
|
171 |
invalid_rs_writer = csv.writer(invalid_rs_csv, delimiter=',', |
|
172 |
quotechar='"', quoting=csv.QUOTE_MINIMAL) |
|
173 |
invalid_rr_csv = open('./scripts/invalid_rr_%s.csv' % (service.name, ), 'wb+') |
|
174 |
invalid_rr_writer = csv.writer(invalid_rr_csv, delimiter=',', |
|
175 |
quotechar='"', quoting=csv.QUOTE_MINIMAL) |
|
176 |
for year in range(2011, 2014): |
|
177 |
print service.name, ' - Year', year |
|
178 |
rs_data, rs_idx, rs_cols = load_csv(db, 'rs', year=year) |
|
179 |
rr_data, rr_idx, rr_cols = load_csv(db, 'rr', year=year) |
|
180 |
print service.name, year, 'read', len(rs_data), 'rs and', len(rr_data), 'rr' |
|
181 |
rs_cols.extend(['workers', 'invalid']) |
|
182 |
rr_cols.extend(['workers', 'invalid']) |
|
183 |
invalid_rs_writer.writerow(map(lambda x: x.encode('utf-8'), rs_cols)) |
|
184 |
invalid_rr_writer.writerow(map(lambda x: x.encode('utf-8'), rr_cols)) |
|
185 |
|
|
186 |
single_rdv_idx = dict(EventWithAct.objects.filter(services=service, |
|
187 |
start_datetime__year=year, |
|
188 |
recurrence_periodicity__isnull=True).values_list('old_rs_id', 'id')) |
|
189 |
multi_rdv_idx = dict(EventWithAct.objects.filter(services=service, |
|
190 |
start_datetime__year=year, |
|
191 |
recurrence_periodicity__isnull=False).values_list('old_rr_id', 'id')) |
|
192 |
|
|
193 |
rs_details_data, _, _ = load_csv(db, 'details_rs') |
|
194 |
rr_details_data, _, _ = load_csv(db, 'details_rr') |
|
195 |
|
|
196 |
def set_act_type(row, not_found=None): |
|
197 |
act_type_id = row['type_acte'] |
|
198 |
if act_type_id == '0': |
|
199 |
add_invalid(row, 'no act_id=>not importable') |
|
200 |
elif act_type_id in act_types_idx: |
|
201 |
row['act_type'] = act_types_idx[act_type_id] |
|
202 |
else: |
|
203 |
add_invalid(row, 'act_type not found %s' % act_type_id) |
|
204 |
if not_found: |
|
205 |
not_found.add(act_type_id) |
|
206 |
|
|
207 |
def handle_details(data, idx, details, id_key): |
|
208 |
not_found = set() |
|
209 |
for detail in details: |
|
210 |
i = detail[id_key] |
|
211 |
thera_id = detail['thera_id'] |
|
212 |
if i not in idx: |
|
213 |
continue |
|
214 |
row = data[idx[i]] |
|
215 |
if thera_id in workers_idx: |
|
216 |
workers = row.setdefault('workers', set()) |
|
217 |
workers.add(workers_idx[thera_id]) |
|
218 |
else: |
|
219 |
# add_invalid(row, 'unknown thera_id %s' % thera_id) |
|
220 |
not_found.add(thera_id) |
|
221 |
print "%s - Liste des worker not found : %s" % (service.name, str(set(not_found))) |
|
222 |
|
|
223 |
print ' - Traitement rs_detail....' |
|
224 |
handle_details(rs_data, rs_idx, rs_details_data, 'rs_id') |
|
225 |
print ' - Traitement rr_detail....' |
|
226 |
handle_details(rr_data, rr_idx, rr_details_data, 'rr_id') |
|
227 |
|
|
228 |
enfant_idx = {} |
|
229 |
for enfant in PatientRecord.objects.filter(service=service): |
|
230 |
enfant_idx[enfant.old_id] = enfant |
|
231 |
|
|
232 |
def set_enfant(row, not_found=None): |
|
233 |
# connect enfant |
|
234 |
enfant_id = row['enfant_id'] |
|
235 |
if enfant_id == '0': |
|
236 |
add_invalid(row, 'no enfant_id=>not an appointment') |
|
237 |
row['event'] = True |
|
238 |
elif enfant_id in enfant_idx: |
|
239 |
row['enfant'] = enfant_idx[enfant_id] |
|
240 |
else: |
|
241 |
add_invalid(row, 'enfant_id not found %s' % enfant_id) |
|
242 |
if not_found: |
|
243 |
not_found.add(enfant_id) |
|
244 |
|
|
245 |
enfant_not_found = set() |
|
246 |
rr_not_found = set() |
|
247 |
rs_without_act_type = set() |
|
248 |
unknown_act_type_id = set() |
|
249 |
for rs in rs_data: |
|
250 |
if rs['id'] in single_rdv_idx: |
|
251 |
continue |
|
252 |
rs.setdefault('workers', set()) |
|
253 |
rs['exception'] = False |
|
254 |
rs['event'] = False |
|
255 |
rs['date'] = _to_date(rs['date_rdv']) |
|
256 |
# connect enfant |
|
257 |
set_enfant(rs) |
|
258 |
set_act_type(rs) |
|
259 |
if rs['event']: |
|
260 |
continue |
|
261 |
# connect rr |
|
262 |
rr_id = rs['rr_ev_id'] |
|
263 |
if rr_id: |
|
264 |
if rr_id.startswith('ev_'): |
|
265 |
continue |
|
266 |
rs['time'] = _to_time(rs['heure']) |
|
267 |
rs['duration'] = _to_duration(rs['duree']) |
|
268 |
rs['start_datetime'] = datetime.combine(rs['date'], rs['time']) |
|
269 |
rs['end_datetime'] = rs['start_datetime'] + rs['duration'] |
|
270 |
if len(rs['workers']) == 0: |
|
271 |
add_invalid(rs, 'aucun participant') |
|
272 |
if rs.get('invalid') and not rs['event']: |
|
273 |
invalid_rs.add(rs['id']) |
|
274 |
invalid_rs_writer.writerow([ unicode(rs[col]).encode('utf-8') for col in rs_cols ]) |
|
275 |
else: |
|
276 |
new_rs.append(rs) |
|
277 |
|
|
278 |
|
|
279 |
print "%s - Liste des enfants not found : %s" % (service.name, str(enfant_not_found)) |
|
280 |
print "%s - Liste des RR not found : %s" % (service.name, str(rr_not_found)) |
|
281 |
print "%s - Liste des RS sans type d'acte : %s" % (service.name, str(rs_without_act_type)) |
|
282 |
print "%s - Liste des types d'actes inconnus : %s" % (service.name, str(unknown_act_type_id)) |
|
283 |
|
|
284 |
|
|
285 |
enfant_not_found = set() |
|
286 |
rr_not_found = set() |
|
287 |
rs_without_act_type = set() |
|
288 |
unknown_act_type_id = set() |
|
289 |
for rr in rr_data: |
|
290 |
if rr['id'] in multi_rdv_idx: |
|
291 |
continue |
|
292 |
rr['event'] = False |
|
293 |
rs.setdefault('workers', set()) |
|
294 |
rr.setdefault('exceptions', []) |
|
295 |
rr['start_date'] = _to_date(rr['date_debut']) |
|
296 |
rr['end_date'] = _to_date(rr['date_fin']) |
|
297 |
if rr['end_date'] and rr['start_date'] > rr['end_date']: |
|
298 |
add_invalid(rr, 'date_fin < date_debut') |
|
299 |
rr['time'] = _to_time(rr['heure']) |
|
300 |
rr['duration'] = _to_duration(rr['duree']) |
|
301 |
rr['start_datetime'] = datetime.combine(rr['start_date'], rr['time']) |
|
302 |
rr['end_datetime'] = rr['start_datetime'] + rr['duration'] |
|
303 |
# connect rythme |
|
304 |
rr['rythme'] = int(rr['rythme']) |
|
305 |
if PERIOD_FAURE_NOUS.get(rr['rythme']): |
|
306 |
rr['recurrence_periodicity'] = PERIOD_FAURE_NOUS[rr['rythme']] |
|
307 |
else: |
|
308 |
add_invalid(rr, 'rythme not found %s' % rr['rythme']) |
|
309 |
set_enfant(rr) |
|
310 |
set_act_type(rr) |
|
311 |
if rr['event']: |
|
312 |
continue |
|
313 |
if len(rr['workers']) == 0: |
|
314 |
add_invalid(rr, 'aucun participant') |
|
315 |
if rr.get('invalid'): |
|
316 |
invalid_rr.add(rr['id']) |
|
317 |
invalid_rr_writer.writerow([ unicode(rr[col]).encode('utf-8') for col in rr_cols ]) |
|
318 |
else: |
|
319 |
new_rr.append(rr) |
|
320 |
print service.name, 'found', len(new_rs), 'individual rdv not imported' |
|
321 |
print service.name, 'found', len(invalid_rs), 'individual rdv invalid' |
|
322 |
print service.name, 'found', len(new_rr), 'multiple rdv not imported' |
|
323 |
print service.name, 'found', len(invalid_rr), 'multiple rdv invalid' |
|
324 |
|
|
325 |
for row in new_rs: |
|
326 |
act_id = row['base_id'] |
|
327 |
if act_id == '0': |
|
328 |
continue |
|
329 |
acts = Act.objects.filter(old_id=act_id) |
|
330 |
row['act'] = None |
|
331 |
if len(acts) == 0: |
|
332 |
print service.name, 'act not imported', act_id, 'linked to rs', row['id'] |
|
333 |
elif len(acts) > 1: |
|
334 |
print service.name, 'more than one act', acts.values_list('id', flat=True), 'linked to rs', row['id'] |
|
335 |
else: |
|
336 |
row['act'] = acts[0] |
|
337 |
|
|
338 |
|
|
339 |
# RR |
|
340 |
for row in new_rr: |
|
341 |
event = EventWithAct.objects.create( |
|
342 |
patient=row['enfant'], |
|
343 |
start_datetime=row['start_datetime'], |
|
344 |
end_datetime=row['end_datetime'], |
|
345 |
act_type=row['act_type'], |
|
346 |
old_rr_id=row['id'], |
|
347 |
title=row['enfant'].display_name, |
|
348 |
description=row['texte'], |
|
349 |
recurrence_periodicity=row['recurrence_periodicity'], |
|
350 |
recurrence_end_date=row['end_date']) |
|
351 |
event.services = [ service ] |
|
352 |
event.participants = row['workers'] |
|
353 |
print 'created', event |
|
354 |
for row in new_rs: |
|
355 |
if row['exception'] or row.get('invalid'): |
|
356 |
continue |
|
357 |
exception_to = None |
|
358 |
exception_date = None |
|
359 |
if row['rr_ev_id']: |
|
360 |
_, rr_id = row['rr_ev_id'].split('_') |
|
361 |
e = EventWithAct.objects.filter(old_rr_id=rr_id) |
|
362 |
if len(e) == 0: |
|
363 |
pass |
|
364 |
elif len(e) > 1: |
|
365 |
add_invalid(row, 'more than one recurring event %s' % e.values_list('id', flat=True)) |
|
366 |
invalid_rs_writer.writerow([ unicode(row[col]).encode('utf-8') for col in rs_cols ]) |
|
367 |
continue |
|
368 |
else: |
|
369 |
exception_to = e[0] |
|
370 |
exception_date = row['start_datetime'].date() |
|
371 |
if exception_to and EventWithAct.objects.filter(exception_to=exception_to, exception_date=exception_date): |
|
372 |
print 'exception existante', EventWithAct.objects.filter(exception_to=exception_to, exception_date=exception_date), ' ligne ', row, 'ignore' |
|
373 |
continue |
|
374 |
|
|
375 |
|
|
376 |
event = EventWithAct.objects.create(patient=row['enfant'], |
|
377 |
start_datetime=row['start_datetime'], |
|
378 |
end_datetime=row['end_datetime'], |
|
379 |
act_type=row['act_type'], |
|
380 |
old_rs_id=row['id'], |
|
381 |
title=row['enfant'].display_name, |
|
382 |
description=row['texte'], |
|
383 |
exception_to=exception_to, |
|
384 |
exception_date=exception_date) |
|
385 |
event.services = [ service ] |
|
386 |
event.participants = row['workers'] |
|
387 |
print 'created', event |
|
388 |
|
|
389 |
|
|
390 |
if __name__ == "__main__": |
|
391 |
main() |
Also available in: Unified diff
scripts: add import_rs2.py