forked from ScoDoc/DocScoDoc
Merge branch 'master' of https://scodoc.org/git/viennet/ScoDoc into table
This commit is contained in:
commit
569df98e25
@ -630,19 +630,38 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
d[dec_rcue.rcue.ue_2.id] = dec_rcue
|
||||
return d
|
||||
|
||||
def next_annee_semestre_id(self, code: str) -> int:
|
||||
"""L'indice du semestre dans lequel l'étudiant est autorisé à
|
||||
poursuivre l'année suivante. None si aucun."""
|
||||
if self.formsemestre_pair is None:
|
||||
return None # seulement sur année
|
||||
if code == RED:
|
||||
return self.formsemestre_pair.semestre_id - 1
|
||||
elif (
|
||||
code in sco_codes.BUT_CODES_PASSAGE
|
||||
def next_semestre_ids(self, code: str) -> set[int]:
|
||||
"""Les indices des semestres dans lequels l'étudiant est autorisé
|
||||
à poursuivre après le semestre courant.
|
||||
"""
|
||||
ids = set()
|
||||
# La poursuite d'études dans un semestre pair d’une même année
|
||||
# est de droit pour tout étudiant:
|
||||
if (self.formsemestre.semestre_id % 2) and sco_codes.ParcoursBUT.NB_SEM:
|
||||
ids.add(self.formsemestre.semestre_id + 1)
|
||||
|
||||
# La poursuite d’études dans un semestre impair est possible si
|
||||
# et seulement si l’étudiant a obtenu :
|
||||
# - la moyenne à plus de la moitié des regroupements cohérents d’UE ;
|
||||
# - et une moyenne égale ou supérieure à 8 sur 20 à chaque RCUE.
|
||||
#
|
||||
# La condition a paru trop stricte à de nombreux collègues.
|
||||
# ScoDoc ne contraint donc pas à la respecter strictement.
|
||||
# Si le code est dans BUT_CODES_PASSAGE (ADM, ADJ, PASD, PAS1NCI, ATJ),
|
||||
# autorise à passer dans le semestre suivant
|
||||
if (
|
||||
self.jury_annuel
|
||||
and code in sco_codes.BUT_CODES_PASSAGE
|
||||
and self.formsemestre_pair.semestre_id < sco_codes.ParcoursBUT.NB_SEM
|
||||
):
|
||||
return self.formsemestre_pair.semestre_id + 1
|
||||
return None
|
||||
ids.add(self.formsemestre.semestre_id + 1)
|
||||
|
||||
if code == RED:
|
||||
ids.add(
|
||||
self.formsemestre.semestre_id - (self.formsemestre.semestre_id + 1) % 2
|
||||
)
|
||||
|
||||
return ids
|
||||
|
||||
def record_form(self, form: dict):
|
||||
"""Enregistre les codes de jury en base
|
||||
@ -704,47 +723,43 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
raise ScoValueError(
|
||||
f"code annee <tt>{html.escape(code)}</tt> invalide pour formsemestre {html.escape(self.formsemestre)}"
|
||||
)
|
||||
if code == self.code_valide or (self.code_valide is not None and no_overwrite):
|
||||
self.recorded = True
|
||||
return False # no change
|
||||
if self.validation:
|
||||
db.session.delete(self.validation)
|
||||
db.session.commit()
|
||||
if code is None:
|
||||
self.validation = None
|
||||
else:
|
||||
self.validation = ApcValidationAnnee(
|
||||
etudid=self.etud.id,
|
||||
formsemestre=self.formsemestre_impair,
|
||||
ordre=self.annee_but,
|
||||
annee_scolaire=self.annee_scolaire(),
|
||||
code=code,
|
||||
)
|
||||
db.session.add(self.validation)
|
||||
db.session.commit()
|
||||
log(f"Recording {self}: {code}")
|
||||
Scolog.logdb(
|
||||
method="jury_but",
|
||||
etudid=self.etud.id,
|
||||
msg=f"Validation année BUT{self.annee_but}: {code}",
|
||||
)
|
||||
|
||||
if code != self.code_valide and (self.code_valide is None or not no_overwrite):
|
||||
# Enregistrement du code annuel BUT
|
||||
if self.validation:
|
||||
db.session.delete(self.validation)
|
||||
db.session.commit()
|
||||
if code is None:
|
||||
self.validation = None
|
||||
else:
|
||||
self.validation = ApcValidationAnnee(
|
||||
etudid=self.etud.id,
|
||||
formsemestre=self.formsemestre_impair,
|
||||
ordre=self.annee_but,
|
||||
annee_scolaire=self.annee_scolaire(),
|
||||
code=code,
|
||||
)
|
||||
db.session.add(self.validation)
|
||||
db.session.commit()
|
||||
log(f"Recording {self}: {code}")
|
||||
Scolog.logdb(
|
||||
method="jury_but",
|
||||
etudid=self.etud.id,
|
||||
msg=f"Validation année BUT{self.annee_but}: {code}",
|
||||
)
|
||||
|
||||
# --- Autorisation d'inscription dans semestre suivant ?
|
||||
if self.formsemestre_pair is not None:
|
||||
if code is None:
|
||||
ScolarAutorisationInscription.delete_autorisation_etud(
|
||||
etudid=self.etud.id,
|
||||
origin_formsemestre_id=self.formsemestre_pair.id,
|
||||
)
|
||||
else:
|
||||
next_semestre_id = self.next_annee_semestre_id(code)
|
||||
if next_semestre_id is not None:
|
||||
ScolarAutorisationInscription.autorise_etud(
|
||||
self.etud.id,
|
||||
self.formsemestre_pair.formation.formation_code,
|
||||
self.formsemestre_pair.id,
|
||||
next_semestre_id,
|
||||
)
|
||||
ScolarAutorisationInscription.delete_autorisation_etud(
|
||||
etudid=self.etud.id,
|
||||
origin_formsemestre_id=self.formsemestre.id,
|
||||
)
|
||||
for next_semestre_id in self.next_semestre_ids(code):
|
||||
ScolarAutorisationInscription.autorise_etud(
|
||||
self.etud.id,
|
||||
self.formsemestre.formation.formation_code,
|
||||
self.formsemestre.id,
|
||||
next_semestre_id,
|
||||
)
|
||||
|
||||
db.session.commit()
|
||||
self.recorded = True
|
||||
@ -872,18 +887,18 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
||||
self.invalidate_formsemestre_cache()
|
||||
|
||||
def get_autorisations_passage(self) -> list[int]:
|
||||
"""Les liste des indices de semestres auxquels on est autorisé à
|
||||
s'inscrire depuis cette année"""
|
||||
formsemestre = self.formsemestre_pair or self.formsemestre_impair
|
||||
if not formsemestre:
|
||||
return []
|
||||
return [
|
||||
a.semestre_id
|
||||
for a in ScolarAutorisationInscription.query.filter_by(
|
||||
etudid=self.etud.id,
|
||||
origin_formsemestre_id=formsemestre.id,
|
||||
)
|
||||
]
|
||||
"""Liste des indices de semestres auxquels on est autorisé à
|
||||
s'inscrire depuis le semestre courant.
|
||||
"""
|
||||
return sorted(
|
||||
[
|
||||
a.semestre_id
|
||||
for a in ScolarAutorisationInscription.query.filter_by(
|
||||
etudid=self.etud.id,
|
||||
origin_formsemestre_id=self.formsemestre.id,
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
def descr_niveaux_validation(self, line_sep: str = "\n") -> str:
|
||||
"""Description textuelle des niveaux validés (enregistrés)
|
||||
|
@ -11,7 +11,7 @@ import re
|
||||
import numpy as np
|
||||
|
||||
import flask
|
||||
from flask import flash, url_for
|
||||
from flask import flash, render_template, url_for
|
||||
from flask import g, request
|
||||
|
||||
from app import db
|
||||
@ -32,8 +32,10 @@ from app.models import (
|
||||
ScolarAutorisationInscription,
|
||||
ScolarFormSemestreValidation,
|
||||
)
|
||||
from app.models.config import ScoDocSiteConfig
|
||||
from app.scodoc import html_sco_header
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
from app.scodoc import sco_preferences
|
||||
from app.scodoc import sco_utils as scu
|
||||
|
||||
|
||||
@ -43,21 +45,20 @@ def show_etud(deca: DecisionsProposeesAnnee, read_only: bool = True) -> str:
|
||||
"""
|
||||
H = []
|
||||
|
||||
H.append("""<div class="but_section_annee">""")
|
||||
H.append(
|
||||
f"""
|
||||
<div>
|
||||
<b>Décision de jury pour l'année :</b> {
|
||||
_gen_but_select("code_annee", deca.codes, deca.code_valide,
|
||||
disabled=True, klass="manual")
|
||||
}
|
||||
<span>({deca.code_valide or 'non'} enregistrée)</span>
|
||||
if deca.jury_annuel:
|
||||
H.append(
|
||||
f"""
|
||||
<div class="but_section_annee">
|
||||
<div>
|
||||
<b>Décision de jury pour l'année :</b> {
|
||||
_gen_but_select("code_annee", deca.codes, deca.code_valide,
|
||||
disabled=True, klass="manual")
|
||||
}
|
||||
<span>({deca.code_valide or 'non'} enregistrée)</span>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
)
|
||||
div_explanation = f"""<div class="but_explanation">{deca.explanation}</div>"""
|
||||
|
||||
H.append("""</div>""")
|
||||
)
|
||||
|
||||
formsemestre_1 = deca.formsemestre_impair
|
||||
formsemestre_2 = deca.formsemestre_pair
|
||||
@ -74,7 +75,7 @@ def show_etud(deca: DecisionsProposeesAnnee, read_only: bool = True) -> str:
|
||||
<div class="titre_niveaux">
|
||||
<b>Niveaux de compétences et unités d'enseignement du BUT{deca.annee_but}</b>
|
||||
</div>
|
||||
{div_explanation}
|
||||
<div class="but_explanation">{deca.explanation}</div>
|
||||
<div class="but_annee">
|
||||
<div class="titre"></div>
|
||||
<div class="titre">{"S" +str(formsemestre_1.semestre_id)
|
||||
@ -285,7 +286,7 @@ def jury_but_semestriel(
|
||||
read_only: bool,
|
||||
navigation_div: str = "",
|
||||
) -> str:
|
||||
"""Formulaire saisie décision d'UE d'un semestre BUT isolé (pas jury annuel)"""
|
||||
"""Page: formulaire saisie décision d'UE d'un semestre BUT isolé (pas jury annuel)."""
|
||||
res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre)
|
||||
parcour, ues = jury_but.list_ue_parcour_etud(formsemestre, etud, res)
|
||||
inscription_etat = etud.inscription_etat(formsemestre.id)
|
||||
@ -374,20 +375,20 @@ def jury_but_semestriel(
|
||||
f"""
|
||||
<div class="jury_but">
|
||||
<div>
|
||||
<div class="bull_head">
|
||||
<div>
|
||||
<div class="titre_parcours">Jury BUT S{formsemestre.id}
|
||||
- Parcours {(parcour.libelle if parcour else False) or "non spécifié"}
|
||||
<div class="bull_head">
|
||||
<div>
|
||||
<div class="titre_parcours">Jury BUT S{formsemestre.id}
|
||||
- Parcours {(parcour.libelle if parcour else False) or "non spécifié"}
|
||||
</div>
|
||||
<div class="nom_etud">{etud.nomprenom}</div>
|
||||
</div>
|
||||
<div class="bull_photo"><a href="{
|
||||
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id)
|
||||
}">{etud.photo_html(title="fiche de " + etud.nomprenom)}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nom_etud">{etud.nomprenom}</div>
|
||||
</div>
|
||||
<div class="bull_photo"><a href="{
|
||||
url_for("scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id)
|
||||
}">{etud.photo_html(title="fiche de " + etud.nomprenom)}</a>
|
||||
</div>
|
||||
</div>
|
||||
<h3>Jury sur un semestre BUT isolé (ne concerne que les UEs)</h3>
|
||||
{warning}
|
||||
<h3>Jury sur un semestre BUT isolé (ne concerne que les UEs)</h3>
|
||||
{warning}
|
||||
</div>
|
||||
|
||||
<form method="post" id="jury_but">
|
||||
@ -450,24 +451,37 @@ def jury_but_semestriel(
|
||||
)
|
||||
H.append("</div>") # but_annee
|
||||
|
||||
div_autorisations_passage = (
|
||||
f"""
|
||||
<div class="but_autorisations_passage">
|
||||
<span>Autorisé à passer en :</span>
|
||||
{ ", ".join( ["S" + str(a.semestre_id or '') for a in autorisations_passage ] )}
|
||||
</div>
|
||||
"""
|
||||
if autorisations_passage
|
||||
else """<div class="but_autorisations_passage but_explanation">pas d'autorisations de passage enregistrées.</div>"""
|
||||
)
|
||||
H.append(div_autorisations_passage)
|
||||
|
||||
if read_only:
|
||||
H.append(
|
||||
"""<div class="but_explanation">
|
||||
Vous n'avez pas la permission de modifier ces décisions.
|
||||
Les champs entourés en vert sont enregistrés.</div>"""
|
||||
f"""<div class="but_explanation">
|
||||
{"Vous n'avez pas la permission de modifier ces décisions."
|
||||
if formsemestre.etat
|
||||
else "Semestre verrouillé."}
|
||||
Les champs entourés en vert sont enregistrés.
|
||||
</div>
|
||||
"""
|
||||
)
|
||||
else:
|
||||
if formsemestre.semestre_id < formsemestre.formation.get_parcours().NB_SEM:
|
||||
H.append(
|
||||
f"""
|
||||
<div class="but_settings">
|
||||
<input type="checkbox" name="autorisation_passage" value="1" {
|
||||
"checked" if est_autorise_a_passer else ""}>
|
||||
<em>autoriser à passer dans le semestre S{formsemestre.semestre_id+1}</em>
|
||||
{("(autorisations enregistrées: " + ' '.join(
|
||||
'S' + str(a.semestre_id or '') for a in autorisations_passage) + ")"
|
||||
) if autorisations_passage else ""}
|
||||
</input>
|
||||
<input type="checkbox" name="autorisation_passage" value="1" {
|
||||
"checked" if est_autorise_a_passer else ""}>
|
||||
<em>autoriser à passer dans le semestre S{formsemestre.semestre_id+1}</em>
|
||||
</input>
|
||||
</div>
|
||||
"""
|
||||
)
|
||||
@ -481,7 +495,19 @@ def jury_but_semestriel(
|
||||
</div>
|
||||
"""
|
||||
)
|
||||
H.append(navigation_div)
|
||||
|
||||
H.append(navigation_div)
|
||||
H.append("</div>")
|
||||
H.append(
|
||||
render_template(
|
||||
"but/documentation_codes_jury.html",
|
||||
nom_univ=f"""Export {sco_preferences.get_preference("InstituteName")
|
||||
or sco_preferences.get_preference("UnivName")
|
||||
or "Apogée"}""",
|
||||
codes=ScoDocSiteConfig.get_codes_apo_dict(),
|
||||
)
|
||||
)
|
||||
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
|
@ -740,7 +740,8 @@ class ResultatsSemestre(ResultatsCache):
|
||||
f"""<a href="{url_for('notes.formsemestre_validation_etud_form',
|
||||
scodoc_dept=g.scodoc_dept, formsemestre_id=self.formsemestre.id, etudid=etudid
|
||||
)
|
||||
}">{"saisir" if not jury_code_sem else "modifier"} décision</a>""",
|
||||
}">{("saisir" if not jury_code_sem else "modifier")
|
||||
if self.formsemestre.etat else "voir"} décisions</a>""",
|
||||
"col_jury_link",
|
||||
)
|
||||
|
||||
|
@ -55,7 +55,8 @@ class Formation(db.Model):
|
||||
modules = db.relationship("Module", lazy="dynamic", backref="formation")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__name__}(id={self.id}, dept_id={self.dept_id}, acronyme='{self.acronyme!r}')>"
|
||||
return f"""<{self.__class__.__name__}(id={self.id}, dept_id={
|
||||
self.dept_id}, acronyme={self.acronyme!r}, version={self.version})>"""
|
||||
|
||||
def to_html(self) -> str:
|
||||
"titre complet pour affichage"
|
||||
|
@ -111,6 +111,7 @@ class UniteEns(db.Model):
|
||||
e["ects"] = e["ects"]
|
||||
e["coefficient"] = e["coefficient"] if e["coefficient"] else 0.0
|
||||
e["code_apogee"] = e["code_apogee"] or "" # pas de None
|
||||
e["parcour"] = self.parcour.to_dict() if self.parcour else None
|
||||
if with_module_ue_coefs:
|
||||
if convert_objects:
|
||||
e["module_ue_coefs"] = [
|
||||
|
@ -99,7 +99,7 @@ def html_edit_formation_apc(
|
||||
|
||||
H = [
|
||||
render_template(
|
||||
"pn/form_ues.html",
|
||||
"pn/form_ues.j2",
|
||||
formation=formation,
|
||||
semestre_ids=semestre_ids,
|
||||
editable=editable,
|
||||
@ -122,7 +122,7 @@ def html_edit_formation_apc(
|
||||
).first()
|
||||
H += [
|
||||
render_template(
|
||||
"pn/form_mods.html",
|
||||
"pn/form_mods.j2",
|
||||
formation=formation,
|
||||
titre=f"Ressources du S{semestre_idx}",
|
||||
create_element_msg="créer une nouvelle ressource",
|
||||
@ -138,7 +138,7 @@ def html_edit_formation_apc(
|
||||
if ues_by_sem[semestre_idx].count() > 0
|
||||
else "",
|
||||
render_template(
|
||||
"pn/form_mods.html",
|
||||
"pn/form_mods.j2",
|
||||
formation=formation,
|
||||
titre=f"Situations d'Apprentissage et d'Évaluation (SAÉs) S{semestre_idx}",
|
||||
create_element_msg="créer une nouvelle SAÉ",
|
||||
@ -154,7 +154,7 @@ def html_edit_formation_apc(
|
||||
if ues_by_sem[semestre_idx].count() > 0
|
||||
else "",
|
||||
render_template(
|
||||
"pn/form_mods.html",
|
||||
"pn/form_mods.j2",
|
||||
formation=formation,
|
||||
titre=f"Autres modules (non BUT) du S{semestre_idx}",
|
||||
create_element_msg="créer un nouveau module",
|
||||
@ -196,7 +196,7 @@ def html_ue_infos(ue):
|
||||
and ue.matieres.count() == 0
|
||||
)
|
||||
return render_template(
|
||||
"pn/ue_infos.html",
|
||||
"pn/ue_infos.j2",
|
||||
titre=f"UE {ue.acronyme} {ue.titre}",
|
||||
ue=ue,
|
||||
formsemestres=formsemestres,
|
||||
|
@ -723,7 +723,7 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""): # was ue_list
|
||||
"libjs/jQuery-tagEditor/jquery.caret.min.js",
|
||||
"js/module_tag_editor.js",
|
||||
],
|
||||
page_title=f"Programme {formation.acronyme}",
|
||||
page_title=f"Programme {formation.acronyme} v{formation.version}",
|
||||
),
|
||||
f"""<h2>{formation.to_html()} {lockicon}
|
||||
</h2>
|
||||
@ -765,7 +765,7 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
||||
# Description de la formation
|
||||
H.append(
|
||||
render_template(
|
||||
"pn/form_descr.html",
|
||||
"pn/form_descr.j2",
|
||||
formation=formation,
|
||||
parcours=parcours,
|
||||
editable=editable,
|
||||
@ -913,8 +913,12 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
||||
<li><a class="stdlink" href="{
|
||||
url_for('notes.formation_export', scodoc_dept=g.scodoc_dept,
|
||||
formation_id=formation_id, format='xml')
|
||||
}">Export XML de la formation</a>
|
||||
(permet de la sauvegarder pour l'échanger avec un autre site)
|
||||
}">Export XML de la formation</a> ou
|
||||
<a class="stdlink" href="{
|
||||
url_for('notes.formation_export', scodoc_dept=g.scodoc_dept,
|
||||
formation_id=formation_id, format='xml', export_codes_apo=0)
|
||||
}">sans codes Apogée</a>
|
||||
(permet de l'enregistrer pour l'échanger avec un autre site)
|
||||
</li>
|
||||
|
||||
<li><a class="stdlink" href="{
|
||||
|
@ -109,6 +109,7 @@ def formation_export(
|
||||
export_ids=False,
|
||||
export_tags=True,
|
||||
export_external_ues=False,
|
||||
export_codes_apo=True,
|
||||
format=None,
|
||||
):
|
||||
"""Get a formation, with UE, matieres, modules
|
||||
@ -116,30 +117,45 @@ def formation_export(
|
||||
"""
|
||||
formation: Formation = Formation.query.get_or_404(formation_id)
|
||||
f_dict = formation.to_dict(with_refcomp_attrs=True)
|
||||
selector = {"formation_id": formation_id}
|
||||
if not export_ids:
|
||||
del f_dict["formation_id"]
|
||||
del f_dict["dept_id"]
|
||||
ues = formation.ues
|
||||
if not export_external_ues:
|
||||
selector["is_external"] = False
|
||||
ues = sco_edit_ue.ue_list(selector)
|
||||
f_dict["ue"] = ues
|
||||
for ue_dict in ues:
|
||||
ue_id = ue_dict["ue_id"]
|
||||
ues = ues.filter_by(is_external=False)
|
||||
ues = ues.all()
|
||||
ues.sort(key=lambda u: (u.semestre_idx or 0, u.numero or 0, u.acronyme))
|
||||
f_dict["ue"] = []
|
||||
for ue in ues:
|
||||
ue_dict = ue.to_dict()
|
||||
f_dict["ue"].append(ue_dict)
|
||||
ue_dict.pop("module_ue_coefs", None)
|
||||
if formation.is_apc():
|
||||
# BUT: indique niveau de compétence associé à l'UE
|
||||
ue = UniteEns.query.get(ue_id)
|
||||
if ue.niveau_competence:
|
||||
ue_dict["apc_niveau_libelle"] = ue.niveau_competence.libelle
|
||||
ue_dict["apc_niveau_annee"] = ue.niveau_competence.annee
|
||||
ue_dict["apc_niveau_ordre"] = ue.niveau_competence.ordre
|
||||
ue_dict["reference"] = ue_id # pour les coefficients
|
||||
# Et le parcour:
|
||||
if ue.parcour:
|
||||
ue_dict["parcour"] = [ue.parcour.to_dict(with_annees=False)]
|
||||
ue_dict["reference"] = ue.id # pour les coefficients
|
||||
if not export_ids:
|
||||
del ue_dict["id"]
|
||||
del ue_dict["ue_id"]
|
||||
del ue_dict["formation_id"]
|
||||
if "niveau_competence_id" in ue_dict:
|
||||
del ue_dict["niveau_competence_id"]
|
||||
for id_id in (
|
||||
"id",
|
||||
"ue_id",
|
||||
"formation_id",
|
||||
"parcour_id",
|
||||
"niveau_competence_id",
|
||||
):
|
||||
ue_dict.pop(id_id, None)
|
||||
|
||||
if not export_codes_apo:
|
||||
ue_dict.pop("code_apogee", None)
|
||||
if ue_dict["ects"] is None:
|
||||
del ue_dict["ects"]
|
||||
mats = sco_edit_matiere.matiere_list({"ue_id": ue_id})
|
||||
mats = sco_edit_matiere.matiere_list({"ue_id": ue.id})
|
||||
mats.sort(key=lambda m: m["numero"] or 0)
|
||||
ue_dict["matiere"] = mats
|
||||
for mat in mats:
|
||||
matiere_id = mat["matiere_id"]
|
||||
@ -148,6 +164,7 @@ def formation_export(
|
||||
del mat["matiere_id"]
|
||||
del mat["ue_id"]
|
||||
mods = sco_edit_module.module_list({"matiere_id": matiere_id})
|
||||
mods.sort(key=lambda m: (m["numero"] or 0, m["code"]))
|
||||
mat["module"] = mods
|
||||
for mod in mods:
|
||||
module_id = mod["module_id"]
|
||||
@ -183,6 +200,8 @@ def formation_export(
|
||||
del mod["matiere_id"]
|
||||
del mod["module_id"]
|
||||
del mod["formation_id"]
|
||||
if not export_codes_apo:
|
||||
del mod["code_apogee"]
|
||||
if mod["ects"] is None:
|
||||
del mod["ects"]
|
||||
|
||||
@ -323,14 +342,30 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
|
||||
referentiel_competence_id, ue_info[1]
|
||||
)
|
||||
ue_id = sco_edit_ue.do_ue_create(ue_info[1])
|
||||
ue: UniteEns = UniteEns.query.get(ue_id)
|
||||
assert ue
|
||||
if xml_ue_id:
|
||||
ues_old2new[xml_ue_id] = ue_id
|
||||
# élément optionnel présent dans les exports BUT:
|
||||
ue_reference = ue_info[1].get("reference")
|
||||
if ue_reference:
|
||||
ue_reference_to_id[int(ue_reference)] = ue_id
|
||||
|
||||
# -- create matieres
|
||||
for mat_info in ue_info[2]:
|
||||
if mat_info[0] == "parcour":
|
||||
# Parcours (BUT)
|
||||
code_parcours = mat_info[1]["code"]
|
||||
parcour = ApcParcours.query.filter_by(
|
||||
code=code_parcours,
|
||||
referentiel_id=referentiel_competence_id,
|
||||
).first()
|
||||
if parcour:
|
||||
ue.parcour = parcour
|
||||
db.session.add(ue)
|
||||
else:
|
||||
log(f"Warning: parcours {code_parcours} inexistant !")
|
||||
continue
|
||||
assert mat_info[0] == "matiere"
|
||||
mat_info[1]["ue_id"] = ue_id
|
||||
mat_id = sco_edit_matiere.do_matiere_create(mat_info[1])
|
||||
@ -382,12 +417,12 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
|
||||
# associe les parcours de ce module (BUT)
|
||||
if referentiel_competence_id is not None:
|
||||
code_parcours = child[1]["code"]
|
||||
parcours = ApcParcours.query.filter_by(
|
||||
parcour = ApcParcours.query.filter_by(
|
||||
code=code_parcours,
|
||||
referentiel_id=referentiel_competence_id,
|
||||
).first()
|
||||
if parcours:
|
||||
module.parcours.append(parcours)
|
||||
if parcour:
|
||||
module.parcours.append(parcour)
|
||||
db.session.add(module)
|
||||
else:
|
||||
log(
|
||||
|
@ -556,9 +556,10 @@ def do_formsemestre_createwithmodules(edit=False, formsemestre: FormSemestre = N
|
||||
str(parcour.id) for parcour in ref_comp.parcours
|
||||
],
|
||||
"explanation": """Parcours proposés dans ce semestre.
|
||||
S'il s'agit d'un semestre de "tronc commun", ne pas indiquer de parcours.
|
||||
Attention, si aucun parcours n'est coché, toutes les UEs du
|
||||
programme seront considérées, quel que soit leur parcours.
|
||||
Cocher tous les parcours est exactement équivalent à n'en cocher aucun:
|
||||
par exemple, pour un semestre de "tronc commun", on peut ne pas indiquer de parcours.
|
||||
Si aucun parcours n'est coché, toutes les UEs du
|
||||
programme seront donc considérées, quel que soit leur parcours.
|
||||
""",
|
||||
},
|
||||
)
|
||||
|
@ -602,9 +602,21 @@ def formsemestre_recap_parcours_table(
|
||||
<td class="datedebut">{sem['mois_debut']}</td>
|
||||
<td class="rcp_titre_sem"><a class="formsemestre_status_link"
|
||||
href="{a_url}formsemestre_bulletinetud?formsemestre_id={formsemestre.id}&etudid={etudid}"
|
||||
title="Bulletin de notes">{formsemestre.titre_annee()}{parcours_name}</a></td>
|
||||
title="Bulletin de notes">{formsemestre.titre_annee()}{parcours_name}</a>
|
||||
"""
|
||||
)
|
||||
if nt.is_apc:
|
||||
H.append(
|
||||
f"""<a class="stdlink jury_link" title="Validations du semestre BUT"
|
||||
href="{ url_for("notes.formsemestre_validation_but",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre.id,
|
||||
etudid=etudid,
|
||||
)
|
||||
}">jury</a>"""
|
||||
)
|
||||
H.append("""</td>""")
|
||||
|
||||
if nt.is_apc:
|
||||
H.append('<td class="rcp_but">BUT</td>')
|
||||
elif decision_sem:
|
||||
|
@ -39,21 +39,22 @@ from app import log
|
||||
from app.models import FormSemestre
|
||||
from app.scodoc.gen_tables import GenTable
|
||||
from app.scodoc import html_sco_header
|
||||
from app.scodoc import sco_cache
|
||||
from app.scodoc import sco_codes_parcours
|
||||
from app.scodoc import sco_preferences
|
||||
from app.scodoc import sco_pvjury
|
||||
from app.scodoc import sco_etud
|
||||
from app.scodoc import sco_formations
|
||||
from app.scodoc import sco_formsemestre
|
||||
from app.scodoc import sco_formsemestre_inscriptions
|
||||
from app.scodoc import sco_formations
|
||||
from app.scodoc import sco_groups
|
||||
from app.scodoc import sco_etud
|
||||
from app.scodoc import sco_preferences
|
||||
from app.scodoc import sco_pvjury
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
|
||||
|
||||
def list_authorized_etuds_by_sem(sem, delai=274, ignore_jury=False):
|
||||
"""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 comem autorisés, même
|
||||
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)
|
||||
@ -276,8 +277,8 @@ def formsemestre_inscr_passage(
|
||||
submitted=False,
|
||||
dialog_confirmed=False,
|
||||
ignore_jury=False,
|
||||
):
|
||||
"""Form. pour inscription des etudiants d'un semestre dans un autre
|
||||
) -> str:
|
||||
"""Page Form. pour inscription des etudiants d'un semestre dans un autre
|
||||
(donné par formsemestre_id).
|
||||
Permet de selectionner parmi les etudiants autorisés à s'inscrire.
|
||||
Principe:
|
||||
@ -285,8 +286,8 @@ def formsemestre_inscr_passage(
|
||||
- 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
|
||||
- seuls les etudiants non inscrits changent (de groupe)
|
||||
- les etudiants inscrit qui se trouvent décochés sont désinscrits
|
||||
- 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.
|
||||
|
||||
"""
|
||||
@ -326,11 +327,9 @@ def formsemestre_inscr_passage(
|
||||
a_desinscrire = inscrits_set - etuds_set
|
||||
else:
|
||||
a_inscrire = a_desinscrire = []
|
||||
# log('formsemestre_inscr_passage: a_inscrire=%s' % str(a_inscrire) )
|
||||
# log('formsemestre_inscr_passage: a_desinscrire=%s' % str(a_desinscrire) )
|
||||
|
||||
if not submitted:
|
||||
H += build_page(
|
||||
H += _build_page(
|
||||
sem,
|
||||
auth_etuds_by_sem,
|
||||
inscrits,
|
||||
@ -343,7 +342,7 @@ def formsemestre_inscr_passage(
|
||||
if not dialog_confirmed:
|
||||
# Confirmation
|
||||
if a_inscrire:
|
||||
H.append("<h3>Etudiants à inscrire</h3><ol>")
|
||||
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("</ol>")
|
||||
@ -354,7 +353,7 @@ def formsemestre_inscr_passage(
|
||||
H.append('<li class="inscrailleurs">%(nomprenom)s</li>' % etud)
|
||||
H.append("</ul>")
|
||||
if a_desinscrire:
|
||||
H.append("<h3>Etudiants à désinscrire</h3><ol>")
|
||||
H.append("<h3>Étudiants à désinscrire</h3><ol>")
|
||||
for etudid in a_desinscrire:
|
||||
H.append(
|
||||
'<li class="desinscription">%(nomprenom)s</li>'
|
||||
@ -384,21 +383,29 @@ def formsemestre_inscr_passage(
|
||||
)
|
||||
)
|
||||
else:
|
||||
# Inscription des étudiants au nouveau semestre:
|
||||
do_inscrit(
|
||||
sem,
|
||||
a_inscrire,
|
||||
inscrit_groupes=inscrit_groupes,
|
||||
)
|
||||
|
||||
# Desincriptions:
|
||||
do_desinscrit(sem, a_desinscrire)
|
||||
with sco_cache.DeferredSemCacheManager():
|
||||
# Inscription des étudiants au nouveau semestre:
|
||||
do_inscrit(
|
||||
sem,
|
||||
a_inscrire,
|
||||
inscrit_groupes=inscrit_groupes,
|
||||
)
|
||||
# Désinscriptions:
|
||||
do_desinscrit(sem, a_desinscrire)
|
||||
|
||||
H.append(
|
||||
"""<h3>Opération effectuée</h3>
|
||||
<ul><li><a class="stdlink" href="formsemestre_inscr_passage?formsemestre_id=%s">Continuer les inscriptions</a></li>
|
||||
<li><a class="stdlink" href="formsemestre_status?formsemestre_id=%s">Tableau de bord du semestre</a></li>"""
|
||||
% (formsemestre_id, formsemestre_id)
|
||||
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>"""
|
||||
)
|
||||
partition = sco_groups.formsemestre_get_main_partition(formsemestre_id)
|
||||
if (
|
||||
@ -410,7 +417,7 @@ def formsemestre_inscr_passage(
|
||||
H.append(
|
||||
f"""<li><a class="stdlink" href="{
|
||||
url_for("scolar.affect_groups",
|
||||
scodoc_dept=g.scodoc_dept, partition_id=partition["partition_id"])
|
||||
scodoc_dept=g.scodoc_dept, partition_id=partition["partition_id"])
|
||||
}">Répartir les groupes de {partition["partition_name"]}</a></li>
|
||||
"""
|
||||
)
|
||||
@ -420,7 +427,7 @@ def formsemestre_inscr_passage(
|
||||
return "\n".join(H)
|
||||
|
||||
|
||||
def build_page(
|
||||
def _build_page(
|
||||
sem,
|
||||
auth_etuds_by_sem,
|
||||
inscrits,
|
||||
@ -429,6 +436,7 @@ def build_page(
|
||||
inscrit_groupes=False,
|
||||
ignore_jury=False,
|
||||
):
|
||||
formsemestre: FormSemestre = FormSemestre.query.get(sem["formsemestre_id"])
|
||||
inscrit_groupes = int(inscrit_groupes)
|
||||
ignore_jury = int(ignore_jury)
|
||||
if inscrit_groupes:
|
||||
@ -443,27 +451,36 @@ def build_page(
|
||||
html_sco_header.html_sem_header(
|
||||
"Passages dans le semestre", with_page_header=False
|
||||
),
|
||||
"""<form name="f" method="post" action="%s">""" % request.base_url,
|
||||
"""<input type="hidden" name="formsemestre_id" value="%(formsemestre_id)s"/>
|
||||
<input type="submit" name="submitted" value="Appliquer les modifications"/>
|
||||
<a href="#help">aide</a>
|
||||
"""
|
||||
% sem, # "
|
||||
"""<input name="inscrit_groupes" type="checkbox" value="1" %s>inscrire aux mêmes groupes</input>"""
|
||||
% inscrit_groupes_checked,
|
||||
"""<input name="ignore_jury" type="checkbox" value="1" onchange="document.f.submit()" %s>inclure tous les étudiants (même sans décision de jury)</input>"""
|
||||
% ignore_jury_checked,
|
||||
"""<div class="pas_recap">Actuellement <span id="nbinscrits">%s</span> inscrits
|
||||
et %d candidats supplémentaires
|
||||
</div>"""
|
||||
% (len(inscrits), len(candidats_non_inscrits)),
|
||||
etuds_select_boxes(auth_etuds_by_sem, inscrits_ailleurs),
|
||||
"""<p/><input type="submit" name="submitted" value="Appliquer les modifications"/>""",
|
||||
formsemestre_inscr_passage_help(sem),
|
||||
"""</form>""",
|
||||
f"""<form name="f" method="post" action="{request.base_url}">
|
||||
|
||||
<input type="hidden" name="formsemestre_id" value="{sem['formsemestre_id']}"/>
|
||||
|
||||
<input type="submit" name="submitted" value="Appliquer les modifications"/>
|
||||
<a href="#help">aide</a>
|
||||
|
||||
<input name="inscrit_groupes" type="checkbox" value="1"
|
||||
{inscrit_groupes_checked}>inscrire aux mêmes groupes</input>
|
||||
|
||||
<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
|
||||
</div>
|
||||
|
||||
<div>{scu.EMO_WARNING} <em>Seuls les semestres dont la date de fin est antérieure à la date de début
|
||||
de ce semestre ({formsemestre.date_debut.strftime("%d/%m/%Y")}) sont pris en compte.</em></div>
|
||||
{etuds_select_boxes(auth_etuds_by_sem, inscrits_ailleurs)}
|
||||
|
||||
<input type="submit" name="submitted" value="Appliquer les modifications"/>
|
||||
|
||||
{formsemestre_inscr_passage_help(sem)}
|
||||
|
||||
</form>
|
||||
""",
|
||||
]
|
||||
|
||||
# Semestres sans etudiants autorisés
|
||||
# Semestres sans étudiants autorisés
|
||||
empty_sems = []
|
||||
for formsemestre_id in auth_etuds_by_sem.keys():
|
||||
if not auth_etuds_by_sem[formsemestre_id]["etuds"]:
|
||||
@ -473,7 +490,10 @@ def build_page(
|
||||
"""<div class="pas_empty_sems"><h3>Autres semestres sans candidats :</h3><ul>"""
|
||||
)
|
||||
for infos in empty_sems:
|
||||
H.append("""<li><a href="%(title_target)s">%(title)s</a></li>""" % infos)
|
||||
H.append(
|
||||
"""<li><a class="stdlink" href="%(title_target)s">%(title)s</a></li>"""
|
||||
% infos
|
||||
)
|
||||
H.append("""</ul></div>""")
|
||||
|
||||
return H
|
||||
|
@ -544,7 +544,9 @@ def _ligne_evaluation(
|
||||
if not first_eval:
|
||||
H.append("""<tr><td colspan="8"> </td></tr>""")
|
||||
tr_class_1 += " mievr_spaced"
|
||||
H.append(f"""<tr class="{tr_class_1}"><td class="mievr_tit" colspan="8">""")
|
||||
H.append(
|
||||
f"""<tr class="{tr_class_1} mievr_tit"><td class="mievr_tit" colspan="8">"""
|
||||
)
|
||||
coef = evaluation.coefficient
|
||||
if is_apc:
|
||||
if not evaluation.get_ue_poids_dict():
|
||||
@ -588,7 +590,9 @@ def _ligne_evaluation(
|
||||
)
|
||||
#
|
||||
H.append(
|
||||
f"""<div class="evaluation_order">
|
||||
f"""
|
||||
</td>
|
||||
<td class="evaluation_order">
|
||||
<span class="evalindex" title="Indice dans les vecteurs (formules)">{
|
||||
eval_index:2}</span>
|
||||
<span class="eval_arrows_chld">
|
||||
@ -612,20 +616,6 @@ def _ligne_evaluation(
|
||||
else:
|
||||
H.append(arrow_none)
|
||||
|
||||
H.append(
|
||||
f"""</span></span></td>
|
||||
</div>
|
||||
</tr>
|
||||
<tr class="{tr_class}">
|
||||
<th class="moduleimpl_evaluations" colspan="2"> </th>
|
||||
<th class="moduleimpl_evaluations">Durée</th>
|
||||
<th class="moduleimpl_evaluations">Coef.</th>
|
||||
<th class="moduleimpl_evaluations">Notes</th>
|
||||
<th class="moduleimpl_evaluations">Abs</th>
|
||||
<th class="moduleimpl_evaluations">N</th>
|
||||
<th class="moduleimpl_evaluations">Moyenne """
|
||||
)
|
||||
|
||||
if etat["evalcomplete"]:
|
||||
etat_txt = """(prise en compte)"""
|
||||
etat_descr = "notes utilisées dans les moyennes"
|
||||
@ -648,9 +638,19 @@ def _ligne_evaluation(
|
||||
}" title="{etat_descr}">{etat_txt}</a>"""
|
||||
|
||||
H.append(
|
||||
f"""{etat_txt}</th>
|
||||
</tr>
|
||||
<tr class="{tr_class}"><td class="mievr">"""
|
||||
f"""</span></span></td>
|
||||
</tr>
|
||||
<tr class="{tr_class}">
|
||||
<th class="moduleimpl_evaluations" colspan="2"> </th>
|
||||
<th class="moduleimpl_evaluations">Durée</th>
|
||||
<th class="moduleimpl_evaluations">Coef.</th>
|
||||
<th class="moduleimpl_evaluations">Notes</th>
|
||||
<th class="moduleimpl_evaluations">Abs</th>
|
||||
<th class="moduleimpl_evaluations">N</th>
|
||||
<th class="moduleimpl_evaluations" colspan="2">Moyenne {etat_txt}</th>
|
||||
</tr>
|
||||
<tr class="{tr_class}">
|
||||
<td class="mievr">"""
|
||||
)
|
||||
if can_edit_evals:
|
||||
H.append(
|
||||
@ -726,7 +726,7 @@ def _ligne_evaluation(
|
||||
<td class="rightcell mievr_nbnotes">{etat["nb_notes"]} / {etat["nb_inscrits"]}</td>
|
||||
<td class="rightcell mievr_coef">{etat["nb_abs"]}</td>
|
||||
<td class="rightcell mievr_coef">{etat["nb_neutre"]}</td>
|
||||
<td class="rightcell">"""
|
||||
<td class="rightcell" colspan="2">"""
|
||||
% etat
|
||||
)
|
||||
if etat["moy"]:
|
||||
@ -750,11 +750,11 @@ def _ligne_evaluation(
|
||||
H.append(f"""<tr class="{tr_class}"><td></td>""")
|
||||
if modimpl.module.is_apc():
|
||||
H.append(
|
||||
f"""<td colspan="7" class="eval_poids">{
|
||||
f"""<td colspan="8" class="eval_poids">{
|
||||
evaluation.get_ue_poids_str()}</td>"""
|
||||
)
|
||||
else:
|
||||
H.append('<td colspan="7"></td>')
|
||||
H.append('<td colspan="8"></td>')
|
||||
H.append("""</tr>""")
|
||||
else: # il y a deja des notes saisies
|
||||
gr_moyennes = etat["gr_moyennes"]
|
||||
@ -773,7 +773,10 @@ def _ligne_evaluation(
|
||||
name = "Tous" # tous
|
||||
else:
|
||||
name = f"""Groupe {gr_moyenne["group_name"]}"""
|
||||
H.append(f"""<td colspan="2" class="mievr_grtit">{name} </td><td>""")
|
||||
H.append(
|
||||
f"""<td colspan="2" class="mievr_grtit">{name} </td>
|
||||
<td colspan="2">"""
|
||||
)
|
||||
if gr_moyenne["gr_nb_notes"] > 0:
|
||||
H.append(
|
||||
f"""{gr_moyenne["gr_moy"]} (<a href="{
|
||||
|
@ -200,7 +200,7 @@ def etud_photo_html(etud: dict = None, etudid=None, title=None, size="small") ->
|
||||
return abort(404, "etudiant inconnu")
|
||||
etud = etuds[0]
|
||||
else:
|
||||
raise ValueError("etud_photo_html: either etud or etudid must be specified")
|
||||
abort(404, "etud_photo_html: either etud or etudid must be specified")
|
||||
photo_url = etud_photo_url(etud, size=size)
|
||||
nom = etud.get("nomprenom", etud["nom_disp"])
|
||||
if title is None:
|
||||
@ -244,7 +244,7 @@ def photo_pathname(photo_filename: str, size="orig"):
|
||||
elif size == "orig":
|
||||
version = ""
|
||||
else:
|
||||
raise ValueError("invalid size parameter for photo")
|
||||
abort(404, "invalid size parameter for photo")
|
||||
if not photo_filename:
|
||||
return False
|
||||
path = os.path.join(PHOTO_DIR, photo_filename) + version + IMAGE_EXT
|
||||
|
@ -1309,7 +1309,7 @@ def _form_saisie_notes(E, M, groups_infos, destination=""):
|
||||
H = []
|
||||
if nb_decisions > 0:
|
||||
H.append(
|
||||
"""<div class="saisie_warn">
|
||||
f"""<div class="saisie_warn">
|
||||
<ul class="tf-msg">
|
||||
<li class="tf-msg">Attention: il y a déjà des <b>décisions de jury</b> enregistrées pour
|
||||
{nb_decisions} étudiants. Après changement des notes, vérifiez la situation !</li>
|
||||
|
@ -1,5 +1,10 @@
|
||||
/* Saisie décision de jury BUT */
|
||||
|
||||
:root {
|
||||
--color-recorded: rgb(3, 157, 3);
|
||||
--color-explanation: blueviolet;
|
||||
}
|
||||
|
||||
.jury_but {
|
||||
font-family: Verdana, Geneva, Tahoma, sans-serif;
|
||||
}
|
||||
@ -18,6 +23,19 @@
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
form#jury_but {
|
||||
margin: 0px 16px 16px 16px;
|
||||
background-color: rgb(253, 253, 231);
|
||||
border: 2px solid rgb(4, 4, 118);
|
||||
border-radius: 4px;
|
||||
padding-top: 8px;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
padding-bottom: 16px;
|
||||
min-width: var(--sco-content-min-width);
|
||||
max-width: var(--sco-content-max-width);
|
||||
}
|
||||
|
||||
.but_annee {
|
||||
margin-left: 32px;
|
||||
display: inline-grid;
|
||||
@ -112,11 +130,10 @@ div.but_settings {
|
||||
}
|
||||
|
||||
.but_explanation {
|
||||
color: blueviolet;
|
||||
color: var(--color-explanation);
|
||||
font-style: italic;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 12px;
|
||||
;
|
||||
}
|
||||
|
||||
select:disabled {
|
||||
@ -130,7 +147,7 @@ select:invalid {
|
||||
|
||||
select.but_code option.recorded,
|
||||
div.but_code recorded {
|
||||
color: rgb(3, 157, 3);
|
||||
color: var(--color-recorded);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@ -143,14 +160,14 @@ div.but_code {
|
||||
|
||||
div.but_niveau_ue.recorded,
|
||||
div.but_niveau_rcue.recorded {
|
||||
border-color: rgb(0, 169, 0);
|
||||
border-color: var(--color-recorded);
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
div.but_niveau_ue.recorded_different,
|
||||
div.but_niveau_rcue.recorded_different {
|
||||
box-shadow: 0 0 0 3px red;
|
||||
outline: dashed 3px rgb(0, 169, 0);
|
||||
outline: dashed 3px var(--color-recorded);
|
||||
}
|
||||
|
||||
div.but_niveau_ue.annee_prec {
|
||||
@ -172,8 +189,16 @@ div.but_buttons span {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
div.but_doc_codes.but_warning_rcue_cap {
|
||||
padding-top: 8px;
|
||||
font-size: 100%;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div.but_doc_codes {
|
||||
margin: 16px;
|
||||
min-width: var(--sco-content-min-width);
|
||||
max-width: var(--sco-content-max-width);
|
||||
background-color: rgb(227, 254, 254);
|
||||
font-size: 75%;
|
||||
border: 2px solid rgb(4, 4, 118);
|
||||
@ -227,4 +252,16 @@ div.but_doc table tr td.amue {
|
||||
|
||||
.but_niveau_rcue .scoplement {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.but_autorisations_passage {
|
||||
margin-top: 12px;
|
||||
margin-left: 32px;
|
||||
font-weight: bold;
|
||||
color: var(--color-recorded);
|
||||
}
|
||||
|
||||
.but_autorisations_passage.but_explanation {
|
||||
font-weight: normal;
|
||||
color: var(--color-explanation);
|
||||
}
|
@ -1,7 +1,11 @@
|
||||
/* # -*- mode: css -*-
|
||||
ScoDoc, (c) Emmanuel Viennet 1998 - 2021
|
||||
/* ScoDoc, (c) Emmanuel Viennet 1998 - 2023
|
||||
*/
|
||||
|
||||
:root {
|
||||
--sco-content-min-width: 600px;
|
||||
--sco-content-max-width: 1024px;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
@ -1657,6 +1661,11 @@ td.formsemestre_status_inscrits {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
td.rcp_titre_sem a.jury_link {
|
||||
margin-left: 8px;
|
||||
color: red;
|
||||
}
|
||||
|
||||
td.formsemestre_status_cell {
|
||||
white-space: nowrap;
|
||||
}
|
||||
@ -1728,6 +1737,8 @@ ul.ue_inscr_list li.etud {
|
||||
div.moduleimpl_tableaubord {
|
||||
padding: 7px;
|
||||
border: 2px solid gray;
|
||||
min-width: var(--sco-content-min-width);
|
||||
max-width: var(--sco-content-max-width);
|
||||
}
|
||||
|
||||
div.moduleimpl_type_sae {
|
||||
@ -1855,11 +1866,19 @@ span.mievr_rattr {
|
||||
padding: 1px 3px 1px 3px;
|
||||
}
|
||||
|
||||
tr.mievr td.mievr_tit {
|
||||
tr.mievr_tit td.mievr_tit {
|
||||
font-weight: bold;
|
||||
background-color: #cccccc;
|
||||
border-top-left-radius: 8px;
|
||||
}
|
||||
|
||||
tr.mievr.mievr_tit td {
|
||||
background-color: #e1e1e1;
|
||||
}
|
||||
|
||||
tr.mievr_tit td:last-child {
|
||||
border-top-right-radius: 8px;
|
||||
text-align: right;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
tr.mievr td {
|
||||
@ -1922,11 +1941,6 @@ span.eval_warning_coef {
|
||||
background-color: rgb(255, 225, 0);
|
||||
}
|
||||
|
||||
div.evaluation_order {
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
}
|
||||
|
||||
span.evalindex {
|
||||
font-weight: normal;
|
||||
font-size: 80%;
|
||||
@ -2580,11 +2594,13 @@ div.bull_head {
|
||||
display: grid;
|
||||
justify-content: space-between;
|
||||
grid-template-columns: auto auto;
|
||||
min-width: 600px;
|
||||
max-width: 1072px;
|
||||
}
|
||||
|
||||
div.bull_photo {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
span.bulletin_menubar_but {
|
||||
|
@ -78,7 +78,10 @@ $(function () {
|
||||
} else {
|
||||
document.querySelector("div.next").innerHTML = "";
|
||||
}
|
||||
|
||||
} else {
|
||||
// Supprime les liens de navigation
|
||||
document.querySelector("div.prev").innerHTML = "";
|
||||
document.querySelector("div.next").innerHTML = "";
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -262,10 +262,11 @@
|
||||
<b>Textes de référence:</b>
|
||||
<ul>
|
||||
<li><a href="https://www.enseignementsup-recherche.gouv.fr/fr/bo/21/Special4/ESRS2114777A.htm">Bulletin
|
||||
officiel spécial n°4 du 17 juin 2021</a></li>
|
||||
officiel spécial n°4 du 26 mai 2022 </a></li>
|
||||
<li><a
|
||||
href="https://cache.media.enseignementsup-recherche.gouv.fr//file/SPE4-MESRI-17-6-2021/19/4/SP4_ESR_17_6_2021_1413194.pdf">Version
|
||||
pdf complète</a></li>
|
||||
href="https://cache.media.education.gouv.fr/file/SP4-MESRI-26-5-2022/10/0/spe617_annexe1_1426100.pdf">Version
|
||||
pdf de l'arrêté de mai 2022 sur la licence professionnelle « bachelor universitaire de technologie
|
||||
»</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
@ -49,7 +49,8 @@
|
||||
<span class="formation_module_ue">(<a title="UE de rattachement">{{mod.ue.acronyme}}</a>)</span>,
|
||||
{% endif %}
|
||||
|
||||
parcours <b>{{ mod.get_parcours()|map(attribute="code")|join("</b>, <b>")|default('tronc commun', true)|safe
|
||||
- parcours <b>{{ mod.get_parcours()|map(attribute="code")|join("</b>, <b>")|default('tronc commun',
|
||||
true)|safe
|
||||
}}</b>
|
||||
{% if mod.heures_cours or mod.heures_td or mod.heures_tp %}
|
||||
({{mod.heures_cours|default(" ",true)|safe}}/{{mod.heures_td|default(" ",true)|safe}}/{{mod.heures_tp|default(" ",true)|safe}},
|
@ -704,10 +704,15 @@ def formation_list(format=None, formation_id=None, args={}):
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoView)
|
||||
@scodoc7func
|
||||
def formation_export(formation_id, export_ids=False, format=None):
|
||||
def formation_export(
|
||||
formation_id, export_ids=False, format=None, export_codes_apo=True
|
||||
):
|
||||
"Export de la formation au format indiqué (xml ou json)"
|
||||
return sco_formations.formation_export(
|
||||
formation_id, export_ids=export_ids, format=format
|
||||
formation_id,
|
||||
export_ids=export_ids,
|
||||
format=format,
|
||||
export_codes_apo=export_codes_apo,
|
||||
)
|
||||
|
||||
|
||||
@ -2494,11 +2499,31 @@ def formsemestre_validation_but(
|
||||
|
||||
H.append(jury_but_view.show_etud(deca, read_only=read_only))
|
||||
|
||||
autorisations_idx = deca.get_autorisations_passage()
|
||||
div_autorisations_passage = (
|
||||
f"""
|
||||
<div class="but_autorisations_passage">
|
||||
<span>Autorisé à passer en :</span>
|
||||
{ ", ".join( ["S" + str(i) for i in autorisations_idx ] )}
|
||||
</div>
|
||||
"""
|
||||
if autorisations_idx
|
||||
else """<div class="but_autorisations_passage but_explanation">
|
||||
pas d'autorisations de passage enregistrées.
|
||||
</div>
|
||||
"""
|
||||
)
|
||||
H.append(div_autorisations_passage)
|
||||
|
||||
if read_only:
|
||||
H.append(
|
||||
"""<div class="but_explanation">
|
||||
Vous n'avez pas la permission de modifier ces décisions.
|
||||
Les champs entourés en vert sont enregistrés.</div>"""
|
||||
f"""
|
||||
<div class="but_explanation">
|
||||
{"Vous n'avez pas la permission de modifier ces décisions."
|
||||
if formsemestre.etat
|
||||
else "Semestre verrouillé."}
|
||||
Les champs entourés en vert sont enregistrés.
|
||||
</div>"""
|
||||
)
|
||||
else:
|
||||
erase_span = f"""<a href="{
|
||||
@ -2508,9 +2533,11 @@ def formsemestre_validation_but(
|
||||
H.append(
|
||||
f"""<div class="but_settings">
|
||||
<input type="checkbox" onchange="enable_manual_codes(this)">
|
||||
<em>permettre la saisie manuelles des codes d'année et de niveaux.
|
||||
Dans ce cas, il vous revient de vous assurer de la cohérence entre
|
||||
vos codes d'UE/RCUE/Année !</em>
|
||||
<em>permettre la saisie manuelles des codes
|
||||
{"d'année et " if deca.jury_annuel else ""}
|
||||
de niveaux.
|
||||
Dans ce cas, assurez-vous de la cohérence entre les codes d'UE/RCUE/Année !
|
||||
</em>
|
||||
</input>
|
||||
</div>
|
||||
|
||||
@ -2522,7 +2549,15 @@ def formsemestre_validation_but(
|
||||
)
|
||||
H.append(navigation_div)
|
||||
H.append("</form>")
|
||||
|
||||
if deca.a_cheval:
|
||||
H.append(
|
||||
f"""<div class="but_doc_codes but_warning_rcue_cap">
|
||||
{scu.EMO_WARNING} Rappel: pour les redoublants, seules les UE <b>capitalisées</b> (note > 10)
|
||||
lors d'une année précédente peuvent être prise en compte pour former
|
||||
un RCUE (associé à un niveau de compétence du BUT).
|
||||
</div>
|
||||
"""
|
||||
)
|
||||
H.append(
|
||||
render_template(
|
||||
"but/documentation_codes_jury.html",
|
||||
|
@ -216,7 +216,7 @@ def edit_modules_ue_coefs():
|
||||
</h2>
|
||||
""",
|
||||
render_template(
|
||||
"pn/form_modules_ue_coefs.html",
|
||||
"pn/form_modules_ue_coefs.j2",
|
||||
formation=formation,
|
||||
data_source=url_for(
|
||||
"notes.table_modules_ue_coefs",
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
SCOVERSION = "9.4.31"
|
||||
SCOVERSION = "9.4.32"
|
||||
|
||||
SCONAME = "ScoDoc"
|
||||
|
||||
|
@ -32,7 +32,7 @@ from app.models import GroupDescr
|
||||
from app.models import Identite
|
||||
from app.models import ModuleImpl, ModuleImplInscription
|
||||
from app.models import Partition
|
||||
from app.models import ScolarFormSemestreValidation
|
||||
from app.models import ScolarAutorisationInscription, ScolarFormSemestreValidation
|
||||
from app.models.but_refcomp import (
|
||||
ApcCompetence,
|
||||
ApcNiveau,
|
||||
@ -101,6 +101,7 @@ def make_shell_context():
|
||||
"ResultatsSemestreBUT": ResultatsSemestreBUT,
|
||||
"Role": Role,
|
||||
"scolar": scolar,
|
||||
"ScolarAutorisationInscription": ScolarAutorisationInscription,
|
||||
"ScolarFormSemestreValidation": ScolarFormSemestreValidation,
|
||||
"ScolarNews": models.ScolarNews,
|
||||
"scu": scu,
|
||||
|
@ -1022,3 +1022,84 @@ Etudiants:
|
||||
moy_ue: 9.5000
|
||||
moy_ue_with_cap: 12.7600
|
||||
decision_annee: AJ
|
||||
geii1000:
|
||||
prenom: etugeii1000
|
||||
civilite: M
|
||||
formsemestres:
|
||||
S1:
|
||||
notes_modules: # on joue avec les SAE seulement car elles sont "diagonales"
|
||||
"S1.1": 12.0000
|
||||
"S1.2": 9.0000
|
||||
attendu: # les codes jury que l'on doit vérifier
|
||||
deca:
|
||||
passage_de_droit: False
|
||||
nb_competences: 2
|
||||
nb_rcue_annee: 0
|
||||
decisions_ues:
|
||||
"UE11":
|
||||
codes: [ "ADM", "..." ]
|
||||
code_valide: ADM
|
||||
moy_ue: 12.0000
|
||||
"UE12":
|
||||
codes: [ "AJ", "..." ]
|
||||
code_valide: AJ
|
||||
decision_jury: AJ
|
||||
moy_ue: 9.0000
|
||||
S2:
|
||||
notes_modules: # on joue avec les SAE seulement car elles sont "diagonales"
|
||||
"S2.1": 12.0000
|
||||
"S2.2": 10.50 # capitalise mais ne compense pas
|
||||
attendu: # les codes jury que l'on doit vérifier
|
||||
deca:
|
||||
passage_de_droit: False
|
||||
nb_competences: 2
|
||||
nb_rcue_annee: 2
|
||||
valide_moitie_rcue: False
|
||||
codes: [ "RED", "..." ]
|
||||
decisions_ues:
|
||||
"UE21":
|
||||
codes: [ "ADM", "..." ]
|
||||
code_valide: ADM
|
||||
moy_ue: 12.0000
|
||||
"UE22":
|
||||
code_valide: ADM
|
||||
moy_ue: 10.5
|
||||
decisions_rcues: # on repère ici les RCUE par l'acronyme de leur 1ere UE (donc du S1)
|
||||
"UE11":
|
||||
code_valide: ADM
|
||||
decision_jury: ADM
|
||||
rcue:
|
||||
moy_rcue: 12.0000
|
||||
est_compensable: False
|
||||
"UE12":
|
||||
code_valide: AJ
|
||||
decision_jury: AJ
|
||||
rcue:
|
||||
moy_rcue: 9.75
|
||||
est_compensable: False
|
||||
decision_annee: RED
|
||||
S1-red:
|
||||
notes_modules: # on joue avec les SAE seulement car elles sont "diagonales"
|
||||
"S1.1": 5.0000
|
||||
"S1.2": 12.0000
|
||||
attendu: # les codes jury que l'on doit vérifier
|
||||
deca:
|
||||
passage_de_droit: False
|
||||
nb_competences: 2
|
||||
nb_rcue_annee: 0
|
||||
decisions_ues:
|
||||
"UE11":
|
||||
code_valide: AJ
|
||||
moy_ue: 5. # LA MOYENNE COURANTE
|
||||
moy_ue_with_cap: 12.0000
|
||||
"UE12":
|
||||
code_valide: ADM
|
||||
decision_jury: ADM
|
||||
moy_ue: 12.0000
|
||||
# RCUE inter-annuel
|
||||
decisions_rcues: # on repère ici les RCUE par l'acronyme de leur 1ere UE (donc du S1)
|
||||
"UE12":
|
||||
code_valide: ADM
|
||||
rcue:
|
||||
moy_rcue: 11.25
|
||||
est_compensable: False
|
||||
|
@ -33,7 +33,7 @@ DEPT = TestConfig.DEPT_TEST
|
||||
@pytest.mark.but_gb
|
||||
def test_but_jury_GB(test_client):
|
||||
"""Tests sur un cursus GB
|
||||
- construction des semestres et de leurs étudianst à partir du yaml
|
||||
- construction des semestres et de leurs étudiants à partir du yaml
|
||||
- vérification jury de S1
|
||||
- vérification jury de S2
|
||||
- vérification jury de S3
|
||||
@ -96,7 +96,6 @@ def test_but_jury_GEII_lyon(test_client):
|
||||
# Construit la base de test GB une seule fois
|
||||
# puis lance les tests de jury
|
||||
doc = yaml_setup.setup_from_yaml("tests/unit/cursus_but_geii_lyon.yaml")
|
||||
|
||||
formsemestres = FormSemestre.query.order_by(
|
||||
FormSemestre.date_debut, FormSemestre.semestre_id
|
||||
).all()
|
||||
|
Loading…
Reference in New Issue
Block a user