diff --git a/app/api/jury.py b/app/api/jury.py
index 6103d11649a7130373c4a11ea207eea842aaa57e..6f0710770d3333343ddd434e7380a29b75cd69c9 100644
--- a/app/api/jury.py
+++ b/app/api/jury.py
@@ -114,16 +114,16 @@ def _validation_ue_delete(etudid: int, validation_id: int):
     # rattachées à un formsemestre)
     if not g.scodoc_dept:  # accès API
         if not current_user.has_permission(Permission.ScoEtudInscrit):
-            return json_error(403, "validation_delete: non autorise")
+            return json_error(403, "opération non autorisée (117)")
     else:
         if validation.formsemestre:
             if (
                 validation.formsemestre.dept_id != g.scodoc_dept_id
             ) or not validation.formsemestre.can_edit_jury():
-                return json_error(403, "validation_delete: non autorise")
+                return json_error(403, "opération non autorisée (123)")
         elif not current_user.has_permission(Permission.ScoEtudInscrit):
             # Validation non rattachée à un semestre: on doit être chef
-            return json_error(403, "validation_delete: non autorise")
+            return json_error(403, "opération non autorisée (126)")
 
     log(f"validation_ue_delete: etuid={etudid} {validation}")
     db.session.delete(validation)
diff --git a/app/models/but_validations.py b/app/models/but_validations.py
index aedf4cbaf9db321d1567eb74330bb625c18404eb..fcab132bd0fc0d7828faa03fae781468943bee58 100644
--- a/app/models/but_validations.py
+++ b/app/models/but_validations.py
@@ -158,8 +158,16 @@ class ApcValidationAnnee(db.Model):
             if self.date
             else "(sans date)"
         )
+        link = (
+            self.formsemestre.html_link_status(
+                label=f"{self.formsemestre.titre_formation(with_sem_idx=1)}",
+                title=self.formsemestre.titre_annee(),
+            )
+            if self.formsemestre
+            else "externe/antérieure"
+        )
         return f"""Validation <b>année BUT{self.ordre}</b> émise par
-            {self.formsemestre.html_link_status() if self.formsemestre else "-"}
+            {link}
             : <b>{self.code}</b>
             {date_str}
         """
diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py
index cd296353f6e6da4cff66621e6dc0233b09193b93..64668fa16898538529e449db292d564a6f3e19a1 100644
--- a/app/models/formsemestre.py
+++ b/app/models/formsemestre.py
@@ -163,12 +163,12 @@ class FormSemestre(db.Model):
     def __repr__(self):
         return f"<{self.__class__.__name__} {self.id} {self.titre_annee()}>"
 
-    def html_link_status(self) -> str:
+    def html_link_status(self, label=None, title=None) -> str:
         "html link to status page"
         return f"""<a class="stdlink" href="{
             url_for("notes.formsemestre_status", scodoc_dept=g.scodoc_dept,
                 formsemestre_id=self.id,)
-        }">{self.titre_mois()}</a>
+        }" title="{title or ''}">{label or self.titre_mois()}</a>
         """
 
     @classmethod
diff --git a/app/models/validations.py b/app/models/validations.py
index 9e2cf5e27d58bc96e73d42800cc8c57cac261aaa..91f17f605ab429e7e0b0aa6cd35d509bf39f6716 100644
--- a/app/models/validations.py
+++ b/app/models/validations.py
@@ -94,6 +94,14 @@ class ScolarFormSemestreValidation(db.Model):
                 if self.moy_ue is not None
                 else ""
             )
