forked from ScoDoc/ScoDoc
sépare modèles UE et Module
This commit is contained in:
parent
11b3f64319
commit
857c3007a5
@ -126,7 +126,7 @@ class ResultatsSemestreBUT:
|
||||
"max": fmt_note(self.etud_moy_ue[ue.id].max()),
|
||||
"moy": fmt_note(self.etud_moy_ue[ue.id].mean()),
|
||||
},
|
||||
"bonus": 17.8, # None, # XXX TODO
|
||||
"bonus": None, # XXX TODO
|
||||
"malus": None, # XXX TODO voir ce qui est ici
|
||||
"capitalise": None, # "AAAA-MM-JJ" TODO
|
||||
"ressources": self.etud_ue_mod_results(etud, ue, self.ressources),
|
||||
|
@ -30,14 +30,9 @@ from app.models.etudiants import (
|
||||
EtudAnnotation,
|
||||
)
|
||||
from app.models.events import Scolog, ScolarNews
|
||||
from app.models.formations import (
|
||||
Formation,
|
||||
UniteEns,
|
||||
Matiere,
|
||||
Module,
|
||||
ModuleUECoef,
|
||||
NotesTag,
|
||||
)
|
||||
from app.models.formations import Formation, Matiere
|
||||
from app.models.modules import Module, ModuleUECoef, NotesTag
|
||||
from app.models.ues import UniteEns
|
||||
from app.models.formsemestre import (
|
||||
FormSemestre,
|
||||
FormsemestreEtape,
|
||||
|
@ -1,13 +1,10 @@
|
||||
"""ScoDoc8 models : Formations (hors BUT)
|
||||
"""ScoDoc 9 models : Formations
|
||||
"""
|
||||
from typing import Any
|
||||
|
||||
from app import db
|
||||
from app.models import APO_CODE_STR_LEN
|
||||
from app.models import SHORT_STR_LEN
|
||||
from app.scodoc import notesdb as ndb
|
||||
from app.scodoc import sco_utils as scu
|
||||
from app.scodoc.sco_utils import ModuleType
|
||||
from app.scodoc import sco_codes_parcours
|
||||
from app.comp import df_cache
|
||||
|
||||
@ -91,82 +88,6 @@ class Formation(db.Model):
|
||||
df_cache.ModuleCoefsCache.delete_many(keys | {f"{self.id}"})
|
||||
|
||||
|
||||
class UniteEns(db.Model):
|
||||
"""Unité d'Enseignement (UE)"""
|
||||
|
||||
__tablename__ = "notes_ue"
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
ue_id = db.synonym("id")
|
||||
formation_id = db.Column(db.Integer, db.ForeignKey("notes_formations.id"))
|
||||
acronyme = db.Column(db.Text(), nullable=False)
|
||||
numero = db.Column(db.Integer) # ordre de présentation
|
||||
titre = db.Column(db.Text())
|
||||
# Le semestre_idx n'est pas un id mais le numéro du semestre: 1, 2, ...
|
||||
# En ScoDoc7 et pour les formations classiques, il est NULL
|
||||
# (le numéro du semestre étant alors déterminé par celui des modules de l'UE)
|
||||
# Pour les formations APC, il est obligatoire (de 1 à 6 pour le BUT):
|
||||
semestre_idx = db.Column(db.Integer, nullable=True, index=True)
|
||||
# Type d'UE: 0 normal ("fondamentale"), 1 "sport", 2 "projet et stage (LP)",
|
||||
# 4 "élective"
|
||||
type = db.Column(db.Integer, default=0, server_default="0")
|
||||
# Les UE sont "compatibles" (pour la capitalisation) ssi elles ont ^m code
|
||||
# note: la fonction SQL notes_newid_ucod doit être créée à part
|
||||
ue_code = db.Column(
|
||||
db.String(SHORT_STR_LEN),
|
||||
server_default=db.text("notes_newid_ucod()"),
|
||||
nullable=False,
|
||||
)
|
||||
ects = db.Column(db.Float) # nombre de credits ECTS
|
||||
is_external = db.Column(db.Boolean(), default=False, server_default="false")
|
||||
# id de l'element pedagogique Apogee correspondant:
|
||||
code_apogee = db.Column(db.String(APO_CODE_STR_LEN))
|
||||
# coef UE, utilise seulement si l'option use_ue_coefs est activée:
|
||||
coefficient = db.Column(db.Float)
|
||||
|
||||
# relations
|
||||
matieres = db.relationship("Matiere", lazy="dynamic", backref="ue")
|
||||
modules = db.relationship("Module", lazy="dynamic", backref="ue")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__name__}(id={self.id}, formation_id={self.formation_id}, acronyme='{self.acronyme}')>"
|
||||
|
||||
def to_dict(self):
|
||||
"""as a dict, with the same conversions as in ScoDoc7"""
|
||||
e = dict(self.__dict__)
|
||||
e.pop("_sa_instance_state", None)
|
||||
# ScoDoc7 output_formators
|
||||
e["ue_id"] = self.id
|
||||
e["numero"] = e["numero"] if e["numero"] else 0
|
||||
e["ects"] = e["ects"] if e["ects"] else 0.0
|
||||
e["coefficient"] = e["coefficient"] if e["coefficient"] else 0.0
|
||||
return e
|
||||
|
||||
def is_locked(self):
|
||||
"""True if UE should not be modified
|
||||
(contains modules used in a locked formsemestre)
|
||||
"""
|
||||
# XXX todo : à ré-écrire avec SQLAlchemy
|
||||
from app.scodoc import sco_edit_ue
|
||||
|
||||
return sco_edit_ue.ue_is_locked(self.id)
|
||||
|
||||
def guess_semestre_idx(self) -> None:
|
||||
"""Lorsqu'on prend une ancienne formation non APC,
|
||||
les UE n'ont pas d'indication de semestre.
|
||||
Cette méthode fixe le semestre en prenant celui du premier module,
|
||||
ou à défaut le met à 1.
|
||||
"""
|
||||
if self.semestre_idx is None:
|
||||
module = self.modules.first()
|
||||
if module is None:
|
||||
self.semestre_idx = 1
|
||||
else:
|
||||
self.semestre_idx = module.semestre_id
|
||||
db.session.add(self)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
class Matiere(db.Model):
|
||||
"""Matières: regroupe les modules d'une UE
|
||||
La matière a peu d'utilité en dehors de la présentation des modules
|
||||
@ -183,178 +104,3 @@ class Matiere(db.Model):
|
||||
numero = db.Column(db.Integer) # ordre de présentation
|
||||
|
||||
modules = db.relationship("Module", lazy="dynamic", backref="matiere")
|
||||
|
||||
|
||||
class Module(db.Model):
|
||||
"""Module"""
|
||||
|
||||
__tablename__ = "notes_modules"
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
module_id = db.synonym("id")
|
||||
titre = db.Column(db.Text())
|
||||
abbrev = db.Column(db.Text()) # nom court
|
||||
# certains départements ont des codes infiniment longs: donc Text !
|
||||
code = db.Column(db.Text(), nullable=False)
|
||||
heures_cours = db.Column(db.Float)
|
||||
heures_td = db.Column(db.Float)
|
||||
heures_tp = db.Column(db.Float)
|
||||
coefficient = db.Column(db.Float) # coef PPN (sauf en APC)
|
||||
ects = db.Column(db.Float) # Crédits ECTS
|
||||
ue_id = db.Column(db.Integer, db.ForeignKey("notes_ue.id"), index=True)
|
||||
formation_id = db.Column(db.Integer, db.ForeignKey("notes_formations.id"))
|
||||
matiere_id = db.Column(db.Integer, db.ForeignKey("notes_matieres.id"))
|
||||
# pas un id mais le numéro du semestre: 1, 2, ...
|
||||
semestre_id = db.Column(db.Integer, nullable=False, default=1, server_default="1")
|
||||
numero = db.Column(db.Integer) # ordre de présentation
|
||||
# id de l'element pedagogique Apogee correspondant:
|
||||
code_apogee = db.Column(db.String(APO_CODE_STR_LEN))
|
||||
# Type: ModuleType: DEFAULT, MALUS, RESSOURCE, MODULE_SAE (enum)
|
||||
module_type = db.Column(db.Integer)
|
||||
# Relations:
|
||||
modimpls = db.relationship("ModuleImpl", backref="module", lazy="dynamic")
|
||||
ues_apc = db.relationship("UniteEns", secondary="module_ue_coef", viewonly=True)
|
||||
tags = db.relationship(
|
||||
"NotesTag",
|
||||
secondary="notes_modules_tags",
|
||||
lazy=True,
|
||||
backref=db.backref("modules", lazy=True),
|
||||
)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.ue_coefs = []
|
||||
super(Module, self).__init__(**kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
f"<Module{ModuleType(self.module_type).name} id={self.id} code={self.code}>"
|
||||
)
|
||||
|
||||
def to_dict(self):
|
||||
e = dict(self.__dict__)
|
||||
e.pop("_sa_instance_state", None)
|
||||
# ScoDoc7 output_formators: (backward compat)
|
||||
e["module_id"] = self.id
|
||||
e["heures_cours"] = 0.0 if self.heures_cours is None else self.heures_cours
|
||||
e["heures_td"] = 0.0 if self.heures_td is None else self.heures_td
|
||||
e["heures_tp"] = 0.0 if self.heures_tp is None else self.heures_tp
|
||||
e["numero"] = 0 if self.numero is None else self.numero
|
||||
e["coefficient"] = 0.0 if self.coefficient is None else self.coefficient
|
||||
e["module_type"] = 0 if self.module_type is None else self.module_type
|
||||
return e
|
||||
|
||||
def is_apc(self):
|
||||
"True si module SAÉ ou Ressource"
|
||||
return self.module_type and scu.ModuleType(self.module_type) in {
|
||||
scu.ModuleType.RESSOURCE,
|
||||
scu.ModuleType.SAE,
|
||||
}
|
||||
|
||||
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 }
|
||||
Les coefs nuls (zéro) ne sont pas stockés: la relation est supprimée.
|
||||
"""
|
||||
ue_coefs = []
|
||||
for ue_id, coef in ue_coef_dict.items():
|
||||
ue = UniteEns.query.get(ue_id)
|
||||
if coef == 0.0:
|
||||
self.delete_ue_coef(ue)
|
||||
else:
|
||||
ue_coefs.append(ModuleUECoef(module=self, ue=ue, coef=coef))
|
||||
self.ue_coefs = ue_coefs
|
||||
self.formation.invalidate_module_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))
|
||||
if ue_coef:
|
||||
db.session.delete(ue_coef)
|
||||
self.formation.invalidate_module_coefs()
|
||||
|
||||
def ue_coefs_descr(self):
|
||||
"""List of tuples [ (ue_acronyme, coef) ]"""
|
||||
return [(c.ue.acronyme, c.coef) for c in self.ue_coefs]
|
||||
|
||||
|
||||
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", ondelete="CASCADE"),
|
||||
primary_key=True,
|
||||
)
|
||||
ue_id = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey("notes_ue.id", ondelete="CASCADE"),
|
||||
primary_key=True,
|
||||
)
|
||||
coef = db.Column(
|
||||
db.Float,
|
||||
nullable=False,
|
||||
)
|
||||
module = db.relationship(
|
||||
Module,
|
||||
backref=db.backref(
|
||||
"ue_coefs",
|
||||
passive_deletes=True,
|
||||
cascade="save-update, merge, delete, delete-orphan",
|
||||
),
|
||||
)
|
||||
ue = db.relationship(
|
||||
UniteEns,
|
||||
backref=db.backref(
|
||||
"module_ue_coefs",
|
||||
passive_deletes=True,
|
||||
cascade="save-update, merge, delete, delete-orphan",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class NotesTag(db.Model):
|
||||
"""Tag sur un module"""
|
||||
|
||||
__tablename__ = "notes_tags"
|
||||
__table_args__ = (db.UniqueConstraint("title", "dept_id"),)
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
tag_id = db.synonym("id")
|
||||
|
||||
dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"), index=True)
|
||||
title = db.Column(db.Text(), nullable=False)
|
||||
|
||||
|
||||
# Association tag <-> module
|
||||
notes_modules_tags = db.Table(
|
||||
"notes_modules_tags",
|
||||
db.Column(
|
||||
"tag_id",
|
||||
db.Integer,
|
||||
db.ForeignKey("notes_tags.id", ondelete="CASCADE"),
|
||||
),
|
||||
db.Column(
|
||||
"module_id", db.Integer, db.ForeignKey("notes_modules.id", ondelete="CASCADE")
|
||||
),
|
||||
)
|
||||
|
@ -16,7 +16,8 @@ from app.models import UniteEns
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc import sco_evaluation_db
|
||||
from app.models.formations import UniteEns, Module
|
||||
from app.models.ues import UniteEns
|
||||
from app.models.modules import Module
|
||||
from app.models.moduleimpls import ModuleImpl
|
||||
from app.models.etudiants import Identite
|
||||
from app.scodoc import sco_codes_parcours
|
||||
|
@ -2,19 +2,14 @@
|
||||
|
||||
"""ScoDoc models: moduleimpls
|
||||
"""
|
||||
from typing import Any
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from app import db
|
||||
from app.comp import df_cache
|
||||
from app.models import APO_CODE_STR_LEN
|
||||
from app.models import SHORT_STR_LEN
|
||||
from app.models import CODE_STR_LEN
|
||||
from app.models import UniteEns, Identite
|
||||
|
||||
import app.scodoc.notesdb as ndb
|
||||
from app.scodoc import sco_evaluation_db
|
||||
from app.scodoc import sco_utils as scu
|
||||
|
||||
|
||||
|
185
app/models/modules.py
Normal file
185
app/models/modules.py
Normal file
@ -0,0 +1,185 @@
|
||||
"""ScoDoc 9 models : Modules
|
||||
"""
|
||||
from typing import Any
|
||||
|
||||
from app import db
|
||||
from app.models import APO_CODE_STR_LEN
|
||||
from app.scodoc import sco_utils as scu
|
||||
from app.scodoc.sco_utils import ModuleType
|
||||
|
||||
|
||||
class Module(db.Model):
|
||||
"""Module"""
|
||||
|
||||
__tablename__ = "notes_modules"
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
module_id = db.synonym("id")
|
||||
titre = db.Column(db.Text())
|
||||
abbrev = db.Column(db.Text()) # nom court
|
||||
# certains départements ont des codes infiniment longs: donc Text !
|
||||
code = db.Column(db.Text(), nullable=False)
|
||||
heures_cours = db.Column(db.Float)
|
||||
heures_td = db.Column(db.Float)
|
||||
heures_tp = db.Column(db.Float)
|
||||
coefficient = db.Column(db.Float) # coef PPN (sauf en APC)
|
||||
ects = db.Column(db.Float) # Crédits ECTS
|
||||
ue_id = db.Column(db.Integer, db.ForeignKey("notes_ue.id"), index=True)
|
||||
formation_id = db.Column(db.Integer, db.ForeignKey("notes_formations.id"))
|
||||
matiere_id = db.Column(db.Integer, db.ForeignKey("notes_matieres.id"))
|
||||
# pas un id mais le numéro du semestre: 1, 2, ...
|
||||
semestre_id = db.Column(db.Integer, nullable=False, default=1, server_default="1")
|
||||
numero = db.Column(db.Integer) # ordre de présentation
|
||||
# id de l'element pedagogique Apogee correspondant:
|
||||
code_apogee = db.Column(db.String(APO_CODE_STR_LEN))
|
||||
# Type: ModuleType: DEFAULT, MALUS, RESSOURCE, MODULE_SAE (enum)
|
||||
module_type = db.Column(db.Integer)
|
||||
# Relations:
|
||||
modimpls = db.relationship("ModuleImpl", backref="module", lazy="dynamic")
|
||||
ues_apc = db.relationship("UniteEns", secondary="module_ue_coef", viewonly=True)
|
||||
tags = db.relationship(
|
||||
"NotesTag",
|
||||
secondary="notes_modules_tags",
|
||||
lazy=True,
|
||||
backref=db.backref("modules", lazy=True),
|
||||
)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.ue_coefs = []
|
||||
super(Module, self).__init__(**kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
f"<Module{ModuleType(self.module_type).name} id={self.id} code={self.code}>"
|
||||
)
|
||||
|
||||
def to_dict(self):
|
||||
e = dict(self.__dict__)
|
||||
e.pop("_sa_instance_state", None)
|
||||
# ScoDoc7 output_formators: (backward compat)
|
||||
e["module_id"] = self.id
|
||||
e["heures_cours"] = 0.0 if self.heures_cours is None else self.heures_cours
|
||||
e["heures_td"] = 0.0 if self.heures_td is None else self.heures_td
|
||||
e["heures_tp"] = 0.0 if self.heures_tp is None else self.heures_tp
|
||||
e["numero"] = 0 if self.numero is None else self.numero
|
||||
e["coefficient"] = 0.0 if self.coefficient is None else self.coefficient
|
||||
e["module_type"] = 0 if self.module_type is None else self.module_type
|
||||
return e
|
||||
|
||||
def is_apc(self):
|
||||
"True si module SAÉ ou Ressource"
|
||||
return self.module_type and scu.ModuleType(self.module_type) in {
|
||||
scu.ModuleType.RESSOURCE,
|
||||
scu.ModuleType.SAE,
|
||||
}
|
||||
|
||||
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 }
|
||||
Les coefs nuls (zéro) ne sont pas stockés: la relation est supprimée.
|
||||
"""
|
||||
ue_coefs = []
|
||||
for ue_id, coef in ue_coef_dict.items():
|
||||
ue = UniteEns.query.get(ue_id)
|
||||
if coef == 0.0:
|
||||
self.delete_ue_coef(ue)
|
||||
else:
|
||||
ue_coefs.append(ModuleUECoef(module=self, ue=ue, coef=coef))
|
||||
self.ue_coefs = ue_coefs
|
||||
self.formation.invalidate_module_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))
|
||||
if ue_coef:
|
||||
db.session.delete(ue_coef)
|
||||
self.formation.invalidate_module_coefs()
|
||||
|
||||
def ue_coefs_descr(self):
|
||||
"""List of tuples [ (ue_acronyme, coef) ]"""
|
||||
return [(c.ue.acronyme, c.coef) for c in self.ue_coefs]
|
||||
|
||||
|
||||
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", ondelete="CASCADE"),
|
||||
primary_key=True,
|
||||
)
|
||||
ue_id = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey("notes_ue.id", ondelete="CASCADE"),
|
||||
primary_key=True,
|
||||
)
|
||||
coef = db.Column(
|
||||
db.Float,
|
||||
nullable=False,
|
||||
)
|
||||
module = db.relationship(
|
||||
Module,
|
||||
backref=db.backref(
|
||||
"ue_coefs",
|
||||
passive_deletes=True,
|
||||
cascade="save-update, merge, delete, delete-orphan",
|
||||
),
|
||||
)
|
||||
ue = db.relationship(
|
||||
"UniteEns",
|
||||
backref=db.backref(
|
||||
"module_ue_coefs",
|
||||
passive_deletes=True,
|
||||
cascade="save-update, merge, delete, delete-orphan",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class NotesTag(db.Model):
|
||||
"""Tag sur un module"""
|
||||
|
||||
__tablename__ = "notes_tags"
|
||||
__table_args__ = (db.UniqueConstraint("title", "dept_id"),)
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
tag_id = db.synonym("id")
|
||||
|
||||
dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"), index=True)
|
||||
title = db.Column(db.Text(), nullable=False)
|
||||
|
||||
|
||||
# Association tag <-> module
|
||||
notes_modules_tags = db.Table(
|
||||
"notes_modules_tags",
|
||||
db.Column(
|
||||
"tag_id",
|
||||
db.Integer,
|
||||
db.ForeignKey("notes_tags.id", ondelete="CASCADE"),
|
||||
),
|
||||
db.Column(
|
||||
"module_id", db.Integer, db.ForeignKey("notes_modules.id", ondelete="CASCADE")
|
||||
),
|
||||
)
|
||||
|
||||
from app.models.ues import UniteEns
|
84
app/models/ues.py
Normal file
84
app/models/ues.py
Normal file
@ -0,0 +1,84 @@
|
||||
"""ScoDoc 9 models : Unités d'Enseignement (UE)
|
||||
"""
|
||||
|
||||
from app import db
|
||||
from app.models import APO_CODE_STR_LEN
|
||||
from app.models import SHORT_STR_LEN
|
||||
from app.scodoc import notesdb as ndb
|
||||
from app.scodoc import sco_utils as scu
|
||||
|
||||
|
||||
class UniteEns(db.Model):
|
||||
"""Unité d'Enseignement (UE)"""
|
||||
|
||||
__tablename__ = "notes_ue"
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
ue_id = db.synonym("id")
|
||||
formation_id = db.Column(db.Integer, db.ForeignKey("notes_formations.id"))
|
||||
acronyme = db.Column(db.Text(), nullable=False)
|
||||
numero = db.Column(db.Integer) # ordre de présentation
|
||||
titre = db.Column(db.Text())
|
||||
# Le semestre_idx n'est pas un id mais le numéro du semestre: 1, 2, ...
|
||||
# En ScoDoc7 et pour les formations classiques, il est NULL
|
||||
# (le numéro du semestre étant alors déterminé par celui des modules de l'UE)
|
||||
# Pour les formations APC, il est obligatoire (de 1 à 6 pour le BUT):
|
||||
semestre_idx = db.Column(db.Integer, nullable=True, index=True)
|
||||
# Type d'UE: 0 normal ("fondamentale"), 1 "sport", 2 "projet et stage (LP)",
|
||||
# 4 "élective"
|
||||
type = db.Column(db.Integer, default=0, server_default="0")
|
||||
# Les UE sont "compatibles" (pour la capitalisation) ssi elles ont ^m code
|
||||
# note: la fonction SQL notes_newid_ucod doit être créée à part
|
||||
ue_code = db.Column(
|
||||
db.String(SHORT_STR_LEN),
|
||||
server_default=db.text("notes_newid_ucod()"),
|
||||
nullable=False,
|
||||
)
|
||||
ects = db.Column(db.Float) # nombre de credits ECTS
|
||||
is_external = db.Column(db.Boolean(), default=False, server_default="false")
|
||||
# id de l'element pedagogique Apogee correspondant:
|
||||
code_apogee = db.Column(db.String(APO_CODE_STR_LEN))
|
||||
# coef UE, utilise seulement si l'option use_ue_coefs est activée:
|
||||
coefficient = db.Column(db.Float)
|
||||
|
||||
# relations
|
||||
matieres = db.relationship("Matiere", lazy="dynamic", backref="ue")
|
||||
modules = db.relationship("Module", lazy="dynamic", backref="ue")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__name__}(id={self.id}, formation_id={self.formation_id}, acronyme='{self.acronyme}')>"
|
||||
|
||||
def to_dict(self):
|
||||
"""as a dict, with the same conversions as in ScoDoc7"""
|
||||
e = dict(self.__dict__)
|
||||
e.pop("_sa_instance_state", None)
|
||||
# ScoDoc7 output_formators
|
||||
e["ue_id"] = self.id
|
||||
e["numero"] = e["numero"] if e["numero"] else 0
|
||||
e["ects"] = e["ects"] if e["ects"] else 0.0
|
||||
e["coefficient"] = e["coefficient"] if e["coefficient"] else 0.0
|
||||
return e
|
||||
|
||||
def is_locked(self):
|
||||
"""True if UE should not be modified
|
||||
(contains modules used in a locked formsemestre)
|
||||
"""
|
||||
# XXX todo : à ré-écrire avec SQLAlchemy
|
||||
from app.scodoc import sco_edit_ue
|
||||
|
||||
return sco_edit_ue.ue_is_locked(self.id)
|
||||
|
||||
def guess_semestre_idx(self) -> None:
|
||||
"""Lorsqu'on prend une ancienne formation non APC,
|
||||
les UE n'ont pas d'indication de semestre.
|
||||
Cette méthode fixe le semestre en prenant celui du premier module,
|
||||
ou à défaut le met à 1.
|
||||
"""
|
||||
if self.semestre_idx is None:
|
||||
module = self.modules.first()
|
||||
if module is None:
|
||||
self.semestre_idx = 1
|
||||
else:
|
||||
self.semestre_idx = module.semestre_id
|
||||
db.session.add(self)
|
||||
db.session.commit()
|
@ -546,21 +546,21 @@ def list_abs_non_just(etudid, datedebut):
|
||||
cnx = ndb.GetDBConnexion()
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"""SELECT ETUDID, JOUR, MATIN FROM ABSENCES A
|
||||
"""SELECT ETUDID, JOUR, MATIN FROM ABSENCES A
|
||||
WHERE A.ETUDID = %(etudid)s
|
||||
AND A.estabs
|
||||
AND A.estabs
|
||||
AND A.jour >= %(datedebut)s
|
||||
EXCEPT SELECT ETUDID, JOUR, MATIN FROM ABSENCES B
|
||||
WHERE B.estjust
|
||||
EXCEPT SELECT ETUDID, JOUR, MATIN FROM ABSENCES B
|
||||
WHERE B.estjust
|
||||
AND B.ETUDID = %(etudid)s
|
||||
ORDER BY JOUR
|
||||
""",
|
||||
vars(),
|
||||
)
|
||||
A = cursor.dictfetchall()
|
||||
for a in A:
|
||||
abs_list = cursor.dictfetchall()
|
||||
for a in abs_list:
|
||||
a["description"] = _get_abs_description(a, cursor=cursor)
|
||||
return A
|
||||
return abs_list
|
||||
|
||||
|
||||
def list_abs_just(etudid, datedebut):
|
||||
@ -570,7 +570,7 @@ def list_abs_just(etudid, datedebut):
|
||||
cursor.execute(
|
||||
"""SELECT DISTINCT A.ETUDID, A.JOUR, A.MATIN FROM ABSENCES A, ABSENCES B
|
||||
WHERE A.ETUDID = %(etudid)s
|
||||
AND A.ETUDID = B.ETUDID
|
||||
AND A.ETUDID = B.ETUDID
|
||||
AND A.JOUR = B.JOUR AND A.MATIN = B.MATIN AND A.JOUR >= %(datedebut)s
|
||||
AND A.ESTABS AND (A.ESTJUST OR B.ESTJUST)
|
||||
ORDER BY A.JOUR
|
||||
@ -638,8 +638,12 @@ def add_absence(
|
||||
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT into absences (etudid,jour,estabs,estjust,matin,description, moduleimpl_id)
|
||||
VALUES (%(etudid)s, %(jour)s, true, %(estjust)s, %(matin)s, %(description)s, %(moduleimpl_id)s )
|
||||
INSERT into absences
|
||||
(etudid, jour, estabs, estjust, matin, description, moduleimpl_id)
|
||||
VALUES
|
||||
(%(etudid)s, %(jour)s, true, %(estjust)s, %(matin)s,
|
||||
%(description)s, %(moduleimpl_id)s
|
||||
)
|
||||
""",
|
||||
vars(),
|
||||
)
|
||||
|
@ -28,7 +28,7 @@ import flask
|
||||
from flask import url_for, render_template
|
||||
from flask import g, request
|
||||
from flask_login import current_user
|
||||
from app.models.formations import Formation, UniteEns, Matiere, Module
|
||||
from app.models import Formation, UniteEns, Matiere, Module
|
||||
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
@ -32,7 +32,7 @@ import flask
|
||||
from flask import url_for, render_template
|
||||
from flask import g, request
|
||||
from flask_login import current_user
|
||||
from app.models.formations import Matiere, UniteEns
|
||||
from app.models import Matiere, UniteEns
|
||||
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
|
@ -33,7 +33,7 @@ from flask import url_for, render_template
|
||||
from flask import g, request
|
||||
from flask_login import current_user
|
||||
|
||||
from app.models.formations import Formation, UniteEns
|
||||
from app.models import Formation, UniteEns
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc.sco_utils import ModuleType
|
||||
|
@ -1106,7 +1106,7 @@ def formsemestre_associate_new_version(
|
||||
"etat": "1",
|
||||
},
|
||||
)
|
||||
of = []
|
||||
H = []
|
||||
for s in othersems:
|
||||
if (
|
||||
s["formsemestre_id"] == formsemestre_id
|
||||
@ -1119,9 +1119,10 @@ def formsemestre_associate_new_version(
|
||||
disabled = 'disabled="1"'
|
||||
else:
|
||||
disabled = ""
|
||||
of.append(
|
||||
'<div><input type="checkbox" name="other_formsemestre_ids:list" value="%s" %s %s>%s</input></div>'
|
||||
% (s["formsemestre_id"], checked, disabled, s["titremois"])
|
||||
H.append(
|
||||
f"""<div><input type="checkbox" name="other_formsemestre_ids:list"
|
||||
value="{s['formsemestre_id']}" {checked} {disabled}
|
||||
>{s['titremois']}</input></div>"""
|
||||
)
|
||||
|
||||
return scu.confirm_dialog(
|
||||
@ -1130,7 +1131,7 @@ def formsemestre_associate_new_version(
|
||||
<p>Veillez à ne pas abuser de cette possibilité, car créer trop de versions de formations va vous compliquer la gestion (à vous de garder trace des différences et à ne pas vous tromper par la suite...).
|
||||
</p>
|
||||
<div class="othersemlist"><p>Si vous voulez associer aussi d'autres semestres à la nouvelle version, cochez-les:</p>"""
|
||||
+ "".join(of)
|
||||
+ "".join(H)
|
||||
+ "</div>",
|
||||
OK="Associer ces semestres à une nouvelle version",
|
||||
dest_url="",
|
||||
|
@ -826,7 +826,7 @@ def _add_apc_columns(
|
||||
col_id = f"moy_ue_{ue.id}"
|
||||
titles[col_id] = ue.acronyme
|
||||
columns_ids.append(col_id)
|
||||
row_coefs[f"moy_ue_{ue.id}"] = [uc for uc in ue_coefs if uc.ue_id == ue.id][
|
||||
0
|
||||
].coef
|
||||
row_coefs[f"_moy_ue_{ue.id}_td_attrs"] = ' class="coef_mod_ue" '
|
||||
coefs = [uc for uc in ue_coefs if uc.ue_id == ue.id]
|
||||
if coefs:
|
||||
row_coefs[f"moy_ue_{ue.id}"] = coefs[0].coef
|
||||
row_coefs[f"_moy_ue_{ue.id}_td_attrs"] = ' class="coef_mod_ue" '
|
||||
|
@ -115,7 +115,7 @@ function showSynthese(data) {
|
||||
${(dataUE.competence) ? dataUE.competence + " - " : ""}${ue}
|
||||
</h3>
|
||||
<div>
|
||||
<div class=moyenne>Moyenn : ${dataUE.moyenne?.value || "-"}</div>
|
||||
<div class=moyenne>Moyenne : ${dataUE.moyenne?.value || "-"}</div>
|
||||
<div class=info>
|
||||
Bonus : ${dataUE.bonus || 0} -
|
||||
Malus : ${dataUE.malus || 0}
|
||||
@ -125,7 +125,7 @@ function showSynthese(data) {
|
||||
</div>
|
||||
</div>
|
||||
<div class=absences>
|
||||
<div>Abs inj.</div><div>${dataUE.absences?.injustifie || 0}</div>
|
||||
<div>Abs N.J.</div><div>${dataUE.absences?.injustifie || 0}</div>
|
||||
<div>Total</div><div>${dataUE.absences?.total || 0}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -381,7 +381,7 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""):
|
||||
@scodoc7func
|
||||
def ue_set_internal(ue_id):
|
||||
""""""
|
||||
ue = models.formations.UniteEns.query.get(ue_id)
|
||||
ue = models.UniteEns.query.get(ue_id)
|
||||
if not ue:
|
||||
raise ScoValueError("invalid ue_id")
|
||||
ue.is_external = False
|
||||
|
@ -56,7 +56,7 @@ from app.scodoc import notesdb as ndb
|
||||
from app.scodoc import sco_formations
|
||||
from app import log
|
||||
|
||||
from app.models.formations import Formation, UniteEns, Module
|
||||
from app.models import Formation, UniteEns, Module
|
||||
from app.scodoc.sco_exceptions import (
|
||||
ScoValueError,
|
||||
ScoLockedFormError,
|
||||
|
@ -18,7 +18,7 @@ from app import db
|
||||
from app import models
|
||||
|
||||
from app.decorators import scodoc, permission_required
|
||||
from app.models.formations import Formation
|
||||
from app.models import Formation
|
||||
from app.models.but_refcomp import ApcReferentielCompetences
|
||||
from app.but.import_refcomp import orebut_import_refcomp
|
||||
from app.but.forms.refcomp_forms import FormationRefCompForm, RefCompLoadForm
|
||||
|
Loading…
Reference in New Issue
Block a user