diff --git a/app/scodoc/sco_assiduites.py b/app/scodoc/sco_assiduites.py
index f085a83f4cc7189c930a7b69a3604d76301e1d38..c8c4b7943117480a217276ca4f1a61f08a67685b 100644
--- a/app/scodoc/sco_assiduites.py
+++ b/app/scodoc/sco_assiduites.py
@@ -935,57 +935,35 @@ def get_assiduites_count_in_interval(
     return (nb_abs_nj, nb_abs_just, nb_abs)
 
 
-def invalidate_assiduites_count(etudid: int, sem: dict):
+def invalidate_assiduites_count(etudid: int, fs: FormSemestre):
     """Invalidate (clear) cached counts"""
-    date_debut = sem["date_debut_iso"]
-    date_fin = sem["date_fin_iso"]
-    key = str(etudid) + "_" + date_debut + "_" + date_fin + "_assiduites"
+    key = f"{etudid}_{fs.date_debut.isoformat()}_{fs.date_fin.isoformat()}_assiduites"
     sco_cache.AbsSemEtudCache.delete(key)
 
 
-# Non utilisé
-def invalidate_assiduites_count_sem(sem: dict):
-    """Invalidate (clear) cached abs counts for all the students of this semestre"""
-    inscriptions = (
-        sco_formsemestre_inscriptions.do_formsemestre_inscription_listinscrits(
-            sem["formsemestre_id"]
-        )
-    )
-    for ins in inscriptions:
-        invalidate_assiduites_count(ins["etudid"], sem)
-
-
 def invalidate_assiduites_etud_date(etudid: int, the_date: datetime):
     """Doit etre appelé à chaque modification des assiduites
     pour cet étudiant et cette date.
     Invalide cache absence et caches semestre
     """
-
-    # Semestres a cette date:
-    etud = sco_etud.get_etud_info(etudid=etudid, filled=True)
-    if len(etud) == 0:
+    etud = Identite.get_etud(etudid, accept_none=True)
+    if not etud:
         return
-    else:
-        etud = etud[0]
-    sems = [
-        sem
-        for sem in etud["sems"]
-        if scu.is_iso_formated(sem["date_debut_iso"], True).replace(tzinfo=UTC)
-        <= the_date.replace(tzinfo=UTC)
-        and scu.is_iso_formated(sem["date_fin_iso"], True).replace(tzinfo=UTC)
-        >= the_date.replace(tzinfo=UTC)
+    the_day = the_date.replace(tzinfo=UTC).day
+    # Semestres de l'étudiant à cette date:
+    formsemestres = [
+        ins.formsemestre
+        for ins in etud.formsemestre_inscriptions
+        if ins.formsemestre.date_debut <= the_day <= ins.formsemestre.date_fin
     ]
-
     # Invalide les PDF et les absences:
-    for sem in sems:
+    for formsemestre in formsemestres:
         # Inval cache bulletin et/ou note_table
         # efface toujours le PDF car il affiche en général les absences
-        sco_cache.invalidate_formsemestre(
-            formsemestre_id=sem["formsemestre_id"], pdfonly=True
-        )
+        sco_cache.invalidate_formsemestre(formsemestre_id=formsemestre.id, pdfonly=True)
 
         # Inval cache compteurs absences:
-        invalidate_assiduites_count(etudid, sem)
+        invalidate_assiduites_count(etudid, formsemestre)
 
 
 def simple_invalidate_cache(obj: dict, etudid: str | int = None):
diff --git a/app/scodoc/sco_cache.py b/app/scodoc/sco_cache.py
index a64dd76146ee1c1d8e5956af60fe2e366a0efc8c..caf1187c825e07add95556db430fa070953ee6e9 100644
--- a/app/scodoc/sco_cache.py
+++ b/app/scodoc/sco_cache.py
@@ -193,7 +193,8 @@ class AbsSemEtudCache(ScoDocCache):
     C'est pourquoi il expire après timeout secondes.
     Le timeout evite aussi d'éliminer explicitement ces éléments cachés lors
     des suppressions d'étudiants ou de semestres.
-    Clé: etudid + "_" + date_debut + "_" + date_fin
+
+    Clé: etudid + "_" + date_debut_iso + "_" + date_fin_iso
     Valeur: (nb_abs, nb_abs_just)
     """
 
@@ -225,8 +226,16 @@ class SemBulletinsPDFCache(ScoDocCache):
 class SemInscriptionsCache(ScoDocCache):
     """Cache les inscriptions à un semestre.
     Clé: formsemestre_id
-    Valeur: liste d'inscriptions
-    [ {'formsemestre_inscription_id': 'SI78677', 'etudid': '1234', 'formsemestre_id': 'SEM012', 'etat': 'I', 'etape': ''}, ... ]
+    Valeur: liste d'inscriptions.
+    Exemple:
+    [ {'formsemestre_inscription_id': '78677',
+       'etudid': '1234',
+       'formsemestre_id': '4567',
+       'etat': 'I',
+       'etape': '',
+       "parcour_id" : 4,
+       },
+       ... ]
     """
 
     prefix = "SI"
diff --git a/app/scodoc/sco_formsemestre_inscriptions.py b/app/scodoc/sco_formsemestre_inscriptions.py
index c0cec9ac517e23fa443f469b0d9db65e75c62dd4..77b9eb7c9df2ff23244c6b2de5d4a8d3bae48d0d 100644
--- a/app/scodoc/sco_formsemestre_inscriptions.py
+++ b/app/scodoc/sco_formsemestre_inscriptions.py
@@ -77,7 +77,7 @@ def do_formsemestre_inscription_list(*args, **kw):
 
 def do_formsemestre_inscription_listinscrits(formsemestre_id):
     """Liste les inscrits (état I) à ce semestre et cache le résultat.
-    Result: [ { "etudid":, "formsemestre_id": , "etat": , "etape": }]
+    Result: [ { "etudid":, "formsemestre_id": , "etat": , "etape": , "parcour_id":}]
     """
     r = sco_cache.SemInscriptionsCache.get(formsemestre_id)
     if r is None:
diff --git a/app/scodoc/sco_report.py b/app/scodoc/sco_report.py
index 1b77beeac33dc979b910ef98c0c0b0c83c16189d..f35cfa62bb6abb559d1b74fd2d7f11b294739dcd 100644
--- a/app/scodoc/sco_report.py
+++ b/app/scodoc/sco_report.py
@@ -75,7 +75,7 @@ def formsemestre_etuds_stats(
     formsemestre: FormSemestre,
     only_primo=False,
     groups_infos: sco_groups_view.DisplayedGroupsInfos | None = None,
-):
+) -> list[dict]:
     """Récupère liste d'etudiants avec etat et decision."""
     nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
     etudids = groups_infos.get_etudids() if groups_infos else set()
@@ -90,17 +90,18 @@ def formsemestre_etuds_stats(
         etudid = t[-1]
         if etudids and etudid not in etudids:
             continue
-        etudiant = Identite.get_etud(etudid)
-        etud = sco_etud.get_etud_info(etudid=etudid, filled=True)[0]
-        etud["annee_admission"] = etud["annee"]  # plus explicite
+        etud = Identite.get_etud(etudid)
+        e_dict = etud.to_dict_scodoc7()
+        e_dict |= etud.admission.to_dict()
+        e_dict["annee_admission"] = etud.admission.annee  # plus explicite
         decision = nt.get_etud_decision_sem(etudid)
         if decision:
-            etud["codedecision"] = decision["code"]
-        etud["etat"] = nt.get_etud_etat(etudid)
-        if etud["etat"] == "D":
-            etud["codedecision"] = "DEM"
-        if "codedecision" not in etud:
-            etud["codedecision"] = "(nd)"  # pas de decision jury
+            e_dict["codedecision"] = decision["code"]
+        e_dict["etat"] = nt.get_etud_etat(etudid)
+        if e_dict["etat"] == "D":
+            e_dict["codedecision"] = "DEM"
+        if "codedecision" not in e_dict:
+            e_dict["codedecision"] = "(nd)"  # pas de decision jury
         # Ajout devenir (autorisations inscriptions), utile pour stats passage
         aut_list = ScolarAutorisationInscription.query.filter_by(
             etudid=etudid, origin_formsemestre_id=formsemestre.id
@@ -108,22 +109,22 @@ def formsemestre_etuds_stats(
         autorisations = [f"S{a.semestre_id}" for a in aut_list]
         autorisations.sort()
         autorisations_str = ", ".join(autorisations)
-        etud["devenir"] = autorisations_str
+        e_dict["devenir"] = autorisations_str
         # Décisions de jury BUT (APC)
         if jury_but_mode:
-            deca = jury_but.DecisionsProposeesAnnee(etudiant, formsemestre)
-            etud["nb_rcue_valides"] = deca.nb_rcue_valides
-            etud["decision_annee"] = deca.code_valide
+            deca = jury_but.DecisionsProposeesAnnee(etud, formsemestre)
+            e_dict["nb_rcue_valides"] = deca.nb_rcue_valides
+            e_dict["decision_annee"] = deca.code_valide
         # Ajout clé 'bac-specialite'
         bs = []
-        if etud["bac"]:
-            bs.append(etud["bac"])
-        if etud["specialite"]:
-            bs.append(etud["specialite"])
-        etud["bac-specialite"] = " ".join(bs)
+        if e_dict["bac"]:
+            bs.append(e_dict["bac"])
+        if e_dict["specialite"]:
+            bs.append(e_dict["specialite"])
+        e_dict["bac-specialite"] = " ".join(bs)
         #
-        if (not only_primo) or is_primo_etud(etud, formsemestre):
-            etuds.append(etud)
+        if (not only_primo) or is_primo_etud(e_dict, formsemestre):
+            etuds.append(e_dict)
     return etuds
 
 
diff --git a/app/views/assiduites.py b/app/views/assiduites.py
index 70cf79dc4ad8f4fb29d88ed2f9863effff2012d1..70182f03defe3265dcfcff2f3226bd41f3dc43f4 100644
--- a/app/views/assiduites.py
+++ b/app/views/assiduites.py
@@ -1081,12 +1081,6 @@ def signal_assiduites_group():
     if formsemestre.dept_id != g.scodoc_dept_id:
         abort(404, "groupes inexistants dans ce département")
 
-    # Récupération des étudiants des groupes
-    etuds = [
-        sco_etud.get_etud_info(etudid=m["etudid"], filled=True)[0]
-        for m in groups_infos.members
-    ]
-
     # --- Vérification de la date ---
     real_date = scu.is_iso_formated(date, True).date()
 
@@ -1111,23 +1105,13 @@ def signal_assiduites_group():
             titre="Choix de la date",
         )
 
-    # --- Restriction en fonction du moduleimpl_id ---
+    # Si module préselectionné et aucun étudiant inscrit, le déselectionne
     if moduleimpl_id:
-        mod_inscrits = {
-            x["etudid"]
-            for x in sco_moduleimpl.do_moduleimpl_inscription_list(
-                moduleimpl_id=moduleimpl_id
-            )
-        }
-        etuds_inscrits_module = [e for e in etuds if e["etudid"] in mod_inscrits]
-        if etuds_inscrits_module:
-            etuds = etuds_inscrits_module
-        else:
-            # Si aucun etudiant n'est inscrit au module choisi...
+        modimpl = ModuleImpl.get_modimpl(moduleimpl_id)
+        if not modimpl.inscriptions:
             moduleimpl_id = None
 
     # Récupération du nom des/du groupe(s)
-
     if groups_infos.tous_les_etuds_du_sem:
         gr_tit = "en"
     else:
@@ -1139,9 +1123,6 @@ def signal_assiduites_group():
             grp + ' <span class="fontred">' + groups_infos.groups_titles + "</span>"
         )
 
-    # Récupération du semestre en dictionnaire
-    sem = formsemestre.to_dict()
-
     # Page HTML
     return render_template(
         "assiduites/pages/signal_assiduites_group.j2",
@@ -1167,7 +1148,7 @@ def signal_assiduites_group():
         nonworkdays=_non_work_days(),
         readonly="false",
         sco=ScoData(formsemestre=formsemestre),
-        sem=sem["titre_num"],
+        sem=formsemestre.titre_num(),
         timeline=_timeline(heures=",".join([f"'{s}'" for s in heures])),
         title="Saisie de l'assiduité",
     )
diff --git a/tests/unit/test_assiduites.py b/tests/unit/test_assiduites.py
index 1ca1579cf7dba8a8319d8ba0231f076562a0e363..4046717175d99ced7092ff3aeb3d9685c05f5a5d 100644
--- a/tests/unit/test_assiduites.py
+++ b/tests/unit/test_assiduites.py
@@ -1724,7 +1724,7 @@ def test_cache_assiduites(test_client):
     assert scass.get_assiduites_count(etud.id, formsemestre2.to_dict()) == (2, 1, 3)
 
     # On invalide maintenant le cache
-    scass.invalidate_assiduites_count(etud.id, formsemestre1.to_dict())
+    scass.invalidate_assiduites_count(etud.id, formsemestre1)
 
     # Premier semestre 3nj / 2j / 5t (Change car cache invalidé)
     assert scass.get_assiduites_count(etud.id, formsemestre1.to_dict()) == (3, 2, 5)