+            link = (
+                self.formsemestre.html_link_status(
+                    label=f"{self.formsemestre.titre_formation(with_sem_idx=1)}",
+                    title=self.formsemestre.titre_annee(),
+                )
+                if self.formsemestre
+                else "externe/antérieure"
+            )
             return f"""Validation
                 {'<span class="redboldtext">externe</span>' if self.is_external else ""}
                 de l'UE <b>{self.ue.acronyme}</b>
@@ -101,9 +109,7 @@ class ScolarFormSemestreValidation(db.Model):
                   + ", ".join([p.code for p in self.ue.parcours]))
                   + "</span>"
                   if self.ue.parcours else ""}
-                de {self.ue.formation.acronyme}
-                {("émise par " + self.formsemestre.html_link_status()) 
-                    if self.formsemestre else "externe/antérieure"}
+                {("émise par " + link)}
                 : <b>{self.code}</b>{moyenne}
                 le {self.event_date.strftime("%d/%m/%Y")} à {self.event_date.strftime("%Hh%M")}
             """
@@ -149,10 +155,16 @@ class ScolarAutorisationInscription(db.Model):
 
     def html(self) -> str:
         "Affichage html"
+        link = (
+            self.origin_formsemestre.html_link_status(
+                label=f"{self.origin_formsemestre.titre_formation(with_sem_idx=1)}",
+                title=self.origin_formsemestre.titre_annee(),
+            )
+            if self.origin_formsemestre
+            else "externe/antérieure"
+        )
         return f"""Autorisation de passage vers <b>S{self.semestre_id}</b> émise par
-            {self.origin_formsemestre.html_link_status()
-             if self.origin_formsemestre
-             else "-"}
+            {link}
             le {self.date.strftime("%d/%m/%Y")} à {self.date.strftime("%Hh%M")}
         """
 
diff --git a/app/scodoc/codes_cursus.py b/app/scodoc/codes_cursus.py
index 85d14b957b48ae55f7eff0fb5c1108d20bafaa37..dff4ead7b3d22f0bbc180e26dd6dc3eb634c4f37 100644
--- a/app/scodoc/codes_cursus.py
+++ b/app/scodoc/codes_cursus.py
@@ -196,6 +196,8 @@ CODES_SEM_ATTENTES = {ATT, ATB, ATJ}  # semestre en attente
 
 CODES_SEM_REO = {NAR}  # reorientation
 
+# Les codes d'UEs
+CODES_JURY_UE = {ADM, CMP, ADJ, ADJR, ADSUP, AJ, ATJ, RAT, DEF, ABAN, DEM, UEBSL}
 CODES_UE_VALIDES_DE_DROIT = {ADM, CMP}  # validation "de droit"
 CODES_UE_VALIDES = CODES_UE_VALIDES_DE_DROIT | {ADJ, ADJR, ADSUP}
 "UE validée"
diff --git a/app/scodoc/sco_formsemestre_validation.py b/app/scodoc/sco_formsemestre_validation.py
index 6234e5f53f70243a9f23a991e18dae3dcb4c6c7e..f8ce9847139f73c33ea9842a5da8a4c1b83433e7 100644
--- a/app/scodoc/sco_formsemestre_validation.py
+++ b/app/scodoc/sco_formsemestre_validation.py
@@ -398,7 +398,7 @@ def formsemestre_validation_etud(
             selected_choice = choice
             break
     if not selected_choice:
-        raise ValueError("code choix invalide ! (%s)" % codechoice)
+        raise ValueError(f"code choix invalide ! ({codechoice})")
     #
     Se.valide_decision(selected_choice)  # enregistre
     return _redirect_valid_choice(
@@ -1132,6 +1132,7 @@ def formsemestre_validate_previous_ue(formsemestre: FormSemestre, etud: Identite
                 },
             )
         )
