From 56aa5fbba3ea8b87334ce11ad2e6fbed361d7127 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Mon, 19 Feb 2024 19:10:12 +0100 Subject: [PATCH] Modernise code inscription/passage semestre. Closes #859 --- app/scodoc/codes_cursus.py | 13 - app/scodoc/sco_formsemestre_inscriptions.py | 27 ++- app/scodoc/sco_inscr_passage.py | 256 +++++++++++--------- app/scodoc/sco_synchro_etuds.py | 44 ++-- app/static/css/scodoc.css | 9 +- 5 files changed, 194 insertions(+), 155 deletions(-) diff --git a/app/scodoc/codes_cursus.py b/app/scodoc/codes_cursus.py index 8e595ead7..5120aa05c 100644 --- a/app/scodoc/codes_cursus.py +++ b/app/scodoc/codes_cursus.py @@ -85,17 +85,6 @@ UE_ELECTIVE = 4 # UE "élective" dans certains cursus (UCAC?, ISCID) UE_PROFESSIONNELLE = 5 # UE "professionnelle" (ISCID, ...) UE_OPTIONNELLE = 6 # UE non fondamentales (ILEPS, ...) - -def ue_is_fondamentale(ue_type): - return ue_type in (UE_STANDARD, UE_STAGE_LP, UE_PROFESSIONNELLE) - - -def ue_is_professionnelle(ue_type): - return ( - ue_type == UE_PROFESSIONNELLE - ) # NB: les UE_PROFESSIONNELLE sont à la fois fondamentales et pro - - UE_TYPE_NAME = { UE_STANDARD: "Standard", UE_SPORT: "Sport/Culture (points bonus)", @@ -104,8 +93,6 @@ UE_TYPE_NAME = { UE_ELECTIVE: "Elective (ISCID)", UE_PROFESSIONNELLE: "Professionnelle (ISCID)", UE_OPTIONNELLE: "Optionnelle", - # UE_FONDAMENTALE : '"Fondamentale" (eg UCAC)', - # UE_OPTIONNELLE : '"Optionnelle" (UCAC)' } # Couleurs RGB (dans [0.,1.]) des UE pour les bulletins: diff --git a/app/scodoc/sco_formsemestre_inscriptions.py b/app/scodoc/sco_formsemestre_inscriptions.py index e3474ebf2..7ee6439a7 100644 --- a/app/scodoc/sco_formsemestre_inscriptions.py +++ b/app/scodoc/sco_formsemestre_inscriptions.py @@ -191,7 +191,23 @@ def do_formsemestre_inscription_edit(args=None, formsemestre_id=None): ) # > modif inscription semestre -def do_formsemestre_desinscription(etudid, formsemestre_id): +def check_if_has_decision_jury( + formsemestre: FormSemestre, etudids: list[int] | set[int] +): + "raise exception if one of the etuds has a decision in formsemestre" + nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) + for etudid in etudids: + if nt.etud_has_decision(etudid): + etud = Identite.query.get(etudid) + raise ScoValueError( + f"""désinscription impossible: l'étudiant {etud.nomprenom} a + une décision de jury (la supprimer avant si nécessaire)""" + ) + + +def do_formsemestre_desinscription( + etudid, formsemestre_id: int, check_has_dec_jury=True +): """Désinscription d'un étudiant. Si semestre extérieur et dernier inscrit, suppression de ce semestre. """ @@ -204,13 +220,8 @@ def do_formsemestre_desinscription(etudid, formsemestre_id): raise ScoValueError("désinscription impossible: semestre verrouille") # -- Si decisions de jury, désinscription interdite - nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) - - if nt.etud_has_decision(etudid): - raise ScoValueError( - f"""désinscription impossible: l'étudiant {etud.nomprenom} a - une décision de jury (la supprimer avant si nécessaire)""" - ) + if check_has_dec_jury: + check_if_has_decision_jury(formsemestre, [etudid]) insem = do_formsemestre_inscription_list( args={"formsemestre_id": formsemestre_id, "etudid": etudid} diff --git a/app/scodoc/sco_inscr_passage.py b/app/scodoc/sco_inscr_passage.py index f97e0d440..4f881022f 100644 --- a/app/scodoc/sco_inscr_passage.py +++ b/app/scodoc/sco_inscr_passage.py @@ -36,13 +36,14 @@ from flask import url_for, g, request import app.scodoc.notesdb as ndb import app.scodoc.sco_utils as scu from app import db, log -from app.models import Formation, FormSemestre, GroupDescr +from app.comp import res_sem +from app.comp.res_compat import NotesTableCompat +from app.models import Formation, FormSemestre, GroupDescr, Identite from app.scodoc.gen_tables import GenTable from app.scodoc import html_sco_header from app.scodoc import sco_cache from app.scodoc import codes_cursus from app.scodoc import sco_etud -from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre_inscriptions from app.scodoc import sco_groups from app.scodoc import sco_preferences @@ -50,62 +51,69 @@ from app.scodoc import sco_pv_dict from app.scodoc.sco_exceptions import ScoValueError -def list_authorized_etuds_by_sem(sem, delai=274, ignore_jury=False): +def _list_authorized_etuds_by_sem( + formsemestre: FormSemestre, ignore_jury=False +) -> tuple[dict[int, dict], list[dict], dict[int, Identite]]: """Liste des etudiants autorisés à s'inscrire dans sem. delai = nb de jours max entre la date de l'autorisation et celle de debut du semestre cible. ignore_jury: si vrai, considère tous les étudiants comme autorisés, même s'ils n'ont pas de décision de jury. """ - src_sems = list_source_sems(sem, delai=delai) - inscrits = list_inscrits(sem["formsemestre_id"]) + src_sems = _list_source_sems(formsemestre) + inscrits = list_inscrits(formsemestre.id) r = {} candidats = {} # etudid : etud (tous les etudiants candidats) nb = 0 # debug - for src in src_sems: + src_formsemestre: FormSemestre + for src_formsemestre in src_sems: if ignore_jury: # liste de tous les inscrits au semestre (sans dems) - liste = list_inscrits(src["formsemestre_id"]).values() + etud_list = list_inscrits(formsemestre.id).values() else: # liste des étudiants autorisés par le jury à s'inscrire ici - liste = list_etuds_from_sem(src, sem) + etud_list = _list_etuds_from_sem(src_formsemestre, formsemestre) liste_filtree = [] - for e in liste: + for e in etud_list: # Filtre ceux qui se sont déjà inscrit dans un semestre APRES le semestre src auth_used = False # autorisation deja utilisée ? - etud = sco_etud.get_etud_info(etudid=e["etudid"], filled=True)[0] - for isem in etud["sems"]: - if ndb.DateDMYtoISO(isem["date_debut"]) >= ndb.DateDMYtoISO( - src["date_fin"] - ): + etud = Identite.get_etud(e["etudid"]) + for inscription in etud.inscriptions(): + if inscription.formsemestre.date_debut >= src_formsemestre.date_fin: auth_used = True if not auth_used: candidats[e["etudid"]] = etud liste_filtree.append(e) nb += 1 - r[src["formsemestre_id"]] = { + r[src_formsemestre.id] = { "etuds": liste_filtree, "infos": { - "id": src["formsemestre_id"], - "title": src["titreannee"], - "title_target": "formsemestre_status?formsemestre_id=%s" - % src["formsemestre_id"], + "id": src_formsemestre.id, + "title": src_formsemestre.titre_annee(), + "title_target": url_for( + "notes.formsemestre_status", + scodoc_dept=g.scodoc_dept, + formsemestre_id=src_formsemestre.id, + ), "filename": "etud_autorises", }, } # ajoute attribut inscrit qui indique si l'étudiant est déjà inscrit dans le semestre dest. - for e in r[src["formsemestre_id"]]["etuds"]: + for e in r[src_formsemestre.id]["etuds"]: e["inscrit"] = e["etudid"] in inscrits # Ajoute liste des etudiants actuellement inscrits for e in inscrits.values(): e["inscrit"] = True - r[sem["formsemestre_id"]] = { + r[formsemestre.id] = { "etuds": list(inscrits.values()), "infos": { - "id": sem["formsemestre_id"], - "title": "Semestre cible: " + sem["titreannee"], - "title_target": "formsemestre_status?formsemestre_id=%s" - % sem["formsemestre_id"], + "id": formsemestre.id, + "title": "Semestre cible: " + formsemestre.titre_annee(), + "title_target": url_for( + "notes.formsemestre_status", + scodoc_dept=g.scodoc_dept, + formsemestre_id=formsemestre.id, + ), "comment": " actuellement inscrits dans ce semestre", "help": "Ces étudiants sont actuellement inscrits dans ce semestre. Si vous les décochez, il seront désinscrits.", "filename": "etud_inscrits", @@ -115,7 +123,7 @@ def list_authorized_etuds_by_sem(sem, delai=274, ignore_jury=False): return r, inscrits, candidats -def list_inscrits(formsemestre_id, with_dems=False): +def list_inscrits(formsemestre_id: int, with_dems=False) -> list[dict]: """Étudiants déjà inscrits à ce semestre { etudid : etud } """ @@ -133,28 +141,27 @@ def list_inscrits(formsemestre_id, with_dems=False): return inscr -def list_etuds_from_sem(src, dst) -> list[dict]: - """Liste des etudiants du semestre src qui sont autorisés à passer dans le semestre dst.""" - target = dst["semestre_id"] - dpv = sco_pv_dict.dict_pvjury(src["formsemestre_id"]) +def _list_etuds_from_sem(src: FormSemestre, dst: FormSemestre) -> list[dict]: + """Liste des étudiants du semestre src qui sont autorisés à passer dans le semestre dst.""" + target_semestre_id = dst.semestre_id + dpv = sco_pv_dict.dict_pvjury(src.id) if not dpv: return [] etuds = [ x["identite"] for x in dpv["decisions"] - if target in [a["semestre_id"] for a in x["autorisations"]] + if target_semestre_id in [a["semestre_id"] for a in x["autorisations"]] ] return etuds -def list_inscrits_date(sem): - """Liste les etudiants inscrits dans n'importe quel semestre - du même département - SAUF sem à la date de début de sem. +def list_inscrits_date(formsemestre: FormSemestre): + """Liste les etudiants inscrits à la date de début de formsemestre + dans n'importe quel semestre du même département + SAUF formsemestre """ cnx = ndb.GetDBConnexion() cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) - sem["date_debut_iso"] = ndb.DateDMYtoISO(sem["date_debut"]) cursor.execute( """SELECT ins.etudid FROM @@ -166,12 +173,18 @@ def list_inscrits_date(sem): AND S.date_fin >= %(date_debut_iso)s AND S.dept_id = %(dept_id)s """, - sem, + { + "formsemestre_id": formsemestre.id, + "date_debut_iso": formsemestre.date_debut.isoformat(), + "dept_id": formsemestre.dept_id, + }, ) return [x[0] for x in cursor.fetchall()] -def do_inscrit(sem, etudids, inscrit_groupes=False, inscrit_parcours=False): +def do_inscrit( + formsemestre: FormSemestre, etudids, inscrit_groupes=False, inscrit_parcours=False +): """Inscrit ces etudiants dans ce semestre (la liste doit avoir été vérifiée au préalable) En option: @@ -181,12 +194,11 @@ def do_inscrit(sem, etudids, inscrit_groupes=False, inscrit_parcours=False): (si les deux sont vrais, inscrit_parcours n'a pas d'effet) """ # TODO à ré-écrire pour utiliser les modèles, notamment GroupDescr - formsemestre: FormSemestre = db.session.get(FormSemestre, sem["formsemestre_id"]) formsemestre.setup_parcours_groups() log(f"do_inscrit (inscrit_groupes={inscrit_groupes}): {etudids}") for etudid in etudids: sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules( - sem["formsemestre_id"], + formsemestre.id, etudid, etat=scu.INSCRIT, method="formsemestre_inscr_passage", @@ -210,7 +222,7 @@ def do_inscrit(sem, etudids, inscrit_groupes=False, inscrit_parcours=False): cursem_groups_by_name = { g["group_name"]: g - for g in sco_groups.get_sem_groups(sem["formsemestre_id"]) + for g in sco_groups.get_sem_groups(formsemestre.id) if g["group_name"] } @@ -234,53 +246,46 @@ def do_inscrit(sem, etudids, inscrit_groupes=False, inscrit_parcours=False): sco_groups.change_etud_group_in_partition(etudid, group) -def do_desinscrit(sem: dict, etudids: list[int]): +def do_desinscrit( + formsemestre: FormSemestre, etudids: list[int], check_has_dec_jury=True +): "désinscrit les étudiants indiqués du formsemestre" log(f"do_desinscrit: {etudids}") for etudid in etudids: sco_formsemestre_inscriptions.do_formsemestre_desinscription( - etudid, sem["formsemestre_id"] + etudid, formsemestre.id, check_has_dec_jury=check_has_dec_jury ) -def list_source_sems(sem, delai=None) -> list[dict]: +def _list_source_sems(formsemestre: FormSemestre) -> list[FormSemestre]: """Liste des semestres sources - sem est le semestre destination + formsemestre est le semestre destination """ - # liste des semestres débutant a moins - # de delai (en jours) de la date de fin du semestre d'origine. - sems = sco_formsemestre.do_formsemestre_list() - othersems = [] - d, m, y = [int(x) for x in sem["date_debut"].split("/")] - date_debut_dst = datetime.date(y, m, d) - - delais = datetime.timedelta(delai) - for s in sems: - if s["formsemestre_id"] == sem["formsemestre_id"]: - continue # saute le semestre destination - if s["date_fin"]: - d, m, y = [int(x) for x in s["date_fin"].split("/")] - date_fin = datetime.date(y, m, d) - if date_debut_dst - date_fin > delais: - continue # semestre trop ancien - if date_fin > date_debut_dst: - continue # semestre trop récent - # Elimine les semestres de formations speciales (sans parcours) - if s["semestre_id"] == codes_cursus.NO_SEMESTRE_ID: - continue - # - formation: Formation = Formation.query.get_or_404(s["formation_id"]) - parcours = codes_cursus.get_cursus_from_code(formation.type_parcours) - if not parcours.ALLOW_SEM_SKIP: - if s["semestre_id"] < (sem["semestre_id"] - 1): - continue - othersems.append(s) - return othersems + # liste des semestres du même type de cursus terminant + # pas trop loin de la date de début du semestre destination + date_fin_min = formsemestre.date_debut - datetime.timedelta(days=275) + date_fin_max = formsemestre.date_debut + datetime.timedelta(days=45) + return ( + FormSemestre.query.filter( + FormSemestre.dept_id == formsemestre.dept_id, + # saute le semestre destination: + FormSemestre.id != formsemestre.id, + # et les semestres de formations speciales (monosemestres): + FormSemestre.semestre_id != codes_cursus.NO_SEMESTRE_ID, + # semestre pas trop dans le futur + FormSemestre.date_fin <= date_fin_max, + # ni trop loin dans le passé + FormSemestre.date_fin >= date_fin_min, + ) + .join(Formation) + .filter_by(type_parcours=formsemestre.formation.type_parcours) + ).all() +# view, GET, POST def formsemestre_inscr_passage( formsemestre_id, - etuds=[], + etuds: str | list[int] | list[str] | int | None = None, inscrit_groupes=False, inscrit_parcours=False, submitted=False, @@ -300,36 +305,41 @@ def formsemestre_inscr_passage( - Confirmation: indiquer les étudiants inscrits et ceux désinscrits, le total courant. """ + formsemestre = FormSemestre.get_formsemestre(formsemestre_id) inscrit_groupes = int(inscrit_groupes) inscrit_parcours = int(inscrit_parcours) ignore_jury = int(ignore_jury) - sem = sco_formsemestre.get_formsemestre(formsemestre_id) # -- check lock - if not sem["etat"]: + if not formsemestre.etat: raise ScoValueError("opération impossible: semestre verrouille") - header = html_sco_header.sco_header(page_title="Passage des étudiants") + header = html_sco_header.sco_header( + page_title="Passage des étudiants", + init_qtip=True, + javascripts=["js/etud_info.js"], + ) footer = html_sco_header.sco_footer() H = [header] + etuds = [] if etuds is None else etuds if isinstance(etuds, str): - # list de strings, vient du form de confirmation + # string, vient du form de confirmation etuds = [int(x) for x in etuds.split(",") if x] elif isinstance(etuds, int): etuds = [etuds] elif etuds and isinstance(etuds[0], str): etuds = [int(x) for x in etuds] - auth_etuds_by_sem, inscrits, candidats = list_authorized_etuds_by_sem( - sem, ignore_jury=ignore_jury + auth_etuds_by_sem, inscrits, candidats = _list_authorized_etuds_by_sem( + formsemestre, ignore_jury=ignore_jury ) etuds_set = set(etuds) candidats_set = set(candidats) inscrits_set = set(inscrits) candidats_non_inscrits = candidats_set - inscrits_set - inscrits_ailleurs = set(list_inscrits_date(sem)) + inscrits_ailleurs = set(list_inscrits_date(formsemestre)) - def set_to_sorted_etud_list(etudset): + def set_to_sorted_etud_list(etudset) -> list[Identite]: etuds = [candidats[etudid] for etudid in etudset] - etuds.sort(key=itemgetter("nom")) + etuds.sort(key=lambda e: e.sort_key) return etuds if submitted: @@ -340,7 +350,7 @@ def formsemestre_inscr_passage( if not submitted: H += _build_page( - sem, + formsemestre, auth_etuds_by_sem, inscrits, candidats_non_inscrits, @@ -355,30 +365,31 @@ def formsemestre_inscr_passage( if a_inscrire: H.append("

