2023-09-20 22:38:01 +02:00
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
# Copyright (c) 1999 - 2023 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
# module codé par Matthias Hartmann, 2023
#
##############################################################################
2023-04-17 15:44:55 +02:00
import datetime
2023-09-06 11:21:53 +02:00
from flask import g , request , render_template , flash
from flask import abort , url_for , redirect
2023-08-29 19:30:56 +02:00
from flask_login import current_user
2023-04-17 15:44:55 +02:00
2023-07-26 13:27:57 +02:00
from app import db
2023-04-17 15:44:55 +02:00
from app . comp import res_sem
from app . comp . res_compat import NotesTableCompat
from app . decorators import (
scodoc ,
permission_required ,
)
2023-07-25 19:59:47 +02:00
from app . models import (
FormSemestre ,
Identite ,
ScoDocSiteConfig ,
Assiduite ,
2023-09-08 11:59:10 +02:00
Justificatif ,
2023-07-25 19:59:47 +02:00
Departement ,
2023-09-06 11:21:53 +02:00
Evaluation ,
2023-07-25 19:59:47 +02:00
)
2023-04-17 15:44:55 +02:00
from app . views import assiduites_bp as bp
from app . views import ScoData
# ---------------
from app . scodoc . sco_permissions import Permission
from app . scodoc import html_sco_header
2023-08-29 19:30:56 +02:00
from app . scodoc import safehtml
2023-04-17 15:44:55 +02:00
from app . scodoc import sco_moduleimpl
from app . scodoc import sco_preferences
from app . scodoc import sco_groups_view
from app . scodoc import sco_etud
from app . scodoc import sco_find_etud
2023-05-30 17:16:07 +02:00
from app . scodoc import sco_assiduites as scass
2023-08-29 19:30:56 +02:00
from app . scodoc import sco_utils as scu
from app . scodoc . sco_exceptions import ScoValueError
2023-04-17 15:44:55 +02:00
2023-07-10 17:38:50 +02:00
from app . tables . visu_assiduites import TableAssi , etuds_sorted_from_ids
2023-04-17 15:44:55 +02:00
CSSSTYLES = html_sco_header . BOOTSTRAP_MULTISELECT_CSS
# --- UTILS ---
class HTMLElement :
""" Représentation d ' un HTMLElement version Python """
def __init__ ( self , tag : str , * attr , * * kattr ) - > None :
self . tag : str = tag
2023-09-14 12:08:20 +02:00
self . children : list [ " HTMLElement " ] = [ ]
2023-04-17 15:44:55 +02:00
self . self_close : bool = kattr . get ( " self_close " , False )
self . text_content : str = kattr . get ( " text_content " , " " )
self . key_attributes : dict [ str , any ] = kattr
self . attributes : list [ str ] = list ( attr )
2023-09-14 12:08:20 +02:00
def add ( self , * child : " HTMLElement " ) - > None :
2023-04-17 15:44:55 +02:00
""" add child element to self """
for kid in child :
self . children . append ( kid )
2023-09-14 12:08:20 +02:00
def remove ( self , child : " HTMLElement " ) - > None :
2023-04-17 15:44:55 +02:00
""" Remove child element from self """
if child in self . children :
self . children . remove ( child )
def __str__ ( self ) - > str :
attr : list [ str ] = self . attributes
for att , val in self . key_attributes . items ( ) :
if att in ( " self_close " , " text_content " ) :
continue
if att != " cls " :
attr . append ( f ' { att } = " { val } " ' )
else :
attr . append ( f ' class= " { val } " ' )
if not self . self_close :
head : str = f " < { self . tag } { ' ' . join ( attr ) } > { self . text_content } "
body : str = " \n " . join ( map ( str , self . children ) )
foot : str = f " </ { self . tag } > "
return head + body + foot
return f " < { self . tag } { ' ' . join ( attr ) } /> "
def __add__ ( self , other : str ) :
return str ( self ) + other
def __radd__ ( self , other : str ) :
return other + str ( self )
class HTMLStringElement ( HTMLElement ) :
""" Utilisation d ' une chaine de caracètres pour représenter un element """
def __init__ ( self , text : str ) - > None :
self . text : str = text
HTMLElement . __init__ ( self , " textnode " )
def __str__ ( self ) - > str :
return self . text
class HTMLBuilder :
2023-09-12 19:57:39 +02:00
def __init__ ( self , * content : HTMLElement | str ) - > None :
self . content : list [ HTMLElement | str ] = list ( content )
2023-04-17 15:44:55 +02:00
2023-09-12 19:57:39 +02:00
def add ( self , * element : HTMLElement | str ) :
2023-04-17 15:44:55 +02:00
self . content . extend ( element )
2023-09-12 19:57:39 +02:00
def remove ( self , element : HTMLElement | str ) :
2023-04-17 15:44:55 +02:00
if element in self . content :
self . content . remove ( element )
def __str__ ( self ) - > str :
return " \n " . join ( map ( str , self . content ) )
def build ( self ) - > str :
return self . __str__ ( )
# --------------------------------------------------------------------
#
2023-09-21 08:46:21 +02:00
# Assiduité (/ScoDoc/<dept>/Scolarite/Assiduites/...)
2023-04-17 15:44:55 +02:00
#
# --------------------------------------------------------------------
@bp.route ( " / " )
2023-09-13 15:19:21 +02:00
@bp.route ( " /BilanDept " )
2023-04-17 15:44:55 +02:00
@scodoc
2023-07-25 14:03:09 +02:00
@permission_required ( Permission . ScoAbsChange )
2023-09-13 15:19:21 +02:00
def bilan_dept ( ) :
2023-04-17 15:44:55 +02:00
""" Gestionnaire assiduités, page principale """
H = [
html_sco_header . sco_header (
2023-09-19 23:04:46 +02:00
page_title = " Saisie de l ' assiduité " ,
2023-06-28 17:15:24 +02:00
javascripts = [
" js/assiduites.js " ,
" libjs/moment.new.min.js " ,
" libjs/moment-timezone.js " ,
] ,
cssstyles = [
" css/assiduites.css " ,
] ,
2023-04-17 15:44:55 +02:00
) ,
2023-09-19 23:04:46 +02:00
""" <h2>Traitement de l ' assiduité</h2>
2023-04-17 15:44:55 +02:00
< p class = " help " >
2023-09-19 23:04:46 +02:00
Pour saisir l ' assiduité ou consulter les états, il est recommandé de passer par
2023-06-28 17:15:24 +02:00
le semestre concerné ( saisie par jour ou saisie différée ) .
2023-04-17 15:44:55 +02:00
< / p >
""" ,
]
H . append (
2023-09-19 23:04:46 +02:00
""" <p class= " help " >Pour signaler, annuler ou justifier l ' assiduité d ' un seul étudiant,
choisissez d ' abord la personne concernée :</p> " " "
2023-04-17 15:44:55 +02:00
)
2023-09-11 11:11:00 +02:00
H . append ( sco_find_etud . form_search_etud ( dest_url = " assiduites.bilan_etud " ) )
if current_user . has_permission (
Permission . ScoAbsChange
) and sco_preferences . get_preference ( " handle_billets_abs " ) :
H . append (
f """
< h2 style = " margin-top: 30px; " > Billets d ' absence</h2>
< ul > < li > < a href = " { url_for( " absences . list_billets " , scodoc_dept=g.scodoc_dept)
} " >Traitement des billets d ' absence en attente</a>
< / li > < / ul >
"""
)
2023-09-12 09:41:50 +02:00
dept : Departement = Departement . query . filter_by ( id = g . scodoc_dept_id ) . first ( )
2023-09-12 09:37:03 +02:00
annees : list [ int ] = sorted (
[ f . date_debut . year for f in dept . formsemestres ] ,
reverse = True ,
)
2023-09-13 15:19:21 +02:00
annee = scu . annee_scolaire ( )
2023-09-12 09:37:03 +02:00
annees_str : str = " [ "
for ann in annees :
annees_str + = f " { ann } , "
annees_str + = " ] "
2023-06-28 17:15:24 +02:00
2023-09-13 15:19:21 +02:00
formsemestre_id = request . args . get ( " formsemestre_id " , " " )
if formsemestre_id :
try :
formsemestre : FormSemestre = FormSemestre . get_formsemestre ( formsemestre_id )
annee = formsemestre . annee_scolaire ( )
except AttributeError :
formsemestre_id = " "
2023-06-28 17:15:24 +02:00
H . append (
render_template (
" assiduites/pages/bilan_dept.j2 " ,
dept_id = g . scodoc_dept_id ,
2023-09-13 15:19:21 +02:00
annee = annee ,
2023-09-12 09:37:03 +02:00
annees = annees_str ,
2023-09-13 15:19:21 +02:00
formsemestre_id = formsemestre_id ,
group_id = request . args . get ( " group_id " , " " ) ,
2023-06-28 17:15:24 +02:00
) ,
)
2023-04-17 15:44:55 +02:00
H . append ( html_sco_header . sco_footer ( ) )
return " \n " . join ( H )
2023-09-18 16:27:07 +02:00
# @bp.route("/ListeSemestre")
# @scodoc
# @permission_required(Permission.ScoView)
# def liste_assiduites_formsemestre():
# """
# liste_assiduites_etud Affichage de toutes les assiduites et justificatifs d'un etudiant
# Args:
# etudid (int): l'identifiant de l'étudiant
# Returns:
# str: l'html généré
# """
# formsemestre_id = request.args.get("formsemestre_id", -1)
# formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
# if formsemestre.dept_id != g.scodoc_dept_id:
# abort(404, "FormSemestre inexistant dans ce département")
# header: str = html_sco_header.sco_header(
# page_title="Liste des assiduités du semestre",
# init_qtip=True,
# javascripts=[
# "js/assiduites.js",
# "libjs/moment.new.min.js",
# "libjs/moment-timezone.js",
# ],
# cssstyles=CSSSTYLES
# + [
# "css/assiduites.css",
# ],
# )
# return HTMLBuilder(
# header,
# render_template(
# "assiduites/pages/liste_semestre.j2",
# sco=ScoData(formsemestre=formsemestre),
# sem=formsemestre.titre_annee(),
# formsemestre_id=formsemestre.id,
# ),
# ).build()
2023-09-15 10:51:40 +02:00
2023-04-17 15:44:55 +02:00
@bp.route ( " /SignaleAssiduiteEtud " )
@scodoc
2023-07-25 14:03:09 +02:00
@permission_required ( Permission . ScoAbsChange )
2023-04-17 15:44:55 +02:00
def signal_assiduites_etud ( ) :
"""
signal_assiduites_etud Saisie de l ' assiduité d ' un étudiant
Args :
etudid ( int ) : l ' identifiant de l ' étudiant
Returns :
str : l ' html généré
"""
etudid = request . args . get ( " etudid " , - 1 )
etud : Identite = Identite . query . get_or_404 ( etudid )
if etud . dept_id != g . scodoc_dept_id :
abort ( 404 , " étudiant inexistant dans ce département " )
2023-09-06 11:21:53 +02:00
date = request . args . get ( " date " , datetime . date . today ( ) . isoformat ( ) )
# gestion évaluations
saisie_eval : bool = request . args . get ( " saisie_eval " ) is not None
date_deb : str = request . args . get ( " date_deb " )
date_fin : str = request . args . get ( " date_fin " )
moduleimpl_id : int = request . args . get ( " moduleimpl_id " , " " )
evaluation_id : int = request . args . get ( " evaluation_id " )
redirect_url : str = (
" # "
if not saisie_eval
else url_for (
" notes.evaluation_check_absences_html " ,
evaluation_id = evaluation_id ,
scodoc_dept = g . scodoc_dept ,
)
)
2023-04-17 15:44:55 +02:00
header : str = html_sco_header . sco_header (
2023-09-21 08:46:21 +02:00
page_title = " Saisie assiduité " ,
2023-04-17 15:44:55 +02:00
init_qtip = True ,
javascripts = [
" js/assiduites.js " ,
" libjs/moment.new.min.js " ,
" libjs/moment-timezone.js " ,
2023-09-04 14:27:48 +02:00
" js/etud_info.js " ,
2023-04-17 15:44:55 +02:00
] ,
2023-06-12 17:54:30 +02:00
cssstyles = [
2023-04-17 15:44:55 +02:00
" css/assiduites.css " ,
] ,
)
2023-04-25 22:59:06 +02:00
# Gestion des horaires (journée, matin, soir)
2023-09-20 22:38:01 +02:00
morning = ScoDocSiteConfig . assi_get_rounded_time ( " assi_morning_time " , " 08:00:00 " )
lunch = ScoDocSiteConfig . assi_get_rounded_time ( " assi_lunch_time " , " 13:00:00 " )
afternoon = ScoDocSiteConfig . assi_get_rounded_time (
" assi_afternoon_time " , " 18:00:00 "
)
2023-04-25 22:59:06 +02:00
2023-06-12 17:54:30 +02:00
select = """
< select class = " dynaSelect " >
< option value = " " selected > Non spécifié < / option >
< / select >
"""
2023-04-17 15:44:55 +02:00
return HTMLBuilder (
header ,
2023-05-30 10:17:49 +02:00
_mini_timeline ( ) ,
2023-04-17 15:44:55 +02:00
render_template (
2023-06-20 08:33:49 +02:00
" assiduites/pages/signal_assiduites_etud.j2 " ,
2023-04-17 15:44:55 +02:00
sco = ScoData ( etud ) ,
2023-09-06 11:21:53 +02:00
date = date ,
2023-04-25 22:59:06 +02:00
morning = morning ,
lunch = lunch ,
2023-05-17 20:18:02 +02:00
timeline = _timeline ( ) ,
2023-04-25 22:59:06 +02:00
afternoon = afternoon ,
2023-05-30 11:47:59 +02:00
nonworkdays = _non_work_days ( ) ,
2023-04-25 22:59:06 +02:00
forcer_module = sco_preferences . get_preference (
" forcer_module " , dept_id = g . scodoc_dept_id
) ,
2023-06-12 17:54:30 +02:00
moduleimpl_select = _dynamic_module_selector ( ) ,
diff = _differee (
etudiants = [ sco_etud . get_etud_info ( etudid = etud . etudid , filled = True ) [ 0 ] ] ,
moduleimpl_select = select ,
) ,
2023-09-06 11:21:53 +02:00
saisie_eval = saisie_eval ,
date_deb = date_deb ,
date_fin = date_fin ,
redirect_url = redirect_url ,
moduleimpl_id = moduleimpl_id ,
2023-04-17 15:44:55 +02:00
) ,
) . build ( )
2023-04-20 18:04:21 +02:00
@bp.route ( " /ListeAssiduitesEtud " )
@scodoc
2023-06-30 17:24:16 +02:00
@permission_required ( Permission . ScoView )
2023-04-20 18:04:21 +02:00
def liste_assiduites_etud ( ) :
"""
liste_assiduites_etud Affichage de toutes les assiduites et justificatifs d ' un etudiant
Args :
etudid ( int ) : l ' identifiant de l ' étudiant
Returns :
str : l ' html généré
"""
etudid = request . args . get ( " etudid " , - 1 )
etud : Identite = Identite . query . get_or_404 ( etudid )
if etud . dept_id != g . scodoc_dept_id :
abort ( 404 , " étudiant inexistant dans ce département " )
2023-09-11 15:55:18 +02:00
assiduite_id : int = request . args . get ( " assiduite_id " , - 1 )
2023-04-20 18:04:21 +02:00
header : str = html_sco_header . sco_header (
2023-09-19 23:04:46 +02:00
page_title = f " Assiduité de { etud . nomprenom } " ,
2023-04-20 18:04:21 +02:00
init_qtip = True ,
javascripts = [
" js/assiduites.js " ,
" libjs/moment.new.min.js " ,
" libjs/moment-timezone.js " ,
] ,
cssstyles = CSSSTYLES
+ [
" css/assiduites.css " ,
] ,
)
return HTMLBuilder (
header ,
render_template (
2023-06-20 08:33:49 +02:00
" assiduites/pages/liste_assiduites.j2 " ,
2023-04-20 18:04:21 +02:00
sco = ScoData ( etud ) ,
date = datetime . date . today ( ) . isoformat ( ) ,
2023-09-11 15:55:18 +02:00
assi_id = assiduite_id ,
2023-09-12 09:37:03 +02:00
assi_limit_annee = sco_preferences . get_preference (
" assi_limit_annee " ,
dept_id = g . scodoc_dept_id ,
) ,
2023-04-20 18:04:21 +02:00
) ,
) . build ( )
2023-06-28 17:15:24 +02:00
@bp.route ( " /BilanEtud " )
@scodoc
2023-06-30 17:24:16 +02:00
@permission_required ( Permission . ScoView )
2023-06-28 17:15:24 +02:00
def bilan_etud ( ) :
"""
bilan_etud Affichage de toutes les assiduites et justificatifs d ' un etudiant
Args :
etudid ( int ) : l ' identifiant de l ' étudiant
Returns :
str : l ' html généré
"""
etudid = request . args . get ( " etudid " , - 1 )
etud : Identite = Identite . query . get_or_404 ( etudid )
if etud . dept_id != g . scodoc_dept_id :
abort ( 404 , " étudiant inexistant dans ce département " )
header : str = html_sco_header . sco_header (
2023-09-19 23:04:46 +02:00
page_title = f " Bilan de l ' assiduité de { etud . nomprenom } " ,
2023-06-28 17:15:24 +02:00
init_qtip = True ,
javascripts = [
" js/assiduites.js " ,
" libjs/moment.new.min.js " ,
" libjs/moment-timezone.js " ,
] ,
cssstyles = CSSSTYLES
+ [
" css/assiduites.css " ,
] ,
)
date_debut : str = f " { scu . annee_scolaire ( ) } -09-01 "
date_fin : str = f " { scu . annee_scolaire ( ) + 1 } -06-30 "
2023-08-22 15:43:10 +02:00
assi_metric = scu . translate_assiduites_metric (
sco_preferences . get_preference ( " assi_metrique " , dept_id = g . scodoc_dept_id ) ,
2023-08-14 01:08:04 +02:00
)
2023-06-28 17:15:24 +02:00
return HTMLBuilder (
header ,
render_template (
" assiduites/pages/bilan_etud.j2 " ,
sco = ScoData ( etud ) ,
date_debut = date_debut ,
date_fin = date_fin ,
assi_metric = assi_metric ,
assi_seuil = _get_seuil ( ) ,
2023-09-12 09:37:03 +02:00
assi_limit_annee = sco_preferences . get_preference (
" assi_limit_annee " ,
dept_id = g . scodoc_dept_id ,
) ,
2023-06-28 17:15:24 +02:00
) ,
) . build ( )
2023-06-20 15:50:56 +02:00
@bp.route ( " /AjoutJustificatifEtud " )
@scodoc
2023-07-25 14:03:09 +02:00
@permission_required ( Permission . ScoAbsChange )
2023-06-20 15:50:56 +02:00
def ajout_justificatif_etud ( ) :
"""
ajout_justificatif_etud : Affichage et création / modification des justificatifs de l ' étudiant
Args :
etudid ( int ) : l ' identifiant de l ' étudiant
Returns :
str : l ' html généré
"""
etudid = request . args . get ( " etudid " , - 1 )
etud : Identite = Identite . query . get_or_404 ( etudid )
if etud . dept_id != g . scodoc_dept_id :
abort ( 404 , " étudiant inexistant dans ce département " )
header : str = html_sco_header . sco_header (
page_title = " Justificatifs " ,
init_qtip = True ,
javascripts = [
" js/assiduites.js " ,
" libjs/moment.new.min.js " ,
" libjs/moment-timezone.js " ,
] ,
cssstyles = CSSSTYLES
+ [
" css/assiduites.css " ,
] ,
)
return HTMLBuilder (
header ,
render_template (
" assiduites/pages/ajout_justificatif.j2 " ,
sco = ScoData ( etud ) ,
2023-09-12 09:37:03 +02:00
assi_limit_annee = sco_preferences . get_preference (
" assi_limit_annee " ,
dept_id = g . scodoc_dept_id ,
) ,
2023-09-12 09:41:50 +02:00
assi_morning = ScoDocSiteConfig . get ( " assi_morning_time " , " 08:00 " ) ,
2023-09-27 08:27:13 +02:00
assi_evening = ScoDocSiteConfig . get ( " assi_afternoon_time " , " 18:00 " ) ,
2023-06-20 15:50:56 +02:00
) ,
) . build ( )
2023-06-22 16:25:13 +02:00
@bp.route ( " /CalendrierAssiduitesEtud " )
@scodoc
@permission_required ( Permission . ScoView )
def calendrier_etud ( ) :
"""
calendrier_etud : Affichage d ' un calendrier des assiduités de l ' étudiant
Args :
etudid ( int ) : l ' identifiant de l ' étudiant
Returns :
str : l ' html généré
"""
etudid = request . args . get ( " etudid " , - 1 )
etud : Identite = Identite . query . get_or_404 ( etudid )
if etud . dept_id != g . scodoc_dept_id :
abort ( 404 , " étudiant inexistant dans ce département " )
header : str = html_sco_header . sco_header (
2023-09-21 08:46:21 +02:00
page_title = " Calendrier de l ' assiduité " ,
2023-06-22 16:25:13 +02:00
init_qtip = True ,
javascripts = [
" js/assiduites.js " ,
" libjs/moment.new.min.js " ,
" libjs/moment-timezone.js " ,
] ,
cssstyles = CSSSTYLES
+ [
" css/assiduites.css " ,
] ,
)
2023-08-22 16:06:56 +02:00
annees : list [ int ] = sorted (
[ ins . formsemestre . date_debut . year for ins in etud . formsemestre_inscriptions ] ,
reverse = True ,
)
annees_str : str = " [ "
for ann in annees :
annees_str + = f " { ann } , "
annees_str + = " ] "
2023-06-22 16:25:13 +02:00
return HTMLBuilder (
header ,
render_template (
" assiduites/pages/calendrier.j2 " ,
sco = ScoData ( etud ) ,
annee = scu . annee_scolaire ( ) ,
nonworkdays = _non_work_days ( ) ,
minitimeline = _mini_timeline ( ) ,
2023-08-22 16:06:56 +02:00
annees = annees_str ,
2023-06-22 16:25:13 +02:00
) ,
) . build ( )
2023-04-17 15:44:55 +02:00
@bp.route ( " /SignalAssiduiteGr " )
@scodoc
2023-07-25 14:03:09 +02:00
@permission_required ( Permission . ScoAbsChange )
2023-04-17 15:44:55 +02:00
def signal_assiduites_group ( ) :
"""
signal_assiduites_group Saisie des assiduités des groupes pour le jour donnée
Returns :
str : l ' html généré
"""
formsemestre_id : int = request . args . get ( " formsemestre_id " , - 1 )
moduleimpl_id : int = request . args . get ( " moduleimpl_id " )
date : str = request . args . get ( " jour " , datetime . date . today ( ) . isoformat ( ) )
group_ids : list [ int ] = request . args . get ( " group_ids " , None )
2023-07-26 16:43:49 +02:00
if group_ids is None :
group_ids = [ ]
else :
group_ids = group_ids . split ( " , " )
map ( str , group_ids )
# Vérification du moduleimpl_id
try :
moduleimpl_id = int ( moduleimpl_id )
except ( TypeError , ValueError ) :
moduleimpl_id = None
# Vérification du formsemestre_id
try :
formsemestre_id = int ( formsemestre_id )
except ( TypeError , ValueError ) :
formsemestre_id = None
groups_infos = sco_groups_view . DisplayedGroupsInfos (
group_ids , moduleimpl_id = moduleimpl_id , formsemestre_id = formsemestre_id
)
if not groups_infos . members :
return (
2023-09-21 08:46:21 +02:00
html_sco_header . sco_header ( page_title = " Saisie journalière de l ' assiduité " )
2023-07-26 16:43:49 +02:00
+ " <h3>Aucun étudiant ! </h3> "
+ html_sco_header . sco_footer ( )
)
# --- URL DEFAULT ---
base_url : str = f " SignalAssiduiteGr?date= { date } & { groups_infos . groups_query_args } "
# --- Filtrage par formsemestre ---
formsemestre_id = groups_infos . formsemestre_id
formsemestre : FormSemestre = FormSemestre . query . get_or_404 ( formsemestre_id )
if formsemestre . dept_id != g . scodoc_dept_id :
abort ( 404 , " groupes inexistants dans ce département " )
require_module = sco_preferences . get_preference (
" abs_require_module " , formsemestre_id
)
etuds = [
sco_etud . get_etud_info ( etudid = m [ " etudid " ] , filled = True ) [ 0 ]
for m in groups_infos . members
]
# --- Vérification de la date ---
real_date = scu . is_iso_formated ( date , True ) . date ( )
2023-09-13 08:59:54 +02:00
if real_date < formsemestre . date_debut or real_date > formsemestre . date_fin :
real_str = real_date . strftime ( " %d / % m/ % Y " )
form_deb = formsemestre . date_debut . strftime ( " %d / % m/ % Y " )
form_fin = formsemestre . date_fin . strftime ( " %d / % m/ % Y " )
raise ScoValueError (
2023-09-19 23:04:46 +02:00
f " Impossible de saisir l ' assiduité pour le { real_str } "
2023-09-13 08:59:54 +02:00
+ f " : Jour en dehors du semestre ( { form_deb } → { form_fin } ) "
)
2023-07-26 16:43:49 +02:00
# --- Restriction en fonction du moduleimpl_id ---
if moduleimpl_id :
mod_inscrits = {
x [ " etudid " ]
for x in sco_moduleimpl . do_moduleimpl_inscription_list (
moduleimpl_id = moduleimpl_id
)
}
etuds_inscrits_module = [ e for e in etuds if e [ " etudid " ] in mod_inscrits ]
if etuds_inscrits_module :
etuds = etuds_inscrits_module
else :
# Si aucun etudiant n'est inscrit au module choisi...
moduleimpl_id = None
# --- Génération de l'HTML ---
sem = formsemestre . to_dict ( )
if groups_infos . tous_les_etuds_du_sem :
gr_tit = " en "
else :
if len ( groups_infos . group_ids ) > 1 :
grp = " des groupes "
else :
grp = " du groupe "
gr_tit = (
grp + ' <span class= " fontred " > ' + groups_infos . groups_titles + " </span> "
)
header : str = html_sco_header . sco_header (
page_title = " Saisie journalière des assiduités " ,
init_qtip = True ,
javascripts = html_sco_header . BOOTSTRAP_MULTISELECT_JS
+ [
# Voir fonctionnement JS
" js/etud_info.js " ,
" js/groups_view.js " ,
" js/assiduites.js " ,
" libjs/moment.new.min.js " ,
" libjs/moment-timezone.js " ,
] ,
cssstyles = CSSSTYLES
+ [
" css/assiduites.css " ,
] ,
)
return HTMLBuilder (
header ,
_mini_timeline ( ) ,
render_template (
" assiduites/pages/signal_assiduites_group.j2 " ,
gr_tit = gr_tit ,
sem = sem [ " titre_num " ] ,
date = date ,
formsemestre_id = formsemestre_id ,
grp = sco_groups_view . menu_groups_choice ( groups_infos ) ,
moduleimpl_select = _module_selector ( formsemestre , moduleimpl_id ) ,
timeline = _timeline ( ) ,
nonworkdays = _non_work_days ( ) ,
formsemestre_date_debut = str ( formsemestre . date_debut ) ,
formsemestre_date_fin = str ( formsemestre . date_fin ) ,
forcer_module = sco_preferences . get_preference (
" forcer_module " ,
formsemestre_id = formsemestre_id ,
dept_id = g . scodoc_dept_id ,
) ,
defdem = _get_etuds_dem_def ( formsemestre ) ,
2023-07-27 14:58:57 +02:00
readonly = " false " ,
2023-07-26 16:43:49 +02:00
) ,
html_sco_header . sco_footer ( ) ,
) . build ( )
@bp.route ( " /VisuAssiduiteGr " )
@scodoc
@permission_required ( Permission . ScoView )
def visu_assiduites_group ( ) :
"""
2023-09-18 22:47:25 +02:00
Visualisation des assiduités des groupes pour le jour donné
dans le formsemestre_id et le moduleimpl_id
2023-07-26 16:43:49 +02:00
Returns :
str : l ' html généré
"""
formsemestre_id : int = request . args . get ( " formsemestre_id " , - 1 )
moduleimpl_id : int = request . args . get ( " moduleimpl_id " )
date : str = request . args . get ( " jour " , datetime . date . today ( ) . isoformat ( ) )
group_ids : list [ int ] = request . args . get ( " group_ids " , None )
2023-04-17 15:44:55 +02:00
if group_ids is None :
group_ids = [ ]
else :
group_ids = group_ids . split ( " , " )
map ( str , group_ids )
# Vérification du moduleimpl_id
2023-09-18 22:47:25 +02:00
if moduleimpl_id is not None :
try :
moduleimpl_id = int ( moduleimpl_id )
except ( TypeError , ValueError ) as exc :
raise ScoValueError ( " identifiant de moduleimpl invalide " ) from exc
2023-04-17 15:44:55 +02:00
# Vérification du formsemestre_id
2023-09-18 22:47:25 +02:00
if formsemestre_id is not None :
try :
formsemestre_id = int ( formsemestre_id )
except ( TypeError , ValueError ) as exc :
raise ScoValueError ( " identifiant de formsemestre invalide " ) from exc
2023-04-17 15:44:55 +02:00
groups_infos = sco_groups_view . DisplayedGroupsInfos (
group_ids , moduleimpl_id = moduleimpl_id , formsemestre_id = formsemestre_id
)
if not groups_infos . members :
return (
2023-09-21 08:46:21 +02:00
html_sco_header . sco_header ( page_title = " Saisie journalière de l ' assiduité " )
2023-04-17 15:44:55 +02:00
+ " <h3>Aucun étudiant ! </h3> "
+ html_sco_header . sco_footer ( )
)
# --- URL DEFAULT ---
base_url : str = f " SignalAssiduiteGr?date= { date } & { groups_infos . groups_query_args } "
# --- Filtrage par formsemestre ---
formsemestre_id = groups_infos . formsemestre_id
2023-06-01 17:32:50 +02:00
2023-04-17 15:44:55 +02:00
formsemestre : FormSemestre = FormSemestre . query . get_or_404 ( formsemestre_id )
if formsemestre . dept_id != g . scodoc_dept_id :
abort ( 404 , " groupes inexistants dans ce département " )
require_module = sco_preferences . get_preference (
" abs_require_module " , formsemestre_id
)
etuds = [
sco_etud . get_etud_info ( etudid = m [ " etudid " ] , filled = True ) [ 0 ]
for m in groups_infos . members
]
2023-06-12 17:54:30 +02:00
# --- Vérification de la date ---
real_date = scu . is_iso_formated ( date , True ) . date ( )
if real_date < formsemestre . date_debut :
date = formsemestre . date_debut . isoformat ( )
elif real_date > formsemestre . date_fin :
date = formsemestre . date_fin . isoformat ( )
2023-04-17 15:44:55 +02:00
# --- Restriction en fonction du moduleimpl_id ---
if moduleimpl_id :
mod_inscrits = {
x [ " etudid " ]
for x in sco_moduleimpl . do_moduleimpl_inscription_list (
moduleimpl_id = moduleimpl_id
)
}
etuds_inscrits_module = [ e for e in etuds if e [ " etudid " ] in mod_inscrits ]
if etuds_inscrits_module :
etuds = etuds_inscrits_module
else :
# Si aucun etudiant n'est inscrit au module choisi...
moduleimpl_id = None
# --- Génération de l'HTML ---
sem = formsemestre . to_dict ( )
if groups_infos . tous_les_etuds_du_sem :
gr_tit = " en "
else :
if len ( groups_infos . group_ids ) > 1 :
grp = " des groupes "
else :
grp = " du groupe "
gr_tit = (
grp + ' <span class= " fontred " > ' + groups_infos . groups_titles + " </span> "
)
header : str = html_sco_header . sco_header (
2023-09-19 23:04:46 +02:00
page_title = " Saisie journalière de l ' assiduité " ,
2023-04-17 15:44:55 +02:00
init_qtip = True ,
javascripts = html_sco_header . BOOTSTRAP_MULTISELECT_JS
+ [
# Voir fonctionnement JS
" js/etud_info.js " ,
" js/groups_view.js " ,
" js/assiduites.js " ,
" libjs/moment.new.min.js " ,
" libjs/moment-timezone.js " ,
] ,
cssstyles = CSSSTYLES
+ [
" css/assiduites.css " ,
] ,
)
return HTMLBuilder (
header ,
2023-05-30 10:17:49 +02:00
_mini_timeline ( ) ,
2023-04-17 15:44:55 +02:00
render_template (
2023-06-20 08:33:49 +02:00
" assiduites/pages/signal_assiduites_group.j2 " ,
2023-04-17 15:44:55 +02:00
gr_tit = gr_tit ,
sem = sem [ " titre_num " ] ,
date = date ,
formsemestre_id = formsemestre_id ,
grp = sco_groups_view . menu_groups_choice ( groups_infos ) ,
moduleimpl_select = _module_selector ( formsemestre , moduleimpl_id ) ,
timeline = _timeline ( ) ,
2023-05-30 11:47:59 +02:00
nonworkdays = _non_work_days ( ) ,
2023-04-17 15:44:55 +02:00
formsemestre_date_debut = str ( formsemestre . date_debut ) ,
formsemestre_date_fin = str ( formsemestre . date_fin ) ,
2023-04-25 22:59:06 +02:00
forcer_module = sco_preferences . get_preference (
" forcer_module " ,
formsemestre_id = formsemestre_id ,
dept_id = g . scodoc_dept_id ,
) ,
2023-07-25 19:59:47 +02:00
defdem = _get_etuds_dem_def ( formsemestre ) ,
2023-07-27 14:58:57 +02:00
readonly = " true " ,
2023-04-17 15:44:55 +02:00
) ,
html_sco_header . sco_footer ( ) ,
) . build ( )
2023-08-30 08:53:36 +02:00
@bp.route ( " /etat_abs_date " )
2023-05-30 17:16:07 +02:00
@scodoc
2023-06-01 17:32:50 +02:00
@permission_required ( Permission . ScoView )
2023-08-30 08:53:36 +02:00
def etat_abs_date ( ) :
2023-08-29 19:30:56 +02:00
""" date_debut, date_fin en ISO """
date_debut_str = request . args . get ( " date_debut " )
date_fin_str = request . args . get ( " date_fin " )
title = request . args . get ( " desc " )
2023-05-30 17:16:07 +02:00
group_ids : list [ int ] = request . args . get ( " group_ids " , None )
2023-08-29 19:30:56 +02:00
try :
date_debut = datetime . datetime . fromisoformat ( date_debut_str )
except ValueError as exc :
raise ScoValueError ( " date_debut invalide " ) from exc
try :
date_fin = datetime . datetime . fromisoformat ( date_fin_str )
except ValueError as exc :
raise ScoValueError ( " date_fin invalide " ) from exc
2023-05-30 17:16:07 +02:00
if group_ids is None :
group_ids = [ ]
else :
group_ids = group_ids . split ( " , " )
map ( str , group_ids )
groups_infos = sco_groups_view . DisplayedGroupsInfos ( group_ids )
etuds = [
sco_etud . get_etud_info ( etudid = m [ " etudid " ] , filled = True ) [ 0 ]
for m in groups_infos . members
]
assiduites : Assiduite = Assiduite . query . filter (
Assiduite . etudid . in_ ( [ e [ " etudid " ] for e in etuds ] )
)
assiduites = scass . filter_by_date (
assiduites , Assiduite , date_debut , date_fin , False
)
2023-08-25 17:59:57 +02:00
etudiants : list [ dict ] = [ ]
2023-05-30 17:16:07 +02:00
for etud in etuds :
assi = assiduites . filter_by ( etudid = etud [ " etudid " ] ) . first ( )
etat = " "
2023-08-25 17:59:57 +02:00
if assi is not None and assi . etat != 0 :
2023-05-30 17:16:07 +02:00
etat = scu . EtatAssiduite . inverse ( ) . get ( assi . etat ) . name
etudiant = {
2023-08-25 17:59:57 +02:00
" nom " : f """ <a href= " { url_for (
" assiduites.calendrier_etud " ,
scodoc_dept = g . scodoc_dept ,
etudid = etud [ " etudid " ] )
} " ><font color= " #A00000">{etud["nomprenom"]}</font></a>""",
2023-05-30 17:16:07 +02:00
" etat " : etat ,
}
etudiants . append ( etudiant )
etudiants = list ( sorted ( etudiants , key = lambda x : x [ " nom " ] ) )
header : str = html_sco_header . sco_header (
2023-08-29 19:30:56 +02:00
page_title = safehtml . html_to_safe_html ( title ) ,
2023-05-30 17:16:07 +02:00
init_qtip = True ,
)
return HTMLBuilder (
header ,
render_template (
2023-06-20 08:33:49 +02:00
" assiduites/pages/etat_absence_date.j2 " ,
etudiants = etudiants ,
2023-08-25 17:59:57 +02:00
group_title = groups_infos . groups_titles ,
date_debut = date_debut ,
date_fin = date_fin ,
2023-05-30 17:16:07 +02:00
) ,
html_sco_header . sco_footer ( ) ,
) . build ( )
2023-07-10 17:38:50 +02:00
@bp.route ( " /VisualisationAssiduitesGroupe " )
@scodoc
@permission_required ( Permission . ScoView )
def visu_assi_group ( ) :
2023-09-18 22:47:25 +02:00
""" Visualisation de l ' assiduité d ' un groupe entre deux dates """
2023-07-10 17:38:50 +02:00
dates = {
" debut " : request . args . get ( " date_debut " ) ,
" fin " : request . args . get ( " date_fin " ) ,
}
2023-09-21 10:20:19 +02:00
fmt = request . args . get ( " fmt " , " html " )
2023-07-10 17:38:50 +02:00
group_ids : list [ int ] = request . args . get ( " group_ids " , None )
if group_ids is None :
group_ids = [ ]
else :
group_ids = group_ids . split ( " , " )
map ( str , group_ids )
groups_infos = sco_groups_view . DisplayedGroupsInfos ( group_ids )
2023-07-26 13:27:57 +02:00
formsemestre = db . session . get ( FormSemestre , groups_infos . formsemestre_id )
2023-07-10 17:38:50 +02:00
etuds = etuds_sorted_from_ids ( [ m [ " etudid " ] for m in groups_infos . members ] )
2023-07-26 13:27:57 +02:00
table : TableAssi = TableAssi (
etuds = etuds , dates = list ( dates . values ( ) ) , formsemestre = formsemestre
)
2023-07-10 17:38:50 +02:00
2023-07-20 15:53:59 +02:00
if fmt . startswith ( " xls " ) :
return scu . send_file (
table . excel ( ) ,
filename = f " assiduite- { groups_infos . groups_filename } " ,
mime = scu . XLSX_MIMETYPE ,
suffix = scu . XLSX_SUFFIX ,
)
2023-07-10 17:38:50 +02:00
if groups_infos . tous_les_etuds_du_sem :
2023-07-25 14:03:09 +02:00
gr_tit = " "
grp = " "
2023-07-10 17:38:50 +02:00
else :
if len ( groups_infos . group_ids ) > 1 :
grp = " des groupes "
else :
grp = " du groupe "
gr_tit = (
grp + ' <span class= " fontred " > ' + groups_infos . groups_titles + " </span> "
)
2023-07-20 15:53:59 +02:00
return render_template (
" assiduites/pages/visu_assi.j2 " ,
2023-08-22 15:43:10 +02:00
assi_metric = scu . translate_assiduites_metric (
scu . translate_assiduites_metric (
sco_preferences . get_preference (
" assi_metrique " , dept_id = g . scodoc_dept_id
) ,
) ,
inverse = False ,
short = False ,
2023-08-13 22:40:16 +02:00
) ,
2023-07-20 15:53:59 +02:00
date_debut = dates [ " debut " ] ,
date_fin = dates [ " fin " ] ,
2023-08-13 22:40:16 +02:00
gr_tit = gr_tit ,
2023-07-20 15:53:59 +02:00
group_ids = request . args . get ( " group_ids " , None ) ,
sco = ScoData ( formsemestre = groups_infos . get_formsemestre ( ) ) ,
2023-08-13 22:40:16 +02:00
tableau = table . html ( ) ,
2023-07-20 15:53:59 +02:00
title = f " Assiduité { grp } { groups_infos . groups_titles } " ,
)
2023-07-10 17:38:50 +02:00
2023-06-01 17:32:50 +02:00
@bp.route ( " /SignalAssiduiteDifferee " )
@scodoc
2023-07-25 14:03:09 +02:00
@permission_required ( Permission . ScoAbsChange )
2023-06-01 17:32:50 +02:00
def signal_assiduites_diff ( ) :
group_ids : list [ int ] = request . args . get ( " group_ids " , None )
formsemestre_id : int = request . args . get ( " formsemestre_id " , - 1 )
2023-06-12 17:54:30 +02:00
date : str = request . args . get ( " jour " , datetime . date . today ( ) . isoformat ( ) )
2023-09-04 14:27:48 +02:00
date_deb : str = request . args . get ( " date_deb " )
date_fin : str = request . args . get ( " date_fin " )
semaine : str = request . args . get ( " semaine " )
if semaine is not None :
semaine = (
f " { scu . annee_scolaire ( ) } -W { semaine } " if " W " not in semaine else semaine
)
date_deb : datetime . date = datetime . datetime . strptime (
semaine + " -1 " , " % Y-W % W- % w "
)
date_fin : datetime . date = date_deb + datetime . timedelta ( days = 6 )
2023-06-01 17:32:50 +02:00
etudiants : list [ dict ] = [ ]
titre = None
# Vérification du formsemestre_id
try :
formsemestre_id = int ( formsemestre_id )
except ( TypeError , ValueError ) :
formsemestre_id = None
formsemestre : FormSemestre = FormSemestre . query . get_or_404 ( formsemestre_id )
2023-06-12 17:54:30 +02:00
# --- Vérification de la date ---
real_date = scu . is_iso_formated ( date , True ) . date ( )
if real_date < formsemestre . date_debut :
date = formsemestre . date_debut . isoformat ( )
elif real_date > formsemestre . date_fin :
date = formsemestre . date_fin . isoformat ( )
2023-06-01 17:32:50 +02:00
if group_ids is None :
group_ids = [ ]
else :
group_ids = group_ids . split ( " , " )
map ( str , group_ids )
groups_infos = sco_groups_view . DisplayedGroupsInfos ( group_ids )
2023-06-05 16:18:06 +02:00
if not groups_infos . members :
return (
2023-09-19 23:04:46 +02:00
html_sco_header . sco_header ( page_title = " Assiduité: saisie différée " )
2023-06-05 16:18:06 +02:00
+ " <h3>Aucun étudiant ! </h3> "
+ html_sco_header . sco_footer ( )
)
2023-06-01 17:32:50 +02:00
etudiants . extend (
[
sco_etud . get_etud_info ( etudid = m [ " etudid " ] , filled = True ) [ 0 ]
for m in groups_infos . members
]
)
etudiants = list ( sorted ( etudiants , key = lambda x : x [ " nom " ] ) )
header : str = html_sco_header . sco_header (
2023-09-19 23:04:46 +02:00
page_title = " Assiduité: saisie différée " ,
2023-06-01 17:32:50 +02:00
init_qtip = True ,
2023-06-12 17:54:30 +02:00
cssstyles = [
" css/assiduites.css " ,
] ,
2023-06-01 17:32:50 +02:00
javascripts = html_sco_header . BOOTSTRAP_MULTISELECT_JS
+ [
" js/assiduites.js " ,
" libjs/moment.new.min.js " ,
" libjs/moment-timezone.js " ,
2023-09-04 14:27:48 +02:00
" js/etud_info.js " ,
2023-06-01 17:32:50 +02:00
] ,
)
sem = formsemestre . to_dict ( )
if groups_infos . tous_les_etuds_du_sem :
gr_tit = " en "
else :
if len ( groups_infos . group_ids ) > 1 :
grp = " des groupes "
else :
grp = " du groupe "
gr_tit = (
grp + ' <span class= " fontred " > ' + groups_infos . groups_titles + " </span> "
)
return HTMLBuilder (
header ,
render_template (
2023-06-20 08:33:49 +02:00
" assiduites/pages/signal_assiduites_diff.j2 " ,
2023-06-12 17:54:30 +02:00
diff = _differee (
etudiants = etudiants ,
2023-09-06 15:09:43 +02:00
moduleimpl_select = _module_selector (
formsemestre , request . args . get ( " moduleimpl_id " , None )
) ,
2023-06-12 17:54:30 +02:00
date = date ,
periode = {
" deb " : formsemestre . date_debut . isoformat ( ) ,
" fin " : formsemestre . date_fin . isoformat ( ) ,
} ,
2023-06-05 16:18:06 +02:00
) ,
2023-06-01 17:32:50 +02:00
gr = gr_tit ,
sem = sem [ " titre_num " ] ,
2023-07-25 19:59:47 +02:00
defdem = _get_etuds_dem_def ( formsemestre ) ,
2023-09-04 14:27:48 +02:00
timeMorning = ScoDocSiteConfig . get ( " assi_morning_time " , " 08:00:00 " ) ,
timeNoon = ScoDocSiteConfig . get ( " assi_lunch_time " , " 13:00:00 " ) ,
2023-09-27 08:27:13 +02:00
timeEvening = ScoDocSiteConfig . get ( " assi_afternoon_time " , " 18:00:00 " ) ,
2023-09-04 14:27:48 +02:00
defaultDates = _get_days_between_dates ( date_deb , date_fin ) ,
nonworkdays = _non_work_days ( ) ,
2023-06-01 17:32:50 +02:00
) ,
html_sco_header . sco_footer ( ) ,
) . build ( )
2023-09-06 11:21:53 +02:00
@bp.route ( " /SignalEvaluationAbs/<int:evaluation_id>/<int:etudid> " )
@scodoc
@permission_required ( Permission . ScoView )
def signal_evaluation_abs ( etudid : int = None , evaluation_id : int = None ) :
"""
Signale l ' absence d ' un étudiant à une évaluation
Si la durée de l ' évaluation est inférieur à 1 jour
Alors l ' absence sera sur la période de l ' évaluation
Sinon L ' utilisateur sera redirigé vers la page de saisie des absences de l ' étudiant
"""
etud : Identite = Identite . query . get_or_404 ( etudid )
if etud . dept_id != g . scodoc_dept_id :
abort ( 404 , " étudiant inexistant dans ce département " )
evaluation : Evaluation = Evaluation . query . get_or_404 ( evaluation_id )
delta : datetime . timedelta = evaluation . date_fin - evaluation . date_debut
if delta > datetime . timedelta ( days = 1 ) :
# rediriger vers page saisie
return redirect (
url_for (
" assiduites.signal_assiduites_etud " ,
etudid = etudid ,
evaluation_id = evaluation . id ,
date_deb = evaluation . date_debut . strftime ( " % Y- % m- %d T % H: % M: % S " ) ,
date_fin = evaluation . date_fin . strftime ( " % Y- % m- %d T % H: % M: % S " ) ,
moduleimpl_id = evaluation . moduleimpl . id ,
saisie_eval = " true " ,
scodoc_dept = g . scodoc_dept ,
)
)
# créer l'assiduité
2023-09-07 09:17:25 +02:00
try :
assiduite_unique : Assiduite = Assiduite . create_assiduite (
etud = etud ,
date_debut = scu . localize_datetime ( evaluation . date_debut ) ,
date_fin = scu . localize_datetime ( evaluation . date_fin ) ,
etat = scu . EtatAssiduite . ABSENT ,
moduleimpl = evaluation . moduleimpl ,
)
except ScoValueError as see :
msg : str = see . args [ 0 ]
if " Duplication " in msg :
msg = " Une autre assiduité concerne déjà cette période. En cliquant sur continuer vous serez redirigé vers la page de saisie des assiduités de l ' étudiant. "
dest : str = url_for (
" assiduites.signal_assiduites_etud " ,
etudid = etudid ,
evaluation_id = evaluation . id ,
date_deb = evaluation . date_debut . strftime ( " % Y- % m- %d T % H: % M: % S " ) ,
date_fin = evaluation . date_fin . strftime ( " % Y- % m- %d T % H: % M: % S " ) ,
moduleimpl_id = evaluation . moduleimpl . id ,
saisie_eval = " true " ,
scodoc_dept = g . scodoc_dept ,
duplication = " oui " ,
)
2023-09-08 11:59:10 +02:00
raise ScoValueError ( msg , dest ) from see
2023-09-06 11:21:53 +02:00
db . session . add ( assiduite_unique )
db . session . commit ( )
flash ( " L ' absence a bien été créée " )
# rediriger vers la page d'évaluation
return redirect (
url_for (
" notes.evaluation_check_absences_html " ,
evaluation_id = evaluation . id ,
scodoc_dept = g . scodoc_dept ,
)
)
2023-09-08 11:59:10 +02:00
def generate_bul_list ( etud : Identite , semestre : FormSemestre ) - > str :
""" Génère la liste des assiduités d ' un étudiant pour le bulletin mail """
metrique : str = scu . translate_assiduites_metric (
sco_preferences . get_preference ( " assi_metrique " , formsemestre_id = semestre . id ) ,
)
max_nb : int = int (
sco_preferences . get_preference (
" bul_mail_list_abs_nb " , formsemestre_id = semestre . id
)
)
assiduites = scass . filter_by_formsemestre (
etud . assiduites , Assiduite , semestre
) . order_by ( Assiduite . entry_date . desc ( ) )
justificatifs = scass . filter_by_formsemestre (
etud . justificatifs , Justificatif , semestre
) . order_by ( Justificatif . entry_date . desc ( ) )
stats : dict = scass . get_assiduites_stats (
assiduites , metric = metrique , filtered = { " split " : True }
)
abs_j : list [ str ] = [
{ " date " : _get_date_str ( assi . date_debut , assi . date_fin ) }
for assi in assiduites
if assi . etat == scu . EtatAssiduite . ABSENT and assi . est_just is True
]
abs_nj : list [ str ] = [
{ " date " : _get_date_str ( assi . date_debut , assi . date_fin ) }
for assi in assiduites
if assi . etat == scu . EtatAssiduite . ABSENT and assi . est_just is False
]
retards : list [ str ] = [
{ " date " : _get_date_str ( assi . date_debut , assi . date_fin ) }
for assi in assiduites
if assi . etat == scu . EtatAssiduite . RETARD
]
justifs : list [ dict [ str , str ] ] = [
{
" date " : _get_date_str ( justi . date_debut , justi . date_fin ) ,
" raison " : " " if justi . raison is None else justi . raison ,
" etat " : {
scu . EtatJustificatif . VALIDE : " justificatif valide " ,
scu . EtatJustificatif . NON_VALIDE : " justificatif invalide " ,
scu . EtatJustificatif . ATTENTE : " justificatif en attente de validation " ,
scu . EtatJustificatif . MODIFIE : " justificatif ayant été modifié " ,
} . get ( justi . etat ) ,
}
for justi in justificatifs
]
return render_template (
" assiduites/widgets/liste_assiduites_mail.j2 " ,
abs_j = abs_j [ : max_nb ] ,
abs_nj = abs_nj [ : max_nb ] ,
retards = retards [ : max_nb ] ,
justifs = justifs [ : max_nb ] ,
stats = stats ,
metrique = scu . translate_assiduites_metric ( metrique , short = True , inverse = False ) ,
metric = metrique ,
)
2023-09-06 11:21:53 +02:00
# --- Fonctions internes ---
2023-09-08 11:59:10 +02:00
def _get_date_str ( deb : datetime . datetime , fin : datetime . datetime ) - > str :
if deb . date ( ) == fin . date ( ) :
temps = deb . strftime ( " %d / % m/ % Y % H: % M " ) . split ( " " ) + [ fin . strftime ( " % H: % M " ) ]
return f " le { temps [ 0 ] } de { temps [ 1 ] } à { temps [ 2 ] } "
return f ' du { deb . strftime ( " %d / % m/ % Y % H: % M " ) } au { fin . strftime ( " %d / % m/ % Y % H: % M " ) } '
2023-09-04 14:27:48 +02:00
def _get_days_between_dates ( deb : str , fin : str ) :
if deb is None or fin is None :
return " null "
try :
if isinstance ( deb , str ) and isinstance ( fin , str ) :
date_deb : datetime . date = datetime . date . fromisoformat ( deb )
date_fin : datetime . date = datetime . date . fromisoformat ( fin )
else :
date_deb , date_fin = deb . date ( ) , fin . date ( )
except ValueError :
return " null "
dates : list [ str ] = [ ]
while date_deb < = date_fin :
dates . append ( f ' " { date_deb . isoformat ( ) } " ' )
date_deb = date_deb + datetime . timedelta ( days = 1 )
return f " [ { ' , ' . join ( dates ) } ] "
2023-06-12 17:54:30 +02:00
def _differee (
etudiants , moduleimpl_select , date = None , periode = None , formsemestre_id = None
) :
if date is None :
date = datetime . date . today ( ) . isoformat ( )
forcer_module = sco_preferences . get_preference (
" forcer_module " ,
formsemestre_id = formsemestre_id ,
dept_id = g . scodoc_dept_id ,
)
etat_def = sco_preferences . get_preference (
" assi_etat_defaut " ,
formsemestre_id = formsemestre_id ,
dept_id = g . scodoc_dept_id ,
)
return render_template (
2023-06-20 08:33:49 +02:00
" assiduites/widgets/differee.j2 " ,
2023-06-12 17:54:30 +02:00
etudiants = etudiants ,
etat_def = etat_def ,
forcer_module = forcer_module ,
moduleimpl_select = moduleimpl_select ,
date = date ,
periode = periode ,
)
2023-04-17 15:44:55 +02:00
def _module_selector (
formsemestre : FormSemestre , moduleimpl_id : int = None
) - > HTMLElement :
"""
_module_selector Génère un HTMLSelectElement à partir des moduleimpl du formsemestre
Args :
formsemestre ( FormSemestre ) : Le formsemestre d ' où les moduleimpls seront pris.
Returns :
str : La représentation str d ' un HTMLSelectElement
"""
ntc : NotesTableCompat = res_sem . load_formsemestre_results ( formsemestre )
modimpls_list : list [ dict ] = [ ]
ues = ntc . get_ues_stat_dict ( )
for ue in ues :
modimpls_list + = ntc . get_modimpls_dict ( ue_id = ue [ " ue_id " ] )
2023-09-01 15:24:44 +02:00
selected = " " if moduleimpl_id is not None else " selected "
2023-04-17 15:44:55 +02:00
modules = [ ]
for modimpl in modimpls_list :
modname : str = (
( modimpl [ " module " ] [ " code " ] or " " )
+ " "
+ ( modimpl [ " module " ] [ " abbrev " ] or modimpl [ " module " ] [ " titre " ] or " " )
)
modules . append ( { " moduleimpl_id " : modimpl [ " moduleimpl_id " ] , " name " : modname } )
2023-09-06 15:09:43 +02:00
try :
moduleimpl_id = int ( moduleimpl_id )
except ( ValueError , TypeError ) :
moduleimpl_id = None
2023-04-17 15:44:55 +02:00
return render_template (
2023-09-01 15:24:44 +02:00
" assiduites/widgets/moduleimpl_selector.j2 " ,
selected = selected ,
modules = modules ,
moduleimpl_id = moduleimpl_id ,
2023-04-17 15:44:55 +02:00
)
2023-06-12 17:54:30 +02:00
def _dynamic_module_selector ( ) :
2023-06-20 08:33:49 +02:00
return render_template ( " assiduites/widgets/moduleimpl_dynamic_selector.j2 " )
2023-06-12 17:54:30 +02:00
2023-05-17 20:46:10 +02:00
def _timeline ( formsemestre_id = None ) - > HTMLElement :
2023-04-25 22:59:06 +02:00
return render_template (
2023-06-20 08:33:49 +02:00
" assiduites/widgets/timeline.j2 " ,
2023-09-20 22:38:01 +02:00
t_start = ScoDocSiteConfig . assi_get_rounded_time ( " assi_morning_time " , " 08:00:00 " ) ,
t_end = ScoDocSiteConfig . assi_get_rounded_time ( " assi_afternoon_time " , " 18:00:00 " ) ,
2023-06-02 17:19:55 +02:00
tick_time = ScoDocSiteConfig . get ( " assi_tick_time " , 15 ) ,
2023-05-17 20:46:10 +02:00
periode_defaut = sco_preferences . get_preference (
" periode_defaut " , formsemestre_id
) ,
2023-04-25 22:59:06 +02:00
)
2023-05-30 10:17:49 +02:00
def _mini_timeline ( ) - > HTMLElement :
return render_template (
2023-06-20 08:33:49 +02:00
" assiduites/widgets/minitimeline.j2 " ,
2023-09-20 22:38:01 +02:00
t_start = ScoDocSiteConfig . assi_get_rounded_time ( " assi_morning_time " , " 08:00:00 " ) ,
t_end = ScoDocSiteConfig . assi_get_rounded_time ( " assi_afternoon_time " , " 18:00:00 " ) ,
2023-05-30 10:17:49 +02:00
)
2023-06-12 17:54:30 +02:00
2023-09-20 22:38:01 +02:00
def _non_work_days ( ) - > str :
""" Abbréviation des jours non travaillés: " ' sam ' , ' dim ' " .
donnés par les préférences du département
"""
non_travail = sco_preferences . get_preference ( " non_travail " )
2023-06-12 17:54:30 +02:00
non_travail = non_travail . replace ( " " , " " ) . split ( " , " )
return " , " . join ( [ f " ' { i . lower ( ) } ' " for i in non_travail ] )
2023-09-20 22:38:01 +02:00
def _get_seuil ( ) - > int :
""" Seuil d ' alerte des absences (en unité de la métrique),
tel que fixé dans les préférences du département . """
2023-06-28 17:15:24 +02:00
return sco_preferences . get_preference ( " assi_seuil " , dept_id = g . scodoc_dept_id )
2023-07-25 19:59:47 +02:00
2023-09-20 22:38:01 +02:00
def _get_etuds_dem_def ( formsemestre ) - > str :
""" Une chaine json donnant les étudiants démissionnaires ou défaillants
du formsemestre , sous la forme
' { " 516 " : " D " , ... } '
"""
return (
" { "
+ " , " . join (
[
f ' " { ins . etudid } " : " { ins . etat } " '
for ins in formsemestre . inscriptions
if ins . etat != scu . INSCRIT
]
)
+ " } "
)