diff --git a/app/but/jury_but.py b/app/but/jury_but.py
index c1ded7b8837799c8126d8a5b39ae2a1d959fc85d..af9b46731e932b017f6e1d48d7ef02ba735032f8 100644
--- a/app/but/jury_but.py
+++ b/app/but/jury_but.py
@@ -75,11 +75,9 @@ from app.comp.res_but import ResultatsSemestreBUT
 from app.comp import res_sem
 
 from app.models.but_refcomp import (
-    ApcAnneeParcours,
     ApcCompetence,
     ApcNiveau,
     ApcParcours,
-    ApcParcoursNiveauCompetence,
 )
 from app.models import Scolog, ScolarAutorisationInscription
 from app.models.but_validations import (
@@ -89,7 +87,7 @@ from app.models.but_validations import (
 )
 from app.models.etudiants import Identite
 from app.models.formations import Formation
-from app.models.formsemestre import FormSemestre, FormSemestreInscription
+from app.models.formsemestre import FormSemestre
 from app.models.ues import UniteEns
 from app.models.validations import ScolarFormSemestreValidation
 from app.scodoc import sco_cache
@@ -473,7 +471,7 @@ class DecisionsProposeesAnnee(DecisionsProposees):
                         scodoc_dept=g.scodoc_dept,
                         semestre_idx=formsemestre.semestre_id,
                         formation_id=formsemestre.formation.id)}">