+    ue_codes = sorted(codes_cursus.CODES_JURY_UE)
     form_descr += [
         (
             "date",
@@ -1152,6 +1153,18 @@ def formsemestre_validate_previous_ue(formsemestre: FormSemestre, etud: Identite
                 "title": "Moyenne (/20) obtenue dans cette UE:",
             },
         ),
+        (
+            "code_jury",
+            {
+                "input_type": "menu",
+                "title": "Code jury",
+                "explanation": " code donné par le jury (ADM si validée normalement)",
+                "allow_null": True,
+                "allowed_values": [""] + ue_codes,
+                "labels": ["-"] + ue_codes,
+                "default": ADM,
+            },
+        ),
     ]
     tf = TrivialFormulator(
         request.base_url,
@@ -1173,17 +1186,20 @@ def formsemestre_validate_previous_ue(formsemestre: FormSemestre, etud: Identite
     de {etud.html_link_fiche()}
     </h2>
 
-    <p class="help">Utiliser cette page pour enregistrer une UE validée antérieurement,
+    <p class="help">Utiliser cette page pour enregistrer des UEs validées antérieurement,
     <em>dans un semestre hors ScoDoc</em>.</p>
-    <p class="expl"><b>Les UE validées dans ScoDoc sont déjà
-    automatiquement prises en compte</b>. Cette page n'est utile que pour les étudiants ayant
-    suivi un début de cursus dans <b>un autre établissement</b>, ou bien dans un semestre géré
-    <b>sans ScoDoc</b> et qui <b>redouble</b> ce semestre
-    (<em>pour les semestres précédents gérés avec ScoDoc,
-    passer par la page jury normale)</em>).
+    <p class="expl"><b>Les UE validées dans ScoDoc sont 
+    automatiquement prises en compte</b>. 
+    </p>
+    <p>Cette page est surtout utile  pour les étudiants ayant
+    suivi un début de cursus dans <b>un autre établissement</b>, ou qui 
+    ont suivi une UE à l'étranger ou dans un semestre géré <b>sans ScoDoc</b>.
+    </p>
+    <p>Pour les semestres précédents gérés avec ScoDoc, passer par la page jury normale.
+    </p>
+    <p>Notez que l'UE est validée, avec enregistrement immédiat de la décision et
+    l'attribution des ECTS si le code jury est validant (ADM).
     </p>
-    <p>Notez que l'UE est validée (ADM), avec enregistrement immédiat de la décision et
-    l'attribution des ECTS.</p>
     <p>On ne peut valider ici que les UEs du cursus <b>{formation.titre}</b></p>
 
     {_get_etud_ue_cap_html(etud, formsemestre)}
@@ -1221,12 +1237,16 @@ def formsemestre_validate_previous_ue(formsemestre: FormSemestre, etud: Identite
     else:
         semestre_id = None
 
+    if tf[2]["code_jury"] not in CODES_JURY_UE:
+        flash("Code UE invalide")
+        return flask.redirect(dest_url)
     do_formsemestre_validate_previous_ue(
         formsemestre,
         etud.id,
         tf[2]["ue_id"],
         tf[2]["moy_ue"],
         tf[2]["date"],
+        code=tf[2]["code_jury"],
         semestre_id=semestre_id,
     )
     flash("Validation d'UE enregistrée")
@@ -1258,7 +1278,7 @@ def _get_etud_ue_cap_html(etud: Identite, formsemestre: FormSemestre) -> str:
         <div class="help">Liste de toutes les UEs validées par {etud.html_link_fiche()}, 
         sur des semestres ou déclarées comme "antérieures" (externes).
         </div>
-        <ul>"""
+        <ul class="liste_validations">"""
     ]
     for validation in validations:
         if validation.formsemestre_id is None:
@@ -1267,17 +1287,20 @@ def _get_etud_ue_cap_html(etud: Identite, formsemestre: FormSemestre) -> str:
             origine = f", du semestre {formsemestre.html_link_status()}"
         if validation.semestre_id is not None:
             origine += f" (<b>S{validation.semestre_id}</b>)"
-        H.append(
-            f"""
-            <li>{validation.html()}
+        H.append(f"""<li>{validation.html()}""")
+        if validation.formsemestre.can_edit_jury():
+            H.append(
+                f"""
                 <form class="inline-form">
                     <button 
                     data-v_id="{validation.id}" data-type="validation_ue" data-etudid="{etud.id}"
                     >effacer</button>
                 </form>
-            </li>
-            """,
-        )
+                """,
+            )
+        else:
+            H.append(scu.icontag("lock_img", border="0", title="Semestre verrouillé"))
+        H.append("</li>")
     H.append("</ul></div>")
     return "\n".join(H)
 
@@ -1300,7 +1323,7 @@ def do_formsemestre_validate_previous_ue(
     ue: UniteEns = UniteEns.query.get_or_404(ue_id)
 
     cnx = ndb.GetDBConnexion()
-    if ue_coefficient != None:
+    if ue_coefficient is not None:
         sco_formsemestre.do_formsemestre_uecoef_edit_or_create(
             cnx, formsemestre.id, ue_id, ue_coefficient
         )
diff --git a/app/scodoc/sco_page_etud.py b/app/scodoc/sco_page_etud.py
index e2dbd1cbce675ea4d822b355aaff6541db9f7a88..cbb26f08f4569bca1c9018ca0d85449bf72f0f0e 100644
--- a/app/scodoc/sco_page_etud.py
+++ b/app/scodoc/sco_page_etud.py
@@ -59,11 +59,13 @@ from app.scodoc.sco_formsemestre_validation import formsemestre_recap_parcours_t
 from app.scodoc.sco_permissions import Permission
 
 
-def _menu_scolarite(authuser, sem: dict, etudid: int):
+def _menu_scolarite(
+    authuser, formsemestre: FormSemestre, etudid: int, etat_inscription: str
+):
     """HTML pour menu "scolarite" pour un etudiant dans un semestre.
     Le contenu du menu depend des droits de l'utilisateur et de l'état de l'étudiant.
     """
-    locked = not sem["etat"]
+    locked = not formsemestre.etat
     if locked:
         lockicon = scu.icontag("lock32_img", title="verrouillé", border="0")
         return lockicon  # no menu
@@ -71,10 +73,10 @@ def _menu_scolarite(authuser, sem: dict, etudid: int):
         Permission.ScoEtudInscrit
     ) and not authuser.has_permission(Permission.ScoEtudChangeGroups):
         return ""  # no menu
-    ins = sem["ins"]
-    args = {"etudid": etudid, "formsemestre_id": ins["formsemestre_id"]}
 
-    if ins["etat"] != "D":
+    args = {"etudid": etudid, "formsemestre_id": formsemestre.id}
+
+    if etat_inscription != scu.DEMISSION:
         dem_title = "Démission"
         dem_url = "scolar.form_dem"
     else:
@@ -82,14 +84,14 @@ def _menu_scolarite(authuser, sem: dict, etudid: int):
         dem_url = "scolar.do_cancel_dem"
 
     # Note: seul un etudiant inscrit (I) peut devenir défaillant.
-    if ins["etat"] != codes_cursus.DEF:
+    if etat_inscription != codes_cursus.DEF:
         def_title = "Déclarer défaillance"
         def_url = "scolar.form_def"
-    elif ins["etat"] == codes_cursus.DEF:
+    elif etat_inscription == codes_cursus.DEF:
         def_title = "Annuler la défaillance"
         def_url = "scolar.do_cancel_def"
     def_enabled = (
-        (ins["etat"] != "D")
+        (etat_inscription != scu.DEMISSION)
         and authuser.has_permission(Permission.ScoEtudInscrit)
         and not locked
     )
@@ -128,6 +130,12 @@ def _menu_scolarite(authuser, sem: dict, etudid: int):
             "enabled": authuser.has_permission(Permission.ScoEtudInscrit)
             and not locked,
         },
