Projet

Général

Profil

« Précédent | Suivant » 

Révision 552cb32b

Ajouté par Mikaël Ates (de retour le 29 avril) il y a plus de 9 ans

scripts: script to control database functional integrity.

Voir les différences:

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

  
4
"""
5
Script de contrôle et de reporting
6
"""
7

  
8
import os
9
import tempfile
10

  
11
from datetime import datetime, timedelta
12
from datetime import date as date_setter
13

  
14
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "calebasse.settings")
15

  
16
from calebasse.facturation.models import Invoice
17
from calebasse.actes.models import Act, ValidationMessage
18
from calebasse.dossiers.models import PatientRecord
19
from calebasse.agenda.models import EventWithAct
20

  
21
SEND_MAIL = "mates@entrouvert.com"
22
OUTPUT_DIR = "./"
23
PREFIX = "analyse"
24

  
25
ANALYSE_SDT = datetime(2013,1,1)
26

  
27
ALWAYS_SEND_MAIL = True
28

  
29
LOOKUP_NEW = True
30
END_LOOKUP = datetime.today()
31

  
32
SERVICES = ('CMPP', 'CAMSP', 'SESSAD TED', 'SESSAD DYS')
33
#SERVICES = ('CAMSP',)
34
#SERVICES = ('CAMSP', 'SESSAD TED', 'SESSAD DYS')
35
#SERVICES = ('SESSAD DYS',)
36

  
37
QUIET = False
38

  
39
if __name__ == '__main__' :
40
    prefix = '%s-%s.' % (PREFIX, datetime.utcnow())
41
    logger_fn = os.path.join(OUTPUT_DIR, prefix + 'log')
42
    assert not os.path.isfile(logger_fn), 'Analyse log file "%s" already exists' % logger_fn
43
    logger = tempfile.NamedTemporaryFile(suffix='.logtmp',
44
            prefix=prefix, dir=OUTPUT_DIR, delete=False)
45

  
46
    logger.write("Script de contôle de Calebasse : %s\n\n" % datetime.utcnow())
47

  
48
    need_mail = False
49

  
50
    if LOOKUP_NEW:
51
        for service_name in SERVICES:
52
            for date in [(ANALYSE_SDT + timedelta(days=i)).date() for i in range(0, (END_LOOKUP.date()-ANALYSE_SDT.date()).days)]:
53
                "Be sure all acts are created in 2014"
54
                acts = list(Act.objects \
55
                        .filter(date=date, patient__service__name=service_name) \
56
                        .select_related() \
57
                        .prefetch_related('doctors',
58
                                'patient__patientcontact',
59
                                'actvalidationstate_set__previous_state') \
60
                        .order_by('time'))
61
                event_ids = [ a.parent_event_id for a in acts if a.parent_event_id ]
62
                events = EventWithAct.objects.for_today(date) \
63
                        .filter(patient__service__name=service_name) \
64
                        .exclude(id__in=event_ids)
65
                events = [ event.today_occurrence(date) for event in events ]
66
                acts += [ event.act for event in events if event ]
67
                for act in acts:
68
                    if not act.id:
69
                        act.save()
70

  
71
    logger.write("Traitement des données\n")
72
    logger.write("----------------------\n\n")
73
    invoices = {'CMPP' : {}, 'CAMSP' : {}, 'SESSAD TED' : {}, 'SESSAD DYS' : {}}
74
    for invoice in Invoice.objects.all():
75
        try:
76
            patient = PatientRecord.objects.get(id=invoice.patient_id)
77
            invoices[patient.service.name].setdefault(invoice.invoicing, []).append(invoice)
78
        except:
79
            if invoice.patient_id:
80
                need_mail = True
81
                logger.write("$$$ La facture %d (%d, %d) a pour id patient %d qui n'existe pas\n" % (invoice.id, invoice.batch, invoice.number, invoice.patient_id))
82
            else:
83
                logger.write("La facture %d n'a pas de patient\n" % invoice.id)
84
            if len(invoice.list_dates.split('$')) > invoice.acts.all().count():
85
                logger.write("Cette facture présente des actes manquants\n")
86
    logger.write("Traitement terminé\n\n")
87

  
88
    for service_name in SERVICES:
89
        service_str = "Service : %s" % service_name