-                        {formsemestre.formation.to_html()} ({
+                        {formsemestre.formation.html()} ({
                             formsemestre.formation.id})</a>
                     </li>
                     </ul>
@@ -902,7 +900,8 @@ class DecisionsProposeesAnnee(DecisionsProposees):
         pour cette année: décisions d'UE, de RCUE, d'année,
         et autorisations d'inscription émises.
         Efface même si étudiant DEM ou DEF.
-        Si à cheval, n'efface que pour le semestre d'origine du deca.
+        Si à cheval ou only_one_sem, n'efface que les décisions UE et les
+        autorisations de passage du semestre d'origine du deca.
         (commite la session.)
         """
         if only_one_sem or self.a_cheval:
diff --git a/app/but/jury_but_view.py b/app/but/jury_but_view.py
index 0a20e9334ef2a34e98b7c608f56b028c34b6938d..a61f1f14bb7ec9e9ed6250649461210660ed9ecd 100644
--- a/app/but/jury_but_view.py
+++ b/app/but/jury_but_view.py
@@ -246,7 +246,7 @@ def _gen_but_rcue(dec_rcue: DecisionsProposeesRCUE, niveau: ApcNiveau) -> str:
 
     scoplement = (
         f"""<div class="scoplement">{
-            dec_rcue.validation.to_html()
+            dec_rcue.validation.html()
         }</div>"""
         if dec_rcue.validation
         else ""
diff --git a/app/comp/jury.py b/app/comp/jury.py
index cee32ffddff4518ea05f0bef05f85f9b34a867c2..1c43158da4ad1d1221a10692622d5f8e36e09022 100644
--- a/app/comp/jury.py
+++ b/app/comp/jury.py
@@ -10,8 +10,17 @@ import pandas as pd
 import sqlalchemy as sa
 
 from app import db
-from app.models import FormSemestre, Identite, ScolarFormSemestreValidation, UniteEns
 from app.comp.res_cache import ResultatsCache
+from app.models import (
+    ApcValidationAnnee,
+    ApcValidationRCUE,
+    Formation,
+    FormSemestre,
+    Identite,
+    ScolarAutorisationInscription,
+    ScolarFormSemestreValidation,
+    UniteEns,
+)
 from app.scodoc import sco_cache
 from app.scodoc import codes_cursus
 
@@ -81,7 +90,7 @@ class ValidationsSemestre(ResultatsCache):
 
         # UEs: { etudid : { ue_id : {"code":, "ects":, "event_date":} }}
         decisions_jury_ues = {}
-        # Parcours les décisions d'UE:
+        # Parcoure les décisions d'UE:
         for decision in (
             decisions_jury_q.filter(db.text("ue_id is not NULL"))
             .join(UniteEns)
@@ -172,3 +181,80 @@ def formsemestre_get_ue_capitalisees(formsemestre: FormSemestre) -> pd.DataFrame
     with db.engine.begin() as connection:
         df = pd.read_sql_query(query, connection, params=params, index_col="etudid")
     return df
+
+
+def erase_decisions_annee_formation(
+    etud: Identite, formation: Formation, annee: int, delete=False
+) -> list:
+    """Efface toutes les décisions de jury de l'étudiant dans les formations de même code
+    que celle donnée pour cette année de la formation:
+        UEs, RCUEs de l'année BUT, année BUT, passage vers l'année suivante.
+    Ne considère pas l'origine de la décision.
+    annee: entier, 1, 2, 3, ...
+    Si delete est faux, renvoie la liste des validations qu'il faudrait effacer, sans y toucher.
+    """
+    sem1, sem2 = annee * 2 - 1, annee * 2
+    # UEs
+    validations = (
+        ScolarFormSemestreValidation.query.filter_by(etudid=etud.id)
+        .join(UniteEns)
+        .filter(db.or_(UniteEns.semestre_idx == sem1, UniteEns.semestre_idx == sem2))
+        .join(Formation)
+        .filter_by(formation_code=formation.formation_code)
+        .order_by(
+            UniteEns.acronyme, UniteEns.numero
+        )  # acronyme d'abord car 2 semestres
+        .all()
+    )
+    # RCUEs (a priori inutile de matcher sur l'ue2_id)
+    validations += (
+        ApcValidationRCUE.query.filter_by(etudid=etud.id)
+        .join(UniteEns, UniteEns.id == ApcValidationRCUE.ue1_id)
+        .filter_by(semestre_idx=sem1)
+        .join(Formation)
+        .filter_by(formation_code=formation.formation_code)
+        .order_by(UniteEns.acronyme, UniteEns.numero)
+        .all()
+    )
+    # Validation de semestres classiques
+    validations += (
+        ScolarFormSemestreValidation.query.filter_by(etudid=etud.id, ue_id=None)
+        .join(
+            FormSemestre,
+            FormSemestre.id == ScolarFormSemestreValidation.formsemestre_id,
+        )
+        .filter(
+            db.or_(FormSemestre.semestre_id == sem1, FormSemestre.semestre_id == sem2)
+        )
+        .join(Formation)
+        .filter_by(formation_code=formation.formation_code)
+        .all()
+    )
+    # Année BUT
+    validations += (
+        ApcValidationAnnee.query.filter_by(etudid=etud.id, ordre=annee)
+        .join(Formation)
+        .filter_by(formation_code=formation.formation_code)
+        .all()
+    )
+    # Autorisations vers les semestres suivants ceux de l'année:
+    validations += (
+        ScolarAutorisationInscription.query.filter_by(
+            etudid=etud.id, formation_code=formation.formation_code
+        )
+        .filter(
+            db.or_(
+                ScolarAutorisationInscription.semestre_id == sem1 + 1,
+                ScolarAutorisationInscription.semestre_id == sem2 + 1,
+            )
+        )
+        .all()
+    )
+
+    if delete:
+        for validation in validations:
+            db.session.delete(validation)
+        db.session.commit()
+        sco_cache.invalidate_formsemestre_etud(etud)
+        return []
+    return validations
diff --git a/app/models/but_validations.py b/app/models/but_validations.py
index c2be058b3f4dcceb146c1eb3545026fa8311ead8..778164765f2a76d4d8a9c5b4ee9ccfb9fe670529 100644
--- a/app/models/but_validations.py
+++ b/app/models/but_validations.py
@@ -66,7 +66,7 @@ class ApcValidationRCUE(db.Model):
         return f"""Décision sur RCUE {self.ue1.acronyme}/{self.ue2.acronyme}: {
             self.code} enregistrée le {self.date.strftime("%d/%m/%Y")}"""
 
-    def to_html(self) -> str:
+    def html(self) -> str:
         "description en HTML"
         return f"""Décision sur RCUE {self.ue1.acronyme}/{self.ue2.acronyme}:
                 <b>{self.code}</b>
@@ -348,6 +348,13 @@ class ApcValidationAnnee(db.Model):
             "ordre": self.ordre,
         }
 
+    def html(self) -> str:
+        "Affichage html"
+        return f"""Validation <b>année BUT{self.ordre}</b> émise par
+            {self.formsemestre.html_link_status() if self.formsemestre else "-"}
+            le {self.date.strftime("%d/%m/%Y")} à {self.date.strftime("%Hh%M")}
+        """
+
 
 def dict_decision_jury(etud: Identite, formsemestre: FormSemestre) -> dict:
     """
diff --git a/app/models/formations.py b/app/models/formations.py
index e98d66f7b135daeeef19c693fede845698af680f..fb7529e323ef18a7f48a94e48f7a7ce1e2ffbf5a 100644
--- a/app/models/formations.py
+++ b/app/models/formations.py
@@ -60,7 +60,7 @@ class Formation(db.Model):
         return f"""<{self.__class__.__name__}(id={self.id}, dept_id={
                 self.dept_id}, acronyme={self.acronyme!r}, version={self.version})>"""
 
-    def to_html(self) -> str:
+    def html(self) -> str:
         "titre complet pour affichage"
         return f"""Formation {self.titre} ({self.acronyme}) [version {self.version}] code {self.formation_code}"""
 
diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py
index 516d8fc513c19a1ae3ffcf8d942fa8b5b45b0753..efbceb74b6d40f7e326a96e2786486ff660c8b9f 100644
--- a/app/models/formsemestre.py
+++ b/app/models/formsemestre.py
@@ -16,7 +16,7 @@ from operator import attrgetter
 
 from flask_login import current_user
 
-from flask import flash, g
+from flask import flash, g, url_for
 from sqlalchemy.sql import text
 
 import app.scodoc.sco_utils as scu
@@ -163,6 +163,14 @@ class FormSemestre(db.Model):
     def __repr__(self):
         return f"<{self.__class__.__name__} {self.id} {self.titre_annee()}>"
 
+    def html_link_status(self) -> 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>
+        """
+
     @classmethod
     def get_formsemestre(cls, formsemestre_id: int) -> "FormSemestre":
         """ "FormSemestre ou 404, cherche uniquement dans le département courant"""
diff --git a/app/models/validations.py b/app/models/validations.py
index 229d15ad5425b53d88226bb592b182ab43a36613..9a938b6c5ab6759fea7eb21ecf4ed5988cd6b7e7 100644
--- a/app/models/validations.py
+++ b/app/models/validations.py
@@ -59,13 +59,16 @@ class ScolarFormSemestreValidation(db.Model):
     )
 
     def __repr__(self):