+        {
+            "title": "Gérer les validations d'UEs antérieures",
+            "endpoint": "notes.formsemestre_validate_previous_ue",
+            "args": args,
+            "enabled": formsemestre.can_edit_jury(),
+        },
         {
             "title": "Inscrire à un autre semestre",
             "endpoint": "notes.formsemestre_inscription_with_modules_form",
@@ -250,8 +258,8 @@ def ficheEtud(etudid=None):
         info["last_formsemestre_id"] = ""
     sem_info = {}
     for sem in info["sems"]:
+        formsemestre: FormSemestre = FormSemestre.query.get(sem["formsemestre_id"])
         if sem["ins"]["etat"] != scu.INSCRIT:
-            formsemestre: FormSemestre = FormSemestre.query.get(sem["formsemestre_id"])
             descr, _ = etud_descr_situation_semestre(
                 etudid,
                 formsemestre,
@@ -283,7 +291,7 @@ def ficheEtud(etudid=None):
                 )
             grlink = ", ".join(grlinks)
         # infos ajoutées au semestre dans le parcours (groupe, menu)
-        menu = _menu_scolarite(authuser, sem, etudid)
+        menu = _menu_scolarite(authuser, formsemestre, etudid, sem["ins"]["etat"])
         if menu:
             sem_info[sem["formsemestre_id"]] = (
                 "<table><tr><td>" + grlink + "</td><td>" + menu + "</td></tr></table>"
diff --git a/app/static/css/jury_delete_manual.css b/app/static/css/jury_delete_manual.css
index d41e4f802b16655c24fcf231c7c6ebc5ffbde8ac..eda3bc6331100faf73f9ccf7f0661015732d03c4 100644
--- a/app/static/css/jury_delete_manual.css
+++ b/app/static/css/jury_delete_manual.css
@@ -7,3 +7,7 @@ div.jury_decisions_list div {
 span.parcours {
     color:blueviolet;
 }
+
+div.ue_list_etud_validations ul.liste_validations li {
+    margin-bottom: 8px;
+}
\ No newline at end of file
diff --git a/app/static/js/validate_previous_ue.js b/app/static/js/validate_previous_ue.js
index 22655f498e23016a74dc2ec745e0359b145e731c..c2fe3c88882ab4def85ce1d36b50e6f4b78edb4b 100644
--- a/app/static/js/validate_previous_ue.js
+++ b/app/static/js/validate_previous_ue.js
@@ -11,27 +11,30 @@ document.addEventListener("DOMContentLoaded", () => {
       // Handle button click event here
       event.preventDefault();
       const etudid = event.target.dataset.etudid;
-      const v_id = event.target.dataset.v_id;
+      const validation_id = event.target.dataset.v_id;
       const validation_type = event.target.dataset.type;
       if (confirm("Supprimer cette validation ?")) {
-        fetch(
-          `${SCO_URL}/../api/etudiant/${etudid}/jury/${validation_type}/${v_id}/delete`,
-          {
-            method: "POST",
-          }
-        ).then((response) => {
-          // Handle the response
-          if (response.ok) {
-            location.reload();
-          } else {
-            throw new Error("Request failed");
-          }
-        });
+        delete_validation(etudid, validation_type, validation_id);
       }
     });
   });
 });
 
