diff --git a/app/scodoc/sco_abs_billets.py b/app/scodoc/sco_abs_billets.py
index 5f05ddba..d281b312 100644
--- a/app/scodoc/sco_abs_billets.py
+++ b/app/scodoc/sco_abs_billets.py
@@ -1,153 +1,162 @@
-# -*- mode: python -*-
-# -*- coding: utf-8 -*-
-
-##############################################################################
-#
-# Gestion scolarite IUT
-#
-# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-# Emmanuel Viennet emmanuel.viennet@viennet.net
-#
-##############################################################################
-
-"""Fonctions sur les billets d'absences
-"""
-
-from flask import g, url_for
-import flask_sqlalchemy
-from app.models.absences import BilletAbsence
-from app.models.etudiants import Identite
-from app.scodoc.gen_tables import GenTable
-from app.scodoc import sco_preferences
-
-
-def query_billets_etud(
- etudid: int = None, etat: bool = None
-) -> flask_sqlalchemy.BaseQuery:
- """Billets d'absences pour un étudiant, ou tous si etudid is None.
- Si etat, filtre par état.
- Si dans un département et que la gestion des billets n'a pas été activée
- dans ses préférences, table toujours vide.
- """
- if g.scodoc_dept is not None and not sco_preferences.get_preference(
- "handle_billets_abs"
- ):
- return []
- billets = BilletAbsence.query
- if etudid is not None:
- billets = billets.filter_by(etudid=etudid)
- if etat is not None:
- billets = billets.filter_by(etat=False)
- if g.scodoc_dept is not None:
- # jointure avec departement de l'étudiant
- billets = billets.join(BilletAbsence.etudiant).filter_by(
- dept_id=g.scodoc_dept_id
- )
- return billets
-
-
-def table_billets_etud(
- etudid: int = None, etat: bool = None, with_links=True
-) -> GenTable:
- """Page avec table billets."""
- etud = Identite.query.get_or_404(etudid) if etudid is not None else None
- billets = query_billets_etud(etudid, etat)
- return table_billets(billets, etud=etud, with_links=with_links)
-
-
-def table_billets(
- billets: list[BilletAbsence], etud: Identite = None, title="", with_links=True
-) -> GenTable:
- """Construit une table de billets d'absences"""
- rows = []
- for billet in billets:
- billet_dict = billet.to_dict()
- rows.append(billet_dict)
- if billet_dict["abs_begin"].hour < 12:
- m = " matin"
- else:
- m = " après-midi"
- billet_dict["abs_begin_str"] = billet.abs_begin.strftime("%d/%m/%Y") + m
- if billet.abs_end.hour < 12:
- m = " matin"
- else:
- m = " après-midi"
- billet_dict["abs_end_str"] = billet.abs_end.strftime("%d/%m/%Y") + m
- if billet.etat == 0:
- if billet.justified:
- billet_dict["etat_str"] = "à traiter"
- else:
- billet_dict["etat_str"] = "à justifier"
- if with_links:
- if etud:
- billet_dict["_etat_str_target"] = url_for(
- "absences.process_billet_absence_form",
- billet_id=billet_dict["billet_id"],
- scodoc_dept=billet.etudiant.departement.acronym,
- etudid=etud.id,
- )
- else:
- billet_dict["_etat_str_target"] = url_for(
- "absences.process_billet_absence_form",
- billet_id=billet_dict["billet_id"],
- scodoc_dept=g.scodoc_dept,
- )
- billet_dict["_billet_id_target"] = billet_dict["_etat_str_target"]
- else:
- billet_dict["etat_str"] = "ok"
- if not etud:
- # ajoute info etudiant
- if not billet.etudiant:
- billet_dict["nomprenom"] = "???" # should not occur
- else:
- billet_dict["nomprenom"] = billet.etudiant.nomprenom
- billet_dict["_nomprenom_disp_order"] = billet.etudiant.sort_key
- billet_dict[
- "_nomprenom_td_attrs"
- ] = f'id="{billet.etudiant.id}" class="etudinfo"'
- if with_links:
- billet_dict["_nomprenom_target"] = url_for(
- "scolar.ficheEtud",
- scodoc_dept=g.scodoc_dept,
- etudid=billet_dict["etudid"],
- )
-
- if etud and not title:
- title = f"Billets d'absence déclarés par {etud.nomprenom}"
-
- columns_ids = ["billet_id"]
- if not etud:
- columns_ids += ["nomprenom"]
- columns_ids += ["abs_begin_str", "abs_end_str", "description", "etat_str"]
- tab = GenTable(
- titles={
- "billet_id": "Numéro",
- "abs_begin_str": "Début",
- "abs_end_str": "Fin",
- "description": "Raison de l'absence",
- "etat_str": "Etat",
- },
- columns_ids=columns_ids,
- page_title=title,
- html_title=f"
{title}
",
- preferences=sco_preferences.SemPreferences(),
- rows=rows,
- html_sortable=True,
- html_class="table_leftalign",
- )
- return tab
+# -*- mode: python -*-
+# -*- coding: utf-8 -*-
+
+##############################################################################
+#
+# Gestion scolarite IUT
+#
+# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Emmanuel Viennet emmanuel.viennet@viennet.net
+#
+##############################################################################
+
+"""Fonctions sur les billets d'absences
+"""
+
+from flask import g, url_for
+import flask_sqlalchemy
+from app.models.absences import BilletAbsence
+from app.models.etudiants import Identite
+from app.scodoc.gen_tables import GenTable
+from app.scodoc import sco_preferences
+
+
+def query_billets_etud(
+ etudid: int = None, etat: bool = None
+) -> flask_sqlalchemy.BaseQuery:
+ """Billets d'absences pour un étudiant, ou tous si etudid is None.
+ Si etat, filtre par état.
+ Si dans un département et que la gestion des billets n'a pas été activée
+ dans ses préférences, table toujours vide.
+ """
+ if g.scodoc_dept is not None and not sco_preferences.get_preference(
+ "handle_billets_abs"
+ ):
+ return []
+ billets = BilletAbsence.query
+ if etudid is not None:
+ billets = billets.filter_by(etudid=etudid)
+ if etat is not None:
+ billets = billets.filter_by(etat=False)
+ if g.scodoc_dept is not None:
+ # jointure avec departement de l'étudiant
+ billets = billets.join(BilletAbsence.etudiant).filter_by(
+ dept_id=g.scodoc_dept_id
+ )
+ return billets
+
+
+def table_billets_etud(
+ etudid: int = None, etat: bool = None, with_links=True
+) -> GenTable:
+ """Page avec table billets."""
+ etud = Identite.query.get_or_404(etudid) if etudid is not None else None
+ billets = query_billets_etud(etudid, etat)
+ return table_billets(billets, etud=etud, with_links=with_links)
+
+
+def table_billets(
+ billets: list[BilletAbsence], etud: Identite = None, title="", with_links=True
+) -> GenTable:
+ """Construit une table de billets d'absences"""
+ rows = []
+ for billet in billets:
+ billet_dict = billet.to_dict()
+ rows.append(billet_dict)
+ billet_dict["_nomprenom_order"] = (
+ billet.etudiant.sort_key if billet.etudiant else ""
+ )
+ billet_dict["_abs_begin_str_order"] = (
+ billet.abs_begin.isoformat() if billet.abs_begin else ""
+ )
+ billet_dict["_abs_begin_str_order"] = (
+ billet.abs_begin.isoformat() if billet.abs_end else ""
+ )
+ if billet_dict["abs_begin"].hour < 12:
+ m = " matin"
+ else:
+ m = " après-midi"
+ billet_dict["abs_begin_str"] = billet.abs_begin.strftime("%d/%m/%Y") + m
+ if billet.abs_end.hour < 12:
+ m = " matin"
+ else:
+ m = " après-midi"
+ billet_dict["abs_end_str"] = billet.abs_end.strftime("%d/%m/%Y") + m
+ if billet.etat == 0:
+ if billet.justified:
+ billet_dict["etat_str"] = "à traiter"
+ else:
+ billet_dict["etat_str"] = "à justifier"
+ if with_links:
+ if etud:
+ billet_dict["_etat_str_target"] = url_for(
+ "absences.process_billet_absence_form",
+ billet_id=billet_dict["billet_id"],
+ scodoc_dept=billet.etudiant.departement.acronym,
+ etudid=etud.id,
+ )
+ else:
+ billet_dict["_etat_str_target"] = url_for(
+ "absences.process_billet_absence_form",
+ billet_id=billet_dict["billet_id"],
+ scodoc_dept=g.scodoc_dept,
+ )
+ billet_dict["_billet_id_target"] = billet_dict["_etat_str_target"]
+ else:
+ billet_dict["etat_str"] = "ok"
+ if not etud:
+ # ajoute info etudiant
+ if not billet.etudiant:
+ billet_dict["nomprenom"] = "???" # should not occur
+ else:
+ billet_dict["nomprenom"] = billet.etudiant.nomprenom
+ billet_dict["_nomprenom_order"] = billet.etudiant.sort_key
+ billet_dict[
+ "_nomprenom_td_attrs"
+ ] = f'id="{billet.etudiant.id}" class="etudinfo"'
+ if with_links:
+ billet_dict["_nomprenom_target"] = url_for(
+ "scolar.ficheEtud",
+ scodoc_dept=g.scodoc_dept,
+ etudid=billet_dict["etudid"],
+ )
+
+ if etud and not title:
+ title = f"Billets d'absence déclarés par {etud.nomprenom}"
+
+ columns_ids = ["billet_id"]
+ if not etud:
+ columns_ids += ["nomprenom"]
+ columns_ids += ["abs_begin_str", "abs_end_str", "description", "etat_str"]
+ tab = GenTable(
+ titles={
+ "billet_id": "Numéro",
+ "abs_begin_str": "Début",
+ "abs_end_str": "Fin",
+ "description": "Raison de l'absence",
+ "etat_str": "Etat",
+ },
+ columns_ids=columns_ids,
+ page_title=title,
+ html_title=f"{title}
",
+ preferences=sco_preferences.SemPreferences(),
+ rows=rows,
+ html_sortable=True,
+ html_class="table_leftalign",
+ )
+ return tab