forked from ScoDoc/ScoDoc
Modernisation code: formations
This commit is contained in:
parent
09657f1ebb
commit
246fa62920
@ -40,7 +40,7 @@ Created on Thu Sep 8 09:36:33 2016
|
|||||||
import datetime
|
import datetime
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from app.scodoc import notes_table
|
from app.scodoc import sco_utils as scu
|
||||||
|
|
||||||
|
|
||||||
class TableTag(object):
|
class TableTag(object):
|
||||||
@ -186,7 +186,7 @@ class TableTag(object):
|
|||||||
if isinstance(col[0], float)
|
if isinstance(col[0], float)
|
||||||
else 0, # remplace les None et autres chaines par des zéros
|
else 0, # remplace les None et autres chaines par des zéros
|
||||||
) # triées
|
) # triées
|
||||||
self.rangs[tag] = notes_table.comp_ranks(lesMoyennesTriees) # les rangs
|
self.rangs[tag] = scu.comp_ranks(lesMoyennesTriees) # les rangs
|
||||||
|
|
||||||
# calcul des stats
|
# calcul des stats
|
||||||
self.comp_stats_d_un_tag(tag)
|
self.comp_stats_d_un_tag(tag)
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -25,43 +25,22 @@
|
|||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
"""Calcul des moyennes de module
|
"""Calcul des moyennes de module (restes de fonctions ScoDoc 7)
|
||||||
"""
|
"""
|
||||||
import pprint
|
from app.models import ModuleImpl
|
||||||
import traceback
|
|
||||||
|
|
||||||
from flask import url_for, g
|
|
||||||
import app.scodoc.sco_utils as scu
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app.scodoc.sco_utils import (
|
|
||||||
ModuleType,
|
|
||||||
NOTES_ATTENTE,
|
def moduleimpl_has_expression(modimpl: ModuleImpl):
|
||||||
NOTES_NEUTRALISE,
|
"""True if we should use a user-defined expression
|
||||||
EVALUATION_NORMALE,
|
En ScoDoc 9, utilisé pour afficher un avertissement, l'expression elle même
|
||||||
EVALUATION_RATTRAPAGE,
|
n'est plus supportée.
|
||||||
EVALUATION_SESSION2,
|
"""
|
||||||
|
return (
|
||||||
|
modimpl.computation_expr
|
||||||
|
and modimpl.computation_expr.strip()
|
||||||
|
and modimpl.computation_expr.strip()[0] != "#"
|
||||||
)
|
)
|
||||||
from app.scodoc.sco_exceptions import ScoValueError
|
|
||||||
from app import log
|
|
||||||
from app.scodoc import sco_abs
|
|
||||||
from app.scodoc import sco_edit_module
|
|
||||||
from app.scodoc import sco_evaluation_db
|
|
||||||
from app.scodoc import sco_formsemestre
|
|
||||||
from app.scodoc import sco_formsemestre_inscriptions
|
|
||||||
from app.scodoc import sco_formulas
|
|
||||||
from app.scodoc import sco_moduleimpl
|
|
||||||
from app.scodoc import sco_etud
|
|
||||||
|
|
||||||
|
|
||||||
def moduleimpl_has_expression(mod):
|
|
||||||
"True if we should use a user-defined expression"
|
|
||||||
expr = mod["computation_expr"]
|
|
||||||
if not expr:
|
|
||||||
return False
|
|
||||||
expr = expr.strip()
|
|
||||||
if not expr or expr[0] == "#":
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def formsemestre_expressions_use_abscounts(formsemestre_id):
|
def formsemestre_expressions_use_abscounts(formsemestre_id):
|
||||||
@ -81,9 +60,10 @@ def formsemestre_expressions_use_abscounts(formsemestre_id):
|
|||||||
if expr and expr[0] != "#" and ab in expr:
|
if expr and expr[0] != "#" and ab in expr:
|
||||||
return True
|
return True
|
||||||
# 2- moyennes de modules
|
# 2- moyennes de modules
|
||||||
for mod in sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id):
|
# #sco9 il n'y a plus d'expressions
|
||||||
if moduleimpl_has_expression(mod) and ab in mod["computation_expr"]:
|
# for mod in sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id):
|
||||||
return True
|
# if moduleimpl_has_expression(mod) and ab in mod["computation_expr"]:
|
||||||
|
# return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@ -120,296 +100,3 @@ def get_ue_expression(formsemestre_id, ue_id, html_quote=False):
|
|||||||
return expr
|
return expr
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def compute_user_formula(
|
|
||||||
sem,
|
|
||||||
etudid,
|
|
||||||
moy,
|
|
||||||
moy_valid,
|
|
||||||
notes,
|
|
||||||
coefs,
|
|
||||||
coefs_mask,
|
|
||||||
formula,
|
|
||||||
diag_info=None, # infos supplementaires a placer ds messages d'erreur
|
|
||||||
use_abs=True,
|
|
||||||
):
|
|
||||||
"""Calcul moyenne a partir des notes et coefs, en utilisant la formule utilisateur (une chaine).
|
|
||||||
Retourne moy, et en cas d'erreur met à jour diag_info (msg)
|
|
||||||
"""
|
|
||||||
if use_abs:
|
|
||||||
nbabs, nbabs_just = sco_abs.get_abs_count(etudid, sem)
|
|
||||||
else:
|
|
||||||
nbabs, nbabs_just = 0, 0
|
|
||||||
try:
|
|
||||||
moy_val = float(moy)
|
|
||||||
except ValueError:
|
|
||||||
moy_val = 0.0 # 0. when no valid value
|
|
||||||
variables = {
|
|
||||||
"cmask": coefs_mask, # NoteVector(v=coefs_mask),
|
|
||||||
"notes": notes, # NoteVector(v=notes),
|
|
||||||
"coefs": coefs, # NoteVector(v=coefs),
|
|
||||||
"moy": moy,
|
|
||||||
"moy_valid": moy_valid, # deprecated, use moy_is_valid
|
|
||||||
"moy_is_valid": moy_valid, # True si moyenne numerique
|
|
||||||
"moy_val": moy_val,
|
|
||||||
"nb_abs": float(nbabs),
|
|
||||||
"nb_abs_just": float(nbabs_just),
|
|
||||||
"nb_abs_nojust": float(nbabs - nbabs_just),
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
formula = formula.replace("\n", "").replace("\r", "")
|
|
||||||
# log('expression : %s\nvariables=%s\n' % (formula, variables)) # debug
|
|
||||||
user_moy = sco_formulas.eval_user_expression(formula, variables)
|
|
||||||
# log('user_moy=%s' % user_moy)
|
|
||||||
if user_moy != "NA":
|
|
||||||
user_moy = float(user_moy)
|
|
||||||
if (user_moy > 20) or (user_moy < 0):
|
|
||||||
etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
|
|
||||||
|
|
||||||
raise ScoValueError(
|
|
||||||
f"""
|
|
||||||
Valeur moyenne {user_moy} hors limite pour
|
|
||||||
<a href="{url_for('notes.formsemestre_bulletinetud',
|
|
||||||
scodoc_dept=g.scodoc_dept,
|
|
||||||
formsemestre_id=sem["formsemestre_id"],
|
|
||||||
etudid=etudid
|
|
||||||
)}">{etud["nomprenom"]}</a>"""
|
|
||||||
)
|
|
||||||
except:
|
|
||||||
log(
|
|
||||||
"invalid expression : %s\nvariables=%s\n"
|
|
||||||
% (formula, pprint.pformat(variables))
|
|
||||||
)
|
|
||||||
tb = traceback.format_exc()
|
|
||||||
log("Exception during evaluation:\n%s\n" % tb)
|
|
||||||
diag_info.update({"msg": tb.splitlines()[-1]})
|
|
||||||
user_moy = "ERR"
|
|
||||||
|
|
||||||
# log('formula=%s\nvariables=%s\nmoy=%s\nuser_moy=%s' % (formula, variables, moy, user_moy))
|
|
||||||
|
|
||||||
return user_moy
|
|
||||||
|
|
||||||
|
|
||||||
# XXX OBSOLETE
|
|
||||||
def compute_moduleimpl_moyennes(nt, modimpl):
|
|
||||||
"""Retourne dict { etudid : note_moyenne } pour tous les etuds inscrits
|
|
||||||
au moduleimpl mod, la liste des evaluations "valides" (toutes notes entrées
|
|
||||||
ou en attente), et att (vrai s'il y a des notes en attente dans ce module).
|
|
||||||
La moyenne est calculée en utilisant les coefs des évaluations.
|
|
||||||
Les notes NEUTRES (abs. excuses) ne sont pas prises en compte.
|
|
||||||
Les notes ABS sont remplacées par des zéros.
|
|
||||||
S'il manque des notes et que le coef n'est pas nul,
|
|
||||||
la moyenne n'est pas calculée: NA
|
|
||||||
Ne prend en compte que les evaluations où toutes les notes sont entrées.
|
|
||||||
Le résultat note_moyenne est une note sur 20.
|
|
||||||
"""
|
|
||||||
diag_info = {} # message d'erreur formule
|
|
||||||
moduleimpl_id = modimpl["moduleimpl_id"]
|
|
||||||
is_malus = modimpl["module"]["module_type"] == ModuleType.MALUS
|
|
||||||
sem = sco_formsemestre.get_formsemestre(modimpl["formsemestre_id"])
|
|
||||||
etudids = sco_moduleimpl.moduleimpl_listeetuds(
|
|
||||||
moduleimpl_id
|
|
||||||
) # tous, y compris demissions
|
|
||||||
# Inscrits au semestre (pour traiter les demissions):
|
|
||||||
inssem_set = set(
|
|
||||||
[
|
|
||||||
x["etudid"]
|
|
||||||
for x in sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
|
|
||||||
modimpl["formsemestre_id"]
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
insmod_set = inssem_set.intersection(etudids) # inscrits au semestre et au module
|
|
||||||
|
|
||||||
evals = nt.get_mod_evaluation_etat_list(moduleimpl_id)
|
|
||||||
evals.sort(
|
|
||||||
key=lambda x: (x["numero"], x["jour"], x["heure_debut"])
|
|
||||||
) # la plus ancienne en tête
|
|
||||||
|
|
||||||
user_expr = moduleimpl_has_expression(modimpl)
|
|
||||||
attente = False
|
|
||||||
# récupere les notes de toutes les evaluations
|
|
||||||
eval_rattr = None
|
|
||||||
for e in evals:
|
|
||||||
e["nb_inscrits"] = e["etat"]["nb_inscrits"]
|
|
||||||
# XXX OBSOLETE
|
|
||||||
notes_db = sco_evaluation_db.do_evaluation_get_all_notes(
|
|
||||||
e["evaluation_id"]
|
|
||||||
) # toutes, y compris demissions
|
|
||||||
# restreint aux étudiants encore inscrits à ce module
|
|
||||||
notes = [
|
|
||||||
notes_db[etudid]["value"] for etudid in notes_db if (etudid in insmod_set)
|
|
||||||
]
|
|
||||||
e["nb_notes"] = len(notes)
|
|
||||||
e["nb_abs"] = len([x for x in notes if x is None])
|
|
||||||
e["nb_neutre"] = len([x for x in notes if x == NOTES_NEUTRALISE])
|
|
||||||
e["nb_att"] = len([x for x in notes if x == NOTES_ATTENTE])
|
|
||||||
e["notes"] = notes_db
|
|
||||||
|
|
||||||
if e["etat"]["evalattente"]:
|
|
||||||
attente = True
|
|
||||||
if (
|
|
||||||
e["evaluation_type"] == EVALUATION_RATTRAPAGE
|
|
||||||
or e["evaluation_type"] == EVALUATION_SESSION2
|
|
||||||
):
|
|
||||||
if eval_rattr:
|
|
||||||
# !!! plusieurs rattrapages !
|
|
||||||
diag_info.update(
|
|
||||||
{
|
|
||||||
"msg": "plusieurs évaluations de rattrapage !",
|
|
||||||
"moduleimpl_id": moduleimpl_id,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
eval_rattr = e
|
|
||||||
|
|
||||||
# Les modules MALUS ne sont jamais considérés en attente
|
|
||||||
if is_malus:
|
|
||||||
attente = False
|
|
||||||
|
|
||||||
# filtre les evals valides (toutes les notes entrées)
|
|
||||||
valid_evals = [
|
|
||||||
e
|
|
||||||
for e in evals
|
|
||||||
if (
|
|
||||||
(e["etat"]["evalcomplete"] or e["etat"]["evalattente"])
|
|
||||||
and (e["note_max"] > 0)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
#
|
|
||||||
R = {}
|
|
||||||
formula = scu.unescape_html(modimpl["computation_expr"])
|
|
||||||
formula_use_abs = "abs" in formula
|
|
||||||
|
|
||||||
for etudid in insmod_set: # inscrits au semestre et au module
|
|
||||||
sum_notes = 0.0
|
|
||||||
sum_coefs = 0.0
|
|
||||||
nb_missing = 0
|
|
||||||
for e in valid_evals:
|
|
||||||
if e["evaluation_type"] != EVALUATION_NORMALE:
|
|
||||||
continue
|
|
||||||
if etudid in e["notes"]:
|
|
||||||
note = e["notes"][etudid]["value"]
|
|
||||||
if note is None: # ABSENT
|
|
||||||
note = 0
|
|
||||||
if note != NOTES_NEUTRALISE and note != NOTES_ATTENTE:
|
|
||||||
sum_notes += (note * 20.0 / e["note_max"]) * e["coefficient"]
|
|
||||||
sum_coefs += e["coefficient"]
|
|
||||||
else:
|
|
||||||
# il manque une note ! (si publish_incomplete, cela peut arriver, on ignore)
|
|
||||||
if e["coefficient"] > 0 and not e["publish_incomplete"]:
|
|
||||||
nb_missing += 1
|
|
||||||
# ne devrait pas arriver ?
|
|
||||||
log("\nXXX SCM298\n")
|
|
||||||
if nb_missing == 0 and sum_coefs > 0:
|
|
||||||
if sum_coefs > 0:
|
|
||||||
R[etudid] = sum_notes / sum_coefs
|
|
||||||
moy_valid = True
|
|
||||||
else:
|
|
||||||
R[etudid] = "NA"
|
|
||||||
moy_valid = False
|
|
||||||
else:
|
|
||||||
R[etudid] = "NA"
|
|
||||||
moy_valid = False
|
|
||||||
|
|
||||||
if user_expr:
|
|
||||||
# recalcule la moyenne en utilisant la formule utilisateur
|
|
||||||
notes = []
|
|
||||||
coefs = []
|
|
||||||
coefs_mask = [] # 0/1, 0 si coef a ete annulé
|
|
||||||
nb_notes = 0 # nombre de notes valides
|
|
||||||
for e in evals:
|
|
||||||
if (
|
|
||||||
(e["etat"]["evalcomplete"] or e["etat"]["evalattente"])
|
|
||||||
and etudid in e["notes"]
|
|
||||||
) and (e["note_max"] > 0):
|
|
||||||
note = e["notes"][etudid]["value"]
|
|
||||||
if note is None:
|
|
||||||
note = 0
|
|
||||||
if note != NOTES_NEUTRALISE and note != NOTES_ATTENTE:
|
|
||||||
notes.append(note * 20.0 / e["note_max"])
|
|
||||||
coefs.append(e["coefficient"])
|
|
||||||
coefs_mask.append(1)
|
|
||||||
nb_notes += 1
|
|
||||||
else:
|
|
||||||
notes.append(0.0)
|
|
||||||
coefs.append(0.0)
|
|
||||||
coefs_mask.append(0)
|
|
||||||
else:
|
|
||||||
notes.append(0.0)
|
|
||||||
coefs.append(0.0)
|
|
||||||
coefs_mask.append(0)
|
|
||||||
if nb_notes > 0 or formula_use_abs:
|
|
||||||
user_moy = compute_user_formula(
|
|
||||||
sem,
|
|
||||||
etudid,
|
|
||||||
R[etudid],
|
|
||||||
moy_valid,
|
|
||||||
notes,
|
|
||||||
coefs,
|
|
||||||
coefs_mask,
|
|
||||||
formula,
|
|
||||||
diag_info=diag_info,
|
|
||||||
use_abs=formula_use_abs,
|
|
||||||
)
|
|
||||||
if diag_info:
|
|
||||||
diag_info["moduleimpl_id"] = moduleimpl_id
|
|
||||||
R[etudid] = user_moy
|
|
||||||
# Note de rattrapage ou deuxième session ?
|
|
||||||
if eval_rattr:
|
|
||||||
if etudid in eval_rattr["notes"]:
|
|
||||||
note = eval_rattr["notes"][etudid]["value"]
|
|
||||||
if note != None and note != NOTES_NEUTRALISE and note != NOTES_ATTENTE:
|
|
||||||
if not isinstance(R[etudid], float):
|
|
||||||
R[etudid] = note
|
|
||||||
else:
|
|
||||||
note_sur_20 = note * 20.0 / eval_rattr["note_max"]
|
|
||||||
if eval_rattr["evaluation_type"] == EVALUATION_RATTRAPAGE:
|
|
||||||
# rattrapage classique: prend la meilleure note entre moyenne
|
|
||||||
# module et note eval rattrapage
|
|
||||||
if (R[etudid] == "NA") or (note_sur_20 > R[etudid]):
|
|
||||||
# log('note_sur_20=%s' % note_sur_20)
|
|
||||||
R[etudid] = note_sur_20
|
|
||||||
elif eval_rattr["evaluation_type"] == EVALUATION_SESSION2:
|
|
||||||
# rattrapage type "deuxième session": remplace la note moyenne
|
|
||||||
R[etudid] = note_sur_20
|
|
||||||
|
|
||||||
return R, valid_evals, attente, diag_info
|
|
||||||
|
|
||||||
|
|
||||||
def formsemestre_compute_modimpls_moyennes(nt, formsemestre_id):
|
|
||||||
"""retourne dict { moduleimpl_id : { etudid, note_moyenne_dans_ce_module } },
|
|
||||||
la liste des moduleimpls, la liste des evaluations valides,
|
|
||||||
liste des moduleimpls avec notes en attente.
|
|
||||||
"""
|
|
||||||
# sem = sco_formsemestre.get_formsemestre( formsemestre_id)
|
|
||||||
# inscr = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
|
||||||
# args={"formsemestre_id": formsemestre_id}
|
|
||||||
# )
|
|
||||||
# etudids = [x["etudid"] for x in inscr]
|
|
||||||
modimpls = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
|
||||||
# recupere les moyennes des etudiants de tous les modules
|
|
||||||
D = {}
|
|
||||||
valid_evals = []
|
|
||||||
valid_evals_per_mod = {} # { moduleimpl_id : eval }
|
|
||||||
mods_att = []
|
|
||||||
expr_diags = []
|
|
||||||
for modimpl in modimpls:
|
|
||||||
mod = sco_edit_module.module_list(args={"module_id": modimpl["module_id"]})[0]
|
|
||||||
modimpl["module"] = mod # add module dict to moduleimpl (used by nt)
|
|
||||||
moduleimpl_id = modimpl["moduleimpl_id"]
|
|
||||||
assert moduleimpl_id not in D
|
|
||||||
(
|
|
||||||
D[moduleimpl_id],
|
|
||||||
valid_evals_mod,
|
|
||||||
attente,
|
|
||||||
expr_diag,
|
|
||||||
) = compute_moduleimpl_moyennes(nt, modimpl)
|
|
||||||
valid_evals_per_mod[moduleimpl_id] = valid_evals_mod
|
|
||||||
valid_evals += valid_evals_mod
|
|
||||||
if attente:
|
|
||||||
mods_att.append(modimpl)
|
|
||||||
if expr_diag:
|
|
||||||
expr_diags.append(expr_diag)
|
|
||||||
#
|
|
||||||
return D, modimpls, valid_evals_per_mod, valid_evals, mods_att, expr_diags
|
|
||||||
|
@ -29,18 +29,16 @@
|
|||||||
(portage from DTML)
|
(portage from DTML)
|
||||||
"""
|
"""
|
||||||
import flask
|
import flask
|
||||||
from flask import g, url_for, request
|
from flask import flash, g, url_for, request
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
|
||||||
from app import db
|
from app import db
|
||||||
from app import log
|
|
||||||
from app.models import SHORT_STR_LEN
|
from app.models import SHORT_STR_LEN
|
||||||
from app.models.formations import Formation
|
from app.models.formations import Formation
|
||||||
from app.models.modules import Module
|
from app.models.modules import Module
|
||||||
from app.models.ues import UniteEns
|
from app.models.ues import UniteEns
|
||||||
from app.models import ScolarNews
|
from app.models import ScolarNews
|
||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
||||||
from app.scodoc.sco_exceptions import ScoValueError, ScoNonEmptyFormationObject
|
from app.scodoc.sco_exceptions import ScoValueError, ScoNonEmptyFormationObject
|
||||||
@ -49,7 +47,6 @@ from app.scodoc import html_sco_header
|
|||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import codes_cursus
|
from app.scodoc import codes_cursus
|
||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
from app.scodoc import sco_formations
|
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
|
|
||||||
|
|
||||||
@ -283,38 +280,55 @@ def formation_edit(formation_id=None, create=False):
|
|||||||
)
|
)
|
||||||
#
|
#
|
||||||
if create:
|
if create:
|
||||||
formation_id = do_formation_create(tf[2])
|
formation = do_formation_create(tf[2])
|
||||||
else:
|
else:
|
||||||
do_formation_edit(tf[2])
|
do_formation_edit(tf[2])
|
||||||
|
flash(
|
||||||
|
f"""Création de la formation {
|
||||||
|
formation.titre} ({formation.acronyme}) version {formation.version}"""
|
||||||
|
)
|
||||||
return flask.redirect(
|
return flask.redirect(
|
||||||
url_for(
|
url_for(
|
||||||
"notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=formation_id
|
"notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=formation.id
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def do_formation_create(args):
|
def do_formation_create(args: dict) -> Formation:
|
||||||
"create a formation"
|
"create a formation"
|
||||||
cnx = ndb.GetDBConnexion()
|
formation = Formation(
|
||||||
# check unique acronyme/titre/version
|
dept_id=g.scodoc_dept_id,
|
||||||
a = args.copy()
|
acronyme=args["acronyme"].strip(),
|
||||||
if "formation_id" in a:
|
titre=args["titre"].strip(),
|
||||||
del a["formation_id"]
|
titre_officiel=args["titre_officiel"].strip(),
|
||||||
f_dicts = sco_formations.formation_list(args=a)
|
version=args.get("version"),
|
||||||
if len(f_dicts) > 0:
|
commentaire=scu.strip_str(args["commentaire"]),
|
||||||
log(f"do_formation_create: error: {len(f_dicts)} formations matching args={a}")
|
formation_code=args.get("formation_code", "").strip() or None,
|
||||||
raise ScoValueError(f"Formation non unique ({a}) !")
|
type_parcours=args.get("type_parcours"),
|
||||||
# Si pas de formation_code, l'enleve (default SQL)
|
code_specialite=args.get("code_specialite").strip() or None,
|
||||||
if "formation_code" in args and not args["formation_code"]:
|
referentiel_competence_id=args.get("referentiel_competence_id"),
|
||||||
del args["formation_code"]
|
)
|
||||||
#
|
db.session.add(formation)
|
||||||
r = sco_formations._formationEditor.create(cnx, args)
|
|
||||||
|
try:
|
||||||
|
db.session.commit()
|
||||||
|
except sqlalchemy.exc.IntegrityError as exc:
|
||||||
|
db.session.rollback()
|
||||||
|
raise ScoValueError(
|
||||||
|
"On ne peut pas créer deux formations avec mêmes acronymes, titres et versions !",
|
||||||
|
dest_url=url_for(
|
||||||
|
"notes.formation_edit",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
formation_id=formation.id,
|
||||||
|
),
|
||||||
|
) from exc
|
||||||
|
|
||||||
ScolarNews.add(
|
ScolarNews.add(
|
||||||
typ=ScolarNews.NEWS_FORM,
|
typ=ScolarNews.NEWS_FORM,
|
||||||
text="Création de la formation %(titre)s (%(acronyme)s)" % args,
|
text=f"""Création de la formation {
|
||||||
|
formation.titre} ({formation.acronyme}) version {formation.version}""",
|
||||||
)
|
)
|
||||||
return r
|
return formation
|
||||||
|
|
||||||
|
|
||||||
def do_formation_edit(args):
|
def do_formation_edit(args):
|
||||||
|
@ -303,8 +303,8 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
|
|||||||
f_dict["version"] = version + 1
|
f_dict["version"] = version + 1
|
||||||
|
|
||||||
# create formation
|
# create formation
|
||||||
formation_id = sco_edit_formation.do_formation_create(f_dict)
|
formation = sco_edit_formation.do_formation_create(f_dict)
|
||||||
log(f"formation {formation_id} created")
|
log(f"formation {formation.id} created")
|
||||||
|
|
||||||
ues_old2new = {} # xml ue_id : new ue_id
|
ues_old2new = {} # xml ue_id : new ue_id
|
||||||
modules_old2new = {} # xml module_id : new module_id
|
modules_old2new = {} # xml module_id : new module_id
|
||||||
@ -316,7 +316,7 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
|
|||||||
# -- create UEs
|
# -- create UEs
|
||||||
for ue_info in D[2]:
|
for ue_info in D[2]:
|
||||||
assert ue_info[0] == "ue"
|
assert ue_info[0] == "ue"
|
||||||
ue_info[1]["formation_id"] = formation_id
|
ue_info[1]["formation_id"] = formation.id
|
||||||
if "ue_id" in ue_info[1]:
|
if "ue_id" in ue_info[1]:
|
||||||
xml_ue_id = int(ue_info[1]["ue_id"])
|
xml_ue_id = int(ue_info[1]["ue_id"])
|
||||||
del ue_info[1]["ue_id"]
|
del ue_info[1]["ue_id"]
|
||||||
@ -365,7 +365,7 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
|
|||||||
del mod_info[1]["module_id"]
|
del mod_info[1]["module_id"]
|
||||||
else:
|
else:
|
||||||
xml_module_id = None
|
xml_module_id = None
|
||||||
mod_info[1]["formation_id"] = formation_id
|
mod_info[1]["formation_id"] = formation.id
|
||||||
mod_info[1]["matiere_id"] = mat_id
|
mod_info[1]["matiere_id"] = mat_id
|
||||||
mod_info[1]["ue_id"] = ue_id
|
mod_info[1]["ue_id"] = ue_id
|
||||||
if not "module_type" in mod_info[1]:
|
if not "module_type" in mod_info[1]:
|
||||||
@ -428,14 +428,15 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
|
|||||||
}
|
}
|
||||||
module.set_ue_coef_dict(ue_coef_dict)
|
module.set_ue_coef_dict(ue_coef_dict)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return formation_id, modules_old2new, ues_old2new
|
return formation.id, modules_old2new, ues_old2new
|
||||||
|
|
||||||
|
|
||||||
def formation_list_table(formation_id=None, args={}):
|
def formation_list_table(formation_id=None, args: dict = None):
|
||||||
"""List formation, grouped by titre and sorted by versions
|
"""List formation, grouped by titre and sorted by versions
|
||||||
and listing associated semestres
|
and listing associated semestres
|
||||||
returns a table
|
returns a table
|
||||||
"""
|
"""
|
||||||
|
args = args or {}
|
||||||
formations = formation_list(formation_id=formation_id, args=args)
|
formations = formation_list(formation_id=formation_id, args=args)
|
||||||
title = "Programmes pédagogiques"
|
title = "Programmes pédagogiques"
|
||||||
lockicon = scu.icontag(
|
lockicon = scu.icontag(
|
||||||
|
@ -53,6 +53,7 @@ from app.scodoc import html_sco_header
|
|||||||
from app.scodoc import codes_cursus
|
from app.scodoc import codes_cursus
|
||||||
from app.scodoc import sco_compute_moy
|
from app.scodoc import sco_compute_moy
|
||||||
from app.scodoc import sco_edit_module
|
from app.scodoc import sco_edit_module
|
||||||
|
from app.scodoc import sco_edit_ue
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
from app.scodoc import sco_evaluation_db
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
@ -1707,12 +1708,10 @@ def formsemestre_change_publication_bul(
|
|||||||
|
|
||||||
def formsemestre_edit_uecoefs(formsemestre_id, err_ue_id=None):
|
def formsemestre_edit_uecoefs(formsemestre_id, err_ue_id=None):
|
||||||
"""Changement manuel des coefficients des UE capitalisées."""
|
"""Changement manuel des coefficients des UE capitalisées."""
|
||||||
from app.scodoc import notes_table
|
|
||||||
|
|
||||||
ok, err = sco_permissions_check.check_access_diretud(formsemestre_id)
|
ok, err = sco_permissions_check.check_access_diretud(formsemestre_id)
|
||||||
if not ok:
|
if not ok:
|
||||||
return err
|
return err
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
|
||||||
|
|
||||||
footer = html_sco_header.sco_footer()
|
footer = html_sco_header.sco_footer()
|
||||||
help = """<p class="help">
|
help = """<p class="help">
|
||||||
@ -1741,7 +1740,7 @@ def formsemestre_edit_uecoefs(formsemestre_id, err_ue_id=None):
|
|||||||
help,
|
help,
|
||||||
]
|
]
|
||||||
#
|
#
|
||||||
ues, modimpls = notes_table.get_sem_ues_modimpls(formsemestre_id)
|
ues, modimpls = _get_sem_ues_modimpls(formsemestre_id)
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
ue["sum_coefs"] = sum(
|
ue["sum_coefs"] = sum(
|
||||||
[
|
[
|
||||||
@ -1865,6 +1864,24 @@ def formsemestre_edit_uecoefs(formsemestre_id, err_ue_id=None):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def _get_sem_ues_modimpls(formsemestre_id, modimpls=None):
|
||||||
|
"""Get liste des UE du semestre (à partir des moduleimpls)
|
||||||
|
(utilisé quand on ne peut pas construire nt et faire nt.get_ues_stat_dict())
|
||||||
|
"""
|
||||||
|
if modimpls is None:
|
||||||
|
modimpls = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
||||||
|
uedict = {}
|
||||||
|
for modimpl in modimpls:
|
||||||
|
mod = sco_edit_module.module_list(args={"module_id": modimpl["module_id"]})[0]
|
||||||
|
modimpl["module"] = mod
|
||||||
|
if not mod["ue_id"] in uedict:
|
||||||
|
ue = sco_edit_ue.ue_list(args={"ue_id": mod["ue_id"]})[0]
|
||||||
|
uedict[ue["ue_id"]] = ue
|
||||||
|
ues = list(uedict.values())
|
||||||
|
ues.sort(key=lambda u: u["numero"])
|
||||||
|
return ues, modimpls
|
||||||
|
|
||||||
|
|
||||||
# ----- identification externe des sessions (pour SOJA et autres logiciels)
|
# ----- identification externe des sessions (pour SOJA et autres logiciels)
|
||||||
def get_formsemestre_session_id(sem, code_specialite, parcours):
|
def get_formsemestre_session_id(sem, code_specialite, parcours):
|
||||||
"""Identifiant de session pour ce semestre
|
"""Identifiant de session pour ce semestre
|
||||||
|
@ -577,8 +577,9 @@ def fill_formsemestre(sem):
|
|||||||
}">{eyeicon}</a>"""
|
}">{eyeicon}</a>"""
|
||||||
else:
|
else:
|
||||||
sem["eyelink"] = ""
|
sem["eyelink"] = ""
|
||||||
F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
sem["formation"] = Formation.query.get_or_404(sem["formation_id"]).to_dict(
|
||||||
sem["formation"] = F
|
with_departement=False
|
||||||
|
)
|
||||||
parcours = codes_cursus.get_cursus_from_code(F["type_parcours"])
|
parcours = codes_cursus.get_cursus_from_code(F["type_parcours"])
|
||||||
if sem["semestre_id"] != -1:
|
if sem["semestre_id"] != -1:
|
||||||
sem["num_sem"] = f""", {parcours.SESSION_NAME} {sem["semestre_id"]}"""
|
sem["num_sem"] = f""", {parcours.SESSION_NAME} {sem["semestre_id"]}"""
|
||||||
|
@ -36,7 +36,7 @@ from flask import url_for, g, request
|
|||||||
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 log
|
from app import log
|
||||||
from app.models import FormSemestre
|
from app.models import Formation, FormSemestre
|
||||||
from app.scodoc.gen_tables import GenTable
|
from app.scodoc.gen_tables import GenTable
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
@ -261,8 +261,8 @@ def list_source_sems(sem, delai=None) -> list[dict]:
|
|||||||
if s["semestre_id"] == codes_cursus.NO_SEMESTRE_ID:
|
if s["semestre_id"] == codes_cursus.NO_SEMESTRE_ID:
|
||||||
continue
|
continue
|
||||||
#
|
#
|
||||||
F = sco_formations.formation_list(args={"formation_id": s["formation_id"]})[0]
|
formation: Formation = Formation.query.get_or_404(s["formation_id"])
|
||||||
parcours = codes_cursus.get_cursus_from_code(F["type_parcours"])
|
parcours = codes_cursus.get_cursus_from_code(formation.type_parcours)
|
||||||
if not parcours.ALLOW_SEM_SKIP:
|
if not parcours.ALLOW_SEM_SKIP:
|
||||||
if s["semestre_id"] < (sem["semestre_id"] - 1):
|
if s["semestre_id"] < (sem["semestre_id"] - 1):
|
||||||
continue
|
continue
|
||||||
|
@ -38,9 +38,7 @@ from app.auth.models import User
|
|||||||
from app.comp import res_sem
|
from app.comp import res_sem
|
||||||
from app.comp.res_common import ResultatsSemestre
|
from app.comp.res_common import ResultatsSemestre
|
||||||
from app.comp.res_compat import NotesTableCompat
|
from app.comp.res_compat import NotesTableCompat
|
||||||
from app.models import FormSemestre, ModuleImpl
|
from app.models import Evaluation, FormSemestre, Module, ModuleImpl, UniteEns
|
||||||
from app.models.evaluations import Evaluation
|
|
||||||
from app.models.ues import UniteEns
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.scodoc.codes_cursus import UE_SPORT
|
from app.scodoc.codes_cursus import UE_SPORT
|
||||||
from app.scodoc.sco_exceptions import ScoInvalidIdType
|
from app.scodoc.sco_exceptions import ScoInvalidIdType
|
||||||
@ -51,11 +49,8 @@ from app.scodoc import html_sco_header
|
|||||||
from app.scodoc import htmlutils
|
from app.scodoc import htmlutils
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
from app.scodoc import sco_compute_moy
|
from app.scodoc import sco_compute_moy
|
||||||
from app.scodoc import sco_edit_module
|
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluations
|
||||||
from app.scodoc import sco_evaluation_db
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formations
|
|
||||||
from app.scodoc import sco_formsemestre
|
|
||||||
from app.scodoc import sco_formsemestre_status
|
from app.scodoc import sco_formsemestre_status
|
||||||
from app.scodoc import sco_groups
|
from app.scodoc import sco_groups
|
||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
@ -80,7 +75,7 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0) -> str:
|
|||||||
else:
|
else:
|
||||||
sup_label = "Supprimer évaluation"
|
sup_label = "Supprimer évaluation"
|
||||||
|
|
||||||
menuEval = [
|
menu_eval = [
|
||||||
{
|
{
|
||||||
"title": "Saisir notes",
|
"title": "Saisir notes",
|
||||||
"endpoint": "notes.saisie_notes",
|
"endpoint": "notes.saisie_notes",
|
||||||
@ -159,7 +154,7 @@ def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0) -> str:
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
return htmlutils.make_menu("actions", menuEval, alone=True)
|
return htmlutils.make_menu("actions", menu_eval, alone=True)
|
||||||
|
|
||||||
|
|
||||||
def _ue_coefs_html(coefs_lst) -> str:
|
def _ue_coefs_html(coefs_lst) -> str:
|
||||||
@ -195,14 +190,9 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
if not isinstance(moduleimpl_id, int):
|
if not isinstance(moduleimpl_id, int):
|
||||||
raise ScoInvalidIdType("moduleimpl_id must be an integer !")
|
raise ScoInvalidIdType("moduleimpl_id must be an integer !")
|
||||||
modimpl: ModuleImpl = ModuleImpl.query.get_or_404(moduleimpl_id)
|
modimpl: ModuleImpl = ModuleImpl.query.get_or_404(moduleimpl_id)
|
||||||
mi_dict = modimpl.to_dict()
|
module: Module = modimpl.module
|
||||||
formsemestre_id = modimpl.formsemestre_id
|
formsemestre_id = modimpl.formsemestre_id
|
||||||
formsemestre: FormSemestre = modimpl.formsemestre
|
formsemestre: FormSemestre = modimpl.formsemestre
|
||||||
mod_dict = sco_edit_module.module_list(args={"module_id": modimpl.module_id})[0]
|
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
|
||||||
formation_dict = sco_formations.formation_list(
|
|
||||||
args={"formation_id": sem["formation_id"]}
|
|
||||||
)[0]
|
|
||||||
mod_inscrits = sco_moduleimpl.do_moduleimpl_inscription_list(
|
mod_inscrits = sco_moduleimpl.do_moduleimpl_inscription_list(
|
||||||
moduleimpl_id=moduleimpl_id
|
moduleimpl_id=moduleimpl_id
|
||||||
)
|
)
|
||||||
@ -223,10 +213,10 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
or [0]
|
or [0]
|
||||||
)
|
)
|
||||||
#
|
#
|
||||||
sem_locked = not sem["etat"]
|
sem_locked = not formsemestre.etat
|
||||||
can_edit_evals = (
|
can_edit_evals = (
|
||||||
sco_permissions_check.can_edit_notes(
|
sco_permissions_check.can_edit_notes(
|
||||||
current_user, moduleimpl_id, allow_ens=sem["ens_can_edit_eval"]
|
current_user, moduleimpl_id, allow_ens=formsemestre.ens_can_edit_eval
|
||||||
)
|
)
|
||||||
and not sem_locked
|
and not sem_locked
|
||||||
)
|
)
|
||||||
@ -237,22 +227,22 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
arrow_up, arrow_down, arrow_none = sco_groups.get_arrow_icons_tags()
|
arrow_up, arrow_down, arrow_none = sco_groups.get_arrow_icons_tags()
|
||||||
#
|
#
|
||||||
module_resp = User.query.get(modimpl.responsable_id)
|
module_resp = User.query.get(modimpl.responsable_id)
|
||||||
mod_type_name = scu.MODULE_TYPE_NAMES[mod_dict["module_type"]]
|
mod_type_name = scu.MODULE_TYPE_NAMES[module.module_type]
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(
|
html_sco_header.sco_header(
|
||||||
page_title=f"{mod_type_name} {mod_dict['code']} {mod_dict['titre']}",
|
page_title=f"{mod_type_name} {module.code} {module.titre}",
|
||||||
javascripts=["js/etud_info.js"],
|
javascripts=["js/etud_info.js"],
|
||||||
init_qtip=True,
|
init_qtip=True,
|
||||||
),
|
),
|
||||||
f"""<h2 class="formsemestre">{mod_type_name}
|
f"""<h2 class="formsemestre">{mod_type_name}
|
||||||
<tt>{mod_dict['code']}</tt> {mod_dict['titre']}
|
<tt>{module.code}</tt> {module.titre}
|
||||||
{"dans l'UE " + modimpl.module.ue.acronyme
|
{"dans l'UE " + modimpl.module.ue.acronyme
|
||||||
if modimpl.module.module_type == scu.ModuleType.MALUS
|
if modimpl.module.module_type == scu.ModuleType.MALUS
|
||||||
else ""
|
else ""
|
||||||
}
|
}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="moduleimpl_tableaubord moduleimpl_type_{
|
<div class="moduleimpl_tableaubord moduleimpl_type_{
|
||||||
scu.ModuleType(mod_dict['module_type']).name.lower()}">
|
scu.ModuleType(module.module_type).name.lower()}">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fichetitre2">Responsable: </td><td class="redboldtext">
|
<td class="fichetitre2">Responsable: </td><td class="redboldtext">
|
||||||
@ -281,8 +271,8 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
|
|
||||||
# 2ieme ligne: Semestre, Coef
|
# 2ieme ligne: Semestre, Coef
|
||||||
H.append("""<tr><td class="fichetitre2">""")
|
H.append("""<tr><td class="fichetitre2">""")
|
||||||
if sem["semestre_id"] >= 0:
|
if formsemestre.semestre_id >= 0:
|
||||||
H.append("""Semestre: </td><td>%s""" % sem["semestre_id"])
|
H.append("""Semestre: </td><td>%s""" % formsemestre.semestre_id)
|
||||||
else:
|
else:
|
||||||
H.append("""</td><td>""")
|
H.append("""</td><td>""")
|
||||||
if sem_locked:
|
if sem_locked:
|
||||||
@ -299,28 +289,28 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
H.append("""</td><td></td></tr>""")
|
H.append("""</td><td></td></tr>""")
|
||||||
# 3ieme ligne: Formation
|
# 3ieme ligne: Formation
|
||||||
H.append(
|
H.append(
|
||||||
"""<tr><td class="fichetitre2">Formation: </td><td>%(titre)s</td></tr>"""
|
f"""<tr>
|
||||||
% formation_dict
|
<td class="fichetitre2">Formation: </td><td>{formsemestre.formation.titre}</td>
|
||||||
|
</tr>
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
# Ligne: Inscrits
|
# Ligne: Inscrits
|
||||||
H.append(
|
H.append(
|
||||||
"""<tr><td class="fichetitre2">Inscrits: </td><td> %d étudiants"""
|
f"""<tr><td class="fichetitre2">Inscrits: </td><td> {len(mod_inscrits)} étudiants"""
|
||||||
% len(mod_inscrits)
|
|
||||||
)
|
)
|
||||||
if current_user.has_permission(Permission.ScoEtudInscrit):
|
if current_user.has_permission(Permission.ScoEtudInscrit):
|
||||||
H.append(
|
H.append(
|
||||||
"""<a class="stdlink" style="margin-left:2em;" href="moduleimpl_inscriptions_edit?moduleimpl_id=%s">modifier</a>"""
|
f"""<a class="stdlink" style="margin-left:2em;" href="moduleimpl_inscriptions_edit?moduleimpl_id={modimpl.id}">modifier</a>"""
|
||||||
% mi_dict["moduleimpl_id"]
|
|
||||||
)
|
)
|
||||||
H.append("</td></tr>")
|
H.append("</td></tr>")
|
||||||
# Ligne: règle de calcul
|
# Ligne: règle de calcul
|
||||||
has_expression = sco_compute_moy.moduleimpl_has_expression(mi_dict)
|
has_expression = sco_compute_moy.moduleimpl_has_expression(modimpl)
|
||||||
if has_expression:
|
if has_expression:
|
||||||
H.append(
|
H.append(
|
||||||
f"""<tr>
|
f"""<tr>
|
||||||
<td class="fichetitre2" colspan="4">Règle de calcul:
|
<td class="fichetitre2" colspan="4">Règle de calcul:
|
||||||
<span class="formula" title="mode de calcul de la moyenne du module"
|
<span class="formula" title="mode de calcul de la moyenne du module"
|
||||||
>moyenne=<tt>{mi_dict["computation_expr"]}</tt>
|
>moyenne=<tt>{modimpl.computation_expr}</tt>
|
||||||
</span>"""
|
</span>"""
|
||||||
)
|
)
|
||||||
H.append("""<span class="warning">inutilisée dans cette version de ScoDoc""")
|
H.append("""<span class="warning">inutilisée dans cette version de ScoDoc""")
|
||||||
@ -335,7 +325,8 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
H.append("</td></tr>")
|
H.append("</td></tr>")
|
||||||
else:
|
else:
|
||||||
H.append(
|
H.append(
|
||||||
'<tr><td colspan="4">' # <em title="mode de calcul de la moyenne du module">règle de calcul standard</em>'
|
'<tr><td colspan="4">'
|
||||||
|
# <em title="mode de calcul de la moyenne du module">règle de calcul standard</em>'
|
||||||
)
|
)
|
||||||
# if sco_moduleimpl.can_change_ens(moduleimpl_id, raise_exc=False):
|
# if sco_moduleimpl.can_change_ens(moduleimpl_id, raise_exc=False):
|
||||||
# H.append(
|
# H.append(
|
||||||
@ -396,7 +387,7 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
)
|
)
|
||||||
#
|
#
|
||||||
# Liste les noms de partitions
|
# Liste les noms de partitions
|
||||||
partitions = sco_groups.get_partitions_list(sem["formsemestre_id"])
|
partitions = sco_groups.get_partitions_list(formsemestre.id)
|
||||||
H.append(
|
H.append(
|
||||||
"""Afficher les groupes
|
"""Afficher les groupes
|
||||||
de <select name="partition_id" onchange="document.f.submit();">"""
|
de <select name="partition_id" onchange="document.f.submit();">"""
|
||||||
@ -417,28 +408,29 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
f"""<option value="{partition['partition_id']}" {selected}>{name}</option>"""
|
f"""<option value="{partition['partition_id']}" {selected}>{name}</option>"""
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
"""</select>
|
f"""</select>
|
||||||
|
|
||||||
<a class="stdlink" href="evaluation_listenotes?moduleimpl_id=%(moduleimpl_id)s">Voir toutes les notes</a>
|
<a class="stdlink" href="{
|
||||||
|
url_for("notes.evaluation_listenotes", scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id)
|
||||||
|
}">Voir toutes les notes</a>
|
||||||
</span>
|
</span>
|
||||||
</form>
|
</form>
|
||||||
</p>
|
</p>
|
||||||
"""
|
"""
|
||||||
% mi_dict
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# -------- Tableau des evaluations
|
# -------- Tableau des evaluations
|
||||||
top_table_links = ""
|
top_table_links = ""
|
||||||
if can_edit_evals:
|
if can_edit_evals:
|
||||||
top_table_links = f"""<a class="stdlink" href="{
|
top_table_links = f"""<a class="stdlink" href="{
|
||||||
url_for("notes.evaluation_create", scodoc_dept=g.scodoc_dept, moduleimpl_id=mi_dict['moduleimpl_id'])
|
url_for("notes.evaluation_create", scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id)
|
||||||
}">Créer nouvelle évaluation</a>
|
}">Créer nouvelle évaluation</a>
|
||||||
"""
|
"""
|
||||||
if nb_evaluations > 0:
|
if nb_evaluations > 0:
|
||||||
top_table_links += f"""
|
top_table_links += f"""
|
||||||
<a class="stdlink" style="margin-left:2em;" href="{
|
<a class="stdlink" style="margin-left:2em;" href="{
|
||||||
url_for("notes.moduleimpl_evaluation_renumber",
|
url_for("notes.moduleimpl_evaluation_renumber",
|
||||||
scodoc_dept=g.scodoc_dept, moduleimpl_id=mi_dict['moduleimpl_id'],
|
scodoc_dept=g.scodoc_dept, moduleimpl_id=modimpl.id,
|
||||||
redirect=1)
|
redirect=1)
|
||||||
}">Trier par date</a>
|
}">Trier par date</a>
|
||||||
"""
|
"""
|
||||||
|
@ -545,6 +545,11 @@ def strnone(s):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def strip_str(s):
|
||||||
|
"if s is a string, strip it, if is None, do nothing"
|
||||||
|
return s.strip() if s else s
|
||||||
|
|
||||||
|
|
||||||
def stripquotes(s):
|
def stripquotes(s):
|
||||||
"strip s from spaces and quotes"
|
"strip s from spaces and quotes"
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
@ -1136,6 +1141,36 @@ def objects_renumber(db, obj_list) -> None:
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def comp_ranks(T: list[tuple]) -> dict[int, str]:
|
||||||
|
"""Calcul rangs à partir d'une liste ordonnée de tuples [ (valeur, ..., etudid) ]
|
||||||
|
(valeur est une note numérique), en tenant compte des ex-aequos
|
||||||
|
Le resultat est: { etudid : rang } où rang est une chaine decrivant le rang
|
||||||
|
"""
|
||||||
|
rangs = {} # { etudid : rang } (rang est une chaine)
|
||||||
|
nb_ex = 0 # nb d'ex-aequo consécutifs en cours
|
||||||
|
for i in range(len(T)):
|
||||||
|
# test ex-aequo
|
||||||
|
if i < len(T) - 1:
|
||||||
|
next = T[i + 1][0]
|
||||||
|
else:
|
||||||
|
next = None
|
||||||
|
moy = T[i][0]
|
||||||
|
if nb_ex:
|
||||||
|
srang = "%d ex" % (i + 1 - nb_ex)
|
||||||
|
if moy == next:
|
||||||
|
nb_ex += 1
|
||||||
|
else:
|
||||||
|
nb_ex = 0
|
||||||
|
else:
|
||||||
|
if moy == next:
|
||||||
|
srang = "%d ex" % (i + 1 - nb_ex)
|
||||||
|
nb_ex = 1
|
||||||
|
else:
|
||||||
|
srang = "%d" % (i + 1)
|
||||||
|
rangs[T[i][-1]] = srang # str(i+1)
|
||||||
|
return rangs
|
||||||
|
|
||||||
|
|
||||||
def gen_cell(key: str, row: dict, elt="td", with_col_class=False):
|
def gen_cell(key: str, row: dict, elt="td", with_col_class=False):
|
||||||
"html table cell"
|
"html table cell"
|
||||||
klass = row.get(f"_{key}_class", "")
|
klass = row.get(f"_{key}_class", "")
|
||||||
|
@ -3383,22 +3383,3 @@ def check_formsemestre_integrity(formsemestre_id):
|
|||||||
return (
|
return (
|
||||||
html_sco_header.sco_header() + "<br>".join(diag) + html_sco_header.sco_footer()
|
html_sco_header.sco_header() + "<br>".join(diag) + html_sco_header.sco_footer()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/check_integrity_all")
|
|
||||||
@scodoc
|
|
||||||
@permission_required(Permission.ScoView)
|
|
||||||
@scodoc7func
|
|
||||||
def check_integrity_all():
|
|
||||||
"debug: verifie tous les semestres et tt les formations"
|
|
||||||
# formations
|
|
||||||
for F in sco_formations.formation_list():
|
|
||||||
check_form_integrity(F["formation_id"])
|
|
||||||
# semestres
|
|
||||||
for sem in sco_formsemestre.do_formsemestre_list():
|
|
||||||
check_formsemestre_integrity(sem["formsemestre_id"])
|
|
||||||
return (
|
|
||||||
html_sco_header.sco_header()
|
|
||||||
+ "<p>empty page: see logs and mails</p>"
|
|
||||||
+ html_sco_header.sco_footer()
|
|
||||||
)
|
|
||||||
|
@ -14,20 +14,16 @@ import sys
|
|||||||
import string
|
import string
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
|
from app import db, log
|
||||||
from config import Config
|
|
||||||
from app.auth.models import User
|
from app.auth.models import User
|
||||||
from app.models import FormationModalite, Matiere
|
from app.models import Formation, FormationModalite, Matiere
|
||||||
from app.scodoc import notesdb as ndb
|
from app.scodoc import notesdb as ndb
|
||||||
from app.scodoc import codes_cursus
|
from app.scodoc import codes_cursus
|
||||||
from app.scodoc import sco_edit_formation
|
|
||||||
from app.scodoc import sco_edit_matiere
|
from app.scodoc import sco_edit_matiere
|
||||||
from app.scodoc import sco_edit_module
|
from app.scodoc import sco_edit_module
|
||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
from app.scodoc import sco_evaluations
|
|
||||||
from app.scodoc import sco_evaluation_db
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formations
|
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_formsemestre_inscriptions
|
from app.scodoc import sco_formsemestre_inscriptions
|
||||||
from app.scodoc import sco_formsemestre_validation
|
from app.scodoc import sco_formsemestre_validation
|
||||||
@ -35,8 +31,8 @@ from app.scodoc import sco_moduleimpl
|
|||||||
from app.scodoc import sco_saisie_notes
|
from app.scodoc import sco_saisie_notes
|
||||||
from app.scodoc import sco_synchro_etuds
|
from app.scodoc import sco_synchro_etuds
|
||||||
from app.scodoc import sco_utils as scu
|
from app.scodoc import sco_utils as scu
|
||||||
from app import log
|
|
||||||
from app.scodoc.sco_exceptions import ScoValueError
|
from app.scodoc.sco_exceptions import ScoValueError
|
||||||
|
from config import Config
|
||||||
|
|
||||||
from tests.unit.setup import NOTES_T
|
from tests.unit.setup import NOTES_T
|
||||||
|
|
||||||
@ -161,11 +157,17 @@ class ScoFake(object):
|
|||||||
"""Crée une formation"""
|
"""Crée une formation"""
|
||||||
if not acronyme:
|
if not acronyme:
|
||||||
acronyme = "TEST" + str(random.randint(100000, 999999))
|
acronyme = "TEST" + str(random.randint(100000, 999999))
|
||||||
oid = sco_edit_formation.do_formation_create(locals())
|
formation = Formation(
|
||||||
oids = sco_formations.formation_list(formation_id=oid)
|
acronyme=scu.strip_str(acronyme),
|
||||||
if not oids:
|
titre=scu.strip_str(titre),
|
||||||
raise ScoValueError("formation not created !")
|
titre_officiel=scu.strip_str(titre_officiel),
|
||||||
return oid
|
type_parcours=scu.strip_str(type_parcours),
|
||||||
|
formation_code=scu.strip_str(formation_code),
|
||||||
|
code_specialite=scu.strip_str(code_specialite),
|
||||||
|
)
|
||||||
|
db.session.add(formation)
|
||||||
|
db.session.commit()
|
||||||
|
return formation.id
|
||||||
|
|
||||||
@logging_meth
|
@logging_meth
|
||||||
def create_ue(
|
def create_ue(
|
||||||
|
@ -29,7 +29,6 @@
|
|||||||
# - create_module
|
# - create_module
|
||||||
# - create_formsemestre
|
# - create_formsemestre
|
||||||
# - create_moduleimpl
|
# - create_moduleimpl
|
||||||
# - formation_list
|
|
||||||
# - formation_export
|
# - formation_export
|
||||||
# - formsemestre_list
|
# - formsemestre_list
|
||||||
# - moduleimpl_list
|
# - moduleimpl_list
|
||||||
@ -73,7 +72,7 @@ def test_formations(test_client):
|
|||||||
formation_id = G.create_formation(
|
formation_id = G.create_formation(
|
||||||
acronyme="F1", titre="Formation 1", titre_officiel="Titre officiel 1"
|
acronyme="F1", titre="Formation 1", titre_officiel="Titre officiel 1"
|
||||||
)
|
)
|
||||||
f = sco_formations.formation_list(formation_id)[0]
|
f = Formation.query.get(formation_id).to_dict()
|
||||||
ue_id = G.create_ue(formation_id=formation_id, acronyme="TST1", titre="ue test")
|
ue_id = G.create_ue(formation_id=formation_id, acronyme="TST1", titre="ue test")
|
||||||
matiere_id = G.create_matiere(ue_id=ue_id, titre="matière test")
|
matiere_id = G.create_matiere(ue_id=ue_id, titre="matière test")
|
||||||
module_id = G.create_module(
|
module_id = G.create_module(
|
||||||
@ -102,7 +101,7 @@ def test_formations(test_client):
|
|||||||
)
|
)
|
||||||
|
|
||||||
formation_id2 = G.create_formation(acronyme="", titre="Formation test")
|
formation_id2 = G.create_formation(acronyme="", titre="Formation test")
|
||||||
formation2 = sco_formations.formation_list(formation_id2)[0]
|
assert Formation.query.get(formation_id2)
|
||||||
ue3 = G.create_ue(formation_id=formation_id2, acronyme="TST3", titre="ue test3")
|
ue3 = G.create_ue(formation_id=formation_id2, acronyme="TST3", titre="ue test3")
|
||||||
matiere_id4 = G.create_matiere(ue_id=ue3, titre="matière test3")
|
matiere_id4 = G.create_matiere(ue_id=ue3, titre="matière test3")
|
||||||
module_id3 = G.create_module(
|
module_id3 = G.create_module(
|
||||||
|
Loading…
Reference in New Issue
Block a user