Update opolka/ScoDoc from ScoDoc/ScoDoc #2

Merged
opolka merged 1272 commits from ScoDoc/ScoDoc:master into master 2024-05-27 09:11:04 +02:00
4 changed files with 94 additions and 81 deletions
Showing only changes of commit ef171364a6 - Show all commits

View File

@ -19,7 +19,7 @@ from app.models.departements import Departement
from app.models.scolar_event import ScolarEvent from app.models.scolar_event import ScolarEvent
from app.scodoc import notesdb as ndb from app.scodoc import notesdb as ndb
from app.scodoc.sco_bac import Baccalaureat from app.scodoc.sco_bac import Baccalaureat
from app.scodoc.sco_exceptions import ScoInvalidParamError, ScoValueError from app.scodoc.sco_exceptions import ScoGenError, ScoInvalidParamError, ScoValueError
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
@ -233,6 +233,15 @@ class Identite(models.ScoDocModel):
log(f"Identite.create {etud}") log(f"Identite.create {etud}")
return etud return etud
def from_dict(self, args, **kwargs) -> bool:
"""Check arguments, then modify.
Add to session but don't commit.
True if modification.
"""
check_etud_duplicate_code(args, "code_nip")
check_etud_duplicate_code(args, "code_ine")
return super().from_dict(args, **kwargs)
@classmethod @classmethod
def filter_model_attributes(cls, data: dict, excluded: set[str] = None) -> dict: def filter_model_attributes(cls, data: dict, excluded: set[str] = None) -> dict:
"""Returns a copy of dict with only the keys belonging to the Model and not in excluded.""" """Returns a copy of dict with only the keys belonging to the Model and not in excluded."""
@ -728,6 +737,60 @@ class Identite(models.ScoDocModel):
) )
def check_etud_duplicate_code(args, code_name, edit=True):
"""Vérifie que le code n'est pas dupliqué.
Raises ScoGenError si problème.
"""
etudid = args.get("etudid", None)
if not args.get(code_name, None):
return
etuds = Identite.query.filter_by(
**{code_name: str(args[code_name]), "dept_id": g.scodoc_dept_id}
).all()
duplicate = False
if edit:
duplicate = (len(etuds) > 1) or (
(len(etuds) == 1) and etuds[0].id != args["etudid"]
)
else:
duplicate = len(etuds) > 0
if duplicate:
listh = [] # liste des doubles
for etud in etuds:
listh.append(f"Autre étudiant: {etud.html_link_fiche()}")
if etudid:
submit_label = "retour à la fiche étudiant"
dest_endpoint = "scolar.fiche_etud"
parameters = {"etudid": etudid}
else:
if "tf_submitted" in args:
del args["tf_submitted"]
submit_label = "Continuer"
dest_endpoint = "scolar.etudident_create_form"
parameters = args
else:
submit_label = "Annuler"
dest_endpoint = "notes.index_html"
parameters = {}
err_page = f"""<h3><h3>Code étudiant ({code_name}) dupliqué !</h3>
<p class="help">Le {code_name} {args[code_name]} est déjà utilisé: un seul étudiant peut avoir
ce code. Vérifier votre valeur ou supprimer l'autre étudiant avec cette valeur.
</p>
<ul><li>
{ '</li><li>'.join(listh) }
</li></ul>
<p>
<a href="{ url_for(dest_endpoint, scodoc_dept=g.scodoc_dept, **parameters) }
">{submit_label}</a>
</p>
"""
log(f"*** error: code {code_name} duplique: {args[code_name]}")
raise ScoGenError(err_page)
def make_etud_args( def make_etud_args(
etudid=None, code_nip=None, use_request=True, raise_exc=False, abort_404=True etudid=None, code_nip=None, use_request=True, raise_exc=False, abort_404=True
) -> dict: ) -> dict:

View File

