ScoDoc-Lille/app/scodoc/sco_inscr_passage.py

758 lines
29 KiB
Python
Raw Normal View History

2020-09-26 16:19:37 +02:00
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
2023-12-31 23:04:06 +01:00
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
2020-09-26 16:19:37 +02:00
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Emmanuel Viennet emmanuel.viennet@viennet.net
#
##############################################################################
"""Form. pour inscription rapide des etudiants d'un semestre dans un autre
Utilise les autorisations d'inscription délivrées en jury.
"""
2021-02-04 20:02:44 +01:00
import datetime
2021-07-09 23:19:30 +02:00
from operator import itemgetter
2020-09-26 16:19:37 +02:00
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.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
2023-01-26 18:29:16 +01:00
from app.scodoc import sco_cache
from app.scodoc import codes_cursus
2023-01-26 18:29:16 +01:00
from app.scodoc import sco_etud
from app.scodoc import sco_formsemestre_inscriptions
from app.scodoc import sco_groups
2023-01-26 18:29:16 +01:00
from app.scodoc import sco_preferences
from app.scodoc import sco_pv_dict
from app.scodoc.sco_exceptions import ScoValueError
2020-09-26 16:19:37 +02:00
def _list_authorized_etuds_by_sem(
formsemestre: FormSemestre, ignore_jury=False
) -> tuple[dict[int, dict], list[dict], dict[int, Identite]]:
2020-09-26 16:19:37 +02:00
"""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.
2023-01-26 18:29:16 +01:00
ignore_jury: si vrai, considère tous les étudiants comme autorisés, même
s'ils n'ont pas de décision de jury.
2020-09-26 16:19:37 +02:00
"""
src_sems = _list_source_sems(formsemestre)
inscrits = list_inscrits(formsemestre.id)
2020-09-26 16:19:37 +02:00
r = {}
candidats = {} # etudid : etud (tous les etudiants candidats)
nb = 0 # debug
src_formsemestre: FormSemestre
for src_formsemestre in src_sems:
if ignore_jury:
# liste de tous les inscrits au semestre (sans dems)
etud_list = list_inscrits(src_formsemestre.id).values()
else:
# liste des étudiants autorisés par le jury à s'inscrire ici
etud_list = _list_etuds_from_sem(src_formsemestre, formsemestre)
2020-09-26 16:19:37 +02:00
liste_filtree = []
for e in etud_list:
2020-09-26 16:19:37 +02:00
# Filtre ceux qui se sont déjà inscrit dans un semestre APRES le semestre src
auth_used = False # autorisation deja utilisée ?
etud = Identite.get_etud(e["etudid"])
for inscription in etud.inscriptions():
if inscription.formsemestre.date_debut >= src_formsemestre.date_fin:
2020-09-26 16:19:37 +02:00
auth_used = True
if not auth_used:
candidats[e["etudid"]] = etud
liste_filtree.append(e)
nb += 1
r[src_formsemestre.id] = {
2020-09-26 16:19:37 +02:00
"etuds": liste_filtree,
"infos": {
"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",
2020-09-26 16:19:37 +02:00
},
}
# ajoute attribut inscrit qui indique si l'étudiant est déjà inscrit dans le semestre dest.
for e in r[src_formsemestre.id]["etuds"]:
2021-07-09 17:47:06 +02:00
e["inscrit"] = e["etudid"] in inscrits
2020-09-26 16:19:37 +02:00
# Ajoute liste des etudiants actuellement inscrits
for e in inscrits.values():
e["inscrit"] = True
r[formsemestre.id] = {
2021-07-09 17:47:06 +02:00
"etuds": list(inscrits.values()),
2020-09-26 16:19:37 +02:00
"infos": {
"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,
),
2020-09-26 16:19:37 +02:00
"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",
2020-09-26 16:19:37 +02:00
},
}
return r, inscrits, candidats
def list_inscrits(formsemestre_id: int, with_dems=False) -> list[dict]:
"""Étudiants déjà inscrits à ce semestre
2020-09-26 16:19:37 +02:00
{ etudid : etud }
"""
if not with_dems:
2021-06-21 10:17:16 +02:00
ins = sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
2021-08-19 10:28:35 +02:00
formsemestre_id
2020-09-26 16:19:37 +02:00
) # optimized
else:
args = {"formsemestre_id": formsemestre_id}
2021-08-19 10:28:35 +02:00
ins = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(args=args)
2020-09-26 16:19:37 +02:00
inscr = {}
for i in ins:
etudid = i["etudid"]
inscr[etudid] = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
2020-09-26 16:19:37 +02:00
return inscr
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)
2020-09-26 16:19:37 +02:00
if not dpv:
return []
etuds = [
x["identite"]
for x in dpv["decisions"]
if target_semestre_id in [a["semestre_id"] for a in x["autorisations"]]
2020-09-26 16:19:37 +02:00
]
return etuds
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
2020-09-26 16:19:37 +02:00
"""
2021-06-15 13:59:56 +02:00
cnx = ndb.GetDBConnexion()
2021-02-03 22:00:41 +01:00
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
2020-09-26 16:19:37 +02:00
cursor.execute(
2021-09-15 00:54:18 +02:00
"""SELECT ins.etudid
FROM
notes_formsemestre_inscription ins,
notes_formsemestre S
2021-09-13 22:10:01 +02:00
WHERE ins.formsemestre_id = S.id
2021-08-21 15:17:14 +02:00
AND S.id != %(formsemestre_id)s
AND S.date_debut <= %(date_debut_iso)s
AND S.date_fin >= %(date_debut_iso)s
2021-09-15 00:54:18 +02:00
AND S.dept_id = %(dept_id)s
2021-08-21 15:17:14 +02:00
""",
{
"formsemestre_id": formsemestre.id,
"date_debut_iso": formsemestre.date_debut.isoformat(),
"dept_id": formsemestre.dept_id,
},
2020-09-26 16:19:37 +02:00
)
return [x[0] for x in cursor.fetchall()]
def do_inscrit(
formsemestre: FormSemestre, etudids, inscrit_groupes=False, inscrit_parcours=False
):
2020-09-26 16:19:37 +02:00
"""Inscrit ces etudiants dans ce semestre
(la liste doit avoir été vérifiée au préalable)
En option:
- Si inscrit_groupes, inscrit aux mêmes groupes que dans le semestre origine
(toutes partitions, y compris parcours)
- Si inscrit_parcours, inscrit au même groupe de parcours (mais ignore les autres partitions)
(si les deux sont vrais, inscrit_parcours n'a pas d'effet)
2020-09-26 16:19:37 +02:00
"""
# TODO à ré-écrire pour utiliser les modèles, notamment GroupDescr
formsemestre.setup_parcours_groups()
log(f"do_inscrit (inscrit_groupes={inscrit_groupes}): {etudids}")
2020-09-26 16:19:37 +02:00
for etudid in etudids:
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
formsemestre.id,
2020-09-26 16:19:37 +02:00
etudid,
etat=scu.INSCRIT,
2020-09-26 16:19:37 +02:00
method="formsemestre_inscr_passage",
)
if inscrit_groupes or inscrit_parcours:
2020-09-26 16:19:37 +02:00
# Inscription dans les mêmes groupes que ceux du semestre d'origine,
# s'ils existent.
# (mise en correspondance à partir du nom du groupe, sans tenir compte
# du nom de la partition: évidemment, cela ne marche pas si on a les
# même noms de groupes dans des partitions différentes)
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
2020-09-26 16:19:37 +02:00
# recherche le semestre origine (il serait plus propre de l'avoir conservé!)
if len(etud["sems"]) < 2:
continue
prev_formsemestre = etud["sems"][1]
2022-03-05 12:47:08 +01:00
sco_groups.etud_add_group_infos(
etud,
prev_formsemestre["formsemestre_id"] if prev_formsemestre else None,
)
2020-09-26 16:19:37 +02:00
cursem_groups_by_name = {
g["group_name"]: g
for g in sco_groups.get_sem_groups(formsemestre.id)
if g["group_name"]
}
2020-09-26 16:19:37 +02:00
# forme la liste des groupes présents dans les deux semestres:
partition_groups = [] # [ partition+group ] (ds nouveau sem.)
for partition_id in etud["partitions"]:
prev_group_name = etud["partitions"][partition_id]["group_name"]
if prev_group_name in cursem_groups_by_name:
new_group = cursem_groups_by_name[prev_group_name]
partition_groups.append(new_group)
# Inscrit aux groupes
2020-09-26 16:19:37 +02:00
for partition_group in partition_groups:
group: GroupDescr = db.session.get(
GroupDescr, partition_group["group_id"]
)
if inscrit_groupes or (
group.partition.partition_name == scu.PARTITION_PARCOURS
and inscrit_parcours
):
sco_groups.change_etud_group_in_partition(etudid, group)
2020-09-26 16:19:37 +02:00
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}")
2020-09-26 16:19:37 +02:00
for etudid in etudids:
2021-06-21 10:17:16 +02:00
sco_formsemestre_inscriptions.do_formsemestre_desinscription(
etudid, formsemestre.id, check_has_dec_jury=check_has_dec_jury
2020-09-26 16:19:37 +02:00
)
def _list_source_sems(formsemestre: FormSemestre) -> list[FormSemestre]:
2020-09-26 16:19:37 +02:00
"""Liste des semestres sources
formsemestre est le semestre destination
2020-09-26 16:19:37 +02:00
"""
# 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()
2020-09-26 16:19:37 +02:00
# view, GET, POST
2020-09-26 16:19:37 +02:00
def formsemestre_inscr_passage(
formsemestre_id,
etuds: str | list[int] | list[str] | int | None = None,
2020-09-26 16:19:37 +02:00
inscrit_groupes=False,
inscrit_parcours=False,
2020-09-26 16:19:37 +02:00
submitted=False,
dialog_confirmed=False,
ignore_jury=False,
2023-01-26 18:29:16 +01:00
) -> str:
"""Page Form. pour inscription des etudiants d'un semestre dans un autre
2020-09-26 16:19:37 +02:00
(donné par formsemestre_id).
Permet de selectionner parmi les etudiants autorisés à s'inscrire.
Principe:
- trouver liste d'etud, par semestre
- afficher chaque semestre "boites" avec cases à cocher
- si l'étudiant est déjà inscrit, le signaler (gras, nom de groupes): il peut être désinscrit
- on peut choisir les groupes TD, TP, TA
2023-01-26 18:29:16 +01:00
- seuls les étudiants non inscrits changent (de groupe)
- les étudiants inscrit qui se trouvent décochés sont désinscrits
- Confirmation: indiquer les étudiants inscrits et ceux désinscrits, le total courant.
2020-09-26 16:19:37 +02:00
"""
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
2020-09-26 16:19:37 +02:00
inscrit_groupes = int(inscrit_groupes)
inscrit_parcours = int(inscrit_parcours)
ignore_jury = int(ignore_jury)
2020-09-26 16:19:37 +02:00
# -- check lock
if not formsemestre.etat:
2020-09-26 16:19:37 +02:00
raise ScoValueError("opération impossible: semestre verrouille")
H = [
html_sco_header.sco_header(
page_title="Passage des étudiants",
init_qtip=True,
javascripts=["js/etud_info.js"],
)
]
footer = html_sco_header.sco_footer()
etuds = [] if etuds is None else etuds
2021-09-27 13:43:11 +02:00
if isinstance(etuds, str):
# string, vient du form de confirmation
etuds = [int(x) for x in etuds.split(",") if x]
2021-09-27 13:43:11 +02:00
elif isinstance(etuds, int):
etuds = [etuds]
2022-01-07 18:38:32 +01:00
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(
formsemestre, ignore_jury=ignore_jury
)
etuds_set = set(etuds)
candidats_set = set(candidats)
inscrits_set = set(inscrits)
2020-09-26 16:19:37 +02:00
candidats_non_inscrits = candidats_set - inscrits_set
inscrits_ailleurs = set(list_inscrits_date(formsemestre))
2020-09-26 16:19:37 +02:00
def set_to_sorted_etud_list(etudset) -> list[Identite]:
2020-09-26 16:19:37 +02:00
etuds = [candidats[etudid] for etudid in etudset]
etuds.sort(key=lambda e: e.sort_key)
2020-09-26 16:19:37 +02:00
return etuds
if submitted:
a_inscrire = etuds_set.intersection(candidats_set) - inscrits_set
a_desinscrire = inscrits_set - etuds_set
else:
a_inscrire = a_desinscrire = []
if not submitted:
2023-01-26 18:29:16 +01:00
H += _build_page(
formsemestre,
2020-09-26 16:19:37 +02:00
auth_etuds_by_sem,
inscrits,
candidats_non_inscrits,
inscrits_ailleurs,
inscrit_groupes=inscrit_groupes,
inscrit_parcours=inscrit_parcours,
ignore_jury=ignore_jury,
2020-09-26 16:19:37 +02:00
)
else:
if not dialog_confirmed:
# Confirmation
if a_inscrire:
2023-01-26 18:29:16 +01:00
H.append("<h3>Étudiants à inscrire</h3><ol>")
2020-09-26 16:19:37 +02:00
for etud in set_to_sorted_etud_list(a_inscrire):
H.append(f"<li>{etud.nomprenom}</li>")
2020-09-26 16:19:37 +02:00
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(f'<li class="inscrit-ailleurs">{etud.nomprenom}</li>')
2020-09-26 16:19:37 +02:00
H.append("</ul>")
if a_desinscrire:
2023-01-26 18:29:16 +01:00
H.append("<h3>Étudiants à désinscrire</h3><ol>")
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>')
2020-09-26 16:19:37 +02:00
H.append("</ol>")
2021-09-27 22:54:58 +02:00
todo = a_inscrire or a_desinscrire
if not todo:
2020-09-26 16:19:37 +02:00
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"
),
2021-09-27 22:54:58 +02:00
message="<p>Confirmer ?</p>" if todo else "",
2020-09-26 16:19:37 +02:00
add_headers=False,
cancel_url="formsemestre_inscr_passage?formsemestre_id="
2021-08-10 17:12:10 +02:00
+ str(formsemestre_id),
2021-09-27 22:54:58 +02:00
OK="Effectuer l'opération" if todo else "",
2020-09-26 16:19:37 +02:00
parameters={
"formsemestre_id": formsemestre_id,
"etuds": ",".join([str(x) for x in etuds]),
2020-09-26 16:19:37 +02:00
"inscrit_groupes": inscrit_groupes,
"inscrit_parcours": inscrit_parcours,
2022-01-18 22:55:33 +01:00
"ignore_jury": ignore_jury,
2020-09-26 16:19:37 +02:00
"submitted": 1,
},
)
)
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
)
2023-01-26 18:29:16 +01:00
with sco_cache.DeferredSemCacheManager():
# Inscription des étudiants au nouveau semestre:
do_inscrit(
formsemestre,
2023-01-26 18:29:16 +01:00
a_inscrire,
inscrit_groupes=inscrit_groupes,
inscrit_parcours=inscrit_parcours,
2023-01-26 18:29:16 +01:00
)
# Désinscriptions:
do_desinscrit(formsemestre, a_desinscrire, check_has_dec_jury=False)
2020-09-26 16:19:37 +02:00
H.append(
2023-01-26 18:29:16 +01:00
f"""<h3>Opération effectuée</h3>
<ul>
<li><a class="stdlink" href="{
url_for("notes.formsemestre_inscr_passage",
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id)
}">Continuer les inscriptions</a>
</li>
<li><a class="stdlink" href="{
url_for("notes.formsemestre_status",
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id)
}">Tableau de bord du semestre</a>
</li>"""
2020-09-26 16:19:37 +02:00
)
2021-08-19 10:28:35 +02:00
partition = sco_groups.formsemestre_get_main_partition(formsemestre_id)
2020-09-26 16:19:37 +02:00
if (
partition["partition_id"]
2021-08-19 10:28:35 +02:00
!= sco_groups.formsemestre_get_main_partition(formsemestre_id)[
2020-09-26 16:19:37 +02:00
"partition_id"
]
): # il y a au moins une vraie partition
H.append(
2021-08-16 08:33:12 +02:00
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 {partition["partition_name"]}</a></li>
"""
2020-09-26 16:19:37 +02:00
)
#
H.append(footer)
return "\n".join(H)
2023-01-26 18:29:16 +01:00
def _build_page(
formsemestre: FormSemestre,
2020-09-26 16:19:37 +02:00
auth_etuds_by_sem,
inscrits,
candidats_non_inscrits,
inscrits_ailleurs,
inscrit_groupes=False,
inscrit_parcours=False,
ignore_jury=False,
2020-09-26 16:19:37 +02:00
):
inscrit_groupes = int(inscrit_groupes)
inscrit_parcours = int(inscrit_parcours)
ignore_jury = int(ignore_jury)
2020-09-26 16:19:37 +02:00
if inscrit_groupes:
inscrit_groupes_checked = " checked"
else:
inscrit_groupes_checked = ""
if inscrit_parcours:
inscrit_parcours_checked = " checked"
else:
inscrit_parcours_checked = ""
if ignore_jury:
ignore_jury_checked = " checked"
else:
ignore_jury_checked = ""
2020-09-26 16:19:37 +02:00
H = [
2021-06-13 19:12:20 +02:00
html_sco_header.html_sem_header(
2022-01-07 15:11:24 +01:00
"Passages dans le semestre", with_page_header=False
2020-09-26 16:19:37 +02:00
),
2023-01-26 18:29:16 +01:00
f"""<form name="f" method="post" action="{request.base_url}">
<input type="hidden" name="formsemestre_id" value="{formsemestre.id}"/>
2023-01-26 18:29:16 +01:00
<input type="submit" name="submitted" value="Appliquer les modifications"/>
&nbsp;<a href="#help">aide</a>
<input name="inscrit_groupes" type="checkbox" value="1"
{inscrit_groupes_checked}>inscrire aux mêmes groupes (y compris parcours)</input>
<input name="inscrit_parcours" type="checkbox" value="1"
{inscrit_parcours_checked}>inscrire aux mêmes parcours</input>
2023-01-26 18:29:16 +01:00
<input name="ignore_jury" type="checkbox" value="1" onchange="document.f.submit()"
{ignore_jury_checked}>inclure tous les étudiants (même sans décision de jury)</input>
<div class="pas_recap">Actuellement <span id="nbinscrits">{len(inscrits)}</span>
inscrits et {len(candidats_non_inscrits)} candidats supplémentaires.
2023-01-26 18:29:16 +01:00
</div>
<div>{scu.EMO_WARNING}
<em>Seuls les semestres dont la date de fin est proche de la date de début
de ce semestre ({formsemestre.date_debut.strftime(scu.DATE_FMT)}) sont pris en
compte.</em>
</div>
2023-01-26 18:29:16 +01:00
{etuds_select_boxes(auth_etuds_by_sem, inscrits_ailleurs)}
<input type="submit" name="submitted" value="Appliquer les modifications"/>
{formsemestre_inscr_passage_help(formsemestre)}
2023-01-26 18:29:16 +01:00
</form>
""",
2020-09-26 16:19:37 +02:00
]
2023-01-26 18:29:16 +01:00
# Semestres sans étudiants autorisés
2020-09-26 16:19:37 +02:00
empty_sems = []
for formsemestre_id in auth_etuds_by_sem.keys():
if not auth_etuds_by_sem[formsemestre_id]["etuds"]:
empty_sems.append(auth_etuds_by_sem[formsemestre_id]["infos"])
if empty_sems:
H.append(
"""<div class="pas_empty_sems"><h3>Autres semestres sans candidats :</h3><ul>"""
)
for infos in empty_sems:
2023-01-26 18:29:16 +01:00
H.append(
"""<li><a class="stdlink" href="%(title_target)s">%(title)s</a></li>"""
% infos
)
2020-09-26 16:19:37 +02:00
H.append("""</ul></div>""")
return H
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>
2020-09-26 16:19:37 +02:00
<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=formsemestre.id )
}">{formsemestre.titre_annee()}</a>,
2020-09-26 16:19:37 +02:00
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="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
d'autres étudiants à inscrire dans le semestre destination.
</p>
<p>Si vous -selectionnez un étudiant déjà inscrit (en gras), il sera désinscrit.
</p>
<p>Le bouton <em>inscrire aux mêmes groupes</em> ne prend en compte que les groupes
qui existent dans les deux semestres: pensez à créer les partitions et groupes que
vous souhaitez conserver <b>avant</b> d'inscrire les étudiants.
</p>
<p>Les parcours de BUT sont gérés comme des groupes de la partition parcours: si on
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=formsemestre.id )
}">modifier le semestre</a> avant de faire passer les étudiants).
</a>
<p class="help">Aucune action ne sera effectuée si vous n'appuyez pas sur le bouton
"Appliquer les modifications" !
</p>
</div>
"""
2020-09-26 16:19:37 +02:00
def etuds_select_boxes(
auth_etuds_by_cat,
inscrits_ailleurs={},
sel_inscrits=True,
show_empty_boxes=False,
export_cat_xls=None,
base_url="",
read_only=False,
):
"""Boites pour selection étudiants par catégorie
auth_etuds_by_cat = { category : { 'info' : {}, 'etuds' : ... }
inscrits_ailleurs =
sel_inscrits=
2020-09-26 16:19:37 +02:00
export_cat_xls =
"""
if export_cat_xls:
return etuds_select_box_xls(auth_etuds_by_cat[export_cat_xls])
2020-09-26 16:19:37 +02:00
H = [
"""<script type="text/javascript">
function sem_select(formsemestre_id, state) {
var elems = document.getElementById(formsemestre_id).getElementsByTagName("input");
for (var i =0; i < elems.length; i++) { elems[i].checked=state; }
}
function sem_select_inscrits(formsemestre_id) {
var elems = document.getElementById(formsemestre_id).getElementsByTagName("input");
for (var i =0; i < elems.length; i++) {
if (elems[i].parentNode.className.indexOf('inscrit') >= 0) {
elems[i].checked=true;
} else {
elems[i].checked=false;
2023-12-31 23:04:06 +01:00
}
2020-09-26 16:19:37 +02:00
}
}
</script>
<div class="etuds_select_boxes">"""
] # "
# Élimine les boites vides:
auth_etuds_by_cat = {
k: auth_etuds_by_cat[k]
for k in auth_etuds_by_cat
if auth_etuds_by_cat[k]["etuds"]
}
2020-09-26 16:19:37 +02:00
for src_cat in auth_etuds_by_cat.keys():
infos = auth_etuds_by_cat[src_cat]["infos"]
infos["comment"] = infos.get("comment", "") # commentaire dans sous-titre boite
help = infos.get("help", "")
etuds = auth_etuds_by_cat[src_cat]["etuds"]
2021-07-09 23:19:30 +02:00
etuds.sort(key=itemgetter("nom"))
2020-09-26 16:19:37 +02:00
with_checkbox = (not read_only) and auth_etuds_by_cat[src_cat]["infos"].get(
"with_checkbox", True
)
checkbox_name = auth_etuds_by_cat[src_cat]["infos"].get(
"checkbox_name", "etuds"
)
etud_key = auth_etuds_by_cat[src_cat]["infos"].get("etud_key", "etudid")
if etuds or show_empty_boxes:
infos["nbetuds"] = len(etuds)
H.append(
"""<div class="pas_sembox" id="%(id)s">
<div class="pas_sembox_title"><a href="%(title_target)s" """
% infos
)
if help: # bubble
H.append('title="%s"' % help)
H.append(
""">%(title)s</a></div>
<div class="pas_sembox_subtitle">(%(nbetuds)d étudiants%(comment)s)"""
% infos
)
if with_checkbox:
H.append(
""" (Select.
<a href="#" class="stdlink" onclick="sem_select('%(id)s', true);">tous</a>
<a href="#" class="stdlink" onclick="sem_select('%(id)s', false );">aucun</a>""" # "
2020-09-26 16:19:37 +02:00
% infos
)
if sel_inscrits:
H.append(
"""<a href="#" class="stdlink" onclick="sem_select_inscrits('%(id)s');">inscrits</a>"""
2020-09-26 16:19:37 +02:00
% infos
)
if with_checkbox or sel_inscrits:
H.append(")")
if base_url and etuds:
url = scu.build_url_query(base_url, export_cat_xls=src_cat)
H.append(f'<a href="{url}">{scu.ICON_XLS}</a>&nbsp;')
2020-09-26 16:19:37 +02:00
H.append("</div>")
for etud in etuds:
if etud.get("inscrit", False):
c = " deja-inscrit"
2020-09-26 16:19:37 +02:00
checked = 'checked="checked"'
else:
checked = ""
if etud["etudid"] in inscrits_ailleurs:
c = " inscrit-ailleurs"
2020-09-26 16:19:37 +02:00
else:
c = ""
sco_etud.format_etud_ident(etud)
2020-09-26 16:19:37 +02:00
if etud["etudid"]:
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']}</a>
"""
2020-09-26 16:19:37 +02:00
else:
# ce n'est pas un etudiant ScoDoc
elink = etud["nomprenom"]
if etud.get("datefinalisationinscription", None):
elink += (
'<span class="finalisationinscription">'
+ " : inscription finalisée le "
+ etud["datefinalisationinscription"].strftime(scu.DATE_FMT)
2020-09-26 16:19:37 +02:00
+ "</span>"
)
if not etud.get("paiementinscription", True):
elink += '<span class="paspaye"> (non paiement)</span>'
H.append("""<div class="pas_etud%s">""" % c)
if "etape" in etud:
etape_str = etud["etape"] or ""
else:
etape_str = ""
H.append("""<span class="sp_etape">%s</span>""" % etape_str)
if with_checkbox:
H.append(
"""<input type="checkbox" name="%s:list" value="%s" %s>"""
% (checkbox_name, etud[etud_key], checked)
)
H.append(elink)
if with_checkbox:
H.append("""</input>""")
H.append("</div>")
H.append("</div>")
H.append("</div>")
return "\n".join(H)
def etuds_select_box_xls(src_cat):
2020-09-26 16:19:37 +02:00
"export a box to excel"
etuds = src_cat["etuds"]
columns_ids = ["etudid", "civilite_str", "nom", "prenom", "etape"]
titles = {x: x for x in columns_ids}
2020-09-26 16:19:37 +02:00
# Ajoute colonne paiement inscription
columns_ids.append("paiementinscription_str")
titles["paiementinscription_str"] = "paiement inscription"
for e in etuds:
if not e.get("paiementinscription", True):
e["paiementinscription_str"] = "NON"
else:
e["paiementinscription_str"] = "-"
tab = GenTable(
caption="%(title)s. %(help)s" % src_cat["infos"],
columns_ids=columns_ids,
preferences=sco_preferences.SemPreferences(),
rows=etuds,
table_id="etuds_select_box_xls",
titles=titles,
2020-09-26 16:19:37 +02:00
)
2024-07-19 18:03:24 +02:00
return tab.excel()