-        return f"{self.__class__.__name__}(sem={self.formsemestre_id}, etuid={self.etudid}, code={self.code}, ue={self.ue}, moy_ue={self.moy_ue})"
+        return f"""{self.__class__.__name__}(sem={self.formsemestre_id}, etuid={
+            self.etudid}, code={self.code}, ue={self.ue}, moy_ue={self.moy_ue})"""
 
     def __str__(self):
         if self.ue_id:
             # Note: si l'objet vient d'être créé, ue_id peut exister mais pas ue !
-            return f"""décision sur UE {self.ue.acronyme if self.ue else self.ue_id}: {self.code}"""
-        return f"""décision sur semestre {self.formsemestre.titre_mois()} du {self.event_date.strftime("%d/%m/%Y")}"""
+            return f"""décision sur UE {self.ue.acronyme if self.ue else self.ue_id
+                                        }: {self.code}"""
+        return f"""décision sur semestre {self.formsemestre.titre_mois()} du {
+                self.event_date.strftime("%d/%m/%Y")}"""
 
     def to_dict(self) -> dict:
         "as a dict"
@@ -73,6 +76,20 @@ class ScolarFormSemestreValidation(db.Model):
         d.pop("_sa_instance_state", None)
         return d
 
+    def html(self) -> str:
+        "Affichage html"
+        if self.ue_id is not None:
+            return f"""Validation de l'UE {self.ue.acronyme}
+                (<b>{self.code}</b>
+                le {self.event_date.strftime("%d/%m/%Y")} à {self.event_date.strftime("%Hh%M")})
+            """
+        else:
+            return f"""Validation du semestre S{
+                self.formsemestre.semestre_id if self.formsemestre else "?"}
+                (<b>{self.code}</b>
+                le {self.event_date.strftime("%d/%m/%Y")} à {self.event_date.strftime("%Hh%M")})
+            """
+
 
 class ScolarAutorisationInscription(db.Model):
     """Autorisation d'inscription dans un semestre"""
