diff --git a/app/models/but_refcomp.py b/app/models/but_refcomp.py
index 3b28676514..b585019753 100644
--- a/app/models/but_refcomp.py
+++ b/app/models/but_refcomp.py
@@ -286,6 +286,21 @@ class ApcNiveau(db.Model, XMLModel):
)
+app_critiques_modules = db.Table(
+ "apc_modules_acs",
+ db.Column(
+ "module_id",
+ db.ForeignKey("notes_modules.id", ondelete="CASCADE"),
+ primary_key=True,
+ ),
+ db.Column(
+ "app_crit_id",
+ db.ForeignKey("apc_app_critique.id"),
+ primary_key=True,
+ ),
+)
+
+
class ApcAppCritique(db.Model, XMLModel):
"Apprentissage Critique BUT"
id = db.Column(db.Integer, primary_key=True)
@@ -293,12 +308,31 @@ class ApcAppCritique(db.Model, XMLModel):
code = db.Column(db.Text(), nullable=False, index=True)
libelle = db.Column(db.Text())
- modules = db.relationship(
- "Module",
- secondary="apc_modules_acs",
- lazy="dynamic",
- backref=db.backref("app_critiques", lazy="dynamic"),
- )
+ # modules = db.relationship(
+ # "Module",
+ # secondary="apc_modules_acs",
+ # lazy="dynamic",
+ # backref=db.backref("app_critiques", lazy="dynamic"),
+ # )
+
+ @classmethod
+ def app_critiques_ref_comp(
+ cls,
+ ref_comp: ApcReferentielCompetences,
+ annee: str,
+ competence: ApcCompetence = None,
+ ) -> flask_sqlalchemy.BaseQuery:
+ "Liste les AC de tous les parcours de ref_comp pour l'année indiquée"
+ assert annee in {"BUT1", "BUT2", "BUT3"}
+ query = cls.query.filter(
+ ApcAppCritique.niveau_id == ApcNiveau.id,
+ ApcNiveau.competence_id == ApcCompetence.id,
+ ApcNiveau.annee == annee,
+ ApcCompetence.referentiel_id == ref_comp.id,
+ )
+ if competence is not None:
+ query = query.filter(ApcNiveau.competence == competence)
+ return query
def to_dict(self) -> dict:
return {"libelle": self.libelle}
@@ -314,13 +348,6 @@ class ApcAppCritique(db.Model, XMLModel):
return [m for m in self.modules if m.module_type == ModuleType.SAE]
-ApcAppCritiqueModules = db.Table(
- "apc_modules_acs",
- db.Column("module_id", db.ForeignKey("notes_modules.id")),
- db.Column("app_crit_id", db.ForeignKey("apc_app_critique.id")),
-)
-
-
parcours_modules = db.Table(
"parcours_modules",
db.Column(
@@ -350,11 +377,6 @@ class ApcParcours(db.Model, XMLModel):
lazy="dynamic",
cascade="all, delete-orphan",
)
- # modules = db.relationship(
- # "Module",
- # secondary=parcours_modules,
- # back_populates="parcours",
- # )
def __repr__(self):
return f"<{self.__class__.__name__} {self.code}>"
diff --git a/app/models/modules.py b/app/models/modules.py
index 5ffac90435..28ef949b88 100644
--- a/app/models/modules.py
+++ b/app/models/modules.py
@@ -3,7 +3,7 @@
from app import db
from app.models import APO_CODE_STR_LEN
-from app.models.but_refcomp import parcours_modules
+from app.models.but_refcomp import app_critiques_modules, parcours_modules
from app.scodoc import sco_utils as scu
from app.scodoc.sco_codes_parcours import UE_SPORT
from app.scodoc.sco_utils import ModuleType
@@ -50,7 +50,13 @@ class Module(db.Model):
"ApcParcours",
secondary=parcours_modules,
lazy="subquery",
- # cascade="all, delete",
+ backref=db.backref("modules", lazy=True),
+ )
+
+ app_critiques = db.relationship(
+ "ApcAppCritique",
+ secondary=app_critiques_modules,
+ lazy="subquery",
backref=db.backref("modules", lazy=True),
)
diff --git a/app/scodoc/sco_edit_apc.py b/app/scodoc/sco_edit_apc.py
index 11bb53af19..8cb516a5a2 100644
--- a/app/scodoc/sco_edit_apc.py
+++ b/app/scodoc/sco_edit_apc.py
@@ -127,7 +127,7 @@ def html_edit_formation_apc(
formation=formation,
titre=f"Ressources du S{semestre_idx}",
create_element_msg="créer une nouvelle ressource",
- matiere_parent=matiere_parent,
+ # matiere_parent=matiere_parent,
modules=ressources_in_sem,
module_type=ModuleType.RESSOURCE,
editable=editable,
@@ -143,7 +143,7 @@ def html_edit_formation_apc(
formation=formation,
titre=f"Situations d'Apprentissage et d'Évaluation (SAÉs) S{semestre_idx}",
create_element_msg="créer une nouvelle SAÉ",
- matiere_parent=matiere_parent,
+ # matiere_parent=matiere_parent,
modules=saes_in_sem,
module_type=ModuleType.SAE,
editable=editable,
diff --git a/app/scodoc/sco_edit_module.py b/app/scodoc/sco_edit_module.py
index 2317d8b4ce..d986c60e06 100644
--- a/app/scodoc/sco_edit_module.py
+++ b/app/scodoc/sco_edit_module.py
@@ -39,7 +39,7 @@ from app.models import APO_CODE_STR_LEN
from app.models import Formation, Matiere, Module, UniteEns
from app.models import FormSemestre, ModuleImpl
from app.models import ScolarNews
-from app.models.but_refcomp import ApcParcours
+from app.models.but_refcomp import ApcAppCritique, ApcParcours
import app.scodoc.notesdb as ndb
import app.scodoc.sco_utils as scu
@@ -272,6 +272,7 @@ def module_edit(
# --- Détermination de la formation
orig_semestre_idx = None
+ ue = None
if create:
if matiere_id:
matiere = Matiere.query.get_or_404(matiere_id)
@@ -286,6 +287,7 @@ def module_edit(
if not module_id:
raise ValueError("missing module_id !")
module = models.Module.query.get_or_404(module_id)
+ ue = module.ue
module_dict = module.to_dict()
formation = module.formation
unlocked = not module_is_locked(module_id)
@@ -633,8 +635,9 @@ def module_edit(
},
),
]
- # Choix des parcours
+
if is_apc:
+ # Choix des parcours
ref_comp = formation.referentiel_competence
if ref_comp:
descr += [
@@ -656,13 +659,54 @@ def module_edit(
module_dict["parcours"] = [
str(parcour.id) for parcour in module.parcours
]
+ module_dict["app_critiques"] = [
+ str(app_crit.id) for app_crit in module.app_critiques
+ ]
+ # Choix des Apprentissages Critiques
+ if ue is not None:
+ annee = f"BUT{orig_semestre_idx//2 + 1}"
+ app_critiques = ApcAppCritique.app_critiques_ref_comp(ref_comp, annee)
+ descr += (
+ [
+ (
+ "app_critiques",
+ {
+ "title": "Apprentissages Critiques",
+ "input_type": "checkbox",
+ "vertical": True,
+ "dom_id": "tf_module_app_critiques",
+ "labels": [
+ 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.",
+ },
+ )
+ ]
+ if (ue.niveau_competence is not None)
+ else [
+ (
+ "app_critiques",
+ {
+ "input_type": "separator",
+ "title": f"""{scu.EMO_WARNING }
+ L'UE {ue.acronyme} {ue.titre}
+ n'est pas associée à un niveau de compétences
+ """,
+ },
+ )
+ ]
+ )
else:
descr += [
(
"parcours",
{
"input_type": "separator",
- "title": f"""Pas de parcours:
+ "title": f"""{scu.EMO_WARNING }
+ Pas de parcours:
associer un référentiel de compétence
@@ -748,10 +792,17 @@ def module_edit(
#
do_module_edit(tf[2])
# Modifie les parcours
- module.parcours = [
- ApcParcours.query.get(int(parcour_id_str))
- for parcour_id_str in tf[2]["parcours"]
- ]
+ if "parcours" in tf[2]:
+ 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 = [
+ ApcAppCritique.query.get(int(ac_id_str))
+ for ac_id_str in tf[2]["app_critiques"]
+ ]
db.session.add(module)
db.session.commit()
return flask.redirect(
diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css
index 170d191744..c9933ffb58 100644
--- a/app/static/css/scodoc.css
+++ b/app/static/css/scodoc.css
@@ -2271,6 +2271,10 @@ tr#tf_module_parcours>td {
background-color: rgb(229, 229, 229);
}
+tr#tf_module_app_critiques>td {
+ background-color: rgb(194, 209, 228);
+}
+
/* tableau recap notes */
table.notes_recapcomplet {
border: 2px solid blue;
diff --git a/migrations/versions/6002d7d366e5_assoc_ue_niveau.py b/migrations/versions/6002d7d366e5_assoc_ue_niveau.py
index cf6c5932e2..7448ab60fa 100644
--- a/migrations/versions/6002d7d366e5_assoc_ue_niveau.py
+++ b/migrations/versions/6002d7d366e5_assoc_ue_niveau.py
@@ -47,6 +47,23 @@ def upgrade():
),
sa.PrimaryKeyConstraint("parcours_id", "module_id"),
)
+ op.alter_column(
+ "apc_modules_acs", "module_id", existing_type=sa.INTEGER(), nullable=False
+ )
+ op.alter_column(
+ "apc_modules_acs", "app_crit_id", existing_type=sa.INTEGER(), nullable=False
+ )
+ op.drop_constraint(
+ "apc_modules_acs_module_id_fkey", "apc_modules_acs", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_modules_acs_module_id_fkey",
+ "apc_modules_acs",
+ "notes_modules",
+ ["module_id"],
+ ["id"],
+ ondelete="CASCADE",
+ )
# ### end Alembic commands ###
@@ -57,4 +74,20 @@ def downgrade():
)
op.drop_column("notes_ue", "niveau_competence_id")
op.drop_table("parcours_modules")
+ op.drop_constraint(
+ "apc_modules_acs_module_id_fkey", "apc_modules_acs", type_="foreignkey"
+ )
+ op.create_foreign_key(
+ "apc_modules_acs_module_id_fkey",
+ "apc_modules_acs",
+ "notes_modules",
+ ["module_id"],
+ ["id"],
+ )
+ op.alter_column(
+ "apc_modules_acs", "app_crit_id", existing_type=sa.INTEGER(), nullable=True
+ )
+ op.alter_column(
+ "apc_modules_acs", "module_id", existing_type=sa.INTEGER(), nullable=True
+ )
# ### end Alembic commands ###