forked from ScoDoc/ScoDoc
Parcours BUT / Ref. Compétences
+ association UE -> ApcNiveau + choix sur la page ue_edit + association Module <-> ensemble de ApcParcours + choix sur la page module_edit + association Module - ApcAppCritique ~ choix sur la page module_edit TODO: revoir pour présenter les AC du semestre et parcours sélectionnés (JS) + association FormSemestre <-> ApcParcours + choix sur la page formsemestre_editwithmodules
This commit is contained in:
parent
539041fd0d
commit
fd8116a772
@ -17,7 +17,13 @@ def form_ue_choix_niveau(ue: UniteEns) -> str:
|
||||
"""Form. HTML pour associer une UE à un niveau de compétence"""
|
||||
ref_comp = ue.formation.referentiel_competence
|
||||
if ref_comp is None:
|
||||
return """<div class="ue_choix_niveau">pas de référentiel de compétence</div>"""
|
||||
return f"""<div class="ue_choix_niveau">
|
||||
<div class="warning">Pas de référentiel de compétence associé à cette formation !</div>
|
||||
<div><a class="stdlink" href="{ url_for('notes.refcomp_assoc_formation',
|
||||
scodoc_dept=g.scodoc_dept, formation_id=ue.formation.id)
|
||||
}">associer un référentiel de compétence</a>
|
||||
</div>
|
||||
</div>"""
|
||||
annee = (ue.semestre_idx + 1) // 2 # 1, 2, 3
|
||||
niveaux_by_parcours = ref_comp.get_niveaux_by_parcours(annee)
|
||||
|
||||
@ -39,7 +45,7 @@ def form_ue_choix_niveau(ue: UniteEns) -> str:
|
||||
options.append("""</optgroup>""")
|
||||
options_str = "\n".join(options)
|
||||
return f"""
|
||||
<div id="ue_choix_niveau">
|
||||
<div class="ue_choix_niveau">
|
||||
<form id="form_ue_choix_niveau">
|
||||
<b>Niveau de compétence associé:</b>
|
||||
<select onchange="set_ue_niveau_competence();" data-setter="{
|
||||
|
@ -13,7 +13,9 @@ from wtforms import SelectField, SubmitField
|
||||
|
||||
|
||||
class FormationRefCompForm(FlaskForm):
|
||||
referentiel_competence = SelectField("Référentiels déjà chargés")
|
||||
referentiel_competence = SelectField(
|
||||
"Choisir parmi les référentiels déjà chargés :"
|
||||
)
|
||||
submit = SubmitField("Valider")
|
||||
cancel = SubmitField("Annuler")
|
||||
|
||||
|
@ -1,12 +1,9 @@
|
||||
"""ScoDoc 9 models : Formation BUT 2021
|
||||
XXX inutilisé
|
||||
"""
|
||||
from enum import unique
|
||||
from typing import Any
|
||||
|
||||
from app import db
|
||||
|
||||
from app.scodoc.sco_utils import ModuleType
|
||||
|
||||
|
||||
class APCFormation(db.Model):
|
||||
"""Formation par compétence"""
|
||||
|
@ -83,7 +83,7 @@ class ApcReferentielCompetences(db.Model, XMLModel):
|
||||
formations = db.relationship("Formation", backref="referentiel_competence")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<ApcReferentielCompetences {self.id} {self.specialite}>"
|
||||
return f"<ApcReferentielCompetences {self.id} {self.specialite!r}>"
|
||||
|
||||
def to_dict(self):
|
||||
"""Représentation complète du ref. de comp.
|
||||
@ -191,7 +191,7 @@ class ApcCompetence(db.Model, XMLModel):
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<ApcCompetence {self.id} {self.titre}>"
|
||||
return f"<ApcCompetence {self.id} {self.titre!r}>"
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
@ -257,7 +257,8 @@ class ApcNiveau(db.Model, XMLModel):
|
||||
ues = db.relationship("UniteEns", back_populates="niveau_competence")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__name__} ordre={self.ordre} annee={self.annee} {self.competence}>"
|
||||
return f"""<{self.__class__.__name__} ordre={self.ordre!r} annee={
|
||||
self.annee!r} {self.competence!r}>"""
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
@ -341,7 +342,7 @@ class ApcAppCritique(db.Model, XMLModel):
|
||||
return self.code + " - " + self.titre
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__name__} {self.code}>"
|
||||
return f"<{self.__class__.__name__} {self.code!r}>"
|
||||
|
||||
def get_saes(self):
|
||||
"""Liste des SAE associées"""
|
||||
@ -362,6 +363,20 @@ parcours_modules = db.Table(
|
||||
)
|
||||
"""Association parcours <-> modules (many-to-many)"""
|
||||
|
||||
parcours_formsemestre = db.Table(
|
||||
"parcours_formsemestre",
|
||||
db.Column(
|
||||
"parcours_id", db.Integer, db.ForeignKey("apc_parcours.id"), primary_key=True
|
||||
),
|
||||
db.Column(
|
||||
"formsemestre_id",
|
||||
db.Integer,
|
||||
db.ForeignKey("notes_formsemestre.id", ondelete="CASCADE"),
|
||||
primary_key=True,
|
||||
),
|
||||
)
|
||||
"""Association parcours <-> formsemestre (many-to-many)"""
|
||||
|
||||
|
||||
class ApcParcours(db.Model, XMLModel):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
@ -379,7 +394,7 @@ class ApcParcours(db.Model, XMLModel):
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__name__} {self.code}>"
|
||||
return f"<{self.__class__.__name__} {self.code!r}>"
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
@ -399,7 +414,7 @@ class ApcAnneeParcours(db.Model, XMLModel):
|
||||
"numéro de l'année: 1, 2, 3"
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__name__} ordre={self.ordre} parcours={self.parcours.code}>"
|
||||
return f"<{self.__class__.__name__} ordre={self.ordre!r} parcours={self.parcours.code!r}>"
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
@ -450,4 +465,4 @@ class ApcParcoursNiveauCompetence(db.Model):
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__name__} {self.competence}<->{self.annee_parcours} niveau={self.niveau}>"
|
||||
return f"<{self.__class__.__name__} {self.competence!r}<->{self.annee_parcours!r} niveau={self.niveau!r}>"
|
||||
|
@ -515,21 +515,21 @@ class Admission(db.Model):
|
||||
|
||||
def to_dict(self, no_nulls=False):
|
||||
"""Représentation dictionnaire,"""
|
||||
e = dict(self.__dict__)
|
||||
e.pop("_sa_instance_state", None)
|
||||
d = dict(self.__dict__)
|
||||
d.pop("_sa_instance_state", None)
|
||||
if no_nulls:
|
||||
for k in e:
|
||||
if e[k] is None:
|
||||
for k in d.keys():
|
||||
if d[k] is None:
|
||||
col_type = getattr(
|
||||
sqlalchemy.inspect(models.Admission).columns, "apb_groupe"
|
||||
).expression.type
|
||||
if isinstance(col_type, sqlalchemy.Text):
|
||||
e[k] = ""
|
||||
d[k] = ""
|
||||
elif isinstance(col_type, sqlalchemy.Integer):
|
||||
e[k] = 0
|
||||
d[k] = 0
|
||||
elif isinstance(col_type, sqlalchemy.Boolean):
|
||||
e[k] = False
|
||||
return e
|
||||
d[k] = False
|
||||
return d
|
||||
|
||||
|
||||
# Suivi scolarité / débouchés
|
||||
|
@ -45,7 +45,7 @@ class Formation(db.Model):
|
||||
modules = db.relationship("Module", lazy="dynamic", backref="formation")
|
||||
|
||||
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!r}')>"
|
||||
|
||||
def to_dict(self):
|
||||
e = dict(self.__dict__)
|
||||
@ -168,7 +168,7 @@ class Matiere(db.Model):
|
||||
|
||||
def __repr__(self):
|
||||
return f"""<{self.__class__.__name__}(id={self.id}, ue_id={
|
||||
self.ue_id}, titre='{self.titre}')>"""
|
||||
self.ue_id}, titre='{self.titre!r}')>"""
|
||||
|
||||
def to_dict(self):
|
||||
"""as a dict, with the same conversions as in ScoDoc7"""
|
||||
|
@ -14,10 +14,12 @@ from app.models import SHORT_STR_LEN
|
||||
from app.models import CODE_STR_LEN
|
||||
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.models.ues import UniteEns
|
||||
from app.models.but_refcomp import parcours_formsemestre
|
||||
from app.models.etudiants import Identite
|
||||
from app.models.modules import Module
|
||||
from app.models.moduleimpls import ModuleImpl
|
||||
from app.models.etudiants import Identite
|
||||
from app.models.ues import UniteEns
|
||||
|
||||
from app.scodoc import sco_codes_parcours
|
||||
from app.scodoc import sco_preferences
|
||||
from app.scodoc.sco_vdi import ApoEtapeVDI
|
||||
@ -113,6 +115,14 @@ class FormSemestre(db.Model):
|
||||
# ne pas utiliser après migrate_scodoc7_dept_archives
|
||||
scodoc7_id = db.Column(db.Text(), nullable=True)
|
||||
|
||||
# BUT
|
||||
parcours = db.relationship(
|
||||
"ApcParcours",
|
||||
secondary=parcours_formsemestre,
|
||||
lazy="subquery",
|
||||
backref=db.backref("formsemestres", lazy=True),
|
||||
)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(FormSemestre, self).__init__(**kwargs)
|
||||
if self.modalite is None:
|
||||
|
@ -65,7 +65,7 @@ class Module(db.Model):
|
||||
super(Module, self).__init__(**kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Module{ModuleType(self.module_type or ModuleType.STANDARD).name} id={self.id} code={self.code}>"
|
||||
return f"<Module{ModuleType(self.module_type or ModuleType.STANDARD).name} id={self.id} code={self.code!r}>"
|
||||
|
||||
def to_dict(self):
|
||||
e = dict(self.__dict__)
|
||||
|
@ -207,12 +207,16 @@ class TF(object):
|
||||
else:
|
||||
self.values[field] = 1
|
||||
if field not in self.values:
|
||||
if "default" in descr: # first: default in form description
|
||||
self.values[field] = descr["default"]
|
||||
else: # then: use initvalues dict
|
||||
self.values[field] = self.initvalues.get(field, "")
|
||||
if self.values[field] == None:
|
||||
self.values[field] = ""
|
||||
if (descr.get("input_type", None) == "checkbox") and self.submitted():
|
||||
# aucune case cochée
|
||||
self.values[field] = []
|
||||
else:
|
||||
if "default" in descr: # first: default in form description
|
||||
self.values[field] = descr["default"]
|
||||
else: # then: use initvalues dict
|
||||
self.values[field] = self.initvalues.get(field, "")
|
||||
if self.values[field] is None:
|
||||
self.values[field] = ""
|
||||
|
||||
# convert numbers, except ids
|
||||
if field.endswith("id") and self.values[field]:
|
||||
@ -392,9 +396,7 @@ class TF(object):
|
||||
if self.top_buttons:
|
||||
R.append(buttons_markup + "<p></p>")
|
||||
R.append('<table class="tf">')
|
||||
idx = 0
|
||||
for idx in range(len(self.formdescription)):
|
||||
(field, descr) = self.formdescription[idx]
|
||||
for field, descr in self.formdescription:
|
||||
if descr.get("readonly", False):
|
||||
R.append(self._ReadOnlyElement(field, descr))
|
||||
continue
|
||||
@ -408,7 +410,7 @@ class TF(object):
|
||||
input_type = descr.get("input_type", "text")
|
||||
item_dom_id = descr.get("dom_id", "")
|
||||
if item_dom_id:
|
||||
item_dom_attr = ' id="%s"' % item_dom_id
|
||||
item_dom_attr = f' id="{item_dom_id}"'
|
||||
else:
|
||||
item_dom_attr = ""
|
||||
# choix du template
|
||||
@ -523,7 +525,6 @@ class TF(object):
|
||||
else:
|
||||
checked = ""
|
||||
else: # boolcheckbox
|
||||
# open('/tmp/toto','a').write('GenForm: values[%s] = %s (%s)\n' % (field, values[field], type(values[field])))
|
||||
if values[field] == "True":
|
||||
v = True
|
||||
elif values[field] == "False":
|
||||
|
@ -365,6 +365,7 @@ def module_edit(
|
||||
"libjs/jQuery-tagEditor/jquery.tag-editor.min.js",
|
||||
"libjs/jQuery-tagEditor/jquery.caret.min.js",
|
||||
"js/module_tag_editor.js",
|
||||
"js/module_edit.js",
|
||||
],
|
||||
),
|
||||
f"""<h2>{title}</h2>""",
|
||||
@ -605,8 +606,7 @@ def module_edit(
|
||||
"input_type": "menu",
|
||||
"type": "int",
|
||||
"title": parcours.SESSION_NAME.capitalize(),
|
||||
"explanation": "%s de début du module dans la formation standard"
|
||||
% parcours.SESSION_NAME,
|
||||
"explanation": f"{parcours.SESSION_NAME} de début du module dans la formation standard",
|
||||
"labels": [str(x) for x in semestres_indices],
|
||||
"allowed_values": semestres_indices,
|
||||
"enabled": unlocked,
|
||||
@ -619,7 +619,7 @@ def module_edit(
|
||||
{
|
||||
"title": "Code Apogée",
|
||||
"size": 25,
|
||||
"explanation": """(optionnel) code élément pédagogique Apogée ou liste de codes ELP
|
||||
"explanation": """(optionnel) code élément pédagogique Apogée ou liste de codes ELP
|
||||
séparés par des virgules (ce code est propre à chaque établissement, se rapprocher
|
||||
du référent Apogée).
|
||||
""",
|
||||
@ -648,11 +648,15 @@ def module_edit(
|
||||
"input_type": "checkbox",
|
||||
"vertical": True,
|
||||
"dom_id": "tf_module_parcours",
|
||||
"labels": [parcour.libelle for parcour in ref_comp.parcours],
|
||||
"labels": [parcour.libelle for parcour in ref_comp.parcours]
|
||||
+ ["Tous (tronc commun)"],
|
||||
"allowed_values": [
|
||||
str(parcour.id) for parcour in ref_comp.parcours
|
||||
],
|
||||
"explanation": "parcours dans lesquels est utilisé ce module.",
|
||||
]
|
||||
+ ["-1"],
|
||||
"explanation": """Parcours dans lesquels est utilisé ce module.<br>
|
||||
Attention: si le module ne doit pas avoir les mêmes coefficients suivant le parcours,
|
||||
il faut en créer plusieurs versions, car dans ScoDoc chaque module a ses coefficients.""",
|
||||
},
|
||||
)
|
||||
]
|
||||
@ -677,12 +681,17 @@ def module_edit(
|
||||
"vertical": True,
|
||||
"dom_id": "tf_module_app_critiques",
|
||||
"labels": [
|
||||
app_crit.libelle for app_crit in app_critiques
|
||||
f"{app_crit.code} {app_crit.libelle}"
|
||||
for app_crit in app_critiques
|
||||
],
|
||||
"allowed_values": [
|
||||
str(app_crit.id) for app_crit in app_critiques
|
||||
],
|
||||
"explanation": "apprentissages critiques liés à ce module.",
|
||||
"html_data": [],
|
||||
"explanation": """Apprentissages Critiques liés à ce module.
|
||||
(si vous changez le semestre, revenez ensuite sur cette page
|
||||
pour associer les AC.)
|
||||
""",
|
||||
},
|
||||
)
|
||||
]
|
||||
@ -693,7 +702,9 @@ def module_edit(
|
||||
{
|
||||
"input_type": "separator",
|
||||
"title": f"""<span class="fontred">{scu.EMO_WARNING }
|
||||
L'UE {ue.acronyme} {ue.titre}
|
||||
L'UE <a class="stdlink" href="{
|
||||
url_for("notes.ue_edit", scodoc_dept=g.scodoc_dept, ue_id=ue.id)
|
||||
}">{ue.acronyme} {ue.titre}</a>
|
||||
n'est pas associée à un niveau de compétences
|
||||
</span>""",
|
||||
},
|
||||
@ -727,9 +738,10 @@ def module_edit(
|
||||
request.base_url,
|
||||
scu.get_request_args(),
|
||||
descr,
|
||||
html_foot_markup="""<div class="sco_tag_module_edit"><span class="sco_tag_edit"><textarea data-module_id="{}" class="module_tag_editor">{}</textarea></span></div>""".format(
|
||||
module_id, ",".join(sco_tag_module.module_tag_list(module_id))
|
||||
)
|
||||
html_foot_markup=f"""<div class="sco_tag_module_edit"><span
|
||||
class="sco_tag_edit"><textarea data-module_id="{module_id}" class="module_tag_editor"
|
||||
>{','.join(sco_tag_module.module_tag_list(module_id))}</textarea></span></div>
|
||||
"""
|
||||
if not create
|
||||
else "",
|
||||
initvalues=module_dict if module else {},
|
||||
@ -793,11 +805,14 @@ def module_edit(
|
||||
#
|
||||
do_module_edit(tf[2])
|
||||
# Modifie les parcours
|
||||
if "parcours" in tf[2]:
|
||||
module.parcours = [
|
||||
ApcParcours.query.get(int(parcour_id_str))
|
||||
for parcour_id_str in tf[2]["parcours"]
|
||||
]
|
||||
if ("parcours" in tf[2]) and formation.referentiel_competence:
|
||||
if "-1" in tf[2]["parcours"]: # "tous"
|
||||
module.parcours = formation.referentiel_competence.parcours.all()
|
||||
else:
|
||||
module.parcours = [
|
||||
ApcParcours.query.get(int(parcour_id_str))
|
||||
for parcour_id_str in tf[2]["parcours"]
|
||||
]
|
||||
# Modifie les AC
|
||||
if "app_critiques" in tf[2]:
|
||||
module.app_critiques = [
|
||||
@ -811,7 +826,7 @@ def module_edit(
|
||||
"notes.ue_table",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formation_id=formation.id,
|
||||
semestre_idx=tf[2]["semestre_id"],
|
||||
semestre_idx=tf[2]["semestre_id"] if is_apc else 1,
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -39,23 +39,21 @@ from app.models import Module, ModuleImpl, Evaluation, EvaluationUEPoids, UniteE
|
||||
from app.models import ScolarNews
|
||||
from app.models.formations import Formation
|
||||
from app.models.formsemestre import FormSemestre
|
||||
from app.models.but_refcomp import ApcParcours
|
||||
import app.scodoc.notesdb as ndb
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc import sco_cache
|
||||
from app.scodoc import sco_groups
|
||||
from app import log
|
||||
from app.scodoc.TrivialFormulator import TrivialFormulator, TF
|
||||
from app.scodoc.TrivialFormulator import TrivialFormulator
|
||||
from app.scodoc.sco_exceptions import AccessDenied, ScoValueError
|
||||
from app.scodoc.sco_permissions import Permission
|
||||
from app.scodoc.sco_vdi import ApoEtapeVDI
|
||||
from app.scodoc import html_sco_header
|
||||
from app.scodoc import sco_codes_parcours
|
||||
from app.scodoc import sco_compute_moy
|
||||
from app.scodoc import sco_edit_matiere
|
||||
from app.scodoc import sco_edit_module
|
||||
from app.scodoc import sco_edit_ue
|
||||
from app.scodoc import sco_etud
|
||||
from app.scodoc import sco_evaluations
|
||||
from app.scodoc import sco_evaluation_db
|
||||
from app.scodoc import sco_formations
|
||||
from app.scodoc import sco_formsemestre
|
||||
@ -119,12 +117,12 @@ def formsemestre_editwithmodules(formsemestre_id):
|
||||
vals = scu.get_request_args()
|
||||
if not vals.get("tf_submitted", False):
|
||||
H.append(
|
||||
"""<p class="help">Seuls les modules cochés font partie de ce semestre.
|
||||
"""<p class="help">Seuls les modules cochés font partie de ce semestre.
|
||||
Pour les retirer, les décocher et appuyer sur le bouton "modifier".
|
||||
</p>
|
||||
<p class="help">Attention : s'il y a déjà des évaluations dans un module,
|
||||
<p class="help">Attention : s'il y a déjà des évaluations dans un module,
|
||||
il ne peut pas être supprimé !</p>
|
||||
<p class="help">Les modules ont toujours un responsable.
|
||||
<p class="help">Les modules ont toujours un responsable.
|
||||
Par défaut, c'est le directeur des études.</p>
|
||||
<p class="help">Un semestre ne peut comporter qu'une seule UE "bonus
|
||||
sport/culture"</p>
|
||||
@ -153,7 +151,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||
if not current_user.has_permission(Permission.ScoImplement):
|
||||
if not edit:
|
||||
# il faut ScoImplement pour creer un semestre
|
||||
# il faut ScoImplement pour créer un semestre
|
||||
raise AccessDenied("vous n'avez pas le droit d'effectuer cette opération")
|
||||
else:
|
||||
if not sem["resp_can_edit"] or current_user.id not in sem["responsables"]:
|
||||
@ -175,6 +173,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
formation = Formation.query.get(formation_id)
|
||||
if formation is None:
|
||||
raise ScoValueError("Formation inexistante !")
|
||||
is_apc = formation.is_apc()
|
||||
if not edit:
|
||||
initvalues = {"titre": _default_sem_title(formation)}
|
||||
semestre_id = int(vals["semestre_id"])
|
||||
@ -210,12 +209,12 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
if NB_SEM == 1:
|
||||
semestre_id_list = [-1]
|
||||
else:
|
||||
if edit and formation.is_apc():
|
||||
if edit and is_apc:
|
||||
# en APC, ne permet pas de changer de semestre
|
||||
semestre_id_list = [formsemestre.semestre_id]
|
||||
else:
|
||||
semestre_id_list = list(range(1, NB_SEM + 1))
|
||||
if not formation.is_apc():
|
||||
if not is_apc:
|
||||
# propose "pas de semestre" seulement en classique
|
||||
semestre_id_list.insert(0, -1)
|
||||
|
||||
@ -226,7 +225,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
else:
|
||||
semestre_id_labels.append(f"S{sid}")
|
||||
# Liste des modules dans cette formation
|
||||
if formation.is_apc():
|
||||
if is_apc:
|
||||
modules = formation.modules.order_by(Module.module_type, Module.numero)
|
||||
else:
|
||||
modules = (
|
||||
@ -318,10 +317,10 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
{
|
||||
"size": 40,
|
||||
"title": "Nom de ce semestre",
|
||||
"explanation": """n'indiquez pas les dates, ni le semestre, ni la modalité dans
|
||||
"explanation": f"""n'indiquez pas les dates, ni le semestre, ni la modalité dans
|
||||
le titre: ils seront automatiquement ajoutés <input type="button"
|
||||
value="remettre titre par défaut" onClick="document.tf.titre.value='%s';"/>"""
|
||||
% _default_sem_title(formation),
|
||||
value="remettre titre par défaut" onClick="document.tf.titre.value='{
|
||||
_default_sem_title(formation)}';"/>""",
|
||||
},
|
||||
),
|
||||
(
|
||||
@ -343,11 +342,9 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
"allowed_values": semestre_id_list,
|
||||
"labels": semestre_id_labels,
|
||||
"explanation": "en BUT, on ne peut pas modifier le semestre après création"
|
||||
if formation.is_apc()
|
||||
else "",
|
||||
"attributes": ['onchange="change_semestre_id();"']
|
||||
if formation.is_apc()
|
||||
if is_apc
|
||||
else "",
|
||||
"attributes": ['onchange="change_semestre_id();"'] if is_apc else "",
|
||||
},
|
||||
),
|
||||
)
|
||||
@ -386,7 +383,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
mf = mf_manual
|
||||
|
||||
for n in range(1, scu.EDIT_NB_ETAPES + 1):
|
||||
mf["title"] = "Etape Apogée (%d)" % n
|
||||
mf["title"] = f"Etape Apogée ({n})"
|
||||
modform.append(("etape_apo" + str(n), mf.copy()))
|
||||
modform.append(
|
||||
(
|
||||
@ -443,15 +440,19 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
)
|
||||
)
|
||||
if edit:
|
||||
formtit = (
|
||||
"""
|
||||
<p><a href="formsemestre_edit_uecoefs?formsemestre_id=%s">Modifier les coefficients des UE capitalisées</a></p>
|
||||
<h3>Sélectionner les modules, leurs responsables et les étudiants à inscrire:</h3>
|
||||
formtit = f"""
|
||||
<p><a href="formsemestre_edit_uecoefs?formsemestre_id={formsemestre_id}"
|
||||
>Modifier les coefficients des UE capitalisées</a></p>
|
||||
<h3>Sélectionner les modules, leurs responsables et les étudiants
|
||||
à inscrire:</h3>
|
||||
"""
|
||||
% formsemestre_id
|
||||
)
|
||||
else:
|
||||
formtit = """<h3>Sélectionner les modules et leurs responsables</h3><p class="help">Si vous avez des parcours (options), ne sélectionnez que les modules du tronc commun.</p>"""
|
||||
formtit = """<h3>Sélectionner les modules et leurs responsables</h3>
|
||||
<p class="help">Si vous avez des parcours (options), dans un premier
|
||||
ne sélectionnez que les modules du tronc commun, puis après inscriptions,
|
||||
revenez ajouter les modules de parcours en sélectionnant les groupes d'étudiants
|
||||
à y inscrire.
|
||||
</p>"""
|
||||
|
||||
modform += [
|
||||
(
|
||||
@ -531,12 +532,52 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
"explanation": "empêcher le calcul des moyennes d'UE et générale.",
|
||||
},
|
||||
),
|
||||
]
|
||||
# Choix des parcours
|
||||
if is_apc:
|
||||
ref_comp = formation.referentiel_competence
|
||||
if ref_comp:
|
||||
modform += [
|
||||
(
|
||||
"parcours",
|
||||
{
|
||||
"input_type": "checkbox",
|
||||
"vertical": True,
|
||||
"dom_id": "tf_module_parcours",
|
||||
"labels": [parcour.libelle for parcour in ref_comp.parcours],
|
||||
"allowed_values": [
|
||||
str(parcour.id) for parcour in ref_comp.parcours
|
||||
],
|
||||
"explanation": "Parcours proposés dans ce semestre.",
|
||||
},
|
||||
)
|
||||
]
|
||||
if edit:
|
||||
sem["parcours"] = [str(parcour.id) for parcour in formsemestre.parcours]
|
||||
else:
|
||||
modform += [
|
||||
(
|
||||
"parcours",
|
||||
{
|
||||
"input_type": "separator",
|
||||
"title": f"""<span class="fontred">{scu.EMO_WARNING }
|
||||
Pas de parcours:
|
||||
<a class="stdlink" href="{ url_for('notes.ue_table',
|
||||
scodoc_dept=g.scodoc_dept, formation_id=formation.id)
|
||||
}">vérifier la formation</a>
|
||||
</span>""",
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
# Choix des modules
|
||||
modform += [
|
||||
(
|
||||
"sep",
|
||||
{
|
||||
"input_type": "separator",
|
||||
"title": "",
|
||||
"template": "</table>%s<table>" % formtit,
|
||||
"template": f"</table>{formtit}<table>",
|
||||
},
|
||||
),
|
||||
]
|
||||
@ -544,8 +585,8 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
nbmod = 0
|
||||
|
||||
for semestre_id in semestre_ids:
|
||||
if formation.is_apc():
|
||||
# pour restreindre l'édition aux module du semestre sélectionné
|
||||
if is_apc:
|
||||
# pour restreindre l'édition aux modules du semestre sélectionné
|
||||
tr_class = f'class="sem{semestre_id}"'
|
||||
else:
|
||||
tr_class = ""
|
||||
@ -560,7 +601,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
"sep",
|
||||
{
|
||||
"input_type": "separator",
|
||||
"title": "<b>Semestre %s</b>" % semestre_id,
|
||||
"title": f"<b>Semestre {semestre_id}</b>",
|
||||
"template": templ_sep,
|
||||
},
|
||||
)
|
||||
@ -568,13 +609,13 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
for mod in mods:
|
||||
if mod["semestre_id"] == semestre_id and (
|
||||
(not edit) # creation => tous modules
|
||||
or (not formation.is_apc()) # pas BUT, on peut mixer les semestres
|
||||
or (not is_apc) # pas BUT, on peut mixer les semestres
|
||||
or (semestre_id == formsemestre.semestre_id) # module du semestre
|
||||
or (mod["module_id"] in module_ids_set) # module déjà présent
|
||||
):
|
||||
nbmod += 1
|
||||
if edit:
|
||||
select_name = "%s!group_id" % mod["module_id"]
|
||||
select_name = f"{mod['module_id']}!group_id"
|
||||
|
||||
def opt_selected(gid):
|
||||
if gid == vals.get(select_name):
|
||||
@ -603,13 +644,16 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
group["group_name"],
|
||||
)
|
||||
fcg += "</select>"
|
||||
itemtemplate = (
|
||||
f"""<tr {tr_class}><td class="tf-fieldlabel">%(label)s</td><td class="tf-field">%(elem)s</td><td>"""
|
||||
+ fcg
|
||||
+ "</td></tr>"
|
||||
)
|
||||
itemtemplate = f"""<tr {tr_class}>
|
||||
<td class="tf-fieldlabel">%(label)s</td>
|
||||
<td class="tf-field">%(elem)s</td>
|
||||
<td>{fcg}</td>
|
||||
</tr>"""
|
||||
else:
|
||||
itemtemplate = f"""<tr {tr_class}><td class="tf-fieldlabel">%(label)s</td><td class="tf-field">%(elem)s</td></tr>"""
|
||||
itemtemplate = f"""<tr {tr_class}>
|
||||
<td class="tf-fieldlabel">%(label)s</td>
|
||||
<td class="tf-field">%(elem)s</td>
|
||||
</tr>"""
|
||||
modform.append(
|
||||
(
|
||||
"MI" + str(mod["module_id"]),
|
||||
@ -742,7 +786,8 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
for module_id in tf[2]["tf-checked"]:
|
||||
mod_resp_id = User.get_user_id_from_nomplogin(tf[2][module_id])
|
||||
if mod_resp_id is None:
|
||||
# Si un module n'a pas de responsable (ou inconnu), l'affecte au 1er directeur des etudes:
|
||||
# Si un module n'a pas de responsable (ou inconnu),
|
||||
# l'affecte au 1er directeur des etudes:
|
||||
mod_resp_id = tf[2]["responsable_id"]
|
||||
tf[2][module_id] = mod_resp_id
|
||||
|
||||
@ -763,7 +808,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
module_ids_checked = [int(x[2:]) for x in tf[2]["tf-checked"]]
|
||||
_formsemestre_check_ue_bonus_unicity(module_ids_checked)
|
||||
if not edit:
|
||||
if formation.is_apc():
|
||||
if is_apc:
|
||||
_formsemestre_check_module_list(
|
||||
module_ids_checked, tf[2]["semestre_id"]
|
||||
)
|
||||
@ -777,14 +822,6 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
"responsable_id": tf[2][f"MI{module_id}"],
|
||||
}
|
||||
_ = sco_moduleimpl.do_moduleimpl_create(modargs)
|
||||
flash("Nouveau semestre créé")
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"notes.formsemestre_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre_id,
|
||||
)
|
||||
)
|
||||
else:
|
||||
# Modification du semestre:
|
||||
# on doit creer les modules nouvellement selectionnés
|
||||
@ -794,7 +831,7 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
module_ids_tocreate = [
|
||||
x for x in module_ids_checked if not x in module_ids_existing
|
||||
]
|
||||
if formation.is_apc():
|
||||
if is_apc:
|
||||
_formsemestre_check_module_list(
|
||||
module_ids_tocreate, tf[2]["semestre_id"]
|
||||
)
|
||||
@ -868,27 +905,46 @@ def do_formsemestre_createwithmodules(edit=False):
|
||||
modargs, formsemestre_id=formsemestre_id
|
||||
)
|
||||
mod = sco_edit_module.module_list({"module_id": module_id})[0]
|
||||
|
||||
if msg:
|
||||
msg_html = (
|
||||
'<div class="ue_warning"><span>Attention !<ul><li>'
|
||||
+ "</li><li>".join(msg)
|
||||
+ "</li></ul></span></div>"
|
||||
)
|
||||
if ok:
|
||||
msg_html += "<p>Modification effectuée</p>"
|
||||
else:
|
||||
msg_html += "<p>Modification effectuée (<b>mais modules cités non supprimés</b>)</p>"
|
||||
msg_html += (
|
||||
'<a href="formsemestre_status?formsemestre_id=%s">retour au tableau de bord</a>'
|
||||
% formsemestre_id
|
||||
)
|
||||
return msg_html
|
||||
# --- Assocation des parcours
|
||||
formsemestre = FormSemestre.query.get(formsemestre_id)
|
||||
if "parcours" in tf[2]:
|
||||
formsemestre.parcours = [
|
||||
ApcParcours.query.get(int(parcour_id_str))
|
||||
for parcour_id_str in tf[2]["parcours"]
|
||||
]
|
||||
db.session.add(formsemestre)
|
||||
db.session.commit()
|
||||
# --- Fin
|
||||
if edit:
|
||||
if msg:
|
||||
msg_html = (
|
||||
'<div class="ue_warning"><span>Attention !<ul><li>'
|
||||
+ "</li><li>".join(msg)
|
||||
+ "</li></ul></span></div>"
|
||||
)
|
||||
if ok:
|
||||
msg_html += "<p>Modification effectuée</p>"
|
||||
else:
|
||||
return flask.redirect(
|
||||
"formsemestre_status?formsemestre_id=%s&head_message=Semestre modifié"
|
||||
% formsemestre_id
|
||||
)
|
||||
msg_html += "<p>Modification effectuée (<b>mais modules cités non supprimés</b>)</p>"
|
||||
msg_html += (
|
||||
'<a href="formsemestre_status?formsemestre_id=%s">retour au tableau de bord</a>'
|
||||
% formsemestre_id
|
||||
)
|
||||
return msg_html
|
||||
else:
|
||||
return flask.redirect(
|
||||
"formsemestre_status?formsemestre_id=%s&head_message=Semestre modifié"
|
||||
% formsemestre_id
|
||||
)
|
||||
else:
|
||||
flash("Nouveau semestre créé")
|
||||
return flask.redirect(
|
||||
url_for(
|
||||
"notes.formsemestre_status",
|
||||
scodoc_dept=g.scodoc_dept,
|
||||
formsemestre_id=formsemestre_id,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _formsemestre_check_module_list(module_ids, semestre_idx):
|
||||
|
@ -929,10 +929,18 @@ def formsemestre_status_head(formsemestre_id=None, page_title=None):
|
||||
}</tt></b>)"""
|
||||
)
|
||||
H.append("</td></tr>")
|
||||
if sem.parcours:
|
||||
H.append(
|
||||
f"""
|
||||
<tr><td class="fichetitre2">Parcours: </td>
|
||||
<td style="color: blue;">{', '.join(parcours.code for parcours in sem.parcours)}</td>
|
||||
</tr>
|
||||
"""
|
||||
)
|
||||
|
||||
evals = sco_evaluations.do_evaluation_etat_in_sem(formsemestre_id)
|
||||
H.append(
|
||||
'<tr><td class="fichetitre2">Evaluations: </td><td> %(nb_evals_completes)s ok, %(nb_evals_en_cours)s en cours, %(nb_evals_vides)s vides'
|
||||
'<tr><td class="fichetitre2">Évaluations: </td><td> %(nb_evals_completes)s ok, %(nb_evals_en_cours)s en cours, %(nb_evals_vides)s vides'
|
||||
% evals
|
||||
)
|
||||
if evals["last_modif"]:
|
||||
|
@ -2206,7 +2206,7 @@ ul.notes_module_list {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
div#ue_choix_niveau {
|
||||
div.ue_choix_niveau {
|
||||
background-color: rgb(191, 242, 255);
|
||||
border: 1px solid blue;
|
||||
border-radius: 10px;
|
||||
|
8
app/static/js/module_edit.js
Normal file
8
app/static/js/module_edit.js
Normal file
@ -0,0 +1,8 @@
|
||||
/* Page édition module */
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
});
|
||||
|
||||
|
@ -6,11 +6,25 @@
|
||||
<h1>Associer un référentiel de compétences</h1>
|
||||
<div class="help">
|
||||
Association d'un référentiel de compétence à la formation
|
||||
{{formation.titre}} ({{formation.acronyme}})
|
||||
<a href="{{
|
||||
url_for('notes.ue_table', scodoc_dept=g.scodoc_dept, formation_id=formation.id)
|
||||
}}">{{formation.titre}} ({{formation.acronyme}})</a>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
{{ wtf.quick_form(form) }}
|
||||
<div style="margin-top: 20px; margin-bottom: 20px;">
|
||||
|
||||
Référentiel actuellement associé:
|
||||
{% if formation.referentiel_competence is not none %}
|
||||
<b>{{ formation.referentiel_competence.specialite_long }}</b>
|
||||
<a href="{{
|
||||
url_for('notes.refcomp_desassoc_formation', scodoc_dept=g.scodoc_dept, formation_id=formation.id)
|
||||
}}" class="stdlink">supprimer</a>
|
||||
{% else %}
|
||||
<b>aucun</b>
|
||||
{% endif %}
|
||||
<div class="row" style="margin-top: 20px;">
|
||||
<div class="col-md-4">
|
||||
{{ wtf.quick_form(form) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -160,6 +160,20 @@ def refcomp_assoc_formation(formation_id: int):
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/referentiel/comp/desassoc_formation/<int:formation_id>", methods=["GET"])
|
||||
@scodoc
|
||||
@permission_required(Permission.ScoChangeFormation)
|
||||
def refcomp_desassoc_formation(formation_id: int):
|
||||
"""Désassocie la formation de son ref. de compétence"""
|
||||
formation = Formation.query.get_or_404(formation_id)
|
||||
formation.referentiel_competence = None
|
||||
db.session.add(formation)
|
||||
db.session.commit()
|
||||
return redirect(
|
||||
url_for("notes.ue_table", scodoc_dept=g.scodoc_dept, formation_id=formation.id)
|
||||
)
|
||||
|
||||
|
||||
@bp.route(
|
||||
"/referentiel/comp/load", defaults={"formation_id": None}, methods=["GET", "POST"]
|
||||
)
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- mode: python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
SCOVERSION = "9.2.22"
|
||||
SCOVERSION = "9.3a"
|
||||
|
||||
SCONAME = "ScoDoc"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user