@@ -93,6 +110,7 @@ class ScolarAutorisationInscription(db.Model):
         db.Integer,
         db.ForeignKey("notes_formsemestre.id"),
     )
+    origin_formsemestre = db.relationship("FormSemestre", lazy="select", uselist=False)
 
     def __repr__(self) -> str:
         return f"""{self.__class__.__name__}(id={self.id}, etudid={
@@ -104,6 +122,15 @@ class ScolarAutorisationInscription(db.Model):
         d.pop("_sa_instance_state", None)
         return d
 
+    def html(self) -> str:
+        "Affichage html"
+        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 "-"}
+            le {self.date.strftime("%d/%m/%Y")} à {self.date.strftime("%Hh%M")}
+        """
+
     @classmethod
     def autorise_etud(
         cls,
diff --git a/app/scodoc/sco_cache.py b/app/scodoc/sco_cache.py
index 0b9d27a8350f86606c1ee46ae69ba3bbfe8064e8..36b8db30b3c117d5f3eed2c8ee6f24aa316fb8a0 100644
--- a/app/scodoc/sco_cache.py
+++ b/app/scodoc/sco_cache.py
@@ -315,6 +315,19 @@ def invalidate_formsemestre(  # was inval_cache(formsemestre_id=None, pdfonly=Fa
     SemBulletinsPDFCache.invalidate_sems(formsemestre_ids)
 
 
+def invalidate_formsemestre_etud(etud: "Identite"):
+    """Invalide tous les formsemestres auxquels l'étudiant est inscrit"""
+    from app.models import FormSemestre, FormSemestreInscription
+
+    inscriptions = (
+        FormSemestreInscription.query.filter_by(etudid=etud.id)
+        .join(FormSemestre)
+        .filter_by(dept_id=g.scodoc_dept_id)
+    )
+    for inscription in inscriptions:
+        invalidate_formsemestre(inscription.formsemestre_id)
+
+
 class DeferredSemCacheManager:
     """Contexte pour effectuer des opérations indépendantes dans la
     même requete qui invalident le cache. Par exemple, quand on inscrit
diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py
index f41804f1371e2ecd43b25d5d66a5354d800ac392..ba6cb918eeb2f3b045657438418e8b1fe9f9a7ef 100644
--- a/app/scodoc/sco_edit_ue.py
+++ b/app/scodoc/sco_edit_ue.py
@@ -757,7 +757,7 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""):  # was ue_list
             ],
             page_title=f"Programme {formation.acronyme} v{formation.version}",
         ),
-        f"""<h2>{formation.to_html()} {lockicon}
+        f"""<h2>{formation.html()} {lockicon}
         </h2>
         """,
     ]
@@ -1010,12 +1010,7 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
         <p><ul>"""
         )
         for formsemestre in formsemestres:
-            H.append(
-                f"""<li><a class="stdlink" href="{
-                    url_for("notes.formsemestre_status", scodoc_dept=g.scodoc_dept,
-                        formsemestre_id=formsemestre.id
-                    )}">{formsemestre.titre_mois()}</a>"""
-            )
+            H.append(f"""<li>{formsemestre.html_link_status()}""")
             if not formsemestre.etat:
                 H.append(" [verrouillé]")
             else:
