diff --git a/app/but/jury_but.py b/app/but/jury_but.py
index 99ea436857e4e56e9f7399251a984ae3ca425d36..05978de2d817bc9e58c3929c85e832443f4d3d39 100644
--- a/app/but/jury_but.py
+++ b/app/but/jury_but.py
@@ -1208,6 +1208,7 @@ class DecisionsProposeesRCUE(DecisionsProposees):
                     ue1_id=ue1.id,
                     ue2_id=ue2.id,
                     code=sco_codes.ADSUP,
+                    formsemestre_id=self.deca.formsemestre.id,  # origine
                 )
                 db.session.add(validation_rcue)
                 db.session.commit()
diff --git a/app/models/but_validations.py b/app/models/but_validations.py
index fcab132bd0fc0d7828faa03fae781468943bee58..185ab539875340a5ddabeee0ce7c2b5a54f5adc8 100644
--- a/app/models/but_validations.py
+++ b/app/models/but_validations.py
@@ -36,7 +36,7 @@ class ApcValidationRCUE(db.Model):
     formsemestre_id = db.Column(
         db.Integer, db.ForeignKey("notes_formsemestre.id"), index=True, nullable=True
     )
-    "formsemestre pair du RCUE"
+    "formsemestre origine du RCUE (celui d'où a été émis la validation)"
     # Les deux UE associées à ce niveau:
     ue1_id = db.Column(db.Integer, db.ForeignKey("notes_ue.id"), nullable=False)
     ue2_id = db.Column(db.Integer, db.ForeignKey("notes_ue.id"), nullable=False)
diff --git a/app/models/validations.py b/app/models/validations.py
index 91f17f605ab429e7e0b0aa6cd35d509bf39f6716..d4ca5bb074fce52bfeeef4e705a11fa7431ea781 100644
--- a/app/models/validations.py
+++ b/app/models/validations.py
@@ -56,6 +56,7 @@ class ScolarFormSemestreValidation(db.Model):
     )
 
     ue = db.relationship("UniteEns", lazy="select", uselist=False)
+    etud = db.relationship("Identite", backref="validations")
     formsemestre = db.relationship(
         "FormSemestre", lazy="select", uselist=False, foreign_keys=[formsemestre_id]
     )
diff --git a/app/scodoc/gen_tables.py b/app/scodoc/gen_tables.py
index 436ecde25d46710b188aac71b7e2e90369229b33..2b5e867a9259f235bc02ee9b63cc90e34a18034d 100644
--- a/app/scodoc/gen_tables.py
+++ b/app/scodoc/gen_tables.py
@@ -88,7 +88,7 @@ class DEFAULT_TABLE_PREFERENCES(object):
         return self.values[k]
 
 
-class GenTable(object):
+class GenTable:
     """Simple 2D tables with export to HTML, PDF, Excel, CSV.
     Can be sub-classed to generate fancy formats.
     """
@@ -197,6 +197,9 @@ class GenTable(object):
     def __repr__(self):
         return f"<gen_table( nrows={self.get_nb_rows()}, ncols={self.get_nb_cols()} )>"
 
+    def __len__(self):
+        return len(self.rows)
+
     def get_nb_cols(self):
         return len(self.columns_ids)
 
diff --git a/app/scodoc/sco_apogee_csv.py b/app/scodoc/sco_apogee_csv.py
index 2d3b6af440315d7f9ef4405dd2c72e5856ff9eee..e58e05002a075e745262f05e12aced7d77a8fbd9 100644
--- a/app/scodoc/sco_apogee_csv.py
+++ b/app/scodoc/sco_apogee_csv.py
@@ -51,7 +51,14 @@ from app import log
 from app.comp import res_sem
 from app.comp.res_compat import NotesTableCompat
 from app.comp.res_but import ResultatsSemestreBUT