Étudiants à inscrire

    ") for etud in set_to_sorted_etud_list(a_inscrire): - H.append("
  1. %(nomprenom)s
  2. " % etud) + H.append(f"
  3. {etud.nomprenom}
  4. ") H.append("
") a_inscrire_en_double = inscrits_ailleurs.intersection(a_inscrire) if a_inscrire_en_double: H.append("

dont étudiants déjà inscrits:

") if a_desinscrire: H.append("

Étudiants à désinscrire

    ") - for etudid in a_desinscrire: - H.append( - '
  1. %(nomprenom)s
  2. ' - % inscrits[etudid] - ) + a_desinscrire_ident = sorted( + (Identite.query.get(eid) for eid in a_desinscrire), + key=lambda x: x.sort_key, + ) + for etud in a_desinscrire_ident: + H.append(f'
  3. {etud.nomprenom}
  4. ') H.append("
") todo = a_inscrire or a_desinscrire if not todo: H.append("""

Il n'y a rien à modifier !

""") H.append( scu.confirm_dialog( - dest_url="formsemestre_inscr_passage" - if todo - else "formsemestre_status", + dest_url=( + "formsemestre_inscr_passage" if todo else "formsemestre_status" + ), message="

Confirmer ?

" if todo else "", add_headers=False, cancel_url="formsemestre_inscr_passage?formsemestre_id=" @@ -395,16 +406,26 @@ def formsemestre_inscr_passage( ) ) else: + # check decisions jury ici pour éviter de recontruire le cache + # après chaque desinscription + sco_formsemestre_inscriptions.check_if_has_decision_jury( + formsemestre, a_desinscrire + ) + # check decisions jury ici pour éviter de recontruire le cache + # après chaque desinscription + sco_formsemestre_inscriptions.check_if_has_decision_jury( + formsemestre, a_desinscrire + ) with sco_cache.DeferredSemCacheManager(): # Inscription des étudiants au nouveau semestre: do_inscrit( - sem, + formsemestre, a_inscrire, inscrit_groupes=inscrit_groupes, inscrit_parcours=inscrit_parcours, ) # Désinscriptions: - do_desinscrit(sem, a_desinscrire) + do_desinscrit(formsemestre, a_desinscrire, check_has_dec_jury=False) H.append( f"""

