forked from ScoDoc/ScoDoc
- Coef evaluations (modèles).
- Refactoring. - Changement des noms des classes (modèles) des formations. - Début intégration calculs BUT. - Requiert numpy et pandas.
This commit is contained in:
parent
d71b399c3d
commit
89e7250f4a
@ -357,7 +357,7 @@ def sco_db_insert_constants():
|
|||||||
|
|
||||||
current_app.logger.info("Init Sco db")
|
current_app.logger.info("Init Sco db")
|
||||||
# Modalités:
|
# Modalités:
|
||||||
models.NotesFormModalite.insert_modalites()
|
models.FormationModalite.insert_modalites()
|
||||||
|
|
||||||
|
|
||||||
def initialize_scodoc_database(erase=False, create_all=False):
|
def initialize_scodoc_database(erase=False, create_all=False):
|
||||||
|
54
app/comp/moy_ue.py
Normal file
54
app/comp/moy_ue.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gestion scolarite IUT
|
||||||
|
#
|
||||||
|
# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Emmanuel Viennet emmanuel.viennet@viennet.net
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
"""Fonctions de calcul des moyennes d'UE
|
||||||
|
"""
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
from app import db
|
||||||
|
from app import models
|
||||||
|
|
||||||
|
|
||||||
|
def df_load_ue_coefs(formation_id):
|
||||||
|
"""Load coefs of all modules in formation and returns a DataFrame
|
||||||
|
rows = modules, columns = UE, value = coef.
|
||||||
|
Unspecified coefs (not defined in db) are set to zero.
|
||||||
|
"""
|
||||||
|
ues = models.UniteEns.query.filter_by(formation_id=formation_id).all()
|
||||||
|
modules = models.Module.query.filter_by(formation_id=formation_id).all()
|
||||||
|
ue_ids = [ue.id for ue in ues]
|
||||||
|
module_ids = [module.id for module in modules]
|
||||||
|
df = pd.DataFrame(columns=ue_ids, index=module_ids, dtype=float)
|
||||||
|
for mod_coef in (
|
||||||
|
db.session.query(models.ModuleUECoef)
|
||||||
|
.filter(models.UniteEns.formation_id == formation_id)
|
||||||
|
.filter(models.ModuleUECoef.ue_id == models.UniteEns.id)
|
||||||
|
):
|
||||||
|
df[mod_coef.ue_id][mod_coef.module_id] = mod_coef.coef
|
||||||
|
df.fillna(value=0, inplace=True)
|
||||||
|
return df
|
@ -31,26 +31,27 @@ from app.models.etudiants import (
|
|||||||
)
|
)
|
||||||
from app.models.events import Scolog, ScolarNews
|
from app.models.events import Scolog, ScolarNews
|
||||||
from app.models.formations import (
|
from app.models.formations import (
|
||||||
NotesFormation,
|
Formation,
|
||||||
NotesUE,
|
UniteEns,
|
||||||
NotesMatiere,
|
Matiere,
|
||||||
NotesModule,
|
Module,
|
||||||
|
ModuleUECoef,
|
||||||
NotesTag,
|
NotesTag,
|
||||||
notes_modules_tags,
|
notes_modules_tags,
|
||||||
)
|
)
|
||||||
from app.models.formsemestre import (
|
from app.models.formsemestre import (
|
||||||
FormSemestre,
|
FormSemestre,
|
||||||
NotesFormsemestreEtape,
|
FormsemestreEtape,
|
||||||
NotesFormModalite,
|
FormationModalite,
|
||||||
NotesFormsemestreUECoef,
|
FormsemestreUECoef,
|
||||||
NotesFormsemestreUEComputationExpr,
|
FormsemestreUEComputationExpr,
|
||||||
NotesFormsemestreCustomMenu,
|
FormsemestreCustomMenu,
|
||||||
NotesFormsemestreInscription,
|
FormsemestreInscription,
|
||||||
notes_formsemestre_responsables,
|
notes_formsemestre_responsables,
|
||||||
NotesModuleImpl,
|
ModuleImpl,
|
||||||
notes_modules_enseignants,
|
notes_modules_enseignants,
|
||||||
NotesModuleImplInscription,
|
ModuleImplInscription,
|
||||||
NotesEvaluation,
|
Evaluation,
|
||||||
EvaluationUEPoids,
|
EvaluationUEPoids,
|
||||||
NotesSemSet,
|
NotesSemSet,
|
||||||
notes_semset_formsemestre,
|
notes_semset_formsemestre,
|
||||||
@ -61,7 +62,7 @@ from app.models.notes import (
|
|||||||
ScolarEvent,
|
ScolarEvent,
|
||||||
ScolarFormsemestreValidation,
|
ScolarFormsemestreValidation,
|
||||||
ScolarAutorisationInscription,
|
ScolarAutorisationInscription,
|
||||||
NotesAppreciations,
|
BulAppreciations,
|
||||||
NotesNotes,
|
NotesNotes,
|
||||||
NotesNotesLog,
|
NotesNotesLog,
|
||||||
)
|
)
|
||||||
|
@ -22,7 +22,7 @@ class AppCrit(db.Model):
|
|||||||
titre = db.Column(db.Text(), info={"label": "Titre"})
|
titre = db.Column(db.Text(), info={"label": "Titre"})
|
||||||
|
|
||||||
modules = db.relationship(
|
modules = db.relationship(
|
||||||
"NotesModule", secondary=Modules_ACs, lazy="dynamic", backref="acs"
|
"Module", secondary=Modules_ACs, lazy="dynamic", backref="acs"
|
||||||
)
|
)
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
|
@ -21,9 +21,7 @@ class Departement(db.Model):
|
|||||||
|
|
||||||
entreprises = db.relationship("Entreprise", lazy="dynamic", backref="departement")
|
entreprises = db.relationship("Entreprise", lazy="dynamic", backref="departement")
|
||||||
etudiants = db.relationship("Identite", lazy="dynamic", backref="departement")
|
etudiants = db.relationship("Identite", lazy="dynamic", backref="departement")
|
||||||
formations = db.relationship(
|
formations = db.relationship("Formation", lazy="dynamic", backref="departement")
|
||||||
"NotesFormation", lazy="dynamic", backref="departement"
|
|
||||||
)
|
|
||||||
formsemestres = db.relationship(
|
formsemestres = db.relationship(
|
||||||
"FormSemestre", lazy="dynamic", backref="departement"
|
"FormSemestre", lazy="dynamic", backref="departement"
|
||||||
)
|
)
|
||||||
|
@ -5,10 +5,11 @@ from typing import Any
|
|||||||
from app import db
|
from app import db
|
||||||
from app.models import APO_CODE_STR_LEN
|
from app.models import APO_CODE_STR_LEN
|
||||||
from app.models import SHORT_STR_LEN
|
from app.models import SHORT_STR_LEN
|
||||||
|
from app.scodoc import sco_utils as scu
|
||||||
from app.scodoc.sco_utils import ModuleType
|
from app.scodoc.sco_utils import ModuleType
|
||||||
|
|
||||||
|
|
||||||
class NotesFormation(db.Model):
|
class Formation(db.Model):
|
||||||
"""Programme pédagogique d'une formation"""
|
"""Programme pédagogique d'une formation"""
|
||||||
|
|
||||||
__tablename__ = "notes_formations"
|
__tablename__ = "notes_formations"
|
||||||
@ -31,16 +32,16 @@ class NotesFormation(db.Model):
|
|||||||
type_parcours = db.Column(db.Integer, default=0, server_default="0")
|
type_parcours = db.Column(db.Integer, default=0, server_default="0")
|
||||||
code_specialite = db.Column(db.String(SHORT_STR_LEN))
|
code_specialite = db.Column(db.String(SHORT_STR_LEN))
|
||||||
|
|
||||||
ues = db.relationship("NotesUE", backref="formation", lazy="dynamic")
|
ues = db.relationship("UniteEns", backref="formation", lazy="dynamic")
|
||||||
formsemestres = db.relationship("FormSemestre", lazy="dynamic", backref="formation")
|
formsemestres = db.relationship("FormSemestre", lazy="dynamic", backref="formation")
|
||||||
ues = db.relationship("NotesUE", lazy="dynamic", backref="formation")
|
ues = db.relationship("UniteEns", lazy="dynamic", backref="formation")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.__class__.__name__}(id={self.id}, dept_id={self.dept_id}, acronyme='{self.acronyme}')>"
|
return f"<{self.__class__.__name__}(id={self.id}, dept_id={self.dept_id}, acronyme='{self.acronyme}')>"
|
||||||
|
|
||||||
|
|
||||||
class NotesUE(db.Model):
|
class UniteEns(db.Model):
|
||||||
"""Unité d'Enseignement"""
|
"""Unité d'Enseignement (UE)"""
|
||||||
|
|
||||||
__tablename__ = "notes_ue"
|
__tablename__ = "notes_ue"
|
||||||
|
|
||||||
@ -68,14 +69,14 @@ class NotesUE(db.Model):
|
|||||||
coefficient = db.Column(db.Float)
|
coefficient = db.Column(db.Float)
|
||||||
|
|
||||||
# relations
|
# relations
|
||||||
matieres = db.relationship("NotesMatiere", lazy="dynamic", backref="ue")
|
matieres = db.relationship("Matiere", lazy="dynamic", backref="ue")
|
||||||
modules = db.relationship("NotesModule", lazy="dynamic", backref="ue")
|
modules = db.relationship("Module", lazy="dynamic", backref="ue")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.__class__.__name__}(id={self.id}, formation_id={self.formation_id}, acronyme='{self.acronyme}')>"
|
return f"<{self.__class__.__name__}(id={self.id}, formation_id={self.formation_id}, acronyme='{self.acronyme}')>"
|
||||||
|
|
||||||
|
|
||||||
class NotesMatiere(db.Model):
|
class Matiere(db.Model):
|
||||||
"""Matières: regroupe les modules d'une UE
|
"""Matières: regroupe les modules d'une UE
|
||||||
La matière a peu d'utilité en dehors de la présentation des modules
|
La matière a peu d'utilité en dehors de la présentation des modules
|
||||||
d'une UE.
|
d'une UE.
|
||||||
@ -90,10 +91,10 @@ class NotesMatiere(db.Model):
|
|||||||
titre = db.Column(db.Text())
|
titre = db.Column(db.Text())
|
||||||
numero = db.Column(db.Integer) # ordre de présentation
|
numero = db.Column(db.Integer) # ordre de présentation
|
||||||
|
|
||||||
modules = db.relationship("NotesModule", lazy="dynamic", backref="matiere")
|
modules = db.relationship("Module", lazy="dynamic", backref="matiere")
|
||||||
|
|
||||||
|
|
||||||
class NotesModule(db.Model):
|
class Module(db.Model):
|
||||||
"""Module"""
|
"""Module"""
|
||||||
|
|
||||||
__tablename__ = "notes_modules"
|
__tablename__ = "notes_modules"
|
||||||
@ -107,7 +108,7 @@ class NotesModule(db.Model):
|
|||||||
heures_cours = db.Column(db.Float)
|
heures_cours = db.Column(db.Float)
|
||||||
heures_td = db.Column(db.Float)
|
heures_td = db.Column(db.Float)
|
||||||
heures_tp = db.Column(db.Float)
|
heures_tp = db.Column(db.Float)
|
||||||
coefficient = db.Column(db.Float) # coef PPN
|
coefficient = db.Column(db.Float) # coef PPN (sauf en APC)
|
||||||
ects = db.Column(db.Float) # Crédits ECTS
|
ects = db.Column(db.Float) # Crédits ECTS
|
||||||
ue_id = db.Column(db.Integer, db.ForeignKey("notes_ue.id"), index=True)
|
ue_id = db.Column(db.Integer, db.ForeignKey("notes_ue.id"), index=True)
|
||||||
formation_id = db.Column(db.Integer, db.ForeignKey("notes_formations.id"))
|
formation_id = db.Column(db.Integer, db.ForeignKey("notes_formations.id"))
|
||||||
@ -120,13 +121,75 @@ class NotesModule(db.Model):
|
|||||||
# Type: ModuleType: DEFAULT, MALUS, RESSOURCE, MODULE_SAE (enum)
|
# Type: ModuleType: DEFAULT, MALUS, RESSOURCE, MODULE_SAE (enum)
|
||||||
module_type = db.Column(db.Integer)
|
module_type = db.Column(db.Integer)
|
||||||
# Relations:
|
# Relations:
|
||||||
modimpls = db.relationship("NotesModuleImpl", backref="module", lazy="dynamic")
|
modimpls = db.relationship("ModuleImpl", backref="module", lazy="dynamic")
|
||||||
|
ues_apc = db.relationship("UniteEns", secondary="module_ue_coef", viewonly=True)
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.ue_coefs = []
|
||||||
|
super(Module, self).__init__(**kwargs)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return (
|
return (
|
||||||
f"<Module{ModuleType(self.module_type).name} id={self.id} code={self.code}>"
|
f"<Module{ModuleType(self.module_type).name} id={self.id} code={self.code}>"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def type_name(self):
|
||||||
|
return scu.MODULE_TYPE_NAMES[self.module_type]
|
||||||
|
|
||||||
|
def set_ue_coef(self, ue, coef: float) -> None:
|
||||||
|
"""Set coef module vers cette UE"""
|
||||||
|
self.update_ue_coef_dict({ue.id: coef})
|
||||||
|
|
||||||
|
def set_ue_coef_dict(self, ue_coef_dict: dict) -> None:
|
||||||
|
"""set coefs vers les UE (remplace existants)
|
||||||
|
ue_coef_dict = { ue_id : coef }
|
||||||
|
"""
|
||||||
|
ue_coefs = []
|
||||||
|
for ue_id, coef in ue_coef_dict.items():
|
||||||
|
ue = UniteEns.query.get(ue_id)
|
||||||
|
ue_coefs.append(ModuleUECoef(module=self, ue=ue, coef=coef))
|
||||||
|
self.ue_coefs = ue_coefs
|
||||||
|
|
||||||
|
def update_ue_coef_dict(self, ue_coef_dict: dict):
|
||||||
|
"""update coefs vers UE (ajoute aux existants)"""
|
||||||
|
current = self.get_ue_coef_dict()
|
||||||
|
current.update(ue_coef_dict)
|
||||||
|
self.set_ue_coef_dict(current)
|
||||||
|
|
||||||
|
def get_ue_coef_dict(self):
|
||||||
|
"""returns { ue_id : coef }"""
|
||||||
|
return {p.ue.id: p.coef for p in self.ue_coefs}
|
||||||
|
|
||||||
|
def delete_ue_coef(self, ue):
|
||||||
|
"""delete coef"""
|
||||||
|
ue_coef = ModuleUECoef.query.get((self.id, ue.id))
|
||||||
|
db.session.delete(ue_coef)
|
||||||
|
|
||||||
|
|
||||||
|
class ModuleUECoef(db.Model):
|
||||||
|
"""Coefficients des modules vers les UE (APC, BUT)
|
||||||
|
En mode APC, ces coefs remplacent le coefficient "PPN" du module.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = "module_ue_coef"
|
||||||
|
|
||||||
|
module_id = db.Column(
|
||||||
|
db.Integer, db.ForeignKey("notes_modules.id"), primary_key=True
|
||||||
|
)
|
||||||
|
ue_id = db.Column(db.Integer, db.ForeignKey("notes_ue.id"), primary_key=True)
|
||||||
|
coef = db.Column(
|
||||||
|
db.Float,
|
||||||
|
nullable=False,
|
||||||
|
)
|
||||||
|
module = db.relationship(
|
||||||
|
Module,
|
||||||
|
backref=db.backref("ue_coefs", cascade="all, delete-orphan"),
|
||||||
|
)
|
||||||
|
ue = db.relationship(
|
||||||
|
UniteEns,
|
||||||
|
backref=db.backref("module_ue_coefs", cascade="all, delete-orphan"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class NotesTag(db.Model):
|
class NotesTag(db.Model):
|
||||||
"""Tag sur un module"""
|
"""Tag sur un module"""
|
||||||
|
@ -8,7 +8,10 @@ from app import db
|
|||||||
from app.models import APO_CODE_STR_LEN
|
from app.models import APO_CODE_STR_LEN
|
||||||
from app.models import SHORT_STR_LEN
|
from app.models import SHORT_STR_LEN
|
||||||
from app.models import CODE_STR_LEN
|
from app.models import CODE_STR_LEN
|
||||||
from app.models import NotesUE
|
from app.models import UniteEns
|
||||||
|
|
||||||
|
import app.scodoc.notesdb as ndb
|
||||||
|
from app.scodoc import sco_evaluation_db
|
||||||
|
|
||||||
|
|
||||||
class FormSemestre(db.Model):
|
class FormSemestre(db.Model):
|
||||||
@ -73,11 +76,9 @@ class FormSemestre(db.Model):
|
|||||||
|
|
||||||
# Relations:
|
# Relations:
|
||||||
etapes = db.relationship(
|
etapes = db.relationship(
|
||||||
"NotesFormsemestreEtape", cascade="all,delete", backref="formsemestre"
|
"FormsemestreEtape", cascade="all,delete", backref="formsemestre"
|
||||||
)
|
|
||||||
formsemestres = db.relationship(
|
|
||||||
"NotesModuleImpl", backref="formsemestre", lazy="dynamic"
|
|
||||||
)
|
)
|
||||||
|
modimpls = db.relationship("ModuleImpl", backref="formsemestre", lazy="dynamic")
|
||||||
|
|
||||||
# Ancien id ScoDoc7 pour les migrations de bases anciennes
|
# Ancien id ScoDoc7 pour les migrations de bases anciennes
|
||||||
# ne pas utiliser après migrate_scodoc7_dept_archives
|
# ne pas utiliser après migrate_scodoc7_dept_archives
|
||||||
@ -86,7 +87,7 @@ class FormSemestre(db.Model):
|
|||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(FormSemestre, self).__init__(**kwargs)
|
super(FormSemestre, self).__init__(**kwargs)
|
||||||
if self.modalite is None:
|
if self.modalite is None:
|
||||||
self.modalite = NotesFormModalite.DEFAULT_MODALITE
|
self.modalite = FormationModalite.DEFAULT_MODALITE
|
||||||
|
|
||||||
|
|
||||||
# Association id des utilisateurs responsables (aka directeurs des etudes) du semestre
|
# Association id des utilisateurs responsables (aka directeurs des etudes) du semestre
|
||||||
@ -101,7 +102,7 @@ notes_formsemestre_responsables = db.Table(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class NotesFormsemestreEtape(db.Model):
|
class FormsemestreEtape(db.Model):
|
||||||
"""Étape Apogée associées au semestre"""
|
"""Étape Apogée associées au semestre"""
|
||||||
|
|
||||||
__tablename__ = "notes_formsemestre_etapes"
|
__tablename__ = "notes_formsemestre_etapes"
|
||||||
@ -113,7 +114,7 @@ class NotesFormsemestreEtape(db.Model):
|
|||||||
etape_apo = db.Column(db.String(APO_CODE_STR_LEN))
|
etape_apo = db.Column(db.String(APO_CODE_STR_LEN))
|
||||||
|
|
||||||
|
|
||||||
class NotesFormModalite(db.Model):
|
class FormationModalite(db.Model):
|
||||||
"""Modalités de formation, utilisées pour la présentation
|
"""Modalités de formation, utilisées pour la présentation
|
||||||
(grouper les semestres, générer des codes, etc.)
|
(grouper les semestres, générer des codes, etc.)
|
||||||
"""
|
"""
|
||||||
@ -140,7 +141,7 @@ class NotesFormModalite(db.Model):
|
|||||||
numero = 0
|
numero = 0
|
||||||
try:
|
try:
|
||||||
for (code, titre) in (
|
for (code, titre) in (
|
||||||
(NotesFormModalite.DEFAULT_MODALITE, "Formation Initiale"),
|
(FormationModalite.DEFAULT_MODALITE, "Formation Initiale"),
|
||||||
("FAP", "Apprentissage"),
|
("FAP", "Apprentissage"),
|
||||||
("FC", "Formation Continue"),
|
("FC", "Formation Continue"),
|
||||||
("DEC", "Formation Décalées"),
|
("DEC", "Formation Décalées"),
|
||||||
@ -151,9 +152,9 @@ class NotesFormModalite(db.Model):
|
|||||||
("EXT", "Extérieur"),
|
("EXT", "Extérieur"),
|
||||||
("OTHER", "Autres formations"),
|
("OTHER", "Autres formations"),
|
||||||
):
|
):
|
||||||
modalite = NotesFormModalite.query.filter_by(modalite=code).first()
|
modalite = FormationModalite.query.filter_by(modalite=code).first()
|
||||||
if modalite is None:
|
if modalite is None:
|
||||||
modalite = NotesFormModalite(
|
modalite = FormationModalite(
|
||||||
modalite=code, titre=titre, numero=numero
|
modalite=code, titre=titre, numero=numero
|
||||||
)
|
)
|
||||||
db.session.add(modalite)
|
db.session.add(modalite)
|
||||||
@ -164,7 +165,7 @@ class NotesFormModalite(db.Model):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
class NotesFormsemestreUECoef(db.Model):
|
class FormsemestreUECoef(db.Model):
|
||||||
"""Coef des UE capitalisees arrivant dans ce semestre"""
|
"""Coef des UE capitalisees arrivant dans ce semestre"""
|
||||||
|
|
||||||
__tablename__ = "notes_formsemestre_uecoef"
|
__tablename__ = "notes_formsemestre_uecoef"
|
||||||
@ -183,7 +184,7 @@ class NotesFormsemestreUECoef(db.Model):
|
|||||||
coefficient = db.Column(db.Float, nullable=False)
|
coefficient = db.Column(db.Float, nullable=False)
|
||||||
|
|
||||||
|
|
||||||
class NotesFormsemestreUEComputationExpr(db.Model):
|
class FormsemestreUEComputationExpr(db.Model):
|
||||||
"""Formules utilisateurs pour calcul moyenne UE"""
|
"""Formules utilisateurs pour calcul moyenne UE"""
|
||||||
|
|
||||||
__tablename__ = "notes_formsemestre_ue_computation_expr"
|
__tablename__ = "notes_formsemestre_ue_computation_expr"
|
||||||
@ -203,7 +204,7 @@ class NotesFormsemestreUEComputationExpr(db.Model):
|
|||||||
computation_expr = db.Column(db.Text())
|
computation_expr = db.Column(db.Text())
|
||||||
|
|
||||||
|
|
||||||
class NotesFormsemestreCustomMenu(db.Model):
|
class FormsemestreCustomMenu(db.Model):
|
||||||
"""Menu custom associe au semestre"""
|
"""Menu custom associe au semestre"""
|
||||||
|
|
||||||
__tablename__ = "notes_formsemestre_custommenu"
|
__tablename__ = "notes_formsemestre_custommenu"
|
||||||
@ -219,7 +220,7 @@ class NotesFormsemestreCustomMenu(db.Model):
|
|||||||
idx = db.Column(db.Integer, default=0, server_default="0") # rang dans le menu
|
idx = db.Column(db.Integer, default=0, server_default="0") # rang dans le menu
|
||||||
|
|
||||||
|
|
||||||
class NotesFormsemestreInscription(db.Model):
|
class FormsemestreInscription(db.Model):
|
||||||
"""Inscription à un semestre de formation"""
|
"""Inscription à un semestre de formation"""
|
||||||
|
|
||||||
__tablename__ = "notes_formsemestre_inscription"
|
__tablename__ = "notes_formsemestre_inscription"
|
||||||
@ -239,7 +240,7 @@ class NotesFormsemestreInscription(db.Model):
|
|||||||
etape = db.Column(db.String(APO_CODE_STR_LEN))
|
etape = db.Column(db.String(APO_CODE_STR_LEN))
|
||||||
|
|
||||||
|
|
||||||
class NotesModuleImpl(db.Model):
|
class ModuleImpl(db.Model):
|
||||||
"""Mise en oeuvre d'un module pour une annee/semestre"""
|
"""Mise en oeuvre d'un module pour une annee/semestre"""
|
||||||
|
|
||||||
__tablename__ = "notes_moduleimpl"
|
__tablename__ = "notes_moduleimpl"
|
||||||
@ -275,7 +276,7 @@ notes_modules_enseignants = db.Table(
|
|||||||
# XXX il manque probablement une relation pour gérer cela
|
# XXX il manque probablement une relation pour gérer cela
|
||||||
|
|
||||||
|
|
||||||
class NotesModuleImplInscription(db.Model):
|
class ModuleImplInscription(db.Model):
|
||||||
"""Inscription à un module (etudiants,moduleimpl)"""
|
"""Inscription à un module (etudiants,moduleimpl)"""
|
||||||
|
|
||||||
__tablename__ = "notes_moduleimpl_inscription"
|
__tablename__ = "notes_moduleimpl_inscription"
|
||||||
@ -291,7 +292,7 @@ class NotesModuleImplInscription(db.Model):
|
|||||||
etudid = db.Column(db.Integer, db.ForeignKey("identite.id"), index=True)
|
etudid = db.Column(db.Integer, db.ForeignKey("identite.id"), index=True)
|
||||||
|
|
||||||
|
|
||||||
class NotesEvaluation(db.Model):
|
class Evaluation(db.Model):
|
||||||
"""Evaluation (contrôle, examen, ...)"""
|
"""Evaluation (contrôle, examen, ...)"""
|
||||||
|
|
||||||
__tablename__ = "notes_evaluation"
|
__tablename__ = "notes_evaluation"
|
||||||
@ -306,7 +307,7 @@ class NotesEvaluation(db.Model):
|
|||||||
heure_fin = db.Column(db.Time)
|
heure_fin = db.Column(db.Time)
|
||||||
description = db.Column(db.Text)
|
description = db.Column(db.Text)
|
||||||
note_max = db.Column(db.Float)
|
note_max = db.Column(db.Float)
|
||||||
coefficient = db.Column(db.Float) # non BUT
|
coefficient = db.Column(db.Float)
|
||||||
visibulletin = db.Column(
|
visibulletin = db.Column(
|
||||||
db.Boolean, nullable=False, default=True, server_default="true"
|
db.Boolean, nullable=False, default=True, server_default="true"
|
||||||
)
|
)
|
||||||
@ -320,7 +321,34 @@ class NotesEvaluation(db.Model):
|
|||||||
# ordre de presentation (par défaut, le plus petit numero
|
# ordre de presentation (par défaut, le plus petit numero
|
||||||
# est la plus ancienne eval):
|
# est la plus ancienne eval):
|
||||||
numero = db.Column(db.Integer)
|
numero = db.Column(db.Integer)
|
||||||
ues = db.relationship("NotesUE", secondary="evaluation_ue_poids", viewonly=True)
|
ues = db.relationship("UniteEns", secondary="evaluation_ue_poids", viewonly=True)
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
e = dict(self.__dict__)
|
||||||
|
e.pop("_sa_instance_state", None)
|
||||||
|
# ScoDoc7 output_formators
|
||||||
|
e["jour"] = ndb.DateISOtoDMY(e["jour"])
|
||||||
|
e["numero"] = ndb.int_null_is_zero(e["numero"])
|
||||||
|
return sco_evaluation_db.evaluation_enrich_dict(e)
|
||||||
|
|
||||||
|
# def from_dict(self, data):
|
||||||
|
# """Set evaluation attributes from given dict values."""
|
||||||
|
# sco_evaluation_db._check_evaluation_args(data)
|
||||||
|
# for field in [
|
||||||
|
# "moduleimpl_id",
|
||||||
|
# "jour",
|
||||||
|
# "heure_debut",
|
||||||
|
# "heure_fin",
|
||||||
|
# "description",
|
||||||
|
# "note_max",
|
||||||
|
# "coefficient",
|
||||||
|
# "visibulletin",
|
||||||
|
# "publish_incomplete",
|
||||||
|
# "evaluation_type",
|
||||||
|
# "numero",
|
||||||
|
# ]:
|
||||||
|
# if field in data:
|
||||||
|
# setattr(self, field, data[field] or None)
|
||||||
|
|
||||||
def set_ue_poids(self, ue, poids: float):
|
def set_ue_poids(self, ue, poids: float):
|
||||||
"""Set poids évaluation vers cette UE"""
|
"""Set poids évaluation vers cette UE"""
|
||||||
@ -332,7 +360,7 @@ class NotesEvaluation(db.Model):
|
|||||||
"""
|
"""
|
||||||
L = []
|
L = []
|
||||||
for ue_id, poids in ue_poids_dict.items():
|
for ue_id, poids in ue_poids_dict.items():
|
||||||
ue = NotesUE.query.get(ue_id)
|
ue = UniteEns.query.get(ue_id)
|
||||||
L.append(EvaluationUEPoids(evaluation=self, ue=ue, poids=poids))
|
L.append(EvaluationUEPoids(evaluation=self, ue=ue, poids=poids))
|
||||||
self.ue_poids = L
|
self.ue_poids = L
|
||||||
|
|
||||||
@ -361,11 +389,12 @@ class EvaluationUEPoids(db.Model):
|
|||||||
nullable=False,
|
nullable=False,
|
||||||
)
|
)
|
||||||
evaluation = db.relationship(
|
evaluation = db.relationship(
|
||||||
NotesEvaluation,
|
Evaluation,
|
||||||
backref=db.backref("ue_poids", cascade="all, delete-orphan"),
|
backref=db.backref("ue_poids", cascade="all, delete-orphan"),
|
||||||
)
|
)
|
||||||
ue = db.relationship(
|
ue = db.relationship(
|
||||||
NotesUE, backref=db.backref("evaluation_ue_poids", cascade="all, delete-orphan")
|
UniteEns,
|
||||||
|
backref=db.backref("evaluation_ue_poids", cascade="all, delete-orphan"),
|
||||||
)
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -100,9 +100,10 @@ class ScolarAutorisationInscription(db.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class NotesAppreciations(db.Model):
|
class BulAppreciations(db.Model):
|
||||||
"""Appréciations sur bulletins"""
|
"""Appréciations sur bulletins"""
|
||||||
|
|
||||||
|
__tablename__ = "notes_appreciations"
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
|
date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
|
||||||
etudid = db.Column(
|
etudid = db.Column(
|
||||||
|
@ -34,6 +34,7 @@ from flask import g, url_for
|
|||||||
|
|
||||||
from app.models import ScoDocSiteConfig
|
from app.models import ScoDocSiteConfig
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
from app.scodoc.sco_utils import ModuleType
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.sco_formulas import NoteVector
|
from app.scodoc.sco_formulas import NoteVector
|
||||||
@ -607,7 +608,7 @@ class NotesTable(object):
|
|||||||
# si 'NI', etudiant non inscrit a ce module
|
# si 'NI', etudiant non inscrit a ce module
|
||||||
if val != "NI":
|
if val != "NI":
|
||||||
est_inscrit = True
|
est_inscrit = True
|
||||||
if modimpl["module"]["module_type"] == scu.MODULE_STANDARD:
|
if modimpl["module"]["module_type"] == ModuleType.STANDARD:
|
||||||
coef = modimpl["module"]["coefficient"]
|
coef = modimpl["module"]["coefficient"]
|
||||||
if modimpl["ue"]["type"] != UE_SPORT:
|
if modimpl["ue"]["type"] != UE_SPORT:
|
||||||
notes.append(val, name=modimpl["module"]["code"])
|
notes.append(val, name=modimpl["module"]["code"])
|
||||||
@ -644,11 +645,17 @@ class NotesTable(object):
|
|||||||
except:
|
except:
|
||||||
# log('comp_etud_moy_ue: exception: val=%s coef=%s' % (val,coef))
|
# log('comp_etud_moy_ue: exception: val=%s coef=%s' % (val,coef))
|
||||||
pass
|
pass
|
||||||
elif modimpl["module"]["module_type"] == scu.MODULE_MALUS:
|
elif modimpl["module"]["module_type"] == ModuleType.MALUS:
|
||||||
try:
|
try:
|
||||||
ue_malus += val
|
ue_malus += val
|
||||||
except:
|
except:
|
||||||
pass # si non inscrit ou manquant, ignore
|
pass # si non inscrit ou manquant, ignore
|
||||||
|
elif modimpl["module"]["module_type"] in (
|
||||||
|
ModuleType.RESSOURCE,
|
||||||
|
ModuleType.SAE,
|
||||||
|
):
|
||||||
|
# XXX temporaire pour ne pas bloquer durant le dev
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"invalid module type (%s)" % modimpl["module"]["module_type"]
|
"invalid module type (%s)" % modimpl["module"]["module_type"]
|
||||||
@ -672,7 +679,7 @@ class NotesTable(object):
|
|||||||
|
|
||||||
# Recalcule la moyenne en utilisant une formule utilisateur
|
# Recalcule la moyenne en utilisant une formule utilisateur
|
||||||
expr_diag = {}
|
expr_diag = {}
|
||||||
formula = sco_compute_moy.get_ue_expression(self.formsemestre_id, ue_id, cnx)
|
formula = sco_compute_moy.get_ue_expression(self.formsemestre_id, ue_id)
|
||||||
if formula:
|
if formula:
|
||||||
moy = sco_compute_moy.compute_user_formula(
|
moy = sco_compute_moy.compute_user_formula(
|
||||||
self.sem,
|
self.sem,
|
||||||
|
@ -53,7 +53,7 @@ def close_db_connection():
|
|||||||
del g.db_conn
|
del g.db_conn
|
||||||
|
|
||||||
|
|
||||||
def GetDBConnexion(autocommit=True): # on n'utilise plus autocommit
|
def GetDBConnexion():
|
||||||
return g.db_conn
|
return g.db_conn
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ from flask_login import current_user
|
|||||||
from flask_mail import Message
|
from flask_mail import Message
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
from app.scodoc.sco_utils import ModuleType
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
@ -59,7 +60,7 @@ from app.scodoc import sco_bulletins_xml
|
|||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
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_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_groups
|
from app.scodoc import sco_groups
|
||||||
@ -428,7 +429,7 @@ def _ue_mod_bulletin(etudid, formsemestre_id, ue_id, modimpls, nt, version):
|
|||||||
mod_moy = nt.get_etud_mod_moy(
|
mod_moy = nt.get_etud_mod_moy(
|
||||||
modimpl["moduleimpl_id"], etudid
|
modimpl["moduleimpl_id"], etudid
|
||||||
) # peut etre 'NI'
|
) # peut etre 'NI'
|
||||||
is_malus = mod["module"]["module_type"] == scu.MODULE_MALUS
|
is_malus = mod["module"]["module_type"] == ModuleType.MALUS
|
||||||
if bul_show_abs_modules:
|
if bul_show_abs_modules:
|
||||||
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem)
|
||||||
mod_abs = [nbabs, nbabsjust]
|
mod_abs = [nbabs, nbabsjust]
|
||||||
@ -558,7 +559,7 @@ def _ue_mod_bulletin(etudid, formsemestre_id, ue_id, modimpls, nt, version):
|
|||||||
mod["evaluations_incompletes"] = []
|
mod["evaluations_incompletes"] = []
|
||||||
if sco_preferences.get_preference("bul_show_all_evals", formsemestre_id):
|
if sco_preferences.get_preference("bul_show_all_evals", formsemestre_id):
|
||||||
complete_eval_ids = set([e["evaluation_id"] for e in evals])
|
complete_eval_ids = set([e["evaluation_id"] for e in evals])
|
||||||
all_evals = sco_evaluations.do_evaluation_list(
|
all_evals = sco_evaluation_db.do_evaluation_list(
|
||||||
args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
||||||
)
|
)
|
||||||
all_evals.reverse() # plus ancienne d'abord
|
all_evals.reverse() # plus ancienne d'abord
|
||||||
|
@ -36,7 +36,7 @@ import app.scodoc.notesdb as ndb
|
|||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_groups
|
from app.scodoc import sco_groups
|
||||||
from app.scodoc import sco_photos
|
from app.scodoc import sco_photos
|
||||||
@ -277,7 +277,7 @@ def formsemestre_bulletinetud_published_dict(
|
|||||||
if sco_preferences.get_preference(
|
if sco_preferences.get_preference(
|
||||||
"bul_show_all_evals", formsemestre_id
|
"bul_show_all_evals", formsemestre_id
|
||||||
):
|
):
|
||||||
all_evals = sco_evaluations.do_evaluation_list(
|
all_evals = sco_evaluation_db.do_evaluation_list(
|
||||||
args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
||||||
)
|
)
|
||||||
all_evals.reverse() # plus ancienne d'abord
|
all_evals.reverse() # plus ancienne d'abord
|
||||||
|
@ -51,7 +51,7 @@ from app.scodoc import sco_abs
|
|||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_groups
|
from app.scodoc import sco_groups
|
||||||
from app.scodoc import sco_photos
|
from app.scodoc import sco_photos
|
||||||
@ -289,7 +289,7 @@ def make_xml_formsemestre_bulletinetud(
|
|||||||
if sco_preferences.get_preference(
|
if sco_preferences.get_preference(
|
||||||
"bul_show_all_evals", formsemestre_id
|
"bul_show_all_evals", formsemestre_id
|
||||||
):
|
):
|
||||||
all_evals = sco_evaluations.do_evaluation_list(
|
all_evals = sco_evaluation_db.do_evaluation_list(
|
||||||
args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
args={"moduleimpl_id": modimpl["moduleimpl_id"]}
|
||||||
)
|
)
|
||||||
all_evals.reverse() # plus ancienne d'abord
|
all_evals.reverse() # plus ancienne d'abord
|
||||||
|
@ -34,6 +34,7 @@ from flask import url_for, g
|
|||||||
import app.scodoc.sco_utils as scu
|
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 (
|
from app.scodoc.sco_utils import (
|
||||||
|
ModuleType,
|
||||||
NOTES_ATTENTE,
|
NOTES_ATTENTE,
|
||||||
NOTES_NEUTRALISE,
|
NOTES_NEUTRALISE,
|
||||||
EVALUATION_NORMALE,
|
EVALUATION_NORMALE,
|
||||||
@ -44,7 +45,7 @@ from app.scodoc.sco_exceptions import ScoValueError
|
|||||||
from app import log
|
from app import log
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
from app.scodoc import sco_edit_module
|
from app.scodoc import sco_edit_module
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluation_db
|
||||||
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_formulas
|
from app.scodoc import sco_formulas
|
||||||
@ -103,8 +104,9 @@ formsemestre_ue_computation_expr_list = _formsemestre_ue_computation_exprEditor.
|
|||||||
formsemestre_ue_computation_expr_edit = _formsemestre_ue_computation_exprEditor.edit
|
formsemestre_ue_computation_expr_edit = _formsemestre_ue_computation_exprEditor.edit
|
||||||
|
|
||||||
|
|
||||||
def get_ue_expression(formsemestre_id, ue_id, cnx, html_quote=False):
|
def get_ue_expression(formsemestre_id, ue_id, html_quote=False):
|
||||||
"""Returns UE expression (formula), or None if no expression has been defined"""
|
"""Returns UE expression (formula), or None if no expression has been defined"""
|
||||||
|
cnx = ndb.GetDBConnexion()
|
||||||
el = formsemestre_ue_computation_expr_list(
|
el = formsemestre_ue_computation_expr_list(
|
||||||
cnx, {"formsemestre_id": formsemestre_id, "ue_id": ue_id}
|
cnx, {"formsemestre_id": formsemestre_id, "ue_id": ue_id}
|
||||||
)
|
)
|
||||||
@ -203,7 +205,7 @@ def compute_moduleimpl_moyennes(nt, modimpl):
|
|||||||
"""
|
"""
|
||||||
diag_info = {} # message d'erreur formule
|
diag_info = {} # message d'erreur formule
|
||||||
moduleimpl_id = modimpl["moduleimpl_id"]
|
moduleimpl_id = modimpl["moduleimpl_id"]
|
||||||
is_malus = modimpl["module"]["module_type"] == scu.MODULE_MALUS
|
is_malus = modimpl["module"]["module_type"] == ModuleType.MALUS
|
||||||
sem = sco_formsemestre.get_formsemestre(modimpl["formsemestre_id"])
|
sem = sco_formsemestre.get_formsemestre(modimpl["formsemestre_id"])
|
||||||
etudids = sco_moduleimpl.moduleimpl_listeetuds(
|
etudids = sco_moduleimpl.moduleimpl_listeetuds(
|
||||||
moduleimpl_id
|
moduleimpl_id
|
||||||
@ -230,7 +232,7 @@ def compute_moduleimpl_moyennes(nt, modimpl):
|
|||||||
eval_rattr = None
|
eval_rattr = None
|
||||||
for e in evals:
|
for e in evals:
|
||||||
e["nb_inscrits"] = e["etat"]["nb_inscrits"]
|
e["nb_inscrits"] = e["etat"]["nb_inscrits"]
|
||||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(
|
NotesDB = sco_evaluation_db.do_evaluation_get_all_notes(
|
||||||
e["evaluation_id"]
|
e["evaluation_id"]
|
||||||
) # toutes, y compris demissions
|
) # toutes, y compris demissions
|
||||||
# restreint aux étudiants encore inscrits à ce module
|
# restreint aux étudiants encore inscrits à ce module
|
||||||
|
@ -29,11 +29,13 @@
|
|||||||
(portage from DTML)
|
(portage from DTML)
|
||||||
"""
|
"""
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for, g, request
|
from flask import url_for, render_template
|
||||||
|
from flask import g, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
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.scodoc.sco_utils import ModuleType
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator
|
from app.scodoc.TrivialFormulator import TrivialFormulator
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
@ -44,22 +46,6 @@ from app.scodoc import sco_edit_matiere
|
|||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
from app.scodoc import sco_news
|
from app.scodoc import sco_news
|
||||||
|
|
||||||
_MODULE_HELP = """<p class="help">
|
|
||||||
Les modules sont décrits dans le programme pédagogique. Un module est pour ce
|
|
||||||
logiciel l'unité pédagogique élémentaire. On va lui associer une note
|
|
||||||
à travers des <em>évaluations</em>. <br/>
|
|
||||||
Cette note (moyenne de module) sera utilisée pour calculer la moyenne
|
|
||||||
générale (et la moyenne de l'UE à laquelle appartient le module). Pour
|
|
||||||
cela, on utilisera le <em>coefficient</em> associé au module.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p class="help">Un module possède un enseignant responsable
|
|
||||||
(typiquement celui qui dispense le cours magistral). On peut associer
|
|
||||||
au module une liste d'enseignants (typiquement les chargés de TD).
|
|
||||||
Tous ces enseignants, plus le responsable du semestre, pourront
|
|
||||||
saisir et modifier les notes de ce module.
|
|
||||||
</p> """
|
|
||||||
|
|
||||||
_moduleEditor = ndb.EditableTable(
|
_moduleEditor = ndb.EditableTable(
|
||||||
"notes_modules",
|
"notes_modules",
|
||||||
"module_id",
|
"module_id",
|
||||||
@ -120,27 +106,30 @@ def do_module_create(args) -> int:
|
|||||||
|
|
||||||
|
|
||||||
def module_create(matiere_id=None):
|
def module_create(matiere_id=None):
|
||||||
"""Creation d'un module"""
|
"""Création d'un module"""
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
|
|
||||||
if matiere_id is None:
|
if matiere_id is None:
|
||||||
raise ScoValueError("invalid matiere !")
|
raise ScoValueError("invalid matiere !")
|
||||||
M = sco_edit_matiere.matiere_list(args={"matiere_id": matiere_id})[0]
|
matiere = sco_edit_matiere.matiere_list(args={"matiere_id": matiere_id})[0]
|
||||||
UE = sco_edit_ue.ue_list(args={"ue_id": M["ue_id"]})[0]
|
UE = sco_edit_ue.ue_list(args={"ue_id": matiere["ue_id"]})[0]
|
||||||
Fo = sco_formations.formation_list(args={"formation_id": UE["formation_id"]})[0]
|
formation = sco_formations.formation_list(
|
||||||
parcours = sco_codes_parcours.get_parcours_from_code(Fo["type_parcours"])
|
args={"formation_id": UE["formation_id"]}
|
||||||
|
)[0]
|
||||||
|
parcours = sco_codes_parcours.get_parcours_from_code(formation["type_parcours"])
|
||||||
|
is_apc = parcours.APC_SAE
|
||||||
semestres_indices = list(range(1, parcours.NB_SEM + 1))
|
semestres_indices = list(range(1, parcours.NB_SEM + 1))
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(page_title="Création d'un module"),
|
html_sco_header.sco_header(page_title="Création d'un module"),
|
||||||
"""<h2>Création d'un module dans la matière %(titre)s""" % M,
|
"""<h2>Création d'un module dans la matière %(titre)s""" % matiere,
|
||||||
""" (UE %(acronyme)s)</h2>""" % UE,
|
""" (UE %(acronyme)s)</h2>""" % UE,
|
||||||
_MODULE_HELP,
|
render_template("scodoc/help/modules.html", is_apc=is_apc),
|
||||||
]
|
]
|
||||||
# cherche le numero adequat (pour placer le module en fin de liste)
|
# cherche le numero adéquat (pour placer le module en fin de liste)
|
||||||
Mods = module_list(args={"matiere_id": matiere_id})
|
modules = module_list(args={"matiere_id": matiere_id})
|
||||||
if Mods:
|
if modules:
|
||||||
default_num = max([m["numero"] for m in Mods]) + 10
|
default_num = max([m["numero"] for m in modules]) + 10
|
||||||
else:
|
else:
|
||||||
default_num = 10
|
default_num = 10
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
@ -153,7 +142,7 @@ def module_create(matiere_id=None):
|
|||||||
"size": 10,
|
"size": 10,
|
||||||
"explanation": "code du module (doit être unique dans la formation)",
|
"explanation": "code du module (doit être unique dans la formation)",
|
||||||
"allow_null": False,
|
"allow_null": False,
|
||||||
"validator": lambda val, field, formation_id=Fo[
|
"validator": lambda val, field, formation_id=formation[
|
||||||
"formation_id"
|
"formation_id"
|
||||||
]: check_module_code_unicity(val, field, formation_id),
|
]: check_module_code_unicity(val, field, formation_id),
|
||||||
},
|
},
|
||||||
@ -166,8 +155,8 @@ def module_create(matiere_id=None):
|
|||||||
"input_type": "menu",
|
"input_type": "menu",
|
||||||
"title": "Type",
|
"title": "Type",
|
||||||
"explanation": "",
|
"explanation": "",
|
||||||
"labels": ("Standard", "Malus"),
|
"labels": [x.name.capitalize() for x in scu.ModuleType],
|
||||||
"allowed_values": (str(scu.MODULE_STANDARD), str(scu.MODULE_MALUS)),
|
"allowed_values": [str(int(x)) for x in scu.ModuleType],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -201,8 +190,8 @@ def module_create(matiere_id=None):
|
|||||||
),
|
),
|
||||||
# ('ects', { 'size' : 4, 'type' : 'float', 'title' : 'ECTS', 'explanation' : 'nombre de crédits ECTS (inutilisés: les crédits sont associés aux UE)' }),
|
# ('ects', { 'size' : 4, 'type' : 'float', 'title' : 'ECTS', 'explanation' : 'nombre de crédits ECTS (inutilisés: les crédits sont associés aux UE)' }),
|
||||||
("formation_id", {"default": UE["formation_id"], "input_type": "hidden"}),
|
("formation_id", {"default": UE["formation_id"], "input_type": "hidden"}),
|
||||||
("ue_id", {"default": M["ue_id"], "input_type": "hidden"}),
|
("ue_id", {"default": matiere["ue_id"], "input_type": "hidden"}),
|
||||||
("matiere_id", {"default": M["matiere_id"], "input_type": "hidden"}),
|
("matiere_id", {"default": matiere["matiere_id"], "input_type": "hidden"}),
|
||||||
(
|
(
|
||||||
"semestre_id",
|
"semestre_id",
|
||||||
{
|
{
|
||||||
@ -350,35 +339,38 @@ def module_edit(module_id=None):
|
|||||||
|
|
||||||
if not module_id:
|
if not module_id:
|
||||||
raise ScoValueError("invalid module !")
|
raise ScoValueError("invalid module !")
|
||||||
Mod = module_list(args={"module_id": module_id})
|
modules = module_list(args={"module_id": module_id})
|
||||||
if not Mod:
|
if not modules:
|
||||||
raise ScoValueError("invalid module !")
|
raise ScoValueError("invalid module !")
|
||||||
Mod = Mod[0]
|
module = modules[0]
|
||||||
unlocked = not module_is_locked(module_id)
|
unlocked = not module_is_locked(module_id)
|
||||||
Fo = sco_formations.formation_list(args={"formation_id": Mod["formation_id"]})[0]
|
formation = sco_formations.formation_list(
|
||||||
parcours = sco_codes_parcours.get_parcours_from_code(Fo["type_parcours"])
|
args={"formation_id": module["formation_id"]}
|
||||||
M = ndb.SimpleDictFetch(
|
)[0]
|
||||||
|
parcours = sco_codes_parcours.get_parcours_from_code(formation["type_parcours"])
|
||||||
|
is_apc = parcours.APC_SAE
|
||||||
|
ues_matieres = ndb.SimpleDictFetch(
|
||||||
"""SELECT ue.acronyme, mat.*, mat.id AS matiere_id
|
"""SELECT ue.acronyme, mat.*, mat.id AS matiere_id
|
||||||
FROM notes_matieres mat, notes_ue ue
|
FROM notes_matieres mat, notes_ue ue
|
||||||
WHERE mat.ue_id = ue.id
|
WHERE mat.ue_id = ue.id
|
||||||
AND ue.formation_id = %(formation_id)s
|
AND ue.formation_id = %(formation_id)s
|
||||||
ORDER BY ue.numero, mat.numero
|
ORDER BY ue.numero, mat.numero
|
||||||
""",
|
""",
|
||||||
{"formation_id": Mod["formation_id"]},
|
{"formation_id": module["formation_id"]},
|
||||||
)
|
)
|
||||||
Mnames = ["%s / %s" % (x["acronyme"], x["titre"]) for x in M]
|
mat_names = ["%s / %s" % (x["acronyme"], x["titre"]) for x in ues_matieres]
|
||||||
Mids = ["%s!%s" % (x["ue_id"], x["matiere_id"]) for x in M]
|
ue_mat_ids = ["%s!%s" % (x["ue_id"], x["matiere_id"]) for x in ues_matieres]
|
||||||
Mod["ue_matiere_id"] = "%s!%s" % (Mod["ue_id"], Mod["matiere_id"])
|
module["ue_matiere_id"] = "%s!%s" % (module["ue_id"], module["matiere_id"])
|
||||||
|
|
||||||
semestres_indices = list(range(1, parcours.NB_SEM + 1))
|
semestres_indices = list(range(1, parcours.NB_SEM + 1))
|
||||||
dest_url = url_for(
|
dest_url = url_for(
|
||||||
"notes.ue_table",
|
"notes.ue_table",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
formation_id=str(Mod["formation_id"]),
|
formation_id=str(module["formation_id"]),
|
||||||
)
|
)
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(
|
html_sco_header.sco_header(
|
||||||
page_title="Modification du module %(titre)s" % Mod,
|
page_title="Modification du module %(titre)s" % module,
|
||||||
cssstyles=["libjs/jQuery-tagEditor/jquery.tag-editor.css"],
|
cssstyles=["libjs/jQuery-tagEditor/jquery.tag-editor.css"],
|
||||||
javascripts=[
|
javascripts=[
|
||||||
"libjs/jQuery-tagEditor/jquery.tag-editor.min.js",
|
"libjs/jQuery-tagEditor/jquery.tag-editor.min.js",
|
||||||
@ -386,9 +378,9 @@ def module_edit(module_id=None):
|
|||||||
"js/module_tag_editor.js",
|
"js/module_tag_editor.js",
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
"""<h2>Modification du module %(titre)s""" % Mod,
|
"""<h2>Modification du module %(titre)s""" % module,
|
||||||
""" (formation %(acronyme)s, version %(version)s)</h2>""" % Fo,
|
""" (formation %(acronyme)s, version %(version)s)</h2>""" % formation,
|
||||||
_MODULE_HELP,
|
render_template("scodoc/help/modules.html", is_apc=is_apc),
|
||||||
]
|
]
|
||||||
if not unlocked:
|
if not unlocked:
|
||||||
H.append(
|
H.append(
|
||||||
@ -405,7 +397,7 @@ def module_edit(module_id=None):
|
|||||||
"size": 10,
|
"size": 10,
|
||||||
"explanation": "code du module (doit être unique dans la formation)",
|
"explanation": "code du module (doit être unique dans la formation)",
|
||||||
"allow_null": False,
|
"allow_null": False,
|
||||||
"validator": lambda val, field, formation_id=Mod[
|
"validator": lambda val, field, formation_id=module[
|
||||||
"formation_id"
|
"formation_id"
|
||||||
]: check_module_code_unicity(
|
]: check_module_code_unicity(
|
||||||
val, field, formation_id, module_id=module_id
|
val, field, formation_id, module_id=module_id
|
||||||
@ -465,8 +457,8 @@ def module_edit(module_id=None):
|
|||||||
"input_type": "menu",
|
"input_type": "menu",
|
||||||
"title": "Matière",
|
"title": "Matière",
|
||||||
"explanation": "un module appartient à une seule matière.",
|
"explanation": "un module appartient à une seule matière.",
|
||||||
"labels": Mnames,
|
"labels": mat_names,
|
||||||
"allowed_values": Mids,
|
"allowed_values": ue_mat_ids,
|
||||||
"enabled": unlocked,
|
"enabled": unlocked,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -503,7 +495,7 @@ def module_edit(module_id=None):
|
|||||||
html_foot_markup="""<div style="width: 90%;"><span class="sco_tag_edit"><textarea data-module_id="{}" class="module_tag_editor">{}</textarea></span></div>""".format(
|
html_foot_markup="""<div style="width: 90%;"><span class="sco_tag_edit"><textarea data-module_id="{}" class="module_tag_editor">{}</textarea></span></div>""".format(
|
||||||
module_id, ",".join(sco_tag_module.module_tag_list(module_id))
|
module_id, ",".join(sco_tag_module.module_tag_list(module_id))
|
||||||
),
|
),
|
||||||
initvalues=Mod,
|
initvalues=module,
|
||||||
submitlabel="Modifier ce module",
|
submitlabel="Modifier ce module",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -602,7 +594,7 @@ def formation_add_malus_modules(formation_id, titre=None, redirect=True):
|
|||||||
[
|
[
|
||||||
mod
|
mod
|
||||||
for mod in module_list(args={"ue_id": ue["ue_id"]})
|
for mod in module_list(args={"ue_id": ue["ue_id"]})
|
||||||
if mod["module_type"] == scu.MODULE_MALUS
|
if mod["module_type"] == ModuleType.MALUS
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
if nb_mod_malus == 0:
|
if nb_mod_malus == 0:
|
||||||
@ -654,7 +646,7 @@ def ue_add_malus_module(ue_id, titre=None, code=None):
|
|||||||
"matiere_id": matiere_id,
|
"matiere_id": matiere_id,
|
||||||
"formation_id": ue["formation_id"],
|
"formation_id": ue["formation_id"],
|
||||||
"semestre_id": semestre_id,
|
"semestre_id": semestre_id,
|
||||||
"module_type": scu.MODULE_MALUS,
|
"module_type": ModuleType.MALUS,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,9 +32,10 @@ import flask
|
|||||||
from flask import g, url_for, request
|
from flask import g, url_for, request
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
from app.models.formations import NotesUE
|
from app.models.formations import UniteEns
|
||||||
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.scodoc.sco_utils import ModuleType
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator, TF
|
from app.scodoc.TrivialFormulator import TrivialFormulator, TF
|
||||||
from app.scodoc.gen_tables import GenTable
|
from app.scodoc.gen_tables import GenTable
|
||||||
@ -955,7 +956,7 @@ def _ue_table_modules(
|
|||||||
mod["module_id"]
|
mod["module_id"]
|
||||||
)
|
)
|
||||||
klass = "notes_module_list"
|
klass = "notes_module_list"
|
||||||
if mod["module_type"] == scu.MODULE_MALUS:
|
if mod["module_type"] == ModuleType.MALUS:
|
||||||
klass += " module_malus"
|
klass += " module_malus"
|
||||||
H.append('<li class="%s">' % klass)
|
H.append('<li class="%s">' % klass)
|
||||||
|
|
||||||
@ -1066,20 +1067,20 @@ def ue_sharing_code(ue_code=None, ue_id=None, hide_ue_id=None):
|
|||||||
formation_code = F["formation_code"]
|
formation_code = F["formation_code"]
|
||||||
# UE du même code, code formation et departement:
|
# UE du même code, code formation et departement:
|
||||||
q_ues = (
|
q_ues = (
|
||||||
NotesUE.query.filter_by(ue_code=ue_code)
|
UniteEns.query.filter_by(ue_code=ue_code)
|
||||||
.join(NotesUE.formation, aliased=True)
|
.join(UniteEns.formation, aliased=True)
|
||||||
.filter_by(dept_id=g.scodoc_dept_id, formation_code=formation_code)
|
.filter_by(dept_id=g.scodoc_dept_id, formation_code=formation_code)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# Toutes les UE du departement avec ce code:
|
# Toutes les UE du departement avec ce code:
|
||||||
q_ues = (
|
q_ues = (
|
||||||
NotesUE.query.filter_by(ue_code=ue_code)
|
UniteEns.query.filter_by(ue_code=ue_code)
|
||||||
.join(NotesUE.formation, aliased=True)
|
.join(UniteEns.formation, aliased=True)
|
||||||
.filter_by(dept_id=g.scodoc_dept_id)
|
.filter_by(dept_id=g.scodoc_dept_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
if hide_ue_id: # enlève l'ue de depart
|
if hide_ue_id: # enlève l'ue de depart
|
||||||
q_ues = q_ues.filter(NotesUE.id != hide_ue_id)
|
q_ues = q_ues.filter(UniteEns.id != hide_ue_id)
|
||||||
|
|
||||||
ues = q_ues.all()
|
ues = q_ues.all()
|
||||||
if not ues:
|
if not ues:
|
||||||
|
482
app/scodoc/sco_evaluation_db.py
Normal file
482
app/scodoc/sco_evaluation_db.py
Normal file
@ -0,0 +1,482 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gestion scolarite IUT
|
||||||
|
#
|
||||||
|
# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Emmanuel Viennet emmanuel.viennet@gmail.com
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
"""Gestion evaluations (ScoDoc7, sans SQlAlchemy)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
import flask
|
||||||
|
from flask import url_for, g
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
|
from app import log
|
||||||
|
import app.scodoc.sco_utils as scu
|
||||||
|
import app.scodoc.notesdb as ndb
|
||||||
|
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||||
|
|
||||||
|
from app.scodoc import sco_cache
|
||||||
|
from app.scodoc import sco_edit_module
|
||||||
|
from app.scodoc import sco_formsemestre
|
||||||
|
from app.scodoc import sco_moduleimpl
|
||||||
|
from app.scodoc import sco_news
|
||||||
|
from app.scodoc import sco_permissions_check
|
||||||
|
|
||||||
|
|
||||||
|
_evaluationEditor = ndb.EditableTable(
|
||||||
|
"notes_evaluation",
|
||||||
|
"evaluation_id",
|
||||||
|
(
|
||||||
|
"evaluation_id",
|
||||||
|
"moduleimpl_id",
|
||||||
|
"jour",
|
||||||
|
"heure_debut",
|
||||||
|
"heure_fin",
|
||||||
|
"description",
|
||||||
|
"note_max",
|
||||||
|
"coefficient",
|
||||||
|
"visibulletin",
|
||||||
|
"publish_incomplete",
|
||||||
|
"evaluation_type",
|
||||||
|
"numero",
|
||||||
|
),
|
||||||
|
sortkey="numero desc, jour desc, heure_debut desc", # plus recente d'abord
|
||||||
|
output_formators={
|
||||||
|
"jour": ndb.DateISOtoDMY,
|
||||||
|
"numero": ndb.int_null_is_zero,
|
||||||
|
},
|
||||||
|
input_formators={
|
||||||
|
"jour": ndb.DateDMYtoISO,
|
||||||
|
"heure_debut": ndb.TimetoISO8601, # converti par evaluation_enrich_dict
|
||||||
|
"heure_fin": ndb.TimetoISO8601, # converti par evaluation_enrich_dict
|
||||||
|
"visibulletin": bool,
|
||||||
|
"publish_incomplete": bool,
|
||||||
|
"evaluation_type": int,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def evaluation_enrich_dict(e):
|
||||||
|
"""add or convert some fileds in an evaluation dict"""
|
||||||
|
# For ScoDoc7 compat
|
||||||
|
heure_debut_dt = e["heure_debut"] or datetime.time(
|
||||||
|
8, 00
|
||||||
|
) # au cas ou pas d'heure (note externe?)
|
||||||
|
heure_fin_dt = e["heure_fin"] or datetime.time(8, 00)
|
||||||
|
e["heure_debut"] = ndb.TimefromISO8601(e["heure_debut"])
|
||||||
|
e["heure_fin"] = ndb.TimefromISO8601(e["heure_fin"])
|
||||||
|
e["jouriso"] = ndb.DateDMYtoISO(e["jour"])
|
||||||
|
heure_debut, heure_fin = e["heure_debut"], e["heure_fin"]
|
||||||
|
d = ndb.TimeDuration(heure_debut, heure_fin)
|
||||||
|
if d is not None:
|
||||||
|
m = d % 60
|
||||||
|
e["duree"] = "%dh" % (d / 60)
|
||||||
|
if m != 0:
|
||||||
|
e["duree"] += "%02d" % m
|
||||||
|
else:
|
||||||
|
e["duree"] = ""
|
||||||
|
if heure_debut and (not heure_fin or heure_fin == heure_debut):
|
||||||
|
e["descrheure"] = " à " + heure_debut
|
||||||
|
elif heure_debut and heure_fin:
|
||||||
|
e["descrheure"] = " de %s à %s" % (heure_debut, heure_fin)
|
||||||
|
else:
|
||||||
|
e["descrheure"] = ""
|
||||||
|
# matin, apresmidi: utile pour se referer aux absences:
|
||||||
|
if heure_debut_dt < datetime.time(12, 00):
|
||||||
|
e["matin"] = 1
|
||||||
|
else:
|
||||||
|
e["matin"] = 0
|
||||||
|
if heure_fin_dt > datetime.time(12, 00):
|
||||||
|
e["apresmidi"] = 1
|
||||||
|
else:
|
||||||
|
e["apresmidi"] = 0
|
||||||
|
return e
|
||||||
|
|
||||||
|
|
||||||
|
def do_evaluation_list(args, sortkey=None):
|
||||||
|
"""List evaluations, sorted by numero (or most recent date first).
|
||||||
|
|
||||||
|
Ajoute les champs:
|
||||||
|
'duree' : '2h30'
|
||||||
|
'matin' : 1 (commence avant 12:00) ou 0
|
||||||
|
'apresmidi' : 1 (termine après 12:00) ou 0
|
||||||
|
'descrheure' : ' de 15h00 à 16h30'
|
||||||
|
"""
|
||||||
|
# Attention: transformation fonction ScoDc7 en SQLAlchemy
|
||||||
|
cnx = ndb.GetDBConnexion()
|
||||||
|
evals = _evaluationEditor.list(cnx, args, sortkey=sortkey)
|
||||||
|
# calcule duree (chaine de car.) de chaque evaluation et ajoute jouriso, matin, apresmidi
|
||||||
|
for e in evals:
|
||||||
|
evaluation_enrich_dict(e)
|
||||||
|
|
||||||
|
return evals
|
||||||
|
|
||||||
|
|
||||||
|
def do_evaluation_list_in_formsemestre(formsemestre_id):
|
||||||
|
"list evaluations in this formsemestre"
|
||||||
|
mods = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
||||||
|
evals = []
|
||||||
|
for modimpl in mods:
|
||||||
|
evals += do_evaluation_list(args={"moduleimpl_id": modimpl["moduleimpl_id"]})
|
||||||
|
return evals
|
||||||
|
|
||||||
|
|
||||||
|
def _check_evaluation_args(args):
|
||||||
|
"Check coefficient, dates and duration, raises exception if invalid"
|
||||||
|
moduleimpl_id = args["moduleimpl_id"]
|
||||||
|
# check bareme
|
||||||
|
note_max = args.get("note_max", None)
|
||||||
|
if note_max is None:
|
||||||
|
raise ScoValueError("missing note_max")
|
||||||
|
try:
|
||||||
|
note_max = float(note_max)
|
||||||
|
except ValueError:
|
||||||
|
raise ScoValueError("Invalid note_max value")
|
||||||
|
if note_max < 0:
|
||||||
|
raise ScoValueError("Invalid note_max value (must be positive or null)")
|
||||||
|
# check coefficient
|
||||||
|
coef = args.get("coefficient", None)
|
||||||
|
if coef is None:
|
||||||
|
raise ScoValueError("missing coefficient")
|
||||||
|
try:
|
||||||
|
coef = float(coef)
|
||||||
|
except ValueError:
|
||||||
|
raise ScoValueError("Invalid coefficient value")
|
||||||
|
if coef < 0:
|
||||||
|
raise ScoValueError("Invalid coefficient value (must be positive or null)")
|
||||||
|
# check date
|
||||||
|
jour = args.get("jour", None)
|
||||||
|
args["jour"] = jour
|
||||||
|
if jour:
|
||||||
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
|
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
||||||
|
d, m, y = [int(x) for x in sem["date_debut"].split("/")]
|
||||||
|
date_debut = datetime.date(y, m, d)
|
||||||
|
d, m, y = [int(x) for x in sem["date_fin"].split("/")]
|
||||||
|
date_fin = datetime.date(y, m, d)
|
||||||
|
# passe par ndb.DateDMYtoISO pour avoir date pivot
|
||||||
|
y, m, d = [int(x) for x in ndb.DateDMYtoISO(jour).split("-")]
|
||||||
|
jour = datetime.date(y, m, d)
|
||||||
|
if (jour > date_fin) or (jour < date_debut):
|
||||||
|
raise ScoValueError(
|
||||||
|
"La date de l'évaluation (%s/%s/%s) n'est pas dans le semestre !"
|
||||||
|
% (d, m, y)
|
||||||
|
)
|
||||||
|
heure_debut = args.get("heure_debut", None)
|
||||||
|
args["heure_debut"] = heure_debut
|
||||||
|
heure_fin = args.get("heure_fin", None)
|
||||||
|
args["heure_fin"] = heure_fin
|
||||||
|
if jour and ((not heure_debut) or (not heure_fin)):
|
||||||
|
raise ScoValueError("Les heures doivent être précisées")
|
||||||
|
d = ndb.TimeDuration(heure_debut, heure_fin)
|
||||||
|
if d and ((d < 0) or (d > 60 * 12)):
|
||||||
|
raise ScoValueError("Heures de l'évaluation incohérentes !")
|
||||||
|
|
||||||
|
|
||||||
|
def do_evaluation_create(
|
||||||
|
moduleimpl_id=None,
|
||||||
|
jour=None,
|
||||||
|
heure_debut=None,
|
||||||
|
heure_fin=None,
|
||||||
|
description=None,
|
||||||
|
note_max=None,
|
||||||
|
coefficient=None,
|
||||||
|
visibulletin=None,
|
||||||
|
publish_incomplete=None,
|
||||||
|
evaluation_type=None,
|
||||||
|
numero=None,
|
||||||
|
**kw, # ceci pour absorber les arguments excedentaires de tf #sco8
|
||||||
|
):
|
||||||
|
"""Create an evaluation"""
|
||||||
|
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=moduleimpl_id):
|
||||||
|
raise AccessDenied(
|
||||||
|
"Modification évaluation impossible pour %s" % current_user.get_nomplogin()
|
||||||
|
)
|
||||||
|
args = locals()
|
||||||
|
log("do_evaluation_create: args=" + str(args))
|
||||||
|
_check_evaluation_args(args)
|
||||||
|
# Check numeros
|
||||||
|
module_evaluation_renumber(moduleimpl_id, only_if_unumbered=True)
|
||||||
|
if not "numero" in args or args["numero"] is None:
|
||||||
|
n = None
|
||||||
|
# determine le numero avec la date
|
||||||
|
# Liste des eval existantes triees par date, la plus ancienne en tete
|
||||||
|
mod_evals = do_evaluation_list(
|
||||||
|
args={"moduleimpl_id": moduleimpl_id},
|
||||||
|
sortkey="jour asc, heure_debut asc",
|
||||||
|
)
|
||||||
|
if args["jour"]:
|
||||||
|
next_eval = None
|
||||||
|
t = (
|
||||||
|
ndb.DateDMYtoISO(args["jour"], null_is_empty=True),
|
||||||
|
ndb.TimetoISO8601(args["heure_debut"], null_is_empty=True),
|
||||||
|
)
|
||||||
|
for e in mod_evals:
|
||||||
|
if (
|
||||||
|
ndb.DateDMYtoISO(e["jour"], null_is_empty=True),
|
||||||
|
ndb.TimetoISO8601(e["heure_debut"], null_is_empty=True),
|
||||||
|
) > t:
|
||||||
|
next_eval = e
|
||||||
|
break
|
||||||
|
if next_eval:
|
||||||
|
n = module_evaluation_insert_before(mod_evals, next_eval)
|
||||||
|
else:
|
||||||
|
n = None # a placer en fin
|
||||||
|
if n is None: # pas de date ou en fin:
|
||||||
|
if mod_evals:
|
||||||
|
log(pprint.pformat(mod_evals[-1]))
|
||||||
|
n = mod_evals[-1]["numero"] + 1
|
||||||
|
else:
|
||||||
|
n = 0 # the only one
|
||||||
|
# log("creating with numero n=%d" % n)
|
||||||
|
args["numero"] = n
|
||||||
|
|
||||||
|
#
|
||||||
|
cnx = ndb.GetDBConnexion()
|
||||||
|
r = _evaluationEditor.create(cnx, args)
|
||||||
|
|
||||||
|
# news
|
||||||
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
|
mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
|
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
||||||
|
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
||||||
|
sco_news.add(
|
||||||
|
typ=sco_news.NEWS_NOTE,
|
||||||
|
object=moduleimpl_id,
|
||||||
|
text='Création d\'une évaluation dans <a href="%(url)s">%(titre)s</a>' % mod,
|
||||||
|
url=mod["url"],
|
||||||
|
)
|
||||||
|
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def do_evaluation_edit(args):
|
||||||
|
"edit an evaluation"
|
||||||
|
evaluation_id = args["evaluation_id"]
|
||||||
|
the_evals = do_evaluation_list({"evaluation_id": evaluation_id})
|
||||||
|
if not the_evals:
|
||||||
|
raise ValueError("evaluation inexistante !")
|
||||||
|
moduleimpl_id = the_evals[0]["moduleimpl_id"]
|
||||||
|
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=moduleimpl_id):
|
||||||
|
raise AccessDenied(
|
||||||
|
"Modification évaluation impossible pour %s" % current_user.get_nomplogin()
|
||||||
|
)
|
||||||
|
args["moduleimpl_id"] = moduleimpl_id
|
||||||
|
_check_evaluation_args(args)
|
||||||
|
|
||||||
|
cnx = ndb.GetDBConnexion()
|
||||||
|
_evaluationEditor.edit(cnx, args)
|
||||||
|
# inval cache pour ce semestre
|
||||||
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
|
sco_cache.invalidate_formsemestre(formsemestre_id=M["formsemestre_id"])
|
||||||
|
|
||||||
|
|
||||||
|
def do_evaluation_delete(evaluation_id):
|
||||||
|
"delete evaluation"
|
||||||
|
the_evals = do_evaluation_list({"evaluation_id": evaluation_id})
|
||||||
|
if not the_evals:
|
||||||
|
raise ValueError("evaluation inexistante !")
|
||||||
|
moduleimpl_id = the_evals[0]["moduleimpl_id"]
|
||||||
|
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=moduleimpl_id):
|
||||||
|
raise AccessDenied(
|
||||||
|
"Modification évaluation impossible pour %s" % current_user.get_nomplogin()
|
||||||
|
)
|
||||||
|
NotesDB = do_evaluation_get_all_notes(evaluation_id) # { etudid : value }
|
||||||
|
notes = [x["value"] for x in NotesDB.values()]
|
||||||
|
if notes:
|
||||||
|
raise ScoValueError(
|
||||||
|
"Impossible de supprimer cette évaluation: il reste des notes"
|
||||||
|
)
|
||||||
|
|
||||||
|
cnx = ndb.GetDBConnexion()
|
||||||
|
|
||||||
|
_evaluationEditor.delete(cnx, evaluation_id)
|
||||||
|
# inval cache pour ce semestre
|
||||||
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
|
sco_cache.invalidate_formsemestre(formsemestre_id=M["formsemestre_id"])
|
||||||
|
# news
|
||||||
|
|
||||||
|
mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
|
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
||||||
|
mod["url"] = (
|
||||||
|
scu.NotesURL() + "/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
||||||
|
)
|
||||||
|
sco_news.add(
|
||||||
|
typ=sco_news.NEWS_NOTE,
|
||||||
|
object=moduleimpl_id,
|
||||||
|
text='Suppression d\'une évaluation dans <a href="%(url)s">%(titre)s</a>' % mod,
|
||||||
|
url=mod["url"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ancien _notes_getall
|
||||||
|
def do_evaluation_get_all_notes(
|
||||||
|
evaluation_id, table="notes_notes", filter_suppressed=True, by_uid=None
|
||||||
|
):
|
||||||
|
"""Toutes les notes pour une evaluation: { etudid : { 'value' : value, 'date' : date ... }}
|
||||||
|
Attention: inclut aussi les notes des étudiants qui ne sont plus inscrits au module.
|
||||||
|
"""
|
||||||
|
do_cache = (
|
||||||
|
filter_suppressed and table == "notes_notes" and (by_uid is None)
|
||||||
|
) # pas de cache pour (rares) appels via undo_notes ou specifiant un enseignant
|
||||||
|
if do_cache:
|
||||||
|
r = sco_cache.EvaluationCache.get(evaluation_id)
|
||||||
|
if r != None:
|
||||||
|
return r
|
||||||
|
cnx = ndb.GetDBConnexion()
|
||||||
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
|
cond = " where evaluation_id=%(evaluation_id)s"
|
||||||
|
if by_uid:
|
||||||
|
cond += " and uid=%(by_uid)s"
|
||||||
|
|
||||||
|
cursor.execute(
|
||||||
|
"select * from " + table + cond,
|
||||||
|
{"evaluation_id": evaluation_id, "by_uid": by_uid},
|
||||||
|
)
|
||||||
|
res = cursor.dictfetchall()
|
||||||
|
d = {}
|
||||||
|
if filter_suppressed:
|
||||||
|
for x in res:
|
||||||
|
if x["value"] != scu.NOTES_SUPPRESS:
|
||||||
|
d[x["etudid"]] = x
|
||||||
|
else:
|
||||||
|
for x in res:
|
||||||
|
d[x["etudid"]] = x
|
||||||
|
if do_cache:
|
||||||
|
status = sco_cache.EvaluationCache.set(evaluation_id, d)
|
||||||
|
if not status:
|
||||||
|
log(f"Warning: EvaluationCache.set: {evaluation_id}\t{status}")
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def module_evaluation_renumber(moduleimpl_id, only_if_unumbered=False, redirect=0):
|
||||||
|
"""Renumber evaluations in this module, according to their date. (numero=0: oldest one)
|
||||||
|
Needed because previous versions of ScoDoc did not have eval numeros
|
||||||
|
Note: existing numeros are ignored
|
||||||
|
"""
|
||||||
|
redirect = int(redirect)
|
||||||
|
# log('module_evaluation_renumber( moduleimpl_id=%s )' % moduleimpl_id )
|
||||||
|
# List sorted according to date/heure, ignoring numeros:
|
||||||
|
# (note that we place evaluations with NULL date at the end)
|
||||||
|
mod_evals = do_evaluation_list(
|
||||||
|
args={"moduleimpl_id": moduleimpl_id},
|
||||||
|
sortkey="jour asc, heure_debut asc",
|
||||||
|
)
|
||||||
|
|
||||||
|
all_numbered = False not in [x["numero"] > 0 for x in mod_evals]
|
||||||
|
if all_numbered and only_if_unumbered:
|
||||||
|
return # all ok
|
||||||
|
|
||||||
|
# Reset all numeros:
|
||||||
|
i = 1
|
||||||
|
for e in mod_evals:
|
||||||
|
e["numero"] = i
|
||||||
|
do_evaluation_edit(e)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
# If requested, redirect to moduleimpl page:
|
||||||
|
if redirect:
|
||||||
|
return flask.redirect(
|
||||||
|
url_for(
|
||||||
|
"notes.moduleimpl_status",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
moduleimpl_id=moduleimpl_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def module_evaluation_insert_before(mod_evals, next_eval):
|
||||||
|
"""Renumber evals such that an evaluation with can be inserted before next_eval
|
||||||
|
Returns numero suitable for the inserted evaluation
|
||||||
|
"""
|
||||||
|
if next_eval:
|
||||||
|
n = next_eval["numero"]
|
||||||
|
if not n:
|
||||||
|
log("renumbering old evals")
|
||||||
|
module_evaluation_renumber(next_eval["moduleimpl_id"])
|
||||||
|
next_eval = do_evaluation_list(
|
||||||
|
args={"evaluation_id": next_eval["evaluation_id"]}
|
||||||
|
)[0]
|
||||||
|
n = next_eval["numero"]
|
||||||
|
else:
|
||||||
|
n = 1
|
||||||
|
# log('inserting at position numero %s' % n )
|
||||||
|
# all numeros >= n are incremented
|
||||||
|
for e in mod_evals:
|
||||||
|
if e["numero"] >= n:
|
||||||
|
e["numero"] += 1
|
||||||
|
# log('incrementing %s to %s' % (e['evaluation_id'], e['numero']))
|
||||||
|
do_evaluation_edit(e)
|
||||||
|
|
||||||
|
return n
|
||||||
|
|
||||||
|
|
||||||
|
def module_evaluation_move(evaluation_id, after=0, redirect=1):
|
||||||
|
"""Move before/after previous one (decrement/increment numero)
|
||||||
|
(published)
|
||||||
|
"""
|
||||||
|
e = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
||||||
|
redirect = int(redirect)
|
||||||
|
# access: can change eval ?
|
||||||
|
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=e["moduleimpl_id"]):
|
||||||
|
raise AccessDenied(
|
||||||
|
"Modification évaluation impossible pour %s" % current_user.get_nomplogin()
|
||||||
|
)
|
||||||
|
|
||||||
|
module_evaluation_renumber(e["moduleimpl_id"], only_if_unumbered=True)
|
||||||
|
e = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
||||||
|
|
||||||
|
after = int(after) # 0: deplace avant, 1 deplace apres
|
||||||
|
if after not in (0, 1):
|
||||||
|
raise ValueError('invalid value for "after"')
|
||||||
|
mod_evals = do_evaluation_list({"moduleimpl_id": e["moduleimpl_id"]})
|
||||||
|
if len(mod_evals) > 1:
|
||||||
|
idx = [p["evaluation_id"] for p in mod_evals].index(evaluation_id)
|
||||||
|
neigh = None # object to swap with
|
||||||
|
if after == 0 and idx > 0:
|
||||||
|
neigh = mod_evals[idx - 1]
|
||||||
|
elif after == 1 and idx < len(mod_evals) - 1:
|
||||||
|
neigh = mod_evals[idx + 1]
|
||||||
|
if neigh: #
|
||||||
|
if neigh["numero"] == e["numero"]:
|
||||||
|
log("Warning: module_evaluation_move: forcing renumber")
|
||||||
|
module_evaluation_renumber(e["moduleimpl_id"], only_if_unumbered=False)
|
||||||
|
else:
|
||||||
|
# swap numero with neighbor
|
||||||
|
e["numero"], neigh["numero"] = neigh["numero"], e["numero"]
|
||||||
|
do_evaluation_edit(e)
|
||||||
|
do_evaluation_edit(neigh)
|
||||||
|
# redirect to moduleimpl page:
|
||||||
|
if redirect:
|
||||||
|
return flask.redirect(
|
||||||
|
url_for(
|
||||||
|
"notes.moduleimpl_status",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
moduleimpl_id=e["moduleimpl_id"],
|
||||||
|
)
|
||||||
|
)
|
332
app/scodoc/sco_evaluation_edit.py
Normal file
332
app/scodoc/sco_evaluation_edit.py
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gestion scolarite IUT
|
||||||
|
#
|
||||||
|
# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Emmanuel Viennet emmanuel.viennet@gmail.com
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
"""Formulaire ajout/édition d'une évaluation
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
import flask
|
||||||
|
from flask import url_for, render_template
|
||||||
|
from flask import g
|
||||||
|
from flask_login import current_user
|
||||||
|
from flask import request
|
||||||
|
|
||||||
|
from app import db
|
||||||
|
from app import log
|
||||||
|
from app import models
|
||||||
|
import app.scodoc.sco_utils as scu
|
||||||
|
from app.scodoc.sco_utils import ModuleType
|
||||||
|
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||||
|
from app.scodoc.TrivialFormulator import TrivialFormulator
|
||||||
|
from app.scodoc import html_sco_header
|
||||||
|
from app.scodoc import sco_evaluations
|
||||||
|
from app.scodoc import sco_evaluation_db
|
||||||
|
from app.scodoc import sco_moduleimpl
|
||||||
|
from app.scodoc import sco_permissions_check
|
||||||
|
|
||||||
|
|
||||||
|
def evaluation_create_form(
|
||||||
|
moduleimpl_id=None,
|
||||||
|
evaluation_id=None,
|
||||||
|
edit=False,
|
||||||
|
page_title="Évaluation",
|
||||||
|
):
|
||||||
|
"Formulaire création/édition d'une évaluation (pas de ses notes)"
|
||||||
|
if evaluation_id is not None:
|
||||||
|
evaluation = models.Evaluation.query.get(evaluation_id)
|
||||||
|
moduleimpl_id = evaluation.moduleimpl_id
|
||||||
|
#
|
||||||
|
modimpl = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
|
mod = modimpl["module"]
|
||||||
|
formsemestre_id = modimpl["formsemestre_id"]
|
||||||
|
sem_ues = db.session.query(models.UniteEns).filter(
|
||||||
|
models.ModuleImpl.formsemestre_id == formsemestre_id,
|
||||||
|
models.Module.id == models.ModuleImpl.module_id,
|
||||||
|
models.UniteEns.id == models.Module.ue_id,
|
||||||
|
)
|
||||||
|
is_malus = mod["module_type"] == ModuleType.MALUS
|
||||||
|
is_apc = mod["module_type"] in (ModuleType.RESSOURCE, ModuleType.SAE)
|
||||||
|
|
||||||
|
min_note_max = scu.NOTES_PRECISION # le plus petit bareme possible
|
||||||
|
#
|
||||||
|
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=moduleimpl_id):
|
||||||
|
return (
|
||||||
|
html_sco_header.sco_header()
|
||||||
|
+ "<h2>Opération non autorisée</h2><p>"
|
||||||
|
+ "Modification évaluation impossible pour %s"
|
||||||
|
% current_user.get_nomplogin()
|
||||||
|
+ "</p>"
|
||||||
|
+ '<p><a href="moduleimpl_status?moduleimpl_id=%s">Revenir</a></p>'
|
||||||
|
% (moduleimpl_id,)
|
||||||
|
+ html_sco_header.sco_footer()
|
||||||
|
)
|
||||||
|
if not edit:
|
||||||
|
# creation nouvel
|
||||||
|
if moduleimpl_id is None:
|
||||||
|
raise ValueError("missing moduleimpl_id parameter")
|
||||||
|
initvalues = {
|
||||||
|
"note_max": 20,
|
||||||
|
"jour": time.strftime("%d/%m/%Y", time.localtime()),
|
||||||
|
"publish_incomplete": is_malus,
|
||||||
|
}
|
||||||
|
submitlabel = "Créer cette évaluation"
|
||||||
|
action = "Création d'une évaluation"
|
||||||
|
link = ""
|
||||||
|
else:
|
||||||
|
# édition données existantes
|
||||||
|
# setup form init values
|
||||||
|
if evaluation_id is None:
|
||||||
|
raise ValueError("missing evaluation_id parameter")
|
||||||
|
initvalues = evaluation.to_dict()
|
||||||
|
moduleimpl_id = initvalues["moduleimpl_id"]
|
||||||
|
submitlabel = "Modifier les données"
|
||||||
|
action = "Modification d'une évaluation"
|
||||||
|
link = ""
|
||||||
|
# Note maximale actuelle dans cette éval ?
|
||||||
|
etat = sco_evaluations.do_evaluation_etat(evaluation_id)
|
||||||
|
if etat["maxi_num"] is not None:
|
||||||
|
min_note_max = max(scu.NOTES_PRECISION, etat["maxi_num"])
|
||||||
|
else:
|
||||||
|
min_note_max = scu.NOTES_PRECISION
|
||||||
|
#
|
||||||
|
if min_note_max > scu.NOTES_PRECISION:
|
||||||
|
min_note_max_str = scu.fmt_note(min_note_max)
|
||||||
|
else:
|
||||||
|
min_note_max_str = "0"
|
||||||
|
#
|
||||||
|
mod_descr = '<a href="moduleimpl_status?moduleimpl_id=%s">%s %s</a> %s' % (
|
||||||
|
moduleimpl_id,
|
||||||
|
mod["code"],
|
||||||
|
mod["titre"],
|
||||||
|
link,
|
||||||
|
)
|
||||||
|
H = [
|
||||||
|
f"""<h3>{action} en
|
||||||
|
{scu.MODULE_TYPE_NAMES[mod["module_type"]]} {mod_descr}</h3>
|
||||||
|
"""
|
||||||
|
]
|
||||||
|
|
||||||
|
heures = ["%02dh%02d" % (h, m) for h in range(8, 19) for m in (0, 30)]
|
||||||
|
#
|
||||||
|
initvalues["visibulletin"] = initvalues.get("visibulletin", True)
|
||||||
|
if initvalues["visibulletin"]:
|
||||||
|
initvalues["visibulletinlist"] = ["X"]
|
||||||
|
else:
|
||||||
|
initvalues["visibulletinlist"] = []
|
||||||
|
vals = scu.get_request_args()
|
||||||
|
if vals.get("tf_submitted", False) and "visibulletinlist" not in vals:
|
||||||
|
vals["visibulletinlist"] = []
|
||||||
|
#
|
||||||
|
if is_apc: # BUT: poids vers les UE
|
||||||
|
for ue in sem_ues:
|
||||||
|
if edit:
|
||||||
|
existing_poids = models.EvaluationUEPoids.query.filter_by(
|
||||||
|
ue=ue, evaluation=evaluation
|
||||||
|
).first()
|
||||||
|
else:
|
||||||
|
existing_poids = None
|
||||||
|
if existing_poids:
|
||||||
|
poids = existing_poids.poids
|
||||||
|
else:
|
||||||
|
poids = 1.0 # par defaut au départ
|
||||||
|
initvalues[f"poids_{ue.id}"] = poids
|
||||||
|
#
|
||||||
|
form = [
|
||||||
|
("evaluation_id", {"default": evaluation_id, "input_type": "hidden"}),
|
||||||
|
("formsemestre_id", {"default": formsemestre_id, "input_type": "hidden"}),
|
||||||
|
("moduleimpl_id", {"default": moduleimpl_id, "input_type": "hidden"}),
|
||||||
|
# ('jour', { 'title' : 'Date (j/m/a)', 'size' : 12, 'explanation' : 'date de l\'examen, devoir ou contrôle' }),
|
||||||
|
(
|
||||||
|
"jour",
|
||||||
|
{
|
||||||
|
"input_type": "date",
|
||||||
|
"title": "Date",
|
||||||
|
"size": 12,
|
||||||
|
"explanation": "date de l'examen, devoir ou contrôle",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"heure_debut",
|
||||||
|
{
|
||||||
|
"title": "Heure de début",
|
||||||
|
"explanation": "heure du début de l'épreuve",
|
||||||
|
"input_type": "menu",
|
||||||
|
"allowed_values": heures,
|
||||||
|
"labels": heures,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"heure_fin",
|
||||||
|
{
|
||||||
|
"title": "Heure de fin",
|
||||||
|
"explanation": "heure de fin de l'épreuve",
|
||||||
|
"input_type": "menu",
|
||||||
|
"allowed_values": heures,
|
||||||
|
"labels": heures,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
if is_malus: # pas de coefficient
|
||||||
|
form.append(("coefficient", {"input_type": "hidden", "default": "1."}))
|
||||||
|
elif not is_apc: # modules standard hors BUT
|
||||||
|
form.append(
|
||||||
|
(
|
||||||
|
"coefficient",
|
||||||
|
{
|
||||||
|
"size": 6,
|
||||||
|
"type": "float",
|
||||||
|
"explanation": "coef. dans le module (choisi librement par l'enseignant)",
|
||||||
|
"allow_null": False,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
form += [
|
||||||
|
(
|
||||||
|
"note_max",
|
||||||
|
{
|
||||||
|
"size": 4,
|
||||||
|
"type": "float",
|
||||||
|
"title": "Notes de 0 à",
|
||||||
|
"explanation": "barème (note max actuelle: %s)" % min_note_max_str,
|
||||||
|
"allow_null": False,
|
||||||
|
"max_value": scu.NOTES_MAX,
|
||||||
|
"min_value": min_note_max,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"description",
|
||||||
|
{
|
||||||
|
"size": 36,
|
||||||
|
"type": "text",
|
||||||
|
"explanation": 'type d\'évaluation, apparait sur le bulletins longs. Exemples: "contrôle court", "examen de TP", "examen final".',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"visibulletinlist",
|
||||||
|
{
|
||||||
|
"input_type": "checkbox",
|
||||||
|
"allowed_values": ["X"],
|
||||||
|
"labels": [""],
|
||||||
|
"title": "Visible sur bulletins",
|
||||||
|
"explanation": "(pour les bulletins en version intermédiaire)",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"publish_incomplete",
|
||||||
|
{
|
||||||
|
"input_type": "boolcheckbox",
|
||||||
|
"title": "Prise en compte immédiate",
|
||||||
|
"explanation": "notes utilisées même si incomplètes",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"evaluation_type",
|
||||||
|
{
|
||||||
|
"input_type": "menu",
|
||||||
|
"title": "Modalité",
|
||||||
|
"allowed_values": (
|
||||||
|
scu.EVALUATION_NORMALE,
|
||||||
|
scu.EVALUATION_RATTRAPAGE,
|
||||||
|
scu.EVALUATION_SESSION2,
|
||||||
|
),
|
||||||
|
"type": "int",
|
||||||
|
"labels": (
|
||||||
|
"Normale",
|
||||||
|
"Rattrapage (remplace si meilleure note)",
|
||||||
|
"Deuxième session (remplace toujours)",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
if is_apc: # ressources et SAÉs
|
||||||
|
form += [
|
||||||
|
(
|
||||||
|
"coefficient",
|
||||||
|
{
|
||||||
|
"size": 6,
|
||||||
|
"type": "float",
|
||||||
|
"explanation": "importance de l'évaluation (multiplie les poids ci-dessous)",
|
||||||
|
"allow_null": False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
# Liste des UE utilisées dans des modules de ce semestre:
|
||||||
|
for ue in sem_ues:
|
||||||
|
form.append(
|
||||||
|
(
|
||||||
|
f"poids_{ue.id}",
|
||||||
|
{
|
||||||
|
"title": f"Poids {ue.acronyme}",
|
||||||
|
"size": 2,
|
||||||
|
"type": "float",
|
||||||
|
"explanation": f"{ue.titre}",
|
||||||
|
"allow_null": False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
tf = TrivialFormulator(
|
||||||
|
request.base_url,
|
||||||
|
vals,
|
||||||
|
form,
|
||||||
|
cancelbutton="Annuler",
|
||||||
|
submitlabel=submitlabel,
|
||||||
|
initvalues=initvalues,
|
||||||
|
readonly=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
dest_url = "moduleimpl_status?moduleimpl_id=%s" % modimpl["moduleimpl_id"]
|
||||||
|
if tf[0] == 0:
|
||||||
|
head = html_sco_header.sco_header(page_title=page_title)
|
||||||
|
return (
|
||||||
|
head
|
||||||
|
+ "\n".join(H)
|
||||||
|
+ "\n"
|
||||||
|
+ tf[1]
|
||||||
|
+ render_template("scodoc/help/evaluations.html", is_apc=is_apc)
|
||||||
|
+ html_sco_header.sco_footer()
|
||||||
|
)
|
||||||
|
elif tf[0] == -1:
|
||||||
|
return flask.redirect(dest_url)
|
||||||
|
else:
|
||||||
|
# form submission
|
||||||
|
if tf[2]["visibulletinlist"]:
|
||||||
|
tf[2]["visibulletin"] = True
|
||||||
|
else:
|
||||||
|
tf[2]["visibulletin"] = False
|
||||||
|
if edit:
|
||||||
|
sco_evaluation_db.do_evaluation_edit(tf[2])
|
||||||
|
else:
|
||||||
|
# creation d'une evaluation
|
||||||
|
evaluation_id = sco_evaluation_db.do_evaluation_create(**tf[2])
|
||||||
|
# Set poids
|
||||||
|
evaluation = models.Evaluation.query.get(evaluation_id)
|
||||||
|
for ue in sem_ues:
|
||||||
|
evaluation.set_ue_poids(ue, tf[2][f"poids_{ue.id}"])
|
||||||
|
db.session.add(evaluation)
|
||||||
|
db.session.commit()
|
||||||
|
return flask.redirect(dest_url)
|
@ -29,9 +29,7 @@
|
|||||||
"""
|
"""
|
||||||
import datetime
|
import datetime
|
||||||
import operator
|
import operator
|
||||||
import pprint
|
|
||||||
import time
|
import time
|
||||||
import urllib
|
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
@ -41,12 +39,13 @@ from flask import request
|
|||||||
|
|
||||||
from app import log
|
from app import log
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
from app.scodoc.sco_utils import ModuleType
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||||
import sco_version
|
import sco_version
|
||||||
from app.scodoc.gen_tables import GenTable
|
from app.scodoc.gen_tables import GenTable
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator
|
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_edit_module
|
from app.scodoc import sco_edit_module
|
||||||
@ -96,281 +95,6 @@ def ListMedian(L):
|
|||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
_evaluationEditor = ndb.EditableTable(
|
|
||||||
"notes_evaluation",
|
|
||||||
"evaluation_id",
|
|
||||||
(
|
|
||||||
"evaluation_id",
|
|
||||||
"moduleimpl_id",
|
|
||||||
"jour",
|
|
||||||
"heure_debut",
|
|
||||||
"heure_fin",
|
|
||||||
"description",
|
|
||||||
"note_max",
|
|
||||||
"coefficient",
|
|
||||||
"visibulletin",
|
|
||||||
"publish_incomplete",
|
|
||||||
"evaluation_type",
|
|
||||||
"numero",
|
|
||||||
),
|
|
||||||
sortkey="numero desc, jour desc, heure_debut desc", # plus recente d'abord
|
|
||||||
output_formators={
|
|
||||||
"jour": ndb.DateISOtoDMY,
|
|
||||||
"numero": ndb.int_null_is_zero,
|
|
||||||
},
|
|
||||||
input_formators={
|
|
||||||
"jour": ndb.DateDMYtoISO,
|
|
||||||
"heure_debut": ndb.TimetoISO8601, # converti par do_evaluation_list
|
|
||||||
"heure_fin": ndb.TimetoISO8601, # converti par do_evaluation_list
|
|
||||||
"visibulletin": bool,
|
|
||||||
"publish_incomplete": bool,
|
|
||||||
"evaluation_type": int,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def do_evaluation_list(args, sortkey=None):
|
|
||||||
"""List evaluations, sorted by numero (or most recent date first).
|
|
||||||
|
|
||||||
Ajoute les champs:
|
|
||||||
'duree' : '2h30'
|
|
||||||
'matin' : 1 (commence avant 12:00) ou 0
|
|
||||||
'apresmidi' : 1 (termine après 12:00) ou 0
|
|
||||||
'descrheure' : ' de 15h00 à 16h30'
|
|
||||||
"""
|
|
||||||
cnx = ndb.GetDBConnexion()
|
|
||||||
evals = _evaluationEditor.list(cnx, args, sortkey=sortkey)
|
|
||||||
# calcule duree (chaine de car.) de chaque evaluation et ajoute jouriso, matin, apresmidi
|
|
||||||
for e in evals:
|
|
||||||
heure_debut_dt = e["heure_debut"] or datetime.time(
|
|
||||||
8, 00
|
|
||||||
) # au cas ou pas d'heure (note externe?)
|
|
||||||
heure_fin_dt = e["heure_fin"] or datetime.time(8, 00)
|
|
||||||
e["heure_debut"] = ndb.TimefromISO8601(e["heure_debut"])
|
|
||||||
e["heure_fin"] = ndb.TimefromISO8601(e["heure_fin"])
|
|
||||||
e["jouriso"] = ndb.DateDMYtoISO(e["jour"])
|
|
||||||
heure_debut, heure_fin = e["heure_debut"], e["heure_fin"]
|
|
||||||
d = ndb.TimeDuration(heure_debut, heure_fin)
|
|
||||||
if d is not None:
|
|
||||||
m = d % 60
|
|
||||||
e["duree"] = "%dh" % (d / 60)
|
|
||||||
if m != 0:
|
|
||||||
e["duree"] += "%02d" % m
|
|
||||||
else:
|
|
||||||
e["duree"] = ""
|
|
||||||
if heure_debut and (not heure_fin or heure_fin == heure_debut):
|
|
||||||
e["descrheure"] = " à " + heure_debut
|
|
||||||
elif heure_debut and heure_fin:
|
|
||||||
e["descrheure"] = " de %s à %s" % (heure_debut, heure_fin)
|
|
||||||
else:
|
|
||||||
e["descrheure"] = ""
|
|
||||||
# matin, apresmidi: utile pour se referer aux absences:
|
|
||||||
if heure_debut_dt < datetime.time(12, 00):
|
|
||||||
e["matin"] = 1
|
|
||||||
else:
|
|
||||||
e["matin"] = 0
|
|
||||||
if heure_fin_dt > datetime.time(12, 00):
|
|
||||||
e["apresmidi"] = 1
|
|
||||||
else:
|
|
||||||
e["apresmidi"] = 0
|
|
||||||
|
|
||||||
return evals
|
|
||||||
|
|
||||||
|
|
||||||
def do_evaluation_list_in_formsemestre(formsemestre_id):
|
|
||||||
"list evaluations in this formsemestre"
|
|
||||||
mods = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
|
||||||
evals = []
|
|
||||||
for mod in mods:
|
|
||||||
evals += do_evaluation_list(args={"moduleimpl_id": mod["moduleimpl_id"]})
|
|
||||||
return evals
|
|
||||||
|
|
||||||
|
|
||||||
def _check_evaluation_args(args):
|
|
||||||
"Check coefficient, dates and duration, raises exception if invalid"
|
|
||||||
moduleimpl_id = args["moduleimpl_id"]
|
|
||||||
# check bareme
|
|
||||||
note_max = args.get("note_max", None)
|
|
||||||
if note_max is None:
|
|
||||||
raise ScoValueError("missing note_max")
|
|
||||||
try:
|
|
||||||
note_max = float(note_max)
|
|
||||||
except ValueError:
|
|
||||||
raise ScoValueError("Invalid note_max value")
|
|
||||||
if note_max < 0:
|
|
||||||
raise ScoValueError("Invalid note_max value (must be positive or null)")
|
|
||||||
# check coefficient
|
|
||||||
coef = args.get("coefficient", None)
|
|
||||||
if coef is None:
|
|
||||||
raise ScoValueError("missing coefficient")
|
|
||||||
try:
|
|
||||||
coef = float(coef)
|
|
||||||
except ValueError:
|
|
||||||
raise ScoValueError("Invalid coefficient value")
|
|
||||||
if coef < 0:
|
|
||||||
raise ScoValueError("Invalid coefficient value (must be positive or null)")
|
|
||||||
# check date
|
|
||||||
jour = args.get("jour", None)
|
|
||||||
args["jour"] = jour
|
|
||||||
if jour:
|
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
|
||||||
sem = sco_formsemestre.get_formsemestre(M["formsemestre_id"])
|
|
||||||
d, m, y = [int(x) for x in sem["date_debut"].split("/")]
|
|
||||||
date_debut = datetime.date(y, m, d)
|
|
||||||
d, m, y = [int(x) for x in sem["date_fin"].split("/")]
|
|
||||||
date_fin = datetime.date(y, m, d)
|
|
||||||
# passe par ndb.DateDMYtoISO pour avoir date pivot
|
|
||||||
y, m, d = [int(x) for x in ndb.DateDMYtoISO(jour).split("-")]
|
|
||||||
jour = datetime.date(y, m, d)
|
|
||||||
if (jour > date_fin) or (jour < date_debut):
|
|
||||||
raise ScoValueError(
|
|
||||||
"La date de l'évaluation (%s/%s/%s) n'est pas dans le semestre !"
|
|
||||||
% (d, m, y)
|
|
||||||
)
|
|
||||||
heure_debut = args.get("heure_debut", None)
|
|
||||||
args["heure_debut"] = heure_debut
|
|
||||||
heure_fin = args.get("heure_fin", None)
|
|
||||||
args["heure_fin"] = heure_fin
|
|
||||||
if jour and ((not heure_debut) or (not heure_fin)):
|
|
||||||
raise ScoValueError("Les heures doivent être précisées")
|
|
||||||
d = ndb.TimeDuration(heure_debut, heure_fin)
|
|
||||||
if d and ((d < 0) or (d > 60 * 12)):
|
|
||||||
raise ScoValueError("Heures de l'évaluation incohérentes !")
|
|
||||||
|
|
||||||
|
|
||||||
def do_evaluation_create(
|
|
||||||
moduleimpl_id=None,
|
|
||||||
jour=None,
|
|
||||||
heure_debut=None,
|
|
||||||
heure_fin=None,
|
|
||||||
description=None,
|
|
||||||
note_max=None,
|
|
||||||
coefficient=None,
|
|
||||||
visibulletin=None,
|
|
||||||
publish_incomplete=None,
|
|
||||||
evaluation_type=None,
|
|
||||||
numero=None,
|
|
||||||
**kw, # ceci pour absorber les arguments excedentaires de tf #sco8
|
|
||||||
):
|
|
||||||
"""Create an evaluation"""
|
|
||||||
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=moduleimpl_id):
|
|
||||||
raise AccessDenied(
|
|
||||||
"Modification évaluation impossible pour %s" % current_user.get_nomplogin()
|
|
||||||
)
|
|
||||||
args = locals()
|
|
||||||
log("do_evaluation_create: args=" + str(args))
|
|
||||||
_check_evaluation_args(args)
|
|
||||||
# Check numeros
|
|
||||||
module_evaluation_renumber(moduleimpl_id, only_if_unumbered=True)
|
|
||||||
if not "numero" in args or args["numero"] is None:
|
|
||||||
n = None
|
|
||||||
# determine le numero avec la date
|
|
||||||
# Liste des eval existantes triees par date, la plus ancienne en tete
|
|
||||||
ModEvals = do_evaluation_list(
|
|
||||||
args={"moduleimpl_id": moduleimpl_id},
|
|
||||||
sortkey="jour asc, heure_debut asc",
|
|
||||||
)
|
|
||||||
if args["jour"]:
|
|
||||||
next_eval = None
|
|
||||||
t = (
|
|
||||||
ndb.DateDMYtoISO(args["jour"], null_is_empty=True),
|
|
||||||
ndb.TimetoISO8601(args["heure_debut"], null_is_empty=True),
|
|
||||||
)
|
|
||||||
for e in ModEvals:
|
|
||||||
if (
|
|
||||||
ndb.DateDMYtoISO(e["jour"], null_is_empty=True),
|
|
||||||
ndb.TimetoISO8601(e["heure_debut"], null_is_empty=True),
|
|
||||||
) > t:
|
|
||||||
next_eval = e
|
|
||||||
break
|
|
||||||
if next_eval:
|
|
||||||
n = module_evaluation_insert_before(ModEvals, next_eval)
|
|
||||||
else:
|
|
||||||
n = None # a placer en fin
|
|
||||||
if n is None: # pas de date ou en fin:
|
|
||||||
if ModEvals:
|
|
||||||
log(pprint.pformat(ModEvals[-1]))
|
|
||||||
n = ModEvals[-1]["numero"] + 1
|
|
||||||
else:
|
|
||||||
n = 0 # the only one
|
|
||||||
# log("creating with numero n=%d" % n)
|
|
||||||
args["numero"] = n
|
|
||||||
|
|
||||||
#
|
|
||||||
cnx = ndb.GetDBConnexion()
|
|
||||||
r = _evaluationEditor.create(cnx, args)
|
|
||||||
|
|
||||||
# news
|
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
|
||||||
mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
|
||||||
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
|
||||||
mod["url"] = "Notes/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
|
||||||
sco_news.add(
|
|
||||||
typ=sco_news.NEWS_NOTE,
|
|
||||||
object=moduleimpl_id,
|
|
||||||
text='Création d\'une évaluation dans <a href="%(url)s">%(titre)s</a>' % mod,
|
|
||||||
url=mod["url"],
|
|
||||||
)
|
|
||||||
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def do_evaluation_edit(args):
|
|
||||||
"edit an evaluation"
|
|
||||||
evaluation_id = args["evaluation_id"]
|
|
||||||
the_evals = do_evaluation_list({"evaluation_id": evaluation_id})
|
|
||||||
if not the_evals:
|
|
||||||
raise ValueError("evaluation inexistante !")
|
|
||||||
moduleimpl_id = the_evals[0]["moduleimpl_id"]
|
|
||||||
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=moduleimpl_id):
|
|
||||||
raise AccessDenied(
|
|
||||||
"Modification évaluation impossible pour %s" % current_user.get_nomplogin()
|
|
||||||
)
|
|
||||||
args["moduleimpl_id"] = moduleimpl_id
|
|
||||||
_check_evaluation_args(args)
|
|
||||||
|
|
||||||
cnx = ndb.GetDBConnexion()
|
|
||||||
_evaluationEditor.edit(cnx, args)
|
|
||||||
# inval cache pour ce semestre
|
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
|
||||||
sco_cache.invalidate_formsemestre(formsemestre_id=M["formsemestre_id"])
|
|
||||||
|
|
||||||
|
|
||||||
def do_evaluation_delete(evaluation_id):
|
|
||||||
"delete evaluation"
|
|
||||||
the_evals = do_evaluation_list({"evaluation_id": evaluation_id})
|
|
||||||
if not the_evals:
|
|
||||||
raise ValueError("evaluation inexistante !")
|
|
||||||
moduleimpl_id = the_evals[0]["moduleimpl_id"]
|
|
||||||
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=moduleimpl_id):
|
|
||||||
raise AccessDenied(
|
|
||||||
"Modification évaluation impossible pour %s" % current_user.get_nomplogin()
|
|
||||||
)
|
|
||||||
NotesDB = do_evaluation_get_all_notes(evaluation_id) # { etudid : value }
|
|
||||||
notes = [x["value"] for x in NotesDB.values()]
|
|
||||||
if notes:
|
|
||||||
raise ScoValueError(
|
|
||||||
"Impossible de supprimer cette évaluation: il reste des notes"
|
|
||||||
)
|
|
||||||
|
|
||||||
cnx = ndb.GetDBConnexion()
|
|
||||||
|
|
||||||
_evaluationEditor.delete(cnx, evaluation_id)
|
|
||||||
# inval cache pour ce semestre
|
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
|
||||||
sco_cache.invalidate_formsemestre(formsemestre_id=M["formsemestre_id"])
|
|
||||||
# news
|
|
||||||
mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
|
||||||
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
|
||||||
mod["url"] = (
|
|
||||||
scu.NotesURL() + "/moduleimpl_status?moduleimpl_id=%(moduleimpl_id)s" % mod
|
|
||||||
)
|
|
||||||
sco_news.add(
|
|
||||||
typ=sco_news.NEWS_NOTE,
|
|
||||||
object=moduleimpl_id,
|
|
||||||
text='Suppression d\'une évaluation dans <a href="%(url)s">%(titre)s</a>' % mod,
|
|
||||||
url=mod["url"],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def do_evaluation_etat(evaluation_id, partition_id=None, select_first_partition=False):
|
def do_evaluation_etat(evaluation_id, partition_id=None, select_first_partition=False):
|
||||||
@ -385,7 +109,9 @@ def do_evaluation_etat(evaluation_id, partition_id=None, select_first_partition=
|
|||||||
nb_inscrits = len(
|
nb_inscrits = len(
|
||||||
sco_groups.do_evaluation_listeetuds_groups(evaluation_id, getallstudents=True)
|
sco_groups.do_evaluation_listeetuds_groups(evaluation_id, getallstudents=True)
|
||||||
)
|
)
|
||||||
NotesDB = do_evaluation_get_all_notes(evaluation_id) # { etudid : value }
|
NotesDB = sco_evaluation_db.do_evaluation_get_all_notes(
|
||||||
|
evaluation_id
|
||||||
|
) # { etudid : value }
|
||||||
notes = [x["value"] for x in NotesDB.values()]
|
notes = [x["value"] for x in NotesDB.values()]
|
||||||
nb_abs = len([x for x in notes if x is None])
|
nb_abs = len([x for x in notes if x is None])
|
||||||
nb_neutre = len([x for x in notes if x == scu.NOTES_NEUTRALISE])
|
nb_neutre = len([x for x in notes if x == scu.NOTES_NEUTRALISE])
|
||||||
@ -408,10 +134,10 @@ def do_evaluation_etat(evaluation_id, partition_id=None, select_first_partition=
|
|||||||
else:
|
else:
|
||||||
last_modif = None
|
last_modif = None
|
||||||
# ---- Liste des groupes complets et incomplets
|
# ---- Liste des groupes complets et incomplets
|
||||||
E = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
is_malus = Mod["module_type"] == scu.MODULE_MALUS # True si module de malus
|
is_malus = Mod["module_type"] == ModuleType.MALUS # True si module de malus
|
||||||
formsemestre_id = M["formsemestre_id"]
|
formsemestre_id = M["formsemestre_id"]
|
||||||
# Si partition_id is None, prend 'all' ou bien la premiere:
|
# Si partition_id is None, prend 'all' ou bien la premiere:
|
||||||
if partition_id is None:
|
if partition_id is None:
|
||||||
@ -611,46 +337,6 @@ def do_evaluation_list_in_sem(formsemestre_id, with_etat=True):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
# ancien _notes_getall
|
|
||||||
def do_evaluation_get_all_notes(
|
|
||||||
evaluation_id, table="notes_notes", filter_suppressed=True, by_uid=None
|
|
||||||
):
|
|
||||||
"""Toutes les notes pour une evaluation: { etudid : { 'value' : value, 'date' : date ... }}
|
|
||||||
Attention: inclut aussi les notes des étudiants qui ne sont plus inscrits au module.
|
|
||||||
"""
|
|
||||||
do_cache = (
|
|
||||||
filter_suppressed and table == "notes_notes" and (by_uid is None)
|
|
||||||
) # pas de cache pour (rares) appels via undo_notes ou specifiant un enseignant
|
|
||||||
if do_cache:
|
|
||||||
r = sco_cache.EvaluationCache.get(evaluation_id)
|
|
||||||
if r != None:
|
|
||||||
return r
|
|
||||||
cnx = ndb.GetDBConnexion()
|
|
||||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
|
||||||
cond = " where evaluation_id=%(evaluation_id)s"
|
|
||||||
if by_uid:
|
|
||||||
cond += " and uid=%(by_uid)s"
|
|
||||||
|
|
||||||
cursor.execute(
|
|
||||||
"select * from " + table + cond,
|
|
||||||
{"evaluation_id": evaluation_id, "by_uid": by_uid},
|
|
||||||
)
|
|
||||||
res = cursor.dictfetchall()
|
|
||||||
d = {}
|
|
||||||
if filter_suppressed:
|
|
||||||
for x in res:
|
|
||||||
if x["value"] != scu.NOTES_SUPPRESS:
|
|
||||||
d[x["etudid"]] = x
|
|
||||||
else:
|
|
||||||
for x in res:
|
|
||||||
d[x["etudid"]] = x
|
|
||||||
if do_cache:
|
|
||||||
status = sco_cache.EvaluationCache.set(evaluation_id, d)
|
|
||||||
if not status:
|
|
||||||
log(f"Warning: EvaluationCache.set: {evaluation_id}\t{status}")
|
|
||||||
return d
|
|
||||||
|
|
||||||
|
|
||||||
def _eval_etat(evals):
|
def _eval_etat(evals):
|
||||||
"""evals: list of mappings (etats)
|
"""evals: list of mappings (etats)
|
||||||
-> nb_eval_completes, nb_evals_en_cours,
|
-> nb_eval_completes, nb_evals_en_cours,
|
||||||
@ -818,10 +504,12 @@ def evaluation_date_first_completion(evaluation_id):
|
|||||||
# ins = [i for i in insem if i["etudid"] in insmodset]
|
# ins = [i for i in insem if i["etudid"] in insmodset]
|
||||||
|
|
||||||
notes = list(
|
notes = list(
|
||||||
do_evaluation_get_all_notes(evaluation_id, filter_suppressed=False).values()
|
sco_evaluation_db.do_evaluation_get_all_notes(
|
||||||
|
evaluation_id, filter_suppressed=False
|
||||||
|
).values()
|
||||||
)
|
)
|
||||||
notes_log = list(
|
notes_log = list(
|
||||||
do_evaluation_get_all_notes(
|
sco_evaluation_db.do_evaluation_get_all_notes(
|
||||||
evaluation_id, filter_suppressed=False, table="notes_notes_log"
|
evaluation_id, filter_suppressed=False, table="notes_notes_log"
|
||||||
).values()
|
).values()
|
||||||
)
|
)
|
||||||
@ -854,7 +542,7 @@ def formsemestre_evaluations_delai_correction(formsemestre_id, format="html"):
|
|||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=e["moduleimpl_id"])[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=e["moduleimpl_id"])[0]
|
||||||
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
if (e["evaluation_type"] != scu.EVALUATION_NORMALE) or (
|
if (e["evaluation_type"] != scu.EVALUATION_NORMALE) or (
|
||||||
Mod["module_type"] == scu.MODULE_MALUS
|
Mod["module_type"] == ModuleType.MALUS
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
e["date_first_complete"] = evaluation_date_first_completion(e["evaluation_id"])
|
e["date_first_complete"] = evaluation_date_first_completion(e["evaluation_id"])
|
||||||
@ -917,112 +605,6 @@ def formsemestre_evaluations_delai_correction(formsemestre_id, format="html"):
|
|||||||
return tab.make_page(format=format)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
|
|
||||||
def module_evaluation_insert_before(ModEvals, next_eval):
|
|
||||||
"""Renumber evals such that an evaluation with can be inserted before next_eval
|
|
||||||
Returns numero suitable for the inserted evaluation
|
|
||||||
"""
|
|
||||||
if next_eval:
|
|
||||||
n = next_eval["numero"]
|
|
||||||
if not n:
|
|
||||||
log("renumbering old evals")
|
|
||||||
module_evaluation_renumber(next_eval["moduleimpl_id"])
|
|
||||||
next_eval = do_evaluation_list(
|
|
||||||
args={"evaluation_id": next_eval["evaluation_id"]}
|
|
||||||
)[0]
|
|
||||||
n = next_eval["numero"]
|
|
||||||
else:
|
|
||||||
n = 1
|
|
||||||
# log('inserting at position numero %s' % n )
|
|
||||||
# all numeros >= n are incremented
|
|
||||||
for e in ModEvals:
|
|
||||||
if e["numero"] >= n:
|
|
||||||
e["numero"] += 1
|
|
||||||
# log('incrementing %s to %s' % (e['evaluation_id'], e['numero']))
|
|
||||||
do_evaluation_edit(e)
|
|
||||||
|
|
||||||
return n
|
|
||||||
|
|
||||||
|
|
||||||
def module_evaluation_move(evaluation_id, after=0, redirect=1):
|
|
||||||
"""Move before/after previous one (decrement/increment numero)
|
|
||||||
(published)
|
|
||||||
"""
|
|
||||||
e = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
|
||||||
redirect = int(redirect)
|
|
||||||
# access: can change eval ?
|
|
||||||
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=e["moduleimpl_id"]):
|
|
||||||
raise AccessDenied(
|
|
||||||
"Modification évaluation impossible pour %s" % current_user.get_nomplogin()
|
|
||||||
)
|
|
||||||
|
|
||||||
module_evaluation_renumber(e["moduleimpl_id"], only_if_unumbered=True)
|
|
||||||
e = do_evaluation_list(args={"evaluation_id": evaluation_id})[0]
|
|
||||||
|
|
||||||
after = int(after) # 0: deplace avant, 1 deplace apres
|
|
||||||
if after not in (0, 1):
|
|
||||||
raise ValueError('invalid value for "after"')
|
|
||||||
ModEvals = do_evaluation_list({"moduleimpl_id": e["moduleimpl_id"]})
|
|
||||||
# log('ModEvals=%s' % [ x['evaluation_id'] for x in ModEvals] )
|
|
||||||
if len(ModEvals) > 1:
|
|
||||||
idx = [p["evaluation_id"] for p in ModEvals].index(evaluation_id)
|
|
||||||
neigh = None # object to swap with
|
|
||||||
if after == 0 and idx > 0:
|
|
||||||
neigh = ModEvals[idx - 1]
|
|
||||||
elif after == 1 and idx < len(ModEvals) - 1:
|
|
||||||
neigh = ModEvals[idx + 1]
|
|
||||||
if neigh: #
|
|
||||||
# swap numero with neighbor
|
|
||||||
e["numero"], neigh["numero"] = neigh["numero"], e["numero"]
|
|
||||||
do_evaluation_edit(e)
|
|
||||||
do_evaluation_edit(neigh)
|
|
||||||
# redirect to moduleimpl page:
|
|
||||||
if redirect:
|
|
||||||
return flask.redirect(
|
|
||||||
url_for(
|
|
||||||
"notes.moduleimpl_status",
|
|
||||||
scodoc_dept=g.scodoc_dept,
|
|
||||||
moduleimpl_id=e["moduleimpl_id"],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def module_evaluation_renumber(moduleimpl_id, only_if_unumbered=False, redirect=0):
|
|
||||||
"""Renumber evaluations in this module, according to their date. (numero=0: oldest one)
|
|
||||||
Needed because previous versions of ScoDoc did not have eval numeros
|
|
||||||
Note: existing numeros are ignored
|
|
||||||
"""
|
|
||||||
redirect = int(redirect)
|
|
||||||
# log('module_evaluation_renumber( moduleimpl_id=%s )' % moduleimpl_id )
|
|
||||||
# List sorted according to date/heure, ignoring numeros:
|
|
||||||
# (note that we place evaluations with NULL date at the end)
|
|
||||||
ModEvals = do_evaluation_list(
|
|
||||||
args={"moduleimpl_id": moduleimpl_id},
|
|
||||||
sortkey="jour asc, heure_debut asc",
|
|
||||||
)
|
|
||||||
|
|
||||||
all_numbered = False not in [x["numero"] > 0 for x in ModEvals]
|
|
||||||
if all_numbered and only_if_unumbered:
|
|
||||||
return # all ok
|
|
||||||
|
|
||||||
# log('module_evaluation_renumber')
|
|
||||||
# Reset all numeros:
|
|
||||||
i = 1
|
|
||||||
for e in ModEvals:
|
|
||||||
e["numero"] = i
|
|
||||||
do_evaluation_edit(e)
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
# If requested, redirect to moduleimpl page:
|
|
||||||
if redirect:
|
|
||||||
return flask.redirect(
|
|
||||||
url_for(
|
|
||||||
"notes.moduleimpl_status",
|
|
||||||
scodoc_dept=g.scodoc_dept,
|
|
||||||
moduleimpl_id=moduleimpl_id,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# -------------- VIEWS
|
# -------------- VIEWS
|
||||||
def evaluation_describe(evaluation_id="", edit_in_place=True):
|
def evaluation_describe(evaluation_id="", edit_in_place=True):
|
||||||
"""HTML description of evaluation, for page headers
|
"""HTML description of evaluation, for page headers
|
||||||
@ -1030,7 +612,7 @@ def evaluation_describe(evaluation_id="", edit_in_place=True):
|
|||||||
"""
|
"""
|
||||||
from app.scodoc import sco_saisie_notes
|
from app.scodoc import sco_saisie_notes
|
||||||
|
|
||||||
E = do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
moduleimpl_id = E["moduleimpl_id"]
|
moduleimpl_id = E["moduleimpl_id"]
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
@ -1054,13 +636,13 @@ def evaluation_describe(evaluation_id="", edit_in_place=True):
|
|||||||
etit = E["description"] or ""
|
etit = E["description"] or ""
|
||||||
if etit:
|
if etit:
|
||||||
etit = ' "' + etit + '"'
|
etit = ' "' + etit + '"'
|
||||||
if Mod["module_type"] == scu.MODULE_MALUS:
|
if Mod["module_type"] == ModuleType.MALUS:
|
||||||
etit += ' <span class="eval_malus">(points de malus)</span>'
|
etit += ' <span class="eval_malus">(points de malus)</span>'
|
||||||
H = [
|
H = [
|
||||||
'<span class="eval_title">Evaluation%s</span><p><b>Module : %s</b></p>'
|
'<span class="eval_title">Evaluation%s</span><p><b>Module : %s</b></p>'
|
||||||
% (etit, mod_descr)
|
% (etit, mod_descr)
|
||||||
]
|
]
|
||||||
if Mod["module_type"] == scu.MODULE_MALUS:
|
if Mod["module_type"] == ModuleType.MALUS:
|
||||||
# Indique l'UE
|
# Indique l'UE
|
||||||
ue = sco_edit_ue.ue_list(args={"ue_id": Mod["ue_id"]})[0]
|
ue = sco_edit_ue.ue_list(args={"ue_id": Mod["ue_id"]})[0]
|
||||||
H.append("<p><b>UE : %(acronyme)s</b></p>" % ue)
|
H.append("<p><b>UE : %(acronyme)s</b></p>" % ue)
|
||||||
@ -1099,269 +681,3 @@ def evaluation_describe(evaluation_id="", edit_in_place=True):
|
|||||||
H.append("</p>")
|
H.append("</p>")
|
||||||
|
|
||||||
return '<div class="eval_description">' + "\n".join(H) + "</div>"
|
return '<div class="eval_description">' + "\n".join(H) + "</div>"
|
||||||
|
|
||||||
|
|
||||||
def evaluation_create_form(
|
|
||||||
moduleimpl_id=None,
|
|
||||||
evaluation_id=None,
|
|
||||||
edit=False,
|
|
||||||
readonly=False,
|
|
||||||
page_title="Evaluation",
|
|
||||||
):
|
|
||||||
"formulaire creation/edition des evaluations (pas des notes)"
|
|
||||||
if evaluation_id != None:
|
|
||||||
the_eval = do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
|
||||||
moduleimpl_id = the_eval["moduleimpl_id"]
|
|
||||||
#
|
|
||||||
M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
|
||||||
is_malus = M["module"]["module_type"] == scu.MODULE_MALUS # True si module de malus
|
|
||||||
formsemestre_id = M["formsemestre_id"]
|
|
||||||
min_note_max = scu.NOTES_PRECISION # le plus petit bareme possible
|
|
||||||
if not readonly:
|
|
||||||
if not sco_permissions_check.can_edit_evaluation(moduleimpl_id=moduleimpl_id):
|
|
||||||
return (
|
|
||||||
html_sco_header.sco_header()
|
|
||||||
+ "<h2>Opération non autorisée</h2><p>"
|
|
||||||
+ "Modification évaluation impossible pour %s"
|
|
||||||
% current_user.get_nomplogin()
|
|
||||||
+ "</p>"
|
|
||||||
+ '<p><a href="moduleimpl_status?moduleimpl_id=%s">Revenir</a></p>'
|
|
||||||
% (moduleimpl_id,)
|
|
||||||
+ html_sco_header.sco_footer()
|
|
||||||
)
|
|
||||||
if readonly:
|
|
||||||
edit = True # montre les donnees existantes
|
|
||||||
if not edit:
|
|
||||||
# creation nouvel
|
|
||||||
if moduleimpl_id is None:
|
|
||||||
raise ValueError("missing moduleimpl_id parameter")
|
|
||||||
initvalues = {
|
|
||||||
"note_max": 20,
|
|
||||||
"jour": time.strftime("%d/%m/%Y", time.localtime()),
|
|
||||||
"publish_incomplete": is_malus,
|
|
||||||
}
|
|
||||||
submitlabel = "Créer cette évaluation"
|
|
||||||
action = "Création d'une é"
|
|
||||||
link = ""
|
|
||||||
else:
|
|
||||||
# edition donnees existantes
|
|
||||||
# setup form init values
|
|
||||||
if evaluation_id is None:
|
|
||||||
raise ValueError("missing evaluation_id parameter")
|
|
||||||
initvalues = the_eval
|
|
||||||
moduleimpl_id = initvalues["moduleimpl_id"]
|
|
||||||
submitlabel = "Modifier les données"
|
|
||||||
if readonly:
|
|
||||||
action = "E"
|
|
||||||
link = (
|
|
||||||
'<span class="evallink"><a class="stdlink" href="evaluation_listenotes?moduleimpl_id=%s">voir toutes les notes du module</a></span>'
|
|
||||||
% M["moduleimpl_id"]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
action = "Modification d'une é"
|
|
||||||
link = ""
|
|
||||||
# Note maximale actuelle dans cette eval ?
|
|
||||||
etat = do_evaluation_etat(evaluation_id)
|
|
||||||
if etat["maxi_num"] is not None:
|
|
||||||
min_note_max = max(scu.NOTES_PRECISION, etat["maxi_num"])
|
|
||||||
else:
|
|
||||||
min_note_max = scu.NOTES_PRECISION
|
|
||||||
#
|
|
||||||
if min_note_max > scu.NOTES_PRECISION:
|
|
||||||
min_note_max_str = scu.fmt_note(min_note_max)
|
|
||||||
else:
|
|
||||||
min_note_max_str = "0"
|
|
||||||
#
|
|
||||||
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
|
||||||
#
|
|
||||||
help = """<div class="help"><p class="help">
|
|
||||||
Le coefficient d'une évaluation n'est utilisé que pour pondérer les évaluations au sein d'un module.
|
|
||||||
Il est fixé librement par l'enseignant pour refléter l'importance de ses différentes notes
|
|
||||||
(examens, projets, travaux pratiques...). Ce coefficient est utilisé pour calculer la note
|
|
||||||
moyenne de chaque étudiant dans ce module.
|
|
||||||
</p><p class="help">
|
|
||||||
Ne pas confondre ce coefficient avec le coefficient du module, qui est lui fixé par le programme
|
|
||||||
pédagogique (le PPN pour les DUT) et pondère les moyennes de chaque module pour obtenir
|
|
||||||
les moyennes d'UE et la moyenne générale.
|
|
||||||
</p><p class="help">
|
|
||||||
L'option <em>Visible sur bulletins</em> indique que la note sera reportée sur les bulletins
|
|
||||||
en version dite "intermédiaire" (dans cette version, on peut ne faire apparaitre que certaines
|
|
||||||
notes, en sus des moyennes de modules. Attention, cette option n'empêche pas la publication sur
|
|
||||||
les bulletins en version "longue" (la note est donc visible par les étudiants sur le portail).
|
|
||||||
</p><p class="help">
|
|
||||||
Les modalités "rattrapage" et "deuxième session" définissent des évaluations prises en compte de
|
|
||||||
façon spéciale: </p>
|
|
||||||
<ul>
|
|
||||||
<li>les notes d'une évaluation de "rattrapage" remplaceront les moyennes du module
|
|
||||||
<em>si elles sont meilleures que celles calculées</em>.</li>
|
|
||||||
<li>les notes de "deuxième session" remplacent, lorsqu'elles sont saisies, la moyenne de l'étudiant
|
|
||||||
à ce module, même si la note de deuxième session est plus faible.</li>
|
|
||||||
</ul>
|
|
||||||
<p class="help">
|
|
||||||
Dans ces deux cas, le coefficient est ignoré, et toutes les notes n'ont
|
|
||||||
pas besoin d'être rentrées.
|
|
||||||
</p>
|
|
||||||
<p class="help">
|
|
||||||
Par ailleurs, les évaluations des modules de type "malus" sont toujours spéciales: le coefficient n'est pas utilisé.
|
|
||||||
Les notes de malus sont toujours comprises entre -20 et 20. Les points sont soustraits à la moyenne
|
|
||||||
de l'UE à laquelle appartient le module malus (si la note est négative, la moyenne est donc augmentée).
|
|
||||||
</p>
|
|
||||||
"""
|
|
||||||
mod_descr = '<a href="moduleimpl_status?moduleimpl_id=%s">%s %s</a> %s' % (
|
|
||||||
moduleimpl_id,
|
|
||||||
Mod["code"],
|
|
||||||
Mod["titre"],
|
|
||||||
link,
|
|
||||||
)
|
|
||||||
if not readonly:
|
|
||||||
H = ["<h3>%svaluation en %s</h3>" % (action, mod_descr)]
|
|
||||||
else:
|
|
||||||
return evaluation_describe(evaluation_id)
|
|
||||||
|
|
||||||
heures = ["%02dh%02d" % (h, m) for h in range(8, 19) for m in (0, 30)]
|
|
||||||
#
|
|
||||||
initvalues["visibulletin"] = initvalues.get("visibulletin", True)
|
|
||||||
if initvalues["visibulletin"]:
|
|
||||||
initvalues["visibulletinlist"] = ["X"]
|
|
||||||
else:
|
|
||||||
initvalues["visibulletinlist"] = []
|
|
||||||
vals = scu.get_request_args()
|
|
||||||
if vals.get("tf_submitted", False) and "visibulletinlist" not in vals:
|
|
||||||
vals["visibulletinlist"] = []
|
|
||||||
#
|
|
||||||
form = [
|
|
||||||
("evaluation_id", {"default": evaluation_id, "input_type": "hidden"}),
|
|
||||||
("formsemestre_id", {"default": formsemestre_id, "input_type": "hidden"}),
|
|
||||||
("moduleimpl_id", {"default": moduleimpl_id, "input_type": "hidden"}),
|
|
||||||
# ('jour', { 'title' : 'Date (j/m/a)', 'size' : 12, 'explanation' : 'date de l\'examen, devoir ou contrôle' }),
|
|
||||||
(
|
|
||||||
"jour",
|
|
||||||
{
|
|
||||||
"input_type": "date",
|
|
||||||
"title": "Date",
|
|
||||||
"size": 12,
|
|
||||||
"explanation": "date de l'examen, devoir ou contrôle",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"heure_debut",
|
|
||||||
{
|
|
||||||
"title": "Heure de début",
|
|
||||||
"explanation": "heure du début de l'épreuve",
|
|
||||||
"input_type": "menu",
|
|
||||||
"allowed_values": heures,
|
|
||||||
"labels": heures,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"heure_fin",
|
|
||||||
{
|
|
||||||
"title": "Heure de fin",
|
|
||||||
"explanation": "heure de fin de l'épreuve",
|
|
||||||
"input_type": "menu",
|
|
||||||
"allowed_values": heures,
|
|
||||||
"labels": heures,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
if is_malus: # pas de coefficient
|
|
||||||
form.append(("coefficient", {"input_type": "hidden", "default": "1."}))
|
|
||||||
else:
|
|
||||||
form.append(
|
|
||||||
(
|
|
||||||
"coefficient",
|
|
||||||
{
|
|
||||||
"size": 10,
|
|
||||||
"type": "float",
|
|
||||||
"explanation": "coef. dans le module (choisi librement par l'enseignant)",
|
|
||||||
"allow_null": False,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
)
|
|
||||||
form += [
|
|
||||||
(
|
|
||||||
"note_max",
|
|
||||||
{
|
|
||||||
"size": 4,
|
|
||||||
"type": "float",
|
|
||||||
"title": "Notes de 0 à",
|
|
||||||
"explanation": "barème (note max actuelle: %s)" % min_note_max_str,
|
|
||||||
"allow_null": False,
|
|
||||||
"max_value": scu.NOTES_MAX,
|
|
||||||
"min_value": min_note_max,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"description",
|
|
||||||
{
|
|
||||||
"size": 36,
|
|
||||||
"type": "text",
|
|
||||||
"explanation": 'type d\'évaluation, apparait sur le bulletins longs. Exemples: "contrôle court", "examen de TP", "examen final".',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"visibulletinlist",
|
|
||||||
{
|
|
||||||
"input_type": "checkbox",
|
|
||||||
"allowed_values": ["X"],
|
|
||||||
"labels": [""],
|
|
||||||
"title": "Visible sur bulletins",
|
|
||||||
"explanation": "(pour les bulletins en version intermédiaire)",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"publish_incomplete",
|
|
||||||
{
|
|
||||||
"input_type": "boolcheckbox",
|
|
||||||
"title": "Prise en compte immédiate",
|
|
||||||
"explanation": "notes utilisées même si incomplètes",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"evaluation_type",
|
|
||||||
{
|
|
||||||
"input_type": "menu",
|
|
||||||
"title": "Modalité",
|
|
||||||
"allowed_values": (
|
|
||||||
scu.EVALUATION_NORMALE,
|
|
||||||
scu.EVALUATION_RATTRAPAGE,
|
|
||||||
scu.EVALUATION_SESSION2,
|
|
||||||
),
|
|
||||||
"type": "int",
|
|
||||||
"labels": (
|
|
||||||
"Normale",
|
|
||||||
"Rattrapage (remplace si meilleure note)",
|
|
||||||
"Deuxième session (remplace toujours)",
|
|
||||||
),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
tf = TrivialFormulator(
|
|
||||||
request.base_url,
|
|
||||||
vals,
|
|
||||||
form,
|
|
||||||
cancelbutton="Annuler",
|
|
||||||
submitlabel=submitlabel,
|
|
||||||
initvalues=initvalues,
|
|
||||||
readonly=readonly,
|
|
||||||
)
|
|
||||||
|
|
||||||
dest_url = "moduleimpl_status?moduleimpl_id=%s" % M["moduleimpl_id"]
|
|
||||||
if tf[0] == 0:
|
|
||||||
head = html_sco_header.sco_header(page_title=page_title)
|
|
||||||
return head + "\n".join(H) + "\n" + tf[1] + help + html_sco_header.sco_footer()
|
|
||||||
elif tf[0] == -1:
|
|
||||||
return flask.redirect(dest_url)
|
|
||||||
else:
|
|
||||||
# form submission
|
|
||||||
if tf[2]["visibulletinlist"]:
|
|
||||||
tf[2]["visibulletin"] = True
|
|
||||||
else:
|
|
||||||
tf[2]["visibulletin"] = False
|
|
||||||
if not edit:
|
|
||||||
# creation d'une evaluation
|
|
||||||
evaluation_id = do_evaluation_create(**tf[2])
|
|
||||||
return flask.redirect(dest_url)
|
|
||||||
else:
|
|
||||||
do_evaluation_edit(tf[2])
|
|
||||||
return flask.redirect(dest_url)
|
|
||||||
|
@ -39,7 +39,6 @@ from app.scodoc import sco_codes_parcours
|
|||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc import sco_users
|
|
||||||
from app.scodoc.gen_tables import GenTable
|
from app.scodoc.gen_tables import GenTable
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.sco_codes_parcours import NO_SEMESTRE_ID
|
from app.scodoc.sco_codes_parcours import NO_SEMESTRE_ID
|
||||||
@ -369,7 +368,7 @@ def _write_formsemestre_aux(sem, fieldname, valuename):
|
|||||||
# uniquify
|
# uniquify
|
||||||
values = set([str(x) for x in sem[fieldname]])
|
values = set([str(x) for x in sem[fieldname]])
|
||||||
|
|
||||||
cnx = ndb.GetDBConnexion(autocommit=False)
|
cnx = ndb.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
tablename = "notes_formsemestre_" + fieldname
|
tablename = "notes_formsemestre_" + fieldname
|
||||||
try:
|
try:
|
||||||
@ -398,6 +397,8 @@ def _write_formsemestre_aux(sem, fieldname, valuename):
|
|||||||
|
|
||||||
def sem_set_responsable_name(sem):
|
def sem_set_responsable_name(sem):
|
||||||
"ajoute champs responsable_name"
|
"ajoute champs responsable_name"
|
||||||
|
from app.scodoc import sco_users
|
||||||
|
|
||||||
sem["responsable_name"] = ", ".join(
|
sem["responsable_name"] = ", ".join(
|
||||||
[
|
[
|
||||||
sco_users.user_info(responsable_id)["nomprenom"]
|
sco_users.user_info(responsable_id)["nomprenom"]
|
||||||
|
@ -49,6 +49,7 @@ 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_evaluations
|
||||||
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_groups_copy
|
from app.scodoc import sco_groups_copy
|
||||||
@ -851,7 +852,7 @@ def formsemestre_delete_moduleimpls(formsemestre_id, module_ids_to_del):
|
|||||||
)[0]["moduleimpl_id"]
|
)[0]["moduleimpl_id"]
|
||||||
mod = sco_edit_module.module_list({"module_id": module_id})[0]
|
mod = sco_edit_module.module_list({"module_id": module_id})[0]
|
||||||
# Evaluations dans ce module ?
|
# Evaluations dans ce module ?
|
||||||
evals = sco_evaluations.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
evals = sco_evaluation_db.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
||||||
if evals:
|
if evals:
|
||||||
msg += [
|
msg += [
|
||||||
'<b>impossible de supprimer %s (%s) car il y a %d évaluations définies (<a href="moduleimpl_status?moduleimpl_id=%s" class="stdlink">supprimer les d\'abord</a>)</b>'
|
'<b>impossible de supprimer %s (%s) car il y a %d évaluations définies (<a href="moduleimpl_status?moduleimpl_id=%s" class="stdlink">supprimer les d\'abord</a>)</b>'
|
||||||
@ -1030,14 +1031,14 @@ def do_formsemestre_clone(
|
|||||||
sco_moduleimpl.do_ens_create(args)
|
sco_moduleimpl.do_ens_create(args)
|
||||||
# optionally, copy evaluations
|
# optionally, copy evaluations
|
||||||
if clone_evaluations:
|
if clone_evaluations:
|
||||||
evals = sco_evaluations.do_evaluation_list(
|
evals = sco_evaluation_db.do_evaluation_list(
|
||||||
args={"moduleimpl_id": mod_orig["moduleimpl_id"]}
|
args={"moduleimpl_id": mod_orig["moduleimpl_id"]}
|
||||||
)
|
)
|
||||||
for e in evals:
|
for e in evals:
|
||||||
args = e.copy()
|
args = e.copy()
|
||||||
del args["jour"] # erase date
|
del args["jour"] # erase date
|
||||||
args["moduleimpl_id"] = mid
|
args["moduleimpl_id"] = mid
|
||||||
_ = sco_evaluations.do_evaluation_create(**args)
|
_ = sco_evaluation_db.do_evaluation_create(**args)
|
||||||
|
|
||||||
# 3- copy uecoefs
|
# 3- copy uecoefs
|
||||||
objs = sco_formsemestre.formsemestre_uecoef_list(
|
objs = sco_formsemestre.formsemestre_uecoef_list(
|
||||||
@ -1229,7 +1230,7 @@ def formsemestre_delete(formsemestre_id):
|
|||||||
</ol></div>""",
|
</ol></div>""",
|
||||||
]
|
]
|
||||||
|
|
||||||
evals = sco_evaluations.do_evaluation_list_in_formsemestre(formsemestre_id)
|
evals = sco_evaluation_db.do_evaluation_list_in_formsemestre(formsemestre_id)
|
||||||
if evals:
|
if evals:
|
||||||
H.append(
|
H.append(
|
||||||
"""<p class="warning">Attention: il y a %d évaluations dans ce semestre (sa suppression entrainera l'effacement définif des notes) !</p>"""
|
"""<p class="warning">Attention: il y a %d évaluations dans ce semestre (sa suppression entrainera l'effacement définif des notes) !</p>"""
|
||||||
@ -1311,7 +1312,7 @@ def do_formsemestre_delete(formsemestre_id):
|
|||||||
mods = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
mods = sco_moduleimpl.moduleimpl_list(formsemestre_id=formsemestre_id)
|
||||||
for mod in mods:
|
for mod in mods:
|
||||||
# evaluations
|
# evaluations
|
||||||
evals = sco_evaluations.do_evaluation_list(
|
evals = sco_evaluation_db.do_evaluation_list(
|
||||||
args={"moduleimpl_id": mod["moduleimpl_id"]}
|
args={"moduleimpl_id": mod["moduleimpl_id"]}
|
||||||
)
|
)
|
||||||
for e in evals:
|
for e in evals:
|
||||||
|
@ -36,6 +36,7 @@ from flask_login import current_user
|
|||||||
|
|
||||||
from app import log
|
from app import log
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
from app.scodoc.sco_utils import ModuleType
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
from app.scodoc.sco_exceptions import ScoValueError, ScoInvalidDateError
|
from app.scodoc.sco_exceptions import ScoValueError, ScoInvalidDateError
|
||||||
@ -50,6 +51,7 @@ from app.scodoc import sco_compute_moy
|
|||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_edit_ue
|
from app.scodoc import sco_edit_ue
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluations
|
||||||
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_formsemestre_edit
|
from app.scodoc import sco_formsemestre_edit
|
||||||
@ -459,7 +461,9 @@ def retreive_formsemestre_from_request() -> int:
|
|||||||
modimpl = modimpl[0]
|
modimpl = modimpl[0]
|
||||||
formsemestre_id = modimpl["formsemestre_id"]
|
formsemestre_id = modimpl["formsemestre_id"]
|
||||||
elif "evaluation_id" in args:
|
elif "evaluation_id" in args:
|
||||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": args["evaluation_id"]})
|
E = sco_evaluation_db.do_evaluation_list(
|
||||||
|
{"evaluation_id": args["evaluation_id"]}
|
||||||
|
)
|
||||||
if not E:
|
if not E:
|
||||||
return None # evaluation suppressed ?
|
return None # evaluation suppressed ?
|
||||||
E = E[0]
|
E = E[0]
|
||||||
@ -979,13 +983,22 @@ def formsemestre_status(formsemestre_id=None):
|
|||||||
# porté du DTML
|
# porté du DTML
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id, raise_soft_exc=True)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id, raise_soft_exc=True)
|
||||||
Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
modimpls = sco_moduleimpl.moduleimpl_withmodule_list(
|
||||||
# inscrits = sco_formsemestre_inscriptions.do_formsemestre_inscription_list(
|
formsemestre_id=formsemestre_id
|
||||||
# args={"formsemestre_id": formsemestre_id}
|
)
|
||||||
# )
|
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
||||||
prev_ue_id = None
|
# Construit la liste de tous les enseignants de ce semestre:
|
||||||
|
mails_enseignants = set(
|
||||||
|
[sco_users.user_info(ens_id)["email"] for ens_id in sem["responsables"]]
|
||||||
|
)
|
||||||
|
for modimpl in modimpls:
|
||||||
|
mails_enseignants.add(sco_users.user_info(modimpl["responsable_id"])["email"])
|
||||||
|
mails_enseignants |= set(
|
||||||
|
[sco_users.user_info(m["ens_id"])["email"] for m in modimpl["ens"]]
|
||||||
|
)
|
||||||
|
|
||||||
can_edit = sco_formsemestre_edit.can_edit_sem(formsemestre_id, sem=sem)
|
can_edit = sco_formsemestre_edit.can_edit_sem(formsemestre_id, sem=sem)
|
||||||
|
use_ue_coefs = sco_preferences.get_preference("use_ue_coefs", formsemestre_id)
|
||||||
|
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(page_title="Semestre %s" % sem["titreannee"]),
|
html_sco_header.sco_header(page_title="Semestre %s" % sem["titreannee"]),
|
||||||
@ -995,158 +1008,69 @@ def formsemestre_status(formsemestre_id=None):
|
|||||||
),
|
),
|
||||||
"""<p><b style="font-size: 130%">Tableau de bord: </b><span class="help">cliquez sur un module pour saisir des notes</span></p>""",
|
"""<p><b style="font-size: 130%">Tableau de bord: </b><span class="help">cliquez sur un module pour saisir des notes</span></p>""",
|
||||||
]
|
]
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
|
||||||
if nt.expr_diagnostics:
|
if nt.expr_diagnostics:
|
||||||
H.append(html_expr_diagnostic(nt.expr_diagnostics))
|
H.append(html_expr_diagnostic(nt.expr_diagnostics))
|
||||||
H.append(
|
|
||||||
"""
|
|
||||||
<p>
|
|
||||||
<table class="formsemestre_status">
|
|
||||||
<tr>
|
|
||||||
<th class="formsemestre_status">Code</th>
|
|
||||||
<th class="formsemestre_status">Module</th>
|
|
||||||
<th class="formsemestre_status">Inscrits</th>
|
|
||||||
<th class="resp">Responsable</th>
|
|
||||||
<th class="evals">Evaluations</th></tr>"""
|
|
||||||
)
|
|
||||||
mails_enseignants = set(
|
|
||||||
[sco_users.user_info(ens_id)["email"] for ens_id in sem["responsables"]]
|
|
||||||
) # adr. mail des enseignants
|
|
||||||
for M in Mlist:
|
|
||||||
Mod = M["module"]
|
|
||||||
ModDescr = (
|
|
||||||
"Module "
|
|
||||||
+ M["module"]["titre"]
|
|
||||||
+ ", coef. "
|
|
||||||
+ str(M["module"]["coefficient"])
|
|
||||||
)
|
|
||||||
ModEns = sco_users.user_info(M["responsable_id"])["nomcomplet"]
|
|
||||||
if M["ens"]:
|
|
||||||
ModEns += " (resp.), " + ", ".join(
|
|
||||||
[sco_users.user_info(e["ens_id"])["nomcomplet"] for e in M["ens"]]
|
|
||||||
)
|
|
||||||
ModInscrits = sco_moduleimpl.do_moduleimpl_inscription_list(
|
|
||||||
moduleimpl_id=M["moduleimpl_id"]
|
|
||||||
)
|
|
||||||
mails_enseignants.add(sco_users.user_info(M["responsable_id"])["email"])
|
|
||||||
mails_enseignants |= set(
|
|
||||||
[sco_users.user_info(m["ens_id"])["email"] for m in M["ens"]]
|
|
||||||
)
|
|
||||||
ue = M["ue"]
|
|
||||||
if prev_ue_id != ue["ue_id"]:
|
|
||||||
prev_ue_id = ue["ue_id"]
|
|
||||||
acronyme = ue["acronyme"]
|
|
||||||
titre = ue["titre"]
|
|
||||||
if sco_preferences.get_preference("use_ue_coefs", formsemestre_id):
|
|
||||||
titre += " <b>(coef. %s)</b>" % (ue["coefficient"] or 0.0)
|
|
||||||
H.append(
|
|
||||||
"""<tr class="formsemestre_status_ue"><td colspan="4">
|
|
||||||
<span class="status_ue_acro">%s</span>
|
|
||||||
<span class="status_ue_title">%s</span>
|
|
||||||
</td><td>"""
|
|
||||||
% (acronyme, titre)
|
|
||||||
)
|
|
||||||
|
|
||||||
expr = sco_compute_moy.get_ue_expression(
|
if nt.parcours.APC_SAE:
|
||||||
formsemestre_id, ue["ue_id"], cnx, html_quote=True
|
# BUT: tableau ressources puis SAE
|
||||||
)
|
ressources = [
|
||||||
|
m for m in modimpls if m["module"]["module_type"] == ModuleType.RESSOURCE
|
||||||
if can_edit:
|
|
||||||
H.append(
|
|
||||||
' <a href="edit_ue_expr?formsemestre_id=%s&ue_id=%s">'
|
|
||||||
% (formsemestre_id, ue["ue_id"])
|
|
||||||
)
|
|
||||||
H.append(
|
|
||||||
scu.icontag(
|
|
||||||
"formula",
|
|
||||||
title="Mode calcul moyenne d'UE",
|
|
||||||
style="vertical-align:middle",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if can_edit:
|
|
||||||
H.append("</a>")
|
|
||||||
if expr:
|
|
||||||
H.append(
|
|
||||||
""" <span class="formula" title="mode de calcul de la moyenne d'UE">%s</span>"""
|
|
||||||
% expr
|
|
||||||
)
|
|
||||||
|
|
||||||
H.append("</td></tr>")
|
|
||||||
|
|
||||||
if M["ue"]["type"] != sco_codes_parcours.UE_STANDARD:
|
|
||||||
fontorange = " fontorange" # style css additionnel
|
|
||||||
else:
|
|
||||||
fontorange = ""
|
|
||||||
|
|
||||||
etat = sco_evaluations.do_evaluation_etat_in_mod(nt, M["moduleimpl_id"])
|
|
||||||
if (
|
|
||||||
etat["nb_evals_completes"] > 0
|
|
||||||
and etat["nb_evals_en_cours"] == 0
|
|
||||||
and etat["nb_evals_vides"] == 0
|
|
||||||
):
|
|
||||||
H.append('<tr class="formsemestre_status_green%s">' % fontorange)
|
|
||||||
else:
|
|
||||||
H.append('<tr class="formsemestre_status%s">' % fontorange)
|
|
||||||
|
|
||||||
H.append(
|
|
||||||
'<td class="formsemestre_status_code"><a href="moduleimpl_status?moduleimpl_id=%s" title="%s" class="stdlink">%s</a></td>'
|
|
||||||
% (M["moduleimpl_id"], ModDescr, Mod["code"])
|
|
||||||
)
|
|
||||||
H.append(
|
|
||||||
'<td class="scotext"><a href="moduleimpl_status?moduleimpl_id=%s" title="%s" class="formsemestre_status_link">%s</a></td>'
|
|
||||||
% (M["moduleimpl_id"], ModDescr, Mod["abbrev"] or Mod["titre"])
|
|
||||||
)
|
|
||||||
H.append('<td class="formsemestre_status_inscrits">%s</td>' % len(ModInscrits))
|
|
||||||
H.append(
|
|
||||||
'<td class="resp scotext"><a class="discretelink" href="moduleimpl_status?moduleimpl_id=%s" title="%s">%s</a></td>'
|
|
||||||
% (
|
|
||||||
M["moduleimpl_id"],
|
|
||||||
ModEns,
|
|
||||||
sco_users.user_info(M["responsable_id"])["prenomnom"],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if Mod["module_type"] == scu.MODULE_STANDARD:
|
|
||||||
H.append('<td class="evals">')
|
|
||||||
nb_evals = (
|
|
||||||
etat["nb_evals_completes"]
|
|
||||||
+ etat["nb_evals_en_cours"]
|
|
||||||
+ etat["nb_evals_vides"]
|
|
||||||
)
|
|
||||||
if nb_evals != 0:
|
|
||||||
H.append(
|
|
||||||
'<a href="moduleimpl_status?moduleimpl_id=%s" class="formsemestre_status_link">%s prévues, %s ok</a>'
|
|
||||||
% (M["moduleimpl_id"], nb_evals, etat["nb_evals_completes"])
|
|
||||||
)
|
|
||||||
if etat["nb_evals_en_cours"] > 0:
|
|
||||||
H.append(
|
|
||||||
', <span><a class="redlink" href="moduleimpl_status?moduleimpl_id=%s" title="Il manque des notes">%s en cours</a></span>'
|
|
||||||
% (M["moduleimpl_id"], etat["nb_evals_en_cours"])
|
|
||||||
)
|
|
||||||
if etat["attente"]:
|
|
||||||
H.append(
|
|
||||||
' <span><a class="redlink" href="moduleimpl_status?moduleimpl_id=%s" title="Il y a des notes en attente">[en attente]</a></span>'
|
|
||||||
% M["moduleimpl_id"]
|
|
||||||
)
|
|
||||||
elif Mod["module_type"] == scu.MODULE_MALUS:
|
|
||||||
nb_malus_notes = sum(
|
|
||||||
[
|
|
||||||
e["etat"]["nb_notes"]
|
|
||||||
for e in nt.get_mod_evaluation_etat_list(M["moduleimpl_id"])
|
|
||||||
]
|
]
|
||||||
)
|
saes = [m for m in modimpls if m["module"]["module_type"] == ModuleType.SAE]
|
||||||
H.append(
|
autres = [
|
||||||
"""<td class="malus">
|
m
|
||||||
<a href="moduleimpl_status?moduleimpl_id=%s" class="formsemestre_status_link">malus (%d notes)</a>
|
for m in modimpls
|
||||||
|
if m["module"]["module_type"] not in (ModuleType.RESSOURCE, ModuleType.SAE)
|
||||||
|
]
|
||||||
|
H += [
|
||||||
"""
|
"""
|
||||||
% (M["moduleimpl_id"], nb_malus_notes)
|
<div class="tableau_modules">
|
||||||
)
|
""",
|
||||||
|
_TABLEAU_MODULES_HEAD,
|
||||||
|
f"""<tr class="formsemestre_status_cat">
|
||||||
|
<td colspan="5">
|
||||||
|
<span class="status_module_cat">Ressources</span>
|
||||||
|
</td></tr>""",
|
||||||
|
formsemestre_tableau_modules(
|
||||||
|
ressources, nt, formsemestre_id, can_edit=can_edit, show_ues=False
|
||||||
|
),
|
||||||
|
f"""<tr class="formsemestre_status_cat">
|
||||||
|
<td colspan="5">
|
||||||
|
<span class="status_module_cat">SAÉs</span>
|
||||||
|
</td></tr>""",
|
||||||
|
formsemestre_tableau_modules(
|
||||||
|
saes, nt, formsemestre_id, can_edit=can_edit, show_ues=False
|
||||||
|
),
|
||||||
|
]
|
||||||
|
if autres:
|
||||||
|
H += [
|
||||||
|
f"""<tr class="formsemestre_status_cat">
|
||||||
|
<td colspan="5">
|
||||||
|
<span class="status_module_cat">Autres modules</span>
|
||||||
|
</td></tr>""",
|
||||||
|
formsemestre_tableau_modules(
|
||||||
|
autres, nt, formsemestre_id, can_edit=can_edit, show_ues=False
|
||||||
|
),
|
||||||
|
]
|
||||||
|
H += [_TABLEAU_MODULES_FOOT, "</div>"]
|
||||||
else:
|
else:
|
||||||
raise ValueError("Invalid module_type") # a bug
|
# formations classiques: groupe par UE
|
||||||
|
H += [
|
||||||
|
"<p>",
|
||||||
|
_TABLEAU_MODULES_HEAD,
|
||||||
|
formsemestre_tableau_modules(
|
||||||
|
modimpls,
|
||||||
|
nt,
|
||||||
|
formsemestre_id,
|
||||||
|
can_edit=can_edit,
|
||||||
|
use_ue_coefs=use_ue_coefs,
|
||||||
|
),
|
||||||
|
_TABLEAU_MODULES_FOOT,
|
||||||
|
"</p>",
|
||||||
|
]
|
||||||
|
|
||||||
H.append("</td></tr>")
|
if use_ue_coefs:
|
||||||
H.append("</table></p>")
|
|
||||||
if sco_preferences.get_preference("use_ue_coefs", formsemestre_id):
|
|
||||||
H.append(
|
H.append(
|
||||||
"""
|
"""
|
||||||
<p class="infop">utilise les coefficients d'UE pour calculer la moyenne générale.</p>
|
<p class="infop">utilise les coefficients d'UE pour calculer la moyenne générale.</p>
|
||||||
@ -1166,3 +1090,156 @@ def formsemestre_status(formsemestre_id=None):
|
|||||||
% (",".join(adrlist), len(adrlist))
|
% (",".join(adrlist), len(adrlist))
|
||||||
)
|
)
|
||||||
return "".join(H) + html_sco_header.sco_footer()
|
return "".join(H) + html_sco_header.sco_footer()
|
||||||
|
|
||||||
|
|
||||||
|
_TABLEAU_MODULES_HEAD = """
|
||||||
|
<table class="formsemestre_status">
|
||||||
|
<tr>
|
||||||
|
<th class="formsemestre_status">Code</th>
|
||||||
|
<th class="formsemestre_status">Module</th>
|
||||||
|
<th class="formsemestre_status">Inscrits</th>
|
||||||
|
<th class="resp">Responsable</th>
|
||||||
|
<th class="evals">Évaluations</th>
|
||||||
|
</tr>
|
||||||
|
"""
|
||||||
|
_TABLEAU_MODULES_FOOT = """</table>"""
|
||||||
|
|
||||||
|
|
||||||
|
def formsemestre_tableau_modules(
|
||||||
|
modimpls, nt, formsemestre_id, can_edit=True, show_ues=True, use_ue_coefs=False
|
||||||
|
) -> str:
|
||||||
|
"Lignes table HTML avec modules du semestre"
|
||||||
|
H = []
|
||||||
|
prev_ue_id = None
|
||||||
|
for modimpl in modimpls:
|
||||||
|
mod = modimpl["module"]
|
||||||
|
mod_descr = (
|
||||||
|
"Module "
|
||||||
|
+ modimpl["module"]["titre"]
|
||||||
|
+ ", coef. "
|
||||||
|
+ str(modimpl["module"]["coefficient"])
|
||||||
|
)
|
||||||
|
mod_ens = sco_users.user_info(modimpl["responsable_id"])["nomcomplet"]
|
||||||
|
if modimpl["ens"]:
|
||||||
|
mod_ens += " (resp.), " + ", ".join(
|
||||||
|
[sco_users.user_info(e["ens_id"])["nomcomplet"] for e in modimpl["ens"]]
|
||||||
|
)
|
||||||
|
mod_inscrits = sco_moduleimpl.do_moduleimpl_inscription_list(
|
||||||
|
moduleimpl_id=modimpl["moduleimpl_id"]
|
||||||
|
)
|
||||||
|
|
||||||
|
ue = modimpl["ue"]
|
||||||
|
if show_ues and (prev_ue_id != ue["ue_id"]):
|
||||||
|
prev_ue_id = ue["ue_id"]
|
||||||
|
titre = ue["titre"]
|
||||||
|
if use_ue_coefs:
|
||||||
|
titre += " <b>(coef. %s)</b>" % (ue["coefficient"] or 0.0)
|
||||||
|
H.append(
|
||||||
|
f"""<tr class="formsemestre_status_ue"><td colspan="4">
|
||||||
|
<span class="status_ue_acro">{ue["acronyme"]}</span>
|
||||||
|
<span class="status_ue_title">{titre}</span>
|
||||||
|
</td><td>"""
|
||||||
|
)
|
||||||
|
if can_edit:
|
||||||
|
H.append(
|
||||||
|
' <a href="edit_ue_expr?formsemestre_id=%s&ue_id=%s">'
|
||||||
|
% (formsemestre_id, ue["ue_id"])
|
||||||
|
)
|
||||||
|
H.append(
|
||||||
|
scu.icontag(
|
||||||
|
"formula",
|
||||||
|
title="Mode calcul moyenne d'UE",
|
||||||
|
style="vertical-align:middle",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if can_edit:
|
||||||
|
H.append("</a>")
|
||||||
|
|
||||||
|
expr = sco_compute_moy.get_ue_expression(
|
||||||
|
formsemestre_id, ue["ue_id"], html_quote=True
|
||||||
|
)
|
||||||
|
if expr:
|
||||||
|
H.append(
|
||||||
|
""" <span class="formula" title="mode de calcul de la moyenne d'UE">%s</span>"""
|
||||||
|
% expr
|
||||||
|
)
|
||||||
|
|
||||||
|
H.append("</td></tr>")
|
||||||
|
|
||||||
|
if modimpl["ue"]["type"] != sco_codes_parcours.UE_STANDARD:
|
||||||
|
fontorange = " fontorange" # style css additionnel
|
||||||
|
else:
|
||||||
|
fontorange = ""
|
||||||
|
|
||||||
|
etat = sco_evaluations.do_evaluation_etat_in_mod(nt, modimpl["moduleimpl_id"])
|
||||||
|
if (
|
||||||
|
etat["nb_evals_completes"] > 0
|
||||||
|
and etat["nb_evals_en_cours"] == 0
|
||||||
|
and etat["nb_evals_vides"] == 0
|
||||||
|
):
|
||||||
|
H.append('<tr class="formsemestre_status_green%s">' % fontorange)
|
||||||
|
else:
|
||||||
|
H.append('<tr class="formsemestre_status%s">' % fontorange)
|
||||||
|
|
||||||
|
H.append(
|
||||||
|
'<td class="formsemestre_status_code"><a href="moduleimpl_status?moduleimpl_id=%s" title="%s" class="stdlink">%s</a></td>'
|
||||||
|
% (modimpl["moduleimpl_id"], mod_descr, mod["code"])
|
||||||
|
)
|
||||||
|
H.append(
|
||||||
|
'<td class="scotext"><a href="moduleimpl_status?moduleimpl_id=%s" title="%s" class="formsemestre_status_link">%s</a></td>'
|
||||||
|
% (modimpl["moduleimpl_id"], mod_descr, mod["abbrev"] or mod["titre"])
|
||||||
|
)
|
||||||
|
H.append('<td class="formsemestre_status_inscrits">%s</td>' % len(mod_inscrits))
|
||||||
|
H.append(
|
||||||
|
'<td class="resp scotext"><a class="discretelink" href="moduleimpl_status?moduleimpl_id=%s" title="%s">%s</a></td>'
|
||||||
|
% (
|
||||||
|
modimpl["moduleimpl_id"],
|
||||||
|
mod_ens,
|
||||||
|
sco_users.user_info(modimpl["responsable_id"])["prenomnom"],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if mod["module_type"] in (
|
||||||
|
ModuleType.STANDARD,
|
||||||
|
ModuleType.RESSOURCE,
|
||||||
|
ModuleType.SAE,
|
||||||
|
):
|
||||||
|
H.append('<td class="evals">')
|
||||||
|
nb_evals = (
|
||||||
|
etat["nb_evals_completes"]
|
||||||
|
+ etat["nb_evals_en_cours"]
|
||||||
|
+ etat["nb_evals_vides"]
|
||||||
|
)
|
||||||
|
if nb_evals != 0:
|
||||||
|
H.append(
|
||||||
|
'<a href="moduleimpl_status?moduleimpl_id=%s" class="formsemestre_status_link">%s prévues, %s ok</a>'
|
||||||
|
% (modimpl["moduleimpl_id"], nb_evals, etat["nb_evals_completes"])
|
||||||
|
)
|
||||||
|
if etat["nb_evals_en_cours"] > 0:
|
||||||
|
H.append(
|
||||||
|
', <span><a class="redlink" href="moduleimpl_status?moduleimpl_id=%s" title="Il manque des notes">%s en cours</a></span>'
|
||||||
|
% (modimpl["moduleimpl_id"], etat["nb_evals_en_cours"])
|
||||||
|
)
|
||||||
|
if etat["attente"]:
|
||||||
|
H.append(
|
||||||
|
' <span><a class="redlink" href="moduleimpl_status?moduleimpl_id=%s" title="Il y a des notes en attente">[en attente]</a></span>'
|
||||||
|
% modimpl["moduleimpl_id"]
|
||||||
|
)
|
||||||
|
elif mod["module_type"] == ModuleType.MALUS:
|
||||||
|
nb_malus_notes = sum(
|
||||||
|
[
|
||||||
|
e["etat"]["nb_notes"]
|
||||||
|
for e in nt.get_mod_evaluation_etat_list(modimpl["moduleimpl_id"])
|
||||||
|
]
|
||||||
|
)
|
||||||
|
H.append(
|
||||||
|
"""<td class="malus">
|
||||||
|
<a href="moduleimpl_status?moduleimpl_id=%s" class="formsemestre_status_link">malus (%d notes)</a>
|
||||||
|
"""
|
||||||
|
% (modimpl["moduleimpl_id"], nb_malus_notes)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise ValueError("Invalid module_type") # a bug
|
||||||
|
|
||||||
|
H.append("</td></tr>")
|
||||||
|
return "\n".join(H)
|
||||||
|
@ -956,7 +956,7 @@ def do_formsemestre_validation_auto(formsemestre_id):
|
|||||||
def formsemestre_validation_suppress_etud(formsemestre_id, etudid):
|
def formsemestre_validation_suppress_etud(formsemestre_id, etudid):
|
||||||
"""Suppression des decisions de jury pour un etudiant."""
|
"""Suppression des decisions de jury pour un etudiant."""
|
||||||
log("formsemestre_validation_suppress_etud( %s, %s)" % (formsemestre_id, etudid))
|
log("formsemestre_validation_suppress_etud( %s, %s)" % (formsemestre_id, etudid))
|
||||||
cnx = ndb.GetDBConnexion(autocommit=False)
|
cnx = ndb.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
args = {"formsemestre_id": formsemestre_id, "etudid": etudid}
|
args = {"formsemestre_id": formsemestre_id, "etudid": etudid}
|
||||||
try:
|
try:
|
||||||
@ -1123,7 +1123,7 @@ def do_formsemestre_validate_previous_ue(
|
|||||||
cette UE (utile seulement pour les semestres extérieurs).
|
cette UE (utile seulement pour les semestres extérieurs).
|
||||||
"""
|
"""
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
cnx = ndb.GetDBConnexion(autocommit=False)
|
cnx = ndb.GetDBConnexion()
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etud_ue_status
|
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_etud_ue_status
|
||||||
if ue_coefficient != None:
|
if ue_coefficient != None:
|
||||||
sco_formsemestre.do_formsemestre_uecoef_edit_or_create(
|
sco_formsemestre.do_formsemestre_uecoef_edit_or_create(
|
||||||
|
@ -262,7 +262,7 @@ def scolars_import_excel_file(
|
|||||||
et les inscrit dans le semestre indiqué (et à TOUS ses modules)
|
et les inscrit dans le semestre indiqué (et à TOUS ses modules)
|
||||||
"""
|
"""
|
||||||
log("scolars_import_excel_file: formsemestre_id=%s" % formsemestre_id)
|
log("scolars_import_excel_file: formsemestre_id=%s" % formsemestre_id)
|
||||||
cnx = ndb.GetDBConnexion(autocommit=False)
|
cnx = ndb.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
annee_courante = time.localtime()[0]
|
annee_courante = time.localtime()[0]
|
||||||
always_require_ine = sco_preferences.get_preference("always_require_ine")
|
always_require_ine = sco_preferences.get_preference("always_require_ine")
|
||||||
|
@ -37,13 +37,12 @@ import app.scodoc.sco_utils as scu
|
|||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator
|
from app.scodoc.TrivialFormulator import TrivialFormulator
|
||||||
from app.scodoc import htmlutils
|
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import sco_abs
|
from app.scodoc import sco_abs
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_edit_module
|
from app.scodoc import sco_edit_module
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluations
|
||||||
from app.scodoc import sco_excel
|
from app.scodoc import sco_evaluation_db
|
||||||
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_groups
|
from app.scodoc import sco_groups
|
||||||
@ -68,11 +67,11 @@ def do_evaluation_listenotes():
|
|||||||
if "evaluation_id" in vals:
|
if "evaluation_id" in vals:
|
||||||
evaluation_id = int(vals["evaluation_id"])
|
evaluation_id = int(vals["evaluation_id"])
|
||||||
mode = "eval"
|
mode = "eval"
|
||||||
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
evals = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})
|
||||||
if "moduleimpl_id" in vals and vals["moduleimpl_id"]:
|
if "moduleimpl_id" in vals and vals["moduleimpl_id"]:
|
||||||
moduleimpl_id = int(vals["moduleimpl_id"])
|
moduleimpl_id = int(vals["moduleimpl_id"])
|
||||||
mode = "module"
|
mode = "module"
|
||||||
evals = sco_evaluations.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
evals = sco_evaluation_db.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
||||||
if not mode:
|
if not mode:
|
||||||
raise ValueError("missing argument: evaluation or module")
|
raise ValueError("missing argument: evaluation or module")
|
||||||
if not evals:
|
if not evals:
|
||||||
@ -545,7 +544,7 @@ def _add_eval_columns(
|
|||||||
sum_notes = 0
|
sum_notes = 0
|
||||||
notes = [] # liste des notes numeriques, pour calcul histogramme uniquement
|
notes = [] # liste des notes numeriques, pour calcul histogramme uniquement
|
||||||
evaluation_id = e["evaluation_id"]
|
evaluation_id = e["evaluation_id"]
|
||||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(evaluation_id)
|
NotesDB = sco_evaluation_db.do_evaluation_get_all_notes(evaluation_id)
|
||||||
for row in rows:
|
for row in rows:
|
||||||
etudid = row["etudid"]
|
etudid = row["etudid"]
|
||||||
if etudid in NotesDB:
|
if etudid in NotesDB:
|
||||||
@ -710,7 +709,7 @@ def evaluation_check_absences(evaluation_id):
|
|||||||
EXC et pas justifie
|
EXC et pas justifie
|
||||||
Ramene 3 listes d'etudid
|
Ramene 3 listes d'etudid
|
||||||
"""
|
"""
|
||||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
if not E["jour"]:
|
if not E["jour"]:
|
||||||
return [], [], [], [], [] # evaluation sans date
|
return [], [], [], [], [] # evaluation sans date
|
||||||
|
|
||||||
@ -731,7 +730,7 @@ def evaluation_check_absences(evaluation_id):
|
|||||||
Justs = set([x["etudid"] for x in Just]) # ensemble des etudiants avec justif
|
Justs = set([x["etudid"] for x in Just]) # ensemble des etudiants avec justif
|
||||||
|
|
||||||
# Les notes:
|
# Les notes:
|
||||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(evaluation_id)
|
NotesDB = sco_evaluation_db.do_evaluation_get_all_notes(evaluation_id)
|
||||||
ValButAbs = [] # une note mais noté absent
|
ValButAbs = [] # une note mais noté absent
|
||||||
AbsNonSignalee = [] # note ABS mais pas noté absent
|
AbsNonSignalee = [] # note ABS mais pas noté absent
|
||||||
ExcNonSignalee = [] # note EXC mais pas noté absent
|
ExcNonSignalee = [] # note EXC mais pas noté absent
|
||||||
@ -764,7 +763,7 @@ def evaluation_check_absences(evaluation_id):
|
|||||||
def evaluation_check_absences_html(evaluation_id, with_header=True, show_ok=True):
|
def evaluation_check_absences_html(evaluation_id, with_header=True, show_ok=True):
|
||||||
"""Affiche etat verification absences d'une evaluation"""
|
"""Affiche etat verification absences d'une evaluation"""
|
||||||
|
|
||||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
am, pm, demijournee = _eval_demijournee(E)
|
am, pm, demijournee = _eval_demijournee(E)
|
||||||
|
|
||||||
(
|
(
|
||||||
@ -876,7 +875,7 @@ def formsemestre_check_absences_html(formsemestre_id):
|
|||||||
# Modules, dans l'ordre
|
# Modules, dans l'ordre
|
||||||
Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
Mlist = sco_moduleimpl.moduleimpl_withmodule_list(formsemestre_id=formsemestre_id)
|
||||||
for M in Mlist:
|
for M in Mlist:
|
||||||
evals = sco_evaluations.do_evaluation_list(
|
evals = sco_evaluation_db.do_evaluation_list(
|
||||||
{"moduleimpl_id": M["moduleimpl_id"]}
|
{"moduleimpl_id": M["moduleimpl_id"]}
|
||||||
)
|
)
|
||||||
if evals:
|
if evals:
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
"""Tableau de bord module
|
"""Tableau de bord module
|
||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
import urllib
|
|
||||||
|
|
||||||
from flask import g, url_for
|
from flask import g, url_for
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
@ -44,6 +43,7 @@ from app.scodoc import sco_compute_moy
|
|||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_edit_module
|
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_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_formsemestre_status
|
from app.scodoc import sco_formsemestre_status
|
||||||
@ -57,7 +57,7 @@ from app.scodoc import sco_users
|
|||||||
# menu evaluation dans moduleimpl
|
# menu evaluation dans moduleimpl
|
||||||
def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0):
|
def moduleimpl_evaluation_menu(evaluation_id, nbnotes=0):
|
||||||
"Menu avec actions sur une evaluation"
|
"Menu avec actions sur une evaluation"
|
||||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
modimpl = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
modimpl = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
|
|
||||||
group_id = sco_groups.get_default_group(modimpl["formsemestre_id"])
|
group_id = sco_groups.get_default_group(modimpl["formsemestre_id"])
|
||||||
@ -161,13 +161,13 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0]
|
||||||
ModInscrits = sco_moduleimpl.do_moduleimpl_inscription_list(
|
mod_inscrits = sco_moduleimpl.do_moduleimpl_inscription_list(
|
||||||
moduleimpl_id=M["moduleimpl_id"]
|
moduleimpl_id=M["moduleimpl_id"]
|
||||||
)
|
)
|
||||||
|
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
nt = sco_cache.NotesTableCache.get(formsemestre_id)
|
||||||
ModEvals = sco_evaluations.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
mod_evals = sco_evaluation_db.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
|
||||||
ModEvals.sort(
|
mod_evals.sort(
|
||||||
key=lambda x: (x["numero"], x["jour"], x["heure_debut"]), reverse=True
|
key=lambda x: (x["numero"], x["jour"], x["heure_debut"]), reverse=True
|
||||||
) # la plus RECENTE en tête
|
) # la plus RECENTE en tête
|
||||||
|
|
||||||
@ -179,15 +179,19 @@ 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(M["responsable_id"])
|
module_resp = User.query.get(M["responsable_id"])
|
||||||
|
mod_type_name = scu.MODULE_TYPE_NAMES[Mod["module_type"]]
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(page_title="Module %(titre)s" % Mod),
|
html_sco_header.sco_header(page_title=f"{mod_type_name} {Mod['titre']}"),
|
||||||
"""<h2 class="formsemestre">Module <tt>%(code)s</tt> %(titre)s</h2>""" % Mod,
|
f"""<h2 class="formsemestre">{mod_type_name}
|
||||||
"""<div class="moduleimpl_tableaubord">
|
<tt>{Mod['code']}</tt> {Mod['titre']}</h2>
|
||||||
|
<div class="moduleimpl_tableaubord moduleimpl_type_{
|
||||||
|
scu.ModuleType(Mod['module_type']).name.lower()}">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fichetitre2">Responsable: </td><td class="redboldtext">""",
|
<td class="fichetitre2">Responsable: </td><td class="redboldtext">
|
||||||
module_resp.get_nomcomplet(), # sco_users.user_info(M["responsable_id"])["nomprenom"],
|
{module_resp.get_nomcomplet()}
|
||||||
f"""<span class="blacktt">({module_resp.user_name})</span>""",
|
<span class="blacktt">({module_resp.user_name})</span>
|
||||||
|
""",
|
||||||
]
|
]
|
||||||
try:
|
try:
|
||||||
sco_moduleimpl.can_change_module_resp(moduleimpl_id)
|
sco_moduleimpl.can_change_module_resp(moduleimpl_id)
|
||||||
@ -231,7 +235,7 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
# Ligne: Inscrits
|
# Ligne: Inscrits
|
||||||
H.append(
|
H.append(
|
||||||
"""<tr><td class="fichetitre2">Inscrits: </td><td> %d étudiants"""
|
"""<tr><td class="fichetitre2">Inscrits: </td><td> %d étudiants"""
|
||||||
% len(ModInscrits)
|
% len(mod_inscrits)
|
||||||
)
|
)
|
||||||
if current_user.has_permission(Permission.ScoEtudInscrit):
|
if current_user.has_permission(Permission.ScoEtudInscrit):
|
||||||
H.append(
|
H.append(
|
||||||
@ -297,7 +301,7 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
"""<p><form name="f"><span style="font-size:120%%; font-weight: bold;">%d évaluations :</span>
|
"""<p><form name="f"><span style="font-size:120%%; font-weight: bold;">%d évaluations :</span>
|
||||||
<span style="padding-left: 30px;">
|
<span style="padding-left: 30px;">
|
||||||
<input type="hidden" name="moduleimpl_id" value="%s"/>"""
|
<input type="hidden" name="moduleimpl_id" value="%s"/>"""
|
||||||
% (len(ModEvals), moduleimpl_id)
|
% (len(mod_evals), moduleimpl_id)
|
||||||
)
|
)
|
||||||
#
|
#
|
||||||
# Liste les noms de partitions
|
# Liste les noms de partitions
|
||||||
@ -341,16 +345,16 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
"""
|
"""
|
||||||
% M
|
% M
|
||||||
)
|
)
|
||||||
if ModEvals:
|
if mod_evals:
|
||||||
H.append(
|
H.append(
|
||||||
'<div class="moduleimpl_evaluations_top_links">'
|
'<div class="moduleimpl_evaluations_top_links">'
|
||||||
+ top_table_links
|
+ top_table_links
|
||||||
+ "</div>"
|
+ "</div>"
|
||||||
)
|
)
|
||||||
H.append("""<table class="moduleimpl_evaluations">""")
|
H.append("""<table class="moduleimpl_evaluations">""")
|
||||||
eval_index = len(ModEvals) - 1
|
eval_index = len(mod_evals) - 1
|
||||||
first = True
|
first = True
|
||||||
for eval in ModEvals:
|
for eval in mod_evals:
|
||||||
etat = sco_evaluations.do_evaluation_etat(
|
etat = sco_evaluations.do_evaluation_etat(
|
||||||
eval["evaluation_id"],
|
eval["evaluation_id"],
|
||||||
partition_id=partition_id,
|
partition_id=partition_id,
|
||||||
@ -399,7 +403,7 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
|
|||||||
)
|
)
|
||||||
# Fleches:
|
# Fleches:
|
||||||
H.append('<span class="eval_arrows_chld">')
|
H.append('<span class="eval_arrows_chld">')
|
||||||
if eval_index != (len(ModEvals) - 1) and caneditevals:
|
if eval_index != (len(mod_evals) - 1) and caneditevals:
|
||||||
H.append(
|
H.append(
|
||||||
'<a href="module_evaluation_move?evaluation_id=%s&after=0" class="aud">%s</a>'
|
'<a href="module_evaluation_move?evaluation_id=%s&after=0" class="aud">%s</a>'
|
||||||
% (eval["evaluation_id"], arrow_up)
|
% (eval["evaluation_id"], arrow_up)
|
||||||
|
@ -42,7 +42,6 @@ from app import log
|
|||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc import sco_users
|
|
||||||
from app import email
|
from app import email
|
||||||
|
|
||||||
|
|
||||||
@ -82,6 +81,8 @@ def add(typ, object=None, text="", url=None, max_frequency=False):
|
|||||||
Si max_frequency, ne genere pas 2 nouvelles identiques à moins de max_frequency
|
Si max_frequency, ne genere pas 2 nouvelles identiques à moins de max_frequency
|
||||||
secondes d'intervalle.
|
secondes d'intervalle.
|
||||||
"""
|
"""
|
||||||
|
from app.scodoc import sco_users
|
||||||
|
|
||||||
authuser_name = current_user.user_name
|
authuser_name = current_user.user_name
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
args = {
|
args = {
|
||||||
@ -112,6 +113,7 @@ def scolar_news_summary(n=5):
|
|||||||
News are "compressed", ie redondant events are joined.
|
News are "compressed", ie redondant events are joined.
|
||||||
"""
|
"""
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
|
from app.scodoc import sco_users
|
||||||
|
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
|
@ -539,7 +539,7 @@ class SituationEtudParcoursGeneric(object):
|
|||||||
"""Enregistre la decision (instance de DecisionSem)
|
"""Enregistre la decision (instance de DecisionSem)
|
||||||
Enregistre codes semestre et UE, et autorisations inscription.
|
Enregistre codes semestre et UE, et autorisations inscription.
|
||||||
"""
|
"""
|
||||||
cnx = ndb.GetDBConnexion(autocommit=False)
|
cnx = ndb.GetDBConnexion()
|
||||||
# -- check
|
# -- check
|
||||||
if decision.code_etat in self.parcours.UNUSED_CODES:
|
if decision.code_etat in self.parcours.UNUSED_CODES:
|
||||||
raise ScoValueError("code decision invalide dans ce parcours")
|
raise ScoValueError("code decision invalide dans ce parcours")
|
||||||
@ -902,7 +902,7 @@ def formsemestre_validate_ues(formsemestre_id, etudid, code_etat_sem, assiduite)
|
|||||||
Les UE des semestres NON ASSIDUS ne sont jamais validées (code AJ).
|
Les UE des semestres NON ASSIDUS ne sont jamais validées (code AJ).
|
||||||
"""
|
"""
|
||||||
valid_semestre = CODES_SEM_VALIDES.get(code_etat_sem, False)
|
valid_semestre = CODES_SEM_VALIDES.get(code_etat_sem, False)
|
||||||
cnx = ndb.GetDBConnexion(autocommit=False)
|
cnx = ndb.GetDBConnexion()
|
||||||
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_ues, get_etud_ue_status
|
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > get_ues, get_etud_ue_status
|
||||||
ue_ids = [x["ue_id"] for x in nt.get_ues(etudid=etudid, filter_sport=True)]
|
ue_ids = [x["ue_id"] for x in nt.get_ues(etudid=etudid, filter_sport=True)]
|
||||||
for ue_id in ue_ids:
|
for ue_id in ue_ids:
|
||||||
|
@ -54,6 +54,7 @@ from app import ScoValueError
|
|||||||
from app.scodoc import html_sco_header, sco_preferences
|
from app.scodoc import html_sco_header, sco_preferences
|
||||||
from app.scodoc import sco_edit_module
|
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_excel
|
from app.scodoc import sco_excel
|
||||||
from app.scodoc.sco_excel import ScoExcelBook, COLORS
|
from app.scodoc.sco_excel import ScoExcelBook, COLORS
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
@ -137,7 +138,9 @@ class PlacementForm(FlaskForm):
|
|||||||
|
|
||||||
def set_evaluation_infos(self, evaluation_id):
|
def set_evaluation_infos(self, evaluation_id):
|
||||||
"""Initialise les données du formulaire avec les données de l'évaluation."""
|
"""Initialise les données du formulaire avec les données de l'évaluation."""
|
||||||
eval_data = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
eval_data = sco_evaluation_db.do_evaluation_list(
|
||||||
|
{"evaluation_id": evaluation_id}
|
||||||
|
)
|
||||||
if not eval_data:
|
if not eval_data:
|
||||||
raise ScoValueError("invalid evaluation_id")
|
raise ScoValueError("invalid evaluation_id")
|
||||||
self.groups_tree, self.has_groups, self.nb_groups = _get_group_info(
|
self.groups_tree, self.has_groups, self.nb_groups = _get_group_info(
|
||||||
@ -236,7 +239,7 @@ class PlacementRunner:
|
|||||||
self.groups_ids = [
|
self.groups_ids = [
|
||||||
gid if gid != TOUS else form.tous_id for gid in form["groups"].data
|
gid if gid != TOUS else form.tous_id for gid in form["groups"].data
|
||||||
]
|
]
|
||||||
self.eval_data = sco_evaluations.do_evaluation_list(
|
self.eval_data = sco_evaluation_db.do_evaluation_list(
|
||||||
{"evaluation_id": self.evaluation_id}
|
{"evaluation_id": self.evaluation_id}
|
||||||
)[0]
|
)[0]
|
||||||
self.groups = sco_groups.listgroups(self.groups_ids)
|
self.groups = sco_groups.listgroups(self.groups_ids)
|
||||||
|
@ -45,11 +45,11 @@ from app.scodoc import sco_bulletins, sco_excel
|
|||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluations
|
||||||
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_formsemestre
|
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_permissions
|
|
||||||
from app.scodoc import sco_permissions_check
|
from app.scodoc import sco_permissions_check
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
@ -818,9 +818,9 @@ def _list_notes_evals(evals, etudid):
|
|||||||
or e["etat"]["evalattente"]
|
or e["etat"]["evalattente"]
|
||||||
or e["publish_incomplete"]
|
or e["publish_incomplete"]
|
||||||
):
|
):
|
||||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(e["evaluation_id"])
|
notes_db = sco_evaluation_db.do_evaluation_get_all_notes(e["evaluation_id"])
|
||||||
if etudid in NotesDB:
|
if etudid in notes_db:
|
||||||
val = NotesDB[etudid]["value"]
|
val = notes_db[etudid]["value"]
|
||||||
else:
|
else:
|
||||||
# Note manquante mais prise en compte immédiate: affiche ATT
|
# Note manquante mais prise en compte immédiate: affiche ATT
|
||||||
val = scu.NOTES_ATTENTE
|
val = scu.NOTES_ATTENTE
|
||||||
|
@ -40,7 +40,7 @@ from flask import url_for, g, request
|
|||||||
import pydot
|
import pydot
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
from app.models import NotesFormModalite
|
from app.models import FormationModalite
|
||||||
from app.scodoc import notesdb as ndb
|
from app.scodoc import notesdb as ndb
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
@ -1340,7 +1340,7 @@ def graph_parcours(
|
|||||||
log("n=%s" % n)
|
log("n=%s" % n)
|
||||||
log("get=%s" % g.get_node(sem_node_name(s)))
|
log("get=%s" % g.get_node(sem_node_name(s)))
|
||||||
log("nodes names = %s" % [x.get_name() for x in g.get_node_list()])
|
log("nodes names = %s" % [x.get_name() for x in g.get_node_list()])
|
||||||
if s["modalite"] and s["modalite"] != NotesFormModalite.DEFAULT_MODALITE:
|
if s["modalite"] and s["modalite"] != FormationModalite.DEFAULT_MODALITE:
|
||||||
modalite = " " + s["modalite"]
|
modalite = " " + s["modalite"]
|
||||||
else:
|
else:
|
||||||
modalite = ""
|
modalite = ""
|
||||||
|
@ -39,6 +39,7 @@ from flask import g, url_for, request
|
|||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
from app.scodoc.sco_utils import ModuleType
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.sco_exceptions import (
|
from app.scodoc.sco_exceptions import (
|
||||||
@ -56,6 +57,7 @@ from app.scodoc import sco_abs
|
|||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_edit_module
|
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_excel
|
from app.scodoc import sco_excel
|
||||||
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
|
||||||
@ -133,9 +135,13 @@ def _check_notes(notes, evaluation, mod):
|
|||||||
and 4 lists of etudid: invalids, withoutnotes, absents, tosuppress, existingjury
|
and 4 lists of etudid: invalids, withoutnotes, absents, tosuppress, existingjury
|
||||||
"""
|
"""
|
||||||
note_max = evaluation["note_max"]
|
note_max = evaluation["note_max"]
|
||||||
if mod["module_type"] == scu.MODULE_STANDARD:
|
if mod["module_type"] in (
|
||||||
|
scu.ModuleType.STANDARD,
|
||||||
|
scu.ModuleType.RESSOURCE,
|
||||||
|
scu.ModuleType.SAE,
|
||||||
|
):
|
||||||
note_min = scu.NOTES_MIN
|
note_min = scu.NOTES_MIN
|
||||||
elif mod["module_type"] == scu.MODULE_MALUS:
|
elif mod["module_type"] == ModuleType.MALUS:
|
||||||
note_min = -20.0
|
note_min = -20.0
|
||||||
else:
|
else:
|
||||||
raise ValueError("Invalid module type") # bug
|
raise ValueError("Invalid module type") # bug
|
||||||
@ -176,7 +182,7 @@ def do_evaluation_upload_xls():
|
|||||||
vals = scu.get_request_args()
|
vals = scu.get_request_args()
|
||||||
evaluation_id = int(vals["evaluation_id"])
|
evaluation_id = int(vals["evaluation_id"])
|
||||||
comment = vals["comment"]
|
comment = vals["comment"]
|
||||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
# Check access
|
# Check access
|
||||||
# (admin, respformation, and responsable_id)
|
# (admin, respformation, and responsable_id)
|
||||||
@ -253,7 +259,9 @@ def do_evaluation_upload_xls():
|
|||||||
authuser, evaluation_id, L, comment
|
authuser, evaluation_id, L, comment
|
||||||
)
|
)
|
||||||
# news
|
# news
|
||||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[
|
||||||
|
0
|
||||||
|
]
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
mod["moduleimpl_id"] = M["moduleimpl_id"]
|
||||||
@ -292,7 +300,7 @@ def do_evaluation_upload_xls():
|
|||||||
|
|
||||||
def do_evaluation_set_missing(evaluation_id, value, dialog_confirmed=False):
|
def do_evaluation_set_missing(evaluation_id, value, dialog_confirmed=False):
|
||||||
"""Initialisation des notes manquantes"""
|
"""Initialisation des notes manquantes"""
|
||||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
# Check access
|
# Check access
|
||||||
# (admin, respformation, and responsable_id)
|
# (admin, respformation, and responsable_id)
|
||||||
@ -300,7 +308,7 @@ def do_evaluation_set_missing(evaluation_id, value, dialog_confirmed=False):
|
|||||||
# XXX imaginer un redirect + msg erreur
|
# XXX imaginer un redirect + msg erreur
|
||||||
raise AccessDenied("Modification des notes impossible pour %s" % current_user)
|
raise AccessDenied("Modification des notes impossible pour %s" % current_user)
|
||||||
#
|
#
|
||||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(evaluation_id)
|
NotesDB = sco_evaluation_db.do_evaluation_get_all_notes(evaluation_id)
|
||||||
etudids = sco_groups.do_evaluation_listeetuds_groups(
|
etudids = sco_groups.do_evaluation_listeetuds_groups(
|
||||||
evaluation_id, getallstudents=True, include_dems=False
|
evaluation_id, getallstudents=True, include_dems=False
|
||||||
)
|
)
|
||||||
@ -378,19 +386,19 @@ def do_evaluation_set_missing(evaluation_id, value, dialog_confirmed=False):
|
|||||||
|
|
||||||
def evaluation_suppress_alln(evaluation_id, dialog_confirmed=False):
|
def evaluation_suppress_alln(evaluation_id, dialog_confirmed=False):
|
||||||
"suppress all notes in this eval"
|
"suppress all notes in this eval"
|
||||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
|
|
||||||
if sco_permissions_check.can_edit_notes(
|
if sco_permissions_check.can_edit_notes(
|
||||||
current_user, E["moduleimpl_id"], allow_ens=False
|
current_user, E["moduleimpl_id"], allow_ens=False
|
||||||
):
|
):
|
||||||
# On a le droit de modifier toutes les notes
|
# On a le droit de modifier toutes les notes
|
||||||
# recupere les etuds ayant une note
|
# recupere les etuds ayant une note
|
||||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(evaluation_id)
|
NotesDB = sco_evaluation_db.do_evaluation_get_all_notes(evaluation_id)
|
||||||
elif sco_permissions_check.can_edit_notes(
|
elif sco_permissions_check.can_edit_notes(
|
||||||
current_user, E["moduleimpl_id"], allow_ens=True
|
current_user, E["moduleimpl_id"], allow_ens=True
|
||||||
):
|
):
|
||||||
# Enseignant associé au module: ne peut supprimer que les notes qu'il a saisi
|
# Enseignant associé au module: ne peut supprimer que les notes qu'il a saisi
|
||||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(
|
NotesDB = sco_evaluation_db.do_evaluation_get_all_notes(
|
||||||
evaluation_id, by_uid=current_user.id
|
evaluation_id, by_uid=current_user.id
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -471,13 +479,13 @@ def _notes_add(user, evaluation_id: int, notes: list, comment=None, do_it=True):
|
|||||||
"etudiant %s: valeur de note invalide (%s)" % (etudid, value)
|
"etudiant %s: valeur de note invalide (%s)" % (etudid, value)
|
||||||
)
|
)
|
||||||
# Recherche notes existantes
|
# Recherche notes existantes
|
||||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(evaluation_id)
|
NotesDB = sco_evaluation_db.do_evaluation_get_all_notes(evaluation_id)
|
||||||
# Met a jour la base
|
# Met a jour la base
|
||||||
cnx = ndb.GetDBConnexion(autocommit=False)
|
cnx = ndb.GetDBConnexion()
|
||||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||||
nb_changed = 0
|
nb_changed = 0
|
||||||
nb_suppress = 0
|
nb_suppress = 0
|
||||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
existing_decisions = (
|
existing_decisions = (
|
||||||
[]
|
[]
|
||||||
@ -596,7 +604,7 @@ def _notes_add(user, evaluation_id: int, notes: list, comment=None, do_it=True):
|
|||||||
|
|
||||||
def saisie_notes_tableur(evaluation_id, group_ids=()):
|
def saisie_notes_tableur(evaluation_id, group_ids=()):
|
||||||
"""Saisie des notes via un fichier Excel"""
|
"""Saisie des notes via un fichier Excel"""
|
||||||
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
evals = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})
|
||||||
if not evals:
|
if not evals:
|
||||||
raise ScoValueError("invalid evaluation_id")
|
raise ScoValueError("invalid evaluation_id")
|
||||||
E = evals[0]
|
E = evals[0]
|
||||||
@ -767,7 +775,7 @@ def saisie_notes_tableur(evaluation_id, group_ids=()):
|
|||||||
|
|
||||||
def feuille_saisie_notes(evaluation_id, group_ids=[]):
|
def feuille_saisie_notes(evaluation_id, group_ids=[]):
|
||||||
"""Document Excel pour saisie notes dans l'évaluation et les groupes indiqués"""
|
"""Document Excel pour saisie notes dans l'évaluation et les groupes indiqués"""
|
||||||
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
evals = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})
|
||||||
if not evals:
|
if not evals:
|
||||||
raise ScoValueError("invalid evaluation_id")
|
raise ScoValueError("invalid evaluation_id")
|
||||||
E = evals[0]
|
E = evals[0]
|
||||||
@ -866,7 +874,7 @@ def has_existing_decision(M, E, etudid):
|
|||||||
def saisie_notes(evaluation_id, group_ids=[]):
|
def saisie_notes(evaluation_id, group_ids=[]):
|
||||||
"""Formulaire saisie notes d'une évaluation pour un groupe"""
|
"""Formulaire saisie notes d'une évaluation pour un groupe"""
|
||||||
group_ids = [int(group_id) for group_id in group_ids]
|
group_ids = [int(group_id) for group_id in group_ids]
|
||||||
evals = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})
|
evals = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})
|
||||||
if not evals:
|
if not evals:
|
||||||
raise ScoValueError("invalid evaluation_id")
|
raise ScoValueError("invalid evaluation_id")
|
||||||
E = evals[0]
|
E = evals[0]
|
||||||
@ -977,7 +985,7 @@ def saisie_notes(evaluation_id, group_ids=[]):
|
|||||||
|
|
||||||
def _get_sorted_etuds(E, etudids, formsemestre_id):
|
def _get_sorted_etuds(E, etudids, formsemestre_id):
|
||||||
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
sem = sco_formsemestre.get_formsemestre(formsemestre_id)
|
||||||
NotesDB = sco_evaluations.do_evaluation_get_all_notes(
|
notes_db = sco_evaluation_db.do_evaluation_get_all_notes(
|
||||||
E["evaluation_id"]
|
E["evaluation_id"]
|
||||||
) # Notes existantes
|
) # Notes existantes
|
||||||
cnx = ndb.GetDBConnexion()
|
cnx = ndb.GetDBConnexion()
|
||||||
@ -1017,14 +1025,14 @@ def _get_sorted_etuds(E, etudids, formsemestre_id):
|
|||||||
e["absinfo"] = '<span class="sn_abs">' + " ".join(warn_abs_lst) + "</span> "
|
e["absinfo"] = '<span class="sn_abs">' + " ".join(warn_abs_lst) + "</span> "
|
||||||
|
|
||||||
# Note actuelle de l'étudiant:
|
# Note actuelle de l'étudiant:
|
||||||
if etudid in NotesDB:
|
if etudid in notes_db:
|
||||||
e["val"] = _displayNote(NotesDB[etudid]["value"])
|
e["val"] = _displayNote(notes_db[etudid]["value"])
|
||||||
comment = NotesDB[etudid]["comment"]
|
comment = notes_db[etudid]["comment"]
|
||||||
if comment is None:
|
if comment is None:
|
||||||
comment = ""
|
comment = ""
|
||||||
e["explanation"] = "%s (%s) %s" % (
|
e["explanation"] = "%s (%s) %s" % (
|
||||||
NotesDB[etudid]["date"].strftime("%d/%m/%y %Hh%M"),
|
notes_db[etudid]["date"].strftime("%d/%m/%y %Hh%M"),
|
||||||
NotesDB[etudid]["uid"],
|
notes_db[etudid]["uid"],
|
||||||
comment,
|
comment,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -1073,7 +1081,11 @@ def _form_saisie_notes(E, M, group_ids, destination=""):
|
|||||||
("comment", {"size": 44, "title": "Commentaire", "return_focus_next": True}),
|
("comment", {"size": 44, "title": "Commentaire", "return_focus_next": True}),
|
||||||
("changed", {"default": "0", "input_type": "hidden"}), # changed in JS
|
("changed", {"default": "0", "input_type": "hidden"}), # changed in JS
|
||||||
]
|
]
|
||||||
if M["module"]["module_type"] == scu.MODULE_STANDARD:
|
if M["module"]["module_type"] in (
|
||||||
|
ModuleType.STANDARD,
|
||||||
|
ModuleType.RESSOURCE,
|
||||||
|
ModuleType.SAE,
|
||||||
|
):
|
||||||
descr.append(
|
descr.append(
|
||||||
(
|
(
|
||||||
"s3",
|
"s3",
|
||||||
@ -1086,7 +1098,7 @@ def _form_saisie_notes(E, M, group_ids, destination=""):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif M["module"]["module_type"] == scu.MODULE_MALUS:
|
elif M["module"]["module_type"] == ModuleType.MALUS:
|
||||||
descr.append(
|
descr.append(
|
||||||
(
|
(
|
||||||
"s3",
|
"s3",
|
||||||
@ -1229,7 +1241,7 @@ def save_note(etudid=None, evaluation_id=None, value=None, comment=""):
|
|||||||
"save_note: evaluation_id=%s etudid=%s uid=%s value=%s"
|
"save_note: evaluation_id=%s etudid=%s uid=%s value=%s"
|
||||||
% (evaluation_id, etudid, authuser, value)
|
% (evaluation_id, etudid, authuser, value)
|
||||||
)
|
)
|
||||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
Mod = sco_edit_module.module_list(args={"module_id": M["module_id"]})[0]
|
||||||
Mod["url"] = url_for(
|
Mod["url"] = url_for(
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
"""Fonction de gestion des UE "externes" (effectuees dans un cursus exterieur)
|
"""Fonction de gestion des UE "externes" (effectuees dans un cursus exterieur)
|
||||||
|
|
||||||
On rapatrie (saisit) les notes (et crédits ECTS).
|
On rapatrie (saisie) les notes (et crédits ECTS).
|
||||||
|
|
||||||
Cas d'usage: les étudiants d'une formation gérée par ScoDoc peuvent
|
Cas d'usage: les étudiants d'une formation gérée par ScoDoc peuvent
|
||||||
suivre un certain nombre d'UE à l'extérieur. L'établissement a reconnu
|
suivre un certain nombre d'UE à l'extérieur. L'établissement a reconnu
|
||||||
@ -66,6 +66,7 @@ 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_evaluations
|
from app.scodoc import sco_evaluations
|
||||||
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
@ -148,13 +149,15 @@ def external_ue_inscrit_et_note(moduleimpl_id, formsemestre_id, notes_etuds):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Création d'une évaluation si il n'y en a pas déjà:
|
# Création d'une évaluation si il n'y en a pas déjà:
|
||||||
ModEvals = sco_evaluations.do_evaluation_list(args={"moduleimpl_id": moduleimpl_id})
|
mod_evals = sco_evaluation_db.do_evaluation_list(
|
||||||
if len(ModEvals):
|
args={"moduleimpl_id": moduleimpl_id}
|
||||||
|
)
|
||||||
|
if len(mod_evals):
|
||||||
# met la note dans le première évaluation existante:
|
# met la note dans le première évaluation existante:
|
||||||
evaluation_id = ModEvals[0]["evaluation_id"]
|
evaluation_id = mod_evals[0]["evaluation_id"]
|
||||||
else:
|
else:
|
||||||
# crée une évaluation:
|
# crée une évaluation:
|
||||||
evaluation_id = sco_evaluations.do_evaluation_create(
|
evaluation_id = sco_evaluation_db.do_evaluation_create(
|
||||||
moduleimpl_id=moduleimpl_id,
|
moduleimpl_id=moduleimpl_id,
|
||||||
note_max=20.0,
|
note_max=20.0,
|
||||||
coefficient=1.0,
|
coefficient=1.0,
|
||||||
|
@ -53,6 +53,7 @@ from app.scodoc.intervals import intervalmap
|
|||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluations
|
||||||
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import sco_moduleimpl
|
from app.scodoc import sco_moduleimpl
|
||||||
from app.scodoc import sco_preferences
|
from app.scodoc import sco_preferences
|
||||||
@ -105,12 +106,12 @@ class NotesOperation(dict):
|
|||||||
def list_operations(evaluation_id):
|
def list_operations(evaluation_id):
|
||||||
"""returns list of NotesOperation for this evaluation"""
|
"""returns list of NotesOperation for this evaluation"""
|
||||||
notes = list(
|
notes = list(
|
||||||
sco_evaluations.do_evaluation_get_all_notes(
|
sco_evaluation_db.do_evaluation_get_all_notes(
|
||||||
evaluation_id, filter_suppressed=False
|
evaluation_id, filter_suppressed=False
|
||||||
).values()
|
).values()
|
||||||
)
|
)
|
||||||
notes_log = list(
|
notes_log = list(
|
||||||
sco_evaluations.do_evaluation_get_all_notes(
|
sco_evaluation_db.do_evaluation_get_all_notes(
|
||||||
evaluation_id, filter_suppressed=False, table="notes_notes_log"
|
evaluation_id, filter_suppressed=False, table="notes_notes_log"
|
||||||
).values()
|
).values()
|
||||||
)
|
)
|
||||||
@ -148,7 +149,7 @@ def list_operations(evaluation_id):
|
|||||||
|
|
||||||
def evaluation_list_operations(evaluation_id):
|
def evaluation_list_operations(evaluation_id):
|
||||||
"""Page listing operations on evaluation"""
|
"""Page listing operations on evaluation"""
|
||||||
E = sco_evaluations.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
E = sco_evaluation_db.do_evaluation_list({"evaluation_id": evaluation_id})[0]
|
||||||
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=E["moduleimpl_id"])[0]
|
||||||
|
|
||||||
Ops = list_operations(evaluation_id)
|
Ops = list_operations(evaluation_id)
|
||||||
|
@ -49,7 +49,7 @@ import pydot
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
from flask import g, request
|
from flask import g, request
|
||||||
from flask import url_for, make_response
|
from flask import url_for, make_response, jsonify
|
||||||
|
|
||||||
from config import Config
|
from config import Config
|
||||||
from app import log
|
from app import log
|
||||||
@ -71,20 +71,23 @@ NOTES_ATTENTE = -1002.0 # note "en attente" (se calcule comme une note neutrali
|
|||||||
|
|
||||||
|
|
||||||
# Types de modules
|
# Types de modules
|
||||||
MODULE_STANDARD = 0
|
|
||||||
MODULE_MALUS = 1
|
|
||||||
|
|
||||||
|
|
||||||
class ModuleType(IntEnum):
|
class ModuleType(IntEnum):
|
||||||
"""Code des types de module."""
|
"""Code des types de module."""
|
||||||
|
|
||||||
# Stockés en BD dans NotesModule.module_type: ne pas modifier ces valeurs
|
# Stockés en BD dans Module.module_type: ne pas modifier ces valeurs
|
||||||
STANDARD = 0
|
STANDARD = 0
|
||||||
MALUS = 1
|
MALUS = 1
|
||||||
RESSOURCE = 2 # BUT
|
RESSOURCE = 2 # BUT
|
||||||
SAE = 3 # BUT
|
SAE = 3 # BUT
|
||||||
|
|
||||||
|
|
||||||
|
MODULE_TYPE_NAMES = {
|
||||||
|
ModuleType.STANDARD: "Module",
|
||||||
|
ModuleType.MALUS: "Malus",
|
||||||
|
ModuleType.RESSOURCE: "Ressource",
|
||||||
|
ModuleType.SAE: "SAÉ",
|
||||||
|
}
|
||||||
|
|
||||||
MALUS_MAX = 20.0
|
MALUS_MAX = 20.0
|
||||||
MALUS_MIN = -20.0
|
MALUS_MIN = -20.0
|
||||||
|
|
||||||
@ -667,6 +670,17 @@ def get_request_args():
|
|||||||
return vals
|
return vals
|
||||||
|
|
||||||
|
|
||||||
|
def json_error(message, success=False, status=404):
|
||||||
|
"""Simple JSON response, for errors"""
|
||||||
|
response = {
|
||||||
|
"success": success,
|
||||||
|
"status": status,
|
||||||
|
"message": message,
|
||||||
|
}
|
||||||
|
log(f"Error: {response}")
|
||||||
|
return jsonify(response), status
|
||||||
|
|
||||||
|
|
||||||
def get_scodoc_version():
|
def get_scodoc_version():
|
||||||
"return a string identifying ScoDoc version"
|
"return a string identifying ScoDoc version"
|
||||||
return sco_version.SCOVERSION
|
return sco_version.SCOVERSION
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* # -*- mode: css -*-
|
/* # -*- mode: css -*-
|
||||||
ScoDoc, (c) Emmanuel Viennet 1998 - 2020
|
ScoDoc, (c) Emmanuel Viennet 1998 - 2021
|
||||||
*/
|
*/
|
||||||
|
|
||||||
html,body {
|
html,body {
|
||||||
@ -1192,6 +1192,7 @@ table.formsemestre_status {
|
|||||||
tr.formsemestre_status { background-color: rgb(90%,90%,90%); }
|
tr.formsemestre_status { background-color: rgb(90%,90%,90%); }
|
||||||
tr.formsemestre_status_green { background-color: #EFF7F2; }
|
tr.formsemestre_status_green { background-color: #EFF7F2; }
|
||||||
tr.formsemestre_status_ue { background-color: rgb(90%,90%,90%); }
|
tr.formsemestre_status_ue { background-color: rgb(90%,90%,90%); }
|
||||||
|
tr.formsemestre_status_cat td { padding-top: 2ex;}
|
||||||
table.formsemestre_status td {
|
table.formsemestre_status td {
|
||||||
border-top: 1px solid rgb(80%,80%,80%);
|
border-top: 1px solid rgb(80%,80%,80%);
|
||||||
border-bottom: 1px solid rgb(80%,80%,80%);
|
border-bottom: 1px solid rgb(80%,80%,80%);
|
||||||
@ -1236,6 +1237,7 @@ td.formsemestre_status_cell {
|
|||||||
|
|
||||||
span.status_ue_acro { font-weight: bold; }
|
span.status_ue_acro { font-weight: bold; }
|
||||||
span.status_ue_title { font-style: italic; padding-left: 1cm;}
|
span.status_ue_title { font-style: italic; padding-left: 1cm;}
|
||||||
|
span.status_module_cat { font-weight: bold; }
|
||||||
|
|
||||||
table.formsemestre_inscr td {
|
table.formsemestre_inscr td {
|
||||||
padding-right: 1.25em;
|
padding-right: 1.25em;
|
||||||
@ -1268,11 +1270,18 @@ ul.ue_inscr_list li.etud {
|
|||||||
border-spacing: 1px;
|
border-spacing: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Modules */
|
/* Tableau de bord module */
|
||||||
div.moduleimpl_tableaubord {
|
div.moduleimpl_tableaubord {
|
||||||
padding: 7px;
|
padding: 7px;
|
||||||
border: 2px solid gray;
|
border: 2px solid gray;
|
||||||
}
|
}
|
||||||
|
div.moduleimpl_type_sae {
|
||||||
|
background-color:#cfeccf;
|
||||||
|
}
|
||||||
|
div.moduleimpl_type_ressource {
|
||||||
|
background-color:#f5e9d2;
|
||||||
|
}
|
||||||
|
|
||||||
span.moduleimpl_abs_link {
|
span.moduleimpl_abs_link {
|
||||||
padding-right: 2em;
|
padding-right: 2em;
|
||||||
}
|
}
|
||||||
|
93
app/static/css/table_editor.css
Normal file
93
app/static/css/table_editor.css
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/* table_editor, par Sébastien L.
|
||||||
|
*/
|
||||||
|
body {
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************/
|
||||||
|
/* Le tableau */
|
||||||
|
/***************************/
|
||||||
|
.tableau {
|
||||||
|
display: grid;
|
||||||
|
grid-auto-rows: minmax(24px, auto);
|
||||||
|
}
|
||||||
|
|
||||||
|
.entete {
|
||||||
|
background: #09c;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableau>div {
|
||||||
|
padding: 4px;
|
||||||
|
border: 1px solid #999;
|
||||||
|
grid-column: var(--x) / span var(--nbX);
|
||||||
|
grid-row: var(--y) / span var(--nbY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************/
|
||||||
|
/* Attente */
|
||||||
|
/***************************/
|
||||||
|
.wait {
|
||||||
|
position: fixed;
|
||||||
|
top: 32px;
|
||||||
|
left: 50%;
|
||||||
|
height: 4px;
|
||||||
|
width: 32px;
|
||||||
|
margin-left: -16px;
|
||||||
|
background: #424242;
|
||||||
|
animation: attente 0.4s infinite alternate;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.go {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes attente {
|
||||||
|
100% {
|
||||||
|
transform: translateY(-16px) rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************/
|
||||||
|
/* Système de modification */
|
||||||
|
/***************************/
|
||||||
|
.modifOnOff {
|
||||||
|
position: relative;
|
||||||
|
display: table;
|
||||||
|
margin: 16px;
|
||||||
|
padding-right: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modifOnOff::before {
|
||||||
|
content: '';
|
||||||
|
width: 40px;
|
||||||
|
height: 20px;
|
||||||
|
background: #c90;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 100%;
|
||||||
|
border-radius: 20px;
|
||||||
|
transition: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modifOnOff::after {
|
||||||
|
content: '';
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background: #FFF;
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
left: calc(100% + 2px);
|
||||||
|
border-radius: 100%;
|
||||||
|
transition: 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modifOnOff.active::before {
|
||||||
|
background: #9c0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modifOnOff.active::after {
|
||||||
|
transform: translateX(20px);
|
||||||
|
}
|
56
app/static/js/table_editor.js
Normal file
56
app/static/js/table_editor.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/* table_editor, par Sébastien L.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/******************************/
|
||||||
|
/* Gestion de la modification */
|
||||||
|
/******************************/
|
||||||
|
|
||||||
|
function editableOnOff() {
|
||||||
|
if (this.classList.toggle("active")) {
|
||||||
|
document.querySelectorAll("[data-editable=true]").forEach(cellule => {
|
||||||
|
cellule.contentEditable = true;
|
||||||
|
cellule.addEventListener("input", delayBeforeSave);
|
||||||
|
cellule.addEventListener("blur", save);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
document.querySelectorAll("[data-editable=true]").forEach(cellule => {
|
||||||
|
cellule.removeAttribute("contentEditable");
|
||||||
|
cellule.removeEventListener("input", delayBeforeSave);
|
||||||
|
cellule.removeEventListener("blur", save);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let timeout = 0;
|
||||||
|
|
||||||
|
function delayBeforeSave() {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
document.querySelector(".wait").classList.add("go");
|
||||||
|
timeout = setTimeout(() => { save(this) }, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************/
|
||||||
|
/* Mise en place des données */
|
||||||
|
/*****************************/
|
||||||
|
function build_table(data) {
|
||||||
|
let output = "";
|
||||||
|
|
||||||
|
data.forEach((cellule) => {
|
||||||
|
output += `
|
||||||
|
<div
|
||||||
|
class="${cellule.style}"
|
||||||
|
data-editable="${cellule.editable || "false"}"
|
||||||
|
data-module_id="${cellule.module_id}"
|
||||||
|
data-ue_id="${cellule.ue_id}"
|
||||||
|
style="
|
||||||
|
--x:${cellule.x};
|
||||||
|
--y:${cellule.y};
|
||||||
|
--nbX:${cellule.nbX};
|
||||||
|
--nbY: ${cellule.nbY};
|
||||||
|
">
|
||||||
|
${cellule.data}
|
||||||
|
</div>`;
|
||||||
|
})
|
||||||
|
document.querySelector(".tableau").innerHTML = output;
|
||||||
|
document.querySelector(".modifOnOff").addEventListener("click", editableOnOff);
|
||||||
|
}
|
55
app/templates/pn/form_modules_ue_coefs.html
Normal file
55
app/templates/pn/form_modules_ue_coefs.html
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<script src="/ScoDoc/static/jQuery/jquery.js"></script>
|
||||||
|
<script src="/ScoDoc/static/js/table_editor.js"></script>
|
||||||
|
<link href="/ScoDoc/static/css/table_editor.css" rel="stylesheet" type="text/css" />
|
||||||
|
<title>Édition coef. formation</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h2>Formation {{formation.titre}} ({{formation.acronyme}})
|
||||||
|
[version {{formation.version}}] code {{formation.code}}</h2>
|
||||||
|
|
||||||
|
<div class=wait></div>
|
||||||
|
<div class=modifOnOff>Modifier</div>
|
||||||
|
<div class="tableau"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
$.getJSON("{{data_source}}", function (data) {
|
||||||
|
build_table(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
function save(obj) {
|
||||||
|
if (event?.currentTarget) {
|
||||||
|
obj = event.currentTarget;
|
||||||
|
}
|
||||||
|
document.querySelector(".wait").classList.remove("go");
|
||||||
|
// XXX DEBUG
|
||||||
|
console.log(`
|
||||||
|
x : ${getComputedStyle(obj).getPropertyValue("--x")}
|
||||||
|
y : ${getComputedStyle(obj).getPropertyValue("--y")}
|
||||||
|
data : ${obj.innerText}
|
||||||
|
ue_id: ${obj.dataset.ue_id}
|
||||||
|
module_id : ${obj.dataset.module_id}
|
||||||
|
`);
|
||||||
|
$.post("{{data_save}}",
|
||||||
|
{
|
||||||
|
module_id: `${obj.dataset.module_id}`,
|
||||||
|
ue_id: `${obj.dataset.ue_id}`,
|
||||||
|
coef: `${obj.innerText}`
|
||||||
|
},
|
||||||
|
function (result) {
|
||||||
|
console.log("enregistré");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
53
app/templates/scodoc/help/evaluations.html
Normal file
53
app/templates/scodoc/help/evaluations.html
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<div class="help">
|
||||||
|
<p class="help">
|
||||||
|
Le coefficient d'une évaluation est utilisé pour pondérer les
|
||||||
|
évaluations au sein d'un module. Il est fixé librement par l'enseignant
|
||||||
|
pour refléter l'importance de ses différentes notes (examens, projets,
|
||||||
|
travaux pratiques...). Ce coefficient est utilisé pour calculer la note
|
||||||
|
moyenne de chaque étudiant dans ce module.
|
||||||
|
</p>
|
||||||
|
{%if is_apc%}
|
||||||
|
<p class="help help_but">
|
||||||
|
Dans le BUT, une évaluation peut évaluer différents apprentissages critiques... (à compléter)
|
||||||
|
Le coefficient est multiplié par les poids vers chaque UE.
|
||||||
|
</p>
|
||||||
|
{%endif%}
|
||||||
|
<p class="help">
|
||||||
|
Ne pas confondre ce coefficient avec le coefficient du module, qui est
|
||||||
|
lui fixé par le programme pédagogique (le PPN pour les DUT) et pondère
|
||||||
|
les moyennes de chaque module pour obtenir les moyennes d'UE et la
|
||||||
|
moyenne générale.
|
||||||
|
</p>
|
||||||
|
<p class="help">
|
||||||
|
L'option <em>Visible sur bulletins</em> indique que la note sera
|
||||||
|
reportée sur les bulletins en version dite "intermédiaire" (dans cette
|
||||||
|
version, on peut ne faire apparaitre que certaines notes, en sus des
|
||||||
|
moyennes de modules. Attention, cette option n'empêche pas la
|
||||||
|
publication sur les bulletins en version "longue" (la note est donc
|
||||||
|
visible par les étudiants sur le portail).
|
||||||
|
</p>
|
||||||
|
<p class="help">
|
||||||
|
Les modalités "rattrapage" et "deuxième session" définissent des
|
||||||
|
évaluations prises en compte de façon spéciale:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>les notes d'une évaluation de "rattrapage" remplaceront les moyennes
|
||||||
|
du module <em>si elles sont meilleures que celles calculées</em>.
|
||||||
|
</li>
|
||||||
|
<li>les notes de "deuxième session" remplacent, lorsqu'elles sont
|
||||||
|
saisies, la moyenne de l'étudiant à ce module, même si la note de
|
||||||
|
deuxième session est plus faible.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p class="help">
|
||||||
|
Dans ces deux cas, le coefficient est ignoré, et toutes les notes n'ont
|
||||||
|
pas besoin d'être rentrées.
|
||||||
|
</p>
|
||||||
|
<p class="help">
|
||||||
|
Par ailleurs, les évaluations des modules de type "<b>malus</b>" sont
|
||||||
|
toujours spéciales: le coefficient n'est pas utilisé. Les notes de malus
|
||||||
|
sont toujours comprises entre -20 et 20. Les points sont soustraits à la
|
||||||
|
moyenne de l'UE à laquelle appartient le module malus (si la note est
|
||||||
|
négative, la moyenne est donc augmentée).
|
||||||
|
</p>
|
||||||
|
</div>
|
27
app/templates/scodoc/help/modules.html
Normal file
27
app/templates/scodoc/help/modules.html
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<div class="help">
|
||||||
|
<p class="help">
|
||||||
|
Les modules sont décrits dans le programme pédagogique. Un module est pour ce
|
||||||
|
logiciel l'unité pédagogique élémentaire. On va lui associer une note
|
||||||
|
à travers des <em>évaluations</em>. <br />
|
||||||
|
Cette note (moyenne de module) sera utilisée pour calculer la moyenne
|
||||||
|
générale (et la moyenne de l'UE à laquelle appartient le module). Pour
|
||||||
|
cela, on utilisera le <em>coefficient</em> associé au module.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="help">Un module possède un enseignant responsable
|
||||||
|
(typiquement celui qui dispense le cours magistral). On peut associer
|
||||||
|
au module une liste d'enseignants (typiquement les chargés de TD).
|
||||||
|
Tous ces enseignants, et le responsable du semestre, pourront
|
||||||
|
saisir et modifier les notes de ce module.
|
||||||
|
</p>
|
||||||
|
{%if is_apc%}
|
||||||
|
<p class="help help_but">
|
||||||
|
Dans le BUT, les modules peuvent être de type "ressource" ou "Situation
|
||||||
|
d'apprentissage et d'évaluation" (SAÉ). Ne pas oublier de préciser le
|
||||||
|
type, et de saisir les coefficients pondérant l'influence de la
|
||||||
|
ressource ou SAÉ vers les Unités d'Enseignement (UE).
|
||||||
|
Voir les détails sur
|
||||||
|
<a href="https://scodoc.org/BUT" target="_blank">la documentation</a>.
|
||||||
|
</p>
|
||||||
|
{%endif%}
|
||||||
|
</div>
|
@ -16,7 +16,7 @@ notes_bp = Blueprint("notes", __name__)
|
|||||||
users_bp = Blueprint("users", __name__)
|
users_bp = Blueprint("users", __name__)
|
||||||
absences_bp = Blueprint("absences", __name__)
|
absences_bp = Blueprint("absences", __name__)
|
||||||
|
|
||||||
from app.views import scodoc, notes, scolar, absences, users
|
from app.views import scodoc, notes, scolar, absences, users, pn_modules
|
||||||
|
|
||||||
|
|
||||||
# Cette fonction est bien appelée avant toutes les requêtes
|
# Cette fonction est bien appelée avant toutes les requêtes
|
||||||
|
@ -83,7 +83,6 @@ from app.scodoc import sco_archives
|
|||||||
from app.scodoc import sco_bulletins
|
from app.scodoc import sco_bulletins
|
||||||
from app.scodoc import sco_bulletins_pdf
|
from app.scodoc import sco_bulletins_pdf
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_codes_parcours
|
|
||||||
from app.scodoc import sco_compute_moy
|
from app.scodoc import sco_compute_moy
|
||||||
from app.scodoc import sco_cost_formation
|
from app.scodoc import sco_cost_formation
|
||||||
from app.scodoc import sco_debouche
|
from app.scodoc import sco_debouche
|
||||||
@ -94,7 +93,8 @@ from app.scodoc import sco_edit_ue
|
|||||||
from app.scodoc import sco_etape_apogee_view
|
from app.scodoc import sco_etape_apogee_view
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluations
|
||||||
from app.scodoc import sco_excel
|
from app.scodoc import sco_evaluation_db
|
||||||
|
from app.scodoc import sco_evaluation_edit
|
||||||
from app.scodoc import sco_export_results
|
from app.scodoc import sco_export_results
|
||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
@ -306,12 +306,12 @@ sco_publish(
|
|||||||
)
|
)
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/module_evaluation_renumber",
|
"/module_evaluation_renumber",
|
||||||
sco_evaluations.module_evaluation_renumber,
|
sco_evaluation_db.module_evaluation_renumber,
|
||||||
Permission.ScoView,
|
Permission.ScoView,
|
||||||
)
|
)
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/module_evaluation_move",
|
"/module_evaluation_move",
|
||||||
sco_evaluations.module_evaluation_move,
|
sco_evaluation_db.module_evaluation_move,
|
||||||
Permission.ScoView,
|
Permission.ScoView,
|
||||||
)
|
)
|
||||||
sco_publish(
|
sco_publish(
|
||||||
@ -354,7 +354,7 @@ def ue_table(formation_id=None, msg=""):
|
|||||||
@scodoc7func
|
@scodoc7func
|
||||||
def ue_set_internal(ue_id):
|
def ue_set_internal(ue_id):
|
||||||
""""""
|
""""""
|
||||||
ue = models.formations.NotesUE.query.get(ue_id)
|
ue = models.formations.UniteEns.query.get(ue_id)
|
||||||
if not ue:
|
if not ue:
|
||||||
raise ScoValueError("invalid ue_id")
|
raise ScoValueError("invalid ue_id")
|
||||||
ue.is_external = False
|
ue.is_external = False
|
||||||
@ -1557,7 +1557,7 @@ sco_publish(
|
|||||||
@scodoc7func
|
@scodoc7func
|
||||||
def evaluation_delete(evaluation_id):
|
def evaluation_delete(evaluation_id):
|
||||||
"""Form delete evaluation"""
|
"""Form delete evaluation"""
|
||||||
El = sco_evaluations.do_evaluation_list(args={"evaluation_id": evaluation_id})
|
El = sco_evaluation_db.do_evaluation_list(args={"evaluation_id": evaluation_id})
|
||||||
if not El:
|
if not El:
|
||||||
raise ValueError("Evalution inexistante ! (%s)" % evaluation_id)
|
raise ValueError("Evalution inexistante ! (%s)" % evaluation_id)
|
||||||
E = El[0]
|
E = El[0]
|
||||||
@ -1630,7 +1630,7 @@ def evaluation_delete(evaluation_id):
|
|||||||
|
|
||||||
sco_publish(
|
sco_publish(
|
||||||
"/do_evaluation_list",
|
"/do_evaluation_list",
|
||||||
sco_evaluations.do_evaluation_list,
|
sco_evaluation_db.do_evaluation_list,
|
||||||
Permission.ScoView,
|
Permission.ScoView,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1641,7 +1641,7 @@ sco_publish(
|
|||||||
@scodoc7func
|
@scodoc7func
|
||||||
def evaluation_edit(evaluation_id):
|
def evaluation_edit(evaluation_id):
|
||||||
"form edit evaluation"
|
"form edit evaluation"
|
||||||
return sco_evaluations.evaluation_create_form(
|
return sco_evaluation_edit.evaluation_create_form(
|
||||||
evaluation_id=evaluation_id, edit=True
|
evaluation_id=evaluation_id, edit=True
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1652,7 +1652,7 @@ def evaluation_edit(evaluation_id):
|
|||||||
@scodoc7func
|
@scodoc7func
|
||||||
def evaluation_create(moduleimpl_id):
|
def evaluation_create(moduleimpl_id):
|
||||||
"form create evaluation"
|
"form create evaluation"
|
||||||
return sco_evaluations.evaluation_create_form(
|
return sco_evaluation_edit.evaluation_create_form(
|
||||||
moduleimpl_id=moduleimpl_id, edit=False
|
moduleimpl_id=moduleimpl_id, edit=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
171
app/views/pn_modules.py
Normal file
171
app/views/pn_modules.py
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# ScoDoc
|
||||||
|
#
|
||||||
|
# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# Emmanuel Viennet emmanuel.viennet@viennet.net
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
PN / Edition des coefs
|
||||||
|
|
||||||
|
Emmanuel Viennet, 2021
|
||||||
|
"""
|
||||||
|
|
||||||
|
from flask import url_for
|
||||||
|
from flask import jsonify
|
||||||
|
from flask import current_app, g, request
|
||||||
|
from flask.templating import render_template
|
||||||
|
from flask_login import current_user
|
||||||
|
from werkzeug.utils import redirect
|
||||||
|
|
||||||
|
from config import Config
|
||||||
|
|
||||||
|
from app import db
|
||||||
|
from app import models
|
||||||
|
from app.auth.models import User
|
||||||
|
|
||||||
|
from app.comp import moy_ue
|
||||||
|
from app.decorators import scodoc, permission_required
|
||||||
|
from app.scodoc import sco_edit_formation
|
||||||
|
from app.views import notes_bp as bp
|
||||||
|
|
||||||
|
# ---------------
|
||||||
|
|
||||||
|
from app.scodoc import sco_utils as scu
|
||||||
|
from app.scodoc import notesdb as ndb
|
||||||
|
from app import log
|
||||||
|
|
||||||
|
from app.models.formations import Formation, UniteEns, Module
|
||||||
|
from app.scodoc.sco_exceptions import (
|
||||||
|
ScoValueError,
|
||||||
|
ScoLockedFormError,
|
||||||
|
ScoGenError,
|
||||||
|
AccessDenied,
|
||||||
|
)
|
||||||
|
from app.scodoc import html_sco_header
|
||||||
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/table_modules_ue_coefs/<formation_id>")
|
||||||
|
@scodoc
|
||||||
|
@permission_required(Permission.ScoView)
|
||||||
|
def table_modules_ue_coefs(formation_id):
|
||||||
|
"""Description JSON de la table des coefs modules/UE dans une formation"""
|
||||||
|
_ = models.Formation.query.get_or_404(formation_id) # check
|
||||||
|
|
||||||
|
df = moy_ue.df_load_ue_coefs(formation_id)
|
||||||
|
ues = models.UniteEns.query.filter_by(formation_id=formation_id).all()
|
||||||
|
modules = models.Module.query.filter_by(formation_id=formation_id).all()
|
||||||
|
# Titre des modules, en ligne
|
||||||
|
col_titres_mods = [
|
||||||
|
{
|
||||||
|
"x": 1, # 1ere colonne
|
||||||
|
"y": row,
|
||||||
|
# "nbX": 1,
|
||||||
|
# "nbY": 1,
|
||||||
|
"style": "title_mod " + scu.ModuleType(mod.module_type).name,
|
||||||
|
"data": mod.code,
|
||||||
|
"title": mod.titre,
|
||||||
|
}
|
||||||
|
for (row, mod) in enumerate(modules, start=2)
|
||||||
|
]
|
||||||
|
row_titres_ue = [
|
||||||
|
{
|
||||||
|
"x": col,
|
||||||
|
"y": 1, # 1ere ligne
|
||||||
|
"nbX": 1,
|
||||||
|
"nbY": 1,
|
||||||
|
"style": "title_ue",
|
||||||
|
"data": ue.acronyme,
|
||||||
|
"title": ue.titre,
|
||||||
|
}
|
||||||
|
for (col, ue) in enumerate(ues, start=2)
|
||||||
|
]
|
||||||
|
# Les champs de saisie
|
||||||
|
cells = []
|
||||||
|
for (row, mod) in enumerate(modules, start=2):
|
||||||
|
for (col, ue) in enumerate(ues, start=2):
|
||||||
|
cells.append(
|
||||||
|
{
|
||||||
|
"x": col,
|
||||||
|
"y": row,
|
||||||
|
"style": "champs",
|
||||||
|
"data": df[ue.id][mod.id],
|
||||||
|
"editable": True,
|
||||||
|
"module_id": mod.id,
|
||||||
|
"ue_id": ue.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return jsonify(col_titres_mods + row_titres_ue + cells)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/set_module_ue_coef", methods=["POST"])
|
||||||
|
@scodoc
|
||||||
|
@permission_required(Permission.ScoChangeFormation)
|
||||||
|
def set_module_ue_coef():
|
||||||
|
"""Set coef from module to UE"""
|
||||||
|
try:
|
||||||
|
module_id = int(request.form["module_id"])
|
||||||
|
except ValueError:
|
||||||
|
return scu.json_error("invalid module_id", 400)
|
||||||
|
try:
|
||||||
|
ue_id = int(request.form["ue_id"])
|
||||||
|
except ValueError:
|
||||||
|
return scu.json_error("invalid ue_id", 400)
|
||||||
|
try:
|
||||||
|
coef = float(request.form["coef"].replace(",", "."))
|
||||||
|
except ValueError:
|
||||||
|
return scu.json_error("invalid coef", 400)
|
||||||
|
module = models.Module.query.get(module_id)
|
||||||
|
if module is None:
|
||||||
|
return scu.json_error(f"module not found ({module_id})", 404)
|
||||||
|
ue = models.UniteEns.query.get(ue_id)
|
||||||
|
if not ue:
|
||||||
|
return scu.json_error(f"UE not found ({ue_id})", 404)
|
||||||
|
module.set_ue_coef(ue, coef)
|
||||||
|
db.session.commit()
|
||||||
|
sco_edit_formation.invalidate_sems_in_formation(module.formation_id)
|
||||||
|
return scu.json_error("ok", success=True, status=201)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/edit_modules_ue_coefs/<formation_id>")
|
||||||
|
@scodoc
|
||||||
|
@permission_required(Permission.ScoChangeFormation)
|
||||||
|
def edit_modules_ue_coefs(formation_id):
|
||||||
|
"""Formulaire édition grille coefs EU/modules"""
|
||||||
|
formation = models.Formation.query.filter_by(
|
||||||
|
formation_id=formation_id
|
||||||
|
).first_or_404()
|
||||||
|
return render_template(
|
||||||
|
"pn/form_modules_ue_coefs.html",
|
||||||
|
formation=formation,
|
||||||
|
data_source=url_for(
|
||||||
|
"notes.table_modules_ue_coefs",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
formation_id=formation_id,
|
||||||
|
),
|
||||||
|
data_save=url_for(
|
||||||
|
"notes.set_module_ue_coef",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
),
|
||||||
|
)
|
@ -49,7 +49,7 @@ from wtforms.validators import ValidationError, DataRequired, Email, EqualTo
|
|||||||
|
|
||||||
import app
|
import app
|
||||||
from app.models import Departement, Identite
|
from app.models import Departement, Identite
|
||||||
from app.models import FormSemestre, NotesFormsemestreInscription
|
from app.models import FormSemestre, FormsemestreInscription
|
||||||
from app.models import ScoDocSiteConfig
|
from app.models import ScoDocSiteConfig
|
||||||
import sco_version
|
import sco_version
|
||||||
from app.scodoc import sco_logos
|
from app.scodoc import sco_logos
|
||||||
@ -124,9 +124,7 @@ def get_etud_dept():
|
|||||||
last_etud = None
|
last_etud = None
|
||||||
last_date = None
|
last_date = None
|
||||||
for etud in etuds:
|
for etud in etuds:
|
||||||
inscriptions = NotesFormsemestreInscription.query.filter_by(
|
inscriptions = FormsemestreInscription.query.filter_by(etudid=etud.id).all()
|
||||||
etudid=etud.id
|
|
||||||
).all()
|
|
||||||
for ins in inscriptions:
|
for ins in inscriptions:
|
||||||
date_fin = FormSemestre.query.get(ins.formsemestre_id).date_fin
|
date_fin = FormSemestre.query.get(ins.formsemestre_id).date_fin
|
||||||
if (last_date is None) or date_fin > last_date:
|
if (last_date is None) or date_fin > last_date:
|
||||||
|
35
migrations/versions/6cfc21a7ae1b_coefs_modules_but.py
Normal file
35
migrations/versions/6cfc21a7ae1b_coefs_modules_but.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
"""coefs modules but
|
||||||
|
|
||||||
|
Revision ID: 6cfc21a7ae1b
|
||||||
|
Revises: ada0d1f3d84f
|
||||||
|
Create Date: 2021-11-11 21:04:05.573172
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '6cfc21a7ae1b'
|
||||||
|
down_revision = 'ada0d1f3d84f'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('module_ue_coef',
|
||||||
|
sa.Column('module_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('ue_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('coef', sa.Float(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['module_id'], ['notes_modules.id'], ),
|
||||||
|
sa.ForeignKeyConstraint(['ue_id'], ['notes_ue.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('module_id', 'ue_id')
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table('module_ue_coef')
|
||||||
|
# ### end Alembic commands ###
|
@ -37,8 +37,10 @@ lazy-object-proxy==1.6.0
|
|||||||
Mako==1.1.4
|
Mako==1.1.4
|
||||||
MarkupSafe==2.0.1
|
MarkupSafe==2.0.1
|
||||||
mccabe==0.6.1
|
mccabe==0.6.1
|
||||||
|
numpy==1.21.4
|
||||||
openpyxl==3.0.7
|
openpyxl==3.0.7
|
||||||
packaging==21.0
|
packaging==21.0
|
||||||
|
pandas==1.3.4
|
||||||
Pillow==8.3.1
|
Pillow==8.3.1
|
||||||
pluggy==0.13.1
|
pluggy==0.13.1
|
||||||
psycopg2==2.9.1
|
psycopg2==2.9.1
|
||||||
@ -46,7 +48,6 @@ py==1.10.0
|
|||||||
pycparser==2.20
|
pycparser==2.20
|
||||||
pydot==1.4.2
|
pydot==1.4.2
|
||||||
PyJWT==2.1.0
|
PyJWT==2.1.0
|
||||||
pylint==2.9.6
|
|
||||||
pyOpenSSL==20.0.1
|
pyOpenSSL==20.0.1
|
||||||
pyparsing==2.4.7
|
pyparsing==2.4.7
|
||||||
pytest==6.2.4
|
pytest==6.2.4
|
||||||
@ -58,8 +59,10 @@ redis==3.5.3
|
|||||||
reportlab==3.6.1
|
reportlab==3.6.1
|
||||||
requests==2.26.0
|
requests==2.26.0
|
||||||
rq==1.9.0
|
rq==1.9.0
|
||||||
|
six==1.16.0
|
||||||
SQLAlchemy==1.4.22
|
SQLAlchemy==1.4.22
|
||||||
toml==0.10.2
|
toml==0.10.2
|
||||||
|
tornado==6.1
|
||||||
urllib3==1.26.6
|
urllib3==1.26.6
|
||||||
visitor==0.1.3
|
visitor==0.1.3
|
||||||
Werkzeug==2.0.1
|
Werkzeug==2.0.1
|
||||||
|
@ -17,7 +17,7 @@ import typing
|
|||||||
|
|
||||||
from config import Config
|
from config import Config
|
||||||
from app.auth.models import User
|
from app.auth.models import User
|
||||||
from app.models import NotesFormModalite
|
from app.models import FormationModalite
|
||||||
from app.scodoc import notesdb as ndb
|
from app.scodoc import notesdb as ndb
|
||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
from app.scodoc import sco_edit_formation
|
from app.scodoc import sco_edit_formation
|
||||||
@ -26,6 +26,7 @@ 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_evaluations
|
||||||
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formations
|
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
|
||||||
@ -222,7 +223,7 @@ class ScoFake(object):
|
|||||||
block_moyennes=None,
|
block_moyennes=None,
|
||||||
gestion_semestrielle=None,
|
gestion_semestrielle=None,
|
||||||
bul_bgcolor=None,
|
bul_bgcolor=None,
|
||||||
modalite=NotesFormModalite.DEFAULT_MODALITE,
|
modalite=FormationModalite.DEFAULT_MODALITE,
|
||||||
resp_can_edit=None,
|
resp_can_edit=None,
|
||||||
resp_can_change_ens=None,
|
resp_can_change_ens=None,
|
||||||
ens_can_edit_eval=None,
|
ens_can_edit_eval=None,
|
||||||
@ -283,8 +284,8 @@ class ScoFake(object):
|
|||||||
):
|
):
|
||||||
args = locals()
|
args = locals()
|
||||||
del args["self"]
|
del args["self"]
|
||||||
oid = sco_evaluations.do_evaluation_create(**args)
|
oid = sco_evaluation_db.do_evaluation_create(**args)
|
||||||
oids = sco_evaluations.do_evaluation_list(args={"evaluation_id": oid})
|
oids = sco_evaluation_db.do_evaluation_list(args={"evaluation_id": oid})
|
||||||
if not oids:
|
if not oids:
|
||||||
raise ScoValueError("evaluation not created !")
|
raise ScoValueError("evaluation not created !")
|
||||||
return oids[0]
|
return oids[0]
|
||||||
|
@ -15,8 +15,7 @@ login_user(admin_user)
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def test_evaluation_poids(test_client):
|
def setup_formation_test():
|
||||||
"""Association de poids vers les UE"""
|
|
||||||
G = sco_fake_gen.ScoFake(verbose=False)
|
G = sco_fake_gen.ScoFake(verbose=False)
|
||||||
_f = G.create_formation(
|
_f = G.create_formation(
|
||||||
acronyme="F3", titre="Formation 2", titre_officiel="Titre officiel 2"
|
acronyme="F3", titre="Formation 2", titre_officiel="Titre officiel 2"
|
||||||
@ -33,14 +32,20 @@ def test_evaluation_poids(test_client):
|
|||||||
ue_id=_ue1["ue_id"],
|
ue_id=_ue1["ue_id"],
|
||||||
formation_id=_f["formation_id"],
|
formation_id=_f["formation_id"],
|
||||||
)
|
)
|
||||||
|
return G, _f["id"], _ue1["id"], _ue2["id"], _ue3["id"], _mod["id"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_evaluation_poids(test_client):
|
||||||
|
"""Association de poids vers les UE"""
|
||||||
|
G, formation_id, ue1_id, ue2_id, ue3_id, module_id = setup_formation_test()
|
||||||
sem = G.create_formsemestre(
|
sem = G.create_formsemestre(
|
||||||
formation_id=_f["formation_id"],
|
formation_id=formation_id,
|
||||||
semestre_id=1,
|
semestre_id=1,
|
||||||
date_debut="01/01/2021",
|
date_debut="01/01/2021",
|
||||||
date_fin="30/06/2021",
|
date_fin="30/06/2021",
|
||||||
) # formsemestre_id=716
|
) # formsemestre_id=716
|
||||||
mi = G.create_moduleimpl(
|
mi = G.create_moduleimpl(
|
||||||
module_id=_mod["module_id"],
|
module_id=module_id,
|
||||||
formsemestre_id=sem["formsemestre_id"],
|
formsemestre_id=sem["formsemestre_id"],
|
||||||
)
|
)
|
||||||
moduleimpl_id = mi["id"]
|
moduleimpl_id = mi["id"]
|
||||||
@ -51,17 +56,17 @@ def test_evaluation_poids(test_client):
|
|||||||
coefficient=0,
|
coefficient=0,
|
||||||
)
|
)
|
||||||
evaluation_id = _e1["evaluation_id"] # evaluation_id=25246
|
evaluation_id = _e1["evaluation_id"] # evaluation_id=25246
|
||||||
ue1_id = _ue1["id"] # ue1_id=1684
|
# ue1_id=1684
|
||||||
formation_id = _f["id"] # formation_id=199
|
# formation_id=199
|
||||||
#
|
#
|
||||||
e1 = models.NotesEvaluation.query.get(evaluation_id)
|
e1 = models.Evaluation.query.get(evaluation_id)
|
||||||
ue1 = models.NotesUE.query.get(ue1_id)
|
ue1 = models.UniteEns.query.get(ue1_id)
|
||||||
assert e1.ue_poids == []
|
assert e1.ue_poids == []
|
||||||
p1 = 3.14
|
p1 = 3.14
|
||||||
e1.set_ue_poids(ue1, p1)
|
e1.set_ue_poids(ue1, p1)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
assert e1.get_ue_poids_dict()[ue1_id] == p1
|
assert e1.get_ue_poids_dict()[ue1_id] == p1
|
||||||
ues = models.NotesUE.query.filter_by(formation_id=formation_id).all()
|
ues = models.UniteEns.query.filter_by(formation_id=formation_id).all()
|
||||||
poids = [1.0, 2.0, 3.0]
|
poids = [1.0, 2.0, 3.0]
|
||||||
for (ue, p) in zip(ues, poids):
|
for (ue, p) in zip(ues, poids):
|
||||||
e1.set_ue_poids(ue, p)
|
e1.set_ue_poids(ue, p)
|
||||||
@ -81,3 +86,22 @@ def test_evaluation_poids(test_client):
|
|||||||
db.session.delete(e1)
|
db.session.delete(e1)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
assert len(models.EvaluationUEPoids.query.all()) == 0
|
assert len(models.EvaluationUEPoids.query.all()) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_modules_coefs(test_client):
|
||||||
|
"""Coefs vers les UE (BUT)"""
|
||||||
|
G, formation_id, ue1_id, ue2_id, ue3_id, module_id = setup_formation_test()
|
||||||
|
ue1 = models.UniteEns.query.get(ue1_id)
|
||||||
|
ue2 = models.UniteEns.query.get(ue2_id)
|
||||||
|
mod = models.Module.query.get(module_id)
|
||||||
|
coef = 2.5
|
||||||
|
mod.set_ue_coef(ue1, coef)
|
||||||
|
db.session.commit()
|
||||||
|
assert mod.ue_coefs[0].coef == coef
|
||||||
|
mod.set_ue_coef(ue2, 2 * coef)
|
||||||
|
db.session.commit()
|
||||||
|
assert set(mod.get_ue_coef_dict().values()) == {coef, 2 * coef}
|
||||||
|
assert set(mod.get_ue_coef_dict().keys()) == {ue1_id, ue2_id}
|
||||||
|
mod.delete_ue_coef(ue1)
|
||||||
|
db.session.commit()
|
||||||
|
assert len(mod.ue_coefs) == 1
|
||||||
|
@ -15,6 +15,7 @@ import app
|
|||||||
from app import db
|
from app import db
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluations
|
||||||
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formsemestre
|
from app.scodoc import sco_formsemestre
|
||||||
from app.scodoc import notesdb as ndb
|
from app.scodoc import notesdb as ndb
|
||||||
from config import TestConfig
|
from config import TestConfig
|
||||||
@ -66,7 +67,7 @@ def test_cache_evaluations(test_client):
|
|||||||
raise Exception("no evaluations")
|
raise Exception("no evaluations")
|
||||||
#
|
#
|
||||||
evaluation_id = sem_evals[0]["evaluation_id"]
|
evaluation_id = sem_evals[0]["evaluation_id"]
|
||||||
eval_notes = sco_evaluations.do_evaluation_get_all_notes(evaluation_id)
|
eval_notes = sco_evaluation_db.do_evaluation_get_all_notes(evaluation_id)
|
||||||
# should have been be cached, except if empty
|
# should have been be cached, except if empty
|
||||||
if eval_notes:
|
if eval_notes:
|
||||||
assert sco_cache.EvaluationCache.get(evaluation_id)
|
assert sco_cache.EvaluationCache.get(evaluation_id)
|
||||||
|
@ -25,6 +25,7 @@ from app.scodoc import sco_abs_views
|
|||||||
from app.scodoc import sco_bulletins
|
from app.scodoc import sco_bulletins
|
||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
from app.scodoc import sco_evaluations
|
from app.scodoc import sco_evaluations
|
||||||
|
from app.scodoc import sco_evaluation_db
|
||||||
from app.scodoc import sco_formsemestre_validation
|
from app.scodoc import sco_formsemestre_validation
|
||||||
from app.scodoc import sco_parcours_dut
|
from app.scodoc import sco_parcours_dut
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
@ -134,7 +135,7 @@ def run_sco_basic(verbose=False):
|
|||||||
|
|
||||||
# Modifie l'évaluation 2 pour "prise en compte immédiate"
|
# Modifie l'évaluation 2 pour "prise en compte immédiate"
|
||||||
e2["publish_incomplete"] = True
|
e2["publish_incomplete"] = True
|
||||||
sco_evaluations.do_evaluation_edit(e2)
|
sco_evaluation_db.do_evaluation_edit(e2)
|
||||||
etat = sco_evaluations.do_evaluation_etat(e2["evaluation_id"])
|
etat = sco_evaluations.do_evaluation_etat(e2["evaluation_id"])
|
||||||
assert etat["evalcomplete"] == False
|
assert etat["evalcomplete"] == False
|
||||||
assert etat["nb_att"] == 0 # il n'y a pas de notes (explicitement) en attente
|
assert etat["nb_att"] == 0 # il n'y a pas de notes (explicitement) en attente
|
||||||
|
Loading…
Reference in New Issue
Block a user