-from app.models import FormSemestre, Identite, ApcValidationAnnee
+from app.models import (
+    ApcValidationAnnee,
+    ApcValidationRCUE,
+    FormSemestre,
+    Identite,
+    ScolarFormSemestreValidation,
+)
+
 from app.models.config import ScoDocSiteConfig
 from app.scodoc.sco_apogee_reader import (
     APO_DECIMAL_SEP,
@@ -64,6 +71,7 @@ from app.scodoc.gen_tables import GenTable
 from app.scodoc.sco_vdi import ApoEtapeVDI
 from app.scodoc.codes_cursus import code_semestre_validant
 from app.scodoc.codes_cursus import (
+    ADSUP,
     DEF,
     DEM,
     NAR,
@@ -903,6 +911,54 @@ class ApoData:
         )
         return T
 
+    def build_adsup_table(self):
+        """Construit une table listant les ADSUP émis depuis les formsemestres
+        NIP nom prenom nom_formsemestre etape UE
+        """
+        validations_ues, validations_rcue = self.list_adsup()
+        rows = [
+            {
+                "code_nip": v.etud.code_nip,
+                "nom": v.etud.nom,
+                "prenom": v.etud.prenom,
+                "formsemestre": v.formsemestre.titre_formation(with_sem_idx=1),
+                "etape": v.formsemestre.etapes_apo_str(),
+                "ue": v.ue.acronyme,
+            }
+            for v in validations_ues
+        ]
+        return GenTable(
+            columns_ids=("code_nip", "nom", "prenom", "formsemestre", "etape", "ue"),
+            titles={
+                "code_nip": "NIP",
+                "nom": "Nom",
+                "prenom": "Prénom",
+                "formsemestre": "Semestre",
+                "etape": "Etape",
+                "ue": "UE",
+            },
+            row=rows,
+            xls_sheet_name="ADSUPs",
+        )
+
+    def list_adsup(
+        self,
+    ) -> tuple[list[ScolarFormSemestreValidation], list[ApcValidationRCUE]]:
+        """Liste les validations ADSUP émises par des formsemestres de cet ensemble"""
+        validations_ues = (
+            ScolarFormSemestreValidation.query.filter_by(code=ADSUP)
+            .filter(ScolarFormSemestreValidation.ue_id != None)
+            .filter(
+                ScolarFormSemestreValidation.formsemestre_id.in_(
+                    self.etape_formsemestre_ids
+                )
+            )
+        )
+        validations_rcue = ApcValidationRCUE.query.filter_by(code=ADSUP).filter(
+            ApcValidationRCUE.formsemestre_id.in_(self.etape_formsemestre_ids)
+        )
+        return validations_ues, validations_rcue
+
 
 def comp_apo_sems(etape_apogee, annee_scolaire: int) -> list[dict]:
     """
@@ -1029,6 +1085,10 @@ def export_csv_to_apogee(
     cr_table = apo_data.build_cr_table()
     cr_xls = cr_table.excel()
 
+    # ADSUPs
+    adsup_table = apo_data.build_adsup_table()
+    adsup_xls = adsup_table.excel() if len(adsup_table) else None
+
     # Create ZIP
     if not dest_zip:
         data = io.BytesIO()
@@ -1054,6 +1114,7 @@ def export_csv_to_apogee(
     log_filename = "scodoc-" + basename + ".log.txt"
     nar_filename = basename + "-nar" + scu.XLSX_SUFFIX
     cr_filename = basename + "-decisions" + scu.XLSX_SUFFIX
+    adsup_filename = f"{basename}-adsups{scu.XLSX_SUFFIX}"
 
     logf = io.StringIO()
     logf.write(f"export_to_apogee du {time.ctime()}\n\n")
@@ -1090,6 +1151,8 @@ def export_csv_to_apogee(
         "\n\nElements Apogee inconnus dans ces semestres ScoDoc:\n"
         + "\n".join(apo_data.list_unknown_elements())
     )
+    if adsup_xls:
+        logf.write(f"\n\nADSUP générés: {len(adsup_table)}\n")
     log(logf.getvalue())  # sortie aussi sur le log ScoDoc
 
     # Write data to ZIP
@@ -1098,6 +1161,8 @@ def export_csv_to_apogee(
     if nar_xls:
         dest_zip.writestr(nar_filename, nar_xls)
     dest_zip.writestr(cr_filename, cr_xls)
+    if adsup_xls:
+        dest_zip.writestr(adsup_filename, adsup_xls)
 
     if my_zip:
         dest_zip.close()
diff --git a/app/scodoc/sco_semset.py b/app/scodoc/sco_semset.py
index c028429356269b73bf348a5208b85787a8fef330..f3d8c6d3a5de815476e95ab8e0357012c450b39c 100644
--- a/app/scodoc/sco_semset.py
+++ b/app/scodoc/sco_semset.py
@@ -42,6 +42,7 @@ sem_set_list()
 import flask
 from flask import g, url_for
 
+from app import log
 from app.comp import res_sem
 from app.comp.res_compat import NotesTableCompat
 from app.models import FormSemestre
@@ -52,7 +53,6 @@ from app.scodoc import sco_formsemestre_status
 from app.scodoc import sco_portal_apogee
 from app.scodoc import sco_preferences
 from app.scodoc.gen_tables import GenTable
-from app import log
 from app.scodoc.sco_etape_bilan import EtapeBilan
 from app.scodoc.sco_exceptions import ScoValueError
 from app.scodoc.sco_vdi import ApoEtapeVDI