Opération effectuée

@@ -441,7 +462,7 @@ def formsemestre_inscr_passage( def _build_page( - sem, + formsemestre: FormSemestre, auth_etuds_by_sem, inscrits, candidats_non_inscrits, @@ -450,7 +471,6 @@ def _build_page( inscrit_parcours=False, ignore_jury=False, ): - formsemestre: FormSemestre = db.session.get(FormSemestre, sem["formsemestre_id"]) inscrit_groupes = int(inscrit_groupes) inscrit_parcours = int(inscrit_parcours) ignore_jury = int(ignore_jury) @@ -472,7 +492,7 @@ def _build_page( ), f"""
- +  aide @@ -491,7 +511,7 @@ def _build_page(
{scu.EMO_WARNING} - Seuls les semestres dont la date de fin est antérieure à la date de début + Seuls les semestres dont la date de fin est proche de la date de début de ce semestre ({formsemestre.date_debut.strftime("%d/%m/%Y")}) sont pris en compte.
@@ -499,7 +519,7 @@ def _build_page( - {formsemestre_inscr_passage_help(sem)} + {formsemestre_inscr_passage_help(formsemestre)} """, @@ -524,19 +544,20 @@ def _build_page( return H -def formsemestre_inscr_passage_help(sem: dict): +def formsemestre_inscr_passage_help(formsemestre: FormSemestre): "texte d'aide en bas de la page passage des étudiants" return f"""

Explications

Cette page permet d'inscrire des étudiants dans le semestre destination {sem['titreannee']}, + url_for("notes.formsemestre_status", + scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id ) + }">{formsemestre.titre_annee()}, et d'en désincrire si besoin.

Les étudiants sont groupés par semestre d'origine. Ceux qui sont en caractères - gras sont déjà inscrits dans le semestre destination. - Ceux qui sont en gras et en rouge sont inscrits + gras sont déjà inscrits dans le semestre destination. + Ceux qui sont en gras et en rouge sont inscrits dans un autre semestre.

Au départ, les étudiants déjà inscrits sont sélectionnés; vous pouvez ajouter @@ -555,7 +576,7 @@ def formsemestre_inscr_passage_help(sem: dict): conserve les groupes, on conserve les parcours (là aussi, pensez à les cocher dans modifier le semestre avant de faire passer les étudiants). @@ -656,25 +677,24 @@ def etuds_select_boxes( H.append("

") for etud in etuds: if etud.get("inscrit", False): - c = " inscrit" + c = " deja-inscrit" checked = 'checked="checked"' else: checked = "" if etud["etudid"] in inscrits_ailleurs: - c = " inscrailleurs" + c = " inscrit-ailleurs" else: c = "" sco_etud.format_etud_ident(etud) if etud["etudid"]: - elink = """%s""" % ( - c, - url_for( - "scolar.fiche_etud", + elink = f"""{etud['nomprenom']} + """ else: # ce n'est pas un etudiant ScoDoc elink = etud["nomprenom"] diff --git a/app/scodoc/sco_synchro_etuds.py b/app/scodoc/sco_synchro_etuds.py index 5cab9c870..a4a9fd2c8 100644 --- a/app/scodoc/sco_synchro_etuds.py +++ b/app/scodoc/sco_synchro_etuds.py @@ -35,7 +35,7 @@ from flask import g, url_for from flask_login import current_user from app import db, log -from app.models import Admission, Adresse, Identite, ScolarNews +from app.models import Admission, Adresse, FormSemestre, Identite, ScolarNews import app.scodoc.sco_utils as scu import app.scodoc.notesdb as ndb @@ -94,6 +94,7 @@ def formsemestre_synchro_etuds( que l'on va importer/inscrire """ etuds = etuds or [] + formsemestre = FormSemestre.get_formsemestre(formsemestre_id) inscrits_without_key = inscrits_without_key or [] log(f"formsemestre_synchro_etuds: formsemestre_id={formsemestre_id}") sem = sco_formsemestre.get_formsemestre(formsemestre_id) @@ -184,7 +185,7 @@ def formsemestre_synchro_etuds( inscrits_without_key ) log("a_desinscrire_without_key=%s" % a_desinscrire_without_key) - inscrits_ailleurs = set(sco_inscr_passage.list_inscrits_date(sem)) + inscrits_ailleurs = set(sco_inscr_passage.list_inscrits_date(formsemestre)) a_inscrire = a_inscrire.intersection(etuds_set) if not dialog_confirmed: @@ -205,10 +206,12 @@ def formsemestre_synchro_etuds( a_inscrire_en_double = inscrits_ailleurs.intersection(a_inscrire) if a_inscrire_en_double: - H.append("

dont étudiants déjà inscrits:

    ") + H.append( + "

    dont étudiants déjà inscrits dans un autre semestre:

      " + ) for key in a_inscrire_en_double: nom = f"""{etudsapo_ident[key]['nom']} {etudsapo_ident[key].get("prenom", "")}""" - H.append(f'
    1. {nom}
    2. ') + H.append(f'
    3. {nom}
    4. ') H.append("
    ") if a_desinscrire: @@ -260,16 +263,26 @@ def formsemestre_synchro_etuds( etudids_a_desinscrire = [nip2etudid(x) for x in a_desinscrire] etudids_a_desinscrire += a_desinscrire_without_key # + # check decisions jury ici pour éviter de recontruire le cache + # après chaque desinscription + sco_formsemestre_inscriptions.check_if_has_decision_jury( + formsemestre, a_desinscrire + ) with sco_cache.DeferredSemCacheManager(): - do_import_etuds_from_portal(sem, a_importer, etudsapo_ident) - sco_inscr_passage.do_inscrit(sem, etudids_a_inscrire) - sco_inscr_passage.do_desinscrit(sem, etudids_a_desinscrire) + do_import_etuds_from_portal(formsemestre, a_importer, etudsapo_ident) + sco_inscr_passage.do_inscrit(formsemestre, etudids_a_inscrire) + sco_inscr_passage.do_desinscrit( + formsemestre, etudids_a_desinscrire, check_has_dec_jury=False + ) H.append( - """

    Opération effectuée

    + f"""

    Opération effectuée

      -
    • Continuer la synchronisation
    • """ - % formsemestre_id +
    • Continuer la synchronisation +
    • """ ) # partitions = sco_groups.get_partitions_list( @@ -279,8 +292,9 @@ def formsemestre_synchro_etuds( H.append( f"""
    • Répartir les groupes de {partitions[0]["partition_name"]}
    • + scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id + )}">Répartir les groupes de {partitions[0]["partition_name"]} + """ ) @@ -618,7 +632,7 @@ def get_annee_naissance(ddmmyyyyy: str) -> int: return None -def do_import_etuds_from_portal(sem, a_importer, etudsapo_ident): +def do_import_etuds_from_portal(formsemestre: FormSemestre, a_importer, etudsapo_ident): """Inscrit les etudiants Apogee dans ce semestre.""" log(f"do_import_etuds_from_portal: a_importer={a_importer}") if not a_importer: @@ -672,7 +686,7 @@ def do_import_etuds_from_portal(sem, a_importer, etudsapo_ident): # Inscription au semestre sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules( - sem["formsemestre_id"], + formsemestre.id, etud.id, etat=scu.INSCRIT, etape=args["etape"], @@ -716,7 +730,7 @@ def do_import_etuds_from_portal(sem, a_importer, etudsapo_ident): ScolarNews.add( typ=ScolarNews.NEWS_INSCR, text=f"Import Apogée de {len(created_etudids)} étudiants en ", - obj=sem["formsemestre_id"], + obj=formsemestre.id, ) diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index 948554f2f..5d141fd58 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -3714,10 +3714,17 @@ span.sp_etape { color: black; } -.inscrailleurs { +.deja-inscrit { + font-weight: bold; + color: rgb(1, 76, 1) !important; +} +.inscrit-ailleurs { font-weight: bold; color: red !important; } +div.etuds_select_boxes { + margin-bottom: 16px; +} span.paspaye, span.paspaye a {