@ -39,6 +39,7 @@ from app import db, email
from app import log from app import log
from app.models import Admission, Identite from app.models import Admission, Identite
from app.models.etudiants import ( from app.models.etudiants import (
check_etud_duplicate_code,
input_civilite, input_civilite,
input_civilite_etat_civil, input_civilite_etat_civil,
make_etud_args, make_etud_args,
@ -229,74 +230,12 @@ def check_nom_prenom_homonyms(
return True, query.all() return True, query.all()
def _check_duplicate_code(cnx, args, code_name, disable_notify=False, edit=True):
"""Vérifie que le code n'est pas dupliqué.
Raises ScoGenError si problème.
"""
etudid = args.get("etudid", None)
if args.get(code_name, None):
etuds = identite_list(cnx, {code_name: str(args[code_name])})
duplicate = False
if edit:
duplicate = (len(etuds) > 1) or (
(len(etuds) == 1) and etuds[0]["id"] != args["etudid"]
)
else:
duplicate = len(etuds) > 0
if duplicate:
listh = [] # liste des doubles
for e in etuds:
listh.append(
f"""Autre étudiant: <a href="{
url_for(
"scolar.fiche_etud",
scodoc_dept=g.scodoc_dept,
etudid=e["etudid"]
)}">{e['nom']} {e['prenom']}</a>"""
)
if etudid:
OK = "retour à la fiche étudiant"
dest_endpoint = "scolar.fiche_etud"
parameters = {"etudid": etudid}
else:
if "tf_submitted" in args:
del args["tf_submitted"]
OK = "Continuer"
dest_endpoint = "scolar.etudident_create_form"
parameters = args
else:
OK = "Annuler"
dest_endpoint = "notes.index_html"
parameters = {}
if not disable_notify:
err_page = f"""<h3><h3>Code étudiant ({code_name}) dupliqué !</h3>
<p class="help">Le {code_name} {args[code_name]} est déjà utilisé: un seul étudiant peut avoir
ce code. Vérifier votre valeur ou supprimer l'autre étudiant avec cette valeur.
</p>
<ul><li>
{ '</li><li>'.join(listh) }
</li></ul>
<p>
<a href="{ url_for(dest_endpoint, scodoc_dept=g.scodoc_dept, **parameters) }
">{OK}</a>
</p>
"""
else:
err_page = f"""<h3>Code étudiant ({code_name}) dupliqué !</h3>"""
log(f"*** error: code {code_name} duplique: {args[code_name]}")
raise ScoGenError(err_page)
def identite_edit(cnx, args, disable_notify=False): def identite_edit(cnx, args, disable_notify=False):
"""Modifie l'identite d'un étudiant. """Modifie l'identite d'un étudiant.
Si pref notification et difference, envoie message notification, sauf si disable_notify Si pref notification et difference, envoie message notification, sauf si disable_notify
""" """
_check_duplicate_code( check_etud_duplicate_code(args, "code_nip", edit=True)
cnx, args, "code_nip", disable_notify=disable_notify, edit=True check_etud_duplicate_code(args, "code_ine", edit=True)
)
_check_duplicate_code(
cnx, args, "code_ine", disable_notify=disable_notify, edit=True
)
notify_to = None notify_to = None
if not disable_notify: if not disable_notify:
try: try:
@ -325,16 +264,14 @@ def identite_edit(cnx, args, disable_notify=False):
def identite_create(cnx, args): def identite_create(cnx, args):
"check unique etudid, then create" "check unique etudid, then create"
_check_duplicate_code(cnx, args, "code_nip", edit=False) check_etud_duplicate_code(args, "code_nip", edit=False)
_check_duplicate_code(cnx, args, "code_ine", edit=False) check_etud_duplicate_code(args, "code_ine", edit=False)
if "etudid" in args: if "etudid" in args:
etudid = args["etudid"] etudid = args["etudid"]
r = identite_list(cnx, {"etudid": etudid}) r = identite_list(cnx, {"etudid": etudid})
if r: if r:
raise ScoValueError( raise ScoValueError(f"Code identifiant (etudid) déjà utilisé ! ({etudid})")
"Code identifiant (etudid) déjà utilisé ! (%s)" % etudid
)
return _identiteEditor.create(cnx, args) return _identiteEditor.create(cnx, args)

View File

@ -508,15 +508,20 @@ def students_import_admission(
H = [html_sco_header.sco_header(page_title="Import données admissions")] H = [html_sco_header.sco_header(page_title="Import données admissions")]
H.append("<p>Import terminé !</p>") H.append("<p>Import terminé !</p>")
H.append( H.append(
'<p><a class="stdlink" href="%s">Continuer</a></p>' f"""<p><a class="stdlink" href="{ url_for(
% url_for(
"notes.formsemestre_status", "notes.formsemestre_status",
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
formsemestre_id=formsemestre_id, formsemestre_id=formsemestre_id,
) )
}">Continuer</a></p>"""
) )
if diag: if diag:
H.append("<p>Diagnostic: <ul><li>%s</li></ul></p>" % "</li><li>".join(diag)) H.append(
f"""<p>Diagnostic: <ul><li>{
"</li><li>".join(diag)
}</li></ul></p>
"""
)
return "\n".join(H) + html_sco_header.sco_footer() return "\n".join(H) + html_sco_header.sco_footer()

View File

@ -2306,23 +2306,31 @@ def form_students_import_infos_admissions(formsemestre_id=None):
html_sco_header.sco_header( html_sco_header.sco_header(
page_title="Export données admissions (Parcoursup ou autre)", page_title="Export données admissions (Parcoursup ou autre)",
), ),
"""<h2 class="formsemestre">Téléchargement des informations sur l'admission des étudiants</h2> f"""<h2 class="formsemestre">Téléchargement des informations sur l'admission
des étudiants</h2>
<p> <p>
<a href="import_generate_admission_sample?formsemestre_id=%(formsemestre_id)s">Exporter les informations de ScoDoc (classeur Excel)</a> (ce fichier peut être -importé après d'éventuelles modifications) <a href="{ url_for('scolar.import_generate_admission_sample',
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id )
}">Exporter les informations de ScoDoc (classeur Excel)</a> (ce fichier
peut être -importé après d'éventuelles modifications)
</p> </p>
<p class="warning">Vous n'avez pas le droit d'importer les données</p> <p class="warning">Vous n'avez pas le droit d'importer les données</p>
""" """,
% {"formsemestre_id": formsemestre_id},
] ]
return "\n".join(H) + F return "\n".join(H) + F
# On a le droit d'importer: # On a le droit d'importer:
H = [ H = [
html_sco_header.sco_header(page_title="Import données admissions Parcoursup"), html_sco_header.sco_header(page_title="Import données admissions Parcoursup"),
f"""<h2 class="formsemestre">Téléchargement des informations sur l'admission des étudiants depuis feuilles import Parcoursup</h2> f"""<h2 class="formsemestre">Téléchargement des informations sur l'admission des étudiants
<div style="color: red"> depuis feuilles import Parcoursup</h2>
<p>A utiliser pour renseigner les informations sur l'origine des étudiants (lycées, bac, etc). Ces informations sont facultatives mais souvent utiles pour mieux connaitre les étudiants et aussi pour effectuer des statistiques (résultats suivant le type de bac...). Les données sont affichées sur les fiches individuelles des étudiants.</p> <div style="color: red">
</div> <p>A utiliser pour renseigner les informations sur l'origine des étudiants (lycées, bac, etc).
Ces informations sont facultatives mais souvent utiles pour mieux connaitre les étudiants
et aussi pour effectuer des statistiques (résultats suivant le type de bac...).
Les données sont affichées sur les fiches individuelles des étudiants.
</p>
</div>
<p> <p>
Importer ici la feuille excel utilisée pour envoyer le classement Parcoursup. Importer ici la feuille excel utilisée pour envoyer le classement Parcoursup.
Seuls les étudiants actuellement inscrits dans ce semestre ScoDoc seront affectés, Seuls les étudiants actuellement inscrits dans ce semestre ScoDoc seront affectés,