forked from ScoDoc/ScoDoc
Bloque saisie jury si évaluation à paraitre. Modif icon warning. Closes #858
This commit is contained in:
parent
1c01d987be
commit
c0a965d774
@ -77,7 +77,7 @@ from app.models.but_refcomp import (
|
|||||||
ApcNiveau,
|
ApcNiveau,
|
||||||
ApcParcours,
|
ApcParcours,
|
||||||
)
|
)
|
||||||
from app.models import Scolog, ScolarAutorisationInscription
|
from app.models import Evaluation, Scolog, ScolarAutorisationInscription
|
||||||
from app.models.but_validations import (
|
from app.models.but_validations import (
|
||||||
ApcValidationAnnee,
|
ApcValidationAnnee,
|
||||||
ApcValidationRCUE,
|
ApcValidationRCUE,
|
||||||
@ -260,11 +260,11 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
else []
|
else []
|
||||||
)
|
)
|
||||||
# ---- Niveaux et RCUEs
|
# ---- Niveaux et RCUEs
|
||||||
niveaux_by_parcours = (
|
niveaux_by_parcours = formsemestre.formation.referentiel_competence.get_niveaux_by_parcours(
|
||||||
formsemestre.formation.referentiel_competence.get_niveaux_by_parcours(
|
self.annee_but, [self.parcour] if self.parcour else None
|
||||||
self.annee_but, [self.parcour] if self.parcour else None
|
)[
|
||||||
)[1]
|
1
|
||||||
)
|
]
|
||||||
self.niveaux_competences = niveaux_by_parcours["TC"] + (
|
self.niveaux_competences = niveaux_by_parcours["TC"] + (
|
||||||
niveaux_by_parcours[self.parcour.id] if self.parcour else []
|
niveaux_by_parcours[self.parcour.id] if self.parcour else []
|
||||||
)
|
)
|
||||||
@ -358,13 +358,17 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
# self.codes = [] # pas de décision annuelle sur semestres impairs
|
# self.codes = [] # pas de décision annuelle sur semestres impairs
|
||||||
elif self.inscription_etat != scu.INSCRIT:
|
elif self.inscription_etat != scu.INSCRIT:
|
||||||
self.codes = [
|
self.codes = [
|
||||||
sco_codes.DEM
|
(
|
||||||
if self.inscription_etat == scu.DEMISSION
|
sco_codes.DEM
|
||||||
else sco_codes.DEF,
|
if self.inscription_etat == scu.DEMISSION
|
||||||
|
else sco_codes.DEF
|
||||||
|
),
|
||||||
# propose aussi d'autres codes, au cas où...
|
# propose aussi d'autres codes, au cas où...
|
||||||
sco_codes.DEM
|
(
|
||||||
if self.inscription_etat != scu.DEMISSION
|
sco_codes.DEM
|
||||||
else sco_codes.DEF,
|
if self.inscription_etat != scu.DEMISSION
|
||||||
|
else sco_codes.DEF
|
||||||
|
),
|
||||||
sco_codes.ABAN,
|
sco_codes.ABAN,
|
||||||
sco_codes.ABL,
|
sco_codes.ABL,
|
||||||
sco_codes.EXCLU,
|
sco_codes.EXCLU,
|
||||||
@ -595,11 +599,9 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
# Ordonne par numéro d'UE
|
# Ordonne par numéro d'UE
|
||||||
niv_rcue = sorted(
|
niv_rcue = sorted(
|
||||||
self.rcue_by_niveau.items(),
|
self.rcue_by_niveau.items(),
|
||||||
key=lambda x: x[1].ue_1.numero
|
key=lambda x: (
|
||||||
if x[1].ue_1
|
x[1].ue_1.numero if x[1].ue_1 else x[1].ue_2.numero if x[1].ue_2 else 0
|
||||||
else x[1].ue_2.numero
|
),
|
||||||
if x[1].ue_2
|
|
||||||
else 0,
|
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
niveau_id: DecisionsProposeesRCUE(self, rcue, self.inscription_etat)
|
niveau_id: DecisionsProposeesRCUE(self, rcue, self.inscription_etat)
|
||||||
@ -816,9 +818,15 @@ class DecisionsProposeesAnnee(DecisionsProposees):
|
|||||||
Return: True si au moins un code modifié et enregistré.
|
Return: True si au moins un code modifié et enregistré.
|
||||||
"""
|
"""
|
||||||
modif = False
|
modif = False
|
||||||
# Vérification notes en attente dans formsemestre origine
|
if only_validantes:
|
||||||
if only_validantes and self.has_notes_en_attente():
|
if self.has_notes_en_attente():
|
||||||
return False
|
# notes en attente dans formsemestre origine
|
||||||
|
return False
|
||||||
|
if Evaluation.get_evaluations_blocked_for_etud(
|
||||||
|
self.formsemestre, self.etud
|
||||||
|
):
|
||||||
|
# évaluation(s) qui seront débloquées dans le futur
|
||||||
|
return False
|
||||||
|
|
||||||
# Toujours valider dans l'ordre UE, RCUE, Année
|
# Toujours valider dans l'ordre UE, RCUE, Année
|
||||||
annee_scolaire = self.formsemestre.annee_scolaire()
|
annee_scolaire = self.formsemestre.annee_scolaire()
|
||||||
@ -1488,9 +1496,11 @@ class DecisionsProposeesUE(DecisionsProposees):
|
|||||||
self.validation = None # cache toute validation
|
self.validation = None # cache toute validation
|
||||||
self.explanation = "non inscrit (dem. ou déf.)"
|
self.explanation = "non inscrit (dem. ou déf.)"
|
||||||
self.codes = [
|
self.codes = [
|
||||||
sco_codes.DEM
|
(
|
||||||
if res.get_etud_etat(etud.id) == scu.DEMISSION
|
sco_codes.DEM
|
||||||
else sco_codes.DEF
|
if res.get_etud_etat(etud.id) == scu.DEMISSION
|
||||||
|
else sco_codes.DEF
|
||||||
|
)
|
||||||
]
|
]
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -488,6 +488,29 @@ class Evaluation(models.ScoDocModel):
|
|||||||
"""
|
"""
|
||||||
return NotesNotes.query.filter_by(etudid=etud.id, evaluation_id=self.id).first()
|
return NotesNotes.query.filter_by(etudid=etud.id, evaluation_id=self.id).first()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_evaluations_blocked_for_etud(
|
||||||
|
cls, formsemestre, etud: Identite
|
||||||
|
) -> list["Evaluation"]:
|
||||||
|
"""Liste des évaluations de ce semestre avec note pour cet étudiant et date blocage
|
||||||
|
et date blocage < FOREVER.
|
||||||
|
Si non vide, une note apparaitra dans le futur pour cet étudiant: il faut
|
||||||
|
donc interdire la saisie du jury.
|
||||||
|
"""
|
||||||
|
now = datetime.datetime.now(scu.TIME_ZONE)
|
||||||
|
return (
|
||||||
|
Evaluation.query.filter(
|
||||||
|
Evaluation.blocked_until != None, # pylint: disable=C0121
|
||||||
|
Evaluation.blocked_until >= now,
|
||||||
|
)
|
||||||
|
.join(ModuleImpl)
|
||||||
|
.filter_by(formsemestre_id=formsemestre.id)
|
||||||
|
.join(ModuleImplInscription)
|
||||||
|
.filter_by(etudid=etud.id)
|
||||||
|
.join(NotesNotes)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class EvaluationUEPoids(db.Model):
|
class EvaluationUEPoids(db.Model):
|
||||||
"""Poids des évaluations (BUT)
|
"""Poids des évaluations (BUT)
|
||||||
@ -657,3 +680,6 @@ def _moduleimpl_evaluation_insert_before(
|
|||||||
db.session.add(e)
|
db.session.add(e)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
|
|
||||||
|
from app.models.moduleimpls import ModuleImpl, ModuleImplInscription
|
||||||
|
@ -34,7 +34,7 @@ from flask import url_for, flash, g, request
|
|||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
|
||||||
from app.models.etudiants import Identite
|
from app.models import Identite, Evaluation
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app import db, log
|
from app import db, log
|
||||||
@ -232,7 +232,9 @@ def formsemestre_validation_etud_form(
|
|||||||
H.append(
|
H.append(
|
||||||
tf_error_message(
|
tf_error_message(
|
||||||
f"""Impossible de statuer sur cet étudiant: il a des notes en
|
f"""Impossible de statuer sur cet étudiant: il a des notes en
|
||||||
attente dans des évaluations de ce semestre (voir <a href="{
|
attente dans des évaluations de ce semestre (voir
|
||||||
|
<a class="stdlink"
|
||||||
|
href="{
|
||||||
url_for( "notes.formsemestre_status",
|
url_for( "notes.formsemestre_status",
|
||||||
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id)
|
scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id)
|
||||||
}">tableau de bord</a>)
|
}">tableau de bord</a>)
|
||||||
@ -241,6 +243,26 @@ def formsemestre_validation_etud_form(
|
|||||||
)
|
)
|
||||||
return "\n".join(H + footer)
|
return "\n".join(H + footer)
|
||||||
|
|
||||||
|
evaluations_a_debloquer = Evaluation.get_evaluations_blocked_for_etud(
|
||||||
|
formsemestre, etud
|
||||||
|
)
|
||||||
|
if evaluations_a_debloquer:
|
||||||
|
links_evals = [
|
||||||
|
f"""<a class="stdlink" href="{url_for(
|
||||||
|
'notes.evaluation_listenotes', scodoc_dept=g.scodoc_dept, evaluation_id=e.id
|
||||||
|
)}">{e.description} en {e.moduleimpl.module.code}</a>"""
|
||||||
|
for e in evaluations_a_debloquer
|
||||||
|
]
|
||||||
|
H.append(
|
||||||
|
tf_error_message(
|
||||||
|
f"""Impossible de statuer sur cet étudiant:
|
||||||
|
il a des notes dans des évaluations qui seront débloquées plus tard:
|
||||||
|
voir {", ".join(links_evals)}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return "\n".join(H + footer)
|
||||||
|
|
||||||
# Infos si pas de semestre précédent
|
# Infos si pas de semestre précédent
|
||||||
if not Se.prev:
|
if not Se.prev:
|
||||||
if Se.sem["semestre_id"] == 1:
|
if Se.sem["semestre_id"] == 1:
|
||||||
|
@ -3391,14 +3391,24 @@ li.tf-msg {
|
|||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.warning {
|
.warning, .warning-bloquant {
|
||||||
font-weight: bold;
|
|
||||||
color: red;
|
color: red;
|
||||||
|
margin-left: 16px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
min-width: var(--sco-content-min-width);
|
||||||
|
max-width: var(--sco-content-max-width);
|
||||||
}
|
}
|
||||||
|
|
||||||
.warning::before {
|
.warning::before {
|
||||||
content: url(/ScoDoc/static/icons/warning_img.png);
|
content:"";
|
||||||
vertical-align: -80%;
|
margin-right: 8px;
|
||||||
|
height:32px;
|
||||||
|
width: 32px;
|
||||||
|
background-size: 32px 32px;
|
||||||
|
background-image: url(/ScoDoc/static/icons/warning_std.svg);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: -40%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.warning-light {
|
.warning-light {
|
||||||
@ -3411,6 +3421,19 @@ li.tf-msg {
|
|||||||
/* EMO_WARNING, "⚠️" */
|
/* EMO_WARNING, "⚠️" */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.warning-bloquant::before {
|
||||||
|
content:"";
|
||||||
|
margin-right: 8px;
|
||||||
|
height:32px;
|
||||||
|
width: 32px;
|
||||||
|
background-size: 32px 32px;
|
||||||
|
background-image: url(/ScoDoc/static/icons/warning_bloquant.svg);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: -40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
p.error {
|
p.error {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: red;
|
color: red;
|
||||||
|
1
app/static/icons/warning_bloquant.svg
Normal file
1
app/static/icons/warning_bloquant.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 8.5 KiB |
1
app/static/icons/warning_std.svg
Normal file
1
app/static/icons/warning_std.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg id="Capa_1" enable-background="new 0 0 512 512" height="512" viewBox="0 0 512 512" width="512" xmlns="http://www.w3.org/2000/svg"><path d="m208.587 54.407-201.17 348.437c-21.073 36.499 5.268 82.122 47.413 82.122h402.34c42.145 0 68.486-45.624 47.413-82.122l-201.17-348.437c-21.072-36.498-73.754-36.498-94.826 0z" fill="#da4a54"/><path d="m54.83 443.76c-6.802 0-10.267-4.242-11.727-6.771s-3.401-7.65 0-13.542l201.17-348.436c3.401-5.891 8.807-6.771 11.727-6.771s8.326.88 11.727 6.771l201.17 348.436c3.401 5.891 1.46 11.013 0 13.541-1.46 2.529-4.925 6.771-11.727 6.771h-402.34z" fill="#f6e266"/><g fill="#544f57"><path d="m256 327.138c-14.379 0-26.036-11.657-26.036-26.036v-119.216c0-14.379 11.657-26.036 26.036-26.036 14.379 0 26.036 11.657 26.036 26.036v119.217c0 14.379-11.657 26.035-26.036 26.035z"/><circle cx="256" cy="381.152" r="26.036"/></g></svg>
|
After Width: | Height: | Size: 857 B |
@ -2408,6 +2408,12 @@ def formsemestre_validation_but(
|
|||||||
)
|
)
|
||||||
|
|
||||||
deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
|
deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
|
||||||
|
has_notes_en_attente = deca.has_notes_en_attente()
|
||||||
|
evaluations_a_debloquer = Evaluation.get_evaluations_blocked_for_etud(
|
||||||
|
formsemestre, etud
|
||||||
|
)
|
||||||
|
if has_notes_en_attente or evaluations_a_debloquer:
|
||||||
|
read_only = True
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
if not read_only:
|
if not read_only:
|
||||||
deca.record_form(request.form)
|
deca.record_form(request.form)
|
||||||
@ -2452,9 +2458,21 @@ def formsemestre_validation_but(
|
|||||||
etat_ins = scu.ETATS_INSCRIPTION.get(inscription.etat, "inconnu?")
|
etat_ins = scu.ETATS_INSCRIPTION.get(inscription.etat, "inconnu?")
|
||||||
warning += f"""<div class="warning">{etat_ins} en S{deca.formsemestre_pair.semestre_id}</div>"""
|
warning += f"""<div class="warning">{etat_ins} en S{deca.formsemestre_pair.semestre_id}</div>"""
|
||||||
|
|
||||||
if deca.has_notes_en_attente():
|
if has_notes_en_attente:
|
||||||
warning += f"""<div class="warning">{etud.nomprenom} a des notes en ATTente.
|
warning += f"""<div class="warning-bloquant">{etud.nomprenom} a des notes en ATTente.
|
||||||
Vous devriez régler cela avant de statuer en jury !</div>"""
|
Vous devez régler cela avant de statuer en jury !</div>"""
|
||||||
|
if evaluations_a_debloquer:
|
||||||
|
links_evals = [
|
||||||
|
f"""<a class="stdlink" href="{url_for(
|
||||||
|
'notes.evaluation_listenotes', scodoc_dept=g.scodoc_dept, evaluation_id=e.id
|
||||||
|
)}">{e.description} en {e.moduleimpl.module.code}</a>"""
|
||||||
|
for e in evaluations_a_debloquer
|
||||||
|
]
|
||||||
|
warning += f"""<div class="warning-bloquant">Impossible de statuer sur cet étudiant:
|
||||||
|
il a des notes dans des évaluations qui seront débloquées plus tard:
|
||||||
|
voir {", ".join(links_evals)}
|
||||||
|
"""
|
||||||
|
|
||||||
H.append(
|
H.append(
|
||||||
f"""
|
f"""
|
||||||
<div>
|
<div>
|
||||||
|
Loading…
Reference in New Issue
Block a user