bouton pour changer les dates bougé
[perso/Denise/oms.git] / gestion_donnees.py
CommitLineData
5679dfd0
DL
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
d03279e7 4from configuration import CONFIG,DEFAUT
5679dfd0 5from gestion_erreurs import *
fd69b6b5 6from gestion_couleurs import *
5679dfd0 7import datetime
be2bf515
DL
8import json
9import unidecode
915e90bb 10import copy
5679dfd0 11
61020126
DL
12### Les données "tournent" selon :
13### python -> json -> (export/import) -> formulaire HTML -> données POST -> python etc
5679dfd0
DL
14
15############ Fonctions de conversion
16
17def convertit_jours_vers_python(chaine,liste_err):
18 """ convertit une chaine de type 1a 3m 1s 10j en jours
be2bf515 19 Renvoie un nombre de jours en float
5679dfd0
DL
20 Si un des caractères n'est ni un nombre, ni une lettre "autorisée" ni une espace,
21 on affiche un warning et on ignore ce caractère
22 """
23 chainenombre = ""
24 agejours = 0.
25 for lettre in chaine:
26 if lettre.isdigit():
27 chainenombre += lettre
28 else:
29 if lettre == 'a' or lettre == 'A':
30 # On a trouvé l'année, on ajoute tout ce qui est trouvé jusque là
d03279e7 31 agejours += int(chainenombre)*CONFIG["jours_dans_annee"]
5679dfd0
DL
32 chainenombre = ""
33 elif lettre == 'm' or lettre == 'M':
34 # On a trouvé le mois
d03279e7 35 agejours += int(chainenombre)*CONFIG["jours_dans_mois"]
5679dfd0
DL
36 chainenombre = ""
37 elif lettre == 's' or lettre == 'S':
38 # la semaine
d03279e7 39 agejours += int(chainenombre)*CONFIG["jours_dans_semaine"]
5679dfd0
DL
40 chainenombre = ""
41 elif lettre == 'j' or lettre == 'J':
42 # On a trouvé le jour
43 agejours += int(chainenombre)
44 chainenombre = ""
45 elif lettre != ' ':
46 # autre caractère : bizarre ?
47 warning("convertit_jour_vers_python : caractère invalide : "+lettre,liste_err)
48 # à la fin s'il reste qqch on le garde dans les jours
49 if chainenombre != "":
be2bf515 50 agejours += int(chainenombre)
5679dfd0
DL
51 if agejours<0:
52 warning("L'âge est négatif !",liste_err)
53 agejours = 0
be2bf515 54 return agejours
5679dfd0
DL
55
56def convertit_age_vers_texte(nombre):
57 """ convertit un nombre de jours en un truc plus lisible en mois, années, jours
58 et renvoie une chaîne sous la forme 3a2m1j par exemple"""
d03279e7
DL
59 annees = int(nombre / CONFIG["jours_dans_annee"])
60 restant = nombre - annees*CONFIG["jours_dans_annee"]
61 mois = int(restant/CONFIG["jours_dans_mois"])
62 jours= round(nombre - mois*CONFIG["jours_dans_mois"] - annees*CONFIG["jours_dans_annee"])
5679dfd0
DL
63
64 chaine = ""
65 if annees >0:
66 chaine += str(annees)+"a"
67 if mois >0:
68 chaine += str(mois)+"m"
69 if jours>0 or nombre ==0: # si c'est la naissance, faut beien écrire 0j quand même
70 chaine += str(jours)+"j"
71 return chaine
72##########################
be2bf515
DL
73
74
75def simplifie_nom(chaine):
76 """ simplifie le nom chaine afin d'en faire une extension
77 pour le nom du fichier. Met tout en minuscules et vire les caractères spéciaux
78 et max 15 caractères"""
79 chaine2 = ""
80 for l in chaine:
81 if l.isalpha():
82 chaine2+=l
83 chaine2 = unidecode.unidecode(chaine2)
84 return chaine2[:15]
5679dfd0
DL
85
86def convertit_poids_vers_python(chaine,liste_err):
87 """ convertit une chaine vers un float qui est le poids.
88 On gère notamment la virgule, et on enlève les espaces
89 Un poids invalide -> on renvoie 0 avec un warning"""
90 chaine2 = chaine.replace(",",".")
91 chaine2 = chaine2.replace(" ","")
92
93 try:
66a3e38c 94 poids = float(chaine2)
5679dfd0
DL
95 except:
96 warning("Poids impossible à lire : "+chaine,liste_err)
97 poids = 0
d03279e7 98 if not( 0<=poids<CONFIG["poids_maxi"]):
66a3e38c 99 warning("Poids incohérent : "+str(poids),liste_err)
5679dfd0
DL
100 poids = 0
101 return poids
102
be2bf515
DL
103#def convertit_poids_vers_texte(poids):
104# """ convertit un poids vers du texte. Rien à dire là pour l'instant """
105# return str(poids)
5679dfd0
DL
106
107#########################
108
109def convertit_date_vers_python(chaine,liste_err):
110 """ prend une chaine comme renvoyée par un champ de formulaire date
111 aaaa-mm-jj et en fait une date python
112 renvoie "" si ne marche pas"""
113 liste = chaine.split("-")
114 if len(liste) != 3:
115 warning("La date : "+chaine+" est invalide !",liste_err)
116 return ""
117 else:
30158504 118 debug("Conversion de la date "+chaine+". Découpage : "+str(liste),liste_err)
9cb3c31c
DL
119 try:
120 date = datetime.date(int(liste[0]),int(liste[1]),int(liste[2]))
121 except:
122 date = ""
30158504 123 warning("Impossible de lire la date "+chaine+". Format accepté : aaaa-mm-jj",liste_err)
9cb3c31c 124 return date
5679dfd0
DL
125
126def convertit_date_vers_texte(date):
127 """ convertit une date python en format texte aaaa-mm-jj"""
128 if date == "":
129 return ""
130 else:
131 return (str(date.year)+"-"+str(date.month)+"-"+str(date.day))
132
133
134def delta_date(date1,datenaissance):
135 """ renvoie le nombre de jours (entier) entre date1 et datenaissance format "datetime"
136 datenaissance est supposée antérieure. Erreur sinon."""
137 d = date1 - datenaissance
138 jours = d.days
139 if jours<0:
140 erreur_continue("La différence entre les dates est négative... :/")
141 return -1
142 return jours
143
144
145########### Fonctions qui gèretn les données
146
147
148def gere_configuration(data,liste_err):
be2bf515 149 """ prend en argument le dictionnaire de requête (configuration imparfaite), et
5679dfd0
DL
150 construit le dictionnaire de configuration qui va bien.
151 Vérifie que chaque entrée est cohérente évidemment."""
152 configuration = {}
153
154 # Pour le nom, osef qu'il soit vide
155 nom = data.get("nom","")
156 # Par contre s'il est trop long on le tronque
d03279e7 157 configuration["nom"] = nom[:CONFIG["longueur_max_nom_bebe"]]
5679dfd0
DL
158
159 sexe = data.get("sexe","")
a46e1269 160 if not (sexe in ["F","M","N"]):
5679dfd0 161 warning("Le sexe de l'enfant est invalide ! "+sexe,liste_err)
a46e1269 162 sexe = "N"
5679dfd0
DL
163 configuration["sexe"] = sexe
164
165 naissance = data.get("naissance","")
166 if naissance !="":
167 naissance = convertit_date_vers_python(naissance,liste_err)
168 configuration["naissance"] = naissance
169
170 # Type de courbe. Au pire on met P
171 tyc = data.get("typecourbe","")
172 if not (tyc in ["P","Z"]):
173 tyc = "P"
174 configuration["typecourbe"] = tyc
175
176 # unité
177 unite = data.get("unite","")
9e4c51c7
DL
178
179 if not (unite in CONFIG["liste_unites"]):
5679dfd0
DL
180 unite = ""
181 #warning("L'unité "+unite+" n'est pas reconnue !",liste_err)
182 configuration["unite"] = unite
9e4c51c7 183
5679dfd0
DL
184 # grille
185 grille = data.get("grille","")
186 if grille != "on":
187 configuration["grille"] = ""
188 else:
189 configuration["grille"] = "oui"
190
191 # maxi. 0 signifie qu'on veut pas de maxi
192 maxi = data.get("maxi","")
193 if maxi == "":
194 configuration["maxi"] = 0
195 else:
54c71831 196 configuration["maxi"] = int(convertit_jours_vers_python(maxi,liste_err))
5679dfd0
DL
197
198 # dimensions du graphique
be2bf515 199 largeur = data.get("largeur","")
5679dfd0 200 if largeur == "":
915e90bb 201 largeur = DEFAUT["largeur_graphique"]
5679dfd0
DL
202 else:
203 try:
204 largeur = int(largeur)
205 except:
206 warning("La largeur "+largeur+"est invalide !",liste_err)
915e90bb 207 largeur = DEFAUT["largeur_graphique"]
d03279e7
DL
208 if largeur > CONFIG["largeur_graphique_max"]:
209 largeur = CONFIG["largeur_graphique_max"]
210 warning("Largeur du graphique trop grande !",liste_err)
211 elif largeur < CONFIG["largeur_graphique_min"]:
212 largeur = CONFIG["largeur_graphique_min"]
213 warning("Largeur du graphique trop petite !",liste_err)
5679dfd0
DL
214 configuration["largeur"] = largeur
215
be2bf515 216 hauteur = data.get("hauteur","")
5679dfd0 217 if hauteur == "":
915e90bb 218 hauteur = DEFAUT["hauteur_graphique"]
5679dfd0
DL
219 else:
220 try:
221 hauteur = int(hauteur)
222 except:
223 warning("La hauteur "+hauteur+"est invalide !",liste_err)
915e90bb 224 hauteur = DEFAUT["hauteur_graphique"]
d03279e7
DL
225 if hauteur > CONFIG["hauteur_graphique_max"]:
226 hauteur = CONFIG["hauteur_graphique_max"]
227 warning("Hauteur du graphique trop grande !",liste_err)
228 elif hauteur < CONFIG["hauteur_graphique_min"]:
229 hauteur = CONFIG["hauteur_graphique_min"]
230 warning("Hauteur du graphique trop petite !",liste_err)
5679dfd0
DL
231 configuration["hauteur"] = hauteur
232
233 # existence et position de la légende
234 legende = data.get("legende","")
235 if legende =="":
236 legende = "non"
237 elif legende=="on":
238 legende = "oui"
239 else:
240 legende = "oui"
241 configuration["legende"] = legende
242
243 positionlegende = data.get("positionlegende","")
244 if not(positionlegende in ['upper left','upper right','lower left','lower right']):
245 positionlegende = "upper left"
246 configuration["positionlegende"] = positionlegende
61020126 247
fd69b6b5 248
915e90bb
DL
249 configuration["couleurs"] = {}
250 # gérer les couleurs
915e90bb
DL
251 for clecouleur in DEFAUT["couleurs"]:
252 coul = rgb_vers_tuple(data.get("couleur_"+clecouleur,""),CONFIG["couleurs"][clecouleur],liste_err)
253 configuration["couleurs"][clecouleur] = coul
fd69b6b5 254
fd69b6b5 255
5679dfd0 256 return configuration
5679dfd0
DL
257
258
259def gere_donneespoids(data,naissance,liste_err):
260 """ prend en argument le dictionnaire de requête, et la date de naissance
261 (éventuellement vide) et construit les deux listes l_jours et l_poids"""
262
263 # On construit la liste des couples
264 liste_donnees = []
265
266 i = 0
267 # On va chercher si y'a des données à poids_i
268 while "poids_"+str(i) in data.keys():
269 if data["poids_"+str(i)] != "":
270 poids = convertit_poids_vers_python(data["poids_"+str(i)],liste_err)
271 age = data.get("age_"+str(i),"")
272 if age !="":
273 age = convertit_jours_vers_python(age,liste_err)
274 liste_donnees.append((age,poids))
275 else:
276 date = data.get("date_"+str(i),"")
277 datep = convertit_date_vers_python(date,liste_err)
278 # on vérifie la date
279 if naissance == "":
280 warning("La date de naissance n'a pas été précisée. Du coup on ne peut pas calculer l'âge de l'enfant le "+date,liste_err)
281 elif datep != "": # la date est valide et on a une date de naissance
282 age = delta_date(datep,naissance)
283 liste_donnees.append((age,poids))
284 i+=1
285
286 # Trier la liste
287 liste_donnees.sort(key=lambda x : x[0])
288
289 # splitter la liste
290 l_jours = [x[0] for x in liste_donnees]
291 l_poids = [x[1] for x in liste_donnees]
292
293 return (l_jours,l_poids)
be2bf515
DL
294
295
296
297
298def donnees_vers_json(l_jours,l_poids,config):
299 """ retourne le json à renvoyer"""
915e90bb 300 gros_dico = copy.deepcopy(config)
be2bf515
DL
301 l_jours2 = [convertit_age_vers_texte(d) for d in l_jours]
302 gros_dico["data_j"] = l_jours2
303 gros_dico["data_p"] = l_poids
304 # gérer la date de naissance
305 if gros_dico.get("naissance","") != "":
306 gros_dico["naissance"] = convertit_date_vers_texte(gros_dico["naissance"])
307 # gérer l'age maxi
308 gros_dico["maxi"] = convertit_age_vers_texte(gros_dico["maxi"])
fd69b6b5 309 # gérer les couleurs
915e90bb
DL
310# for cle in ["couleur1", "couleur2", "couleur3", "couleur_fond","couleur_grille","couleur_cadretxt"]:
311# gros_dico[cle] = tuple_vers_rgb(gros_dico[cle])
312 for clecouleur in DEFAUT["couleurs"]:
313 gros_dico["couleurs"][clecouleur] = tuple_vers_rgb(gros_dico["couleurs"][clecouleur])
fd69b6b5
DL
314
315
5679dfd0 316
be2bf515 317 return json.dumps(gros_dico, indent=2,ensure_ascii=False )
5679dfd0
DL
318
319
d03279e7
DL
320def fichier_json_vers_configdonnees(chaine,liste_err):
321 """ prend le json importé (chaine) et l'exporte vers les valeurs du formulaire """
322 debug("json vers config : Prêt à interpréter le json",liste_err)
323 try:
324 valform = json.loads(chaine)
325 except :
326 erreur("Impossible de lire le fichier json !",liste_err)
327 return {}
be2bf515
DL
328 # Il faut maintenant récupérer les l_jours et l_poids puis les remettre
329 # sous forme de age_i et poids_i
330 l_jours= valform.get("data_j",[])
331 l_poids=valform.get("data_p",[])
332 if len(l_poids) != len(l_jours):
333 warning("Lecture du json : les données sont incohérentes (listes de taille différentes et/ou pb de lecture")
334 long = min(len(l_jours),len(l_poids))
335 else:
336 long = len(l_jours)
337 for i in range(long):
338 valform["age_"+str(i)] = l_jours[i]
339 valform["poids_"+str(i)] = l_poids[i]
340
915e90bb 341 valform["nb_data"] = max(long +2,DEFAUT["nb_data"])
5679dfd0 342
be2bf515 343 return valform
5679dfd0 344
5679dfd0 345
be2bf515 346