diff --git a/app/scodoc/sco_inscr_passage.py b/app/scodoc/sco_inscr_passage.py
index a7564b35d6b0f55c088aaa46b1366c71758ff308..e15818d529f5ec52816f146da24fde13fe070bea 100644
--- a/app/scodoc/sco_inscr_passage.py
+++ b/app/scodoc/sco_inscr_passage.py
@@ -701,6 +701,10 @@ def etuds_select_boxes(
 
                 if not etud.get("paiementinscription", True):
                     elink += '<span class="paspaye"> (non paiement)</span>'
+                if etud.get("datefinalisationinscription"):
+                    elink += f"""<span class="finalise"> (inscr. finalisée le {
+                        etud["datefinalisationinscription"].strftime(scu.DATE_FMT)
+                    })</span>"""
 
                 H.append("""<div class="pas_etud%s">""" % c)
                 if "etape" in etud:
@@ -726,17 +730,36 @@ def etuds_select_boxes(
 def etuds_select_box_xls(src_cat):
     "export a box to excel"
     etuds = src_cat["etuds"]
-    columns_ids = ["etudid", "civilite_str", "nom", "prenom", "etape"]
-    titles = {x: x for x in columns_ids}
-
-    # Ajoute colonne paiement inscription
-    columns_ids.append("paiementinscription_str")
-    titles["paiementinscription_str"] = "paiement inscription"
+    columns_ids = [
+        "etudid",
+        "ine",
+        "nip",
+        "civilite_str",
+        "nom",
+        "prenom",
+        "etape",
+        "paiementinscription_str",
+        "datefinalisationinscription",
+    ]
+    titles = {x: x for x in columns_ids} | {
+        "paiementinscription_str": "Paiement inscr.",
+        "datefinalisationinscription": "Finalisation inscr.",
+    }
     for e in etuds:
         if not e.get("paiementinscription", True):
             e["paiementinscription_str"] = "NON"
         else:
             e["paiementinscription_str"] = "-"
+        # si e est un étudiant Apo, on a nip et ine
+        # mais si e est ScoDoc, on a code_nip et code_ine:
+        e["nip"] = e.get("nip", e.get("code_nip"))
+        e["ine"] = e.get("ine", e.get("code_ine"))
+        # Pour excel, datefinalisationinscription doit être datetime
+        dat = e.get("datefinalisationinscription")
+        if isinstance(dat, datetime.date):
+            e["datefinalisationinscription"] = datetime.datetime.combine(
+                dat, datetime.time.min
+            )
     tab = GenTable(
         caption="%(title)s. %(help)s" % src_cat["infos"],
         columns_ids=columns_ids,
diff --git a/app/scodoc/sco_portal_apogee.py b/app/scodoc/sco_portal_apogee.py
index 634002b8b73cb6c01b97f129fe25564c688b19ab..4da1700b334dcc8a49d4ece16014a74ecd84871f 100644
--- a/app/scodoc/sco_portal_apogee.py
+++ b/app/scodoc/sco_portal_apogee.py
@@ -476,28 +476,37 @@ def get_etapes_apogee_dept():
     return etapes
 
 
-def _portal_date_dmy2date(s):
-    """date inscription renvoyée sous la forme dd/mm/yy
-    renvoie un objet date, ou None
+def _portal_date_dmy2date(s: str) -> datetime.date | None:
+    """s est la date inscription fournie par le portail
+    sous la forme dd/mm/yy
+    Renvoie un objet date, ou None
+    Raises ValueError si format invalide.
     """
     s = s.strip()
     if not s:
         return None
-    else:
-        d, m, y = [int(x) for x in s.split("/")]  # raises ValueError if bad format
-        if y < 100:
-            y += 2000  # 21ème siècle
-        return datetime.date(y, m, d)
+    d, m, y = [int(x) for x in s.split("/")]  # raises ValueError if bad format
+    if y < 100:
+        y += 2000  # 21ème siècle
+    return datetime.date(y, m, d)
 
 
 def _normalize_apo_fields(infolist):
     """
     infolist: liste de dict renvoyés par le portail Apogee
 
-    recode les champs: paiementinscription (-> booleen), datefinalisationinscription (date)
-    ajoute le champ 'paiementinscription_str' : 'ok', 'Non' ou '?'
-    ajoute les champs 'etape' (= None) et 'prenom' ('') s'ils ne sont pas présents.
-    ajoute le champ 'civilite_etat_civil' (=''), et 'prenom_etat_civil' (='') si non présent.
+    Recode les champs:
+    - paiementinscription (-> booleen)
+    - datefinalisationinscription (date)
+
+    Ajoute le champ
+    - 'paiementinscription_str' : 'ok', 'Non' ou '?'
+
+    S'ils ne sont pas présents, ajoute les champs:
+    - 'etape' (None)
+    - 'prenom' ('')
+    - 'civilite_etat_civil' ('')
+    - 'prenom_etat_civil' ('')
     """
     for infos in infolist:
         if "paiementinscription" in infos:
@@ -516,9 +525,11 @@ def _normalize_apo_fields(infolist):
             infos["datefinalisationinscription"] = _portal_date_dmy2date(
                 infos["datefinalisationinscription"]
             )
-            infos["datefinalisationinscription_str"] = infos[
-                "datefinalisationinscription"
-            ].strftime(scu.DATE_FMT)
+            infos["datefinalisationinscription_str"] = (
+                infos["datefinalisationinscription"].strftime(scu.DATE_FMT)
+                if infos["datefinalisationinscription"]
+                else ""
+            )
         else:
             infos["datefinalisationinscription"] = None
             infos["datefinalisationinscription_str"] = ""
diff --git a/app/scodoc/sco_synchro_etuds.py b/app/scodoc/sco_synchro_etuds.py
index e8879d3ad70d54b04677cbfec0714f56abb0ea2d..73bbe928938e3c937cec08a1c36c37c44e6be079 100644
--- a/app/scodoc/sco_synchro_etuds.py
+++ b/app/scodoc/sco_synchro_etuds.py
@@ -523,7 +523,7 @@ def list_synch(sem, annee_apogee=None):
             "etuds": set_to_sorted_list(etuds_ok, is_inscrit=True),
             "infos": {
                 "id": "etuds_ok",
-                "title": "Étudiants dans Apogée et déjà inscrits",
+                "title": "Étudiants dans Apogée et déjà dans ScoDoc",
                 "help": """Ces etudiants sont inscrits dans le semestre ScoDoc et sont présents dans Apogée:
                 tout est donc correct. Décocher les étudiants que vous souhaitez désinscrire.""",
                 "title_target": "",
diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css
index bcba9fb3ee2c56afc485caa16ff5599c4a81f4c1..42f0c175d76036b75e2e6e9bebabb400e8c8ee69 100644
--- a/app/static/css/scodoc.css
+++ b/app/static/css/scodoc.css
@@ -3850,6 +3850,11 @@ span.finalisationinscription {
   color: green;
 }
 
+span.finalise {
+  font-weight: normal;
+  font-style: italic;
+}
+
 .pas_sembox_title a {
   font-weight: bold;
   font-size: 100%;
diff --git a/tools/fakeportal/etud_template.xml b/tools/fakeportal/etud_template.xml
index fd15ad84da8a34c532113306f9009c403c6213f7..57d3ef67f6ec7f5401032d41b348a81272a07c58 100644
--- a/tools/fakeportal/etud_template.xml
+++ b/tools/fakeportal/etud_template.xml
@@ -24,8 +24,8 @@
 	<codepostal_lycee>code postal lycée</codepostal_lycee>
 	<mention>AB</mention>
 	<bourse>N</bourse>
-	<paiementinscription>true</paiementinscription>
-	<datefinalisationinscription></datefinalisationinscription>
+	<paiementinscription>{paiementinscription}</paiementinscription>
+	<datefinalisationinscription>{datefinalisationinscription}</datefinalisationinscription>
 	<ville_naissance>{ville_naissance}</ville_naissance>
 	<code_dep_naissance>{code_dep_naissance}</code_dep_naissance>
 	<libelle_dep_naissance>{libelle_dep_naissance}</libelle_dep_naissance>
diff --git a/tools/fakeportal/fakeportal.py b/tools/fakeportal/fakeportal.py
index 33b81f65af7ed3b8ea92042a4dec026bb03831fb..da21fe3f3ec72c4b7afdc4ec218de4895dbd9f3b 100755
--- a/tools/fakeportal/fakeportal.py
+++ b/tools/fakeportal/fakeportal.py
@@ -80,6 +80,8 @@ def make_random_etud(nip, etape=None, annee=None, template=ETUD_TEMPLATE_FULL):
         ville_naissance=random.choice(("Paris", "Berlin", "Londres", "")),
         code_dep_naissance=random.choice(("75", "99", "89")),
         libelle_dep_naissance="nom département",
+        paiementinscription=random.choice(("true", "false")),
+        datefinalisationinscription=random.choice(("30/10/2024", "1/10/66", "")),
     )
     return data