forked from ScoDoc/ScoDoc
Suppressions de décisions de jury
This commit is contained in:
parent
9ee36f5eba
commit
fbca147d7e
@ -75,11 +75,9 @@ from app.comp.res_but import ResultatsSemestreBUT
|
|||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
|
|
||||||
from app.models.but_refcomp import (
|
from app.models.but_refcomp import (
|
||||||
ApcAnneeParcours,
|
|
||||||
ApcCompetence,
|
ApcCompetence,
|
||||||
ApcNiveau,
|
ApcNiveau,
|
||||||
ApcParcours,
|
ApcParcours,
|
||||||
ApcParcoursNiveauCompetence,
|
|
||||||
)
|
)
|
||||||
from app.models import Scolog, ScolarAutorisationInscription
|
from app.models import Scolog, ScolarAutorisationInscription
|
||||||
from app.models.but_validations import (
|
from app.models.but_validations import (
|
||||||
@ -89,7 +87,7 @@ from app.models.but_validations import (
|
|||||||
)
|
)
|
||||||
from app.models.etudiants import Identite
|
from app.models.etudiants import Identite
|
||||||
from app.models.formations import Formation
|
from app.models.formations import Formation
|
||||||
from app.models.formsemestre import FormSemestre, FormSemestreInscription
|
from app.models.formsemestre import FormSemestre
|
||||||
from app.models.ues import UniteEns
|
from app.models.ues import UniteEns
|
||||||
from app.models.validations import ScolarFormSemestreValidation
|
from app.models.validations import ScolarFormSemestreValidation
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
@ -473,7 +471,7 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
semestre_idx=formsemestre.semestre_id,
|
semestre_idx=formsemestre.semestre_id,
|
||||||
formation_id=formsemestre.formation.id)}">
|
formation_id=formsemestre.formation.id)}">
|
||||||
{formsemestre.formation.to_html()} ({
|
{formsemestre.formation.html()} ({
|
||||||
formsemestre.formation.id})</a>
|
formsemestre.formation.id})</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -902,7 +900,8 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
pour cette année: décisions d'UE, de RCUE, d'année,
|
pour cette année: décisions d'UE, de RCUE, d'année,
|
||||||
et autorisations d'inscription émises.
|
et autorisations d'inscription émises.
|
||||||
Efface même si étudiant DEM ou DEF.
|
Efface même si étudiant DEM ou DEF.
|
||||||
Si à cheval, n'efface que pour le semestre d'origine du deca.
|
Si à cheval ou only_one_sem, n'efface que les décisions UE et les
|
||||||
|
autorisations de passage du semestre d'origine du deca.
|
||||||
(commite la session.)
|
(commite la session.)
|
||||||
"""
|
"""
|
||||||
if only_one_sem or self.a_cheval:
|
if only_one_sem or self.a_cheval:
|
||||||
|
@ -246,7 +246,7 @@ def _gen_but_rcue(dec_rcue: DecisionsProposeesRCUE, niveau: ApcNiveau) -> str:
|
|||||||
|
|
||||||
scoplement = (
|
scoplement = (
|
||||||
f"""<div class="scoplement">{
|
f"""<div class="scoplement">{
|
||||||
dec_rcue.validation.to_html()
|
dec_rcue.validation.html()
|
||||||
}</div>"""
|
}</div>"""
|
||||||
if dec_rcue.validation
|
if dec_rcue.validation
|
||||||
else ""
|
else ""
|
||||||
|
@ -10,8 +10,17 @@ import pandas as pd
|
|||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
from app.models import FormSemestre, Identite, ScolarFormSemestreValidation, UniteEns
|
|
||||||
from app.comp.res_cache import ResultatsCache
|
from app.comp.res_cache import ResultatsCache
|
||||||
|
from app.models import (
|
||||||
|
ApcValidationAnnee,
|
||||||
|
ApcValidationRCUE,
|
||||||
|
Formation,
|
||||||
|
FormSemestre,
|
||||||
|
Identite,
|
||||||
|
ScolarAutorisationInscription,
|
||||||
|
ScolarFormSemestreValidation,
|
||||||
|
UniteEns,
|
||||||
|
)
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import codes_cursus
|
from app.scodoc import codes_cursus
|
||||||
|
|
||||||
@ -81,7 +90,7 @@ class ValidationsSemestre(ResultatsCache):
|
|||||||
|
|
||||||
# UEs: { etudid : { ue_id : {"code":, "ects":, "event_date":} }}
|
# UEs: { etudid : { ue_id : {"code":, "ects":, "event_date":} }}
|
||||||
decisions_jury_ues = {}
|
decisions_jury_ues = {}
|
||||||
# Parcours les décisions d'UE:
|
# Parcoure les décisions d'UE:
|
||||||
for decision in (
|
for decision in (
|
||||||
decisions_jury_q.filter(db.text("ue_id is not NULL"))
|
decisions_jury_q.filter(db.text("ue_id is not NULL"))
|
||||||
.join(UniteEns)
|
.join(UniteEns)
|
||||||
@ -172,3 +181,80 @@ def formsemestre_get_ue_capitalisees(formsemestre: FormSemestre) -> pd.DataFrame
|
|||||||
with db.engine.begin() as connection:
|
with db.engine.begin() as connection:
|
||||||
df = pd.read_sql_query(query, connection, params=params, index_col="etudid")
|
df = pd.read_sql_query(query, connection, params=params, index_col="etudid")
|
||||||
return df
|
return df
|
||||||
|
|
||||||
|
|
||||||
|
def erase_decisions_annee_formation(
|
||||||
|
etud: Identite, formation: Formation, annee: int, delete=False
|
||||||
|
) -> list:
|
||||||
|
"""Efface toutes les décisions de jury de l'étudiant dans les formations de même code
|
||||||
|
que celle donnée pour cette année de la formation:
|
||||||
|
UEs, RCUEs de l'année BUT, année BUT, passage vers l'année suivante.
|
||||||
|
Ne considère pas l'origine de la décision.
|
||||||
|
annee: entier, 1, 2, 3, ...
|
||||||
|
Si delete est faux, renvoie la liste des validations qu'il faudrait effacer, sans y toucher.
|
||||||
|
"""
|
||||||
|
sem1, sem2 = annee * 2 - 1, annee * 2
|
||||||
|
# UEs
|
||||||
|
validations = (
|
||||||
|
ScolarFormSemestreValidation.query.filter_by(etudid=etud.id)
|
||||||
|
.join(UniteEns)
|
||||||
|
.filter(db.or_(UniteEns.semestre_idx == sem1, UniteEns.semestre_idx == sem2))
|
||||||
|
.join(Formation)
|
||||||
|
.filter_by(formation_code=formation.formation_code)
|
||||||
|
.order_by(
|
||||||
|
UniteEns.acronyme, UniteEns.numero
|
||||||
|
) # acronyme d'abord car 2 semestres
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
# RCUEs (a priori inutile de matcher sur l'ue2_id)
|
||||||
|
validations += (
|
||||||
|
ApcValidationRCUE.query.filter_by(etudid=etud.id)
|
||||||
|
.join(UniteEns, UniteEns.id == ApcValidationRCUE.ue1_id)
|
||||||
|
.filter_by(semestre_idx=sem1)
|
||||||
|
.join(Formation)
|
||||||
|
.filter_by(formation_code=formation.formation_code)
|
||||||
|
.order_by(UniteEns.acronyme, UniteEns.numero)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
# Validation de semestres classiques
|
||||||
|
validations += (
|
||||||
|
ScolarFormSemestreValidation.query.filter_by(etudid=etud.id, ue_id=None)
|
||||||
|
.join(
|
||||||
|
FormSemestre,
|
||||||
|
FormSemestre.id == ScolarFormSemestreValidation.formsemestre_id,
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
db.or_(FormSemestre.semestre_id == sem1, FormSemestre.semestre_id == sem2)
|
||||||
|
)
|
||||||
|
.join(Formation)
|
||||||
|
.filter_by(formation_code=formation.formation_code)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
# Année BUT
|
||||||
|
validations += (
|
||||||
|
ApcValidationAnnee.query.filter_by(etudid=etud.id, ordre=annee)
|
||||||
|
.join(Formation)
|
||||||
|
.filter_by(formation_code=formation.formation_code)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
# Autorisations vers les semestres suivants ceux de l'année:
|
||||||
|
validations += (
|
||||||
|
ScolarAutorisationInscription.query.filter_by(
|
||||||
|
etudid=etud.id, formation_code=formation.formation_code
|
||||||
|
)
|
||||||
|
.filter(
|
||||||
|
db.or_(
|
||||||
|
ScolarAutorisationInscription.semestre_id == sem1 + 1,
|
||||||
|
ScolarAutorisationInscription.semestre_id == sem2 + 1,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
|
if delete:
|
||||||
|
for validation in validations:
|
||||||
|
db.session.delete(validation)
|
||||||
|
db.session.commit()
|
||||||
|
sco_cache.invalidate_formsemestre_etud(etud)
|
||||||
|
return []
|
||||||
|
return validations
|
||||||
|
@ -66,7 +66,7 @@ class ApcValidationRCUE(db.Model):
|
|||||||
return f"""Décision sur RCUE {self.ue1.acronyme}/{self.ue2.acronyme}: {
|
return f"""Décision sur RCUE {self.ue1.acronyme}/{self.ue2.acronyme}: {
|
||||||
self.code} enregistrée le {self.date.strftime("%d/%m/%Y")}"""
|
self.code} enregistrée le {self.date.strftime("%d/%m/%Y")}"""
|
||||||
|
|
||||||
def to_html(self) -> str:
|
def html(self) -> str:
|
||||||
"description en HTML"
|
"description en HTML"
|
||||||
return f"""Décision sur RCUE {self.ue1.acronyme}/{self.ue2.acronyme}:
|
return f"""Décision sur RCUE {self.ue1.acronyme}/{self.ue2.acronyme}:
|
||||||
<b>{self.code}</b>
|
<b>{self.code}</b>
|
||||||
@ -348,6 +348,13 @@ class ApcValidationAnnee(db.Model):
|
|||||||
"ordre": self.ordre,
|
"ordre": self.ordre,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def html(self) -> str:
|
||||||
|
"Affichage html"
|
||||||
|
return f"""Validation <b>année BUT{self.ordre}</b> émise par
|
||||||
|
{self.formsemestre.html_link_status() if self.formsemestre else "-"}
|
||||||
|
le {self.date.strftime("%d/%m/%Y")} à {self.date.strftime("%Hh%M")}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def dict_decision_jury(etud: Identite, formsemestre: FormSemestre) -> dict:
|
def dict_decision_jury(etud: Identite, formsemestre: FormSemestre) -> dict:
|
||||||
"""
|
"""
|
||||||
|
@ -60,7 +60,7 @@ class Formation(db.Model):
|
|||||||
return f"""<{self.__class__.__name__}(id={self.id}, dept_id={
|
return f"""<{self.__class__.__name__}(id={self.id}, dept_id={
|
||||||
self.dept_id}, acronyme={self.acronyme!r}, version={self.version})>"""
|
self.dept_id}, acronyme={self.acronyme!r}, version={self.version})>"""
|
||||||
|
|
||||||
def to_html(self) -> str:
|
def html(self) -> str:
|
||||||
"titre complet pour affichage"
|
"titre complet pour affichage"
|
||||||
return f"""Formation {self.titre} ({self.acronyme}) [version {self.version}] code {self.formation_code}"""
|
return f"""Formation {self.titre} ({self.acronyme}) [version {self.version}] code {self.formation_code}"""
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ from operator import attrgetter
|
|||||||
|
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
from flask import flash, g
|
from flask import flash, g, url_for
|
||||||
from sqlalchemy.sql import text
|
from sqlalchemy.sql import text
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
@ -165,6 +165,14 @@ class FormSemestre(db.Model):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.__class__.__name__} {self.id} {self.titre_annee()}>"
|
return f"<{self.__class__.__name__} {self.id} {self.titre_annee()}>"
|
||||||
|
|
||||||
|
def html_link_status(self) -> str:
|
||||||
|
"html link to status page"
|
||||||
|
return f"""<a class="stdlink" href="{
|
||||||
|
url_for("notes.formsemestre_status", scodoc_dept=g.scodoc_dept,
|
||||||
|
formsemestre_id=self.id,)
|
||||||
|
}">{self.titre_mois()}</a>
|
||||||
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_formsemestre(cls, formsemestre_id: int) -> "FormSemestre":
|
def get_formsemestre(cls, formsemestre_id: int) -> "FormSemestre":
|
||||||
""" "FormSemestre ou 404, cherche uniquement dans le département courant"""
|
""" "FormSemestre ou 404, cherche uniquement dans le département courant"""
|
||||||
|
@ -59,13 +59,16 @@ class ScolarFormSemestreValidation(db.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"{self.__class__.__name__}(sem={self.formsemestre_id}, etuid={self.etudid}, code={self.code}, ue={self.ue}, moy_ue={self.moy_ue})"
|
return f"""{self.__class__.__name__}(sem={self.formsemestre_id}, etuid={
|
||||||
|
self.etudid}, code={self.code}, ue={self.ue}, moy_ue={self.moy_ue})"""
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.ue_id:
|
if self.ue_id:
|
||||||
# Note: si l'objet vient d'être créé, ue_id peut exister mais pas ue !
|
# Note: si l'objet vient d'être créé, ue_id peut exister mais pas ue !
|
||||||
return f"""décision sur UE {self.ue.acronyme if self.ue else self.ue_id}: {self.code}"""
|
return f"""décision sur UE {self.ue.acronyme if self.ue else self.ue_id
|
||||||
return f"""décision sur semestre {self.formsemestre.titre_mois()} du {self.event_date.strftime("%d/%m/%Y")}"""
|
}: {self.code}"""
|
||||||
|
return f"""décision sur semestre {self.formsemestre.titre_mois()} du {
|
||||||
|
self.event_date.strftime("%d/%m/%Y")}"""
|
||||||
|
|
||||||
def to_dict(self) -> dict:
|
def to_dict(self) -> dict:
|
||||||
"as a dict"
|
"as a dict"
|
||||||
@ -73,6 +76,20 @@ class ScolarFormSemestreValidation(db.Model):
|
|||||||
d.pop("_sa_instance_state", None)
|
d.pop("_sa_instance_state", None)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def html(self) -> str:
|
||||||
|
"Affichage html"
|
||||||
|
if self.ue_id is not None:
|
||||||
|
return f"""Validation de l'UE {self.ue.acronyme}
|
||||||
|
(<b>{self.code}</b>
|
||||||
|
le {self.event_date.strftime("%d/%m/%Y")} à {self.event_date.strftime("%Hh%M")})
|
||||||
|
"""
|
||||||
|
else:
|
||||||
|
return f"""Validation du semestre S{
|
||||||
|
self.formsemestre.semestre_id if self.formsemestre else "?"}
|
||||||
|
(<b>{self.code}</b>
|
||||||
|
le {self.event_date.strftime("%d/%m/%Y")} à {self.event_date.strftime("%Hh%M")})
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class ScolarAutorisationInscription(db.Model):
|
class ScolarAutorisationInscription(db.Model):
|
||||||
"""Autorisation d'inscription dans un semestre"""
|
"""Autorisation d'inscription dans un semestre"""
|
||||||
@ -93,6 +110,7 @@ class ScolarAutorisationInscription(db.Model):
|
|||||||
db.Integer,
|
db.Integer,
|
||||||
db.ForeignKey("notes_formsemestre.id"),
|
db.ForeignKey("notes_formsemestre.id"),
|
||||||
)
|
)
|
||||||
|
origin_formsemestre = db.relationship("FormSemestre", lazy="select", uselist=False)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"""{self.__class__.__name__}(id={self.id}, etudid={
|
return f"""{self.__class__.__name__}(id={self.id}, etudid={
|
||||||
@ -104,6 +122,15 @@ class ScolarAutorisationInscription(db.Model):
|
|||||||
d.pop("_sa_instance_state", None)
|
d.pop("_sa_instance_state", None)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def html(self) -> str:
|
||||||
|
"Affichage html"
|
||||||
|
return f"""Autorisation de passage vers <b>S{self.semestre_id}</b> émise par
|
||||||
|
{self.origin_formsemestre.html_link_status()
|
||||||
|
if self.origin_formsemestre
|
||||||
|
else "-"}
|
||||||
|
le {self.date.strftime("%d/%m/%Y")} à {self.date.strftime("%Hh%M")}
|
||||||
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def autorise_etud(
|
def autorise_etud(
|
||||||
cls,
|
cls,
|
||||||
|
@ -315,6 +315,19 @@ def invalidate_formsemestre( # was inval_cache(formsemestre_id=None, pdfonly=Fa
|
|||||||
SemBulletinsPDFCache.invalidate_sems(formsemestre_ids)
|
SemBulletinsPDFCache.invalidate_sems(formsemestre_ids)
|
||||||
|
|
||||||
|
|
||||||
|
def invalidate_formsemestre_etud(etud: "Identite"):
|
||||||
|
"""Invalide tous les formsemestres auxquels l'étudiant est inscrit"""
|
||||||
|
from app.models import FormSemestre, FormSemestreInscription
|
||||||
|
|
||||||
|
inscriptions = (
|
||||||
|
FormSemestreInscription.query.filter_by(etudid=etud.id)
|
||||||
|
.join(FormSemestre)
|
||||||
|
.filter_by(dept_id=g.scodoc_dept_id)
|
||||||
|
)
|
||||||
|
for inscription in inscriptions:
|
||||||
|
invalidate_formsemestre(inscription.formsemestre_id)
|
||||||
|
|
||||||
|
|
||||||
class DeferredSemCacheManager:
|
class DeferredSemCacheManager:
|
||||||
"""Contexte pour effectuer des opérations indépendantes dans la
|
"""Contexte pour effectuer des opérations indépendantes dans la
|
||||||
même requete qui invalident le cache. Par exemple, quand on inscrit
|
même requete qui invalident le cache. Par exemple, quand on inscrit
|
||||||
|
@ -757,7 +757,7 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""): # was ue_list
|
|||||||
],
|
],
|
||||||
page_title=f"Programme {formation.acronyme} v{formation.version}",
|
page_title=f"Programme {formation.acronyme} v{formation.version}",
|
||||||
),
|
),
|
||||||
f"""<h2>{formation.to_html()} {lockicon}
|
f"""<h2>{formation.html()} {lockicon}
|
||||||
</h2>
|
</h2>
|
||||||
""",
|
""",
|
||||||
]
|
]
|
||||||
@ -1010,12 +1010,7 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
|||||||
<p><ul>"""
|
<p><ul>"""
|
||||||
)
|
)
|
||||||
for formsemestre in formsemestres:
|
for formsemestre in formsemestres:
|
||||||
H.append(
|
H.append(f"""<li>{formsemestre.html_link_status()}""")
|
||||||
f"""<li><a class="stdlink" href="{
|
|
||||||
url_for("notes.formsemestre_status", scodoc_dept=g.scodoc_dept,
|
|
||||||
formsemestre_id=formsemestre.id
|
|
||||||
)}">{formsemestre.titre_mois()}</a>"""
|
|
||||||
)
|
|
||||||
if not formsemestre.etat:
|
if not formsemestre.etat:
|
||||||
H.append(" [verrouillé]")
|
H.append(" [verrouillé]")
|
||||||
else:
|
else:
|
||||||
|
@ -142,7 +142,7 @@ def formsemestre_recapcomplet(
|
|||||||
H.append(
|
H.append(
|
||||||
'<select name="tabformat" onchange="document.f.submit()" class="noprint">'
|
'<select name="tabformat" onchange="document.f.submit()" class="noprint">'
|
||||||
)
|
)
|
||||||
for (fmt, label) in (
|
for fmt, label in (
|
||||||
("html", "Tableau"),
|
("html", "Tableau"),
|
||||||
("evals", "Avec toutes les évaluations"),
|
("evals", "Avec toutes les évaluations"),
|
||||||
("xlsx", "Excel (non formaté)"),
|
("xlsx", "Excel (non formaté)"),
|
||||||
@ -186,7 +186,7 @@ def formsemestre_recapcomplet(
|
|||||||
</li>
|
</li>
|
||||||
<li><a class="stdlink" href="{url_for('notes.formsemestre_jury_but_erase',
|
<li><a class="stdlink" href="{url_for('notes.formsemestre_jury_but_erase',
|
||||||
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id, only_one_sem=1)
|
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id, only_one_sem=1)
|
||||||
}">Effacer <em>toutes</em> les décisions de jury (BUT) du semestre</a>
|
}">Effacer <em>toutes</em> les décisions de jury BUT issues de ce semestre</a>
|
||||||
</li>
|
</li>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@ -145,12 +145,7 @@ class SemSet(dict):
|
|||||||
|
|
||||||
# Construction du ou des lien(s) vers le semestre
|
# Construction du ou des lien(s) vers le semestre
|
||||||
self["semlinks"] = [
|
self["semlinks"] = [
|
||||||
f"""<a class="stdlink" href="{
|
formsemestre.html_link_status() for formsemestre in self.formsemestres
|
||||||
url_for("notes.formsemestre_status", scodoc_dept=g.scodoc_dept,
|
|
||||||
formsemestre_id=formsemestre.id)
|
|
||||||
}">{formsemestre.titre_annee()}</a>
|
|
||||||
"""
|
|
||||||
for formsemestre in self.formsemestres
|
|
||||||
]
|
]
|
||||||
|
|
||||||
self["semtitles_str"] = "<br>".join(self["semlinks"])
|
self["semtitles_str"] = "<br>".join(self["semlinks"])
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
padding-bottom: 0px;
|
padding-bottom: 0px;
|
||||||
padding-left: 16px;
|
padding-left: 16px;
|
||||||
padding-right: 0px;
|
padding-right: 0px;
|
||||||
|
|
||||||
background: #FFF;
|
background: #FFF;
|
||||||
border: 1px solid #aaa;
|
border: 1px solid #aaa;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@ -40,3 +39,9 @@ div.code_rcue {
|
|||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.code_jury {
|
||||||
|
padding-right: 4px;
|
||||||
|
padding-left: 4px;
|
||||||
|
width: 64px;
|
||||||
|
}
|
@ -15,11 +15,9 @@
|
|||||||
<input type="hidden" name="etudid" value="{{etud.id}}"></input>
|
<input type="hidden" name="etudid" value="{{etud.id}}"></input>
|
||||||
<input type="hidden" name="format" value="{{format}}"></input>
|
<input type="hidden" name="format" value="{{format}}"></input>
|
||||||
Bulletin
|
Bulletin
|
||||||
<span class="bull_liensemestre"><a href="{{
|
<span class="bull_liensemestre">
|
||||||
url_for("notes.formsemestre_status",
|
{{formsemestre.html_link_status() | safe}}
|
||||||
scodoc_dept=g.scodoc_dept,
|
</span>
|
||||||
formsemestre_id=formsemestre.id)}}">{{formsemestre.titre_mois()
|
|
||||||
}}</a></span>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<em>établi le {{time.strftime("%d/%m/%Y à %Hh%M")}} (notes sur 20)</em>
|
<em>établi le {{time.strftime("%d/%m/%Y à %Hh%M")}} (notes sur 20)</em>
|
||||||
|
@ -15,14 +15,16 @@
|
|||||||
<div class="code_jury">{{validation.code}}</div>
|
<div class="code_jury">{{validation.code}}</div>
|
||||||
<div class="scoplement">
|
<div class="scoplement">
|
||||||
<div>{{validation.ue1.acronyme}} - {{validation.ue2.acronyme}}</div>
|
<div>{{validation.ue1.acronyme}} - {{validation.ue2.acronyme}}</div>
|
||||||
<div>Jury de {{validation.formsemestre.titre_annee()}}</div>
|
<div>Jury de {{validation.formsemestre.titre_annee() if validation.formsemestre else "-"}}</div>
|
||||||
<div>enregistré le {{
|
<div>enregistré le {{
|
||||||
validation.date.strftime("%d/%m/%Y à %H:%M")
|
validation.date.strftime("%d/%m/%Y à %H:%M")
|
||||||
}}</div>
|
}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
-
|
<div class="code_rcue">
|
||||||
|
<div class="code_jury">-</div>
|
||||||
|
</div>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{% block app_content %}
|
{% block app_content %}
|
||||||
<h2>{{formation.to_html()}}</h2>
|
<h2>{{formation.html()}}</h2>
|
||||||
|
|
||||||
{# Liens vers les différents parcours #}
|
{# Liens vers les différents parcours #}
|
||||||
<div class="les_parcours">
|
<div class="les_parcours">
|
||||||
@ -127,7 +127,7 @@ Choisissez un parcours...
|
|||||||
d'associer à chaque semestre d'un niveau de compétence une UE de la formation
|
d'associer à chaque semestre d'un niveau de compétence une UE de la formation
|
||||||
<a class="stdlink"
|
<a class="stdlink"
|
||||||
href="{{url_for('notes.ue_table', scodoc_dept=g.scodoc_dept, formation_id=formation.id )
|
href="{{url_for('notes.ue_table', scodoc_dept=g.scodoc_dept, formation_id=formation.id )
|
||||||
}}">{{formation.to_html()}}
|
}}">{{formation.html()}}
|
||||||
</a>.</p>
|
</a>.</p>
|
||||||
|
|
||||||
<p>Le symbole <span class="parc">TC</span> désigne un niveau du tronc commun
|
<p>Le symbole <span class="parc">TC</span> désigne un niveau du tronc commun
|
||||||
|
41
app/templates/jury/erase_decisions_annee_formation.j2
Normal file
41
app/templates/jury/erase_decisions_annee_formation.j2
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{% extends 'base.j2' %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
|
||||||
|
{% if not validations %}
|
||||||
|
<p>Aucune validation de jury enregistrée pour <b>{{etud.nom_disp()}}</b> sur
|
||||||
|
<b>l'année {{annee}}</b>
|
||||||
|
de la formation <em>{{ formation.html() }}</em>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div style="margin-top: 16px;">
|
||||||
|
<a class="stdlink" href="{{ cancel_url }}">continuer</a>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
<h2>Effacer les décisions de jury pour l'année {{annee}} de {{etud.nom_disp()}} ?</h2>
|
||||||
|
|
||||||
|
<p class="help">Affectera toutes les décisions concernant l'année {{annee}} de la formation,
|
||||||
|
quelle que soit leur origine.</p>
|
||||||
|
|
||||||
|
<p>Les décisions concernées sont:</p>
|
||||||
|
<ul>
|
||||||
|
{% for validation in validations %}
|
||||||
|
<li>{{ validation.html() | safe}}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<div style="margin-top: 16px;">
|
||||||
|
<form method="post">
|
||||||
|
<input type="submit" value="Effacer ces décisions" />
|
||||||
|
{% if cancel_url %}
|
||||||
|
<input type="button" value="Annuler" style="margin-left: 16px;"
|
||||||
|
onClick="document.location='{{ cancel_url }}';" />
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -48,9 +48,9 @@ from app.but.forms import jury_but_forms
|
|||||||
from app.but import jury_but_pv
|
from app.but import jury_but_pv
|
||||||
from app.but import jury_but_view
|
from app.but import jury_but_view
|
||||||
|
|
||||||
from app.comp import res_sem
|
from app.comp import jury, res_sem
|
||||||
from app.comp.res_compat import NotesTableCompat
|
from app.comp.res_compat import NotesTableCompat
|
||||||
from app.models import ScolarAutorisationInscription, ScolarNews, Scolog
|
from app.models import Formation, ScolarAutorisationInscription, ScolarNews, Scolog
|
||||||
from app.models.but_refcomp import ApcNiveau, ApcParcours
|
from app.models.but_refcomp import ApcNiveau, ApcParcours
|
||||||
from app.models.config import ScoDocSiteConfig
|
from app.models.config import ScoDocSiteConfig
|
||||||
from app.models.etudiants import Identite
|
from app.models.etudiants import Identite
|
||||||
@ -2494,7 +2494,19 @@ def formsemestre_validation_but(
|
|||||||
erase_span = f"""<a href="{
|
erase_span = f"""<a href="{
|
||||||
url_for("notes.formsemestre_jury_but_erase",
|
url_for("notes.formsemestre_jury_but_erase",
|
||||||
scodoc_dept=g.scodoc_dept, formsemestre_id=deca.formsemestre_id,
|
scodoc_dept=g.scodoc_dept, formsemestre_id=deca.formsemestre_id,
|
||||||
etudid=deca.etud.id)}" class="stdlink">effacer décisions</a>"""
|
etudid=deca.etud.id)}" class="stdlink"
|
||||||
|
title="efface décisions issues des jurys de cette année"
|
||||||
|
>effacer décisions</a>
|
||||||
|
|
||||||
|
<a style="margin-left: 16px;" class="stdlink"
|
||||||
|
href="{
|
||||||
|
url_for("notes.erase_decisions_annee_formation",
|
||||||
|
scodoc_dept=g.scodoc_dept, formation_id=deca.formsemestre.formation.id,
|
||||||
|
etudid=deca.etud.id, annee=deca.annee_but)}"
|
||||||
|
title="efface toutes décisions concernant le BUT{deca.annee_but}
|
||||||
|
de cet étudiant (même extérieures ou issues d'un redoublement)"
|
||||||
|
>effacer toutes ses décisions de BUT{deca.annee_but}</a>
|
||||||
|
"""
|
||||||
H.append(
|
H.append(
|
||||||
f"""<div class="but_settings">
|
f"""<div class="but_settings">
|
||||||
<input type="checkbox" onchange="enable_manual_codes(this)">
|
<input type="checkbox" onchange="enable_manual_codes(this)">
|
||||||
@ -2815,15 +2827,15 @@ def formsemestre_saisie_jury(formsemestre_id: int, selected_etudid: int = None):
|
|||||||
)
|
)
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
def formsemestre_jury_but_erase(
|
def formsemestre_jury_but_erase(formsemestre_id: int, etudid: int = None):
|
||||||
formsemestre_id: int, etudid: int = None, only_one_sem=False
|
|
||||||
):
|
|
||||||
"""Supprime la décision de jury BUT pour cette année.
|
"""Supprime la décision de jury BUT pour cette année.
|
||||||
Si only_one_sem, n'efface que pour le formsemestre indiqué, pas les deux de l'année.
|
|
||||||
Si l'étudiant n'est pas spécifié, efface les décisions de tous les inscrits.
|
Si l'étudiant n'est pas spécifié, efface les décisions de tous les inscrits.
|
||||||
|
Si only_one_sem, n'efface que pour le formsemestre indiqué, pas les deux de l'année.
|
||||||
"""
|
"""
|
||||||
only_one_sem = int(request.args.get("only_one_sem") or False)
|
only_one_sem = int(request.args.get("only_one_sem") or False)
|
||||||
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
formsemestre: FormSemestre = FormSemestre.query.filter_by(
|
||||||
|
id=formsemestre_id, dept_id=g.scodoc_dept_id
|
||||||
|
).first_or_404()
|
||||||
if not formsemestre.can_edit_jury():
|
if not formsemestre.can_edit_jury():
|
||||||
raise ScoPermissionDenied(
|
raise ScoPermissionDenied(
|
||||||
dest_url=url_for(
|
dest_url=url_for(
|
||||||
@ -2881,14 +2893,53 @@ def formsemestre_jury_but_erase(
|
|||||||
if only_one_sem
|
if only_one_sem
|
||||||
else """Les validations de toutes les UE, RCUE (compétences) et année
|
else """Les validations de toutes les UE, RCUE (compétences) et année
|
||||||
issues de cette année scolaire seront effacées.
|
issues de cette année scolaire seront effacées.
|
||||||
Les décisions des années scolaires précédentes ne seront pas modifiées.
|
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
+ """<div class="warning">Cette opération est irréversible !</div>""",
|
+ """
|
||||||
|
<p>Les décisions des années scolaires précédentes ne seront pas modifiées.</p>
|
||||||
|
<div class="warning">Cette opération est irréversible !</div>
|
||||||
|
""",
|
||||||
cancel_url=dest_url,
|
cancel_url=dest_url,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route(
|
||||||
|
"/erase_decisions_annee_formation/<int:etudid>/<int:formation_id>/<int:annee>",
|
||||||
|
methods=["GET", "POST"],
|
||||||
|
)
|
||||||
|
@scodoc
|
||||||
|
@permission_required(Permission.ScoEtudInscrit)
|
||||||
|
def erase_decisions_annee_formation(etudid: int, formation_id: int, annee: int):
|
||||||
|
"""Efface toute les décisions d'une année pour cet étudiant"""
|
||||||
|
etud: Identite = Identite.query.get_or_404(etudid)
|
||||||
|
formation: Formation = Formation.query.filter_by(
|
||||||
|
id=formation_id, dept_id=g.scodoc_dept_id
|
||||||
|
).first_or_404()
|
||||||
|
if request.method == "POST":
|
||||||
|
jury.erase_decisions_annee_formation(etud, formation, annee, delete=True)
|
||||||
|
flash("Décisions de jury effacées")
|
||||||
|
return redirect(
|
||||||
|
url_for(
|
||||||
|
"scolar.ficheEtud",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
etudid=etud.id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
validations = jury.erase_decisions_annee_formation(etud, formation, annee)
|
||||||
|
return render_template(
|
||||||
|
"jury/erase_decisions_annee_formation.j2",
|
||||||
|
annee=annee,
|
||||||
|
cancel_url=url_for(
|
||||||
|
"scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id
|
||||||
|
),
|
||||||
|
etud=etud,
|
||||||
|
formation=formation,
|
||||||
|
validations=validations,
|
||||||
|
sco=ScoData(),
|
||||||
|
title=f"Effacer décisions de jury {etud.nom} - année {annee}",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/formsemestre_lettres_individuelles",
|
"/formsemestre_lettres_individuelles",
|
||||||
sco_pv_forms.formsemestre_lettres_individuelles,
|
sco_pv_forms.formsemestre_lettres_individuelles,
|
||||||
|
Loading…
Reference in New Issue
Block a user