90
        logger.write('='+'='.join(['' for c in service_str])+"\n")
91
        logger.write(service_str+"\n")
92
        logger.write('='+'='.join(['' for c in service_str])+"\n\n")
93

  
94
        acts = Act.objects.filter(date__gte=ANALYSE_SDT.date(), patient__service__name=service_name)
95

  
96
        logger.write("Vérifications Event canceled avec des actes already_billed\n")
97
        logger.write("---------------------------------------------------------\n\n")
98
        r_list = []
99
        for id in set([a.parent_event.id for a in Act.objects.filter(parent_event__canceled = True, already_billed = True)]):
100
            e = EventWithAct.objects.get(id=id)
101
            if e.is_recurring():
102
                logger.write("Recurrent : %d\n" % e.id)
103
                r_list.append(id)
104
            elif e.exception_to:
105
                logger.write("Exception %d au recurrent : %d\n" % (e.id, e.exception_to.id))
106
                if not e.exception_to.canceled:
107
                    logger.write("\tLe récurrent n'est pas canceled, we can fix easily setting this exception not canceled\n")
108
            else:
109
                logger.write("Simple : %d, we can fix easily setting this exception not canceled\n" % e.id)
110

  
111
        logger.write("\n")
112

  
113
        logger.write("Vérifications des pointages et vérouillages des actes\n")
114
        logger.write("-----------------------------------------------------\n\n")
115
        logger.write("*** Les 7 valeurs suivantes doivent rester nulles\n")
116
        analyse = [[], [], [], [], [], [], [], []]
117
        for a in acts:
118
            if not a.last_validation_state:
119
                analyse[0].append(a)
120
                need_mail = True
121
            if a.is_billed and (a.is_new() or a.is_absent()):
122
                analyse[1].append(a)
123
                need_mail = True
124
            if a.validation_locked and a.is_new():
125
                analyse[2].append(a)
126
                need_mail = True
127
            if a.is_billed and not a.validation_locked:
128
                analyse[3].append(a)
129
                need_mail = True
130
            if a.is_state('ACT_LOST'):
131
                analyse[4].append(a)
132
                need_mail = True
133
            if a.is_state('VALIDE') and not a.valide:
134
                analyse[5].append(a)
135
                need_mail = True
136
            if not a.parent_event:
137
                analyse[6].append(a)
138
                need_mail = True
139
            if a.invoice_set.all() and not a.already_billed:
140
                analyse[7].append(a)
141
                need_mail = True
142

  
143
        logger.write("$$$ Actes sans valeur 'last validation state' : %d\n" % len(analyse[0]))
144
        for a in analyse[0]:
145
            logger.write("\tActe %d : %s\n" % (a.id, a))
146
        logger.write("$$$ Actes facturés mais non pointés en présent : %d\n" % len(analyse[1]))
147
        for a in analyse[1]:
148
            logger.write("\tActe %d : %s\n" % (a.id, a))
149
        logger.write("$$$ Actes vérouillés mais non pointés : %d\n" % len(analyse[2]))
150
        for a in analyse[2]:
151
            logger.write("\tActe %d : %s\n" % (a.id, a))
152
        logger.write("$$$ Actes facturés mais non vérouillés : %d\n" % len(analyse[3]))
153
        for a in analyse[3]:
154
            logger.write("\tActe %d : %s\n" % (a.id, a))
155
        logger.write("$$$ Actes pointés perdus (déprécié) : %d\n" % len(analyse[4]))
156
        for a in analyse[4]:
157
            logger.write("\tActe %d : %s\n" % (a.id, a))
158
        logger.write("$$$ Actes validés mais avec valeur de contrôle non initialisée : %d\n" % len(analyse[5]))
159
        for a in analyse[5]:
160
            logger.write("\tActe %d : %s\n" % (a.id, a))
161
        logger.write("$$$ Actes sans événement parent : %d\n" % len(analyse[6]))
162
        for a in analyse[6]:
163
            logger.write("\tActe %d : %s\n" % (a.id, a))
164
        logger.write("$$$ Actes deja facturés mais already_billed est False : %d\n" % len(analyse[6]))
165
        for a in analyse[7]:
166
            logger.write("\tActe %d : %s\n" % (a.id, a))
167
        logger.write("\n")
