forked from ScoDoc/ScoDoc
WIP: PN BUT
This commit is contained in:
parent
14ab816bee
commit
58a7508043
14
README.md
14
README.md
@ -89,6 +89,17 @@ exemple pour travailler en mode "développement" avec `FLASK_ENV=development`.
|
|||||||
|
|
||||||
### Tests unitaires
|
### Tests unitaires
|
||||||
|
|
||||||
|
Les tests unitaires utilisent normalement la base postgresql `SCODOC_TEST`.
|
||||||
|
Avant le premier lancement, créer cette base ainsi:
|
||||||
|
|
||||||
|
./tools/create_database.sh SCODOC_TEST
|
||||||
|
export FLASK_ENV=test
|
||||||
|
flask db upgrade
|
||||||
|
|
||||||
|
Cette commande n'est nécessaire que la première fois (le contenu de la base
|
||||||
|
est effacé au début de chaque test, mais son schéma reste) et aussi si des
|
||||||
|
migrations (changements de schéma) ont eu lieu dans le code.
|
||||||
|
|
||||||
Certains tests ont besoin d'un département déjà créé, qui n'est pas créé par les
|
Certains tests ont besoin d'un département déjà créé, qui n'est pas créé par les
|
||||||
scripts de tests:
|
scripts de tests:
|
||||||
Lancer au préalable:
|
Lancer au préalable:
|
||||||
@ -109,7 +120,8 @@ On peut aussi utiliser les tests unitaires pour mettre la base
|
|||||||
de données de développement dans un état connu, par exemple pour éviter de
|
de données de développement dans un état connu, par exemple pour éviter de
|
||||||
recréer à la main étudiants et semestres quand on développe.
|
recréer à la main étudiants et semestres quand on développe.
|
||||||
|
|
||||||
Il suffit de positionner une variable d'environnement indiquant la BD utilisée par les tests:
|
Il suffit de positionner une variable d'environnement indiquant la BD
|
||||||
|
utilisée par les tests:
|
||||||
|
|
||||||
export SCODOC_TEST_DATABASE_URI=postgresql:///SCODOC_DEV
|
export SCODOC_TEST_DATABASE_URI=postgresql:///SCODOC_DEV
|
||||||
|
|
||||||
|
75
app/comp/moy_mod.py
Normal file
75
app/comp/moy_mod.py
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# -*- 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 de modules (modules, ressources ou SAÉ)
|
||||||
|
|
||||||
|
Rappel: pour éviter les confusions, on appelera *poids* les coefficients d'une
|
||||||
|
évaluation dans un module, et *coefficients* ceux utilisés pour le calcul de la
|
||||||
|
moyenne générale d'une UE.
|
||||||
|
"""
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
from app import db
|
||||||
|
from app import models
|
||||||
|
|
||||||
|
|
||||||
|
def df_load_evaluations_poids(moduleimpl_id: int, default_poids=1.0) -> pd.DataFrame:
|
||||||
|
"""Charge poids des évaluations d'un module et retourne un dataframe
|
||||||
|
rows = evaluations, columns = UE, value = poids (float).
|
||||||
|
Les valeurs manquantes (évaluations sans coef vers des UE) sont
|
||||||
|
remplies par default_poids.
|
||||||
|
"""
|
||||||
|
modimpl = models.ModuleImpl.query.get(moduleimpl_id)
|
||||||
|
evaluations = models.Evaluation.query.filter_by(moduleimpl_id=moduleimpl_id).all()
|
||||||
|
ues = modimpl.formsemestre.query_ues().all()
|
||||||
|
ue_ids = [ue.id for ue in ues]
|
||||||
|
evaluation_ids = [evaluation.id for evaluation in evaluations]
|
||||||
|
df = pd.DataFrame(columns=ue_ids, index=evaluation_ids, dtype=float)
|
||||||
|
for eval_poids in models.EvaluationUEPoids.query.join(
|
||||||
|
models.EvaluationUEPoids.evaluation
|
||||||
|
).filter_by(moduleimpl_id=moduleimpl_id):
|
||||||
|
df[eval_poids.ue_id][eval_poids.evaluation_id] = eval_poids.poids
|
||||||
|
if default_poids is not None:
|
||||||
|
df.fillna(value=default_poids, inplace=True)
|
||||||
|
return df
|
||||||
|
|
||||||
|
|
||||||
|
def check_moduleimpl_conformity(
|
||||||
|
moduleimpl, evals_poids: pd.DataFrame, modules_coefficients: pd.DataFrame
|
||||||
|
) -> bool:
|
||||||
|
"""Vérifie que les évaluations de ce moduleimpl sont bien conformes
|
||||||
|
au PN.
|
||||||
|
Un module est dit *conforme* si et seulement si la somme des poids de ses
|
||||||
|
évaluations vers une UE de coefficient non nul est non nulle.
|
||||||
|
"""
|
||||||
|
module_evals_poids = evals_poids.transpose().sum(axis=1).to_numpy() != 0
|
||||||
|
check = all(
|
||||||
|
(modules_coefficients[moduleimpl.module.id].to_numpy() != 0)
|
||||||
|
== module_evals_poids
|
||||||
|
)
|
||||||
|
return check
|
@ -34,21 +34,22 @@ from app import db
|
|||||||
from app import models
|
from app import models
|
||||||
|
|
||||||
|
|
||||||
def df_load_ue_coefs(formation_id):
|
def df_load_ue_coefs(formation_id: int, semestre_idx: int) -> pd.DataFrame:
|
||||||
"""Load coefs of all modules in formation and returns a DataFrame
|
"""Load coefs of all modules in formation and returns a DataFrame
|
||||||
rows = modules, columns = UE, value = coef.
|
rows = UEs, columns = modules, value = coef.
|
||||||
|
On considère toutes les UE et modules du semestre.
|
||||||
Unspecified coefs (not defined in db) are set to zero.
|
Unspecified coefs (not defined in db) are set to zero.
|
||||||
"""
|
"""
|
||||||
ues = models.UniteEns.query.filter_by(formation_id=formation_id).all()
|
ues = models.UniteEns.query.filter_by(formation_id=formation_id)
|
||||||
modules = models.Module.query.filter_by(formation_id=formation_id).all()
|
modules = models.Module.query.filter_by(formation_id=formation_id)
|
||||||
ue_ids = [ue.id for ue in ues]
|
ue_ids = [ue.id for ue in ues]
|
||||||
module_ids = [module.id for module in modules]
|
module_ids = [module.id for module in modules]
|
||||||
df = pd.DataFrame(columns=ue_ids, index=module_ids, dtype=float)
|
df = pd.DataFrame(columns=module_ids, index=ue_ids, dtype=float)
|
||||||
for mod_coef in (
|
for mod_coef in (
|
||||||
db.session.query(models.ModuleUECoef)
|
db.session.query(models.ModuleUECoef)
|
||||||
.filter(models.UniteEns.formation_id == formation_id)
|
.filter(models.UniteEns.formation_id == formation_id)
|
||||||
.filter(models.ModuleUECoef.ue_id == models.UniteEns.id)
|
.filter(models.ModuleUECoef.ue_id == models.UniteEns.id)
|
||||||
):
|
):
|
||||||
df[mod_coef.ue_id][mod_coef.module_id] = mod_coef.coef
|
df[mod_coef.module_id][mod_coef.ue_id] = mod_coef.coef
|
||||||
df.fillna(value=0, inplace=True)
|
df.fillna(value=0, inplace=True)
|
||||||
return df
|
return df
|
||||||
|
@ -37,7 +37,6 @@ from app.models.formations import (
|
|||||||
Module,
|
Module,
|
||||||
ModuleUECoef,
|
ModuleUECoef,
|
||||||
NotesTag,
|
NotesTag,
|
||||||
notes_modules_tags,
|
|
||||||
)
|
)
|
||||||
from app.models.formsemestre import (
|
from app.models.formsemestre import (
|
||||||
FormSemestre,
|
FormSemestre,
|
||||||
|
@ -36,6 +36,7 @@ class Formation(db.Model):
|
|||||||
ues = db.relationship("UniteEns", 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("UniteEns", lazy="dynamic", backref="formation")
|
ues = db.relationship("UniteEns", lazy="dynamic", backref="formation")
|
||||||
|
modules = db.relationship("Module", 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}')>"
|
||||||
@ -133,6 +134,12 @@ class Module(db.Model):
|
|||||||
# Relations:
|
# Relations:
|
||||||
modimpls = db.relationship("ModuleImpl", backref="module", lazy="dynamic")
|
modimpls = db.relationship("ModuleImpl", backref="module", lazy="dynamic")
|
||||||
ues_apc = db.relationship("UniteEns", secondary="module_ue_coef", viewonly=True)
|
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):
|
def __init__(self, **kwargs):
|
||||||
self.ue_coefs = []
|
self.ue_coefs = []
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
"""
|
"""
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
import flask_sqlalchemy
|
||||||
|
|
||||||
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
|
||||||
@ -12,6 +14,8 @@ from app.models import UniteEns
|
|||||||
|
|
||||||
import app.scodoc.notesdb as ndb
|
import app.scodoc.notesdb as ndb
|
||||||
from app.scodoc import sco_evaluation_db
|
from app.scodoc import sco_evaluation_db
|
||||||
|
from app.models.formations import UniteEns, Module
|
||||||
|
from app.models.moduleimpls import ModuleImpl
|
||||||
|
|
||||||
|
|
||||||
class FormSemestre(db.Model):
|
class FormSemestre(db.Model):
|
||||||
@ -87,8 +91,24 @@ class FormSemestre(db.Model):
|
|||||||
if self.modalite is None:
|
if self.modalite is None:
|
||||||
self.modalite = FormationModalite.DEFAULT_MODALITE
|
self.modalite = FormationModalite.DEFAULT_MODALITE
|
||||||
|
|
||||||
def get_ues(self):
|
def query_ues(self) -> flask_sqlalchemy.BaseQuery:
|
||||||
"UE des modules de ce semestre"
|
"""UE des modules de ce semestre.
|
||||||
|
- Formations classiques: les UEs auxquelles appartiennent
|
||||||
|
les modules mis en place dans ce semestre.
|
||||||
|
- Formations APC / BUT: les UEs de la formation qui ont
|
||||||
|
le même numéro de semestre que ce formsemestre.
|
||||||
|
"""
|
||||||
|
if self.formation.get_parcours().APC_SAE:
|
||||||
|
sem_ues = UniteEns.query.filter_by(
|
||||||
|
formation=self.formation, semestre_idx=self.semestre_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
sem_ues = db.session.query(UniteEns).filter(
|
||||||
|
ModuleImpl.formsemestre_id == self.id,
|
||||||
|
Module.id == ModuleImpl.module_id,
|
||||||
|
UniteEns.id == Module.ue_id,
|
||||||
|
)
|
||||||
|
return sem_ues
|
||||||
|
|
||||||
|
|
||||||
# Association id des utilisateurs responsables (aka directeurs des etudes) du semestre
|
# Association id des utilisateurs responsables (aka directeurs des etudes) du semestre
|
||||||
|
122
app/scodoc/sco_edit_apc.py
Normal file
122
app/scodoc/sco_edit_apc.py
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
"""Édition formation APC (BUT)
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
|
||||||
|
import app.scodoc.notesdb as ndb
|
||||||
|
import app.scodoc.sco_utils as scu
|
||||||
|
from app.scodoc import sco_groups
|
||||||
|
from app.scodoc.sco_utils import ModuleType
|
||||||
|
|
||||||
|
|
||||||
|
def html_edit_formation_apc(
|
||||||
|
formation,
|
||||||
|
editable=True,
|
||||||
|
tag_editable=True,
|
||||||
|
):
|
||||||
|
"""Formulaire html pour visualisation ou édition d'une formation APC.
|
||||||
|
- Les UEs
|
||||||
|
- Les ressources
|
||||||
|
- Les SAÉs
|
||||||
|
"""
|
||||||
|
parcours = formation.get_parcours()
|
||||||
|
assert parcours.APC_SAE
|
||||||
|
ressources = formation.modules.filter_by(module_type=ModuleType.RESSOURCE)
|
||||||
|
saes = formation.modules.filter_by(module_type=ModuleType.SAE)
|
||||||
|
other_modules = formation.modules.filter(
|
||||||
|
Module.module_type != ModuleType.SAE
|
||||||
|
and Module.module_type != ModuleType.RESSOURCE
|
||||||
|
)
|
||||||
|
arrow_up, arrow_down, arrow_none = sco_groups.get_arrow_icons_tags()
|
||||||
|
delete_icon = scu.icontag(
|
||||||
|
"delete_small_img", title="Supprimer (module inutilisé)", alt="supprimer"
|
||||||
|
)
|
||||||
|
delete_disabled_icon = scu.icontag(
|
||||||
|
"delete_small_dis_img", title="Suppression impossible (module utilisé)"
|
||||||
|
)
|
||||||
|
H = [
|
||||||
|
render_template(
|
||||||
|
"pn/form_ues.html",
|
||||||
|
formation=formation,
|
||||||
|
editable=editable,
|
||||||
|
arrow_up=arrow_up,
|
||||||
|
arrow_down=arrow_down,
|
||||||
|
arrow_none=arrow_none,
|
||||||
|
delete_icon=delete_icon,
|
||||||
|
delete_disabled_icon=delete_disabled_icon,
|
||||||
|
),
|
||||||
|
render_template(
|
||||||
|
"pn/form_mods.html",
|
||||||
|
formation=formation,
|
||||||
|
titre="Ressources",
|
||||||
|
create_element_msg="créer une nouvelle ressource",
|
||||||
|
modules=ressources,
|
||||||
|
module_type=ModuleType.RESSOURCE,
|
||||||
|
editable=editable,
|
||||||
|
arrow_up=arrow_up,
|
||||||
|
arrow_down=arrow_down,
|
||||||
|
arrow_none=arrow_none,
|
||||||
|
delete_icon=delete_icon,
|
||||||
|
delete_disabled_icon=delete_disabled_icon,
|
||||||
|
scu=scu,
|
||||||
|
),
|
||||||
|
render_template(
|
||||||
|
"pn/form_mods.html",
|
||||||
|
formation=formation,
|
||||||
|
titre="Situations d'Apprentissage et d'Évaluation (SAÉs)",
|
||||||
|
create_element_msg="créer une nouvelle SAÉ",
|
||||||
|
modules=saes,
|
||||||
|
module_type=ModuleType.SAE,
|
||||||
|
editable=editable,
|
||||||
|
arrow_up=arrow_up,
|
||||||
|
arrow_down=arrow_down,
|
||||||
|
arrow_none=arrow_none,
|
||||||
|
delete_icon=delete_icon,
|
||||||
|
delete_disabled_icon=delete_disabled_icon,
|
||||||
|
scu=scu,
|
||||||
|
),
|
||||||
|
render_template(
|
||||||
|
"pn/form_mods.html",
|
||||||
|
formation=formation,
|
||||||
|
titre="Autres modules (non BUT)",
|
||||||
|
create_element_msg="créer un nouveau module",
|
||||||
|
modules=other_modules,
|
||||||
|
module_type=ModuleType.STANDARD,
|
||||||
|
editable=editable,
|
||||||
|
arrow_up=arrow_up,
|
||||||
|
arrow_down=arrow_down,
|
||||||
|
arrow_none=arrow_none,
|
||||||
|
delete_icon=delete_icon,
|
||||||
|
delete_disabled_icon=delete_disabled_icon,
|
||||||
|
scu=scu,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
return "\n".join(H)
|
@ -32,6 +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
|
||||||
|
|
||||||
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
|
||||||
@ -106,46 +107,49 @@ def do_module_create(args) -> int:
|
|||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def module_create(matiere_id=None):
|
def module_create(matiere_id=None, module_type=None, semestre_id=None):
|
||||||
"""Création 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:
|
matiere = Matiere.query.get(matiere_id)
|
||||||
|
if matiere is None:
|
||||||
raise ScoValueError("invalid matiere !")
|
raise ScoValueError("invalid matiere !")
|
||||||
matiere = sco_edit_matiere.matiere_list(args={"matiere_id": matiere_id})[0]
|
ue = matiere.ue
|
||||||
UE = sco_edit_ue.ue_list(args={"ue_id": matiere["ue_id"]})[0]
|
parcours = ue.formation.get_parcours()
|
||||||
formation = sco_formations.formation_list(
|
|
||||||
args={"formation_id": UE["formation_id"]}
|
|
||||||
)[0]
|
|
||||||
parcours = sco_codes_parcours.get_parcours_from_code(formation["type_parcours"])
|
|
||||||
is_apc = parcours.APC_SAE
|
is_apc = parcours.APC_SAE
|
||||||
semestres_indices = list(range(1, parcours.NB_SEM + 1))
|
if is_apc and module_type is not None:
|
||||||
|
object_name = scu.MODULE_TYPE_NAMES[module_type]
|
||||||
|
else:
|
||||||
|
object_name = "Module"
|
||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(page_title="Création d'un module"),
|
html_sco_header.sco_header(page_title=f"Création {object_name}"),
|
||||||
"""<h2>Création d'un module dans la matière %(titre)s""" % matiere,
|
f"""<h2>Création {object_name} dans la matière {matiere.titre},
|
||||||
""" (UE %(acronyme)s)</h2>""" % UE,
|
(UE {ue.acronyme})</h2>
|
||||||
render_template("scodoc/help/modules.html", is_apc=is_apc),
|
""",
|
||||||
|
render_template(
|
||||||
|
"scodoc/help/modules.html",
|
||||||
|
is_apc=is_apc,
|
||||||
|
ue=ue,
|
||||||
|
semestre_id=semestre_id,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
# cherche le numero adéquat (pour placer le module en fin de liste)
|
# cherche le numero adéquat (pour placer le module en fin de liste)
|
||||||
modules = module_list(args={"matiere_id": matiere_id})
|
modules = Matiere.query.get(1).modules.all()
|
||||||
if modules:
|
if modules:
|
||||||
default_num = max([m["numero"] for m in modules]) + 10
|
default_num = max([m.numero for m in modules]) + 10
|
||||||
else:
|
else:
|
||||||
default_num = 10
|
default_num = 10
|
||||||
tf = TrivialFormulator(
|
descr = [
|
||||||
request.base_url,
|
|
||||||
scu.get_request_args(),
|
|
||||||
(
|
|
||||||
(
|
(
|
||||||
"code",
|
"code",
|
||||||
{
|
{
|
||||||
"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=formation[
|
"validator": lambda val, field, formation_id=ue.formation_id: check_module_code_unicity(
|
||||||
"formation_id"
|
val, field, formation_id
|
||||||
]: check_module_code_unicity(val, field, formation_id),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
("titre", {"size": 30, "explanation": "nom du module"}),
|
("titre", {"size": 30, "explanation": "nom du module"}),
|
||||||
@ -180,6 +184,22 @@ def module_create(matiere_id=None):
|
|||||||
"explanation": "nombre d'heures de Travaux Pratiques",
|
"explanation": "nombre d'heures de Travaux Pratiques",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
]
|
||||||
|
if is_apc:
|
||||||
|
descr += [
|
||||||
|
(
|
||||||
|
"sep_ue_coefs",
|
||||||
|
{
|
||||||
|
"input_type": "separator",
|
||||||
|
"title": """
|
||||||
|
<div>(<em>les coefficients vers les UE se fixent sur la page dédiée</em>)
|
||||||
|
</div>""",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
semestres_indices = list(range(1, parcours.NB_SEM + 1))
|
||||||
|
descr += [
|
||||||
(
|
(
|
||||||
"coefficient",
|
"coefficient",
|
||||||
{
|
{
|
||||||
@ -189,10 +209,6 @@ def module_create(matiere_id=None):
|
|||||||
"allow_null": False,
|
"allow_null": False,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
# ('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"}),
|
|
||||||
("ue_id", {"default": matiere["ue_id"], "input_type": "hidden"}),
|
|
||||||
("matiere_id", {"default": matiere["matiere_id"], "input_type": "hidden"}),
|
|
||||||
(
|
(
|
||||||
"semestre_id",
|
"semestre_id",
|
||||||
{
|
{
|
||||||
@ -205,6 +221,12 @@ def module_create(matiere_id=None):
|
|||||||
"allowed_values": semestres_indices,
|
"allowed_values": semestres_indices,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
]
|
||||||
|
descr += [
|
||||||
|
# ('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"}),
|
||||||
|
("ue_id", {"default": ue.id, "input_type": "hidden"}),
|
||||||
|
("matiere_id", {"default": matiere.id, "input_type": "hidden"}),
|
||||||
(
|
(
|
||||||
"code_apogee",
|
"code_apogee",
|
||||||
{
|
{
|
||||||
@ -222,7 +244,12 @@ def module_create(matiere_id=None):
|
|||||||
"default": default_num,
|
"default": default_num,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
]
|
||||||
|
args = scu.get_request_args()
|
||||||
|
tf = TrivialFormulator(
|
||||||
|
request.base_url,
|
||||||
|
args,
|
||||||
|
descr,
|
||||||
submitlabel="Créer ce module",
|
submitlabel="Créer ce module",
|
||||||
)
|
)
|
||||||
if tf[0] == 0:
|
if tf[0] == 0:
|
||||||
@ -233,7 +260,7 @@ def module_create(matiere_id=None):
|
|||||||
url_for(
|
url_for(
|
||||||
"notes.ue_table",
|
"notes.ue_table",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
formation_id=UE["formation_id"],
|
formation_id=ue.formation_id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -344,6 +371,7 @@ def module_edit(module_id=None):
|
|||||||
if not modules:
|
if not modules:
|
||||||
raise ScoValueError("invalid module !")
|
raise ScoValueError("invalid module !")
|
||||||
module = modules[0]
|
module = modules[0]
|
||||||
|
a_module = models.Module.query.get(module_id)
|
||||||
unlocked = not module_is_locked(module_id)
|
unlocked = not module_is_locked(module_id)
|
||||||
formation_id = module["formation_id"]
|
formation_id = module["formation_id"]
|
||||||
formation = sco_formations.formation_list(args={"formation_id": formation_id})[0]
|
formation = sco_formations.formation_list(args={"formation_id": formation_id})[0]
|
||||||
@ -434,7 +462,6 @@ def module_edit(module_id=None):
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
if is_apc:
|
if is_apc:
|
||||||
a_module = models.Module.query.get(module_id)
|
|
||||||
coefs_descr = a_module.ue_coefs_descr()
|
coefs_descr = a_module.ue_coefs_descr()
|
||||||
if coefs_descr:
|
if coefs_descr:
|
||||||
coefs_descr_txt = ", ".join(["%s: %s" % x for x in coefs_descr])
|
coefs_descr_txt = ", ".join(["%s: %s" % x for x in coefs_descr])
|
||||||
@ -479,6 +506,21 @@ def module_edit(module_id=None):
|
|||||||
"enabled": unlocked,
|
"enabled": unlocked,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
]
|
||||||
|
if is_apc:
|
||||||
|
# le semestre du module est toujours celui de son UE
|
||||||
|
descr += [
|
||||||
|
(
|
||||||
|
"semestre_id",
|
||||||
|
{
|
||||||
|
"input_type": "hidden",
|
||||||
|
"type": "int",
|
||||||
|
"readonly": True,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
descr += [
|
||||||
(
|
(
|
||||||
"semestre_id",
|
"semestre_id",
|
||||||
{
|
{
|
||||||
@ -491,7 +533,9 @@ def module_edit(module_id=None):
|
|||||||
"allowed_values": semestres_indices,
|
"allowed_values": semestres_indices,
|
||||||
"enabled": unlocked,
|
"enabled": unlocked,
|
||||||
},
|
},
|
||||||
),
|
)
|
||||||
|
]
|
||||||
|
descr += [
|
||||||
(
|
(
|
||||||
"code_apogee",
|
"code_apogee",
|
||||||
{
|
{
|
||||||
@ -509,7 +553,8 @@ def module_edit(module_id=None):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
# force module semestre_idx to its UE
|
||||||
|
module["semestre_id"] = a_module.ue.semestre_idx
|
||||||
tf = TrivialFormulator(
|
tf = TrivialFormulator(
|
||||||
request.base_url,
|
request.base_url,
|
||||||
scu.get_request_args(),
|
scu.get_request_args(),
|
||||||
@ -538,7 +583,7 @@ def module_edit(module_id=None):
|
|||||||
def edit_module_set_code_apogee(id=None, value=None):
|
def edit_module_set_code_apogee(id=None, value=None):
|
||||||
"Set UE code apogee"
|
"Set UE code apogee"
|
||||||
module_id = id
|
module_id = id
|
||||||
value = value.strip("-_ \t")
|
value = str(value).strip("-_ \t")
|
||||||
log("edit_module_set_code_apogee: module_id=%s code_apogee=%s" % (module_id, value))
|
log("edit_module_set_code_apogee: module_id=%s code_apogee=%s" % (module_id, value))
|
||||||
|
|
||||||
modules = module_list(args={"module_id": module_id})
|
modules = module_list(args={"module_id": module_id})
|
||||||
|
@ -45,6 +45,7 @@ from app.scodoc.sco_exceptions import ScoValueError, ScoLockedFormError
|
|||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
from app.scodoc import sco_codes_parcours
|
from app.scodoc import sco_codes_parcours
|
||||||
|
from app.scodoc import sco_edit_apc
|
||||||
from app.scodoc import sco_edit_formation
|
from app.scodoc import sco_edit_formation
|
||||||
from app.scodoc import sco_edit_matiere
|
from app.scodoc import sco_edit_matiere
|
||||||
from app.scodoc import sco_edit_module
|
from app.scodoc import sco_edit_module
|
||||||
@ -382,27 +383,32 @@ def ue_edit(ue_id=None, create=False, formation_id=None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _add_ue_semestre_id(ues):
|
def _add_ue_semestre_id(ues: list[dict], is_apc):
|
||||||
"""ajoute semestre_id dans les ue, en regardant
|
"""ajoute semestre_id dans les ue, en regardant
|
||||||
semestre_idx ou à défaut le premier module de chacune.
|
semestre_idx ou à défaut, pour les formations non APC, le premier module
|
||||||
|
de chacune.
|
||||||
Les UE sans modules se voient attribuer le numero UE_SEM_DEFAULT (1000000),
|
Les UE sans modules se voient attribuer le numero UE_SEM_DEFAULT (1000000),
|
||||||
qui les place à la fin de la liste.
|
qui les place à la fin de la liste.
|
||||||
"""
|
"""
|
||||||
for ue in ues:
|
for ue in ues:
|
||||||
if ue["semestre_idx"] is not None:
|
if ue["semestre_idx"] is not None:
|
||||||
ue["semestre_id"] = ue["semestre_idx"]
|
ue["semestre_id"] = ue["semestre_idx"]
|
||||||
|
elif is_apc:
|
||||||
|
ue["semestre_id"] = sco_codes_parcours.UE_SEM_DEFAULT
|
||||||
else:
|
else:
|
||||||
|
# était le comportement ScoDoc7
|
||||||
modules = sco_edit_module.module_list(args={"ue_id": ue["ue_id"]})
|
modules = sco_edit_module.module_list(args={"ue_id": ue["ue_id"]})
|
||||||
if modules:
|
if modules:
|
||||||
ue["semestre_id"] = modules[0]["semestre_id"]
|
ue["semestre_id"] = modules[0]["semestre_id"]
|
||||||
else:
|
else:
|
||||||
ue["semestre_id"] = 1000000
|
ue["semestre_id"] = sco_codes_parcours.UE_SEM_DEFAULT
|
||||||
|
|
||||||
|
|
||||||
def next_ue_numero(formation_id, semestre_id=None):
|
def next_ue_numero(formation_id, semestre_id=None):
|
||||||
"""Numero d'une nouvelle UE dans cette formation.
|
"""Numero d'une nouvelle UE dans cette formation.
|
||||||
Si le semestre est specifie, cherche les UE ayant des modules de ce semestre
|
Si le semestre est specifie, cherche les UE ayant des modules de ce semestre
|
||||||
"""
|
"""
|
||||||
|
formation = Formation.query.get(formation_id)
|
||||||
ues = ue_list(args={"formation_id": formation_id})
|
ues = ue_list(args={"formation_id": formation_id})
|
||||||
if not ues:
|
if not ues:
|
||||||
return 0
|
return 0
|
||||||
@ -410,7 +416,7 @@ def next_ue_numero(formation_id, semestre_id=None):
|
|||||||
return ues[-1]["numero"] + 1000
|
return ues[-1]["numero"] + 1000
|
||||||
else:
|
else:
|
||||||
# Avec semestre: (prend le semestre du 1er module de l'UE)
|
# Avec semestre: (prend le semestre du 1er module de l'UE)
|
||||||
_add_ue_semestre_id(ues)
|
_add_ue_semestre_id(ues, formation.get_parcours().APC_SAE)
|
||||||
ue_list_semestre = [ue for ue in ues if ue["semestre_id"] == semestre_id]
|
ue_list_semestre = [ue for ue in ues if ue["semestre_id"] == semestre_id]
|
||||||
if ue_list_semestre:
|
if ue_list_semestre:
|
||||||
return ue_list_semestre[-1]["numero"] + 10
|
return ue_list_semestre[-1]["numero"] + 10
|
||||||
@ -447,27 +453,27 @@ def ue_table(formation_id=None, msg=""): # was ue_list
|
|||||||
from app.scodoc import sco_formations
|
from app.scodoc import sco_formations
|
||||||
from app.scodoc import sco_formsemestre_validation
|
from app.scodoc import sco_formsemestre_validation
|
||||||
|
|
||||||
F = sco_formations.formation_list(args={"formation_id": formation_id})
|
formation = Formation.query.get(formation_id)
|
||||||
if not F:
|
if not formation:
|
||||||
raise ScoValueError("invalid formation_id")
|
raise ScoValueError("invalid formation_id")
|
||||||
F = F[0]
|
parcours = formation.get_parcours()
|
||||||
parcours = sco_codes_parcours.get_parcours_from_code(F["type_parcours"])
|
|
||||||
is_apc = parcours.APC_SAE
|
is_apc = parcours.APC_SAE
|
||||||
locked = sco_formations.formation_has_locked_sems(formation_id)
|
locked = sco_formations.formation_has_locked_sems(formation_id)
|
||||||
|
|
||||||
ues = ue_list(args={"formation_id": formation_id, "is_external": False})
|
ues = ue_list(args={"formation_id": formation_id, "is_external": False})
|
||||||
ues_externes = ue_list(args={"formation_id": formation_id, "is_external": True})
|
ues_externes = ue_list(args={"formation_id": formation_id, "is_external": True})
|
||||||
# tri par semestre et numero:
|
# tri par semestre et numero:
|
||||||
_add_ue_semestre_id(ues)
|
_add_ue_semestre_id(ues, is_apc)
|
||||||
_add_ue_semestre_id(ues_externes)
|
_add_ue_semestre_id(ues_externes, is_apc)
|
||||||
ues.sort(key=lambda u: (u["semestre_id"], u["numero"]))
|
ues.sort(key=lambda u: (u["semestre_id"], u["numero"]))
|
||||||
ues_externes.sort(key=lambda u: (u["semestre_id"], u["numero"]))
|
ues_externes.sort(key=lambda u: (u["semestre_id"], u["numero"]))
|
||||||
has_duplicate_ue_codes = len(set([ue["ue_code"] for ue in ues])) != len(ues)
|
has_duplicate_ue_codes = len(set([ue["ue_code"] for ue in ues])) != len(ues)
|
||||||
|
|
||||||
has_perm_change = current_user.has_permission(Permission.ScoChangeFormation)
|
has_perm_change = current_user.has_permission(Permission.ScoChangeFormation)
|
||||||
# editable = (not locked) and has_perm_change
|
# editable = (not locked) and has_perm_change
|
||||||
# On autorise maintanant la modification des formations qui ont des semestres verrouillés,
|
# On autorise maintenant la modification des formations qui ont
|
||||||
# sauf si cela affect les notes passées (verrouillées):
|
# des semestres verrouillés, sauf si cela affect les notes passées
|
||||||
|
# (verrouillées):
|
||||||
# - pas de modif des modules utilisés dans des semestres verrouillés
|
# - pas de modif des modules utilisés dans des semestres verrouillés
|
||||||
# - pas de changement des codes d'UE utilisés dans des semestres verrouillés
|
# - pas de changement des codes d'UE utilisés dans des semestres verrouillés
|
||||||
editable = has_perm_change
|
editable = has_perm_change
|
||||||
@ -496,12 +502,13 @@ def ue_table(formation_id=None, msg=""): # was ue_list
|
|||||||
"libjs/jQuery-tagEditor/jquery.caret.min.js",
|
"libjs/jQuery-tagEditor/jquery.caret.min.js",
|
||||||
"js/module_tag_editor.js",
|
"js/module_tag_editor.js",
|
||||||
],
|
],
|
||||||
page_title="Programme %s" % F["acronyme"],
|
page_title=f"Programme {formation.acronyme}",
|
||||||
),
|
),
|
||||||
"""<h2>Formation %(titre)s (%(acronyme)s) [version %(version)s] code %(formation_code)s"""
|
f"""<h2>Formation {formation.titre} ({formation.acronyme})
|
||||||
% F,
|
[version {formation.version}] code {formation.formation_code}
|
||||||
lockicon,
|
{lockicon}
|
||||||
"</h2>",
|
</h2>
|
||||||
|
""",
|
||||||
]
|
]
|
||||||
if locked:
|
if locked:
|
||||||
H.append(
|
H.append(
|
||||||
@ -533,41 +540,41 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
|||||||
# Description de la formation
|
# Description de la formation
|
||||||
H.append('<div class="formation_descr">')
|
H.append('<div class="formation_descr">')
|
||||||
H.append(
|
H.append(
|
||||||
'<div class="fd_d"><span class="fd_t">Titre:</span><span class="fd_v">%(titre)s</span></div>'
|
f"""<div class="fd_d"><span class="fd_t">Titre:
|
||||||
% F
|
</span><span class="fd_v">{formation.titre}</span>
|
||||||
)
|
</div>
|
||||||
H.append(
|
<div class="fd_d"><span class="fd_t">Titre officiel:</span>
|
||||||
'<div class="fd_d"><span class="fd_t">Titre officiel:</span><span class="fd_v">%(titre_officiel)s</span></div>'
|
<span class="fd_v">{formation.titre_officiel}</span>
|
||||||
% F
|
</div>
|
||||||
)
|
<div class="fd_d"><span class="fd_t">Acronyme:</span>
|
||||||
H.append(
|
<span class="fd_v">{formation.acronyme}</span>
|
||||||
'<div class="fd_d"><span class="fd_t">Acronyme:</span><span class="fd_v">%(acronyme)s</span></div>'
|
</div>
|
||||||
% F
|
<div class="fd_d"><span class="fd_t">Code:</span>
|
||||||
)
|
<span class="fd_v">{formation.formation_code}</span>
|
||||||
H.append(
|
</div>
|
||||||
'<div class="fd_d"><span class="fd_t">Code:</span><span class="fd_v">%(formation_code)s</span></div>'
|
<div class="fd_d"><span class="fd_t">Version:</span>
|
||||||
% F
|
<span class="fd_v">{formation.version}</span>
|
||||||
)
|
</div>
|
||||||
H.append(
|
<div class="fd_d"><span class="fd_t">Type parcours:</span>
|
||||||
'<div class="fd_d"><span class="fd_t">Version:</span><span class="fd_v">%(version)s</span></div>'
|
<span class="fd_v">{parcours.__doc__}</span>
|
||||||
% F
|
</div>
|
||||||
)
|
"""
|
||||||
H.append(
|
|
||||||
'<div class="fd_d"><span class="fd_t">Type parcours:</span><span class="fd_v">%s</span></div>'
|
|
||||||
% parcours.__doc__
|
|
||||||
)
|
)
|
||||||
if parcours.UE_IS_MODULE:
|
if parcours.UE_IS_MODULE:
|
||||||
H.append(
|
H.append(
|
||||||
'<div class="fd_d"><span class="fd_t"> </span><span class="fd_n">(Chaque module est une UE)</span></div>'
|
"""<div class="fd_d"><span class="fd_t"> </span>
|
||||||
|
<span class="fd_n">(Chaque module est une UE)</span></div>"""
|
||||||
)
|
)
|
||||||
|
|
||||||
if editable:
|
if editable:
|
||||||
H.append(
|
H.append(
|
||||||
'<div><a href="formation_edit?formation_id=%(formation_id)s" class="stdlink">modifier ces informations</a></div>'
|
f"""<div><a href="{
|
||||||
% F
|
url_for('notes.formation_edit', scodoc_dept=g.scodoc_dept,
|
||||||
|
formation_id=formation_id)
|
||||||
|
}" class="stdlink">modifier ces informations</a></div>"""
|
||||||
)
|
)
|
||||||
|
|
||||||
H.append("</div>")
|
H.append("</div>")
|
||||||
|
|
||||||
# Formation APC (BUT) ?
|
# Formation APC (BUT) ?
|
||||||
if is_apc:
|
if is_apc:
|
||||||
H.append(
|
H.append(
|
||||||
@ -575,18 +582,28 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
|||||||
<div class="ue_list_tit">Formation par compétences (BUT)</div>
|
<div class="ue_list_tit">Formation par compétences (BUT)</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a class="stdlink" href="{
|
<li><a class="stdlink" href="{
|
||||||
url_for('notes.edit_modules_ue_coefs', scodoc_dept=g.scodoc_dept, formation_id=formation_id)
|
url_for('notes.edit_modules_ue_coefs', scodoc_dept=g.scodoc_dept, formation_id=formation_id, semestre_idx=None)
|
||||||
}">éditer les coefficients des ressources et SAÉs</a></li>
|
}">éditer les coefficients des ressources et SAÉs</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>"""
|
</div>"""
|
||||||
)
|
)
|
||||||
# Description des UE/matières/modules
|
# Description des UE/matières/modules
|
||||||
H.append('<div class="formation_ue_list">')
|
|
||||||
H.append('<div class="ue_list_tit">Programme pédagogique:</div>')
|
|
||||||
|
|
||||||
H.append(
|
H.append(
|
||||||
'<form><input type="checkbox" class="sco_tag_checkbox">montrer les tags</input></form>'
|
"""
|
||||||
|
<div class="formation_ue_list">
|
||||||
|
<div class="ue_list_tit">Programme pédagogique:</div>
|
||||||
|
<form>
|
||||||
|
<input type="checkbox" class="sco_tag_checkbox">montrer les tags</input>
|
||||||
|
</form>
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
|
if is_apc:
|
||||||
|
H.append(
|
||||||
|
sco_edit_apc.html_edit_formation_apc(
|
||||||
|
formation, editable=editable, tag_editable=tag_editable
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
H.append(
|
H.append(
|
||||||
_ue_table_ues(
|
_ue_table_ues(
|
||||||
parcours,
|
parcours,
|
||||||
@ -603,22 +620,29 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
|||||||
)
|
)
|
||||||
if editable:
|
if editable:
|
||||||
H.append(
|
H.append(
|
||||||
'<ul><li><a class="stdlink" href="ue_create?formation_id=%s">Ajouter une UE</a></li>'
|
f"""<ul>
|
||||||
% formation_id
|
<li><a class="stdlink" href="{
|
||||||
)
|
url_for('notes.ue_create', scodoc_dept=g.scodoc_dept, formation_id=formation_id)
|
||||||
H.append(
|
}">Ajouter une UE</a>
|
||||||
'<li><a href="formation_add_malus_modules?formation_id=%(formation_id)s" class="stdlink">Ajouter des modules de malus dans chaque UE</a></li></ul>'
|
</li>
|
||||||
% F
|
<li><a href="{
|
||||||
|
url_for('notes.formation_add_malus_modules',
|
||||||
|
scodoc_dept=g.scodoc_dept, formation_id=formation_id)
|
||||||
|
}" class="stdlink">Ajouter des modules de malus dans chaque UE</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
H.append("</div>") # formation_ue_list
|
H.append("</div>") # formation_ue_list
|
||||||
|
|
||||||
if ues_externes:
|
if ues_externes:
|
||||||
H.append('<div class="formation_ue_list formation_ue_list_externes">')
|
|
||||||
H.append(
|
H.append(
|
||||||
'<div class="ue_list_tit">UE externes déclarées (pour information):</div>'
|
f"""
|
||||||
)
|
<div class="formation_ue_list formation_ue_list_externes">
|
||||||
H.append(
|
<div class="ue_list_tit">UE externes déclarées (pour information):
|
||||||
_ue_table_ues(
|
</div>
|
||||||
|
{_ue_table_ues(
|
||||||
parcours,
|
parcours,
|
||||||
ues_externes,
|
ues_externes,
|
||||||
editable,
|
editable,
|
||||||
@ -629,30 +653,49 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
|||||||
arrow_none,
|
arrow_none,
|
||||||
delete_icon,
|
delete_icon,
|
||||||
delete_disabled_icon,
|
delete_disabled_icon,
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
)
|
|
||||||
H.append("</div>") # formation_ue_list
|
|
||||||
|
|
||||||
H.append("<p><ul>")
|
H.append("<p><ul>")
|
||||||
if editable:
|
if editable:
|
||||||
H.append(
|
H.append(
|
||||||
|
f"""
|
||||||
|
<li><a class="stdlink" href="{
|
||||||
|
url_for('notes.formation_create_new_version',
|
||||||
|
scodoc_dept=g.scodoc_dept, formation_id=formation_id
|
||||||
|
)
|
||||||
|
}">Créer une nouvelle version (non verrouillée)</a>
|
||||||
|
</li>
|
||||||
"""
|
"""
|
||||||
<li><a class="stdlink" href="formation_create_new_version?formation_id=%(formation_id)s">Créer une nouvelle version (non verrouillée)</a></li>
|
|
||||||
"""
|
|
||||||
% F
|
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
"""
|
f"""
|
||||||
<li><a class="stdlink" href="formation_table_recap?formation_id=%(formation_id)s">Table récapitulative de la formation</a></li>
|
<li><a class="stdlink" href="{
|
||||||
|
url_for('notes.formation_table_recap', scodoc_dept=g.scodoc_dept,
|
||||||
|
formation_id=formation_id)
|
||||||
|
}">Table récapitulative de la formation</a>
|
||||||
|
</li>
|
||||||
|
<li><a class="stdlink" href="{
|
||||||
|
url_for('notes.formation_export', scodoc_dept=g.scodoc_dept,
|
||||||
|
formation_id=formation_id, format='xml')
|
||||||
|
}">Export XML de la formation</a>
|
||||||
|
(permet de la sauvegarder pour l'échanger avec un autre site)
|
||||||
|
</li>
|
||||||
|
|
||||||
<li><a class="stdlink" href="formation_export?formation_id=%(formation_id)s&format=xml">Export XML de la formation</a> (permet de la sauvegarder pour l'échanger avec un autre site)</li>
|
<li><a class="stdlink" href="{
|
||||||
|
url_for('notes.formation_export', scodoc_dept=g.scodoc_dept,
|
||||||
|
formation_id=formation_id, format='json')
|
||||||
|
}">Export JSON de la formation</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li><a class="stdlink" href="formation_export?formation_id=%(formation_id)s&format=json">Export JSON de la formation</a></li>
|
<li><a class="stdlink" href="{
|
||||||
|
url_for('notes.module_table', scodoc_dept=g.scodoc_dept,
|
||||||
<li><a class="stdlink" href="module_list?formation_id=%(formation_id)s">Liste détaillée des modules de la formation</a> (debug) </li>
|
formation_id=formation_id)
|
||||||
</ul>
|
}">Liste détaillée des modules de la formation</a> (debug)
|
||||||
</p>"""
|
</li>
|
||||||
% F
|
</ul>
|
||||||
|
</p>"""
|
||||||
)
|
)
|
||||||
if has_perm_change:
|
if has_perm_change:
|
||||||
H.append(
|
H.append(
|
||||||
@ -679,12 +722,13 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
|
|||||||
|
|
||||||
if current_user.has_permission(Permission.ScoImplement):
|
if current_user.has_permission(Permission.ScoImplement):
|
||||||
H.append(
|
H.append(
|
||||||
"""<ul>
|
f"""<ul>
|
||||||
<li><a class="stdlink" href="formsemestre_createwithmodules?formation_id=%(formation_id)s&semestre_id=1">Mettre en place un nouveau semestre de formation %(acronyme)s</a>
|
<li><a class="stdlink" href="{
|
||||||
|
url_for('notes.formsemestre_createwithmodules', scodoc_dept=g.scodoc_dept,
|
||||||
|
formation_id=formation_id, semestre_id=1)
|
||||||
|
}">Mettre en place un nouveau semestre de formation %(acronyme)s</a>
|
||||||
</li>
|
</li>
|
||||||
|
</ul>"""
|
||||||
</ul>"""
|
|
||||||
% F
|
|
||||||
)
|
)
|
||||||
# <li>(debug) <a class="stdlink" href="check_form_integrity?formation_id=%(formation_id)s">Vérifier cohérence</a></li>
|
# <li>(debug) <a class="stdlink" href="check_form_integrity?formation_id=%(formation_id)s">Vérifier cohérence</a></li>
|
||||||
|
|
||||||
@ -707,7 +751,9 @@ def _ue_table_ues(
|
|||||||
delete_icon,
|
delete_icon,
|
||||||
delete_disabled_icon,
|
delete_disabled_icon,
|
||||||
):
|
):
|
||||||
"""Édition de programme: liste des UEs (avec leurs matières et modules)."""
|
"""Édition de programme: liste des UEs (avec leurs matières et modules).
|
||||||
|
Pour les formations classiques (non APC/BUT)
|
||||||
|
"""
|
||||||
H = []
|
H = []
|
||||||
cur_ue_semestre_id = None
|
cur_ue_semestre_id = None
|
||||||
iue = 0
|
iue = 0
|
||||||
@ -802,6 +848,7 @@ def _ue_table_ues(
|
|||||||
arrow_none,
|
arrow_none,
|
||||||
delete_icon,
|
delete_icon,
|
||||||
delete_disabled_icon,
|
delete_disabled_icon,
|
||||||
|
module_type=module_type,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
@ -817,6 +864,7 @@ def _ue_table_matieres(
|
|||||||
arrow_none,
|
arrow_none,
|
||||||
delete_icon,
|
delete_icon,
|
||||||
delete_disabled_icon,
|
delete_disabled_icon,
|
||||||
|
module_type=None,
|
||||||
):
|
):
|
||||||
"""Édition de programme: liste des matières (et leurs modules) d'une UE."""
|
"""Édition de programme: liste des matières (et leurs modules) d'une UE."""
|
||||||
H = []
|
H = []
|
||||||
@ -883,6 +931,7 @@ def _ue_table_ressources_saes(
|
|||||||
arrow_none,
|
arrow_none,
|
||||||
delete_icon,
|
delete_icon,
|
||||||
delete_disabled_icon,
|
delete_disabled_icon,
|
||||||
|
module_type=None,
|
||||||
):
|
):
|
||||||
"""Édition de programme: liste des ressources et SAÉs d'une UE.
|
"""Édition de programme: liste des ressources et SAÉs d'une UE.
|
||||||
(pour les parcours APC_SAE)
|
(pour les parcours APC_SAE)
|
||||||
@ -905,7 +954,7 @@ def _ue_table_ressources_saes(
|
|||||||
"""
|
"""
|
||||||
]
|
]
|
||||||
modules = sco_edit_module.module_list(args={"ue_id": ue["ue_id"]})
|
modules = sco_edit_module.module_list(args={"ue_id": ue["ue_id"]})
|
||||||
for titre, element_name, module_type in (
|
for titre, element_name, element_type in (
|
||||||
("Ressources", "ressource", scu.ModuleType.RESSOURCE),
|
("Ressources", "ressource", scu.ModuleType.RESSOURCE),
|
||||||
("SAÉs", "SAÉ", scu.ModuleType.SAE),
|
("SAÉs", "SAÉ", scu.ModuleType.SAE),
|
||||||
("Autres modules", "xxx", None),
|
("Autres modules", "xxx", None),
|
||||||
@ -914,9 +963,9 @@ def _ue_table_ressources_saes(
|
|||||||
elements = [
|
elements = [
|
||||||
m
|
m
|
||||||
for m in modules
|
for m in modules
|
||||||
if module_type == m["module_type"]
|
if element_type == m["module_type"]
|
||||||
or (
|
or (
|
||||||
(module_type is None)
|
(element_type is None)
|
||||||
and m["module_type"]
|
and m["module_type"]
|
||||||
not in (scu.ModuleType.RESSOURCE, scu.ModuleType.SAE)
|
not in (scu.ModuleType.RESSOURCE, scu.ModuleType.SAE)
|
||||||
)
|
)
|
||||||
@ -933,6 +982,7 @@ def _ue_table_ressources_saes(
|
|||||||
arrow_none,
|
arrow_none,
|
||||||
delete_icon,
|
delete_icon,
|
||||||
delete_disabled_icon,
|
delete_disabled_icon,
|
||||||
|
module_type=module_type,
|
||||||
empty_list_msg="Aucune " + element_name,
|
empty_list_msg="Aucune " + element_name,
|
||||||
create_element_msg="créer une " + element_name,
|
create_element_msg="créer une " + element_name,
|
||||||
add_suppress_link=False,
|
add_suppress_link=False,
|
||||||
@ -1273,5 +1323,5 @@ def ue_list_semestre_ids(ue):
|
|||||||
Mais cela n'a pas toujours été le cas dans les programmes pédagogiques officiels,
|
Mais cela n'a pas toujours été le cas dans les programmes pédagogiques officiels,
|
||||||
aussi ScoDoc laisse le choix.
|
aussi ScoDoc laisse le choix.
|
||||||
"""
|
"""
|
||||||
Modlist = sco_edit_module.module_list(args={"ue_id": ue["ue_id"]})
|
modules = sco_edit_module.module_list(args={"ue_id": ue["ue_id"]})
|
||||||
return sorted(list(set([mod["semestre_id"] for mod in Modlist])))
|
return sorted(list(set([mod["semestre_id"] for mod in modules])))
|
||||||
|
@ -39,6 +39,7 @@ from flask import request
|
|||||||
from app import db
|
from app import db
|
||||||
from app import log
|
from app import log
|
||||||
from app import models
|
from app import models
|
||||||
|
from app.models.formsemestre import FormSemestre
|
||||||
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
|
||||||
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||||
@ -64,11 +65,8 @@ def evaluation_create_form(
|
|||||||
modimpl = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
modimpl = sco_moduleimpl.moduleimpl_withmodule_list(moduleimpl_id=moduleimpl_id)[0]
|
||||||
mod = modimpl["module"]
|
mod = modimpl["module"]
|
||||||
formsemestre_id = modimpl["formsemestre_id"]
|
formsemestre_id = modimpl["formsemestre_id"]
|
||||||
sem_ues = db.session.query(models.UniteEns).filter(
|
sem = FormSemestre.query.get(formsemestre_id)
|
||||||
models.ModuleImpl.formsemestre_id == formsemestre_id,
|
sem_ues = sem.query_ues().all()
|
||||||
models.Module.id == models.ModuleImpl.module_id,
|
|
||||||
models.UniteEns.id == models.Module.ue_id,
|
|
||||||
)
|
|
||||||
is_malus = mod["module_type"] == ModuleType.MALUS
|
is_malus = mod["module_type"] == ModuleType.MALUS
|
||||||
is_apc = mod["module_type"] in (ModuleType.RESSOURCE, ModuleType.SAE)
|
is_apc = mod["module_type"] in (ModuleType.RESSOURCE, ModuleType.SAE)
|
||||||
|
|
||||||
|
@ -263,7 +263,8 @@ div.logo-logo {
|
|||||||
}
|
}
|
||||||
div.logo-logo img {
|
div.logo-logo img {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
width: 100px;
|
width: 55px; /* 100px */
|
||||||
|
padding-right: 50px;
|
||||||
}
|
}
|
||||||
div.sidebar-bottom {
|
div.sidebar-bottom {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
@ -1480,7 +1481,40 @@ div.formation_ue_list {
|
|||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
}
|
}
|
||||||
|
div.formation_list_ues_titre {
|
||||||
|
padding-left: 24px;
|
||||||
|
padding-right: 24px;
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.formation_list_modules {
|
||||||
|
border-radius: 18px;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
}
|
||||||
|
div.formation_list_modules_titre {
|
||||||
|
padding-left: 24px;
|
||||||
|
padding-right: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
div.formation_list_modules_RESSOURCE {
|
||||||
|
background-color: #f8c844;
|
||||||
|
}
|
||||||
|
div.formation_list_modules_SAE {
|
||||||
|
background-color: #c6ffab;
|
||||||
|
}
|
||||||
|
div.formation_list_modules_STANDARD {
|
||||||
|
background-color: #afafc2;
|
||||||
|
}
|
||||||
|
div.formation_list_modules ul.notes_module_list {
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
padding-top: 5px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
li.module_malus span.formation_module_tit {
|
li.module_malus span.formation_module_tit {
|
||||||
color: red;
|
color: red;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@ -1498,7 +1532,6 @@ div.ue_list_tit {
|
|||||||
|
|
||||||
ul.notes_ue_list {
|
ul.notes_ue_list {
|
||||||
background-color: rgb(240,240,240);
|
background-color: rgb(240,240,240);
|
||||||
font-weight: bold;
|
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
}
|
}
|
||||||
@ -1519,7 +1552,10 @@ span.ue_type {
|
|||||||
margin-left: 1.5em;
|
margin-left: 1.5em;
|
||||||
margin-right: 1.5em;
|
margin-right: 1.5em;
|
||||||
}
|
}
|
||||||
|
ul.notes_module_list span.ue_coefs_list {
|
||||||
|
color: blue;
|
||||||
|
font-size: 70%;
|
||||||
|
}
|
||||||
div.formation_ue_list_externes {
|
div.formation_ue_list_externes {
|
||||||
background-color: #98cc98;
|
background-color: #98cc98;
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 7.8 KiB |
82
app/templates/pn/form_mods.html
Normal file
82
app/templates/pn/form_mods.html
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
{# Édition liste modules APC (SAÉ ou ressources) #}
|
||||||
|
|
||||||
|
<div class="formation_list_modules formation_list_modules_{{module_type.name}}">
|
||||||
|
<div class="formation_list_modules_titre">{{titre}}</div>
|
||||||
|
|
||||||
|
<ul class="notes_module_list">
|
||||||
|
|
||||||
|
{% if not formation.ues.count() %}
|
||||||
|
<li class="notes_module_list"><em>aucune UE</em></li>
|
||||||
|
{% else %}
|
||||||
|
{% for mod in modules %}
|
||||||
|
<li class="notes_module_list module_{{mod.type_name()}}">
|
||||||
|
<span class="notes_module_list_buts">
|
||||||
|
{% if editable and not loop.first %}
|
||||||
|
<a href="{{ url_for('notes.module_move',
|
||||||
|
scodoc_dept=g.scodoc_dept, module_id=mod.id, after=0 )
|
||||||
|
}}" class="aud">{{arrow_up|safe}}</a>
|
||||||
|
{% else %}
|
||||||
|
{{arrow_none|safe}}
|
||||||
|
{% endif %}
|
||||||
|
{% if editable and not loop.last %}
|
||||||
|
<a href="{{ url_for('notes.module_move',
|
||||||
|
scodoc_dept=g.scodoc_dept, module_id=mod.id, after=1 )
|
||||||
|
}}" class="aud">{{arrow_down|safe}}</a>
|
||||||
|
{% else %}
|
||||||
|
{{arrow_none|safe}}
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
{% if editable and not mod.modimpls.count() %}
|
||||||
|
<a class="smallbutton" href="{{ url_for('notes.module_delete',
|
||||||
|
scodoc_dept=g.scodoc_dept, module_id=mod.id)
|
||||||
|
}}">{{delete_icon|safe}}</a>
|
||||||
|
{% else %}
|
||||||
|
{{delete_disabled_icon|safe}}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if editable %}
|
||||||
|
<a class="discretelink" title="Modifier le module {{mod.code}},
|
||||||
|
utilisé par {{mod.modimpls.count()}} sessions"
|
||||||
|
href="{{ url_for('notes.module_edit',
|
||||||
|
scodoc_dept=g.scodoc_dept, module_id=mod.id)
|
||||||
|
}}">
|
||||||
|
{% endif %}
|
||||||
|
<span class="formation_module_tit">{{mod.code}} {{mod.titre|default("", true)}}</span>
|
||||||
|
{% if editable %}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{formation.get_parcours().SESSION_NAME}} {{mod.semestre_id}}
|
||||||
|
|
||||||
|
({{mod.heures_cours}}/{{mod.heures_td}}/{{mod.heures_tp}},
|
||||||
|
|
||||||
|
Apo:<span class="{% if editable %}span_apo_edit{% endif %}"
|
||||||
|
data-url="edit_module_set_code_apogee"
|
||||||
|
id="{{mod.id}}"
|
||||||
|
data-placeholder="{{scu.APO_MISSING_CODE_STR}}">
|
||||||
|
{{mod.code_apogee|default("", true)}}</span>)
|
||||||
|
|
||||||
|
<span class="ue_coefs_list">
|
||||||
|
{% for coef in mod.ue_coefs %}
|
||||||
|
<span>{{coef.ue.acronyme}}:{{coef.coef}}</span>
|
||||||
|
{% endfor %}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="sco_tag_edit"><form><textarea data-module_id="{{mod.id}}"
|
||||||
|
class="{% if editable %}module_tag_editor{% else %}module_tag_editor_ro{% endif %}">{{mod.tags|join(', ', attribute='title')}}</textarea></form></span>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if editable %}
|
||||||
|
<li><a class="stdlink" href="{{
|
||||||
|
url_for("notes.module_create",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
module_type=module_type|int,
|
||||||
|
)}}"
|
||||||
|
>{{create_element_msg}}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
@ -15,13 +15,35 @@
|
|||||||
<h2>Formation {{formation.titre}} ({{formation.acronyme}})
|
<h2>Formation {{formation.titre}} ({{formation.acronyme}})
|
||||||
[version {{formation.version}}] code {{formation.code}}</h2>
|
[version {{formation.version}}] code {{formation.code}}</h2>
|
||||||
|
|
||||||
|
<form onchange="change_semestre()">Semestre:
|
||||||
|
<select name="semestre_idx" id="semestre_idx" >
|
||||||
|
{% for i in semestre_ids %}
|
||||||
|
<option value="{{i}}" {%if semestre_idx == i%}selected{%endif%}>{{i}}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</form>
|
||||||
|
|
||||||
<div class="tableau"></div>
|
<div class="tableau"></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
function change_semestre() {
|
||||||
|
let semestre_idx = $("#semestre_idx")[0].value;
|
||||||
|
let url = window.location.href.replace( /\/[\-0-9]*$/, "/" + semestre_idx);
|
||||||
|
window.location.href = url;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
$.getJSON("{{data_source}}", function (data) {
|
let semestre_idx = $("#semestre_idx")[0].value;
|
||||||
|
if (semestre_idx > -10) {
|
||||||
|
let base_url = "{{data_source}}";
|
||||||
|
let data_url = base_url.replace( /\/[\-0-9]*$/, "/" + semestre_idx);
|
||||||
|
console.log("data_url=", data_url );
|
||||||
|
$.getJSON(data_url, function (data) {
|
||||||
|
console.log("build_table")
|
||||||
build_table(data);
|
build_table(data);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
function save(obj) {
|
function save(obj) {
|
||||||
var value = obj.innerText.trim();
|
var value = obj.innerText.trim();
|
||||||
|
49
app/templates/pn/form_ues.html
Normal file
49
app/templates/pn/form_ues.html
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{# Édition liste UEs APC #}
|
||||||
|
<div class="formation_list_ues">
|
||||||
|
<div class="formation_list_ues_titre">Unités d'Enseignement (UEs)</div>
|
||||||
|
<ul class="notes_ue_list">
|
||||||
|
{% if not formation.ues.count() %}
|
||||||
|
<li class="notes_ue_list"><em>aucune UE</em></li>
|
||||||
|
{% else %}
|
||||||
|
{% for ue in formation.ues %}
|
||||||
|
<li class="notes_ue_list">
|
||||||
|
{% if editable and not loop.first %}
|
||||||
|
<a href="{{ url_for('notes.ue_move',
|
||||||
|
scodoc_dept=g.scodoc_dept, ue_id=ue.id, after=0 )
|
||||||
|
}}" class="aud">{{arrow_up|safe}}</a>
|
||||||
|
{% else %}
|
||||||
|
{{arrow_none|safe}}
|
||||||
|
{% endif %}
|
||||||
|
{% if editable and not loop.last %}
|
||||||
|
<a href="{{ url_for('notes.ue_move',
|
||||||
|
scodoc_dept=g.scodoc_dept, ue_id=ue.id, after=1 )
|
||||||
|
}}" class="aud">{{arrow_down|safe}}</a>
|
||||||
|
{% else %}
|
||||||
|
{{arrow_none|safe}}
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
{% if editable and not ue.modules.count() %}
|
||||||
|
<a class="smallbutton" href="{{ url_for('notes.ue_delete',
|
||||||
|
scodoc_dept=g.scodoc_dept, ue_id=ue.id)
|
||||||
|
}}">{{delete_icon|safe}}</a>
|
||||||
|
{% else %}
|
||||||
|
{{delete_disabled_icon|safe}}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<b>{{ue.acronyme}}</b> {{ue.titre}}
|
||||||
|
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if editable %}
|
||||||
|
<li><a class="stdlink" href="{{
|
||||||
|
url_for("notes.ue_create",
|
||||||
|
scodoc_dept=g.scodoc_dept,
|
||||||
|
formation_id=formation.id,
|
||||||
|
)}}"
|
||||||
|
>ajouter une UE</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
@ -429,6 +429,7 @@ sco_publish(
|
|||||||
"/edit_module_set_code_apogee",
|
"/edit_module_set_code_apogee",
|
||||||
sco_edit_module.edit_module_set_code_apogee,
|
sco_edit_module.edit_module_set_code_apogee,
|
||||||
Permission.ScoChangeFormation,
|
Permission.ScoChangeFormation,
|
||||||
|
methods=["GET", "POST"],
|
||||||
)
|
)
|
||||||
sco_publish("/module_list", sco_edit_module.module_table, Permission.ScoView)
|
sco_publish("/module_list", sco_edit_module.module_table, Permission.ScoView)
|
||||||
sco_publish("/module_tag_search", sco_tag_module.module_tag_search, Permission.ScoView)
|
sco_publish("/module_tag_search", sco_tag_module.module_tag_search, Permission.ScoView)
|
||||||
|
@ -66,16 +66,20 @@ from app.scodoc import html_sco_header
|
|||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/table_modules_ue_coefs/<formation_id>")
|
@bp.route("/table_modules_ue_coefs/<int:formation_id>/<semestre_idx>")
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
def table_modules_ue_coefs(formation_id):
|
def table_modules_ue_coefs(formation_id, semestre_idx):
|
||||||
"""Description JSON de la table des coefs modules/UE dans une formation"""
|
"""Description JSON de la table des coefs modules/UE dans une formation"""
|
||||||
_ = models.Formation.query.get_or_404(formation_id) # check
|
_ = models.Formation.query.get_or_404(formation_id) # check
|
||||||
|
|
||||||
df = moy_ue.df_load_ue_coefs(formation_id)
|
df = moy_ue.df_load_ue_coefs(formation_id, semestre_idx)
|
||||||
ues = models.UniteEns.query.filter_by(formation_id=formation_id).all()
|
ues = models.UniteEns.query.filter_by(
|
||||||
modules = models.Module.query.filter_by(formation_id=formation_id).all()
|
formation_id=formation_id, semestre_idx=semestre_idx
|
||||||
|
)
|
||||||
|
modules = models.Module.query.filter_by(
|
||||||
|
formation_id=formation_id, semestre_id=semestre_idx
|
||||||
|
)
|
||||||
# Titre des modules, en ligne
|
# Titre des modules, en ligne
|
||||||
col_titres_mods = [
|
col_titres_mods = [
|
||||||
{
|
{
|
||||||
@ -108,7 +112,7 @@ def table_modules_ue_coefs(formation_id):
|
|||||||
"x": col,
|
"x": col,
|
||||||
"y": row,
|
"y": row,
|
||||||
"style": "champs",
|
"style": "champs",
|
||||||
"data": df[ue.id][mod.id] or "",
|
"data": df[mod.id][ue.id] or "",
|
||||||
"editable": True,
|
"editable": True,
|
||||||
"module_id": mod.id,
|
"module_id": mod.id,
|
||||||
"ue_id": ue.id,
|
"ue_id": ue.id,
|
||||||
@ -146,10 +150,11 @@ def set_module_ue_coef():
|
|||||||
return scu.json_error("ok", success=True, status=201)
|
return scu.json_error("ok", success=True, status=201)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/edit_modules_ue_coefs/<formation_id>")
|
@bp.route("/edit_modules_ue_coefs/<formation_id>", defaults={"semestre_idx": -100})
|
||||||
|
@bp.route("/edit_modules_ue_coefs/<formation_id>/<semestre_idx>")
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoChangeFormation)
|
@permission_required(Permission.ScoChangeFormation)
|
||||||
def edit_modules_ue_coefs(formation_id):
|
def edit_modules_ue_coefs(formation_id, semestre_idx=None):
|
||||||
"""Formulaire édition grille coefs EU/modules"""
|
"""Formulaire édition grille coefs EU/modules"""
|
||||||
formation = models.Formation.query.filter_by(
|
formation = models.Formation.query.filter_by(
|
||||||
formation_id=formation_id
|
formation_id=formation_id
|
||||||
@ -161,9 +166,12 @@ def edit_modules_ue_coefs(formation_id):
|
|||||||
"notes.table_modules_ue_coefs",
|
"notes.table_modules_ue_coefs",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
formation_id=formation_id,
|
formation_id=formation_id,
|
||||||
|
semestre_idx=semestre_idx or "",
|
||||||
),
|
),
|
||||||
data_save=url_for(
|
data_save=url_for(
|
||||||
"notes.set_module_ue_coef",
|
"notes.set_module_ue_coef",
|
||||||
scodoc_dept=g.scodoc_dept,
|
scodoc_dept=g.scodoc_dept,
|
||||||
),
|
),
|
||||||
|
semestre_idx=int(semestre_idx),
|
||||||
|
semestre_ids=range(1, formation.get_parcours().NB_SEM + 1),
|
||||||
)
|
)
|
||||||
|
@ -281,7 +281,7 @@ def list_depts(depts=""): # list-dept
|
|||||||
"--name",
|
"--name",
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
help="show database name instead of connexion string (required for "
|
help="show database name instead of connexion string (required for "
|
||||||
"dropdb/createddb commands)",
|
"dropdb/createdb commands)",
|
||||||
)
|
)
|
||||||
def scodoc_database(name): # list-dept
|
def scodoc_database(name): # list-dept
|
||||||
"""print the database connexion string"""
|
"""print the database connexion string"""
|
||||||
|
@ -166,6 +166,7 @@ class ScoFake(object):
|
|||||||
is_external=None,
|
is_external=None,
|
||||||
code_apogee=None,
|
code_apogee=None,
|
||||||
coefficient=None,
|
coefficient=None,
|
||||||
|
semestre_idx=None,
|
||||||
):
|
):
|
||||||
"""Crée une UE"""
|
"""Crée une UE"""
|
||||||
if numero is None:
|
if numero is None:
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
"""
|
"""
|
||||||
Test modèles évaluations avec poids BUT
|
Test modèles évaluations avec poids BUT
|
||||||
"""
|
"""
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
from tests.unit import sco_fake_gen
|
from tests.unit import sco_fake_gen
|
||||||
from app import db
|
from app import db
|
||||||
from app import models
|
from app import models
|
||||||
|
from app.comp import moy_mod
|
||||||
|
from app.comp import moy_ue
|
||||||
|
from app.scodoc import sco_codes_parcours
|
||||||
|
|
||||||
"""
|
"""
|
||||||
mapp.set_sco_dept("RT")
|
mapp.set_sco_dept("RT")
|
||||||
@ -18,11 +23,24 @@ login_user(admin_user)
|
|||||||
def setup_formation_test():
|
def setup_formation_test():
|
||||||
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",
|
||||||
|
type_parcours=sco_codes_parcours.ParcoursBUT.TYPE_PARCOURS,
|
||||||
|
)
|
||||||
|
_ue1 = G.create_ue(
|
||||||
|
formation_id=_f["formation_id"], acronyme="UE1", titre="ue 1", semestre_idx=2
|
||||||
|
)
|
||||||
|
_ue2 = G.create_ue(
|
||||||
|
formation_id=_f["formation_id"], acronyme="UE2", titre="ue 2", semestre_idx=2
|
||||||
|
)
|
||||||
|
_ue3 = G.create_ue(
|
||||||
|
formation_id=_f["formation_id"], acronyme="UE3", titre="ue 3", semestre_idx=2
|
||||||
|
)
|
||||||
|
# une 4eme UE en dehors du semestre 2
|
||||||
|
_ = G.create_ue(
|
||||||
|
formation_id=_f["formation_id"], acronyme="UE41", titre="ue 41", semestre_idx=4
|
||||||
)
|
)
|
||||||
_ue1 = G.create_ue(formation_id=_f["formation_id"], acronyme="UE1", titre="ue 1")
|
|
||||||
_ue2 = G.create_ue(formation_id=_f["formation_id"], acronyme="UE2", titre="ue 2")
|
|
||||||
_ue3 = G.create_ue(formation_id=_f["formation_id"], acronyme="UE3", titre="ue 3")
|
|
||||||
_mat = G.create_matiere(ue_id=_ue1["ue_id"], titre="matière test")
|
_mat = G.create_matiere(ue_id=_ue1["ue_id"], titre="matière test")
|
||||||
_mod = G.create_module(
|
_mod = G.create_module(
|
||||||
matiere_id=_mat["matiere_id"],
|
matiere_id=_mat["matiere_id"],
|
||||||
@ -31,6 +49,7 @@ def setup_formation_test():
|
|||||||
titre="module test",
|
titre="module test",
|
||||||
ue_id=_ue1["ue_id"],
|
ue_id=_ue1["ue_id"],
|
||||||
formation_id=_f["formation_id"],
|
formation_id=_f["formation_id"],
|
||||||
|
semestre_id=2,
|
||||||
)
|
)
|
||||||
return G, _f["id"], _ue1["id"], _ue2["id"], _ue3["id"], _mod["id"]
|
return G, _f["id"], _ue1["id"], _ue2["id"], _ue3["id"], _mod["id"]
|
||||||
|
|
||||||
@ -66,7 +85,9 @@ def test_evaluation_poids(test_client):
|
|||||||
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.UniteEns.query.filter_by(formation_id=formation_id).all()
|
ues = models.UniteEns.query.filter_by(
|
||||||
|
formation_id=formation_id, semestre_idx=2
|
||||||
|
).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)
|
||||||
@ -109,3 +130,60 @@ def test_modules_coefs(test_client):
|
|||||||
mod.set_ue_coef(ue2, 0.0)
|
mod.set_ue_coef(ue2, 0.0)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
assert len(mod.ue_coefs) == 0
|
assert len(mod.ue_coefs) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_modules_conformity(test_client):
|
||||||
|
"""Vérification coefficients module<->UE vs poids des évaluations"""
|
||||||
|
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)
|
||||||
|
ue3 = models.UniteEns.query.get(ue3_id)
|
||||||
|
mod = models.Module.query.get(module_id)
|
||||||
|
nb_ues = 3 # 3 UEs dans ce test
|
||||||
|
nb_mods = 1 # 1 seul module
|
||||||
|
# Coef du module vers les UE
|
||||||
|
c1, c2, c3 = 1.0, 2.0, 3.0
|
||||||
|
coefs_mod = {ue1.id: c1, ue2.id: c2, ue3.id: c3}
|
||||||
|
mod.set_ue_coef_dict(coefs_mod)
|
||||||
|
assert mod.get_ue_coef_dict() == coefs_mod
|
||||||
|
# Mise en place:
|
||||||
|
sem = G.create_formsemestre(
|
||||||
|
formation_id=formation_id,
|
||||||
|
semestre_id=2,
|
||||||
|
date_debut="01/01/2021",
|
||||||
|
date_fin="30/06/2021",
|
||||||
|
)
|
||||||
|
mi = G.create_moduleimpl(
|
||||||
|
module_id=module_id,
|
||||||
|
formsemestre_id=sem["formsemestre_id"],
|
||||||
|
)
|
||||||
|
moduleimpl_id = mi["id"]
|
||||||
|
modimpl = models.ModuleImpl.query.get(moduleimpl_id)
|
||||||
|
assert modimpl.formsemestre.formation.get_parcours().APC_SAE # BUT
|
||||||
|
# Check ModuleImpl
|
||||||
|
ues = modimpl.formsemestre.query_ues().all()
|
||||||
|
assert len(ues) == 3
|
||||||
|
#
|
||||||
|
_e1 = G.create_evaluation(
|
||||||
|
moduleimpl_id=moduleimpl_id,
|
||||||
|
jour="01/01/2021",
|
||||||
|
description="evaluation 1",
|
||||||
|
coefficient=0,
|
||||||
|
)
|
||||||
|
evaluation_id = _e1["evaluation_id"]
|
||||||
|
nb_evals = 1 # 1 seule evaluation pour l'instant
|
||||||
|
p1, p2, p3 = 1.0, 2.0, 0.0 # poids de l'éval vers les UE 1, 2 et 3
|
||||||
|
evaluation = models.Evaluation.query.get(evaluation_id)
|
||||||
|
evaluation.set_ue_poids_dict({ue1.id: p1, ue2.id: p2})
|
||||||
|
assert evaluation.get_ue_poids_dict() == {ue1.id: p1, ue2.id: p2}
|
||||||
|
# On n'est pas conforme car p3 est nul alors que c3 est non nul
|
||||||
|
modules_coefficients = moy_ue.df_load_ue_coefs(formation_id)
|
||||||
|
assert isinstance(modules_coefficients, pd.DataFrame)
|
||||||
|
assert modules_coefficients.shape == (nb_ues, nb_mods)
|
||||||
|
evals_poids = moy_mod.df_load_evaluations_poids(moduleimpl_id)
|
||||||
|
assert isinstance(evals_poids, pd.DataFrame)
|
||||||
|
assert all(evals_poids.dtypes == np.float64)
|
||||||
|
assert evals_poids.shape == (nb_evals, nb_ues)
|
||||||
|
assert not moy_mod.check_moduleimpl_conformity(
|
||||||
|
modimpl, evals_poids, modules_coefficients
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user