diff --git a/app/comp/res_common.py b/app/comp/res_common.py index d43f597ec..2298842f8 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -926,7 +926,7 @@ class ResultatsSemestre(ResultatsCache): group = None # group (dict) de l'étudiant dans cette partition # dans NotesTableCompat, à revoir etud_etat = self.get_etud_etat(row["etudid"]) - if etud_etat == "D": + if etud_etat == scu.DEMISSION: gr_name = "Dém." row["_tr_class"] = "dem" elif etud_etat == DEF: diff --git a/app/models/validations.py b/app/models/validations.py index b24685a87..fb470b974 100644 --- a/app/models/validations.py +++ b/app/models/validations.py @@ -156,8 +156,16 @@ class ScolarEvent(db.Model): db.Integer, db.ForeignKey("notes_formsemestre.id"), ) + etud = db.relationship("Identite", lazy="select", backref="events", uselist=False) + formsemestre = db.relationship( + "FormSemestre", lazy="select", uselist=False, foreign_keys=[formsemestre_id] + ) def to_dict(self) -> dict: + "as a dict" d = dict(self.__dict__) d.pop("_sa_instance_state", None) return d + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.event_type}, {self.event_date.isoformat()}, {self.formsemestre})" diff --git a/app/pe/pe_semestretag.py b/app/pe/pe_semestretag.py index 0a7adcaba..bed334656 100644 --- a/app/pe/pe_semestretag.py +++ b/app/pe/pe_semestretag.py @@ -41,10 +41,11 @@ from app.comp import res_sem from app.comp.res_compat import NotesTableCompat from app.models import FormSemestre from app.models.moduleimpls import ModuleImpl +from app.pe import pe_tagtable from app.scodoc import sco_codes_parcours from app.scodoc import sco_tag_module -from app.pe import pe_tagtable +from app.scodoc import sco_utils as scu class SemestreTag(pe_tagtable.TableTag): @@ -103,7 +104,7 @@ class SemestreTag(pe_tagtable.TableTag): self.inscrlist = [ etud for etud in self.nt.inscrlist - if self.nt.get_etud_etat(etud["etudid"]) == "I" + if self.nt.get_etud_etat(etud["etudid"]) == scu.INSCRIT ] self.identdict = { etudid: ident diff --git a/app/scodoc/notes_table.py b/app/scodoc/notes_table.py index 56f2b93e3..a8322f166 100644 --- a/app/scodoc/notes_table.py +++ b/app/scodoc/notes_table.py @@ -411,9 +411,9 @@ class NotesTable: def get_etud_etat_html(self, etudid): etat = self.inscrdict[etudid]["etat"] - if etat == "I": + if etat == scu.INSCRIT: return "" - elif etat == "D": + elif etat == scu.DEMISSION: return ' (DEMISSIONNAIRE) ' elif etat == DEF: return ' (DEFAILLANT) ' @@ -465,7 +465,7 @@ class NotesTable: vals = [] for etudid in self.get_etudids(): # saute les demissionnaires et les défaillants: - if self.inscrdict[etudid]["etat"] != "I": + if self.inscrdict[etudid]["etat"] != scu.INSCRIT: continue val = moys.get(etudid, None) # None si non inscrit try: @@ -507,8 +507,8 @@ class NotesTable: for t in T: etudid = t[-1] # saute les demissionnaires et les défaillants: - if self.inscrdict[etudid]["etat"] != "I": - if self.inscrdict[etudid]["etat"] == "D": + if self.inscrdict[etudid]["etat"] != scu.INSCRIT: + if self.inscrdict[etudid]["etat"] == scu.DEMISSION: nb_dem += 1 if self.inscrdict[etudid]["etat"] == DEF: nb_def += 1 diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index 227349328..ae2cc60dd 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -435,11 +435,11 @@ def get_appreciations_list(formsemestre_id: int, etudid: int) -> dict: def _get_etud_etat_html(etat: str) -> str: """chaine html représentant l'état (backward compat sco7)""" - if etat == scu.INSCRIT: # "I" + if etat == scu.INSCRIT: return "" - elif etat == scu.DEMISSION: # "D" + elif etat == scu.DEMISSION: return ' (DEMISSIONNAIRE) ' - elif etat == scu.DEF: # "DEF" + elif etat == scu.DEF: return ' (DEFAILLANT) ' else: return f' ({etat}) ' diff --git a/app/scodoc/sco_cursus_dut.py b/app/scodoc/sco_cursus_dut.py index f4354c6f1..32d4796b9 100644 --- a/app/scodoc/sco_cursus_dut.py +++ b/app/scodoc/sco_cursus_dut.py @@ -360,7 +360,7 @@ class SituationEtudCursusClassic(SituationEtudCursus): cur_begin_date = self.sem["dateord"] p = [] for s in self.sems: - if s["ins"]["etat"] == "D": + if s["ins"]["etat"] == scu.DEMISSION: dem = " (dem.)" else: dem = "" diff --git a/app/scodoc/sco_etud.py b/app/scodoc/sco_etud.py index 096cc8490..bb869d5a9 100644 --- a/app/scodoc/sco_etud.py +++ b/app/scodoc/sco_etud.py @@ -1010,7 +1010,7 @@ def descr_situation_etud(etudid: int, ne="") -> str: situation = "non inscrit" + ne else: sem = sco_formsemestre.get_formsemestre(r["formsemestre_id"]) - if r["etat"] == "I": + if r["etat"] == scu.INSCRIT: situation = "inscrit%s en %s" % (ne, sem["titremois"]) # Cherche la date d'inscription dans scolar_events: events = scolar_events_list( diff --git a/app/scodoc/sco_formsemestre_exterieurs.py b/app/scodoc/sco_formsemestre_exterieurs.py index baec914d8..c33b7309f 100644 --- a/app/scodoc/sco_formsemestre_exterieurs.py +++ b/app/scodoc/sco_formsemestre_exterieurs.py @@ -117,7 +117,7 @@ def formsemestre_ext_create_form(etudid, formsemestre_id): # Les autres situations (eg redoublements en changeant d'établissement) # doivent être gérées par les validations de semestres "antérieurs" insem = sco_formsemestre_inscriptions.do_formsemestre_inscription_list( - args={"etudid": etudid, "etat": "I"} + args={"etudid": etudid, "etat": scu.INSCRIT} ) semlist = [sco_formsemestre.get_formsemestre(i["formsemestre_id"]) for i in insem] existing_semestre_ids = {s["semestre_id"] for s in semlist} diff --git a/app/scodoc/sco_formsemestre_inscriptions.py b/app/scodoc/sco_formsemestre_inscriptions.py index 8236f2ab7..540282e9c 100644 --- a/app/scodoc/sco_formsemestre_inscriptions.py +++ b/app/scodoc/sco_formsemestre_inscriptions.py @@ -32,11 +32,13 @@ import time import flask from flask import flash, url_for, g, request +from app import db from app.comp import res_sem from app.comp.res_compat import NotesTableCompat -from app.models import Formation, FormSemestre, FormSemestreInscription +from app.models import Formation, FormSemestre, FormSemestreInscription, Scolog from app.models.etudiants import Identite from app.models.groups import GroupDescr +from app.models.validations import ScolarEvent import app.scodoc.sco_utils as scu from app import log from app.scodoc.scolog import logdb @@ -77,7 +79,7 @@ def do_formsemestre_inscription_listinscrits(formsemestre_id): if r is None: # retreive list r = do_formsemestre_inscription_list( - args={"formsemestre_id": formsemestre_id, "etat": "I"} + args={"formsemestre_id": formsemestre_id, "etat": scu.INSCRIT} ) sco_cache.SemInscriptionsCache.set(formsemestre_id, r) return r @@ -133,36 +135,51 @@ def do_formsemestre_demission( etudid, formsemestre_id, event_date=None, - etat_new="D", # 'D' or DEF - operation_method="demEtudiant", + etat_new=scu.DEMISSION, # DEMISSION or DEF + operation_method="dem_etudiant", event_type="DEMISSION", ): "Démission ou défaillance d'un étudiant" # marque 'D' ou DEF dans l'inscription au semestre et ajoute # un "evenement" scolarite - cnx = ndb.GetDBConnexion() + if etat_new not in (scu.DEF, scu.DEMISSION): + raise ScoValueError("nouveau code d'état invalide") + try: + event_date_iso = ndb.DateDMYtoISO(event_date) + except ValueError as exc: + raise ScoValueError("format de date invalide") from exc + etud: Identite = Identite.query.filter_by( + id=etudid, dept_id=g.scodoc_dept_id + ).first_or_404() # check lock - sem = sco_formsemestre.get_formsemestre(formsemestre_id) - if not sem["etat"]: + formsemestre: FormSemestre = FormSemestre.query.filter_by( + id=formsemestre_id, dept_id=g.scodoc_dept_id + ).first_or_404() + if not formsemestre.etat: raise ScoValueError("Modification impossible: semestre verrouille") # - ins = do_formsemestre_inscription_list( - {"etudid": etudid, "formsemestre_id": formsemestre_id} - )[0] - if not ins: - raise ScoException("etudiant non inscrit ?!") - ins["etat"] = etat_new - do_formsemestre_inscription_edit(args=ins, formsemestre_id=formsemestre_id) - logdb(cnx, method=operation_method, etudid=etudid) - sco_etud.scolar_events_create( - cnx, - args={ - "etudid": etudid, - "event_date": event_date, - "formsemestre_id": formsemestre_id, - "event_type": event_type, - }, + if formsemestre_id not in (inscr.formsemestre_id for inscr in etud.inscriptions()): + raise ScoValueError("étudiant non inscrit dans ce semestre !") + inscr = next( + inscr + for inscr in etud.inscriptions() + if inscr.formsemestre_id == formsemestre_id ) + inscr.etat = etat_new + db.session.add(inscr) + Scolog.logdb(method=operation_method, etudid=etudid) + event = ScolarEvent( + etudid=etudid, + event_date=event_date_iso, + formsemestre_id=formsemestre_id, + event_type=event_type, + ) + db.session.add(event) + db.session.commit() + if etat_new == scu.DEMISSION: + flash("Démission enregistrée") + elif etat_new == scu.DEF: + flash("Défaillance enregistrée") def do_formsemestre_inscription_edit(args=None, formsemestre_id=None): @@ -250,7 +267,7 @@ def do_formsemestre_inscription_with_modules( formsemestre_id, etudid, group_ids=[], - etat="I", + etat=scu.INSCRIT, etape=None, method="inscription_with_modules", ): @@ -467,7 +484,7 @@ def formsemestre_inscription_with_modules( formsemestre_id, etudid, group_ids=group_ids, - etat="I", + etat=scu.INSCRIT, method="formsemestre_inscription_with_modules", ) return flask.redirect( diff --git a/app/scodoc/sco_formsemestre_validation.py b/app/scodoc/sco_formsemestre_validation.py index 177b97581..f129a36a2 100644 --- a/app/scodoc/sco_formsemestre_validation.py +++ b/app/scodoc/sco_formsemestre_validation.py @@ -191,11 +191,11 @@ def formsemestre_validation_etud_form( ) etud_etat = nt.get_etud_etat(etudid) - if etud_etat == "D": + if etud_etat == scu.DEMISSION: H.append('
Etudiant démissionnaire
') - if etud_etat == DEF: + if etud_etat == scu.DEF: H.append('
Etudiant défaillant
') - if etud_etat != "I": + if etud_etat != scu.INSCRIT: H.append( tf_error_message( f"""Impossible de statuer sur cet étudiant: @@ -357,7 +357,7 @@ def formsemestre_validation_etud_form( H.append( f"""""" ) @@ -910,7 +910,7 @@ def do_formsemestre_validation_auto(formsemestre_id): )[0] # Conditions pour validation automatique: - if ins["etat"] == "I" and ( + if ins["etat"] == scu.INSCRIT and ( ( (not Se.prev) or ( diff --git a/app/scodoc/sco_groups.py b/app/scodoc/sco_groups.py index ffee6a7e6..4da76d313 100644 --- a/app/scodoc/sco_groups.py +++ b/app/scodoc/sco_groups.py @@ -308,9 +308,9 @@ def get_group_infos(group_id, etat=None): # was _getlisteetud # add human readable description of state: nbdem = 0 for t in members: - if t["etat"] == "I": + if t["etat"] == scu.INSCRIT: t["etath"] = "" # etudiant inscrit, ne l'indique pas dans la liste HTML - elif t["etat"] == "D": + elif t["etat"] == scu.DEMISSION: events = sco_etud.scolar_events_list( cnx, args={ diff --git a/app/scodoc/sco_import_etuds.py b/app/scodoc/sco_import_etuds.py index 53b4563d8..89338e8bc 100644 --- a/app/scodoc/sco_import_etuds.py +++ b/app/scodoc/sco_import_etuds.py @@ -545,7 +545,7 @@ def _import_one_student( args["description"] = "(infos admission)" _ = sco_etud.adresse_create(cnx, args) # Inscription au semestre - args["etat"] = "I" # etat insc. semestre + args["etat"] = scu.INSCRIT # etat insc. semestre if formsemestre_id: args["formsemestre_id"] = formsemestre_id else: @@ -576,7 +576,7 @@ def _import_one_student( int(args["formsemestre_id"]), etudid, group_ids, - etat="I", + etat=scu.INSCRIT, method="import_csv_file", ) return args["formsemestre_id"] diff --git a/app/scodoc/sco_inscr_passage.py b/app/scodoc/sco_inscr_passage.py index 6ab1baf10..2d3b644f0 100644 --- a/app/scodoc/sco_inscr_passage.py +++ b/app/scodoc/sco_inscr_passage.py @@ -175,12 +175,12 @@ def do_inscrit(sem, etudids, inscrit_groupes=False): (la liste doit avoir été vérifiée au préalable) En option: inscrit aux mêmes groupes que dans le semestre origine """ - log("do_inscrit (inscrit_groupes=%s): %s" % (inscrit_groupes, etudids)) + log(f"do_inscrit (inscrit_groupes={inscrit_groupes}): {etudids}") for etudid in etudids: sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules( sem["formsemestre_id"], etudid, - etat="I", + etat=scu.INSCRIT, method="formsemestre_inscr_passage", ) if inscrit_groupes: diff --git a/app/scodoc/sco_liste_notes.py b/app/scodoc/sco_liste_notes.py index 54d53e936..b3aeba7ad 100644 --- a/app/scodoc/sco_liste_notes.py +++ b/app/scodoc/sco_liste_notes.py @@ -325,11 +325,11 @@ def _make_table_notes( if etud is None: continue - if etat == "I": # si inscrit, indique groupe + if etat == scu.INSCRIT: # si inscrit, indique groupe groups = sco_groups.get_etud_groups(etudid, modimpl_o["formsemestre_id"]) grc = sco_groups.listgroups_abbrev(groups) else: - if etat == "D": + if etat == scu.DEMISSION: grc = "DEM" # attention: ce code est re-ecrit plus bas, ne pas le changer (?) css_row_class = "etuddem" else: diff --git a/app/scodoc/sco_page_etud.py b/app/scodoc/sco_page_etud.py index 79a33d0d5..12828e870 100644 --- a/app/scodoc/sco_page_etud.py +++ b/app/scodoc/sco_page_etud.py @@ -75,18 +75,18 @@ def _menuScolarite(authuser, sem, etudid): if ins["etat"] != "D": dem_title = "Démission" - dem_url = "scolar.formDem" + dem_url = "scolar.form_dem" else: dem_title = "Annuler la démission" - dem_url = "scolar.doCancelDem" + dem_url = "scolar.do_cancel_dem" # Note: seul un etudiant inscrit (I) peut devenir défaillant. if ins["etat"] != sco_codes_parcours.DEF: def_title = "Déclarer défaillance" - def_url = "scolar.formDef" + def_url = "scolar.form_def" elif ins["etat"] == sco_codes_parcours.DEF: def_title = "Annuler la défaillance" - def_url = "scolar.doCancelDef" + def_url = "scolar.do_cancel_def" def_enabled = ( (ins["etat"] != "D") and authuser.has_permission(Permission.ScoEtudInscrit) @@ -230,7 +230,7 @@ def ficheEtud(etudid=None): info["last_formsemestre_id"] = "" sem_info = {} for sem in info["sems"]: - if sem["ins"]["etat"] != "I": + if sem["ins"]["etat"] != scu.INSCRIT: descr, _ = etud_descr_situation_semestre( etudid, sem["formsemestre_id"], @@ -554,7 +554,7 @@ def menus_etud(etudid): }, { "title": "Changer la photo", - "endpoint": "scolar.formChangePhoto", + "endpoint": "scolar.form_change_photo", "args": {"etudid": etud["etudid"]}, "enabled": authuser.has_permission(Permission.ScoEtudChangeAdr), }, diff --git a/app/scodoc/sco_poursuite_dut.py b/app/scodoc/sco_poursuite_dut.py index 41b29259b..36e9ca0ec 100644 --- a/app/scodoc/sco_poursuite_dut.py +++ b/app/scodoc/sco_poursuite_dut.py @@ -115,7 +115,7 @@ def etud_get_poursuite_info(sem, etud): code_semestre_validant(dec["code"]) or code_semestre_attente(dec["code"]) ) - and nt.get_etud_etat(etudid) == "I" + and nt.get_etud_etat(etudid) == scu.INSCRIT ): d = [ ("moy", scu.fmt_note(nt.get_etud_moy_gen(etudid))), diff --git a/app/scodoc/sco_pvjury.py b/app/scodoc/sco_pvjury.py index 27427aebc..3edcf6607 100644 --- a/app/scodoc/sco_pvjury.py +++ b/app/scodoc/sco_pvjury.py @@ -350,7 +350,9 @@ def dict_pvjury( if Se.prev and Se.prev_decision: d["prev_decision_sem"] = Se.prev_decision d["prev_code"] = Se.prev_decision["code"] - d["prev_code_descr"] = _descr_decision_sem("I", Se.prev_decision) + d["prev_code_descr"] = _descr_decision_sem( + scu.INSCRIT, Se.prev_decision + ) d["prev"] = Se.prev has_prev = True else: diff --git a/app/scodoc/sco_report.py b/app/scodoc/sco_report.py index 6978e2eb3..31e9d90ef 100644 --- a/app/scodoc/sco_report.py +++ b/app/scodoc/sco_report.py @@ -1315,7 +1315,7 @@ def graph_parcours( s["semestre_id"] == nt.parcours.NB_SEM and dec and code_semestre_validant(dec["code"]) - and nt.get_etud_etat(etudid) == "I" + and nt.get_etud_etat(etudid) == scu.INSCRIT ): # cas particulier du diplome puis poursuite etude edges[ @@ -1360,7 +1360,7 @@ def graph_parcours( if ( dec and code_semestre_validant(dec["code"]) - and nt.get_etud_etat(etudid) == "I" + and nt.get_etud_etat(etudid) == scu.INSCRIT ): nid = sem_node_name(s, "_dipl_") edges[(sem_node_name(s), nid)].add(etudid) diff --git a/app/scodoc/sco_synchro_etuds.py b/app/scodoc/sco_synchro_etuds.py index 9c3887a73..bfcd0f81f 100644 --- a/app/scodoc/sco_synchro_etuds.py +++ b/app/scodoc/sco_synchro_etuds.py @@ -658,7 +658,7 @@ def do_import_etuds_from_portal(sem, a_importer, etudsapo_ident): sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules( sem["formsemestre_id"], args["etudid"], - etat="I", + etat=scu.INSCRIT, etape=args["etape"], method="synchro_apogee", ) diff --git a/app/scodoc/sco_trombino_tours.py b/app/scodoc/sco_trombino_tours.py index fd11da4e8..85867b1e8 100644 --- a/app/scodoc/sco_trombino_tours.py +++ b/app/scodoc/sco_trombino_tours.py @@ -145,7 +145,9 @@ def pdf_trombino_tours( for group_id in groups_infos.group_ids: if group_id != "None": - members, _, group_tit, sem, _ = sco_groups.get_group_infos(group_id, "I") + members, _, group_tit, sem, _ = sco_groups.get_group_infos( + group_id, scu.INSCRIT + ) groups += " %s" % group_tit L = [] currow = [] @@ -391,7 +393,7 @@ def pdf_feuille_releve_absences( ) for group_id in groups_infos.group_ids: - members, _, group_tit, _, _ = sco_groups.get_group_infos(group_id, "I") + members, _, group_tit, _, _ = sco_groups.get_group_infos(group_id, scu.INSCRIT) L = [] currow = [ diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index 296f22c94..ce001b544 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -1034,6 +1034,10 @@ div.sco_help { background-color: rgb(200, 200, 220); } +div.vertical_spacing_but { + margin-top: 12px; +} + span.wtf-field ul.errors li { color: red; } diff --git a/app/views/scolar.py b/app/views/scolar.py index ed8e93d72..505cff5be 100644 --- a/app/views/scolar.py +++ b/app/views/scolar.py @@ -52,12 +52,11 @@ from app.decorators import ( admin_required, login_required, ) -from app.models import formsemestre from app.models.etudiants import Identite from app.models.etudiants import make_etud_args -from app.models.events import ScolarNews +from app.models.events import ScolarNews, Scolog from app.models.formsemestre import FormSemestre - +from app.models.validations import ScolarEvent from app.views import scolar_bp as bp from app.views import ScoData @@ -972,11 +971,11 @@ def etud_photo_orig_page(etudid=None): return "\n".join(H) -@bp.route("/formChangePhoto", methods=["GET", "POST"]) +@bp.route("/form_change_photo", methods=["GET", "POST"]) @scodoc @permission_required(Permission.ScoEtudChangeAdr) @scodoc7func -def formChangePhoto(etudid=None): +def form_change_photo(etudid=None): """Formulaire changement photo étudiant""" etud = sco_etud.get_etud_info(filled=True)[0] if sco_photos.etud_photo_is_local(etud): @@ -1014,7 +1013,7 @@ def formChangePhoto(etudid=None): return ( "\n".join(H) + tf[1] - + '

Supprimer cette photo

' + + '

Supprimer cette photo

' % etudid + html_sco_header.sco_footer() ) @@ -1032,13 +1031,15 @@ def formChangePhoto(etudid=None): return "\n".join(H) + html_sco_header.sco_footer() -@bp.route("/formSuppressPhoto", methods=["POST", "GET"]) +@bp.route("/form_suppress_photo", methods=["POST", "GET"]) @scodoc @permission_required(Permission.ScoEtudChangeAdr) @scodoc7func -def formSuppressPhoto(etudid=None, dialog_confirmed=False): +def form_suppress_photo(etudid=None, dialog_confirmed=False): """Formulaire suppression photo étudiant""" - etud = Identite.query.get_or_404(etudid) + etud: Identite = Identite.query.filter_by( + id=etudid, dept_id=g.scodoc_dept_id + ).first_or_404() if not dialog_confirmed: return scu.confirm_dialog( f"

Confirmer la suppression de la photo de {etud.nom_disp()} ?

", @@ -1057,99 +1058,91 @@ def formSuppressPhoto(etudid=None, dialog_confirmed=False): # -@bp.route("/formDem") +@bp.route("/form_dem") @scodoc @permission_required(Permission.ScoEtudInscrit) @scodoc7func -def formDem(etudid, formsemestre_id): +def form_dem(etudid, formsemestre_id): "Formulaire Démission Etudiant" - return _formDem_of_Def( + return _form_dem_of_def( etudid, formsemestre_id, operation_name="Démission", - operation_method="doDemEtudiant", + operation_method="do_dem_etudiant", ) -@bp.route("/formDef") +@bp.route("/form_def") @scodoc @permission_required(Permission.ScoEtudInscrit) @scodoc7func -def formDef(etudid, formsemestre_id): +def form_def(etudid, formsemestre_id): "Formulaire Défaillance Etudiant" - return _formDem_of_Def( + return _form_dem_of_def( etudid, formsemestre_id, operation_name="Défaillance", - operation_method="doDefEtudiant", + operation_method="do_def_etudiant", ) -def _formDem_of_Def( - etudid, - formsemestre_id, - operation_name="", - operation_method="", +def _form_dem_of_def( + etudid: int, + formsemestre_id: int, + operation_name: str = "", + operation_method: str = "", ): "Formulaire démission ou défaillance Etudiant" - etud = sco_etud.get_etud_info(filled=True, etudid=etudid)[0] - sem = sco_formsemestre.get_formsemestre(formsemestre_id) - if not sem["etat"]: + etud: Identite = Identite.query.filter_by( + id=etudid, dept_id=g.scodoc_dept_id + ).first_or_404() + formsemestre: FormSemestre = FormSemestre.query.filter_by( + id=formsemestre_id, dept_id=g.scodoc_dept_id + ).first_or_404() + if not formsemestre.etat: raise ScoValueError("Modification impossible: semestre verrouille") - - etud["formsemestre_id"] = formsemestre_id - etud["semtitre"] = sem["titremois"] - etud["nowdmy"] = time.strftime("%d/%m/%Y") - etud["operation_name"] = operation_name + nowdmy = time.strftime("%d/%m/%Y") # header = html_sco_header.sco_header( - page_title="%(operation_name)s de %(nomprenom)s (du semestre %(semtitre)s)" - % etud, + page_title=f"""{operation_name} de {etud.nomprenom} (du semestre {formsemestre.titre_mois()})""" ) - H = [ - '

%(operation_name)s de %(nomprenom)s (semestre %(semtitre)s)

' - % etud - ] - H.append( - """

- Date de la %s (J/M/AAAA):  + return f""" + {header} +

{operation_name} de {etud.nomprenom} ({formsemestre.titre_mois()})

+ + +
Date de la {operation_name.lower()} (J/M/AAAA):  + +
+ + +
+
+ {html_sco_header.sco_footer()} """ - % (operation_method, operation_name.lower()) - ) - H.append( - """ - - - -

- -""" - % etud - ) - return header + "\n".join(H) + html_sco_header.sco_footer() -@bp.route("/doDemEtudiant") +@bp.route("/do_dem_etudiant") @scodoc @permission_required(Permission.ScoEtudInscrit) @scodoc7func -def doDemEtudiant(etudid, formsemestre_id, event_date=None): +def do_dem_etudiant(etudid, formsemestre_id, event_date=None): "Déclare la démission d'un etudiant dans le semestre" return _do_dem_or_def_etud( etudid, formsemestre_id, event_date=event_date, - etat_new="D", - operation_method="demEtudiant", + etat_new=scu.DEMISSION, + operation_method="dem_etudiant", event_type="DEMISSION", ) -@bp.route("/doDefEtudiant") +@bp.route("/do_def_etudiant") @scodoc @permission_required(Permission.ScoEtudInscrit) @scodoc7func -def doDefEtudiant(etudid, formsemestre_id, event_date=None): +def do_def_etudiant(etudid, formsemestre_id, event_date=None): "Déclare la défaillance d'un etudiant dans le semestre" return _do_dem_or_def_etud( etudid, @@ -1165,7 +1158,7 @@ def _do_dem_or_def_etud( etudid, formsemestre_id, event_date=None, - etat_new="D", # 'D' or DEF + etat_new=scu.DEMISSION, # DEMISSION or DEF operation_method="demEtudiant", event_type="DEMISSION", redirect=True, @@ -1175,7 +1168,7 @@ def _do_dem_or_def_etud( etudid, formsemestre_id, event_date=event_date, - etat_new=etat_new, # 'D' or DEF + etat_new=etat_new, # DEMISSION or DEF operation_method=operation_method, event_type=event_type, ) @@ -1185,11 +1178,11 @@ def _do_dem_or_def_etud( ) -@bp.route("/doCancelDem", methods=["GET", "POST"]) +@bp.route("/do_cancel_dem", methods=["GET", "POST"]) @scodoc @permission_required(Permission.ScoEtudInscrit) @scodoc7func -def doCancelDem(etudid, formsemestre_id, dialog_confirmed=False, args=None): +def do_cancel_dem(etudid, formsemestre_id, dialog_confirmed=False, args=None): "Annule une démission" return _do_cancel_dem_or_def( etudid, @@ -1197,18 +1190,18 @@ def doCancelDem(etudid, formsemestre_id, dialog_confirmed=False, args=None): dialog_confirmed=dialog_confirmed, args=args, operation_name="démission", - etat_current="D", - etat_new="I", + etat_current=scu.DEMISSION, + etat_new=scu.INSCRIT, operation_method="cancelDem", event_type="DEMISSION", ) -@bp.route("/doCancelDef", methods=["GET", "POST"]) +@bp.route("/do_cancel_def", methods=["GET", "POST"]) @scodoc @permission_required(Permission.ScoEtudInscrit) @scodoc7func -def doCancelDef(etudid, formsemestre_id, dialog_confirmed=False, args=None): +def do_cancel_def(etudid, formsemestre_id, dialog_confirmed=False, args=None): "Annule la défaillance de l'étudiant" return _do_cancel_dem_or_def( etudid, @@ -1217,8 +1210,8 @@ def doCancelDef(etudid, formsemestre_id, dialog_confirmed=False, args=None): args=args, operation_name="défaillance", etat_current=sco_codes_parcours.DEF, - etat_new="I", - operation_method="cancelDef", + etat_new=scu.INSCRIT, + operation_method="cancel_def", event_type="DEFAILLANCE", ) @@ -1229,30 +1222,30 @@ def _do_cancel_dem_or_def( dialog_confirmed=False, args=None, operation_name="", # "démission" ou "défaillance" - etat_current="D", - etat_new="I", - operation_method="cancelDem", + etat_current=scu.DEMISSION, + etat_new=scu.INSCRIT, + operation_method="cancel_dem", event_type="DEMISSION", ): - "Annule une demission ou une défaillance" + "Annule une démission ou une défaillance" + etud: Identite = Identite.query.filter_by( + id=etudid, dept_id=g.scodoc_dept_id + ).first_or_404() + formsemestre: FormSemestre = FormSemestre.query.filter_by( + id=formsemestre_id, dept_id=g.scodoc_dept_id + ).first_or_404() # check lock - sem = sco_formsemestre.get_formsemestre(formsemestre_id) - if not sem["etat"]: + if not formsemestre.etat: raise ScoValueError("Modification impossible: semestre verrouille") # verif - info = sco_etud.get_etud_info(etudid, filled=True)[0] - ok = False - for i in info["ins"]: - if i["formsemestre_id"] == formsemestre_id: - if i["etat"] != etat_current: - raise ScoValueError("etudiant non %s !" % operation_name) - ok = True - break - if not ok: - raise ScoValueError("etudiant non inscrit ???") + if formsemestre_id not in (inscr.formsemestre_id for inscr in etud.inscriptions()): + raise ScoValueError("étudiant non inscrit dans ce semestre !") + if etud.inscription_etat(formsemestre_id) != etat_current: + raise ScoValueError(f"etudiant non {operation_name} !") + if not dialog_confirmed: return scu.confirm_dialog( - "

Confirmer l'annulation de la %s ?

" % operation_name, + f"

Confirmer l'annulation de la {operation_name} ?

", dest_url="", cancel_url=url_for( "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid @@ -1260,25 +1253,22 @@ def _do_cancel_dem_or_def( parameters={"etudid": etudid, "formsemestre_id": formsemestre_id}, ) # - ins = sco_formsemestre_inscriptions.do_formsemestre_inscription_list( - {"etudid": etudid, "formsemestre_id": formsemestre_id} - )[0] - if ins["etat"] != etat_current: - raise ScoException("etudiant non %s !!!" % etat_current) # obviously a bug - ins["etat"] = etat_new - cnx = ndb.GetDBConnexion() - sco_formsemestre_inscriptions.do_formsemestre_inscription_edit( - args=ins, formsemestre_id=formsemestre_id + inscr = next( + inscr + for inscr in etud.inscriptions() + if inscr.formsemestre_id == formsemestre_id ) - logdb(cnx, method=operation_method, etudid=etudid) - cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) - cursor.execute( - "delete from scolar_events where etudid=%(etudid)s and formsemestre_id=%(formsemestre_id)s and event_type='" - + event_type - + "'", - {"etudid": etudid, "formsemestre_id": formsemestre_id}, - ) - cnx.commit() + inscr.etat = etat_new + db.session.add(inscr) + Scolog.logdb(method=operation_method, etudid=etudid) + # Efface les évènements + for event in ScolarEvent.query.filter_by( + etudid=etudid, formsemestre_id=formsemestre_id, event_type=event_type + ): + db.session.delete(event) + + db.session.commit() + flash(f"{operation_name} annulée.") return flask.redirect( url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etudid) )