168

  
169

  
170
        logger.write("Vérifications des factures\n")
171
        logger.write("--------------------------\n\n")
172

  
173
        for invoicing, invoice_list in invoices[service_name].items():
174
            logger.write("Facturation %d\n" % invoicing.seq_id)
175
            for invoice in invoice_list:
176
                if len(invoice.list_dates.split('$')) > invoice.acts.all().count():
177
                    need_mail = True
178
                    logger.write("$$$ Facture %d (%d, %d) patient %s avec des actes manquants\n" % (invoice.id, invoice.batch or 0, invoice.number or 0, PatientRecord.objects.get(id=invoice.patient_id)))
179
                    acts_dates = [datetime.strptime(d, '%d/%m/%Y').date() for d in invoice.list_dates.split('$')]
180
                    if service_name=='CMPP' and len(acts_dates) != len(set(acts_dates)):
181
                        print "$$$ Il y a plus d'un acte facturé le meme jour!"
182
                    logger.write("$$$ Nombre d'actes manquants %d\n" % (len(acts_dates)-invoice.acts.all().count()))
183
                    acts_missing_dates = set(acts_dates) - set([act.date for act in invoice.acts.all()])
184
                    for date in acts_missing_dates:
185
                        logger.write("$$$ Il manque un acte le %s\n" % date)
186
                else:
187
                    #Chech that dates of acts and dates in list_dates match
188
                    pass
189

  
190
                for act in invoice.acts.all():
191
                    if service_name=='CMPP':
192
                        if not act.is_billed and not act.is_lost:
193
                            logger.write("Facture %d (%d, %d) patient %s avec acte id %d %s à ce jour en refacturation (normal, autres factures %s)\n" % (invoice.id, invoice.batch or 0, invoice.number or 0, PatientRecord.objects.get(id=invoice.patient_id), act.id, act, str([str(i.number) for i in act.invoice_set.all()])))
194
                    else:
195
                        if not act.is_billed:
196
                            need_mail = True
197
                            logger.write("$$$ Facture %d (%d, %d) patient %s avec acte id %d %s non is_billed (anormal)\n" % (invoice.id, invoice.batch or 0, invoice.number or 0, PatientRecord.objects.get(id=invoice.patient_id), act.id, act))
198

  
199
        logger.write("\n")
200

  
201
        logger.write("Vérifications des actes facturés\n")
202
        logger.write("--------------------------------\n\n")
203

  
204

  
205
        acts_billed = Act.objects.filter(date__gte=ANALYSE_SDT.date(), patient__service__name=service_name, is_billed=True)
206
        for act in acts_billed:
207
            if not act.invoice_set.all():
208
                logger.write("$$$ Acte facturé sans facture id %d : %s\n" % (act.id, act))
209
                need_mail = True
210

  
211
        dic = {}
212
        if service_name=='CMPP':
213
            for act in acts_billed:
214
                dic.setdefault(act.patient, []).append(act)
215
            for patient, acts in dic.items():
216
                dates = []
217
                bad_dates = []
218
                for act in acts:
219
                    if act.date in dates and not act.date in bad_dates:
220
                        bad_dates.append(act.date)
221
                    else:
222
                        dates.append(act.date)
223
                for date in bad_dates:
224
                    need_mail = True
225
                    logger.write("$$$ %s a des actes facturés le même jour\n" % patient)
226
                    for act in Act.objects.filter(date=date, patient=patient, is_billed=True):
227
                        if act.invoice_set.all():
228
                            logger.write("Acte %d (factures %s) : %s\n" % (act.id, str([i.number for i in act.invoice_set.all()]), act))
229
                        else:
230
                            logger.write("Acte %d (sans factures) : %s\n" % (act.id, act))
231

  
232
        logger.write("\n")
233

  
234
        logger.write("Vérifications des jours de validation\n")
235
        logger.write("-------------------------------------\n\n")
236

  
237

  
238
        for date in [(ANALYSE_SDT + timedelta(days=i)).date() for i in range(0, (datetime.today().date()-ANALYSE_SDT.date()).days)]:
239
            # Actes non pointés
240
            acts = Act.objects.filter(last_validation_state__state_name='NON_VALIDE', date=date, patient__service__name=service_name)
241
            if acts:
242
                for act in acts:
243
                    if act.validation_locked:
