Modernise code inscription/passage semestre. Closes #859

This commit is contained in:
Emmanuel Viennet 2024-02-19 19:10:12 +01:00
parent e6d61fcd8a
commit 56aa5fbba3
5 changed files with 194 additions and 155 deletions

View File

@ -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:

View File

@ -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}

View File

@ -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("<h3>Étudiants à inscrire</h3><ol>")
for etud in set_to_sorted_etud_list(a_inscrire):
H.append("<li>%(nomprenom)s</li>" % etud)
H.append(f"<li>{etud.nomprenom}</li>")
H.append("</ol>")
a_inscrire_en_double = inscrits_ailleurs.intersection(a_inscrire)
if a_inscrire_en_double:
H.append("<h3>dont étudiants déjà inscrits:</h3><ul>")
for etud in set_to_sorted_etud_list(a_inscrire_en_double):
H.append('<li class="inscrailleurs">%(nomprenom)s</li>' % etud)
H.append(f'<li class="inscrit-ailleurs">{etud.nomprenom}</li>')
H.append("</ul>")
if a_desinscrire:
H.append("<h3>Étudiants à désinscrire</h3><ol>")
for etudid in a_desinscrire:
H.append(
'<li class="desinscription">%(nomprenom)s</li>'
% 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'<li class="desinscription">{etud.nomprenom}</li>')
H.append("</ol>")
todo = a_inscrire or a_desinscrire
if not todo:
H.append("""<h3>Il n'y a rien à modifier !</h3>""")
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="<p>Confirmer ?</p>" 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"""<h3>Opération effectuée</h3>
@ -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"""<form name="f" method="post" action="{request.base_url}">
<input type="hidden" name="formsemestre_id" value="{sem['formsemestre_id']}"/>
<input type="hidden" name="formsemestre_id" value="{formsemestre.id}"/>
<input type="submit" name="submitted" value="Appliquer les modifications"/>
&nbsp;<a href="#help">aide</a>
@ -491,7 +511,7 @@ def _build_page(
</div>
<div>{scu.EMO_WARNING}
<em>Seuls les semestres dont la date de fin est antérieure à la date de début
<em>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.</em>
</div>
@ -499,7 +519,7 @@ def _build_page(
<input type="submit" name="submitted" value="Appliquer les modifications"/>
{formsemestre_inscr_passage_help(sem)}
{formsemestre_inscr_passage_help(formsemestre)}
</form>
""",
@ -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"""<div class="pas_help"><h3><a name="help">Explications</a></h3>
<p>Cette page permet d'inscrire des étudiants dans le semestre destination
<a class="stdlink"
href="{
url_for("notes.formsemestre_status", scodoc_dept=g.scodoc_dept, formsemestre_id=sem["formsemestre_id"] )
}">{sem['titreannee']}</a>,
url_for("notes.formsemestre_status",
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre.id )
}">{formsemestre.titre_annee()}</a>,
et d'en désincrire si besoin.
</p>
<p>Les étudiants sont groupés par semestre d'origine. Ceux qui sont en caractères
<span class="inscrit">gras</span> sont déjà inscrits dans le semestre destination.
Ceux qui sont en <span class"inscrailleurs">gras et en rouge</span> sont inscrits
<span class="deja-inscrit">gras</span> sont déjà inscrits dans le semestre destination.
Ceux qui sont en <span class="inscrit-ailleurs">gras et en rouge</span> sont inscrits
dans un <em>autre</em> semestre.
</p>
<p>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 ( aussi, pensez à les cocher dans
<a class="stdlink" href="{
url_for("notes.formsemestre_editwithmodules", scodoc_dept=g.scodoc_dept,
formsemestre_id=sem["formsemestre_id"] )
formsemestre_id=formsemestre.id )
}">modifier le semestre</a> avant de faire passer les étudiants).
</a>
@ -656,25 +677,24 @@ def etuds_select_boxes(
H.append("</div>")
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 = """<a class="discretelink %s" href="%s">%s</a>""" % (
c,
url_for(
"scolar.fiche_etud",
elink = f"""<a id="{etud['etudid']}" class="discretelink etudinfo {c}"
href="{ url_for(
'scolar.fiche_etud',
scodoc_dept=g.scodoc_dept,
etudid=etud["etudid"],
),
etud["nomprenom"],
)
etudid=etud['etudid'],
)
}">{etud['nomprenom']}</a>
"""
else:
# ce n'est pas un etudiant ScoDoc
elink = etud["nomprenom"]

View File

@ -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("<h3>dont étudiants déjà inscrits:</h3><ol>")
H.append(
"<h3>dont étudiants déjà inscrits dans un autre semestre:</h3><ol>"
)
for key in a_inscrire_en_double:
nom = f"""{etudsapo_ident[key]['nom']} {etudsapo_ident[key].get("prenom", "")}"""
H.append(f'<li class="inscrailleurs">{nom}</li>')
H.append(f'<li class="inscrit-ailleurs">{nom}</li>')
H.append("</ol>")
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(
"""<h3>Opération effectuée</h3>
f"""<h3>Opération effectuée</h3>
<ul>
<li><a class="stdlink" href="formsemestre_synchro_etuds?formsemestre_id=%s">Continuer la synchronisation</a></li>"""
% formsemestre_id
<li><a class="stdlink" href="{
url_for('notes.formsemestre_synchro_etuds',
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id
)}">Continuer la synchronisation</a>
</li>"""
)
#
partitions = sco_groups.get_partitions_list(
@ -279,8 +292,9 @@ def formsemestre_synchro_etuds(
H.append(
f"""<li><a class="stdlink" href="{
url_for("scolar.partition_editor",
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id)
}">Répartir les groupes de {partitions[0]["partition_name"]}</a></li>
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id
)}">Répartir les groupes de {partitions[0]["partition_name"]}</a>
</li>
"""
)
@ -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,
)

View File

@ -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 {