diff --git a/app/but/validations_view.py b/app/but/validations_view.py
index 06145a194f4845986aae61199b1d97c84e7075a6..d05857c2afc06a1a3306d9d93edb93f664b5b879 100644
--- a/app/but/validations_view.py
+++ b/app/but/validations_view.py
@@ -25,7 +25,7 @@ from app.models import (
     ScolarFormSemestreValidation,
 )
 from app.scodoc import codes_cursus
-from app.scodoc.sco_exceptions import ScoNoReferentielCompetences
+from app.scodoc.sco_exceptions import ScoNoReferentielCompetences, ScoValueError
 from app.views import ScoData
 
 
@@ -38,6 +38,10 @@ def validation_rcues(etud: Identite, formsemestre: FormSemestre, edit: bool = Fa
     refcomp = formation.referentiel_competence
     if refcomp is None:
         raise ScoNoReferentielCompetences(formation=formation)
+    if etud.id not in formsemestre.etuds_inscriptions:
+        raise ScoValueError(
+            f"Etudiant {etud.nom_prenom()} non inscrit à {formsemestre.titre_mois()}"
+        )
     parcour = formsemestre.etuds_inscriptions[etud.id].parcour
     # Si non inscrit à un parcours, prend toutes les compétences
     competences_parcour, ects_parcours = cursus_but.parcour_formation_competences(
diff --git a/app/scodoc/sco_formsemestre_edit.py b/app/scodoc/sco_formsemestre_edit.py
index 2509739ce83fa7430c1435af815db5de01673d99..8af2d89e4b4def7ba0b0360d9d50806354e124a5 100644
--- a/app/scodoc/sco_formsemestre_edit.py
+++ b/app/scodoc/sco_formsemestre_edit.py
@@ -39,6 +39,7 @@ from app.models import (
     ApcValidationAnnee,
     ApcValidationRCUE,
     Evaluation,
+    FormationModalite,
     FormSemestreUECoef,
     Module,
     ModuleImpl,
@@ -64,7 +65,6 @@ from app.scodoc import codes_cursus
 from app.scodoc import sco_edit_module
 from app.scodoc import sco_formsemestre
 from app.scodoc import sco_groups_copy
-from app.scodoc import sco_modalites
 from app.scodoc import sco_moduleimpl
 from app.scodoc import sco_permissions_check
 from app.scodoc import sco_portal_apogee
@@ -258,15 +258,12 @@ def do_formsemestre_createwithmodules(edit=False, formsemestre: FormSemestre = N
             or m.id in module_ids_set
         ]
     # Pour regroupement des modules par semestres:
-    semestre_ids = {}
-    for mod in modules:
-        semestre_ids[mod.semestre_id] = 1
-    semestre_ids = list(semestre_ids.keys())
-    semestre_ids.sort()
-
-    modalites = sco_modalites.do_modalite_list()
-    modalites_abbrv = [m["modalite"] for m in modalites]
-    modalites_titles = [m["titre"] for m in modalites]
+    semestre_ids = sorted({mod.semestre_id for mod in modules})
+    # Liste des modalités
+    modalites_abbrv_titres = {
+        modalite.modalite: modalite.titre
+        for modalite in FormationModalite.query.order_by(FormationModalite.numero)
+    }
     #
     modform = [
         ("formsemestre_id", {"input_type": "hidden"}),
@@ -340,8 +337,8 @@ def do_formsemestre_createwithmodules(edit=False, formsemestre: FormSemestre = N
             {
                 "input_type": "menu",
                 "title": "Modalité",
-                "allowed_values": modalites_abbrv,
-                "labels": modalites_titles,
+                "allowed_values": modalites_abbrv_titres.keys(),
+                "labels": modalites_abbrv_titres.values(),
             },
         ),
         (
diff --git a/app/scodoc/sco_modalites.py b/app/scodoc/sco_modalites.py
index 075fa4476b52aa0607aa87ebe543354478eddb43..669b1c69dac299940fffaf777847c1f43c2093c4 100644
--- a/app/scodoc/sco_modalites.py
+++ b/app/scodoc/sco_modalites.py
@@ -34,21 +34,22 @@ Elle n'est pas utilisée pour les parcours, ni pour rien d'autre
 
 """
 import collections
-import app.scodoc.notesdb as ndb
-from app import log
-from app.models import FormSemestre
+from app.models import FormSemestre, FormationModalite
 
 
-def list_formsemestres_modalites(formsemestres: list[FormSemestre]) -> list[dict]:
+def _list_formsemestres_modalites(
+    formsemestres: list[FormSemestre],
+) -> list[FormationModalite]:
     """Liste ordonnée des modalités présentes dans ces formsemestres"""
     modalites = {}
     for formsemestre in formsemestres:
         if formsemestre.modalite not in modalites:
-            m = do_modalite_list(args={"modalite": formsemestre.modalite})[0]
-            modalites[m["modalite"]] = m
-    modalites = list(modalites.values())
-    modalites.sort(key=lambda x: x["numero"])
-    return modalites
+            m = FormationModalite.query.filter_by(
+                modalite=formsemestre.modalite
+            ).first()
+            if m is not None:
+                modalites[m.modalite] = m
+    return sorted(modalites.values(), key=lambda m: m.numero)
 
 
 def group_formsemestres_by_modalite(
@@ -58,18 +59,18 @@ def group_formsemestres_by_modalite(
     sorted in each one by semestre id and date
     """
     sems_by_mod = collections.defaultdict(list)
-    modalites = list_formsemestres_modalites(formsemestres)
+    modalites = _list_formsemestres_modalites(formsemestres)
     sems_by_mod = {
-        modalite["modalite"]: [
+        modalite.modalite: [
             formsemestre
             for formsemestre in formsemestres
-            if formsemestre.modalite == modalite["modalite"]
+            if formsemestre.modalite == modalite.modalite
         ]
         for modalite in modalites
     }
     # tri dans chaque modalité par indice de semestre et date debut
     for modalite in modalites:
-        sems_by_mod[modalite["modalite"]].sort(
+        sems_by_mod[modalite.modalite].sort(
             key=lambda x: (
                 x.semestre_id if x.semestre_id > 0 else -1000 * x.semestre_id,
                 x.date_debut,
@@ -77,42 +78,3 @@ def group_formsemestres_by_modalite(
         )
 
     return sems_by_mod, modalites
-
-
-# ------ Low level interface (database) ------
-
-_modaliteEditor = ndb.EditableTable(
-    "notes_form_modalites",
-    "form_modalite_id",
-    ("form_modalite_id", "modalite", "titre", "numero"),
-    sortkey="numero",
-    output_formators={"numero": ndb.int_null_is_zero},
-)
-
-
-def do_modalite_list(*args, **kw):
-    """Liste des modalites"""
-    cnx = ndb.GetDBConnexion()
-    return _modaliteEditor.list(cnx, *args, **kw)
-
-
-def do_modalite_create(args):
-    "create a modalite"
-    cnx = ndb.GetDBConnexion()
-    r = _modaliteEditor.create(cnx, args)
-    return r
-
-
-def do_modalite_delete(oid):
-    "delete a modalite"
-    cnx = ndb.GetDBConnexion()
-    log("do_modalite_delete: form_modalite_id=%s" % oid)
-    _modaliteEditor.delete(cnx, oid)
-
-
-def do_modalite_edit(*args, **kw):  # unused
-    "edit a modalite"
-    cnx = ndb.GetDBConnexion()
-    # check
-    _ = do_modalite_list({"form_modalite_id": args[0]["form_modalite_id"]})[0]
-    _modaliteEditor.edit(cnx, *args, **kw)
diff --git a/sco_version.py b/sco_version.py
index 8c0bf96692b8193c2a6dae656475156316aa5735..5b57b097930d36dfb2d09ad94154efe81ccd55c0 100644
--- a/sco_version.py
+++ b/sco_version.py
@@ -1,7 +1,7 @@
 # -*- mode: python -*-
 # -*- coding: utf-8 -*-
 
-SCOVERSION = "9.7.15"
+SCOVERSION = "9.7.16"
 
 SCONAME = "ScoDoc"