diff --git a/app/but/jury_but.py b/app/but/jury_but.py
index 8db372b1f254ba27891d4f58c74a77e8fb1f917f..391f77ed1eb0de853f88823513cc16cd34d5c158 100644
--- a/app/but/jury_but.py
+++ b/app/but/jury_but.py
@@ -246,6 +246,8 @@ class DecisionsProposeesAnnee(DecisionsProposees):
         "liste des niveaux de compétences associés à cette année"
         self.decisions_rcue_by_niveau = self.compute_decisions_niveaux()
         "les décisions rcue associées aux niveau_id"
+        self.dec_rcue_by_ue = self._dec_rcue_by_ue()
+        "{ ue_id : DecisionsProposeesRCUE }"
         self.nb_competences = len(self.niveaux_competences)
         "le nombre de niveaux de compétences à valider cette année"
         self.nb_validables = len(
@@ -357,6 +359,7 @@ class DecisionsProposeesAnnee(DecisionsProposees):
                 if res.etuds_parcour_id[etudid] is None:
                     # pas de parcour: prend toutes les UEs (non bonus)
                     ues = [ue for ue in res.etud_ues(etudid) if ue.type == UE_STANDARD]
+                    ues.sort(key=lambda u: u.numero)
                 else:
                     parcour = ApcParcours.query.get(res.etuds_parcour_id[etudid])
                     if parcour is not None:
@@ -364,6 +367,7 @@ class DecisionsProposeesAnnee(DecisionsProposees):
                     ues = (
                         formation.query_ues_parcour(parcour)
                         .filter_by(semestre_idx=formsemestre.semestre_id)
+                        .order_by(UniteEns.numero)
                         .all()
                     )
             ues_sems.append(ues)
@@ -418,9 +422,10 @@ class DecisionsProposeesAnnee(DecisionsProposees):
         return rcues_annee
 
     def compute_decisions_niveaux(self) -> dict[int, "DecisionsProposeesRCUE"]:
-        """Pour chaque niveau de compétence de cette année, donne le DecisionsProposeesRCUE
-        ou None s'il n'y en a pas (ne devrait pas arriver car
-            compute_rcues_annee vérifie déjà cela).
+        """Pour chaque niveau de compétence de cette année, construit
+        le DecisionsProposeesRCUE,
+        ou None s'il n'y en a pas
+            (ne devrait pas arriver car compute_rcues_annee vérifie déjà cela).
         Return: { niveau_id : DecisionsProposeesRCUE }
         """
         # Retrouve le RCUE associé à chaque niveau
@@ -442,6 +447,15 @@ class DecisionsProposeesAnnee(DecisionsProposees):
         decisions_rcue_by_niveau = {x[1]: x[0] for x in rc_niveaux}
         return decisions_rcue_by_niveau
 
+    def _dec_rcue_by_ue(self) -> dict[int, "DecisionsProposeesRCUE"]:
+        """construit dict { ue_id : DecisionsProposeesRCUE }
+        à partir de self.decisions_rcue_by_niveau"""
+        d = {}
+        for dec_rcue in self.decisions_rcue_by_niveau.values():
+            d[dec_rcue.rcue.ue_1.id] = dec_rcue
+            d[dec_rcue.rcue.ue_2.id] = dec_rcue
+        return d
+
     # def lookup_ue(self, ue_id: int) -> UniteEns:
     #     "check that ue_id belongs to our UE, if not returns None"
     #     ues = [ue for ue in self.ues_impair + self.ues_pair if ue.id == ue_id]
diff --git a/app/but/jury_but_recap.py b/app/but/jury_but_recap.py
index 47f826083f3edc15b14ecb2a1408dfbf002666f0..b9ed57a304edf00ae3f5827be41a97e2675c1b0a 100644
--- a/app/but/jury_but_recap.py
+++ b/app/but/jury_but_recap.py
@@ -11,7 +11,11 @@ import time
 from flask import g, url_for
 
 from app.but import jury_but
-from app.but.jury_but import DecisionsProposeesAnnee
+from app.but.jury_but import (
+    DecisionsProposeesAnnee,
+    DecisionsProposeesRCUE,
+    DecisionsProposeesUE,
+)
 from app.comp.res_but import ResultatsSemestreBUT
 from app.comp import res_sem
 from app.models.but_validations import RegroupementCoherentUE
@@ -179,10 +183,11 @@ class RowCollector:
         self["_nom_disp_target_attrs"] = self["_nom_short_target_attrs"]
         self.last_etud_cell_idx = self.idx
 
-    def add_ue_cell(self, ue: UniteEns, val):
+    def add_ue_cells(self, dec_ue: DecisionsProposeesUE):
         "cell de moyenne d'UE"
-        col_id = f"moy_ue_{ue.id}"
+        col_id = f"moy_ue_{dec_ue.ue.id}"
         note_class = ""
+        val = dec_ue.moy_ue
         if isinstance(val, float):
             if val < BUT_BARRE_UE:
                 note_class = " moy_inf"
@@ -190,10 +195,19 @@ class RowCollector:
                 note_class = " moy_ue_valid"
             if val < BUT_BARRE_UE8:
                 note_class = " moy_ue_warning"  # notes très basses
-        self.add_cell(col_id, ue.acronyme, self.fmt_note(val), "col_ue" + note_class)
+        self.add_cell(
+            col_id, dec_ue.ue.acronyme, self.fmt_note(val), "col_ue" + note_class
+        )
+        self.add_cell(
+            col_id + "_code",
+            dec_ue.ue.acronyme,
+            dec_ue.code_valide or "",
+            "col_ue_code recorded_code",
+        )
 
-    def add_rcue_cell(self, rcue: RegroupementCoherentUE):
-        "cell de moyenne d'UE"
+    def add_rcue_cells(self, dec_rcue: DecisionsProposeesRCUE):
+        "2 cells: moyenne du RCUE, code enregistré"
+        rcue = dec_rcue.rcue
         col_id = f"moy_rcue_{rcue.ue_1.niveau_competence_id}"  # le niveau_id
         note_class = ""
         val = rcue.moy_rcue
@@ -210,6 +224,12 @@ class RowCollector:
             self.fmt_note(val),
             "col_rcue" + note_class,
         )
+        self.add_cell(
+            col_id + "_code",
+            f"<div>{rcue.ue_1.acronyme}</div><div>{rcue.ue_2.acronyme}</div>",
+            dec_rcue.code_valide or "",
+            "col_rcue_code recorded_code",
+        )
 
     def add_nb_rcues_cell(self, deca: DecisionsProposeesAnnee):
         "cell avec nb niveaux validables / total"
@@ -259,9 +279,10 @@ def get_table_jury_but(
         row.add_nb_rcues_cell(deca)
         # --- Les RCUEs
         for rcue in deca.rcues_annee:
-            row.add_ue_cell(rcue.ue_1, rcue.moy_ue_1)
-            row.add_ue_cell(rcue.ue_2, rcue.moy_ue_2)
-            row.add_rcue_cell(rcue)
+            dec_rcue = deca.dec_rcue_by_ue[rcue.ue_1.id]
+            row.add_ue_cells(deca.decisions_ues[rcue.ue_1.id])
+            row.add_ue_cells(deca.decisions_ues[rcue.ue_2.id])
+            row.add_rcue_cells(dec_rcue)
         # --- Le code annuel existant
         row.add_cell(
             "code_annee",
diff --git a/app/scodoc/sco_codes_parcours.py b/app/scodoc/sco_codes_parcours.py
index cfc440159757da9dc480905e18a4fc87da92997d..d4479939b5d5d8db308bf94cb88a1243901db38b 100644
--- a/app/scodoc/sco_codes_parcours.py
+++ b/app/scodoc/sco_codes_parcours.py
@@ -188,7 +188,7 @@ CODES_SEM_ATTENTES = {ATT: True, ATB: True, ATJ: True}  # semestre en attente
 
 CODES_SEM_REO = {NAR: 1}  # reorientation
 
-CODES_UE_VALIDES = {ADM: True, CMP: True}  # UE validée
+CODES_UE_VALIDES = {ADM: True, CMP: True, ADJ: True}  # UE validée
 
 # Pour le BUT:
 CODES_ANNEE_ARRET = {DEF, DEM, ABAN, ABL}
diff --git a/app/static/js/table_recap.js b/app/static/js/table_recap.js
index 0c87ecdaafa8167d5e39b9ff79207f69befa27b5..18829d8edb36ea3fe52b5e87a4ea7d0cf25beb05 100644
--- a/app/static/js/table_recap.js
+++ b/app/static/js/table_recap.js
@@ -35,6 +35,18 @@ $(function () {
                         dt.buttons('toggle_partitions_rangs:name').text(rangs_visible ? "Rangs groupes" : "Cacher rangs groupes");
                     }
                 });
+        } else {
+            // table jury BUT: avec ou sans codes enregistrés
+            buttons.push(
+                {
+                    name: "toggle_recorded_code",
+                    text: "Code jury enregistrés",
+                    action: function (e, dt, node, config) {
+                        let visible = dt.columns(".recorded_code").visible()[0];
+                        dt.columns(".recorded_code").visible(!visible);
+                        dt.buttons('toggle_recorded_code:name').text(visible ? "Code jury enregistrés" : "Cacher codes jury");
+                    }
+                });
         }
 
         if (!$('table.table_recap').hasClass("jury")) {
@@ -113,7 +125,7 @@ $(function () {
                 "columnDefs": [
                     {
                         // cache les codes, le détail de l'identité, les groupes, les colonnes admission et les vides
-                        targets: ["codes", "identite_detail", "partition_aux", "partition_rangs", "admission", "col_empty"],
+                        targets: ["codes", "identite_detail", "partition_aux", "partition_rangs", "admission", "col_empty", "recorded_code"],
                         visible: false,
                     },
                     {