This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
calebasse/scripts/control_integrity.py

322 lines
16 KiB
Python

# -*- coding: utf-8 -*-
#!/usr/bin/env python
"""
Script de contrôle et de reporting
"""
import os
import tempfile
from datetime import datetime, timedelta
from datetime import date as date_setter
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "calebasse.settings")
from calebasse.facturation.models import Invoice
from calebasse.actes.models import Act, ValidationMessage
from calebasse.dossiers.models import PatientRecord
from calebasse.agenda.models import EventWithAct
SEND_MAIL = "mates@entrouvert.com"
OUTPUT_DIR = "/var/log/calebasse"
PREFIX = "analyse"
ANALYSE_SDT = datetime(2013,1,1)
ALWAYS_SEND_MAIL = True
LOOKUP_NEW = True
END_LOOKUP = datetime.today()
SERVICES = ('CMPP', 'CAMSP', 'SESSAD TED', 'SESSAD DYS')
#SERVICES = ('CAMSP',)
#SERVICES = ('CAMSP', 'SESSAD TED', 'SESSAD DYS')
#SERVICES = ('SESSAD DYS',)
QUIET = False
if __name__ == '__main__' :
prefix = '%s-%s.' % (PREFIX, datetime.utcnow())
logger_fn = os.path.join(OUTPUT_DIR, prefix + 'log')
assert not os.path.isfile(logger_fn), 'Analyse log file "%s" already exists' % logger_fn
logger = tempfile.NamedTemporaryFile(suffix='.logtmp',
prefix=prefix, dir=OUTPUT_DIR, delete=False)
logger.write("Script de contôle de Calebasse : %s\n\n" % datetime.utcnow())
need_mail = False
if LOOKUP_NEW:
for service_name in SERVICES:
for date in [(ANALYSE_SDT + timedelta(days=i)).date() for i in range(0, (END_LOOKUP.date()-ANALYSE_SDT.date()).days)]:
"Be sure all acts are created in 2014"
acts = list(Act.objects \
.filter(date=date, patient__service__name=service_name) \
.select_related() \
.prefetch_related('doctors',
'patient__patientcontact',
'actvalidationstate_set__previous_state') \
.order_by('time'))
event_ids = [ a.parent_event_id for a in acts if a.parent_event_id ]
events = EventWithAct.objects.for_today(date) \
.filter(patient__service__name=service_name) \
.exclude(id__in=event_ids)
events = [ event.today_occurrence(date) for event in events ]
acts += [ event.act for event in events if event ]
for act in acts:
if not act.id:
act.save()
logger.write("Traitement des données\n")
logger.write("----------------------\n\n")
invoices = {'CMPP' : {}, 'CAMSP' : {}, 'SESSAD TED' : {}, 'SESSAD DYS' : {}}
for invoice in Invoice.objects.all():
try:
patient = PatientRecord.objects.get(id=invoice.patient_id)
invoices[patient.service.name].setdefault(invoice.invoicing, []).append(invoice)
except:
if invoice.patient_id:
need_mail = True
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))
else:
logger.write("La facture %d n'a pas de patient\n" % invoice.id)
if len(invoice.list_dates.split('$')) > invoice.acts.all().count():
logger.write("Cette facture présente des actes manquants\n")
logger.write("Traitement terminé\n\n")
for service_name in SERVICES:
service_str = "Service : %s" % service_name
logger.write('='+'='.join(['' for c in service_str])+"\n")
logger.write(service_str+"\n")
logger.write('='+'='.join(['' for c in service_str])+"\n\n")
acts = Act.objects.filter(date__gte=ANALYSE_SDT.date(), patient__service__name=service_name)
logger.write("Vérifications Event canceled avec des actes already_billed\n")
logger.write("---------------------------------------------------------\n\n")
r_list = []
for id in set([a.parent_event.id for a in Act.objects.filter(parent_event__canceled = True, already_billed = True)]):
e = EventWithAct.objects.get(id=id)
if e.is_recurring():
logger.write("Recurrent : %d\n" % e.id)
r_list.append(id)
elif e.exception_to:
logger.write("Exception %d au recurrent : %d\n" % (e.id, e.exception_to.id))
if not e.exception_to.canceled:
logger.write("\tLe récurrent n'est pas canceled, we can fix easily setting this exception not canceled\n")
else:
logger.write("Simple : %d, we can fix easily setting this exception not canceled\n" % e.id)
logger.write("\n")
logger.write("Vérifications des pointages et vérouillages des actes\n")
logger.write("-----------------------------------------------------\n\n")
logger.write("*** Les 7 valeurs suivantes doivent rester nulles\n")
analyse = [[], [], [], [], [], [], [], []]
for a in acts:
if not a.last_validation_state:
analyse[0].append(a)
need_mail = True
if a.is_billed and (a.is_new() or a.is_absent()):
analyse[1].append(a)
need_mail = True
if a.validation_locked and a.is_new():
analyse[2].append(a)
need_mail = True
if a.is_billed and not a.validation_locked:
analyse[3].append(a)
need_mail = True
if a.is_state('ACT_LOST'):
analyse[4].append(a)
need_mail = True
if a.is_state('VALIDE') and not a.valide:
analyse[5].append(a)
need_mail = True
if not a.parent_event:
analyse[6].append(a)
need_mail = True
if a.invoice_set.all() and not a.already_billed:
analyse[7].append(a)
need_mail = True
logger.write("$$$ Actes sans valeur 'last validation state' : %d\n" % len(analyse[0]))
for a in analyse[0]:
logger.write("\tActe %d : %s\n" % (a.id, a))
logger.write("$$$ Actes facturés mais non pointés en présent : %d\n" % len(analyse[1]))
for a in analyse[1]:
logger.write("\tActe %d : %s\n" % (a.id, a))
logger.write("$$$ Actes vérouillés mais non pointés : %d\n" % len(analyse[2]))
for a in analyse[2]:
logger.write("\tActe %d : %s\n" % (a.id, a))
logger.write("$$$ Actes facturés mais non vérouillés : %d\n" % len(analyse[3]))
for a in analyse[3]:
logger.write("\tActe %d : %s\n" % (a.id, a))
logger.write("$$$ Actes pointés perdus (déprécié) : %d\n" % len(analyse[4]))
for a in analyse[4]:
logger.write("\tActe %d : %s\n" % (a.id, a))
logger.write("$$$ Actes validés mais avec valeur de contrôle non initialisée : %d\n" % len(analyse[5]))
for a in analyse[5]:
logger.write("\tActe %d : %s\n" % (a.id, a))
logger.write("$$$ Actes sans événement parent : %d\n" % len(analyse[6]))
for a in analyse[6]:
logger.write("\tActe %d : %s\n" % (a.id, a))
logger.write("$$$ Actes deja facturés mais already_billed est False : %d\n" % len(analyse[6]))
for a in analyse[7]:
logger.write("\tActe %d : %s\n" % (a.id, a))
logger.write("\n")
logger.write("Vérifications des factures\n")
logger.write("--------------------------\n\n")
for invoicing, invoice_list in invoices[service_name].items():
logger.write("Facturation %d\n" % invoicing.seq_id)
for invoice in invoice_list:
if len(invoice.list_dates.split('$')) > invoice.acts.all().count():
need_mail = True
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)))
acts_dates = [datetime.strptime(d, '%d/%m/%Y').date() for d in invoice.list_dates.split('$')]
if service_name=='CMPP' and len(acts_dates) != len(set(acts_dates)):
print "$$$ Il y a plus d'un acte facturé le meme jour!"
logger.write("$$$ Nombre d'actes manquants %d\n" % (len(acts_dates)-invoice.acts.all().count()))
acts_missing_dates = set(acts_dates) - set([act.date for act in invoice.acts.all()])
for date in acts_missing_dates:
logger.write("$$$ Il manque un acte le %s\n" % date)
else:
#Chech that dates of acts and dates in list_dates match
pass
for act in invoice.acts.all():
if service_name=='CMPP':
if not act.is_billed and not act.is_lost:
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()])))
else:
if not act.is_billed:
need_mail = True
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))
logger.write("\n")
logger.write("Vérifications des actes facturés\n")
logger.write("--------------------------------\n\n")
acts_billed = Act.objects.filter(date__gte=ANALYSE_SDT.date(), patient__service__name=service_name, is_billed=True)
for act in acts_billed:
if not act.invoice_set.all():
logger.write("$$$ Acte facturé sans facture id %d : %s\n" % (act.id, act))
need_mail = True
dic = {}
if service_name=='CMPP':
for act in acts_billed:
dic.setdefault(act.patient, []).append(act)
for patient, acts in dic.items():
dates = []
bad_dates = []
for act in acts:
if act.date in dates and not act.date in bad_dates:
bad_dates.append(act.date)
else:
dates.append(act.date)
for date in bad_dates:
need_mail = True
logger.write("$$$ %s a des actes facturés le même jour\n" % patient)
for act in Act.objects.filter(date=date, patient=patient, is_billed=True):
if act.invoice_set.all():
logger.write("Acte %d (factures %s) : %s\n" % (act.id, str([i.number for i in act.invoice_set.all()]), act))
else:
logger.write("Acte %d (sans factures) : %s\n" % (act.id, act))
logger.write("\n")
logger.write("Vérifications des jours de validation\n")
logger.write("-------------------------------------\n\n")
for date in [(ANALYSE_SDT + timedelta(days=i)).date() for i in range(0, (datetime.today().date()-ANALYSE_SDT.date()).days)]:
# Actes non pointés
acts = Act.objects.filter(last_validation_state__state_name='NON_VALIDE', date=date, patient__service__name=service_name)
if acts:
for act in acts:
if act.validation_locked:
need_mail = True
logger.write("$$$ Act %d : %s non validé mais verouillé\n" % (act.id, act))
vms = ValidationMessage.objects.filter(validation_date=date, service__name=service_name)
if not vms:
logger.write("Acte non pointés et aucune opération de validation pour le %s\n" % date)
else:
last = ValidationMessage.objects.filter(validation_date=date, service__name=service_name).latest('when')
if last.what != 'Validation automatique':
logger.write("Jour %s dévérouillé le %s par %s\n" % (date, last.when, last.who))
else:
logger.write("$$$ Jour %s vérouillé le %s par %s\n" % (date, last.when, last.who))
need_mail = True
for act in acts:
logger.write("$$$ Act %d : %s\n" % (act.id, act))
logger.write("$$$ Evenement parent %d créé par %s le %s\n" % (act.parent_event.id, act.parent_event.creator, act.parent_event.create_date))
if act.parent_event.create_date < last.when:
logger.write("-------> Création de l'événement antérieur à la validation\n")
logger.write("\n")
logger.write("\n")
logger.write("Vérifications des actes en double\n")
logger.write("---------------------------------\n\n")
for date in [(ANALYSE_SDT + timedelta(days=i)).date() for i in range(0, (datetime.today().date()-ANALYSE_SDT.date()).days)]:
acts = Act.objects.filter(date=date, patient__service__name=service_name).order_by('time')
if QUIET:
# En double qu'on ne peut traiter.
# On en exclue qu'un seul pour voir si un troisième apparait...
acts = acts.exclude(id__in=(575896, 580500))
acts_p = {}
for a in acts:
acts_p.setdefault(a.patient, []).append(a)
for p, acts in acts_p.items():
if len(acts) > 1:
acts_t = {}
for a in acts:
acts_t.setdefault((a.time, a.act_type), []).append(a)
for k, aa in acts_t.items():
if len(aa) > 1:
t, ty = k
logger.write("$$$ Actes en double pour %s le %s à %s\n" % (p, date, t))
acts_pe = {}
for a in aa:
acts_pe.setdefault(a.parent_event, []).append(a)
if len(aa) == len(acts_pe.keys()):
logger.write("$$$ Les événements parents sont distincts\n")
else:
logger.write("$$$ Il y a des événements parents communs\n")
for a in aa:
logger.write("\t %d : %s\n" % (a.id, a))
logger.write("\t\t %s\n" % a.last_validation_state)
if a.is_billed:
logger.write("\t\t Acte facturé\n")
if a.invoice_set.all():
logger.write("\t\tHistorique de facturation : %s\n" % str([i.number for i in a.invoice_set.all()]))
logger.write("\t\t evenement %d : %s, %s\n" % (a.parent_event.id, a.parent_event.creator, a.parent_event.create_date))
if a.parent_event.description:
logger.write("\t\tCommentaire sur event %s\n" % a.parent_event.description.encode('utf-8'))
if a.parent_event.canceled:
logger.write("\t\tC'est un événement annulé\n")
if a.parent_event.is_recurring():
logger.write("\t\tC'est un événement récurrent\n")
if a.parent_event.exception_to:
logger.write("\t\tC'est une exception à %d\n" % a.parent_event.exception_to.id)
logger.write("\n\n")
if need_mail or ALWAYS_SEND_MAIL:
# send_mail
pass
logger.write("Fin du script de contôle de Calebasse : %s" % datetime.utcnow())
old_fn = logger.name
logger.close()
os.rename(old_fn, logger_fn)