Project

General

Profile

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

calebasse / scripts / import_rs.py @ 50f8b1ae

1
# -*- coding: utf-8 -*-
2
#!/usr/bin/env python
3

    
4
import os
5
import csv
6

    
7
from datetime import datetime
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, Event
16
from calebasse.dossiers.models import PatientRecord
17
from calebasse.personnes.models import Worker
18
from calebasse.ressources.models import Service, Room
19
from calebasse.ressources.models import ActType
20

    
21
# Configuration
22
db_path = "./scripts/20121221-192258"
23

    
24
# dbs = ["F_ST_ETIENNE_SESSAD_TED", "F_ST_ETIENNE_CMPP", "F_ST_ETIENNE_CAMSP", "F_ST_ETIENNE_SESSAD"]
25
dbs = ["F_ST_ETIENNE_CAMSP"]
26

    
27
def _to_datetime(str_date):
28
    if not str_date:
29
        return None
30
    return datetime.strptime(str_date[:19], "%Y-%m-%d %H:%M:%S")
31

    
32
def _to_date(str_date):
33
    dt = _to_datetime(str_date)
34
    return dt and dt.date()
35

    
36
def _to_time(str_date):
37
    dt = _to_datetime(str_date)
38
    return dt and dt.time()
39

    
40
def _to_duration(str_date):
41
    dt = _to_datetime(str_date)
42
    if dt is None:
43
        return None
44
    return dt - datetime(1900, 01, 01, 0, 0)
45

    
46
def _to_int(str_int):
47
    if not str_int:
48
        return None
49
    return int(str_int)
50

    
51
def _get_dict(cols, line):
52
    """"""
53
    res = {}
54
    for i, data in enumerate(line):
55
        res[cols[i]] = data.decode('utf-8')
56
    return res
57

    
58

    
59
PERIOD_FAURE_NOUS = {1 : 1,
60
2 : 2,
61
3 : 3,
62
4 : 4,
63
5: 6,
64
6: 7,
65
7: 8,
66
8: 9,
67
9: None,
68
10: 10,
69
12: 11,
70
13: 12,
71
}
72

    
73
JOURS = {1: 'lundi',
74
2: 'mardi',
75
3: 'mercredi',
76
4: 'jeudi',
77
5: 'vendredi'
78
}
79

    
80
dic_worker = {}
81

    
82
def load_csv(db, name):
83
    records = []
84
    idx = {}
85

    
86
    csvfile = open(os.path.join(db_path, db, name + '.csv'), 'rb')
87
    csvlines = csv.reader(csvfile, delimiter=';', quotechar='|')
88
    cols = csvlines.next()
89
    i = 0
90
    for line in csvlines:
91
        # ignore line for timetable
92
        data = _get_dict(cols, line)
93
        records.append(data)
94
        idx[data['id']] = i
95
        i += 1
96
    csvfile.close()
97
    return records, idx, cols
98

    
99
def add_invalid(d, reason):
100
    d.setdefault('invalid', '')
101
    if d['invalid']:
102
        d['invalid'] += ', '
103
    d['invalid'] += reason
104

    
105
def main():
106
    """ """
107

    
108
    workers = Worker.objects.all()
109
    invalid_rs_csv = open('./scripts/invalid_rs.csv', 'wb+')
