diff --git a/app/but/bulletin_but.py b/app/but/bulletin_but.py
index 4379fdac5..f64769fc9 100644
--- a/app/but/bulletin_but.py
+++ b/app/but/bulletin_but.py
@@ -111,9 +111,10 @@ class BulletinBUT:
d["modules"] = self.etud_mods_results(etud, modimpls_spo)
return d
- def etud_mods_results(self, etud, modimpls) -> dict:
+ def etud_mods_results(self, etud, modimpls, version="long") -> dict:
"""dict synthèse résultats des modules indiqués,
- avec évaluations de chacun."""
+ avec évaluations de chacun (sauf si version == "short")
+ """
res = self.res
d = {}
# etud_idx = self.etud_index[etud.id]
@@ -154,12 +155,14 @@ class BulletinBUT:
"evaluations": [
self.etud_eval_results(etud, e)
for e in modimpl.evaluations
- if e.visibulletin
+ if (e.visibulletin or version == "long")
and (
modimpl_results.evaluations_etat[e.id].is_complete
or self.prefs["bul_show_all_evals"]
)
- ],
+ ]
+ if version != "short"
+ else [],
}
return d
@@ -217,9 +220,17 @@ class BulletinBUT:
return f"Bonus de {fmt_note(bonus_vect.iloc[0])}"
def bulletin_etud(
- self, etud: Identite, formsemestre: FormSemestre, force_publishing=False
+ self,
+ etud: Identite,
+ formsemestre: FormSemestre,
+ force_publishing=False,
+ version="long",
) -> dict:
"""Le bulletin de l'étudiant dans ce semestre: dict pour la version JSON / HTML.
+ - version:
+ "long", "selectedevals": toutes les infos (notes des évaluations)
+ "short" : ne descend pas plus bas que les modules.
+
- Si force_publishing, rempli le bulletin même si bul_hide_xml est vrai
(bulletins non publiés).
"""
@@ -282,8 +293,10 @@ class BulletinBUT:
)
d.update(
{
- "ressources": self.etud_mods_results(etud, res.ressources),
- "saes": self.etud_mods_results(etud, res.saes),
+ "ressources": self.etud_mods_results(
+ etud, res.ressources, version=version
+ ),
+ "saes": self.etud_mods_results(etud, res.saes, version=version),
"ues": {
ue.acronyme: self.etud_ue_results(etud, ue)
for ue in res.ues
diff --git a/app/models/etudiants.py b/app/models/etudiants.py
index 953fb280a..060debc3b 100644
--- a/app/models/etudiants.py
+++ b/app/models/etudiants.py
@@ -160,6 +160,7 @@ class Identite(db.Model):
"etudid": self.id,
"nom": self.nom_disp(),
"prenom": self.prenom,
+ "nomprenom": self.nomprenom,
}
if include_urls:
d["fiche_url"] = url_for(
diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py
index ce162d249..d92c375fb 100644
--- a/app/models/formsemestre.py
+++ b/app/models/formsemestre.py
@@ -22,6 +22,7 @@ from app.scodoc import sco_codes_parcours
from app.scodoc import sco_preferences
from app.scodoc.sco_vdi import ApoEtapeVDI
from app.scodoc.sco_permissions import Permission
+from app.scodoc.sco_utils import MONTH_NAMES_ABBREV
class FormSemestre(db.Model):
@@ -162,8 +163,8 @@ class FormSemestre(db.Model):
d["periode"] = 2 # typiquement, début en février: S2, S4...
d["titre_num"] = self.titre_num()
d["titreannee"] = self.titre_annee()
- d["mois_debut"] = f"{self.date_debut.month} {self.date_debut.year}"
- d["mois_fin"] = f"{self.date_fin.month} {self.date_fin.year}"
+ d["mois_debut"] = self.mois_debut()
+ d["mois_fin"] = self.mois_fin()
d["titremois"] = "%s %s (%s - %s)" % (
d["titre_num"],
self.modalite or "",
@@ -293,6 +294,7 @@ class FormSemestre(db.Model):
"""chaîne "J. Dupond, X. Martin"
ou "Jacques Dupond, Xavier Martin"
"""
+ # was "nomcomplet"
if not self.responsables:
return ""
if abbrev_prenom:
@@ -304,6 +306,14 @@ class FormSemestre(db.Model):
"2021 - 2022"
return scu.annee_scolaire_repr(self.date_debut.year, self.date_debut.month)
+ def mois_debut(self) -> str:
+ "Oct 2021"
+ return f"{MONTH_NAMES_ABBREV[self.date_debut.month - 1]} {self.date_debut.year}"
+
+ def mois_fin(self) -> str:
+ "Jul 2022"
+ return f"{MONTH_NAMES_ABBREV[self.date_fin.month - 1]} {self.date_debut.year}"
+
def session_id(self) -> str:
"""identifiant externe de semestre de formation
Exemple: RT-DUT-FI-S1-ANNEE
diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py
index 046c81468..b21404276 100644
--- a/app/scodoc/sco_bulletins.py
+++ b/app/scodoc/sco_bulletins.py
@@ -793,13 +793,14 @@ def etud_descr_situation_semestre(
def formsemestre_bulletinetud(
etudid=None,
formsemestre_id=None,
- format="html",
+ format=None,
version="long",
xml_with_decisions=False,
force_publishing=False, # force publication meme si semestre non publie sur "portail"
prefer_mail_perso=False,
):
"page bulletin de notes"
+ format = format or "html"
etud: Identite = Identite.query.get_or_404(etudid)
formsemestre: FormSemestre = FormSemestre.query.get(formsemestre_id)
if not formsemestre:
@@ -879,7 +880,7 @@ def do_formsemestre_bulletinetud(
formsemestre: FormSemestre,
etudid: int,
version="long", # short, long, selectedevals
- format="html",
+ format=None,
nohtml=False,
xml_with_decisions=False, # force décisions dans XML
force_publishing=False, # force publication meme si semestre non publié sur "portail"
@@ -890,6 +891,7 @@ def do_formsemestre_bulletinetud(
où bul est str ou bytes au format demandé (html, pdf, pdfmail, pdfpart, xml, json)
et filigranne est un message à placer en "filigranne" (eg "Provisoire").
"""
+ format = format or "html"
if format == "xml":
bul = sco_bulletins_xml.make_xml_formsemestre_bulletinetud(
formsemestre.id,
@@ -1258,7 +1260,7 @@ def make_menu_autres_operations(
"enabled": sco_permissions_check.can_validate_sem(formsemestre.id),
},
{
- "title": "Editer PV jury",
+ "title": "Éditer PV jury",
"endpoint": "notes.formsemestre_pvjury_pdf",
"args": {
"formsemestre_id": formsemestre.id,
diff --git a/app/scodoc/sco_bulletins_generator.py b/app/scodoc/sco_bulletins_generator.py
index 7f6a53c60..2aeb792fb 100644
--- a/app/scodoc/sco_bulletins_generator.py
+++ b/app/scodoc/sco_bulletins_generator.py
@@ -297,7 +297,11 @@ def register_bulletin_class(klass):
def bulletin_class_descriptions():
- return [x.description for x in BULLETIN_CLASSES.values()]
+ return [
+ BULLETIN_CLASSES[class_name].description
+ for class_name in BULLETIN_CLASSES
+ if BULLETIN_CLASSES[class_name].list_in_menu
+ ]
def bulletin_class_names() -> list[str]:
diff --git a/app/scodoc/sco_formsemestre_status.py b/app/scodoc/sco_formsemestre_status.py
index 2080e9572..11e665d92 100644
--- a/app/scodoc/sco_formsemestre_status.py
+++ b/app/scodoc/sco_formsemestre_status.py
@@ -31,7 +31,7 @@
from flask import current_app
from flask import g
from flask import request
-from flask import url_for
+from flask import render_template, url_for
from flask_login import current_user
from app import log
@@ -411,7 +411,7 @@ def formsemestre_status_menubar(sem):
"enabled": sco_permissions_check.can_validate_sem(formsemestre_id),
},
{
- "title": "Editer les PV et archiver les résultats",
+ "title": "Éditer les PV et archiver les résultats",
"endpoint": "notes.formsemestre_archive",
"args": {"formsemestre_id": formsemestre_id},
"enabled": sco_permissions_check.can_edit_pv(formsemestre_id),
@@ -445,6 +445,7 @@ def retreive_formsemestre_from_request() -> int:
"""Cherche si on a de quoi déduire le semestre affiché à partir des
arguments de la requête:
formsemestre_id ou moduleimpl ou evaluation ou group_id ou partition_id
+ Returns None si pas défini.
"""
if request.method == "GET":
args = request.args
@@ -505,34 +506,17 @@ def formsemestre_page_title():
return ""
try:
formsemestre_id = int(formsemestre_id)
- sem = sco_formsemestre.get_formsemestre(formsemestre_id).copy()
+ formsemestre = FormSemestre.query.get(formsemestre_id)
except:
log("can't find formsemestre_id %s" % formsemestre_id)
return ""
- fill_formsemestre(sem)
-
- h = f"""
-
- {formsemestre_status_menubar(sem)}
-
- """
+ h = render_template(
+ "formsemestre_page_title.html",
+ formsemestre=formsemestre,
+ scu=scu,
+ sem_menu_bar=formsemestre_status_menubar(formsemestre.to_dict()),
+ )
return h
diff --git a/app/scodoc/sco_photos.py b/app/scodoc/sco_photos.py
index cf66a8526..0dfeaafe3 100644
--- a/app/scodoc/sco_photos.py
+++ b/app/scodoc/sco_photos.py
@@ -175,7 +175,7 @@ def etud_photo_is_local(etud: dict, size="small"):
return photo_pathname(etud["photo_filename"], size=size)
-def etud_photo_html(etud=None, etudid=None, title=None, size="small"):
+def etud_photo_html(etud: dict = None, etudid=None, title=None, size="small"):
"""HTML img tag for the photo, either in small size (h90)
or original size (size=="orig")
"""
diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py
index b30c493ca..ba7fd504a 100644
--- a/app/scodoc/sco_utils.py
+++ b/app/scodoc/sco_utils.py
@@ -619,7 +619,7 @@ def bul_filename_old(sem: dict, etud: dict, format):
def bul_filename(formsemestre, etud, format):
"""Build a filename for this bulletin"""
dt = time.strftime("%Y-%m-%d")
- filename = f"bul-{formsemestre.sem.titre_num}-{dt}-{etud.nom}.{format}"
+ filename = f"bul-{formsemestre.titre_num()}-{dt}-{etud.nom}.{format}"
filename = make_filename(filename)
return filename
diff --git a/app/static/css/releve-but.css b/app/static/css/releve-but.css
index 02cceb94c..d9756ace4 100644
--- a/app/static/css/releve-but.css
+++ b/app/static/css/releve-but.css
@@ -14,16 +14,25 @@
}
main{
--couleurPrincipale: rgb(240,250,255);
- --couleurFondTitresUE: rgb(206,255,235);
- --couleurFondTitresRes: rgb(125, 170, 255);
- --couleurFondTitresSAE: rgb(211, 255, 255);
+ --couleurFondTitresUE: #b6ebff;
+ --couleurFondTitresRes: #f8c844;
+ --couleurFondTitresSAE: #c6ffab;
--couleurSecondaire: #fec;
- --couleurIntense: #c09;
- --couleurSurlignage: rgba(232, 255, 132, 0.47);
+ --couleurIntense: rgb(4, 16, 159);;
+ --couleurSurlignage: rgba(255, 253, 110, 0.49);
max-width: 1000px;
margin: auto;
display: none;
}
+.releve a, .releve a:visited {
+ color: navy;
+ text-decoration: none;
+}
+.releve a:hover {
+ color: red;
+ text-decoration: underline;
+}
+
.ready .wait{display: none;}
.ready main{display: block;}
h2{
@@ -152,12 +161,14 @@ section>div:nth-child(1){
column-gap: 4px;
flex: none;
}
-.infoSemestre>div:nth-child(1){
- margin-right: auto;
-}
+
.infoSemestre>div>div:nth-child(even){
text-align: right;
}
+.photo {
+ border: none;
+ margin-left: auto;
+}
.rang{
font-weight: bold;
}
@@ -213,7 +224,6 @@ section>div:nth-child(1){
scroll-margin-top: 60px;
}
.module, .ue {
- background: var(--couleurSecondaire);
color: #000;
padding: 4px 32px;
border-radius: 4px;
@@ -225,6 +235,15 @@ section>div:nth-child(1){
cursor: pointer;
position: relative;
}
+.ue {
+ background: var(--couleurFondTitresRes);
+}
+.module {
+ background: var(--couleurFondTitresRes);
+}
+.module h3 {
+ background: var(--couleurFondTitresRes);
+}
.module::before, .ue::before {
content:url("data:image/svg+xml;utf8, ");
width: 26px;
diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css
index a9390db24..31603a34b 100644
--- a/app/static/css/scodoc.css
+++ b/app/static/css/scodoc.css
@@ -1963,7 +1963,9 @@ table.notes_recapcomplet a:hover {
div.notes_bulletin {
margin-right: 5px;
}
-
+div.bulletin_menubar {
+ margin-right: 2em;
+}
table.notes_bulletin {
border-collapse: collapse;
border: 2px solid rgb(100,100,240);
diff --git a/app/static/js/releve-but.js b/app/static/js/releve-but.js
index c7c649e51..97f97e29d 100644
--- a/app/static/js/releve-but.js
+++ b/app/static/js/releve-but.js
@@ -79,8 +79,8 @@ class releveBUT extends HTMLElement {
- Semestre
-
+
+
@@ -97,7 +97,7 @@ class releveBUT extends HTMLElement {
-
Synthèse
+ Unités d'enseignement
La moyenne des ressources dans une UE dépend des poids donnés aux évaluations.
@@ -126,7 +126,7 @@ class releveBUT extends HTMLElement {
-
SAÉ
+
Situations d'apprentissage et d'évaluation (SAÉ)
Liste
@@ -192,7 +192,8 @@ class releveBUT extends HTMLElement {
/* Information sur le semestre */
/*******************************/
showSemestre(data) {
- this.shadow.querySelector("h2").innerHTML += data.semestre.numero;
+
+ this.shadow.querySelector("#identite_etudiant").innerHTML = ` ${data.etudiant.nomprenom} `;
this.shadow.querySelector(".dateInscription").innerHTML += this.ISOToDate(data.semestre.inscription);
let output = `
@@ -206,7 +207,9 @@ class releveBUT extends HTMLElement {
Absences
N.J. ${data.semestre.absences?.injustifie ?? "-"}
Total ${data.semestre.absences?.total ?? "-"}
-
`;
+
+
+ `;
/*${data.semestre.groupes.map(groupe => {
return `
diff --git a/app/templates/bul_head.html b/app/templates/bul_head.html
index 5211fcd4f..12df3c4f8 100644
--- a/app/templates/bul_head.html
+++ b/app/templates/bul_head.html
@@ -5,10 +5,12 @@
diff --git a/app/templates/but/bulletin.html b/app/templates/but/bulletin.html
index 02a09e848..c3e8c834e 100644
--- a/app/templates/but/bulletin.html
+++ b/app/templates/but/bulletin.html
@@ -6,8 +6,8 @@
{% endblock %}
{% block app_content %}
-
Totoro
+{% include 'bul_head.html' %}
diff --git a/app/templates/formsemestre_page_title.html b/app/templates/formsemestre_page_title.html
new file mode 100644
index 000000000..70fef579d
--- /dev/null
+++ b/app/templates/formsemestre_page_title.html
@@ -0,0 +1,50 @@
+{# -*- mode: jinja-html -*- #}
+{# Element HTML decrivant un semestre (barre de menu et infos) #}
+{# was formsemestre_page_title #}
+
+
+
+ {{sem_menu_bar|safe}}
+
\ No newline at end of file
diff --git a/app/views/__init__.py b/app/views/__init__.py
index 3d8af0777..f3c8e13d4 100644
--- a/app/views/__init__.py
+++ b/app/views/__init__.py
@@ -50,27 +50,29 @@ def close_dept_db_connection(arg):
class ScoData:
"""Classe utilisée pour passer des valeurs aux vues (templates)"""
- def __init__(self):
+ def __init__(self, etud=None, formsemestre=None):
# Champs utilisés par toutes les pages ScoDoc (sidebar, en-tête)
self.Permission = Permission
self.scu = scu
self.SCOVERSION = sco_version.SCOVERSION
# -- Informations étudiant courant, si sélectionné:
- etudid = g.get("etudid", None)
- if not etudid:
- if request.method == "GET":
- etudid = request.args.get("etudid", None)
- elif request.method == "POST":
- etudid = request.form.get("etudid", None)
-
- if etudid:
+ if etud is None:
+ etudid = g.get("etudid", None)
+ if etudid is None:
+ if request.method == "GET":
+ etudid = request.args.get("etudid", None)
+ elif request.method == "POST":
+ etudid = request.form.get("etudid", None)
+ if etudid is not None:
+ etud = Identite.query.get_or_404(etudid)
+ self.etud = etud
+ if etud is not None:
# Infos sur l'étudiant courant
- self.etud = Identite.query.get_or_404(etudid)
ins = self.etud.inscription_courante()
if ins:
self.etud_cur_sem = ins.formsemestre
self.nbabs, self.nbabsjust = sco_abs.get_abs_count_in_interval(
- etudid,
+ etud.id,
self.etud_cur_sem.date_debut.isoformat(),
self.etud_cur_sem.date_fin.isoformat(),
)
@@ -80,17 +82,22 @@ class ScoData:
else:
self.etud = None
# --- Informations sur semestre courant, si sélectionné
- formsemestre_id = sco_formsemestre_status.retreive_formsemestre_from_request()
- if formsemestre_id is None:
+ if formsemestre is None:
+ formsemestre_id = (
+ sco_formsemestre_status.retreive_formsemestre_from_request()
+ )
+ if formsemestre_id is not None:
+ formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
+ if formsemestre is None:
self.sem = None
self.sem_menu_bar = None
else:
- self.sem = FormSemestre.query.get_or_404(formsemestre_id)
+ self.sem = formsemestre
self.sem_menu_bar = sco_formsemestre_status.formsemestre_status_menubar(
self.sem.to_dict()
)
# --- Préférences
- self.prefs = sco_preferences.SemPreferences(formsemestre_id)
+ self.prefs = sco_preferences.SemPreferences(formsemestre.id)
from app.views import scodoc, notes, scolar, absences, users, pn_modules, refcomp
diff --git a/app/views/notes.py b/app/views/notes.py
index 6cbf0be43..5ca463b4c 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -32,6 +32,7 @@ Emmanuel Viennet, 2021
"""
from operator import itemgetter
+import time
from xml.etree import ElementTree
import flask
@@ -276,7 +277,7 @@ sco_publish(
def formsemestre_bulletinetud(
etudid=None,
formsemestre_id=None,
- format="html",
+ format=None,
version="long",
xml_with_decisions=False,
force_publishing=False,
@@ -284,6 +285,7 @@ def formsemestre_bulletinetud(
code_nip=None,
code_ine=None,
):
+ format = format or "html"
if not formsemestre_id:
flask.abort(404, "argument manquant: formsemestre_id")
if not isinstance(formsemestre_id, int):
@@ -311,12 +313,16 @@ def formsemestre_bulletinetud(
if format == "json":
r = bulletin_but.BulletinBUT(formsemestre)
return jsonify(
- r.bulletin_etud(etud, formsemestre, force_publishing=force_publishing)
+ r.bulletin_etud(
+ etud,
+ formsemestre,
+ force_publishing=force_publishing,
+ version=version,
+ )
)
elif format == "html":
return render_template(
"but/bulletin.html",
- title=f"Bul. {etud.nom} - BUT",
bul_url=url_for(
"notes.formsemestre_bulletinetud",
scodoc_dept=g.scodoc_dept,
@@ -324,8 +330,19 @@ def formsemestre_bulletinetud(
etudid=etudid,
format="json",
force_publishing=1, # pour ScoDoc lui même
+ version=version,
),
- sco=ScoData(),
+ etud=etud,
+ formsemestre=formsemestre,
+ is_apc=formsemestre.formation.is_apc(),
+ menu_autres_operations=sco_bulletins.make_menu_autres_operations(
+ formsemestre, etud, "notes.formsemestre_bulletinetud", version
+ ),
+ sco=ScoData(etud=etud),
+ scu=scu,
+ time=time,
+ title=f"Bul. {etud.nom} - BUT",
+ version=version,
)
if not (etudid or code_nip or code_ine):