forked from ScoDoc/ScoDoc
Assiduites : préférences - métrique + lien assiduité avec reste scodoc
This commit is contained in:
parent
238b6b10d4
commit
825dc6ecb1
@ -386,6 +386,12 @@ class BulletinBUT:
|
||||
semestre_infos["absences"] = {
|
||||
"injustifie": nbabs - nbabsjust,
|
||||
"total": nbabs,
|
||||
"metrique": {
|
||||
"H.": "Heure(s)",
|
||||
"J.": "Journée(s)",
|
||||
"1/2 J.": "1/2 Jour.",
|
||||
"N.": "Nombre",
|
||||
}.get(sco_preferences.get_preference("assi_metrique")),
|
||||
}
|
||||
decisions_ues = self.res.get_etud_decisions_ue(etud.id) or {}
|
||||
if self.prefs["bul_show_ects"]:
|
||||
|
@ -39,9 +39,11 @@ from app.models.validations import ScolarFormSemestreValidation
|
||||
from app.scodoc import codes_cursus, sco_preferences
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
from app.scodoc.sco_utils import MONTH_NAMES_ABBREV
|
||||
from app.scodoc.sco_utils import MONTH_NAMES_ABBREV, translate_assiduites_metric
|
||||
from app.scodoc.sco_vdi import ApoEtapeVDI
|
||||
|
||||
from app.scodoc.sco_utils import translate_assiduites_metric
|
||||
|
||||
GROUPS_AUTO_ASSIGNMENT_DATA_MAX = 1024 * 1024 # bytes
|
||||
|
||||
|
||||
@ -678,8 +680,12 @@ class FormSemestre(db.Model):
|
||||
"""
|
||||
from app.scodoc import sco_abs
|
||||
|
||||
return sco_abs.get_abs_count_in_interval(
|
||||
etudid, self.date_debut.isoformat(), self.date_fin.isoformat()
|
||||
metrique = sco_preferences.get_preference("assi_metrique", self.id)
|
||||
return sco_abs.get_assiduites_count_in_interval(
|
||||
etudid,
|
||||
self.date_debut.isoformat(),
|
||||
self.date_fin.isoformat(),
|
||||
translate_assiduites_metric(metrique),
|
||||
)
|
||||
|
||||
def get_codes_apogee(self, category=None) -> set[str]:
|
||||
|
@ -116,10 +116,10 @@ def sidebar(etudid: int = None):
|
||||
)
|
||||
if etud["cursem"]:
|
||||
cur_sem = etud["cursem"]
|
||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, cur_sem)
|
||||
nbabs, nbabsjust = sco_abs.get_assiduites_count(etudid, cur_sem)
|
||||
nbabsnj = nbabs - nbabsjust
|
||||
H.append(
|
||||
f"""<span title="absences du { cur_sem["date_debut"] } au { cur_sem["date_fin"] }">(1/2 j.)
|
||||
f"""<span title="absences du { cur_sem["date_debut"] } au { cur_sem["date_fin"] }">({sco_preferences.get_preference("assi_metrique", None)})
|
||||
<br>{ nbabsjust } J., { nbabsnj } N.J.</span>"""
|
||||
)
|
||||
H.append("<ul>")
|
||||
|
@ -1054,19 +1054,42 @@ def get_abs_count_in_interval(etudid, date_debut_iso, date_fin_iso):
|
||||
return r
|
||||
|
||||
|
||||
def get_assiduites_count_in_interval(etudid, date_debut_iso, date_fin_iso):
|
||||
def get_assiduites_count(etudid, sem):
|
||||
"""Les comptes d'absences de cet étudiant dans ce semestre:
|
||||
tuple (nb abs non justifiées, nb abs justifiées)
|
||||
Utilise un cache.
|
||||
"""
|
||||
metrique = sco_preferences.get_preference("assi_metrique", sem["formsemestre_id"])
|
||||
return get_assiduites_count_in_interval(
|
||||
etudid,
|
||||
sem["date_debut_iso"],
|
||||
sem["date_fin_iso"],
|
||||
scu.translate_assiduites_metric(metrique),
|
||||
)
|
||||
|
||||
|
||||
def get_assiduites_count_in_interval(
|
||||
etudid, date_debut_iso, date_fin_iso, metrique="demi"
|
||||
):
|
||||
"""Les comptes d'absences de cet étudiant entre ces deux dates, incluses:
|
||||
tuple (nb abs, nb abs justifiées)
|
||||
Utilise un cache.
|
||||
"""
|
||||
key = str(etudid) + "_" + date_debut_iso + "_" + date_fin_iso + "_assiduites"
|
||||
key = (
|
||||
str(etudid)
|
||||
+ "_"
|
||||
+ date_debut_iso
|
||||
+ "_"
|
||||
+ date_fin_iso
|
||||
+ f"{metrique}_assiduites"
|
||||
)
|
||||
r = sco_cache.AbsSemEtudCache.get(key)
|
||||
if not r:
|
||||
|
||||
date_debut: datetime.datetime = scu.is_iso_formated(date_debut_iso, True)
|
||||
date_fin: datetime.datetime = scu.is_iso_formated(date_fin_iso, True)
|
||||
|
||||
assiduites: Assiduite = Assiduite.query.filter_by(etudid=etudid)
|
||||
assiduites = assiduites.filter(Assiduite.etat != 0)
|
||||
justificatifs: Justificatif = Justificatif.query.filter_by(etudid=etudid)
|
||||
|
||||
assiduites = scass.filter_by_date(assiduites, Assiduite, date_debut, date_fin)
|
||||
@ -1076,7 +1099,7 @@ def get_assiduites_count_in_interval(etudid, date_debut_iso, date_fin_iso):
|
||||
|
||||
calculator: scass.CountCalculator = scass.CountCalculator()
|
||||
calculator.compute_assiduites(assiduites)
|
||||
nb_abs: dict = calculator.to_dict()["demi"]
|
||||
nb_abs: dict = calculator.to_dict()[metrique]
|
||||
|
||||
abs_just: list[Assiduite] = scass.get_all_justified(
|
||||
etudid, date_debut, date_fin
|
||||
@ -1084,7 +1107,7 @@ def get_assiduites_count_in_interval(etudid, date_debut_iso, date_fin_iso):
|
||||
|
||||
calculator.reset()
|
||||
calculator.compute_assiduites(abs_just)
|
||||
nb_abs_just: dict = calculator.to_dict()["demi"]
|
||||
nb_abs_just: dict = calculator.to_dict()[metrique]
|
||||
|
||||
r = (nb_abs, nb_abs_just)
|
||||
ans = sco_cache.AbsSemEtudCache.set(key, r)
|
||||
@ -1101,6 +1124,15 @@ def invalidate_abs_count(etudid, sem):
|
||||
sco_cache.AbsSemEtudCache.delete(key)
|
||||
|
||||
|
||||
def invalidate_assiduites_count(etudid, sem):
|
||||
"""Invalidate (clear) cached counts"""
|
||||
date_debut = sem["date_debut_iso"]
|
||||
date_fin = sem["date_fin_iso"]
|
||||
for met in ["demi", "journee", "compte", "heure"]:
|
||||
key = str(etudid) + "_" + date_debut + "_" + date_fin + f"{met}_assiduites"
|
||||
sco_cache.AbsSemEtudCache.delete(key)
|
||||
|
||||
|
||||
def invalidate_abs_count_sem(sem):
|
||||
"""Invalidate (clear) cached abs counts for all the students of this semestre"""
|
||||
inscriptions = (
|
||||
@ -1112,6 +1144,17 @@ def invalidate_abs_count_sem(sem):
|
||||
invalidate_abs_count(ins["etudid"], sem)
|
||||
|
||||
|
||||
def invalidate_assiduites_count_sem(sem):
|
||||
"""Invalidate (clear) cached abs counts for all the students of this semestre"""
|
||||
inscriptions = (
|
||||
sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
|
||||
sem["formsemestre_id"]
|
||||
)
|
||||
)
|
||||
for ins in inscriptions:
|
||||
invalidate_assiduites_count(ins["etudid"], sem)
|
||||
|
||||
|
||||
def invalidate_abs_etud_date(etudid, date): # was invalidateAbsEtudDate
|
||||
"""Doit etre appelé à chaque modification des absences pour cet étudiant et cette date.
|
||||
Invalide cache absence et caches semestre
|
||||
@ -1145,3 +1188,38 @@ def invalidate_abs_etud_date(etudid, date): # was invalidateAbsEtudDate
|
||||
|
||||
# Inval cache compteurs absences:
|
||||
invalidate_abs_count_sem(sem)
|
||||
|
||||
|
||||
def invalidate_assiduites_etud_date(etudid, date):
|
||||
"""Doit etre appelé à chaque modification des assiduites pour cet étudiant et cette date.
|
||||
Invalide cache absence et caches semestre
|
||||
date: date au format ISO
|
||||
"""
|
||||
from app.scodoc import sco_compute_moy
|
||||
|
||||
# Semestres a cette date:
|
||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
||||
sems = [
|
||||
sem
|
||||
for sem in etud["sems"]
|
||||
if sem["date_debut_iso"] <= date and sem["date_fin_iso"] >= date
|
||||
]
|
||||
|
||||
# Invalide les PDF et les absences:
|
||||
for sem in sems:
|
||||
# Inval cache bulletin et/ou note_table
|
||||
if sco_compute_moy.formsemestre_expressions_use_abscounts(
|
||||
sem["formsemestre_id"]
|
||||
):
|
||||
# certaines formules utilisent les absences
|
||||
pdfonly = False
|
||||
else:
|
||||
# efface toujours le PDF car il affiche en général les absences
|
||||
pdfonly = True
|
||||
|
||||
sco_cache.invalidate_formsemestre(
|
||||
formsemestre_id=sem["formsemestre_id"], pdfonly=pdfonly
|
||||
)
|
||||
|
||||
# Inval cache compteurs absences:
|
||||
invalidate_assiduites_count(etudid, sem)
|
||||
|
@ -47,6 +47,7 @@ import app.scodoc.notesdb as ndb
|
||||
from app.scodoc import sco_etud
|
||||
from app.scodoc import sco_preferences
|
||||
from app.scodoc import sco_users
|
||||
from app.scodoc import sco_utils as scu
|
||||
|
||||
|
||||
def abs_notify(etudid, date):
|
||||
@ -61,8 +62,15 @@ def abs_notify(etudid, date):
|
||||
if not formsemestre:
|
||||
return # non inscrit a la date, pas de notification
|
||||
|
||||
nbabs, nbabsjust = sco_abs.get_abs_count_in_interval(
|
||||
etudid, formsemestre.date_debut.isoformat(), formsemestre.date_fin.isoformat()
|
||||
nbabs, nbabsjust = sco_abs.get_assiduites_count_in_interval(
|
||||
etudid,
|
||||
formsemestre.date_debut.isoformat(),
|
||||
formsemestre.date_fin.isoformat(),
|
||||
scu.translate_assiduites_metric(
|
||||
sco_preferences.get_preference(
|
||||
"assi_metrique", formsemestre.formsemestre_id
|
||||
)
|
||||
),
|
||||
)
|
||||
do_abs_notify(formsemestre, etudid, date, nbabs, nbabsjust)
|
||||
|
||||
@ -85,6 +93,7 @@ def do_abs_notify(formsemestre: FormSemestre, etudid, date, nbabs, nbabsjust):
|
||||
return # abort
|
||||
|
||||
# Vérification fréquence (pour ne pas envoyer de mails trop souvent)
|
||||
# TODO Mettre la fréquence dans les préférences assiduités
|
||||
abs_notify_max_freq = sco_preferences.get_preference("abs_notify_max_freq")
|
||||
destinations_filtered = []
|
||||
for email_addr in destinations:
|
||||
@ -174,6 +183,8 @@ def abs_notify_is_above_threshold(etudid, nbabs, nbabsjust, formsemestre_id):
|
||||
|
||||
(nbabs > abs_notify_abs_threshold)
|
||||
(nbabs - nbabs_last_notified) > abs_notify_abs_increment
|
||||
|
||||
TODO Mettre à jour avec le module assiduité + fonctionnement métrique
|
||||
"""
|
||||
abs_notify_abs_threshold = sco_preferences.get_preference(
|
||||
"abs_notify_abs_threshold", formsemestre_id
|
||||
|
@ -197,7 +197,7 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
|
||||
pid = partition["partition_id"]
|
||||
partitions_etud_groups[pid] = sco_groups.get_etud_groups_in_partition(pid)
|
||||
# --- Absences
|
||||
I["nbabs"], I["nbabsjust"] = sco_abs.get_abs_count(etudid, nt.sem)
|
||||
I["nbabs"], I["nbabsjust"] = sco_abs.get_assiduites_count(etudid, nt.sem)
|
||||
|
||||
# --- Decision Jury
|
||||
infos, dpv = etud_descr_situation_semestre(
|
||||
@ -487,7 +487,7 @@ def _ue_mod_bulletin(
|
||||
) # peut etre 'NI'
|
||||
is_malus = mod["module"]["module_type"] == ModuleType.MALUS
|
||||
if bul_show_abs_modules:
|
||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||
nbabs, nbabsjust = sco_abs.get_assiduites_count(etudid, sem)
|
||||
mod_abs = [nbabs, nbabsjust]
|
||||
mod["mod_abs_txt"] = scu.fmt_abs(mod_abs)
|
||||
else:
|
||||
|
@ -297,7 +297,7 @@ def formsemestre_bulletinetud_published_dict(
|
||||
|
||||
# --- Absences
|
||||
if prefs["bul_show_abs"]:
|
||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||
nbabs, nbabsjust = sco_abs.get_assiduites_count(etudid, sem)
|
||||
d["absences"] = dict(nbabs=nbabs, nbabsjust=nbabsjust)
|
||||
|
||||
# --- Décision Jury
|
||||
|
@ -63,6 +63,7 @@ from app.scodoc import sco_etud
|
||||
from app.scodoc import sco_xml
|
||||
from app.scodoc.sco_xml import quote_xml_attr
|
||||
|
||||
|
||||
# -------- Bulletin en XML
|
||||
# (fonction séparée: n'utilise pas formsemestre_bulletinetud_dict()
|
||||
# pour simplifier le code, mais attention a la maintenance !)
|
||||
@ -369,7 +370,7 @@ def make_xml_formsemestre_bulletinetud(
|
||||
|
||||
# --- Absences
|
||||
if sco_preferences.get_preference("bul_show_abs", formsemestre_id):
|
||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||
nbabs, nbabsjust = sco_abs.get_assiduites_count(etudid, sem)
|
||||
doc.append(Element("absences", nbabs=str(nbabs), nbabsjust=str(nbabsjust)))
|
||||
# --- Decision Jury
|
||||
if (
|
||||
|
@ -696,7 +696,7 @@ def formsemestre_recap_parcours_table(
|
||||
f"""<td class="rcp_moy">{scu.fmt_note(nt.get_etud_moy_gen(etudid))}</td>"""
|
||||
)
|
||||
# Absences (nb d'abs non just. dans ce semestre)
|
||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||
nbabs, nbabsjust = sco_abs.get_assiduites_count(etudid, sem)
|
||||
H.append(f"""<td class="rcp_abs">{nbabs - nbabsjust}</td>""")
|
||||
|
||||
# UEs
|
||||
|
@ -107,7 +107,7 @@ def etud_get_poursuite_info(sem, etud):
|
||||
rangs.append(["rang_" + codeModule, rangModule])
|
||||
|
||||
# Absences
|
||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, nt.sem)
|
||||
nbabs, nbabsjust = sco_abs.get_assiduites_count(etudid, nt.sem)
|
||||
if (
|
||||
dec
|
||||
and not sem_descr # not sem_descr pour ne prendre que le semestre validé le plus récent
|
||||
|
@ -653,6 +653,19 @@ class BasePreferences(object):
|
||||
"explanation": "Liste des jours (lun,mar,mer,jeu,ven,sam,dim)",
|
||||
},
|
||||
),
|
||||
(
|
||||
"assi_metrique",
|
||||
{
|
||||
"initvalue": "1/2 J.",
|
||||
"input_type": "menu",
|
||||
"labels": ["1/2 J.", "J.", "H.", "N."],
|
||||
"allowed_values": ["1/2 J.", "J.", "H.", "N."],
|
||||
"title": "Métrique de l'assiduité",
|
||||
"explanation": "Unité affichée dans la fiche étudiante et le bilan\n(J. = journée, H. = heure, N. = nombre)",
|
||||
"category": "assi",
|
||||
"only_global" : True,
|
||||
},
|
||||
),
|
||||
# portal
|
||||
(
|
||||
"portal_url",
|
||||
|
@ -139,7 +139,7 @@ def feuille_preparation_jury(formsemestre_id):
|
||||
main_partition_id, ""
|
||||
)
|
||||
# absences:
|
||||
e_nbabs, e_nbabsjust = sco_abs.get_abs_count(etud.id, sem)
|
||||
e_nbabs, e_nbabsjust = sco_abs.get_assiduites_count(etud.id, sem)
|
||||
nbabs[etud.id] = e_nbabs
|
||||
nbabsjust[etud.id] = e_nbabs - e_nbabsjust
|
||||
|
||||
|
@ -251,6 +251,17 @@ def is_period_overlapping(
|
||||
return p_deb < i_fin and p_fin > i_deb
|
||||
|
||||
|
||||
def translate_assiduites_metric(hr_metric) -> str:
|
||||
if hr_metric == "1/2 J.":
|
||||
return "demi"
|
||||
if hr_metric == "J.":
|
||||
return "journee"
|
||||
if hr_metric == "N.":
|
||||
return "compte"
|
||||
if hr_metric == "H.":
|
||||
return "heure"
|
||||
|
||||
|
||||
# Types de modules
|
||||
class ModuleType(IntEnum):
|
||||
"""Code des types de module."""
|
||||
|
@ -2,38 +2,45 @@
|
||||
class releveBUT extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.shadow = this.attachShadow({ mode: 'open' });
|
||||
this.shadow = this.attachShadow({ mode: "open" });
|
||||
|
||||
/* Config par defaut */
|
||||
this.config = {
|
||||
showURL: true
|
||||
showURL: true,
|
||||
};
|
||||
|
||||
/* Template du module */
|
||||
this.shadow.innerHTML = this.template();
|
||||
|
||||
/* Style du module */
|
||||
const styles = document.createElement('link');
|
||||
styles.setAttribute('rel', 'stylesheet');
|
||||
const styles = document.createElement("link");
|
||||
styles.setAttribute("rel", "stylesheet");
|
||||
if (location.href.includes("ScoDoc")) {
|
||||
styles.setAttribute('href', removeLastTwoComponents(getCurrentScriptPath()) + '/css/releve-but.css'); // Scodoc
|
||||
styles.setAttribute(
|
||||
"href",
|
||||
removeLastTwoComponents(getCurrentScriptPath()) + "/css/releve-but.css"
|
||||
); // Scodoc
|
||||
} else {
|
||||
styles.setAttribute('href', '/assets/styles/releve-but.css'); // Passerelle
|
||||
styles.setAttribute("href", "/assets/styles/releve-but.css"); // Passerelle
|
||||
}
|
||||
this.shadow.appendChild(styles);
|
||||
}
|
||||
listeOnOff() {
|
||||
this.parentElement.parentElement.classList.toggle("listeOff");
|
||||
this.parentElement.parentElement.querySelectorAll(".moduleOnOff").forEach(e => {
|
||||
e.classList.remove("moduleOnOff")
|
||||
})
|
||||
this.parentElement.parentElement
|
||||
.querySelectorAll(".moduleOnOff")
|
||||
.forEach((e) => {
|
||||
e.classList.remove("moduleOnOff");
|
||||
});
|
||||
}
|
||||
moduleOnOff() {
|
||||
this.parentElement.classList.toggle("moduleOnOff");
|
||||
}
|
||||
goTo() {
|
||||
let module = this.dataset.module;
|
||||
this.parentElement.parentElement.parentElement.parentElement.querySelector("#Module_" + module).scrollIntoView();
|
||||
this.parentElement.parentElement.parentElement.parentElement
|
||||
.querySelector("#Module_" + module)
|
||||
.scrollIntoView();
|
||||
}
|
||||
|
||||
set setConfig(config) {
|
||||
@ -50,15 +57,17 @@ class releveBUT extends HTMLElement {
|
||||
|
||||
this.setOptions(data.options);
|
||||
|
||||
this.shadow.querySelectorAll(".CTA_Liste").forEach(e => {
|
||||
e.addEventListener("click", this.listeOnOff)
|
||||
})
|
||||
this.shadow.querySelectorAll(".ue, .module").forEach(e => {
|
||||
e.addEventListener("click", this.moduleOnOff)
|
||||
})
|
||||
this.shadow.querySelectorAll(":not(.ueBonus)+.syntheseModule").forEach(e => {
|
||||
e.addEventListener("click", this.goTo)
|
||||
})
|
||||
this.shadow.querySelectorAll(".CTA_Liste").forEach((e) => {
|
||||
e.addEventListener("click", this.listeOnOff);
|
||||
});
|
||||
this.shadow.querySelectorAll(".ue, .module").forEach((e) => {
|
||||
e.addEventListener("click", this.moduleOnOff);
|
||||
});
|
||||
this.shadow
|
||||
.querySelectorAll(":not(.ueBonus)+.syntheseModule")
|
||||
.forEach((e) => {
|
||||
e.addEventListener("click", this.goTo);
|
||||
});
|
||||
|
||||
this.shadow.children[0].classList.add("ready");
|
||||
}
|
||||
@ -146,9 +155,10 @@ class releveBUT extends HTMLElement {
|
||||
/* Informations sur l'étudiant */
|
||||
/********************************/
|
||||
showInformations(data) {
|
||||
this.shadow.querySelector(".studentPic").src = data.etudiant.photo_url || "default_Student.svg";
|
||||
this.shadow.querySelector(".studentPic").src =
|
||||
data.etudiant.photo_url || "default_Student.svg";
|
||||
|
||||
let output = '';
|
||||
let output = "";
|
||||
|
||||
if (this.config.showURL) {
|
||||
output += `<a href="${data.etudiant.fiche_url}" class=info_etudiant>`;
|
||||
@ -163,7 +173,9 @@ class releveBUT extends HTMLElement {
|
||||
${data.etudiant.prenom}`;
|
||||
|
||||
if (data.etudiant.date_naissance) {
|
||||
output += ` <div class=dateNaissance>né${(data.etudiant.civilite == "F") ? "e" : ""} le ${this.ISOToDate(data.etudiant.date_naissance)}</div>`;
|
||||
output += ` <div class=dateNaissance>né${
|
||||
data.etudiant.civilite == "F" ? "e" : ""
|
||||
} le ${this.ISOToDate(data.etudiant.date_naissance)}</div>`;
|
||||
}
|
||||
|
||||
output += `
|
||||
@ -195,23 +207,28 @@ class releveBUT extends HTMLElement {
|
||||
/*******************************/
|
||||
showSemestre(data) {
|
||||
let correspondanceCodes = {
|
||||
"ADM": "Admis",
|
||||
"AJD": "Admis par décision de jury",
|
||||
"PASD": "Passage de droit : tout n'est pas validé, mais d'après les règles du BUT, vous passez",
|
||||
"PAS1NCI": "Vous passez par décision de jury mais attention, vous n'avez pas partout le niveau suffisant",
|
||||
"RED": "Ajourné mais autorisé à redoubler",
|
||||
"NAR": "Non admis et non autorisé à redoubler : réorientation",
|
||||
"DEM": "Démission",
|
||||
"ABAN": "Abandon constaté sans lettre de démission",
|
||||
"RAT": "En attente d'un rattrapage",
|
||||
"EXCLU": "Exclusion dans le cadre d'une décision disciplinaire",
|
||||
"DEF": "Défaillance : non évalué par manque d'assiduité",
|
||||
"ABL": "Année blanche"
|
||||
}
|
||||
ADM: "Admis",
|
||||
AJD: "Admis par décision de jury",
|
||||
PASD: "Passage de droit : tout n'est pas validé, mais d'après les règles du BUT, vous passez",
|
||||
PAS1NCI:
|
||||
"Vous passez par décision de jury mais attention, vous n'avez pas partout le niveau suffisant",
|
||||
RED: "Ajourné mais autorisé à redoubler",
|
||||
NAR: "Non admis et non autorisé à redoubler : réorientation",
|
||||
DEM: "Démission",
|
||||
ABAN: "Abandon constaté sans lettre de démission",
|
||||
RAT: "En attente d'un rattrapage",
|
||||
EXCLU: "Exclusion dans le cadre d'une décision disciplinaire",
|
||||
DEF: "Défaillance : non évalué par manque d'assiduité",
|
||||
ABL: "Année blanche",
|
||||
};
|
||||
|
||||
this.shadow.querySelector("#identite_etudiant").innerHTML = ` <a href="${data.etudiant.fiche_url}">${data.etudiant.nomprenom}</a> `;
|
||||
this.shadow.querySelector(".dateInscription").innerHTML += this.ISOToDate(data.semestre.inscription);
|
||||
let output = '';
|
||||
this.shadow.querySelector(
|
||||
"#identite_etudiant"
|
||||
).innerHTML = ` <a href="${data.etudiant.fiche_url}">${data.etudiant.nomprenom}</a> `;
|
||||
this.shadow.querySelector(".dateInscription").innerHTML += this.ISOToDate(
|
||||
data.semestre.inscription
|
||||
);
|
||||
let output = "";
|
||||
if (!data.options.block_moyenne_generale) {
|
||||
output += `
|
||||
<div>
|
||||
@ -225,12 +242,16 @@ class releveBUT extends HTMLElement {
|
||||
}
|
||||
output += `
|
||||
${(() => {
|
||||
if ((!data.semestre.rang.groupes) ||
|
||||
(Object.keys(data.semestre.rang.groupes).length == 0)) {
|
||||
if (
|
||||
!data.semestre.rang.groupes ||
|
||||
Object.keys(data.semestre.rang.groupes).length == 0
|
||||
) {
|
||||
return "";
|
||||
}
|
||||
let output = "";
|
||||
let [idGroupe, dataGroupe] = Object.entries(data.semestre.rang.groupes)[0];
|
||||
let [idGroupe, dataGroupe] = Object.entries(
|
||||
data.semestre.rang.groupes
|
||||
)[0];
|
||||
output += `<div>
|
||||
<div class=enteteSemestre>${data.semestre.groupes[0]?.group_name}</div><div></div>
|
||||
<div class=rang>Rang :</div><div class=rang>${dataGroupe.value} / ${dataGroupe.total}</div>
|
||||
@ -241,7 +262,9 @@ class releveBUT extends HTMLElement {
|
||||
return output;
|
||||
})()}
|
||||
<div class=absencesRecap>
|
||||
<div class=enteteSemestre>Absences</div><div class=enteteSemestre>1/2 jour.</div>
|
||||
<div class=enteteSemestre>Absences</div><div class=enteteSemestre>${
|
||||
data.semestre.absences?.metrique ?? "1/2 jour."
|
||||
}</div>
|
||||
<div class=abs>Non justifiées</div>
|
||||
<div>${data.semestre.absences?.injustifie ?? "-"}</div>
|
||||
<div class=abs>Total</div><div>${data.semestre.absences?.total ?? "-"}</div>
|
||||
@ -252,13 +275,13 @@ class releveBUT extends HTMLElement {
|
||||
<div class=enteteSemestre>RCUE</div><div></div>
|
||||
${(() => {
|
||||
let output = "";
|
||||
data.semestre.decision_rcue.forEach(competence => {
|
||||
data.semestre.decision_rcue.forEach((competence) => {
|
||||
output += `<div class=competence>${competence.niveau.competence.titre}</div><div>${competence.code}</div>`;
|
||||
})
|
||||
});
|
||||
return output;
|
||||
})()}
|
||||
</div>
|
||||
</div>`
|
||||
</div>`;
|
||||
}
|
||||
if (data.semestre.decision_ue?.length) {
|
||||
output += `
|
||||
@ -266,18 +289,20 @@ class releveBUT extends HTMLElement {
|
||||
<div class=enteteSemestre>UE</div><div></div>
|
||||
${(() => {
|
||||
let output = "";
|
||||
data.semestre.decision_ue.forEach(ue => {
|
||||
data.semestre.decision_ue.forEach((ue) => {
|
||||
output += `<div class=competence>${ue.acronyme}</div><div>${ue.code}</div>`;
|
||||
})
|
||||
});
|
||||
return output;
|
||||
})()}
|
||||
</div>
|
||||
</div>`
|
||||
</div>`;
|
||||
}
|
||||
|
||||
output += `
|
||||
<a class=photo href="${data.etudiant.fiche_url}">
|
||||
<img src="${data.etudiant.photo_url || "default_Student.svg"}" alt="photo de l'étudiant" title="fiche de l'étudiant" height="120" border="0">
|
||||
<img src="${
|
||||
data.etudiant.photo_url || "default_Student.svg"
|
||||
}" alt="photo de l'étudiant" title="fiche de l'étudiant" height="120" border="0">
|
||||
</a>`;
|
||||
/*${data.semestre.groupes.map(groupe => {
|
||||
return `
|
||||
@ -293,16 +318,20 @@ class releveBUT extends HTMLElement {
|
||||
}*/
|
||||
this.shadow.querySelector(".infoSemestre").innerHTML = output;
|
||||
|
||||
|
||||
/*if(data.semestre.decision_annee?.code){
|
||||
this.shadow.querySelector(".decision_annee").innerHTML = "Décision année : " + data.semestre.decision_annee.code + " - " + correspondanceCodes[data.semestre.decision_annee.code];
|
||||
}*/
|
||||
|
||||
this.shadow.querySelector(".decision").innerHTML = data.semestre.situation || "";
|
||||
this.shadow.querySelector(".decision").innerHTML =
|
||||
data.semestre.situation || "";
|
||||
/*if (data.semestre.decision?.code) {
|
||||
this.shadow.querySelector(".decision").innerHTML = "Décision jury: " + (data.semestre.decision?.code || "");
|
||||
}*/
|
||||
this.shadow.querySelector("#ects_tot").innerHTML = "ECTS : " + (data.semestre.ECTS?.acquis ?? "-") + " / " + (data.semestre.ECTS?.total ?? "-");
|
||||
this.shadow.querySelector("#ects_tot").innerHTML =
|
||||
"ECTS : " +
|
||||
(data.semestre.ECTS?.acquis ?? "-") +
|
||||
" / " +
|
||||
(data.semestre.ECTS?.total ?? "-");
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
@ -313,14 +342,15 @@ class releveBUT extends HTMLElement {
|
||||
/* Fusion et tri des UE et UE capitalisées */
|
||||
let fusionUE = [
|
||||
...Object.entries(data.ues),
|
||||
...Object.entries(data.ues_capitalisees)
|
||||
...Object.entries(data.ues_capitalisees),
|
||||
].sort((a, b) => {
|
||||
return a[1].numero - b[1].numero
|
||||
return a[1].numero - b[1].numero;
|
||||
});
|
||||
|
||||
/* Affichage */
|
||||
fusionUE.forEach(([ue, dataUE]) => {
|
||||
if (dataUE.type == 1) { // UE Sport / Bonus
|
||||
if (dataUE.type == 1) {
|
||||
// UE Sport / Bonus
|
||||
output += `
|
||||
<div>
|
||||
<div class="ue ueBonus">
|
||||
@ -335,21 +365,29 @@ class releveBUT extends HTMLElement {
|
||||
<div>
|
||||
<div class="ue ${dataUE.date_capitalisation ? "capitalisee" : ""}">
|
||||
<h3>
|
||||
${ue}${(dataUE.titre) ? " - " + dataUE.titre : ""}
|
||||
${ue}${dataUE.titre ? " - " + dataUE.titre : ""}
|
||||
</h3>
|
||||
<div>
|
||||
<div class=moyenne>Moyenne : ${dataUE.moyenne?.value || dataUE.moyenne || "-"}</div>
|
||||
<div class=ue_rang>Rang : ${dataUE.moyenne?.rang} / ${dataUE.moyenne?.total}</div>
|
||||
<div class=moyenne>Moyenne : ${
|
||||
dataUE.moyenne?.value || dataUE.moyenne || "-"
|
||||
}</div>
|
||||
<div class=ue_rang>Rang : ${dataUE.moyenne?.rang} / ${
|
||||
dataUE.moyenne?.total
|
||||
}</div>
|
||||
<div class=info>`;
|
||||
if (!dataUE.date_capitalisation) {
|
||||
output += ` Bonus : ${dataUE.bonus || 0} -
|
||||
Malus : ${dataUE.malus || 0}`;
|
||||
} else {
|
||||
output += ` le ${this.ISOToDate(dataUE.date_capitalisation.split("T")[0])} <a href="${dataUE.bul_orig_url}">dans ce semestre</a>`;
|
||||
output += ` le ${this.ISOToDate(
|
||||
dataUE.date_capitalisation.split("T")[0]
|
||||
)} <a href="${dataUE.bul_orig_url}">dans ce semestre</a>`;
|
||||
}
|
||||
|
||||
output += ` <span class=ects> -
|
||||
ECTS : ${dataUE.ECTS?.acquis ?? "-"} / ${dataUE.ECTS?.total ?? "-"}
|
||||
ECTS : ${dataUE.ECTS?.acquis ?? "-"} / ${
|
||||
dataUE.ECTS?.total ?? "-"
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</div>`;
|
||||
@ -384,7 +422,7 @@ class releveBUT extends HTMLElement {
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
})
|
||||
});
|
||||
return output;
|
||||
}
|
||||
ueSport(modules) {
|
||||
@ -400,8 +438,8 @@ class releveBUT extends HTMLElement {
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -409,7 +447,9 @@ class releveBUT extends HTMLElement {
|
||||
/* Evaluations */
|
||||
/*******************************/
|
||||
showEvaluations(data) {
|
||||
this.shadow.querySelector(".evaluations").innerHTML = this.module(data.ressources);
|
||||
this.shadow.querySelector(".evaluations").innerHTML = this.module(
|
||||
data.ressources
|
||||
);
|
||||
this.shadow.querySelector(".sae").innerHTML += this.module(data.saes);
|
||||
}
|
||||
module(module) {
|
||||
@ -420,7 +460,9 @@ class releveBUT extends HTMLElement {
|
||||
<div class=module>
|
||||
<h3>${this.URL(content.url, `${numero} - ${content.titre}`)}</h3>
|
||||
<div>
|
||||
<div class=moyenne>Moyenne indicative : ${content.moyenne.value}</div>
|
||||
<div class=moyenne>Moyenne indicative : ${
|
||||
content.moyenne.value
|
||||
}</div>
|
||||
<div class=info>
|
||||
Classe : ${content.moyenne.moy} -
|
||||
Max : ${content.moyenne.max} -
|
||||
@ -435,7 +477,7 @@ class releveBUT extends HTMLElement {
|
||||
${this.evaluation(content.evaluations)}
|
||||
</div>
|
||||
`;
|
||||
})
|
||||
});
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -454,16 +496,18 @@ class releveBUT extends HTMLElement {
|
||||
<div>Max. promo.</div><div>${evaluation.note.max}</div>
|
||||
<div>Moy. promo.</div><div>${evaluation.note.moy}</div>
|
||||
<div>Min. promo.</div><div>${evaluation.note.min}</div>
|
||||
${Object.entries(evaluation.poids).map(([UE, poids]) => {
|
||||
${Object.entries(evaluation.poids)
|
||||
.map(([UE, poids]) => {
|
||||
return `
|
||||
<div>Poids ${UE}</div>
|
||||
<div>${poids}</div>
|
||||
`;
|
||||
}).join("")}
|
||||
})
|
||||
.join("")}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
})
|
||||
});
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -478,7 +522,6 @@ class releveBUT extends HTMLElement {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/********************/
|
||||
/* Fonctions d'aide */
|
||||
/********************/
|
||||
@ -491,15 +534,17 @@ class releveBUT extends HTMLElement {
|
||||
}
|
||||
civilite(txt) {
|
||||
switch (txt) {
|
||||
case "M": return "M.";
|
||||
case "F": return "Mme";
|
||||
default: return "";
|
||||
case "M":
|
||||
return "M.";
|
||||
case "F":
|
||||
return "Mme";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
ISOToDate(ISO) {
|
||||
return ISO.split("-").reverse().join("/");
|
||||
}
|
||||
|
||||
}
|
||||
customElements.define('releve-but', releveBUT);
|
||||
customElements.define("releve-but", releveBUT);
|
||||
|
@ -55,7 +55,7 @@
|
||||
<b>Absences</b>
|
||||
{% if sco.etud_cur_sem %}
|
||||
<span title="absences du {{ sco.etud_cur_sem['date_debut'] }}
|
||||
au {{ sco.etud_cur_sem['date_fin'] }}">(1/2 j.)
|
||||
au {{ sco.etud_cur_sem['date_fin'] }}">({{sco.prefs["assi_metrique"]}})
|
||||
<br />{{sco.nbabsjust}} J., {{sco.nbabsnj}} N.J.</span>
|
||||
{% endif %}
|
||||
<ul>
|
||||
|
@ -72,10 +72,13 @@ class ScoData:
|
||||
ins = self.etud.inscription_courante()
|
||||
if ins:
|
||||
self.etud_cur_sem = ins.formsemestre
|
||||
self.nbabs, self.nbabsjust = sco_abs.get_abs_count_in_interval(
|
||||
self.nbabs, self.nbabsjust = sco_abs.get_assiduites_count_in_interval(
|
||||
etud.id,
|
||||
self.etud_cur_sem.date_debut.isoformat(),
|
||||
self.etud_cur_sem.date_fin.isoformat(),
|
||||
scu.translate_assiduites_metric(
|
||||
sco_preferences.get_preference("assi_metrique")
|
||||
),
|
||||
)
|
||||
self.nbabsnj = self.nbabs - self.nbabsjust
|
||||
else:
|
||||
|
Loading…
Reference in New Issue
Block a user