diff --git a/app/scodoc/sco_recapcomplet.py b/app/scodoc/sco_recapcomplet.py
index 549b375d1ce068a5b690e68e105998e8e9bd7e89..63a0d4e2521f15834fd95b0ecb075c83916db582 100644
--- a/app/scodoc/sco_recapcomplet.py
+++ b/app/scodoc/sco_recapcomplet.py
@@ -142,7 +142,7 @@ def formsemestre_recapcomplet(
         H.append(
             '<select name="tabformat" onchange="document.f.submit()" class="noprint">'
         )
-        for (fmt, label) in (
+        for fmt, label in (
             ("html", "Tableau"),
             ("evals", "Avec toutes les évaluations"),
             ("xlsx", "Excel (non formaté)"),
@@ -186,7 +186,7 @@ def formsemestre_recapcomplet(
                     </li>
                     <li><a class="stdlink" href="{url_for('notes.formsemestre_jury_but_erase',
                     scodoc_dept=g.scodoc_dept, formsemestre_id=formsemestre_id, only_one_sem=1)
-                    }">Effacer <em>toutes</em> les décisions de jury (BUT) du semestre</a>
+                    }">Effacer <em>toutes</em> les décisions de jury BUT issues de ce semestre</a>
                     </li>
                     """
                 )
diff --git a/app/scodoc/sco_semset.py b/app/scodoc/sco_semset.py
index 1a4e68bbdcc3065b297e88b9e1b03c3409e657b9..c028429356269b73bf348a5208b85787a8fef330 100644
--- a/app/scodoc/sco_semset.py
+++ b/app/scodoc/sco_semset.py
@@ -145,12 +145,7 @@ class SemSet(dict):
 
         # Construction du ou des lien(s) vers le semestre
         self["semlinks"] = [
-            f"""<a class="stdlink" href="{
-                url_for("notes.formsemestre_status", scodoc_dept=g.scodoc_dept,
-                    formsemestre_id=formsemestre.id)
-            }">{formsemestre.titre_annee()}</a>
-            """
-            for formsemestre in self.formsemestres
+            formsemestre.html_link_status() for formsemestre in self.formsemestres
         ]
 
         self["semtitles_str"] = "<br>".join(self["semlinks"])
diff --git a/app/static/css/cursus_but.css b/app/static/css/cursus_but.css
index 79cde97cb0b75ad8dfb01723e5f79109071a1a1c..e998ccda54caf0467d93062eb3d1fb8ea04970a6 100644
--- a/app/static/css/cursus_but.css
+++ b/app/static/css/cursus_but.css
@@ -15,7 +15,6 @@
     padding-bottom: 0px;
     padding-left: 16px;
     padding-right: 0px;
-
     background: #FFF;
     border: 1px solid #aaa;
     border-radius: 8px;
@@ -39,4 +38,10 @@ div.code_rcue {
     padding-top: 8px;
     padding-bottom: 8px;
     position: relative;
+}
+
+div.code_jury {
+    padding-right: 4px;
+    padding-left: 4px;
+    width: 64px;
 }
\ No newline at end of file
diff --git a/app/templates/bul_head.j2 b/app/templates/bul_head.j2
index 473393802b5e35133e05d0291d3770efb4acb3b2..691cb4fb3271f75590589a32e26cfb4518363068 100644
--- a/app/templates/bul_head.j2
+++ b/app/templates/bul_head.j2
@@ -15,11 +15,9 @@
         <input type="hidden" name="etudid" value="{{etud.id}}"></input>
         <input type="hidden" name="format" value="{{format}}"></input>
         Bulletin 
-        <span class="bull_liensemestre"><a href="{{
-        url_for("notes.formsemestre_status",
-        scodoc_dept=g.scodoc_dept,
-        formsemestre_id=formsemestre.id)}}">{{formsemestre.titre_mois()
-        }}</a></span>
+        <span class="bull_liensemestre">
+        {{formsemestre.html_link_status() | safe}}
+        </span>
         
         <div>
         <em>établi le {{time.strftime("%d/%m/%Y à %Hh%M")}} (notes sur 20)</em>
diff --git a/app/templates/but/cursus_etud.j2 b/app/templates/but/cursus_etud.j2
index 571909683a93c0fd1c2877c5c894a90b6d3c4ddc..4baaa96f191cc62d4ddbaecbfb141fb8939bc43e 100644
--- a/app/templates/but/cursus_etud.j2
+++ b/app/templates/but/cursus_etud.j2
@@ -15,14 +15,16 @@
             <div class="code_jury">{{validation.code}}</div>
             <div class="scoplement">
                 <div>{{validation.ue1.acronyme}} - {{validation.ue2.acronyme}}</div>
-                <div>Jury de {{validation.formsemestre.titre_annee()}}</div>
+                <div>Jury de {{validation.formsemestre.titre_annee() if validation.formsemestre else "-"}}</div>
                 <div>enregistré le {{
                     validation.date.strftime("%d/%m/%Y à %H:%M")
                     }}</div>
             </div>
         </div>
         {% else %}
-        -
+        <div class="code_rcue">
+            <div class="code_jury">-</div>
+        </div>
         {%endif%}
     </div>
     {% endfor %}
diff --git a/app/templates/but/parcour_formation.j2 b/app/templates/but/parcour_formation.j2
index f128c052438953c2cd2919ceaa8b704e18f39f18..84aa11f02a781192d7218d295821911987c4a27c 100644
--- a/app/templates/but/parcour_formation.j2
+++ b/app/templates/but/parcour_formation.j2
@@ -44,7 +44,7 @@
 {%- endmacro %}
 
 {% block app_content %}
-<h2>{{formation.to_html()}}</h2>
+<h2>{{formation.html()}}</h2>
 
 {# Liens vers les différents parcours #}
 <div class="les_parcours">
@@ -127,7 +127,7 @@ Choisissez un parcours...
     d'associer à chaque semestre d'un niveau de compétence une UE de la formation
     <a class="stdlink" 
     href="{{url_for('notes.ue_table', scodoc_dept=g.scodoc_dept, formation_id=formation.id )
-    }}">{{formation.to_html()}}
+    }}">{{formation.html()}}
     </a>.</p> 
 
     <p>Le symbole <span class="parc">TC</span> désigne un niveau du tronc commun
diff --git a/app/templates/jury/erase_decisions_annee_formation.j2 b/app/templates/jury/erase_decisions_annee_formation.j2
new file mode 100644
index 0000000000000000000000000000000000000000..5298437a5c816961380174651c7df8742cc74ed0
--- /dev/null
+++ b/app/templates/jury/erase_decisions_annee_formation.j2
@@ -0,0 +1,41 @@
+{% extends 'base.j2' %}
+
+{% block app_content %}
+
+{% if not validations %}
+<p>Aucune validation de jury enregistrée pour <b>{{etud.nom_disp()}}</b> sur 
+<b>l'année {{annee}}</b>
+de la formation <em>{{ formation.html() }}</em>
+</p>
+
+<div style="margin-top: 16px;">
+    <a class="stdlink" href="{{ cancel_url }}">continuer</a>
+</div>
+{% else %}
+
+<h2>Effacer les décisions de jury pour l'année {{annee}} de {{etud.nom_disp()}} ?</h2>
+
+<p class="help">Affectera toutes les décisions concernant l'année {{annee}} de la formation,
+quelle que soit leur origine.</p>
+
+<p>Les décisions concernées sont:</p>
+<ul>
+    {% for validation in validations %}
+    <li>{{ validation.html() | safe}}
+    </li>
+    {% endfor %}
+</ul>
+<div style="margin-top: 16px;">
+    <form method="post">
+        <input type="submit" value="Effacer ces décisions" />
+        {% if cancel_url %}
+        <input type="button" value="Annuler" style="margin-left: 16px;"
+            onClick="document.location='{{ cancel_url }}';" />
+        {% endif %}
+    </form>
+</div>
+{% endif %}
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/views/notes.py b/app/views/notes.py
index 70990ac60a1af68b4ef2ebdc601c7c6fbcb08b99..e29a93c918c14bc004013cbb15a2f5c28d25b09d 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -48,9 +48,9 @@ from app.but.forms import jury_but_forms
 from app.but import jury_but_pv
 from app.but import jury_but_view
 
-from app.comp import res_sem
+from app.comp import jury, res_sem
 from app.comp.res_compat import NotesTableCompat
-from app.models import ScolarAutorisationInscription, ScolarNews, Scolog
+from app.models import Formation, ScolarAutorisationInscription, ScolarNews, Scolog
 from app.models.but_refcomp import ApcNiveau, ApcParcours
 from app.models.config import ScoDocSiteConfig
 from app.models.etudiants import Identite
@@ -2494,7 +2494,19 @@ def formsemestre_validation_but(
         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">effacer décisions</a>"""
