diff --git a/app/scodoc/sco_portal_apogee.py b/app/scodoc/sco_portal_apogee.py
index 4da1700b3..d0ef82c4a 100644
--- a/app/scodoc/sco_portal_apogee.py
+++ b/app/scodoc/sco_portal_apogee.py
@@ -202,8 +202,7 @@ def get_inscrits_etape(
return False
else:
log(
- "get_inscrits_etape: pas inscription dans code_etape=%s e=%s"
- % (code_etape, e)
+ "get_inscrits_etape: pas inscription dans code_etape={code_etape} e={e}"
)
return False # ??? pas d'annee d'inscription dans la réponse
@@ -215,8 +214,7 @@ def get_inscrits_etape(
def query_apogee_portal(**args):
"""Recupere les infos sur les etudiants nommés
- args: nom, prenom, code_nip
- (nom et prenom matchent des parties de noms)
+ args: nom, prenom, code_ine, code_nip
"""
etud_url = get_etud_url()
api_ver = get_portal_api_version()
@@ -225,7 +223,6 @@ def query_apogee_portal(**args):
if api_ver > 1:
if args["nom"] or args["prenom"]:
# Ne fonctionne pas avec l'API 2 sur nom et prenom
- # XXX TODO : va poser problème pour la page modif données étudiants : A VOIR
return []
portal_timeout = sco_preferences.get_preference("portal_timeout")
req = etud_url + "?" + urllib.parse.urlencode(list(args.items()))
@@ -243,22 +240,21 @@ def xml_to_list_of_dicts(doc, req=None):
"& ": "& ", # only when followed by a space (avoid affecting entities)
# to be completed...
}
- for k in invalid_entities:
- doc = doc.replace(k, invalid_entities[k])
+ for k, repl in invalid_entities.items():
+ doc = doc.replace(k, repl)
#
try:
dom = xml.dom.minidom.parseString(doc)
- except xml.parsers.expat.ExpatError as e:
+ except xml.parsers.expat.ExpatError as exc:
# Find faulty part
- err_zone = doc.splitlines()[e.lineno - 1][e.offset : e.offset + 20]
+ err_zone = doc.splitlines()[exc.lineno - 1][exc.offset : exc.offset + 20]
# catch bug: log and re-raise exception
log(
- "xml_to_list_of_dicts: exception in XML parseString\ndoc:\n%s\n(end xml doc)\n"
- % doc
+ f"xml_to_list_of_dicts: exception in XML parseString\ndoc:\n{doc}\n(end xml doc)\n"
)
raise ScoValueError(
- 'erreur dans la réponse reçue du portail ! (peut être : "%s")' % err_zone
- )
+ f'erreur dans la réponse reçue du portail ! (peut être : "{err_zone}")'
+ ) from exc
infos = []
try:
if dom.childNodes[0].nodeName != "etudiants":
@@ -267,17 +263,19 @@ def xml_to_list_of_dicts(doc, req=None):
for etudiant in etudiants:
d = {}
# recupere toutes les valeurs XXX
- for e in etudiant.childNodes:
- if e.nodeType == e.ELEMENT_NODE:
- childs = e.childNodes
+ for exc in etudiant.childNodes:
+ if exc.nodeType == exc.ELEMENT_NODE:
+ childs = exc.childNodes
if len(childs):
- d[str(e.nodeName)] = childs[0].nodeValue
+ d[str(exc.nodeName)] = childs[0].nodeValue
infos.append(d)
- except:
+ except Exception as exc:
log("*** invalid XML response from Etudiant Web Service")
- log("req=%s" % req)
- log("doc=%s" % doc)
- raise ValueError("invalid XML response from Etudiant Web Service\n%s" % doc)
+ log(f"req={req}")
+ log(f"doc={doc}")
+ raise ValueError(
+ f"invalid XML response from Etudiant Web Service\n{doc}"
+ ) from exc
return infos
@@ -301,8 +299,8 @@ def get_infos_apogee_allaccents(nom, prenom):
return infos
-def get_infos_apogee(nom, prenom):
- """recupere les codes Apogee en utilisant le web service CRIT"""
+def get_etuds_apogee_for_nom_prenom(nom: str, prenom: str) -> list[dict]:
+ """Récupere les codes Apogee en utilisant le portail Apogée"""
if (not nom) and (not prenom):
return []
# essaie plusieurs codages: tirets, accents
@@ -326,27 +324,27 @@ def get_infos_apogee(nom, prenom):
return infos
-def get_etud_apogee(code_nip):
+def get_etuds_apogee_from_nip(code_nip: str) -> list[dict]:
"""Informations à partir du code NIP.
- None si pas d'infos sur cet etudiant.
+ Liste des étudiants ayant ce code NIP.
Exception si reponse invalide.
"""
if not code_nip:
- return {}
+ return []
etud_url = get_etud_url()
if not etud_url:
- return {}
+ return []
portal_timeout = sco_preferences.get_preference("portal_timeout")
req = etud_url + "?" + urllib.parse.urlencode((("nip", code_nip),))
doc = scu.query_portal(req, timeout=portal_timeout)
d = _normalize_apo_fields(xml_to_list_of_dicts(doc, req=req))
if not d:
- return None
+ return []
if len(d) > 1:
- log(f"get_etud_apogee({code_nip}): {len(d)} etudiants !\n{doc}")
- flash("Attention: plusieurs étudiants inscrits avec le NIP {code_nip}")
+ log(f"get_etuds_apogee_from_nip({code_nip}): {len(d)} etudiants !\n{doc}")
+ flash(f"Attention: plusieurs étudiants inscrits avec le NIP {code_nip}")
# dans ce cas, renvoie le premier étudiant
- return d[0]
+ return d
def get_default_etapes():
@@ -413,14 +411,14 @@ def get_etapes_apogee():
SCO_CACHE_ETAPE_FILENAME, "w", encoding=scu.SCO_ENCODING
) as f:
f.write(doc)
- except:
+ except Exception:
log(f"invalid XML response from getEtapes Web Service\n{etapes_url}")
# Avons-nous la copie d'une réponse récente ?
try:
doc = open(SCO_CACHE_ETAPE_FILENAME, encoding=scu.SCO_ENCODING).read()
infos = _parse_etapes_from_xml(doc)
log(f"using last saved version from {SCO_CACHE_ETAPE_FILENAME}")
- except:
+ except Exception:
infos = {}
else:
# Pas de portail: utilise étapes par défaut livrées avec ScoDoc
@@ -452,7 +450,7 @@ def get_etapes_apogee_dept():
xml_etapes_by_dept = sco_preferences.get_preference("xml_etapes_by_dept")
if xml_etapes_by_dept:
portal_dept_name = sco_preferences.get_preference("portal_dept_name")
- log('get_etapes_apogee_dept: portal_dept_name="%s"' % portal_dept_name)
+ log(f'get_etapes_apogee_dept: portal_dept_name="{portal_dept_name}"')
else:
portal_dept_name = ""
log("get_etapes_apogee_dept: pas de sections par departement")
@@ -460,8 +458,7 @@ def get_etapes_apogee_dept():
infos = get_etapes_apogee()
if portal_dept_name and portal_dept_name not in infos:
log(
- "get_etapes_apogee_dept: pas de section '%s' dans la reponse portail"
- % portal_dept_name
+ f"get_etapes_apogee_dept: pas de section '{portal_dept_name}' dans la reponse portail"
)
return []
if portal_dept_name:
@@ -469,8 +466,8 @@ def get_etapes_apogee_dept():
else:
# prend toutes les etapes
etapes = []
- for k in infos.keys():
- etapes += list(infos[k].items())
+ for info in infos.values():
+ etapes += list(info.items())
etapes.sort() # tri sur le code etape
return etapes
@@ -571,8 +568,8 @@ def check_paiement_etuds(etuds):
etud["etape"] = None
else:
# Modifie certains champs de l'étudiant:
- infos = get_etud_apogee(etud["code_nip"])
- if infos:
+ etuds_apo = get_etuds_apogee_from_nip(etud["code_nip"])
+ if etuds_apo:
for k in (
"paiementinscription",
"paiementinscription_str",
@@ -580,7 +577,7 @@ def check_paiement_etuds(etuds):
"datefinalisationinscription_str",
"etape",
):
- etud[k] = infos[k]
+ etud[k] = etuds_apo[0][k]
else:
etud["datefinalisationinscription"] = None
etud["datefinalisationinscription_str"] = "Erreur"
diff --git a/app/scodoc/sco_synchro_etuds.py b/app/scodoc/sco_synchro_etuds.py
index 4f7168f61..80f8fcf16 100644
--- a/app/scodoc/sco_synchro_etuds.py
+++ b/app/scodoc/sco_synchro_etuds.py
@@ -837,7 +837,7 @@ def formsemestre_import_etud_admission(
# Essaie de recuperer les etudiants des étapes, car
# la requete get_inscrits_etape est en général beaucoup plus
- # rapide que les requetes individuelles get_etud_apogee
+ # rapide que les requetes individuelles get_etuds_apogee_from_nip
annee_apogee = str(
scu.annee_scolaire_debut(sem["annee_debut"], sem["mois_debut_ord"])
)
@@ -858,7 +858,8 @@ def formsemestre_import_etud_admission(
data_apo = apo_etuds.get(code_nip)
if not data_apo:
# pas vu dans les etudiants de l'étape, tente en individuel
- data_apo = sco_portal_apogee.get_etud_apogee(code_nip)
+ etuds_apo = sco_portal_apogee.get_etuds_apogee_from_nip(code_nip)
+ data_apo = etuds_apo[0] if etuds_apo else None
if data_apo:
update_etape_formsemestre_inscription(i, data_apo)
do_import_etud_admission(
diff --git a/app/views/scolar.py b/app/views/scolar.py
index ae2c6ef98..756b051e1 100644
--- a/app/views/scolar.py
+++ b/app/views/scolar.py
@@ -1374,15 +1374,17 @@ def _etudident_create_or_edit_form(edit):
submitlabel = "Ajouter cet étudiant"
H.append(
"""
Création d'un étudiant
- En général, il est recommandé d'importer les
- étudiants depuis Apogée ou via un fichier Excel (menu Inscriptions
- dans le semestre).
-
-
- N'utilisez ce formulaire au cas par cas que pour les cas particuliers
- ou si votre établissement n'utilise pas d'autre logiciel de gestion des
- inscriptions.
-
+ Attention
+
En général, il est recommandé d'importer les
+ étudiants depuis Apogée ou via un fichier Excel (menu Inscriptions
+ dans le semestre).
+
+
+ N'utilisez ce formulaire au cas par cas que pour les cas particuliers
+ ou si votre établissement n'utilise pas d'autre logiciel de gestion des
+ inscriptions.
+
+
L'étudiant créé ne sera pas inscrit.
Pensez à l'inscrire dans un semestre !
"""
@@ -1395,63 +1397,13 @@ def _etudident_create_or_edit_form(edit):
etud_o: Identite = Identite.get_etud(etudid)
descr.append(("etudid", {"default": etudid, "input_type": "hidden"}))
H.append(f"""Modification des données de {etud_o.html_link_fiche()}
""")
- initvalues = sco_etud.etudident_list(cnx, {"etudid": etudid})
+ initvalues = sco_etud.etudident_list(cnx, {"etudid": etudid}) # XXX TODO
assert len(initvalues) == 1
initvalues = initvalues[0]
submitlabel = "Modifier les données"
+ infos_apogee_html = _infos_apogee_html_etuds(scu.get_request_args(), initvalues)
vals = scu.get_request_args()
- nom = vals.get("nom", None)
- if nom is None:
- nom = initvalues.get("nom", None)
- if nom is None:
- infos = []
- else:
- prenom = vals.get("prenom", "")
- if vals.get("tf_submitted", False) and not prenom:
- prenom = initvalues.get("prenom", "")
- infos = sco_portal_apogee.get_infos_apogee(nom, prenom)
-
- if infos:
- formatted_infos = [
- """
-
- """
- ]
- nanswers = len(infos)
- nmax = 10 # nb max de reponse montrées
- infos = infos[:nmax]
- for i in infos:
- formatted_infos.append("")
- for k in i.keys():
- if k != "nip":
- item = "- %s : %s
" % (k, i[k])
- else:
- item = (
- ''
- % (k, i[k], i[k])
- )
- formatted_infos.append(item)
-
- formatted_infos.append("
")
- formatted_infos.append("
")
- m = "%d étudiants trouvés" % nanswers
- if len(infos) != nanswers:
- m += " (%d montrés)" % len(infos)
- A = """
-
Informations Apogée
-
%s
- %s
-
""" % (
- m,
- "\n".join(formatted_infos),
- )
- else:
- A = """Pas d'informations d'Apogée
"""
require_ine = sco_preferences.get_preference("always_require_ine")
@@ -1727,7 +1679,7 @@ def _etudident_create_or_edit_form(edit):
if tf[0] in (0, -1):
return render_template(
"sco_page_dept.j2",
- content="\n".join(H) + tf[1] + "" + A,
+ content="\n".join(H) + tf[1] + infos_apogee_html,
title="Création/édition d'étudiant",
)
else:
@@ -1746,8 +1698,7 @@ def _etudident_create_or_edit_form(edit):
content="\n".join(H)
+ tf_error_message("Nom ou prénom invalide")
+ tf[1]
- + "
"
- + A,
+ + infos_apogee_html,
title="Création/édition d'étudiant",
)
if not tf[2]["dont_check_homonyms"] and nb_homonyms > 0:
@@ -1773,9 +1724,8 @@ def _etudident_create_or_edit_form(edit):
"""
)
+ tf[1]
- + "
"
- + A
+ homonyms_html
+ + infos_apogee_html
),
)
tf[2]["date_naissance"] = (
@@ -1796,19 +1746,70 @@ def _etudident_create_or_edit_form(edit):
etud_o.admission = admission
admission.from_dict(tf[2])
db.session.commit()
-
- etud = sco_etud.etudident_list(cnx, {"etudid": etud_o.id})[0]
- sco_etud.fill_etuds_info([etud])
- # Inval semesters with this student:
- to_inval = [s["formsemestre_id"] for s in etud["sems"]]
- for formsemestre_id in to_inval:
- sco_cache.invalidate_formsemestre(formsemestre_id=formsemestre_id)
- #
+ # Inval semesters with this student:
+ for inscription in etud_o.formsemestre_inscriptions:
+ sco_cache.invalidate_formsemestre(
+ formsemestre_id=inscription.formsemestre_id
+ )
+ #
return flask.redirect(
url_for("scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etudid)
)
+def _infos_apogee_html_etuds(vals: dict, initvalues: dict) -> str:
+ "fragment de html pour lister les étudiants correspondants"
+ nom = vals.get("nom", initvalues.get("nom", None))
+ nip = vals.get("code_nip", initvalues.get("code_nip", "")).strip()
+ if nom is None and nip is None:
+ etuds_apo = []
+ elif nip:
+ etuds_apo = sco_portal_apogee.get_etuds_apogee_from_nip(nip)
+ else:
+ prenom = vals.get("prenom", "")
+ if vals.get("tf_submitted", False) and not prenom:
+ prenom = initvalues.get("prenom", "")
+ etuds_apo = sco_portal_apogee.get_etuds_apogee_for_nom_prenom(nom, prenom)
+
+ if etuds_apo:
+ formatted_infos = [
+ """
+
+
"""
+ ]
+ nanswers = len(etuds_apo)
+ nmax = 10 # nb max de réponse montrées
+ etuds_apo = etuds_apo[:nmax]
+ for i in etuds_apo:
+ formatted_infos.append("")
+ for k in i.keys():
+ if k != "nip":
+ item = f"- {k} : {i[k]}
"
+ else:
+ item = f"""-
+
"""
+ formatted_infos.append(item)
+
+ formatted_infos.append("
")
+ formatted_infos.append("
")
+ m = f"{nanswers} étudiants trouvés"
+ if len(etuds_apo) != nanswers:
+ m += " ({len(etuds_apo)} affichés)"
+ return f"""
+
+
Informations Apogée
+
{m}
+ {''.join(formatted_infos)}
+
"""
+ return """Pas d'informations d'Apogée
"""
+
+
@bp.route("/etud_copy_in_other_dept/", methods=["GET", "POST"])
@scodoc
@permission_required(
@@ -1985,7 +1986,7 @@ def check_group_apogee(group_id, etat=None, fix=False, fixmail=False):
t["email"],
t["code_nip"],
)
- infos = sco_portal_apogee.get_infos_apogee(nom, prenom)
+ infos = sco_portal_apogee.get_etuds_apogee_for_nom_prenom(nom, prenom)
if not infos:
info_apogee = f"""Pas d'information
(