1
0
forked from ScoDoc/ScoDoc

sépare modèles UE et Module

This commit is contained in:
Emmanuel Viennet 2021-12-08 22:33:32 +01:00
parent 11b3f64319
commit 857c3007a5
17 changed files with 308 additions and 297 deletions

View File

@ -126,7 +126,7 @@ class ResultatsSemestreBUT:
"max": fmt_note(self.etud_moy_ue[ue.id].max()), "max": fmt_note(self.etud_moy_ue[ue.id].max()),
"moy": fmt_note(self.etud_moy_ue[ue.id].mean()), "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 "malus": None, # XXX TODO voir ce qui est ici
"capitalise": None, # "AAAA-MM-JJ" TODO "capitalise": None, # "AAAA-MM-JJ" TODO
"ressources": self.etud_ue_mod_results(etud, ue, self.ressources), "ressources": self.etud_ue_mod_results(etud, ue, self.ressources),

View File

@ -30,14 +30,9 @@ from app.models.etudiants import (
EtudAnnotation, EtudAnnotation,
) )
from app.models.events import Scolog, ScolarNews from app.models.events import Scolog, ScolarNews
from app.models.formations import ( from app.models.formations import Formation, Matiere
Formation, from app.models.modules import Module, ModuleUECoef, NotesTag
UniteEns, from app.models.ues import UniteEns
Matiere,
Module,
ModuleUECoef,
NotesTag,
)
from app.models.formsemestre import ( from app.models.formsemestre import (
FormSemestre, FormSemestre,
FormsemestreEtape, FormsemestreEtape,

View File

@ -1,13 +1,10 @@
"""ScoDoc8 models : Formations (hors BUT) """ScoDoc 9 models : Formations
""" """
from typing import Any
from app import db from app import db
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 notesdb as ndb from app.scodoc import notesdb as ndb
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu
from app.scodoc.sco_utils import ModuleType
from app.scodoc import sco_codes_parcours from app.scodoc import sco_codes_parcours
from app.comp import df_cache from app.comp import df_cache
@ -91,82 +88,6 @@ class Formation(db.Model):
df_cache.ModuleCoefsCache.delete_many(keys | {f"{self.id}"}) 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): 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
@ -183,178 +104,3 @@ class Matiere(db.Model):
numero = db.Column(db.Integer) # ordre de présentation numero = db.Column(db.Integer) # ordre de présentation
modules = db.relationship("Module", lazy="dynamic", backref="matiere") 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")
),
)

View File

@ -16,7 +16,8 @@ from app.models 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 import sco_evaluation_db 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.moduleimpls import ModuleImpl
from app.models.etudiants import Identite from app.models.etudiants import Identite
from app.scodoc import sco_codes_parcours from app.scodoc import sco_codes_parcours

View File

@ -2,19 +2,14 @@
"""ScoDoc models: moduleimpls """ScoDoc models: moduleimpls
""" """
from typing import Any
import pandas as pd import pandas as pd
from app import db from app import db
from app.comp import df_cache 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 from app.models import UniteEns, Identite
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app.scodoc import sco_evaluation_db
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu

185
app/models/modules.py Normal file
View 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
View 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()

View File