+async function delete_validation(etudid, validation_type, validation_id) {
+  const response = await fetch(
+    `${SCO_URL}/../api/etudiant/${etudid}/jury/${validation_type}/${validation_id}/delete`,
+    {
+      method: "POST",
+    }
+  );
+  if (response.ok) {
+    location.reload();
+  } else {
+    const data = await response.json();
+    sco_error_message("erreur: " + data.message);
+  }
+}
+
 function update_ue_list() {
   var ue_id = $("#tf_ue_id")[0].value;
   if (ue_id) {
diff --git a/app/templates/jury/erase_decisions_annee_formation.j2 b/app/templates/jury/erase_decisions_annee_formation.j2
index 0c231b5325c4fde38f3bb68ce31ae862f4b3a949..fc8fd0ce0217549f380d4f8202d51c3930337410 100644
--- a/app/templates/jury/erase_decisions_annee_formation.j2
+++ b/app/templates/jury/erase_decisions_annee_formation.j2
@@ -34,6 +34,32 @@ quelle que soit leur origine.</p>
         {% endif %}
     </form>
 </div>
+
+<div class="sco_box">
+<div class="sco_box_title">Autres actions:</div>
+<ul>
+    <li><a class="stdlink" href="{{
+        url_for('notes.jury_delete_manual',
+                    scodoc_dept=g.scodoc_dept,
+                    etudid=etud.id
+                )
+    }}">effacer les décisions une à une</a>
+    </li>
+    {% if formsemestre_origine is not none %}
+        <li><a class="stdlink" href="{{
+            url_for('notes.formsemestre_jury_but_erase',
+                    scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_origine.id,
+                    etudid=etud.id, only_one_sem=1)
+            }}">
+            effacer seulement les décisions émises par le semestre 
+            {{formsemestre_origine.titre_formation(with_sem_idx=1)|safe}}
+            (efface aussi la décision annuelle)
+            </a>
+        </li>
+    {% endif %}
+</ul>
+</div>
+
 {% endif %}
 
 
