Import utilisateurs: strip champs

This commit is contained in:
Emmanuel Viennet 2024-06-14 20:15:20 +02:00
parent c94fea9f9e
commit 07c2f00277
10 changed files with 244 additions and 198 deletions

View File

@ -973,7 +973,7 @@ class FormSemestre(models.ScoDocModel):
def etudids_actifs(self) -> tuple[list[int], set[int]]:
"""Liste les etudids inscrits (incluant DEM et DEF),
qui ser al'index des dataframes de notes
qui sera l'index des dataframes de notes
et donne l'ensemble des inscrits non DEM ni DEF.
"""
return [inscr.etudid for inscr in self.inscriptions], {

View File

@ -140,7 +140,7 @@ def read_users_excel_file(datafile, titles=TITLES) -> list[dict]:
for line in data[1:]:
d = {}
for i, field in enumerate(xls_titles):
d[field] = line[i]
d[field] = (line[i] or "").strip()
users.append(d)
return users

View File

@ -70,13 +70,21 @@ def moduleimpl_evaluation_menu(evaluation: Evaluation, nbnotes: int = 0) -> str:
menu_eval = [
{
"title": "Saisir notes",
"title": "Saisir les notes",
"endpoint": "notes.saisie_notes",
"args": {
"evaluation_id": evaluation_id,
},
"enabled": can_edit_notes_ens,
},
{
"title": "Saisir par fichier tableur",
"id": "menu_saisie_tableur",
"endpoint": "notes.saisie_notes_tableur",
"args": {
"evaluation_id": evaluation.id,
},
},
{
"title": "Modifier évaluation",
"endpoint": "notes.evaluation_edit",

View File

@ -29,12 +29,15 @@
Formulaire revu en juillet 2016
"""
import html
import time
import psycopg2
import flask
from flask import g, url_for, request
from flask_login import current_user
from flask_sqlalchemy.query import Query
import psycopg2
from app import db, log
from app.auth.models import User
@ -75,8 +78,6 @@ import app.scodoc.sco_utils as scu
from app.scodoc.sco_utils import json_error
from app.scodoc.sco_utils import ModuleType
from flask_sqlalchemy.query import Query
def convert_note_from_string(
note: str,
@ -115,7 +116,7 @@ def convert_note_from_string(
return note_value, invalid
def _displayNote(val):
def _display_note(val):
"""Convert note from DB to viewable string.
Utilisé seulement pour I/O vers formulaires (sans perte de precision)
(Utiliser fmt_note pour les affichages)
@ -272,7 +273,7 @@ def do_evaluation_upload_xls():
diag.append("Notes invalides pour: " + ", ".join(etudsnames))
raise InvalidNoteValue()
else:
etudids_changed, nb_suppress, etudids_with_decisions = notes_add(
etudids_changed, nb_suppress, etudids_with_decisions, messages = notes_add(
current_user, evaluation_id, valid_notes, comment
)
# news
@ -292,9 +293,19 @@ def do_evaluation_upload_xls():
max_frequency=30 * 60, # 30 minutes
)
msg = f"""<p>{len(etudids_changed)} notes changées ({len(withoutnotes)} sans notes, {
len(absents)} absents, {nb_suppress} note supprimées)
msg = f"""<p>
{len(etudids_changed)} notes changées ({len(withoutnotes)} sans notes,
{len(absents)} absents, {nb_suppress} note supprimées)
</p>"""
if messages:
msg += f"""<div class="warning">Attention&nbsp;:
<ul>
<li>{
'</li><li>'.join(messages)
}
</li>
</ul>
</div>"""
if etudids_with_decisions:
msg += """<p class="warning">Important: il y avait déjà des décisions de jury
enregistrées, qui sont peut-être à revoir suite à cette modification !</p>
@ -322,7 +333,7 @@ def do_evaluation_set_etud_note(evaluation: Evaluation, etud: Identite, value) -
# Convert and check value
L, invalids, _, _, _ = _check_notes([(etud.id, value)], evaluation)
if len(invalids) == 0:
etudids_changed, _, _ = notes_add(
etudids_changed, _, _, _ = notes_add(
current_user, evaluation.id, L, "Initialisation notes"
)
if len(etudids_changed) == 1:
@ -398,7 +409,9 @@ def do_evaluation_set_missing(
)
# ok
comment = "Initialisation notes manquantes"
etudids_changed, _, _ = notes_add(current_user, evaluation_id, valid_notes, comment)
etudids_changed, _, _, _ = notes_add(
current_user, evaluation_id, valid_notes, comment
)
# news
url = url_for(
"notes.moduleimpl_status",
@ -456,7 +469,7 @@ def evaluation_suppress_alln(evaluation_id, dialog_confirmed=False):
)
if not dialog_confirmed:
etudids_changed, nb_suppress, existing_decisions = notes_add(
etudids_changed, nb_suppress, existing_decisions, _ = notes_add(
current_user, evaluation_id, notes, do_it=False, check_inscription=False
)
msg = f"""<p>Confirmer la suppression des {nb_suppress} notes ?
@ -477,7 +490,7 @@ def evaluation_suppress_alln(evaluation_id, dialog_confirmed=False):
)
# modif
etudids_changed, nb_suppress, existing_decisions = notes_add(
etudids_changed, nb_suppress, existing_decisions, _ = notes_add(
current_user,
evaluation_id,
notes,
@ -519,7 +532,7 @@ def notes_add(
comment=None,
do_it=True,
check_inscription=True,
) -> tuple[list[int], int, list[int]]:
) -> tuple[list[int], int, list[int], list[str]]:
"""
Insert or update notes
notes is a list of tuples (etudid,value)
@ -528,30 +541,48 @@ def notes_add(
Nota:
- si la note existe deja avec valeur distincte, ajoute une entree au log (notes_notes_log)
Return: tuple (etudids_changed, nb_suppress, etudids_with_decision)
Return: tuple (etudids_changed, nb_suppress, etudids_with_decision, messages)
messages = list de messages d'avertissement/information pour l'utilisateur
"""
evaluation = Evaluation.get_evaluation(evaluation_id)
now = psycopg2.Timestamp(*time.localtime()[:6])
# Vérifie inscription et valeur note
inscrits = {
messages = []
# Vérifie inscription au module (même DEM/DEF)
etudids_inscrits_mod = {
x[0]
for x in sco_groups.do_evaluation_listeetuds_groups(
evaluation_id, getallstudents=True, include_demdef=True
)
}
# Les étudiants inscrits au semestre ni DEM ni DEF
_, etudids_actifs = evaluation.moduleimpl.formsemestre.etudids_actifs()
# Les étudiants inscrits au semestre et ceux "actifs" (ni DEM ni DEF)
etudids_inscrits_sem, etudids_actifs = (
evaluation.moduleimpl.formsemestre.etudids_actifs()
)
for etudid, value in notes:
if check_inscription and (
(etudid not in inscrits) or (etudid not in etudids_actifs)
):
log(f"notes_add: {etudid} non inscrit ou DEM/DEF: aborting")
raise NoteProcessError(f"étudiant {etudid} non inscrit dans ce module")
if check_inscription:
msg_err, msg_warn = "", ""
if etudid not in etudids_inscrits_sem:
msg_err = "non inscrit au semestre"
elif etudid not in etudids_inscrits_mod:
msg_err = "non inscrit au module"
elif etudid not in etudids_actifs:
# DEM ou DEF
msg_warn = "démissionnaire ou défaillant (note enregistrée)"
if msg_err or msg_warn:
etud = Identite.query.get(etudid) if isinstance(etudid, int) else None
msg = f"étudiant {etud.nomprenom if etud else etudid} {msg_err or msg_warn}"
if msg_err:
log(f"notes_add: {etudid} non inscrit ou DEM/DEF: aborting")
raise NoteProcessError(msg)
if msg_warn:
messages.append(msg)
if (value is not None) and not isinstance(value, float):
log(f"notes_add: {etudid} valeur de note invalide ({value}): aborting")
etud = Identite.query.get(etudid) if isinstance(etudid, int) else None
raise NoteProcessError(
f"etudiant {etudid}: valeur de note invalide ({value})"
f"etudiant {etud.nomprenom if etud else etudid}: valeur de note invalide ({value})"
)
# Recherche notes existantes
notes_db = sco_evaluation_db.do_evaluation_get_all_notes(evaluation_id)
@ -566,102 +597,20 @@ def notes_add(
etudids_with_decision = []
try:
for etudid, value in notes:
changed = False
if etudid not in notes_db:
# nouvelle note
if value != scu.NOTES_SUPPRESS:
if do_it:
args = {
"etudid": etudid,
"evaluation_id": evaluation_id,
"value": value,
"comment": comment,
"uid": user.id,
"date": now,
}
ndb.quote_dict(args)
# Note: le conflit ci-dessous peut arriver si un autre thread
# a modifié la base après qu'on ait lu notes_db
cursor.execute(
"""INSERT INTO notes_notes
(etudid, evaluation_id, value, comment, date, uid)
VALUES
(%(etudid)s,%(evaluation_id)s,%(value)s,
%(comment)s,%(date)s,%(uid)s)
ON CONFLICT ON CONSTRAINT notes_notes_etudid_evaluation_id_key
DO UPDATE SET etudid=%(etudid)s, evaluation_id=%(evaluation_id)s,
value=%(value)s, comment=%(comment)s, date=%(date)s, uid=%(uid)s
""",
args,
)
changed = True
else:
# il y a deja une note
oldval = notes_db[etudid]["value"]
if type(value) != type(oldval):
changed = True
elif isinstance(value, float) and (
abs(value - oldval) > scu.NOTES_PRECISION
):
changed = True
elif value != oldval:
changed = True
if changed:
# recopie l'ancienne note dans notes_notes_log, puis update
if do_it:
cursor.execute(
"""INSERT INTO notes_notes_log
(etudid,evaluation_id,value,comment,date,uid)
SELECT etudid, evaluation_id, value, comment, date, uid
FROM notes_notes
WHERE etudid=%(etudid)s
and evaluation_id=%(evaluation_id)s
""",
{"etudid": etudid, "evaluation_id": evaluation_id},
)
args = {
"etudid": etudid,
"evaluation_id": evaluation_id,
"value": value,
"date": now,
"comment": comment,
"uid": user.id,
}
ndb.quote_dict(args)
if value != scu.NOTES_SUPPRESS:
if do_it:
cursor.execute(
"""UPDATE notes_notes
SET value=%(value)s, comment=%(comment)s, date=%(date)s, uid=%(uid)s
WHERE etudid = %(etudid)s
and evaluation_id = %(evaluation_id)s
""",
args,
)
else: # suppression ancienne note
if do_it:
log(
f"""notes_add, suppress, evaluation_id={evaluation_id}, etudid={
etudid}, oldval={oldval}"""
)
cursor.execute(
"""DELETE FROM notes_notes
WHERE etudid = %(etudid)s
AND evaluation_id = %(evaluation_id)s
""",
args,
)
# garde trace de la suppression dans l'historique:
args["value"] = scu.NOTES_SUPPRESS
cursor.execute(
"""INSERT INTO notes_notes_log
(etudid,evaluation_id,value,comment,date,uid)
VALUES
(%(etudid)s, %(evaluation_id)s, %(value)s, %(comment)s, %(date)s, %(uid)s)
""",
args,
)
nb_suppress += 1
changed, suppressed = _record_note(
cursor,
notes_db,
etudid,
evaluation_id,
value,
comment=comment,
user=user,
date=now,
do_it=do_it,
)
if suppressed:
nb_suppress += 1
if changed:
etudids_changed.append(etudid)
if res.etud_has_decision(etudid, include_rcues=False):
@ -678,7 +627,108 @@ def notes_add(
cnx.commit()
sco_cache.invalidate_formsemestre(formsemestre_id=formsemestre.id)
sco_cache.EvaluationCache.delete(evaluation_id)
return etudids_changed, nb_suppress, etudids_with_decision
return etudids_changed, nb_suppress, etudids_with_decision, messages
def _record_note(
cursor,
notes_db,
etudid: int,
evaluation_id: int,
value: float,
comment: str = "",
user: User = None,
date=None,
do_it=False,
):
"Enregistrement de la note en base"
changed = False
suppressed = False
args = {
"etudid": etudid,
"evaluation_id": evaluation_id,
"value": value,
# convention scodoc7 quote comment:
"comment": (html.escape(comment) if isinstance(comment, str) else comment),
"uid": user.id,
"date": date,
}
if etudid not in notes_db:
# nouvelle note
if value != scu.NOTES_SUPPRESS:
if do_it:
# Note: le conflit ci-dessous peut arriver si un autre thread
# a modifié la base après qu'on ait lu notes_db
cursor.execute(
"""INSERT INTO notes_notes
(etudid, evaluation_id, value, comment, date, uid)
VALUES
(%(etudid)s,%(evaluation_id)s,%(value)s,
%(comment)s,%(date)s,%(uid)s)
ON CONFLICT ON CONSTRAINT notes_notes_etudid_evaluation_id_key
DO UPDATE SET etudid=%(etudid)s, evaluation_id=%(evaluation_id)s,
value=%(value)s, comment=%(comment)s, date=%(date)s, uid=%(uid)s
""",
args,
)
changed = True
else:
# il y a deja une note
oldval = notes_db[etudid]["value"]
if type(value) != type(oldval):
changed = True
elif isinstance(value, float) and (abs(value - oldval) > scu.NOTES_PRECISION):
changed = True
elif value != oldval:
changed = True
if changed:
# recopie l'ancienne note dans notes_notes_log, puis update
if do_it:
cursor.execute(
"""INSERT INTO notes_notes_log
(etudid,evaluation_id,value,comment,date,uid)
SELECT etudid, evaluation_id, value, comment, date, uid
FROM notes_notes
WHERE etudid=%(etudid)s
and evaluation_id=%(evaluation_id)s
""",
args,
)
if value != scu.NOTES_SUPPRESS:
if do_it:
cursor.execute(
"""UPDATE notes_notes
SET value=%(value)s, comment=%(comment)s, date=%(date)s, uid=%(uid)s
WHERE etudid = %(etudid)s
and evaluation_id = %(evaluation_id)s
""",
args,
)
else: # suppression ancienne note
if do_it:
log(
f"""notes_add, suppress, evaluation_id={evaluation_id}, etudid={
etudid}, oldval={oldval}"""
)
cursor.execute(
"""DELETE FROM notes_notes
WHERE etudid = %(etudid)s
AND evaluation_id = %(evaluation_id)s
""",
args,
)
# garde trace de la suppression dans l'historique:
args["value"] = scu.NOTES_SUPPRESS
cursor.execute(
"""INSERT INTO notes_notes_log
(etudid,evaluation_id,value,comment,date,uid)
VALUES
(%(etudid)s, %(evaluation_id)s, %(value)s, %(comment)s, %(date)s, %(uid)s)
""",
args,
)
suppressed = True
return changed, suppressed
def saisie_notes_tableur(evaluation_id, group_ids=()):
@ -703,7 +753,7 @@ def saisie_notes_tableur(evaluation_id, group_ids=()):
)
page_title = "Saisie des notes" + (
f"""de {evaluation.description}""" if evaluation.description else ""
f""" de {evaluation.description}""" if evaluation.description else ""
)
# Informations sur les groupes à afficher:
@ -797,9 +847,13 @@ def saisie_notes_tableur(evaluation_id, group_ids=()):
}">
Revenir au tableau de bord du module</a>
&nbsp;&nbsp;&nbsp;
<a class="stdlink" href="{url_for("notes.saisie_notes_tableur",
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id)
}">Charger un autre fichier de notes</a>
&nbsp;&nbsp;&nbsp;
<a class="stdlink" href="{url_for("notes.saisie_notes",
scodoc_dept=g.scodoc_dept, evaluation_id=evaluation.id)
}">Charger d'autres notes dans cette évaluation</a>
}">Formulaire de saisie des notes</a>
</p>"""
)
else:
@ -1015,7 +1069,7 @@ def saisie_notes(evaluation_id: int, group_ids: list = None):
"Autres opérations",
[
{
"title": "Saisie par fichier tableur",
"title": "Saisir par fichier tableur",
"id": "menu_saisie_tableur",
"endpoint": "notes.saisie_notes_tableur",
"args": {
@ -1126,7 +1180,7 @@ def _get_sorted_etuds(evaluation: Evaluation, etudids: list, formsemestre_id: in
# Note actuelle de l'étudiant:
if etudid in notes_db:
e["val"] = _displayNote(notes_db[etudid]["value"])
e["val"] = _display_note(notes_db[etudid]["value"])
comment = notes_db[etudid]["comment"]
if comment is None:
comment = ""
@ -1368,7 +1422,7 @@ def save_notes(
#
valid_notes, _, _, _, _ = _check_notes(notes, evaluation)
if valid_notes:
etudids_changed, _, etudids_with_decision = notes_add(
etudids_changed, _, etudids_with_decision, messages = notes_add(
current_user, evaluation.id, valid_notes, comment=comment, do_it=True
)
ScolarNews.add(
@ -1386,12 +1440,14 @@ def save_notes(
etudid: get_note_history_menu(evaluation.id, etudid)
for etudid in etudids_changed
},
"messages": messages,
}
else:
result = {
"etudids_changed": [],
"etudids_with_decision": [],
"history_menu": [],
"messages": [],
}
return result
@ -1420,7 +1476,7 @@ def get_note_history_menu(evaluation_id: int, etudid: int) -> str:
first = True
for i in history:
jt = i["date"].strftime("le %d/%m/%Y à %H:%M") + " (%s)" % i["user_name"]
dispnote = _displayNote(i["value"])
dispnote = _display_note(i["value"])
if first:
nv = "" # ne repete pas la valeur de la note courante
else:

View File

@ -180,7 +180,7 @@ def external_ue_inscrit_et_note(
description="note externe",
)
# Saisie des notes
_, _, _ = sco_saisie_notes.notes_add(
_, _, _, _ = sco_saisie_notes.notes_add(
current_user,
evaluation.id,
list(notes_etuds.items()),

View File

@ -35,7 +35,7 @@ from flask import url_for, g, request
from flask_login import current_user
from app import db, Departement
from app import Departement
from app.auth.models import Permission, Role, User, UserRole
from app.models import ScoDocSiteConfig, USERNAME_STR_LEN

View File

@ -1,7 +1,7 @@
# -*- mode: python -*-
# -*- coding: utf-8 -*-
SCOVERSION = "9.6.975"
SCOVERSION = "9.6.976"
SCONAME = "ScoDoc"

View File

@ -2,6 +2,7 @@
Vérif moyennes de modules des bulletins
et aussi moyennes modules et UE internes (via nt)
"""
import datetime
import numpy as np
from flask import g
@ -107,16 +108,16 @@ def test_notes_modules(test_client):
# --- Notes ordinaires
note_1 = 12.0
note_2 = 13.0
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e1["evaluation_id"], etudid=etuds[0]["etudid"], note=note_1
)
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e2["evaluation_id"], etudid=etuds[0]["etudid"], note=note_2
)
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e1["evaluation_id"], etudid=etuds[1]["etudid"], note=note_1 / 2
)
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e2["evaluation_id"], etudid=etuds[1]["etudid"], note=note_2 / 3
)
b = sco_bulletins.formsemestre_bulletinetud_dict(
@ -139,22 +140,20 @@ def test_notes_modules(test_client):
)
# Absence à une évaluation
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e1["evaluation_id"], etudid=etudid, note=None
) # abs
_, _, _ = G.create_note(
evaluation_id=e2["evaluation_id"], etudid=etudid, note=note_2
)
_ = G.create_note(evaluation_id=e2["evaluation_id"], etudid=etudid, note=note_2)
b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"]
)
note_th = (coef_1 * 0.0 + coef_2 * note_2) / (coef_1 + coef_2)
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(note_th)
# Absences aux deux évaluations
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e1["evaluation_id"], etudid=etudid, note=None
) # abs
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e2["evaluation_id"], etudid=etudid, note=None
) # abs
b = sco_bulletins.formsemestre_bulletinetud_dict(
@ -171,10 +170,8 @@ def test_notes_modules(test_client):
)
# Note excusée EXC <-> scu.NOTES_NEUTRALISE
_, _, _ = G.create_note(
evaluation_id=e1["evaluation_id"], etudid=etudid, note=note_1
)
_, _, _ = G.create_note(
_ = G.create_note(evaluation_id=e1["evaluation_id"], etudid=etudid, note=note_1)
_ = G.create_note(
evaluation_id=e2["evaluation_id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
) # EXC
b = sco_bulletins.formsemestre_bulletinetud_dict(
@ -190,10 +187,8 @@ def test_notes_modules(test_client):
expected_moy_ue=note_1,
)
# Note en attente ATT <-> scu.NOTES_ATTENTE
_, _, _ = G.create_note(
evaluation_id=e1["evaluation_id"], etudid=etudid, note=note_1
)
_, _, _ = G.create_note(
_ = G.create_note(evaluation_id=e1["evaluation_id"], etudid=etudid, note=note_1)
_ = G.create_note(
evaluation_id=e2["evaluation_id"], etudid=etudid, note=scu.NOTES_ATTENTE
) # ATT
b = sco_bulletins.formsemestre_bulletinetud_dict(
@ -209,10 +204,10 @@ def test_notes_modules(test_client):
expected_moy_ue=note_1,
)
# Neutralisation (EXC) des 2 évals
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e1["evaluation_id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
) # EXC
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e2["evaluation_id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
) # EXC
b = sco_bulletins.formsemestre_bulletinetud_dict(
@ -228,10 +223,10 @@ def test_notes_modules(test_client):
expected_moy_ue=np.nan,
)
# Attente (ATT) sur les 2 evals
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e1["evaluation_id"], etudid=etudid, note=scu.NOTES_ATTENTE
) # ATT
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e2["evaluation_id"], etudid=etudid, note=scu.NOTES_ATTENTE
) # ATT
b = sco_bulletins.formsemestre_bulletinetud_dict(
@ -290,7 +285,7 @@ def test_notes_modules(test_client):
{"etudid": etudid, "moduleimpl_id": moduleimpl_id},
formsemestre_id=formsemestre_id,
)
_, _, _ = G.create_note(evaluation_id=e1["evaluation_id"], etudid=etudid, note=12.5)
_ = G.create_note(evaluation_id=e1["evaluation_id"], etudid=etudid, note=12.5)
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
mod_stats = nt.get_mod_stats(moduleimpl_id)
@ -318,9 +313,7 @@ def test_notes_modules(test_client):
description="evaluation mod 2",
coefficient=1.0,
)
_, _, _ = G.create_note(
evaluation_id=e_m2["evaluation_id"], etudid=etudid, note=19.5
)
_ = G.create_note(evaluation_id=e_m2["evaluation_id"], etudid=etudid, note=19.5)
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
ue_status = nt.get_etud_ue_status(etudid, ue_id)
@ -328,22 +321,20 @@ def test_notes_modules(test_client):
# Moyenne d'UE si l'un des modules est EXC ("NA")
# 2 modules, notes EXC dans le premier, note valide n dans le second
# la moyenne de l'UE doit être n
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e1["evaluation_id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
) # EXC
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e2["evaluation_id"], etudid=etudid, note=scu.NOTES_NEUTRALISE
) # EXC
_, _, _ = G.create_note(
evaluation_id=e_m2["evaluation_id"], etudid=etudid, note=12.5
)
_, _, _ = G.create_note(
_ = G.create_note(evaluation_id=e_m2["evaluation_id"], etudid=etudid, note=12.5)
_ = G.create_note(
evaluation_id=e1["evaluation_id"], etudid=etuds[1]["etudid"], note=11.0
)
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e2["evaluation_id"], etudid=etuds[1]["etudid"], note=11.0
)
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e_m2["evaluation_id"], etudid=etuds[1]["etudid"], note=11.0
)
@ -407,12 +398,12 @@ def test_notes_modules_att_dem(test_client):
coefficient=coef_1,
)
# Attente (ATT) sur les 2 evals
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e1["evaluation_id"],
etudid=etuds[0]["etudid"],
note=scu.NOTES_ATTENTE,
) # ATT
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e1["evaluation_id"],
etudid=etuds[1]["etudid"],
note=scu.NOTES_ATTENTE,
@ -455,7 +446,7 @@ def test_notes_modules_att_dem(test_client):
assert note_e1 == scu.NOTES_ATTENTE # XXXX un peu contestable
# Saisie note ABS pour le deuxième etud
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e1["evaluation_id"], etudid=etuds[1]["etudid"], note=None
)
nt = check_nt(

View File

@ -72,8 +72,8 @@ def test_notes_rattrapage(test_client):
evaluation_type=Evaluation.EVALUATION_RATTRAPAGE,
)
etud = etuds[0]
_, _, _ = G.create_note(evaluation_id=e["id"], etudid=etud["etudid"], note=12.0)
_, _, _ = G.create_note(evaluation_id=e_rat["id"], etudid=etud["etudid"], note=11.0)
_ = G.create_note(evaluation_id=e["id"], etudid=etud["etudid"], note=12.0)
_ = G.create_note(evaluation_id=e_rat["id"], etudid=etud["etudid"], note=11.0)
# --- Vérifications internes structures ScoDoc
formsemestre = db.session.get(FormSemestre, formsemestre_id)
@ -98,23 +98,21 @@ def test_notes_rattrapage(test_client):
# Note moyenne: ici le ratrapage est inférieur à la note:
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(12.0)
# rattrapage > moyenne:
_, _, _ = G.create_note(evaluation_id=e_rat["id"], etudid=etud["etudid"], note=18.0)
_ = G.create_note(evaluation_id=e_rat["id"], etudid=etud["etudid"], note=18.0)
b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"]
)
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(18.0)
# rattrapage vs absences
_, _, _ = G.create_note(
evaluation_id=e["id"], etudid=etud["etudid"], note=None
) # abs
_, _, _ = G.create_note(evaluation_id=e_rat["id"], etudid=etud["etudid"], note=17.0)
_ = G.create_note(evaluation_id=e["id"], etudid=etud["etudid"], note=None) # abs
_ = G.create_note(evaluation_id=e_rat["id"], etudid=etud["etudid"], note=17.0)
b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"]
)
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(17.0)
# et sans note de rattrapage
_, _, _ = G.create_note(evaluation_id=e["id"], etudid=etud["etudid"], note=10.0)
_, _, _ = G.create_note(evaluation_id=e_rat["id"], etudid=etud["etudid"], note=None)
_ = G.create_note(evaluation_id=e["id"], etudid=etud["etudid"], note=10.0)
_ = G.create_note(evaluation_id=e_rat["id"], etudid=etud["etudid"], note=None)
b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"]
)
@ -159,18 +157,14 @@ def test_notes_rattrapage(test_client):
assert len(mod_res.get_evaluations_completes(moduleimpl)) == 2
# Saisie note session 2:
_, _, _ = G.create_note(
evaluation_id=e_session2["id"], etudid=etud["etudid"], note=5.0
)
_ = G.create_note(evaluation_id=e_session2["id"], etudid=etud["etudid"], note=5.0)
b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"]
)
# Note moyenne: utilise session 2 même si inférieure
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(5.0)
_, _, _ = G.create_note(
evaluation_id=e_session2["id"], etudid=etud["etudid"], note=20.0
)
_ = G.create_note(evaluation_id=e_session2["id"], etudid=etud["etudid"], note=20.0)
b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"]
)
@ -178,16 +172,14 @@ def test_notes_rattrapage(test_client):
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(20.0)
# Met la note session2 à ABS (None)
_, _, _ = G.create_note(
evaluation_id=e_session2["id"], etudid=etud["etudid"], note=None
)
_ = G.create_note(evaluation_id=e_session2["id"], etudid=etud["etudid"], note=None)
b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"]
)
# Note moyenne: zéro car ABS
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(0.0)
# Supprime note session 2
_, _, _ = G.create_note(
_ = G.create_note(
evaluation_id=e_session2["id"], etudid=etud["etudid"], note=scu.NOTES_SUPPRESS
)
b = sco_bulletins.formsemestre_bulletinetud_dict(
@ -216,18 +208,14 @@ def test_notes_rattrapage(test_client):
# Note moyenne sans bonus
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(10.0)
# Saisie note bonus
_, _, _ = G.create_note(
evaluation_id=e_bonus["id"], etudid=etud["etudid"], note=1.0
)
_ = G.create_note(evaluation_id=e_bonus["id"], etudid=etud["etudid"], note=1.0)
b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"]
)
# Note moyenne sans bonus
assert b["ues"][0]["modules"][0]["mod_moy_txt"] == scu.fmt_note(11.0)
# Négatif, avec clip à zéro
_, _, _ = G.create_note(
evaluation_id=e_bonus["id"], etudid=etud["etudid"], note=-20.0
)
_ = G.create_note(evaluation_id=e_bonus["id"], etudid=etud["etudid"], note=-20.0)
b = sco_bulletins.formsemestre_bulletinetud_dict(
sem["formsemestre_id"], etud["etudid"]
)

View File

@ -105,7 +105,7 @@ def run_sco_basic(verbose=False, dept=None) -> FormSemestre:
# --- Saisie toutes les notes de l'évaluation
for idx, etud in enumerate(etuds):
etudids_changed, nb_suppress, existing_decisions = G.create_note(
etudids_changed, nb_suppress, existing_decisions, messages = G.create_note(
evaluation_id=e1.id,
etudid=etud["etudid"],
note=NOTES_T[idx % len(NOTES_T)],
@ -113,6 +113,7 @@ def run_sco_basic(verbose=False, dept=None) -> FormSemestre:
assert not existing_decisions
assert nb_suppress == 0
assert len(etudids_changed) == 1
assert messages == []
# --- Vérifie que les notes sont prises en compte:
b = sco_bulletins.formsemestre_bulletinetud_dict(formsemestre_id, etud["etudid"])
@ -139,11 +140,12 @@ def run_sco_basic(verbose=False, dept=None) -> FormSemestre:
db.session.commit()
# Saisie les notes des 5 premiers étudiants:
for idx, etud in enumerate(etuds[:5]):
etudids_changed, nb_suppress, existing_decisions = G.create_note(
etudids_changed, nb_suppress, existing_decisions, messages = G.create_note(
evaluation_id=e2.id,
etudid=etud["etudid"],
note=NOTES_T[idx % len(NOTES_T)],
)
assert messages == []
# Cette éval n'est pas complète
etat = sco_evaluations.do_evaluation_etat(e2.id)
assert etat["evalcomplete"] is False
@ -162,11 +164,12 @@ def run_sco_basic(verbose=False, dept=None) -> FormSemestre:
# Saisie des notes qui manquent:
for idx, etud in enumerate(etuds[5:]):
etudids_changed, nb_suppress, existing_decisions = G.create_note(
etudids_changed, nb_suppress, existing_decisions, messages = G.create_note(
evaluation_id=e2.id,
etudid=etud["etudid"],
note=NOTES_T[idx % len(NOTES_T)],
)
assert messages == []
etat = sco_evaluations.do_evaluation_etat(e2.id)
assert etat["evalcomplete"]
assert etat["nb_att"] == 0