From d97cb6f309f7b0aa9de9bd8af57799504756d1b1 Mon Sep 17 00:00:00 2001
From: Emmanuel Viennet <emmanuel.viennet@gmail.com>
Date: Mon, 28 Oct 2024 22:16:06 +0100
Subject: [PATCH] =?UTF-8?q?Fix:=20assiduit=C3=A9:=20heures=20des=20assidui?=
 =?UTF-8?q?t=C3=A9s=20cr=C3=A9es=20dans=20log=20et=20journal=20=C3=A9tudia?=
 =?UTF-8?q?nt?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 app/api/assiduites.py            |  4 +++-
 app/models/assiduites.py         | 12 +++++++++---
 app/scodoc/sco_utils.py          |  1 -
 app/static/js/etud_info.js       |  2 +-
 tests/api/test_api_assiduites.py | 32 +++++++++++++++++++++++++++++---
 5 files changed, 42 insertions(+), 9 deletions(-)

diff --git a/app/api/assiduites.py b/app/api/assiduites.py
index 5471d0a8..36d31d9b 100644
--- a/app/api/assiduites.py
+++ b/app/api/assiduites.py
@@ -650,7 +650,9 @@ def assiduites_formsemestre_count(
 @permission_required(Permission.AbsChange)
 def assiduite_create(etudid: int = None, nip=None, ine=None):
     """
-    Enregistrement d'assiduités pour un étudiant (etudid)
+    Enregistrement d'assiduités pour un étudiant (etudid).
+
+    Si les heures n'ont pas de timezone, elles sont exprimées dans celle du serveur.
 
     DATA
     ----
diff --git a/app/models/assiduites.py b/app/models/assiduites.py
index 7104c86a..5c36a171 100644
--- a/app/models/assiduites.py
+++ b/app/models/assiduites.py
@@ -124,19 +124,25 @@ class Assiduite(ScoDocModel):
         return data
 
     def __str__(self) -> str:
-        "chaine pour journaux et debug (lisible par humain français)"
+        "chaine pour journaux et debug (lisible par humain français, en timezone serveur)"
         try:
             etat_str = EtatAssiduite(self.etat).name.lower().capitalize()
         except ValueError:
             etat_str = "Invalide"
+        # passe en timezone serveur
+        d_deb = self.date_debut.astimezone(scu.TIME_ZONE)
+        d_fin = self.date_fin.astimezone(scu.TIME_ZONE)
         return f"""{etat_str} {
                 "just." if self.est_just else "non just."
             } de {
-                self.date_debut.strftime("%d/%m/%Y %Hh%M")
+                d_deb.strftime("%d/%m/%Y %Hh%M")
             } à {
-                self.date_fin.strftime("%d/%m/%Y %Hh%M")
+                d_fin.strftime("%d/%m/%Y %Hh%M")
             }"""
 
+    def __repr__(self) -> str:
+        return f"<Assiduite {self.id}: {self.__str__()}>"
+
     @classmethod
     def create_assiduite(
         cls,
diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py
index 20c351da..50f767a4 100644
--- a/app/scodoc/sco_utils.py
+++ b/app/scodoc/sco_utils.py
@@ -432,7 +432,6 @@ def localize_datetime(date: datetime.datetime) -> datetime.datetime:
     Tente de mettre l'offset de la timezone du serveur (ex : UTC+1)
     Si erreur, mettra l'offset UTC
     """
-
     new_date: datetime.datetime = date
     if new_date.tzinfo is None:
         try:
diff --git a/app/static/js/etud_info.js b/app/static/js/etud_info.js
index 56e59858..4fbcb42b 100644
--- a/app/static/js/etud_info.js
+++ b/app/static/js/etud_info.js
@@ -5,7 +5,7 @@
 function get_etudid_from_elem(e) {
   // renvoie l'etudid, obtenu a partir de l'id de l'element
   // qui est soit de la forme xxxx-etudid, soit tout simplement etudid
-  var etudid = e.id.split("-")[1];
+  let etudid = e.id.split("-")[1];
   if (etudid == undefined) {
     return e.id;
   } else {
diff --git a/tests/api/test_api_assiduites.py b/tests/api/test_api_assiduites.py
index a95f06cf..c860e573 100644
--- a/tests/api/test_api_assiduites.py
+++ b/tests/api/test_api_assiduites.py
@@ -5,9 +5,11 @@ Ecrit par HARTMANN Matthias
 
 """
 
+import datetime
 from random import randint
 from types import NoneType
 
+from app.scodoc import sco_utils as scu
 from tests.api.setup_test_api import (
     GET,
     POST,
@@ -265,15 +267,39 @@ def test_route_create(api_admin_headers):
     )
     check_fields(res, BATCH_FIELD)
     assert len(res["success"]) == 1
-
     TO_REMOVE.append(res["success"][0]["message"]["assiduite_id"])
-    data = GET(
+    data_get = GET(
         path=f'/assiduite/{res["success"][0]["message"]["assiduite_id"]}',
         headers=api_admin_headers,
         dept=DEPT_ACRONYM,
     )
-    check_fields(data, fields=ASSIDUITES_FIELDS)
+    check_fields(data_get, fields=ASSIDUITES_FIELDS)
+    # la date de début est sans fournie sans timezone, mais celle renvoyé avec.
+    # Compare en ajoutant la timezone serveur:
+    assert scu.localize_datetime(
+        datetime.datetime.fromisoformat(data["date_debut"])
+    ) == datetime.datetime.fromisoformat(data_get["date_debut"])
+
+    # Création avec timezone (comme le fait assiduite.js)
+    data["date_debut"] = "2024-10-28T10:00:00.000Z"
+    data["date_fin"] = "2024-10-28T12:00:00.000Z"
+    res = POST(
+        f"/assiduite/{ETUDID}/create", [data], api_admin_headers, dept=DEPT_ACRONYM
+    )
+    check_fields(res, BATCH_FIELD)
+    assert len(res["success"]) == 1
+    TO_REMOVE.append(res["success"][0]["message"]["assiduite_id"])
+    data_get = GET(
+        path=f'/assiduite/{res["success"][0]["message"]["assiduite_id"]}',
+        headers=api_admin_headers,
+        dept=DEPT_ACRONYM,
+    )
+    check_fields(data_get, fields=ASSIDUITES_FIELDS)
+    assert scu.localize_datetime(
+        datetime.datetime.fromisoformat(data["date_debut"])
+    ) == datetime.datetime.fromisoformat(data_get["date_debut"])
 
+    # Absence avec module
     data2 = create_data("absent", "04", MODULE, "desc")
     res = POST(
         f"/assiduite/{ETUDID}/create", [data2], api_admin_headers, dept=DEPT_ACRONYM
-- 
GitLab