@ -546,21 +546,21 @@ def list_abs_non_just(etudid, datedebut):
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
cursor.execute( cursor.execute(
"""SELECT ETUDID, JOUR, MATIN FROM ABSENCES A """SELECT ETUDID, JOUR, MATIN FROM ABSENCES A
WHERE A.ETUDID = %(etudid)s WHERE A.ETUDID = %(etudid)s
AND A.estabs AND A.estabs
AND A.jour >= %(datedebut)s AND A.jour >= %(datedebut)s
EXCEPT SELECT ETUDID, JOUR, MATIN FROM ABSENCES B EXCEPT SELECT ETUDID, JOUR, MATIN FROM ABSENCES B
WHERE B.estjust WHERE B.estjust
AND B.ETUDID = %(etudid)s AND B.ETUDID = %(etudid)s
ORDER BY JOUR ORDER BY JOUR
""", """,
vars(), vars(),
) )
A = cursor.dictfetchall() abs_list = cursor.dictfetchall()
for a in A: for a in abs_list:
a["description"] = _get_abs_description(a, cursor=cursor) a["description"] = _get_abs_description(a, cursor=cursor)
return A return abs_list
def list_abs_just(etudid, datedebut): def list_abs_just(etudid, datedebut):
@ -570,7 +570,7 @@ def list_abs_just(etudid, datedebut):
cursor.execute( cursor.execute(
"""SELECT DISTINCT A.ETUDID, A.JOUR, A.MATIN FROM ABSENCES A, ABSENCES B """SELECT DISTINCT A.ETUDID, A.JOUR, A.MATIN FROM ABSENCES A, ABSENCES B
WHERE A.ETUDID = %(etudid)s 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.JOUR = B.JOUR AND A.MATIN = B.MATIN AND A.JOUR >= %(datedebut)s
AND A.ESTABS AND (A.ESTJUST OR B.ESTJUST) AND A.ESTABS AND (A.ESTJUST OR B.ESTJUST)
ORDER BY A.JOUR ORDER BY A.JOUR
@ -638,8 +638,12 @@ def add_absence(
cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor) cursor = cnx.cursor(cursor_factory=ndb.ScoDocCursor)
cursor.execute( cursor.execute(
""" """
INSERT into absences (etudid,jour,estabs,estjust,matin,description, moduleimpl_id) INSERT into absences
VALUES (%(etudid)s, %(jour)s, true, %(estjust)s, %(matin)s, %(description)s, %(moduleimpl_id)s ) (etudid, jour, estabs, estjust, matin, description, moduleimpl_id)
VALUES
(%(etudid)s, %(jour)s, true, %(estjust)s, %(matin)s,
%(description)s, %(moduleimpl_id)s
)
""", """,
vars(), vars(),
) )

View File

@ -28,7 +28,7 @@ import flask
from flask import url_for, render_template from flask import url_for, render_template
from flask import g, request from flask import g, request
from flask_login import current_user 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.notesdb as ndb
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu

View File

@ -32,7 +32,7 @@ import flask
from flask import url_for, render_template from flask import url_for, render_template
from flask import g, request from flask import g, request
from flask_login import current_user 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.notesdb as ndb
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu

View File

@ -33,7 +33,7 @@ from flask import url_for, render_template
from flask import g, request from flask import g, request
from flask_login import current_user 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.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.scodoc.sco_utils import ModuleType

View File

@ -1106,7 +1106,7 @@ def formsemestre_associate_new_version(
"etat": "1", "etat": "1",
}, },
) )
of = [] H = []
for s in othersems: for s in othersems:
if ( if (
s["formsemestre_id"] == formsemestre_id s["formsemestre_id"] == formsemestre_id
@ -1119,9 +1119,10 @@ def formsemestre_associate_new_version(
disabled = 'disabled="1"' disabled = 'disabled="1"'
else: else:
disabled = "" disabled = ""
of.append( H.append(
'<div><input type="checkbox" name="other_formsemestre_ids:list" value="%s" %s %s>%s</input></div>' f"""<div><input type="checkbox" name="other_formsemestre_ids:list"
% (s["formsemestre_id"], checked, disabled, s["titremois"]) value="{s['formsemestre_id']}" {checked} {disabled}
>{s['titremois']}</input></div>"""
) )
return scu.confirm_dialog( 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>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> </p>
<div class="othersemlist"><p>Si vous voulez associer aussi d'autres semestres à la nouvelle version, cochez-les:</p>""" <div class="othersemlist"><p>Si vous voulez associer aussi d'autres semestres à la nouvelle version, cochez-les:</p>"""
+ "".join(of) + "".join(H)
+ "</div>", + "</div>",
OK="Associer ces semestres à une nouvelle version", OK="Associer ces semestres à une nouvelle version",
dest_url="", dest_url="",

View File

@ -826,7 +826,7 @@ def _add_apc_columns(
col_id = f"moy_ue_{ue.id}" col_id = f"moy_ue_{ue.id}"
titles[col_id] = ue.acronyme titles[col_id] = ue.acronyme
columns_ids.append(col_id) columns_ids.append(col_id)
row_coefs[f"moy_ue_{ue.id}"] = [uc for uc in ue_coefs if uc.ue_id == ue.id][ coefs = [uc for uc in ue_coefs if uc.ue_id == ue.id]
0 if coefs:
].coef row_coefs[f"moy_ue_{ue.id}"] = coefs[0].coef
row_coefs[f"_moy_ue_{ue.id}_td_attrs"] = ' class="coef_mod_ue" ' row_coefs[f"_moy_ue_{ue.id}_td_attrs"] = ' class="coef_mod_ue" '

View File

@ -115,7 +115,7 @@ function showSynthese(data) {
${(dataUE.competence) ? dataUE.competence + " - " : ""}${ue} ${(dataUE.competence) ? dataUE.competence + " - " : ""}${ue}
</h3> </h3>
<div> <div>
<div class=moyenne>Moyenn&nbsp;:&nbsp;${dataUE.moyenne?.value || "-"}</div> <div class=moyenne>Moyenne&nbsp;:&nbsp;${dataUE.moyenne?.value || "-"}</div>
<div class=info> <div class=info>
Bonus&nbsp;:&nbsp;${dataUE.bonus || 0}&nbsp;- Bonus&nbsp;:&nbsp;${dataUE.bonus || 0}&nbsp;-
Malus&nbsp;:&nbsp;${dataUE.malus || 0} Malus&nbsp;:&nbsp;${dataUE.malus || 0}
@ -125,7 +125,7 @@ function showSynthese(data) {
</div> </div>
</div> </div>
<div class=absences> <div class=absences>
<div>Abs&nbsp;inj.</div><div>${dataUE.absences?.injustifie || 0}</div> <div>Abs&nbsp;N.J.</div><div>${dataUE.absences?.injustifie || 0}</div>
<div>Total</div><div>${dataUE.absences?.total || 0}</div> <div>Total</div><div>${dataUE.absences?.total || 0}</div>
</div> </div>
</div> </div>

View File

@ -381,7 +381,7 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""):
@scodoc7func @scodoc7func
def ue_set_internal(ue_id): def ue_set_internal(ue_id):
"""""" """"""
ue = models.formations.UniteEns.query.get(ue_id) ue = models.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

View File

@ -56,7 +56,7 @@ from app.scodoc import notesdb as ndb
from app.scodoc import sco_formations from app.scodoc import sco_formations
from app import log 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 ( from app.scodoc.sco_exceptions import (
ScoValueError, ScoValueError,
ScoLockedFormError, ScoLockedFormError,

View File

@ -18,7 +18,7 @@ from app import db
from app import models from app import models
from app.decorators import scodoc, permission_required 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.models.but_refcomp import ApcReferentielCompetences
from app.but.import_refcomp import orebut_import_refcomp from app.but.import_refcomp import orebut_import_refcomp
from app.but.forms.refcomp_forms import FormationRefCompForm, RefCompLoadForm from app.but.forms.refcomp_forms import FormationRefCompForm, RefCompLoadForm