2020-09-26 16:19:37 +02:00
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# Gestion scolarite IUT
#
2021-01-01 17:51:08 +01:00
# Copyright (c) 1999 - 2021 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
#
##############################################################################
2021-06-16 18:18:32 +02:00
""" Ajout/Modification/Suppression UE
2020-09-26 16:19:37 +02:00
"""
2021-07-31 18:01:10 +02:00
import flask
2021-09-18 10:10:02 +02:00
from flask import g , url_for , request
2021-07-31 18:01:10 +02:00
from flask_login import current_user
2021-11-14 18:09:20 +01:00
from app . models . formations import Formation , UniteEns
2021-06-19 23:21:37 +02:00
import app . scodoc . notesdb as ndb
import app . scodoc . sco_utils as scu
2021-11-12 22:17:46 +01:00
from app . scodoc . sco_utils import ModuleType
2021-08-29 19:57:32 +02:00
from app import log
2021-06-19 23:21:37 +02:00
from app . scodoc . TrivialFormulator import TrivialFormulator , TF
from app . scodoc . gen_tables import GenTable
from app . scodoc . sco_permissions import Permission
from app . scodoc . sco_exceptions import ScoValueError , ScoLockedFormError
from app . scodoc import html_sco_header
2021-07-19 19:53:01 +02:00
from app . scodoc import sco_cache
2021-06-19 23:21:37 +02:00
from app . scodoc import sco_codes_parcours
2021-11-17 10:28:51 +01:00
from app . scodoc import sco_edit_apc
2021-07-19 19:53:01 +02:00
from app . scodoc import sco_edit_formation
2021-06-19 23:21:37 +02:00
from app . scodoc import sco_edit_matiere
from app . scodoc import sco_edit_module
2021-07-19 19:53:01 +02:00
from app . scodoc import sco_etud
2021-06-19 23:21:37 +02:00
from app . scodoc import sco_formsemestre
from app . scodoc import sco_groups
from app . scodoc import sco_moduleimpl
from app . scodoc import sco_news
from app . scodoc import sco_permissions
from app . scodoc import sco_preferences
from app . scodoc import sco_tag_module
2020-09-26 16:19:37 +02:00
2021-06-16 18:18:32 +02:00
_ueEditor = ndb . EditableTable (
" notes_ue " ,
" ue_id " ,
(
" ue_id " ,
" formation_id " ,
" acronyme " ,
" numero " ,
" titre " ,
2021-11-14 18:09:20 +01:00
" semestre_idx " ,
2021-06-16 18:18:32 +02:00
" type " ,
" ue_code " ,
" ects " ,
" is_external " ,
" code_apogee " ,
" coefficient " ,
) ,
sortkey = " numero " ,
2021-08-11 00:36:07 +02:00
input_formators = {
" type " : ndb . int_null_is_zero ,
2021-10-22 23:09:15 +02:00
" is_external " : ndb . bool_or_str ,
2021-08-11 00:36:07 +02:00
} ,
2021-06-16 18:18:32 +02:00
output_formators = {
" numero " : ndb . int_null_is_zero ,
" ects " : ndb . float_null_is_null ,
" coefficient " : ndb . float_null_is_zero ,
2021-11-14 18:09:20 +01:00
" semestre_idx " : ndb . int_null_is_null ,
2021-06-16 18:18:32 +02:00
} ,
)
2021-10-17 23:19:26 +02:00
def ue_list ( * args , * * kw ) :
2021-06-16 18:18:32 +02:00
" list UEs "
cnx = ndb . GetDBConnexion ( )
return _ueEditor . list ( cnx , * args , * * kw )
2021-08-20 01:09:55 +02:00
def do_ue_create ( args ) :
2021-06-16 18:18:32 +02:00
" create an ue "
2021-06-19 23:21:37 +02:00
from app . scodoc import sco_formations
2021-06-16 18:18:32 +02:00
cnx = ndb . GetDBConnexion ( )
# check duplicates
2021-10-17 23:19:26 +02:00
ues = ue_list ( { " formation_id " : args [ " formation_id " ] , " acronyme " : args [ " acronyme " ] } )
2021-06-16 18:18:32 +02:00
if ues :
raise ScoValueError ( ' Acronyme d \' UE " %s " déjà utilisé ! ' % args [ " acronyme " ] )
# create
2021-06-17 00:08:37 +02:00
r = _ueEditor . create ( cnx , args )
2021-06-16 18:18:32 +02:00
# news
2021-08-19 10:28:35 +02:00
F = sco_formations . formation_list ( args = { " formation_id " : args [ " formation_id " ] } ) [ 0 ]
2021-06-16 18:18:32 +02:00
sco_news . add (
2021-06-19 23:21:37 +02:00
typ = sco_news . NEWS_FORM ,
2021-06-16 18:18:32 +02:00
object = args [ " formation_id " ] ,
text = " Modification de la formation %(acronyme)s " % F ,
2021-08-01 10:16:16 +02:00
max_frequency = 3 ,
2021-06-16 18:18:32 +02:00
)
return r
2021-08-30 23:28:15 +02:00
def do_ue_delete ( ue_id , delete_validations = False , force = False ) :
2021-06-19 23:21:37 +02:00
" delete UE and attached matieres (but not modules) "
from app . scodoc import sco_formations
from app . scodoc import sco_parcours_dut
2021-06-16 18:18:32 +02:00
cnx = ndb . GetDBConnexion ( )
log ( " do_ue_delete: ue_id= %s , delete_validations= %s " % ( ue_id , delete_validations ) )
# check
2021-10-17 23:19:26 +02:00
ue = ue_list ( { " ue_id " : ue_id } )
2021-06-16 18:18:32 +02:00
if not ue :
raise ScoValueError ( " UE inexistante ! " )
ue = ue [ 0 ]
2021-08-20 01:09:55 +02:00
if ue_is_locked ( ue [ " ue_id " ] ) :
2021-06-16 18:18:32 +02:00
raise ScoLockedFormError ( )
# Il y a-t-il des etudiants ayant validé cette UE ?
# si oui, propose de supprimer les validations
validations = sco_parcours_dut . scolar_formsemestre_validation_list (
cnx , args = { " ue_id " : ue_id }
)
if validations and not delete_validations and not force :
return scu . confirm_dialog (
" <p> %d étudiants ont validé l ' UE %s ( %s )</p><p>Si vous supprimez cette UE, ces validations vont être supprimées !</p> "
% ( len ( validations ) , ue [ " acronyme " ] , ue [ " titre " ] ) ,
dest_url = " " ,
target_variable = " delete_validations " ,
2021-10-22 23:09:15 +02:00
cancel_url = url_for (
" notes.ue_table " ,
scodoc_dept = g . scodoc_dept ,
formation_id = str ( ue [ " formation_id " ] ) ,
) ,
2021-06-16 18:18:32 +02:00
parameters = { " ue_id " : ue_id , " dialog_confirmed " : 1 } ,
)
if delete_validations :
log ( " deleting all validations of UE %s " % ue_id )
ndb . SimpleQuery (
" DELETE FROM scolar_formsemestre_validation WHERE ue_id= %(ue_id)s " ,
{ " ue_id " : ue_id } ,
)
# delete all matiere in this UE
2021-10-17 23:19:26 +02:00
mats = sco_edit_matiere . matiere_list ( { " ue_id " : ue_id } )
2021-06-16 18:18:32 +02:00
for mat in mats :
2021-08-20 01:09:55 +02:00
sco_edit_matiere . do_matiere_delete ( mat [ " matiere_id " ] )
2021-06-16 18:18:32 +02:00
# delete uecoef and events
ndb . SimpleQuery (
" DELETE FROM notes_formsemestre_uecoef WHERE ue_id= %(ue_id)s " ,
{ " ue_id " : ue_id } ,
)
2021-07-28 17:03:54 +02:00
ndb . SimpleQuery ( " DELETE FROM scolar_events WHERE ue_id= %(ue_id)s " , { " ue_id " : ue_id } )
2021-06-16 18:18:32 +02:00
cnx = ndb . GetDBConnexion ( )
2021-06-17 00:08:37 +02:00
_ueEditor . delete ( cnx , ue_id )
2021-06-16 18:18:32 +02:00
# > UE delete + supr. validations associées etudiants (cas compliqué, mais rarement utilisé: acceptable de tout invalider ?):
2021-07-19 19:53:01 +02:00
sco_cache . invalidate_formsemestre ( )
2021-06-16 18:18:32 +02:00
# news
2021-08-19 10:28:35 +02:00
F = sco_formations . formation_list ( args = { " formation_id " : ue [ " formation_id " ] } ) [ 0 ]
2021-06-16 18:18:32 +02:00
sco_news . add (
2021-06-19 23:21:37 +02:00
typ = sco_news . NEWS_FORM ,
2021-06-16 18:18:32 +02:00
object = ue [ " formation_id " ] ,
text = " Modification de la formation %(acronyme)s " % F ,
2021-08-01 10:16:16 +02:00
max_frequency = 3 ,
2021-06-16 18:18:32 +02:00
)
#
if not force :
2021-07-31 18:01:10 +02:00
return flask . redirect (
url_for (
2021-10-17 23:19:26 +02:00
" notes.ue_table " ,
2021-07-31 18:01:10 +02:00
scodoc_dept = g . scodoc_dept ,
formation_id = ue [ " formation_id " ] ,
)
2021-06-16 18:18:32 +02:00
)
else :
return None
2020-09-26 16:19:37 +02:00
2021-09-27 10:20:10 +02:00
def ue_create ( formation_id = None ) :
2021-01-01 18:40:47 +01:00
""" Creation d ' une UE """
2021-09-27 10:20:10 +02:00
return ue_edit ( create = True , formation_id = formation_id )
2020-09-26 16:19:37 +02:00
2021-09-27 10:20:10 +02:00
def ue_edit ( ue_id = None , create = False , formation_id = None ) :
2021-11-14 18:09:20 +01:00
""" Modification ou création d ' une UE """
2021-06-19 23:21:37 +02:00
from app . scodoc import sco_formations
2020-09-26 16:19:37 +02:00
create = int ( create )
if not create :
2021-10-17 23:19:26 +02:00
U = ue_list ( args = { " ue_id " : ue_id } )
2020-09-26 16:19:37 +02:00
if not U :
raise ScoValueError ( " UE inexistante ! " )
U = U [ 0 ]
formation_id = U [ " formation_id " ]
title = " Modification de l ' UE %(titre)s " % U
initvalues = U
submitlabel = " Modifier les valeurs "
else :
title = " Création d ' une UE "
initvalues = { }
submitlabel = " Créer cette UE "
2021-11-14 18:09:20 +01:00
formation = Formation . query . get ( formation_id )
if not formation :
raise ScoValueError ( f " Formation inexistante ! (id= { formation_id } ) " )
parcours = formation . get_parcours ( )
is_apc = parcours . APC_SAE
semestres_indices = list ( range ( 1 , parcours . NB_SEM + 1 ) )
2020-09-26 16:19:37 +02:00
H = [
2021-07-29 16:31:15 +02:00
html_sco_header . sco_header ( page_title = title , javascripts = [ " js/edit_ue.js " ] ) ,
2020-09-26 16:19:37 +02:00
" <h2> " + title ,
2021-11-14 18:09:20 +01:00
f " (formation { formation . acronyme } , version { formation . version } )</h2> " ,
2020-09-26 16:19:37 +02:00
"""
2021-11-14 18:09:20 +01:00
< p class = " help " > Les UE sont des groupes de modules dans une formation donnée ,
utilisés pour la validation ( on calcule des moyennes par UE et applique des
seuils ( " barres " ) ) .
< / p >
< p class = " help " > Note : sauf exception , l ' UE n ' a pas de coefficient associé .
Seuls les < em > modules < / em > ont des coefficients .
< / p > """ ,
2020-09-26 16:19:37 +02:00
]
ue_types = parcours . ALLOWED_UE_TYPES
ue_types . sort ( )
2021-02-03 22:00:41 +01:00
ue_types_names = [ sco_codes_parcours . UE_TYPE_NAME [ k ] for k in ue_types ]
2020-09-26 16:19:37 +02:00
ue_types = [ str ( x ) for x in ue_types ]
fw = [
( " ue_id " , { " input_type " : " hidden " } ) ,
( " create " , { " input_type " : " hidden " , " default " : create } ) ,
( " formation_id " , { " input_type " : " hidden " , " default " : formation_id } ) ,
( " titre " , { " size " : 30 , " explanation " : " nom de l ' UE " } ) ,
( " acronyme " , { " size " : 8 , " explanation " : " abbréviation " , " allow_null " : False } ) ,
(
" numero " ,
{
" size " : 2 ,
" explanation " : " numéro (1,2,3,4) de l ' UE pour l ' ordre d ' affichage " ,
" type " : " int " ,
} ,
) ,
2021-11-14 18:09:20 +01:00
(
" semestre_idx " ,
{
" input_type " : " menu " ,
" type " : " int " ,
" allow_null " : True ,
" title " : parcours . SESSION_NAME . capitalize ( ) ,
" explanation " : " %s de l ' UE dans la formation " % parcours . SESSION_NAME ,
" labels " : [ " non spécifié " ] + [ str ( x ) for x in semestres_indices ] ,
" allowed_values " : [ " " ] + semestres_indices ,
} ,
) ,
2020-09-26 16:19:37 +02:00
(
" type " ,
{
" explanation " : " type d ' UE " ,
" input_type " : " menu " ,
" allowed_values " : ue_types ,
" labels " : ue_types_names ,
} ,
) ,
(
" ects " ,
{
" size " : 4 ,
" type " : " float " ,
" title " : " ECTS " ,
" explanation " : " nombre de crédits ECTS " ,
} ,
) ,
(
" coefficient " ,
{
" size " : 4 ,
" type " : " float " ,
" title " : " Coefficient " ,
2021-11-14 18:09:20 +01:00
" explanation " : """ les coefficients d ' UE ne sont utilisés que
lorsque l ' option <em>Utiliser les coefficients d ' UE pour calculer
la moyenne générale < / em > est activée . Par défaut , le coefficient
d ' une UE est simplement la somme des coefficients des modules dans
lesquels l ' étudiant a des notes.
""" ,
2020-09-26 16:19:37 +02:00
} ,
) ,
(
" ue_code " ,
{
" size " : 12 ,
" title " : " Code UE " ,
" explanation " : " code interne (optionnel). Toutes les UE partageant le même code (et le même code de formation) sont compatibles (compensation de semestres, capitalisation d ' UE). Voir liste ci-dessous. " ,
} ,
) ,
(
" code_apogee " ,
{
" title " : " Code Apogée " ,
2021-06-24 23:09:06 +02:00
" size " : 25 ,
" explanation " : " (optionnel) code élément pédagogique Apogée ou liste de codes ELP séparés par des virgules " ,
2020-09-26 16:19:37 +02:00
} ,
) ,
2021-10-22 23:09:15 +02:00
(
" is_external " ,
{
" input_type " : " boolcheckbox " ,
" title " : " UE externe " ,
" explanation " : " réservé pour les capitalisations d ' UE effectuées à l ' extérieur de l ' établissement " ,
} ,
) ,
2020-09-26 16:19:37 +02:00
]
if create and not parcours . UE_IS_MODULE :
fw . append (
(
" create_matiere " ,
{
" input_type " : " boolcheckbox " ,
2021-11-14 18:09:20 +01:00
" default " : True ,
2020-09-26 16:19:37 +02:00
" title " : " Créer matière identique " ,
" explanation " : " créer immédiatement une matière dans cette UE (utile si on n ' utilise pas de matières) " ,
} ,
)
)
tf = TrivialFormulator (
2021-09-18 10:10:02 +02:00
request . base_url ,
2021-09-27 16:42:14 +02:00
scu . get_request_args ( ) ,
2021-09-18 10:10:02 +02:00
fw ,
initvalues = initvalues ,
submitlabel = submitlabel ,
2020-09-26 16:19:37 +02:00
)
if tf [ 0 ] == 0 :
X = """ <div id= " ue_list_code " ></div>
"""
2021-07-29 10:19:00 +02:00
return " \n " . join ( H ) + tf [ 1 ] + X + html_sco_header . sco_footer ( )
2020-09-26 16:19:37 +02:00
else :
if create :
if not tf [ 2 ] [ " ue_code " ] :
del tf [ 2 ] [ " ue_code " ]
if not tf [ 2 ] [ " numero " ] :
# numero regroupant par semestre ou année:
tf [ 2 ] [ " numero " ] = next_ue_numero (
2021-11-14 18:09:20 +01:00
formation_id , int ( tf [ 2 ] [ " semestre_idx " ] )
2020-09-26 16:19:37 +02:00
)
2021-08-20 01:09:55 +02:00
ue_id = do_ue_create ( tf [ 2 ] )
2020-09-26 16:19:37 +02:00
if parcours . UE_IS_MODULE or tf [ 2 ] [ " create_matiere " ] :
2021-06-17 00:08:37 +02:00
matiere_id = sco_edit_matiere . do_matiere_create (
{ " ue_id " : ue_id , " titre " : tf [ 2 ] [ " titre " ] , " numero " : 1 } ,
2020-09-26 16:19:37 +02:00
)
if parcours . UE_IS_MODULE :
# dans ce mode, crée un (unique) module dans l'UE:
2021-06-17 00:08:37 +02:00
_ = sco_edit_module . do_module_create (
2020-09-26 16:19:37 +02:00
{
" titre " : tf [ 2 ] [ " titre " ] ,
" code " : tf [ 2 ] [ " acronyme " ] ,
" coefficient " : 1.0 , # tous les modules auront coef 1, et on utilisera les ECTS
" ue_id " : ue_id ,
" matiere_id " : matiere_id ,
" formation_id " : formation_id ,
2021-11-14 18:09:20 +01:00
" semestre_id " : tf [ 2 ] [ " semestre_idx " ] ,
2020-09-26 16:19:37 +02:00
} ,
)
else :
2021-08-20 01:09:55 +02:00
do_ue_edit ( tf [ 2 ] )
2021-07-31 18:01:10 +02:00
return flask . redirect (
url_for (
2021-10-17 23:19:26 +02:00
" notes.ue_table " , scodoc_dept = g . scodoc_dept , formation_id = formation_id
2021-07-31 18:01:10 +02:00
)
2020-09-26 16:19:37 +02:00
)
2021-11-17 10:28:51 +01:00
def _add_ue_semestre_id ( ues : list [ dict ] , is_apc ) :
2021-11-14 18:09:20 +01:00
""" ajoute semestre_id dans les ue, en regardant
2021-11-17 10:28:51 +01:00
semestre_idx ou à défaut , pour les formations non APC , le premier module
de chacune .
Les UE sans modules se voient attribuer le numero UE_SEM_DEFAULT ( 1000000 ) ,
2020-09-26 16:19:37 +02:00
qui les place à la fin de la liste .
"""
2021-10-21 06:32:03 +02:00
for ue in ues :
2021-11-14 18:09:20 +01:00
if ue [ " semestre_idx " ] is not None :
ue [ " semestre_id " ] = ue [ " semestre_idx " ]
2021-11-17 10:28:51 +01:00
elif is_apc :
ue [ " semestre_id " ] = sco_codes_parcours . UE_SEM_DEFAULT
2020-09-26 16:19:37 +02:00
else :
2021-11-17 10:28:51 +01:00
# était le comportement ScoDoc7
2021-11-14 18:09:20 +01:00
modules = sco_edit_module . module_list ( args = { " ue_id " : ue [ " ue_id " ] } )
if modules :
ue [ " semestre_id " ] = modules [ 0 ] [ " semestre_id " ]
else :
2021-11-17 10:28:51 +01:00
ue [ " semestre_id " ] = sco_codes_parcours . UE_SEM_DEFAULT
2020-09-26 16:19:37 +02:00
2021-08-20 01:09:55 +02:00
def next_ue_numero ( formation_id , semestre_id = None ) :
2020-09-26 16:19:37 +02:00
""" Numero d ' une nouvelle UE dans cette formation.
Si le semestre est specifie , cherche les UE ayant des modules de ce semestre
"""
2021-11-17 10:28:51 +01:00
formation = Formation . query . get ( formation_id )
2021-10-21 06:32:03 +02:00
ues = ue_list ( args = { " formation_id " : formation_id } )
if not ues :
2020-09-26 16:19:37 +02:00
return 0
if semestre_id is None :
2021-10-21 06:32:03 +02:00
return ues [ - 1 ] [ " numero " ] + 1000
2020-09-26 16:19:37 +02:00
else :
# Avec semestre: (prend le semestre du 1er module de l'UE)
2021-11-17 10:28:51 +01:00
_add_ue_semestre_id ( ues , formation . get_parcours ( ) . APC_SAE )
2021-10-21 06:32:03 +02:00
ue_list_semestre = [ ue for ue in ues if ue [ " semestre_id " ] == semestre_id ]
2020-09-26 16:19:37 +02:00
if ue_list_semestre :
return ue_list_semestre [ - 1 ] [ " numero " ] + 10
else :
2021-10-21 06:32:03 +02:00
return ues [ - 1 ] [ " numero " ] + 1000
2020-09-26 16:19:37 +02:00
2021-08-31 08:21:30 +02:00
def ue_delete ( ue_id = None , delete_validations = False , dialog_confirmed = False ) :
2020-09-26 16:19:37 +02:00
""" Delete an UE """
2021-10-21 06:32:03 +02:00
ues = ue_list ( args = { " ue_id " : ue_id } )
if not ues :
2020-09-26 16:19:37 +02:00
raise ScoValueError ( " UE inexistante ! " )
2021-10-21 06:32:03 +02:00
ue = ues [ 0 ]
2020-09-26 16:19:37 +02:00
if not dialog_confirmed :
2021-06-02 22:40:34 +02:00
return scu . confirm_dialog (
2020-09-26 16:19:37 +02:00
" <h2>Suppression de l ' UE %(titre)s ( %(acronyme)s ))</h2> " % ue ,
dest_url = " " ,
parameters = { " ue_id " : ue_id } ,
2021-10-22 23:09:15 +02:00
cancel_url = url_for (
" notes.ue_table " ,
scodoc_dept = g . scodoc_dept ,
formation_id = str ( ue [ " formation_id " ] ) ,
) ,
2020-09-26 16:19:37 +02:00
)
2021-08-30 23:28:15 +02:00
return do_ue_delete ( ue_id , delete_validations = delete_validations )
2020-09-26 16:19:37 +02:00
2021-10-17 23:19:26 +02:00
def ue_table ( formation_id = None , msg = " " ) : # was ue_list
2021-01-01 18:40:47 +01:00
""" Liste des matières et modules d ' une formation, avec liens pour
2021-10-17 23:19:26 +02:00
éditer ( si non verrouillée ) .
2020-09-26 16:19:37 +02:00
"""
2021-06-19 23:21:37 +02:00
from app . scodoc import sco_formations
from app . scodoc import sco_formsemestre_validation
2021-11-17 10:28:51 +01:00
formation = Formation . query . get ( formation_id )
if not formation :
2020-09-26 16:19:37 +02:00
raise ScoValueError ( " invalid formation_id " )
2021-11-17 10:28:51 +01:00
parcours = formation . get_parcours ( )
2021-11-13 12:09:30 +01:00
is_apc = parcours . APC_SAE
2021-08-20 01:09:55 +02:00
locked = sco_formations . formation_has_locked_sems ( formation_id )
2020-09-26 16:19:37 +02:00
2021-10-22 23:09:15 +02:00
ues = ue_list ( args = { " formation_id " : formation_id , " is_external " : False } )
ues_externes = ue_list ( args = { " formation_id " : formation_id , " is_external " : True } )
2020-09-26 16:19:37 +02:00
# tri par semestre et numero:
2021-11-17 10:28:51 +01:00
_add_ue_semestre_id ( ues , is_apc )
_add_ue_semestre_id ( ues_externes , is_apc )
2021-10-21 06:32:03 +02:00
ues . sort ( key = lambda u : ( u [ " semestre_id " ] , u [ " numero " ] ) )
2021-10-22 23:09:15 +02:00
ues_externes . sort ( key = lambda u : ( u [ " semestre_id " ] , u [ " numero " ] ) )
2021-10-21 06:32:03 +02:00
has_duplicate_ue_codes = len ( set ( [ ue [ " ue_code " ] for ue in ues ] ) ) != len ( ues )
2020-09-26 16:19:37 +02:00
2021-10-22 23:09:15 +02:00
has_perm_change = current_user . has_permission ( Permission . ScoChangeFormation )
# editable = (not locked) and has_perm_change
2021-11-17 10:28:51 +01:00
# On autorise maintenant la modification des formations qui ont
# des semestres verrouillés, sauf si cela affect les notes passées
# (verrouillées):
2020-09-26 16:19:37 +02:00
# - pas de modif des modules utilisés dans des semestres verrouillés
# - pas de changement des codes d'UE utilisés dans des semestres verrouillés
2021-10-22 23:09:15 +02:00
editable = has_perm_change
2021-06-12 22:43:22 +02:00
tag_editable = (
2021-10-22 23:09:15 +02:00
current_user . has_permission ( Permission . ScoEditFormationTags ) or has_perm_change
2021-06-12 22:43:22 +02:00
)
2020-09-26 16:19:37 +02:00
if locked :
2021-02-04 20:02:44 +01:00
lockicon = scu . icontag ( " lock32_img " , title = " verrouillé " )
2020-09-26 16:19:37 +02:00
else :
lockicon = " "
2021-10-12 16:05:50 +02:00
arrow_up , arrow_down , arrow_none = sco_groups . get_arrow_icons_tags ( )
2021-02-04 20:02:44 +01:00
delete_icon = scu . icontag (
2020-09-26 16:19:37 +02:00
" delete_small_img " , title = " Supprimer (module inutilisé) " , alt = " supprimer "
)
2021-02-04 20:02:44 +01:00
delete_disabled_icon = scu . icontag (
2020-09-26 16:19:37 +02:00
" delete_small_dis_img " , title = " Suppression impossible (module utilisé) "
)
H = [
2021-06-13 19:12:20 +02:00
html_sco_header . sco_header (
2020-09-26 16:19:37 +02:00
cssstyles = [ " libjs/jQuery-tagEditor/jquery.tag-editor.css " ] ,
javascripts = [
" libjs/jinplace-1.2.1.min.js " ,
" js/ue_list.js " ,
" libjs/jQuery-tagEditor/jquery.tag-editor.min.js " ,
" libjs/jQuery-tagEditor/jquery.caret.min.js " ,
" js/module_tag_editor.js " ,
] ,
2021-11-17 10:28:51 +01:00
page_title = f " Programme { formation . acronyme } " ,
2020-09-26 16:19:37 +02:00
) ,
2021-11-17 10:28:51 +01:00
f """ <h2>Formation { formation . titre } ( { formation . acronyme } )
[ version { formation . version } ] code { formation . formation_code }
{ lockicon }
< / h2 >
""" ,
2020-09-26 16:19:37 +02:00
]
if locked :
H . append (
2021-08-30 23:28:15 +02:00
f """ <p class= " help " >Cette formation est verrouillée car
{ len ( locked ) } semestres verrouillés s ' y réferent.
Si vous souhaitez modifier cette formation ( par exemple pour y ajouter un module ) ,
vous devez :
2020-09-26 16:19:37 +02:00
< / p >
< ul class = " help " >
2021-08-30 23:28:15 +02:00
< li > soit créer une nouvelle version de cette formation pour pouvoir l ' éditer
librement ( vous pouvez passer par la fonction " Associer à une nouvelle version
du programme " (menu " Semestre " ) si vous avez un semestre en cours);
< / li >
< li > soit déverrouiller le ou les semestres qui s ' y réfèrent (attention, en
principe ces semestres sont archivés et ne devraient pas être modifiés ) .
< / li >
2020-09-26 16:19:37 +02:00
< / ul > """
)
if msg :
H . append ( ' <p class= " msg " > ' + msg + " </p> " )
if has_duplicate_ue_codes :
H . append (
2021-08-30 23:28:15 +02:00
""" <div class= " ue_warning " ><span>Attention: plusieurs UE de cette
formation ont le même code . Il faut corriger cela ci - dessous ,
sinon les calculs d ' ECTS seront erronés !</span></div> " " "
2020-09-26 16:19:37 +02:00
)
# Description de la formation
H . append ( ' <div class= " formation_descr " > ' )
H . append (
2021-11-17 10:28:51 +01:00
f """ <div class= " fd_d " ><span class= " fd_t " >Titre:
< / span > < span class = " fd_v " > { formation . titre } < / span >
< / div >
< div class = " fd_d " > < span class = " fd_t " > Titre officiel : < / span >
< span class = " fd_v " > { formation . titre_officiel } < / span >
< / div >
< div class = " fd_d " > < span class = " fd_t " > Acronyme : < / span >
< span class = " fd_v " > { formation . acronyme } < / span >
< / div >
< div class = " fd_d " > < span class = " fd_t " > Code : < / span >
< span class = " fd_v " > { formation . formation_code } < / span >
< / div >
< div class = " fd_d " > < span class = " fd_t " > Version : < / span >
< span class = " fd_v " > { formation . version } < / span >
< / div >
< div class = " fd_d " > < span class = " fd_t " > Type parcours : < / span >
< span class = " fd_v " > { parcours . __doc__ } < / span >
< / div >
"""
2020-09-26 16:19:37 +02:00
)
if parcours . UE_IS_MODULE :
H . append (
2021-11-17 10:28:51 +01:00
""" <div class= " fd_d " ><span class= " fd_t " > </span>
< span class = " fd_n " > ( Chaque module est une UE ) < / span > < / div > """
2020-09-26 16:19:37 +02:00
)
if editable :
H . append (
2021-11-17 10:28:51 +01:00
f """ <div><a href= " {
url_for ( ' notes.formation_edit ' , scodoc_dept = g . scodoc_dept ,
formation_id = formation_id )
} " class= " stdlink " >modifier ces informations</a></div> " " "
2020-09-26 16:19:37 +02:00
)
H . append ( " </div> " )
2021-11-17 10:28:51 +01:00
2021-11-13 12:09:30 +01:00
# Formation APC (BUT) ?
if is_apc :
H . append (
f """ <div class= " formation_apc_infos " >
< div class = " ue_list_tit " > Formation par compétences ( BUT ) < / div >
< ul >
< li > < a class = " stdlink " href = " {
2021-11-17 10:28:51 +01:00
url_for ( ' notes.edit_modules_ue_coefs ' , scodoc_dept = g . scodoc_dept , formation_id = formation_id , semestre_idx = None )
2021-11-13 12:09:30 +01:00
} " >éditer les coefficients des ressources et SAÉs</a></li>
< / ul >
< / div > """
)
2020-09-26 16:19:37 +02:00
# Description des UE/matières/modules
2021-10-22 23:09:15 +02:00
H . append (
2021-11-17 10:28:51 +01:00
"""
< div class = " formation_ue_list " >
< div class = " ue_list_tit " > Programme pédagogique : < / div >
< form >
< input type = " checkbox " class = " sco_tag_checkbox " > montrer les tags < / input >
< / form >
"""
2021-10-22 23:09:15 +02:00
)
2021-11-17 10:28:51 +01:00
if is_apc :
2020-09-26 16:19:37 +02:00
H . append (
2021-11-17 10:28:51 +01:00
sco_edit_apc . html_edit_formation_apc (
formation , editable = editable , tag_editable = tag_editable
)
2020-09-26 16:19:37 +02:00
)
2021-11-17 10:28:51 +01:00
else :
2020-09-26 16:19:37 +02:00
H . append (
2021-11-17 10:28:51 +01:00
_ue_table_ues (
parcours ,
ues ,
editable ,
tag_editable ,
has_perm_change ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
)
2020-09-26 16:19:37 +02:00
)
2021-11-17 10:28:51 +01:00
if editable :
H . append (
f """ <ul>
< li > < a class = " stdlink " href = " {
url_for ( ' notes.ue_create ' , scodoc_dept = g . scodoc_dept , formation_id = formation_id )
} " >Ajouter une UE</a>
< / li >
< li > < a href = " {
url_for ( ' notes.formation_add_malus_modules ' ,
scodoc_dept = g . scodoc_dept , formation_id = formation_id )
} " class= " stdlink " >Ajouter des modules de malus dans chaque UE</a>
< / li >
< / ul >
"""
)
2020-09-26 16:19:37 +02:00
H . append ( " </div> " ) # formation_ue_list
2021-10-22 23:09:15 +02:00
if ues_externes :
H . append (
2021-11-17 10:28:51 +01:00
f """
< div class = " formation_ue_list formation_ue_list_externes " >
< div class = " ue_list_tit " > UE externes déclarées ( pour information ) :
< / div >
{ _ue_table_ues (
2021-10-22 23:09:15 +02:00
parcours ,
ues_externes ,
editable ,
tag_editable ,
has_perm_change ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
2021-11-17 10:28:51 +01:00
) }
< / div >
"""
2021-10-22 23:09:15 +02:00
)
2020-09-26 16:19:37 +02:00
H . append ( " <p><ul> " )
if editable :
H . append (
2021-11-17 10:28:51 +01:00
f """
< li > < a class = " stdlink " href = " {
url_for ( ' notes.formation_create_new_version ' ,
scodoc_dept = g . scodoc_dept , formation_id = formation_id
)
} " >Créer une nouvelle version (non verrouillée)</a>
< / li >
"""
2020-09-26 16:19:37 +02:00
)
H . append (
2021-11-17 10:28:51 +01:00
f """
< li > < a class = " stdlink " href = " {
url_for ( ' notes.formation_table_recap ' , scodoc_dept = g . scodoc_dept ,
formation_id = formation_id )
} " >Table récapitulative de la formation</a>
< / li >
< li > < a class = " stdlink " href = " {
url_for ( ' notes.formation_export ' , scodoc_dept = g . scodoc_dept ,
formation_id = formation_id , format = ' xml ' )
} " >Export XML de la formation</a>
( permet de la sauvegarder pour l ' échanger avec un autre site)
< / li >
2020-09-26 16:19:37 +02:00
2021-11-17 10:28:51 +01:00
< li > < a class = " stdlink " href = " {
url_for ( ' notes.formation_export ' , scodoc_dept = g . scodoc_dept ,
formation_id = formation_id , format = ' json ' )
} " >Export JSON de la formation</a>
< / li >
2020-09-26 16:19:37 +02:00
2021-11-17 10:28:51 +01:00
< li > < a class = " stdlink " href = " {
url_for ( ' notes.module_table ' , scodoc_dept = g . scodoc_dept ,
formation_id = formation_id )
} " >Liste détaillée des modules de la formation</a> (debug)
< / li >
< / ul >
< / p > """
2020-09-26 16:19:37 +02:00
)
2021-10-22 23:09:15 +02:00
if has_perm_change :
2020-09-26 16:19:37 +02:00
H . append (
"""
< h3 > < a name = " sems " > Semestres ou sessions de cette formation < / a > < / h3 >
< p > < ul > """
)
for sem in sco_formsemestre . do_formsemestre_list (
2021-08-19 10:28:35 +02:00
args = { " formation_id " : formation_id }
2020-09-26 16:19:37 +02:00
) :
H . append (
' <li><a class= " stdlink " href= " formsemestre_status?formsemestre_id= %(formsemestre_id)s " > %(titremois)s </a> '
% sem
)
2021-08-10 12:57:38 +02:00
if not sem [ " etat " ] :
2020-09-26 16:19:37 +02:00
H . append ( " [verrouillé] " )
else :
H . append (
2021-05-11 11:48:32 +02:00
' <a class= " stdlink " href= " formsemestre_editwithmodules?formation_id= %(formation_id)s &formsemestre_id= %(formsemestre_id)s " >Modifier</a> '
2020-09-26 16:19:37 +02:00
% sem
)
H . append ( " </li> " )
H . append ( " </ul> " )
2021-07-31 18:01:10 +02:00
if current_user . has_permission ( Permission . ScoImplement ) :
2020-09-26 16:19:37 +02:00
H . append (
2021-11-17 10:28:51 +01:00
f """ <ul>
< li > < a class = " stdlink " href = " {
url_for ( ' notes.formsemestre_createwithmodules ' , scodoc_dept = g . scodoc_dept ,
formation_id = formation_id , semestre_id = 1 )
} " >Mettre en place un nouveau semestre de formation %(acronyme)s </a>
< / li >
< / ul > """
2020-09-26 16:19:37 +02:00
)
# <li>(debug) <a class="stdlink" href="check_form_integrity?formation_id=%(formation_id)s">Vérifier cohérence</a></li>
2021-08-20 01:09:55 +02:00
warn , _ = sco_formsemestre_validation . check_formation_ues ( formation_id )
2020-09-26 16:19:37 +02:00
H . append ( warn )
2021-07-29 10:19:00 +02:00
H . append ( html_sco_header . sco_footer ( ) )
2020-09-26 16:19:37 +02:00
return " " . join ( H )
2021-10-22 23:09:15 +02:00
def _ue_table_ues (
parcours ,
ues ,
editable ,
tag_editable ,
has_perm_change ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
) :
2021-11-17 10:28:51 +01:00
""" Édition de programme: liste des UEs (avec leurs matières et modules).
Pour les formations classiques ( non APC / BUT )
"""
2021-10-22 23:09:15 +02:00
H = [ ]
cur_ue_semestre_id = None
iue = 0
for ue in ues :
if ue [ " ects " ] :
ue [ " ects_str " ] = " , %g ECTS " % ue [ " ects " ]
else :
ue [ " ects_str " ] = " "
if editable :
klass = " span_apo_edit "
else :
klass = " "
ue [ " code_apogee_str " ] = (
""" , Apo: <span class= " %s " data-url= " edit_ue_set_code_apogee " id= " %s " data-placeholder= " %s " > """
% ( klass , ue [ " ue_id " ] , scu . APO_MISSING_CODE_STR )
+ ( ue [ " code_apogee " ] or " " )
+ " </span> "
)
if cur_ue_semestre_id != ue [ " semestre_id " ] :
cur_ue_semestre_id = ue [ " semestre_id " ]
if iue > 0 :
H . append ( " </ul> " )
if ue [ " semestre_id " ] == sco_codes_parcours . UE_SEM_DEFAULT :
lab = " Pas d ' indication de semestre: "
else :
lab = " Semestre %s : " % ue [ " semestre_id " ]
H . append ( ' <div class= " ue_list_tit_sem " > %s </div> ' % lab )
H . append ( ' <ul class= " notes_ue_list " > ' )
H . append ( ' <li class= " notes_ue_list " > ' )
if iue != 0 and editable :
H . append (
' <a href= " ue_move?ue_id= %s &after=0 " class= " aud " > %s </a> '
% ( ue [ " ue_id " ] , arrow_up )
)
else :
H . append ( arrow_none )
if iue < len ( ues ) - 1 and editable :
H . append (
' <a href= " ue_move?ue_id= %s &after=1 " class= " aud " > %s </a> '
% ( ue [ " ue_id " ] , arrow_down )
)
else :
H . append ( arrow_none )
iue + = 1
ue [ " acro_titre " ] = str ( ue [ " acronyme " ] )
if ue [ " titre " ] != ue [ " acronyme " ] :
ue [ " acro_titre " ] + = " " + str ( ue [ " titre " ] )
H . append (
""" %(acro_titre)s <span class= " ue_code " >(code %(ue_code)s %(ects_str)s , coef. %(coefficient)3.2f %(code_apogee_str)s )</span>
< span class = " ue_coef " > < / span >
"""
% ue
)
if ue [ " type " ] != sco_codes_parcours . UE_STANDARD :
H . append (
' <span class= " ue_type " > %s </span> '
% sco_codes_parcours . UE_TYPE_NAME [ ue [ " type " ] ]
)
if ue [ " is_external " ] :
# Cas spécial: si l'UE externe a plus d'un module, c'est peut être une UE
# qui a été déclarée externe par erreur (ou suite à un bug d'import/export xml)
# Dans ce cas, propose de changer le type (même si verrouillée)
if len ( sco_moduleimpl . moduleimpls_in_external_ue ( ue [ " ue_id " ] ) ) > 1 :
H . append ( ' <span class= " ue_is_external " > ' )
if has_perm_change :
H . append (
f """ <a class= " stdlink " href= " {
url_for ( " notes.ue_set_internal " , scodoc_dept = g . scodoc_dept , ue_id = ue [ " ue_id " ] )
} " >transformer en UE ordinaire</a> " " "
)
H . append ( " </span> " )
ue_editable = editable and not ue_is_locked ( ue [ " ue_id " ] )
if ue_editable :
H . append (
' <a class= " stdlink " href= " ue_edit?ue_id= %(ue_id)s " >modifier</a> ' % ue
)
else :
H . append ( ' <span class= " locked " >[verrouillé]</span> ' )
2021-11-08 19:44:25 +01:00
if parcours . APC_SAE :
func_html_list = _ue_table_ressources_saes
else :
func_html_list = _ue_table_matieres
2021-10-22 23:09:15 +02:00
H . append (
2021-11-08 19:44:25 +01:00
func_html_list (
2021-10-22 23:09:15 +02:00
parcours ,
ue ,
editable ,
tag_editable ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
2021-11-17 10:28:51 +01:00
module_type = module_type ,
2021-10-22 23:09:15 +02:00
)
)
return " \n " . join ( H )
def _ue_table_matieres (
parcours ,
ue ,
editable ,
tag_editable ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
2021-11-17 10:28:51 +01:00
module_type = None ,
2021-10-22 23:09:15 +02:00
) :
""" Édition de programme: liste des matières (et leurs modules) d ' une UE. """
H = [ ]
if not parcours . UE_IS_MODULE :
H . append ( ' <ul class= " notes_matiere_list " > ' )
matieres = sco_edit_matiere . matiere_list ( args = { " ue_id " : ue [ " ue_id " ] } )
for mat in matieres :
if not parcours . UE_IS_MODULE :
H . append ( ' <li class= " notes_matiere_list " > ' )
if editable and not sco_edit_matiere . matiere_is_locked ( mat [ " matiere_id " ] ) :
H . append (
f """ <a class= " stdlink " href= " {
url_for ( " notes.matiere_edit " ,
scodoc_dept = g . scodoc_dept , matiere_id = mat [ " matiere_id " ] )
} " >
"""
)
H . append ( " %(titre)s " % mat )
if editable and not sco_edit_matiere . matiere_is_locked ( mat [ " matiere_id " ] ) :
H . append ( " </a> " )
modules = sco_edit_module . module_list ( args = { " matiere_id " : mat [ " matiere_id " ] } )
H . append (
_ue_table_modules (
parcours ,
mat ,
modules ,
editable ,
tag_editable ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
)
)
2021-11-08 19:44:25 +01:00
if not parcours . UE_IS_MODULE :
H . append ( " </li> " )
2021-10-22 23:09:15 +02:00
if not matieres :
H . append ( " <li>Aucune matière dans cette UE ! " )
if editable :
H . append (
""" <a class= " stdlink " href= " ue_delete?ue_id= %(ue_id)s " >supprimer l ' UE</a> """
% ue
)
H . append ( " </li> " )
if editable and not parcours . UE_IS_MODULE :
H . append (
' <li><a class= " stdlink " href= " matiere_create?ue_id= %(ue_id)s " >créer une matière</a> </li> '
% ue
)
if not parcours . UE_IS_MODULE :
H . append ( " </ul> " )
return " \n " . join ( H )
2021-11-08 19:44:25 +01:00
def _ue_table_ressources_saes (
parcours ,
ue ,
editable ,
tag_editable ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
2021-11-17 10:28:51 +01:00
module_type = None ,
2021-11-08 19:44:25 +01:00
) :
""" Édition de programme: liste des ressources et SAÉs d ' une UE.
( pour les parcours APC_SAE )
"""
matieres = sco_edit_matiere . matiere_list ( args = { " ue_id " : ue [ " ue_id " ] } )
if not matieres :
# Les formations APC (BUT) n'utilisent pas de matières
# mais il doit y en avoir une par UE
# silently fix this on-the-fly to ease migration
_ = sco_edit_matiere . do_matiere_create (
{ " ue_id " : ue [ " ue_id " ] , " titre " : " APC " , " numero " : 1 } ,
)
matieres = sco_edit_matiere . matiere_list ( args = { " ue_id " : ue [ " ue_id " ] } )
assert matieres
mat = matieres [ 0 ]
H = [
"""
< ul class = " notes_matiere_list but_matiere_list " >
"""
]
modules = sco_edit_module . module_list ( args = { " ue_id " : ue [ " ue_id " ] } )
2021-11-17 10:28:51 +01:00
for titre , element_name , element_type in (
2021-11-08 19:44:25 +01:00
( " Ressources " , " ressource " , scu . ModuleType . RESSOURCE ) ,
( " SAÉs " , " SAÉ " , scu . ModuleType . SAE ) ,
( " Autres modules " , " xxx " , None ) ,
) :
H . append ( f ' <li class= " notes_matiere_list " > { titre } ' )
elements = [
m
for m in modules
2021-11-17 10:28:51 +01:00
if element_type == m [ " module_type " ]
2021-11-08 19:44:25 +01:00
or (
2021-11-17 10:28:51 +01:00
( element_type is None )
2021-11-08 19:44:25 +01:00
and m [ " module_type " ]
not in ( scu . ModuleType . RESSOURCE , scu . ModuleType . SAE )
)
]
H . append (
_ue_table_modules (
parcours ,
mat ,
elements ,
editable ,
tag_editable ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
2021-11-17 10:28:51 +01:00
module_type = module_type ,
2021-11-08 19:44:25 +01:00
empty_list_msg = " Aucune " + element_name ,
create_element_msg = " créer une " + element_name ,
add_suppress_link = False ,
)
)
H . append ( " </li></ul> " )
return " \n " . join ( H )
2021-10-22 23:09:15 +02:00
def _ue_table_modules (
parcours ,
mat ,
modules ,
editable ,
tag_editable ,
arrow_up ,
arrow_down ,
arrow_none ,
delete_icon ,
delete_disabled_icon ,
2021-11-08 19:44:25 +01:00
unit_name = " matière " ,
add_suppress_link = True , # lien "supprimer cette matière"
empty_list_msg = " Aucun élément dans cette matière " ,
create_element_msg = " créer un module " ,
2021-10-22 23:09:15 +02:00
) :
""" Édition de programme: liste des modules d ' une matière d ' une UE """
H = [ ' <ul class= " notes_module_list " > ' ]
im = 0
for mod in modules :
mod [ " nb_moduleimpls " ] = sco_edit_module . module_count_moduleimpls (
mod [ " module_id " ]
)
klass = " notes_module_list "
2021-11-12 22:17:46 +01:00
if mod [ " module_type " ] == ModuleType . MALUS :
2021-10-22 23:09:15 +02:00
klass + = " module_malus "
H . append ( ' <li class= " %s " > ' % klass )
H . append ( ' <span class= " notes_module_list_buts " > ' )
if im != 0 and editable :
H . append (
' <a href= " module_move?module_id= %s &after=0 " class= " aud " > %s </a> '
% ( mod [ " module_id " ] , arrow_up )
)
else :
H . append ( arrow_none )
if im < len ( modules ) - 1 and editable :
H . append (
' <a href= " module_move?module_id= %s &after=1 " class= " aud " > %s </a> '
% ( mod [ " module_id " ] , arrow_down )
)
else :
H . append ( arrow_none )
im + = 1
if mod [ " nb_moduleimpls " ] == 0 and editable :
H . append (
' <a class= " smallbutton " href= " module_delete?module_id= %s " > %s </a> '
% ( mod [ " module_id " ] , delete_icon )
)
else :
H . append ( delete_disabled_icon )
H . append ( " </span> " )
mod_editable = (
editable # and not sco_edit_module.module_is_locked( Mod['module_id'])
)
if mod_editable :
H . append (
' <a class= " discretelink " title= " Modifier le module numéro %(numero)s , utilisé par %(nb_moduleimpls)d sessions " href= " module_edit?module_id= %(module_id)s " > '
% mod
)
H . append (
' <span class= " formation_module_tit " > %s </span> '
% scu . join_words ( mod [ " code " ] , mod [ " titre " ] )
)
if mod_editable :
H . append ( " </a> " )
heurescoef = (
" %(heures_cours)s / %(heures_td)s / %(heures_tp)s , coef. %(coefficient)s " % mod
)
if mod_editable :
klass = " span_apo_edit "
else :
klass = " "
heurescoef + = (
' , Apo: <span class= " %s " data-url= " edit_module_set_code_apogee " id= " %s " data-placeholder= " %s " > '
% ( klass , mod [ " module_id " ] , scu . APO_MISSING_CODE_STR )
+ ( mod [ " code_apogee " ] or " " )
+ " </span> "
)
if tag_editable :
tag_cls = " module_tag_editor "
else :
tag_cls = " module_tag_editor_ro "
tag_mk = """ <span class= " sco_tag_edit " ><form><textarea data-module_id= " {} " class= " {} " > {} </textarea></form></span> """
tag_edit = tag_mk . format (
mod [ " module_id " ] ,
tag_cls ,
" , " . join ( sco_tag_module . module_tag_list ( mod [ " module_id " ] ) ) ,
)
H . append (
" %s %s " % ( parcours . SESSION_NAME , mod [ " semestre_id " ] )
+ " ( %s ) " % heurescoef
+ tag_edit
)
H . append ( " </li> " )
if not modules :
2021-11-08 19:44:25 +01:00
H . append ( f " <li> { empty_list_msg } ! " )
if editable and add_suppress_link :
2021-10-22 23:09:15 +02:00
H . append (
f """ <a class= " stdlink " href= " {
url_for ( " notes.matiere_delete " ,
scodoc_dept = g . scodoc_dept , matiere_id = mat [ " matiere_id " ] ) } "
> la supprimer < / a >
"""
)
H . append ( " </li> " )
if editable : # and ((not parcours.UE_IS_MODULE) or len(Modlist) == 0):
H . append (
f """ <li> <a class= " stdlink " href= " {
url_for ( " notes.module_create " ,
scodoc_dept = g . scodoc_dept , matiere_id = mat [ " matiere_id " ] ) } "
2021-11-08 19:44:25 +01:00
> { create_element_msg } < / a > < / li >
2021-10-22 23:09:15 +02:00
"""
)
H . append ( " </ul> " )
return " \n " . join ( H )
2021-08-20 01:09:55 +02:00
def ue_sharing_code ( ue_code = None , ue_id = None , hide_ue_id = None ) :
2020-09-26 16:19:37 +02:00
""" HTML list of UE sharing this code
Either ue_code or ue_id may be specified .
2021-08-09 07:43:41 +02:00
hide_ue_id spécifie un id à retirer de la liste .
2020-09-26 16:19:37 +02:00
"""
2021-06-19 23:21:37 +02:00
from app . scodoc import sco_formations
2021-09-30 17:50:37 +02:00
ue_code = str ( ue_code )
2020-09-26 16:19:37 +02:00
if ue_id :
2021-10-17 23:19:26 +02:00
ue = ue_list ( args = { " ue_id " : ue_id } ) [ 0 ]
2020-09-26 16:19:37 +02:00
if not ue_code :
ue_code = ue [ " ue_code " ]
2021-08-19 10:28:35 +02:00
F = sco_formations . formation_list ( args = { " formation_id " : ue [ " formation_id " ] } ) [ 0 ]
2020-09-26 16:19:37 +02:00
formation_code = F [ " formation_code " ]
2021-09-27 17:18:43 +02:00
# UE du même code, code formation et departement:
2021-09-26 11:28:13 +02:00
q_ues = (
2021-11-12 22:17:46 +01:00
UniteEns . query . filter_by ( ue_code = ue_code )
. join ( UniteEns . formation , aliased = True )
2021-09-27 17:18:43 +02:00
. filter_by ( dept_id = g . scodoc_dept_id , formation_code = formation_code )
2021-09-26 11:28:13 +02:00
)
2020-09-26 16:19:37 +02:00
else :
2021-09-27 17:18:43 +02:00
# Toutes les UE du departement avec ce code:
2021-09-26 11:28:13 +02:00
q_ues = (
2021-11-12 22:17:46 +01:00
UniteEns . query . filter_by ( ue_code = ue_code )
. join ( UniteEns . formation , aliased = True )
2021-09-27 17:18:43 +02:00
. filter_by ( dept_id = g . scodoc_dept_id )
2021-09-26 11:28:13 +02:00
)
2020-09-26 16:19:37 +02:00
if hide_ue_id : # enlève l'ue de depart
2021-11-12 22:17:46 +01:00
q_ues = q_ues . filter ( UniteEns . id != hide_ue_id )
2020-09-26 16:19:37 +02:00
2021-09-26 11:28:13 +02:00
ues = q_ues . all ( )
if not ues :
2020-09-26 16:19:37 +02:00
if ue_id :
return """ <span class= " ue_share " >Seule UE avec code %s </span> """ % ue_code
else :
return """ <span class= " ue_share " >Aucune UE avec code %s </span> """ % ue_code
H = [ ]
if ue_id :
H . append ( ' <span class= " ue_share " >Autres UE avec le code %s :</span> ' % ue_code )
else :
H . append ( ' <span class= " ue_share " >UE avec le code %s :</span> ' % ue_code )
H . append ( " <ul> " )
2021-09-26 11:28:13 +02:00
for ue in ues :
2020-09-26 16:19:37 +02:00
H . append (
2021-09-26 11:28:13 +02:00
f """ <li> { ue . acronyme } ( { ue . titre } ) dans <a class= " stdlink "
2021-10-17 23:19:26 +02:00
href = " { url_for( " notes . ue_table " , scodoc_dept=g.scodoc_dept, formation_id=ue.formation.id)} "
2021-09-26 11:28:13 +02:00
> { ue . formation . acronyme } ( { ue . formation . titre } ) < / a > , version { ue . formation . version }
< / li >
"""
2020-09-26 16:19:37 +02:00
)
H . append ( " </ul> " )
return " \n " . join ( H )
2021-08-20 01:09:55 +02:00
def do_ue_edit ( args , bypass_lock = False , dont_invalidate_cache = False ) :
2020-09-26 16:19:37 +02:00
" edit an UE "
# check
ue_id = args [ " ue_id " ]
2021-10-17 23:19:26 +02:00
ue = ue_list ( { " ue_id " : ue_id } ) [ 0 ]
2021-08-20 01:09:55 +02:00
if ( not bypass_lock ) and ue_is_locked ( ue [ " ue_id " ] ) :
2020-09-26 16:19:37 +02:00
raise ScoLockedFormError ( )
# check: acronyme unique dans cette formation
2021-07-09 17:47:06 +02:00
if " acronyme " in args :
2020-09-26 16:19:37 +02:00
new_acro = args [ " acronyme " ]
2021-10-17 23:19:26 +02:00
ues = ue_list ( { " formation_id " : ue [ " formation_id " ] , " acronyme " : new_acro } )
2020-09-26 16:19:37 +02:00
if ues and ues [ 0 ] [ " ue_id " ] != ue_id :
raise ScoValueError ( ' Acronyme d \' UE " %s " déjà utilisé ! ' % args [ " acronyme " ] )
# On ne peut pas supprimer le code UE:
2021-07-09 17:47:06 +02:00
if " ue_code " in args and not args [ " ue_code " ] :
2020-09-26 16:19:37 +02:00
del args [ " ue_code " ]
2021-06-15 13:59:56 +02:00
cnx = ndb . GetDBConnexion ( )
2021-06-17 00:08:37 +02:00
_ueEditor . edit ( cnx , args )
2020-09-26 16:19:37 +02:00
if not dont_invalidate_cache :
# Invalide les semestres utilisant cette formation:
2021-07-19 19:53:01 +02:00
sco_edit_formation . invalidate_sems_in_formation ( ue [ " formation_id " ] )
2020-09-26 16:19:37 +02:00
# essai edition en ligne:
2021-08-30 23:28:15 +02:00
def edit_ue_set_code_apogee ( id = None , value = None ) :
2020-09-26 16:19:37 +02:00
" set UE code apogee "
ue_id = id
value = value . strip ( " -_ \t " )
log ( " edit_ue_set_code_apogee: ue_id= %s code_apogee= %s " % ( ue_id , value ) )
2021-10-17 23:19:26 +02:00
ues = ue_list ( args = { " ue_id " : ue_id } )
2020-09-26 16:19:37 +02:00
if not ues :
return " ue invalide "
do_ue_edit (
{ " ue_id " : ue_id , " code_apogee " : value } ,
bypass_lock = True ,
dont_invalidate_cache = False ,
)
if not value :
2021-02-04 20:02:44 +01:00
value = scu . APO_MISSING_CODE_STR
2020-09-26 16:19:37 +02:00
return value
2021-08-20 01:09:55 +02:00
def ue_is_locked ( ue_id ) :
2021-06-13 18:29:53 +02:00
""" True if UE should not be modified
( contains modules used in a locked formsemestre )
"""
r = ndb . SimpleDictFetch (
2021-08-08 17:38:46 +02:00
""" SELECT ue.id
FROM notes_ue ue , notes_modules mod , notes_formsemestre sem , notes_moduleimpl mi
WHERE ue . id = mod . ue_id
AND mi . module_id = mod . id AND mi . formsemestre_id = sem . id
AND ue . id = % ( ue_id ) s AND sem . etat = false
2021-06-13 18:29:53 +02:00
""" ,
{ " ue_id " : ue_id } ,
)
return len ( r ) > 0
2020-09-26 16:19:37 +02:00
# ---- Table recap formation
2021-09-27 10:20:10 +02:00
def formation_table_recap ( formation_id , format = " html " ) :
2021-01-16 11:49:02 +01:00
""" Table recapitulant formation. """
2021-06-19 23:21:37 +02:00
from app . scodoc import sco_formations
2021-08-19 10:28:35 +02:00
F = sco_formations . formation_list ( args = { " formation_id " : formation_id } )
2020-09-26 16:19:37 +02:00
if not F :
raise ScoValueError ( " invalid formation_id " )
F = F [ 0 ]
T = [ ]
2021-10-21 06:32:03 +02:00
ues = ue_list ( args = { " formation_id " : formation_id } )
for ue in ues :
Matlist = sco_edit_matiere . matiere_list ( args = { " ue_id " : ue [ " ue_id " ] } )
2020-09-26 16:19:37 +02:00
for Mat in Matlist :
2021-10-16 19:20:36 +02:00
Modlist = sco_edit_module . module_list (
2021-08-20 01:09:55 +02:00
args = { " matiere_id " : Mat [ " matiere_id " ] }
2021-06-17 00:08:37 +02:00
)
2020-09-26 16:19:37 +02:00
for Mod in Modlist :
2021-06-13 19:12:20 +02:00
Mod [ " nb_moduleimpls " ] = sco_edit_module . module_count_moduleimpls (
2021-08-20 01:09:55 +02:00
Mod [ " module_id " ]
2020-09-26 16:19:37 +02:00
)
#
T . append (
{
2021-10-21 06:32:03 +02:00
" UE_acro " : ue [ " acronyme " ] ,
2020-09-26 16:19:37 +02:00
" Mat_tit " : Mat [ " titre " ] ,
" Mod_tit " : Mod [ " abbrev " ] or Mod [ " titre " ] ,
" Mod_code " : Mod [ " code " ] ,
" Mod_coef " : Mod [ " coefficient " ] ,
" Mod_sem " : Mod [ " semestre_id " ] ,
" nb_moduleimpls " : Mod [ " nb_moduleimpls " ] ,
" heures_cours " : Mod [ " heures_cours " ] ,
" heures_td " : Mod [ " heures_td " ] ,
" heures_tp " : Mod [ " heures_tp " ] ,
" ects " : Mod [ " ects " ] ,
}
)
columns_ids = [
" UE_acro " ,
" Mat_tit " ,
" Mod_tit " ,
" Mod_code " ,
" Mod_coef " ,
" Mod_sem " ,
" nb_moduleimpls " ,
" heures_cours " ,
" heures_td " ,
" heures_tp " ,
" ects " ,
]
titles = {
" UE_acro " : " UE " ,
" Mat_tit " : " Matière " ,
" Mod_tit " : " Module " ,
" Mod_code " : " Code " ,
" Mod_coef " : " Coef. " ,
" Mod_sem " : " Sem. " ,
" nb_moduleimpls " : " Nb utilisé " ,
" heures_cours " : " Cours (h) " ,
" heures_td " : " TD (h) " ,
" heures_tp " : " TP (h) " ,
" ects " : " ECTS " ,
}
title = (
""" Formation %(titre)s ( %(acronyme)s ) [version %(version)s ] code %(formation_code)s """
% F
)
tab = GenTable (
columns_ids = columns_ids ,
rows = T ,
titles = titles ,
2021-08-21 17:07:44 +02:00
origin = " Généré par %s le " % scu . sco_version . SCONAME
2021-02-05 21:35:21 +01:00
+ scu . timedate_human_repr ( )
+ " " ,
2020-09-26 16:19:37 +02:00
caption = title ,
html_caption = title ,
html_class = " table_leftalign " ,
2021-09-18 10:10:02 +02:00
base_url = " %s ?formation_id= %s " % ( request . base_url , formation_id ) ,
2020-09-26 16:19:37 +02:00
page_title = title ,
html_title = " <h2> " + title + " </h2> " ,
pdf_title = title ,
2021-07-28 17:03:54 +02:00
preferences = sco_preferences . SemPreferences ( ) ,
2020-09-26 16:19:37 +02:00
)
2021-09-16 00:15:10 +02:00
return tab . make_page ( format = format )
2020-09-26 16:19:37 +02:00
2021-08-20 01:09:55 +02:00
def ue_list_semestre_ids ( ue ) :
2020-09-26 16:19:37 +02:00
""" Liste triée des numeros de semestres des modules dans cette UE
Il est recommandable que tous les modules d ' une UE aient le même indice de semestre.
Mais cela n ' a pas toujours été le cas dans les programmes pédagogiques officiels,
aussi ScoDoc laisse le choix .
"""
2021-11-17 10:28:51 +01:00
modules = sco_edit_module . module_list ( args = { " ue_id " : ue [ " ue_id " ] } )
return sorted ( list ( set ( [ mod [ " semestre_id " ] for mod in modules ] ) ) )