+            etudid=deca.etud.id)}" class="stdlink"
+            title="efface décisions issues des jurys de cette année"
+            >effacer décisions</a>
+            
+            <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>
+            """
         H.append(
             f"""<div class="but_settings">
             <input type="checkbox" onchange="enable_manual_codes(this)">
@@ -2815,15 +2827,15 @@ def formsemestre_saisie_jury(formsemestre_id: int, selected_etudid: int = None):
 )
 @scodoc
 @permission_required(Permission.ScoView)
-def formsemestre_jury_but_erase(
-    formsemestre_id: int, etudid: int = None, only_one_sem=False
-):
+def formsemestre_jury_but_erase(formsemestre_id: int, etudid: int = None):
     """Supprime la décision de jury BUT pour cette année.
-    Si only_one_sem, n'efface que pour le formsemestre indiqué, pas les deux de l'année.
     Si l'étudiant n'est pas spécifié, efface les décisions de tous les inscrits.
+    Si only_one_sem, n'efface que pour le formsemestre indiqué, pas les deux de l'année.
     """
     only_one_sem = int(request.args.get("only_one_sem") or False)
-    formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
+    formsemestre: FormSemestre = FormSemestre.query.filter_by(
+        id=formsemestre_id, dept_id=g.scodoc_dept_id
+    ).first_or_404()
     if not formsemestre.can_edit_jury():
         raise ScoPermissionDenied(
             dest_url=url_for(
@@ -2881,14 +2893,53 @@ def formsemestre_jury_but_erase(
             if only_one_sem
             else """Les validations de toutes les UE, RCUE (compétences) et année
         issues de cette année scolaire seront effacées.
-        Les décisions des années scolaires précédentes ne seront pas modifiées.
         """
         )
-        + """<div class="warning">Cette opération est irréversible !</div>""",
+        + """
+        <p>Les décisions des années scolaires précédentes ne seront pas modifiées.</p>
+        <div class="warning">Cette opération est irréversible !</div>
+        """,
         cancel_url=dest_url,
     )
 
 
+@bp.route(
+    "/erase_decisions_annee_formation/<int:etudid>/<int:formation_id>/<int:annee>",
+    methods=["GET", "POST"],
+)
+@scodoc
+@permission_required(Permission.ScoEtudInscrit)
+def erase_decisions_annee_formation(etudid: int, formation_id: int, annee: int):
+    """Efface toute les décisions d'une année pour cet étudiant"""
+    etud: Identite = Identite.query.get_or_404(etudid)
+    formation: Formation = Formation.query.filter_by(
+        id=formation_id, dept_id=g.scodoc_dept_id
+    ).first_or_404()
+    if request.method == "POST":
+        jury.erase_decisions_annee_formation(etud, formation, annee, delete=True)
+        flash("Décisions de jury effacées")
+        return redirect(
+            url_for(
+                "scolar.ficheEtud",
+                scodoc_dept=g.scodoc_dept,
+                etudid=etud.id,
+            )
+        )
+    validations = jury.erase_decisions_annee_formation(etud, formation, annee)
+    return render_template(
+        "jury/erase_decisions_annee_formation.j2",
+        annee=annee,
+        cancel_url=url_for(
+            "scolar.ficheEtud", scodoc_dept=g.scodoc_dept, etudid=etud.id
+        ),
+        etud=etud,
+        formation=formation,
+        validations=validations,
+        sco=ScoData(),
+        title=f"Effacer décisions de jury {etud.nom} - année {annee}",
+    )
+
+
 sco_publish(
     "/formsemestre_lettres_individuelles",
     sco_pv_forms.formsemestre_lettres_individuelles,