2020-09-26 16:19:37 +02:00
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
2022-01-01 14:49:42 +01:00
# Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved.
2020-09-26 16:19:37 +02:00
#
# 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
#
##############################################################################
2022-02-06 16:09:17 +01:00
""" Tableau récapitulatif des notes d ' un semestre
2020-09-26 16:19:37 +02:00
"""
2021-02-04 20:02:44 +01:00
import datetime
2021-09-16 00:15:10 +02:00
import json
import time
2021-07-10 17:40:40 +02:00
from xml . etree import ElementTree
2020-09-26 16:19:37 +02:00
2021-09-18 10:10:02 +02:00
from flask import request
2021-09-27 10:20:10 +02:00
from flask import make_response
2021-09-18 10:10:02 +02:00
2021-08-29 19:57:32 +02:00
from app import log
2021-12-11 20:27:58 +01:00
from app . but import bulletin_but
2022-01-08 18:06:00 +01:00
from app . comp import res_sem
2022-01-08 19:56:09 +01:00
from app . comp . res_common import NotesTableCompat
2021-12-17 21:59:28 +01:00
from app . models import FormSemestre
from app . models . etudiants import Identite
2022-02-06 16:09:17 +01:00
from app . models . evaluations import Evaluation
2021-12-11 20:27:58 +01:00
import app . scodoc . sco_utils as scu
2021-06-19 23:21:37 +02:00
from app . scodoc import html_sco_header
from app . scodoc import sco_bac
from app . scodoc import sco_bulletins_json
from app . scodoc import sco_bulletins_xml
from app . scodoc import sco_bulletins , sco_excel
from app . scodoc import sco_codes_parcours
from app . scodoc import sco_evaluations
2021-11-12 22:17:46 +01:00
from app . scodoc import sco_evaluation_db
2021-06-19 23:21:37 +02:00
from app . scodoc import sco_formations
from app . scodoc import sco_formsemestre
from app . scodoc import sco_formsemestre_status
from app . scodoc import sco_groups
from app . scodoc import sco_permissions_check
from app . scodoc import sco_preferences
from app . scodoc import sco_etud
2021-07-03 23:35:32 +02:00
from app . scodoc import sco_users
2021-07-10 17:40:40 +02:00
from app . scodoc import sco_xml
2021-06-19 23:21:37 +02:00
from app . scodoc . sco_codes_parcours import DEF , UE_SPORT
2020-09-26 16:19:37 +02:00
def formsemestre_recapcomplet (
formsemestre_id = None ,
modejury = False , # affiche lien saisie decision jury
hidemodules = False , # cache colonnes notes modules
hidebac = False , # cache colonne Bac
tabformat = " html " ,
sortcol = None ,
xml_with_decisions = False , # XML avec decisions
rank_partition_id = None , # si None, calcul rang global
pref_override = True , # si vrai, les prefs ont la priorite sur le param hidebac
2020-12-12 17:22:54 +01:00
force_publishing = True , # publie les XML/JSON meme si bulletins non publiés
2020-09-26 16:19:37 +02:00
) :
""" Page récapitulant les notes d ' un semestre.
Grand tableau récapitulatif avec toutes les notes de modules
pour tous les étudiants , les moyennes par UE et générale ,
trié par moyenne générale décroissante .
"""
2021-08-19 10:28:35 +02:00
sem = sco_formsemestre . get_formsemestre ( formsemestre_id )
F = sco_formations . formation_list ( args = { " formation_id " : sem [ " formation_id " ] } ) [ 0 ]
2020-09-26 16:19:37 +02:00
parcours = sco_codes_parcours . get_parcours_from_code ( F [ " type_parcours " ] )
2021-12-11 20:27:58 +01:00
formsemestre = FormSemestre . query . get_or_404 ( formsemestre_id )
2022-02-08 00:04:07 +01:00
# Pour APC (BUT): cache les modules par défaut car moyenne n'a pas de sens
2021-12-11 20:27:58 +01:00
if formsemestre . formation . is_apc ( ) :
hidemodules = True
2020-09-26 16:19:37 +02:00
# traduit du DTML
modejury = int ( modejury )
hidemodules = (
int ( hidemodules ) or parcours . UE_IS_MODULE
) # cache les colonnes des modules
pref_override = int ( pref_override )
if pref_override :
2021-07-28 17:03:54 +02:00
hidebac = int ( sco_preferences . get_preference ( " recap_hidebac " , formsemestre_id ) )
2020-09-26 16:19:37 +02:00
else :
hidebac = int ( hidebac )
xml_with_decisions = int ( xml_with_decisions )
2020-12-12 17:22:54 +01:00
force_publishing = int ( force_publishing )
2020-12-02 01:00:23 +01:00
isFile = tabformat in ( " csv " , " xls " , " xml " , " xlsall " , " json " )
2020-09-26 16:19:37 +02:00
H = [ ]
if not isFile :
H + = [
2021-06-13 23:37:14 +02:00
html_sco_header . sco_header (
2020-09-26 16:19:37 +02:00
page_title = " Récapitulatif " ,
no_side_bar = True ,
init_qtip = True ,
javascripts = [ " libjs/sorttable.js " , " js/etud_info.js " ] ,
) ,
sco_formsemestre_status . formsemestre_status_head (
2021-09-27 10:20:10 +02:00
formsemestre_id = formsemestre_id
2020-09-26 16:19:37 +02:00
) ,
2021-09-18 10:10:02 +02:00
' <form name= " f " method= " get " action= " %s " > ' % request . base_url ,
2020-09-26 16:19:37 +02:00
' <input type= " hidden " name= " formsemestre_id " value= " %s " ></input> '
% formsemestre_id ,
' <input type= " hidden " name= " pref_override " value= " 0 " ></input> ' ,
]
if modejury :
H . append (
' <input type= " hidden " name= " modejury " value= " %s " ></input> ' % modejury
)
H . append (
' <select name= " tabformat " onchange= " document.f.submit() " class= " noprint " > '
)
for ( format , label ) in (
( " html " , " HTML " ) ,
( " xls " , " Fichier tableur (Excel) " ) ,
( " xlsall " , " Fichier tableur avec toutes les évals " ) ,
( " csv " , " Fichier tableur (CSV) " ) ,
( " xml " , " Fichier XML " ) ,
2020-12-02 01:00:23 +01:00
( " json " , " JSON " ) ,
2020-09-26 16:19:37 +02:00
) :
if format == tabformat :
selected = " selected "
else :
selected = " "
H . append ( ' <option value= " %s " %s > %s </option> ' % ( format , selected , label ) )
H . append ( " </select> " )
H . append (
""" (cliquer sur un nom pour afficher son bulletin ou <a class= " stdlink " href= " %s /Notes/formsemestre_bulletins_pdf?formsemestre_id= %s " >ici avoir le classeur papier</a>) """
2021-06-15 12:34:33 +02:00
% ( scu . ScoURL ( ) , formsemestre_id )
2020-09-26 16:19:37 +02:00
)
if not parcours . UE_IS_MODULE :
H . append (
""" <input type= " checkbox " name= " hidemodules " value= " 1 " onchange= " document.f.submit() " """
)
if hidemodules :
H . append ( " checked " )
H . append ( """ >cacher les modules</input> """ )
H . append (
""" <input type= " checkbox " name= " hidebac " value= " 1 " onchange= " document.f.submit() " """
)
if hidebac :
H . append ( " checked " )
H . append ( """ >cacher bac</input> """ )
2021-09-27 10:20:10 +02:00
data = do_formsemestre_recapcomplet (
formsemestre_id ,
format = tabformat ,
hidemodules = hidemodules ,
hidebac = hidebac ,
modejury = modejury ,
sortcol = sortcol ,
xml_with_decisions = xml_with_decisions ,
rank_partition_id = rank_partition_id ,
force_publishing = force_publishing ,
2020-09-26 16:19:37 +02:00
)
2021-09-27 10:20:10 +02:00
if tabformat == " xml " :
response = make_response ( data )
response . headers [ " Content-Type " ] = scu . XML_MIMETYPE
return response
H . append ( data )
2020-09-26 16:19:37 +02:00
if not isFile :
H . append ( " </form> " )
H . append (
""" <p><a class= " stdlink " href= " formsemestre_pvjury?formsemestre_id= %s " >Voir les décisions du jury</a></p> """
% formsemestre_id
)
2021-07-29 16:31:15 +02:00
if sco_permissions_check . can_validate_sem ( formsemestre_id ) :
2020-09-26 16:19:37 +02:00
H . append ( " <p> " )
if modejury :
H . append (
2021-07-13 14:55:53 +02:00
""" <a class= " stdlink " href= " formsemestre_validation_auto?formsemestre_id= %s " >Calcul automatique des décisions du jury</a></p> """
% ( formsemestre_id , )
2020-09-26 16:19:37 +02:00
)
else :
H . append (
2021-05-11 11:48:32 +02:00
""" <a class= " stdlink " href= " formsemestre_recapcomplet?formsemestre_id= %s &modejury=1&hidemodules=1 " >Saisie des décisions du jury</a> """
2020-09-26 16:19:37 +02:00
% formsemestre_id
)
H . append ( " </p> " )
2021-07-28 17:03:54 +02:00
if sco_preferences . get_preference ( " use_ue_coefs " , formsemestre_id ) :
2020-09-26 16:19:37 +02:00
H . append (
"""
< p class = " infop " > utilise les coefficients d ' UE pour calculer la moyenne générale.</p>
"""
)
2021-07-29 10:19:00 +02:00
H . append ( html_sco_header . sco_footer ( ) )
2021-08-21 16:51:08 +02:00
# HTML or binary data ?
if len ( H ) > 1 :
return " " . join ( H )
elif len ( H ) == 1 :
return H [ 0 ]
else :
return H
2020-09-26 16:19:37 +02:00
def do_formsemestre_recapcomplet (
formsemestre_id = None ,
2020-12-02 01:00:23 +01:00
format = " html " , # html, xml, xls, xlsall, json
2020-09-26 16:19:37 +02:00
hidemodules = False , # ne pas montrer les modules (ignoré en XML)
hidebac = False , # pas de colonne Bac (ignoré en XML)
xml_nodate = False , # format XML sans dates (sert pour debug cache: comparaison de XML)
modejury = False , # saisie décisions jury
sortcol = None , # indice colonne a trier dans table T
xml_with_decisions = False ,
disable_etudlink = False ,
rank_partition_id = None , # si None, calcul rang global
2020-12-12 17:22:54 +01:00
force_publishing = True ,
2020-09-26 16:19:37 +02:00
) :
2020-12-02 01:00:23 +01:00
""" Calcule et renvoie le tableau récapitulatif. """
2021-08-22 17:18:15 +02:00
data , filename , format = make_formsemestre_recapcomplet (
formsemestre_id = formsemestre_id ,
format = format ,
hidemodules = hidemodules ,
hidebac = hidebac ,
xml_nodate = xml_nodate ,
modejury = modejury ,
sortcol = sortcol ,
xml_with_decisions = xml_with_decisions ,
disable_etudlink = disable_etudlink ,
rank_partition_id = rank_partition_id ,
force_publishing = force_publishing ,
)
2020-09-26 16:19:37 +02:00
if format == " xml " or format == " html " :
return data
elif format == " csv " :
2021-09-16 00:15:10 +02:00
return scu . send_file ( data , filename = filename , mime = scu . CSV_MIMETYPE )
2021-09-25 10:43:06 +02:00
elif format . startswith ( " xls " ) or format . startswith ( " xlsx " ) :
2021-09-16 00:15:10 +02:00
return scu . send_file ( data , filename = filename , mime = scu . XLSX_MIMETYPE )
2020-12-02 01:00:23 +01:00
elif format == " json " :
2021-09-16 00:15:10 +02:00
js = json . dumps ( data , indent = 1 , cls = scu . ScoDocJSONEncoder )
return scu . send_file (
js , filename = filename , suffix = scu . JSON_SUFFIX , mime = scu . JSON_MIMETYPE
)
2020-09-26 16:19:37 +02:00
else :
raise ValueError ( " unknown format %s " % format )
def make_formsemestre_recapcomplet (
formsemestre_id = None ,
2020-12-02 01:00:23 +01:00
format = " html " , # html, xml, xls, xlsall, json
2020-09-26 16:19:37 +02:00
hidemodules = False , # ne pas montrer les modules (ignoré en XML)
hidebac = False , # pas de colonne Bac (ignoré en XML)
xml_nodate = False , # format XML sans dates (sert pour debug cache: comparaison de XML)
modejury = False , # saisie décisions jury
sortcol = None , # indice colonne a trier dans table T
xml_with_decisions = False ,
disable_etudlink = False ,
rank_partition_id = None , # si None, calcul rang global
2020-12-12 17:22:54 +01:00
force_publishing = True , # donne bulletins JSON/XML meme si non publiés
2020-09-26 16:19:37 +02:00
) :
""" Grand tableau récapitulatif avec toutes les notes de modules
pour tous les étudiants , les moyennes par UE et générale ,
trié par moyenne générale décroissante .
"""
2021-02-13 21:28:59 +01:00
civ_nom_prenom = False # 3 colonnes différentes ou une seule avec prénom abrégé ?
2020-09-26 16:19:37 +02:00
if format == " xml " :
return _formsemestre_recapcomplet_xml (
2020-12-12 17:22:54 +01:00
formsemestre_id ,
xml_nodate ,
xml_with_decisions = xml_with_decisions ,
force_publishing = force_publishing ,
2020-09-26 16:19:37 +02:00
)
2020-12-02 01:00:23 +01:00
elif format == " json " :
return _formsemestre_recapcomplet_json (
2020-12-12 17:22:54 +01:00
formsemestre_id ,
xml_nodate = xml_nodate ,
xml_with_decisions = xml_with_decisions ,
force_publishing = force_publishing ,
2020-12-02 01:00:23 +01:00
)
2020-09-26 16:19:37 +02:00
if format [ : 3 ] == " xls " :
2021-02-13 21:28:59 +01:00
civ_nom_prenom = True # 3 cols: civilite, nom, prenom
2020-09-26 16:19:37 +02:00
keep_numeric = True # pas de conversion des notes en strings
else :
keep_numeric = False
if hidebac :
admission_extra_cols = [ ]
else :
admission_extra_cols = [
" type_admission " ,
" classement " ,
" apb_groupe " ,
" apb_classement_gr " ,
]
2021-12-11 20:27:58 +01:00
formsemestre = FormSemestre . query . get_or_404 ( formsemestre_id )
# A ré-écrire XXX
2020-09-26 16:19:37 +02:00
sem = sco_formsemestre . do_formsemestre_list (
2021-08-19 10:28:35 +02:00
args = { " formsemestre_id " : formsemestre_id }
2020-09-26 16:19:37 +02:00
) [ 0 ]
2022-01-07 10:37:48 +01:00
parcours = formsemestre . formation . get_parcours ( )
2022-02-06 16:09:17 +01:00
nt : NotesTableCompat = res_sem . load_formsemestre_results ( formsemestre )
modimpls = formsemestre . modimpls_sorted
2021-12-24 00:08:25 +01:00
ues = nt . get_ues_stat_dict ( ) # incluant le(s) UE de sport
2022-02-08 00:04:07 +01:00
2020-09-26 16:19:37 +02:00
partitions , partitions_etud_groups = sco_groups . get_formsemestre_groups (
2021-08-19 10:28:35 +02:00
formsemestre_id
2020-09-26 16:19:37 +02:00
)
if rank_partition_id and format == " html " :
# Calcul rang sur une partition et non sur l'ensemble
# seulement en format HTML (car colonnes rangs toujours presentes en xls)
2021-08-19 10:28:35 +02:00
rank_partition = sco_groups . get_partition ( rank_partition_id )
2020-09-26 16:19:37 +02:00
rank_label = " Rg ( %s ) " % rank_partition [ " partition_name " ]
else :
2021-08-19 10:28:35 +02:00
rank_partition = sco_groups . get_default_partition ( formsemestre_id )
2020-09-26 16:19:37 +02:00
rank_label = " Rg "
2020-12-02 01:00:23 +01:00
2020-09-26 16:19:37 +02:00
T = nt . get_table_moyennes_triees ( )
if not T :
return " " , " " , format
# Construit une liste de listes de chaines: le champs du tableau resultat (HTML ou CSV)
F = [ ]
2021-02-13 21:28:59 +01:00
h = [ rank_label ]
if civ_nom_prenom :
h + = [ " Civilité " , " Nom " , " Prénom " ]
else :
h + = [ " Nom " ]
2020-09-26 16:19:37 +02:00
if not hidebac :
h . append ( " Bac " )
# Si CSV ou XLS, indique tous les groupes
if format [ : 3 ] == " xls " or format == " csv " :
for partition in partitions :
h . append ( " %s " % partition [ " partition_name " ] )
else :
h . append ( " Gr " )
h . append ( " Moy " )
# Ajoute rangs dans groupe seulement si CSV ou XLS
if format [ : 3 ] == " xls " or format == " csv " :
for partition in partitions :
h . append ( " rang_ %s " % partition [ " partition_name " ] )
cod2mod = { } # code : moduleimpl
mod_evals = { } # moduleimpl_id : liste de toutes les evals de ce module
for ue in ues :
if ue [ " type " ] != UE_SPORT :
h . append ( ue [ " acronyme " ] )
else : # UE_SPORT:
# n'affiche pas la moyenne d'UE dans ce cas
# mais laisse col. vide si modules affichés (pour séparer les UE)
if not hidemodules :
h . append ( " " )
pass
if not hidemodules and not ue [ " is_external " ] :
for modimpl in modimpls :
2022-02-06 16:09:17 +01:00
if modimpl . module . ue_id == ue [ " ue_id " ] :
code = modimpl . module . code
2020-09-26 16:19:37 +02:00
h . append ( code )
cod2mod [ code ] = modimpl # pour fabriquer le lien
if format == " xlsall " :
2022-02-06 16:09:17 +01:00
evals = nt . modimpls_results [
modimpl . id
] . get_evaluations_completes ( modimpl )
# evals = nt.get_mod_evaluation_etat_list(...
mod_evals [ modimpl . id ] = evals
2021-08-21 00:24:51 +02:00
h + = _list_notes_evals_titles ( code , evals )
2020-09-26 16:19:37 +02:00
h + = admission_extra_cols
h + = [ " code_nip " , " etudid " ]
F . append ( h )
def fmtnum ( val ) : # conversion en nombre pour cellules excel
if keep_numeric :
try :
return float ( val )
except :
return val
else :
return val
# Compte les decisions de jury
2021-02-04 20:02:44 +01:00
codes_nb = scu . DictDefault ( defaultvalue = 0 )
2020-09-26 16:19:37 +02:00
#
is_dem = { } # etudid : bool
for t in T :
etudid = t [ - 1 ]
dec = nt . get_etud_decision_sem ( etudid )
if dec :
codes_nb [ dec [ " code " ] ] + = 1
etud_etat = nt . get_etud_etat ( etudid )
if etud_etat == " D " :
gr_name = " Dém. "
is_dem [ etudid ] = True
elif etud_etat == DEF :
gr_name = " Déf. "
is_dem [ etudid ] = False
else :
2021-08-19 10:28:35 +02:00
group = sco_groups . get_etud_main_group ( etudid , sem )
2020-09-26 16:19:37 +02:00
gr_name = group [ " group_name " ] or " "
is_dem [ etudid ] = False
if rank_partition_id :
2021-02-13 21:28:59 +01:00
rang_gr , _ , rank_gr_name = sco_bulletins . get_etud_rangs_groups (
2021-08-21 00:24:51 +02:00
etudid , formsemestre_id , partitions , partitions_etud_groups , nt
2020-09-26 16:19:37 +02:00
)
if rank_gr_name [ rank_partition_id ] :
rank = " %s %s " % (
rank_gr_name [ rank_partition_id ] ,
rang_gr [ rank_partition_id ] ,
)
else :
rank = " "
else :
rank = nt . get_etud_rang ( etudid )
e = nt . identdict [ etudid ]
2021-02-13 21:28:59 +01:00
if civ_nom_prenom :
2021-06-19 23:21:37 +02:00
sco_etud . format_etud_ident ( e )
2021-02-13 21:28:59 +01:00
l = [ rank , e [ " civilite_str " ] , e [ " nom_disp " ] , e [ " prenom " ] ] # civ, nom prenom
else :
l = [ rank , nt . get_nom_short ( etudid ) ] # rang, nom,
2022-01-09 22:34:49 +01:00
e [ " admission " ] = { }
2020-09-26 16:19:37 +02:00
if not hidebac :
2022-01-16 23:47:52 +01:00
e [ " admission " ] = nt . etuds_dict [ etudid ] . admission . first ( )
if e [ " admission " ] :
bac = nt . etuds_dict [ etudid ] . admission [ 0 ] . get_bac ( )
l . append ( bac . abbrev ( ) )
else :
l . append ( " " )
2020-09-26 16:19:37 +02:00
if format [ : 3 ] == " xls " or format == " csv " : # tous les groupes
for partition in partitions :
group = partitions_etud_groups [ partition [ " partition_id " ] ] . get (
etudid , None
)
if group :
l . append ( group [ " group_name " ] )
else :
l . append ( " " )
else :
l . append ( gr_name ) # groupe
2021-12-11 20:27:58 +01:00
# Moyenne générale
l . append ( fmtnum ( scu . fmt_note ( t [ 0 ] , keep_numeric = keep_numeric ) ) )
2020-09-26 16:19:37 +02:00
# Ajoute rangs dans groupes seulement si CSV ou XLS
if format [ : 3 ] == " xls " or format == " csv " :
2021-02-16 15:16:57 +01:00
rang_gr , _ , gr_name = sco_bulletins . get_etud_rangs_groups (
2021-08-21 00:24:51 +02:00
etudid , formsemestre_id , partitions , partitions_etud_groups , nt
2020-09-26 16:19:37 +02:00
)
for partition in partitions :
l . append ( rang_gr [ partition [ " partition_id " ] ] )
2021-12-11 20:27:58 +01:00
2022-01-08 19:56:09 +01:00
# Nombre d'UE au dessus de 10
2022-01-09 22:34:49 +01:00
# t[i] est une chaine :-)
# nb_ue_ok = sum(
# [t[i] > 10 for i, ue in enumerate(ues, start=1) if ue["type"] != UE_SPORT]
# )
ue_index = [ ] # indices des moy UE dans l (pour appliquer style css)
2021-12-11 20:27:58 +01:00
for i , ue in enumerate ( ues , start = 1 ) :
2020-09-26 16:19:37 +02:00
if ue [ " type " ] != UE_SPORT :
l . append (
2021-02-04 20:02:44 +01:00
fmtnum ( scu . fmt_note ( t [ i ] , keep_numeric = keep_numeric ) )
2020-09-26 16:19:37 +02:00
) # moyenne etud dans ue
else : # UE_SPORT:
# n'affiche pas la moyenne d'UE dans ce cas
if not hidemodules :
l . append ( " " )
ue_index . append ( len ( l ) - 1 )
if not hidemodules and not ue [ " is_external " ] :
j = 0
for modimpl in modimpls :
2022-02-06 16:09:17 +01:00
if modimpl . module . ue_id == ue [ " ue_id " ] :
2020-09-26 16:19:37 +02:00
l . append (
fmtnum (
2021-02-04 20:02:44 +01:00
scu . fmt_note (
t [ j + len ( ues ) + 1 ] , keep_numeric = keep_numeric
)
2020-09-26 16:19:37 +02:00
)
) # moyenne etud dans module
if format == " xlsall " :
2022-02-06 16:09:17 +01:00
l + = _list_notes_evals ( mod_evals [ modimpl . id ] , etudid )
2020-09-26 16:19:37 +02:00
j + = 1
if not hidebac :
for k in admission_extra_cols :
2022-02-10 14:34:16 +01:00
l . append ( getattr ( e [ " admission " ] , k , " " ) or " " )
2020-09-26 16:19:37 +02:00
l . append (
nt . identdict [ etudid ] [ " code_nip " ] or " "
) # avant-derniere colonne = code_nip
l . append ( etudid ) # derniere colonne = etudid
F . append ( l )
# Dernière ligne: moyennes, min et max des UEs et modules
if not hidemodules : # moy/min/max dans chaque module
mods_stats = { } # moduleimpl_id : stats
for modimpl in modimpls :
2022-02-06 16:09:17 +01:00
mods_stats [ modimpl . id ] = nt . get_mod_stats ( modimpl . id )
2020-09-26 16:19:37 +02:00
def add_bottom_stat ( key , title , corner_value = " " ) :
l = [ " " , title ]
2021-02-13 21:28:59 +01:00
if civ_nom_prenom :
l + = [ " " , " " ]
2020-09-26 16:19:37 +02:00
if not hidebac :
l . append ( " " )
if format [ : 3 ] == " xls " or format == " csv " :
l + = [ " " ] * len ( partitions )
else :
l + = [ " " ]
l . append ( corner_value )
if format [ : 3 ] == " xls " or format == " csv " :
2021-02-04 20:02:44 +01:00
for _ in partitions :
2020-09-26 16:19:37 +02:00
l + = [ " " ] # rangs dans les groupes
for ue in ues :
if ue [ " type " ] != UE_SPORT :
if key == " nb_valid_evals " :
l . append ( " " )
elif key == " coef " :
2021-07-28 17:03:54 +02:00
if sco_preferences . get_preference ( " use_ue_coefs " , formsemestre_id ) :
2020-09-26 16:19:37 +02:00
l . append ( " %2.3f " % ue [ " coefficient " ] )
else :
l . append ( " " )
else :
if key == " ects " :
2020-09-28 16:18:14 +02:00
if keep_numeric :
l . append ( ue [ key ] )
else :
l . append ( str ( ue [ key ] ) )
2020-09-26 16:19:37 +02:00
else :
2021-02-04 20:02:44 +01:00
l . append ( scu . fmt_note ( ue [ key ] , keep_numeric = keep_numeric ) )
2020-09-26 16:19:37 +02:00
else : # UE_SPORT:
# n'affiche pas la moyenne d'UE dans ce cas
if not hidemodules :
l . append ( " " )
2022-01-09 22:34:49 +01:00
# ue_index.append(len(l) - 1)
2020-09-26 16:19:37 +02:00
if not hidemodules and not ue [ " is_external " ] :
for modimpl in modimpls :
2022-02-06 16:09:17 +01:00
if modimpl . module . ue_id == ue [ " ue_id " ] :
2020-09-26 16:19:37 +02:00
if key == " coef " :
2022-02-06 16:09:17 +01:00
coef = modimpl . module . coefficient
2020-09-26 16:19:37 +02:00
if format [ : 3 ] != " xls " :
coef = str ( coef )
l . append ( coef )
elif key == " ects " :
l . append ( " " ) # ECTS module ?
else :
2022-02-06 16:09:17 +01:00
val = mods_stats [ modimpl . id ] [ key ]
2020-09-26 16:19:37 +02:00
if key == " nb_valid_evals " :
if (
format [ : 3 ] != " xls "
) : # garde val numerique pour excel
val = str ( val )
else : # moyenne du module
2021-02-04 20:02:44 +01:00
val = scu . fmt_note ( val , keep_numeric = keep_numeric )
2020-09-26 16:19:37 +02:00
l . append ( val )
if format == " xlsall " :
2022-02-06 16:09:17 +01:00
l + = _list_notes_evals_stats ( mod_evals [ modimpl . id ] , key )
2020-09-26 16:19:37 +02:00
if modejury :
l . append ( " " ) # case vide sur ligne "Moyennes"
l + = [ " " ] * len ( admission_extra_cols ) # infos admission vides ici
F . append ( l + [ " " , " " ] ) # ajoute cellules code_nip et etudid inutilisees ici
add_bottom_stat (
2021-02-04 20:02:44 +01:00
" min " , " Min " , corner_value = scu . fmt_note ( nt . moy_min , keep_numeric = keep_numeric )
2020-09-26 16:19:37 +02:00
)
add_bottom_stat (
2021-02-04 20:02:44 +01:00
" max " , " Max " , corner_value = scu . fmt_note ( nt . moy_max , keep_numeric = keep_numeric )
2020-09-26 16:19:37 +02:00
)
add_bottom_stat (
2021-02-04 20:02:44 +01:00
" moy " ,
" Moyennes " ,
corner_value = scu . fmt_note ( nt . moy_moy , keep_numeric = keep_numeric ) ,
2020-09-26 16:19:37 +02:00
)
add_bottom_stat ( " coef " , " Coef " )
add_bottom_stat ( " nb_valid_evals " , " Nb évals " )
add_bottom_stat ( " ects " , " ECTS " )
2022-02-06 16:09:17 +01:00
# Génération de la table au format demandé
2020-09-26 16:19:37 +02:00
if format == " html " :
# Table format HTML
H = [
"""
< script type = " text/javascript " >
function va_saisir ( formsemestre_id , etudid ) {
2021-05-11 11:48:32 +02:00
loc = ' formsemestre_validation_etud_form?formsemestre_id= ' + formsemestre_id + ' &etudid= ' + etudid ;
2020-09-26 16:19:37 +02:00
if ( SORT_COLUMN_INDEX ) {
2021-05-11 11:48:32 +02:00
loc + = ' &sortcol= ' + SORT_COLUMN_INDEX ;
2020-09-26 16:19:37 +02:00
}
loc + = ' #etudid ' + etudid ;
document . location = loc ;
}
< / script >
< table class = " notes_recapcomplet sortable " id = " recapcomplet " >
"""
]
if sortcol : # sort table using JS sorttable
H . append (
""" <script type= " text/javascript " >
function resort_recap ( ) {
var clid = % d ;
/ / element < a place par sorttable ( ligne de titre )
lnk = document . getElementById ( " recap_trtit " ) . childNodes [ clid ] . childNodes [ 0 ] ;
ts_resortTable ( lnk , clid ) ;
/ / Scroll window :
eid = document . location . hash ;
if ( eid ) {
var eid = eid . substring ( 1 ) ; / / remove #
var e = document . getElementById ( eid ) ;
if ( e ) {
var y = e . offsetTop + e . offsetParent . offsetTop ;
window . scrollTo ( 0 , y ) ;
}
}
}
addEvent ( window , " load " , resort_recap ) ;
< / script >
"""
% ( int ( sortcol ) )
)
cells = ' <tr class= " recap_row_tit sortbottom " id= " recap_trtit " > '
for i in range ( len ( F [ 0 ] ) - 2 ) :
if i in ue_index :
cls = " recap_tit_ue "
else :
cls = " recap_tit "
2020-12-02 01:00:23 +01:00
if (
i == 0 or F [ 0 ] [ i ] == " classement "
) : # Rang: force tri numerique pour sortable
2020-09-26 16:19:37 +02:00
cls = cls + " sortnumeric "
2021-07-09 17:47:06 +02:00
if F [ 0 ] [ i ] in cod2mod : # lien vers etat module
2022-02-06 18:29:22 +01:00
modimpl = cod2mod [ F [ 0 ] [ i ] ]
2020-12-02 01:00:23 +01:00
cells + = ' <td class= " %s " ><a href= " moduleimpl_status?moduleimpl_id= %s " title= " %s ( %s ) " > %s </a></td> ' % (
cls ,
2022-02-06 18:29:22 +01:00
modimpl . id ,
modimpl . module . titre ,
sco_users . user_info ( modimpl . responsable_id ) [ " nomcomplet " ] ,
2020-12-02 01:00:23 +01:00
F [ 0 ] [ i ] ,
2020-09-26 16:19:37 +02:00
)
else :
cells + = ' <td class= " %s " > %s </td> ' % ( cls , F [ 0 ] [ i ] )
if modejury :
cells + = ' <td class= " recap_tit " >Décision</td> '
ligne_titres = cells + " </tr> "
H . append ( ligne_titres ) # titres
if disable_etudlink :
etudlink = " %(name)s "
else :
2022-01-08 19:56:09 +01:00
etudlink = """ <a
href = " formsemestre_bulletinetud?formsemestre_id= %(formsemestre_id)s &etudid= %(etudid)s &version=selectedevals "
id = " %(etudid)s " class = " etudinfo " > % ( name ) s < / a > """
2020-09-26 16:19:37 +02:00
ir = 0
nblines = len ( F ) - 1
for l in F [ 1 : ] :
etudid = l [ - 1 ]
if ir > = nblines - 6 :
# dernieres lignes:
el = l [ 1 ]
styl = (
" recap_row_min " ,
" recap_row_max " ,
" recap_row_moy " ,
" recap_row_coef " ,
" recap_row_nbeval " ,
" recap_row_ects " ,
) [ ir - nblines + 6 ]
cells = ' <tr class= " %s sortbottom " > ' % styl
else :
el = etudlink % {
" formsemestre_id " : formsemestre_id ,
" etudid " : etudid ,
" name " : l [ 1 ] ,
}
if ir % 2 == 0 :
cells = ' <tr class= " recap_row_even " id= " etudid %s " > ' % etudid
else :
cells = ' <tr class= " recap_row_odd " id= " etudid %s " > ' % etudid
ir + = 1
2021-10-19 15:52:02 +02:00
# XXX nsn = [ x.replace('NA', '-') for x in l[:-2] ]
# notes sans le NA:
2020-09-26 16:19:37 +02:00
nsn = l [ : - 2 ] # copy
for i in range ( len ( nsn ) ) :
2021-10-19 15:52:02 +02:00
if nsn [ i ] == " NA " :
2020-09-26 16:19:37 +02:00
nsn [ i ] = " - "
cells + = ' <td class= " recap_col " > %s </td> ' % nsn [ 0 ] # rang
cells + = ' <td class= " recap_col " > %s </td> ' % el # nom etud (lien)
if not hidebac :
cells + = ' <td class= " recap_col_bac " > %s </td> ' % nsn [ 2 ] # bac
idx_col_gr = 3
else :
idx_col_gr = 2
cells + = ' <td class= " recap_col " > %s </td> ' % nsn [ idx_col_gr ] # group name
# Style si moyenne generale < barre
idx_col_moy = idx_col_gr + 1
cssclass = " recap_col_moy "
try :
2022-01-07 10:37:48 +01:00
if float ( nsn [ idx_col_moy ] ) < ( parcours . BARRE_MOY - scu . NOTES_TOLERANCE ) :
2020-09-26 16:19:37 +02:00
cssclass = " recap_col_moy_inf "
except :
pass
cells + = ' <td class= " %s " > %s </td> ' % ( cssclass , nsn [ idx_col_moy ] )
ue_number = 0
for i in range ( idx_col_moy + 1 , len ( nsn ) ) :
if i in ue_index :
cssclass = " recap_col_ue "
# grise si moy UE < barre
ue = ues [ ue_number ]
ue_number + = 1
if ( ir < ( nblines - 4 ) ) or ( ir == nblines - 3 ) :
try :
2022-01-07 10:37:48 +01:00
if float ( nsn [ i ] ) < parcours . get_barre_ue (
2020-09-26 16:19:37 +02:00
ue [ " type " ]
) : # NOTES_BARRE_UE
cssclass = " recap_col_ue_inf "
2022-01-07 10:37:48 +01:00
elif float ( nsn [ i ] ) > = parcours . NOTES_BARRE_VALID_UE :
2020-09-26 16:19:37 +02:00
cssclass = " recap_col_ue_val "
except :
pass
else :
cssclass = " recap_col "
if (
ir == nblines - 3
) : # si moyenne generale module < barre ue, surligne:
try :
2022-01-07 10:37:48 +01:00
if float ( nsn [ i ] ) < parcours . get_barre_ue ( ue [ " type " ] ) :
2020-09-26 16:19:37 +02:00
cssclass = " recap_col_moy_inf "
except :
pass
cells + = ' <td class= " %s " > %s </td> ' % ( cssclass , nsn [ i ] )
if modejury and etudid :
decision_sem = nt . get_etud_decision_sem ( etudid )
if is_dem [ etudid ] :
code = " DEM "
act = " "
elif decision_sem :
code = decision_sem [ " code " ]
act = " (modifier) "
else :
code = " "
act = " saisir "
cells + = ' <td class= " decision " > %s ' % code
if act :
2021-05-11 11:48:32 +02:00
# cells += ' <a href="formsemestre_validation_etud_form?formsemestre_id=%s&etudid=%s">%s</a>' % (formsemestre_id, etudid, act)
2020-09-26 16:19:37 +02:00
cells + = (
""" <a href= " # " onclick= " va_saisir( ' %s ' , ' %s ' ) " > %s </a> """
% ( formsemestre_id , etudid , act )
)
cells + = " </td> "
H . append ( cells + " </tr> " )
H . append ( ligne_titres )
H . append ( " </table> " )
# Form pour choisir partition de classement:
if not modejury and partitions :
H . append ( " Afficher le rang des groupes de: " )
if not rank_partition_id :
checked = " checked "
else :
checked = " "
H . append (
' <input type= " radio " name= " rank_partition_id " value= " " onchange= " document.f.submit() " %s />tous '
% ( checked )
)
for p in partitions :
if p [ " partition_id " ] == rank_partition_id :
checked = " checked "
else :
checked = " "
H . append (
' <input type= " radio " name= " rank_partition_id " value= " %s " onchange= " document.f.submit() " %s /> %s '
% ( p [ " partition_id " ] , checked , p [ " partition_name " ] )
)
# recap des decisions jury (nombre dans chaque code):
if codes_nb :
H . append ( " <h4>Décisions du jury</h4><table> " )
2021-07-09 17:47:06 +02:00
cods = list ( codes_nb . keys ( ) )
2020-09-26 16:19:37 +02:00
cods . sort ( )
for cod in cods :
H . append ( " <tr><td> %s </td><td> %d </td></tr> " % ( cod , codes_nb [ cod ] ) )
H . append ( " </table> " )
2022-01-08 19:56:09 +01:00
# Avertissements
if formsemestre . formation . is_apc ( ) :
H . append (
""" <p class= " help " >Pour les formations par compétences (comme le BUT), la moyenne générale est purement indicative et ne devrait pas être communiquée aux étudiants.</p> """
)
2020-09-26 16:19:37 +02:00
return " \n " . join ( H ) , " " , " html "
elif format == " csv " :
2021-02-16 15:22:50 +01:00
CSV = scu . CSV_LINESEP . join (
[ scu . CSV_FIELDSEP . join ( [ str ( x ) for x in l ] ) for l in F ]
)
2020-09-26 16:19:37 +02:00
semname = sem [ " titre_num " ] . replace ( " " , " _ " )
date = time . strftime ( " %d - % m- % Y " )
filename = " notes_modules- %s - %s .csv " % ( semname , date )
return CSV , filename , " csv "
elif format [ : 3 ] == " xls " :
semname = sem [ " titre_num " ] . replace ( " " , " _ " )
date = time . strftime ( " %d - % m- % Y " )
if format == " xls " :
2021-08-12 14:49:53 +02:00
filename = " notes_modules- %s - %s %s " % ( semname , date , scu . XLSX_SUFFIX )
2020-09-26 16:19:37 +02:00
else :
2021-08-12 14:49:53 +02:00
filename = " notes_modules_evals- %s - %s %s " % ( semname , date , scu . XLSX_SUFFIX )
2021-08-22 06:07:02 +02:00
sheet_name = " notes %s %s " % ( semname , date )
if len ( sheet_name ) > 31 :
sheet_name = " notes %s %s " % ( " ... " , date )
2021-08-12 14:49:53 +02:00
xls = sco_excel . excel_simple_table (
2020-09-26 16:19:37 +02:00
titles = [ " etudid " , " code_nip " ] + F [ 0 ] [ : - 2 ] ,
lines = [
[ x [ - 1 ] , x [ - 2 ] ] + x [ : - 2 ] for x in F [ 1 : ]
2021-08-22 06:07:02 +02:00
] , # reordonne cols (etudid et nip en 1er),
sheet_name = sheet_name ,
2020-09-26 16:19:37 +02:00
)
return xls , filename , " xls "
else :
raise ValueError ( " unknown format %s " % format )
2022-02-06 16:09:17 +01:00
def _list_notes_evals ( evals : list [ Evaluation ] , etudid : int ) - > list [ str ] :
2020-09-26 16:19:37 +02:00
""" Liste des notes des evaluations completes de ce module
( pour table xls avec evals )
"""
L = [ ]
for e in evals :
2022-02-06 16:09:17 +01:00
notes_db = sco_evaluation_db . do_evaluation_get_all_notes ( e . evaluation_id )
if etudid in notes_db :
val = notes_db [ etudid ] [ " value " ]
else :
# Note manquante mais prise en compte immédiate: affiche ATT
val = scu . NOTES_ATTENTE
val_fmt = scu . fmt_note ( val , keep_numeric = True )
L . append ( val_fmt )
2020-09-26 16:19:37 +02:00
return L
2022-02-06 16:09:17 +01:00
def _list_notes_evals_titles ( codemodule : str , evals : list [ Evaluation ] ) - > list [ str ] :
2020-09-26 16:19:37 +02:00
""" Liste des titres des evals completes """
L = [ ]
2020-12-23 22:27:21 +01:00
eval_index = len ( evals ) - 1
2020-09-26 16:19:37 +02:00
for e in evals :
2022-02-11 18:26:36 +01:00
L . append (
codemodule
+ " - "
+ str ( eval_index )
+ " - "
+ ( e . jour . isoformat ( ) if e . jour else " " )
)
2020-12-23 22:27:21 +01:00
eval_index - = 1
2020-09-26 16:19:37 +02:00
return L
2022-02-06 16:09:17 +01:00
def _list_notes_evals_stats ( evals : list [ Evaluation ] , key : str ) - > list [ str ] :
2020-09-26 16:19:37 +02:00
""" Liste des stats (moy, ou rien!) des evals completes """
L = [ ]
for e in evals :
2022-02-06 16:09:17 +01:00
if key == " moy " :
# TODO #sco92
# val = e["etat"]["moy_num"]
# L.append(scu.fmt_note(val, keep_numeric=True))
L . append ( " " )
elif key == " max " :
L . append ( e . note_max )
elif key == " min " :
L . append ( 0.0 )
elif key == " coef " :
L . append ( e . coefficient )
else :
L . append ( " " ) # on n'a pas sous la main min/max
2020-09-26 16:19:37 +02:00
return L
def _formsemestre_recapcomplet_xml (
2020-12-12 17:22:54 +01:00
formsemestre_id ,
xml_nodate ,
xml_with_decisions = False ,
force_publishing = True ,
2020-09-26 16:19:37 +02:00
) :
2020-12-02 01:00:23 +01:00
" XML export: liste tous les bulletins XML. "
2022-02-12 22:57:46 +01:00
formsemestre = FormSemestre . query . get_or_404 ( formsemestre_id )
nt : NotesTableCompat = res_sem . load_formsemestre_results ( formsemestre )
2020-09-26 16:19:37 +02:00
T = nt . get_table_moyennes_triees ( )
if not T :
return " " , " " , " xml "
if xml_nodate :
docdate = " "
else :
docdate = datetime . datetime . now ( ) . isoformat ( )
2021-07-10 17:40:40 +02:00
doc = ElementTree . Element (
2021-08-22 17:18:15 +02:00
" recapsemestre " , formsemestre_id = str ( formsemestre_id ) , date = docdate
2021-07-10 17:40:40 +02:00
)
2021-07-29 10:19:00 +02:00
evals = sco_evaluations . do_evaluation_etat_in_sem ( formsemestre_id )
2021-07-10 17:40:40 +02:00
doc . append (
ElementTree . Element (
" evals_info " ,
nb_evals_completes = str ( evals [ " nb_evals_completes " ] ) ,
nb_evals_en_cours = str ( evals [ " nb_evals_en_cours " ] ) ,
nb_evals_vides = str ( evals [ " nb_evals_vides " ] ) ,
date_derniere_note = str ( evals [ " last_modif " ] ) ,
)
2020-09-26 16:19:37 +02:00
)
for t in T :
etudid = t [ - 1 ]
sco_bulletins_xml . make_xml_formsemestre_bulletinetud (
formsemestre_id ,
etudid ,
doc = doc ,
2020-12-12 17:22:54 +01:00
force_publishing = force_publishing ,
2020-09-26 16:19:37 +02:00
xml_nodate = xml_nodate ,
xml_with_decisions = xml_with_decisions ,
)
2021-07-12 23:34:18 +02:00
return (
sco_xml . XML_HEADER + ElementTree . tostring ( doc ) . decode ( scu . SCO_ENCODING ) ,
" " ,
" xml " ,
)
2020-12-02 01:00:23 +01:00
def _formsemestre_recapcomplet_json (
2020-12-12 17:22:54 +01:00
formsemestre_id ,
xml_nodate = False ,
xml_with_decisions = False ,
force_publishing = True ,
2020-12-02 01:00:23 +01:00
) :
2020-12-12 17:22:54 +01:00
""" JSON export: liste tous les bulletins JSON
: param xml_nodate ( bool ) : indique la date courante ( attribut docdate )
: param force_publishing : donne les bulletins même si non " publiés sur portail "
: returns : dict , " " , " json "
"""
2021-12-17 21:59:28 +01:00
formsemestre = FormSemestre . query . get_or_404 ( formsemestre_id )
is_apc = formsemestre . formation . is_apc ( )
2020-12-02 01:00:23 +01:00
if xml_nodate :
docdate = " "
else :
docdate = datetime . datetime . now ( ) . isoformat ( )
2021-07-29 10:19:00 +02:00
evals = sco_evaluations . do_evaluation_etat_in_sem ( formsemestre_id )
2020-12-02 01:00:23 +01:00
J = {
" docdate " : docdate ,
" formsemestre_id " : formsemestre_id ,
" evals_info " : {
" nb_evals_completes " : evals [ " nb_evals_completes " ] ,
" nb_evals_en_cours " : evals [ " nb_evals_en_cours " ] ,
" nb_evals_vides " : evals [ " nb_evals_vides " ] ,
" date_derniere_note " : evals [ " last_modif " ] ,
} ,
" bulletins " : [ ] ,
}
bulletins = J [ " bulletins " ]
2022-02-12 22:57:46 +01:00
formsemestre = FormSemestre . query . get_or_404 ( formsemestre_id )
nt : NotesTableCompat = res_sem . load_formsemestre_results ( formsemestre )
2020-12-02 01:00:23 +01:00
T = nt . get_table_moyennes_triees ( )
for t in T :
etudid = t [ - 1 ]
2021-12-17 21:59:28 +01:00
if is_apc :
etud = Identite . query . get ( etudid )
2021-12-24 00:08:25 +01:00
r = bulletin_but . BulletinBUT ( formsemestre )
2021-12-17 21:59:28 +01:00
bul = r . bulletin_etud ( etud , formsemestre )
else :
bul = sco_bulletins_json . formsemestre_bulletinetud_published_dict (
2020-12-02 01:00:23 +01:00
formsemestre_id ,
etudid ,
2020-12-12 17:22:54 +01:00
force_publishing = force_publishing ,
2020-12-02 01:00:23 +01:00
xml_with_decisions = xml_with_decisions ,
)
2021-12-17 21:59:28 +01:00
bulletins . append ( bul )
2020-12-02 01:00:23 +01:00
return J , " " , " json "
2020-12-12 17:22:54 +01:00
2021-09-27 10:20:10 +02:00
def formsemestres_bulletins ( annee_scolaire ) :
2020-12-12 17:22:54 +01:00
""" Tous les bulletins des semestres publiés des semestres de l ' année indiquée.
2022-02-09 23:22:00 +01:00
: param annee_scolaire ( int ) : année de début de l ' année scolaire
2020-12-12 17:22:54 +01:00
: returns : JSON
"""
jslist = [ ]
2021-08-19 10:28:35 +02:00
sems = sco_formsemestre . list_formsemestre_by_etape ( annee_scolaire = annee_scolaire )
2020-12-12 17:22:54 +01:00
log ( " formsemestres_bulletins( %s ): %d sems " % ( annee_scolaire , len ( sems ) ) )
for sem in sems :
J , _ , _ = _formsemestre_recapcomplet_json (
2021-08-21 00:24:51 +02:00
sem [ " formsemestre_id " ] , force_publishing = False
2020-12-12 17:22:54 +01:00
)
jslist . append ( J )
2021-09-21 13:36:56 +02:00
return scu . sendJSON ( jslist )