110
    invalid_rs_writer = csv.writer(invalid_rs_csv, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
111
    invalid_rr_csv = open('./scripts/invalid_rr.csv', 'wb+')
112
    invalid_rr_writer = csv.writer(invalid_rr_csv, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
113
    for db in dbs:
114
        workers_idx = {}
115
        act_types_idx = {}
116
        not_found = set()
117
        if "F_ST_ETIENNE_CMPP" == db:
118
            service = Service.objects.get(name="CMPP")
119
        elif "F_ST_ETIENNE_CAMSP" == db:
120
            service = Service.objects.get(name="CAMSP")
121
        elif "F_ST_ETIENNE_SESSAD_TED" == db:
122
            service = Service.objects.get(name="SESSAD TED")
123
        elif "F_ST_ETIENNE_SESSAD" == db:
124
            service = Service.objects.get(name="SESSAD DYS")
125

    
126
        print '===', service.name, '==='
127
        print datetime.now()
128

    
129
        rs_data, rs_idx, rs_cols = load_csv(db, 'rs')
130
        rr_data, rr_idx, rr_cols = load_csv(db, 'rr')
131
        rs_cols.extend(['workers', 'invalid'])
132
        rr_cols.extend(['workers', 'invalid'])
133
        invalid_rs_writer.writerow(map(lambda x: x.encode('utf-8'), rs_cols))
134
        invalid_rr_writer.writerow(map(lambda x: x.encode('utf-8'), rr_cols))
135

    
136
        print "%s - Nombre de rdv : %d" % (service.name, len(rs_data))
137
        print u"%s - Nombre de rdv récurrents : %d" % (service.name, len(rr_data))
138

    
139
        rs_details_data, _, _ = load_csv(db, 'details_rs')
140
        rr_details_data, _, _ = load_csv(db, 'details_rr')
141
        for i, worker in enumerate(workers):
142
            if service.name == 'CMPP':
143
                j = worker.old_cmpp_id
144
            elif service.name == 'CAMSP':
145
                j = worker.old_camsp_id
146
            elif service.name == 'SESSAD DYS':
147
                j = worker.old_sessad_dys_id
148
            elif service.name == 'SESSAD TED':
149
                j = worker.old_sessad_ted_id
150
            else:
151
                print "service inconnu!!!"
152
                exit(0)
153
            if j:
154
                workers_idx[j] = worker
155

    
156
        act_types = ActType.objects.for_service(service)
157
        act_type_id_not_found = set()
158
        for i, act_type in enumerate(act_types):
159
            j = act_type.old_id
160
            if j:
161
                act_types_idx[j] = act_type
162
            else:
163
                act_type_id_not_found.add(act_type)
164

    
165
        
166
        def handle_details(data, idx, details, id_key):
167
            not_found = set()
168
            id_not_found = set()
169
            for detail in details:
170
                i = detail[id_key]
171
                thera_id = detail['thera_id']
172
                if i not in idx:
173
                    id_not_found.add(i)
174
                    continue
175
                row = data[idx[i]]
176
                if thera_id in workers_idx:
177
                    workers = row.setdefault('workers', set())
178
                    workers.add(workers_idx[thera_id])
179
                else:
180
                    add_invalid(row, 'unknown thera_id %s' % thera_id)
181
                    not_found.add(thera_id)
182

    
183
            print "%s - Liste des worker not found : %s" % (service.name, str(set(not_found)))
184
            print "%s - Liste des details pour des RS/RR not found : %s" % (service.name, str(set(id_not_found)))
185

    
186
        print ' - Traitement rs_detail....'
187
        handle_details(rs_data, rs_idx, rs_details_data, 'rs_id')
188
        print ' - Traitement rr_detail....'
189
        handle_details(rr_data, rr_idx, rr_details_data, 'rr_id')
190
        print "%s - Nombre de types d'actes : %d" % (service.name, len(act_types))
191
        print "%s - Liste des types d'actes sans id : %s" % (service.name, str(act_type_id_not_found))
192

    
193
        enfant_idx = {}
194
        for enfant in PatientRecord.objects.filter(service=service):
195
            enfant_idx[enfant.old_id] = enfant
196

    
197
        enfant_not_found = set()
198
        rr_not_found = set()
199
        rs_without_act_type = set()
200
        unknown_act_type_id = set()
201
        invalid_rs = set()
202
        seen_exceptions = dict()
203
        for rs in rs_data:
204
            rs['exception'] = False
205
            rs['event'] = False
206
            rs['date'] = _to_date(rs['date_rdv'])
207
            # connect enfant
208
            enfant_id = rs['enfant_id']
209
            if enfant_id == '0':
210
                add_invalid(rs, 'no enfant_id=>not an appointment')
211
                rs['event'] = True
212
            elif enfant_id in enfant_idx:
213
                rs['enfant'] = enfant_idx[enfant_id]
214
            else:
215
                add_invalid(rs, 'enfant_id not found %s' % enfant_id)
216
                enfant_not_found.add(enfant_id)
217
            # connect rr
218
            rr_id = rs['rr_ev_id']
219
            if rr_id:
220
                if rr_id.startswith('ev_'):
221
                    rs['ok'] = False
222
                elif rr_id.startswith('rr_'):
223
                    _, rr_id = rr_id.split('_')
224
                    if rr_id in rr_idx:
225
                        if (rr_id, rs['date']) not in seen_exceptions:
226
                            seen_exceptions[(rr_id, rs['date'])] = rs['id']
227
                            exceptions = rr_data[rr_idx[rr_id]].setdefault('exceptions', [])
228
                            exceptions.append(rs)
229
                            rs['exception'] = True
230
                        else:
231
                            add_invalid(rs, 'already another exception on the same day: %s' %
232
                                    seen_exceptions[(rr_id, rs['date'])])
233
                    else:
234
                        add_invalid(rs, 'rr_id not found %s' % rr_id)
235
                        rr_not_found.add(rr_id)
236
                else:
237
                    add_invalid(rs, 'rr_id invalid %s' % rr_id)
238
            rs['time'] = _to_time(rs['heure'])
239
            rs['duration'] = _to_duration(rs['duree'])
240
            rs['start_datetime'] = datetime.combine(rs['date'], rs['time'])
241
            rs['end_datetime'] = rs['start_datetime'] + rs['duration']
242
            act_type_id = rs['type_acte']
243
            if act_type_id == '0' and rs['enfant_id'] == '0':
244
                add_invalid(rs, 'no act_id=>not an appointment')
245
                rs['event'] = True
246
            elif act_type_id:
247
                if act_type_id in act_types_idx:
248
                    rs['act_type'] = act_types_idx[act_type_id]
249
                else:
250
                    add_invalid(rs, 'act_type not found %s' % act_type_id)
251
                    unknown_act_type_id.add(act_type_id)
252
            else:
253
                raise NotImplemented
254
            if rs.get('invalid') and not rs['event']:
255
                invalid_rs.add(rs['id'])
256
                invalid_rs_writer.writerow([ unicode(rs[col]).encode('utf-8') for col in rs_cols ])
257

    
258

    
259
        print "%s - Liste des enfants not found : %s" % (service.name, str(enfant_not_found))
260
        print "%s - Liste des RR not found : %s" % (service.name, str(rr_not_found))
261
        print "%s - Liste des RS sans type d'acte : %s" % (service.name, str(rs_without_act_type))
262
        print "%s - Liste des types d'actes inconnus : %s" % (service.name, str(unknown_act_type_id))
263
        print "%s - Liste des RS invalides : %s" % (service.name, len(invalid_rs))
264

    
265
        enfant_not_found = set()
266
        rr_not_found = set()
267
        rs_without_act_type = set()
268
        unknown_act_type_id = set()
269
        invalid_rs = set()
270
        for rr in rr_data:
271
            rr.setdefault('exceptions', [])
272
            rr['start_date'] = _to_date(rr['date_debut'])
273
            rr['end_date'] = _to_date(rr['date_fin'])
274
            if rr['end_date'] and rr['start_date'] > rr['end_date']:
275
                add_invalid(rr, 'date_fin < date_debut')
276
            rr['time'] = _to_time(rr['heure'])
277
            rr['duration'] = _to_duration(rr['duree'])
278
            rr['start_datetime'] = datetime.combine(rr['start_date'], rr['time'])
279
            rr['end_datetime'] = rr['start_datetime'] + rr['duration']
280
            # connect rythme
281
            rr['rythme'] = int(rr['rythme'])
282
            if PERIOD_FAURE_NOUS.get(rr['rythme']):
283
                rr['recurrence_periodicity'] = PERIOD_FAURE_NOUS[rr['rythme']]
284
            else:
285
                add_invalid(rr, 'rythme not found %s' % rr['rythme'])
286
            # connect enfant
287
            enfant_id = rr['enfant_id']
288
            if enfant_id == '0':
289
                add_invalid(rr, 'not an appointment')
290
            elif enfant_id in enfant_idx:
291
                rr['enfant'] = enfant_idx[enfant_id]
292
            else:
293
                add_invalid(rr, 'enfant_id not found %s' % enfant_id)
294
                enfant_not_found.add(enfant_id)
295
            # connect act_type
296
            act_type_id = rr['type_acte']
297
            if act_type_id == '0' and rr['enfant_id'] == '0':
298
                add_invalid(rr, 'not an appointment')
299
            elif act_type_id:
300
                if act_type_id in act_types_idx:
301
                    rr['act_type'] = act_types_idx[act_type_id]
302
                else:
303
                    add_invalid(rr, 'act_type not found %s' % act_type_id)
304
                    unknown_act_type_id.add(act_type_id)
305
            else:
306
                raise NotImplemented
307
            if rr.get('invalid'):
308
                invalid_rr_writer.writerow([ unicode(rr[col]).encode('utf-8') for col in rr_cols ])
309

    
310
        # stats
311
        exceptions = 0
312
        events = 0
313
        single = 0
314
        recurrent = 0
315
        invalid_single = 0
316
        invalid_recurrent = 0
317
        for row in rs_data:
318
            if row['event']:
319
                events += 1
320
            elif row.get('invalid'):
321
                invalid_single += 1
322
            elif row['exception']:
323
                exceptions += 1
324
            else:
325
                single += 1
326
        for row in rr_data:
327
            if row.get('invalid'):
328
                invalid_recurrent += 1
329
            else:
330
                recurrent += 1
331
        print ' == Stat == '
332
        print ' Évènements hors RDV', events
333
        print ' Rdv individuels', single
334
        print ' Rdv recurrents', recurrent
335
        print ' Exceptions', exceptions
336
        print ' Rdv recurrents invalides', invalid_recurrent
337
        print ' Rdv individuels invalides', invalid_single
338

    
339
        # create single rdv
340
        limit = 1000000
341
        with transaction.commit_manually():
342
            try:
343
                # single RS
344
                i = 0 
345
                rows = []
346
                events = []
347
                for row in rs_data[:limit]:
348
                    if row['exception'] or row.get('invalid'):
349
                        continue
350
                    i += 1
351
                    rows.append(row)
352
                    events.append(EventWithAct.objects.create(patient=row['enfant'],
353
                            start_datetime=row['start_datetime'],
354
                            end_datetime=row['end_datetime'],
355
                            act_type=row['act_type'],
356
                            old_rs_id=row['id'],
357
                            room=Room(id=1),
358
                            title=row['libelle'],
359
                            description=row['texte']))
360
                    print "Rdv creation %-6d\r" % i,
361
                print
362
                def batch_bulk(model, rows, limit):
363
                    i = 0
364
                    while rows[i:i+limit]:
365
                        model.objects.bulk_create(rows[i:i+limit])
366
                        i += limit
367
                def service_and_workers(events, rows):
368
                    services = []
369
                    ServiceThrough = EventWithAct.services.through
370
                    for event in events:
371
                        services.append(ServiceThrough(
372
                            event_id=event.event_ptr_id,
373
                            service_id=service.id))
374
                    batch_bulk(ServiceThrough, services, 100)
375
                    ParticipantThrough = EventWithAct.participants.through
376
                    participants = []
377
                    for row, event in zip(rows, events):
378
                        for worker in row['workers']:
379
                            participants.append(
380
                                    ParticipantThrough(
381
                                        event_id=event.event_ptr_id,
382
                                        people_id=worker.people_ptr_id))
383
                    batch_bulk(ParticipantThrough, participants, 100)
384
                    print 'Created %s service links' % len(services)
385
                    print 'Created %s participants links' % len(participants)
386
                service_and_workers(events, rows)
387
                # RR
388
                rows = []
389
                events = []
390
                i = 0
391
                for row in rr_data[:limit]:
392
                    if row.get('invalid'):
393
                        continue
394
                    i += 1
395
                    rows.append(row)
396
                    events.append(EventWithAct.objects.create(
397
                            patient=row['enfant'],
398
                            start_datetime=row['start_datetime'],
399
                            end_datetime=row['end_datetime'],
400
                            act_type=row['act_type'],
401
                            old_rs_id=row['id'],
402
                            room=Room(id=1),
403
                            title=row['libelle'],
404
                            description=row['texte'],
405
                            recurrence_periodicity=row['recurrence_periodicity'],
406
                            recurrence_end_date=row['end_date']))
407
                    print "Rdv recurrent creation %-6d\r" % i,
408
                print
409
                service_and_workers(events, rows)
410
                # Exceptions
411
                excrows = []
412
                excevents = []
413
                i = 0
414
                for rr, event in zip(rows, events):
415
                    for row in rr['exceptions']:
416
                        if row.get('invalid'):
417
                            print 'exception invalide'
418
                            continue
419
                        i += 1
420
                        excrows.append(row)
421
                        excevents.append(EventWithAct.objects.create(
422
                                patient=row['enfant'],
423
                                start_datetime=row['start_datetime'],
424
                                end_datetime=row['end_datetime'],
425
                                act_type=row['act_type'],
426
                                old_rs_id=row['id'],
427
                                room=Room(id=1),
428
                                title=row['libelle'],
429
                                description=row['texte'],
430
                                exception_to=event,
431
                                exception_date=row['date']))
432
                        print "Exception creation %-6d\r" % i,
433
                print
434
                service_and_workers(excevents, excrows)
435
            finally:
436
                transaction.rollback()
437

    
438

    
439

    
440

    
441
    invalid_rs_csv.close()
442
    invalid_rr_csv.close()
443

    
444
if __name__ == "__main__":
445
    main()
(18-18/26)