From 10de8c4cc26178b293cf8281ad63bbcc5cc99530 Mon Sep 17 00:00:00 2001
From: Emmanuel Viennet <emmanuel.viennet@gmail.com>
Date: Sun, 2 Jul 2023 12:09:17 +0200
Subject: [PATCH] Export Apogee: ajout table ADSUPs

---
 app/but/jury_but.py           |  1 +
 app/models/but_validations.py |  2 +-
 app/models/validations.py     |  1 +
 app/scodoc/gen_tables.py      |  5 ++-
 app/scodoc/sco_apogee_csv.py  | 67 ++++++++++++++++++++++++++++++++++-
 app/scodoc/sco_semset.py      |  2 +-
 6 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/app/but/jury_but.py b/app/but/jury_but.py
index 99ea43685..05978de2d 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 fcab132bd..185ab5398 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 91f17f605..d4ca5bb07 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 436ecde25..2b5e867a9 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 2d3b6af44..e58e05002 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 c02842935..f3d8c6d3a 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
-- 
GitLab