diff --git a/app/views/notes.py b/app/views/notes.py
index d6a77c614dba19381265486951b95ba96ee044f9..4bc79ebae849674de8d078e5fca46f72870aa66f 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -2534,21 +2534,20 @@ def formsemestre_validation_but(
             </div>"""
         )
     else:
-        erase_span = f"""<a href="{
-            url_for("notes.formsemestre_jury_but_erase",
-            scodoc_dept=g.scodoc_dept, formsemestre_id=deca.formsemestre.id,
-            etudid=deca.etud.id)}" class="stdlink"
-            title="efface décisions issues des jurys de cette année"
-            >effacer décisions de ce jury</a>
-            
+        erase_span = f"""
             <a style="margin-left: 16px;" class="stdlink"
             href="{
                 url_for("notes.erase_decisions_annee_formation",
                 scodoc_dept=g.scodoc_dept, formation_id=deca.formsemestre.formation.id,
-                etudid=deca.etud.id, annee=deca.annee_but)}"
-            title="efface toutes décisions concernant le BUT{deca.annee_but}
-                de cet étudiant (même extérieures ou issues d'un redoublement)"
-            >effacer toutes ses décisions de BUT{deca.annee_but}</a>
+                etudid=deca.etud.id, annee=deca.annee_but, formsemestre_id=formsemestre_id)}"
+            >effacer des décisions de jury</a>
+
+            <a style="margin-left: 16px;" class="stdlink"
+            href="{
+                url_for("notes.formsemestre_validate_previous_ue",
+                scodoc_dept=g.scodoc_dept, 
+                etudid=deca.etud.id, formsemestre_id=formsemestre_id)}"
+            >enregistrer des UEs antérieures</a>
             """
         H.append(
             f"""<div class="but_settings">
@@ -2966,6 +2965,12 @@ def erase_decisions_annee_formation(etudid: int, formation_id: int, annee: int):
             )
         )
     validations = jury.erase_decisions_annee_formation(etud, formation, annee)
+    formsemestre_origine_id = request.args.get("formsemestre_id")
+    formsemestre_origine = (
+        FormSemestre.query.get_or_404(formsemestre_origine_id)
+        if formsemestre_origine_id
+        else None
+    )
     return render_template(
         "jury/erase_decisions_annee_formation.j2",
         annee=annee,
@@ -2974,6 +2979,7 @@ def erase_decisions_annee_formation(etudid: int, formation_id: int, annee: int):
         ),
         etud=etud,
         formation=formation,
+        formsemestre_origine=formsemestre_origine,
         validations=validations,
         sco=ScoData(),
         title=f"Effacer décisions de jury {etud.nom} - année {annee}",