244
                        need_mail = True
245
                        logger.write("$$$ Act %d : %s non validé mais verouillé\n" % (act.id, act))
246
                vms = ValidationMessage.objects.filter(validation_date=date, service__name=service_name)
247
                if not vms:
248
                    logger.write("Acte non pointés et aucune opération de validation pour le %s\n" % date)
249
                else:
250
                    last = ValidationMessage.objects.filter(validation_date=date, service__name=service_name).latest('when')
251
                    if last.what != 'Validation automatique':
252
                        logger.write("Jour %s dévérouillé le %s par %s\n" % (date, last.when, last.who))
253
                    else:
254
                        logger.write("$$$ Jour %s vérouillé le %s par %s\n" % (date, last.when, last.who))
255
                        need_mail = True
256
                        for act in acts:
257
                            logger.write("$$$ Act %d : %s\n" % (act.id, act))
258
                            logger.write("$$$ Evenement parent %d créé par %s le %s\n" % (act.parent_event.id, act.parent_event.creator, act.parent_event.create_date))
259
                            if act.parent_event.create_date < last.when:
260
                                logger.write("-------> Création de l'événement antérieur à la validation\n")
261
                logger.write("\n")
262

  
263
        logger.write("\n")
264

  
265

  
266
        logger.write("Vérifications des actes en double\n")
267
        logger.write("---------------------------------\n\n")
268

  
269
        for date in [(ANALYSE_SDT + timedelta(days=i)).date() for i in range(0, (datetime.today().date()-ANALYSE_SDT.date()).days)]:
270
            acts = Act.objects.filter(date=date, patient__service__name=service_name).order_by('time')
271
            if QUIET:
272
                # En double qu'on ne peut traiter.
273
                # On en exclue qu'un seul pour voir si un troisième apparait...
274
                acts = acts.exclude(id__in=(575896, 580500))
275
            acts_p = {}
276
            for a in acts:
277
                acts_p.setdefault(a.patient, []).append(a)
278
            for p, acts in acts_p.items():
279
                if len(acts) > 1:
280
                    acts_t = {}
281
                    for a in acts:
282
                        acts_t.setdefault((a.time, a.act_type), []).append(a)
283
                    for k, aa in acts_t.items():
284
                        if len(aa) > 1:
285
                            t, ty = k
286
                            logger.write("$$$ Actes en double pour %s le %s à %s\n" % (p, date, t))
287
                            acts_pe = {}
288
                            for a in aa:
289
                                acts_pe.setdefault(a.parent_event, []).append(a)
290
                            if len(aa) == len(acts_pe.keys()):
291
                                logger.write("$$$ Les événements parents sont distincts\n")
292
                            else:
293
                                logger.write("$$$ Il y a des événements parents communs\n")
294
                            for a in aa:
295
                                logger.write("\t %d : %s\n" % (a.id, a))
296
                                logger.write("\t\t %s\n" % a.last_validation_state)
297
                                if a.is_billed:
298
                                    logger.write("\t\t Acte facturé\n")
299
                                if a.invoice_set.all():
300
                                    logger.write("\t\tHistorique de facturation : %s\n" % str([i.number for i in a.invoice_set.all()]))
301
                                logger.write("\t\t evenement %d : %s, %s\n" % (a.parent_event.id, a.parent_event.creator, a.parent_event.create_date))
302
                                if a.parent_event.description:
303
                                    logger.write("\t\tCommentaire sur event %s\n" % a.parent_event.description.encode('utf-8'))
304
                                if a.parent_event.canceled:
305
                                    logger.write("\t\tC'est un événement annulé\n")
306
                                if a.parent_event.is_recurring():
307
                                    logger.write("\t\tC'est un événement récurrent\n")
308
                                if a.parent_event.exception_to:
309
                                    logger.write("\t\tC'est une exception à %d\n" % a.parent_event.exception_to.id)
310

  
311
        logger.write("\n\n")
312

  
313

  
314
    if need_mail or ALWAYS_SEND_MAIL:
315
        # send_mail
316
        pass
317

  
318
    logger.write("Fin du script de contôle de Calebasse : %s" % datetime.utcnow())
319
    old_fn = logger.name
320
    logger.close()
321
    os.rename(old_fn, logger_fn)

Formats disponibles : Unified diff